From 7f052986b3655c64f3b2729a0fb6b63c19f4e865 Mon Sep 17 00:00:00 2001 From: faiztyanirh Date: Thu, 16 Apr 2026 10:52:35 +0700 Subject: [PATCH] continue testmap -fix formSnapshot -add required & fix error state button -add equipment to testmap form -add confirmation before delete --- .../composable/use-master-detail.svelte.js | 13 +-- .../testmap/config/testmap-form-config.js | 30 ++++-- .../testmap/page/create-page.svelte | 99 ++++++++++++++----- .../dictionary/testmap/page/edit-page.svelte | 85 ++++++++++++---- src/lib/config/api.js | 1 + 5 files changed, 172 insertions(+), 56 deletions(-) diff --git a/src/lib/components/composable/use-master-detail.svelte.js b/src/lib/components/composable/use-master-detail.svelte.js index 46139ee..6f032ae 100644 --- a/src/lib/components/composable/use-master-detail.svelte.js +++ b/src/lib/components/composable/use-master-detail.svelte.js @@ -3,7 +3,7 @@ import { useForm } from "./use-form.svelte.js"; import { tick } from "svelte"; export function useMasterDetail(options = {}) { - const { onSelect = null, formConfig = null, extraState = [], } = options; + const { onSelect = null, formConfig = null, } = options; let selectedItem = $state(null); let mode = $state("view"); @@ -51,7 +51,6 @@ export function useMasterDetail(options = {}) { }); }); -$inspect(isDirty) async function select(item) { mode = "view"; @@ -76,20 +75,22 @@ $inspect(isDirty) selectedItem = null; formState.reset(); - for (const { reset } of extraState) { - reset?.(); + for (const item of extraRegistry) { + item.reset?.(); } if (initialData) { formState.setForm(initialData); } + await tick(); + formSnapshot = $state.snapshot(formState.form); + // extraSnapshots = extraRegistry.length > 0 ? Object.fromEntries( // extraRegistry.map(({ key, get }) => [key, $state.snapshot(get())]) // ) : {}; - - const extraSnapshots = extraRegistry.length > 0 + extraSnapshots = extraRegistry.length > 0 ? Object.fromEntries(extraRegistry.map(item => [item.key, $state.snapshot(item.get())])) : {}; } diff --git a/src/lib/components/dictionary/testmap/config/testmap-form-config.js b/src/lib/components/dictionary/testmap/config/testmap-form-config.js index d5c9f60..867ea56 100644 --- a/src/lib/components/dictionary/testmap/config/testmap-form-config.js +++ b/src/lib/components/dictionary/testmap/config/testmap-form-config.js @@ -5,8 +5,10 @@ import { cleanEmptyStrings } from '$lib/utils/cleanEmptyStrings'; export const testMapSchema = z .object({ - HostID: z.string().optional(), - ClientID: z.string().optional() + HostType: z.string().min(1, 'Required'), + HostID: z.string().min(1, 'Required'), + ClientType: z.string().min(1, 'Required'), + ClientID: z.string().min(1, 'Required'), }) // .superRefine((data, ctx) => { // const hostID = data.HostID; @@ -47,11 +49,15 @@ export const testMapDetailInitialForm = { } export const testMapDefaultErrors = { - HostID: null, - ClientID: null + HostType: 'Required', + HostID: 'Required', + ClientType: 'Required', + ClientID: 'Required', }; export const testMapDetailDefaultErrors = { + HostTestCode: 'Required', + ClientTestCode: 'Required', ConDefID: null, }; @@ -64,18 +70,20 @@ export const testMapFormFields = [ { key: 'HostType', label: 'Host Type', - required: false, + required: true, type: 'select', optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`, tabIndex: 1, + validateOn: ['input'] }, { key: 'ClientType', label: 'Client Type', - required: false, + required: true, type: 'select', optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`, tabIndex: 5, + validateOn: ['input'] } ] }, @@ -85,7 +93,7 @@ export const testMapFormFields = [ { key: 'HostID', label: 'Host ID', - required: false, + required: true, type: 'text', validateOn: ['input'], tabIndex: 2, @@ -93,7 +101,7 @@ export const testMapFormFields = [ { key: 'ClientID', label: 'Client ID', - required: false, + required: true, type: 'text', validateOn: ['input'], tabIndex: 6, @@ -113,16 +121,18 @@ export const testMapDetailFormFields = [ { key: 'HostTestCode', label: 'Host Test Code', - required: false, + required: true, type: 'text', tabIndex: 3, + validateOn: ['input'] }, { key: 'ClientTestCode', label: 'Client Test Code', - required: false, + required: true, type: 'text', tabIndex: 7, + validateOn: ['input'] } ] }, diff --git a/src/lib/components/dictionary/testmap/page/create-page.svelte b/src/lib/components/dictionary/testmap/page/create-page.svelte index dd01fd9..900b242 100644 --- a/src/lib/components/dictionary/testmap/page/create-page.svelte +++ b/src/lib/components/dictionary/testmap/page/create-page.svelte @@ -14,6 +14,7 @@ import { untrack } from "svelte"; import { API } from '$lib/config/api'; import { onMount } from "svelte"; + import * as Tooltip from "$lib/components/ui/tooltip/index.js"; let props = $props(); @@ -24,6 +25,8 @@ let editingId = $state(null); let idCounter = $state(0); let tempMap = $state([]); + let showDeleteConfirm = $state(false); + let selectedRow = $state({}); const testMapDetailFormState = useForm({ schema: testMapDetailSchema, @@ -166,6 +169,14 @@ valueKey: 'WorkstationID', labelKey: 'WorkstationName' }; + } else if (formState.form.HostType === 'INST') { + return { + ...col, + type: 'select', + optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`, + valueKey: 'EID', + labelKey: 'InstrumentName' + } } return { ...col, type: 'text', optionsEndpoint: undefined }; } @@ -195,6 +206,14 @@ valueKey: 'WorkstationID', labelKey: 'WorkstationName' }; + } else if (formState.form.ClientType === 'INST') { + return { + ...col, + type: 'select', + optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`, + valueKey: 'EID', + labelKey: 'InstrumentName' + } } return { ...col, type: 'text', optionsEndpoint: undefined }; } @@ -250,7 +269,7 @@ reset: () => { tempMap = []; idCounter = 0; editingId = null; }, }); }); - + $inspect(testMapDetailFormState.errors) @@ -259,11 +278,13 @@ formFields={mapFormFieldsTransformed} mode="create" /> - +
+ +
{#if editingId !== null} @@ -274,7 +295,8 @@ Cancel {:else} - {/if} @@ -312,22 +334,43 @@ {row.ConDefID}
- - + + + + + + +

Edit

+
+
+
+ + + + + + +

Delete

+
+
+
@@ -342,4 +385,14 @@ + + { + handleRemoveDetail(selectedRow.id); + }} /> \ No newline at end of file diff --git a/src/lib/components/dictionary/testmap/page/edit-page.svelte b/src/lib/components/dictionary/testmap/page/edit-page.svelte index 11e4b32..c218f57 100644 --- a/src/lib/components/dictionary/testmap/page/edit-page.svelte +++ b/src/lib/components/dictionary/testmap/page/edit-page.svelte @@ -15,6 +15,7 @@ import { API } from "$lib/config/api"; import { getChangedFields } from "$lib/utils/getChangedFields"; import { onMount } from "svelte"; + import * as Tooltip from "$lib/components/ui/tooltip/index.js"; let props = $props(); @@ -26,6 +27,8 @@ let idCounter = $state(0); let tempMap = $state([]); let deletedDetailIds = $state([]); + let showDeleteConfirm = $state(false); + let selectedRow = $state({}); const testMapDetailFormState = useForm({ schema: testMapDetailSchema, @@ -255,6 +258,14 @@ valueKey: 'WorkstationID', labelKey: 'WorkstationName' }; + } else if (formState.form.HostType === 'INST') { + return { + ...col, + type: 'select', + optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`, + valueKey: 'EID', + labelKey: 'InstrumentName' + } } return { ...col, type: 'text', optionsEndpoint: undefined }; } @@ -284,6 +295,14 @@ valueKey: 'WorkstationID', labelKey: 'WorkstationName' }; + } else if (formState.form.ClientType === 'INST') { + return { + ...col, + type: 'select', + optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`, + valueKey: 'EID', + labelKey: 'InstrumentName' + } } return { ...col, type: 'text', optionsEndpoint: undefined }; } @@ -383,7 +402,8 @@ Cancel {:else} - {/if} @@ -421,22 +441,43 @@ {row.ConDefID}
- - + + + + + + +

Edit

+
+
+
+ + + + + + +

Delete

+
+
+
@@ -451,4 +492,14 @@ + + { + handleRemoveDetail(selectedRow.id); + }} /> \ No newline at end of file diff --git a/src/lib/config/api.js b/src/lib/config/api.js index 58fd021..51812aa 100644 --- a/src/lib/config/api.js +++ b/src/lib/config/api.js @@ -27,4 +27,5 @@ export const API = { HOSTAPP: '/api/organization/hostapp', TEST: '/api/test', TESTMAP: '/api/test/testmap', + EQUIPMENT: '/api/equipmentlist' };