@riducms/admin 0.2.0 → 0.2.2
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/package.json +7 -7
- package/src/app.svelte +1 -10
- package/src/core/api/admin-client.ts +2 -0
- package/src/core/forms/embedded-schema-draft.svelte.ts +4 -2
- package/src/core/forms/field-binding-lifetime.ts +155 -0
- package/src/core/forms/field-condition.ts +6 -11
- package/src/core/forms/field-editor-binding.ts +27 -105
- package/src/core/forms/field-occurrence.ts +6 -23
- package/src/core/forms/form-controller.svelte.ts +68 -0
- package/src/core/forms/plugin-field-authoring.ts +1 -0
- package/src/core/forms/plugin-field-binding.ts +17 -107
- package/src/core/forms/scalar-literal.ts +18 -0
- package/src/core/plugins/field-registry.ts +5 -3
- package/src/core/runtime/admin-runtime.svelte.ts +19 -20
- package/src/fields/embedded-schema-draft-editor.svelte +15 -1
- package/src/fields/embedded-schema-fields.svelte +14 -1
- package/src/fields/nested/block-header.svelte +38 -0
- package/src/fields/nested/block-header.ts +28 -0
- package/src/fields/nested/block-name-input.svelte +126 -0
- package/src/fields/nested/nested-field.svelte +44 -5
- package/src/fields/plugin-field.svelte +39 -3
- package/src/fields/relationship/relationship-query.ts +2 -17
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { onDestroy, type Component } from "svelte";
|
|
3
|
+
import { SvelteMap } from "svelte/reactivity";
|
|
3
4
|
import type {
|
|
4
5
|
EmbeddedSchemaDraft,
|
|
5
6
|
EmbeddedSchemaDraftEditorProps,
|
|
6
7
|
EmbeddedSchemaFormScope,
|
|
8
|
+
EmbeddedSchemaHeaderProps,
|
|
7
9
|
FieldAuthoringHost,
|
|
8
10
|
PluginFieldProps,
|
|
9
11
|
ResolvedPluginField,
|
|
@@ -14,7 +16,6 @@
|
|
|
14
16
|
import { guardPluginAuthoring } from "@admin/core/forms/plugin-field-authoring";
|
|
15
17
|
import { getAdminRuntime } from "@admin/core/runtime/admin-runtime.svelte";
|
|
16
18
|
import { localizeSchemaCollection } from "@admin/core/i18n/localized-schema";
|
|
17
|
-
import { embeddedOccurrences } from "@admin/core/forms/embedded-fields";
|
|
18
19
|
import {
|
|
19
20
|
createEmbeddedSchemaDraft,
|
|
20
21
|
copyEmbeddedSchemaPayload,
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
} from "@admin/core/forms/embedded-schema-draft.svelte";
|
|
23
24
|
import EmbeddedSchemaFields from "@admin/fields/embedded-schema-fields.svelte";
|
|
24
25
|
import EmbeddedSchemaDraftEditor from "@admin/fields/embedded-schema-draft-editor.svelte";
|
|
26
|
+
import BlockHeader from "@admin/fields/nested/block-header.svelte";
|
|
25
27
|
import ReferenceBrowser from "@admin/features/reference-browser/reference-browser-loader.svelte";
|
|
26
28
|
let {
|
|
27
29
|
schema,
|
|
@@ -45,13 +47,14 @@
|
|
|
45
47
|
Omit<PluginFieldProps<unknown, unknown, FieldType>, "config"> & { config?: unknown }
|
|
46
48
|
>;
|
|
47
49
|
onDestroy(field.destroy);
|
|
48
|
-
const drafts = new
|
|
50
|
+
const drafts = new SvelteMap<EmbeddedSchemaDraft, HostedSchemaDraft>();
|
|
49
51
|
const draftAliases = new WeakMap<EmbeddedSchemaDraft, EmbeddedSchemaDraft>();
|
|
50
52
|
onDestroy(() => {
|
|
51
53
|
for (const draft of drafts.keys()) draft.discard();
|
|
52
54
|
});
|
|
53
55
|
const authoring: FieldAuthoringHost = {
|
|
54
56
|
schemaForm,
|
|
57
|
+
schemaHeader,
|
|
55
58
|
schemaDraftEditor,
|
|
56
59
|
beginSchemaDraft: (scope) => {
|
|
57
60
|
const session = createEmbeddedSchemaDraft(
|
|
@@ -98,7 +101,7 @@
|
|
|
98
101
|
return runtime.client.requestPlugin<Result>(owner, path, body, { signal });
|
|
99
102
|
},
|
|
100
103
|
};
|
|
101
|
-
const embedded = $derived(
|
|
104
|
+
const embedded = $derived(form.embeddedFields(schema));
|
|
102
105
|
const embeddedIndex = $derived(
|
|
103
106
|
new Map(
|
|
104
107
|
embedded.occurrences.map((occurrence) => [
|
|
@@ -111,6 +114,15 @@
|
|
|
111
114
|
const guardedAuthoring = guardPluginAuthoring(authoring, field, (draft, raw) => {
|
|
112
115
|
draftAliases.set(draft, raw);
|
|
113
116
|
});
|
|
117
|
+
function headerDraftOpen(options: EmbeddedSchemaHeaderProps) {
|
|
118
|
+
return [...drafts.values()].some(
|
|
119
|
+
({ draft, treeKey }) =>
|
|
120
|
+
treeKey === options.treeKey && draft.identity === options.identity && !draft.stale
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
function headerLocked(options: EmbeddedSchemaHeaderProps) {
|
|
124
|
+
return field.readOnly || options.readOnly === true || headerDraftOpen(options);
|
|
125
|
+
}
|
|
114
126
|
function draftOptions(options: EmbeddedSchemaDraftEditorProps) {
|
|
115
127
|
field.assertActive();
|
|
116
128
|
const session = drafts.get(draftAliases.get(options.draft) ?? options.draft);
|
|
@@ -134,6 +146,30 @@
|
|
|
134
146
|
}
|
|
135
147
|
</script>
|
|
136
148
|
|
|
149
|
+
{#snippet schemaHeader(options: EmbeddedSchemaHeaderProps)}
|
|
150
|
+
{const occurrence = $derived(
|
|
151
|
+
embeddedIndex.get(JSON.stringify([options.treeKey, options.identity]))
|
|
152
|
+
)}
|
|
153
|
+
{const locked = $derived(headerLocked(options))}
|
|
154
|
+
{#if !field.stale && embedded.issues.length === 0 && occurrence !== undefined}
|
|
155
|
+
{#key form.rowMountKey(occurrence.payload)}
|
|
156
|
+
<BlockHeader
|
|
157
|
+
block={occurrence.block}
|
|
158
|
+
path={occurrence.path}
|
|
159
|
+
instance={`${schema.id}-${options.treeKey}-${options.identity}`}
|
|
160
|
+
{form}
|
|
161
|
+
readOnly={locked}
|
|
162
|
+
disabled={headerDraftOpen(options)}
|
|
163
|
+
onChange={(change) => {
|
|
164
|
+
field.assertEditable();
|
|
165
|
+
if (headerLocked(options)) throw new Error("This embedded header is read-only.");
|
|
166
|
+
options.onChange(change);
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
{/key}
|
|
170
|
+
{/if}
|
|
171
|
+
{/snippet}
|
|
172
|
+
|
|
137
173
|
{#snippet schemaForm(scope: EmbeddedSchemaFormScope)}
|
|
138
174
|
<EmbeddedSchemaFields
|
|
139
175
|
field={field.schema}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { scalarLiteralValue } from "@admin/core/forms/scalar-literal";
|
|
1
2
|
import type { FieldReferenceFilter } from "@riducms/plugin";
|
|
2
3
|
import type { SchemaField } from "@riducms/protocol";
|
|
3
4
|
|
|
@@ -49,7 +50,7 @@ export function relationshipOptionFilters(
|
|
|
49
50
|
: typeof values === "function"
|
|
50
51
|
? values(candidate.sourcePath)
|
|
51
52
|
: readPath(values, candidate.sourcePath)
|
|
52
|
-
:
|
|
53
|
+
: scalarLiteralValue(candidate.value);
|
|
53
54
|
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
|
|
54
55
|
return [];
|
|
55
56
|
}
|
|
@@ -64,22 +65,6 @@ export function relationshipOptionFilters(
|
|
|
64
65
|
return filters.length === 0 ? undefined : filters;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
function relationshipFilterLiteral(value: {
|
|
68
|
-
type: "string" | "number" | "boolean";
|
|
69
|
-
value: string;
|
|
70
|
-
}) {
|
|
71
|
-
switch (value.type) {
|
|
72
|
-
case "string":
|
|
73
|
-
return value.value;
|
|
74
|
-
case "number": {
|
|
75
|
-
const parsed = Number(value.value);
|
|
76
|
-
return Number.isFinite(parsed) ? parsed : undefined;
|
|
77
|
-
}
|
|
78
|
-
case "boolean":
|
|
79
|
-
return value.value === "true" ? true : value.value === "false" ? false : undefined;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
68
|
function readPath(values: Record<string, unknown>, path: string) {
|
|
84
69
|
let current: unknown = values;
|
|
85
70
|
for (const segment of path.split(".")) {
|