From 8e38b8f7e87a4a4811de0603876e35ab86d1e6c9 Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Tue, 11 Aug 2026 23:02:18 +0300 Subject: [PATCH] use explicit scheduling levels --- frontend/website/src/stores/schedules.ts | 2 +- frontend/website/src/stores/setLayout.ts | 9 +++ .../website/src/views/CreateScheduleView.vue | 56 ++++++++----------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/frontend/website/src/stores/schedules.ts b/frontend/website/src/stores/schedules.ts index d5b46a2..f8844e6 100644 --- a/frontend/website/src/stores/schedules.ts +++ b/frontend/website/src/stores/schedules.ts @@ -51,7 +51,7 @@ export type ScheduleSummary = z.infer export type ScheduleDetail = z.infer export type CreateScheduleInput = { setId: number - elementKind: string + levelId: number startDate: string targetDate: string } diff --git a/frontend/website/src/stores/setLayout.ts b/frontend/website/src/stores/setLayout.ts index 919c108..2b097c4 100644 --- a/frontend/website/src/stores/setLayout.ts +++ b/frontend/website/src/stores/setLayout.ts @@ -8,6 +8,7 @@ export const setElementNodeSchema = z.object({ id: z.number().int().positive(), name: z.string().min(1), kind: z.string().min(1), + levelId: z.number().int().positive(), get children() { return z.array(setElementNodeSchema) }, @@ -18,6 +19,14 @@ export const setLayoutResponseSchema = z.object({ id: z.number().int().positive(), name: z.string().min(1), }), + levels: z.array( + z.object({ + id: z.number().int().positive(), + kind: z.string().min(1), + depth: z.number().int().nonnegative(), + elementCount: z.number().int().nonnegative(), + }), + ), elements: z.array(setElementNodeSchema), }) diff --git a/frontend/website/src/views/CreateScheduleView.vue b/frontend/website/src/views/CreateScheduleView.vue index 84cc585..87c5e39 100644 --- a/frontend/website/src/views/CreateScheduleView.vue +++ b/frontend/website/src/views/CreateScheduleView.vue @@ -6,9 +6,9 @@ import { z } from 'zod' import AuthenticatedHeader from '@/components/AuthenticatedHeader.vue' import { useSchedulesStore } from '@/stores/schedules' -import { useSetLayoutStore, type SetElementNode } from '@/stores/setLayout' +import { useSetLayoutStore } from '@/stores/setLayout' -type ScheduleField = 'elementKind' | 'startDate' | 'targetDate' +type ScheduleField = 'levelId' | 'startDate' | 'targetDate' type ScheduleFieldErrors = Partial> const route = useRoute() @@ -19,34 +19,24 @@ const { layout, loading, error, notFound } = storeToRefs(setLayoutStore) const { creating, createError } = storeToRefs(schedulesStore) const currentSetId = ref(null) const form = reactive({ - elementKind: '', + levelId: null as number | null, startDate: '', targetDate: '', }) const fieldErrors = ref({}) -const levels = computed(() => { - const counts = new Map() - - function countNodes(nodes: SetElementNode[]): void { - for (const node of nodes) { - counts.set(node.kind, (counts.get(node.kind) ?? 0) + 1) - countNodes(node.children) - } - } - - countNodes(layout.value?.elements ?? []) - - return [...counts.entries()].map(([kind, count]) => ({ - kind, - count, - label: humanizeKind(kind), - })) -}) +const levels = computed(() => + (layout.value?.levels ?? []) + .filter((level) => level.elementCount > 0) + .map((level) => ({ + ...level, + label: humanizeKind(level.kind), + })), +) const scheduleFormSchema = z .object({ - elementKind: z.string().min(1, 'Choose a level to schedule.'), + levelId: z.number('Choose a level to schedule.').int().positive(), startDate: z.string().min(1, 'Choose a start date.'), targetDate: z.string().min(1, 'Choose a target date.'), }) @@ -82,7 +72,7 @@ async function submit(): Promise { for (const issue of result.error.issues) { const field = issue.path[0] if ( - (field === 'elementKind' || field === 'startDate' || field === 'targetDate') && + (field === 'levelId' || field === 'startDate' || field === 'targetDate') && errors[field] === undefined ) { errors[field] = issue.message @@ -95,10 +85,10 @@ async function submit(): Promise { if ( currentSetId.value === null || - !levels.value.some((level) => level.kind === result.data.elementKind) + !levels.value.some((level) => level.id === result.data.levelId) ) { fieldErrors.value = { - elementKind: 'Choose an available level to schedule.', + levelId: 'Choose an available level to schedule.', } return @@ -166,18 +156,18 @@ function humanizeKind(kind: string): string { -

- {{ fieldErrors.elementKind }} +

+ {{ fieldErrors.levelId }}