@duke333/builder-ui 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +85 -0
- package/dist/RuntimeEntryDialog-DAO74GFp.d.ts +282 -0
- package/dist/admin/index.d.ts +631 -0
- package/dist/admin/index.js +644 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/api/index.d.ts +99 -0
- package/dist/api/index.js +92 -0
- package/dist/api/index.js.map +1 -0
- package/dist/components/index.d.ts +137 -0
- package/dist/components/index.js +581 -0
- package/dist/components/index.js.map +1 -0
- package/dist/hooks/index.d.ts +107 -0
- package/dist/hooks/index.js +301 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +1397 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/index.d.ts +28 -0
- package/dist/runtime/index.js +31 -0
- package/dist/runtime/index.js.map +1 -0
- package/package.json +61 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1397 @@
|
|
|
1
|
+
// src/admin/BuilderEditorPage.tsx
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import {
|
|
4
|
+
FormProvider,
|
|
5
|
+
useFieldArray,
|
|
6
|
+
useForm,
|
|
7
|
+
useWatch
|
|
8
|
+
} from "react-hook-form";
|
|
9
|
+
|
|
10
|
+
// src/admin/editorState.ts
|
|
11
|
+
var BUILDER_EDITOR_NONE_VALUE = "__none";
|
|
12
|
+
function builderEditorOptionsToText(options) {
|
|
13
|
+
return (options ?? []).map((option) => `${option.label}:${option.value}`).join("\n");
|
|
14
|
+
}
|
|
15
|
+
function builderEditorTextToOptions(value) {
|
|
16
|
+
const rows = (value ?? "").split("\n").map((line) => line.trim()).filter(Boolean);
|
|
17
|
+
if (rows.length === 0) return void 0;
|
|
18
|
+
return rows.map((line) => {
|
|
19
|
+
const [label, ...rest] = line.split(":");
|
|
20
|
+
return { label: label.trim(), value: rest.join(":").trim() || label.trim() };
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function builderEditorSearchFieldsToText(fields) {
|
|
24
|
+
return (fields ?? []).join("\n");
|
|
25
|
+
}
|
|
26
|
+
function builderEditorTextToSearchFields(value) {
|
|
27
|
+
const fields = (value ?? "").split("\n").map((line) => line.trim()).filter(Boolean);
|
|
28
|
+
return fields.length > 0 ? fields : void 0;
|
|
29
|
+
}
|
|
30
|
+
function getBuilderEditorTriggerRoute(config) {
|
|
31
|
+
const route = config.route ?? config.path ?? config.url;
|
|
32
|
+
return typeof route === "string" ? route : "";
|
|
33
|
+
}
|
|
34
|
+
function valuesFromTriggers(triggers) {
|
|
35
|
+
return triggers.filter((trigger) => trigger.action === "callApi" || trigger.action === "webhook").map((trigger) => ({
|
|
36
|
+
event: trigger.event,
|
|
37
|
+
route: getBuilderEditorTriggerRoute(trigger.config),
|
|
38
|
+
enabled: trigger.enabled,
|
|
39
|
+
blocking: trigger.blocking
|
|
40
|
+
})).filter((trigger) => trigger.route);
|
|
41
|
+
}
|
|
42
|
+
function valuesFromFieldTriggers(triggers) {
|
|
43
|
+
return (triggers ?? []).map((trigger) => ({
|
|
44
|
+
event: trigger.event,
|
|
45
|
+
action: trigger.action,
|
|
46
|
+
enabled: trigger.enabled,
|
|
47
|
+
debounceMs: trigger.debounceMs
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
function clampLayoutSpan(span, columns) {
|
|
51
|
+
if (!span || Number.isNaN(span)) return columns;
|
|
52
|
+
return Math.max(1, Math.min(columns, Math.trunc(span)));
|
|
53
|
+
}
|
|
54
|
+
function builderFormEditorDefaultSpan(field) {
|
|
55
|
+
if (field.type === "textarea" || field.type === "checkbox") return 12;
|
|
56
|
+
return 6;
|
|
57
|
+
}
|
|
58
|
+
function builderFormEditorDefaultLayoutGroups(fields, subforms = []) {
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
id: "main",
|
|
62
|
+
title: "\u04AE\u043D\u0434\u0441\u044D\u043D",
|
|
63
|
+
columns: 12,
|
|
64
|
+
fields: [
|
|
65
|
+
...fields.map((field) => ({
|
|
66
|
+
key: field.key,
|
|
67
|
+
span: builderFormEditorDefaultSpan(field)
|
|
68
|
+
})),
|
|
69
|
+
...subforms.map((subform) => ({ key: subform.key, span: 12 }))
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
function normalizeBuilderFormEditorLayoutGroups(groups, fields, subforms = []) {
|
|
75
|
+
if (fields.length === 0 && subforms.length === 0) return [];
|
|
76
|
+
const layoutItems = [
|
|
77
|
+
...fields.map((field) => ({
|
|
78
|
+
key: field.key,
|
|
79
|
+
span: builderFormEditorDefaultSpan(field)
|
|
80
|
+
})),
|
|
81
|
+
...subforms.map((subform) => ({ key: subform.key, span: 12 }))
|
|
82
|
+
];
|
|
83
|
+
const itemKeys = new Set(layoutItems.map((item) => item.key));
|
|
84
|
+
const usedKeys = /* @__PURE__ */ new Set();
|
|
85
|
+
const normalized = (groups ?? []).map((group, index) => {
|
|
86
|
+
const columns = group.columns === 6 || group.columns === 8 ? group.columns : 12;
|
|
87
|
+
const groupFields = (group.fields ?? []).filter((field) => itemKeys.has(field.key) && !usedKeys.has(field.key)).map((field) => {
|
|
88
|
+
usedKeys.add(field.key);
|
|
89
|
+
return { key: field.key, span: clampLayoutSpan(field.span, columns) };
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
id: group.id || `group${index + 1}`,
|
|
93
|
+
title: group.title || `Group ${index + 1}`,
|
|
94
|
+
columns,
|
|
95
|
+
fields: groupFields
|
|
96
|
+
};
|
|
97
|
+
}).filter((group) => group.fields.length > 0 || group.title.trim());
|
|
98
|
+
const missingFields = layoutItems.filter((item) => !usedKeys.has(item.key));
|
|
99
|
+
if (normalized.length === 0) {
|
|
100
|
+
return builderFormEditorDefaultLayoutGroups(fields, subforms);
|
|
101
|
+
}
|
|
102
|
+
if (missingFields.length > 0) {
|
|
103
|
+
normalized.push({
|
|
104
|
+
id: "ungrouped",
|
|
105
|
+
title: "\u0411\u0443\u0441\u0430\u0434",
|
|
106
|
+
columns: 12,
|
|
107
|
+
fields: missingFields
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return normalized;
|
|
111
|
+
}
|
|
112
|
+
function builderFormEditorValuesFromEntity(form, emptyValues) {
|
|
113
|
+
if (!form) return emptyValues;
|
|
114
|
+
const source = form.source;
|
|
115
|
+
const fields = form.schema.fields.map((field) => ({
|
|
116
|
+
key: field.key,
|
|
117
|
+
label: field.label,
|
|
118
|
+
type: field.type,
|
|
119
|
+
required: field.required,
|
|
120
|
+
hidden: field.hidden ?? false,
|
|
121
|
+
disabled: field.disabled ?? false,
|
|
122
|
+
placeholder: field.placeholder ?? "",
|
|
123
|
+
optionsText: builderEditorOptionsToText(field.options),
|
|
124
|
+
optionsMode: field.optionsSource?.type === "dbTable" ? "table" : "static",
|
|
125
|
+
optionsTable: field.optionsSource?.type === "dbTable" ? field.optionsSource.tableName : BUILDER_EDITOR_NONE_VALUE,
|
|
126
|
+
optionsValueField: field.optionsSource?.type === "dbTable" ? field.optionsSource.valueField : BUILDER_EDITOR_NONE_VALUE,
|
|
127
|
+
optionsLabelField: field.optionsSource?.type === "dbTable" ? field.optionsSource.labelField : BUILDER_EDITOR_NONE_VALUE,
|
|
128
|
+
optionsSearchFieldsText: field.optionsSource?.type === "dbTable" ? builderEditorSearchFieldsToText(field.optionsSource.searchFields) : "",
|
|
129
|
+
optionsDependsOn: field.optionsSource?.type === "dbTable" ? field.optionsSource.filterBy?.valueFromField ?? "" : "",
|
|
130
|
+
optionsFilterField: field.optionsSource?.type === "dbTable" ? field.optionsSource.filterBy?.field ?? "" : "",
|
|
131
|
+
triggers: valuesFromFieldTriggers(field.triggers)
|
|
132
|
+
}));
|
|
133
|
+
const subforms = (form.schema.subforms ?? []).map((subform) => ({
|
|
134
|
+
key: subform.key,
|
|
135
|
+
label: subform.label,
|
|
136
|
+
viewId: subform.viewId,
|
|
137
|
+
parentField: subform.parentField,
|
|
138
|
+
childField: subform.childField,
|
|
139
|
+
buttonLabel: subform.buttonLabel ?? "",
|
|
140
|
+
icon: subform.icon ?? ""
|
|
141
|
+
}));
|
|
142
|
+
return {
|
|
143
|
+
title: form.title,
|
|
144
|
+
description: form.description ?? "",
|
|
145
|
+
sourceType: source?.type ?? "none",
|
|
146
|
+
sourceTable: source?.type === "dbTable" ? source.tableName : BUILDER_EDITOR_NONE_VALUE,
|
|
147
|
+
apiBasePath: source?.type === "apiEndpoint" ? source.basePath : "",
|
|
148
|
+
fields,
|
|
149
|
+
layoutGroups: normalizeBuilderFormEditorLayoutGroups(
|
|
150
|
+
form.schema.layout?.groups,
|
|
151
|
+
fields,
|
|
152
|
+
subforms
|
|
153
|
+
),
|
|
154
|
+
subforms,
|
|
155
|
+
triggers: valuesFromTriggers(form.triggers),
|
|
156
|
+
version: form.version
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function builderListEditorValuesFromEntity(list, emptyValues) {
|
|
160
|
+
if (!list) return emptyValues;
|
|
161
|
+
const source = list.source;
|
|
162
|
+
return {
|
|
163
|
+
title: list.title,
|
|
164
|
+
description: list.description ?? "",
|
|
165
|
+
sourceType: source?.type ?? "none",
|
|
166
|
+
sourceTable: source?.type === "dbTable" ? source.tableName : BUILDER_EDITOR_NONE_VALUE,
|
|
167
|
+
apiBasePath: source?.type === "apiEndpoint" ? source.basePath : "",
|
|
168
|
+
columns: list.schema.columns.map((column) => ({
|
|
169
|
+
key: column.key,
|
|
170
|
+
label: column.label,
|
|
171
|
+
sortable: column.sortable,
|
|
172
|
+
align: column.align
|
|
173
|
+
})),
|
|
174
|
+
triggers: valuesFromTriggers(list.triggers),
|
|
175
|
+
version: list.version
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function builderViewEditorValuesFromEntity(view, emptyValues, defaultPermission) {
|
|
179
|
+
if (!view) return emptyValues;
|
|
180
|
+
return {
|
|
181
|
+
title: view.title,
|
|
182
|
+
description: view.description ?? "",
|
|
183
|
+
formId: view.formId ?? BUILDER_EDITOR_NONE_VALUE,
|
|
184
|
+
listId: view.listId ?? BUILDER_EDITOR_NONE_VALUE,
|
|
185
|
+
permissionRead: view.permissionRead ?? defaultPermission,
|
|
186
|
+
permissionWrite: view.permissionWrite ?? defaultPermission,
|
|
187
|
+
triggersText: JSON.stringify(view.triggers ?? [], null, 2),
|
|
188
|
+
version: view.version
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function builderFormEditorFieldsFromTable(table) {
|
|
192
|
+
return table.columns.map((column) => ({
|
|
193
|
+
key: column.name,
|
|
194
|
+
label: column.label,
|
|
195
|
+
type: column.fieldType,
|
|
196
|
+
required: !column.nullable,
|
|
197
|
+
hidden: false,
|
|
198
|
+
disabled: false,
|
|
199
|
+
placeholder: column.label,
|
|
200
|
+
optionsText: "",
|
|
201
|
+
optionsMode: "static",
|
|
202
|
+
optionsTable: BUILDER_EDITOR_NONE_VALUE,
|
|
203
|
+
optionsValueField: BUILDER_EDITOR_NONE_VALUE,
|
|
204
|
+
optionsLabelField: BUILDER_EDITOR_NONE_VALUE,
|
|
205
|
+
optionsSearchFieldsText: "",
|
|
206
|
+
optionsDependsOn: "",
|
|
207
|
+
optionsFilterField: "",
|
|
208
|
+
triggers: []
|
|
209
|
+
}));
|
|
210
|
+
}
|
|
211
|
+
function builderListEditorColumnsFromTable(table) {
|
|
212
|
+
return table.columns.map((column) => ({
|
|
213
|
+
key: column.name,
|
|
214
|
+
label: column.label,
|
|
215
|
+
sortable: column.sortable,
|
|
216
|
+
align: column.fieldType === "number" || column.fieldType === "money" ? "right" : "left"
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
function builderFormEditorInputFromValues(values) {
|
|
220
|
+
const source = values.sourceType === "dbTable" && values.sourceTable !== BUILDER_EDITOR_NONE_VALUE ? { type: "dbTable", tableName: values.sourceTable } : values.sourceType === "apiEndpoint" && values.apiBasePath ? { type: "apiEndpoint", basePath: values.apiBasePath } : null;
|
|
221
|
+
return {
|
|
222
|
+
title: values.title,
|
|
223
|
+
description: values.description || null,
|
|
224
|
+
source,
|
|
225
|
+
schema: {
|
|
226
|
+
fields: values.fields.map((field) => ({
|
|
227
|
+
key: field.key,
|
|
228
|
+
label: field.label,
|
|
229
|
+
type: field.type,
|
|
230
|
+
required: field.required,
|
|
231
|
+
hidden: field.hidden,
|
|
232
|
+
disabled: field.disabled,
|
|
233
|
+
placeholder: field.placeholder?.trim() || field.label,
|
|
234
|
+
options: field.type === "select" && field.optionsMode === "static" ? builderEditorTextToOptions(field.optionsText) : void 0,
|
|
235
|
+
optionsSource: field.type === "select" && field.optionsMode === "table" && field.optionsTable !== BUILDER_EDITOR_NONE_VALUE && field.optionsValueField !== BUILDER_EDITOR_NONE_VALUE && field.optionsLabelField !== BUILDER_EDITOR_NONE_VALUE ? {
|
|
236
|
+
type: "dbTable",
|
|
237
|
+
tableName: field.optionsTable,
|
|
238
|
+
valueField: field.optionsValueField,
|
|
239
|
+
labelField: field.optionsLabelField,
|
|
240
|
+
searchFields: builderEditorTextToSearchFields(field.optionsSearchFieldsText),
|
|
241
|
+
filterBy: field.optionsDependsOn && field.optionsFilterField ? {
|
|
242
|
+
field: field.optionsFilterField,
|
|
243
|
+
valueFromField: field.optionsDependsOn
|
|
244
|
+
} : void 0
|
|
245
|
+
} : void 0,
|
|
246
|
+
triggers: field.triggers.map((trigger) => ({
|
|
247
|
+
event: trigger.event,
|
|
248
|
+
action: trigger.action,
|
|
249
|
+
enabled: trigger.enabled,
|
|
250
|
+
debounceMs: trigger.debounceMs,
|
|
251
|
+
config: {}
|
|
252
|
+
}))
|
|
253
|
+
})),
|
|
254
|
+
layout: {
|
|
255
|
+
groups: normalizeBuilderFormEditorLayoutGroups(
|
|
256
|
+
values.layoutGroups,
|
|
257
|
+
values.fields,
|
|
258
|
+
values.subforms ?? []
|
|
259
|
+
)
|
|
260
|
+
},
|
|
261
|
+
subforms: (values.subforms ?? []).filter(
|
|
262
|
+
(subform) => subform.key && subform.label && subform.viewId !== BUILDER_EDITOR_NONE_VALUE && subform.parentField && subform.childField
|
|
263
|
+
).map((subform) => ({
|
|
264
|
+
key: subform.key,
|
|
265
|
+
label: subform.label,
|
|
266
|
+
viewId: subform.viewId,
|
|
267
|
+
parentField: subform.parentField,
|
|
268
|
+
childField: subform.childField,
|
|
269
|
+
buttonLabel: subform.buttonLabel?.trim() || void 0,
|
|
270
|
+
icon: subform.icon?.trim() || void 0
|
|
271
|
+
}))
|
|
272
|
+
},
|
|
273
|
+
triggers: values.triggers.map((trigger) => ({
|
|
274
|
+
event: trigger.event,
|
|
275
|
+
action: "callApi",
|
|
276
|
+
enabled: trigger.enabled,
|
|
277
|
+
blocking: trigger.blocking,
|
|
278
|
+
config: { route: trigger.route }
|
|
279
|
+
})),
|
|
280
|
+
version: values.version
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function builderListEditorInputFromValues(values) {
|
|
284
|
+
const source = values.sourceType === "dbTable" && values.sourceTable !== BUILDER_EDITOR_NONE_VALUE ? { type: "dbTable", tableName: values.sourceTable } : values.sourceType === "apiEndpoint" && values.apiBasePath ? { type: "apiEndpoint", basePath: values.apiBasePath } : null;
|
|
285
|
+
return {
|
|
286
|
+
title: values.title,
|
|
287
|
+
description: values.description || null,
|
|
288
|
+
source,
|
|
289
|
+
schema: { columns: values.columns },
|
|
290
|
+
triggers: values.triggers.map((trigger) => ({
|
|
291
|
+
event: trigger.event,
|
|
292
|
+
action: "callApi",
|
|
293
|
+
enabled: trigger.enabled,
|
|
294
|
+
blocking: trigger.blocking,
|
|
295
|
+
config: { route: trigger.route }
|
|
296
|
+
})),
|
|
297
|
+
version: values.version
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function builderViewEditorInputFromValues(values, parseTriggers) {
|
|
301
|
+
return {
|
|
302
|
+
title: values.title,
|
|
303
|
+
description: values.description || null,
|
|
304
|
+
formId: values.formId === BUILDER_EDITOR_NONE_VALUE ? null : values.formId,
|
|
305
|
+
listId: values.listId === BUILDER_EDITOR_NONE_VALUE ? null : values.listId,
|
|
306
|
+
permissionRead: values.permissionRead,
|
|
307
|
+
permissionWrite: values.permissionWrite,
|
|
308
|
+
triggers: values.triggersText?.trim() ? parseTriggers(values.triggersText) : [],
|
|
309
|
+
version: values.version
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/admin/BuilderEditorPage.tsx
|
|
314
|
+
import { jsx } from "react/jsx-runtime";
|
|
315
|
+
function createBuilderFormEditorPageComponent(deps) {
|
|
316
|
+
return function BuilderFormEditorPage({ formId }) {
|
|
317
|
+
const Body = deps.Body;
|
|
318
|
+
const entityQuery = deps.hooks.useEntity(formId);
|
|
319
|
+
const tables = deps.hooks.useTables();
|
|
320
|
+
const save = deps.hooks.useSave();
|
|
321
|
+
const form = useForm({
|
|
322
|
+
resolver: deps.resolver,
|
|
323
|
+
defaultValues: deps.emptyValues
|
|
324
|
+
});
|
|
325
|
+
const fieldArray = useFieldArray({ control: form.control, name: "fields" });
|
|
326
|
+
const subformArray = useFieldArray({ control: form.control, name: "subforms" });
|
|
327
|
+
const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
|
|
328
|
+
const fields = useWatch({ control: form.control, name: "fields" }) ?? [];
|
|
329
|
+
const subforms = useWatch({ control: form.control, name: "subforms" }) ?? [];
|
|
330
|
+
const sourceType = useWatch({ control: form.control, name: "sourceType" });
|
|
331
|
+
const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
|
|
332
|
+
useEffect(() => {
|
|
333
|
+
if (formId && !entityQuery.data) return;
|
|
334
|
+
form.reset(builderFormEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
|
|
335
|
+
}, [entityQuery.data, form, formId]);
|
|
336
|
+
const importFieldsFromTable = () => {
|
|
337
|
+
const table = tables.data?.find((item) => item.name === sourceTable);
|
|
338
|
+
if (!table) return;
|
|
339
|
+
const nextFields = builderFormEditorFieldsFromTable(table);
|
|
340
|
+
fieldArray.replace(nextFields);
|
|
341
|
+
form.setValue("layoutGroups", builderFormEditorDefaultLayoutGroups(nextFields), {
|
|
342
|
+
shouldDirty: true
|
|
343
|
+
});
|
|
344
|
+
};
|
|
345
|
+
const onSubmit = form.handleSubmit(async (values) => {
|
|
346
|
+
try {
|
|
347
|
+
const saved = await save.mutateAsync({ id: formId, input: deps.buildInput(values) });
|
|
348
|
+
deps.notifications.success(formId ? deps.labels.saved : deps.labels.created);
|
|
349
|
+
if (!formId) deps.navigateAfterCreate(saved);
|
|
350
|
+
} catch (error) {
|
|
351
|
+
deps.notifications.error(error);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
if (formId && entityQuery.isPending) {
|
|
355
|
+
return /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
|
|
356
|
+
}
|
|
357
|
+
if (formId && entityQuery.isError) {
|
|
358
|
+
return /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: deps.states.error });
|
|
359
|
+
}
|
|
360
|
+
return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx(
|
|
361
|
+
Body,
|
|
362
|
+
{
|
|
363
|
+
formId,
|
|
364
|
+
form,
|
|
365
|
+
fieldArray,
|
|
366
|
+
subformArray,
|
|
367
|
+
triggerArray,
|
|
368
|
+
fields,
|
|
369
|
+
subforms,
|
|
370
|
+
sourceType,
|
|
371
|
+
sourceTable,
|
|
372
|
+
tables: tables.data ?? [],
|
|
373
|
+
emptyField: deps.emptyField,
|
|
374
|
+
emptyTrigger: deps.emptyTrigger,
|
|
375
|
+
isSaving: save.isPending,
|
|
376
|
+
importFieldsFromTable
|
|
377
|
+
}
|
|
378
|
+
) }) });
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function createBuilderListEditorPageComponent(deps) {
|
|
382
|
+
return function BuilderListEditorPage({ listId }) {
|
|
383
|
+
const Body = deps.Body;
|
|
384
|
+
const entityQuery = deps.hooks.useEntity(listId);
|
|
385
|
+
const tables = deps.hooks.useTables();
|
|
386
|
+
const save = deps.hooks.useSave();
|
|
387
|
+
const form = useForm({
|
|
388
|
+
resolver: deps.resolver,
|
|
389
|
+
defaultValues: deps.emptyValues
|
|
390
|
+
});
|
|
391
|
+
const columnArray = useFieldArray({ control: form.control, name: "columns" });
|
|
392
|
+
const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
|
|
393
|
+
const sourceType = useWatch({ control: form.control, name: "sourceType" });
|
|
394
|
+
const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
if (listId && !entityQuery.data) return;
|
|
397
|
+
form.reset(builderListEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
|
|
398
|
+
}, [entityQuery.data, form, listId]);
|
|
399
|
+
const importColumnsFromTable = () => {
|
|
400
|
+
const table = tables.data?.find((item) => item.name === sourceTable);
|
|
401
|
+
if (!table) return;
|
|
402
|
+
columnArray.replace(builderListEditorColumnsFromTable(table));
|
|
403
|
+
};
|
|
404
|
+
const onSubmit = form.handleSubmit(async (values) => {
|
|
405
|
+
try {
|
|
406
|
+
const saved = await save.mutateAsync({ id: listId, input: deps.buildInput(values) });
|
|
407
|
+
deps.notifications.success(listId ? deps.labels.saved : deps.labels.created);
|
|
408
|
+
if (!listId) deps.navigateAfterCreate(saved);
|
|
409
|
+
} catch (error) {
|
|
410
|
+
deps.notifications.error(error);
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
if (listId && entityQuery.isPending) {
|
|
414
|
+
return /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
|
|
415
|
+
}
|
|
416
|
+
if (listId && entityQuery.isError) {
|
|
417
|
+
return /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: deps.states.error });
|
|
418
|
+
}
|
|
419
|
+
return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx(
|
|
420
|
+
Body,
|
|
421
|
+
{
|
|
422
|
+
listId,
|
|
423
|
+
form,
|
|
424
|
+
columnArray,
|
|
425
|
+
triggerArray,
|
|
426
|
+
sourceType,
|
|
427
|
+
sourceTable,
|
|
428
|
+
tables: tables.data ?? [],
|
|
429
|
+
emptyColumn: deps.emptyColumn,
|
|
430
|
+
emptyTrigger: deps.emptyTrigger,
|
|
431
|
+
isSaving: save.isPending,
|
|
432
|
+
importColumnsFromTable
|
|
433
|
+
}
|
|
434
|
+
) }) });
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/admin/BuilderEntityManager.tsx
|
|
439
|
+
import { useCallback, useMemo, useState } from "react";
|
|
440
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
441
|
+
function createBuilderEntityManagerComponent(deps) {
|
|
442
|
+
return function BuilderEntityManager() {
|
|
443
|
+
const [pendingDelete, setPendingDelete] = useState(null);
|
|
444
|
+
const state = deps.useDataTableState({ pageSize: 20 });
|
|
445
|
+
const query = deps.hooks.useEntities(state.query);
|
|
446
|
+
const remove = deps.hooks.useDelete();
|
|
447
|
+
const replicate = deps.hooks.useReplicate();
|
|
448
|
+
const columns = useMemo(
|
|
449
|
+
() => deps.buildColumns({
|
|
450
|
+
onEdit: deps.navigateToEdit,
|
|
451
|
+
onReplicate: async (entity) => {
|
|
452
|
+
const title = await deps.requestReplicateTitle(entity);
|
|
453
|
+
if (!title) return;
|
|
454
|
+
await replicate.mutateAsync({ id: entity.id, input: { title } });
|
|
455
|
+
},
|
|
456
|
+
onDelete: setPendingDelete,
|
|
457
|
+
runtimeHref: deps.runtimeHref
|
|
458
|
+
}),
|
|
459
|
+
[replicate]
|
|
460
|
+
);
|
|
461
|
+
const controller = deps.useDataTable({
|
|
462
|
+
columns,
|
|
463
|
+
data: query.data?.items ?? [],
|
|
464
|
+
rowCount: query.data?.total ?? 0,
|
|
465
|
+
state,
|
|
466
|
+
getRowId: (row) => row.id
|
|
467
|
+
});
|
|
468
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
469
|
+
/* @__PURE__ */ jsx2(
|
|
470
|
+
deps.DataGrid,
|
|
471
|
+
{
|
|
472
|
+
title: deps.labels.title,
|
|
473
|
+
description: deps.labels.description,
|
|
474
|
+
controller,
|
|
475
|
+
isLoading: query.isPending,
|
|
476
|
+
searchPlaceholder: deps.labels.searchPlaceholder,
|
|
477
|
+
emptyTitle: deps.labels.emptyTitle,
|
|
478
|
+
emptyDescription: deps.labels.emptyDescription,
|
|
479
|
+
onRowClick: deps.navigateToEdit,
|
|
480
|
+
toolbarExtra: /* @__PURE__ */ jsx2(deps.AddButton, { href: deps.createHref, label: deps.labels.addLabel })
|
|
481
|
+
}
|
|
482
|
+
),
|
|
483
|
+
/* @__PURE__ */ jsx2(
|
|
484
|
+
deps.DeleteDialog,
|
|
485
|
+
{
|
|
486
|
+
entity: pendingDelete,
|
|
487
|
+
title: deps.labels.deleteTitle,
|
|
488
|
+
description: deps.labels.deleteDescription(pendingDelete),
|
|
489
|
+
isDeleting: remove.isPending,
|
|
490
|
+
onClose: () => setPendingDelete(null),
|
|
491
|
+
onConfirm: async () => {
|
|
492
|
+
if (!pendingDelete) return;
|
|
493
|
+
await remove.mutateAsync(pendingDelete.id);
|
|
494
|
+
setPendingDelete(null);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
)
|
|
498
|
+
] });
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function createBuilderEntityDialogManagerComponent(deps) {
|
|
502
|
+
return function BuilderEntityDialogManager() {
|
|
503
|
+
const [editing, setEditing] = useState(null);
|
|
504
|
+
const [isEditorOpen, setEditorOpen] = useState(false);
|
|
505
|
+
const [pendingDelete, setPendingDelete] = useState(null);
|
|
506
|
+
const state = deps.useDataTableState({ pageSize: 20 });
|
|
507
|
+
const query = deps.hooks.useEntities(state.query);
|
|
508
|
+
const remove = deps.hooks.useDelete();
|
|
509
|
+
const replicate = deps.hooks.useReplicate();
|
|
510
|
+
const openEditor = useCallback((entity) => {
|
|
511
|
+
setEditing(entity);
|
|
512
|
+
setEditorOpen(true);
|
|
513
|
+
}, []);
|
|
514
|
+
const columns = useMemo(
|
|
515
|
+
() => deps.buildColumns({
|
|
516
|
+
onEdit: (entity) => openEditor(entity),
|
|
517
|
+
onReplicate: async (entity) => {
|
|
518
|
+
const title = await deps.requestReplicateTitle(entity);
|
|
519
|
+
if (!title) return;
|
|
520
|
+
await replicate.mutateAsync({ id: entity.id, input: { title } });
|
|
521
|
+
},
|
|
522
|
+
onDelete: setPendingDelete,
|
|
523
|
+
runtimeHref: deps.runtimeHref
|
|
524
|
+
}),
|
|
525
|
+
[replicate, openEditor]
|
|
526
|
+
);
|
|
527
|
+
const controller = deps.useDataTable({
|
|
528
|
+
columns,
|
|
529
|
+
data: query.data?.items ?? [],
|
|
530
|
+
rowCount: query.data?.total ?? 0,
|
|
531
|
+
state,
|
|
532
|
+
getRowId: (row) => row.id
|
|
533
|
+
});
|
|
534
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
535
|
+
/* @__PURE__ */ jsx2(
|
|
536
|
+
deps.DataGrid,
|
|
537
|
+
{
|
|
538
|
+
title: deps.labels.title,
|
|
539
|
+
description: deps.labels.description,
|
|
540
|
+
controller,
|
|
541
|
+
isLoading: query.isPending,
|
|
542
|
+
searchPlaceholder: deps.labels.searchPlaceholder,
|
|
543
|
+
emptyTitle: deps.labels.emptyTitle,
|
|
544
|
+
emptyDescription: deps.labels.emptyDescription,
|
|
545
|
+
onRowClick: openEditor,
|
|
546
|
+
toolbarExtra: /* @__PURE__ */ jsx2(deps.AddButton, { label: deps.labels.addLabel, onAdd: () => openEditor(null) })
|
|
547
|
+
}
|
|
548
|
+
),
|
|
549
|
+
/* @__PURE__ */ jsx2(
|
|
550
|
+
deps.EditorDialog,
|
|
551
|
+
{
|
|
552
|
+
open: isEditorOpen,
|
|
553
|
+
editing,
|
|
554
|
+
onClose: () => setEditorOpen(false)
|
|
555
|
+
}
|
|
556
|
+
),
|
|
557
|
+
/* @__PURE__ */ jsx2(
|
|
558
|
+
deps.DeleteDialog,
|
|
559
|
+
{
|
|
560
|
+
entity: pendingDelete,
|
|
561
|
+
title: deps.labels.deleteTitle,
|
|
562
|
+
description: deps.labels.deleteDescription(pendingDelete),
|
|
563
|
+
isDeleting: remove.isPending,
|
|
564
|
+
onClose: () => setPendingDelete(null),
|
|
565
|
+
onConfirm: async () => {
|
|
566
|
+
if (!pendingDelete) return;
|
|
567
|
+
await remove.mutateAsync(pendingDelete.id);
|
|
568
|
+
setPendingDelete(null);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
)
|
|
572
|
+
] });
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/admin/BuilderViewDialog.tsx
|
|
577
|
+
import { useEffect as useEffect2 } from "react";
|
|
578
|
+
import { FormProvider as FormProvider2, useForm as useForm2 } from "react-hook-form";
|
|
579
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
580
|
+
function createBuilderViewDialogComponent(deps) {
|
|
581
|
+
return function BuilderViewDialog({
|
|
582
|
+
open,
|
|
583
|
+
editing,
|
|
584
|
+
forms,
|
|
585
|
+
lists,
|
|
586
|
+
onClose,
|
|
587
|
+
onSave,
|
|
588
|
+
isSaving
|
|
589
|
+
}) {
|
|
590
|
+
const form = useForm2({
|
|
591
|
+
resolver: deps.resolver,
|
|
592
|
+
defaultValues: deps.emptyValues
|
|
593
|
+
});
|
|
594
|
+
useEffect2(() => {
|
|
595
|
+
if (!open) return;
|
|
596
|
+
form.reset(
|
|
597
|
+
builderViewEditorValuesFromEntity(editing, deps.emptyValues, deps.defaultPermission)
|
|
598
|
+
);
|
|
599
|
+
}, [editing, form, open]);
|
|
600
|
+
const onSubmit = form.handleSubmit(async (values) => {
|
|
601
|
+
try {
|
|
602
|
+
await onSave({ id: editing?.id, input: deps.buildInput(values) });
|
|
603
|
+
onClose();
|
|
604
|
+
deps.notifications.success(editing ? deps.labels.saved : deps.labels.created);
|
|
605
|
+
} catch (error) {
|
|
606
|
+
deps.notifications.error(error);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
return /* @__PURE__ */ jsx3(deps.Shell, { open, editing, onClose, children: /* @__PURE__ */ jsx3(FormProvider2, { ...form, children: /* @__PURE__ */ jsx3("form", { onSubmit, noValidate: true, children: deps.Body({
|
|
610
|
+
form,
|
|
611
|
+
editing,
|
|
612
|
+
forms,
|
|
613
|
+
lists,
|
|
614
|
+
permissionOptions: deps.permissionOptions,
|
|
615
|
+
noneValue: deps.noneValue,
|
|
616
|
+
isSaving,
|
|
617
|
+
onClose
|
|
618
|
+
}) }) }) });
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// src/api/createBuilderApiClient.ts
|
|
623
|
+
function queryParams(query) {
|
|
624
|
+
return { ...query };
|
|
625
|
+
}
|
|
626
|
+
function fieldOptionsQueryParams(query) {
|
|
627
|
+
const flatQuery = { search: query.search };
|
|
628
|
+
for (const [key, value] of Object.entries(query.depends ?? {})) {
|
|
629
|
+
flatQuery[`depends.${key}`] = value;
|
|
630
|
+
}
|
|
631
|
+
return flatQuery;
|
|
632
|
+
}
|
|
633
|
+
function createBuilderApiClient(transport) {
|
|
634
|
+
return {
|
|
635
|
+
listBuilderForms: (query) => transport.get("/builder/forms", {
|
|
636
|
+
query: queryParams(query)
|
|
637
|
+
}),
|
|
638
|
+
listBuilderDbTables: () => transport.get("/builder/datasources/tables"),
|
|
639
|
+
listBuilderFormOptions: () => transport.get("/builder/forms/options"),
|
|
640
|
+
getBuilderForm: (id) => transport.get(`/builder/forms/${encodeURIComponent(id)}`),
|
|
641
|
+
createBuilderForm: (input) => transport.post("/builder/forms", input),
|
|
642
|
+
updateBuilderForm: (id, input) => transport.patch(`/builder/forms/${encodeURIComponent(id)}`, input),
|
|
643
|
+
replicateBuilderForm: (id, input) => transport.post(`/builder/forms/${encodeURIComponent(id)}/replicate`, input),
|
|
644
|
+
deleteBuilderForm: (id) => transport.delete(`/builder/forms/${encodeURIComponent(id)}`),
|
|
645
|
+
listBuilderLists: (query) => transport.get("/builder/lists", {
|
|
646
|
+
query: queryParams(query)
|
|
647
|
+
}),
|
|
648
|
+
listBuilderListOptions: () => transport.get("/builder/lists/options"),
|
|
649
|
+
getBuilderList: (id) => transport.get(`/builder/lists/${encodeURIComponent(id)}`),
|
|
650
|
+
createBuilderList: (input) => transport.post("/builder/lists", input),
|
|
651
|
+
updateBuilderList: (id, input) => transport.patch(`/builder/lists/${encodeURIComponent(id)}`, input),
|
|
652
|
+
replicateBuilderList: (id, input) => transport.post(`/builder/lists/${encodeURIComponent(id)}/replicate`, input),
|
|
653
|
+
deleteBuilderList: (id) => transport.delete(`/builder/lists/${encodeURIComponent(id)}`),
|
|
654
|
+
listBuilderViews: (query) => transport.get("/builder/views", {
|
|
655
|
+
query: queryParams(query)
|
|
656
|
+
}),
|
|
657
|
+
getBuilderView: (id) => transport.get(`/builder/views/${encodeURIComponent(id)}`),
|
|
658
|
+
createBuilderView: (input) => transport.post("/builder/views", input),
|
|
659
|
+
updateBuilderView: (id, input) => transport.patch(`/builder/views/${encodeURIComponent(id)}`, input),
|
|
660
|
+
replicateBuilderView: (id, input) => transport.post(`/builder/views/${encodeURIComponent(id)}/replicate`, input),
|
|
661
|
+
deleteBuilderView: (id) => transport.delete(`/builder/views/${encodeURIComponent(id)}`),
|
|
662
|
+
getRuntimeBuilderForm: (id) => transport.get(`/builder/runtime/forms/${encodeURIComponent(id)}`),
|
|
663
|
+
createRuntimeBuilderFormEntry: (formId, input) => transport.post(
|
|
664
|
+
`/builder/runtime/forms/${encodeURIComponent(formId)}/entries`,
|
|
665
|
+
input
|
|
666
|
+
),
|
|
667
|
+
listRuntimeBuilderFormFieldOptions: (formId, fieldKey, query) => transport.get(
|
|
668
|
+
`/builder/runtime/forms/${encodeURIComponent(formId)}/fields/${encodeURIComponent(fieldKey)}/options`,
|
|
669
|
+
{ query: fieldOptionsQueryParams(query) }
|
|
670
|
+
),
|
|
671
|
+
runRuntimeBuilderFormFieldTrigger: (formId, fieldKey, event, input) => transport.post(
|
|
672
|
+
`/builder/runtime/forms/${encodeURIComponent(formId)}/fields/${encodeURIComponent(fieldKey)}/triggers/${encodeURIComponent(event)}`,
|
|
673
|
+
input
|
|
674
|
+
),
|
|
675
|
+
getRuntimeBuilderList: (id) => transport.get(`/builder/runtime/lists/${encodeURIComponent(id)}`),
|
|
676
|
+
listRuntimeBuilderListEntries: (listId, query) => transport.get(
|
|
677
|
+
`/builder/runtime/lists/${encodeURIComponent(listId)}/entries`,
|
|
678
|
+
{ query: queryParams(query) }
|
|
679
|
+
),
|
|
680
|
+
getRuntimeBuilderView: (id) => transport.get(`/builder/runtime/views/${encodeURIComponent(id)}`),
|
|
681
|
+
runRuntimeBuilderViewFieldTrigger: (viewId, fieldKey, event, input) => transport.post(
|
|
682
|
+
`/builder/runtime/views/${encodeURIComponent(viewId)}/fields/${encodeURIComponent(fieldKey)}/triggers/${encodeURIComponent(event)}`,
|
|
683
|
+
input
|
|
684
|
+
),
|
|
685
|
+
listBuilderViewEntries: (viewId, query) => transport.get(
|
|
686
|
+
`/builder/runtime/views/${encodeURIComponent(viewId)}/entries`,
|
|
687
|
+
{ query: queryParams(query) }
|
|
688
|
+
),
|
|
689
|
+
createBuilderViewEntry: (viewId, input) => transport.post(
|
|
690
|
+
`/builder/runtime/views/${encodeURIComponent(viewId)}/entries`,
|
|
691
|
+
input
|
|
692
|
+
),
|
|
693
|
+
createCompositeBuilderViewEntry: (viewId, input) => transport.post(
|
|
694
|
+
`/builder/runtime/views/${encodeURIComponent(viewId)}/composite-entries`,
|
|
695
|
+
input
|
|
696
|
+
),
|
|
697
|
+
updateCompositeBuilderViewEntry: (viewId, id, input) => transport.patch(
|
|
698
|
+
`/builder/runtime/views/${encodeURIComponent(viewId)}/composite-entries/${encodeURIComponent(id)}`,
|
|
699
|
+
input
|
|
700
|
+
),
|
|
701
|
+
updateBuilderViewEntry: (viewId, id, input) => transport.patch(
|
|
702
|
+
`/builder/runtime/views/${encodeURIComponent(viewId)}/entries/${encodeURIComponent(id)}`,
|
|
703
|
+
input
|
|
704
|
+
),
|
|
705
|
+
deleteBuilderViewEntry: (viewId, id) => transport.delete(
|
|
706
|
+
`/builder/runtime/views/${encodeURIComponent(viewId)}/entries/${encodeURIComponent(id)}`
|
|
707
|
+
)
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/components/DynamicForm.tsx
|
|
712
|
+
import { useMemo as useMemo2 } from "react";
|
|
713
|
+
import { FormProvider as FormProvider3, useForm as useForm3 } from "react-hook-form";
|
|
714
|
+
|
|
715
|
+
// src/runtime/runtimeUtils.ts
|
|
716
|
+
function emptyFieldValue(field) {
|
|
717
|
+
return field.type === "checkbox" ? false : "";
|
|
718
|
+
}
|
|
719
|
+
function createBuilderFormDefaultValues(schema) {
|
|
720
|
+
const values = {};
|
|
721
|
+
for (const field of schema?.fields ?? []) {
|
|
722
|
+
values[field.key] = emptyFieldValue(field);
|
|
723
|
+
}
|
|
724
|
+
return { values };
|
|
725
|
+
}
|
|
726
|
+
function createBuilderEntryDefaultValues(view, editing) {
|
|
727
|
+
const values = {};
|
|
728
|
+
for (const field of view.form?.schema.fields ?? []) {
|
|
729
|
+
const existing = editing?.values[field.key];
|
|
730
|
+
values[field.key] = existing === void 0 ? emptyFieldValue(field) : existing;
|
|
731
|
+
}
|
|
732
|
+
return { values, version: editing?.version ?? 0 };
|
|
733
|
+
}
|
|
734
|
+
function formatBuilderRuntimeValue(value, locale = "mn-MN") {
|
|
735
|
+
if (value === null || value === void 0 || value === "") return "\u2014";
|
|
736
|
+
if (typeof value === "boolean") return value ? "\u0422\u0438\u0439\u043C" : "\u04AE\u0433\u04AF\u0439";
|
|
737
|
+
if (typeof value === "number") return new Intl.NumberFormat(locale).format(value);
|
|
738
|
+
return String(value);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// src/components/DynamicForm.tsx
|
|
742
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
743
|
+
function createDynamicFormComponent(deps) {
|
|
744
|
+
return function DynamicForm({ formId }) {
|
|
745
|
+
const query = deps.hooks.useRuntimeBuilderForm(formId);
|
|
746
|
+
const save = deps.hooks.useSaveRuntimeBuilderFormEntry(formId);
|
|
747
|
+
const formValues = useMemo2(
|
|
748
|
+
() => query.data ? createBuilderFormDefaultValues(query.data.schema) : void 0,
|
|
749
|
+
[query.data]
|
|
750
|
+
);
|
|
751
|
+
const form = useForm3({
|
|
752
|
+
defaultValues: createBuilderFormDefaultValues(query.data?.schema),
|
|
753
|
+
values: formValues
|
|
754
|
+
});
|
|
755
|
+
const onSubmit = form.handleSubmit(async (values) => {
|
|
756
|
+
try {
|
|
757
|
+
await save.mutateAsync(values);
|
|
758
|
+
form.reset(createBuilderFormDefaultValues(query.data?.schema));
|
|
759
|
+
deps.notifications.success("Form \u0445\u0430\u0434\u0433\u0430\u043B\u0430\u0433\u0434\u043B\u0430\u0430");
|
|
760
|
+
} catch (error) {
|
|
761
|
+
deps.notifications.error(deps.notifications.errorMessage(error, "\u0425\u0430\u0434\u0433\u0430\u043B\u0430\u0445\u0430\u0434 \u0430\u043B\u0434\u0430\u0430 \u0433\u0430\u0440\u043B\u0430\u0430"));
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
if (query.isError) {
|
|
765
|
+
return /* @__PURE__ */ jsx4(
|
|
766
|
+
deps.ErrorState,
|
|
767
|
+
{
|
|
768
|
+
title: "Form \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
769
|
+
description: `\xAB${formId}\xBB id-\u0442\u0430\u0439 form \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439.`
|
|
770
|
+
}
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
if (!query.data) return null;
|
|
774
|
+
return /* @__PURE__ */ jsx4(deps.FormShell, { title: query.data.title, children: /* @__PURE__ */ jsx4(FormProvider3, { ...form, children: /* @__PURE__ */ jsxs2("form", { onSubmit, noValidate: true, className: "space-y-6", children: [
|
|
775
|
+
/* @__PURE__ */ jsx4(deps.FormFields, { formId, schema: query.data.schema, namePrefix: "values" }),
|
|
776
|
+
/* @__PURE__ */ jsx4(deps.SubmitButton, { isSaving: save.isPending })
|
|
777
|
+
] }) }) });
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// src/components/DynamicList.tsx
|
|
782
|
+
import { useMemo as useMemo3 } from "react";
|
|
783
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
784
|
+
function createDynamicListComponent(deps) {
|
|
785
|
+
return function DynamicList({ listId }) {
|
|
786
|
+
const query = deps.hooks.useRuntimeBuilderList(listId);
|
|
787
|
+
const state = deps.useDataTableState({ pageSize: 20 });
|
|
788
|
+
const entriesQuery = deps.hooks.useRuntimeBuilderListEntries(listId, state.query);
|
|
789
|
+
const columns = useMemo3(() => query.data ? deps.buildColumns(query.data) : [], [query.data]);
|
|
790
|
+
const entries = entriesQuery.data?.items ?? [];
|
|
791
|
+
const controller = deps.useDataTable({
|
|
792
|
+
columns,
|
|
793
|
+
data: entries,
|
|
794
|
+
rowCount: entriesQuery.data?.total ?? 0,
|
|
795
|
+
state,
|
|
796
|
+
getRowId: (row) => row.id
|
|
797
|
+
});
|
|
798
|
+
if (query.isError) {
|
|
799
|
+
return /* @__PURE__ */ jsx5(
|
|
800
|
+
deps.ErrorState,
|
|
801
|
+
{
|
|
802
|
+
title: "List \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
803
|
+
description: `\xAB${listId}\xBB id-\u0442\u0430\u0439 list \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439.`
|
|
804
|
+
}
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
return /* @__PURE__ */ jsx5(
|
|
808
|
+
deps.DataGrid,
|
|
809
|
+
{
|
|
810
|
+
title: query.data?.title ?? "Dynamic List",
|
|
811
|
+
description: query.data?.description ?? `/winu/list?id=${listId}`,
|
|
812
|
+
controller,
|
|
813
|
+
isLoading: query.isPending || entriesQuery.isPending,
|
|
814
|
+
searchPlaceholder: "\u041C\u04E9\u0440 \u0445\u0430\u0439\u0445...",
|
|
815
|
+
emptyTitle: "\u041C\u04E9\u0440 \u0430\u043B\u0433\u0430",
|
|
816
|
+
emptyDescription: "\u042D\u043D\u044D list-\u0438\u0439\u043D datasource \u0434\u044D\u044D\u0440 \u043C\u04E9\u0440 \u0430\u043B\u0433\u0430."
|
|
817
|
+
}
|
|
818
|
+
);
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// src/components/DynamicView.tsx
|
|
823
|
+
import { useMemo as useMemo4, useState as useState2 } from "react";
|
|
824
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
825
|
+
function createDynamicViewComponent(deps) {
|
|
826
|
+
return function DynamicView({ viewId }) {
|
|
827
|
+
const [editing, setEditing] = useState2(null);
|
|
828
|
+
const [isDialogOpen, setDialogOpen] = useState2(false);
|
|
829
|
+
const [pendingDelete, setPendingDelete] = useState2(null);
|
|
830
|
+
const viewQuery = deps.hooks.useRuntimeBuilderView(viewId);
|
|
831
|
+
const state = deps.useDataTableState({ pageSize: 20 });
|
|
832
|
+
const entriesQuery = deps.hooks.useBuilderViewEntries(viewId, state.query);
|
|
833
|
+
const save = deps.hooks.useSaveBuilderViewEntry(viewId);
|
|
834
|
+
const remove = deps.hooks.useDeleteBuilderViewEntry(viewId);
|
|
835
|
+
const view = viewQuery.data;
|
|
836
|
+
const columns = useMemo4(
|
|
837
|
+
() => view ? deps.buildColumns(view, {
|
|
838
|
+
onEdit: (entry) => {
|
|
839
|
+
setEditing(entry);
|
|
840
|
+
setDialogOpen(true);
|
|
841
|
+
},
|
|
842
|
+
onDelete: setPendingDelete
|
|
843
|
+
}) : [],
|
|
844
|
+
[view]
|
|
845
|
+
);
|
|
846
|
+
const controller = deps.useDataTable({
|
|
847
|
+
columns,
|
|
848
|
+
data: entriesQuery.data?.items ?? [],
|
|
849
|
+
rowCount: entriesQuery.data?.total ?? 0,
|
|
850
|
+
state,
|
|
851
|
+
getRowId: (row) => row.id
|
|
852
|
+
});
|
|
853
|
+
if (viewQuery.isError) {
|
|
854
|
+
return /* @__PURE__ */ jsx6(
|
|
855
|
+
deps.ErrorState,
|
|
856
|
+
{
|
|
857
|
+
title: "View \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
858
|
+
description: `\xAB${viewId}\xBB id-\u0442\u0430\u0439 view \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439.`
|
|
859
|
+
}
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-6", children: [
|
|
863
|
+
/* @__PURE__ */ jsx6(
|
|
864
|
+
deps.DataGrid,
|
|
865
|
+
{
|
|
866
|
+
title: view?.title ?? "Dynamic View",
|
|
867
|
+
description: view?.description ?? `/winu/view?id=${viewId}`,
|
|
868
|
+
controller,
|
|
869
|
+
isLoading: viewQuery.isPending || entriesQuery.isPending,
|
|
870
|
+
searchPlaceholder: "\u041C\u04E9\u0440 \u0445\u0430\u0439\u0445...",
|
|
871
|
+
emptyTitle: "\u041C\u04E9\u0440 \u0430\u043B\u0433\u0430",
|
|
872
|
+
emptyDescription: "\u042D\u043D\u044D view \u0434\u044D\u044D\u0440 \u044D\u0445\u043D\u0438\u0439 \u043C\u04E9\u0440\u04E9\u04E9 \u043D\u044D\u043C\u044D\u044D\u0440\u044D\u0439.",
|
|
873
|
+
onRowClick: (entry) => {
|
|
874
|
+
setEditing(entry);
|
|
875
|
+
setDialogOpen(true);
|
|
876
|
+
},
|
|
877
|
+
toolbarExtra: /* @__PURE__ */ jsx6(
|
|
878
|
+
deps.AddButton,
|
|
879
|
+
{
|
|
880
|
+
disabled: !view?.form,
|
|
881
|
+
onAdd: () => {
|
|
882
|
+
setEditing(null);
|
|
883
|
+
setDialogOpen(true);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
)
|
|
887
|
+
}
|
|
888
|
+
),
|
|
889
|
+
view ? /* @__PURE__ */ jsx6(
|
|
890
|
+
deps.EntryDialog,
|
|
891
|
+
{
|
|
892
|
+
open: isDialogOpen,
|
|
893
|
+
view,
|
|
894
|
+
editing,
|
|
895
|
+
onClose: () => setDialogOpen(false),
|
|
896
|
+
onSave: save.mutateAsync,
|
|
897
|
+
isSaving: save.isPending
|
|
898
|
+
}
|
|
899
|
+
) : null,
|
|
900
|
+
/* @__PURE__ */ jsx6(
|
|
901
|
+
deps.DeleteDialog,
|
|
902
|
+
{
|
|
903
|
+
entry: pendingDelete,
|
|
904
|
+
isDeleting: remove.isPending,
|
|
905
|
+
onClose: () => setPendingDelete(null),
|
|
906
|
+
onConfirm: async () => {
|
|
907
|
+
if (!pendingDelete) return;
|
|
908
|
+
await remove.mutateAsync(pendingDelete.id);
|
|
909
|
+
setPendingDelete(null);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
)
|
|
913
|
+
] });
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// src/components/RuntimeEntryDialog.tsx
|
|
918
|
+
import { useEffect as useEffect3, useMemo as useMemo5, useState as useState3 } from "react";
|
|
919
|
+
import { FormProvider as FormProvider4, useForm as useForm4 } from "react-hook-form";
|
|
920
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
921
|
+
function isDbTableSource(source) {
|
|
922
|
+
return source?.type === "dbTable" && "tableName" in source;
|
|
923
|
+
}
|
|
924
|
+
function runtimeViewTableName(view) {
|
|
925
|
+
const listSource = view.list?.source;
|
|
926
|
+
if (isDbTableSource(listSource)) return listSource.tableName;
|
|
927
|
+
const formSource = view.form?.source;
|
|
928
|
+
return isDbTableSource(formSource) ? formSource.tableName : void 0;
|
|
929
|
+
}
|
|
930
|
+
function cleanRowValues(values) {
|
|
931
|
+
return Object.fromEntries(
|
|
932
|
+
Object.entries(values).filter(([key]) => key === "_delete" || !key.startsWith("_"))
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
function childRowPayload(row, includeIdentity) {
|
|
936
|
+
const values = cleanRowValues(row.values);
|
|
937
|
+
if (!includeIdentity || row.values._draftNew === true) return values;
|
|
938
|
+
return {
|
|
939
|
+
id: row.id,
|
|
940
|
+
version: row.version,
|
|
941
|
+
...values
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
function createRuntimeEntryDialogComponent(deps) {
|
|
945
|
+
return function RuntimeEntryDialog({
|
|
946
|
+
open,
|
|
947
|
+
view,
|
|
948
|
+
editing,
|
|
949
|
+
onClose,
|
|
950
|
+
onSave,
|
|
951
|
+
isSaving
|
|
952
|
+
}) {
|
|
953
|
+
const [draftSubforms, setDraftSubforms] = useState3({});
|
|
954
|
+
const compositeCreate = deps.useCreateCompositeEntry?.(view.id);
|
|
955
|
+
const compositeUpdate = deps.useUpdateCompositeEntry?.(view.id);
|
|
956
|
+
const form = useForm4({
|
|
957
|
+
defaultValues: createBuilderEntryDefaultValues(view, editing),
|
|
958
|
+
values: open ? createBuilderEntryDefaultValues(view, editing) : void 0
|
|
959
|
+
});
|
|
960
|
+
const mainTableName = runtimeViewTableName(view);
|
|
961
|
+
const hasDraftRows = useMemo5(
|
|
962
|
+
() => Object.values(draftSubforms).some((draft) => draft.rows.length > 0),
|
|
963
|
+
[draftSubforms]
|
|
964
|
+
);
|
|
965
|
+
useEffect3(() => {
|
|
966
|
+
if (open) setDraftSubforms({});
|
|
967
|
+
}, [open]);
|
|
968
|
+
const onSubmit = form.handleSubmit(async (values) => {
|
|
969
|
+
try {
|
|
970
|
+
if (!editing && hasDraftRows) {
|
|
971
|
+
if (!mainTableName) throw new Error("Main form datasource table \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439");
|
|
972
|
+
if (!compositeCreate) throw new Error("Composite create handler \u0442\u043E\u0445\u0438\u0440\u0443\u0443\u043B\u0430\u0433\u0434\u0430\u0430\u0433\u04AF\u0439 \u0431\u0430\u0439\u043D\u0430");
|
|
973
|
+
await compositeCreate.mutateAsync({
|
|
974
|
+
data: {
|
|
975
|
+
[mainTableName]: values.values,
|
|
976
|
+
...Object.fromEntries(
|
|
977
|
+
Object.values(draftSubforms).map((draft) => [
|
|
978
|
+
draft.dataKey,
|
|
979
|
+
draft.rows.filter((row) => row.values._delete !== true).map((row) => childRowPayload(row, false))
|
|
980
|
+
])
|
|
981
|
+
)
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
} else if (editing && hasDraftRows) {
|
|
985
|
+
if (!mainTableName) throw new Error("Main form datasource table \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439");
|
|
986
|
+
if (!compositeUpdate) throw new Error("Composite update handler \u0442\u043E\u0445\u0438\u0440\u0443\u0443\u043B\u0430\u0433\u0434\u0430\u0430\u0433\u04AF\u0439 \u0431\u0430\u0439\u043D\u0430");
|
|
987
|
+
await compositeUpdate.mutateAsync({
|
|
988
|
+
id: editing.id,
|
|
989
|
+
input: {
|
|
990
|
+
data: {
|
|
991
|
+
[mainTableName]: {
|
|
992
|
+
id: editing.id,
|
|
993
|
+
version: values.version,
|
|
994
|
+
...values.values
|
|
995
|
+
},
|
|
996
|
+
...Object.fromEntries(
|
|
997
|
+
Object.values(draftSubforms).map((draft) => [
|
|
998
|
+
draft.dataKey,
|
|
999
|
+
draft.rows.map((row) => childRowPayload(row, true))
|
|
1000
|
+
])
|
|
1001
|
+
)
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
} else {
|
|
1006
|
+
await onSave({ id: editing?.id, input: values });
|
|
1007
|
+
}
|
|
1008
|
+
onClose();
|
|
1009
|
+
deps.notifications.success(editing ? "\u041C\u04E9\u0440 \u0445\u0430\u0434\u0433\u0430\u043B\u0430\u0433\u0434\u043B\u0430\u0430" : "\u041C\u04E9\u0440 \u043D\u044D\u043C\u044D\u0433\u0434\u043B\u044D\u044D");
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
deps.notifications.error(deps.notifications.errorMessage(error, "\u0425\u0430\u0434\u0433\u0430\u043B\u0430\u0445\u0430\u0434 \u0430\u043B\u0434\u0430\u0430 \u0433\u0430\u0440\u043B\u0430\u0430"));
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
const saving = isSaving || Boolean(compositeCreate?.isPending || compositeUpdate?.isPending);
|
|
1015
|
+
const extraItems = deps.SubformField && view.form?.schema.subforms?.length ? view.form.schema.subforms.map((subform) => ({
|
|
1016
|
+
key: subform.key,
|
|
1017
|
+
render: () => deps.SubformField ? /* @__PURE__ */ jsx7(
|
|
1018
|
+
deps.SubformField,
|
|
1019
|
+
{
|
|
1020
|
+
subform,
|
|
1021
|
+
parentEntry: editing,
|
|
1022
|
+
draftRows: draftSubforms[subform.key]?.rows ?? [],
|
|
1023
|
+
onDraftRowsChange: ({ subformKey, dataKey, rows }) => {
|
|
1024
|
+
setDraftSubforms((current) => ({
|
|
1025
|
+
...current,
|
|
1026
|
+
[subformKey]: { dataKey, rows }
|
|
1027
|
+
}));
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
) : null
|
|
1031
|
+
})) : void 0;
|
|
1032
|
+
return /* @__PURE__ */ jsx7(
|
|
1033
|
+
deps.DialogShell,
|
|
1034
|
+
{
|
|
1035
|
+
open,
|
|
1036
|
+
title: editing ? "\u041C\u04E9\u0440 \u0437\u0430\u0441\u0430\u0445" : "\u041C\u04E9\u0440 \u043D\u044D\u043C\u044D\u0445",
|
|
1037
|
+
description: view.title,
|
|
1038
|
+
onClose,
|
|
1039
|
+
children: /* @__PURE__ */ jsx7(FormProvider4, { ...form, children: /* @__PURE__ */ jsxs4("form", { onSubmit, noValidate: true, className: deps.formClassName, children: [
|
|
1040
|
+
view.form ? /* @__PURE__ */ jsx7(
|
|
1041
|
+
deps.FormFields,
|
|
1042
|
+
{
|
|
1043
|
+
formId: view.form.id,
|
|
1044
|
+
viewId: view.id,
|
|
1045
|
+
entry: editing,
|
|
1046
|
+
schema: view.form.schema,
|
|
1047
|
+
namePrefix: "values",
|
|
1048
|
+
extraItems
|
|
1049
|
+
}
|
|
1050
|
+
) : null,
|
|
1051
|
+
/* @__PURE__ */ jsx7(deps.Actions, { isSaving: saving, onClose })
|
|
1052
|
+
] }) })
|
|
1053
|
+
}
|
|
1054
|
+
);
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// src/components/RuntimeSubformField.tsx
|
|
1059
|
+
import { useEffect as useEffect4, useMemo as useMemo6, useRef, useState as useState4 } from "react";
|
|
1060
|
+
import { FormProvider as FormProvider5, useForm as useForm5 } from "react-hook-form";
|
|
1061
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1062
|
+
|
|
1063
|
+
// src/hooks/createBuilderHooks.ts
|
|
1064
|
+
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
1065
|
+
function createBuilderKeys() {
|
|
1066
|
+
const builderKeys = {
|
|
1067
|
+
forms: ["builder", "forms"],
|
|
1068
|
+
dbTables: () => ["builder", "datasources", "tables"],
|
|
1069
|
+
formList: (query) => [...builderKeys.forms, "list", query],
|
|
1070
|
+
form: (id) => [...builderKeys.forms, "detail", id],
|
|
1071
|
+
formOptions: () => [...builderKeys.forms, "options"],
|
|
1072
|
+
lists: ["builder", "lists"],
|
|
1073
|
+
listList: (query) => [...builderKeys.lists, "list", query],
|
|
1074
|
+
list: (id) => [...builderKeys.lists, "detail", id],
|
|
1075
|
+
listOptions: () => [...builderKeys.lists, "options"],
|
|
1076
|
+
views: ["builder", "views"],
|
|
1077
|
+
viewList: (query) => [...builderKeys.views, "list", query],
|
|
1078
|
+
runtimeForm: (id) => ["builder", "runtime", "form", id],
|
|
1079
|
+
runtimeFieldOptions: (formId, fieldKey, query) => [...builderKeys.runtimeForm(formId), "fields", fieldKey, "options", query],
|
|
1080
|
+
runtimeFormEntries: (id) => [...builderKeys.runtimeForm(id), "entries"],
|
|
1081
|
+
runtimeList: (id) => ["builder", "runtime", "list", id],
|
|
1082
|
+
runtimeListEntries: (id, query) => [...builderKeys.runtimeList(id), "entries", query],
|
|
1083
|
+
runtimeView: (id) => ["builder", "runtime", "view", id],
|
|
1084
|
+
entries: (id, query) => [...builderKeys.runtimeView(id), "entries", query]
|
|
1085
|
+
};
|
|
1086
|
+
return builderKeys;
|
|
1087
|
+
}
|
|
1088
|
+
function createBuilderHooks(client) {
|
|
1089
|
+
const builderKeys = createBuilderKeys();
|
|
1090
|
+
function invalidateRuntimeViewEntries(queryClient, viewId) {
|
|
1091
|
+
return Promise.all([
|
|
1092
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.runtimeView(viewId) }),
|
|
1093
|
+
queryClient.invalidateQueries({ queryKey: [...builderKeys.runtimeView(viewId), "entries"] })
|
|
1094
|
+
]);
|
|
1095
|
+
}
|
|
1096
|
+
function useBuilderDbTables() {
|
|
1097
|
+
return useQuery({ queryKey: builderKeys.dbTables(), queryFn: client.listBuilderDbTables });
|
|
1098
|
+
}
|
|
1099
|
+
function useBuilderForms(query) {
|
|
1100
|
+
return useQuery({
|
|
1101
|
+
queryKey: builderKeys.formList(query),
|
|
1102
|
+
queryFn: () => client.listBuilderForms(query),
|
|
1103
|
+
placeholderData: keepPreviousData
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
function useBuilderFormOptions() {
|
|
1107
|
+
return useQuery({
|
|
1108
|
+
queryKey: builderKeys.formOptions(),
|
|
1109
|
+
queryFn: client.listBuilderFormOptions
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
function useBuilderForm(id) {
|
|
1113
|
+
return useQuery({
|
|
1114
|
+
queryKey: builderKeys.form(id ?? ""),
|
|
1115
|
+
queryFn: () => client.getBuilderForm(id ?? ""),
|
|
1116
|
+
enabled: Boolean(id)
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
function useSaveBuilderForm() {
|
|
1120
|
+
const queryClient = useQueryClient();
|
|
1121
|
+
return useMutation({
|
|
1122
|
+
mutationFn: ({ id, input }) => id ? client.updateBuilderForm(id, input) : client.createBuilderForm(input),
|
|
1123
|
+
onSuccess: (form) => {
|
|
1124
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.forms });
|
|
1125
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.form(form.id) });
|
|
1126
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.runtimeForm(form.id) });
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
function useReplicateBuilderForm() {
|
|
1131
|
+
const queryClient = useQueryClient();
|
|
1132
|
+
return useMutation({
|
|
1133
|
+
mutationFn: ({ id, input }) => client.replicateBuilderForm(id, input),
|
|
1134
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.forms })
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
function useDeleteBuilderForm() {
|
|
1138
|
+
const queryClient = useQueryClient();
|
|
1139
|
+
return useMutation({
|
|
1140
|
+
mutationFn: client.deleteBuilderForm,
|
|
1141
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.forms })
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
function useBuilderLists(query) {
|
|
1145
|
+
return useQuery({
|
|
1146
|
+
queryKey: builderKeys.listList(query),
|
|
1147
|
+
queryFn: () => client.listBuilderLists(query),
|
|
1148
|
+
placeholderData: keepPreviousData
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
function useBuilderListOptions() {
|
|
1152
|
+
return useQuery({
|
|
1153
|
+
queryKey: builderKeys.listOptions(),
|
|
1154
|
+
queryFn: client.listBuilderListOptions
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
function useBuilderList(id) {
|
|
1158
|
+
return useQuery({
|
|
1159
|
+
queryKey: builderKeys.list(id ?? ""),
|
|
1160
|
+
queryFn: () => client.getBuilderList(id ?? ""),
|
|
1161
|
+
enabled: Boolean(id)
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
function useSaveBuilderList() {
|
|
1165
|
+
const queryClient = useQueryClient();
|
|
1166
|
+
return useMutation({
|
|
1167
|
+
mutationFn: ({ id, input }) => id ? client.updateBuilderList(id, input) : client.createBuilderList(input),
|
|
1168
|
+
onSuccess: (list) => {
|
|
1169
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.lists });
|
|
1170
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.list(list.id) });
|
|
1171
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.runtimeList(list.id) });
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
function useReplicateBuilderList() {
|
|
1176
|
+
const queryClient = useQueryClient();
|
|
1177
|
+
return useMutation({
|
|
1178
|
+
mutationFn: ({ id, input }) => client.replicateBuilderList(id, input),
|
|
1179
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.lists })
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
function useDeleteBuilderList() {
|
|
1183
|
+
const queryClient = useQueryClient();
|
|
1184
|
+
return useMutation({
|
|
1185
|
+
mutationFn: client.deleteBuilderList,
|
|
1186
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.lists })
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
function useBuilderViews(query) {
|
|
1190
|
+
return useQuery({
|
|
1191
|
+
queryKey: builderKeys.viewList(query),
|
|
1192
|
+
queryFn: () => client.listBuilderViews(query),
|
|
1193
|
+
placeholderData: keepPreviousData
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
function useSaveBuilderView() {
|
|
1197
|
+
const queryClient = useQueryClient();
|
|
1198
|
+
return useMutation({
|
|
1199
|
+
mutationFn: ({ id, input }) => id ? client.updateBuilderView(id, input) : client.createBuilderView(input),
|
|
1200
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.views })
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
function useReplicateBuilderView() {
|
|
1204
|
+
const queryClient = useQueryClient();
|
|
1205
|
+
return useMutation({
|
|
1206
|
+
mutationFn: ({ id, input }) => client.replicateBuilderView(id, input),
|
|
1207
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.views })
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
function useDeleteBuilderView() {
|
|
1211
|
+
const queryClient = useQueryClient();
|
|
1212
|
+
return useMutation({
|
|
1213
|
+
mutationFn: client.deleteBuilderView,
|
|
1214
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.views })
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
function useRuntimeBuilderForm(id) {
|
|
1218
|
+
return useQuery({
|
|
1219
|
+
queryKey: builderKeys.runtimeForm(id),
|
|
1220
|
+
queryFn: () => client.getRuntimeBuilderForm(id)
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
function useRuntimeBuilderFormFieldOptions(formId, fieldKey, query, enabled = true) {
|
|
1224
|
+
return useQuery({
|
|
1225
|
+
queryKey: builderKeys.runtimeFieldOptions(formId ?? "", fieldKey, query),
|
|
1226
|
+
queryFn: () => client.listRuntimeBuilderFormFieldOptions(formId ?? "", fieldKey, query),
|
|
1227
|
+
enabled: Boolean(formId) && enabled
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
function useRunRuntimeBuilderFieldTrigger() {
|
|
1231
|
+
return useMutation({
|
|
1232
|
+
mutationFn: (args) => {
|
|
1233
|
+
if (args.viewId) {
|
|
1234
|
+
return client.runRuntimeBuilderViewFieldTrigger(
|
|
1235
|
+
args.viewId,
|
|
1236
|
+
args.fieldKey,
|
|
1237
|
+
args.event,
|
|
1238
|
+
args.input
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
if (args.formId) {
|
|
1242
|
+
return client.runRuntimeBuilderFormFieldTrigger(
|
|
1243
|
+
args.formId,
|
|
1244
|
+
args.fieldKey,
|
|
1245
|
+
args.event,
|
|
1246
|
+
args.input
|
|
1247
|
+
);
|
|
1248
|
+
}
|
|
1249
|
+
throw new Error("formId \u044D\u0441\u0432\u044D\u043B viewId \u0448\u0430\u0430\u0440\u0434\u043B\u0430\u0433\u0430\u0442\u0430\u0439");
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
function useRuntimeBuilderList(id) {
|
|
1254
|
+
return useQuery({
|
|
1255
|
+
queryKey: builderKeys.runtimeList(id),
|
|
1256
|
+
queryFn: () => client.getRuntimeBuilderList(id)
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
function useRuntimeBuilderListEntries(id, query) {
|
|
1260
|
+
return useQuery({
|
|
1261
|
+
queryKey: builderKeys.runtimeListEntries(id, query),
|
|
1262
|
+
queryFn: () => client.listRuntimeBuilderListEntries(id, query),
|
|
1263
|
+
placeholderData: keepPreviousData
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
function useSaveRuntimeBuilderFormEntry(formId) {
|
|
1267
|
+
const queryClient = useQueryClient();
|
|
1268
|
+
return useMutation({
|
|
1269
|
+
mutationFn: (input) => client.createRuntimeBuilderFormEntry(formId, input),
|
|
1270
|
+
onSuccess: () => {
|
|
1271
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.runtimeFormEntries(formId) });
|
|
1272
|
+
queryClient.invalidateQueries({ queryKey: builderKeys.runtimeForm(formId) });
|
|
1273
|
+
queryClient.invalidateQueries({ queryKey: ["builder", "runtime", "list"] });
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
function useRuntimeBuilderView(id, enabled = true) {
|
|
1278
|
+
return useQuery({
|
|
1279
|
+
queryKey: builderKeys.runtimeView(id),
|
|
1280
|
+
queryFn: () => client.getRuntimeBuilderView(id),
|
|
1281
|
+
enabled: Boolean(id) && enabled
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
function useBuilderViewEntries(id, query, enabled = true) {
|
|
1285
|
+
return useQuery({
|
|
1286
|
+
queryKey: builderKeys.entries(id, query),
|
|
1287
|
+
queryFn: () => client.listBuilderViewEntries(id, query),
|
|
1288
|
+
placeholderData: keepPreviousData,
|
|
1289
|
+
enabled: Boolean(id) && enabled
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
function useSaveBuilderViewEntry(viewId) {
|
|
1293
|
+
const queryClient = useQueryClient();
|
|
1294
|
+
return useMutation({
|
|
1295
|
+
mutationFn: ({ id, input }) => id ? client.updateBuilderViewEntry(viewId, id, input) : client.createBuilderViewEntry(
|
|
1296
|
+
viewId,
|
|
1297
|
+
input
|
|
1298
|
+
),
|
|
1299
|
+
onSuccess: () => invalidateRuntimeViewEntries(queryClient, viewId)
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
function useCreateCompositeBuilderViewEntry(viewId) {
|
|
1303
|
+
const queryClient = useQueryClient();
|
|
1304
|
+
return useMutation({
|
|
1305
|
+
mutationFn: (input) => client.createCompositeBuilderViewEntry(viewId, input),
|
|
1306
|
+
onSuccess: () => invalidateRuntimeViewEntries(queryClient, viewId)
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
function useUpdateCompositeBuilderViewEntry(viewId) {
|
|
1310
|
+
const queryClient = useQueryClient();
|
|
1311
|
+
return useMutation({
|
|
1312
|
+
mutationFn: ({
|
|
1313
|
+
id,
|
|
1314
|
+
input
|
|
1315
|
+
}) => client.updateCompositeBuilderViewEntry(viewId, id, input),
|
|
1316
|
+
onSuccess: () => invalidateRuntimeViewEntries(queryClient, viewId)
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
function useDeleteBuilderViewEntry(id) {
|
|
1320
|
+
const queryClient = useQueryClient();
|
|
1321
|
+
return useMutation({
|
|
1322
|
+
mutationFn: (entryId) => client.deleteBuilderViewEntry(id, entryId),
|
|
1323
|
+
onSuccess: () => invalidateRuntimeViewEntries(queryClient, id)
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
return {
|
|
1327
|
+
builderKeys,
|
|
1328
|
+
useBuilderDbTables,
|
|
1329
|
+
useBuilderForm,
|
|
1330
|
+
useBuilderFormOptions,
|
|
1331
|
+
useBuilderForms,
|
|
1332
|
+
useBuilderList,
|
|
1333
|
+
useBuilderListOptions,
|
|
1334
|
+
useBuilderLists,
|
|
1335
|
+
useBuilderViewEntries,
|
|
1336
|
+
useBuilderViews,
|
|
1337
|
+
useDeleteBuilderForm,
|
|
1338
|
+
useDeleteBuilderList,
|
|
1339
|
+
useDeleteBuilderView,
|
|
1340
|
+
useDeleteBuilderViewEntry,
|
|
1341
|
+
useCreateCompositeBuilderViewEntry,
|
|
1342
|
+
useReplicateBuilderForm,
|
|
1343
|
+
useReplicateBuilderList,
|
|
1344
|
+
useReplicateBuilderView,
|
|
1345
|
+
useRuntimeBuilderForm,
|
|
1346
|
+
useRuntimeBuilderFormFieldOptions,
|
|
1347
|
+
useRuntimeBuilderList,
|
|
1348
|
+
useRuntimeBuilderListEntries,
|
|
1349
|
+
useRuntimeBuilderView,
|
|
1350
|
+
useRunRuntimeBuilderFieldTrigger,
|
|
1351
|
+
useSaveBuilderForm,
|
|
1352
|
+
useSaveBuilderList,
|
|
1353
|
+
useSaveBuilderView,
|
|
1354
|
+
useSaveBuilderViewEntry,
|
|
1355
|
+
useSaveRuntimeBuilderFormEntry,
|
|
1356
|
+
useUpdateCompositeBuilderViewEntry
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// src/index.ts
|
|
1361
|
+
var builderUiPackage = {
|
|
1362
|
+
name: "@duke333/builder-ui",
|
|
1363
|
+
version: "0.1.0"
|
|
1364
|
+
};
|
|
1365
|
+
export {
|
|
1366
|
+
BUILDER_EDITOR_NONE_VALUE,
|
|
1367
|
+
builderEditorOptionsToText,
|
|
1368
|
+
builderEditorSearchFieldsToText,
|
|
1369
|
+
builderEditorTextToOptions,
|
|
1370
|
+
builderEditorTextToSearchFields,
|
|
1371
|
+
builderFormEditorFieldsFromTable,
|
|
1372
|
+
builderFormEditorInputFromValues,
|
|
1373
|
+
builderFormEditorValuesFromEntity,
|
|
1374
|
+
builderListEditorColumnsFromTable,
|
|
1375
|
+
builderListEditorInputFromValues,
|
|
1376
|
+
builderListEditorValuesFromEntity,
|
|
1377
|
+
builderUiPackage,
|
|
1378
|
+
builderViewEditorInputFromValues,
|
|
1379
|
+
builderViewEditorValuesFromEntity,
|
|
1380
|
+
createBuilderApiClient,
|
|
1381
|
+
createBuilderEntityDialogManagerComponent,
|
|
1382
|
+
createBuilderEntityManagerComponent,
|
|
1383
|
+
createBuilderEntryDefaultValues,
|
|
1384
|
+
createBuilderFormDefaultValues,
|
|
1385
|
+
createBuilderFormEditorPageComponent,
|
|
1386
|
+
createBuilderHooks,
|
|
1387
|
+
createBuilderKeys,
|
|
1388
|
+
createBuilderListEditorPageComponent,
|
|
1389
|
+
createBuilderViewDialogComponent,
|
|
1390
|
+
createDynamicFormComponent,
|
|
1391
|
+
createDynamicListComponent,
|
|
1392
|
+
createDynamicViewComponent,
|
|
1393
|
+
createRuntimeEntryDialogComponent,
|
|
1394
|
+
formatBuilderRuntimeValue,
|
|
1395
|
+
getBuilderEditorTriggerRoute
|
|
1396
|
+
};
|
|
1397
|
+
//# sourceMappingURL=index.js.map
|