@ramathibodi/nuxt-commons 4.0.12 → 4.0.14

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 (40) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/dialog/ImportProgress.d.vue.ts +35 -0
  3. package/dist/runtime/components/dialog/ImportProgress.vue +53 -0
  4. package/dist/runtime/components/dialog/ImportProgress.vue.d.ts +35 -0
  5. package/dist/runtime/components/dialog/ImportResult.d.vue.ts +28 -0
  6. package/dist/runtime/components/dialog/ImportResult.vue +122 -0
  7. package/dist/runtime/components/dialog/ImportResult.vue.d.ts +28 -0
  8. package/dist/runtime/components/document/TemplateBuilder.vue +112 -7
  9. package/dist/runtime/components/model/Pad.vue +2 -1
  10. package/dist/runtime/components/model/Table.d.vue.ts +104 -28
  11. package/dist/runtime/components/model/Table.vue +118 -3
  12. package/dist/runtime/components/model/Table.vue.d.ts +104 -28
  13. package/dist/runtime/components/model/iterator.d.vue.ts +146 -49
  14. package/dist/runtime/components/model/iterator.vue +129 -5
  15. package/dist/runtime/components/model/iterator.vue.d.ts +146 -49
  16. package/dist/runtime/composables/api.d.ts +7 -0
  17. package/dist/runtime/composables/api.js +3 -2
  18. package/dist/runtime/composables/apiModel.d.ts +31 -3
  19. package/dist/runtime/composables/apiModel.js +30 -21
  20. package/dist/runtime/composables/apiModelOperation.d.ts +17 -3
  21. package/dist/runtime/composables/apiModelOperation.js +6 -6
  22. package/dist/runtime/composables/document/template.d.ts +61 -0
  23. package/dist/runtime/composables/document/template.js +59 -0
  24. package/dist/runtime/composables/document/validateTemplate.d.ts +62 -0
  25. package/dist/runtime/composables/document/validateTemplate.js +378 -0
  26. package/dist/runtime/composables/graphql.d.ts +3 -3
  27. package/dist/runtime/composables/graphql.js +6 -6
  28. package/dist/runtime/composables/graphqlModel.d.ts +31 -3
  29. package/dist/runtime/composables/graphqlModel.js +28 -20
  30. package/dist/runtime/composables/graphqlModelOperation.d.ts +1 -0
  31. package/dist/runtime/composables/graphqlOperation.d.ts +2 -1
  32. package/dist/runtime/composables/graphqlOperation.js +3 -3
  33. package/dist/runtime/composables/importProgress.d.ts +58 -0
  34. package/dist/runtime/composables/importProgress.js +130 -0
  35. package/dist/runtime/types/graphqlOperation.d.ts +12 -1
  36. package/dist/runtime/utils/virtualize.d.ts +15 -0
  37. package/dist/runtime/utils/virtualize.js +10 -0
  38. package/package.json +2 -1
  39. package/scripts/validate-document-template.mjs +158 -0
  40. package/templates/.codegen/plugin-schema-object.cjs +10 -13
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^4.3.1"
6
6
  },
