@ramathibodi/nuxt-commons 0.1.56 → 0.1.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/document/TemplateBuilder.vue +133 -122
  3. package/dist/runtime/components/form/Pad.vue +39 -0
  4. package/dist/runtime/components/form/TableData.vue +180 -41
  5. package/dist/runtime/components/label/DateCount.vue +40 -0
  6. package/dist/runtime/components/label/Object.vue +14 -0
  7. package/dist/runtime/components/master/Autocomplete.vue +25 -108
  8. package/dist/runtime/components/master/Combobox.vue +59 -83
  9. package/dist/runtime/components/model/Autocomplete.vue +23 -234
  10. package/dist/runtime/components/model/Combobox.vue +70 -0
  11. package/dist/runtime/composables/document/template.d.ts +4 -1
  12. package/dist/runtime/composables/document/template.js +22 -15
  13. package/dist/runtime/composables/document/templateFormHidden.d.ts +1 -1
  14. package/dist/runtime/composables/document/templateFormHidden.js +5 -2
  15. package/dist/runtime/composables/document/templateFormTable.d.ts +3 -2
  16. package/dist/runtime/composables/document/templateFormTable.js +36 -40
  17. package/dist/runtime/composables/document/templateFormTableData.d.ts +2 -0
  18. package/dist/runtime/composables/document/templateFormTableData.js +21 -0
  19. package/dist/runtime/composables/graphqlModel.d.ts +6 -6
  20. package/dist/runtime/composables/graphqlModelItem.d.ts +4 -4
  21. package/dist/runtime/composables/graphqlModelOperation.d.ts +6 -6
  22. package/dist/runtime/composables/lookupList.d.ts +44 -0
  23. package/dist/runtime/composables/lookupList.js +194 -0
  24. package/dist/runtime/composables/lookupListMaster.d.ts +28 -0
  25. package/dist/runtime/composables/lookupListMaster.js +61 -0
  26. package/dist/runtime/types/menu.d.ts +7 -4
  27. package/dist/runtime/utils/formatter.d.ts +1 -0
  28. package/dist/runtime/utils/formatter.js +19 -0
  29. package/dist/runtime/utils/object.d.ts +1 -0
  30. package/dist/runtime/utils/object.js +46 -1
  31. package/package.json +2 -1
@@ -0,0 +1,70 @@
1
+ <script lang="ts" setup>
2
+ import { VCombobox } from 'vuetify/components/VCombobox'
3
+ import { defineModel, withDefaults } from 'vue'
4
+ import { useLookupList, type LookupProps } from '../../composables/lookupList'
5
+
6
+ interface Props extends /* @vue-ignore */ InstanceType<typeof VCombobox['$props']> {}
7
+
8
+ const props = withDefaults(defineProps<Props & LookupProps>(), {
9
+ fuzzy: false,
10
+ showCode: false,
11
+ cache: false,
12
+ serverSearch: false,
13
+ searchSearchSort: false,
14
+ serverSearchText: 'Type to search…',
15
+ serverSearchLoadingText: 'Searching…',
16
+ serverSearchDebounce: 500,
17
+ })
18
+
19
+ const emit = defineEmits<{
20
+ (e: 'update:selectedObject', object: any | any[]): void
21
+ }>()
22
+
23
+ const selectedItems = defineModel<any>()
24
+
25
+ const {
26
+ searchData,
27
+ computedItems,
28
+ computedFilterKeys,
29
+ computedPlaceholder,
30
+ computedNoDataText,
31
+ isLoading,
32
+ isErrorLoading,
33
+ } = useLookupList(props, emit, selectedItems)
34
+ </script>
35
+
36
+ <template>
37
+ <v-combobox
38
+ v-model="selectedItems"
39
+ v-model:search="searchData"
40
+ v-bind="$attrs"
41
+ :items="computedItems"
42
+ :filter-keys="computedFilterKeys"
43
+ :no-filter="props.fuzzy || props.serverSearch"
44
+ :item-title="props.itemTitle"
45
+ :item-value="props.itemValue"
46
+ :loading="isLoading"
47
+ :placeholder="computedPlaceholder"
48
+ :no-data-text="computedNoDataText"
49
+ :multiple="props.multiple"
50
+ :return-object="false"
51
+ >
52
+ <!-- passthrough slots -->
53
+ <!-- @ts-ignore -->
54
+ <template v-for="(_, name, index) in ($slots as {})" :key="index" #[name]="slotData">
55
+ <slot :name="name" v-bind="((slotData || {}) as object)" />
56
+ </template>
57
+
58
+ <template v-if="!$slots.item" #item="{ props: itemProps, item }">
59
+ <v-list-item v-bind="itemProps" :title="(props.showCode ? item.value + '-' : '') + item.title" />
60
+ </template>
61
+
62
+ <template v-if="!$slots.selection && props.showCode" #selection="{ item }">
63
+ {{ item.value + '-' + item.title }}
64
+ </template>
65
+
66
+ <template v-if="isErrorLoading" #append>
67
+ <v-icon color="error">mdi mdi-alert</v-icon>
68
+ </template>
69
+ </v-combobox>
70
+ </template>
@@ -11,6 +11,8 @@ export interface DocumentTemplateItem {
11
11
  conditionalDisplay?: string;
12
12
  computedValue?: string;
13
13
  retrievedValue?: string;
14
+ customClass?: string;
15
+ customStyle?: string;
14
16
  }
