@btst/stack 2.11.4 → 2.11.6
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/dist/components/form-builder/index.d.cts +8 -0
- package/dist/components/form-builder/index.d.mts +8 -0
- package/dist/components/form-builder/index.d.ts +8 -0
- package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.cjs +58 -34
- package/dist/packages/stack/src/plugins/cms/client/components/forms/content-form.mjs +58 -34
- package/dist/packages/stack/src/plugins/cms/client/components/inverse-relations-panel.cjs +29 -7
- package/dist/packages/stack/src/plugins/cms/client/components/inverse-relations-panel.mjs +29 -7
- package/dist/packages/ui/src/components/auto-form/helpers.cjs +24 -1
- package/dist/packages/ui/src/components/auto-form/helpers.mjs +24 -1
- package/dist/packages/ui/src/components/form-builder/schema-utils.cjs +11 -5
- package/dist/packages/ui/src/components/form-builder/schema-utils.mjs +11 -5
- package/dist/plugins/blog/api/index.d.cts +3 -2
- package/dist/plugins/blog/api/index.d.mts +3 -2
- package/dist/plugins/blog/api/index.d.ts +3 -2
- package/dist/plugins/blog/client/components/index.cjs +21 -0
- package/dist/plugins/blog/client/components/index.d.cts +71 -1
- package/dist/plugins/blog/client/components/index.d.mts +71 -1
- package/dist/plugins/blog/client/components/index.d.ts +71 -1
- package/dist/plugins/blog/client/components/index.mjs +15 -1
- package/dist/plugins/blog/client/hooks/index.d.cts +3 -2
- package/dist/plugins/blog/client/hooks/index.d.mts +3 -2
- package/dist/plugins/blog/client/hooks/index.d.ts +3 -2
- package/dist/plugins/blog/client/index.d.cts +3 -2
- package/dist/plugins/blog/client/index.d.mts +3 -2
- package/dist/plugins/blog/client/index.d.ts +3 -2
- package/dist/plugins/blog/query-keys.d.cts +3 -2
- package/dist/plugins/blog/query-keys.d.mts +3 -2
- package/dist/plugins/blog/query-keys.d.ts +3 -2
- package/dist/plugins/kanban/api/index.d.cts +1 -1
- package/dist/plugins/kanban/api/index.d.mts +1 -1
- package/dist/plugins/kanban/api/index.d.ts +1 -1
- package/dist/plugins/kanban/query-keys.d.cts +1 -1
- package/dist/plugins/kanban/query-keys.d.mts +1 -1
- package/dist/plugins/kanban/query-keys.d.ts +1 -1
- package/dist/shared/{stack.6mEHS2WH.d.mts → stack.BnSAhKJi.d.ts} +4 -3
- package/dist/shared/{stack.C1jLzFZ6.d.mts → stack.CLWhMntf.d.cts} +6 -5
- package/dist/shared/{stack.BQmuNl5p.d.mts → stack.CuhcFsAx.d.cts} +3 -38
- package/dist/shared/{stack.BQmuNl5p.d.ts → stack.CuhcFsAx.d.mts} +3 -38
- package/dist/shared/{stack.BQmuNl5p.d.cts → stack.CuhcFsAx.d.ts} +3 -38
- package/dist/shared/{stack.AJTXI7kw.d.cts → stack.DNLuzDb3.d.cts} +4 -3
- package/dist/shared/{stack.QYn-Px94.d.ts → stack.Dfc44JiE.d.mts} +4 -3
- package/dist/shared/{stack.DF1ewpVE.d.ts → stack.DiodAFAa.d.mts} +6 -5
- package/dist/shared/stack.Dsatjh0B.d.cts +35 -0
- package/dist/shared/stack.Dsatjh0B.d.mts +35 -0
- package/dist/shared/stack.Dsatjh0B.d.ts +35 -0
- package/dist/shared/{stack.XulPeAD3.d.cts → stack.ufcExQIR.d.ts} +6 -5
- package/package.json +14 -1
- package/src/plugins/blog/client/components/index.tsx +52 -0
- package/src/plugins/cms/__tests__/auto-form-nested-config.test.ts +177 -0
- package/src/plugins/cms/client/components/forms/content-form.tsx +93 -47
- package/src/plugins/cms/client/components/inverse-relations-panel.tsx +49 -1
- package/src/plugins/form-builder/__tests__/schema-utils.test.ts +362 -0
- package/dist/shared/{stack.j5SFLC1d.d.ts → stack.9dFHtvXR.d.ts} +15 -15
- package/dist/shared/{stack.Bzfx-_lq.d.mts → stack.BzKW7ToW.d.mts} +15 -15
- package/dist/shared/{stack.B6S3cgwN.d.cts → stack.f6MrG7ys.d.cts} +15 -15
|
@@ -23,6 +23,14 @@ interface JSONSchema {
|
|
|
23
23
|
$schema?: string;
|
|
24
24
|
/** Step definitions for multi-step forms (stored in schema meta) */
|
|
25
25
|
steps?: FormStep[];
|
|
26
|
+
/**
|
|
27
|
+
* Optional root-level field-name → step-index map. This is the format produced
|
|
28
|
+
* by `zodToFormSchema(schema, { steps, stepGroupMap })` and consumed by
|
|
29
|
+
* `SteppedAutoForm`. The visual FormBuilder writes per-property `stepGroup`
|
|
30
|
+
* instead, but we accept both on read so a Zod-seeded form opens with its
|
|
31
|
+
* fields correctly assigned to their steps.
|
|
32
|
+
*/
|
|
33
|
+
stepGroupMap?: Record<string, number>;
|
|
26
34
|
additionalProperties?: boolean;
|
|
27
35
|
}
|
|
28
36
|
/**
|
|
@@ -23,6 +23,14 @@ interface JSONSchema {
|
|
|
23
23
|
$schema?: string;
|
|
24
24
|
/** Step definitions for multi-step forms (stored in schema meta) */
|
|
25
25
|
steps?: FormStep[];
|
|
26
|
+
/**
|
|
27
|
+
* Optional root-level field-name → step-index map. This is the format produced
|
|
28
|
+
* by `zodToFormSchema(schema, { steps, stepGroupMap })` and consumed by
|
|
29
|
+
* `SteppedAutoForm`. The visual FormBuilder writes per-property `stepGroup`
|
|
30
|
+
* instead, but we accept both on read so a Zod-seeded form opens with its
|
|
31
|
+
* fields correctly assigned to their steps.
|
|
32
|
+
*/
|
|
33
|
+
stepGroupMap?: Record<string, number>;
|
|
26
34
|
additionalProperties?: boolean;
|
|
27
35
|
}
|
|
28
36
|
/**
|
|
@@ -23,6 +23,14 @@ interface JSONSchema {
|
|
|
23
23
|
$schema?: string;
|
|
24
24
|
/** Step definitions for multi-step forms (stored in schema meta) */
|
|
25
25
|
steps?: FormStep[];
|
|
26
|
+
/**
|
|
27
|
+
* Optional root-level field-name → step-index map. This is the format produced
|
|
28
|
+
* by `zodToFormSchema(schema, { steps, stepGroupMap })` and consumed by
|
|
29
|
+
* `SteppedAutoForm`. The visual FormBuilder writes per-property `stepGroup`
|
|
30
|
+
* instead, but we accept both on read so a Zod-seeded form opens with its
|
|
31
|
+
* fields correctly assigned to their steps.
|
|
32
|
+
*/
|
|
33
|
+
stepGroupMap?: Record<string, number>;
|
|
26
34
|
additionalProperties?: boolean;
|
|
27
35
|
}
|
|
28
36
|
/**
|
|
@@ -20,43 +20,67 @@ function buildFieldConfigFromJsonSchema(jsonSchema, uploadImage, fieldComponents
|
|
|
20
20
|
const baseConfig = helpers.buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents);
|
|
21
21
|
const properties = jsonSchema.properties;
|
|
22
22
|
if (!properties) return baseConfig;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
23
|
+
const injectCustomFieldTypes = (props, targetConfig) => {
|
|
24
|
+
for (const [key, prop] of Object.entries(props)) {
|
|
25
|
+
const existing = targetConfig[key] ?? {};
|
|
26
|
+
let updated = existing;
|
|
27
|
+
if (prop.fieldType === "file" && !fieldComponents?.["file"]) {
|
|
28
|
+
if (!uploadImage && !imageInputField) {
|
|
29
|
+
updated = {
|
|
30
|
+
...updated,
|
|
31
|
+
fieldType: () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive", children: [
|
|
32
|
+
"File upload requires an ",
|
|
33
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "uploadImage" }),
|
|
34
|
+
" or",
|
|
35
|
+
" ",
|
|
36
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "imageInputField" }),
|
|
37
|
+
" function in CMS overrides."
|
|
38
|
+
] })
|
|
39
|
+
};
|
|
40
|
+
} else {
|
|
41
|
+
updated = {
|
|
42
|
+
...updated,
|
|
43
|
+
fieldType: (componentProps) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
44
|
+
fileUpload.CMSFileUpload,
|
|
45
|
+
{
|
|
46
|
+
...componentProps,
|
|
47
|
+
uploadImage: uploadImage ?? (() => Promise.resolve("")),
|
|
48
|
+
imageInputField,
|
|
49
|
+
imagePicker
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (prop.fieldType === "relation" && prop.relation && !fieldComponents?.["relation"]) {
|
|
56
|
+
const relationConfig = prop.relation;
|
|
57
|
+
updated = {
|
|
58
|
+
...updated,
|
|
59
|
+
fieldType: (componentProps) => /* @__PURE__ */ jsxRuntime.jsx(relationField.RelationField, { ...componentProps, relation: relationConfig })
|
|
49
60
|
};
|
|
50
61
|
}
|
|
62
|
+
if (prop.properties) {
|
|
63
|
+
injectCustomFieldTypes(
|
|
64
|
+
prop.properties,
|
|
65
|
+
updated
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
const items = prop.items;
|
|
69
|
+
if (items?.properties) {
|
|
70
|
+
injectCustomFieldTypes(
|
|
71
|
+
items.properties,
|
|
72
|
+
updated
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (Object.keys(updated).length > 0) {
|
|
76
|
+
targetConfig[key] = updated;
|
|
77
|
+
}
|
|
51
78
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
}
|
|
79
|
+
};
|
|
80
|
+
injectCustomFieldTypes(
|
|
81
|
+
properties,
|
|
82
|
+
baseConfig
|
|
83
|
+
);
|
|
60
84
|
return baseConfig;
|
|
61
85
|
}
|
|
62
86
|
function findSlugSourceField(jsonSchema) {
|
|
@@ -18,43 +18,67 @@ function buildFieldConfigFromJsonSchema(jsonSchema, uploadImage, fieldComponents
|
|
|
18
18
|
const baseConfig = buildFieldConfigFromJsonSchema$1(jsonSchema, fieldComponents);
|
|
19
19
|
const properties = jsonSchema.properties;
|
|
20
20
|
if (!properties) return baseConfig;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
21
|
+
const injectCustomFieldTypes = (props, targetConfig) => {
|
|
22
|
+
for (const [key, prop] of Object.entries(props)) {
|
|
23
|
+
const existing = targetConfig[key] ?? {};
|
|
24
|
+
let updated = existing;
|
|
25
|
+
if (prop.fieldType === "file" && !fieldComponents?.["file"]) {
|
|
26
|
+
if (!uploadImage && !imageInputField) {
|
|
27
|
+
updated = {
|
|
28
|
+
...updated,
|
|
29
|
+
fieldType: () => /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive", children: [
|
|
30
|
+
"File upload requires an ",
|
|
31
|
+
/* @__PURE__ */ jsx("code", { children: "uploadImage" }),
|
|
32
|
+
" or",
|
|
33
|
+
" ",
|
|
34
|
+
/* @__PURE__ */ jsx("code", { children: "imageInputField" }),
|
|
35
|
+
" function in CMS overrides."
|
|
36
|
+
] })
|
|
37
|
+
};
|
|
38
|
+
} else {
|
|
39
|
+
updated = {
|
|
40
|
+
...updated,
|
|
41
|
+
fieldType: (componentProps) => /* @__PURE__ */ jsx(
|
|
42
|
+
CMSFileUpload,
|
|
43
|
+
{
|
|
44
|
+
...componentProps,
|
|
45
|
+
uploadImage: uploadImage ?? (() => Promise.resolve("")),
|
|
46
|
+
imageInputField,
|
|
47
|
+
imagePicker
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (prop.fieldType === "relation" && prop.relation && !fieldComponents?.["relation"]) {
|
|
54
|
+
const relationConfig = prop.relation;
|
|
55
|
+
updated = {
|
|
56
|
+
...updated,
|
|
57
|
+
fieldType: (componentProps) => /* @__PURE__ */ jsx(RelationField, { ...componentProps, relation: relationConfig })
|
|
47
58
|
};
|
|
48
59
|
}
|
|
60
|
+
if (prop.properties) {
|
|
61
|
+
injectCustomFieldTypes(
|
|
62
|
+
prop.properties,
|
|
63
|
+
updated
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const items = prop.items;
|
|
67
|
+
if (items?.properties) {
|
|
68
|
+
injectCustomFieldTypes(
|
|
69
|
+
items.properties,
|
|
70
|
+
updated
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (Object.keys(updated).length > 0) {
|
|
74
|
+
targetConfig[key] = updated;
|
|
75
|
+
}
|
|
49
76
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
}
|
|
77
|
+
};
|
|
78
|
+
injectCustomFieldTypes(
|
|
79
|
+
properties,
|
|
80
|
+
baseConfig
|
|
81
|
+
);
|
|
58
82
|
return baseConfig;
|
|
59
83
|
}
|
|
60
84
|
function findSlugSourceField(jsonSchema) {
|
|
@@ -42,6 +42,13 @@ function InverseRelationsPanel({
|
|
|
42
42
|
if (inverseRelations.length === 0) {
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
|
+
const sourceTypeCounts = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const rel of inverseRelations) {
|
|
47
|
+
sourceTypeCounts.set(
|
|
48
|
+
rel.sourceType,
|
|
49
|
+
(sourceTypeCounts.get(rel.sourceType) ?? 0) + 1
|
|
50
|
+
);
|
|
51
|
+
}
|
|
45
52
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
46
53
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold", children: "Related Items" }),
|
|
47
54
|
inverseRelations.map((relation) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -54,12 +61,18 @@ function InverseRelationsPanel({
|
|
|
54
61
|
navigate,
|
|
55
62
|
Link,
|
|
56
63
|
client: client$1,
|
|
57
|
-
headers
|
|
64
|
+
headers,
|
|
65
|
+
ambiguous: (sourceTypeCounts.get(relation.sourceType) ?? 0) > 1
|
|
58
66
|
},
|
|
59
67
|
`${relation.sourceType}-${relation.fieldName}`
|
|
60
68
|
))
|
|
61
69
|
] });
|
|
62
70
|
}
|
|
71
|
+
function humanizeFieldName(fieldName) {
|
|
72
|
+
const stripped = fieldName.replace(/Ids?$/, "") || fieldName;
|
|
73
|
+
const words = stripped.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim().split(/\s+/);
|
|
74
|
+
return words.map((w) => w ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
|
|
75
|
+
}
|
|
63
76
|
function InverseRelationSection({
|
|
64
77
|
relation,
|
|
65
78
|
contentTypeSlug,
|
|
@@ -68,7 +81,8 @@ function InverseRelationSection({
|
|
|
68
81
|
navigate,
|
|
69
82
|
Link,
|
|
70
83
|
client,
|
|
71
|
-
headers
|
|
84
|
+
headers,
|
|
85
|
+
ambiguous
|
|
72
86
|
}) {
|
|
73
87
|
const [isExpanded, setIsExpanded] = React.useState(true);
|
|
74
88
|
const [deleteItemId, setDeleteItemId] = React.useState(null);
|
|
@@ -117,6 +131,7 @@ function InverseRelationSection({
|
|
|
117
131
|
navigate(createUrl);
|
|
118
132
|
};
|
|
119
133
|
const LinkComponent = Link ?? "a";
|
|
134
|
+
const fieldLabel = ambiguous ? humanizeFieldName(relation.fieldName) : null;
|
|
120
135
|
return /* @__PURE__ */ jsxRuntime.jsxs(card.Card, { children: [
|
|
121
136
|
/* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { className: "py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
122
137
|
"button",
|
|
@@ -126,10 +141,16 @@ function InverseRelationSection({
|
|
|
126
141
|
className: "flex items-center justify-between w-full text-left",
|
|
127
142
|
children: /* @__PURE__ */ jsxRuntime.jsxs(card.CardTitle, { className: "text-base flex items-center gap-2", children: [
|
|
128
143
|
isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronRight, { className: "h-4 w-4" }),
|
|
129
|
-
relation.sourceTypeName,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: relation.sourceTypeName }),
|
|
145
|
+
fieldLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-normal text-muted-foreground", children: [
|
|
146
|
+
"\xB7 ",
|
|
147
|
+
fieldLabel
|
|
148
|
+
] }),
|
|
149
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-normal text-muted-foreground", children: [
|
|
150
|
+
"(",
|
|
151
|
+
total,
|
|
152
|
+
")"
|
|
153
|
+
] })
|
|
133
154
|
] })
|
|
134
155
|
}
|
|
135
156
|
) }),
|
|
@@ -182,7 +203,8 @@ function InverseRelationSection({
|
|
|
182
203
|
children: [
|
|
183
204
|
/* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Plus, { className: "h-4 w-4 mr-2" }),
|
|
184
205
|
"Add ",
|
|
185
|
-
relation.sourceTypeName
|
|
206
|
+
relation.sourceTypeName,
|
|
207
|
+
fieldLabel ? ` (${fieldLabel})` : ""
|
|
186
208
|
]
|
|
187
209
|
}
|
|
188
210
|
) })
|
|
@@ -40,6 +40,13 @@ function InverseRelationsPanel({
|
|
|
40
40
|
if (inverseRelations.length === 0) {
|
|
41
41
|
return null;
|
|
42
42
|
}
|
|
43
|
+
const sourceTypeCounts = /* @__PURE__ */ new Map();
|
|
44
|
+
for (const rel of inverseRelations) {
|
|
45
|
+
sourceTypeCounts.set(
|
|
46
|
+
rel.sourceType,
|
|
47
|
+
(sourceTypeCounts.get(rel.sourceType) ?? 0) + 1
|
|
48
|
+
);
|
|
49
|
+
}
|
|
43
50
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
44
51
|
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: "Related Items" }),
|
|
45
52
|
inverseRelations.map((relation) => /* @__PURE__ */ jsx(
|
|
@@ -52,12 +59,18 @@ function InverseRelationsPanel({
|
|
|
52
59
|
navigate,
|
|
53
60
|
Link,
|
|
54
61
|
client,
|
|
55
|
-
headers
|
|
62
|
+
headers,
|
|
63
|
+
ambiguous: (sourceTypeCounts.get(relation.sourceType) ?? 0) > 1
|
|
56
64
|
},
|
|
57
65
|
`${relation.sourceType}-${relation.fieldName}`
|
|
58
66
|
))
|
|
59
67
|
] });
|
|
60
68
|
}
|
|
69
|
+
function humanizeFieldName(fieldName) {
|
|
70
|
+
const stripped = fieldName.replace(/Ids?$/, "") || fieldName;
|
|
71
|
+
const words = stripped.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim().split(/\s+/);
|
|
72
|
+
return words.map((w) => w ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
|
|
73
|
+
}
|
|
61
74
|
function InverseRelationSection({
|
|
62
75
|
relation,
|
|
63
76
|
contentTypeSlug,
|
|
@@ -66,7 +79,8 @@ function InverseRelationSection({
|
|
|
66
79
|
navigate,
|
|
67
80
|
Link,
|
|
68
81
|
client,
|
|
69
|
-
headers
|
|
82
|
+
headers,
|
|
83
|
+
ambiguous
|
|
70
84
|
}) {
|
|
71
85
|
const [isExpanded, setIsExpanded] = useState(true);
|
|
72
86
|
const [deleteItemId, setDeleteItemId] = useState(null);
|
|
@@ -115,6 +129,7 @@ function InverseRelationSection({
|
|
|
115
129
|
navigate(createUrl);
|
|
116
130
|
};
|
|
117
131
|
const LinkComponent = Link ?? "a";
|
|
132
|
+
const fieldLabel = ambiguous ? humanizeFieldName(relation.fieldName) : null;
|
|
118
133
|
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
119
134
|
/* @__PURE__ */ jsx(CardHeader, { className: "py-3", children: /* @__PURE__ */ jsx(
|
|
120
135
|
"button",
|
|
@@ -124,10 +139,16 @@ function InverseRelationSection({
|
|
|
124
139
|
className: "flex items-center justify-between w-full text-left",
|
|
125
140
|
children: /* @__PURE__ */ jsxs(CardTitle, { className: "text-base flex items-center gap-2", children: [
|
|
126
141
|
isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" }),
|
|
127
|
-
relation.sourceTypeName,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
142
|
+
/* @__PURE__ */ jsx("span", { children: relation.sourceTypeName }),
|
|
143
|
+
fieldLabel && /* @__PURE__ */ jsxs("span", { className: "font-normal text-muted-foreground", children: [
|
|
144
|
+
"\xB7 ",
|
|
145
|
+
fieldLabel
|
|
146
|
+
] }),
|
|
147
|
+
/* @__PURE__ */ jsxs("span", { className: "font-normal text-muted-foreground", children: [
|
|
148
|
+
"(",
|
|
149
|
+
total,
|
|
150
|
+
")"
|
|
151
|
+
] })
|
|
131
152
|
] })
|
|
132
153
|
}
|
|
133
154
|
) }),
|
|
@@ -180,7 +201,8 @@ function InverseRelationSection({
|
|
|
180
201
|
children: [
|
|
181
202
|
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
182
203
|
"Add ",
|
|
183
|
-
relation.sourceTypeName
|
|
204
|
+
relation.sourceTypeName,
|
|
205
|
+
fieldLabel ? ` (${fieldLabel})` : ""
|
|
184
206
|
]
|
|
185
207
|
}
|
|
186
208
|
) })
|
|
@@ -216,12 +216,19 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
|
|
|
216
216
|
);
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
|
+
const reservedProps = /* @__PURE__ */ new Set([
|
|
220
|
+
"description",
|
|
221
|
+
"label",
|
|
222
|
+
"inputProps",
|
|
223
|
+
"fieldType",
|
|
224
|
+
"renderParent",
|
|
225
|
+
"order"
|
|
226
|
+
]);
|
|
219
227
|
if (value.properties) {
|
|
220
228
|
const nestedConfig = buildFieldConfigFromJsonSchema(
|
|
221
229
|
{ properties: value.properties },
|
|
222
230
|
fieldComponents
|
|
223
231
|
);
|
|
224
|
-
const reservedProps = /* @__PURE__ */ new Set(["description", "label", "inputProps", "fieldType", "renderParent", "order"]);
|
|
225
232
|
for (const [nestedKey, nestedValue] of Object.entries(nestedConfig)) {
|
|
226
233
|
if (!reservedProps.has(nestedKey)) {
|
|
227
234
|
config[nestedKey] = nestedValue;
|
|
@@ -232,6 +239,22 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
|
|
|
232
239
|
}
|
|
233
240
|
}
|
|
234
241
|
}
|
|
242
|
+
const items = value.items;
|
|
243
|
+
if (items?.properties) {
|
|
244
|
+
const itemConfig = buildFieldConfigFromJsonSchema(
|
|
245
|
+
{ properties: items.properties },
|
|
246
|
+
fieldComponents
|
|
247
|
+
);
|
|
248
|
+
for (const [itemKey, itemValue] of Object.entries(itemConfig)) {
|
|
249
|
+
if (!reservedProps.has(itemKey)) {
|
|
250
|
+
config[itemKey] = itemValue;
|
|
251
|
+
} else {
|
|
252
|
+
console.warn(
|
|
253
|
+
`Array field "${key}" has an item property named "${itemKey}" which conflicts with a reserved FieldConfigItem property. The item field's config will not be accessible inside array items.`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
235
258
|
if (Object.keys(config).length > 0) {
|
|
236
259
|
fieldConfig[key] = config;
|
|
237
260
|
}
|
|
@@ -214,12 +214,19 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
|
|
|
214
214
|
);
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
|
+
const reservedProps = /* @__PURE__ */ new Set([
|
|
218
|
+
"description",
|
|
219
|
+
"label",
|
|
220
|
+
"inputProps",
|
|
221
|
+
"fieldType",
|
|
222
|
+
"renderParent",
|
|
223
|
+
"order"
|
|
224
|
+
]);
|
|
217
225
|
if (value.properties) {
|
|
218
226
|
const nestedConfig = buildFieldConfigFromJsonSchema(
|
|
219
227
|
{ properties: value.properties },
|
|
220
228
|
fieldComponents
|
|
221
229
|
);
|
|
222
|
-
const reservedProps = /* @__PURE__ */ new Set(["description", "label", "inputProps", "fieldType", "renderParent", "order"]);
|
|
223
230
|
for (const [nestedKey, nestedValue] of Object.entries(nestedConfig)) {
|
|
224
231
|
if (!reservedProps.has(nestedKey)) {
|
|
225
232
|
config[nestedKey] = nestedValue;
|
|
@@ -230,6 +237,22 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
|
|
|
230
237
|
}
|
|
231
238
|
}
|
|
232
239
|
}
|
|
240
|
+
const items = value.items;
|
|
241
|
+
if (items?.properties) {
|
|
242
|
+
const itemConfig = buildFieldConfigFromJsonSchema(
|
|
243
|
+
{ properties: items.properties },
|
|
244
|
+
fieldComponents
|
|
245
|
+
);
|
|
246
|
+
for (const [itemKey, itemValue] of Object.entries(itemConfig)) {
|
|
247
|
+
if (!reservedProps.has(itemKey)) {
|
|
248
|
+
config[itemKey] = itemValue;
|
|
249
|
+
} else {
|
|
250
|
+
console.warn(
|
|
251
|
+
`Array field "${key}" has an item property named "${itemKey}" which conflicts with a reserved FieldConfigItem property. The item field's config will not be accessible inside array items.`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
233
256
|
if (Object.keys(config).length > 0) {
|
|
234
257
|
fieldConfig[key] = config;
|
|
235
258
|
}
|
|
@@ -49,7 +49,7 @@ function fieldsToJSONSchema(fields, components, steps) {
|
|
|
49
49
|
...hasMultipleSteps ? { steps } : {}
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
function propertiesToFields(properties, requiredSet, components) {
|
|
52
|
+
function propertiesToFields(properties, requiredSet, components, stepGroupMap) {
|
|
53
53
|
const fields = [];
|
|
54
54
|
for (const [key, prop] of Object.entries(properties)) {
|
|
55
55
|
const isRequired = requiredSet.has(key);
|
|
@@ -60,9 +60,10 @@ function propertiesToFields(properties, requiredSet, components) {
|
|
|
60
60
|
break;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
const resolvedStepGroup = prop.stepGroup !== void 0 ? prop.stepGroup : stepGroupMap?.[key];
|
|
63
64
|
if (field) {
|
|
64
|
-
if (
|
|
65
|
-
field.stepGroup =
|
|
65
|
+
if (resolvedStepGroup !== void 0) {
|
|
66
|
+
field.stepGroup = resolvedStepGroup;
|
|
66
67
|
}
|
|
67
68
|
if (field.type === "object" && prop.properties) {
|
|
68
69
|
const childRequiredSet = new Set(prop.required || []);
|
|
@@ -85,7 +86,7 @@ function propertiesToFields(properties, requiredSet, components) {
|
|
|
85
86
|
required: isRequired
|
|
86
87
|
},
|
|
87
88
|
// Include stepGroup even for fallback fields
|
|
88
|
-
...
|
|
89
|
+
...resolvedStepGroup !== void 0 ? { stepGroup: resolvedStepGroup } : {}
|
|
89
90
|
});
|
|
90
91
|
}
|
|
91
92
|
}
|
|
@@ -96,7 +97,12 @@ function jsonSchemaToFieldsAndSteps(schema, components) {
|
|
|
96
97
|
return { fields: [], steps: [] };
|
|
97
98
|
}
|
|
98
99
|
const requiredSet = new Set(schema.required || []);
|
|
99
|
-
const fields = propertiesToFields(
|
|
100
|
+
const fields = propertiesToFields(
|
|
101
|
+
schema.properties,
|
|
102
|
+
requiredSet,
|
|
103
|
+
components,
|
|
104
|
+
schema.stepGroupMap
|
|
105
|
+
);
|
|
100
106
|
const steps = schema.steps || [];
|
|
101
107
|
return { fields, steps };
|
|
102
108
|
}
|
|
@@ -47,7 +47,7 @@ function fieldsToJSONSchema(fields, components, steps) {
|
|
|
47
47
|
...hasMultipleSteps ? { steps } : {}
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
|
-
function propertiesToFields(properties, requiredSet, components) {
|
|
50
|
+
function propertiesToFields(properties, requiredSet, components, stepGroupMap) {
|
|
51
51
|
const fields = [];
|
|
52
52
|
for (const [key, prop] of Object.entries(properties)) {
|
|
53
53
|
const isRequired = requiredSet.has(key);
|
|
@@ -58,9 +58,10 @@ function propertiesToFields(properties, requiredSet, components) {
|
|
|
58
58
|
break;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
const resolvedStepGroup = prop.stepGroup !== void 0 ? prop.stepGroup : stepGroupMap?.[key];
|
|
61
62
|
if (field) {
|
|
62
|
-
if (
|
|
63
|
-
field.stepGroup =
|
|
63
|
+
if (resolvedStepGroup !== void 0) {
|
|
64
|
+
field.stepGroup = resolvedStepGroup;
|
|
64
65
|
}
|
|
65
66
|
if (field.type === "object" && prop.properties) {
|
|
66
67
|
const childRequiredSet = new Set(prop.required || []);
|
|
@@ -83,7 +84,7 @@ function propertiesToFields(properties, requiredSet, components) {
|
|
|
83
84
|
required: isRequired
|
|
84
85
|
},
|
|
85
86
|
// Include stepGroup even for fallback fields
|
|
86
|
-
...
|
|
87
|
+
...resolvedStepGroup !== void 0 ? { stepGroup: resolvedStepGroup } : {}
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
90
|
}
|
|
@@ -94,7 +95,12 @@ function jsonSchemaToFieldsAndSteps(schema, components) {
|
|
|
94
95
|
return { fields: [], steps: [] };
|
|
95
96
|
}
|
|
96
97
|
const requiredSet = new Set(schema.required || []);
|
|
97
|
-
const fields = propertiesToFields(
|
|
98
|
+
const fields = propertiesToFields(
|
|
99
|
+
schema.properties,
|
|
100
|
+
requiredSet,
|
|
101
|
+
components,
|
|
102
|
+
schema.stepGroupMap
|
|
103
|
+
);
|
|
98
104
|
const steps = schema.steps || [];
|
|
99
105
|
return { fields, steps };
|
|
100
106
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.
|
|
2
|
-
import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.
|
|
1
|
+
export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.CLWhMntf.cjs';
|
|
2
|
+
import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.Dsatjh0B.cjs';
|
|
3
3
|
import '@tanstack/react-query';
|
|
4
4
|
import '@btst/stack/plugins/client';
|
|
5
5
|
import '@btst/stack/plugins/api';
|
|
6
6
|
import '@btst/db';
|
|
7
7
|
import 'better-call';
|
|
8
8
|
import 'zod';
|
|
9
|
+
import '../../../shared/stack.CuhcFsAx.cjs';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Serialize a Tag for SSR/SSG use (convert dates to strings).
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.
|
|
2
|
-
import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.
|
|
1
|
+
export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.DiodAFAa.mjs';
|
|
2
|
+
import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.Dsatjh0B.mjs';
|
|
3
3
|
import '@tanstack/react-query';
|
|
4
4
|
import '@btst/stack/plugins/client';
|
|
5
5
|
import '@btst/stack/plugins/api';
|
|
6
6
|
import '@btst/db';
|
|
7
7
|
import 'better-call';
|
|
8
8
|
import 'zod';
|
|
9
|
+
import '../../../shared/stack.CuhcFsAx.mjs';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Serialize a Tag for SSR/SSG use (convert dates to strings).
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.
|
|
2
|
-
import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.
|
|
1
|
+
export { B as BLOG_QUERY_KEYS, j as BlogApiContext, m as BlogApiRouter, k as BlogBackendHooks, h as BlogRouteKey, C as CreatePostInput, N as NextPreviousPostsQuerySchema, P as PostListParams, i as PostListQuerySchema, c as PostListResult, U as UpdatePostInput, l as blogBackendPlugin, f as createBlogQueryKeys, d as createPost, e as deletePost, g as getAllPosts, b as getAllTags, a as getPostBySlug, u as updatePost } from '../../../shared/stack.ufcExQIR.js';
|
|
2
|
+
import { P as Post, T as Tag, S as SerializedPost, a as SerializedTag } from '../../../shared/stack.Dsatjh0B.js';
|
|
3
3
|
import '@tanstack/react-query';
|
|
4
4
|
import '@btst/stack/plugins/client';
|
|
5
5
|
import '@btst/stack/plugins/api';
|
|
6
6
|
import '@btst/db';
|
|
7
7
|
import 'better-call';
|
|
8
8
|
import 'zod';
|
|
9
|
+
import '../../../shared/stack.CuhcFsAx.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Serialize a Tag for SSR/SSG use (convert dates to strings).
|