7
- "version": "4.0.12",
7
+ "version": "4.0.14",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Public props accepted by DialogImportProgress.
3
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
4
+ */
5
+ interface DialogImportProgressProps {
6
+ modelValue: boolean;
7
+ total: number;
8
+ processed: number;
9
+ succeeded?: number;
10
+ failed?: number;
11
+ percent: number;
12
+ title?: string;
13
+ color?: string;
14
+ }
15
+ declare var __VLS_20: {};
16
+ type __VLS_Slots = {} & {
17
+ default?: (props: typeof __VLS_20) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<DialogImportProgressProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
+ "update:modelValue": (...args: any[]) => void;
21
+ }, string, import("vue").PublicProps, Readonly<DialogImportProgressProps> & Readonly<{
22
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
23
+ }>, {
24
+ title: string;
25
+ succeeded: number;
26
+ failed: number;
27
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
+ declare const _default: typeof __VLS_export;
30
+ export default _default;
31
+ type __VLS_WithSlots<T, S> = T & {
32
+ new (): {
33
+ $slots: S;
34
+ };
35
+ };
@@ -0,0 +1,53 @@
1
+ <script setup>
2
+ import { ref, watch } from "vue";
3
+ const props = defineProps({
4
+ modelValue: { type: Boolean, required: true },
5
+ total: { type: Number, required: true },
6
+ processed: { type: Number, required: true },
7
+ succeeded: { type: Number, required: false, default: 0 },
8
+ failed: { type: Number, required: false, default: 0 },
9
+ percent: { type: Number, required: true },
10
+ title: { type: String, required: false, default: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E19\u0E33\u0E40\u0E02\u0E49\u0E32\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25" },
11
+ color: { type: String, required: false }
12
+ });
13
+ const emit = defineEmits(["update:modelValue"]);
14
+ const dialogVisible = ref(props.modelValue);
15
+ watch(() => props.modelValue, (newValue) => {
16
+ dialogVisible.value = newValue;
17
+ });
18
+ watch(() => dialogVisible.value, (newValue) => {
19
+ emit("update:modelValue", newValue);
20
+ });
21
+ </script>
22
+
23
+ <template>
24
+ <v-dialog
25
+ v-model="dialogVisible"
26
+ persistent
27
+ max-width="500"
28
+ >
29
+ <v-card :color="props.color">
30
+ <v-card-text>
31
+ <div class="text-center mb-2">
32
+ <slot>{{ props.title }}</slot>
33
+ </div>
34
+ <div class="text-center text-body-2 mb-2">
35
+ {{ props.processed }} / {{ props.total }}
36
+ <span
37
+ v-if="props.failed > 0"
38
+ class="text-medium-emphasis"
39
+ >
40
+ (ล้มเหลว {{ props.failed }})
41
+ </span>
42
+ </div>
43
+ </v-card-text>
44
+ <v-progress-linear
45
+ :model-value="props.percent"
46
+ height="20"
47
+ color="primary"
48
+ >
49
+ <strong>{{ props.percent }}%</strong>
50
+ </v-progress-linear>
51
+ </v-card>
52
+ </v-dialog>
53
+ </template>
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Public props accepted by DialogImportProgress.
3
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
4
+ */
5
+ interface DialogImportProgressProps {
6
+ modelValue: boolean;
7
+ total: number;
8
+ processed: number;
9
+ succeeded?: number;
10
+ failed?: number;
11
+ percent: number;
12
+ title?: string;
13
+ color?: string;
14
+ }
15
+ declare var __VLS_20: {};
16
+ type __VLS_Slots = {} & {
17
+ default?: (props: typeof __VLS_20) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<DialogImportProgressProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
+ "update:modelValue": (...args: any[]) => void;
21
+ }, string, import("vue").PublicProps, Readonly<DialogImportProgressProps> & Readonly<{
22
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
23
+ }>, {
24
+ title: string;
25
+ succeeded: number;
26
+ failed: number;
27
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
+ declare const _default: typeof __VLS_export;
30
+ export default _default;
31
+ type __VLS_WithSlots<T, S> = T & {
32
+ new (): {
33
+ $slots: S;
34
+ };
35
+ };
@@ -0,0 +1,28 @@
1
+ import type { ImportError } from '../../composables/importProgress.js';
2
+ /**
3
+ * Public props accepted by DialogImportResult.
4
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
5
+ */
6
+ interface DialogImportResultProps {
7
+ modelValue: boolean;
8
+ errors: ImportError[];
9
+ total: number;
10
+ failed: number;
11
+ isImporting?: boolean;
12
+ title?: string;
13
+ color?: string;
14
+ }
15
+ declare const __VLS_export: import("vue").DefineComponent<DialogImportResultProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
16
+ "update:modelValue": (value: boolean) => any;
17
+ retry: (index: number) => any;
18
+ "retry-all": () => any;
19
+ }, string, import("vue").PublicProps, Readonly<DialogImportResultProps> & Readonly<{
20
+ "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
21
+ onRetry?: ((index: number) => any) | undefined;
22
+ "onRetry-all"?: (() => any) | undefined;
23
+ }>, {
24
+ title: string;
25
+ isImporting: boolean;
26
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
+ declare const _default: typeof __VLS_export;
28
+ export default _default;
@@ -0,0 +1,122 @@
1
+ <script setup>
2
+ import { ref, watch } from "vue";
3
+ const props = defineProps({
4
+ modelValue: { type: Boolean, required: true },
5
+ errors: { type: Array, required: true },
6
+ total: { type: Number, required: true },
7
+ failed: { type: Number, required: true },
8
+ isImporting: { type: Boolean, required: false, default: false },
9
+ title: { type: String, required: false, default: "\u0E19\u0E33\u0E40\u0E02\u0E49\u0E32\u0E25\u0E49\u0E21\u0E40\u0E2B\u0E25\u0E27" },
10
+ color: { type: String, required: false }
11
+ });
12
+ const emit = defineEmits(["update:modelValue", "retry-all", "retry"]);
13
+ const dialogVisible = ref(props.modelValue);
14
+ watch(() => props.modelValue, (newValue) => {
15
+ dialogVisible.value = newValue;
16
+ });
17
+ watch(() => dialogVisible.value, (newValue) => {
18
+ emit("update:modelValue", newValue);
19
+ });
20
+ const chipColor = (t) => t === "server" ? "error" : t === "unknown" ? "grey" : "warning";
21
+ const pretty = (v) => {
22
+ try {
23
+ return typeof v === "string" ? v : JSON.stringify(v, null, 2);
24
+ } catch {
25
+ return String(v);
26
+ }
27
+ };
28
+ </script>
29
+
30
+ <template>
31
+ <v-dialog
32
+ v-model="dialogVisible"
33
+ persistent
34
+ scrollable
35
+ max-width="700"
36
+ >
37
+ <v-card :color="props.color">
38
+ <v-card-title class="d-flex align-center">
39
+ <span>{{ props.title }} {{ props.failed }} / {{ props.total }}</span>
40
+ <v-spacer />
41
+ <v-btn
42
+ color="primary"
43
+ variant="tonal"
44
+ prepend-icon="mdi mdi-refresh"
45
+ :loading="props.isImporting"
46
+ :disabled="props.isImporting || props.errors.length === 0"
47
+ @click="emit('retry-all')"
48
+ >
49
+ Retry all failed
50
+ </v-btn>
51
+ </v-card-title>
52
+
53
+ <v-progress-linear
54
+ v-if="props.isImporting"
55
+ indeterminate
56
+ color="primary"
57
+ height="6"
58
+ />
59
+
60
+ <v-card-text>
61
+ <v-expansion-panels multiple>
62
+ <v-expansion-panel
63
+ v-for="err in props.errors"
64
+ :key="err.index"
65
+ >
66
+ <v-expansion-panel-title>
67
+ <div
68
+ class="d-flex align-center"
69
+ style="gap: 8px; width: 100%"
70
+ >
71
+ <span class="text-medium-emphasis">#{{ err.index + 1 }}</span>
72
+ <v-chip
73
+ :color="chipColor(err.errorType)"
74
+ size="small"
75
+ label
76
+ >
77
+ {{ err.errorType }}
78
+ </v-chip>
79
+ <span class="text-truncate">{{ err.message }}</span>
80
+ <v-spacer />
81
+ <v-btn
82
+ icon="mdi mdi-refresh"
83
+ size="small"
84
+ variant="text"
85
+ :disabled="props.isImporting"
86
+ @click.stop="emit('retry', err.index)"
87
+ />
88
+ </div>
89
+ </v-expansion-panel-title>
90
+ <v-expansion-panel-text>
91
+ <div class="text-caption text-medium-emphasis mb-1">
92
+ Data
93
+ </div>
94
+ <pre class="import-result-pre">{{ pretty(err.item) }}</pre>
95
+ <template v-if="err.detail !== void 0">
96
+ <div class="text-caption text-medium-emphasis mb-1 mt-2">
97
+ Detail
98
+ </div>
99
+ <pre class="import-result-pre">{{ pretty(err.detail) }}</pre>
100
+ </template>
101
+ </v-expansion-panel-text>
102
+ </v-expansion-panel>
103
+ </v-expansion-panels>
104
+ </v-card-text>
105
+
106
+ <v-card-actions>
107
+ <v-spacer />
108
+ <v-btn
109
+ variant="text"
110
+ :disabled="props.isImporting"
111
+ @click="dialogVisible = false"
112
+ >
113
+ ปิด
114
+ </v-btn>
115
+ </v-card-actions>
116
+ </v-card>
117
+ </v-dialog>
118
+ </template>
119
+
120
+ <style scoped>
121
+ .import-result-pre{background:rgba(0,0,0,.04);border-radius:4px;font-size:12px;margin:0;padding:8px;white-space:pre-wrap;word-break:break-word}
122
+ </style>
@@ -0,0 +1,28 @@
1
+ import type { ImportError } from '../../composables/importProgress.js';
2
+ /**
3
+ * Public props accepted by DialogImportResult.
4
+ * Document each prop field with intent, defaults, and side effects for clear generated docs.
5
+ */
6
+ interface DialogImportResultProps {
7
+ modelValue: boolean;
8
+ errors: ImportError[];
9
+ total: number;
10
+ failed: number;
11
+ isImporting?: boolean;
12
+ title?: string;
13
+ color?: string;
14
+ }
15
+ declare const __VLS_export: import("vue").DefineComponent<DialogImportResultProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
16
+ "update:modelValue": (value: boolean) => any;
17
+ retry: (index: number) => any;
18
+ "retry-all": () => any;
19
+ }, string, import("vue").PublicProps, Readonly<DialogImportResultProps> & Readonly<{
20
+ "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
21
+ onRetry?: ((index: number) => any) | undefined;
22
+ "onRetry-all"?: (() => any) | undefined;
23
+ }>, {
24
+ title: string;
25
+ isImporting: boolean;
26
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
+ declare const _default: typeof __VLS_export;
28
+ export default _default;
@@ -2,12 +2,21 @@
2
2
  import { computed, ref, watch } from "vue";
3
3
  import * as prettier from "prettier";
4
4
  import prettierPluginHtml from "prettier/plugins/html";
5
- import { useDocumentTemplate, validationRulesRegex, optionStringToChoiceObject } from "../../composables/document/template";
5
+ import {
6
+ useDocumentTemplate,
7
+ validationRulesRegex,
8
+ optionStringToChoiceObject,
9
+ printConfigToRows,
10
+ rowsToPrintConfig,
11
+ printConfigToAttributes,
12
+ configStringToRows,
13
+ rowsToConfigString
14
+ } from "../../composables/document/template";
6
15
  import {
7
16
  useDocumentTemplateInputTypes
8
17
  } from "../../composables/document/templateInputTypes";
9
18
  import { autoActionHeader, templateToHeader } from "../../composables/document/templateFormTable";
10
- import { cloneDeep } from "lodash-es";
19
+ import { cloneDeep, isPlainObject } from "lodash-es";
11
20
  import VueJsonPretty from "vue-json-pretty";
12
21
  import "vue-json-pretty/lib/styles.css";
13
22
  import { safeParseJSONDeep } from "../../utils/object";
@@ -92,6 +101,51 @@ const choiceHeaders = ref([
92
101
  width: "120px"
93
102
  }
94
103
  ]);
104
+ const printConfigHeaders = ref([
105
+ {
106
+ title: "Attribute",
107
+ key: "key"
108
+ },
109
+ {
110
+ title: "Value",
111
+ key: "value"
112
+ },
113
+ {
114
+ title: "Action",
115
+ key: "action",
116
+ width: "120px"
117
+ }
118
+ ]);
119
+ function itemsForEdit(items) {
120
+ return items.map((item) => isPlainObject(item.printConfig) ? { ...item, printConfig: printConfigToRows(item.printConfig) } : item);
121
+ }
122
+ function itemsForStore(items) {
123
+ return items.map((item) => {
124
+ if (Array.isArray(item.printConfig)) {
125
+ const map = rowsToPrintConfig(item.printConfig);
126
+ const { printConfig, ...rest } = item;
127
+ return Object.keys(map).length ? { ...rest, printConfig: map } : rest;
128
+ }
129
+ if (typeof item.printConfig === "string" && item.printConfig.trim() === "") {
130
+ const { printConfig, ...rest } = item;
131
+ return rest;
132
+ }
133
+ return item;
134
+ });
135
+ }
136
+ function setPrintConfigMode(item, mode) {
137
+ if (mode === "raw") {
138
+ if (typeof item.printConfig === "string") return;
139
+ item.printConfig = rowsToConfigString(Array.isArray(item.printConfig) ? item.printConfig : []);
140
+ } else {
141
+ if (Array.isArray(item.printConfig)) return;
142
+ item.printConfig = configStringToRows(typeof item.printConfig === "string" ? item.printConfig : "");
143
+ }
144
+ }
145
+ function printConfigPreview(printConfig) {
146
+ if (Array.isArray(printConfig)) return printConfigToAttributes(rowsToPrintConfig(printConfig));
147
+ return printConfigToAttributes(printConfig);
148
+ }
95
149
  function isValidJsonArrayOfObjects(str) {
96
150
  try {
97
151
  const parsed = JSON.parse(str);
@@ -101,19 +155,19 @@ function isValidJsonArrayOfObjects(str) {
101
155
  }
102
156
  }
103
157
  watch(templateItems, (newValue) => {
104
- if (!isAdvanceMode.value) modelValue.value = JSON.stringify(newValue);
158
+ if (!isAdvanceMode.value) modelValue.value = JSON.stringify(itemsForStore(newValue));
105
159
  }, { deep: true });
106
160
  watch(modelValue, (newValue) => {
107
- if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = JSON.parse(newValue);
161
+ if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = itemsForEdit(JSON.parse(newValue));
108
162
  else if (typeof newValue === "string") advanceModeCode.value = newValue;
109
- else if (newValue) templateItems.value = cloneDeep(newValue);
163
+ else if (newValue) templateItems.value = itemsForEdit(cloneDeep(newValue));
110
164
  }, { deep: true, immediate: true });
111
165
  watch(advanceModeCode, (newValue) => {
112
166
  if (isAdvanceMode.value) modelValue.value = newValue;
113
167
  });
114
168
  async function convertToAdvanceMode() {
115
169
  if (!isAdvanceMode.value) {
116
- modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll(">", ">\n"), { parser: "html", plugins: [prettierPluginHtml] });
170
+ modelValue.value = await prettier.format(useDocumentTemplate(itemsForStore(templateItems.value)).replaceAll(">", ">\n"), { parser: "html", plugins: [prettierPluginHtml] });
117
171
  }
118
172
  }
119
173
  const inputTypes = computed(() => useDocumentTemplateInputTypes());
@@ -403,6 +457,54 @@ const ruleOptions = (inputType) => (value) => {
403
457
  label="Retrieved Value"
404
458
  />
405
459
  </v-col>
460
+ <v-col cols="12">
461
+ <div class="d-flex align-center ga-2 mb-1">
462
+ <span class="opacity-60">Print Config</span>
463
+ <span class="text-caption opacity-60">— print/docx-only; ignored by the form renderer</span>
464
+ <v-spacer />
465
+ <v-btn-toggle
466
+ :model-value="typeof data.printConfig === 'string' ? 'raw' : 'map'"
467
+ @update:model-value="(mode) => setPrintConfigMode(data, mode)"
468
+ density="compact"
469
+ variant="outlined"
470
+ divided
471
+ mandatory
472
+ >
473
+ <v-btn value="map" size="small">Key / Value</v-btn>
474
+ <v-btn value="raw" size="small">Raw string</v-btn>
475
+ </v-btn-toggle>
476
+ </div>
477
+ <v-textarea
478
+ v-if="typeof data.printConfig === 'string'"
479
+ v-model="data.printConfig"
480
+ label="Print Config (raw attributes)"
481
+ placeholder="format=dd/MM/yyyy; locale=th_TH"
482
+ auto-grow
483
+ rows="1"
484
+ />
485
+ <form-table
486
+ v-else
487
+ v-model="data.printConfig"
488
+ :headers="printConfigHeaders"
489
+ title="Print Config"
490
+ >
491
+ <template #form="{ data: rowData, rules }">
492
+ <v-container fluid>
493
+ <v-row density="compact">
494
+ <v-col cols="6">
495
+ <v-text-field v-model="rowData.key" label="Attribute" :rules="[rules.require()]" />
496
+ </v-col>
497
+ <v-col cols="6">
498
+ <v-text-field v-model="rowData.value" label="Value (blank = flag)" />
499
+ </v-col>
500
+ </v-row>
501
+ </v-container>
502
+ </template>
503
+ </form-table>
504
+ <div class="text-caption opacity-60 mt-1" v-if="printConfigPreview(data.printConfig)">
505
+ Appends to placeholder: <code>{{ printConfigPreview(data.printConfig) }}</code>
506
+ </div>
507
+ </v-col>
406
508
  </v-row>
407
509
  </v-container>
408
510
  </v-expansion-panel-text>
@@ -438,7 +540,7 @@ const ruleOptions = (inputType) => (value) => {
438
540
  elevation="1"
439
541
  max-height="250"
440
542
  class="overflow-y-auto my-1 pa-2"
441
- v-if="props.item.inputType == 'CustomCode' || props.item.validationRules || props.item.inputOptions || props.item.inputAttributes || props.item.columnAttributes || props.item.conditionalDisplay || props.item.computedValue || props.item.retrievedValue"
543
+ v-if="props.item.inputType == 'CustomCode' || props.item.validationRules || props.item.inputOptions || props.item.inputAttributes || props.item.columnAttributes || props.item.conditionalDisplay || props.item.computedValue || props.item.retrievedValue || printConfigPreview(props.item.printConfig)"
442
544
  >
443
545
  <template v-if="props.item.inputType == 'CustomCode'">
444
546
  <b>Custom Code :</b><br>
@@ -466,6 +568,9 @@ const ruleOptions = (inputType) => (value) => {
466
568
  <template v-if="props.item.retrievedValue">
467
569
  <b>Retrieved Value :</b> {{ props.item.retrievedValue }}<br>
468
570
  </template>
571
+ <template v-if="printConfigPreview(props.item.printConfig)">
572
+ <b>Print Config :</b> <code>{{ printConfigPreview(props.item.printConfig) }}</code><br>
573
+ </template>
469
574
  </v-sheet>
470
575
  </template>
471
576
  </FormTable>
@@ -19,7 +19,8 @@ const props = defineProps({
19
19
  operationUpdate: { type: [Object, String], required: false },
20
20
  operationDelete: { type: [Object, String], required: false },
21
21
  operationRead: { type: [Object, String], required: false },
22
- fields: { type: Array, required: false, default: () => ["*"] }
22
+ fields: { type: Array, required: false, default: () => ["*"] },
23
+ importConcurrency: { type: Number, required: false }
23
24
  });
24
25
  const emit = defineEmits(["create", "update"]);
25
26
  const {