15
17
  export interface ChoiceItem {
16
18
  label: string;
@@ -18,7 +20,8 @@ export interface ChoiceItem {
18
20
  }
19
21
  export declare const validationRulesRegex: RegExp;
20
22
  export declare function useDocumentTemplate(items: string | object, parentTemplates?: string | string[]): string;
23
+ export declare function templateItemToString(inputItem: DocumentTemplateItem, parentTemplates: string | string[], dataVariable?: string): string;
21
24
  export declare function optionStringToChoiceObject(option: string | object): ChoiceItem[];
22
25
  export declare function escapeObjectForInlineBinding(obj: object): string;
23
26
  export declare function buildValidationRules(validationString: string): string;
24
- export declare function processDefaultTemplate(item: DocumentTemplateItem, insideTemplate?: string, optionString?: string, validationRules?: string): string;
27
+ export declare function processDefaultTemplate(item: DocumentTemplateItem, insideTemplate?: string, optionString?: string, validationRules?: string, dataVariable?: string): string;
@@ -1,6 +1,7 @@
1
- import { processTemplateFormTable, processTemplateFormTableData } from "./templateFormTable.js";
1
+ import { processTemplateFormTable } from "./templateFormTable.js";
2
+ import { processTemplateFormTableData } from "./templateFormTableData.js";
2
3
  import { processTemplateFormHidden } from "./templateFormHidden.js";
3
- import { some, includes } from "lodash-es";
4
+ import { some, includes, cloneDeep } from "lodash-es";
4
5
  export const validationRulesRegex = /^(require(?:\([^)]*\))?|requireIf\([^)]*\)|requireTrue(?:\([^)]*\))?|requireTrueIf\([^)]*\)|numeric(?:\([^)]*\))?|range\([^)]*\)|integer(?:\([^)]*\))?|unique\([^)]*\)|length(?:\([^)]*\))?|lengthGreater\([^)]*\)|lengthLess\([^)]*\)|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex\([^)]*\)|idcard(?:\([^)]*\))?|DateFuture(?:\([^)]*\))?|DatetimeFuture(?:\([^)]*\))?|DateHappen(?:\([^)]*\))?|DatetimeHappen(?:\([^)]*\))?|DateAfter\([^)]*\)|DateBefore\([^)]*\)|DateEqual\([^)]*\))(,(require(?:\([^)]*\))?|requireIf\([^)]*\)|requireTrue(?:\([^)]*\))?|requireTrueIf\([^)]*\)|numeric(?:\([^)]*\))?|range\([^)]*\)|integer(?:\([^)]*\))?|unique\([^)]*\)|length(?:\([^)]*\))?|lengthGreater\([^)]*\)|lengthLess\([^)]*\)|telephone(?:\([^)]*\))?|email(?:\([^)]*\))?|regex\([^)]*\)|idcard(?:\([^)]*\))?|DateFuture(?:\([^)]*\))?|DatetimeFuture(?:\([^)]*\))?|DateHappen(?:\([^)]*\))?|DatetimeHappen(?:\([^)]*\))?|DateAfter\([^)]*\)|DateBefore\([^)]*\)|DateEqual\([^)]*\)))*$/;
