@questpie/admin 3.2.7 → 3.4.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/README.md +4 -6
- package/dist/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/builder/admin-types.d.mts +3 -3
- package/dist/client/builder/types/action-types.d.mts +1 -1
- package/dist/client/builder/types/collection-types.d.mts +59 -2
- package/dist/client/components/blocks/block-editor-provider.mjs +13 -0
- package/dist/client/components/fields/array-field.mjs +105 -122
- package/dist/client/components/fields/asset-preview-field.mjs +1 -1
- package/dist/client/components/fields/blocks-field/blocks-field.mjs +1 -1
- package/dist/client/components/fields/boolean-field.mjs +1 -1
- package/dist/client/components/fields/date-field.mjs +1 -1
- package/dist/client/components/fields/datetime-field.mjs +1 -1
- package/dist/client/components/fields/email-field.mjs +1 -1
- package/dist/client/components/fields/field-wrapper.mjs +44 -15
- package/dist/client/components/fields/number-field.mjs +1 -1
- package/dist/client/components/fields/object-array-field.mjs +179 -149
- package/dist/client/components/fields/object-field.mjs +96 -87
- package/dist/client/components/fields/relation-picker.mjs +1 -1
- package/dist/client/components/fields/relation-select.mjs +1 -1
- package/dist/client/components/fields/rich-text-editor/index.mjs +1 -1
- package/dist/client/components/fields/select-field.mjs +1 -1
- package/dist/client/components/fields/text-field.mjs +1 -1
- package/dist/client/components/fields/textarea-field.mjs +1 -1
- package/dist/client/components/fields/time-field.mjs +1 -1
- package/dist/client/components/fields/upload-field.mjs +1 -1
- package/dist/client/components/history-sidebar.mjs +10 -4
- package/dist/client/components/structured-diff.mjs +367 -0
- package/dist/client/components/ui/sidebar.mjs +1 -1
- package/dist/client/hooks/use-field-options.mjs +34 -15
- package/dist/client/hooks/use-transition-stage.mjs +2 -2
- package/dist/client/modules/admin.d.mts +3 -0
- package/dist/client/modules/admin.mjs +3 -0
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/preview-banner.d.mts +2 -2
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/utils/auto-expand-fields.mjs +1 -1
- package/dist/client/views/collection/auto-form-fields.mjs +23 -19
- package/dist/client/views/collection/cells/complex-cells.mjs +1 -1
- package/dist/client/views/collection/columns/build-columns.mjs +1 -1
- package/dist/client/views/collection/columns/column-defaults.mjs +17 -4
- package/dist/client/views/collection/field-renderer.mjs +19 -7
- package/dist/client/views/collection/form-view.mjs +10 -6
- package/dist/client/views/collection/list-view.mjs +830 -0
- package/dist/client/views/collection/outline.mjs +363 -0
- package/dist/client/views/collection/table-view.mjs +25 -16
- package/dist/client/views/globals/global-form-view.mjs +47 -27
- package/dist/client/views/layout/admin-layout.d.mts +15 -1
- package/dist/client/views/layout/admin-layout.mjs +95 -31
- package/dist/client/views/layout/admin-sidebar.mjs +2 -2
- package/dist/client.d.mts +6 -6
- package/dist/client.mjs +1 -1
- package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
- package/dist/factories.d.mts +19 -0
- package/dist/factories.mjs +11 -0
- package/dist/fields.d.mts +4 -0
- package/dist/fields.mjs +5 -0
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +1 -1
- package/dist/modules/admin.d.mts +10 -0
- package/dist/modules/admin.mjs +9 -0
- package/dist/modules/audit.d.mts +5 -0
- package/dist/modules/audit.mjs +5 -0
- package/dist/server/augmentation/form-layout.d.mts +57 -2
- package/dist/server/augmentation/index.d.mts +3 -1
- package/dist/server/augmentation/shell.d.mts +48 -0
- package/dist/server/augmentation.d.mts +2 -1
- package/dist/server/codegen/admin-client-template.mjs +11 -4
- package/dist/server/fields/blocks.d.mts +9 -2
- package/dist/server/fields/blocks.mjs +1 -1
- package/dist/server/fields/index.d.mts +2 -2
- package/dist/server/fields/index.mjs +2 -2
- package/dist/server/fields/rich-text.d.mts +9 -2
- package/dist/server/fields/rich-text.mjs +1 -1
- package/dist/server/i18n/messages/cs.mjs +8 -0
- package/dist/server/i18n/messages/de.mjs +8 -0
- package/dist/server/i18n/messages/en.mjs +8 -0
- package/dist/server/i18n/messages/es.mjs +8 -0
- package/dist/server/i18n/messages/fr.mjs +8 -0
- package/dist/server/i18n/messages/pl.mjs +8 -0
- package/dist/server/i18n/messages/pt.mjs +8 -0
- package/dist/server/i18n/messages/sk.mjs +8 -0
- package/dist/server/modules/admin/.generated/module.d.mts +24 -19
- package/dist/server/modules/admin/.generated/module.mjs +5 -1
- package/dist/server/modules/admin/.generated/registries.d.mts +6 -4
- package/dist/server/modules/admin/client/.generated/module.d.mts +70 -70
- package/dist/server/modules/admin/client/.generated/module.mjs +3 -1
- package/dist/server/modules/admin/client/views/collection-form.d.mts +6 -0
- package/dist/server/modules/admin/client/views/collection-table.d.mts +6 -0
- package/dist/server/modules/admin/client/views/global-form.d.mts +6 -0
- package/dist/server/modules/admin/client/views/list-view.d.mts +6 -0
- package/dist/server/modules/admin/client/views/list-view.mjs +10 -0
- package/dist/server/modules/admin/collections/account.d.mts +50 -50
- package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
- package/dist/server/modules/admin/collections/apikey.d.mts +39 -39
- package/dist/server/modules/admin/collections/assets.d.mts +39 -39
- package/dist/server/modules/admin/collections/session.d.mts +42 -42
- package/dist/server/modules/admin/collections/user.d.mts +63 -63
- package/dist/server/modules/admin/collections/verification.d.mts +36 -36
- package/dist/server/modules/admin/dto/admin-config.dto.mjs +17 -0
- package/dist/server/modules/admin/index.d.mts +30 -31
- package/dist/server/modules/admin/routes/admin-config.d.mts +2 -17
- package/dist/server/modules/admin/routes/admin-config.mjs +21 -5
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/execute-action.mjs +18 -12
- package/dist/server/modules/admin/routes/i18n-helpers.d.mts +4 -0
- package/dist/server/modules/admin/routes/locales.d.mts +2 -2
- package/dist/server/modules/admin/routes/preview.d.mts +24 -19
- package/dist/server/modules/admin/routes/preview.mjs +83 -62
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/route-helpers.mjs +36 -1
- package/dist/server/modules/admin/routes/setup.d.mts +7 -14
- package/dist/server/modules/admin/routes/setup.mjs +16 -3
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
- package/dist/server/modules/admin/views/list-view.d.mts +8 -0
- package/dist/server/modules/admin/views/list-view.mjs +7 -0
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +41 -41
- package/dist/server/modules/audit/.generated/module.d.mts +6 -6
- package/dist/server/modules/audit/collections/audit-log.d.mts +87 -80
- package/dist/server/modules/audit/collections/audit-log.mjs +7 -2
- package/dist/server/modules/audit/config/localize-title.mjs +67 -0
- package/dist/server/modules/audit/index.d.mts +3 -2
- package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +2 -2
- package/dist/server/modules/audit/log-audit-entry.d.mts +85 -0
- package/dist/server/modules/audit/log-audit-entry.mjs +125 -0
- package/dist/server/plugin.d.mts +1 -1
- package/dist/server/plugin.mjs +31 -31
- package/dist/server.d.mts +6 -4
- package/dist/server.mjs +9 -8
- package/dist/shared/preview-utils.d.mts +4 -4
- package/dist/shared/preview-utils.mjs +5 -7
- package/package.json +13 -3
- package/dist/client/hooks/use-audit-history.mjs +0 -38
|
@@ -385,20 +385,21 @@ function extractFieldNamesFromFieldItems(fieldItems) {
|
|
|
385
385
|
* Supports recursive tabs/sections nesting and auto-generates
|
|
386
386
|
* field list when no form config is defined.
|
|
387
387
|
*/
|
|
388
|
-
function AutoFormFields({ app: _cms, collection, mode = "collection", config, registry, fieldResolver, fieldPrefix, allCollectionsConfig }) {
|
|
388
|
+
function AutoFormFields({ app: _cms, collection, mode = "collection", config, registry, fieldResolver, fieldPrefix, allCollectionsConfig, resolvedFields: providedFields, schema: providedSchema }) {
|
|
389
389
|
const isActionForm = collection === "__action__";
|
|
390
|
+
const shouldFetchSchema = !providedFields || !providedSchema;
|
|
390
391
|
const collectionResult = useCollectionFields(mode === "collection" ? collection : "", {
|
|
391
392
|
fallbackFields: mode === "collection" ? config?.fields : void 0,
|
|
392
|
-
schemaQueryOptions: { enabled: mode === "collection" && !isActionForm }
|
|
393
|
+
schemaQueryOptions: { enabled: mode === "collection" && !isActionForm && shouldFetchSchema }
|
|
393
394
|
});
|
|
394
|
-
const globalResult = useGlobalFields(mode === "global" ? collection : "", { schemaQueryOptions: { enabled: mode === "global" } });
|
|
395
|
+
const globalResult = useGlobalFields(mode === "global" ? collection : "", { schemaQueryOptions: { enabled: mode === "global" && shouldFetchSchema } });
|
|
395
396
|
const { data: collectionMeta } = useCollectionMeta(collection, { enabled: mode === "collection" && !isActionForm });
|
|
396
397
|
const { data: globalMeta } = useGlobalMeta(collection, { enabled: mode === "global" });
|
|
397
398
|
const resolvedFields = mode === "global" ? {
|
|
398
|
-
...globalResult.fields,
|
|
399
|
+
...providedFields ?? globalResult.fields,
|
|
399
400
|
...config?.fields
|
|
400
|
-
} : collectionResult.fields;
|
|
401
|
-
const schema = mode === "global" ? globalResult.schema : collectionResult.schema;
|
|
401
|
+
} : providedFields ?? collectionResult.fields;
|
|
402
|
+
const schema = providedSchema ?? (mode === "global" ? globalResult.schema : collectionResult.schema);
|
|
402
403
|
const entityMeta = mode === "global" ? globalMeta : collectionMeta;
|
|
403
404
|
const form = useFormContext();
|
|
404
405
|
const resolveText = useResolveText();
|
|
@@ -476,20 +477,23 @@ function AutoFormFields({ app: _cms, collection, mode = "collection", config, re
|
|
|
476
477
|
className: "qa-form-fields__main min-w-0 flex-1",
|
|
477
478
|
children: mainContent
|
|
478
479
|
}), /* @__PURE__ */ jsx("aside", {
|
|
479
|
-
className: cn("qa-form-fields__sidebar", "w-full @max-2xl:pb-2 @2xl:max-w-[18rem] @2xl:pl-1"),
|
|
480
|
+
className: cn("qa-form-fields__sidebar", "w-full @max-2xl:pb-2 @2xl:sticky @2xl:top-4 @2xl:h-[calc(100svh-7rem)] @2xl:min-h-0 @2xl:max-w-[18rem] @2xl:shrink-0 @2xl:self-start @2xl:pl-1"),
|
|
480
481
|
children: /* @__PURE__ */ jsx("div", {
|
|
481
|
-
className: "bg-surface-low/45
|
|
482
|
-
children: /* @__PURE__ */ jsx(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
482
|
+
className: "bg-surface-low/45 flex min-h-0 flex-col rounded-md @2xl:h-full",
|
|
483
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
484
|
+
className: "scrollbar-thin min-h-0 space-y-4 overflow-y-auto px-3 py-3 @2xl:flex-1",
|
|
485
|
+
children: /* @__PURE__ */ jsx(SidebarRenderer, {
|
|
486
|
+
sidebar: formConfig.sidebar,
|
|
487
|
+
fields,
|
|
488
|
+
collection,
|
|
489
|
+
mode,
|
|
490
|
+
registry,
|
|
491
|
+
fieldPrefix,
|
|
492
|
+
allCollectionsConfig,
|
|
493
|
+
entityMeta,
|
|
494
|
+
formValues,
|
|
495
|
+
resolveText
|
|
496
|
+
})
|
|
493
497
|
})
|
|
494
498
|
})
|
|
495
499
|
})]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useResolveText, useTranslation } from "../../../i18n/hooks.mjs";
|
|
2
2
|
import { cn } from "../../../lib/utils.mjs";
|
|
3
|
-
import { Badge } from "../../../components/ui/badge.mjs";
|
|
4
3
|
import { isBlockContent } from "../../../blocks/types.mjs";
|
|
4
|
+
import { Badge } from "../../../components/ui/badge.mjs";
|
|
5
5
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../../../components/ui/tooltip.mjs";
|
|
6
6
|
import { useAdminConfig } from "../../../hooks/use-admin-config.mjs";
|
|
7
7
|
import { formatFieldLabel, formatPrimitiveValue, getFieldLabel, getItemLabel, summarizeValue } from "./shared/cell-helpers.mjs";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useResolveText } from "../../../i18n/hooks.mjs";
|
|
2
2
|
import { useSafeContentLocales } from "../../../runtime/content-locales-provider.mjs";
|
|
3
3
|
import { useScopedLocale } from "../../../runtime/locale-scope.mjs";
|
|
4
|
-
import { DefaultCell, TextCell } from "../cells/primitive-cells.mjs";
|
|
5
4
|
import { LocaleSwitcher } from "../../../components/locale-switcher.mjs";
|
|
5
|
+
import { DefaultCell, TextCell } from "../cells/primitive-cells.mjs";
|
|
6
6
|
import { normalizeColumnConfig } from "../../../builder/types/collection-types.mjs";
|
|
7
7
|
import { computeDefaultColumns, formatHeader } from "./column-defaults.mjs";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -12,6 +12,18 @@ const SYSTEM_FIELDS = new Set([
|
|
|
12
12
|
"createdBy",
|
|
13
13
|
"updatedBy"
|
|
14
14
|
]);
|
|
15
|
+
const DEFAULT_CONTENT_COLUMN_LIMIT = 4;
|
|
16
|
+
const HEAVY_DEFAULT_FIELD_TYPES = new Set([
|
|
17
|
+
"relation",
|
|
18
|
+
"reverseRelation",
|
|
19
|
+
"upload",
|
|
20
|
+
"uploadMany",
|
|
21
|
+
"blocks",
|
|
22
|
+
"json",
|
|
23
|
+
"object",
|
|
24
|
+
"array",
|
|
25
|
+
"richText"
|
|
26
|
+
]);
|
|
15
27
|
/**
|
|
16
28
|
* Compute sane default visible columns for a collection
|
|
17
29
|
*
|
|
@@ -39,13 +51,14 @@ function computeDefaultColumns(fields, options) {
|
|
|
39
51
|
const defaultCols = [titleColumn];
|
|
40
52
|
if (!fields || Object.keys(fields).length === 0) return defaultCols;
|
|
41
53
|
const contentFields = [];
|
|
42
|
-
const systemFields = [];
|
|
43
54
|
for (const key of Object.keys(fields)) {
|
|
44
55
|
if (useTitleField && key === titleFieldName) continue;
|
|
45
|
-
if (SYSTEM_FIELDS.has(key))
|
|
46
|
-
|
|
56
|
+
if (SYSTEM_FIELDS.has(key)) continue;
|
|
57
|
+
const fieldType = fields[key]?.name ?? "text";
|
|
58
|
+
if (HEAVY_DEFAULT_FIELD_TYPES.has(fieldType)) continue;
|
|
59
|
+
contentFields.push(key);
|
|
47
60
|
}
|
|
48
|
-
defaultCols.push(...contentFields);
|
|
61
|
+
defaultCols.push(...contentFields.slice(0, DEFAULT_CONTENT_COLUMN_LIMIT));
|
|
49
62
|
if ((options?.meta?.timestamps ?? !!fields.createdAt) && !defaultCols.includes("createdAt")) defaultCols.push("createdAt");
|
|
50
63
|
return defaultCols;
|
|
51
64
|
}
|
|
@@ -95,6 +95,14 @@ function renderDefinitionComponent({ context, componentProps, blocks }) {
|
|
|
95
95
|
});
|
|
96
96
|
return /* @__PURE__ */ jsx(Component, { ...componentProps });
|
|
97
97
|
}
|
|
98
|
+
function BlocksDefinitionComponent({ context, componentProps }) {
|
|
99
|
+
const { data: adminConfig } = useAdminConfig();
|
|
100
|
+
return renderDefinitionComponent({
|
|
101
|
+
context,
|
|
102
|
+
componentProps,
|
|
103
|
+
blocks: adminConfig?.blocks
|
|
104
|
+
});
|
|
105
|
+
}
|
|
98
106
|
/**
|
|
99
107
|
* Render embedded collection field
|
|
100
108
|
*
|
|
@@ -133,7 +141,6 @@ function FieldRenderer({ fieldName, fieldDef, collection, mode = "collection", r
|
|
|
133
141
|
const form = useFormContext();
|
|
134
142
|
const { locale } = useScopedLocale();
|
|
135
143
|
const resolveText = useResolveText();
|
|
136
|
-
const { data: adminConfig } = useAdminConfig();
|
|
137
144
|
const fullFieldName = getFullFieldName(fieldName, fieldPrefix);
|
|
138
145
|
const fieldOptions = React.useMemo(() => getFieldOptions(fieldDef), [fieldDef]);
|
|
139
146
|
const dynamicDependencyPaths = React.useMemo(() => computeDynamicDependencyPaths({
|
|
@@ -222,14 +229,19 @@ function FieldRenderer({ fieldName, fieldDef, collection, mode = "collection", r
|
|
|
222
229
|
renderEmbeddedFields
|
|
223
230
|
});
|
|
224
231
|
if (!content && componentLoading) content = /* @__PURE__ */ jsx(FieldComponentSkeleton, { type: context.type });
|
|
225
|
-
if (!content && resolvedComponent)
|
|
226
|
-
|
|
232
|
+
if (!content && resolvedComponent) {
|
|
233
|
+
const componentContext = {
|
|
227
234
|
...context,
|
|
228
235
|
component: resolvedComponent
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
236
|
+
};
|
|
237
|
+
content = context.type === "blocks" ? /* @__PURE__ */ jsx(BlocksDefinitionComponent, {
|
|
238
|
+
context: componentContext,
|
|
239
|
+
componentProps
|
|
240
|
+
}) : renderDefinitionComponent({
|
|
241
|
+
context: componentContext,
|
|
242
|
+
componentProps
|
|
243
|
+
});
|
|
244
|
+
}
|
|
233
245
|
if (!content) content = renderConfigError(`No component registered for field type "${context.type}" (field: "${context.fieldName}").`);
|
|
234
246
|
if (className) return /* @__PURE__ */ jsx("div", {
|
|
235
247
|
className,
|
|
@@ -4,11 +4,11 @@ import { useSafeContentLocales } from "../../runtime/content-locales-provider.mj
|
|
|
4
4
|
import { useScopedLocale } from "../../runtime/locale-scope.mjs";
|
|
5
5
|
import { resolveIconElement } from "../../components/component-renderer.mjs";
|
|
6
6
|
import { Button } from "../../components/ui/button.mjs";
|
|
7
|
-
import { Badge } from "../../components/ui/badge.mjs";
|
|
8
|
-
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../../components/ui/dialog.mjs";
|
|
9
7
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "../../components/ui/dropdown-menu.mjs";
|
|
10
8
|
import { LocaleSwitcher } from "../../components/locale-switcher.mjs";
|
|
11
9
|
import { Label } from "../../components/ui/label.mjs";
|
|
10
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../../components/ui/dialog.mjs";
|
|
11
|
+
import { Badge } from "../../components/ui/badge.mjs";
|
|
12
12
|
import { RenderProfiler } from "../../lib/render-profiler.mjs";
|
|
13
13
|
import { scrollFieldIntoView } from "../../contexts/focus-context.mjs";
|
|
14
14
|
import { Checkbox } from "../../components/ui/checkbox.mjs";
|
|
@@ -144,7 +144,7 @@ function ReactiveFieldsManager({ collection, mode = "collection", reactiveConfig
|
|
|
144
144
|
});
|
|
145
145
|
return null;
|
|
146
146
|
}
|
|
147
|
-
const FormFieldsContent = React.memo(function FormFieldsContent$1({ collection, config, registry, allCollectionsConfig }) {
|
|
147
|
+
const FormFieldsContent = React.memo(function FormFieldsContent$1({ collection, config, registry, allCollectionsConfig, resolvedFields, schema }) {
|
|
148
148
|
return /* @__PURE__ */ jsx(RenderProfiler, {
|
|
149
149
|
id: `form.fields.${collection}`,
|
|
150
150
|
minDurationMs: 10,
|
|
@@ -152,7 +152,9 @@ const FormFieldsContent = React.memo(function FormFieldsContent$1({ collection,
|
|
|
152
152
|
collection,
|
|
153
153
|
config,
|
|
154
154
|
registry,
|
|
155
|
-
allCollectionsConfig
|
|
155
|
+
allCollectionsConfig,
|
|
156
|
+
resolvedFields,
|
|
157
|
+
schema
|
|
156
158
|
})
|
|
157
159
|
});
|
|
158
160
|
});
|
|
@@ -930,7 +932,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
930
932
|
if (handler.body) body = JSON.stringify(handler.body(actionContext));
|
|
931
933
|
setActionLoading(true);
|
|
932
934
|
const apiPromise = async () => {
|
|
933
|
-
const url = `${storeBasePath}/${collection}/${endpoint}`;
|
|
935
|
+
const url = `${client.getBasePath?.() ?? storeBasePath}/${collection}/${endpoint}`;
|
|
934
936
|
const response = await fetch(url, {
|
|
935
937
|
method,
|
|
936
938
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1402,7 +1404,9 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1402
1404
|
collection,
|
|
1403
1405
|
config: formConfigBridge,
|
|
1404
1406
|
registry,
|
|
1405
|
-
allCollectionsConfig
|
|
1407
|
+
allCollectionsConfig,
|
|
1408
|
+
resolvedFields,
|
|
1409
|
+
schema
|
|
1406
1410
|
})
|
|
1407
1411
|
]
|
|
1408
1412
|
})
|