mirror of
https://github.com/perstarkse/minne.git
synced 2026-04-23 17:28:34 +02:00
feat: displaying and managing active jobs
This commit is contained in:
284
assets/style.css
284
assets/style.css
@@ -828,6 +828,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tab {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
color: var(--color-base-content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--tab-p: 1rem;
|
||||||
|
--tab-bg: var(--color-base-100);
|
||||||
|
--tab-border-color: var(--color-base-300);
|
||||||
|
--tab-radius-ss: 0;
|
||||||
|
--tab-radius-se: 0;
|
||||||
|
--tab-radius-es: 0;
|
||||||
|
--tab-radius-ee: 0;
|
||||||
|
--tab-order: 0;
|
||||||
|
--tab-radius-min: calc(0.75rem - var(--border));
|
||||||
|
border-color: transparent;
|
||||||
|
order: var(--tab-order);
|
||||||
|
height: calc(var(--size-field, 0.25rem) * 10);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
padding-inline-start: var(--tab-p);
|
||||||
|
padding-inline-end: var(--tab-p);
|
||||||
|
&:is(input[type="radio"]) {
|
||||||
|
min-width: fit-content;
|
||||||
|
&:after {
|
||||||
|
content: attr(aria-label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:checked, &:is(.tab-active, [aria-selected="true"]) {
|
||||||
|
& + .tab-content {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(:checked, :hover, .tab-active, [aria-selected="true"]) {
|
||||||
|
color: color-mix(in oklab, var(--color-base-content) 50%, transparent);
|
||||||
|
}
|
||||||
|
&:not(input):empty {
|
||||||
|
flex-grow: 1;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid currentColor;
|
||||||
|
outline-offset: -5px;
|
||||||
|
}
|
||||||
|
&[disabled] {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
.dropdown {
|
.dropdown {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -2343,6 +2406,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tab-content {
|
||||||
|
order {
|
||||||
|
}
|
||||||
|
order: var(--tabcontent-order);
|
||||||
|
display: none;
|
||||||
|
border-color: transparent;
|
||||||
|
--tabcontent-radius-ss: 0;
|
||||||
|
--tabcontent-radius-se: 0;
|
||||||
|
--tabcontent-radius-es: 0;
|
||||||
|
--tabcontent-radius-ee: 0;
|
||||||
|
--tabcontent-order: 1;
|
||||||
|
width: 100%;
|
||||||
|
margin: var(--tabcontent-margin);
|
||||||
|
border-width: var(--border);
|
||||||
|
border-start-start-radius: var(--tabcontent-radius-ss);
|
||||||
|
border-start-end-radius: var(--tabcontent-radius-se);
|
||||||
|
border-end-start-radius: var(--tabcontent-radius-es);
|
||||||
|
border-end-end-radius: var(--tabcontent-radius-ee);
|
||||||
|
}
|
||||||
.modal-box {
|
.modal-box {
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
grid-row-start: 1;
|
grid-row-start: 1;
|
||||||
@@ -2390,6 +2472,11 @@
|
|||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
.drawer-content {
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-row-start: 1;
|
||||||
|
min-width: calc(0.25rem * 0);
|
||||||
|
}
|
||||||
.chat-image {
|
.chat-image {
|
||||||
grid-row: span 2 / span 2;
|
grid-row: span 2 / span 2;
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
@@ -2427,6 +2514,15 @@
|
|||||||
max-width: 96rem;
|
max-width: 96rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.m-0 {
|
||||||
|
margin: calc(var(--spacing) * 0);
|
||||||
|
}
|
||||||
|
.m-6 {
|
||||||
|
margin: calc(var(--spacing) * 6);
|
||||||
|
}
|
||||||
|
.m-8 {
|
||||||
|
margin: calc(var(--spacing) * 8);
|
||||||
|
}
|
||||||
.filter {
|
.filter {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -3026,6 +3122,9 @@
|
|||||||
.mt-8 {
|
.mt-8 {
|
||||||
margin-top: calc(var(--spacing) * 8);
|
margin-top: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
.mt-10 {
|
||||||
|
margin-top: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
.mr-1 {
|
.mr-1 {
|
||||||
margin-right: calc(var(--spacing) * 1);
|
margin-right: calc(var(--spacing) * 1);
|
||||||
}
|
}
|
||||||
@@ -3048,6 +3147,9 @@
|
|||||||
.mb-8 {
|
.mb-8 {
|
||||||
margin-bottom: calc(var(--spacing) * 8);
|
margin-bottom: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
.mb-10 {
|
||||||
|
margin-bottom: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
.alert {
|
.alert {
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -3319,6 +3421,13 @@
|
|||||||
column-gap: calc(0.25rem * 3);
|
column-gap: calc(0.25rem * 3);
|
||||||
padding-block: calc(0.25rem * 1);
|
padding-block: calc(0.25rem * 1);
|
||||||
}
|
}
|
||||||
|
.mask {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
}
|
||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@@ -3352,6 +3461,27 @@
|
|||||||
.table {
|
.table {
|
||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
|
.btn-square {
|
||||||
|
padding-inline: calc(0.25rem * 0);
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
}
|
||||||
|
.size-6 {
|
||||||
|
width: calc(var(--spacing) * 6);
|
||||||
|
height: calc(var(--spacing) * 6);
|
||||||
|
}
|
||||||
|
.size-8 {
|
||||||
|
width: calc(var(--spacing) * 8);
|
||||||
|
height: calc(var(--spacing) * 8);
|
||||||
|
}
|
||||||
|
.size-10 {
|
||||||
|
width: calc(var(--spacing) * 10);
|
||||||
|
height: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
|
.size-\[1\.2em\] {
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
}
|
||||||
.h-5 {
|
.h-5 {
|
||||||
height: calc(var(--spacing) * 5);
|
height: calc(var(--spacing) * 5);
|
||||||
}
|
}
|
||||||
@@ -3367,12 +3497,6 @@
|
|||||||
.w-5 {
|
.w-5 {
|
||||||
width: calc(var(--spacing) * 5);
|
width: calc(var(--spacing) * 5);
|
||||||
}
|
}
|
||||||
.w-12 {
|
|
||||||
width: calc(var(--spacing) * 12);
|
|
||||||
}
|
|
||||||
.w-24 {
|
|
||||||
width: calc(var(--spacing) * 24);
|
|
||||||
}
|
|
||||||
.w-32 {
|
.w-32 {
|
||||||
width: calc(var(--spacing) * 32);
|
width: calc(var(--spacing) * 32);
|
||||||
}
|
}
|
||||||
@@ -3388,6 +3512,9 @@
|
|||||||
.flex-shrink {
|
.flex-shrink {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
|
.shrink {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
@@ -3463,15 +3590,24 @@
|
|||||||
.grid-cols-1 {
|
.grid-cols-1 {
|
||||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
.\!flex-col {
|
||||||
|
flex-direction: column !important;
|
||||||
|
}
|
||||||
.flex-col {
|
.flex-col {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
.flex-row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
.flex-wrap {
|
.flex-wrap {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.items-center {
|
.items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.justify-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
.justify-center {
|
.justify-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
@@ -3481,6 +3617,9 @@
|
|||||||
.justify-start {
|
.justify-start {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
.gap-1 {
|
||||||
|
gap: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.gap-4 {
|
.gap-4 {
|
||||||
gap: calc(var(--spacing) * 4);
|
gap: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
@@ -3546,12 +3685,21 @@
|
|||||||
.border-transparent {
|
.border-transparent {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
|
.bg-accent {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
}
|
||||||
.bg-base-100 {
|
.bg-base-100 {
|
||||||
background-color: var(--color-base-100);
|
background-color: var(--color-base-100);
|
||||||
}
|
}
|
||||||
.bg-base-200 {
|
.bg-base-200 {
|
||||||
background-color: var(--color-base-200);
|
background-color: var(--color-base-200);
|
||||||
}
|
}
|
||||||
|
.bg-primary {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
}
|
||||||
|
.bg-secondary {
|
||||||
|
background-color: var(--color-secondary);
|
||||||
|
}
|
||||||
.bg-linear-to-r {
|
.bg-linear-to-r {
|
||||||
--tw-gradient-position: to right in oklab,;
|
--tw-gradient-position: to right in oklab,;
|
||||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||||
@@ -3619,6 +3767,9 @@
|
|||||||
.pt-10 {
|
.pt-10 {
|
||||||
padding-top: calc(var(--spacing) * 10);
|
padding-top: calc(var(--spacing) * 10);
|
||||||
}
|
}
|
||||||
|
.pb-2 {
|
||||||
|
padding-bottom: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
.text-center {
|
.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -3672,6 +3823,10 @@
|
|||||||
--tw-font-weight: var(--font-weight-semibold);
|
--tw-font-weight: var(--font-weight-semibold);
|
||||||
font-weight: var(--font-weight-semibold);
|
font-weight: var(--font-weight-semibold);
|
||||||
}
|
}
|
||||||
|
.tracking-wide {
|
||||||
|
--tw-tracking: var(--tracking-wide);
|
||||||
|
letter-spacing: var(--tracking-wide);
|
||||||
|
}
|
||||||
.text-nowrap {
|
.text-nowrap {
|
||||||
text-wrap: nowrap;
|
text-wrap: nowrap;
|
||||||
}
|
}
|
||||||
@@ -3693,6 +3848,9 @@
|
|||||||
.text-accent {
|
.text-accent {
|
||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
}
|
}
|
||||||
|
.text-accent-content {
|
||||||
|
color: var(--color-accent-content);
|
||||||
|
}
|
||||||
.text-base-content {
|
.text-base-content {
|
||||||
color: var(--color-base-content);
|
color: var(--color-base-content);
|
||||||
}
|
}
|
||||||
@@ -3717,6 +3875,9 @@
|
|||||||
.text-secondary {
|
.text-secondary {
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
}
|
}
|
||||||
|
.text-secondary-content {
|
||||||
|
color: var(--color-secondary-content);
|
||||||
|
}
|
||||||
.text-transparent {
|
.text-transparent {
|
||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
@@ -3729,6 +3890,10 @@
|
|||||||
.italic {
|
.italic {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
.ordinal {
|
||||||
|
--tw-ordinal: ordinal;
|
||||||
|
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
||||||
|
}
|
||||||
.btn-link {
|
.btn-link {
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
outline-color: currentColor;
|
outline-color: currentColor;
|
||||||
@@ -3746,6 +3911,9 @@
|
|||||||
.underline {
|
.underline {
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
}
|
}
|
||||||
|
.accent-accent-content {
|
||||||
|
accent-color: var(--color-accent-content);
|
||||||
|
}
|
||||||
.opacity-60 {
|
.opacity-60 {
|
||||||
opacity: 60%;
|
opacity: 60%;
|
||||||
}
|
}
|
||||||
@@ -3757,10 +3925,6 @@
|
|||||||
opacity: 100%;
|
opacity: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ring {
|
|
||||||
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentColor);
|
|
||||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
||||||
}
|
|
||||||
.shadow {
|
.shadow {
|
||||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
@@ -3866,6 +4030,11 @@
|
|||||||
margin-top: calc(var(--spacing) * 4);
|
margin-top: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sm\:w-fit {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:max-w-md {
|
.sm\:max-w-md {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
max-width: var(--container-md);
|
max-width: var(--container-md);
|
||||||
@@ -3876,6 +4045,16 @@
|
|||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sm\:flex-col {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:flex-row {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:px-0 {
|
.sm\:px-0 {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
padding-inline: calc(var(--spacing) * 0);
|
padding-inline: calc(var(--spacing) * 0);
|
||||||
@@ -3887,6 +4066,11 @@
|
|||||||
line-height: var(--tw-leading, var(--text-6xl--line-height));
|
line-height: var(--tw-leading, var(--text-6xl--line-height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:grid-cols-2 {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:grid-cols-3 {
|
.md\:grid-cols-3 {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
@@ -3907,6 +4091,50 @@
|
|||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.\[\&\:before\]\:normal-case {
|
||||||
|
&:before {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.\[\&\:before\]\:uppercase {
|
||||||
|
&:before {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.\[\&\:before\]\:opacity-60 {
|
||||||
|
&:before {
|
||||||
|
opacity: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.\[\&\:before\]\:opacity-100 {
|
||||||
|
&:before {
|
||||||
|
opacity: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.\[\&\:before\]\:content-\[\'Content\:_\'\] {
|
||||||
|
&:before {
|
||||||
|
--tw-content: 'Content: ';
|
||||||
|
content: var(--tw-content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.\[\&\:before\]\:content-\[\'Instructions\:_\'\] {
|
||||||
|
&:before {
|
||||||
|
--tw-content: 'Instructions: ';
|
||||||
|
content: var(--tw-content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.\[\&\:before\]\:content-\[\'Status\:_\'\] {
|
||||||
|
&:before {
|
||||||
|
--tw-content: 'Status: ';
|
||||||
|
content: var(--tw-content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.\[\&\:before\]\:content-\[\'Text\:_\'\] {
|
||||||
|
&:before {
|
||||||
|
--tw-content: 'Text: ';
|
||||||
|
content: var(--tw-content);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@layer base {
|
@layer base {
|
||||||
*, ::after, ::before, ::backdrop, ::file-selector-button {
|
*, ::after, ::before, ::backdrop, ::file-selector-button {
|
||||||
@@ -4262,6 +4490,12 @@ video {
|
|||||||
--tw-gradient-via-position: 50%;
|
--tw-gradient-via-position: 50%;
|
||||||
--tw-gradient-to-position: 100%;
|
--tw-gradient-to-position: 100%;
|
||||||
--tw-font-weight: initial;
|
--tw-font-weight: initial;
|
||||||
|
--tw-tracking: initial;
|
||||||
|
--tw-ordinal: initial;
|
||||||
|
--tw-slashed-zero: initial;
|
||||||
|
--tw-numeric-figure: initial;
|
||||||
|
--tw-numeric-spacing: initial;
|
||||||
|
--tw-numeric-fraction: initial;
|
||||||
--tw-shadow: 0 0 #0000;
|
--tw-shadow: 0 0 #0000;
|
||||||
--tw-shadow-color: initial;
|
--tw-shadow-color: initial;
|
||||||
--tw-inset-shadow: 0 0 #0000;
|
--tw-inset-shadow: 0 0 #0000;
|
||||||
@@ -4294,6 +4528,7 @@ video {
|
|||||||
--tw-backdrop-saturate: initial;
|
--tw-backdrop-saturate: initial;
|
||||||
--tw-backdrop-sepia: initial;
|
--tw-backdrop-sepia: initial;
|
||||||
--tw-ease: initial;
|
--tw-ease: initial;
|
||||||
|
--tw-content: "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4404,6 +4639,30 @@ video {
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
|
@property --tw-tracking {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-ordinal {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-slashed-zero {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-numeric-figure {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-numeric-spacing {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-numeric-fraction {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
@property --tw-shadow {
|
@property --tw-shadow {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -4540,3 +4799,8 @@ video {
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
|
@property --tw-content {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: "";
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,9 +31,8 @@ use zettle_db::{
|
|||||||
admin_panel::{show_admin_panel, toggle_registration_status},
|
admin_panel::{show_admin_panel, toggle_registration_status},
|
||||||
documentation::index::show_documentation_index,
|
documentation::index::show_documentation_index,
|
||||||
gdpr::{accept_gdpr, deny_gdpr},
|
gdpr::{accept_gdpr, deny_gdpr},
|
||||||
index::index_handler,
|
index::{delete_job, delete_text_content, index_handler},
|
||||||
ingress_form::{process_ingress_form, show_ingress_form},
|
ingress_form::{hide_ingress_form, process_ingress_form, show_ingress_form},
|
||||||
ingress_tasks::{delete_task, show_queue_tasks},
|
|
||||||
privacy_policy::show_privacy_policy,
|
privacy_policy::show_privacy_policy,
|
||||||
search_result::search_result_handler,
|
search_result::search_result_handler,
|
||||||
signin::{authenticate_user, show_signin_form},
|
signin::{authenticate_user, show_signin_form},
|
||||||
@@ -168,8 +167,9 @@ fn html_routes(
|
|||||||
"/ingress-form",
|
"/ingress-form",
|
||||||
get(show_ingress_form).post(process_ingress_form),
|
get(show_ingress_form).post(process_ingress_form),
|
||||||
)
|
)
|
||||||
.route("/queue", get(show_queue_tasks))
|
.route("/hide-ingress-form", get(hide_ingress_form))
|
||||||
.route("/queue/:delivery_tag", delete(delete_task))
|
.route("/text-content/:id", delete(delete_text_content))
|
||||||
|
.route("/jobs/:job_id", delete(delete_job))
|
||||||
.route("/account", get(show_account_page))
|
.route("/account", get(show_account_page))
|
||||||
.route("/admin", get(show_admin_panel))
|
.route("/admin", get(show_admin_panel))
|
||||||
.route("/toggle-registrations", patch(toggle_registration_status))
|
.route("/toggle-registrations", patch(toggle_registration_status))
|
||||||
|
|||||||
@@ -57,6 +57,31 @@ impl JobQueue {
|
|||||||
Ok(jobs)
|
Ok(jobs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets all active jobs for a specific user
|
||||||
|
pub async fn get_unfinished_user_jobs(&self, user_id: &str) -> Result<Vec<Job>, AppError> {
|
||||||
|
let jobs: Vec<Job> = self
|
||||||
|
.db
|
||||||
|
.query(
|
||||||
|
"SELECT * FROM type::table($table)
|
||||||
|
WHERE user_id = $user_id
|
||||||
|
AND (
|
||||||
|
status = 'Created'
|
||||||
|
OR (
|
||||||
|
status.InProgress != NONE
|
||||||
|
AND status.InProgress.attempts < $max_attempts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY created_at DESC",
|
||||||
|
)
|
||||||
|
.bind(("table", Job::table_name()))
|
||||||
|
.bind(("user_id", user_id.to_owned()))
|
||||||
|
.bind(("max_attempts", MAX_ATTEMPTS))
|
||||||
|
.await?
|
||||||
|
.take(0)?;
|
||||||
|
debug!("{:?}", jobs);
|
||||||
|
Ok(jobs)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn delete_job(&self, id: &str, user_id: &str) -> Result<(), AppError> {
|
pub async fn delete_job(&self, id: &str, user_id: &str) -> Result<(), AppError> {
|
||||||
get_item::<Job>(&self.db.client, id)
|
get_item::<Job>(&self.db.client, id)
|
||||||
.await?
|
.await?
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use axum::{extract::State, response::IntoResponse};
|
use axum::{
|
||||||
|
extract::{Path, State},
|
||||||
|
response::{IntoResponse, Redirect},
|
||||||
|
};
|
||||||
use axum_session::Session;
|
use axum_session::Session;
|
||||||
use axum_session_auth::AuthSession;
|
use axum_session_auth::AuthSession;
|
||||||
use axum_session_surreal::SessionSurrealPool;
|
use axum_session_surreal::SessionSurrealPool;
|
||||||
@@ -6,17 +9,23 @@ use surrealdb::{engine::any::Any, Surreal};
|
|||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::HtmlError,
|
error::{AppError, HtmlError},
|
||||||
page_data,
|
page_data,
|
||||||
server::{routes::html::render_template, AppState},
|
server::{
|
||||||
storage::types::{text_content::TextContent, user::User},
|
routes::html::{render_block, render_template},
|
||||||
|
AppState,
|
||||||
|
},
|
||||||
|
storage::{
|
||||||
|
db::delete_item,
|
||||||
|
types::{job::Job, text_content::TextContent, user::User},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
page_data!(IndexData, "index/index.html", {
|
page_data!(IndexData, "index/index.html", {
|
||||||
gdpr_accepted: bool,
|
gdpr_accepted: bool,
|
||||||
queue_length: u32,
|
|
||||||
user: Option<User>,
|
user: Option<User>,
|
||||||
latest_text_contents: Vec<TextContent>
|
latest_text_contents: Vec<TextContent>,
|
||||||
|
active_jobs: Vec<Job>
|
||||||
});
|
});
|
||||||
|
|
||||||
pub async fn index_handler(
|
pub async fn index_handler(
|
||||||
@@ -28,17 +37,16 @@ pub async fn index_handler(
|
|||||||
|
|
||||||
let gdpr_accepted = auth.current_user.is_some() | session.get("gdpr_accepted").unwrap_or(false);
|
let gdpr_accepted = auth.current_user.is_some() | session.get("gdpr_accepted").unwrap_or(false);
|
||||||
|
|
||||||
let queue_length = match auth.current_user.is_some() {
|
let active_jobs = match auth.current_user.is_some() {
|
||||||
true => state
|
true => state
|
||||||
.job_queue
|
.job_queue
|
||||||
.get_user_jobs(&auth.current_user.clone().unwrap().id)
|
.get_unfinished_user_jobs(&auth.current_user.clone().unwrap().id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?
|
.map_err(|e| HtmlError::new(e, state.templates.clone()))?,
|
||||||
.len(),
|
false => vec![],
|
||||||
false => 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let latest_text_contents = match auth.current_user.is_some() {
|
let latest_text_contents = match auth.current_user.clone().is_some() {
|
||||||
true => User::get_latest_text_contents(
|
true => User::get_latest_text_contents(
|
||||||
auth.current_user.clone().unwrap().id.as_str(),
|
auth.current_user.clone().unwrap().id.as_str(),
|
||||||
&state.surreal_db_client,
|
&state.surreal_db_client,
|
||||||
@@ -65,10 +73,90 @@ pub async fn index_handler(
|
|||||||
let output = render_template(
|
let output = render_template(
|
||||||
IndexData::template_name(),
|
IndexData::template_name(),
|
||||||
IndexData {
|
IndexData {
|
||||||
queue_length: queue_length.try_into().unwrap(),
|
|
||||||
gdpr_accepted,
|
gdpr_accepted,
|
||||||
user: auth.current_user,
|
user: auth.current_user,
|
||||||
latest_text_contents,
|
latest_text_contents,
|
||||||
|
active_jobs,
|
||||||
|
},
|
||||||
|
state.templates.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(output.into_response())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct LatestTextContentData {
|
||||||
|
latest_text_contents: Vec<TextContent>,
|
||||||
|
user: User,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_text_content(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||||
|
Path(id): Path<String>,
|
||||||
|
) -> Result<impl IntoResponse, HtmlError> {
|
||||||
|
let user = match &auth.current_user {
|
||||||
|
Some(user) => user,
|
||||||
|
None => return Ok(Redirect::to("/").into_response()),
|
||||||
|
};
|
||||||
|
|
||||||
|
delete_item::<TextContent>(&state.surreal_db_client, &id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||||
|
|
||||||
|
let latest_text_contents = User::get_latest_text_contents(&user.id, &state.surreal_db_client)
|
||||||
|
.await
|
||||||
|
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
|
|
||||||
|
info!("{:?}", latest_text_contents);
|
||||||
|
|
||||||
|
let output = render_block(
|
||||||
|
"index/signed_in/recent_content.html",
|
||||||
|
"latest_content_section",
|
||||||
|
LatestTextContentData {
|
||||||
|
user: user.clone(),
|
||||||
|
latest_text_contents,
|
||||||
|
},
|
||||||
|
state.templates.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(output.into_response())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct ActiveJobsData {
|
||||||
|
active_jobs: Vec<Job>,
|
||||||
|
user: User,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_job(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||||
|
Path(id): Path<String>,
|
||||||
|
) -> Result<impl IntoResponse, HtmlError> {
|
||||||
|
let user = match auth.current_user {
|
||||||
|
Some(user) => user,
|
||||||
|
None => return Ok(Redirect::to("/signin").into_response()),
|
||||||
|
};
|
||||||
|
|
||||||
|
state
|
||||||
|
.job_queue
|
||||||
|
.delete_job(&id, &user.id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
|
|
||||||
|
let active_jobs = state
|
||||||
|
.job_queue
|
||||||
|
.get_unfinished_user_jobs(&user.id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||||
|
|
||||||
|
let output = render_block(
|
||||||
|
"index/signed_in/active_jobs.html",
|
||||||
|
"active_jobs_section",
|
||||||
|
ActiveJobsData {
|
||||||
|
user: user.clone(),
|
||||||
|
active_jobs,
|
||||||
},
|
},
|
||||||
state.templates.clone(),
|
state.templates.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@@ -33,6 +33,19 @@ pub async fn show_ingress_form(
|
|||||||
Ok(output.into_response())
|
Ok(output.into_response())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn hide_ingress_form(
|
||||||
|
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||||
|
) -> Result<impl IntoResponse, HtmlError> {
|
||||||
|
if !auth.is_authenticated() {
|
||||||
|
return Ok(Redirect::to("/").into_response());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Html(
|
||||||
|
"<a class='btn btn-primary' hx-get='/ingress-form' hx-swap='outerHTML'>Add Content</a>",
|
||||||
|
)
|
||||||
|
.into_response())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, TryFromMultipart)]
|
#[derive(Debug, TryFromMultipart)]
|
||||||
pub struct IngressParams {
|
pub struct IngressParams {
|
||||||
pub content: Option<String>,
|
pub content: Option<String>,
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
error::HtmlError,
|
|
||||||
page_data,
|
|
||||||
server::AppState,
|
|
||||||
storage::types::{job::Job, user::User},
|
|
||||||
};
|
|
||||||
use axum::{
|
|
||||||
extract::{Path, State},
|
|
||||||
response::{Html, IntoResponse, Redirect},
|
|
||||||
};
|
|
||||||
use axum_session_auth::AuthSession;
|
|
||||||
use axum_session_surreal::SessionSurrealPool;
|
|
||||||
use surrealdb::{engine::any::Any, Surreal};
|
|
||||||
|
|
||||||
use super::render_template;
|
|
||||||
|
|
||||||
page_data!(ShowQueueTasks, "queue_tasks.html", {user : User,jobs: Vec<Job>});
|
|
||||||
|
|
||||||
pub async fn show_queue_tasks(
|
|
||||||
State(state): State<AppState>,
|
|
||||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
|
||||||
) -> Result<impl IntoResponse, HtmlError> {
|
|
||||||
let user = match auth.current_user {
|
|
||||||
Some(user) => user,
|
|
||||||
None => return Ok(Redirect::to("/signin").into_response()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let jobs = state
|
|
||||||
.job_queue
|
|
||||||
.get_user_jobs(&user.id)
|
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
|
||||||
|
|
||||||
let rendered = render_template(
|
|
||||||
ShowQueueTasks::template_name(),
|
|
||||||
ShowQueueTasks { jobs, user },
|
|
||||||
state.templates.clone(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(rendered.into_response())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete_task(
|
|
||||||
State(state): State<AppState>,
|
|
||||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
|
||||||
Path(id): Path<String>,
|
|
||||||
) -> Result<impl IntoResponse, HtmlError> {
|
|
||||||
let user = match auth.current_user {
|
|
||||||
Some(user) => user,
|
|
||||||
None => return Ok(Redirect::to("/signin").into_response()),
|
|
||||||
};
|
|
||||||
|
|
||||||
state
|
|
||||||
.job_queue
|
|
||||||
.delete_job(&id, &user.id)
|
|
||||||
.await
|
|
||||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
|
||||||
|
|
||||||
Ok(Html("").into_response())
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,6 @@ pub mod documentation;
|
|||||||
pub mod gdpr;
|
pub mod gdpr;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
pub mod ingress_form;
|
pub mod ingress_form;
|
||||||
pub mod ingress_tasks;
|
|
||||||
pub mod privacy_policy;
|
pub mod privacy_policy;
|
||||||
pub mod search_result;
|
pub mod search_result;
|
||||||
pub mod signin;
|
pub mod signin;
|
||||||
|
|||||||
46
templates/index/signed_in/active_jobs.html
Normal file
46
templates/index/signed_in/active_jobs.html
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{% block active_jobs_section %}
|
||||||
|
{% if active_jobs %}
|
||||||
|
<ul id="active_jobs_section" class="list bg-base-100 rounded-box shadow-md">
|
||||||
|
<li class="p-4 pb-2 text-xs opacity-60 tracking-wide">Active Jobs</li>
|
||||||
|
{% for item in active_jobs %}
|
||||||
|
<li class="list-row">
|
||||||
|
<div class="bg-secondary rounded-box size-10 flex justify-center items-center text-secondary-content">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||||
|
class="size-8">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{{item.created_at|datetimeformat(format="short", tz=user.timezone)}}</div>
|
||||||
|
<div
|
||||||
|
class="text-xs font-semibold opacity-60 [&:before]:content-['Status:_'] [&:before]:uppercase [&:before]:opacity-60">
|
||||||
|
{{item.status}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="list-col-wrap text-xs [&:before]:content-['Content:_'] [&:before]:uppercase [&:before]:opacity-60">
|
||||||
|
{{item.content}}
|
||||||
|
</p>
|
||||||
|
<!-- <button class="btn disabled btn-square btn-ghost"> -->
|
||||||
|
<!-- <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> -->
|
||||||
|
<!-- <g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"> -->
|
||||||
|
<!-- <path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75z"></path> -->
|
||||||
|
<!-- <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75z"></path> -->
|
||||||
|
<!-- </g> -->
|
||||||
|
<!-- </svg> -->
|
||||||
|
<!-- </button> -->
|
||||||
|
<button hx-delete="/jobs/{{item.id}}" hx-target="#active_jobs_section" hx-swap="outerHTML"
|
||||||
|
class="btn btn-square btn-ghost">
|
||||||
|
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
|
<g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor">
|
||||||
|
<path d="M3 6h18"></path>
|
||||||
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
@@ -2,8 +2,13 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
{% include 'index/signed_in/searchbar.html' %}
|
{% include 'index/signed_in/searchbar.html' %}
|
||||||
|
|
||||||
{% include "index/signed_in/recent_content.html" %}
|
|
||||||
|
|
||||||
{% include "index/signed_in/quick_actions.html" %}
|
{% include "index/signed_in/quick_actions.html" %}
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2">
|
||||||
|
{% include "index/signed_in/active_jobs.html" %}
|
||||||
|
|
||||||
|
{% include "index/signed_in/recent_content.html" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="card bg-base-100 shadow-xl mt-4">
|
<div class="card bg-base-100 shadow-xl mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<a class="btn btn-primary" hx-get="/ingress-form" hx-swap="outerHTML">Add Content</a>
|
<button class="btn btn-primary" hx-get="/ingress-form" hx-swap="outerHTML">Add Content</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,24 +1,45 @@
|
|||||||
<div class="card bg-base-100 shadow-xl mt-4">
|
{% block latest_content_section %}
|
||||||
<!-- <div class="mt-4"> -->
|
<ul id="latest_content_section" class="list bg-base-100 rounded-box shadow-md">
|
||||||
<p>{{latest_text_contents}}</p>
|
<li class="p-4 pb-2 text-xs opacity-60 tracking-wide">Recently added content</li>
|
||||||
<div class="card-body">
|
{% for item in latest_text_contents %}
|
||||||
<h2 class="card-title">Recently Added Content</h2>
|
<li class="list-row">
|
||||||
<ul class="list bg-base-100 rounded-box shadow-md">
|
<div class="bg-accent rounded-box size-10 flex justify-center items-center text-accent-content">
|
||||||
{% for item in latest_text_contents %}
|
|
||||||
<li class="list-row">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||||
<div class="text-2xl text-ellipsis text-nowrap overflow-hidden">
|
class="size-8">
|
||||||
{{item.created_at|datetimeformat(format="short", tz="Europe/Stockholm")}}</div>
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
<div>
|
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
|
||||||
<div>{{item.category}}</div>
|
</svg>
|
||||||
<div class="text-xs uppercase font-semibold opacity-60">{{item.text}}</div>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
<button class="btn btn-outline">
|
<div>
|
||||||
Edit
|
{{item.created_at|datetimeformat(format="short", tz=user.timezone)}}</div>
|
||||||
</button>
|
<div
|
||||||
<button class="btn btn-error">
|
class="text-xs font-semibold opacity-60 [&:before]:content-['Instructions:_'] [&:before]:uppercase [&:before]:opacity-60">
|
||||||
Delete </button>
|
{{item.instructions}}
|
||||||
</li>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
</ul>
|
<p class="list-col-wrap text-xs [&:before]:content-['Content:_'] [&:before]:uppercase [&:before]:opacity-60">
|
||||||
</div>
|
{{item.text}}
|
||||||
</div>
|
</p>
|
||||||
|
<!-- <button class="btn disabled btn-square btn-ghost"> -->
|
||||||
|
<!-- <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> -->
|
||||||
|
<!-- <g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"> -->
|
||||||
|
<!-- <path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75z"></path> -->
|
||||||
|
<!-- <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75z"></path> -->
|
||||||
|
<!-- </g> -->
|
||||||
|
<!-- </svg> -->
|
||||||
|
<!-- </button> -->
|
||||||
|
<button hx-delete="/text-content/{{item.id}}" hx-target="#latest_content_section" hx-swap="outerHTML"
|
||||||
|
class="btn btn-square btn-ghost">
|
||||||
|
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
|
<g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor">
|
||||||
|
<path d="M3 6h18"></path>
|
||||||
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<form class="space-y-4 mt-2 w-full" hx-post="/ingress-form" enctype="multipart/form-data">
|
<form id="ingress-form" class="space-y-4 mt-2 w-full" hx-post="/ingress-form" enctype="multipart/form-data">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label class="floating-label">
|
<label class="floating-label">
|
||||||
<span>Instructions</span>
|
<span>Instructions</span>
|
||||||
@@ -34,7 +34,9 @@
|
|||||||
|
|
||||||
<div id="error-message" class="text-error text-center {% if not error %}hidden{% endif %}">{{ error }}</div>
|
<div id="error-message" class="text-error text-center {% if not error %}hidden{% endif %}">{{ error }}</div>
|
||||||
|
|
||||||
<div class="form-control mt-6">
|
<div class="form-control mt-6 flex flex-col sm:flex-row gap-1">
|
||||||
<button type="submit" class="btn btn-primary w-full">Submit</button>
|
<button hx-get="/hide-ingress-form" hx-target="#ingress-form" hx-swap=outerHTML"
|
||||||
|
class="btn btn-outline w-full sm:w-fit">Cancel</button>
|
||||||
|
<button type="submit" class="btn btn-primary w-full sm:w-fit">Submit</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
{% extends "body_base.html" %}
|
|
||||||
{% block main %}
|
|
||||||
<div class="container mx-auto p-4">
|
|
||||||
<h1 class="text-2xl font-bold mb-4">Active Tasks</h1>
|
|
||||||
{% if not jobs %}
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<span>No active tasks</span>
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="grid gap-4">
|
|
||||||
{% for job in jobs %}
|
|
||||||
{% if job.status == "Created" or job.status is mapping and job.status.InProgress %}
|
|
||||||
<div class="card bg-base-200 shadow-xl" id="job-card-{{ job.id }}">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="card-title">
|
|
||||||
{% if job.content.Url %}
|
|
||||||
<h2>URL Task</h2>
|
|
||||||
<p class="text-sm text-gray-500 break-all">{{ job.content.Url.url }}</p>
|
|
||||||
{% elif job.content.File %}
|
|
||||||
<h2>File Task</h2>
|
|
||||||
<p class="text-sm text-gray-500">{{ job.content.File.file_info.path }}</p>
|
|
||||||
{% elif job.content.Text %}
|
|
||||||
<h2>Text Task</h2>
|
|
||||||
<p class="text-sm text-gray-500">{{ job.content.Text.text }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="space-y-2">
|
|
||||||
<p><span class="font-medium">Status:</span>
|
|
||||||
{% if job.status == "Created" %}
|
|
||||||
Created
|
|
||||||
{% elif job.status.InProgress %}
|
|
||||||
In Progress
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
{% if job.status.InProgress %}
|
|
||||||
<p><span class="font-medium">Attempts:</span> {{ job.status.InProgress.attempts }}</p>
|
|
||||||
<p><span class="font-medium">Last Attempt:</span>
|
|
||||||
{{ job.status.InProgress.last_attempt }}</p>
|
|
||||||
{% endif %}
|
|
||||||
<p><span class="font-medium">Category:</span>
|
|
||||||
{% if job.content.Url %}
|
|
||||||
{{ job.content.Url.category }}
|
|
||||||
{% elif job.content.File %}
|
|
||||||
{{ job.content.File.category }}
|
|
||||||
{% elif job.content.Text %}
|
|
||||||
{{ job.content.Text.category }}
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-actions justify-end mt-4">
|
|
||||||
<form hx-delete="/queue/{{ job.id }}" hx-target="#job-card-{{ job.id }}" hx-swap="outerHTML">
|
|
||||||
<button class="btn btn-error">Cancel Task</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
Reference in New Issue
Block a user