@ghentcdh/json-forms-vue 0.8.5 → 1.0.1

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 (72) hide show
  1. package/form.store.d.ts +1 -1
  2. package/forms/Dispatch.vue.d.ts +10 -0
  3. package/forms/FormComponent.properties.d.ts +48 -0
  4. package/{form.component.vue.d.ts → forms/FormComponent.vue.d.ts} +19 -17
  5. package/forms/FormWithActions.properties.d.ts +52 -0
  6. package/forms/FormWithActions.vue.d.ts +258 -0
  7. package/forms/FormWithTable.properties.d.ts +65 -0
  8. package/{form-with-table.component.vue.d.ts → forms/FormWithTable.vue.d.ts} +24 -15
  9. package/forms/errorMessages.d.ts +10 -0
  10. package/forms/errorMode.d.ts +4 -0
  11. package/forms/modal/FormModal.properties.d.ts +64 -0
  12. package/forms/modal/FormModal.vue.d.ts +275 -0
  13. package/{modal/form-modal.service.d.ts → forms/modal/FormModalService.d.ts} +4 -5
  14. package/forms/renderer-registry.d.ts +7 -0
  15. package/forms/renderers/array/ArrayRenderer.vue.d.ts +7 -0
  16. package/forms/renderers/array/ArrayRenderers.d.ts +10 -0
  17. package/forms/renderers/controls/AutocompleteControlRenderer.vue.d.ts +7 -0
  18. package/forms/renderers/controls/BooleanControlRenderer.vue.d.ts +7 -0
  19. package/forms/renderers/controls/MarkdownControlRenderer.vue.d.ts +7 -0
  20. package/forms/renderers/controls/MultiSelectControlRenderer.vue.d.ts +7 -0
  21. package/forms/renderers/controls/NumberControlRenderer.vue.d.ts +7 -0
  22. package/forms/renderers/controls/SelectControlRenderer.vue.d.ts +7 -0
  23. package/forms/renderers/controls/StringControlRenderer.vue.d.ts +7 -0
  24. package/forms/renderers/controls/TextAreaControlRenderer.vue.d.ts +7 -0
  25. package/forms/renderers/controls/composable/UseControlBinding.d.ts +29 -0
  26. package/forms/renderers/controls/composable/UseFetchOption.d.ts +16 -0
  27. package/forms/renderers/controls/composable/UseInput.d.ts +24 -0
  28. package/forms/renderers/controls/composable/UseSelectBinding.d.ts +23 -0
  29. package/forms/renderers/controls/composable/resource.d.ts +187 -0
  30. package/forms/renderers/controls/index.d.ts +10 -0
  31. package/forms/renderers/index.d.ts +3 -0
  32. package/forms/renderers/layout/CollapseLayoutRenderer.vue.d.ts +7 -0
  33. package/forms/renderers/layout/LayoutRenderer.vue.d.ts +7 -0
  34. package/forms/renderers/layout/LayoutRenders.d.ts +10 -0
  35. package/forms/renderers/layout/colspan.d.ts +1 -0
  36. package/forms/renderes.d.ts +19 -0
  37. package/forms/scope.d.ts +4 -0
  38. package/forms/types.d.ts +36 -0
  39. package/index.d.ts +9 -12
  40. package/index.js +1828 -1491
  41. package/index.mjs +1879 -1542
  42. package/package.json +4 -5
  43. package/renderes/tester.d.ts +2 -0
  44. package/form-with-actions.component.properties.d.ts +0 -40
  45. package/form-with-actions.component.vue.d.ts +0 -88
  46. package/form-with-table.component.properties.d.ts +0 -58
  47. package/form.component.properties.d.ts +0 -49
  48. package/modal/form-modal.props.d.ts +0 -30
  49. package/modal/form-modal.vue.d.ts +0 -35
  50. package/modal/index.d.ts +0 -3
  51. package/renderes/array/ArrayRenderer.vue.d.ts +0 -74
  52. package/renderes/array/index.d.ts +0 -76
  53. package/renderes/controls/AutocompleteControlRenderer.vue.d.ts +0 -74
  54. package/renderes/controls/BooleanControlRenderer.vue.d.ts +0 -74
  55. package/renderes/controls/IntegerControlRenderer.vue.d.ts +0 -74
  56. package/renderes/controls/MarkdownControlRenderer.vue.d.ts +0 -74
  57. package/renderes/controls/MultiSelectControlRender.vue.d.ts +0 -74
  58. package/renderes/controls/NumberControlRenderer.vue.d.ts +0 -74
  59. package/renderes/controls/SelectControlRender.vue.d.ts +0 -74
  60. package/renderes/controls/StringControlRenderer.vue.d.ts +0 -74
  61. package/renderes/controls/TextAreaControlRenderer.vue.d.ts +0 -74
  62. package/renderes/controls/index.d.ts +0 -675
  63. package/renderes/index.d.ts +0 -817
  64. package/renderes/layouts/CollapseLayout.vue.d.ts +0 -73
  65. package/renderes/layouts/GridLayout.vue.d.ts +0 -73
  66. package/renderes/layouts/HorizontalLayout.vue.d.ts +0 -73
  67. package/renderes/layouts/VerticalLayout.vue.d.ts +0 -73
  68. package/renderes/layouts/index.d.ts +0 -75
  69. package/standalone/emits.d.ts +0 -5
  70. package/standalone/properties.d.ts +0 -2
  71. package/utils/style.d.ts +0 -6
  72. package/utils/vanillaControl.d.ts +0 -15
package/index.mjs CHANGED
@@ -1,1113 +1,396 @@
1
- import { useApi, Debugger } from "@ghentcdh/tools-vue";
2
- import { NotificationService, Autocomplete, Checkbox, InputNumber, Markdown, MultiSelect, SelectComponent, Input, Textarea, Btn, IconEnum, Collapse, BtnBadge, TextCell, Table, hasCustomEventListener, Card, ModalService, myStyles, Alert, Color, Modal } from "@ghentcdh/ui";
3
- import { uiTypeIs, rankWith, isNumberControl, isIntegerControl, createDefaultValue, composePaths } from "@jsonforms/core";
4
- import { inject, provide, ref, computed, defineComponent, openBlock, createBlock, unref, mergeProps, createElementBlock, createElementVNode, normalizeClass, Fragment, renderList, createVNode, createCommentVNode, withCtx, createTextVNode, normalizeStyle, watch, toDisplayString, withModifiers, toRaw, renderSlot, useModel, mergeModels } from "vue";
5
- import { useJsonFormsControl, rendererProps, useJsonFormsArrayControl, DispatchRenderer, useJsonFormsLayout, JsonForms } from "@jsonforms/vue";
6
- import axios from "axios";
7
- import { useVanillaControl, useVanillaArrayControl, vanillaRenderers } from "@jsonforms/vue-vanilla";
8
- import { pick as pick$1, omit as omit$1, isArray } from "lodash-es";
9
- import { and, optionIs, or, schemaTypeIs, isBooleanControl as isBooleanControl$1 } from "@jsonforms/core/src/testers/testers";
10
- import { ControlType, LayoutTypes, RequestSchema, extractFilters, findColumnDef } from "@ghentcdh/json-forms-core";
1
+ import { defineComponent, ref, watch, openBlock, createElementBlock, createElementVNode, createBlock, unref, withCtx, createTextVNode, createCommentVNode, Fragment, renderList, toDisplayString, computed, createVNode, inject, provide, resolveDynamicComponent, normalizeClass, useModel, mergeProps, renderSlot, mergeModels, isRef, toRef, onMounted, toRaw, nextTick, withModifiers } from "vue";
2
+ import { isArray, isUndefined, pick as pick$1, isEmpty } from "lodash-es";
3
+ import { RequestSchema, extractFilters, findColumnDef, ControlType, uiFromJsonSchema, enforceRequiredStringMinLength } from "@ghentcdh/json-forms-core";
4
+ import { Btn, BtnBadge, IconEnum, BooleanCell, TextCell, Table, mergeStyles, Modal, Color, ModalService, Autocomplete, Checkbox, Markdown, MultiSelect, InputNumber, SelectComponent, Input, Textarea, Collapse, myStyles, NotificationService, hasCustomEventListener, Card } from "@ghentcdh/ui";
11
5
  import { computedAsync } from "@vueuse/core";
12
6
  import { useRoute, useRouter } from "vue-router";
