From ac4e39ce706501622973adf4ddd0117238465351 Mon Sep 17 00:00:00 2001 From: faiztyanirh Date: Thu, 19 Feb 2026 17:04:37 +0700 Subject: [PATCH] initial dictionary test definition + calculation --- .../dictionary/contact/page/edit-page.svelte | 2 +- .../test/config/test-form-config.js | 58 ++++++- .../dictionary/test/page/create-page.svelte | 127 +++++++++++++- .../form/dictionary-form-renderer.svelte | 158 +++++++++++++++++- .../reusable/form/form-page-container.svelte | 5 +- .../components/topbar/topbar-wrapper.svelte | 2 +- src/lib/components/ui/tabs/index.js | 16 ++ .../components/ui/tabs/tabs-content.svelte | 17 ++ src/lib/components/ui/tabs/tabs-list.svelte | 20 +++ .../components/ui/tabs/tabs-trigger.svelte | 20 +++ src/lib/components/ui/tabs/tabs.svelte | 19 +++ 11 files changed, 422 insertions(+), 22 deletions(-) create mode 100644 src/lib/components/ui/tabs/index.js create mode 100644 src/lib/components/ui/tabs/tabs-content.svelte create mode 100644 src/lib/components/ui/tabs/tabs-list.svelte create mode 100644 src/lib/components/ui/tabs/tabs-trigger.svelte create mode 100644 src/lib/components/ui/tabs/tabs.svelte diff --git a/src/lib/components/dictionary/contact/page/edit-page.svelte b/src/lib/components/dictionary/contact/page/edit-page.svelte index 428ffd8..77af766 100644 --- a/src/lib/components/dictionary/contact/page/edit-page.svelte +++ b/src/lib/components/dictionary/contact/page/edit-page.svelte @@ -48,7 +48,7 @@ const option = detailFormState.selectOptions[fieldKey].find(opt => opt.value === value); return option?.label || value || "-"; } -$inspect(detailFormState.selectOptions) + $effect(() => { untrack(() => { formFields.forEach(group => { diff --git a/src/lib/components/dictionary/test/config/test-form-config.js b/src/lib/components/dictionary/test/config/test-form-config.js index 5d128c3..6b42102 100644 --- a/src/lib/components/dictionary/test/config/test-form-config.js +++ b/src/lib/components/dictionary/test/config/test-form-config.js @@ -34,8 +34,17 @@ export const testInitialForm = { Level: "", }; +export const testCalInitialForm = { + TestCalID: "", + TestSiteID: "", + FormulaInput: "", + FormulaCode: "" +} + export const testDefaultErrors = {}; +export const testCalDefaultErrors = {}; + export const testFormFields = [ { title: "Basic Information", @@ -75,8 +84,8 @@ export const testFormFields = [ key: "TestType", label: "Test Type", required: true, - type: "text", - validateOn: ["input"] + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/test_type`, } ] }, @@ -130,14 +139,14 @@ export const testFormFields = [ { key: "ResultType", label: "Result Type", - required: true, + required: false, type: "select", optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/result_type`, }, { key: "RefType", label: "Reference Type", - required: true, + required: false, type: "select", optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/reference_type`, } @@ -151,7 +160,8 @@ export const testFormFields = [ label: "Value Set", required: false, type: "select", - optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/service_classes`, + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/v_category`, + fullWidth: false }, ] }, @@ -170,6 +180,11 @@ export const testFormFields = [ required: false, type: "text", }, + ] + }, + { + type: "row", + columns: [ { key: "Unit2", label: "Unit 2", @@ -192,6 +207,7 @@ export const testFormFields = [ label: "Expected TAT", required: false, type: "select", + fullWidth: false }, ] }, @@ -299,6 +315,38 @@ export const testFormFields = [ }, ]; +export const testCalFormFields = [ + { + rows: [ + { + type: "row", + columns: [ + { + key: "FormulaInput", + label: "Input Parameter", + required: false, + type: "selectmultiple", + optionsEndpoint: `${API.BASE_URL}${API.TEST}`, + valueKey: "TestSiteID", + labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`, + }, + ] + }, + { + type: "row", + columns: [ + { + key: "FormulaCode", + label: "Formula", + required: false, + type: "textarea", + } + ] + }, + ] + }, +]; + export function getTestFormActions(handlers) { return [ { diff --git a/src/lib/components/dictionary/test/page/create-page.svelte b/src/lib/components/dictionary/test/page/create-page.svelte index b310016..4bff877 100644 --- a/src/lib/components/dictionary/test/page/create-page.svelte +++ b/src/lib/components/dictionary/test/page/create-page.svelte @@ -4,6 +4,9 @@ import DictionaryFormRenderer from "$lib/components/reusable/form/dictionary-form-renderer.svelte"; import { toast } from "svelte-sonner"; import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte"; + import * as Tabs from "$lib/components/ui/tabs/index.js"; + import { useForm } from "$lib/components/composable/use-form.svelte"; + import { testCalInitialForm, testCalDefaultErrors, testCalFormFields } from "$lib/components/dictionary/test/config/test-form-config"; let props = $props(); @@ -11,6 +14,16 @@ const { formState } = masterDetail; + const calFormState = useForm({ + schema: null, + initialForm: testCalInitialForm, + defaultErrors: {}, + mode: 'create', + modeOpt: 'default', + saveEndpoint: null, + editEndpoint: null, + }); + const helpers = useDictionaryForm(formState); const handlers = { @@ -38,14 +51,116 @@ }); const secondaryActions = []; + + // ================================================================== + + let availableTabs = $derived.by(() => { + const testType = formState?.form?.TestType; + + switch(testType) { + case 'TEST': + case 'PARAM': + return ['definition', 'map', 'reference']; + case 'CALC': + return ['definition', 'calculation', 'map', 'reference']; + case 'GROUP': + return ['definition', 'group']; + default: + return ['definition']; + } + }); + + let disabledResultTypes = $derived.by(() => { + const testType = formState?.form?.TestType; + + switch(testType) { + case 'TEST': + case 'PARAM': + return []; + case 'CALC': + return ['RANGE', 'TEXT', 'VSET', 'NORES']; + case 'GROUP': + return ['NMRIC', 'RANGE', 'TEXT', 'VSET', 'NORES']; + case 'TITLE': + return ['NMRIC', 'RANGE', 'TEXT', 'VSET', 'NORES']; + default: + return []; + } + }); + + let disabledReferenceTypes = $derived.by(() => { + const resultType = formState?.form?.ResultType; + + switch(resultType) { + case 'NMRIC': + return ['TEXT', 'VSET', 'NOREF']; + case 'RANGE': + return ['TEXT', 'VSET', 'NOREF']; + case 'TEXT': + return ['RANGE', 'THOLD', 'VSET', 'NOREF']; + case 'VSET': + return ['RANGE', 'THOLD', 'TEXT', 'NOREF']; + case 'NORES': + return ['RANGE', 'THOLD', 'TEXT', 'VSET']; + default: + return ['RANGE', 'THOLD', 'TEXT', 'VSET', 'NOREF']; + } + }); + + let activeTab = $state('definition'); + + $effect(() => { + if (!availableTabs.includes(activeTab)) { + activeTab = availableTabs[0]; + } + }); - - + + + + {#if availableTabs.includes('definition')} + Definition + {/if} + {#if availableTabs.includes('calculation')} + Calculation + {/if} + {#if availableTabs.includes('group')} + Group + {/if} + {#if availableTabs.includes('reference')} + Reference + {/if} + {#if availableTabs.includes('map')} + Map + {/if} + + + + + + + + + group + + + map + + + ref + + + { if (open && optionsEndpoint) { @@ -175,13 +205,132 @@ - None - {/if} {#each filteredOptions as option} - + {option.label} {/each} {/if} + {:else if type === "selectmultiple"} + {@const filteredOptions = getFilteredOptions(key)} + {@const selectedValues = Array.isArray(formState.form[key]) ? formState.form[key] : []} + {@const selectedOptions = selectedValues + .map(val => formState.selectOptions?.[key]?.find(opt => opt.value === val)) + .filter(Boolean)} + + { + formState.form[key] = vals; + if (validateOn?.includes("input")) { + formState.validateField?.(key, formState.form[key], false); + } + }} + onOpenChange={(open) => { + if (open && optionsEndpoint) { + formState.fetchOptions?.( + { key, optionsEndpoint, dependsOn, endpointParamKey, valueKey, labelKey }, + formState.form + ); + } + }} + > + + {#if selectedOptions.length === 0} + Choose + {:else} +
+ {#each selectedOptions as option} + + {option.label} + + {/each} +
+ {/if} +
+ +
+ +
+ {#if formState.loadingOptions?.[key]} + Loading... + {:else} + {#if !required} + - None - + {/if} + {#each filteredOptions as option} + + {option.label} + + {/each} + {/if} +
+
+ + {:else if type === "date"} {/snippet} -
{#each formFields as group}
diff --git a/src/lib/components/reusable/form/form-page-container.svelte b/src/lib/components/reusable/form/form-page-container.svelte index 927b591..8b71a7f 100644 --- a/src/lib/components/reusable/form/form-page-container.svelte +++ b/src/lib/components/reusable/form/form-page-container.svelte @@ -15,14 +15,11 @@ -
+
-
{@render children()}
- -