mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-24 18:18:07 +07:00
continue testmap
-fix formSnapshot -add required & fix error state button -add equipment to testmap form -add confirmation before delete
This commit is contained in:
parent
4ed048d734
commit
7f052986b3
@ -3,7 +3,7 @@ import { useForm } from "./use-form.svelte.js";
|
|||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
|
|
||||||
export function useMasterDetail(options = {}) {
|
export function useMasterDetail(options = {}) {
|
||||||
const { onSelect = null, formConfig = null, extraState = [], } = options;
|
const { onSelect = null, formConfig = null, } = options;
|
||||||
|
|
||||||
let selectedItem = $state(null);
|
let selectedItem = $state(null);
|
||||||
let mode = $state("view");
|
let mode = $state("view");
|
||||||
@ -51,7 +51,6 @@ export function useMasterDetail(options = {}) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$inspect(isDirty)
|
|
||||||
async function select(item) {
|
async function select(item) {
|
||||||
mode = "view";
|
mode = "view";
|
||||||
|
|
||||||
@ -76,20 +75,22 @@ $inspect(isDirty)
|
|||||||
selectedItem = null;
|
selectedItem = null;
|
||||||
formState.reset();
|
formState.reset();
|
||||||
|
|
||||||
for (const { reset } of extraState) {
|
for (const item of extraRegistry) {
|
||||||
reset?.();
|
item.reset?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initialData) {
|
if (initialData) {
|
||||||
formState.setForm(initialData);
|
formState.setForm(initialData);
|
||||||
}
|
}
|
||||||
|
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
formSnapshot = $state.snapshot(formState.form);
|
formSnapshot = $state.snapshot(formState.form);
|
||||||
|
|
||||||
// extraSnapshots = extraRegistry.length > 0 ? Object.fromEntries(
|
// extraSnapshots = extraRegistry.length > 0 ? Object.fromEntries(
|
||||||
// extraRegistry.map(({ key, get }) => [key, $state.snapshot(get())])
|
// extraRegistry.map(({ key, get }) => [key, $state.snapshot(get())])
|
||||||
// ) : {};
|
// ) : {};
|
||||||
|
extraSnapshots = extraRegistry.length > 0
|
||||||
const extraSnapshots = extraRegistry.length > 0
|
|
||||||
? Object.fromEntries(extraRegistry.map(item => [item.key, $state.snapshot(item.get())]))
|
? Object.fromEntries(extraRegistry.map(item => [item.key, $state.snapshot(item.get())]))
|
||||||
: {};
|
: {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,10 @@ import { cleanEmptyStrings } from '$lib/utils/cleanEmptyStrings';
|
|||||||
|
|
||||||
export const testMapSchema = z
|
export const testMapSchema = z
|
||||||
.object({
|
.object({
|
||||||
HostID: z.string().optional(),
|
HostType: z.string().min(1, 'Required'),
|
||||||
ClientID: z.string().optional()
|
HostID: z.string().min(1, 'Required'),
|
||||||
|
ClientType: z.string().min(1, 'Required'),
|
||||||
|
ClientID: z.string().min(1, 'Required'),
|
||||||
})
|
})
|
||||||
// .superRefine((data, ctx) => {
|
// .superRefine((data, ctx) => {
|
||||||
// const hostID = data.HostID;
|
// const hostID = data.HostID;
|
||||||
@ -47,11 +49,15 @@ export const testMapDetailInitialForm = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const testMapDefaultErrors = {
|
export const testMapDefaultErrors = {
|
||||||
HostID: null,
|
HostType: 'Required',
|
||||||
ClientID: null
|
HostID: 'Required',
|
||||||
|
ClientType: 'Required',
|
||||||
|
ClientID: 'Required',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const testMapDetailDefaultErrors = {
|
export const testMapDetailDefaultErrors = {
|
||||||
|
HostTestCode: 'Required',
|
||||||
|
ClientTestCode: 'Required',
|
||||||
ConDefID: null,
|
ConDefID: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -64,18 +70,20 @@ export const testMapFormFields = [
|
|||||||
{
|
{
|
||||||
key: 'HostType',
|
key: 'HostType',
|
||||||
label: 'Host Type',
|
label: 'Host Type',
|
||||||
required: false,
|
required: true,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`,
|
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`,
|
||||||
tabIndex: 1,
|
tabIndex: 1,
|
||||||
|
validateOn: ['input']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'ClientType',
|
key: 'ClientType',
|
||||||
label: 'Client Type',
|
label: 'Client Type',
|
||||||
required: false,
|
required: true,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`,
|
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/entity_type`,
|
||||||
tabIndex: 5,
|
tabIndex: 5,
|
||||||
|
validateOn: ['input']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -85,7 +93,7 @@ export const testMapFormFields = [
|
|||||||
{
|
{
|
||||||
key: 'HostID',
|
key: 'HostID',
|
||||||
label: 'Host ID',
|
label: 'Host ID',
|
||||||
required: false,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
validateOn: ['input'],
|
validateOn: ['input'],
|
||||||
tabIndex: 2,
|
tabIndex: 2,
|
||||||
@ -93,7 +101,7 @@ export const testMapFormFields = [
|
|||||||
{
|
{
|
||||||
key: 'ClientID',
|
key: 'ClientID',
|
||||||
label: 'Client ID',
|
label: 'Client ID',
|
||||||
required: false,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
validateOn: ['input'],
|
validateOn: ['input'],
|
||||||
tabIndex: 6,
|
tabIndex: 6,
|
||||||
@ -113,16 +121,18 @@ export const testMapDetailFormFields = [
|
|||||||
{
|
{
|
||||||
key: 'HostTestCode',
|
key: 'HostTestCode',
|
||||||
label: 'Host Test Code',
|
label: 'Host Test Code',
|
||||||
required: false,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
tabIndex: 3,
|
tabIndex: 3,
|
||||||
|
validateOn: ['input']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'ClientTestCode',
|
key: 'ClientTestCode',
|
||||||
label: 'Client Test Code',
|
label: 'Client Test Code',
|
||||||
required: false,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
tabIndex: 7,
|
tabIndex: 7,
|
||||||
|
validateOn: ['input']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
import { untrack } from "svelte";
|
import { untrack } from "svelte";
|
||||||
import { API } from '$lib/config/api';
|
import { API } from '$lib/config/api';
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
import * as Tooltip from "$lib/components/ui/tooltip/index.js";
|
||||||
|
|
||||||
let props = $props();
|
let props = $props();
|
||||||
|
|
||||||
@ -24,6 +25,8 @@
|
|||||||
let editingId = $state(null);
|
let editingId = $state(null);
|
||||||
let idCounter = $state(0);
|
let idCounter = $state(0);
|
||||||
let tempMap = $state([]);
|
let tempMap = $state([]);
|
||||||
|
let showDeleteConfirm = $state(false);
|
||||||
|
let selectedRow = $state({});
|
||||||
|
|
||||||
const testMapDetailFormState = useForm({
|
const testMapDetailFormState = useForm({
|
||||||
schema: testMapDetailSchema,
|
schema: testMapDetailSchema,
|
||||||
@ -166,6 +169,14 @@
|
|||||||
valueKey: 'WorkstationID',
|
valueKey: 'WorkstationID',
|
||||||
labelKey: 'WorkstationName'
|
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 };
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
||||||
}
|
}
|
||||||
@ -195,6 +206,14 @@
|
|||||||
valueKey: 'WorkstationID',
|
valueKey: 'WorkstationID',
|
||||||
labelKey: 'WorkstationName'
|
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 };
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
||||||
}
|
}
|
||||||
@ -250,7 +269,7 @@
|
|||||||
reset: () => { tempMap = []; idCounter = 0; editingId = null; },
|
reset: () => { tempMap = []; idCounter = 0; editingId = null; },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
$inspect(testMapDetailFormState.errors)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormPageContainer title="Create Test Map" {primaryAction} {secondaryActions} {actions}>
|
<FormPageContainer title="Create Test Map" {primaryAction} {secondaryActions} {actions}>
|
||||||
@ -259,11 +278,13 @@
|
|||||||
formFields={mapFormFieldsTransformed}
|
formFields={mapFormFieldsTransformed}
|
||||||
mode="create"
|
mode="create"
|
||||||
/>
|
/>
|
||||||
<DictionaryFormRenderer
|
<div class="mt-2">
|
||||||
formState={testMapDetailFormState}
|
<DictionaryFormRenderer
|
||||||
formFields={mapDetailFormFieldsTransformed}
|
formState={testMapDetailFormState}
|
||||||
mode="create"
|
formFields={mapDetailFormFieldsTransformed}
|
||||||
/>
|
mode="create"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex gap-2 mt-1 ms-2">
|
<div class="flex gap-2 mt-1 ms-2">
|
||||||
{#if editingId !== null}
|
{#if editingId !== null}
|
||||||
@ -274,7 +295,8 @@
|
|||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<Button size="sm" class="cursor-pointer" onclick={handleInsertDetail}>
|
<Button size="sm" class="cursor-pointer" onclick={handleInsertDetail}
|
||||||
|
disabled={Object.values(testMapDetailFormState.errors).some(v => v !== null)}>
|
||||||
Insert
|
Insert
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
@ -312,22 +334,43 @@
|
|||||||
<Table.Cell>{row.ConDefID}</Table.Cell>
|
<Table.Cell>{row.ConDefID}</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<Button
|
<Tooltip.Provider>
|
||||||
size="icon"
|
<Tooltip.Root>
|
||||||
variant="ghost"
|
<Tooltip.Trigger>
|
||||||
class="h-7 w-7 cursor-pointer"
|
<Button
|
||||||
onclick={() => handleEditDetail(row)}
|
size="icon"
|
||||||
>
|
variant="outline"
|
||||||
<PencilIcon class="h-3.5 w-3.5" />
|
class="h-7 w-7 cursor-pointer"
|
||||||
</Button>
|
onclick={() => handleEditDetail(row)}
|
||||||
<Button
|
>
|
||||||
size="icon"
|
<PencilIcon class="h-3.5 w-3.5" />
|
||||||
variant="ghost"
|
</Button>
|
||||||
class="h-7 w-7 cursor-pointer"
|
</Tooltip.Trigger>
|
||||||
onclick={() => handleRemoveDetail(row.id)}
|
<Tooltip.Content>
|
||||||
>
|
<p>Edit</p>
|
||||||
<Trash2Icon class="h-3.5 w-3.5" />
|
</Tooltip.Content>
|
||||||
</Button>
|
</Tooltip.Root>
|
||||||
|
</Tooltip.Provider>
|
||||||
|
<Tooltip.Provider>
|
||||||
|
<Tooltip.Root>
|
||||||
|
<Tooltip.Trigger>
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
variant="outline"
|
||||||
|
class="h-7 w-7 cursor-pointer"
|
||||||
|
onclick={() => {
|
||||||
|
selectedRow = row;
|
||||||
|
showDeleteConfirm = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2Icon class="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip.Trigger>
|
||||||
|
<Tooltip.Content>
|
||||||
|
<p>Delete</p>
|
||||||
|
</Tooltip.Content>
|
||||||
|
</Tooltip.Root>
|
||||||
|
</Tooltip.Provider>
|
||||||
</div>
|
</div>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
@ -342,4 +385,14 @@
|
|||||||
<ReusableAlertDialog
|
<ReusableAlertDialog
|
||||||
bind:open={masterDetail.showExitConfirm}
|
bind:open={masterDetail.showExitConfirm}
|
||||||
onConfirm={masterDetail.confirmExit}
|
onConfirm={masterDetail.confirmExit}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ReusableAlertDialog
|
||||||
|
bind:open={showDeleteConfirm}
|
||||||
|
title="Delete Test Code?"
|
||||||
|
description="Are you sure you want to disable this test code ({selectedRow.HostTestCode})?"
|
||||||
|
confirmText="Delete"
|
||||||
|
onConfirm={() => {
|
||||||
|
handleRemoveDetail(selectedRow.id);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
@ -15,6 +15,7 @@
|
|||||||
import { API } from "$lib/config/api";
|
import { API } from "$lib/config/api";
|
||||||
import { getChangedFields } from "$lib/utils/getChangedFields";
|
import { getChangedFields } from "$lib/utils/getChangedFields";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
import * as Tooltip from "$lib/components/ui/tooltip/index.js";
|
||||||
|
|
||||||
let props = $props();
|
let props = $props();
|
||||||
|
|
||||||
@ -26,6 +27,8 @@
|
|||||||
let idCounter = $state(0);
|
let idCounter = $state(0);
|
||||||
let tempMap = $state([]);
|
let tempMap = $state([]);
|
||||||
let deletedDetailIds = $state([]);
|
let deletedDetailIds = $state([]);
|
||||||
|
let showDeleteConfirm = $state(false);
|
||||||
|
let selectedRow = $state({});
|
||||||
|
|
||||||
const testMapDetailFormState = useForm({
|
const testMapDetailFormState = useForm({
|
||||||
schema: testMapDetailSchema,
|
schema: testMapDetailSchema,
|
||||||
@ -255,6 +258,14 @@
|
|||||||
valueKey: 'WorkstationID',
|
valueKey: 'WorkstationID',
|
||||||
labelKey: 'WorkstationName'
|
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 };
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
||||||
}
|
}
|
||||||
@ -284,6 +295,14 @@
|
|||||||
valueKey: 'WorkstationID',
|
valueKey: 'WorkstationID',
|
||||||
labelKey: 'WorkstationName'
|
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 };
|
return { ...col, type: 'text', optionsEndpoint: undefined };
|
||||||
}
|
}
|
||||||
@ -383,7 +402,8 @@
|
|||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<Button size="sm" class="cursor-pointer" onclick={handleInsertDetail}>
|
<Button size="sm" class="cursor-pointer" onclick={handleInsertDetail}
|
||||||
|
disabled={Object.values(testMapDetailFormState.errors).some(v => v !== null)}>
|
||||||
Insert
|
Insert
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
@ -421,22 +441,43 @@
|
|||||||
<Table.Cell>{row.ConDefID}</Table.Cell>
|
<Table.Cell>{row.ConDefID}</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<Button
|
<Tooltip.Provider>
|
||||||
size="icon"
|
<Tooltip.Root>
|
||||||
variant="ghost"
|
<Tooltip.Trigger>
|
||||||
class="h-7 w-7 cursor-pointer"
|
<Button
|
||||||
onclick={() => handleEditDetail(row)}
|
size="icon"
|
||||||
>
|
variant="outline"
|
||||||
<PencilIcon class="h-3.5 w-3.5" />
|
class="h-7 w-7 cursor-pointer"
|
||||||
</Button>
|
onclick={() => handleEditDetail(row)}
|
||||||
<Button
|
>
|
||||||
size="icon"
|
<PencilIcon class="h-3.5 w-3.5" />
|
||||||
variant="ghost"
|
</Button>
|
||||||
class="h-7 w-7 cursor-pointer"
|
</Tooltip.Trigger>
|
||||||
onclick={() => handleRemoveDetail(row.id)}
|
<Tooltip.Content>
|
||||||
>
|
<p>Edit</p>
|
||||||
<Trash2Icon class="h-3.5 w-3.5" />
|
</Tooltip.Content>
|
||||||
</Button>
|
</Tooltip.Root>
|
||||||
|
</Tooltip.Provider>
|
||||||
|
<Tooltip.Provider>
|
||||||
|
<Tooltip.Root>
|
||||||
|
<Tooltip.Trigger>
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
variant="outline"
|
||||||
|
class="h-7 w-7 cursor-pointer"
|
||||||
|
onclick={() => {
|
||||||
|
selectedRow = row;
|
||||||
|
showDeleteConfirm = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2Icon class="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip.Trigger>
|
||||||
|
<Tooltip.Content>
|
||||||
|
<p>Delete</p>
|
||||||
|
</Tooltip.Content>
|
||||||
|
</Tooltip.Root>
|
||||||
|
</Tooltip.Provider>
|
||||||
</div>
|
</div>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
@ -451,4 +492,14 @@
|
|||||||
<ReusableAlertDialog
|
<ReusableAlertDialog
|
||||||
bind:open={masterDetail.showExitConfirm}
|
bind:open={masterDetail.showExitConfirm}
|
||||||
onConfirm={masterDetail.confirmExit}
|
onConfirm={masterDetail.confirmExit}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ReusableAlertDialog
|
||||||
|
bind:open={showDeleteConfirm}
|
||||||
|
title="Delete Test Code?"
|
||||||
|
description="Are you sure you want to disable this test code ({selectedRow.HostTestCode})?"
|
||||||
|
confirmText="Delete"
|
||||||
|
onConfirm={() => {
|
||||||
|
handleRemoveDetail(selectedRow.id);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
@ -27,4 +27,5 @@ export const API = {
|
|||||||
HOSTAPP: '/api/organization/hostapp',
|
HOSTAPP: '/api/organization/hostapp',
|
||||||
TEST: '/api/test',
|
TEST: '/api/test',
|
||||||
TESTMAP: '/api/test/testmap',
|
TESTMAP: '/api/test/testmap',
|
||||||
|
EQUIPMENT: '/api/equipmentlist'
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user