13
- class FormStore {
14
- constructor(uri) {
15
- this.uri = uri;
16
- }
17
- async delete(data) {
18
- return useApi().delete(`${this.uri}/${data.id}`).then(() => {
19
- NotificationService.success("Data deleted");
20
- }).catch((error2) => {
21
- console.error(error2);
22
- NotificationService.error("Error deleting data");
23
- });
24
- }
25
- async save(id, data) {
26
- if (!this.uri) return;
27
- const promise2 = id ? useApi().patch(`${this.uri}/${id}`, data) : useApi().post(this.uri, data);
28
- return promise2.then(() => {
29
- NotificationService.success("Data saved");
30
- }).catch((error2) => {
31
- console.error(error2);
32
- NotificationService.error("Error saving data");
33
- });
34
- }
35
- }
36
- const FormComponentProperties = {
37
- /** Unique id applied to the `<form>` element and used as `<json-forms>` key. */
38
- id: { type: String, required: true },
39
- name: { type: String, default: "form" },
7
+ import { useApi } from "@ghentcdh/tools-vue";
8
+ import { useFieldArray, useField, useFieldValue, useForm } from "vee-validate";
9
+ import { uiTypeIs, rankWith, or as or$1 } from "@jsonforms/core";
10
+ import { and, optionIs, or, schemaTypeIs, isBooleanControl as isBooleanControl$1 } from "@jsonforms/core/src/testers/testers";
11
+ import axios from "axios";
12
+ const FormModalProperties = {
13
+ /** Title displayed in the modal header. */
14
+ modalTitle: { type: String, required: true },
15
+ /** Label for the save button. */
16
+ saveLabel: { type: String, default: "save" },
17
+ /** Label for the cancel button. */
18
+ cancelLabel: { type: String, default: "cancel" },
40
19
  /** JSON schema describing the shape of the form data. */
41
20
  schema: { type: Object, required: true },
42
21
  /** UI schema describing the layout and controls. */
43
22
  uiSchema: { type: Object, required: true },
44
- /** Extra renderer entries merged in front of the built-in tailwind renderers. */
45
- renderers: {
46
- type: Array,
47
- default: void 0
23
+ /** Modal width (`'xs'`, `'sm'`, `'md'`, `'lg'`, `'xl'`). */
24
+ modalSize: { type: String, default: "md" },
25
+ /** Callback invoked when the modal closes (with result or `null` on cancel). */
26
+ onClose: {
27
+ type: Function,
28
+ required: true
48
29
  },
49
- /** Disables all controls inside the form. */
50
- disabled: { type: Boolean, default: false },
51
- formData: { type: Object, default: () => ({}) }
52
- };
53
- const FormComponentEmits = [
54
- /** Emitted whenever validity changes (`true` = no errors). */
55
- "valid",
56
- /** Emitted on every change with the latest form data. */
57
- "change",
58
- /** Emitted when the native form submit fires. Payload: `SubmitFormEvent`. */
59
- "submit",
60
- /** Emitted with the raw Ajv validation errors array. */
61
- "errors",
62
- /** Generic event channel for custom renderer dispatches (`FormEventPayload`). */
63
- "events"
64
- ];
65
- const FormWithActionsProperties = {
66
- /** Unique identifier; the inner form receives `form_${id}` as its id. */
67
- id: { type: String, required: true },
68
- /** Title shown when creating a new record (`formData.id` is falsy). */
69
- createTitle: { type: String, required: true },
70
- /** Title shown when editing an existing record. Falls back to `createTitle`. */
71
- updateTitle: { type: String },
72
- /** JSON schema describing the shape of the form data. */
73
- schema: { type: Object },
74
- /** UI schema describing the layout and controls. */
75
- uiSchema: { type: Object },
76
- /** When provided, the component submits the form to this URI via `FormStore`. */
77
- uri: { type: String },
78
- /** When true, the form content scrolls and the action bar stays pinned. */
79
- scrollable: { type: Boolean, default: false },
80
- /** When true, the component takes the full height of its parent. */
81
- fullHeight: { type: Boolean, default: false }
30
+ /** Callback for form events dispatched by custom renderers. */
31
+ onEvents: {
32
+ type: Function
33
+ },
34
+ /** Initial form data to populate the form with. */
35
+ data: { type: Object, required: true },
36
+ /** When validation errors are shown. */
37
+ errorMode: {
38
+ type: String,
39
+ default: "onBlur"
40
+ }
82
41
  };
83
- const FormWithActionsEmits = [
84
- /** v-model binding. */
85
- "update:modelValue",
86
- /** Emitted after a successful backend save (only when `uri` is defined). */
87
- "success",
88
- /** Emitted with form data when saving without a `uri`. */
89
- "submit",
90
- /** Emitted whenever the form validity changes. */
91
- "valid",
92
- /** Forwards custom renderer events (`FormEventPayload`). */
42
+ const FormModalEmits = [
43
+ /** Emitted when the modal is closed (submit or cancel). */
44
+ "closeModal",
45
+ /** Emitted when a custom renderer dispatches a form event. */
93
46
  "events",
47
+ /** Emitted when validation errors change. */
94
48
  "errors",
95
- /** Emitted when the cancel button is clicked (only visible when editing). */
96
- "cancel"
97
- ];
98
- const FormWithTableProperties = {
99
- /** Unique identifier used to generate the table form id (`form_table_${id}`). */
100
- id: { type: String, required: true },
101
- /** Heading displayed above the table. */
102
- tableTitle: { type: String, required: true },
103
- /** Title shown in the create modal. */
104
- createTitle: { type: String, required: true },
105
- /** Title shown in the edit modal. Falls back to `createTitle`. */
106
- updateTitle: { type: String },
107
- /** Overrides `uri` as the data source for the table. */
108
- dataUri: { type: String },
109
- /** Custom action buttons rendered in each table row. */
110
- tableActions: { type: Array },
111
- /** Layout for the create/edit modal form. */
112
- form: { type: Object },
113
- /** Layout for the table columns. */
114
- table: { type: Object },
115
- /** Layout for the table filter controls. */
116
- filter: { type: Object },
117
- /** Base URI used by `FormStore` for CRUD operations and as the default table data source. */
118
- uri: { type: String },
119
- /** Default data used when opening the create modal. */
120
- initialData: { type: Object, default: () => ({}) }
121
- };
122
- const FormWithTableEmits = [
123
- /** Emitted when a table row is edited and a custom listener is bound. */
124
- "editData",
125
- /** Emitted after a record is successfully saved (created or updated). Payload: `{ id?: string, data: Data }`. */
126
- "save",
127
- /** Emitted after a record is successfully deleted. Payload: the deleted record. */
128
- "delete",
129
- /** Forwarded form events dispatched by custom renderers inside the modal (e.g. "create"). Payload: `FormEventPayload`. */
130
- "events",
131
- "custom:edit",
132
- "custom:create"
49
+ /** Emitted when form validity changes. */
50
+ "valid"
133
51
  ];
134
- const createFormEvents = (dispatch) => ({
135
- dispatch
136
- });
137
- const FORM_EVENTS_KEY = /* @__PURE__ */ Symbol("json-forms:events");
138
- const provideFormEvents = (dispatch) => {
139
- const events = createFormEvents(dispatch);
140
- provide(FORM_EVENTS_KEY, events);
141
- return events;
142
- };
143
- const useFormEvents = () => {
144
- return inject(
145
- FORM_EVENTS_KEY,
146
- createFormEvents(() => {
147
- })
148
- );
149
- };
150
- const useVanillaControlCustom = (input, adaptTarget = (v) => v.value) => {
151
- const vanillaControl = useVanillaControl(input, adaptTarget);
152
- const isTouched = ref(false);
153
- const isFocused = ref(false);
154
- const onFocus = () => {
155
- isFocused.value = true;
156
- };
157
- const onBlur = () => {
158
- isTouched.value = true;
159
- isFocused.value = false;
160
- };
161
- const controlWrapper = computed(() => {
162
- return {
163
- ...vanillaControl.controlWrapper.value,
164
- ...omit$1(vanillaControl.appliedOptions.value, "styles"),
165
- ...pick$1(vanillaControl.appliedOptions.value.styles, ["width"]),
166
- isFocused: isFocused.value,
167
- isTouched: isTouched.value
52
+ const _hoisted_1$8 = { class: "" };
53
+ const _hoisted_2$2 = { class: "flex gap-2 items-center mb-2" };
54
+ const _hoisted_3$1 = { class: "flex gap-2" };
55
+ const _sfc_main$h = /* @__PURE__ */ defineComponent({
56
+ __name: "table-filter",
57
+ props: {
58
+ layout: {},
59
+ filters: {}
60
+ },
61
+ emits: ["changeFilters", "removeFilter"],
62
+ setup(__props, { emit: __emit }) {
63
+ const formData = ref();
64
+ const properties = __props;
65
+ const emits = __emit;
66
+ watch(
67
+ () => properties.filters,
68
+ () => {
69
+ formData.value = {};
70
+ properties.filters.forEach((filter) => {
71
+ formData.value[filter.key] = filter.value;
72
+ });
73
+ },
74
+ { immediate: true }
75
+ );
76
+ const onResetFilters = () => {
77
+ emits("changeFilters", {});
168
78
  };
169
- });
170
- return {
171
- ...vanillaControl,
172
- appliedOptions: vanillaControl.appliedOptions,
173
- controlWrapper,
174
- isFocused,
175
- isTouched,
176
- onFocus,
177
- onBlur
178
- // handleChange,
179
- };
79
+ const removeFilter = (filter) => {
80
+ formData.value[filter.key] = void 0;
81
+ emits("changeFilters", formData.value);
82
+ };
83
+ return (_ctx, _cache) => {
84
+ return openBlock(), createElementBlock("div", _hoisted_1$8, [
85
+ createElementVNode("div", _hoisted_2$2, [
86
+ __props.filters.length ? (openBlock(), createBlock(unref(Btn), {
87
+ key: 0,
88
+ size: "xs",
89
+ outline: true,
90
+ onClick: onResetFilters
91
+ }, {
92
+ default: withCtx(() => [..._cache[0] || (_cache[0] = [
93
+ createTextVNode(" Reset all filters ", -1)
94
+ ])]),
95
+ _: 1
96
+ })) : createCommentVNode("", true)
97
+ ]),
98
+ createElementVNode("div", _hoisted_3$1, [
99
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.filters, (filter) => {
100
+ return openBlock(), createBlock(unref(BtnBadge), {
101
+ key: filter.key,
102
+ icon: unref(IconEnum).Close,
103
+ onClick: ($event) => removeFilter(filter)
104
+ }, {
105
+ default: withCtx(() => [
106
+ createTextVNode(toDisplayString(filter.label) + ": " + toDisplayString(filter.value), 1)
107
+ ]),
108
+ _: 2
109
+ }, 1032, ["icon", "onClick"]);
110
+ }), 128))
111
+ ])
112
+ ]);
113
+ };
114
+ }
115
+ });
116
+ const TableComponentProperties = {
117
+ id: { type: String, required: true },
118
+ uiSchema: { type: Object, required: true },
119
+ schema: { type: Object, required: true },
120
+ filterUiSchema: { type: Object },
121
+ filterSchema: { type: Object },
122
+ uri: { type: String, required: true },
123
+ reload: { type: Number },
124
+ actions: { type: Array }
180
125
  };
181
- const _sfc_main$j = /* @__PURE__ */ defineComponent({
182
- __name: "AutocompleteControlRenderer",
183
- props: { ...rendererProps() },
184
- setup(__props) {
185
- const props = __props;
186
- const {
187
- control,
188
- handleChange: _handleChange,
189
- appliedOptions,
190
- onFocus,
191
- onBlur,
192
- controlWrapper
193
- } = useVanillaControlCustom(useJsonFormsControl(props));
194
- const bindProperties = computed(() => ({
195
- ...controlWrapper.value,
196
- ...appliedOptions.value,
197
- enableCreate: !!appliedOptions.value.enableCreate
198
- }));
199
- const fetchOptions = computed(() => {
200
- const options = appliedOptions.value;
201
- if (!options.uri) return null;
202
- return (searchTerm, signal) => {
203
- const fetch = options.skipAuth ? axios : useApi();
204
- return fetch.get(`${options.uri}${searchTerm}`, { signal }).then((data) => data.data[options.dataField ?? "data"]);
126
+ const TableComponentEmits = ["delete", "edit"];
127
+ class TableStore {
128
+ constructor() {
129
+ this.route = useRoute();
130
+ this.router = useRouter();
131
+ this.requestData = ref(RequestSchema.parse(this.route.query));
132
+ this._reload = ref(Date.now());
133
+ this.loading = ref(true);
134
+ this.uri = ref("");
135
+ this.data = computedAsync(async () => {
136
+ this._reload.value;
137
+ if (!this.uri.value) return null;
138
+ this.loading.value = true;
139
+ if (this.requestData.value.page < 1) {
140
+ this.requestData.value.page = 1;
141
+ }
142
+ const response = await useApi().get(this.uri.value, {
143
+ params: this.requestData.value
144
+ }).catch((error2) => {
145
+ console.error(error2);
146
+ return { data: [], request: { totalPages: 1, page: 1 } };
147
+ }).finally(() => this.loading.value = false);
148
+ const data = response.data;
149
+ if (data.request.totalPages < data.request.page) {
150
+ this.updateRequest({ page: data.request.totalPages });
151
+ }
152
+ return data;
153
+ });
154
+ this.pageData = computed(() => {
155
+ const request = this.data.value?.request ?? {
156
+ count: 0,
157
+ pageSize: 1,
158
+ page: 1
159
+ };
160
+ return {
161
+ count: request.count,
162
+ pageSize: request.pageSize,
163
+ page: request.page
205
164
  };
206
165
  });
207
- const handleChange = (result) => {
208
- const { path } = control.value;
209
- _handleChange(path, result);
166
+ this.tableData = computed(() => {
167
+ const d = this.data.value;
168
+ if (!d) return [];
169
+ if (this.loading.value) return [];
170
+ return d.data ?? [];
171
+ });
172
+ this.init = (url2) => {
173
+ this.uri.value = url2;
210
174
  };
211
- const formEvents = useFormEvents();
212
- const create = () => {
213
- formEvents.dispatch({
214
- event: "create",
215
- type: control.value.path,
216
- onSuccess: (result) => {
217
- handleChange(result);
175
+ this.updateRequest = (data) => {
176
+ this.requestData.value = { ...this.requestData.value, ...data };
177
+ this.router.replace({
178
+ query: {
179
+ ...this.route.query,
180
+ ...this.requestData.value
218
181
  }
219
182
  });
220
183
  };
221
- return (_ctx, _cache) => {
222
- return openBlock(), createBlock(unref(Autocomplete), mergeProps(bindProperties.value, {
223
- "model-value": unref(control).data,
224
- enabled: unref(control).enabled,
225
- "fetch-options": fetchOptions.value,
226
- onChange: handleChange,
227
- onFocus: unref(onFocus),
228
- onBlur: unref(onBlur),
229
- onCreate: _cache[0] || (_cache[0] = ($event) => create())
230
- }), null, 16, ["model-value", "enabled", "fetch-options", "onFocus", "onBlur"]);
184
+ this.sort = (id) => {
185
+ const sortDir = this.requestData.value.sort === id && this.requestData.value.sortDir === "asc" ? "desc" : "asc";
186
+ this.updateRequest({ sort: id, sortDir });
231
187
  };
232
- }
233
- });
234
- const _sfc_main$i = /* @__PURE__ */ defineComponent({
235
- __name: "BooleanControlRenderer",
236
- props: { ...rendererProps() },
237
- setup(__props) {
238
- const props = __props;
239
- const { control, onChange, appliedOptions, onFocus, onBlur, controlWrapper } = useVanillaControlCustom(useJsonFormsControl(props), (target) => {
240
- return Boolean(target.value) ?? false;
241
- });
242
- return (_ctx, _cache) => {
243
- return openBlock(), createBlock(unref(Checkbox), mergeProps(unref(controlWrapper), {
244
- "model-value": unref(control).data,
245
- enabled: unref(control).enabled,
246
- config: unref(appliedOptions),
247
- onChange: unref(onChange),
248
- onFocus: unref(onFocus),
249
- onBlur: unref(onBlur)
250
- }), null, 16, ["model-value", "enabled", "config", "onChange", "onFocus", "onBlur"]);
188
+ this.updateFilters = (filters) => {
189
+ const filter = [];
190
+ Object.entries(filters).forEach(([key, value]) => {
191
+ if (!value) return;
192
+ const operator = value?.operator || "contains";
193
+ filter.push(`${key}:${value}:${operator}`);
194
+ });
195
+ this.updateRequest({ filter });
251
196
  };
197
+ this.sorting = computed(() => {
198
+ const requestData = this.requestData.value;
199
+ return {
200
+ sortColumn: requestData.sort,
201
+ sortDirection: requestData.sortDir ?? "asc"
202
+ };
203
+ });
204
+ this.filters = computed(
205
+ () => extractFilters(this.requestData.value.filter)
206
+ );
252
207
  }
253
- });
254
- const _sfc_main$h = /* @__PURE__ */ defineComponent({
255
- __name: "IntegerControlRenderer",
256
- props: { ...rendererProps() },
257
- setup(__props) {
258
- const props = __props;
259
- const { control, onChange, appliedOptions, onFocus, onBlur, controlWrapper } = useVanillaControlCustom(
260
- useJsonFormsControl(props),
261
- (target) => target.value === "" ? void 0 : Number(target.value)
262
- );
263
- const steps = computed(() => appliedOptions.value.steps ?? 1);
264
- return (_ctx, _cache) => {
265
- return openBlock(), createBlock(unref(InputNumber), mergeProps(unref(controlWrapper), {
266
- "model-value": unref(control).data,
267
- enabled: unref(control).enabled,
268
- config: unref(appliedOptions),
269
- steps: steps.value,
270
- onChange: unref(onChange),
271
- onFocus: unref(onFocus),
272
- onBlur: unref(onBlur)
273
- }), null, 16, ["model-value", "enabled", "config", "steps", "onChange", "onFocus", "onBlur"]);
274
- };
275
- }
276
- });
277
- const _sfc_main$g = /* @__PURE__ */ defineComponent({
278
- __name: "MarkdownControlRenderer",
279
- props: { ...rendererProps() },
280
- setup(__props) {
281
- const props = __props;
282
- const {
283
- control,
284
- handleChange,
285
- appliedOptions,
286
- onFocus,
287
- onBlur,
288
- controlWrapper
289
- } = useVanillaControlCustom(useJsonFormsControl(props));
290
- const changeValue = (value) => {
291
- handleChange(control.value.path, value);
292
- };
293
- return (_ctx, _cache) => {
294
- return openBlock(), createBlock(unref(Markdown), mergeProps(unref(controlWrapper), {
295
- "model-value": unref(control).data,
296
- enabled: unref(control).enabled,
297
- config: unref(appliedOptions),
298
- onChange: changeValue,
299
- onFocus: unref(onFocus),
300
- onBlur: unref(onBlur)
301
- }), null, 16, ["model-value", "enabled", "config", "onFocus", "onBlur"]);
302
- };
303
- }
304
- });
305
- const _sfc_main$f = /* @__PURE__ */ defineComponent({
306
- __name: "MultiSelectControlRender",
307
- props: { ...rendererProps() },
308
- setup(__props) {
309
- const props = __props;
310
- const {
311
- control,
312
- handleChange: _handleChange,
313
- onFocus,
314
- onBlur,
315
- controlWrapper
316
- } = useVanillaControlCustom(useJsonFormsControl(props));
317
- const handleChange = (result) => {
318
- const { path } = control.value;
319
- _handleChange(path, result);
320
- };
321
- return (_ctx, _cache) => {
322
- return openBlock(), createBlock(unref(MultiSelect), mergeProps(unref(controlWrapper), {
323
- "model-value": unref(control).data,
324
- enabled: unref(control).enabled,
325
- onChange: handleChange,
326
- onFocus: unref(onFocus),
327
- onBlur: unref(onBlur)
328
- }), null, 16, ["model-value", "enabled", "onFocus", "onBlur"]);
329
- };
330
- }
331
- });
332
- const _sfc_main$e = /* @__PURE__ */ defineComponent({
333
- __name: "NumberControlRenderer",
334
- props: { ...rendererProps() },
335
- setup(__props) {
336
- const props = __props;
337
- const { control, onChange, appliedOptions, onFocus, onBlur, controlWrapper } = useVanillaControlCustom(
338
- useJsonFormsControl(props),
339
- (target) => target.value === "" ? void 0 : Number(target.value)
340
- );
341
- const steps = computed(() => appliedOptions.value.steps ?? 0.01);
342
- return (_ctx, _cache) => {
343
- return openBlock(), createBlock(unref(InputNumber), mergeProps(unref(controlWrapper), {
344
- "model-value": unref(control).data,
345
- enabled: unref(control).enabled,
346
- config: unref(appliedOptions),
347
- steps: steps.value,
348
- onChange: unref(onChange),
349
- onFocus: unref(onFocus),
350
- onBlur: unref(onBlur)
351
- }), null, 16, ["model-value", "enabled", "config", "steps", "onChange", "onFocus", "onBlur"]);
352
- };
208
+ get httpRequest() {
209
+ return useApi();
353
210
  }
354
- });
355
- const _sfc_main$d = /* @__PURE__ */ defineComponent({
356
- __name: "SelectControlRender",
357
- props: { ...rendererProps() },
358
- setup(__props) {
359
- const props = __props;
360
- const {
361
- control,
362
- handleChange: _handleChange,
363
- appliedOptions,
364
- onFocus,
365
- onBlur,
366
- controlWrapper
367
- } = useVanillaControlCustom(useJsonFormsControl(props));
368
- const handleChange = (result) => {
369
- const { path } = control.value;
370
- _handleChange(path, result);
371
- };
372
- return (_ctx, _cache) => {
373
- return openBlock(), createBlock(unref(SelectComponent), mergeProps(unref(controlWrapper), {
374
- "model-value": unref(control).data,
375
- enabled: unref(control).enabled,
376
- options: unref(appliedOptions)?.options,
377
- onChange: handleChange,
378
- onFocus: unref(onFocus),
379
- onBlur: unref(onBlur)
380
- }), null, 16, ["model-value", "enabled", "options", "onFocus", "onBlur"]);
381
- };
211
+ reload() {
212
+ this._reload.value = Date.now();
382
213
  }
383
- });
384
- const _sfc_main$c = /* @__PURE__ */ defineComponent({
385
- __name: "StringControlRenderer",
386
- props: { ...rendererProps() },
387
- setup(__props) {
388
- const props = __props;
389
- const {
390
- control,
391
- onChange,
392
- appliedOptions,
393
- onFocus,
394
- onBlur,
395
- controlWrapper,
396
- styles
397
- } = useVanillaControlCustom(useJsonFormsControl(props));
398
- return (_ctx, _cache) => {
399
- return openBlock(), createBlock(unref(Input), mergeProps(unref(controlWrapper), {
400
- "model-value": unref(control).data,
401
- enabled: unref(control).enabled,
402
- config: unref(appliedOptions),
403
- styles: unref(styles),
404
- onChange: unref(onChange),
405
- onFocus: unref(onFocus),
406
- onBlur: unref(onBlur)
407
- }), null, 16, ["model-value", "enabled", "config", "styles", "onChange", "onFocus", "onBlur"]);
408
- };
214
+ updatePage(page) {
215
+ this.updateRequest({ page });
409
216
  }
410
- });
411
- const _sfc_main$b = /* @__PURE__ */ defineComponent({
412
- __name: "TextAreaControlRenderer",
413
- props: { ...rendererProps() },
414
- setup(__props) {
415
- const props = __props;
416
- const { control, onChange, appliedOptions, onFocus, onBlur, controlWrapper } = useVanillaControlCustom(useJsonFormsControl(props));
417
- return (_ctx, _cache) => {
418
- return openBlock(), createBlock(unref(Textarea), mergeProps(unref(controlWrapper), {
419
- "model-value": unref(control).data,
420
- enabled: unref(control).enabled,
421
- config: unref(appliedOptions),
422
- onChange: unref(onChange),
423
- onFocus: unref(onFocus),
424
- onBlur: unref(onBlur)
425
- }), null, 16, ["model-value", "enabled", "config", "onChange", "onFocus", "onBlur"]);
426
- };
217
+ }
218
+ const tableCache = /* @__PURE__ */ new Map();
219
+ const useTableStore = (name) => {
220
+ const tableStore = tableCache.get(name);
221
+ if (tableStore) {
222
+ return tableStore;
427
223
  }
428
- });
429
- const isAutoCompleteControl = and(
430
- // uiTypeIs('Control'),
431
- optionIs("format", ControlType.autocomplete)
432
- );
433
- const isTextAreaControl = and(
434
- uiTypeIs("Control"),
435
- optionIs("format", ControlType.textArea)
436
- );
437
- const isStringFormat = and(
438
- uiTypeIs("Control"),
439
- or(optionIs("format", ControlType.string), schemaTypeIs("string"))
440
- );
441
- const isMarkdownControl = and(
442
- uiTypeIs("Control"),
443
- optionIs("format", ControlType.markdown)
444
- );
445
- const isArrayRenderer = and(
446
- schemaTypeIs("array")
447
- // optionIs('format', ControlType.array),
448
- );
449
- const isCustomControl = (customType) => {
450
- return and(
451
- optionIs("format", ControlType.custom),
452
- optionIs("type", customType)
453
- );
224
+ const newTableStore = new TableStore();
225
+ tableCache.set(name, newTableStore);
226
+ return newTableStore;
454
227
  };
455
- const isMultiselectControl = and(
456
- uiTypeIs("Control"),
457
- optionIs("format", ControlType.mutliSelect)
458
- );
459
- const isSelectControl = and(
460
- uiTypeIs("Control"),
461
- optionIs("format", ControlType.select)
462
- );
463
- const isBooleanControl = or(
464
- isBooleanControl$1,
465
- and(uiTypeIs("Control"), optionIs("format", ControlType.boolean))
466
- );
467
- const controlRenderers = [
468
- // First custom renderers on format
469
- {
470
- tester: rankWith(10, isMarkdownControl),
471
- renderer: _sfc_main$g
472
- },
473
- {
474
- tester: rankWith(10, isAutoCompleteControl),
475
- renderer: _sfc_main$j
476
- },
477
- {
478
- tester: rankWith(10, isTextAreaControl),
479
- renderer: _sfc_main$b
480
- },
481
- // Renderers based on type if no format is provided
482
- { tester: rankWith(10, isStringFormat), renderer: _sfc_main$c },
483
- { tester: rankWith(10, isSelectControl), renderer: _sfc_main$d },
484
- {
485
- tester: rankWith(10, isMultiselectControl),
486
- renderer: _sfc_main$f
487
- },
488
- { tester: rankWith(10, isNumberControl), renderer: _sfc_main$e },
489
- {
490
- tester: rankWith(10, isIntegerControl),
491
- renderer: _sfc_main$h
492
- },
493
- { tester: rankWith(10, isBooleanControl), renderer: _sfc_main$i }
494
- ];
495
- const _hoisted_1$9 = ["title"];
496
- const _hoisted_2$2 = { key: 0 };
497
- const _hoisted_3$1 = {
498
- key: 1,
499
- class: "list-row"
228
+ const _hoisted_1$7 = {
229
+ key: 0,
230
+ class: "mb-2"
500
231
  };
501
- const _sfc_main$a = /* @__PURE__ */ defineComponent({
502
- __name: "ArrayRenderer",
503
- props: { ...rendererProps() },
504
- setup(__props) {
505
- const props = __props;
506
- const vanillaArrayControl = useVanillaArrayControl(
507
- useJsonFormsArrayControl(props)
232
+ const _sfc_main$g = /* @__PURE__ */ defineComponent({
233
+ __name: "table.component",
234
+ props: TableComponentProperties,
235
+ emits: TableComponentEmits,
236
+ setup(__props, { emit: __emit }) {
237
+ const properties = __props;
238
+ const emit = __emit;
239
+ watch(
240
+ () => properties.reload,
241
+ () => {
242
+ store.reload();
243
+ }
508
244
  );
509
- const { styles, childUiSchema, control, appliedOptions } = vanillaArrayControl;
510
- if (!control.value.data || control.value.data.length < 1) {
511
- vanillaArrayControl.addItem(
512
- control.value.path,
513
- createDefaultValue(control.value.schema, control.value.rootSchema)
514
- )();
515
- }
516
- const noData = computed(
517
- () => !control.value.data || control.value.data.length === 0
245
+ let store = useTableStore(properties.id);
246
+ watch(
247
+ () => properties.uri,
248
+ () => {
249
+ store.init(properties.uri);
250
+ },
251
+ { immediate: true }
518
252
  );
519
- const showDelete = computed(() => control.value.data?.length > 1);
520
- const deleteButtonClick = (index) => {
521
- vanillaArrayControl.removeItems(control.value.path, [index])();
253
+ const edit = (data) => {
254
+ emit("edit", data);
255
+ };
256
+ const deleteFn = (data) => {
257
+ emit("delete", data);
258
+ };
259
+ const components = {
260
+ TextCell,
261
+ BooleanCell
262
+ };
263
+ const displayColumns = computed(() => {
264
+ return properties.uiSchema.elements.map((e) => {
265
+ const element = e;
266
+ const def = findColumnDef(element, properties.schema);
267
+ const type = isArray(def.type) ? def.type[0] : def.type;
268
+ let component;
269
+ if (element.options?.format && element.options.format in components) {
270
+ component = components[element.options.format];
271
+ } else {
272
+ component = components[element.type];
273
+ }
274
+ if (!component) console.warn("No component found for type", element.type);
275
+ return {
276
+ ...def,
277
+ type,
278
+ component
279
+ };
280
+ });
281
+ });
282
+ const onChangeFilters = (filters) => {
283
+ store.updateFilters(filters);
284
+ };
285
+ const onUpdatePage = (page) => {
286
+ store.updatePage(page);
522
287
  };
523
- const addButtonClick = () => {
524
- vanillaArrayControl.addItem(
525
- control.value.path,
526
- createDefaultValue(control.value.schema, control.value.rootSchema)
527
- )();
288
+ const onSort = (id) => {
289
+ store.sort(id);
528
290
  };
529
- const showActions = computed(() => {
530
- return !appliedOptions.value.hideActions;
291
+ const sort = computed(() => {
292
+ return store.sorting.value ?? { orderBy: "", ascending: 1 };
531
293
  });
532
294
  return (_ctx, _cache) => {
533
- return openBlock(), createElementBlock("div", {
534
- title: unref(control).label
535
- }, [
536
- createElementVNode("div", {
537
- class: normalizeClass([
538
- "flex gap-2",
539
- unref(appliedOptions)?.layout === "row" ? "flex-row items-center" : "flex-col"
540
- ])
541
- }, [
542
- (openBlock(true), createElementBlock(Fragment, null, renderList(unref(control).data, (element, index) => {
543
- return openBlock(), createElementBlock("div", {
544
- key: `${unref(control).path}-${index}`,
545
- class: "flex-1"
546
- }, [
547
- createElementVNode("div", {
548
- class: normalizeClass([
549
- "flex gap-2",
550
- unref(appliedOptions)?.layout === "row" ? "flex-col" : "flex-row items-center"
551
- ])
552
- }, [
553
- createElementVNode("div", null, [
554
- createVNode(unref(DispatchRenderer), {
555
- schema: unref(control).schema,
556
- uischema: unref(childUiSchema),
557
- path: unref(composePaths)(unref(control).path, `${index}`),
558
- enabled: unref(control).enabled,
559
- renderers: unref(control).renderers,
560
- cells: unref(control).cells
561
- }, null, 8, ["schema", "uischema", "path", "enabled", "renderers", "cells"])
562
- ]),
563
- showActions.value ? (openBlock(), createElementBlock("div", _hoisted_2$2, [
564
- showDelete.value ? (openBlock(), createBlock(unref(Btn), {
565
- key: 0,
566
- icon: unref(IconEnum).Delete,
567
- outline: true,
568
- onClick: ($event) => deleteButtonClick(index)
569
- }, null, 8, ["icon", "onClick"])) : createCommentVNode("", true)
570
- ])) : createCommentVNode("", true)
571
- ], 2)
572
- ]);
573
- }), 128)),
574
- noData.value ? (openBlock(), createElementBlock("div", {
575
- key: 0,
576
- class: normalizeClass(["list-row", unref(styles).arrayList.noData])
577
- }, " No data ", 2)) : createCommentVNode("", true),
578
- showActions.value ? (openBlock(), createElementBlock("div", _hoisted_3$1, [
579
- createVNode(unref(Btn), {
580
- icon: unref(IconEnum).Plus,
581
- outline: true,
582
- onClick: addButtonClick
583
- }, {
584
- default: withCtx(() => [..._cache[0] || (_cache[0] = [
585
- createTextVNode(" Add ", -1)
586
- ])]),
587
- _: 1
588
- }, 8, ["icon"])
589
- ])) : createCommentVNode("", true)
590
- ], 2)
591
- ], 8, _hoisted_1$9);
295
+ return openBlock(), createElementBlock("div", null, [
296
+ _ctx.filterUiSchema && _ctx.filterSchema ? (openBlock(), createElementBlock("div", _hoisted_1$7, [
297
+ createVNode(_sfc_main$h, {
298
+ layout: { uiSchema: _ctx.filterUiSchema, schema: _ctx.filterSchema },
299
+ filters: unref(store).filters.value,
300
+ onChangeFilters
301
+ }, null, 8, ["layout", "filters"])
302
+ ])) : createCommentVNode("", true),
303
+ createElementVNode("div", null, [
304
+ createVNode(unref(Table), {
305
+ "display-columns": displayColumns.value,
306
+ sort: sort.value,
307
+ page: unref(store).pageData.value,
308
+ loading: unref(store).loading.value,
309
+ data: unref(store).tableData.value,
310
+ actions: _ctx.actions,
311
+ onUpdatePage,
312
+ onDelete: deleteFn,
313
+ onEdit: edit,
314
+ onSort
315
+ }, null, 8, ["display-columns", "sort", "page", "loading", "data", "actions"])
316
+ ])
317
+ ]);
592
318
  };
593
319
  }
594
320
  });
595
- const arrayRenderers = [
596
- {
597
- tester: rankWith(12, isArrayRenderer),
598
- renderer: _sfc_main$a
599
- }
600
- ];
601
- const _hoisted_1$8 = { class: "flex flex-col gap-4" };
602
- const _sfc_main$9 = /* @__PURE__ */ defineComponent({
603
- __name: "CollapseLayout",
604
- props: { ...rendererProps() },
605
- setup(__props) {
606
- const props = __props;
607
- const jsonLayout = useJsonFormsLayout(props);
608
- const { layout, renderers, cells } = jsonLayout;
609
- const title = computed(() => {
610
- const { titleKey, title: title2 } = layout?.value.uischema?.options ?? {};
611
- if (title2) return title2;
612
- if (titleKey) return layout?.value.data[titleKey];
613
- return layout?.value.uischema?.options?.titleKey;
614
- });
615
- return (_ctx, _cache) => {
616
- return openBlock(), createBlock(unref(Collapse), { title: title.value }, {
617
- default: withCtx(() => [
618
- createElementVNode("div", _hoisted_1$8, [
619
- (openBlock(true), createElementBlock(Fragment, null, renderList(unref(layout).uischema.elements, (element, index) => {
620
- return openBlock(), createBlock(unref(DispatchRenderer), {
621
- key: index,
622
- schema: unref(layout).schema,
623
- uischema: element,
624
- path: unref(layout).path,
625
- renderers: unref(renderers),
626
- cells: unref(cells)
627
- }, null, 8, ["schema", "uischema", "path", "renderers", "cells"]);
628
- }), 128))
629
- ])
630
- ]),
631
- _: 1
632
- }, 8, ["title"]);
633
- };
634
- }
635
- });
636
- const _hoisted_1$7 = {
637
- class: "grid gap-4 items-center",
638
- style: { "grid-template-columns": "repeat(12, 1fr)" }
639
- };
640
- const _sfc_main$8 = /* @__PURE__ */ defineComponent({
641
- __name: "GridLayout",
642
- props: { ...rendererProps() },
643
- setup(__props) {
644
- const props = __props;
645
- const { layout, renderers, cells } = useJsonFormsLayout(props);
646
- return (_ctx, _cache) => {
647
- return openBlock(), createElementBlock("div", _hoisted_1$7, [
648
- (openBlock(true), createElementBlock(Fragment, null, renderList(unref(layout).uischema.elements, (element, index) => {
649
- return openBlock(), createElementBlock("div", {
650
- key: index,
651
- style: normalizeStyle({
652
- "grid-column": `span ${element.options?.colspan ?? 12}`
653
- })
654
- }, [
655
- createVNode(unref(DispatchRenderer), {
656
- schema: unref(layout).schema,
657
- uischema: element,
658
- path: unref(layout).path,
659
- renderers: unref(renderers),
660
- cells: unref(cells)
661
- }, null, 8, ["schema", "uischema", "path", "renderers", "cells"])
662
- ], 4);
663
- }), 128))
664
- ]);
665
- };
666
- }
667
- });
668
- const _hoisted_1$6 = { class: "flex flex-row gap-4 items-center" };
669
- const _sfc_main$7 = /* @__PURE__ */ defineComponent({
670
- __name: "HorizontalLayout",
671
- props: { ...rendererProps() },
672
- setup(__props) {
673
- const props = __props;
674
- const { layout, renderers, cells } = useJsonFormsLayout(props);
675
- return (_ctx, _cache) => {
676
- return openBlock(), createElementBlock("div", _hoisted_1$6, [
677
- (openBlock(true), createElementBlock(Fragment, null, renderList(unref(layout).uischema.elements, (element, index) => {
678
- return openBlock(), createBlock(unref(DispatchRenderer), {
679
- key: index,
680
- schema: unref(layout).schema,
681
- uischema: element,
682
- path: unref(layout).path,
683
- renderers: unref(renderers),
684
- cells: unref(cells)
685
- }, null, 8, ["schema", "uischema", "path", "renderers", "cells"]);
686
- }), 128))
687
- ]);
688
- };
689
- }
690
- });
691
- const _hoisted_1$5 = { class: "flex flex-col gap-4" };
692
- const _sfc_main$6 = /* @__PURE__ */ defineComponent({
693
- __name: "VerticalLayout",
694
- props: { ...rendererProps() },
695
- setup(__props) {
696
- const props = __props;
697
- const { layout, renderers, cells } = useJsonFormsLayout(props);
698
- return (_ctx, _cache) => {
699
- return openBlock(), createElementBlock("div", _hoisted_1$5, [
700
- (openBlock(true), createElementBlock(Fragment, null, renderList(unref(layout).uischema.elements, (element, index) => {
701
- return openBlock(), createBlock(unref(DispatchRenderer), {
702
- key: index,
703
- schema: unref(layout).schema,
704
- uischema: element,
705
- path: unref(layout).path,
706
- renderers: unref(renderers),
707
- cells: unref(cells)
708
- }, null, 8, ["schema", "uischema", "path", "renderers", "cells"]);
709
- }), 128))
710
- ]);
711
- };
712
- }
713
- });
714
- const layoutRenderers = [
715
- {
716
- tester: rankWith(10, uiTypeIs(LayoutTypes.VerticalLayout)),
717
- renderer: _sfc_main$6
718
- },
719
- {
720
- tester: rankWith(10, uiTypeIs(LayoutTypes.HorizontalLayout)),
721
- renderer: _sfc_main$7
722
- },
723
- {
724
- tester: rankWith(10, uiTypeIs(LayoutTypes.CollapseLayout)),
725
- renderer: _sfc_main$9
726
- },
727
- {
728
- tester: rankWith(10, uiTypeIs(LayoutTypes.GridLayout)),
729
- renderer: _sfc_main$8
730
- }
731
- ];
732
- const _hoisted_1$4 = { class: "" };
733
- const _hoisted_2$1 = { class: "flex gap-2 items-center mb-2" };
734
- const _hoisted_3 = { class: "flex gap-2" };
735
- const _sfc_main$5 = /* @__PURE__ */ defineComponent({
736
- __name: "table-filter",
737
- props: {
738
- layout: {},
739
- filters: {}
740
- },
741
- emits: ["changeFilters", "removeFilter"],
742
- setup(__props, { emit: __emit }) {
743
- const formData = ref();
744
- const properties = __props;
745
- const emits = __emit;
746
- watch(
747
- () => properties.filters,
748
- () => {
749
- formData.value = {};
750
- properties.filters.forEach((filter) => {
751
- formData.value[filter.key] = filter.value;
752
- });
753
- },
754
- { immediate: true }
755
- );
756
- const onResetFilters = () => {
757
- emits("changeFilters", {});
758
- };
759
- const removeFilter = (filter) => {
760
- formData.value[filter.key] = void 0;
761
- emits("changeFilters", formData.value);
762
- };
763
- return (_ctx, _cache) => {
764
- return openBlock(), createElementBlock("div", _hoisted_1$4, [
765
- createElementVNode("div", _hoisted_2$1, [
766
- __props.filters.length ? (openBlock(), createBlock(unref(Btn), {
767
- key: 0,
768
- size: "xs",
769
- outline: true,
770
- onClick: onResetFilters
771
- }, {
772
- default: withCtx(() => [..._cache[0] || (_cache[0] = [
773
- createTextVNode(" Reset all filters ", -1)
774
- ])]),
775
- _: 1
776
- })) : createCommentVNode("", true)
777
- ]),
778
- createElementVNode("div", _hoisted_3, [
779
- (openBlock(true), createElementBlock(Fragment, null, renderList(__props.filters, (filter) => {
780
- return openBlock(), createBlock(unref(BtnBadge), {
781
- key: filter.key,
782
- icon: unref(IconEnum).Close,
783
- onClick: ($event) => removeFilter(filter)
784
- }, {
785
- default: withCtx(() => [
786
- createTextVNode(toDisplayString(filter.label) + ": " + toDisplayString(filter.value), 1)
787
- ]),
788
- _: 2
789
- }, 1032, ["icon", "onClick"]);
790
- }), 128))
791
- ])
792
- ]);
793
- };
794
- }
795
- });
796
- const TableComponentProperties = {
797
- id: { type: String, required: true },
798
- uiSchema: { type: Object, required: true },
799
- schema: { type: Object, required: true },
800
- filterUiSchema: { type: Object },
801
- filterSchema: { type: Object },
802
- uri: { type: String, required: true },
803
- reload: { type: Number },
804
- actions: { type: Array }
805
- };
806
- const TableComponentEmits = ["delete", "edit"];
807
- class TableStore {
808
- constructor() {
809
- this.route = useRoute();
810
- this.router = useRouter();
811
- this.requestData = ref(RequestSchema.parse(this.route.query));
812
- this._reload = ref(Date.now());
813
- this.loading = ref(true);
814
- this.uri = ref("");
815
- this.data = computedAsync(async () => {
816
- this._reload.value;
817
- if (!this.uri.value) return null;
818
- this.loading.value = true;
819
- if (this.requestData.value.page < 1) {
820
- this.requestData.value.page = 1;
821
- }
822
- const response = await useApi().get(this.uri.value, {
823
- params: this.requestData.value
824
- }).catch((error2) => {
825
- console.error(error2);
826
- return { data: [], request: { totalPages: 1, page: 1 } };
827
- }).finally(() => this.loading.value = false);
828
- const data = response.data;
829
- if (data.request.totalPages < data.request.page) {
830
- this.updateRequest({ page: data.request.totalPages });
831
- }
832
- return data;
833
- });
834
- this.pageData = computed(() => {
835
- const request = this.data.value?.request ?? {
836
- count: 0,
837
- pageSize: 1,
838
- page: 1
839
- };
840
- return {
841
- count: request.count,
842
- pageSize: request.pageSize,
843
- page: request.page
844
- };
845
- });
846
- this.tableData = computed(() => {
847
- const d = this.data.value;
848
- if (!d) return [];
849
- if (this.loading.value) return [];
850
- return d.data ?? [];
321
+ const createRepository = (formSchemaModel, httpRequest, options = {}) => {
322
+ const notificationEntity = options.notification?.entityType || "entity";
323
+ const notificationStore = options.notification?.notification ?? null;
324
+ const getDataUri = (...suffix) => {
325
+ return [formSchemaModel.uri, ...suffix].join("/");
326
+ };
327
+ const handleSuccess = (message) => {
328
+ notificationStore?.success(message);
329
+ };
330
+ const handleError = (error2, message) => {
331
+ console.error(error2);
332
+ notificationStore?.error(message);
333
+ throw new Error(error2);
334
+ };
335
+ const create = (object2, options2) => {
336
+ return httpRequest.post(getDataUri(), object2, options2).then((response) => {
337
+ handleSuccess(`Created ${notificationEntity}`);
338
+ return response.data;
339
+ }).catch((response) => {
340
+ handleError(response, `Failed to create ${notificationEntity}`);
851
341
  });
852
- this.init = (url2) => {
853
- this.uri.value = url2;
854
- };
855
- this.updateRequest = (data) => {
856
- this.requestData.value = { ...this.requestData.value, ...data };
857
- this.router.replace({
858
- query: {
859
- ...this.route.query,
860
- ...this.requestData.value
861
- }
862
- });
863
- };
864
- this.sort = (id) => {
865
- const sortDir = this.requestData.value.sort === id && this.requestData.value.sortDir === "asc" ? "desc" : "asc";
866
- this.updateRequest({ sort: id, sortDir });
867
- };
868
- this.updateFilters = (filters) => {
869
- const filter = [];
870
- Object.entries(filters).forEach(([key, value]) => {
871
- if (!value) return;
872
- const operator = value?.operator || "contains";
873
- filter.push(`${key}:${value}:${operator}`);
874
- });
875
- this.updateRequest({ filter });
876
- };
877
- this.sorting = computed(() => {
878
- const requestData = this.requestData.value;
879
- return {
880
- sortColumn: requestData.sort,
881
- sortDirection: requestData.sortDir ?? "asc"
882
- };
342
+ };
343
+ const patch = (id, object2, options2) => {
344
+ return httpRequest.patch(getDataUri(id), object2, options2).then((response) => {
345
+ handleSuccess(`Saved ${notificationEntity}`);
346
+ return response.data;
347
+ }).catch((response) => {
348
+ handleError(response, `Failed to save ${notificationEntity}`);
883
349
  });
884
- this.filters = computed(
885
- () => extractFilters(this.requestData.value.filter)
886
- );
887
- }
888
- get httpRequest() {
889
- return useApi();
890
- }
891
- reload() {
892
- this._reload.value = Date.now();
893
- }
894
- updatePage(page) {
895
- this.updateRequest({ page });
896
- }
897
- }
898
- const tableCache = /* @__PURE__ */ new Map();
899
- const useTableStore = (name) => {
900
- const tableStore = tableCache.get(name);
901
- if (tableStore) {
902
- return tableStore;
903
- }
904
- const newTableStore = new TableStore();
905
- tableCache.set(name, newTableStore);
906
- return newTableStore;
907
- };
908
- const _hoisted_1$3 = {
909
- key: 0,
910
- class: "mb-2"
911
- };
912
- const _sfc_main$4 = /* @__PURE__ */ defineComponent({
913
- __name: "table.component",
914
- props: TableComponentProperties,
915
- emits: TableComponentEmits,
916
- setup(__props, { emit: __emit }) {
917
- const properties = __props;
918
- const emit = __emit;
919
- watch(
920
- () => properties.reload,
921
- () => {
922
- store.reload();
923
- }
924
- );
925
- let store = useTableStore(properties.id);
926
- watch(
927
- () => properties.uri,
928
- () => {
929
- store.init(properties.uri);
930
- },
931
- { immediate: true }
932
- );
933
- const edit = (data) => {
934
- emit("edit", data);
935
- };
936
- const deleteFn = (data) => {
937
- emit("delete", data);
938
- };
939
- const components = {
940
- TextCell
941
- };
942
- const displayColumns = computed(() => {
943
- return properties.uiSchema.elements.map((e) => {
944
- const element = e;
945
- const def = findColumnDef(element, properties.schema);
946
- const type = isArray(def.type) ? def.type[0] : def.type;
947
- let component;
948
- if (element.options?.format && element.options.format in components) {
949
- component = components[element.options.format];
950
- } else {
951
- component = components[element.type];
952
- }
953
- if (!component) console.warn("No component found for type", element.type);
954
- return {
955
- ...def,
956
- type,
957
- component
958
- };
959
- });
350
+ };
351
+ const get = (id, options2) => {
352
+ return httpRequest.get(getDataUri(id), options2).then((response) => {
353
+ return response.data;
354
+ }).catch((response) => {
355
+ handleError(response, `Failed to load data`);
960
356
  });
961
- const onChangeFilters = (filters) => {
962
- store.updateFilters(filters);
963
- };
964
- const onUpdatePage = (page) => {
965
- store.updatePage(page);
966
- };
967
- const onSort = (id) => {
968
- store.sort(id);
969
- };
970
- const sort = computed(() => {
971
- return store.sorting.value ?? { orderBy: "", ascending: 1 };
357
+ };
358
+ const _delete = (id, options2) => {
359
+ return httpRequest.delete(getDataUri(id), options2).then((response) => {
360
+ handleSuccess(`${notificationEntity} deleted`);
361
+ return response;
362
+ }).catch((response) => {
363
+ handleError(response, `Failed to delete ${notificationEntity}`);
972
364
  });
973
- return (_ctx, _cache) => {
974
- return openBlock(), createElementBlock("div", null, [
975
- _ctx.filterUiSchema && _ctx.filterSchema ? (openBlock(), createElementBlock("div", _hoisted_1$3, [
976
- createVNode(_sfc_main$5, {
977
- layout: { uiSchema: _ctx.filterUiSchema, schema: _ctx.filterSchema },
978
- filters: unref(store).filters.value,
979
- onChangeFilters
980
- }, null, 8, ["layout", "filters"])
981
- ])) : createCommentVNode("", true),
982
- createElementVNode("div", null, [
983
- createVNode(unref(Table), {
984
- "display-columns": displayColumns.value,
985
- sort: sort.value,
986
- page: unref(store).pageData.value,
987
- loading: unref(store).loading.value,
988
- data: unref(store).tableData.value,
989
- actions: _ctx.actions,
990
- onUpdatePage,
991
- onDelete: deleteFn,
992
- onEdit: edit,
993
- onSort
994
- }, null, 8, ["display-columns", "sort", "page", "loading", "data", "actions"])
995
- ])
996
- ]);
997
- };
998
- }
999
- });
1000
- const _hoisted_1$2 = { class: "flex justify-between items-center mb-2" };
1001
- const _sfc_main$3 = /* @__PURE__ */ defineComponent({
1002
- __name: "form-with-table.component",
1003
- props: FormWithTableProperties,
1004
- emits: FormWithTableEmits,
1005
- setup(__props, { emit: __emit }) {
1006
- const properties = __props;
1007
- const emit = __emit;
1008
- const reload = ref(0);
1009
- const resolvedForm = computed(() => properties.form);
1010
- const resolvedTable = computed(() => properties.table);
1011
- const resolvedFilter = computed(() => properties.filter);
1012
- const resolvedUri = computed(() => properties.uri);
1013
- let store = new FormStore(resolvedUri.value ?? "");
1014
- watch(resolvedUri, (uri) => {
1015
- store = new FormStore(uri ?? "");
365
+ };
366
+ const createMulti = (objects, options2) => {
367
+ return Promise.all(
368
+ objects.map((object2) => httpRequest.post(getDataUri(), object2, options2))
369
+ ).then((response) => {
370
+ handleSuccess(`Created ${notificationEntity}`);
371
+ return response.data;
372
+ }).catch((response) => {
373
+ handleError(response, `Failed to save ${notificationEntity}`);
1016
374
  });
1017
- const hasEdit = hasCustomEventListener("editData");
1018
- const customEdit = hasCustomEventListener("custom:edit");
1019
- const customCreate = hasCustomEventListener("custom:create");
1020
- const edit = (data) => {
1021
- if (customEdit) {
1022
- emit("custom:edit", data);
1023
- return;
1024
- }
1025
- if (hasEdit) {
1026
- emit("editData", data);
1027
- return;
1028
- }
1029
- openModal(data);
1030
- };
1031
- const create = () => {
1032
- if (customCreate) {
1033
- emit("custom:create");
1034
- return;
1035
- }
1036
- openModal();
1037
- };
1038
- const deleteFn = (data) => {
1039
- ModalService.showConfirm({
1040
- title: "Delete record",
1041
- message: "Are you sure to delete, the data will be lost?",
1042
- onClose: (result) => {
1043
- if (result.confirmed) {
1044
- store.delete(data).then(() => {
1045
- reload.value = Date.now();
1046
- emit("delete", data);
1047
- });
1048
- }
1049
- }
1050
- });
1051
- };
1052
- const openModal = (formData) => {
1053
- if (!resolvedForm.value) return;
1054
- const isUpdate = !!formData?.id;
1055
- FormModalService.openModal({
1056
- schema: resolvedForm.value.schema,
1057
- uiSchema: resolvedForm.value.uiSchema,
1058
- modalSize: resolvedForm.value.modalSize,
1059
- initialData: formData ?? properties.initialData,
1060
- modalTitle: (isUpdate ? properties.updateTitle ?? properties.createTitle : properties.createTitle) ?? "",
1061
- onClose: (result) => {
1062
- if (result && result.valid) {
1063
- store.save(formData?.id, result.data).then(() => {
1064
- reload.value = Date.now();
1065
- emit("save", { id: formData?.id, data: result.data });
1066
- });
1067
- }
1068
- },
1069
- onEvents: (payload) => emit("events", payload)
1070
- });
1071
- };
1072
- return (_ctx, _cache) => {
1073
- return openBlock(), createElementBlock(Fragment, null, [
1074
- createElementVNode("div", _hoisted_1$2, [
1075
- createElementVNode("h1", null, toDisplayString(_ctx.tableTitle), 1),
1076
- createElementVNode("div", null, [
1077
- createVNode(unref(Btn), {
1078
- icon: unref(IconEnum).Plus,
1079
- outline: true,
1080
- onClick: create
1081
- }, {
1082
- default: withCtx(() => [..._cache[0] || (_cache[0] = [
1083
- createTextVNode(" Add new record ", -1)
1084
- ])]),
1085
- _: 1
1086
- }, 8, ["icon"])
1087
- ])
1088
- ]),
1089
- resolvedTable.value ? (openBlock(), createBlock(unref(Card), { key: 0 }, {
1090
- default: withCtx(() => [
1091
- resolvedUri.value ? (openBlock(), createBlock(unref(_sfc_main$4), {
1092
- key: 0,
1093
- id: `form_table_${_ctx.id}`,
1094
- "ui-schema": resolvedTable.value.uiSchema,
1095
- schema: resolvedTable.value.schema,
1096
- "filter-ui-schema": resolvedFilter.value?.uiSchema,
1097
- "filter-schema": resolvedFilter.value?.schema,
1098
- uri: _ctx.dataUri ?? resolvedUri.value,
1099
- reload: reload.value,
1100
- actions: _ctx.tableActions,
1101
- onEdit: edit,
1102
- onDelete: deleteFn
1103
- }, null, 8, ["id", "ui-schema", "schema", "filter-ui-schema", "filter-schema", "uri", "reload", "actions"])) : createCommentVNode("", true)
1104
- ]),
1105
- _: 1
1106
- })) : createCommentVNode("", true)
1107
- ], 64);
1108
- };
1109
- }
375
+ };
376
+ return { create, patch, createMulti, delete: _delete, get };
377
+ };
378
+ const createFormEvents = (dispatch) => ({
379
+ dispatch
1110
380
  });
381
+ const FORM_EVENTS_KEY = /* @__PURE__ */ Symbol("json-forms:events");
382
+ const provideFormEvents = (dispatch) => {
383
+ const events = createFormEvents(dispatch);
384
+ provide(FORM_EVENTS_KEY, events);
385
+ return events;
386
+ };
387
+ const useFormEvents = () => {
388
+ return inject(
389
+ FORM_EVENTS_KEY,
390
+ createFormEvents(() => {
391
+ })
392
+ );
393
+ };
1111
394
  function $constructor(name, initializer2, params) {
1112
395
  function init(inst, def) {
1113
396
  if (!inst._zod) {
@@ -1642,7 +925,7 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
1642
925
  }
1643
926
  return { formErrors, fieldErrors };
1644
927
  }
1645
- function formatError(error2, mapper = (issue2) => issue2.message) {
928
+ function formatError$1(error2, mapper = (issue2) => issue2.message) {
1646
929
  const fieldErrors = { _errors: [] };
1647
930
  const processError = (error3) => {
1648
931
  for (const issue2 of error3.issues) {
@@ -3095,11 +2378,11 @@ const $ZodDate = /* @__PURE__ */ $constructor("$ZodDate", (inst, def) => {
3095
2378
  return payload;
3096
2379
  };
3097
2380
  });
3098
- function handleArrayResult(result, final, index) {
2381
+ function handleArrayResult(result, final, index2) {
3099
2382
  if (result.issues.length) {
3100
- final.issues.push(...prefixIssues(index, result.issues));
2383
+ final.issues.push(...prefixIssues(index2, result.issues));
3101
2384
  }
3102
- final.value[index] = result.value;
2385
+ final.value[index2] = result.value;
3103
2386
  }
3104
2387
  const $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
3105
2388
  $ZodType.init(inst, def);
@@ -3590,14 +2873,14 @@ function mergeValues(a, b) {
3590
2873
  return { valid: false, mergeErrorPath: [] };
3591
2874
  }
3592
2875
  const newArray = [];
3593
- for (let index = 0; index < a.length; index++) {
3594
- const itemA = a[index];
3595
- const itemB = b[index];
2876
+ for (let index2 = 0; index2 < a.length; index2++) {
2877
+ const itemA = a[index2];
2878
+ const itemB = b[index2];
3596
2879
  const sharedValue = mergeValues(itemA, itemB);
3597
2880
  if (!sharedValue.valid) {
3598
2881
  return {
3599
2882
  valid: false,
3600
- mergeErrorPath: [index, ...sharedValue.mergeErrorPath]
2883
+ mergeErrorPath: [index2, ...sharedValue.mergeErrorPath]
3601
2884
  };
3602
2885
  }
3603
2886
  newArray.push(sharedValue.data);
@@ -3713,11 +2996,11 @@ const $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
3713
2996
  return payload;
3714
2997
  };
3715
2998
  });
3716
- function handleTupleResult(result, final, index) {
2999
+ function handleTupleResult(result, final, index2) {
3717
3000
  if (result.issues.length) {
3718
- final.issues.push(...prefixIssues(index, result.issues));
3001
+ final.issues.push(...prefixIssues(index2, result.issues));
3719
3002
  }
3720
- final.value[index] = result.value;
3003
+ final.value[index2] = result.value;
3721
3004
  }
3722
3005
  const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3723
3006
  $ZodType.init(inst, def);
@@ -6315,7 +5598,7 @@ const initializer = (inst, issues) => {
6315
5598
  inst.name = "ZodError";
6316
5599
  Object.defineProperties(inst, {
6317
5600
  format: {
6318
- value: (mapper) => formatError(inst, mapper)
5601
+ value: (mapper) => formatError$1(inst, mapper)
6319
5602
  // enumerable: false,
6320
5603
  },
6321
5604
  flatten: {
@@ -7877,303 +7160,1402 @@ function convertBaseSchema(schema, ctx) {
7877
7160
  if (typeof schema.multipleOf === "number") {
7878
7161
  numberSchema = numberSchema.multipleOf(schema.multipleOf);
7879
7162
  }
7880
- zodSchema = numberSchema;
7163
+ zodSchema = numberSchema;
7164
+ break;
7165
+ }
7166
+ case "boolean": {
7167
+ zodSchema = z.boolean();
7168
+ break;
7169
+ }
7170
+ case "null": {
7171
+ zodSchema = z.null();
7172
+ break;
7173
+ }
7174
+ case "object": {
7175
+ const shape = {};
7176
+ const properties = schema.properties || {};
7177
+ const requiredSet = new Set(schema.required || []);
7178
+ for (const [key, propSchema] of Object.entries(properties)) {
7179
+ const propZodSchema = convertSchema(propSchema, ctx);
7180
+ shape[key] = requiredSet.has(key) ? propZodSchema : propZodSchema.optional();
7181
+ }
7182
+ if (schema.propertyNames) {
7183
+ const keySchema = convertSchema(schema.propertyNames, ctx);
7184
+ const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z.any();
7185
+ if (Object.keys(shape).length === 0) {
7186
+ zodSchema = z.record(keySchema, valueSchema);
7187
+ break;
7188
+ }
7189
+ const objectSchema2 = z.object(shape).passthrough();
7190
+ const recordSchema = z.looseRecord(keySchema, valueSchema);
7191
+ zodSchema = z.intersection(objectSchema2, recordSchema);
7192
+ break;
7193
+ }
7194
+ if (schema.patternProperties) {
7195
+ const patternProps = schema.patternProperties;
7196
+ const patternKeys = Object.keys(patternProps);
7197
+ const looseRecords = [];
7198
+ for (const pattern of patternKeys) {
7199
+ const patternValue = convertSchema(patternProps[pattern], ctx);
7200
+ const keySchema = z.string().regex(new RegExp(pattern));
7201
+ looseRecords.push(z.looseRecord(keySchema, patternValue));
7202
+ }
7203
+ const schemasToIntersect = [];
7204
+ if (Object.keys(shape).length > 0) {
7205
+ schemasToIntersect.push(z.object(shape).passthrough());
7206
+ }
7207
+ schemasToIntersect.push(...looseRecords);
7208
+ if (schemasToIntersect.length === 0) {
7209
+ zodSchema = z.object({}).passthrough();
7210
+ } else if (schemasToIntersect.length === 1) {
7211
+ zodSchema = schemasToIntersect[0];
7212
+ } else {
7213
+ let result = z.intersection(schemasToIntersect[0], schemasToIntersect[1]);
7214
+ for (let i = 2; i < schemasToIntersect.length; i++) {
7215
+ result = z.intersection(result, schemasToIntersect[i]);
7216
+ }
7217
+ zodSchema = result;
7218
+ }
7219
+ break;
7220
+ }
7221
+ const objectSchema = z.object(shape);
7222
+ if (schema.additionalProperties === false) {
7223
+ zodSchema = objectSchema.strict();
7224
+ } else if (typeof schema.additionalProperties === "object") {
7225
+ zodSchema = objectSchema.catchall(convertSchema(schema.additionalProperties, ctx));
7226
+ } else {
7227
+ zodSchema = objectSchema.passthrough();
7228
+ }
7229
+ break;
7230
+ }
7231
+ case "array": {
7232
+ const prefixItems = schema.prefixItems;
7233
+ const items = schema.items;
7234
+ if (prefixItems && Array.isArray(prefixItems)) {
7235
+ const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
7236
+ const rest = items && typeof items === "object" && !Array.isArray(items) ? convertSchema(items, ctx) : void 0;
7237
+ if (rest) {
7238
+ zodSchema = z.tuple(tupleItems).rest(rest);
7239
+ } else {
7240
+ zodSchema = z.tuple(tupleItems);
7241
+ }
7242
+ if (typeof schema.minItems === "number") {
7243
+ zodSchema = zodSchema.check(z.minLength(schema.minItems));
7244
+ }
7245
+ if (typeof schema.maxItems === "number") {
7246
+ zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
7247
+ }
7248
+ } else if (Array.isArray(items)) {
7249
+ const tupleItems = items.map((item) => convertSchema(item, ctx));
7250
+ const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : void 0;
7251
+ if (rest) {
7252
+ zodSchema = z.tuple(tupleItems).rest(rest);
7253
+ } else {
7254
+ zodSchema = z.tuple(tupleItems);
7255
+ }
7256
+ if (typeof schema.minItems === "number") {
7257
+ zodSchema = zodSchema.check(z.minLength(schema.minItems));
7258
+ }
7259
+ if (typeof schema.maxItems === "number") {
7260
+ zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
7261
+ }
7262
+ } else if (items !== void 0) {
7263
+ const element = convertSchema(items, ctx);
7264
+ let arraySchema = z.array(element);
7265
+ if (typeof schema.minItems === "number") {
7266
+ arraySchema = arraySchema.min(schema.minItems);
7267
+ }
7268
+ if (typeof schema.maxItems === "number") {
7269
+ arraySchema = arraySchema.max(schema.maxItems);
7270
+ }
7271
+ zodSchema = arraySchema;
7272
+ } else {
7273
+ zodSchema = z.array(z.any());
7274
+ }
7881
7275
  break;
7882
7276
  }
7883
- case "boolean": {
7884
- zodSchema = z.boolean();
7885
- break;
7277
+ default:
7278
+ throw new Error(`Unsupported type: ${type}`);
7279
+ }
7280
+ if (schema.description) {
7281
+ zodSchema = zodSchema.describe(schema.description);
7282
+ }
7283
+ if (schema.default !== void 0) {
7284
+ zodSchema = zodSchema.default(schema.default);
7285
+ }
7286
+ return zodSchema;
7287
+ }
7288
+ function convertSchema(schema, ctx) {
7289
+ if (typeof schema === "boolean") {
7290
+ return schema ? z.any() : z.never();
7291
+ }
7292
+ let baseSchema = convertBaseSchema(schema, ctx);
7293
+ const hasExplicitType = schema.type || schema.enum !== void 0 || schema.const !== void 0;
7294
+ if (schema.anyOf && Array.isArray(schema.anyOf)) {
7295
+ const options = schema.anyOf.map((s) => convertSchema(s, ctx));
7296
+ const anyOfUnion = z.union(options);
7297
+ baseSchema = hasExplicitType ? z.intersection(baseSchema, anyOfUnion) : anyOfUnion;
7298
+ }
7299
+ if (schema.oneOf && Array.isArray(schema.oneOf)) {
7300
+ const options = schema.oneOf.map((s) => convertSchema(s, ctx));
7301
+ const oneOfUnion = z.xor(options);
7302
+ baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion;
7303
+ }
7304
+ if (schema.allOf && Array.isArray(schema.allOf)) {
7305
+ if (schema.allOf.length === 0) {
7306
+ baseSchema = hasExplicitType ? baseSchema : z.any();
7307
+ } else {
7308
+ let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx);
7309
+ const startIdx = hasExplicitType ? 0 : 1;
7310
+ for (let i = startIdx; i < schema.allOf.length; i++) {
7311
+ result = z.intersection(result, convertSchema(schema.allOf[i], ctx));
7312
+ }
7313
+ baseSchema = result;
7886
7314
  }
7887
- case "null": {
7888
- zodSchema = z.null();
7889
- break;
7315
+ }
7316
+ if (schema.nullable === true && ctx.version === "openapi-3.0") {
7317
+ baseSchema = z.nullable(baseSchema);
7318
+ }
7319
+ if (schema.readOnly === true) {
7320
+ baseSchema = z.readonly(baseSchema);
7321
+ }
7322
+ const extraMeta = {};
7323
+ const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
7324
+ for (const key of coreMetadataKeys) {
7325
+ if (key in schema) {
7326
+ extraMeta[key] = schema[key];
7890
7327
  }
7891
- case "object": {
7892
- const shape = {};
7893
- const properties = schema.properties || {};
7894
- const requiredSet = new Set(schema.required || []);
7895
- for (const [key, propSchema] of Object.entries(properties)) {
7896
- const propZodSchema = convertSchema(propSchema, ctx);
7897
- shape[key] = requiredSet.has(key) ? propZodSchema : propZodSchema.optional();
7328
+ }
7329
+ const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
7330
+ for (const key of contentMetadataKeys) {
7331
+ if (key in schema) {
7332
+ extraMeta[key] = schema[key];
7333
+ }
7334
+ }
7335
+ for (const key of Object.keys(schema)) {
7336
+ if (!RECOGNIZED_KEYS.has(key)) {
7337
+ extraMeta[key] = schema[key];
7338
+ }
7339
+ }
7340
+ if (Object.keys(extraMeta).length > 0) {
7341
+ ctx.registry.add(baseSchema, extraMeta);
7342
+ }
7343
+ return baseSchema;
7344
+ }
7345
+ function fromJSONSchema(schema, params) {
7346
+ if (typeof schema === "boolean") {
7347
+ return schema ? z.any() : z.never();
7348
+ }
7349
+ const version2 = detectVersion(schema);
7350
+ const defs = schema.$defs || schema.definitions || {};
7351
+ const ctx = {
7352
+ version: version2,
7353
+ defs,
7354
+ refs: /* @__PURE__ */ new Map(),
7355
+ processing: /* @__PURE__ */ new Set(),
7356
+ rootSchema: schema,
7357
+ registry: globalRegistry
7358
+ };
7359
+ return convertSchema(schema, ctx);
7360
+ }
7361
+ config(en());
7362
+ const errorPatterns = [
7363
+ [/^Invalid input: expected \w+, received undefined$/, "This field is required"],
7364
+ [/^Invalid input: expected \w+, received null$/, "This field is required"],
7365
+ [/^Expected string, received/, "Invalid value"],
7366
+ [/^String must contain at least (\d+)/, "Must be at least $1 characters"],
7367
+ [/^Number must be greater than or equal to (\d+)/, "Minimum value is $1"],
7368
+ [/^Number must be less than or equal to (\d+)/, "Maximum value is $1"]
7369
+ ];
7370
+ const formatError = (message) => {
7371
+ if (!message) return void 0;
7372
+ for (const [pattern, replacement] of errorPatterns) {
7373
+ if (pattern.test(message)) {
7374
+ return message.replace(pattern, replacement);
7375
+ }
7376
+ }
7377
+ return message;
7378
+ };
7379
+ const registerZodErrorMap = () => {
7380
+ config({
7381
+ customError: (issue2) => {
7382
+ if (issue2.code === "invalid_type" && issue2.received === "undefined") {
7383
+ return { message: "This field is required" };
7898
7384
  }
7899
- if (schema.propertyNames) {
7900
- const keySchema = convertSchema(schema.propertyNames, ctx);
7901
- const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z.any();
7902
- if (Object.keys(shape).length === 0) {
7903
- zodSchema = z.record(keySchema, valueSchema);
7904
- break;
7905
- }
7906
- const objectSchema2 = z.object(shape).passthrough();
7907
- const recordSchema = z.looseRecord(keySchema, valueSchema);
7908
- zodSchema = z.intersection(objectSchema2, recordSchema);
7909
- break;
7385
+ if (issue2.code === "invalid_type" && issue2.received === "null") {
7386
+ return { message: "This field is required" };
7910
7387
  }
7911
- if (schema.patternProperties) {
7912
- const patternProps = schema.patternProperties;
7913
- const patternKeys = Object.keys(patternProps);
7914
- const looseRecords = [];
7915
- for (const pattern of patternKeys) {
7916
- const patternValue = convertSchema(patternProps[pattern], ctx);
7917
- const keySchema = z.string().regex(new RegExp(pattern));
7918
- looseRecords.push(z.looseRecord(keySchema, patternValue));
7388
+ if (issue2.code === "too_small") {
7389
+ const i = issue2;
7390
+ if (i.type === "string" && i.minimum === 1) {
7391
+ return { message: "This field is required" };
7919
7392
  }
7920
- const schemasToIntersect = [];
7921
- if (Object.keys(shape).length > 0) {
7922
- schemasToIntersect.push(z.object(shape).passthrough());
7393
+ if (i.type === "string") {
7394
+ return { message: `Must be at least ${i.minimum} characters` };
7923
7395
  }
7924
- schemasToIntersect.push(...looseRecords);
7925
- if (schemasToIntersect.length === 0) {
7926
- zodSchema = z.object({}).passthrough();
7927
- } else if (schemasToIntersect.length === 1) {
7928
- zodSchema = schemasToIntersect[0];
7929
- } else {
7930
- let result = z.intersection(schemasToIntersect[0], schemasToIntersect[1]);
7931
- for (let i = 2; i < schemasToIntersect.length; i++) {
7932
- result = z.intersection(result, schemasToIntersect[i]);
7933
- }
7934
- zodSchema = result;
7396
+ }
7397
+ if (issue2.code === "too_big") {
7398
+ const i = issue2;
7399
+ if (i.type === "string") {
7400
+ return { message: `Must be at most ${i.maximum} characters` };
7935
7401
  }
7936
- break;
7937
7402
  }
7938
- const objectSchema = z.object(shape);
7939
- if (schema.additionalProperties === false) {
7940
- zodSchema = objectSchema.strict();
7941
- } else if (typeof schema.additionalProperties === "object") {
7942
- zodSchema = objectSchema.catchall(convertSchema(schema.additionalProperties, ctx));
7943
- } else {
7944
- zodSchema = objectSchema.passthrough();
7403
+ return { message: issue2.message };
7404
+ }
7405
+ });
7406
+ };
7407
+ function findRenderer(registry2, uischema, schema) {
7408
+ let best = null;
7409
+ for (const entry of registry2) {
7410
+ const rank = entry.tester(uischema, schema);
7411
+ if (rank > -1 && (!best || rank > best.rank)) {
7412
+ best = { rank, renderer: entry.renderer };
7413
+ }
7414
+ }
7415
+ return best?.renderer ?? null;
7416
+ }
7417
+ const scopeToPath = (scope) => {
7418
+ if (!scope) return "";
7419
+ return scope.replace(/^#\//, "").split("/").filter((s) => s !== "properties").join(".");
7420
+ };
7421
+ const resolveSchema = (root, scope) => {
7422
+ const segments = scope.replace(/^#\//, "").split("/").filter(Boolean);
7423
+ return segments.reduce((acc, key) => acc?.[key], root);
7424
+ };
7425
+ const _hoisted_1$6 = {
7426
+ key: 1,
7427
+ class: "text-error text-xs"
7428
+ };
7429
+ const _sfc_main$f = /* @__PURE__ */ defineComponent({
7430
+ __name: "Dispatch",
7431
+ props: {
7432
+ uischema: {},
7433
+ schema: {},
7434
+ pathPrefix: { default: void 0 }
7435
+ },
7436
+ setup(__props) {
7437
+ const props = __props;
7438
+ const registry2 = inject("renderers");
7439
+ const rootSchema = inject("rootSchema");
7440
+ const parentPrefix = inject("pathPrefix", "");
7441
+ const effectivePrefix = props.pathPrefix ?? parentPrefix;
7442
+ if (props.pathPrefix !== void 0) {
7443
+ provide("pathPrefix", effectivePrefix);
7444
+ }
7445
+ const resolved = computed(() => {
7446
+ const u = props.uischema;
7447
+ if (!u.scope) return props.schema;
7448
+ const fromRoot = resolveSchema(rootSchema, u.scope);
7449
+ if (fromRoot) return fromRoot;
7450
+ return resolveSchema(props.schema, u.scope) ?? props.schema;
7451
+ });
7452
+ const renderer = computed(
7453
+ () => findRenderer(registry2, props.uischema, resolved.value)
7454
+ );
7455
+ return (_ctx, _cache) => {
7456
+ return renderer.value ? (openBlock(), createBlock(resolveDynamicComponent(renderer.value), {
7457
+ key: 0,
7458
+ uischema: __props.uischema,
7459
+ schema: resolved.value
7460
+ }, null, 8, ["uischema", "schema"])) : (openBlock(), createElementBlock("div", _hoisted_1$6, " No renderer for " + toDisplayString(__props.uischema.scope ?? __props.uischema.type), 1));
7461
+ };
7462
+ }
7463
+ });
7464
+ const JsonFormComponentProperties = {
7465
+ /** Unique identifier used to namespace the form element. */
7466
+ id: { type: String, required: true },
7467
+ /** HTML name attribute for the form. */
7468
+ name: { type: String, default: "form" },
7469
+ /** JSON schema describing the shape of the form data. */
7470
+ schema: { type: Object, required: true },
7471
+ /** UI schema describing the layout and controls. */
7472
+ uiSchema: { type: Object, required: true },
7473
+ /** Disable all form controls. */
7474
+ disabled: { type: Boolean, default: false },
7475
+ /** Current form data object. */
7476
+ formData: { type: Object, default: () => ({}) },
7477
+ /** When validation errors are shown (`'onBlur'`, `'onChange'`, `'onSubmit'`, `'always'`). */
7478
+ errorMode: {
7479
+ type: String,
7480
+ default: "onChanges"
7481
+ }
7482
+ };
7483
+ const JsonFormComponentEmits = [
7484
+ /** Emitted when form data changes. */
7485
+ "change",
7486
+ /** Emitted on form submission. */
7487
+ "submit",
7488
+ /** Emitted when validation errors change. */
7489
+ "errors",
7490
+ /** Emitted when form validity changes. */
7491
+ "valid",
7492
+ /** Emitted when a custom renderer dispatches a form event. */
7493
+ "events"
7494
+ ];
7495
+ const ERROR_MODE_KEY = /* @__PURE__ */ Symbol("errorMode");
7496
+ const FORM_SUBMITTED_KEY = /* @__PURE__ */ Symbol("formSubmitted");
7497
+ const _hoisted_1$5 = { class: "flex-1" };
7498
+ const _hoisted_2$1 = { key: 0 };
7499
+ const _hoisted_3 = {
7500
+ key: 0,
7501
+ class: "text-sm text-base-content/50"
7502
+ };
7503
+ const _hoisted_4 = { key: 1 };
7504
+ const _sfc_main$e = /* @__PURE__ */ defineComponent({
7505
+ __name: "ArrayRenderer",
7506
+ props: {
7507
+ uischema: {},
7508
+ schema: {}
7509
+ },
7510
+ setup(__props) {
7511
+ const props = __props;
7512
+ const parentPrefix = inject("pathPrefix", "");
7513
+ const scope = props.uischema.scope;
7514
+ const scopePath = scopeToPath(scope);
7515
+ const path = parentPrefix ? `${parentPrefix}.${scopePath}` : scopePath;
7516
+ const rootSchema = inject("rootSchema");
7517
+ const arraySchema = resolveSchema(rootSchema, scope);
7518
+ const itemSchema = arraySchema?.items ?? {};
7519
+ const { fields, push, remove } = useFieldArray(path);
7520
+ if (fields.value.length === 0) {
7521
+ push({});
7522
+ }
7523
+ const opts = props.uischema.options ?? {};
7524
+ const layout = opts.layout ?? "column";
7525
+ const showActions = computed(() => !opts.hideActions);
7526
+ const detail = computed(
7527
+ () => props.uischema._detail ?? opts.detail
7528
+ );
7529
+ const childElements = computed(() => {
7530
+ if (!detail.value) {
7531
+ return props.uischema.elements ?? [];
7532
+ }
7533
+ const type = detail.value.type;
7534
+ if (type && type !== "Control") {
7535
+ return [detail.value];
7536
+ }
7537
+ return detail.value.elements ?? [detail.value];
7538
+ });
7539
+ return (_ctx, _cache) => {
7540
+ return openBlock(), createElementBlock("div", null, [
7541
+ createElementVNode("div", {
7542
+ class: normalizeClass([
7543
+ "flex gap-2",
7544
+ unref(layout) === "row" ? "flex-row items-center" : "flex-col"
7545
+ ])
7546
+ }, [
7547
+ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(fields), (entry, index2) => {
7548
+ return openBlock(), createElementBlock("div", {
7549
+ key: entry.key,
7550
+ class: "flex-1"
7551
+ }, [
7552
+ createElementVNode("div", {
7553
+ class: normalizeClass([
7554
+ "flex gap-2",
7555
+ unref(layout) === "row" ? "flex-col" : "flex-row items-center"
7556
+ ])
7557
+ }, [
7558
+ createElementVNode("div", _hoisted_1$5, [
7559
+ (openBlock(true), createElementBlock(Fragment, null, renderList(childElements.value, (child, ci) => {
7560
+ return openBlock(), createBlock(_sfc_main$f, {
7561
+ key: ci,
7562
+ uischema: child,
7563
+ schema: unref(itemSchema),
7564
+ "path-prefix": `${unref(path)}[${index2}]`
7565
+ }, null, 8, ["uischema", "schema", "path-prefix"]);
7566
+ }), 128))
7567
+ ]),
7568
+ showActions.value ? (openBlock(), createElementBlock("div", _hoisted_2$1, [
7569
+ unref(fields).length > 1 ? (openBlock(), createBlock(unref(Btn), {
7570
+ key: 0,
7571
+ icon: unref(IconEnum).Delete,
7572
+ outline: true,
7573
+ onClick: ($event) => unref(remove)(index2)
7574
+ }, null, 8, ["icon", "onClick"])) : createCommentVNode("", true)
7575
+ ])) : createCommentVNode("", true)
7576
+ ], 2)
7577
+ ]);
7578
+ }), 128)),
7579
+ unref(fields).length === 0 ? (openBlock(), createElementBlock("div", _hoisted_3, " No data ")) : createCommentVNode("", true),
7580
+ showActions.value ? (openBlock(), createElementBlock("div", _hoisted_4, [
7581
+ createVNode(unref(Btn), {
7582
+ icon: unref(IconEnum).Plus,
7583
+ outline: true,
7584
+ onClick: _cache[0] || (_cache[0] = ($event) => unref(push)({}))
7585
+ }, {
7586
+ default: withCtx(() => [..._cache[1] || (_cache[1] = [
7587
+ createTextVNode(" Add ", -1)
7588
+ ])]),
7589
+ _: 1
7590
+ }, 8, ["icon"])
7591
+ ])) : createCommentVNode("", true)
7592
+ ], 2)
7593
+ ]);
7594
+ };
7595
+ }
7596
+ });
7597
+ const isAutoCompleteControl = and(
7598
+ // uiTypeIs('Control'),
7599
+ optionIs("format", ControlType.autocomplete)
7600
+ );
7601
+ const isTextAreaControl = and(
7602
+ uiTypeIs("Control"),
7603
+ optionIs("format", ControlType.textArea)
7604
+ );
7605
+ const isStringFormat = and(
7606
+ uiTypeIs("Control"),
7607
+ or(optionIs("format", ControlType.string), schemaTypeIs("string"))
7608
+ );
7609
+ const isMarkdownControl = and(
7610
+ uiTypeIs("Control"),
7611
+ optionIs("format", ControlType.markdown)
7612
+ );
7613
+ const isArrayRenderer = and(
7614
+ schemaTypeIs("array")
7615
+ // optionIs('format', ControlType.array),
7616
+ );
7617
+ const isMultiselectControl = and(
7618
+ uiTypeIs("Control"),
7619
+ optionIs("format", ControlType.mutliSelect)
7620
+ );
7621
+ const isSelectControl = and(
7622
+ uiTypeIs("Control"),
7623
+ optionIs("format", ControlType.select)
7624
+ );
7625
+ const isBooleanControl = or(
7626
+ isBooleanControl$1,
7627
+ and(uiTypeIs("Control"), optionIs("format", ControlType.boolean))
7628
+ );
7629
+ const isNumberFormat = and(
7630
+ uiTypeIs("Control"),
7631
+ or(optionIs("format", ControlType.number), schemaTypeIs("number"))
7632
+ );
7633
+ const isIntegerFormat = and(
7634
+ uiTypeIs("Control"),
7635
+ or(optionIs("format", ControlType.integer), schemaTypeIs("integer"))
7636
+ );
7637
+ const arrayRenderers = [
7638
+ { tester: rankWith(12, isArrayRenderer), renderer: _sfc_main$e }
7639
+ ];
7640
+ const MethodSchema = _enum(["get", "post", "delete", "put", "patch"]);
7641
+ const OperationSchema = object({
7642
+ uri: string(),
7643
+ method: MethodSchema
7644
+ });
7645
+ const OperationsSchema = string().or(OperationSchema);
7646
+ const BooleanOperationSchema = boolean().or(OperationSchema).optional().default(false);
7647
+ const Operations = object({
7648
+ findAll: BooleanOperationSchema,
7649
+ findOne: BooleanOperationSchema,
7650
+ create: BooleanOperationSchema,
7651
+ update: BooleanOperationSchema,
7652
+ delete: BooleanOperationSchema,
7653
+ lookup: OperationsSchema.optional()
7654
+ });
7655
+ const OperationMap = {
7656
+ create: "post",
7657
+ delete: "delete",
7658
+ findAll: "get",
7659
+ findOne: "get",
7660
+ lookup: "get",
7661
+ update: "get"
7662
+ };
7663
+ const ResourceSchema = object({
7664
+ id: string(),
7665
+ uri: string(),
7666
+ operations: Operations,
7667
+ schema: object({
7668
+ ui: any().optional(),
7669
+ data: any()
7670
+ }).optional()
7671
+ }).transform((data) => {
7672
+ const schema = data.schema;
7673
+ if (schema) {
7674
+ if (!schema.ui) {
7675
+ schema.ui = uiFromJsonSchema(schema.data);
7676
+ }
7677
+ }
7678
+ const operations = {};
7679
+ for (const k in OperationMap) {
7680
+ const key = k;
7681
+ const defaultOperation = OperationMap[key];
7682
+ const operation = data.operations[key];
7683
+ const mapResourceSchema = () => {
7684
+ if (isUndefined(operation) || operation === false) return null;
7685
+ if (operation === true)
7686
+ return { uri: data.uri, method: defaultOperation };
7687
+ if (typeof operation === "string")
7688
+ return { uri: operation, method: "get" };
7689
+ return {
7690
+ uri: operation.uri,
7691
+ method: operation.method ?? defaultOperation
7692
+ };
7693
+ };
7694
+ operations[key] = mapResourceSchema();
7695
+ }
7696
+ return {
7697
+ ...data,
7698
+ schema,
7699
+ operations
7700
+ };
7701
+ });
7702
+ const getResourceSchema = async (resourceUri, skipAuth) => {
7703
+ const fetch = skipAuth ? axios : useApi();
7704
+ return fetch.get(resourceUri).then((response) => {
7705
+ const resource = ResourceSchema.safeParse(response.data);
7706
+ if (!resource.success)
7707
+ throw new Error(`Invalid resource schema: ${resource.error}`);
7708
+ return resource.data;
7709
+ });
7710
+ };
7711
+ const useRemoteOption = (options) => {
7712
+ return {
7713
+ fetchOptions: (searchTerm, signal) => {
7714
+ const fetch = options.skipAuth ? axios : useApi();
7715
+ return fetch.get(`${options.uri}${searchTerm}`, { signal }).then((data) => data.data[options.dataField ?? "data"]);
7716
+ }
7717
+ };
7718
+ };
7719
+ const useResourceOptions = async (options) => {
7720
+ const resource = await getResourceSchema(
7721
+ options.resource,
7722
+ options.skipAuth ?? false
7723
+ );
7724
+ const fetch = options.skipAuth ? axios : useApi();
7725
+ const lookup = resource.operations.lookup;
7726
+ return {
7727
+ fetchOptions: (searchTerm, signal) => {
7728
+ const uri = lookup.uri.replace("{text}", searchTerm);
7729
+ const method = lookup.method;
7730
+ return fetch[method](uri, { signal }).then(
7731
+ (data) => data.data[options.dataField ?? "data"]
7732
+ );
7733
+ },
7734
+ enableCreate: !!resource.operations.create,
7735
+ form: resource.operations.create ? {
7736
+ ui_schema: resource.schema.ui,
7737
+ json_schema: resource.schema.data,
7738
+ title: `Create new ${resource.id}`,
7739
+ create: async (data) => {
7740
+ const create = resource.operations.create;
7741
+ return fetch[create.method](create.uri, data).then(
7742
+ (result) => result.data
7743
+ );
7744
+ }
7745
+ } : null
7746
+ };
7747
+ };
7748
+ const useFetchOptions = async (options) => {
7749
+ let config2 = {};
7750
+ if (options.uri)
7751
+ config2 = useRemoteOption(options);
7752
+ if (options.resource)
7753
+ config2 = await useResourceOptions(options);
7754
+ return {
7755
+ fetchOptions: null,
7756
+ labelKey: options.labelKey,
7757
+ valueKey: options.valueKey,
7758
+ enableCreate: options.enableCreate ?? false,
7759
+ form: null,
7760
+ ...config2
7761
+ };
7762
+ };
7763
+ const checkRequired = (rootSchema, scope, fieldName) => {
7764
+ const segments = scope.replace(/^#\//, "").split("/");
7765
+ const parentSegments = segments.slice(0, -2);
7766
+ if (parentSegments.length === 0) {
7767
+ const req2 = rootSchema?.required;
7768
+ return Array.isArray(req2) && req2.includes(fieldName);
7769
+ }
7770
+ const parentScope = `#/${parentSegments.join("/")}`;
7771
+ const parentSchema = resolveSchema(rootSchema, parentScope);
7772
+ const req = parentSchema?.required;
7773
+ return Array.isArray(req) && req.includes(fieldName);
7774
+ };
7775
+ const useInputProps = (uischema, schema, field, options = {}) => {
7776
+ const rootSchema = inject("rootSchema");
7777
+ const path = scopeToPath(uischema.scope);
7778
+ const { errorMessage, meta: meta2 } = field;
7779
+ const opts = uischema.options ?? {};
7780
+ const labelFromScope = path.split(".").pop() ?? "";
7781
+ const isRequired = rootSchema ? checkRequired(rootSchema, uischema.scope, labelFromScope) : false;
7782
+ const s = schema ?? {};
7783
+ const inferredType = (() => {
7784
+ if (opts.format === "text") return "text";
7785
+ if (s.format === "email") return "email";
7786
+ if (s.format === "uri") return "url";
7787
+ if (s.type === "number" || s.type === "integer") return "number";
7788
+ return options.defaultType ?? "text";
7789
+ })();
7790
+ const styles = mergeStyles(opts.styles);
7791
+ const errorMode = inject(ERROR_MODE_KEY, ref("onBlur"));
7792
+ const submitted = inject(FORM_SUBMITTED_KEY, ref(false));
7793
+ const shouldShowError = computed(() => {
7794
+ if (!errorMessage.value) return false;
7795
+ switch (errorMode.value) {
7796
+ case "always":
7797
+ return true;
7798
+ case "onChange":
7799
+ return meta2.dirty;
7800
+ case "onSubmit":
7801
+ return submitted.value;
7802
+ case "onBlur":
7803
+ default:
7804
+ return meta2.touched;
7805
+ }
7806
+ });
7807
+ const width = opts.colspan || styles?.width === "full" ? "w-full" : opts.width ?? "min-w-input";
7808
+ return computed(() => ({
7809
+ id: path,
7810
+ placeholder: opts.placeholder,
7811
+ description: s.description,
7812
+ errors: shouldShowError.value ? opts.errorMessage ?? formatError(errorMessage.value) : void 0,
7813
+ label: opts.label ?? labelFromScope.charAt(0).toUpperCase() + labelFromScope.slice(1),
7814
+ visible: opts.visible ?? true,
7815
+ required: isRequired,
7816
+ enabled: opts.readonly !== true,
7817
+ isFocused: false,
7818
+ isTouched: shouldShowError.value,
7819
+ hideLabel: opts.hideLabel ?? false,
7820
+ styles,
7821
+ width,
7822
+ type: inferredType,
7823
+ ...options.overrides
7824
+ }));
7825
+ };
7826
+ const useCustomControlBinding = ({
7827
+ useProps,
7828
+ setDefaultValue
7829
+ } = {}) => {
7830
+ return (uischema, schema, options = {}) => {
7831
+ const pathPrefix = inject("pathPrefix", "");
7832
+ const scopePath = scopeToPath(uischema.scope);
7833
+ const path = pathPrefix ? `${pathPrefix}.${scopePath}` : scopePath;
7834
+ const field = useField(() => path);
7835
+ setDefaultValue?.(field);
7836
+ const wrapper = useInputProps(uischema, schema, field, options);
7837
+ const customWrapper = useProps?.(uischema, schema, field, options) ?? {
7838
+ value: {}
7839
+ };
7840
+ const onBlur = () => field.handleBlur(new Event("blur"));
7841
+ const onChange = () => field.handleChange(field.value.value);
7842
+ let initialized = false;
7843
+ watch(field.value, (val) => {
7844
+ if (!initialized) {
7845
+ initialized = true;
7846
+ return;
7945
7847
  }
7946
- break;
7848
+ field.handleChange(val);
7849
+ });
7850
+ return {
7851
+ wrapper: computed(() => ({ ...wrapper.value, ...customWrapper.value })),
7852
+ value: field.value,
7853
+ field,
7854
+ onBlur,
7855
+ onChange,
7856
+ appliedOptions: computed(
7857
+ () => uischema.options ?? {}
7858
+ )
7859
+ };
7860
+ };
7861
+ };
7862
+ const useControlBinding = (uischema, schema, options = {}) => {
7863
+ return useCustomControlBinding()(uischema, schema, options);
7864
+ };
7865
+ const useSelectInput = (...fields) => (uischema, schema, field) => {
7866
+ const opts = uischema.options ?? {};
7867
+ return computed(() => {
7868
+ return pick$1(opts, fields);
7869
+ });
7870
+ };
7871
+ const useSelectBinding = useCustomControlBinding({
7872
+ useProps: useSelectInput("options", "labelKey", "valueKey")
7873
+ });
7874
+ const useAutocompleteBinding = useCustomControlBinding({
7875
+ useProps: useSelectInput(
7876
+ "options",
7877
+ "labelKey",
7878
+ "valueKey",
7879
+ "uri",
7880
+ "freeText",
7881
+ "enableCreate",
7882
+ "dataField",
7883
+ "skipAuth"
7884
+ )
7885
+ });
7886
+ const _sfc_main$d = /* @__PURE__ */ defineComponent({
7887
+ __name: "FormModal",
7888
+ props: /* @__PURE__ */ mergeModels(FormModalProperties, {
7889
+ "modelValue": {},
7890
+ "modelModifiers": {}
7891
+ }),
7892
+ emits: /* @__PURE__ */ mergeModels(FormModalEmits, ["update:modelValue"]),
7893
+ setup(__props, { emit: __emit }) {
7894
+ const properties = __props;
7895
+ const id = `modal_${Math.floor(Math.random() * 1e3)}`;
7896
+ const formRef = ref();
7897
+ const valid = ref(false);
7898
+ const formData = useModel(__props, "modelValue");
7899
+ const emits = __emit;
7900
+ if (properties.data) {
7901
+ formData.value = properties.data;
7947
7902
  }
7948
- case "array": {
7949
- const prefixItems = schema.prefixItems;
7950
- const items = schema.items;
7951
- if (prefixItems && Array.isArray(prefixItems)) {
7952
- const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
7953
- const rest = items && typeof items === "object" && !Array.isArray(items) ? convertSchema(items, ctx) : void 0;
7954
- if (rest) {
7955
- zodSchema = z.tuple(tupleItems).rest(rest);
7956
- } else {
7957
- zodSchema = z.tuple(tupleItems);
7958
- }
7959
- if (typeof schema.minItems === "number") {
7960
- zodSchema = zodSchema.check(z.minLength(schema.minItems));
7961
- }
7962
- if (typeof schema.maxItems === "number") {
7963
- zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
7964
- }
7965
- } else if (Array.isArray(items)) {
7966
- const tupleItems = items.map((item) => convertSchema(item, ctx));
7967
- const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : void 0;
7968
- if (rest) {
7969
- zodSchema = z.tuple(tupleItems).rest(rest);
7970
- } else {
7971
- zodSchema = z.tuple(tupleItems);
7972
- }
7973
- if (typeof schema.minItems === "number") {
7974
- zodSchema = zodSchema.check(z.minLength(schema.minItems));
7975
- }
7976
- if (typeof schema.maxItems === "number") {
7977
- zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
7978
- }
7979
- } else if (items !== void 0) {
7980
- const element = convertSchema(items, ctx);
7981
- let arraySchema = z.array(element);
7982
- if (typeof schema.minItems === "number") {
7983
- arraySchema = arraySchema.min(schema.minItems);
7984
- }
7985
- if (typeof schema.maxItems === "number") {
7986
- arraySchema = arraySchema.max(schema.maxItems);
7987
- }
7988
- zodSchema = arraySchema;
7989
- } else {
7990
- zodSchema = z.array(z.any());
7903
+ const onCancel = () => {
7904
+ formData.value = {};
7905
+ emits("closeModal", null);
7906
+ };
7907
+ const onChange = (data) => {
7908
+ formData.value = data;
7909
+ };
7910
+ const onSubmit = () => {
7911
+ formRef.value?.markSubmitted();
7912
+ if (!valid.value) return;
7913
+ emits("closeModal", { data: formData.value, valid: valid.value });
7914
+ };
7915
+ const onErrors = (errors) => {
7916
+ emits("errors", errors);
7917
+ valid.value = isEmpty(errors);
7918
+ };
7919
+ watch(valid, (newValid, oldValid) => {
7920
+ if (newValid !== oldValid) {
7921
+ emits("valid", newValid);
7991
7922
  }
7992
- break;
7993
- }
7994
- default:
7995
- throw new Error(`Unsupported type: ${type}`);
7996
- }
7997
- if (schema.description) {
7998
- zodSchema = zodSchema.describe(schema.description);
7923
+ });
7924
+ return (_ctx, _cache) => {
7925
+ return openBlock(), createBlock(unref(Modal), mergeProps(properties, {
7926
+ open: true,
7927
+ "disable-close": false,
7928
+ width: _ctx.modalSize,
7929
+ onCloseModal: onCancel
7930
+ }), {
7931
+ content: withCtx(() => [
7932
+ renderSlot(_ctx.$slots, "content-before"),
7933
+ createVNode(_sfc_main$2, {
7934
+ id: `modal-${id}`,
7935
+ ref_key: "formRef",
7936
+ ref: formRef,
7937
+ "form-data": formData.value,
7938
+ schema: _ctx.schema,
7939
+ "ui-schema": _ctx.uiSchema,
7940
+ "error-mode": _ctx.errorMode,
7941
+ onErrors,
7942
+ onChange,
7943
+ onEvents: _cache[0] || (_cache[0] = ($event) => emits("events", $event))
7944
+ }, null, 8, ["id", "form-data", "schema", "ui-schema", "error-mode"]),
7945
+ renderSlot(_ctx.$slots, "content-after")
7946
+ ]),
7947
+ actions: withCtx(() => [
7948
+ createVNode(unref(Btn), {
7949
+ color: unref(Color).secondary,
7950
+ outline: true,
7951
+ "aria-label": "Cancel",
7952
+ onClick: onCancel
7953
+ }, {
7954
+ default: withCtx(() => [..._cache[1] || (_cache[1] = [
7955
+ createTextVNode(" Cancel ", -1)
7956
+ ])]),
7957
+ _: 1
7958
+ }, 8, ["color"]),
7959
+ createVNode(unref(Btn), {
7960
+ disabled: !valid.value,
7961
+ "aria-label": "Save",
7962
+ onClick: onSubmit
7963
+ }, {
7964
+ default: withCtx(() => [..._cache[2] || (_cache[2] = [
7965
+ createTextVNode(" Save ", -1)
7966
+ ])]),
7967
+ _: 1
7968
+ }, 8, ["disabled"])
7969
+ ]),
7970
+ _: 3
7971
+ }, 16, ["width"]);
7972
+ };
7999
7973
  }
8000
- if (schema.default !== void 0) {
8001
- zodSchema = zodSchema.default(schema.default);
7974
+ });
7975
+ class JsonFormModalService {
7976
+ static openModal({
7977
+ initialData,
7978
+ modalTitle,
7979
+ schema,
7980
+ uiSchema,
7981
+ modalSize,
7982
+ onClose,
7983
+ onEvents
7984
+ }) {
7985
+ ModalService.openModal({
7986
+ component: _sfc_main$d,
7987
+ props: {
7988
+ schema,
7989
+ uiSchema,
7990
+ modalSize,
7991
+ data: initialData ?? {},
7992
+ modalTitle,
7993
+ onClose,
7994
+ onEvents
7995
+ }
7996
+ });
8002
7997
  }
8003
- return zodSchema;
8004
7998
  }
8005
- function convertSchema(schema, ctx) {
8006
- if (typeof schema === "boolean") {
8007
- return schema ? z.any() : z.never();
7999
+ const _sfc_main$c = /* @__PURE__ */ defineComponent({
8000
+ __name: "AutocompleteControlRenderer",
8001
+ props: {
8002
+ uischema: {},
8003
+ schema: {}
8004
+ },
8005
+ setup(__props) {
8006
+ const props = __props;
8007
+ const {
8008
+ wrapper,
8009
+ value,
8010
+ field,
8011
+ onBlur,
8012
+ onChange: onFieldChange,
8013
+ appliedOptions
8014
+ } = useAutocompleteBinding(props.uischema, props.schema);
8015
+ const fetchOptions = computedAsync(async () => {
8016
+ const config2 = await useFetchOptions(
8017
+ appliedOptions.value
8018
+ );
8019
+ return config2;
8020
+ });
8021
+ const onChange = (val) => {
8022
+ field.setValue(val);
8023
+ onFieldChange();
8024
+ };
8025
+ const formEvents = useFormEvents();
8026
+ const path = scopeToPath(props.uischema.scope);
8027
+ const onCreate = () => {
8028
+ if (fetchOptions.value?.enableCreate === false) return;
8029
+ const form = fetchOptions.value.form;
8030
+ if (form) {
8031
+ JsonFormModalService.openModal({
8032
+ schema: form.json_schema,
8033
+ uiSchema: form.ui_schema,
8034
+ modalTitle: `Create new ${wrapper.value.label}`,
8035
+ onClose: (result) => {
8036
+ if (!result || !result.valid) return;
8037
+ form.create(result.data).then((res) => {
8038
+ field.setValue(res);
8039
+ });
8040
+ }
8041
+ });
8042
+ return;
8043
+ }
8044
+ formEvents.dispatch({
8045
+ event: "create",
8046
+ type: path,
8047
+ data: value.value,
8048
+ onSuccess: (result) => {
8049
+ field.setValue(result);
8050
+ }
8051
+ });
8052
+ };
8053
+ return (_ctx, _cache) => {
8054
+ return unref(fetchOptions) ? (openBlock(), createBlock(unref(Autocomplete), mergeProps({ key: 0 }, unref(wrapper), {
8055
+ "model-value": unref(value),
8056
+ "fetch-options": unref(fetchOptions).fetchOptions,
8057
+ "label-key": unref(fetchOptions).labelKey,
8058
+ "value-key": unref(fetchOptions).valueKey,
8059
+ "enable-create": unref(fetchOptions).enableCreate,
8060
+ onChange,
8061
+ onBlur: unref(onBlur),
8062
+ onCreate
8063
+ }), null, 16, ["model-value", "fetch-options", "label-key", "value-key", "enable-create", "onBlur"])) : createCommentVNode("", true);
8064
+ };
8008
8065
  }
8009
- let baseSchema = convertBaseSchema(schema, ctx);
8010
- const hasExplicitType = schema.type || schema.enum !== void 0 || schema.const !== void 0;
8011
- if (schema.anyOf && Array.isArray(schema.anyOf)) {
8012
- const options = schema.anyOf.map((s) => convertSchema(s, ctx));
8013
- const anyOfUnion = z.union(options);
8014
- baseSchema = hasExplicitType ? z.intersection(baseSchema, anyOfUnion) : anyOfUnion;
8066
+ });
8067
+ const _sfc_main$b = /* @__PURE__ */ defineComponent({
8068
+ __name: "BooleanControlRenderer",
8069
+ props: {
8070
+ uischema: {},
8071
+ schema: {}
8072
+ },
8073
+ setup(__props) {
8074
+ const props = __props;
8075
+ const useBooleanBinding = useCustomControlBinding({
8076
+ setDefaultValue: (field2) => {
8077
+ if (field2.value.value === void 0) field2.setValue(false);
8078
+ }
8079
+ });
8080
+ const { wrapper, value, field, onBlur, onChange: onFieldChange } = useBooleanBinding(props.uischema, props.schema);
8081
+ const onChange = (val) => {
8082
+ field.setValue(Boolean(val) ?? false);
8083
+ onFieldChange();
8084
+ };
8085
+ return (_ctx, _cache) => {
8086
+ return openBlock(), createBlock(unref(Checkbox), mergeProps(unref(wrapper), {
8087
+ "model-value": unref(value),
8088
+ onChange,
8089
+ onBlur: unref(onBlur)
8090
+ }), null, 16, ["model-value", "onBlur"]);
8091
+ };
8092
+ }
8093
+ });
8094
+ const _sfc_main$a = /* @__PURE__ */ defineComponent({
8095
+ __name: "MarkdownControlRenderer",
8096
+ props: {
8097
+ uischema: {},
8098
+ schema: {}
8099
+ },
8100
+ setup(__props) {
8101
+ const props = __props;
8102
+ const {
8103
+ wrapper,
8104
+ value,
8105
+ field,
8106
+ onBlur,
8107
+ onChange: onFieldChange
8108
+ } = useControlBinding(props.uischema, props.schema);
8109
+ const onChange = (val) => {
8110
+ field.setValue(val);
8111
+ onFieldChange();
8112
+ };
8113
+ return (_ctx, _cache) => {
8114
+ return openBlock(), createBlock(unref(Markdown), mergeProps(unref(wrapper), {
8115
+ "model-value": unref(value),
8116
+ onChange,
8117
+ onBlur: unref(onBlur)
8118
+ }), null, 16, ["model-value", "onBlur"]);
8119
+ };
8015
8120
  }
8016
- if (schema.oneOf && Array.isArray(schema.oneOf)) {
8017
- const options = schema.oneOf.map((s) => convertSchema(s, ctx));
8018
- const oneOfUnion = z.xor(options);
8019
- baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion;
8121
+ });
8122
+ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
8123
+ __name: "MultiSelectControlRenderer",
8124
+ props: {
8125
+ uischema: {},
8126
+ schema: {}
8127
+ },
8128
+ setup(__props) {
8129
+ const props = __props;
8130
+ const {
8131
+ wrapper,
8132
+ value,
8133
+ field,
8134
+ onBlur,
8135
+ onChange: onFieldChange
8136
+ } = useSelectBinding(props.uischema, props.schema);
8137
+ const onChange = (val) => {
8138
+ field.setValue(val);
8139
+ onFieldChange();
8140
+ };
8141
+ return (_ctx, _cache) => {
8142
+ return openBlock(), createBlock(unref(MultiSelect), mergeProps(unref(wrapper), {
8143
+ "model-value": unref(value),
8144
+ onChange,
8145
+ onBlur: unref(onBlur)
8146
+ }), null, 16, ["model-value", "onBlur"]);
8147
+ };
8020
8148
  }
8021
- if (schema.allOf && Array.isArray(schema.allOf)) {
8022
- if (schema.allOf.length === 0) {
8023
- baseSchema = hasExplicitType ? baseSchema : z.any();
8024
- } else {
8025
- let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx);
8026
- const startIdx = hasExplicitType ? 0 : 1;
8027
- for (let i = startIdx; i < schema.allOf.length; i++) {
8028
- result = z.intersection(result, convertSchema(schema.allOf[i], ctx));
8029
- }
8030
- baseSchema = result;
8031
- }
8149
+ });
8150
+ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
8151
+ __name: "NumberControlRenderer",
8152
+ props: {
8153
+ uischema: {},
8154
+ schema: {}
8155
+ },
8156
+ setup(__props) {
8157
+ const props = __props;
8158
+ const { wrapper, value, onBlur, onChange } = useControlBinding(
8159
+ props.uischema,
8160
+ props.schema,
8161
+ { defaultType: "number" }
8162
+ );
8163
+ return (_ctx, _cache) => {
8164
+ return openBlock(), createBlock(unref(InputNumber), mergeProps(unref(wrapper), {
8165
+ modelValue: unref(value),
8166
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(value) ? value.value = $event : null),
8167
+ steps: 0.01,
8168
+ onBlur: unref(onBlur),
8169
+ onChange: unref(onChange)
8170
+ }), null, 16, ["modelValue", "onBlur", "onChange"]);
8171
+ };
8032
8172
  }
8033
- if (schema.nullable === true && ctx.version === "openapi-3.0") {
8034
- baseSchema = z.nullable(baseSchema);
8173
+ });
8174
+ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
8175
+ __name: "SelectControlRenderer",
8176
+ props: {
8177
+ uischema: {},
8178
+ schema: {}
8179
+ },
8180
+ setup(__props) {
8181
+ const props = __props;
8182
+ const {
8183
+ wrapper,
8184
+ value,
8185
+ field,
8186
+ onBlur,
8187
+ onChange: onFieldChange,
8188
+ appliedOptions
8189
+ } = useSelectBinding(props.uischema, props.schema);
8190
+ const selectOptions = computed(() => {
8191
+ return appliedOptions.options ?? [];
8192
+ });
8193
+ const onChange = (val) => {
8194
+ field.setValue(val);
8195
+ onFieldChange();
8196
+ };
8197
+ return (_ctx, _cache) => {
8198
+ return openBlock(), createBlock(unref(SelectComponent), mergeProps(unref(wrapper), {
8199
+ "model-value": unref(value),
8200
+ options: selectOptions.value,
8201
+ onChange,
8202
+ onBlur: unref(onBlur)
8203
+ }), null, 16, ["model-value", "options", "onBlur"]);
8204
+ };
8035
8205
  }
8036
- if (schema.readOnly === true) {
8037
- baseSchema = z.readonly(baseSchema);
8206
+ });
8207
+ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
8208
+ __name: "StringControlRenderer",
8209
+ props: {
8210
+ uischema: {},
8211
+ schema: {}
8212
+ },
8213
+ setup(__props) {
8214
+ const props = __props;
8215
+ const { wrapper, value, onBlur, onChange } = useControlBinding(
8216
+ props.uischema,
8217
+ props.schema
8218
+ );
8219
+ return (_ctx, _cache) => {
8220
+ return openBlock(), createBlock(unref(Input), mergeProps(unref(wrapper), {
8221
+ modelValue: unref(value),
8222
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(value) ? value.value = $event : null),
8223
+ onBlur: unref(onBlur),
8224
+ onChange: unref(onChange)
8225
+ }), null, 16, ["modelValue", "onBlur", "onChange"]);
8226
+ };
8038
8227
  }
8039
- const extraMeta = {};
8040
- const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
8041
- for (const key of coreMetadataKeys) {
8042
- if (key in schema) {
8043
- extraMeta[key] = schema[key];
8044
- }
8228
+ });
8229
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
8230
+ __name: "TextAreaControlRenderer",
8231
+ props: {
8232
+ uischema: {},
8233
+ schema: {}
8234
+ },
8235
+ setup(__props) {
8236
+ const props = __props;
8237
+ const { wrapper, value, onBlur, onChange } = useControlBinding(
8238
+ props.uischema,
8239
+ props.schema
8240
+ );
8241
+ return (_ctx, _cache) => {
8242
+ return openBlock(), createBlock(unref(Textarea), mergeProps(unref(wrapper), {
8243
+ modelValue: unref(value),
8244
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(value) ? value.value = $event : null),
8245
+ onBlur: unref(onBlur),
8246
+ onChange: unref(onChange)
8247
+ }), null, 16, ["modelValue", "onBlur", "onChange"]);
8248
+ };
8045
8249
  }
8046
- const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
8047
- for (const key of contentMetadataKeys) {
8048
- if (key in schema) {
8049
- extraMeta[key] = schema[key];
8050
- }
8250
+ });
8251
+ const index = [
8252
+ { tester: rankWith(10, isStringFormat), renderer: _sfc_main$6 },
8253
+ {
8254
+ tester: rankWith(11, isTextAreaControl),
8255
+ renderer: _sfc_main$5
8256
+ },
8257
+ {
8258
+ tester: rankWith(11, isMarkdownControl),
8259
+ renderer: _sfc_main$a
8260
+ },
8261
+ { tester: rankWith(11, isBooleanControl), renderer: _sfc_main$b },
8262
+ { tester: rankWith(11, isSelectControl), renderer: _sfc_main$7 },
8263
+ {
8264
+ tester: rankWith(11, isMultiselectControl),
8265
+ renderer: _sfc_main$9
8266
+ },
8267
+ {
8268
+ tester: rankWith(12, isAutoCompleteControl),
8269
+ renderer: _sfc_main$c
8270
+ },
8271
+ {
8272
+ tester: rankWith(12, isNumberFormat),
8273
+ renderer: _sfc_main$8
8274
+ },
8275
+ {
8276
+ tester: rankWith(12, isIntegerFormat),
8277
+ renderer: _sfc_main$8
8051
8278
  }
8052
- for (const key of Object.keys(schema)) {
8053
- if (!RECOGNIZED_KEYS.has(key)) {
8054
- extraMeta[key] = schema[key];
8055
- }
8279
+ ];
8280
+ const COLSPAN = {
8281
+ 1: "col-span-1",
8282
+ 2: "col-span-2",
8283
+ 3: "col-span-3",
8284
+ 4: "col-span-4",
8285
+ 5: "col-span-5",
8286
+ 6: "col-span-6",
8287
+ 7: "col-span-7",
8288
+ 8: "col-span-8",
8289
+ 9: "col-span-9",
8290
+ 10: "col-span-10",
8291
+ 11: "col-span-11",
8292
+ 12: "col-span-12"
8293
+ };
8294
+ const _hoisted_1$4 = { class: "flex flex-col gap-4" };
8295
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
8296
+ __name: "CollapseLayoutRenderer",
8297
+ props: {
8298
+ uischema: {},
8299
+ schema: {}
8300
+ },
8301
+ setup(__props) {
8302
+ const props = __props;
8303
+ const pathPrefix = inject("pathPrefix", "");
8304
+ const opts = props.uischema.options ?? {};
8305
+ const titleKeyField = opts.titleKey ? useFieldValue(
8306
+ () => pathPrefix ? `${pathPrefix}.${opts.titleKey}` : opts.titleKey
8307
+ ) : void 0;
8308
+ const title = computed(() => {
8309
+ if (titleKeyField?.value) return titleKeyField.value;
8310
+ return props.uischema.label ?? opts.title ?? "Details";
8311
+ });
8312
+ return (_ctx, _cache) => {
8313
+ return openBlock(), createBlock(unref(Collapse), { title: title.value }, {
8314
+ default: withCtx(() => [
8315
+ createElementVNode("div", _hoisted_1$4, [
8316
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.uischema.elements, (child, i) => {
8317
+ return openBlock(), createElementBlock("div", {
8318
+ key: i,
8319
+ class: normalizeClass(unref(COLSPAN)[child.options?.colspan ?? 12])
8320
+ }, [
8321
+ createVNode(_sfc_main$f, {
8322
+ uischema: child,
8323
+ schema: __props.schema
8324
+ }, null, 8, ["uischema", "schema"])
8325
+ ], 2);
8326
+ }), 128))
8327
+ ])
8328
+ ]),
8329
+ _: 1
8330
+ }, 8, ["title"]);
8331
+ };
8056
8332
  }
8057
- if (Object.keys(extraMeta).length > 0) {
8058
- ctx.registry.add(baseSchema, extraMeta);
8333
+ });
8334
+ const _hoisted_1$3 = {
8335
+ key: 1,
8336
+ class: "flex flex-col gap-3"
8337
+ };
8338
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
8339
+ __name: "LayoutRenderer",
8340
+ props: {
8341
+ uischema: {},
8342
+ schema: {}
8343
+ },
8344
+ setup(__props) {
8345
+ const props = __props;
8346
+ const LAYOUT = {
8347
+ GridLayout: "grid grid-cols-12 gap-3",
8348
+ HorizontalLayout: "flex flex-row gap-3",
8349
+ VerticalLayout: "flex flex-col gap-3"
8350
+ };
8351
+ const getLayout = computed(() => LAYOUT[props.uischema.type]);
8352
+ const isLayout = computed(() => props.uischema.type in LAYOUT);
8353
+ return (_ctx, _cache) => {
8354
+ return isLayout.value ? (openBlock(), createElementBlock("div", {
8355
+ key: 0,
8356
+ class: normalizeClass(getLayout.value)
8357
+ }, [
8358
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.uischema.elements, (child, i) => {
8359
+ return openBlock(), createElementBlock("div", {
8360
+ key: i,
8361
+ class: normalizeClass(unref(COLSPAN)[child.options?.colspan ?? 12])
8362
+ }, [
8363
+ createVNode(_sfc_main$f, {
8364
+ uischema: child,
8365
+ schema: __props.schema
8366
+ }, null, 8, ["uischema", "schema"])
8367
+ ], 2);
8368
+ }), 128))
8369
+ ], 2)) : (openBlock(), createElementBlock("div", _hoisted_1$3, " No Applicable Layout found "));
8370
+ };
8059
8371
  }
8060
- return baseSchema;
8061
- }
8062
- function fromJSONSchema(schema, params) {
8063
- if (typeof schema === "boolean") {
8064
- return schema ? z.any() : z.never();
8372
+ });
8373
+ const isLayoutType = or$1(
8374
+ uiTypeIs("GridLayout"),
8375
+ uiTypeIs("HorizontalLayout"),
8376
+ uiTypeIs("VerticalLayout")
8377
+ );
8378
+ const layoutRenderes = [
8379
+ { tester: rankWith(10, isLayoutType), renderer: _sfc_main$3 },
8380
+ {
8381
+ tester: rankWith(10, uiTypeIs("CollapseLayout")),
8382
+ renderer: _sfc_main$4
8065
8383
  }
8066
- const version2 = detectVersion(schema);
8067
- const defs = schema.$defs || schema.definitions || {};
8068
- const ctx = {
8069
- version: version2,
8070
- defs,
8071
- refs: /* @__PURE__ */ new Map(),
8072
- processing: /* @__PURE__ */ new Set(),
8073
- rootSchema: schema,
8074
- registry: globalRegistry
8075
- };
8076
- return convertSchema(schema, ctx);
8077
- }
8078
- config(en());
8079
- const customRenderers = [
8080
- controlRenderers,
8081
- layoutRenderers,
8082
- // ...complexRenderers,
8083
- arrayRenderers
8084
- // ...labelRenderers,
8085
- ].flat();
8086
- const tailwindRenderers = [
8087
- ...vanillaRenderers,
8088
- ...customRenderers
8089
8384
  ];
8090
- const _hoisted_1$1 = ["id", "aria-label"];
8385
+ const customRenderes = [layoutRenderes, index, arrayRenderers].flat();
8386
+ const _hoisted_1$2 = ["id"];
8091
8387
  const _sfc_main$2 = /* @__PURE__ */ defineComponent({
8092
- __name: "form.component",
8093
- props: FormComponentProperties,
8094
- emits: FormComponentEmits,
8095
- setup(__props, { emit: __emit }) {
8388
+ __name: "FormComponent",
8389
+ props: JsonFormComponentProperties,
8390
+ emits: JsonFormComponentEmits,
8391
+ setup(__props, { expose: __expose, emit: __emit }) {
8392
+ registerZodErrorMap();
8096
8393
  const properties = __props;
8097
8394
  const emits = __emit;
8098
- const valid = ref(false);
8099
- const zodSchema = computed(() => fromJSONSchema(properties.schema));
8100
- const stripFormData = (data) => {
8101
- const safeParse2 = zodSchema.value?.strip().safeParse(data);
8102
- return safeParse2?.success ? safeParse2.data : data ?? {};
8103
- };
8104
- const internalFormData = ref(properties.formData ?? {});
8395
+ const zodSchema = computed(() => {
8396
+ if (!properties.schema) return void 0;
8397
+ try {
8398
+ const patched = enforceRequiredStringMinLength(properties.schema);
8399
+ return fromJSONSchema(patched);
8400
+ } catch {
8401
+ return void 0;
8402
+ }
8403
+ });
8404
+ const { values, errors, meta: meta2, setValues, validate } = useForm({
8405
+ validationSchema: zodSchema,
8406
+ initialValues: properties.formData
8407
+ });
8408
+ provide("renderers", customRenderes);
8409
+ provide("rootSchema", properties.schema);
8410
+ provide("styles", myStyles);
8411
+ const submitted = ref(false);
8412
+ provide(ERROR_MODE_KEY, toRef(properties, "errorMode"));
8413
+ provide(FORM_SUBMITTED_KEY, submitted);
8414
+ onMounted(async () => {
8415
+ const result = await validate();
8416
+ emits("valid", result.valid);
8417
+ });
8418
+ provideFormEvents((payload) => {
8419
+ emits("events", payload);
8420
+ });
8421
+ let syncing = false;
8105
8422
  watch(
8106
8423
  () => properties.formData,
8107
- (data, oldData) => {
8108
- if (JSON.stringify(data) === JSON.stringify(internalFormData.value)) return;
8109
- internalFormData.value = stripFormData(data);
8110
- emits("change", internalFormData.value);
8424
+ (newData) => {
8425
+ if (!newData) return;
8426
+ if (JSON.stringify(newData) === JSON.stringify(toRaw(values))) return;
8427
+ syncing = true;
8428
+ setValues(newData);
8429
+ nextTick(() => {
8430
+ syncing = false;
8431
+ });
8111
8432
  },
8112
- { deep: true, immediate: true }
8433
+ { deep: true }
8113
8434
  );
8114
- provideFormEvents((payload) => {
8115
- emits("events", payload);
8116
- });
8117
- const onChange = (event) => {
8118
- internalFormData.value = event.data;
8119
- valid.value = event.errors.length === 0;
8120
- emits("valid", valid.value);
8121
- emits("change", internalFormData.value);
8122
- emits("errors", event.errors);
8123
- Debugger.debug(event.errors);
8124
- };
8125
- const onSubmit = (event) => {
8126
- event.preventDefault();
8435
+ watch(
8436
+ values,
8437
+ (newValues) => {
8438
+ if (syncing) return;
8439
+ const isValid = meta2.value.valid;
8440
+ emits("valid", isValid);
8441
+ emits("change", toRaw(newValues));
8442
+ },
8443
+ { deep: true }
8444
+ );
8445
+ watch(
8446
+ errors,
8447
+ (newErrors) => {
8448
+ const errorList = Object.entries(newErrors).filter(([, msg]) => !!msg).map(([path, message]) => ({ path, message }));
8449
+ emits("errors", errorList);
8450
+ },
8451
+ { deep: true }
8452
+ );
8453
+ const onSubmit = () => {
8454
+ submitted.value = true;
8127
8455
  emits("submit", {
8128
- data: internalFormData.value,
8129
- valid: valid.value
8456
+ data: toRaw(values),
8457
+ valid: meta2.value.valid
8130
8458
  });
8131
8459
  };
8132
- provide("styles", myStyles);
8133
- const renderers = Object.freeze([
8134
- ...properties.renderers ?? [],
8135
- ...tailwindRenderers
8136
- ]);
8460
+ const markSubmitted = () => {
8461
+ submitted.value = true;
8462
+ };
8463
+ __expose({ markSubmitted });
8137
8464
  return (_ctx, _cache) => {
8138
8465
  return openBlock(), createElementBlock("form", {
8139
8466
  id: _ctx.id,
8140
- "aria-label": _ctx.name,
8141
8467
  onSubmit: withModifiers(onSubmit, ["prevent"])
8142
8468
  }, [
8143
- (openBlock(), createBlock(unref(JsonForms), {
8144
- key: _ctx.id,
8145
- data: internalFormData.value,
8146
- schema: _ctx.schema,
8469
+ createVNode(_sfc_main$f, {
8147
8470
  uischema: _ctx.uiSchema,
8148
- renderers: unref(renderers),
8149
- enabled: !_ctx.disabled,
8150
- onChange,
8151
- onSubmit
8152
- }, null, 8, ["data", "schema", "uischema", "renderers", "enabled"]))
8153
- ], 40, _hoisted_1$1);
8471
+ schema: _ctx.schema
8472
+ }, null, 8, ["uischema", "schema"])
8473
+ ], 40, _hoisted_1$2);
8154
8474
  };
8155
8475
  }
8156
8476
  });
8157
- const _hoisted_1 = { class: "flex justify-end gap-2 p-2 mt-2 border-t border-gray-300 z-[30] shrink-0" };
8477
+ const FormWithActionsProperties = {
8478
+ /** Unique identifier used to namespace the inner form element. */
8479
+ id: { type: String, required: true },
8480
+ /** Title shown when creating a new record. */
8481
+ createTitle: { type: String, required: true },
8482
+ /** Title shown when editing an existing record. Falls back to `createTitle` when omitted. */
8483
+ updateTitle: { type: String },
8484
+ /** JSON schema describing the shape of the form data. */
8485
+ schema: { type: Object },
8486
+ /** UI schema describing the layout and controls. */
8487
+ uiSchema: { type: Object },
8488
+ /** REST endpoint used by `FormStore` to persist data. When omitted the form emits `submit` instead. */
8489
+ uri: { type: String },
8490
+ /** Enable vertical scrolling inside the form area. */
8491
+ scrollable: { type: Boolean, default: false },
8492
+ /** Stretch the collapse wrapper to full height. */
8493
+ fullHeight: { type: Boolean, default: false },
8494
+ /** Two-way bound form data object. */
8495
+ modelValue: { type: Object, default: () => ({}) },
8496
+ /** When validation errors are shown (`'onBlur'`, `'onChange'`, `'onSubmit'`, `'always'`). */
8497
+ errorMode: {
8498
+ type: String,
8499
+ default: "onBlur"
8500
+ }
8501
+ };
8502
+ const FormWithActionsEmits = [
8503
+ /** Emitted when `modelValue` changes. */
8504
+ "update:modelValue",
8505
+ /** Emitted after a successful `FormStore.save()`. */
8506
+ "success",
8507
+ /** Emitted on submit when no `uri` is provided. */
8508
+ "submit",
8509
+ /** Emitted whenever form validity changes. */
8510
+ "valid",
8511
+ /** Emitted when a custom renderer dispatches a form event. */
8512
+ "events",
8513
+ /** Emitted when validation errors change. */
8514
+ "errors",
8515
+ /** Emitted when the user cancels editing an existing record. */
8516
+ "cancel"
8517
+ ];
8518
+ class FormStore {
8519
+ constructor(uri) {
8520
+ this.uri = uri;
8521
+ }
8522
+ async delete(data) {
8523
+ return useApi().delete(`${this.uri}/${data.id}`).then(() => {
8524
+ NotificationService.success("Data deleted");
8525
+ }).catch((error2) => {
8526
+ console.error(error2);
8527
+ NotificationService.error("Error deleting data");
8528
+ });
8529
+ }
8530
+ async save(id, data) {
8531
+ if (!this.uri) return;
8532
+ const promise2 = id ? useApi().patch(`${this.uri}/${id}`, data) : useApi().post(this.uri, data);
8533
+ return promise2.then((response) => {
8534
+ NotificationService.success("Data saved");
8535
+ return response.data;
8536
+ }).catch((error2) => {
8537
+ console.error(error2);
8538
+ NotificationService.error("Error saving data");
8539
+ });
8540
+ }
8541
+ }
8542
+ const _hoisted_1$1 = { class: "flex justify-end gap-2 p-2 mt-2 border-t border-gray-300 z-[30] shrink-0" };
8158
8543
  const _hoisted_2 = { class: "flex justify-end gap-2" };
8159
8544
  const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8160
- __name: "form-with-actions.component",
8161
- props: {
8162
- ...FormWithActionsProperties,
8163
- modelValue: { type: Object, default: () => ({}) }
8164
- },
8545
+ __name: "FormWithActions",
8546
+ props: FormWithActionsProperties,
8165
8547
  emits: FormWithActionsEmits,
8166
8548
  setup(__props, { emit: __emit }) {
8167
8549
  const properties = __props;
8168
8550
  const emits = __emit;
8551
+ const formRef = ref();
8169
8552
  const formData = ref(properties.modelValue);
8170
8553
  const initialFormData = ref(structuredClone(toRaw(properties.modelValue)));
8171
8554
  const recordId = ref(properties.modelValue?.id ?? null);
8172
8555
  const valid = ref(false);
8173
- const submitted = ref(false);
8174
8556
  watch(
8175
8557
  () => properties.modelValue,
8176
- (newValue, oldValue) => {
8558
+ (newValue) => {
8177
8559
  if (newValue === formData.value) return;
8178
8560
  recordId.value = newValue?.id ?? null;
8179
8561
  initialFormData.value = structuredClone(toRaw(newValue));
@@ -8188,13 +8570,11 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8188
8570
  emits("update:modelValue", data);
8189
8571
  };
8190
8572
  const save = () => {
8191
- submitted.value = true;
8192
- if (!valid.value) {
8193
- return;
8194
- }
8573
+ formRef.value?.markSubmitted();
8574
+ if (!valid.value) return;
8195
8575
  if (store.value) {
8196
- store.value.save(recordId.value, formData.value).then(() => {
8197
- emits("success");
8576
+ store.value.save(recordId.value, formData.value).then((response) => {
8577
+ emits("success", response);
8198
8578
  });
8199
8579
  } else {
8200
8580
  emits("submit", formData.value);
@@ -8202,28 +8582,31 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8202
8582
  };
8203
8583
  const clear = () => {
8204
8584
  formData.value = { id: null };
8205
- submitted.value = false;
8206
8585
  emits("update:modelValue", formData.value);
8207
8586
  };
8208
8587
  const cancel = () => {
8209
8588
  formData.value = structuredClone(toRaw(initialFormData.value));
8210
- submitted.value = false;
8211
8589
  emits("update:modelValue", formData.value);
8212
8590
  emits("cancel");
8213
8591
  };
8214
- const onValid = (v) => {
8215
- submitted.value = false;
8216
- valid.value = v;
8217
- emits("valid", v);
8218
- };
8219
8592
  const title = computed(() => {
8220
8593
  if (!properties.updateTitle) return properties.createTitle;
8221
8594
  return recordId.value ? properties.updateTitle : properties.createTitle;
8222
8595
  });
8596
+ const onErrors = (errors) => {
8597
+ emits("errors", errors);
8598
+ valid.value = isEmpty(errors);
8599
+ };
8600
+ watch(valid, (newValid, oldValid) => {
8601
+ if (newValid !== oldValid) {
8602
+ emits("valid", newValid);
8603
+ }
8604
+ });
8223
8605
  return (_ctx, _cache) => {
8224
8606
  return openBlock(), createBlock(unref(Collapse), {
8225
8607
  title: title.value,
8226
- "height-full": _ctx.fullHeight
8608
+ "height-full": _ctx.fullHeight,
8609
+ scrollable: true
8227
8610
  }, {
8228
8611
  default: withCtx(() => [
8229
8612
  createElementVNode("div", {
@@ -8234,24 +8617,19 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8234
8617
  }, [
8235
8618
  createVNode(_sfc_main$2, {
8236
8619
  id: `form_${_ctx.id}`,
8620
+ ref_key: "formRef",
8621
+ ref: formRef,
8237
8622
  "form-data": formData.value,
8238
8623
  schema: _ctx.schema,
8239
8624
  "ui-schema": _ctx.uiSchema,
8625
+ "error-mode": _ctx.errorMode,
8240
8626
  onChange: updateValue,
8241
- onValid: _cache[0] || (_cache[0] = ($event) => onValid($event)),
8242
8627
  onSubmit: save,
8243
- onErrors: _cache[1] || (_cache[1] = ($event) => emits("errors", $event)),
8244
- onEvents: _cache[2] || (_cache[2] = ($event) => emits("events", $event))
8245
- }, null, 8, ["id", "form-data", "schema", "ui-schema"])
8628
+ onErrors,
8629
+ onEvents: _cache[0] || (_cache[0] = ($event) => emits("events", $event))
8630
+ }, null, 8, ["id", "form-data", "schema", "ui-schema", "error-mode"])
8246
8631
  ], 2),
8247
- createElementVNode("div", _hoisted_1, [
8248
- createElementVNode("div", null, [
8249
- !valid.value && submitted.value ? (openBlock(), createBlock(unref(Alert), {
8250
- key: 0,
8251
- message: "The form is not valid",
8252
- type: "error"
8253
- })) : createCommentVNode("", true)
8254
- ]),
8632
+ createElementVNode("div", _hoisted_1$1, [
8255
8633
  createElementVNode("div", _hoisted_2, [
8256
8634
  renderSlot(_ctx.$slots, "actions"),
8257
8635
  recordId.value ? (openBlock(), createBlock(unref(Btn), {
@@ -8260,7 +8638,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8260
8638
  outline: true,
8261
8639
  onClick: cancel
8262
8640
  }, {
8263
- default: withCtx(() => [..._cache[3] || (_cache[3] = [
8641
+ default: withCtx(() => [..._cache[1] || (_cache[1] = [
8264
8642
  createTextVNode(" Cancel ", -1)
8265
8643
  ])]),
8266
8644
  _: 1
@@ -8270,7 +8648,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8270
8648
  outline: true,
8271
8649
  onClick: clear
8272
8650
  }, {
8273
- default: withCtx(() => [..._cache[4] || (_cache[4] = [
8651
+ default: withCtx(() => [..._cache[2] || (_cache[2] = [
8274
8652
  createTextVNode(" Clear ", -1)
8275
8653
  ])]),
8276
8654
  _: 1
@@ -8278,10 +8656,10 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8278
8656
  createVNode(unref(Btn), {
8279
8657
  "aria-label": "Save",
8280
8658
  color: unref(Color).primary,
8281
- disabled: submitted.value,
8659
+ disabled: !valid.value,
8282
8660
  onClick: save
8283
8661
  }, {
8284
- default: withCtx(() => [..._cache[5] || (_cache[5] = [
8662
+ default: withCtx(() => [..._cache[3] || (_cache[3] = [
8285
8663
  createTextVNode(" Save ", -1)
8286
8664
  ])]),
8287
8665
  _: 1
@@ -8295,216 +8673,175 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8295
8673
  };
8296
8674
  }
8297
8675
  });
8676
+ const FormWithTableProperties = {
8677
+ /** Unique identifier used to namespace the inner table element. */
8678
+ id: { type: String, required: true },
8679
+ /** Heading displayed above the table. */
8680
+ tableTitle: { type: String, required: true },
8681
+ /** Title shown in the modal when creating a new record. */
8682
+ createTitle: { type: String, required: true },
8683
+ /** Title shown in the modal when editing a record. Falls back to `createTitle` when omitted. */
8684
+ updateTitle: { type: String },
8685
+ /** Override URI used to fetch table data. Defaults to `uri` when omitted. */
8686
+ dataUri: { type: String },
8687
+ /** Custom row actions rendered in the table. */
8688
+ tableActions: { type: Array },
8689
+ /** JSON Forms layout for the create/edit modal form. */
8690
+ form: { type: Object },
8691
+ /** JSON Forms layout for the table. */
8692
+ table: { type: Object },
8693
+ /** JSON Forms layout for the table filter. */
8694
+ filter: { type: Object },
8695
+ /** REST endpoint used by `FormStore` for CRUD operations. */
8696
+ uri: { type: String },
8697
+ /** Default data pre-filled when creating a new record. */
8698
+ initialData: { type: Object, default: () => ({}) },
8699
+ /** When validation errors are shown in the modal form. */
8700
+ errorMode: {
8701
+ type: String,
8702
+ default: "onBlur"
8703
+ }
8704
+ };
8705
+ const FormWithTableEmits = [
8706
+ /** Emitted when a row is selected for editing (listener-based routing). */
8707
+ "editData",
8708
+ /** Emitted after a record is saved through the modal. */
8709
+ "save",
8710
+ /** Emitted after a record is deleted. */
8711
+ "delete",
8712
+ /** Emitted when a custom renderer dispatches a form event. */
8713
+ "events",
8714
+ /** Emitted when a custom edit handler is registered. */
8715
+ "custom:edit",
8716
+ /** Emitted when a custom create handler is registered. */
8717
+ "custom:create"
8718
+ ];
8719
+ const _hoisted_1 = { class: "flex justify-between items-center mb-2" };
8298
8720
  const _sfc_main = /* @__PURE__ */ defineComponent({
8299
- __name: "form-modal",
8300
- props: /* @__PURE__ */ mergeModels({
8301
- modalTitle: {},
8302
- saveLabel: { default: "save" },
8303
- cancelLabel: { default: "cancel" },
8304
- schema: {},
8305
- uiSchema: {},
8306
- modalSize: { default: "md" },
8307
- onClose: {},
8308
- onEvents: {},
8309
- data: {}
8310
- }, {
8311
- "modelValue": {},
8312
- "modelModifiers": {}
8313
- }),
8314
- emits: /* @__PURE__ */ mergeModels(["closeModal", "events"], ["update:modelValue"]),
8721
+ __name: "FormWithTable",
8722
+ props: FormWithTableProperties,
8723
+ emits: FormWithTableEmits,
8315
8724
  setup(__props, { emit: __emit }) {
8316
8725
  const properties = __props;
8317
- const id = `modal_${Math.floor(Math.random() * 1e3)}`;
8318
- const valid = ref(false);
8319
- const hasBeenValid = ref(false);
8320
- const formData = useModel(__props, "modelValue");
8321
- const emits = __emit;
8322
- if (properties.data) {
8323
- formData.value = properties.data;
8324
- }
8325
- const onValid = (v) => {
8326
- valid.value = v;
8327
- if (v) hasBeenValid.value = true;
8726
+ const emit = __emit;
8727
+ const reload = ref(0);
8728
+ const resolvedForm = computed(() => properties.form);
8729
+ const resolvedTable = computed(() => properties.table);
8730
+ const resolvedFilter = computed(() => properties.filter);
8731
+ const resolvedUri = computed(() => properties.uri);
8732
+ let store = new FormStore(resolvedUri.value ?? "");
8733
+ watch(resolvedUri, (uri) => {
8734
+ store = new FormStore(uri ?? "");
8735
+ });
8736
+ const hasEdit = hasCustomEventListener("editData");
8737
+ const customEdit = hasCustomEventListener("custom:edit");
8738
+ const customCreate = hasCustomEventListener("custom:create");
8739
+ const edit = (data) => {
8740
+ if (customEdit) {
8741
+ emit("custom:edit", data);
8742
+ return;
8743
+ }
8744
+ if (hasEdit) {
8745
+ emit("editData", data);
8746
+ return;
8747
+ }
8748
+ openModal(data);
8328
8749
  };
8329
- const onCancel = () => {
8330
- formData.value = {};
8331
- emits("closeModal", null);
8750
+ const create = () => {
8751
+ if (customCreate) {
8752
+ emit("custom:create");
8753
+ return;
8754
+ }
8755
+ openModal();
8332
8756
  };
8333
- const onChange = (data) => {
8334
- formData.value = data;
8757
+ const deleteFn = (data) => {
8758
+ ModalService.showConfirm({
8759
+ title: "Delete record",
8760
+ message: "Are you sure to delete, the data will be lost?",
8761
+ onClose: (result) => {
8762
+ if (result.confirmed) {
8763
+ store.delete(data).then(() => {
8764
+ reload.value = Date.now();
8765
+ emit("delete", data);
8766
+ });
8767
+ }
8768
+ }
8769
+ });
8335
8770
  };
8336
- const onSubmit = () => {
8337
- if (!valid.value) return;
8338
- emits("closeModal", { data: formData.value, valid: valid.value });
8771
+ const openModal = (formData) => {
8772
+ if (!resolvedForm.value) return;
8773
+ const isUpdate = !!formData?.id;
8774
+ JsonFormModalService.openModal({
8775
+ schema: resolvedForm.value.schema,
8776
+ uiSchema: resolvedForm.value.uiSchema,
8777
+ modalSize: resolvedForm.value.modalSize,
8778
+ initialData: formData ?? properties.initialData,
8779
+ modalTitle: (isUpdate ? properties.updateTitle ?? properties.createTitle : properties.createTitle) ?? "",
8780
+ onClose: (result) => {
8781
+ if (result && result.valid) {
8782
+ store.save(formData?.id, result.data).then(() => {
8783
+ reload.value = Date.now();
8784
+ emit("save", { id: formData?.id, data: result.data });
8785
+ });
8786
+ }
8787
+ },
8788
+ onEvents: (payload) => emit("events", payload)
8789
+ });
8339
8790
  };
8340
8791
  return (_ctx, _cache) => {
8341
- return openBlock(), createBlock(unref(Modal), mergeProps(properties, {
8342
- open: true,
8343
- "disable-close": false,
8344
- width: __props.modalSize,
8345
- onCloseModal: onCancel
8346
- }), {
8347
- content: withCtx(() => [
8348
- renderSlot(_ctx.$slots, "content-before"),
8349
- createVNode(_sfc_main$2, {
8350
- id: `modal-${id}`,
8351
- modelValue: formData.value,
8352
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => formData.value = $event),
8353
- schema: __props.schema,
8354
- "ui-schema": __props.uiSchema,
8355
- onValid: _cache[1] || (_cache[1] = ($event) => onValid($event)),
8356
- onChange,
8357
- onEvents: _cache[2] || (_cache[2] = ($event) => emits("events", $event))
8358
- }, null, 8, ["id", "modelValue", "schema", "ui-schema"]),
8359
- renderSlot(_ctx.$slots, "content-after")
8360
- ]),
8361
- actions: withCtx(() => [
8362
- createVNode(unref(Btn), {
8363
- color: unref(Color).secondary,
8364
- outline: true,
8365
- "aria-label": "Cancel",
8366
- onClick: onCancel
8367
- }, {
8368
- default: withCtx(() => [..._cache[3] || (_cache[3] = [
8369
- createTextVNode(" Cancel ", -1)
8370
- ])]),
8371
- _: 1
8372
- }, 8, ["color"]),
8373
- createVNode(unref(Btn), {
8374
- disabled: !hasBeenValid.value,
8375
- "aria-label": "Save",
8376
- onClick: onSubmit
8377
- }, {
8378
- default: withCtx(() => [..._cache[4] || (_cache[4] = [
8379
- createTextVNode(" Save ", -1)
8380
- ])]),
8381
- _: 1
8382
- }, 8, ["disabled"])
8792
+ return openBlock(), createElementBlock(Fragment, null, [
8793
+ createElementVNode("div", _hoisted_1, [
8794
+ createElementVNode("h1", null, toDisplayString(_ctx.tableTitle), 1),
8795
+ createElementVNode("div", null, [
8796
+ createVNode(unref(Btn), {
8797
+ icon: unref(IconEnum).Plus,
8798
+ outline: true,
8799
+ onClick: create
8800
+ }, {
8801
+ default: withCtx(() => [..._cache[0] || (_cache[0] = [
8802
+ createTextVNode(" Add new record ", -1)
8803
+ ])]),
8804
+ _: 1
8805
+ }, 8, ["icon"])
8806
+ ])
8383
8807
  ]),
8384
- _: 3
8385
- }, 16, ["width"]);
8808
+ resolvedTable.value ? (openBlock(), createBlock(unref(Card), { key: 0 }, {
8809
+ default: withCtx(() => [
8810
+ resolvedUri.value ? (openBlock(), createBlock(unref(_sfc_main$g), {
8811
+ key: 0,
8812
+ id: `form_table_${_ctx.id}`,
8813
+ "ui-schema": resolvedTable.value.uiSchema,
8814
+ schema: resolvedTable.value.schema,
8815
+ "filter-ui-schema": resolvedFilter.value?.uiSchema,
8816
+ "filter-schema": resolvedFilter.value?.schema,
8817
+ uri: _ctx.dataUri ?? resolvedUri.value,
8818
+ reload: reload.value,
8819
+ actions: _ctx.tableActions,
8820
+ onEdit: edit,
8821
+ onDelete: deleteFn
8822
+ }, null, 8, ["id", "ui-schema", "schema", "filter-ui-schema", "filter-schema", "uri", "reload", "actions"])) : createCommentVNode("", true)
8823
+ ]),
8824
+ _: 1
8825
+ })) : createCommentVNode("", true)
8826
+ ], 64);
8386
8827
  };
8387
8828
  }
8388
8829
  });
8389
- class FormModalService {
8390
- static openModal({
8391
- initialData,
8392
- modalTitle,
8393
- schema,
8394
- uiSchema,
8395
- modalSize,
8396
- onClose,
8397
- onEvents
8398
- }) {
8399
- ModalService.openModal({
8400
- component: _sfc_main,
8401
- props: {
8402
- schema,
8403
- uiSchema,
8404
- modalSize,
8405
- data: initialData ?? {},
8406
- modalTitle,
8407
- onClose,
8408
- onEvents
8409
- }
8410
- });
8411
- }
8412
- }
8413
- const createRepository = (formSchemaModel, httpRequest, options = {}) => {
8414
- const notificationEntity = options.notification?.entityType || "entity";
8415
- const notificationStore = options.notification?.notification ?? null;
8416
- const getDataUri = (...suffix) => {
8417
- return [formSchemaModel.uri, ...suffix].join("/");
8418
- };
8419
- const handleSuccess = (message) => {
8420
- notificationStore?.success(message);
8421
- };
8422
- const handleError = (error2, message) => {
8423
- console.error(error2);
8424
- notificationStore?.error(message);
8425
- throw new Error(error2);
8426
- };
8427
- const create = (object2, options2) => {
8428
- return httpRequest.post(getDataUri(), object2, options2).then((response) => {
8429
- handleSuccess(`Created ${notificationEntity}`);
8430
- return response.data;
8431
- }).catch((response) => {
8432
- handleError(response, `Failed to create ${notificationEntity}`);
8433
- });
8434
- };
8435
- const patch = (id, object2, options2) => {
8436
- return httpRequest.patch(getDataUri(id), object2, options2).then((response) => {
8437
- handleSuccess(`Saved ${notificationEntity}`);
8438
- return response.data;
8439
- }).catch((response) => {
8440
- handleError(response, `Failed to save ${notificationEntity}`);
8441
- });
8442
- };
8443
- const get = (id, options2) => {
8444
- return httpRequest.get(getDataUri(id), options2).then((response) => {
8445
- return response.data;
8446
- }).catch((response) => {
8447
- handleError(response, `Failed to load data`);
8448
- });
8449
- };
8450
- const _delete = (id, options2) => {
8451
- return httpRequest.delete(getDataUri(id), options2).then((response) => {
8452
- handleSuccess(`${notificationEntity} deleted`);
8453
- return response;
8454
- }).catch((response) => {
8455
- handleError(response, `Failed to delete ${notificationEntity}`);
8456
- });
8457
- };
8458
- const createMulti = (objects, options2) => {
8459
- return Promise.all(
8460
- objects.map((object2) => httpRequest.post(getDataUri(), object2, options2))
8461
- ).then((response) => {
8462
- handleSuccess(`Created ${notificationEntity}`);
8463
- return response.data;
8464
- }).catch((response) => {
8465
- handleError(response, `Failed to save ${notificationEntity}`);
8466
- });
8467
- };
8468
- return { create, patch, createMulti, delete: _delete, get };
8469
- };
8470
8830
  export {
8471
- _sfc_main$a as ArrayRenderer,
8472
- _sfc_main$j as AutocompleteControlRenderer,
8473
- _sfc_main$i as BooleanControlRenderer,
8474
- _sfc_main$2 as FormComponent,
8475
- FormComponentEmits,
8476
- FormComponentProperties,
8477
- _sfc_main as FormModal,
8478
- FormModalService,
8479
- FormStore,
8480
- _sfc_main$1 as FormWithActions,
8481
- FormWithActionsEmits,
8482
- FormWithActionsProperties,
8483
- _sfc_main$3 as FormWithTableComponent,
8484
- FormWithTableEmits,
8485
- FormWithTableProperties,
8486
- _sfc_main$h as IntegerControlRenderer,
8487
- _sfc_main$f as MultiSelectControlRender,
8488
- _sfc_main$e as NumberControlRenderer,
8489
- _sfc_main$d as SelectControlRender,
8490
- _sfc_main$c as StringControlRenderer,
8491
- _sfc_main$4 as TableComponent,
8831
+ FormModalEmits,
8832
+ FormModalProperties,
8833
+ _sfc_main$2 as JsonForm,
8834
+ _sfc_main$d as JsonFormModal,
8835
+ JsonFormModalService,
8836
+ _sfc_main$1 as JsonFormWithActions,
8837
+ _sfc_main as JsonFormWithTable,
8838
+ _sfc_main$g as TableComponent,
8492
8839
  TableComponentEmits,
8493
8840
  TableComponentProperties,
8494
- arrayRenderers,
8495
- controlRenderers,
8496
8841
  createRepository,
8497
- isArrayRenderer,
8498
- isAutoCompleteControl,
8499
- isBooleanControl,
8500
- isCustomControl,
8501
- isMarkdownControl,
8502
- isMultiselectControl,
8503
- isSelectControl,
8504
- isStringFormat,
8505
- isTextAreaControl,
8506
- layoutRenderers,
8507
- _sfc_main$g as markdownControlRenderer,
8842
+ formatError,
8508
8843
  provideFormEvents,
8509
- useFormEvents
8844
+ registerZodErrorMap,
8845
+ useFormEvents,
8846
+ customRenderes as veeRenderers
8510
8847
  };