@jskit-ai/crud-ui-generator 0.1.47 → 0.1.49
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.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/crud-ui-generator",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.49",
|
|
5
5
|
kind: "generator",
|
|
6
6
|
description: "Generate CRUD route trees from resource validators at an explicit route root relative to src/pages/.",
|
|
7
7
|
options: {
|
|
@@ -64,15 +64,7 @@ export default Object.freeze({
|
|
|
64
64
|
inputType: "text",
|
|
65
65
|
defaultValue: "",
|
|
66
66
|
promptLabel: "Link placement",
|
|
67
|
-
promptHint: "Optional target override for the generated list-page link placement (format:
|
|
68
|
-
},
|
|
69
|
-
"link-component-token": {
|
|
70
|
-
required: false,
|
|
71
|
-
inputType: "text",
|
|
72
|
-
defaultValue: "",
|
|
73
|
-
promptLabel: "Link component token",
|
|
74
|
-
promptHint:
|
|
75
|
-
"Optional component token override for the generated list-page link placement (example: local.main.ui.tab-link-item)."
|
|
67
|
+
promptHint: "Optional semantic target override for the generated list-page link placement (format: area.slot)."
|
|
76
68
|
},
|
|
77
69
|
namespace: {
|
|
78
70
|
required: false,
|
|
@@ -119,7 +111,6 @@ export default Object.freeze({
|
|
|
119
111
|
"id-param",
|
|
120
112
|
"parent-title",
|
|
121
113
|
"link-placement",
|
|
122
|
-
"link-component-token",
|
|
123
114
|
"namespace",
|
|
124
115
|
"force"
|
|
125
116
|
],
|
|
@@ -180,7 +171,7 @@ export default Object.freeze({
|
|
|
180
171
|
mutations: {
|
|
181
172
|
dependencies: {
|
|
182
173
|
runtime: {
|
|
183
|
-
"@jskit-ai/users-web": "0.1.
|
|
174
|
+
"@jskit-ai/users-web": "0.1.81"
|
|
184
175
|
},
|
|
185
176
|
dev: {}
|
|
186
177
|
},
|
|
@@ -365,7 +356,7 @@ export default Object.freeze({
|
|
|
365
356
|
position: "bottom",
|
|
366
357
|
skipIfContains: "__JSKIT_UI_MENU_MARKER__",
|
|
367
358
|
value:
|
|
368
|
-
"\n// __JSKIT_UI_MENU_MARKER__\n{\n addPlacement({\n id: \"__JSKIT_UI_MENU_PLACEMENT_ID__\",\n target: \"__JSKIT_UI_MENU_PLACEMENT_TARGET__\",\n surfaces: [\"__JSKIT_UI_SURFACE_ID__\"],\n order: 155,\n
|
|
359
|
+
"\n// __JSKIT_UI_MENU_MARKER__\n{\n addPlacement({\n id: \"__JSKIT_UI_MENU_PLACEMENT_ID__\",\n target: \"__JSKIT_UI_MENU_PLACEMENT_TARGET__\",\n__JSKIT_UI_MENU_OWNER_LINE__ kind: \"link\",\n surfaces: [\"__JSKIT_UI_SURFACE_ID__\"],\n order: 155,\n props: {\n label: \"__JSKIT_UI_MENU_LABEL__\",\n icon: \"__JSKIT_UI_MENU_ICON__\",\n surface: \"__JSKIT_UI_SURFACE_ID__\",\n scopedSuffix: \"__JSKIT_UI_MENU_WORKSPACE_SUFFIX__\",\n unscopedSuffix: \"__JSKIT_UI_MENU_NON_WORKSPACE_SUFFIX__\",\n__JSKIT_UI_MENU_TO_PROP_LINE__ },\n__JSKIT_UI_MENU_WHEN_LINE__ });\n}\n",
|
|
369
360
|
reason: "Append generated CRUD list-page placement.",
|
|
370
361
|
category: "crud-ui-generator",
|
|
371
362
|
id: "crud-ui-placement-menu",
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/crud-ui-generator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@jskit-ai/crud-core": "0.1.
|
|
10
|
-
"@jskit-ai/kernel": "0.1.
|
|
11
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
9
|
+
"@jskit-ai/crud-core": "0.1.74",
|
|
10
|
+
"@jskit-ai/kernel": "0.1.66",
|
|
11
|
+
"@jskit-ai/resource-crud-core": "0.1.11"
|
|
12
12
|
},
|
|
13
13
|
"exports": {
|
|
14
14
|
"./server/buildTemplateContext": "./src/server/buildTemplateContext.js"
|
|
@@ -475,6 +475,14 @@ function resolveMenuToPropLine(linkTo = "") {
|
|
|
475
475
|
return ` to: ${JSON.stringify(linkTo)},\n`;
|
|
476
476
|
}
|
|
477
477
|
|
|
478
|
+
function resolveMenuOwnerLine(owner = "") {
|
|
479
|
+
const normalizedOwner = normalizeText(owner);
|
|
480
|
+
if (!normalizedOwner) {
|
|
481
|
+
return "";
|
|
482
|
+
}
|
|
483
|
+
return ` owner: ${JSON.stringify(normalizedOwner)},\n`;
|
|
484
|
+
}
|
|
485
|
+
|
|
478
486
|
function resolveCrudRelativePath(namespace = "") {
|
|
479
487
|
return `/${requireCrudNamespace(namespace, {
|
|
480
488
|
context: "crud-ui-generator resource namespace"
|
|
@@ -650,7 +658,6 @@ async function buildUiTemplateContext({ appRoot, options } = {}) {
|
|
|
650
658
|
pageTarget,
|
|
651
659
|
targetFile: listTargetFile,
|
|
652
660
|
placement: options?.["link-placement"],
|
|
653
|
-
componentToken: options?.["link-component-token"],
|
|
654
661
|
context: "crud-ui-generator"
|
|
655
662
|
})
|
|
656
663
|
: null;
|
|
@@ -727,7 +734,7 @@ async function buildUiTemplateContext({ appRoot, options } = {}) {
|
|
|
727
734
|
__JSKIT_UI_MENU_MARKER__: menuMarker,
|
|
728
735
|
__JSKIT_UI_MENU_PLACEMENT_ID__: String(pageLinkTarget?.pageTarget?.placementId || ""),
|
|
729
736
|
__JSKIT_UI_MENU_PLACEMENT_TARGET__: String(pageLinkTarget?.placementTarget?.id || ""),
|
|
730
|
-
|
|
737
|
+
__JSKIT_UI_MENU_OWNER_LINE__: resolveMenuOwnerLine(pageLinkTarget?.placementTarget?.owner || ""),
|
|
731
738
|
__JSKIT_UI_MENU_ICON__: DEFAULT_GENERATED_LINK_ICON,
|
|
732
739
|
__JSKIT_UI_MENU_WORKSPACE_SUFFIX__: String(pageLinkTarget?.pageTarget?.routeUrlSuffix || ""),
|
|
733
740
|
__JSKIT_UI_MENU_NON_WORKSPACE_SUFFIX__: String(pageLinkTarget?.pageTarget?.routeUrlSuffix || ""),
|
|
@@ -27,6 +27,67 @@ async function linkTestPackage(appRoot, packageName, packageDir) {
|
|
|
27
27
|
await symlink(packageDir, targetPath, "dir");
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
function renderTopologyVariant(outlet, { linkRenderer = "" } = {}) {
|
|
31
|
+
const rendererLines = linkRenderer
|
|
32
|
+
? `,
|
|
33
|
+
renderers: {
|
|
34
|
+
link: "${linkRenderer}"
|
|
35
|
+
}`
|
|
36
|
+
: "";
|
|
37
|
+
return `{
|
|
38
|
+
outlet: "${outlet}"${rendererLines}
|
|
39
|
+
}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function renderTopologyEntry({
|
|
43
|
+
id = "",
|
|
44
|
+
owner = "",
|
|
45
|
+
surfaces = ["*"],
|
|
46
|
+
defaultPlacement = false,
|
|
47
|
+
outlet = "",
|
|
48
|
+
linkRenderer = ""
|
|
49
|
+
} = {}) {
|
|
50
|
+
const ownerLine = owner ? ` owner: "${owner}",\n` : "";
|
|
51
|
+
const defaultLine = defaultPlacement ? " default: true,\n" : "";
|
|
52
|
+
return ` {
|
|
53
|
+
id: "${id}",
|
|
54
|
+
${ownerLine} surfaces: ${JSON.stringify(surfaces)},
|
|
55
|
+
${defaultLine} variants: {
|
|
56
|
+
compact: ${renderTopologyVariant(outlet, { linkRenderer })},
|
|
57
|
+
medium: ${renderTopologyVariant(outlet, { linkRenderer })},
|
|
58
|
+
expanded: ${renderTopologyVariant(outlet, { linkRenderer })}
|
|
59
|
+
}
|
|
60
|
+
}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function writePlacementTopology(appRoot, entries = []) {
|
|
64
|
+
const defaultEntries = [
|
|
65
|
+
renderTopologyEntry({
|
|
66
|
+
id: "shell.primary-nav",
|
|
67
|
+
surfaces: ["*"],
|
|
68
|
+
defaultPlacement: true,
|
|
69
|
+
outlet: "shell-layout:primary-menu",
|
|
70
|
+
linkRenderer: "local.main.ui.surface-aware-menu-link-item"
|
|
71
|
+
}),
|
|
72
|
+
renderTopologyEntry({
|
|
73
|
+
id: "shell.secondary-nav",
|
|
74
|
+
surfaces: ["*"],
|
|
75
|
+
outlet: "shell-layout:secondary-menu",
|
|
76
|
+
linkRenderer: "local.main.ui.surface-aware-menu-link-item"
|
|
77
|
+
})
|
|
78
|
+
];
|
|
79
|
+
await writeFile(
|
|
80
|
+
path.join(appRoot, "src", "placementTopology.js"),
|
|
81
|
+
`export default {
|
|
82
|
+
placements: [
|
|
83
|
+
${[...defaultEntries, ...entries].join(",\n")}
|
|
84
|
+
]
|
|
85
|
+
};
|
|
86
|
+
`,
|
|
87
|
+
"utf8"
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
30
91
|
async function withTempApp(run) {
|
|
31
92
|
const appRoot = await mkdtemp(path.join(tmpdir(), "crud-ui-generator-"));
|
|
32
93
|
try {
|
|
@@ -54,17 +115,14 @@ async function withTempApp(run) {
|
|
|
54
115
|
<ShellOutlet
|
|
55
116
|
target="shell-layout:primary-menu"
|
|
56
117
|
default
|
|
57
|
-
default-link-component-token="local.main.ui.surface-aware-menu-link-item"
|
|
58
|
-
/>
|
|
59
|
-
<ShellOutlet
|
|
60
|
-
target="shell-layout:secondary-menu"
|
|
61
|
-
default-link-component-token="local.main.ui.surface-aware-menu-link-item"
|
|
62
118
|
/>
|
|
119
|
+
<ShellOutlet target="shell-layout:secondary-menu" />
|
|
63
120
|
</div>
|
|
64
121
|
</template>
|
|
65
122
|
`,
|
|
66
123
|
"utf8"
|
|
67
124
|
);
|
|
125
|
+
await writePlacementTopology(appRoot);
|
|
68
126
|
return await run(appRoot);
|
|
69
127
|
} finally {
|
|
70
128
|
await rm(appRoot, { recursive: true, force: true });
|
|
@@ -614,8 +672,8 @@ test("buildUiTemplateContext resolves list placement from the app default shell
|
|
|
614
672
|
});
|
|
615
673
|
|
|
616
674
|
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_ID__, "ui-generator.page.admin.customers.link");
|
|
617
|
-
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "shell
|
|
618
|
-
assert.equal(context.
|
|
675
|
+
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "shell.primary-nav");
|
|
676
|
+
assert.equal(context.__JSKIT_UI_MENU_OWNER_LINE__, "");
|
|
619
677
|
assert.equal(context.__JSKIT_UI_MENU_WORKSPACE_SUFFIX__, "/customers");
|
|
620
678
|
assert.equal(context.__JSKIT_UI_MENU_NON_WORKSPACE_SUFFIX__, "/customers");
|
|
621
679
|
assert.equal(context.__JSKIT_UI_MENU_TO_PROP_LINE__, "");
|
|
@@ -627,6 +685,15 @@ test("buildUiTemplateContext resolves list placement from the app default shell
|
|
|
627
685
|
test("buildUiTemplateContext infers tab placement and relative link-to from the nearest parent subpages host", async () => {
|
|
628
686
|
await withTempApp(async (appRoot) => {
|
|
629
687
|
await writeResource(appRoot, RESOURCE_FILE, FULL_RESOURCE_SOURCE);
|
|
688
|
+
await writePlacementTopology(appRoot, [
|
|
689
|
+
renderTopologyEntry({
|
|
690
|
+
id: "page.section-nav",
|
|
691
|
+
owner: "catalog",
|
|
692
|
+
surfaces: ["admin"],
|
|
693
|
+
outlet: "catalog:sub-pages",
|
|
694
|
+
linkRenderer: "local.main.ui.surface-aware-menu-link-item"
|
|
695
|
+
})
|
|
696
|
+
]);
|
|
630
697
|
await writeFileInApp(
|
|
631
698
|
appRoot,
|
|
632
699
|
"src/pages/admin/catalog/index.vue",
|
|
@@ -648,8 +715,8 @@ test("buildUiTemplateContext infers tab placement and relative link-to from the
|
|
|
648
715
|
})
|
|
649
716
|
});
|
|
650
717
|
|
|
651
|
-
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "
|
|
652
|
-
assert.equal(context.
|
|
718
|
+
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "page.section-nav");
|
|
719
|
+
assert.equal(context.__JSKIT_UI_MENU_OWNER_LINE__, " owner: \"catalog\",\n");
|
|
653
720
|
assert.equal(context.__JSKIT_UI_MENU_ICON__, "mdi-view-list-outline");
|
|
654
721
|
assert.equal(context.__JSKIT_UI_MENU_TO_PROP_LINE__, " to: \"./products\",\n");
|
|
655
722
|
assert.equal(context.__JSKIT_UI_MENU_WORKSPACE_SUFFIX__, "/catalog/products");
|
|
@@ -659,15 +726,21 @@ test("buildUiTemplateContext infers tab placement and relative link-to from the
|
|
|
659
726
|
test("buildUiTemplateContext prefers an outlet-declared default link token and omits fragile relative to output", async () => {
|
|
660
727
|
await withTempApp(async (appRoot) => {
|
|
661
728
|
await writeResource(appRoot, RESOURCE_FILE, FULL_RESOURCE_SOURCE);
|
|
729
|
+
await writePlacementTopology(appRoot, [
|
|
730
|
+
renderTopologyEntry({
|
|
731
|
+
id: "page.section-nav",
|
|
732
|
+
owner: "admin-settings",
|
|
733
|
+
surfaces: ["admin"],
|
|
734
|
+
outlet: "admin-settings:primary-menu",
|
|
735
|
+
linkRenderer: "local.main.ui.surface-aware-menu-link-item"
|
|
736
|
+
})
|
|
737
|
+
]);
|
|
662
738
|
await writeFileInApp(
|
|
663
739
|
appRoot,
|
|
664
740
|
"src/pages/admin/settings.vue",
|
|
665
741
|
`<template>
|
|
666
742
|
<section>
|
|
667
|
-
<ShellOutlet
|
|
668
|
-
target="admin-settings:primary-menu"
|
|
669
|
-
default-link-component-token="local.main.ui.surface-aware-menu-link-item"
|
|
670
|
-
/>
|
|
743
|
+
<ShellOutlet target="admin-settings:primary-menu" />
|
|
671
744
|
<RouterView />
|
|
672
745
|
</section>
|
|
673
746
|
</template>
|
|
@@ -681,8 +754,8 @@ test("buildUiTemplateContext prefers an outlet-declared default link token and o
|
|
|
681
754
|
})
|
|
682
755
|
});
|
|
683
756
|
|
|
684
|
-
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "
|
|
685
|
-
assert.equal(context.
|
|
757
|
+
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "page.section-nav");
|
|
758
|
+
assert.equal(context.__JSKIT_UI_MENU_OWNER_LINE__, " owner: \"admin-settings\",\n");
|
|
686
759
|
assert.equal(context.__JSKIT_UI_MENU_TO_PROP_LINE__, "");
|
|
687
760
|
});
|
|
688
761
|
});
|
|
@@ -694,12 +767,12 @@ test("buildUiTemplateContext honors explicit link-placement override", async ()
|
|
|
694
767
|
const context = await buildUiTemplateContext({
|
|
695
768
|
appRoot,
|
|
696
769
|
options: createOptions({
|
|
697
|
-
"link-placement": "shell
|
|
770
|
+
"link-placement": "shell.secondary-nav"
|
|
698
771
|
})
|
|
699
772
|
});
|
|
700
773
|
|
|
701
|
-
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "shell
|
|
702
|
-
assert.equal(context.
|
|
774
|
+
assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "shell.secondary-nav");
|
|
775
|
+
assert.equal(context.__JSKIT_UI_MENU_OWNER_LINE__, "");
|
|
703
776
|
});
|
|
704
777
|
});
|
|
705
778
|
|