From e5cec38ac56c568df3f7e771328a88cda70e89cb Mon Sep 17 00:00:00 2001 From: "Calum H." Date: Sun, 15 Jun 2025 01:22:03 +0100 Subject: [PATCH] feat: move to modal --- .../components/ui/servers/ServerSidebar.vue | 26 +- .../scheduling/EditScheduledTaskModal.vue | 531 ++++++++++++++++++ .../composables/servers/modules/scheduling.ts | 79 ++- .../[id]/options/scheduling/[taskId].vue | 441 --------------- .../manage/[id]/options/scheduling/index.vue | 42 +- packages/ui/src/components/base/Chips.vue | 36 +- .../ui/src/components/base/TimePicker.vue | 69 ++- packages/ui/src/components/modal/NewModal.vue | 6 +- 8 files changed, 717 insertions(+), 513 deletions(-) create mode 100644 apps/frontend/src/components/ui/servers/scheduling/EditScheduledTaskModal.vue delete mode 100644 apps/frontend/src/pages/servers/manage/[id]/options/scheduling/[taskId].vue diff --git a/apps/frontend/src/components/ui/servers/ServerSidebar.vue b/apps/frontend/src/components/ui/servers/ServerSidebar.vue index c3edaab68..0c8c30e89 100644 --- a/apps/frontend/src/components/ui/servers/ServerSidebar.vue +++ b/apps/frontend/src/components/ui/servers/ServerSidebar.vue @@ -6,7 +6,7 @@
@@ -39,13 +39,33 @@ import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts"; const emit = defineEmits(["reinstall"]); -defineProps<{ - navLinks: { label: string; href: string; icon: Component; external?: boolean }[]; +const props = defineProps<{ + navLinks: { + label: string; + href: string; + icon: Component; + external?: boolean; + matches?: RegExp[]; + }[]; route: RouteLocationNormalized; server: ModrinthServer; backupInProgress?: BackupInProgressReason; }>(); +const isLinkActive = (link: (typeof props.navLinks)[0]) => { + if (props.route.path === link.href) { + return true; + } + + if (link.matches && link.matches.length > 0) { + return link.matches.some((regex: RegExp) => { + return regex.test(props.route.path); + }); + } + + return false; +}; + const onReinstall = (...args: any[]) => { emit("reinstall", ...args); }; diff --git a/apps/frontend/src/components/ui/servers/scheduling/EditScheduledTaskModal.vue b/apps/frontend/src/components/ui/servers/scheduling/EditScheduledTaskModal.vue new file mode 100644 index 000000000..ea785aac8 --- /dev/null +++ b/apps/frontend/src/components/ui/servers/scheduling/EditScheduledTaskModal.vue @@ -0,0 +1,531 @@ + + + + + diff --git a/apps/frontend/src/composables/servers/modules/scheduling.ts b/apps/frontend/src/composables/servers/modules/scheduling.ts index 491869e7d..e8c2cfbdf 100644 --- a/apps/frontend/src/composables/servers/modules/scheduling.ts +++ b/apps/frontend/src/composables/servers/modules/scheduling.ts @@ -5,41 +5,76 @@ import { ServerModule } from "./base.ts"; export class SchedulingModule extends ServerModule { tasks: ServerSchedule[] = []; + private optimisticUpdate(action: () => void): () => void { + const originalTasks = [...this.tasks]; + action(); + return () => { + this.tasks = originalTasks; + }; + } + async fetch(): Promise { - const response = await useServersFetch<{ items: ServerSchedule[] }>( - `servers/${this.serverId}/options/schedules`, + const response = await useServersFetch<{ schedules: { quota: 32; items: ServerSchedule[] } }>( + `servers/${this.serverId}/options`, { version: 1 }, ); - this.tasks = response.items; + this.tasks = response.schedules.items; } async deleteTask(task: ServerSchedule): Promise { - await useServersFetch(`servers/${this.serverId}/options/schedules/${task.id}`, { - method: "DELETE", - version: 1, + const rollback = this.optimisticUpdate(() => { + this.tasks = this.tasks.filter((t) => t.id !== task.id); }); - this.tasks = this.tasks.filter((t) => t.id !== task.id); + + try { + await useServersFetch(`servers/${this.serverId}/options/schedules/${task.id}`, { + method: "DELETE", + version: 1, + }); + } catch (error) { + rollback(); + throw error; + } } async createTask(task: Schedule): Promise { - const response = await useServersFetch<{ id: number }>( - `servers/${this.serverId}/options/schedules`, - { - method: "POST", - body: task, - version: 1, - }, - ); - await this.fetch(); - return response.id; + const rollback = this.optimisticUpdate(() => {}); + + try { + const response = await useServersFetch<{ id: number }>( + `servers/${this.serverId}/options/schedules`, + { + method: "POST", + body: task, + version: 1, + }, + ); + + this.tasks.push({ ...task, id: response.id } as ServerSchedule); + return response.id; + } catch (error) { + rollback(); + throw error; + } } async editTask(taskId: number, updatedTask: Partial): Promise { - await useServersFetch(`servers/${this.serverId}/options/schedules/${taskId}`, { - method: "PATCH", - body: updatedTask, - version: 1, + const rollback = this.optimisticUpdate(() => { + const taskIndex = this.tasks.findIndex((t) => t.id === taskId); + if (taskIndex !== -1) { + this.tasks[taskIndex] = { ...this.tasks[taskIndex], ...updatedTask }; + } }); - await this.fetch(); + + try { + await useServersFetch(`servers/${this.serverId}/options/schedules/${taskId}`, { + method: "PATCH", + body: updatedTask, + version: 1, + }); + } catch (error) { + rollback(); + throw error; + } } } diff --git a/apps/frontend/src/pages/servers/manage/[id]/options/scheduling/[taskId].vue b/apps/frontend/src/pages/servers/manage/[id]/options/scheduling/[taskId].vue deleted file mode 100644 index 51cc64da4..000000000 --- a/apps/frontend/src/pages/servers/manage/[id]/options/scheduling/[taskId].vue +++ /dev/null @@ -1,441 +0,0 @@ - - - diff --git a/apps/frontend/src/pages/servers/manage/[id]/options/scheduling/index.vue b/apps/frontend/src/pages/servers/manage/[id]/options/scheduling/index.vue index 7c305d061..f6ae44c2a 100644 --- a/apps/frontend/src/pages/servers/manage/[id]/options/scheduling/index.vue +++ b/apps/frontend/src/pages/servers/manage/[id]/options/scheduling/index.vue @@ -1,25 +1,20 @@