From 5e8b78f1d8b8ae3d51ceacf56a4048333d0feb26 Mon Sep 17 00:00:00 2001 From: arturka Date: Sun, 8 Dec 2024 13:41:30 +0100 Subject: [PATCH 01/36] feat: update version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9bdc9de..9230a28 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nuxt-app", "private": true, "type": "module", - "version": "1.1.0", + "version": "1.1.1", "scripts": { "build": "nuxt build", "dev": "nuxt dev", From 4e00b37928a4b4652a7ec92495ad3e4f03e0586c Mon Sep 17 00:00:00 2001 From: arturka Date: Sun, 8 Dec 2024 13:44:38 +0100 Subject: [PATCH 02/36] feat: update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a2adfa..41762d1 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ class TaskiqAdminMiddleware(TaskiqMiddleware): return super().post_execute(message, result) ``` -2) Pull the image from DockerHub: `docker pull artur10/taskiq-admin:1.1.0` +2) Pull the image from DockerHub: `docker pull artur10/taskiq-admin:1.1.1` 3) Replace `ACCESS_TOKEN` with any secret enough string and run: ```bash @@ -85,7 +85,7 @@ docker run -d --rm \ -v ./taskiq-admin-data/:/usr/database/ \ -e TASKIQ_ADMIN_API_TOKEN=supersecret \ --name taskiq-admin \ - artur10/taskiq-admin:1.1.0 + artur10/taskiq-admin:1.1.1 ``` 4) Go to `http://localhost:3000/tasks` From 08fa5bc5ad28e77fe3e56ad746011680d6ddf5a0 Mon Sep 17 00:00:00 2001 From: arturka Date: Sun, 8 Dec 2024 14:11:04 +0100 Subject: [PATCH 03/36] fix: search --- README.md | 4 +-- package.json | 2 +- src/pages/tasks/index.vue | 42 ++++++++++++++++++++------------ src/server/repositories/tasks.ts | 4 +-- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 41762d1..f005f75 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ class TaskiqAdminMiddleware(TaskiqMiddleware): return super().post_execute(message, result) ``` -2) Pull the image from DockerHub: `docker pull artur10/taskiq-admin:1.1.1` +2) Pull the image from DockerHub: `docker pull artur10/taskiq-admin:1.1.2` 3) Replace `ACCESS_TOKEN` with any secret enough string and run: ```bash @@ -85,7 +85,7 @@ docker run -d --rm \ -v ./taskiq-admin-data/:/usr/database/ \ -e TASKIQ_ADMIN_API_TOKEN=supersecret \ --name taskiq-admin \ - artur10/taskiq-admin:1.1.1 + artur10/taskiq-admin:1.1.2 ``` 4) Go to `http://localhost:3000/tasks` diff --git a/package.json b/package.json index 9230a28..b55d9c1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nuxt-app", "private": true, "type": "module", - "version": "1.1.1", + "version": "1.1.2", "scripts": { "build": "nuxt build", "dev": "nuxt dev", diff --git a/src/pages/tasks/index.vue b/src/pages/tasks/index.vue index fda6258..eeac489 100644 --- a/src/pages/tasks/index.vue +++ b/src/pages/tasks/index.vue @@ -11,8 +11,8 @@ if (!route.query.page) { const perPage = 10 const searchRef = ref("") +const search = computed(() => route.query.search || "") const page = computed(() => Number(route.query.page) || 1) -const search = computed(() => Number(route.query.search) || "") const { data } = useAsyncData( "tasks", @@ -38,6 +38,18 @@ function limitText(text: string, length: number) { return text } +function searchSubmit() { + if (searchRef.value) { + router.push({ + path: "/tasks", + query: { + page: 1, + search: searchRef.value, + }, + }) + } +} + function handleNext() { if (page.value < totalPages.value) { router.push({ @@ -71,22 +83,22 @@ function handlePrev() { Backup -
-
-
-
- - -
+
+
+
+ +
- +
diff --git a/src/server/repositories/tasks.ts b/src/server/repositories/tasks.ts index ebf7b80..f2f2ec8 100644 --- a/src/server/repositories/tasks.ts +++ b/src/server/repositories/tasks.ts @@ -1,14 +1,14 @@ import { db } from "../db" import { tasksTable } from "../db/schema" -import { count, eq, desc, ilike } from "drizzle-orm" import { takeUniqueOrThrow } from "../utils" +import { count, eq, desc, like } from "drizzle-orm" export type TaskState = "pending" | "success" | "failed" class TasksRepository { async getAll(name: string | null, limit: number, offset: number) { const whereCondition = name - ? ilike(tasksTable.name, `%${name}%`) + ? like(tasksTable.name, `%${name.toLowerCase()}%`) : undefined const countResult = await db From 5d2c4c6be1f96eeec165e47707895a269ab8dd45 Mon Sep 17 00:00:00 2001 From: arturka Date: Wed, 11 Dec 2024 11:32:37 +0100 Subject: [PATCH 04/36] feat: 1.1.3 version --- package.json | 3 +- pnpm-lock.yaml | 34 ++++++++++++++ src/pages/tasks/index.vue | 77 ++++++++++++++++++++++++------- src/server/api/tasks/index.get.ts | 11 +++-- src/server/db/schema.ts | 6 +-- src/server/repositories/tasks.ts | 22 +++++++-- src/server/schemas/tasks.ts | 1 + 7 files changed, 125 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index b55d9c1..5f8a803 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nuxt-app", "private": true, "type": "module", - "version": "1.1.2", + "version": "1.1.3", "scripts": { "build": "nuxt build", "dev": "nuxt dev", @@ -12,6 +12,7 @@ "db:push": "drizzle-kit push" }, "dependencies": { + "@vueuse/core": "^12.0.0", "better-sqlite3": "^11.6.0", "bootstrap": "^5.3.3", "dayjs": "^1.11.13", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39cb078..a77b5b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@vueuse/core': + specifier: ^12.0.0 + version: 12.0.0(typescript@5.7.2) better-sqlite3: specifier: ^11.6.0 version: 11.6.0 @@ -1173,6 +1176,9 @@ packages: '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + '@unhead/dom@1.11.13': resolution: {integrity: sha512-8Bpo3e50i49/z0TMiskQk3OqUVJpWOO0cnEEydJeFnjsPczDH76H3mWLvB11cv1B/rjLdBiPgui7yetFta5LCw==} @@ -1277,6 +1283,15 @@ packages: '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@vueuse/core@12.0.0': + resolution: {integrity: sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==} + + '@vueuse/metadata@12.0.0': + resolution: {integrity: sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==} + + '@vueuse/shared@12.0.0': + resolution: {integrity: sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==} + abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -4951,6 +4966,8 @@ snapshots: '@types/resolve@1.20.2': {} + '@types/web-bluetooth@0.0.20': {} + '@unhead/dom@1.11.13': dependencies: '@unhead/schema': 1.11.13 @@ -5138,6 +5155,23 @@ snapshots: '@vue/shared@3.5.13': {} + '@vueuse/core@12.0.0(typescript@5.7.2)': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 12.0.0 + '@vueuse/shared': 12.0.0(typescript@5.7.2) + vue: 3.5.13(typescript@5.7.2) + transitivePeerDependencies: + - typescript + + '@vueuse/metadata@12.0.0': {} + + '@vueuse/shared@12.0.0(typescript@5.7.2)': + dependencies: + vue: 3.5.13(typescript@5.7.2) + transitivePeerDependencies: + - typescript + abbrev@1.1.1: {} abort-controller@3.0.0: diff --git a/src/pages/tasks/index.vue b/src/pages/tasks/index.vue index eeac489..5b24260 100644 --- a/src/pages/tasks/index.vue +++ b/src/pages/tasks/index.vue @@ -1,5 +1,7 @@ - diff --git a/src/assets/css/main.css b/src/assets/css/main.css new file mode 100644 index 0000000..e7fdcf4 --- /dev/null +++ b/src/assets/css/main.css @@ -0,0 +1,133 @@ +@import 'tailwindcss'; + +@custom-variant dark (&:is(.dark *)); + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.439 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + ::-webkit-scrollbar { + @apply w-2.5 h-2.5; + } + + ::-webkit-scrollbar-track { + @apply bg-transparent; + } + + ::-webkit-scrollbar-thumb { + @apply rounded-full bg-border border-[1px] border-transparent border-solid bg-clip-padding; + } +} diff --git a/src/components/header.vue b/src/components/header.vue index 0afec2e..eb0ba38 100644 --- a/src/components/header.vue +++ b/src/components/header.vue @@ -1,10 +1,15 @@ - + diff --git a/src/components/task-state.vue b/src/components/task-state.vue new file mode 100644 index 0000000..769f016 --- /dev/null +++ b/src/components/task-state.vue @@ -0,0 +1,19 @@ + + diff --git a/src/components/tasks-table.vue b/src/components/tasks-table.vue new file mode 100644 index 0000000..332ae2b --- /dev/null +++ b/src/components/tasks-table.vue @@ -0,0 +1,185 @@ + + + diff --git a/src/components/theme.vue b/src/components/theme.vue new file mode 100644 index 0000000..4375f22 --- /dev/null +++ b/src/components/theme.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/components/ui/button/Button.vue b/src/components/ui/button/Button.vue new file mode 100644 index 0000000..c6691f6 --- /dev/null +++ b/src/components/ui/button/Button.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/ui/button/index.ts b/src/components/ui/button/index.ts new file mode 100644 index 0000000..616d1d3 --- /dev/null +++ b/src/components/ui/button/index.ts @@ -0,0 +1,36 @@ +import { cva, type VariantProps } from 'class-variance-authority' + +export { default as Button } from './Button.vue' + +export const buttonVariants = cva( + 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*=\'size-\'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive', + { + variants: { + variant: { + default: + 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90', + destructive: + 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: + 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50', + secondary: + 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80', + ghost: + 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-9 px-4 py-2 has-[>svg]:px-3', + sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5', + lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', + icon: 'size-9', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +export type ButtonVariants = VariantProps diff --git a/src/components/ui/card/Card.vue b/src/components/ui/card/Card.vue new file mode 100644 index 0000000..9154a6a --- /dev/null +++ b/src/components/ui/card/Card.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/card/CardAction.vue b/src/components/ui/card/CardAction.vue new file mode 100644 index 0000000..c2beb20 --- /dev/null +++ b/src/components/ui/card/CardAction.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardContent.vue b/src/components/ui/card/CardContent.vue new file mode 100644 index 0000000..6bff4bc --- /dev/null +++ b/src/components/ui/card/CardContent.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardDescription.vue b/src/components/ui/card/CardDescription.vue new file mode 100644 index 0000000..2a0a755 --- /dev/null +++ b/src/components/ui/card/CardDescription.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardFooter.vue b/src/components/ui/card/CardFooter.vue new file mode 100644 index 0000000..1f3648d --- /dev/null +++ b/src/components/ui/card/CardFooter.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardHeader.vue b/src/components/ui/card/CardHeader.vue new file mode 100644 index 0000000..f693a6c --- /dev/null +++ b/src/components/ui/card/CardHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardTitle.vue b/src/components/ui/card/CardTitle.vue new file mode 100644 index 0000000..caa7e06 --- /dev/null +++ b/src/components/ui/card/CardTitle.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/index.ts b/src/components/ui/card/index.ts new file mode 100644 index 0000000..73d985f --- /dev/null +++ b/src/components/ui/card/index.ts @@ -0,0 +1,7 @@ +export { default as Card } from './Card.vue' +export { default as CardAction } from './CardAction.vue' +export { default as CardContent } from './CardContent.vue' +export { default as CardDescription } from './CardDescription.vue' +export { default as CardFooter } from './CardFooter.vue' +export { default as CardHeader } from './CardHeader.vue' +export { default as CardTitle } from './CardTitle.vue' diff --git a/src/components/ui/dropdown-menu/DropdownMenu.vue b/src/components/ui/dropdown-menu/DropdownMenu.vue new file mode 100644 index 0000000..e386052 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenu.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue b/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue new file mode 100644 index 0000000..09b6da3 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue @@ -0,0 +1,41 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuContent.vue b/src/components/ui/dropdown-menu/DropdownMenuContent.vue new file mode 100644 index 0000000..a4d4c15 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuContent.vue @@ -0,0 +1,39 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuGroup.vue b/src/components/ui/dropdown-menu/DropdownMenuGroup.vue new file mode 100644 index 0000000..c7eb308 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuGroup.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuItem.vue b/src/components/ui/dropdown-menu/DropdownMenuItem.vue new file mode 100644 index 0000000..76299c6 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuItem.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuLabel.vue b/src/components/ui/dropdown-menu/DropdownMenuLabel.vue new file mode 100644 index 0000000..50987ab --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuLabel.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue b/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue new file mode 100644 index 0000000..d205d0b --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue b/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue new file mode 100644 index 0000000..d2a0e86 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue b/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue new file mode 100644 index 0000000..a65c50c --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue b/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue new file mode 100644 index 0000000..1bcbb88 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSub.vue b/src/components/ui/dropdown-menu/DropdownMenuSub.vue new file mode 100644 index 0000000..7329bca --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSub.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue b/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue new file mode 100644 index 0000000..d199c91 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue b/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue new file mode 100644 index 0000000..df93e3d --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue b/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue new file mode 100644 index 0000000..7bc7339 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/components/ui/dropdown-menu/index.ts b/src/components/ui/dropdown-menu/index.ts new file mode 100644 index 0000000..f488d39 --- /dev/null +++ b/src/components/ui/dropdown-menu/index.ts @@ -0,0 +1,16 @@ +export { default as DropdownMenu } from './DropdownMenu.vue' + +export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue' +export { default as DropdownMenuContent } from './DropdownMenuContent.vue' +export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue' +export { default as DropdownMenuItem } from './DropdownMenuItem.vue' +export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue' +export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue' +export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue' +export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue' +export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue' +export { default as DropdownMenuSub } from './DropdownMenuSub.vue' +export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue' +export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue' +export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue' +export { DropdownMenuPortal } from 'reka-ui' diff --git a/src/components/ui/input/Input.vue b/src/components/ui/input/Input.vue new file mode 100644 index 0000000..899535e --- /dev/null +++ b/src/components/ui/input/Input.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/ui/input/index.ts b/src/components/ui/input/index.ts new file mode 100644 index 0000000..a691dd6 --- /dev/null +++ b/src/components/ui/input/index.ts @@ -0,0 +1 @@ +export { default as Input } from './Input.vue' diff --git a/src/components/ui/select/Select.vue b/src/components/ui/select/Select.vue new file mode 100644 index 0000000..dc1f83d --- /dev/null +++ b/src/components/ui/select/Select.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/components/ui/select/SelectContent.vue b/src/components/ui/select/SelectContent.vue new file mode 100644 index 0000000..bde01cf --- /dev/null +++ b/src/components/ui/select/SelectContent.vue @@ -0,0 +1,55 @@ + + + diff --git a/src/components/ui/select/SelectGroup.vue b/src/components/ui/select/SelectGroup.vue new file mode 100644 index 0000000..4f36d92 --- /dev/null +++ b/src/components/ui/select/SelectGroup.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/select/SelectItem.vue b/src/components/ui/select/SelectItem.vue new file mode 100644 index 0000000..cddae64 --- /dev/null +++ b/src/components/ui/select/SelectItem.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/components/ui/select/SelectItemText.vue b/src/components/ui/select/SelectItemText.vue new file mode 100644 index 0000000..cff32ac --- /dev/null +++ b/src/components/ui/select/SelectItemText.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/select/SelectLabel.vue b/src/components/ui/select/SelectLabel.vue new file mode 100644 index 0000000..7da0ce2 --- /dev/null +++ b/src/components/ui/select/SelectLabel.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/components/ui/select/SelectScrollDownButton.vue b/src/components/ui/select/SelectScrollDownButton.vue new file mode 100644 index 0000000..37162fd --- /dev/null +++ b/src/components/ui/select/SelectScrollDownButton.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/components/ui/select/SelectScrollUpButton.vue b/src/components/ui/select/SelectScrollUpButton.vue new file mode 100644 index 0000000..d80dacc --- /dev/null +++ b/src/components/ui/select/SelectScrollUpButton.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/components/ui/select/SelectSeparator.vue b/src/components/ui/select/SelectSeparator.vue new file mode 100644 index 0000000..ab51b07 --- /dev/null +++ b/src/components/ui/select/SelectSeparator.vue @@ -0,0 +1,21 @@ + + + diff --git a/src/components/ui/select/SelectTrigger.vue b/src/components/ui/select/SelectTrigger.vue new file mode 100644 index 0000000..97c69a2 --- /dev/null +++ b/src/components/ui/select/SelectTrigger.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/ui/select/SelectValue.vue b/src/components/ui/select/SelectValue.vue new file mode 100644 index 0000000..f198b96 --- /dev/null +++ b/src/components/ui/select/SelectValue.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/select/index.ts b/src/components/ui/select/index.ts new file mode 100644 index 0000000..31b9294 --- /dev/null +++ b/src/components/ui/select/index.ts @@ -0,0 +1,11 @@ +export { default as Select } from './Select.vue' +export { default as SelectContent } from './SelectContent.vue' +export { default as SelectGroup } from './SelectGroup.vue' +export { default as SelectItem } from './SelectItem.vue' +export { default as SelectItemText } from './SelectItemText.vue' +export { default as SelectLabel } from './SelectLabel.vue' +export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue' +export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue' +export { default as SelectSeparator } from './SelectSeparator.vue' +export { default as SelectTrigger } from './SelectTrigger.vue' +export { default as SelectValue } from './SelectValue.vue' diff --git a/src/components/ui/table/Table.vue b/src/components/ui/table/Table.vue new file mode 100644 index 0000000..669b0d4 --- /dev/null +++ b/src/components/ui/table/Table.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/components/ui/table/TableBody.vue b/src/components/ui/table/TableBody.vue new file mode 100644 index 0000000..af688cb --- /dev/null +++ b/src/components/ui/table/TableBody.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/table/TableCaption.vue b/src/components/ui/table/TableCaption.vue new file mode 100644 index 0000000..e6ab397 --- /dev/null +++ b/src/components/ui/table/TableCaption.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/table/TableCell.vue b/src/components/ui/table/TableCell.vue new file mode 100644 index 0000000..841557d --- /dev/null +++ b/src/components/ui/table/TableCell.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/table/TableEmpty.vue b/src/components/ui/table/TableEmpty.vue new file mode 100644 index 0000000..3f6e0ff --- /dev/null +++ b/src/components/ui/table/TableEmpty.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/components/ui/table/TableFooter.vue b/src/components/ui/table/TableFooter.vue new file mode 100644 index 0000000..8055c55 --- /dev/null +++ b/src/components/ui/table/TableFooter.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/table/TableHead.vue b/src/components/ui/table/TableHead.vue new file mode 100644 index 0000000..a2ca70e --- /dev/null +++ b/src/components/ui/table/TableHead.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/table/TableHeader.vue b/src/components/ui/table/TableHeader.vue new file mode 100644 index 0000000..0b0f481 --- /dev/null +++ b/src/components/ui/table/TableHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/table/TableRow.vue b/src/components/ui/table/TableRow.vue new file mode 100644 index 0000000..5befaef --- /dev/null +++ b/src/components/ui/table/TableRow.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/table/index.ts b/src/components/ui/table/index.ts new file mode 100644 index 0000000..2b4ce39 --- /dev/null +++ b/src/components/ui/table/index.ts @@ -0,0 +1,9 @@ +export { default as Table } from './Table.vue' +export { default as TableBody } from './TableBody.vue' +export { default as TableCaption } from './TableCaption.vue' +export { default as TableCell } from './TableCell.vue' +export { default as TableEmpty } from './TableEmpty.vue' +export { default as TableFooter } from './TableFooter.vue' +export { default as TableHead } from './TableHead.vue' +export { default as TableHeader } from './TableHeader.vue' +export { default as TableRow } from './TableRow.vue' diff --git a/src/components/ui/table/utils.ts b/src/components/ui/table/utils.ts new file mode 100644 index 0000000..d812d4b --- /dev/null +++ b/src/components/ui/table/utils.ts @@ -0,0 +1,9 @@ +import type { Updater } from '@tanstack/vue-table' +import type { Ref } from 'vue' + +export function valueUpdater>(updaterOrValue: T, ref: Ref) { + ref.value + = typeof updaterOrValue === 'function' + ? updaterOrValue(ref.value) + : updaterOrValue +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..a6f9644 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,40 @@ +import dayjs from "dayjs" +import utc from "dayjs/plugin/utc" +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" +import type { TaskSelect } from "~/server/db/schema" + +dayjs.extend(utc) + +export function formatDate(date: string) { + return dayjs.utc(date).local().format("MMM D, YYYY hh:mm A") +} + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} + +export function limitText(text: string, length: number) { + if (text.length > length) { + return text.slice(0, length).trim() + "..." + } + return text +} + +export function formatReturnValue(task: TaskSelect) { + if (task.returnValue?.return_value) { + return task.returnValue.return_value + } else { + return "null" + } +} + +// temporarily, while dishka hasn't fixed it's module naming bug +export function formatTaskName(taskName: string) { + if (taskName.includes(":")) { + const parts = taskName.split(":") + return parts[parts.length - 1] + } else { + return taskName + } +} diff --git a/src/pages/index.vue b/src/pages/index.vue index 1427be7..4cb1885 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -1,5 +1,7 @@ diff --git a/src/pages/tasks/[id].vue b/src/pages/tasks/[id].vue index 1a16636..423aa14 100644 --- a/src/pages/tasks/[id].vue +++ b/src/pages/tasks/[id].vue @@ -1,83 +1,111 @@ diff --git a/src/pages/tasks/index.vue b/src/pages/tasks/index.vue index 5c5440f..61113d1 100644 --- a/src/pages/tasks/index.vue +++ b/src/pages/tasks/index.vue @@ -1,118 +1,127 @@ @@ -121,113 +130,89 @@ const handlePrev = () => {
- +
-
-
- +
+ +
+
+

Per Page:

+ +
+
+ - +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameIDStateArgsKwargsResultStartedFinishedRuntime (s)Worker
{{ formatTaskName(task.name) }} - - {{ task.id }} - - - - {{ task.state }} - - {{ task.args }}{{ limitText(JSON.stringify(task.kwargs), 40) }}{{ limitText(formatReturnValue(task), 21) }}{{ formatDate(String(task.startedAt)) }} - {{ task.finishedAt ? formatDate(String(task.finishedAt)) : null }} - {{ task.executionTime }}{{ task.worker }}
-
+ -
-
- diff --git a/src/server/api/tasks/[id]/executed.post.ts b/src/server/api/tasks/[id]/executed.post.ts index 4f238c7..4b67b6c 100644 --- a/src/server/api/tasks/[id]/executed.post.ts +++ b/src/server/api/tasks/[id]/executed.post.ts @@ -1,17 +1,17 @@ import { taskExecutedRequestSchema, - taskRouteParamsSchema, -} from "../../../schemas/tasks" -import { tasksRepository } from "../../../repositories/tasks" -import { envVariables } from "~/server/env" + taskRouteParamsSchema +} from '../../../schemas/tasks' +import { tasksRepository } from '../../../repositories/tasks' +import { envVariables } from '~/server/env' export default defineEventHandler(async (event) => { - const accessToken = getRequestHeader(event, "access-token") + const accessToken = getRequestHeader(event, 'access-token') if (!accessToken || accessToken !== envVariables.taskiqAdminApiToken) { throw createError({ status: 401, - statusMessage: "Unauthorized", - message: "Invalid access token", + statusMessage: 'Unauthorized', + message: 'Invalid access token' }) } const params = await getValidatedRouterParams( @@ -20,14 +20,14 @@ export default defineEventHandler(async (event) => { ) const body = await readValidatedBody(event, taskExecutedRequestSchema.parse) - const state = body.error ? "failure" : "success" + const state = body.error ? 'failure' : 'success' await tasksRepository.update(params.id, { state: state, error: body.error, finishedAt: body.finishedAt, returnValue: body.returnValue, - executionTime: body.executionTime, + executionTime: body.executionTime }) return { success: true } diff --git a/src/server/api/tasks/backup.get.ts b/src/server/api/tasks/backup.get.ts index 9006c12..e4b7ccf 100644 --- a/src/server/api/tasks/backup.get.ts +++ b/src/server/api/tasks/backup.get.ts @@ -1,13 +1,15 @@ -import fs from "fs" -import { db } from "~/server/db" -import { envVariables } from "~/server/env" +import fs from 'fs' +import { db } from '~/server/db' +import { envVariables } from '~/server/env' export default defineEventHandler(async (event) => { + // TODO(future): add check if mode is WAL from dotenv + // await db.$client.pragma('wal_checkpoint') await db.$client.backup(envVariables.backupFilePath) const stream = fs.createReadStream(envVariables.backupFilePath) - setHeader(event, "Content-Type", "application/octet-stream") - setHeader(event, "Content-Disposition", 'attachment; filename="backup.db"') + setHeader(event, 'Content-Type', 'application/octet-stream') + setHeader(event, 'Content-Disposition', 'attachment; filename="backup.db"') return sendStream(event, stream) }) diff --git a/src/server/api/tasks/index.get.ts b/src/server/api/tasks/index.get.ts index 4cc1402..ea668b2 100644 --- a/src/server/api/tasks/index.get.ts +++ b/src/server/api/tasks/index.get.ts @@ -1,6 +1,6 @@ -import { defineEventHandler, getValidatedQuery } from "h3" -import { tasksRepository } from "../../repositories/tasks" -import { getTasksQueryParamsSchema } from "../../schemas/tasks" +import { defineEventHandler, getValidatedQuery } from 'h3' +import { tasksRepository } from '../../repositories/tasks' +import { getTasksQueryParamsSchema } from '../../schemas/tasks' export default defineEventHandler(async (event) => { const query = await getValidatedQuery(event, getTasksQueryParamsSchema.parse) @@ -10,6 +10,8 @@ export default defineEventHandler(async (event) => { limit: query.limit, offset: query.offset, state: query.state, + sortByRuntime: query.sortByRuntime, + sortByStartedAt: query.sortByStartedAt }) return { tasks, count } diff --git a/src/server/db/index.ts b/src/server/db/index.ts index 7c20157..eb2bd87 100644 --- a/src/server/db/index.ts +++ b/src/server/db/index.ts @@ -1,7 +1,7 @@ -import { drizzle } from "drizzle-orm/better-sqlite3" +import { drizzle } from 'drizzle-orm/better-sqlite3' export const db = drizzle({ connection: { - source: process.env.DB_FILE_PATH!, - }, + source: process.env.DB_FILE_PATH! + } }) diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index b074cc2..d02d091 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -1,31 +1,32 @@ -import { InferSelectModel } from "drizzle-orm" -import { int, text, real, sqliteTable, index } from "drizzle-orm/sqlite-core" +import { InferSelectModel, sql } from 'drizzle-orm' +import { int, text, real, sqliteTable, index } from 'drizzle-orm/sqlite-core' export const tasksTable = sqliteTable( - "tasks", + 'tasks', { id: text().primaryKey(), name: text().notNull(), state: text({ - enum: ["success", "running", "failure", "abandoned"], + enum: ['success', 'running', 'failure', 'abandoned'] }).notNull(), error: text(), worker: text(), - executionTime: real("execution_time"), - startedAt: int("started_at", { mode: "timestamp" }).notNull(), - finishedAt: int("finished_at", { mode: "timestamp" }), - args: text({ mode: "json" }).$type>(), - kwargs: text({ mode: "json" }).$type>(), - returnValue: text("return_value", { mode: "json" }).$type<{ + executionTime: real('execution_time'), + startedAt: int('started_at', { mode: 'timestamp' }).notNull(), + finishedAt: int('finished_at', { mode: 'timestamp' }), + args: text({ mode: 'json' }).$type>(), + kwargs: text({ mode: 'json' }).$type>(), + returnValue: text('return_value', { mode: 'json' }).$type<{ return_value: any - }>(), + }>() }, - (t) => ({ - idxState: index("idx_tasks__state").on(t.state), - idxStartedAt: index("idx_tasks__started_at").on(t.startedAt), - idxFinishedAt: index("idx_tasks__finished_at").on(t.finishedAt), - idxExecutionTime: index("idx_tasks__execution_time").on(t.executionTime), - }) + (t) => [ + index('idx_tasks__state').on(t.state), + index('idx_tasks__started_at').on(t.startedAt), + index('idx_tasks__name').on(sql`name COLLATE NOCASE`), + index('idx_tasks__finished_at').on(t.finishedAt), + index('idx_tasks__execution_time').on(t.executionTime) + ] ) export type TaskSelect = InferSelectModel diff --git a/src/server/env.ts b/src/server/env.ts index b89f2dc..ecbaaa9 100644 --- a/src/server/env.ts +++ b/src/server/env.ts @@ -1,5 +1,5 @@ export const envVariables = { dbFilePath: process.env.DB_FILE_PATH!, backupFilePath: process.env.BACKUP_FILE_PATH!, - taskiqAdminApiToken: process.env.TASKIQ_ADMIN_API_TOKEN!, + taskiqAdminApiToken: process.env.TASKIQ_ADMIN_API_TOKEN! } diff --git a/src/server/exceptions.ts b/src/server/exceptions.ts index e95af23..5004fdc 100644 --- a/src/server/exceptions.ts +++ b/src/server/exceptions.ts @@ -1,8 +1,8 @@ export class NotFoundError extends Error { - status: number + status: number; constructor(message: string, status = 404) { - super(message) - this.name = "ValidationError" - this.status = status + super(message); + this.name = "ValidationError"; + this.status = status; } } diff --git a/src/server/repositories/tasks.ts b/src/server/repositories/tasks.ts index f61111f..d4600c0 100644 --- a/src/server/repositories/tasks.ts +++ b/src/server/repositories/tasks.ts @@ -1,9 +1,9 @@ -import { db } from "../db" -import { tasksTable } from "../db/schema" -import { takeUniqueOrThrow } from "../utils" -import { count, eq, desc, like, and } from "drizzle-orm" +import { db } from '../db' +import { tasksTable } from '../db/schema' +import { takeUniqueOrThrow } from '../utils' +import { count, eq, desc, like, and, asc } from 'drizzle-orm' -export type TaskState = "running" | "success" | "failed" | "abandoned" +export type TaskState = 'running' | 'success' | 'failed' | 'abandoned' class TasksRepository { async getAll({ @@ -11,19 +11,35 @@ class TasksRepository { state, limit, offset, + sortByRuntime, + sortByStartedAt }: { limit: number offset: number name: string | null - state?: "success" | "running" | "failure" | "abandoned" + state?: 'success' | 'running' | 'failure' | 'abandoned' + sortByRuntime?: 'asc' | 'desc' + sortByStartedAt?: 'asc' | 'desc' }) { const whereCondition = name ? like(tasksTable.name, `%${name.toLowerCase()}%`) : undefined + const orderMap = { asc, desc } + const sortConditions = [] + if (sortByRuntime) { + sortConditions.push(orderMap[sortByRuntime](tasksTable.executionTime)) + } + if (sortByStartedAt) { + sortConditions.push(orderMap[sortByStartedAt](tasksTable.startedAt)) + } + if (sortConditions.length === 0) { + sortConditions.push(desc(tasksTable.startedAt)) + } + const countResult = await db .select({ - count: count(), + count: count() }) .from(tasksTable) .where( @@ -37,7 +53,7 @@ class TasksRepository { .where( and(whereCondition, state ? eq(tasksTable.state, state) : undefined) ) - .orderBy(desc(tasksTable.startedAt)) + .orderBy(...sortConditions) .limit(limit) .offset(offset) @@ -62,7 +78,7 @@ class TasksRepository { kwargs: Record executionTime: number | null returnValue: { return_value: any } | null - state: "success" | "running" | "failure" + state: 'success' | 'running' | 'failure' }) { return db.insert(tasksTable).values(values) } @@ -74,7 +90,7 @@ class TasksRepository { executionTime?: number finishedAt?: Date | null returnValue?: { return_value: any } | null - state?: "success" | "running" | "failure" | "abandoned" + state?: 'success' | 'running' | 'failure' | 'abandoned' } ) { return db.update(tasksTable).set(values).where(eq(tasksTable.id, taskId)) @@ -83,8 +99,8 @@ class TasksRepository { async setAbandoned() { return db .update(tasksTable) - .set({ state: "abandoned" }) - .where(eq(tasksTable.state, "running")) + .set({ state: 'abandoned' }) + .where(eq(tasksTable.state, 'running')) } } diff --git a/src/server/schemas/tasks.ts b/src/server/schemas/tasks.ts index d3871af..f137b77 100644 --- a/src/server/schemas/tasks.ts +++ b/src/server/schemas/tasks.ts @@ -1,27 +1,29 @@ -import { z } from "zod" +import { z } from 'zod' export const taskStartedRequestSchema = z.object({ worker: z.string(), taskName: z.string(), startedAt: z.coerce.date(), args: z.array(z.unknown()), - kwargs: z.record(z.string(), z.unknown()), + kwargs: z.record(z.string(), z.unknown()) }) export const taskExecutedRequestSchema = z.object({ error: z.string().nullable(), executionTime: z.number(), finishedAt: z.coerce.date(), - returnValue: z.record(z.string(), z.unknown()).nullable(), + returnValue: z.record(z.string(), z.unknown()).nullable() }) export const taskRouteParamsSchema = z.object({ - id: z.string(), + id: z.string() }) export const getTasksQueryParamsSchema = z.object({ search: z.string().optional(), limit: z.coerce.number().gte(0), offset: z.coerce.number().gte(0), - state: z.enum(["success", "running", "failure", "abandoned"]).optional(), + state: z.enum(['success', 'running', 'failure', 'abandoned']).optional(), + sortByRuntime: z.enum(['asc', 'desc']).optional(), + sortByStartedAt: z.enum(['asc', 'desc']).optional() }) diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index 2e0faa4..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -import dayjs from "dayjs" -import utc from "dayjs/plugin/utc" - -dayjs.extend(utc) - -export const formatDate = (date: string) => { - return dayjs.utc(date).local().format("MMM D, YYYY hh:mm A") -} From e875f16ab2794f0ca744fa24dcb2cbffd84fed5a Mon Sep 17 00:00:00 2001 From: arturka Date: Fri, 11 Apr 2025 12:41:05 +0200 Subject: [PATCH 15/36] feat: update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ce4d705..82f2395 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ class TaskiqAdminMiddleware(TaskiqMiddleware): """""" async with httpx.AsyncClient() as client: await client.post( - headers={"access-token": settings.taskiq_admin_access_token}, - url=urljoin(settings.taskiq_admin_url, f"/api/tasks/{message.task_id}/started"), + headers={"access-token": TASKIQ_ADMIN_API_TOKEN}, + url=urljoin(TASKIQ_ADMIN_URL, f"/api/tasks/{message.task_id}/started"), json={ "args": message.args, "kwargs": message.kwargs, @@ -60,8 +60,8 @@ class TaskiqAdminMiddleware(TaskiqMiddleware): """""" async with httpx.AsyncClient() as client: await client.post( - headers={"access-token": settings.taskiq_admin_access_token}, - url=urljoin(settings.taskiq_admin_url, f"/api/tasks/{message.task_id}/executed"), + headers={"access-token": TASKIQ_ADMIN_API_TOKEN}, + url=urljoin(TASKIQ_ADMIN_URL, f"/api/tasks/{message.task_id}/executed"), json={ "error": result.error if result.error is None From 263070cde7fa0ac22b3fb998ae88e7eb32b02ec3 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Sat, 12 Apr 2025 23:17:59 +0200 Subject: [PATCH 16/36] Added releases workflow. --- .github/workflows/release.yaml | 33 +++++++++++++++++++++++++++++++++ docker/Dockerfile => Dockerfile | 0 2 files changed, 33 insertions(+) create mode 100644 .github/workflows/release.yaml rename docker/Dockerfile => Dockerfile (100%) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..a5bc8cb --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,33 @@ +name: Release + +on: + release: + types: [released] + +jobs: + release_image: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Docker + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm/v7 + push: true + tags: ghcr.io/taskiq-python/taskiq-admin:latest,ghcr.io/taskiq-python/taskiq-admin:${{ github.ref_name }} diff --git a/docker/Dockerfile b/Dockerfile similarity index 100% rename from docker/Dockerfile rename to Dockerfile From 231e86f3bd2ccfc415c57992a2ae2e8834193976 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Sat, 12 Apr 2025 23:19:10 +0200 Subject: [PATCH 17/36] Fixed readme. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 82f2395..76c08b7 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ class TaskiqAdminMiddleware(TaskiqMiddleware): return super().post_execute(message, result) ``` -2) Pull the image from DockerHub: `docker pull artur10/taskiq-admin:latest` +2) Pull the image from DockerHub: `docker pull ghcr.io/taskiq-python/taskiq-admin:latest` 3) Replace `TASKIQ_ADMIN_API_TOKEN` with any secret enough string and run: ```bash @@ -84,7 +84,7 @@ docker run -d --rm \ -v ./taskiq-admin-data/:/usr/database/ \ -e TASKIQ_ADMIN_API_TOKEN=supersecret \ --name taskiq-admin \ - artur10/taskiq-admin:latest + ghcr.io/taskiq-python/taskiq-admin:latest ``` 4) Go to `http://localhost:3000/tasks` @@ -115,7 +115,7 @@ compose.yml file example - taskiq_admin taskiq_admin: - image: artur10/taskiq-admin:latest + image: ghcr.io/taskiq-python/taskiq-admin:latest container_name: taskiq_admin ports: - 3000:3000 @@ -129,4 +129,4 @@ compose.yml file example ### Development 1) Run `pnpm install` to install all dependencies 2) Run `pnpm db:push` to create the sqlite database if needed -3) Run `pnpm dev` to run the project \ No newline at end of file +3) Run `pnpm dev` to run the project From 35a51e125d5e7baace36c3f7717cc44825af28f0 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Sat, 12 Apr 2025 23:21:35 +0200 Subject: [PATCH 18/36] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76c08b7..81589c6 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ class TaskiqAdminMiddleware(TaskiqMiddleware): return super().post_execute(message, result) ``` -2) Pull the image from DockerHub: `docker pull ghcr.io/taskiq-python/taskiq-admin:latest` +2) Pull the image from GitHub Container Registry: `docker pull ghcr.io/taskiq-python/taskiq-admin:latest` 3) Replace `TASKIQ_ADMIN_API_TOKEN` with any secret enough string and run: ```bash From 2de5f506c7913c13845a804be54a2ad3c0a29c36 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Sat, 12 Apr 2025 23:42:13 +0200 Subject: [PATCH 19/36] Small readme enhancements. --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 81589c6..df52d02 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,10 @@ class TaskiqAdminMiddleware(TaskiqMiddleware): ```bash docker run -d --rm \ -p "3000:3000" \ - -v ./taskiq-admin-data/:/usr/database/ \ - -e TASKIQ_ADMIN_API_TOKEN=supersecret \ - --name taskiq-admin \ - ghcr.io/taskiq-python/taskiq-admin:latest + -v "./taskiq-admin-data/:/usr/database/" \ + -e "TASKIQ_ADMIN_API_TOKEN=supersecret" \ + --name "taskiq-admin" \ + "ghcr.io/taskiq-python/taskiq-admin:latest" ``` 4) Go to `http://localhost:3000/tasks` @@ -93,15 +93,13 @@ docker run -d --rm \ .env file example: ```bash -... -TASKIQ_ADMIN_URL=http://taskiq_admin:3000 -TASKIQ_ADMIN_API_TOKEN=supersecret -... +TASKIQ_ADMIN_URL="http://taskiq_admin:3000" +TASKIQ_ADMIN_API_TOKEN="supersecret" ``` compose.yml file example -```shell -... +```yaml +services: queue: build: context: . @@ -122,8 +120,10 @@ compose.yml file example env_file: - .env volumes: - - ./any/suitable/path:/usr/database/ -... + - admin_data:/usr/database/ + +volumes: + admin_data: ``` ### Development From 0ca512812f2608d258770fac052fc1ec31ebf4d8 Mon Sep 17 00:00:00 2001 From: arturka Date: Mon, 14 Apr 2025 11:03:30 +0200 Subject: [PATCH 20/36] fix: worker param can be nullable --- src/components/tasks-table.vue | 2 +- src/server/api/tasks/[id]/started.post.ts | 20 ++++++++++---------- src/server/repositories/tasks.ts | 2 +- src/server/schemas/tasks.ts | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/tasks-table.vue b/src/components/tasks-table.vue index 332ae2b..e16a4cf 100644 --- a/src/components/tasks-table.vue +++ b/src/components/tasks-table.vue @@ -138,7 +138,7 @@ const searchHandler: ((value: string) => void) | undefined = />
- Worker + Broker diff --git a/src/server/api/tasks/[id]/started.post.ts b/src/server/api/tasks/[id]/started.post.ts index 550d3b2..e3a74c3 100644 --- a/src/server/api/tasks/[id]/started.post.ts +++ b/src/server/api/tasks/[id]/started.post.ts @@ -1,17 +1,17 @@ import { taskRouteParamsSchema, - taskStartedRequestSchema, -} from "../../../schemas/tasks" -import { tasksRepository } from "../../../repositories/tasks" -import { envVariables } from "~/server/env" + taskStartedRequestSchema +} from '../../../schemas/tasks' +import { tasksRepository } from '../../../repositories/tasks' +import { envVariables } from '~/server/env' export default defineEventHandler(async (event) => { - const accessToken = getRequestHeader(event, "access-token") + const accessToken = getRequestHeader(event, 'access-token') if (!accessToken || accessToken !== envVariables.taskiqAdminApiToken) { throw createError({ status: 401, - statusMessage: "Unauthorized", - message: "Invalid access token", + statusMessage: 'Unauthorized', + message: 'Invalid access token' }) } const params = await getValidatedRouterParams( @@ -24,15 +24,15 @@ export default defineEventHandler(async (event) => { finishedAt: null, returnValue: null, executionTime: null, - state: "running", + state: 'running', args: body.args, id: params.id, worker: body.worker, kwargs: body.kwargs, name: body.taskName, - startedAt: body.startedAt, + startedAt: body.startedAt }) return { - success: true, + success: true } }) diff --git a/src/server/repositories/tasks.ts b/src/server/repositories/tasks.ts index d4600c0..5a608d9 100644 --- a/src/server/repositories/tasks.ts +++ b/src/server/repositories/tasks.ts @@ -71,9 +71,9 @@ class TasksRepository { async create(values: { id: string name: string - worker: string startedAt: Date args: Array + worker: string | null finishedAt: Date | null kwargs: Record executionTime: number | null diff --git a/src/server/schemas/tasks.ts b/src/server/schemas/tasks.ts index f137b77..26752de 100644 --- a/src/server/schemas/tasks.ts +++ b/src/server/schemas/tasks.ts @@ -1,10 +1,10 @@ import { z } from 'zod' export const taskStartedRequestSchema = z.object({ - worker: z.string(), taskName: z.string(), startedAt: z.coerce.date(), args: z.array(z.unknown()), + worker: z.string().nullable(), kwargs: z.record(z.string(), z.unknown()) }) From 22feb0b1dab4c0f403fd62e482de823fd3064c0e Mon Sep 17 00:00:00 2001 From: arturka Date: Sun, 20 Apr 2025 12:16:19 +0200 Subject: [PATCH 21/36] feat: add date range picker, autorefresh for individual taks, backup date --- package.json | 5 +- pnpm-lock.yaml | 356 +++++++++++++++--- src/components/range-picker.vue | 85 +++++ src/components/ui/calendar/Calendar.vue | 63 ++++ src/components/ui/calendar/CalendarCell.vue | 25 ++ .../ui/calendar/CalendarCellTrigger.vue | 41 ++ src/components/ui/calendar/CalendarGrid.vue | 25 ++ .../ui/calendar/CalendarGridBody.vue | 14 + .../ui/calendar/CalendarGridHead.vue | 15 + .../ui/calendar/CalendarGridRow.vue | 24 ++ .../ui/calendar/CalendarHeadCell.vue | 25 ++ src/components/ui/calendar/CalendarHeader.vue | 25 ++ .../ui/calendar/CalendarHeading.vue | 32 ++ .../ui/calendar/CalendarNextButton.vue | 34 ++ .../ui/calendar/CalendarPrevButton.vue | 34 ++ src/components/ui/calendar/index.ts | 12 + src/components/ui/popover/Popover.vue | 18 + src/components/ui/popover/PopoverAnchor.vue | 15 + src/components/ui/popover/PopoverContent.vue | 49 +++ src/components/ui/popover/PopoverTrigger.vue | 14 + src/components/ui/popover/index.ts | 4 + .../ui/range-calendar/RangeCalendar.vue | 91 +++++ .../ui/range-calendar/RangeCalendarCell.vue | 25 ++ .../RangeCalendarCellTrigger.vue | 43 +++ .../ui/range-calendar/RangeCalendarGrid.vue | 25 ++ .../range-calendar/RangeCalendarGridBody.vue | 14 + .../range-calendar/RangeCalendarGridHead.vue | 14 + .../range-calendar/RangeCalendarGridRow.vue | 24 ++ .../range-calendar/RangeCalendarHeadCell.vue | 25 ++ .../ui/range-calendar/RangeCalendarHeader.vue | 25 ++ .../range-calendar/RangeCalendarHeading.vue | 32 ++ .../RangeCalendarNextButton.vue | 34 ++ .../RangeCalendarPrevButton.vue | 34 ++ src/components/ui/range-calendar/index.ts | 12 + src/pages/tasks/[id].vue | 21 +- src/pages/tasks/index.vue | 61 ++- src/server/api/tasks/backup.get.ts | 9 +- src/server/api/tasks/index.get.ts | 4 +- src/server/repositories/tasks.ts | 34 +- src/server/schemas/tasks.ts | 4 +- src/server/utils.ts | 12 +- 41 files changed, 1372 insertions(+), 86 deletions(-) create mode 100644 src/components/range-picker.vue create mode 100644 src/components/ui/calendar/Calendar.vue create mode 100644 src/components/ui/calendar/CalendarCell.vue create mode 100644 src/components/ui/calendar/CalendarCellTrigger.vue create mode 100644 src/components/ui/calendar/CalendarGrid.vue create mode 100644 src/components/ui/calendar/CalendarGridBody.vue create mode 100644 src/components/ui/calendar/CalendarGridHead.vue create mode 100644 src/components/ui/calendar/CalendarGridRow.vue create mode 100644 src/components/ui/calendar/CalendarHeadCell.vue create mode 100644 src/components/ui/calendar/CalendarHeader.vue create mode 100644 src/components/ui/calendar/CalendarHeading.vue create mode 100644 src/components/ui/calendar/CalendarNextButton.vue create mode 100644 src/components/ui/calendar/CalendarPrevButton.vue create mode 100644 src/components/ui/calendar/index.ts create mode 100644 src/components/ui/popover/Popover.vue create mode 100644 src/components/ui/popover/PopoverAnchor.vue create mode 100644 src/components/ui/popover/PopoverContent.vue create mode 100644 src/components/ui/popover/PopoverTrigger.vue create mode 100644 src/components/ui/popover/index.ts create mode 100644 src/components/ui/range-calendar/RangeCalendar.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarCell.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarCellTrigger.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarGrid.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarGridBody.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarGridHead.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarGridRow.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarHeadCell.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarHeader.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarHeading.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarNextButton.vue create mode 100644 src/components/ui/range-calendar/RangeCalendarPrevButton.vue create mode 100644 src/components/ui/range-calendar/index.ts diff --git a/package.json b/package.json index 5e94a5b..65b9fbb 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nuxt-app", "private": true, "type": "module", - "version": "1.4.0", + "version": "1.5.0", "scripts": { "build": "nuxt build", "dev": "nuxt dev", @@ -14,6 +14,7 @@ "generate:future:sql": "drizzle-kit export --sql | sed 's/CREATE TABLE/CREATE TABLE IF NOT EXISTS/g; s/CREATE INDEX/CREATE INDEX IF NOT EXISTS/g' > dbschema.sql; sed -i '1s/^/PRAGMA journal_mode = WAL; PRAGMA synchronous = normal; PRAGMA journal_size_limit = 6144000;\\n/' dbschema.sql" }, "dependencies": { + "@internationalized/date": "^3.8.0", "@tailwindcss/vite": "^4.1.3", "@tanstack/vue-table": "^8.21.2", "@vueuse/core": "^12.8.2", @@ -33,7 +34,7 @@ "vue": "^3.5.13", "vue-router": "^4.5.0", "vue-sonner": "^1.3.0", - "zod": "^3.24.2" + "zod": "^3.24.3" }, "packageManager": "pnpm@8.7.6+sha1.a428b12202bc4f23b17e6dffe730734dae5728e2", "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 382ab7a..6781a78 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,12 @@ settings: excludeLinksFromLockfile: false dependencies: + '@internationalized/date': + specifier: ^3.8.0 + version: 3.8.0 '@tailwindcss/vite': specifier: ^4.1.3 - version: 4.1.3(vite@6.2.5) + version: 4.1.3(vite@6.3.2) '@tanstack/vue-table': specifier: ^8.21.2 version: 8.21.2(vue@3.5.13) @@ -40,7 +43,7 @@ dependencies: version: 0.487.0(vue@3.5.13) nuxt: specifier: ^3.16.2 - version: 3.16.2(better-sqlite3@11.9.1)(drizzle-orm@0.41.0)(typescript@5.8.3)(vite@6.2.5) + version: 3.16.2(better-sqlite3@11.9.1)(drizzle-orm@0.41.0)(typescript@5.8.3)(vite@6.3.2) reka-ui: specifier: ^2.2.0 version: 2.2.0(typescript@5.8.3)(vue@3.5.13) @@ -63,8 +66,8 @@ dependencies: specifier: ^1.3.0 version: 1.3.0 zod: - specifier: ^3.24.2 - version: 3.24.2 + specifier: ^3.24.3 + version: 3.24.3 devDependencies: '@iconify-json/radix-icons': @@ -356,25 +359,25 @@ packages: resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} dev: true - /@emnapi/core@1.4.0: - resolution: {integrity: sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==} + /@emnapi/core@1.4.3: + resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} requiresBuild: true dependencies: - '@emnapi/wasi-threads': 1.0.1 + '@emnapi/wasi-threads': 1.0.2 tslib: 2.8.1 dev: false optional: true - /@emnapi/runtime@1.4.0: - resolution: {integrity: sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==} + /@emnapi/runtime@1.4.3: + resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} requiresBuild: true dependencies: tslib: 2.8.1 dev: false optional: true - /@emnapi/wasi-threads@1.0.1: - resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} + /@emnapi/wasi-threads@1.0.2: + resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} requiresBuild: true dependencies: tslib: 2.8.1 @@ -1074,8 +1077,8 @@ packages: vue: 3.5.13(typescript@5.8.3) dev: true - /@internationalized/date@3.7.0: - resolution: {integrity: sha512-VJ5WS3fcVx0bejE/YHfbDKR/yawZgKqn/if+oEeLqNwBtPzVB06olkfcnojTmEMX+gTpH+FlQ69SHNitJ8/erQ==} + /@internationalized/date@3.8.0: + resolution: {integrity: sha512-J51AJ0fEL68hE4CwGPa6E0PO6JDaVLd8aln48xFCSy7CZkZc96dGEGmLs2OEEbBxcsVZtfrqkXJwI2/MSG8yKw==} dependencies: '@swc/helpers': 0.5.15 dev: false @@ -1174,12 +1177,12 @@ packages: - supports-color dev: false - /@napi-rs/wasm-runtime@0.2.8: - resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==} + /@napi-rs/wasm-runtime@0.2.9: + resolution: {integrity: sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==} requiresBuild: true dependencies: - '@emnapi/core': 1.4.0 - '@emnapi/runtime': 1.4.0 + '@emnapi/core': 1.4.3 + '@emnapi/runtime': 1.4.3 '@tybys/wasm-util': 0.9.0 dev: false optional: true @@ -1254,7 +1257,7 @@ packages: resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==} dev: false - /@nuxt/devtools-kit@2.3.2(magicast@0.3.5)(vite@6.2.5): + /@nuxt/devtools-kit@2.3.2(magicast@0.3.5)(vite@6.3.2): resolution: {integrity: sha512-K0citnz9bSecPCLl4jGfE5I5St+E9XtDmOvYqq3ranGZGZ2Mvs5RwgUkaOrn4rulvUmBGBl7Exwh5YX9PONrEQ==} peerDependencies: vite: '>=6.0' @@ -1262,7 +1265,7 @@ packages: '@nuxt/kit': 3.16.2(magicast@0.3.5) '@nuxt/schema': 3.16.2 execa: 8.0.1 - vite: 6.2.5(jiti@2.4.2) + vite: 6.3.2 transitivePeerDependencies: - magicast dev: false @@ -1281,16 +1284,16 @@ packages: semver: 7.7.1 dev: false - /@nuxt/devtools@2.3.2(vite@6.2.5)(vue@3.5.13): + /@nuxt/devtools@2.3.2(vite@6.3.2)(vue@3.5.13): resolution: {integrity: sha512-MMx7pUW0aPDRmhe3jy91srEiFWq/Q70rjbGoHhzpVosuvyvy/fi0oKOFQqN5V4V7jJLiEx4HAoD0QdqP0I6xBA==} hasBin: true peerDependencies: vite: '>=6.0' dependencies: - '@nuxt/devtools-kit': 2.3.2(magicast@0.3.5)(vite@6.2.5) + '@nuxt/devtools-kit': 2.3.2(magicast@0.3.5)(vite@6.3.2) '@nuxt/devtools-wizard': 2.3.2 '@nuxt/kit': 3.16.2(magicast@0.3.5) - '@vue/devtools-core': 7.7.2(vite@6.2.5)(vue@3.5.13) + '@vue/devtools-core': 7.7.2(vite@6.3.2)(vue@3.5.13) '@vue/devtools-kit': 7.7.2 birpc: 2.3.0 consola: 3.4.2 @@ -1315,9 +1318,9 @@ packages: sirv: 3.0.1 structured-clone-es: 1.0.0 tinyglobby: 0.2.12 - vite: 6.2.5(jiti@2.4.2) - vite-plugin-inspect: 11.0.0(@nuxt/kit@3.16.2)(vite@6.2.5) - vite-plugin-vue-tracer: 0.1.3(vite@6.2.5)(vue@3.5.13) + vite: 6.3.2 + vite-plugin-inspect: 11.0.0(@nuxt/kit@3.16.2)(vite@6.3.2) + vite-plugin-vue-tracer: 0.1.3(vite@6.3.2)(vue@3.5.13) which: 5.0.0 ws: 8.18.1 transitivePeerDependencies: @@ -1523,7 +1526,7 @@ packages: cpu: [wasm32] requiresBuild: true dependencies: - '@napi-rs/wasm-runtime': 0.2.8 + '@napi-rs/wasm-runtime': 0.2.9 dev: false optional: true @@ -1879,6 +1882,14 @@ packages: dev: false optional: true + /@rollup/rollup-android-arm-eabi@4.40.0: + resolution: {integrity: sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-android-arm64@4.39.0: resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} cpu: [arm64] @@ -1887,6 +1898,14 @@ packages: dev: false optional: true + /@rollup/rollup-android-arm64@4.40.0: + resolution: {integrity: sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-darwin-arm64@4.39.0: resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} cpu: [arm64] @@ -1895,6 +1914,14 @@ packages: dev: false optional: true + /@rollup/rollup-darwin-arm64@4.40.0: + resolution: {integrity: sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-darwin-x64@4.39.0: resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} cpu: [x64] @@ -1903,6 +1930,14 @@ packages: dev: false optional: true + /@rollup/rollup-darwin-x64@4.40.0: + resolution: {integrity: sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-freebsd-arm64@4.39.0: resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} cpu: [arm64] @@ -1911,6 +1946,14 @@ packages: dev: false optional: true + /@rollup/rollup-freebsd-arm64@4.40.0: + resolution: {integrity: sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-freebsd-x64@4.39.0: resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} cpu: [x64] @@ -1919,6 +1962,14 @@ packages: dev: false optional: true + /@rollup/rollup-freebsd-x64@4.40.0: + resolution: {integrity: sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-arm-gnueabihf@4.39.0: resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} cpu: [arm] @@ -1927,6 +1978,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm-gnueabihf@4.40.0: + resolution: {integrity: sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-arm-musleabihf@4.39.0: resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} cpu: [arm] @@ -1935,6 +1994,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm-musleabihf@4.40.0: + resolution: {integrity: sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-arm64-gnu@4.39.0: resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} cpu: [arm64] @@ -1943,6 +2010,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm64-gnu@4.40.0: + resolution: {integrity: sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-arm64-musl@4.39.0: resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} cpu: [arm64] @@ -1951,6 +2026,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm64-musl@4.40.0: + resolution: {integrity: sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-loongarch64-gnu@4.39.0: resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} cpu: [loong64] @@ -1959,6 +2042,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-loongarch64-gnu@4.40.0: + resolution: {integrity: sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-powerpc64le-gnu@4.39.0: resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} cpu: [ppc64] @@ -1967,6 +2058,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-powerpc64le-gnu@4.40.0: + resolution: {integrity: sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-riscv64-gnu@4.39.0: resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} cpu: [riscv64] @@ -1975,6 +2074,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-riscv64-gnu@4.40.0: + resolution: {integrity: sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-riscv64-musl@4.39.0: resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} cpu: [riscv64] @@ -1983,6 +2090,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-riscv64-musl@4.40.0: + resolution: {integrity: sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-s390x-gnu@4.39.0: resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} cpu: [s390x] @@ -1991,6 +2106,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-s390x-gnu@4.40.0: + resolution: {integrity: sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-x64-gnu@4.39.0: resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} cpu: [x64] @@ -1999,6 +2122,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-x64-gnu@4.40.0: + resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-linux-x64-musl@4.39.0: resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} cpu: [x64] @@ -2007,6 +2138,14 @@ packages: dev: false optional: true + /@rollup/rollup-linux-x64-musl@4.40.0: + resolution: {integrity: sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-win32-arm64-msvc@4.39.0: resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} cpu: [arm64] @@ -2015,6 +2154,14 @@ packages: dev: false optional: true + /@rollup/rollup-win32-arm64-msvc@4.40.0: + resolution: {integrity: sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-win32-ia32-msvc@4.39.0: resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} cpu: [ia32] @@ -2023,6 +2170,14 @@ packages: dev: false optional: true + /@rollup/rollup-win32-ia32-msvc@4.40.0: + resolution: {integrity: sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@rollup/rollup-win32-x64-msvc@4.39.0: resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} cpu: [x64] @@ -2031,6 +2186,14 @@ packages: dev: false optional: true + /@rollup/rollup-win32-x64-msvc@4.40.0: + resolution: {integrity: sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@sindresorhus/is@7.0.1: resolution: {integrity: sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==} engines: {node: '>=18'} @@ -2176,7 +2339,7 @@ packages: '@tailwindcss/oxide-win32-x64-msvc': 4.1.3 dev: false - /@tailwindcss/vite@4.1.3(vite@6.2.5): + /@tailwindcss/vite@4.1.3(vite@6.3.2): resolution: {integrity: sha512-lUI/QaDxLtlV52Lho6pu07CG9pSnRYLOPmKGIQjyHdTBagemc6HmgZxyjGAQ/5HMPrNeWBfTVIpQl0/jLXvWHQ==} peerDependencies: vite: ^5.2.0 || ^6 @@ -2184,7 +2347,7 @@ packages: '@tailwindcss/node': 4.1.3 '@tailwindcss/oxide': 4.1.3 tailwindcss: 4.1.3 - vite: 6.2.5(jiti@2.4.2) + vite: 6.3.2 dev: false /@tanstack/table-core@8.21.2: @@ -2411,7 +2574,7 @@ packages: resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} dev: false - /@vue/devtools-core@7.7.2(vite@6.2.5)(vue@3.5.13): + /@vue/devtools-core@7.7.2(vite@6.3.2)(vue@3.5.13): resolution: {integrity: sha512-lexREWj1lKi91Tblr38ntSsy6CvI8ba7u+jmwh2yruib/ltLUcsIzEjCnrkh1yYGGIKXbAuYV2tOG10fGDB9OQ==} peerDependencies: vue: ^3.0.0 @@ -2421,7 +2584,7 @@ packages: mitt: 3.0.1 nanoid: 5.1.5 pathe: 2.0.3 - vite-hot-client: 0.2.4(vite@6.2.5) + vite-hot-client: 0.2.4(vite@6.3.2) vue: 3.5.13(typescript@5.8.3) transitivePeerDependencies: - vite @@ -3643,6 +3806,17 @@ packages: picomatch: 4.0.2 dev: false + /fdir@6.4.4(picomatch@4.0.2): + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + dependencies: + picomatch: 4.0.2 + dev: false + /file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} dev: false @@ -4668,7 +4842,7 @@ packages: boolbase: 1.0.0 dev: false - /nuxt@3.16.2(better-sqlite3@11.9.1)(drizzle-orm@0.41.0)(typescript@5.8.3)(vite@6.2.5): + /nuxt@3.16.2(better-sqlite3@11.9.1)(drizzle-orm@0.41.0)(typescript@5.8.3)(vite@6.3.2): resolution: {integrity: sha512-yjIC/C4HW8Pd+m0ACGliEF0HnimXYGYvUzjOsTiLQKkDDt2T+djyZ+pCl9BfhQBA8rYmnsym2jUI+ubjv1iClw==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0.0} hasBin: true @@ -4683,7 +4857,7 @@ packages: dependencies: '@nuxt/cli': 3.24.1 '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 2.3.2(vite@6.2.5)(vue@3.5.13) + '@nuxt/devtools': 2.3.2(vite@6.3.2)(vue@3.5.13) '@nuxt/kit': 3.16.2(magicast@0.3.5) '@nuxt/schema': 3.16.2 '@nuxt/telemetry': 2.6.6 @@ -5451,7 +5625,7 @@ packages: dependencies: '@floating-ui/dom': 1.6.13 '@floating-ui/vue': 1.1.6(vue@3.5.13) - '@internationalized/date': 3.7.0 + '@internationalized/date': 3.8.0 '@internationalized/number': 3.6.0 '@tanstack/vue-virtual': 3.13.6(vue@3.5.13) '@vueuse/core': 12.8.2(typescript@5.8.3) @@ -5548,6 +5722,36 @@ packages: fsevents: 2.3.3 dev: false + /rollup@4.40.0: + resolution: {integrity: sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.40.0 + '@rollup/rollup-android-arm64': 4.40.0 + '@rollup/rollup-darwin-arm64': 4.40.0 + '@rollup/rollup-darwin-x64': 4.40.0 + '@rollup/rollup-freebsd-arm64': 4.40.0 + '@rollup/rollup-freebsd-x64': 4.40.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.0 + '@rollup/rollup-linux-arm-musleabihf': 4.40.0 + '@rollup/rollup-linux-arm64-gnu': 4.40.0 + '@rollup/rollup-linux-arm64-musl': 4.40.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.0 + '@rollup/rollup-linux-riscv64-gnu': 4.40.0 + '@rollup/rollup-linux-riscv64-musl': 4.40.0 + '@rollup/rollup-linux-s390x-gnu': 4.40.0 + '@rollup/rollup-linux-x64-gnu': 4.40.0 + '@rollup/rollup-linux-x64-musl': 4.40.0 + '@rollup/rollup-win32-arm64-msvc': 4.40.0 + '@rollup/rollup-win32-ia32-msvc': 4.40.0 + '@rollup/rollup-win32-x64-msvc': 4.40.0 + fsevents: 2.3.3 + dev: false + /run-applescript@7.0.0: resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} engines: {node: '>=18'} @@ -5942,6 +6146,14 @@ packages: picomatch: 4.0.2 dev: false + /tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + dev: false + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -6226,30 +6438,30 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: false - /vite-dev-rpc@1.0.7(vite@6.2.5): + /vite-dev-rpc@1.0.7(vite@6.3.2): resolution: {integrity: sha512-FxSTEofDbUi2XXujCA+hdzCDkXFG1PXktMjSk1efq9Qb5lOYaaM9zNSvKvPPF7645Bak79kSp1PTooMW2wktcA==} peerDependencies: vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 dependencies: birpc: 2.3.0 - vite: 6.2.5(jiti@2.4.2) - vite-hot-client: 2.0.4(vite@6.2.5) + vite: 6.3.2 + vite-hot-client: 2.0.4(vite@6.3.2) dev: false - /vite-hot-client@0.2.4(vite@6.2.5): + /vite-hot-client@0.2.4(vite@6.3.2): resolution: {integrity: sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==} peerDependencies: vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 dependencies: - vite: 6.2.5(jiti@2.4.2) + vite: 6.3.2 dev: false - /vite-hot-client@2.0.4(vite@6.2.5): + /vite-hot-client@2.0.4(vite@6.3.2): resolution: {integrity: sha512-W9LOGAyGMrbGArYJN4LBCdOC5+Zwh7dHvOHC0KmGKkJhsOzaKbpo/jEjpPKVHIW0/jBWj8RZG0NUxfgA8BxgAg==} peerDependencies: vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 dependencies: - vite: 6.2.5(jiti@2.4.2) + vite: 6.3.2 dev: false /vite-node@3.1.1(jiti@2.4.2): @@ -6324,7 +6536,7 @@ packages: vscode-uri: 3.1.0 dev: false - /vite-plugin-inspect@11.0.0(@nuxt/kit@3.16.2)(vite@6.2.5): + /vite-plugin-inspect@11.0.0(@nuxt/kit@3.16.2)(vite@6.3.2): resolution: {integrity: sha512-Q0RDNcMs1mbI2yGRwOzSapnnA6NFO0j88+Vb8pJX0iYMw34WczwKJi3JgheItDhbWRq/CLUR0cs+ajZpcUaIFQ==} engines: {node: '>=14'} peerDependencies: @@ -6343,13 +6555,13 @@ packages: perfect-debounce: 1.0.0 sirv: 3.0.1 unplugin-utils: 0.2.4 - vite: 6.2.5(jiti@2.4.2) - vite-dev-rpc: 1.0.7(vite@6.2.5) + vite: 6.3.2 + vite-dev-rpc: 1.0.7(vite@6.3.2) transitivePeerDependencies: - supports-color dev: false - /vite-plugin-vue-tracer@0.1.3(vite@6.2.5)(vue@3.5.13): + /vite-plugin-vue-tracer@0.1.3(vite@6.3.2)(vue@3.5.13): resolution: {integrity: sha512-+fN6oo0//dwZP9Ax9gRKeUroCqpQ43P57qlWgL0ljCIxAs+Rpqn/L4anIPZPgjDPga5dZH+ZJsshbF0PNJbm3Q==} peerDependencies: vite: ^6.0.0 @@ -6360,7 +6572,7 @@ packages: magic-string: 0.30.17 pathe: 2.0.3 source-map-js: 1.2.1 - vite: 6.2.5(jiti@2.4.2) + vite: 6.3.2 vue: 3.5.13(typescript@5.8.3) dev: false @@ -6412,6 +6624,56 @@ packages: fsevents: 2.3.3 dev: false + /vite@6.3.2: + resolution: {integrity: sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + dependencies: + esbuild: 0.25.2 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.3 + rollup: 4.40.0 + tinyglobby: 0.2.13 + optionalDependencies: + fsevents: 2.3.3 + dev: false + /vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} dev: false @@ -6608,6 +6870,6 @@ packages: readable-stream: 4.7.0 dev: false - /zod@3.24.2: - resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} + /zod@3.24.3: + resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} dev: false diff --git a/src/components/range-picker.vue b/src/components/range-picker.vue new file mode 100644 index 0000000..a995456 --- /dev/null +++ b/src/components/range-picker.vue @@ -0,0 +1,85 @@ + + + diff --git a/src/components/ui/calendar/Calendar.vue b/src/components/ui/calendar/Calendar.vue new file mode 100644 index 0000000..dac3a3c --- /dev/null +++ b/src/components/ui/calendar/Calendar.vue @@ -0,0 +1,63 @@ + + + diff --git a/src/components/ui/calendar/CalendarCell.vue b/src/components/ui/calendar/CalendarCell.vue new file mode 100644 index 0000000..bc873ed --- /dev/null +++ b/src/components/ui/calendar/CalendarCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/calendar/CalendarCellTrigger.vue b/src/components/ui/calendar/CalendarCellTrigger.vue new file mode 100644 index 0000000..3a52b73 --- /dev/null +++ b/src/components/ui/calendar/CalendarCellTrigger.vue @@ -0,0 +1,41 @@ + + + diff --git a/src/components/ui/calendar/CalendarGrid.vue b/src/components/ui/calendar/CalendarGrid.vue new file mode 100644 index 0000000..4227b56 --- /dev/null +++ b/src/components/ui/calendar/CalendarGrid.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/calendar/CalendarGridBody.vue b/src/components/ui/calendar/CalendarGridBody.vue new file mode 100644 index 0000000..7b2bf41 --- /dev/null +++ b/src/components/ui/calendar/CalendarGridBody.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/calendar/CalendarGridHead.vue b/src/components/ui/calendar/CalendarGridHead.vue new file mode 100644 index 0000000..3ba322b --- /dev/null +++ b/src/components/ui/calendar/CalendarGridHead.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/components/ui/calendar/CalendarGridRow.vue b/src/components/ui/calendar/CalendarGridRow.vue new file mode 100644 index 0000000..a6909d9 --- /dev/null +++ b/src/components/ui/calendar/CalendarGridRow.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/components/ui/calendar/CalendarHeadCell.vue b/src/components/ui/calendar/CalendarHeadCell.vue new file mode 100644 index 0000000..ed9f523 --- /dev/null +++ b/src/components/ui/calendar/CalendarHeadCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/calendar/CalendarHeader.vue b/src/components/ui/calendar/CalendarHeader.vue new file mode 100644 index 0000000..efac13d --- /dev/null +++ b/src/components/ui/calendar/CalendarHeader.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/calendar/CalendarHeading.vue b/src/components/ui/calendar/CalendarHeading.vue new file mode 100644 index 0000000..f49bf3b --- /dev/null +++ b/src/components/ui/calendar/CalendarHeading.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/ui/calendar/CalendarNextButton.vue b/src/components/ui/calendar/CalendarNextButton.vue new file mode 100644 index 0000000..71030ad --- /dev/null +++ b/src/components/ui/calendar/CalendarNextButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/ui/calendar/CalendarPrevButton.vue b/src/components/ui/calendar/CalendarPrevButton.vue new file mode 100644 index 0000000..bfba161 --- /dev/null +++ b/src/components/ui/calendar/CalendarPrevButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/ui/calendar/index.ts b/src/components/ui/calendar/index.ts new file mode 100644 index 0000000..5239a1b --- /dev/null +++ b/src/components/ui/calendar/index.ts @@ -0,0 +1,12 @@ +export { default as Calendar } from './Calendar.vue' +export { default as CalendarCell } from './CalendarCell.vue' +export { default as CalendarCellTrigger } from './CalendarCellTrigger.vue' +export { default as CalendarGrid } from './CalendarGrid.vue' +export { default as CalendarGridBody } from './CalendarGridBody.vue' +export { default as CalendarGridHead } from './CalendarGridHead.vue' +export { default as CalendarGridRow } from './CalendarGridRow.vue' +export { default as CalendarHeadCell } from './CalendarHeadCell.vue' +export { default as CalendarHeader } from './CalendarHeader.vue' +export { default as CalendarHeading } from './CalendarHeading.vue' +export { default as CalendarNextButton } from './CalendarNextButton.vue' +export { default as CalendarPrevButton } from './CalendarPrevButton.vue' diff --git a/src/components/ui/popover/Popover.vue b/src/components/ui/popover/Popover.vue new file mode 100644 index 0000000..69afa77 --- /dev/null +++ b/src/components/ui/popover/Popover.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/components/ui/popover/PopoverAnchor.vue b/src/components/ui/popover/PopoverAnchor.vue new file mode 100644 index 0000000..e96a121 --- /dev/null +++ b/src/components/ui/popover/PopoverAnchor.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/components/ui/popover/PopoverContent.vue b/src/components/ui/popover/PopoverContent.vue new file mode 100644 index 0000000..860280f --- /dev/null +++ b/src/components/ui/popover/PopoverContent.vue @@ -0,0 +1,49 @@ + + + diff --git a/src/components/ui/popover/PopoverTrigger.vue b/src/components/ui/popover/PopoverTrigger.vue new file mode 100644 index 0000000..5ff67df --- /dev/null +++ b/src/components/ui/popover/PopoverTrigger.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/popover/index.ts b/src/components/ui/popover/index.ts new file mode 100644 index 0000000..d724e78 --- /dev/null +++ b/src/components/ui/popover/index.ts @@ -0,0 +1,4 @@ +export { default as Popover } from './Popover.vue' +export { default as PopoverAnchor } from './PopoverAnchor.vue' +export { default as PopoverContent } from './PopoverContent.vue' +export { default as PopoverTrigger } from './PopoverTrigger.vue' diff --git a/src/components/ui/range-calendar/RangeCalendar.vue b/src/components/ui/range-calendar/RangeCalendar.vue new file mode 100644 index 0000000..fc37098 --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendar.vue @@ -0,0 +1,91 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarCell.vue b/src/components/ui/range-calendar/RangeCalendarCell.vue new file mode 100644 index 0000000..f49016b --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarCellTrigger.vue b/src/components/ui/range-calendar/RangeCalendarCellTrigger.vue new file mode 100644 index 0000000..f3385fe --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarCellTrigger.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarGrid.vue b/src/components/ui/range-calendar/RangeCalendarGrid.vue new file mode 100644 index 0000000..aaa909e --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarGrid.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarGridBody.vue b/src/components/ui/range-calendar/RangeCalendarGridBody.vue new file mode 100644 index 0000000..52b6d3a --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarGridBody.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarGridHead.vue b/src/components/ui/range-calendar/RangeCalendarGridHead.vue new file mode 100644 index 0000000..0fe054d --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarGridHead.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarGridRow.vue b/src/components/ui/range-calendar/RangeCalendarGridRow.vue new file mode 100644 index 0000000..b90eb24 --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarGridRow.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarHeadCell.vue b/src/components/ui/range-calendar/RangeCalendarHeadCell.vue new file mode 100644 index 0000000..aa0c2f6 --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarHeadCell.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarHeader.vue b/src/components/ui/range-calendar/RangeCalendarHeader.vue new file mode 100644 index 0000000..9427a56 --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarHeader.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarHeading.vue b/src/components/ui/range-calendar/RangeCalendarHeading.vue new file mode 100644 index 0000000..27c24b2 --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarHeading.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarNextButton.vue b/src/components/ui/range-calendar/RangeCalendarNextButton.vue new file mode 100644 index 0000000..2bd0908 --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarNextButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/ui/range-calendar/RangeCalendarPrevButton.vue b/src/components/ui/range-calendar/RangeCalendarPrevButton.vue new file mode 100644 index 0000000..676ea0d --- /dev/null +++ b/src/components/ui/range-calendar/RangeCalendarPrevButton.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/ui/range-calendar/index.ts b/src/components/ui/range-calendar/index.ts new file mode 100644 index 0000000..7ba1637 --- /dev/null +++ b/src/components/ui/range-calendar/index.ts @@ -0,0 +1,12 @@ +export { default as RangeCalendar } from './RangeCalendar.vue' +export { default as RangeCalendarCell } from './RangeCalendarCell.vue' +export { default as RangeCalendarCellTrigger } from './RangeCalendarCellTrigger.vue' +export { default as RangeCalendarGrid } from './RangeCalendarGrid.vue' +export { default as RangeCalendarGridBody } from './RangeCalendarGridBody.vue' +export { default as RangeCalendarGridHead } from './RangeCalendarGridHead.vue' +export { default as RangeCalendarGridRow } from './RangeCalendarGridRow.vue' +export { default as RangeCalendarHeadCell } from './RangeCalendarHeadCell.vue' +export { default as RangeCalendarHeader } from './RangeCalendarHeader.vue' +export { default as RangeCalendarHeading } from './RangeCalendarHeading.vue' +export { default as RangeCalendarNextButton } from './RangeCalendarNextButton.vue' +export { default as RangeCalendarPrevButton } from './RangeCalendarPrevButton.vue' diff --git a/src/pages/tasks/[id].vue b/src/pages/tasks/[id].vue index 423aa14..30a0c20 100644 --- a/src/pages/tasks/[id].vue +++ b/src/pages/tasks/[id].vue @@ -1,17 +1,23 @@ diff --git a/src/components/range-picker.vue b/src/components/range-picker.vue index a995456..55d257d 100644 --- a/src/components/range-picker.vue +++ b/src/components/range-picker.vue @@ -7,15 +7,12 @@ import { PopoverContent, PopoverTrigger } from '~/components/ui/popover' -import { RangeCalendar } from '~/components/ui/range-calendar' import { type DateRange } from 'reka-ui' -import { - CalendarDate, - DateFormatter, - type DateValue, - getLocalTimeZone -} from '@internationalized/date' +import { ref, watch, type Ref } from 'vue' +import { useRoute, useRouter } from 'vue-router' import { CalendarIcon } from 'lucide-vue-next' +import { RangeCalendar } from '~/components/ui/range-calendar' +import { DateFormatter, getLocalTimeZone } from '@internationalized/date' const route = useRoute() const router = useRouter() diff --git a/src/components/sortable-arrow.vue b/src/components/sortable-arrow.vue new file mode 100644 index 0000000..9ac7c02 --- /dev/null +++ b/src/components/sortable-arrow.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/components/task-state.vue b/src/components/task-state.vue index 769f016..4585a4d 100644 --- a/src/components/task-state.vue +++ b/src/components/task-state.vue @@ -1,11 +1,14 @@ + + diff --git a/src/assets/css/main.css b/app/assets/css/main.css similarity index 100% rename from src/assets/css/main.css rename to app/assets/css/main.css diff --git a/src/components/header.vue b/app/components/header.vue similarity index 100% rename from src/components/header.vue rename to app/components/header.vue diff --git a/src/components/range-picker.vue b/app/components/range-picker.vue similarity index 100% rename from src/components/range-picker.vue rename to app/components/range-picker.vue diff --git a/src/components/sortable-arrow.vue b/app/components/sortable-arrow.vue similarity index 100% rename from src/components/sortable-arrow.vue rename to app/components/sortable-arrow.vue diff --git a/src/components/task-state.vue b/app/components/task-state.vue similarity index 91% rename from src/components/task-state.vue rename to app/components/task-state.vue index 4585a4d..74aed96 100644 --- a/src/components/task-state.vue +++ b/app/components/task-state.vue @@ -1,5 +1,5 @@ diff --git a/app/components/ui/button/index.ts b/app/components/ui/button/index.ts new file mode 100644 index 0000000..7779332 --- /dev/null +++ b/app/components/ui/button/index.ts @@ -0,0 +1,37 @@ +import type { VariantProps } from 'class-variance-authority' +import { cva } from 'class-variance-authority' + +export { default as Button } from './Button.vue' + +export const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: + 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: + 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', + link: 'text-primary underline-offset-4 hover:underline' + }, + size: { + default: 'h-9 px-4 py-2 has-[>svg]:px-3', + sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5', + lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', + icon: 'size-9', + 'icon-sm': 'size-8', + 'icon-lg': 'size-10' + } + }, + defaultVariants: { + variant: 'default', + size: 'default' + } + } +) +export type ButtonVariants = VariantProps diff --git a/src/components/ui/calendar/Calendar.vue b/app/components/ui/calendar/Calendar.vue similarity index 100% rename from src/components/ui/calendar/Calendar.vue rename to app/components/ui/calendar/Calendar.vue diff --git a/src/components/ui/calendar/CalendarCell.vue b/app/components/ui/calendar/CalendarCell.vue similarity index 100% rename from src/components/ui/calendar/CalendarCell.vue rename to app/components/ui/calendar/CalendarCell.vue diff --git a/src/components/ui/calendar/CalendarCellTrigger.vue b/app/components/ui/calendar/CalendarCellTrigger.vue similarity index 100% rename from src/components/ui/calendar/CalendarCellTrigger.vue rename to app/components/ui/calendar/CalendarCellTrigger.vue diff --git a/src/components/ui/calendar/CalendarGrid.vue b/app/components/ui/calendar/CalendarGrid.vue similarity index 100% rename from src/components/ui/calendar/CalendarGrid.vue rename to app/components/ui/calendar/CalendarGrid.vue diff --git a/src/components/ui/calendar/CalendarGridBody.vue b/app/components/ui/calendar/CalendarGridBody.vue similarity index 100% rename from src/components/ui/calendar/CalendarGridBody.vue rename to app/components/ui/calendar/CalendarGridBody.vue diff --git a/src/components/ui/calendar/CalendarGridHead.vue b/app/components/ui/calendar/CalendarGridHead.vue similarity index 100% rename from src/components/ui/calendar/CalendarGridHead.vue rename to app/components/ui/calendar/CalendarGridHead.vue diff --git a/src/components/ui/calendar/CalendarGridRow.vue b/app/components/ui/calendar/CalendarGridRow.vue similarity index 100% rename from src/components/ui/calendar/CalendarGridRow.vue rename to app/components/ui/calendar/CalendarGridRow.vue diff --git a/src/components/ui/calendar/CalendarHeadCell.vue b/app/components/ui/calendar/CalendarHeadCell.vue similarity index 100% rename from src/components/ui/calendar/CalendarHeadCell.vue rename to app/components/ui/calendar/CalendarHeadCell.vue diff --git a/src/components/ui/calendar/CalendarHeader.vue b/app/components/ui/calendar/CalendarHeader.vue similarity index 100% rename from src/components/ui/calendar/CalendarHeader.vue rename to app/components/ui/calendar/CalendarHeader.vue diff --git a/src/components/ui/calendar/CalendarHeading.vue b/app/components/ui/calendar/CalendarHeading.vue similarity index 100% rename from src/components/ui/calendar/CalendarHeading.vue rename to app/components/ui/calendar/CalendarHeading.vue diff --git a/src/components/ui/calendar/CalendarNextButton.vue b/app/components/ui/calendar/CalendarNextButton.vue similarity index 100% rename from src/components/ui/calendar/CalendarNextButton.vue rename to app/components/ui/calendar/CalendarNextButton.vue diff --git a/src/components/ui/calendar/CalendarPrevButton.vue b/app/components/ui/calendar/CalendarPrevButton.vue similarity index 100% rename from src/components/ui/calendar/CalendarPrevButton.vue rename to app/components/ui/calendar/CalendarPrevButton.vue diff --git a/src/components/ui/calendar/index.ts b/app/components/ui/calendar/index.ts similarity index 100% rename from src/components/ui/calendar/index.ts rename to app/components/ui/calendar/index.ts diff --git a/src/components/ui/card/Card.vue b/app/components/ui/card/Card.vue similarity index 100% rename from src/components/ui/card/Card.vue rename to app/components/ui/card/Card.vue diff --git a/src/components/ui/card/CardAction.vue b/app/components/ui/card/CardAction.vue similarity index 100% rename from src/components/ui/card/CardAction.vue rename to app/components/ui/card/CardAction.vue diff --git a/src/components/ui/card/CardContent.vue b/app/components/ui/card/CardContent.vue similarity index 100% rename from src/components/ui/card/CardContent.vue rename to app/components/ui/card/CardContent.vue diff --git a/src/components/ui/card/CardDescription.vue b/app/components/ui/card/CardDescription.vue similarity index 100% rename from src/components/ui/card/CardDescription.vue rename to app/components/ui/card/CardDescription.vue diff --git a/src/components/ui/card/CardFooter.vue b/app/components/ui/card/CardFooter.vue similarity index 100% rename from src/components/ui/card/CardFooter.vue rename to app/components/ui/card/CardFooter.vue diff --git a/src/components/ui/card/CardHeader.vue b/app/components/ui/card/CardHeader.vue similarity index 100% rename from src/components/ui/card/CardHeader.vue rename to app/components/ui/card/CardHeader.vue diff --git a/src/components/ui/card/CardTitle.vue b/app/components/ui/card/CardTitle.vue similarity index 100% rename from src/components/ui/card/CardTitle.vue rename to app/components/ui/card/CardTitle.vue diff --git a/src/components/ui/card/index.ts b/app/components/ui/card/index.ts similarity index 100% rename from src/components/ui/card/index.ts rename to app/components/ui/card/index.ts diff --git a/app/components/ui/checkbox/Checkbox.vue b/app/components/ui/checkbox/Checkbox.vue new file mode 100644 index 0000000..58e42f2 --- /dev/null +++ b/app/components/ui/checkbox/Checkbox.vue @@ -0,0 +1,34 @@ + + + diff --git a/app/components/ui/checkbox/index.ts b/app/components/ui/checkbox/index.ts new file mode 100644 index 0000000..3391a85 --- /dev/null +++ b/app/components/ui/checkbox/index.ts @@ -0,0 +1 @@ +export { default as Checkbox } from "./Checkbox.vue" diff --git a/app/components/ui/dialog/Dialog.vue b/app/components/ui/dialog/Dialog.vue new file mode 100644 index 0000000..ade5260 --- /dev/null +++ b/app/components/ui/dialog/Dialog.vue @@ -0,0 +1,19 @@ + + + diff --git a/app/components/ui/dialog/DialogClose.vue b/app/components/ui/dialog/DialogClose.vue new file mode 100644 index 0000000..c5fae04 --- /dev/null +++ b/app/components/ui/dialog/DialogClose.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/dialog/DialogContent.vue b/app/components/ui/dialog/DialogContent.vue new file mode 100644 index 0000000..7f86b47 --- /dev/null +++ b/app/components/ui/dialog/DialogContent.vue @@ -0,0 +1,53 @@ + + + diff --git a/app/components/ui/dialog/DialogDescription.vue b/app/components/ui/dialog/DialogDescription.vue new file mode 100644 index 0000000..f52e655 --- /dev/null +++ b/app/components/ui/dialog/DialogDescription.vue @@ -0,0 +1,23 @@ + + + diff --git a/app/components/ui/dialog/DialogFooter.vue b/app/components/ui/dialog/DialogFooter.vue new file mode 100644 index 0000000..0a936e6 --- /dev/null +++ b/app/components/ui/dialog/DialogFooter.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/dialog/DialogHeader.vue b/app/components/ui/dialog/DialogHeader.vue new file mode 100644 index 0000000..bfc3c64 --- /dev/null +++ b/app/components/ui/dialog/DialogHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/dialog/DialogOverlay.vue b/app/components/ui/dialog/DialogOverlay.vue new file mode 100644 index 0000000..7790077 --- /dev/null +++ b/app/components/ui/dialog/DialogOverlay.vue @@ -0,0 +1,21 @@ + + + diff --git a/app/components/ui/dialog/DialogScrollContent.vue b/app/components/ui/dialog/DialogScrollContent.vue new file mode 100644 index 0000000..f2475db --- /dev/null +++ b/app/components/ui/dialog/DialogScrollContent.vue @@ -0,0 +1,59 @@ + + + diff --git a/app/components/ui/dialog/DialogTitle.vue b/app/components/ui/dialog/DialogTitle.vue new file mode 100644 index 0000000..860f01a --- /dev/null +++ b/app/components/ui/dialog/DialogTitle.vue @@ -0,0 +1,23 @@ + + + diff --git a/app/components/ui/dialog/DialogTrigger.vue b/app/components/ui/dialog/DialogTrigger.vue new file mode 100644 index 0000000..49667e9 --- /dev/null +++ b/app/components/ui/dialog/DialogTrigger.vue @@ -0,0 +1,15 @@ + + + diff --git a/app/components/ui/dialog/index.ts b/app/components/ui/dialog/index.ts new file mode 100644 index 0000000..6768b09 --- /dev/null +++ b/app/components/ui/dialog/index.ts @@ -0,0 +1,10 @@ +export { default as Dialog } from "./Dialog.vue" +export { default as DialogClose } from "./DialogClose.vue" +export { default as DialogContent } from "./DialogContent.vue" +export { default as DialogDescription } from "./DialogDescription.vue" +export { default as DialogFooter } from "./DialogFooter.vue" +export { default as DialogHeader } from "./DialogHeader.vue" +export { default as DialogOverlay } from "./DialogOverlay.vue" +export { default as DialogScrollContent } from "./DialogScrollContent.vue" +export { default as DialogTitle } from "./DialogTitle.vue" +export { default as DialogTrigger } from "./DialogTrigger.vue" diff --git a/src/components/ui/dropdown-menu/DropdownMenu.vue b/app/components/ui/dropdown-menu/DropdownMenu.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenu.vue rename to app/components/ui/dropdown-menu/DropdownMenu.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue b/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue rename to app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuContent.vue b/app/components/ui/dropdown-menu/DropdownMenuContent.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuContent.vue rename to app/components/ui/dropdown-menu/DropdownMenuContent.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuGroup.vue b/app/components/ui/dropdown-menu/DropdownMenuGroup.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuGroup.vue rename to app/components/ui/dropdown-menu/DropdownMenuGroup.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuItem.vue b/app/components/ui/dropdown-menu/DropdownMenuItem.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuItem.vue rename to app/components/ui/dropdown-menu/DropdownMenuItem.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuLabel.vue b/app/components/ui/dropdown-menu/DropdownMenuLabel.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuLabel.vue rename to app/components/ui/dropdown-menu/DropdownMenuLabel.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue b/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue rename to app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue b/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue rename to app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue b/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuSeparator.vue rename to app/components/ui/dropdown-menu/DropdownMenuSeparator.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue b/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuShortcut.vue rename to app/components/ui/dropdown-menu/DropdownMenuShortcut.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuSub.vue b/app/components/ui/dropdown-menu/DropdownMenuSub.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuSub.vue rename to app/components/ui/dropdown-menu/DropdownMenuSub.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue b/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuSubContent.vue rename to app/components/ui/dropdown-menu/DropdownMenuSubContent.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue b/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue rename to app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue diff --git a/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue b/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue similarity index 100% rename from src/components/ui/dropdown-menu/DropdownMenuTrigger.vue rename to app/components/ui/dropdown-menu/DropdownMenuTrigger.vue diff --git a/src/components/ui/dropdown-menu/index.ts b/app/components/ui/dropdown-menu/index.ts similarity index 100% rename from src/components/ui/dropdown-menu/index.ts rename to app/components/ui/dropdown-menu/index.ts diff --git a/src/components/ui/input/Input.vue b/app/components/ui/input/Input.vue similarity index 100% rename from src/components/ui/input/Input.vue rename to app/components/ui/input/Input.vue diff --git a/src/components/ui/input/index.ts b/app/components/ui/input/index.ts similarity index 100% rename from src/components/ui/input/index.ts rename to app/components/ui/input/index.ts diff --git a/src/components/ui/popover/Popover.vue b/app/components/ui/popover/Popover.vue similarity index 100% rename from src/components/ui/popover/Popover.vue rename to app/components/ui/popover/Popover.vue diff --git a/src/components/ui/popover/PopoverAnchor.vue b/app/components/ui/popover/PopoverAnchor.vue similarity index 100% rename from src/components/ui/popover/PopoverAnchor.vue rename to app/components/ui/popover/PopoverAnchor.vue diff --git a/src/components/ui/popover/PopoverContent.vue b/app/components/ui/popover/PopoverContent.vue similarity index 100% rename from src/components/ui/popover/PopoverContent.vue rename to app/components/ui/popover/PopoverContent.vue diff --git a/src/components/ui/popover/PopoverTrigger.vue b/app/components/ui/popover/PopoverTrigger.vue similarity index 100% rename from src/components/ui/popover/PopoverTrigger.vue rename to app/components/ui/popover/PopoverTrigger.vue diff --git a/src/components/ui/popover/index.ts b/app/components/ui/popover/index.ts similarity index 100% rename from src/components/ui/popover/index.ts rename to app/components/ui/popover/index.ts diff --git a/src/components/ui/range-calendar/RangeCalendar.vue b/app/components/ui/range-calendar/RangeCalendar.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendar.vue rename to app/components/ui/range-calendar/RangeCalendar.vue diff --git a/src/components/ui/range-calendar/RangeCalendarCell.vue b/app/components/ui/range-calendar/RangeCalendarCell.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarCell.vue rename to app/components/ui/range-calendar/RangeCalendarCell.vue diff --git a/src/components/ui/range-calendar/RangeCalendarCellTrigger.vue b/app/components/ui/range-calendar/RangeCalendarCellTrigger.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarCellTrigger.vue rename to app/components/ui/range-calendar/RangeCalendarCellTrigger.vue diff --git a/src/components/ui/range-calendar/RangeCalendarGrid.vue b/app/components/ui/range-calendar/RangeCalendarGrid.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarGrid.vue rename to app/components/ui/range-calendar/RangeCalendarGrid.vue diff --git a/src/components/ui/range-calendar/RangeCalendarGridBody.vue b/app/components/ui/range-calendar/RangeCalendarGridBody.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarGridBody.vue rename to app/components/ui/range-calendar/RangeCalendarGridBody.vue diff --git a/src/components/ui/range-calendar/RangeCalendarGridHead.vue b/app/components/ui/range-calendar/RangeCalendarGridHead.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarGridHead.vue rename to app/components/ui/range-calendar/RangeCalendarGridHead.vue diff --git a/src/components/ui/range-calendar/RangeCalendarGridRow.vue b/app/components/ui/range-calendar/RangeCalendarGridRow.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarGridRow.vue rename to app/components/ui/range-calendar/RangeCalendarGridRow.vue diff --git a/src/components/ui/range-calendar/RangeCalendarHeadCell.vue b/app/components/ui/range-calendar/RangeCalendarHeadCell.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarHeadCell.vue rename to app/components/ui/range-calendar/RangeCalendarHeadCell.vue diff --git a/src/components/ui/range-calendar/RangeCalendarHeader.vue b/app/components/ui/range-calendar/RangeCalendarHeader.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarHeader.vue rename to app/components/ui/range-calendar/RangeCalendarHeader.vue diff --git a/src/components/ui/range-calendar/RangeCalendarHeading.vue b/app/components/ui/range-calendar/RangeCalendarHeading.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarHeading.vue rename to app/components/ui/range-calendar/RangeCalendarHeading.vue diff --git a/src/components/ui/range-calendar/RangeCalendarNextButton.vue b/app/components/ui/range-calendar/RangeCalendarNextButton.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarNextButton.vue rename to app/components/ui/range-calendar/RangeCalendarNextButton.vue diff --git a/src/components/ui/range-calendar/RangeCalendarPrevButton.vue b/app/components/ui/range-calendar/RangeCalendarPrevButton.vue similarity index 100% rename from src/components/ui/range-calendar/RangeCalendarPrevButton.vue rename to app/components/ui/range-calendar/RangeCalendarPrevButton.vue diff --git a/src/components/ui/range-calendar/index.ts b/app/components/ui/range-calendar/index.ts similarity index 100% rename from src/components/ui/range-calendar/index.ts rename to app/components/ui/range-calendar/index.ts diff --git a/src/components/ui/select/Select.vue b/app/components/ui/select/Select.vue similarity index 100% rename from src/components/ui/select/Select.vue rename to app/components/ui/select/Select.vue diff --git a/src/components/ui/select/SelectContent.vue b/app/components/ui/select/SelectContent.vue similarity index 100% rename from src/components/ui/select/SelectContent.vue rename to app/components/ui/select/SelectContent.vue diff --git a/src/components/ui/select/SelectGroup.vue b/app/components/ui/select/SelectGroup.vue similarity index 100% rename from src/components/ui/select/SelectGroup.vue rename to app/components/ui/select/SelectGroup.vue diff --git a/src/components/ui/select/SelectItem.vue b/app/components/ui/select/SelectItem.vue similarity index 100% rename from src/components/ui/select/SelectItem.vue rename to app/components/ui/select/SelectItem.vue diff --git a/src/components/ui/select/SelectItemText.vue b/app/components/ui/select/SelectItemText.vue similarity index 100% rename from src/components/ui/select/SelectItemText.vue rename to app/components/ui/select/SelectItemText.vue diff --git a/src/components/ui/select/SelectLabel.vue b/app/components/ui/select/SelectLabel.vue similarity index 100% rename from src/components/ui/select/SelectLabel.vue rename to app/components/ui/select/SelectLabel.vue diff --git a/src/components/ui/select/SelectScrollDownButton.vue b/app/components/ui/select/SelectScrollDownButton.vue similarity index 100% rename from src/components/ui/select/SelectScrollDownButton.vue rename to app/components/ui/select/SelectScrollDownButton.vue diff --git a/src/components/ui/select/SelectScrollUpButton.vue b/app/components/ui/select/SelectScrollUpButton.vue similarity index 100% rename from src/components/ui/select/SelectScrollUpButton.vue rename to app/components/ui/select/SelectScrollUpButton.vue diff --git a/src/components/ui/select/SelectSeparator.vue b/app/components/ui/select/SelectSeparator.vue similarity index 100% rename from src/components/ui/select/SelectSeparator.vue rename to app/components/ui/select/SelectSeparator.vue diff --git a/src/components/ui/select/SelectTrigger.vue b/app/components/ui/select/SelectTrigger.vue similarity index 100% rename from src/components/ui/select/SelectTrigger.vue rename to app/components/ui/select/SelectTrigger.vue diff --git a/src/components/ui/select/SelectValue.vue b/app/components/ui/select/SelectValue.vue similarity index 100% rename from src/components/ui/select/SelectValue.vue rename to app/components/ui/select/SelectValue.vue diff --git a/src/components/ui/select/index.ts b/app/components/ui/select/index.ts similarity index 100% rename from src/components/ui/select/index.ts rename to app/components/ui/select/index.ts diff --git a/src/components/ui/table/Table.vue b/app/components/ui/table/Table.vue similarity index 100% rename from src/components/ui/table/Table.vue rename to app/components/ui/table/Table.vue diff --git a/src/components/ui/table/TableBody.vue b/app/components/ui/table/TableBody.vue similarity index 100% rename from src/components/ui/table/TableBody.vue rename to app/components/ui/table/TableBody.vue diff --git a/src/components/ui/table/TableCaption.vue b/app/components/ui/table/TableCaption.vue similarity index 100% rename from src/components/ui/table/TableCaption.vue rename to app/components/ui/table/TableCaption.vue diff --git a/src/components/ui/table/TableCell.vue b/app/components/ui/table/TableCell.vue similarity index 100% rename from src/components/ui/table/TableCell.vue rename to app/components/ui/table/TableCell.vue diff --git a/src/components/ui/table/TableEmpty.vue b/app/components/ui/table/TableEmpty.vue similarity index 100% rename from src/components/ui/table/TableEmpty.vue rename to app/components/ui/table/TableEmpty.vue diff --git a/src/components/ui/table/TableFooter.vue b/app/components/ui/table/TableFooter.vue similarity index 100% rename from src/components/ui/table/TableFooter.vue rename to app/components/ui/table/TableFooter.vue diff --git a/src/components/ui/table/TableHead.vue b/app/components/ui/table/TableHead.vue similarity index 100% rename from src/components/ui/table/TableHead.vue rename to app/components/ui/table/TableHead.vue diff --git a/src/components/ui/table/TableHeader.vue b/app/components/ui/table/TableHeader.vue similarity index 100% rename from src/components/ui/table/TableHeader.vue rename to app/components/ui/table/TableHeader.vue diff --git a/src/components/ui/table/TableRow.vue b/app/components/ui/table/TableRow.vue similarity index 100% rename from src/components/ui/table/TableRow.vue rename to app/components/ui/table/TableRow.vue diff --git a/src/components/ui/table/index.ts b/app/components/ui/table/index.ts similarity index 100% rename from src/components/ui/table/index.ts rename to app/components/ui/table/index.ts diff --git a/src/components/ui/table/utils.ts b/app/components/ui/table/utils.ts similarity index 100% rename from src/components/ui/table/utils.ts rename to app/components/ui/table/utils.ts diff --git a/src/lib/utils.ts b/app/lib/utils.ts similarity index 100% rename from src/lib/utils.ts rename to app/lib/utils.ts diff --git a/app/pages/index.vue b/app/pages/index.vue new file mode 100644 index 0000000..f158c47 --- /dev/null +++ b/app/pages/index.vue @@ -0,0 +1,13 @@ + + diff --git a/src/pages/tasks/[id].vue b/app/pages/tasks/[id].vue similarity index 92% rename from src/pages/tasks/[id].vue rename to app/pages/tasks/[id].vue index cc0fd7c..00ef189 100644 --- a/src/pages/tasks/[id].vue +++ b/app/pages/tasks/[id].vue @@ -7,7 +7,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { useIntervalFn } from '@vueuse/core' import { useRoute, useRouter } from 'vue-router' import { useFetch } from '#imports' -import type { TaskSelect } from '~/server/db/schema' +import type { TaskSelect } from '~~/shared/db/schema' const route = useRoute() const router = useRouter() @@ -26,7 +26,7 @@ useIntervalFn(() => { const handleCopy = (value: string) => { copyToClipboard(value) - toast('Successfully copied', { + toast.success('Successfully copied', { description: 'The ID has been copied to your clipboard' }) } @@ -84,7 +84,13 @@ const handleCopy = (value: string) => { Return Value - {{ task.returnValue }} + + {{ + task.returnValue?.return_value + ? task.returnValue?.return_value + : 'null' + }} + Queued At diff --git a/src/pages/tasks/index.vue b/app/pages/tasks/index.vue similarity index 68% rename from src/pages/tasks/index.vue rename to app/pages/tasks/index.vue index f3cac04..4a04424 100644 --- a/src/pages/tasks/index.vue +++ b/app/pages/tasks/index.vue @@ -1,14 +1,15 @@ - diff --git a/src/public/favicon.ico b/src/public/favicon.ico deleted file mode 100644 index 18993ad91cfd43e03b074dd0b5cc3f37ab38e49c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmeHLOKuuL5PjK%MHWVi6lD zOGiREbCw`xmFozJ^aNatJY>w+g ze6a2@u~m#^BZm@8wco9#Crlli0uLb^3E$t2-WIc^#(?t)*@`UpuofJ(Uyh@F>b3Ph z$D^m8Xq~pTkGJ4Q`Q2)te3mgkWYZ^Ijq|hkiP^9`De={bQQ%heZC$QU2UpP(-tbl8 zPWD2abEew;oat@w`uP3J^YpsgT%~jT(Dk%oU}sa$7|n6hBjDj`+I;RX(>)%lm_7N{+B7Mu%H?422lE%MBJH!!YTN2oT7xr>>N-8OF$C&qU^ z>vLsa{$0X%q1fjOe3P1mCv#lN{xQ4_*HCSAZjTb1`}mlc+9rl8$B3OP%VT@mch_~G z7Y+4b{r>9e=M+7vSI;BgB?ryZDY4m>&wcHSn81VH1N~`0gvwH{ z8dv#hG|OK`>1;j7tM#B)Z7zDN?{6=dUal}$e Date: Tue, 2 Dec 2025 12:15:28 +0100 Subject: [PATCH 33/36] feat: add skeleton to the task info page --- app/components/ui/skeleton/Skeleton.vue | 17 +++ app/components/ui/skeleton/index.ts | 1 + app/pages/tasks/[id].vue | 164 +++++++++++++++++++----- 3 files changed, 150 insertions(+), 32 deletions(-) create mode 100644 app/components/ui/skeleton/Skeleton.vue create mode 100644 app/components/ui/skeleton/index.ts diff --git a/app/components/ui/skeleton/Skeleton.vue b/app/components/ui/skeleton/Skeleton.vue new file mode 100644 index 0000000..0dadcef --- /dev/null +++ b/app/components/ui/skeleton/Skeleton.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/components/ui/skeleton/index.ts b/app/components/ui/skeleton/index.ts new file mode 100644 index 0000000..e5ce72c --- /dev/null +++ b/app/components/ui/skeleton/index.ts @@ -0,0 +1 @@ +export { default as Skeleton } from "./Skeleton.vue" diff --git a/app/pages/tasks/[id].vue b/app/pages/tasks/[id].vue index 00ef189..e01b40b 100644 --- a/app/pages/tasks/[id].vue +++ b/app/pages/tasks/[id].vue @@ -1,9 +1,11 @@