5
6
  export function useDocumentTemplate(items, parentTemplates) {
6
7
  if (!items) return "";
@@ -14,10 +15,12 @@ export function useDocumentTemplate(items, parentTemplates) {
14
15
  if (!Array.isArray(items) || !items.every((item) => typeof item === "object" && item !== null)) {
15
16
  return "";
16
17
  }
17
- const templateString = items.map((item) => templateItemToString(item, parentTemplates || [])).join("");
18
+ const templateString = items.map((item) => columnWrapTemplateItemString(item, parentTemplates || [])).join("");
18
19
  return !parentTemplates || parentTemplates.length == 0 ? `<v-container fluid><v-row dense>${templateString}</v-row></v-container>` : `<v-row dense>${templateString}</v-row>`;
19
20
  }
20
- function templateItemToString(item, parentTemplates) {
21
+ export function templateItemToString(inputItem, parentTemplates, dataVariable = "data") {
22
+ let item = cloneDeep(inputItem);
23
+ item.inputAttributes = item.inputAttributes?.trim() || "";
21
24
  let optionString = "";
22
25
  if (item.inputOptions) {
23
26
  if (item.inputType === "MasterAutocomplete") {
@@ -52,22 +55,22 @@ function templateItemToString(item, parentTemplates) {
52
55
  templateString = item.inputCustomCode || "";
53
56
  break;
54
57
  case "VRadio":
55
- templateString = `${item.inputLabel ? `<p class="opacity-60">${item.inputLabel}</p>` : ""} <v-radio-group ${item.inputAttributes?.trim()} v-model="data.${item.variableName || ""}"${validationRules ? " " + validationRules.trim() : ""}>${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
58
+ templateString = `${item.inputLabel ? `<p class="opacity-60">${item.inputLabel}</p>` : ""} <v-radio-group ${item.inputAttributes?.trim()} v-model="${dataVariable}.${item.variableName || ""}"${validationRules ? " " + validationRules.trim() : ""}>${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
56
59
  break;
57
60
  case "VRadioInline":
58
- templateString = `<v-radio-group ${item.inputAttributes?.trim()} v-model="data.${item.variableName || ""}" inline ${validationRules ? " " + validationRules.trim() : ""}>${item.inputLabel ? `<template #prepend><span class="opacity-60">${item.inputLabel}</span></template>` : ""}${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
61
+ templateString = `<v-radio-group ${item.inputAttributes?.trim()} v-model="${dataVariable}.${item.variableName || ""}" inline ${validationRules ? " " + validationRules.trim() : ""}>${item.inputLabel ? `<template #prepend><span class="opacity-60">${item.inputLabel}</span></template>` : ""}${optionString ? " " + optionString.trim() : ""}</v-radio-group>`;
59
62
  break;
60
63
  case "Separator":
61
- templateString = "</v-row><v-row dense>";
64
+ templateString = `</v-row><v-row dense${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>`;
62
65
  break;
63
66
  case "Header":
64
67
  templateString = `<div class="${optionString || "text-h4 font-weight-medium"}">${item.inputLabel || item.variableName || ""}</div>`;
65
68
  break;
66
69
  case "FormTable":
67
- templateString = processTemplateFormTable(item, parentTemplates);
70
+ templateString = processTemplateFormTable(item, parentTemplates, dataVariable);
68
71
  break;
69
72
  case "FormTableData":
70
- templateString = processTemplateFormTableData(item, parentTemplates);
73
+ templateString = processTemplateFormTableData(item, parentTemplates, dataVariable);
71
74
  break;
72
75
  case "FormHidden":
73
76
  templateString = processTemplateFormHidden(item, parentTemplates);
@@ -77,15 +80,19 @@ function templateItemToString(item, parentTemplates) {
77
80
  templateString = `<document-form :model-value="data" templateCode="${item.inputOptions || ""}" parent-templates="${parentTemplatesString}"></document-form>`;
78
81
  break;
79
82
  default:
80
- templateString = processDefaultTemplate(item, void 0, optionString);
83
+ templateString = processDefaultTemplate(item, void 0, optionString, void 0, dataVariable);
81
84
  }
82
- if (!["Separator"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""}>${templateString}</v-col>`;
83
- if (["Header", "DocumentForm"].includes(item.inputType)) templateString = `</v-row><v-row dense>${templateString}</v-row><v-row dense>`;
84
85
  if (item.computedValue && item.variableName) {
85
- templateString = `${templateString || ""}<FormHidden v-model="data.${item.variableName}" :item-value="data" :hook="()=>${item.computedValue}"/>`.trim();
86
+ templateString = `${templateString || ""}<FormHidden v-model="${dataVariable}.${item.variableName}" :item-value="data" :hook="()=>${item.computedValue}"/>`.trim();
86
87
  }
87
88
  return templateString || "";
88
89
  }
90
+ function columnWrapTemplateItemString(item, parentTemplates, dataVariable = "data") {
91
+ let templateString = templateItemToString(item, parentTemplates, dataVariable);
92
+ if (!["Separator", "FormHidden"].includes(item.inputType)) templateString = `<v-col${item.width ? ` cols="${item.width}"` : ""}${item.columnAttributes ? " " + item.columnAttributes : ""}${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-col>`;
93
+ if (["Header", "DocumentForm"].includes(item.inputType)) templateString = `</v-row><v-row dense${item.customClass ? ` class="${item.customClass}"` : ""}${item.customStyle ? ` class="${item.customStyle}"` : ""}>${templateString}</v-row><v-row dense>`;
94
+ return templateString || "";
95
+ }
89
96
  export function optionStringToChoiceObject(option) {
90
97
  if (typeof option === "string") {
91
98
  if (!/^[^'",]+(,[^'",]+)*$/.test(option.trim())) return [];
@@ -137,9 +144,9 @@ export function buildValidationRules(validationString) {
137
144
  });
138
145
  return `:rules="[${formatted.join(",")}]"`;
139
146
  }
140
- export function processDefaultTemplate(item, insideTemplate, optionString, validationRules) {
147
+ export function processDefaultTemplate(item, insideTemplate, optionString, validationRules, dataVariable = "data") {
141
148
  if (!validationRules) validationRules = item.validationRules ? buildValidationRules(item.validationRules) || "" : "";
142
149
  const hasVariant = some([item.inputAttributes], (str) => includes(str, "variant"));
143
150
  const defaultAttributes = `${!hasVariant ? `variant="underlined"` : ""} :active=isReadonly`;
144
- return `<${item.inputType} ${defaultAttributes} v-model="data.${item.variableName || ""}" label="${item.inputLabel || item.variableName || ""}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}>${insideTemplate || ""}</${item.inputType}>`;
151
+ return `<${item.inputType} ${defaultAttributes} v-model="${dataVariable}.${item.variableName || ""}" label="${item.inputLabel || item.variableName || ""}"${item.inputAttributes ? " " + item.inputAttributes : ""}${optionString ? " " + optionString.trim() : ""}${validationRules ? " " + validationRules.trim() : ""}>${insideTemplate || ""}</${item.inputType}>`;
145
152
  }
@@ -1,2 +1,2 @@
1
1
  import { type DocumentTemplateItem } from './template.js';
2
- export declare function processTemplateFormHidden(item: DocumentTemplateItem, parentTemplates: string | string[]): string;
2
+ export declare function processTemplateFormHidden(item: DocumentTemplateItem, parentTemplates: string | string[], dataVariable?: string): string;
@@ -1,10 +1,13 @@
1
- export function processTemplateFormHidden(item, parentTemplates) {
1
+ export function processTemplateFormHidden(item, parentTemplates, dataVariable = "data") {
2
2
  let formHiddenOptions = Object.assign({ itemValue: "", hook: "" }, item.inputOptions);
3
3
  if (formHiddenOptions.hook.trim()) {
4
4
  formHiddenOptions.hook = formHiddenOptions.hook.replace(/\n/g, ";").trim();
5
5
  if (!/^return\s/.test(formHiddenOptions.hook)) {
6
6
  formHiddenOptions.hook = `return ${formHiddenOptions.hook}`;
7
7
  }
8
+ formHiddenOptions.hook = ` :hook="(data,modelValue) => {${formHiddenOptions.hook}}"`;
9
+ } else {
10
+ formHiddenOptions.hook = "";
8
11
  }
9
- return `<form-hidden v-model="data.${item.variableName || ""}" :item-value="${formHiddenOptions.itemValue || "data"}" :hook="(data,modelValue) => {${formHiddenOptions.hook}}"></form-hidden>`;
12
+ return `<form-hidden v-model="${dataVariable}.${item.variableName || ""}" :item-value="${formHiddenOptions.itemValue || "data"}"${formHiddenOptions.hook}></form-hidden>`;
10
13
  }
@@ -1,3 +1,4 @@
1
1
  import { type DocumentTemplateItem } from './template.js';
2
- export declare function processTemplateFormTable(item: DocumentTemplateItem, parentTemplates: string | string[]): string;
3
- export declare function processTemplateFormTableData(item: DocumentTemplateItem, parentTemplates: string | string[]): string;
2
+ export declare function autoActionHeader(tableHeader: Record<string, any>[]): Record<string, any>[];
3
+ export declare function templateToHeader(template: string | object | undefined): Record<string, any>[];
4
+ export declare function processTemplateFormTable(item: DocumentTemplateItem, parentTemplates: string | string[], dataVariable: string): string;
@@ -3,48 +3,44 @@ import {
3
3
  processDefaultTemplate,
4
4
  useDocumentTemplate
5
5
  } from "./template.js";
6
- export function processTemplateFormTable(item, parentTemplates) {
7
- let tableOptions = Object.assign({ title: item.inputLabel || "", formTemplate: "" }, item.inputOptions);
8
- let tableHeader = tableOptions.headers || [];
9
- if (!tableHeader.some((h) => h.key === "action")) tableHeader.push({ title: "Action", key: "action", width: "100px" });
10
- return processDefaultTemplate(item, `<template #form="{data,rules}">${useDocumentTemplate(tableOptions.formTemplate)}</template>`, `title="${tableOptions.title}" :headers='${escapeObjectForInlineBinding(tableHeader)}'`);
6
+ import { cloneDeep, isString, isArray } from "lodash-es";
7
+ export function autoActionHeader(tableHeader) {
8
+ let autoTableHeader = cloneDeep(tableHeader);
9
+ if (!autoTableHeader.some((h) => h.key === "action")) autoTableHeader.push({ title: "Action", key: "action", width: "100px" });
10
+ return autoTableHeader;
11
+ }
12
+ export function templateToHeader(template) {
13
+ if (isString(template)) {
14
+ try {
15
+ template = JSON.parse(template);
16
+ } catch (e) {
17
+ }
18
+ }
19
+ if (!isArray(template)) return [];
20
+ return template.map((item) => {
21
+ return {
22
+ title: item.inputLabel || item.label || item.title || item.variableName || item.key,
23
+ key: item.variableName || item.key,
24
+ width: item.width && item.width > 12 ? guessWidth(item.width) : void 0
25
+ };
26
+ });
11
27
  }
12
- export function processTemplateFormTableData(item, parentTemplates) {
28
+ function guessWidth(width) {
29
+ if (width == 0) return void 0;
30
+ if (width >= 1 && width < 12) return (width * 100 / 12).toFixed(2) + "%";
31
+ if (width > 12 && width < 100) return width + "%";
32
+ else return width + "px";
33
+ }
34
+ export function processTemplateFormTable(item, parentTemplates, dataVariable) {
13
35
  let tableOptions = Object.assign({ title: item.inputLabel || "", formTemplate: "" }, item.inputOptions);
14
36
  let tableHeader = tableOptions.headers || [];
15
- let tableItems = tableOptions.items || [];
16
- let tableTemplate = "";
17
- if (item.conditionalDisplay) {
18
- item.inputAttributes = `${item.inputAttributes?.trim() || ""} v-if="${item.conditionalDisplay}"`.trim();
19
- }
20
- for (const header of tableHeader) {
21
- const inputAttributes = header.conditionalDisplay ? `v-if="${header.conditionalDisplay}"`.trim() : "";
22
- if (header.template) {
23
- tableTemplate += `<template #item.${header.key}="{item}">
24
- <form-pad ${inputAttributes} template='${header.template}' v-model="item.${header.key}">
25
- </form-pad>
26
- </template>`;
27
- }
28
- if (header.headerTemplate) {
29
- tableTemplate += `<template #header.${header.key}>
30
- <form-pad ${inputAttributes} template='${header.headerTemplate}'
31
- @update:model-value='(value) =>{
32
- for (const t of data.${item.variableName}) {
33
- t.${header.key} = {...value}
34
- }
35
- }'>
36
- </form-pad>
37
- </template>`;
37
+ if (!tableHeader.some((h) => h.key === "action")) tableHeader.push({ title: "Action", key: "action", width: "100px" });
38
+ let tableItemTemplate = "";
39
+ tableHeader.forEach((h) => {
40
+ if (h.template) {
41
+ tableItemTemplate += `\r
42
+ <template #item.${h.key}="props">${h.template}</template>`;
38
43
  }
39
- }
40
- item.inputType = "FormTableData";
41
- return processDefaultTemplate(item, tableTemplate, `title="${tableOptions.title}"
42
- :headers='${escapeObjectForInlineBinding(tableHeader)}'
43
- :items='${escapeObjectForInlineBinding(tableItems)}'
44
- :insertable="false"
45
- :importable="false"
46
- :exportable="false"
47
- :searchable="false"
48
- hide-default-footer
49
- `);
44
+ });
45
+ return processDefaultTemplate(item, `<template #form="{data,rules}">${useDocumentTemplate(tableOptions.formTemplate)}</template>${tableItemTemplate}`, `title="${tableOptions.title}" :headers='${escapeObjectForInlineBinding(tableHeader)}'`, void 0, dataVariable);
50
46
  }
@@ -0,0 +1,2 @@
1
+ import { type DocumentTemplateItem } from './template.js';
2
+ export declare function processTemplateFormTableData(item: DocumentTemplateItem, parentTemplates: string | string[], dataVariable: string): string;
@@ -0,0 +1,21 @@
1
+ import {
2
+ escapeObjectForInlineBinding,
3
+ processDefaultTemplate
4
+ } from "./template.js";
5
+ import { templateToHeader } from "./templateFormTable.js";
6
+ export function processTemplateFormTableData(item, parentTemplates, dataVariable) {
7
+ let tableOptions = Object.assign({ title: item.inputLabel || "", dataTemplate: {}, itemTemplate: {} }, item.inputOptions);
8
+ let tableHeader = tableOptions.headers || [];
9
+ if (tableHeader.length === 0) {
10
+ tableHeader = templateToHeader(tableOptions.itemTemplate);
11
+ }
12
+ let tableItemTemplate = "";
13
+ tableHeader.forEach((h) => {
14
+ if (h.template) {
15
+ tableItemTemplate += `\r
16
+ <template #item.${h.key}="props">${h.template}</template>`;
17
+ }
18
+ });
19
+ let disableApplyToAll = tableOptions.disableApplyToAll && tableOptions.disableApplyToAll == "partial" ? escapeObjectForInlineBinding(tableOptions.disableApplyToAllPartial?.split(",").map((h) => h.trim()) || []) : !!(tableOptions.disableApplyToAll && tableOptions.disableApplyToAll == "true");
20
+ return processDefaultTemplate(item, void 0, `title="${tableOptions.title}" :headers='${escapeObjectForInlineBinding(tableHeader)}' :itemsInitial='${escapeObjectForInlineBinding(tableOptions.items || [])}' :dataTemplate='${escapeObjectForInlineBinding(tableOptions.dataTemplate)}' :disableApplyToAll='${disableApplyToAll}'`, void 0, dataVariable);
21
+ }
@@ -13,12 +13,12 @@ export declare function useGraphqlModel<T extends GraphqlModelProps>(props: T):
13
13
  search: import("vue").Ref<string | undefined, string | undefined>;
14
14
  setSearch: (keyword: string) => void;
15
15
  currentOptions: import("vue").Ref<any, any>;
16
- operationCreate: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
17
- operationUpdate: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
18
- operationDelete: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
19
- operationRead: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
20
- operationReadPageable: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
21
- operationSearch: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
16
+ operationCreate: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
17
+ operationUpdate: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
18
+ operationDelete: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
19
+ operationRead: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
20
+ operationReadPageable: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
21
+ operationSearch: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
22
22
  fields: import("vue").ComputedRef<(string | object)[]>;
23
23
  canServerPageable: import("vue").ComputedRef<boolean>;
24
24
  canServerSearch: import("vue").ComputedRef<boolean>;
@@ -4,10 +4,10 @@ export type GraphqlModelItemProps = Omit<GraphqlModelConfigProps, 'operationSear
4
4
  export declare function useGraphqlModelItem<T extends GraphqlModelItemProps>(props: T): {
5
5
  modelBy: import("vue").Ref<object | undefined, object | undefined>;
6
6
  item: import("vue").Ref<Record<string, any> | undefined, Record<string, any> | undefined>;
7
- operationCreate: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
8
- operationUpdate: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
9
- operationDelete: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
10
- operationRead: import("vue").ComputedRef<import("../types/graphqlOperation").graphqlOperationObject<any, any>>;
7
+ operationCreate: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
8
+ operationUpdate: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
9
+ operationDelete: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
10
+ operationRead: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
11
11
  fields: import("vue").ComputedRef<(string | object)[]>;
12
12
  canCreate: import("vue").ComputedRef<boolean>;
13
13
  canUpdate: import("vue").ComputedRef<boolean>;
@@ -12,10 +12,10 @@ export interface GraphqlModelConfigProps {
12
12
  fields?: Array<string | object>;
13
13
  }
14
14
  export declare function useGraphqlModelOperation<T extends GraphqlModelConfigProps>(props: T): {
15
- operationCreate: import("vue").ComputedRef<graphqlOperationObject<any, any>>;
16
- operationUpdate: import("vue").ComputedRef<graphqlOperationObject<any, any>>;
17
- operationDelete: import("vue").ComputedRef<graphqlOperationObject<any, any>>;
18
- operationRead: import("vue").ComputedRef<graphqlOperationObject<any, any>>;
19
- operationReadPageable: import("vue").ComputedRef<graphqlOperationObject<any, any>>;
20
- operationSearch: import("vue").ComputedRef<graphqlOperationObject<any, any>>;
15
+ operationCreate: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
16
+ operationUpdate: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
17
+ operationDelete: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
18
+ operationRead: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
19
+ operationReadPageable: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
20
+ operationSearch: import("vue").ComputedRef<import("~/.nuxt/types/graphqlOperation").graphqlOperationObject<any, any>>;
21
21
  };
@@ -0,0 +1,44 @@
1
+ import { type Ref } from 'vue';
2
+ export interface LookupProps {
3
+ fuzzy?: boolean;
4
+ sortBy?: string | string[];
5
+ showCode?: boolean;
6
+ modelName: string;
7
+ modelBy?: Record<string, any>;
8
+ itemTitle: string;
9
+ itemValue: string;
10
+ fields?: Array<string | object>;
11
+ cache?: boolean | number;
12
+ serverSearch?: boolean;
13
+ serverSearchKey?: string;
14
+ searchSearchSort?: boolean;
15
+ serverSearchDebounce?: number;
16
+ serverSearchText?: string;
17
+ serverSearchLoadingText?: string;
18
+ filterKeys?: string | string[];
19
+ noDataText?: string;
20
+ placeholder?: string;
21
+ multiple?: boolean;
22
+ modelSelectedItem?: string;
23
+ modelSelectedItemBy?: Record<string, any>;
24
+ modelSelectedItemKey?: string;
25
+ }
26
+ export interface LookupEmits {
27
+ (e: 'update:selectedObject', payload: any | any[]): void;
28
+ }
29
+ export declare function useLookupList(props: LookupProps, emit: LookupEmits, selectedItems: Ref<any>): {
30
+ modelItems: Ref<any[], any[]>;
31
+ items: Ref<any[], any[]>;
32
+ searchData: Ref<string, string>;
33
+ isLoading: Ref<boolean, boolean>;
34
+ isErrorLoading: Ref<boolean, boolean>;
35
+ queryFields: import("vue").ComputedRef<any[]>;
36
+ computedFilterKeys: import("vue").ComputedRef<string | string[]>;
37
+ computedPlaceholder: import("vue").ComputedRef<string | undefined>;
38
+ computedNoDataText: import("vue").ComputedRef<string | undefined>;
39
+ computedItems: import("vue").ComputedRef<any[]>;
40
+ selectedItemsObject: Ref<any[], any[]>;
41
+ syncSelectedFromModelValue: () => Promise<void>;
42
+ loadItems: () => Promise<void>;
43
+ applyFuzzy: () => void;
44
+ };
@@ -0,0 +1,194 @@
1
+ import { computed, ref, watch } from "vue";
2
+ import { watchDebounced } from "@vueuse/core";
3
+ import { union, isEmpty, isArray, sortBy, castArray } from "lodash-es";
4
+ import { useFuzzy } from "./utils/fuzzy.js";
5
+ import { useGraphQlOperation } from "./graphqlOperation.js";
6
+ export function useLookupList(props, emit, selectedItems) {
7
+ const modelItems = ref([]);
8
+ const items = ref([]);
9
+ const searchData = ref("");
10
+ const isLoading = ref(false);
11
+ const isErrorLoading = ref(false);
12
+ const queryFields = computed(() => {
13
+ let fieldsArray = [props.itemTitle, props.itemValue];
14
+ if (props.fields) fieldsArray = union(fieldsArray, props.fields);
15
+ return fieldsArray;
16
+ });
17
+ const computedFilterKeys = computed(() => {
18
+ if (props.filterKeys) return props.filterKeys;
19
+ return ["title", "raw." + props.itemValue];
20
+ });
21
+ const computedPlaceholder = computed(() => {
22
+ if (!props.serverSearch) return props.placeholder;
23
+ return isLoading.value ? props.serverSearchLoadingText : props.serverSearchText;
24
+ });
25
+ const computedNoDataText = computed(() => {
26
+ if (!props.serverSearch) return props.noDataText;
27
+ if (isLoading.value) return props.serverSearchLoadingText;
28
+ if (!searchData.value) return props.serverSearchText;
29
+ return props.noDataText;
30
+ });
31
+ let requestId = 0;
32
+ async function loadItems() {
33
+ if (!props.modelName) {
34
+ modelItems.value = [];
35
+ items.value = [];
36
+ return;
37
+ }
38
+ const id = ++requestId;
39
+ isLoading.value = true;
40
+ const variables = { ...props.modelBy || {} };
41
+ if (props.serverSearch && props.serverSearchKey) {
42
+ variables[props.serverSearchKey] = searchData.value;
43
+ }
44
+ try {
45
+ const result = await useGraphQlOperation(
46
+ "Query",
47
+ props.modelName,
48
+ queryFields.value,
49
+ variables,
50
+ props.cache
51
+ );
52
+ if (id !== requestId) return;
53
+ if (isArray(result)) {
54
+ modelItems.value = result;
55
+ items.value = result;
56
+ isErrorLoading.value = false;
57
+ } else {
58
+ isErrorLoading.value = true;
59
+ modelItems.value = [];
60
+ items.value = [];
61
+ }
62
+ } catch (e) {
63
+ if (id !== requestId) return;
64
+ isErrorLoading.value = true;
65
+ modelItems.value = [];
66
+ items.value = [];
67
+ } finally {
68
+ if (id === requestId) isLoading.value = false;
69
+ }
70
+ }
71
+ function applyFuzzy() {
72
+ if (!props.fuzzy) return;
73
+ if (isEmpty(searchData.value)) {
74
+ items.value = modelItems.value;
75
+ return;
76
+ }
77
+ const results = useFuzzy(searchData.value, modelItems.value, queryFields.value);
78
+ const output = [];
79
+ if (results.value?.length) {
80
+ for (let index = 0; index < results.value.length; index++) {
81
+ const result = results.value[index];
82
+ if (result?.item) output.push(result.item);
83
+ }
84
+ }
85
+ items.value = output;
86
+ }
87
+ const selectedItemsObject = ref([]);
88
+ async function syncSelectedFromModelValue() {
89
+ const modelValueData = selectedItems.value;
90
+ const values = castArray(modelValueData).filter(
91
+ (value) => value !== void 0 && value !== null && value !== ""
92
+ );
93
+ if (!values.length) {
94
+ emit("update:selectedObject", props.multiple ? [] : void 0);
95
+ selectedItemsObject.value = [];
96
+ return;
97
+ }
98
+ let alreadyInObject = selectedItemsObject.value?.filter((item) => values.includes(item?.[props.itemValue])) || [];
99
+ const haveSet = /* @__PURE__ */ new Set([...alreadyInObject.map((item) => item?.[props.itemValue])]);
100
+ const missingValues = values.filter((value) => !haveSet.has(value));
101
+ const stillMissing = [];
102
+ for (const value of missingValues) {
103
+ const localHit = modelItems.value.find((item) => item?.[props.itemValue] === value);
104
+ if (localHit) {
105
+ alreadyInObject.push(localHit);
106
+ haveSet.add(value);
107
+ } else {
108
+ stillMissing.push(value);
109
+ }
110
+ }
111
+ if (stillMissing.length && props.modelSelectedItem) {
112
+ try {
113
+ const key = props.modelSelectedItemKey || "id";
114
+ const variables = { ...props.modelSelectedItemBy || {} };
115
+ variables[key] = values;
116
+ const result = await useGraphQlOperation(
117
+ "Query",
118
+ props.modelSelectedItem,
119
+ queryFields.value,
120
+ variables,
121
+ props.cache
122
+ );
123
+ selectedItemsObject.value = castArray(result);
124
+ } catch {
125
+ }
126
+ } else {
127
+ selectedItemsObject.value = alreadyInObject;
128
+ }
129
+ emit("update:selectedObject", props.multiple ? selectedItemsObject.value : selectedItemsObject.value[0]);
130
+ }
131
+ watch(
132
+ () => [
133
+ props.modelName,
134
+ props.serverSearch,
135
+ props.serverSearchKey,
136
+ props.cache,
137
+ props.modelBy,
138
+ queryFields.value
139
+ ],
140
+ () => loadItems(),
141
+ { immediate: true, deep: true }
142
+ );
143
+ watchDebounced(
144
+ searchData,
145
+ () => {
146
+ if (props.serverSearch) loadItems();
147
+ else applyFuzzy();
148
+ },
149
+ { debounce: props.serverSearch ? props.serverSearchDebounce ?? 500 : 300, maxWait: 1500 }
150
+ );
151
+ watch(
152
+ () => modelItems.value,
153
+ () => {
154
+ if (!props.serverSearch) applyFuzzy();
155
+ }
156
+ );
157
+ watch(
158
+ () => selectedItems.value,
159
+ () => {
160
+ syncSelectedFromModelValue();
161
+ },
162
+ { immediate: true, deep: true }
163
+ );
164
+ const computedItems = computed(() => {
165
+ const sortByField = !props.sortBy || typeof props.sortBy === "string" ? [props.sortBy || (props.showCode ? props.itemValue : props.itemTitle)] : props.sortBy;
166
+ const baseItems = (props.fuzzy || props.serverSearch && !props.searchSearchSort) && !isEmpty(searchData.value) ? items.value : sortBy(items.value, sortByField);
167
+ for (const selectedItem of selectedItemsObject.value || []) {
168
+ if (!baseItems.find((existingItem) => existingItem[props.itemValue] === selectedItem[props.itemValue])) {
169
+ baseItems.push(selectedItem);
170
+ }
171
+ }
172
+ return baseItems;
173
+ });
174
+ return {
175
+ // state
176
+ modelItems,
177
+ items,
178
+ searchData,
179
+ isLoading,
180
+ isErrorLoading,
181
+ // derived
182
+ queryFields,
183
+ computedFilterKeys,
184
+ computedPlaceholder,
185
+ computedNoDataText,
186
+ computedItems,
187
+ // selection
188
+ selectedItemsObject,
189
+ syncSelectedFromModelValue,
190
+ // actions (exposed for testing if needed)
191
+ loadItems,
192
+ applyFuzzy
193
+ };
194
+ }