@jskit-ai/ui-generator 0.1.40 → 0.1.41
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 +2 -2
- package/package.json +3 -3
- package/src/server/buildTemplateContext.js +3 -0
- package/src/server/subcommands/page.js +1 -0
- package/src/server/subcommands/pageSupport.js +12 -12
- package/test/addSubpagesSubcommand.test.js +13 -13
- package/test/buildTemplateContext.test.js +8 -5
- package/test/pageSubcommand.test.js +4 -2
package/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/ui-generator",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.41",
|
|
5
5
|
kind: "generator",
|
|
6
6
|
description: "Create non-CRUD pages, reusable UI elements, and subpage hosts.",
|
|
7
7
|
options: {
|
|
@@ -278,7 +278,7 @@ export default Object.freeze({
|
|
|
278
278
|
mutations: {
|
|
279
279
|
dependencies: {
|
|
280
280
|
runtime: {
|
|
281
|
-
"@jskit-ai/users-web": "0.1.
|
|
281
|
+
"@jskit-ai/users-web": "0.1.73"
|
|
282
282
|
},
|
|
283
283
|
dev: {}
|
|
284
284
|
},
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/ui-generator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@jskit-ai/kernel": "0.1.
|
|
10
|
-
"@jskit-ai/shell-web": "0.1.
|
|
9
|
+
"@jskit-ai/kernel": "0.1.58",
|
|
10
|
+
"@jskit-ai/shell-web": "0.1.57"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
13
|
"./server/buildTemplateContext": "./src/server/buildTemplateContext.js"
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
resolvePageTargetDetails
|
|
4
4
|
} from "@jskit-ai/kernel/server/support";
|
|
5
5
|
|
|
6
|
+
const DEFAULT_GENERATED_LINK_ICON = "mdi-view-list-outline";
|
|
7
|
+
|
|
6
8
|
function resolveLinkToPropLine(linkTo = "") {
|
|
7
9
|
if (!linkTo) {
|
|
8
10
|
return "";
|
|
@@ -34,6 +36,7 @@ async function buildUiPageTemplateContext({
|
|
|
34
36
|
__JSKIT_UI_LINK_PLACEMENT_ID__: pageTarget.placementId,
|
|
35
37
|
__JSKIT_UI_LINK_PLACEMENT_TARGET__: String(linkTarget.placementTarget?.id || ""),
|
|
36
38
|
__JSKIT_UI_LINK_COMPONENT_TOKEN__: String(linkTarget.componentToken || ""),
|
|
39
|
+
__JSKIT_UI_LINK_ICON__: DEFAULT_GENERATED_LINK_ICON,
|
|
37
40
|
__JSKIT_UI_LINK_WORKSPACE_SUFFIX__: pageTarget.routeUrlSuffix,
|
|
38
41
|
__JSKIT_UI_LINK_NON_WORKSPACE_SUFFIX__: pageTarget.routeUrlSuffix,
|
|
39
42
|
__JSKIT_UI_LINK_WHEN_LINE__: String(linkTarget.whenLine || ""),
|
|
@@ -31,6 +31,7 @@ function renderPageLinkPlacementBlock({
|
|
|
31
31
|
` componentToken: "${context.__JSKIT_UI_LINK_COMPONENT_TOKEN__}",\n` +
|
|
32
32
|
" props: {\n" +
|
|
33
33
|
` label: "${label}",\n` +
|
|
34
|
+
` icon: "${context.__JSKIT_UI_LINK_ICON__}",\n` +
|
|
34
35
|
` surface: "${surface}",\n` +
|
|
35
36
|
` scopedSuffix: "${context.__JSKIT_UI_LINK_WORKSPACE_SUFFIX__}",\n` +
|
|
36
37
|
` unscopedSuffix: "${context.__JSKIT_UI_LINK_NON_WORKSPACE_SUFFIX__}",\n` +
|
|
@@ -25,15 +25,15 @@ import {
|
|
|
25
25
|
|
|
26
26
|
const DEFAULT_SUBPAGES_POSITION = "sub-pages";
|
|
27
27
|
const SECTION_CONTAINER_SHELL_COMPONENT = "SectionContainerShell";
|
|
28
|
-
const
|
|
28
|
+
const SUBPAGES_LINK_COMPONENT_TOKEN = "local.main.ui.surface-aware-menu-link-item";
|
|
29
29
|
const DEFAULT_MENU_COMPONENT_DIRECTORY = path.join(DEFAULT_COMPONENT_DIRECTORY, "menus");
|
|
30
|
-
const
|
|
30
|
+
const SUBPAGES_LINK_COMPONENT_DEFINITION = findLocalLinkItemDefinition(SUBPAGES_LINK_COMPONENT_TOKEN);
|
|
31
31
|
|
|
32
|
-
if (!
|
|
33
|
-
throw new Error(`ui-generator add-subpages could not resolve ${
|
|
32
|
+
if (!SUBPAGES_LINK_COMPONENT_DEFINITION) {
|
|
33
|
+
throw new Error(`ui-generator add-subpages could not resolve ${SUBPAGES_LINK_COMPONENT_TOKEN} scaffold definition.`);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const
|
|
36
|
+
const SUBPAGES_LINK_COMPONENT = SUBPAGES_LINK_COMPONENT_DEFINITION.componentName;
|
|
37
37
|
|
|
38
38
|
const ROUTE_TAG_PATTERN = /<route\b[^>]*>[\s\S]*?<\/route>\s*/gi;
|
|
39
39
|
const TEMPLATE_TOKEN_PATTERN = /<\/?template\b[^>]*>/gi;
|
|
@@ -145,7 +145,7 @@ async function ensureSubpagesSupportScaffold({
|
|
|
145
145
|
);
|
|
146
146
|
const tabLinkPath = resolvePathWithinApp(
|
|
147
147
|
resolvedAppRoot,
|
|
148
|
-
path.join(normalizedTabLinkComponentDirectory, `${
|
|
148
|
+
path.join(normalizedTabLinkComponentDirectory, `${SUBPAGES_LINK_COMPONENT}.vue`),
|
|
149
149
|
{ context: "ui-generator add-subpages" }
|
|
150
150
|
);
|
|
151
151
|
|
|
@@ -156,7 +156,7 @@ async function ensureSubpagesSupportScaffold({
|
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
const providerRegisterLine = `registerMainClientComponent("${
|
|
159
|
+
const providerRegisterLine = `registerMainClientComponent("${SUBPAGES_LINK_COMPONENT_TOKEN}", () => ${SUBPAGES_LINK_COMPONENT});`;
|
|
160
160
|
const providerHasTabLinkRegistration = providerSource.includes(providerRegisterLine);
|
|
161
161
|
const touchedFiles = new Set();
|
|
162
162
|
const supportFiles = [
|
|
@@ -168,7 +168,7 @@ async function ensureSubpagesSupportScaffold({
|
|
|
168
168
|
if (!providerHasTabLinkRegistration) {
|
|
169
169
|
supportFiles.push({
|
|
170
170
|
path: tabLinkPath,
|
|
171
|
-
desiredSource: await readLocalLinkItemComponentSource(
|
|
171
|
+
desiredSource: await readLocalLinkItemComponentSource(SUBPAGES_LINK_COMPONENT_DEFINITION)
|
|
172
172
|
});
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -191,7 +191,7 @@ async function ensureSubpagesSupportScaffold({
|
|
|
191
191
|
touchedFiles.add(supportFile.path.relativePath);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
const providerImportLine = `import ${
|
|
194
|
+
const providerImportLine = `import ${SUBPAGES_LINK_COMPONENT} from "/${toPosixPath(path.join(normalizedTabLinkComponentDirectory, `${SUBPAGES_LINK_COMPONENT}.vue`))}";`;
|
|
195
195
|
if (providerHasTabLinkRegistration) {
|
|
196
196
|
return Object.freeze({
|
|
197
197
|
touchedFiles: [...touchedFiles].sort((left, right) => left.localeCompare(right)),
|
|
@@ -313,7 +313,7 @@ function renderSubpagesTemplate({
|
|
|
313
313
|
"<template>",
|
|
314
314
|
renderSectionContainerOpenTag({ title, subtitle }),
|
|
315
315
|
" <template #tabs>",
|
|
316
|
-
` <ShellOutlet target="${normalizedTarget}" default-link-component-token="${
|
|
316
|
+
` <ShellOutlet target="${normalizedTarget}" default-link-component-token="${SUBPAGES_LINK_COMPONENT_TOKEN}" />`,
|
|
317
317
|
" </template>"
|
|
318
318
|
];
|
|
319
319
|
|
|
@@ -483,8 +483,8 @@ export {
|
|
|
483
483
|
DEFAULT_SUBPAGES_POSITION,
|
|
484
484
|
DEFAULT_COMPONENT_DIRECTORY,
|
|
485
485
|
SECTION_CONTAINER_SHELL_COMPONENT,
|
|
486
|
-
|
|
487
|
-
|
|
486
|
+
SUBPAGES_LINK_COMPONENT,
|
|
487
|
+
SUBPAGES_LINK_COMPONENT_TOKEN,
|
|
488
488
|
resolvePageTargetDetails,
|
|
489
489
|
resolveNearestParentSubpagesHost,
|
|
490
490
|
deriveDefaultSubpagesHost,
|
|
@@ -97,7 +97,7 @@ test("ui-generator add-subpages derives the default target from an index-route p
|
|
|
97
97
|
|
|
98
98
|
assert.deepEqual(result.touchedFiles, [
|
|
99
99
|
"packages/main/src/client/providers/MainClientProvider.js",
|
|
100
|
-
"src/components/menus/
|
|
100
|
+
"src/components/menus/SurfaceAwareMenuLinkItem.vue",
|
|
101
101
|
"src/components/SectionContainerShell.vue",
|
|
102
102
|
`src/pages/${targetFile}`
|
|
103
103
|
]);
|
|
@@ -105,12 +105,12 @@ test("ui-generator add-subpages derives the default target from an index-route p
|
|
|
105
105
|
const pageSource = await readPageFile(appRoot, targetFile);
|
|
106
106
|
assert.match(
|
|
107
107
|
pageSource,
|
|
108
|
-
/<ShellOutlet target="practice:sub-pages" default-link-component-token="local\.main\.ui\.
|
|
108
|
+
/<ShellOutlet target="practice:sub-pages" default-link-component-token="local\.main\.ui\.surface-aware-menu-link-item" \/>/
|
|
109
109
|
);
|
|
110
110
|
assert.match(pageSource, /<RouterView \/>/);
|
|
111
111
|
assert.equal(
|
|
112
|
-
await readFile(path.join(appRoot, "src", "components", "menus", "
|
|
113
|
-
await readLocalLinkItemComponentSource("local.main.ui.
|
|
112
|
+
await readFile(path.join(appRoot, "src", "components", "menus", "SurfaceAwareMenuLinkItem.vue"), "utf8"),
|
|
113
|
+
await readLocalLinkItemComponentSource("local.main.ui.surface-aware-menu-link-item")
|
|
114
114
|
);
|
|
115
115
|
});
|
|
116
116
|
});
|
|
@@ -132,7 +132,7 @@ test("ui-generator add-subpages derives the default target from a dynamic file-r
|
|
|
132
132
|
const pageSource = await readPageFile(appRoot, targetFile);
|
|
133
133
|
assert.match(
|
|
134
134
|
pageSource,
|
|
135
|
-
/<ShellOutlet target="contacts-contact-id:sub-pages" default-link-component-token="local\.main\.ui\.
|
|
135
|
+
/<ShellOutlet target="contacts-contact-id:sub-pages" default-link-component-token="local\.main\.ui\.surface-aware-menu-link-item" \/>/
|
|
136
136
|
);
|
|
137
137
|
});
|
|
138
138
|
});
|
|
@@ -154,7 +154,7 @@ test("ui-generator add-subpages derives the default target from a nested route p
|
|
|
154
154
|
const pageSource = await readPageFile(appRoot, targetFile);
|
|
155
155
|
assert.match(
|
|
156
156
|
pageSource,
|
|
157
|
-
/<ShellOutlet target="catalog-products:sub-pages" default-link-component-token="local\.main\.ui\.
|
|
157
|
+
/<ShellOutlet target="catalog-products:sub-pages" default-link-component-token="local\.main\.ui\.surface-aware-menu-link-item" \/>/
|
|
158
158
|
);
|
|
159
159
|
});
|
|
160
160
|
});
|
|
@@ -199,7 +199,7 @@ test("ui-generator add-subpages supports explicit target host:position", async (
|
|
|
199
199
|
const pageSource = await readPageFile(appRoot, targetFile);
|
|
200
200
|
assert.match(
|
|
201
201
|
pageSource,
|
|
202
|
-
/<ShellOutlet target="practice-hub:secondary-tabs" default-link-component-token="local\.main\.ui\.
|
|
202
|
+
/<ShellOutlet target="practice-hub:secondary-tabs" default-link-component-token="local\.main\.ui\.surface-aware-menu-link-item" \/>/
|
|
203
203
|
);
|
|
204
204
|
});
|
|
205
205
|
});
|
|
@@ -211,7 +211,7 @@ test("ui-generator add-subpages does not rewrite existing scaffold support compo
|
|
|
211
211
|
const targetFile = "w/[workspaceSlug]/admin/practice/index.vue";
|
|
212
212
|
await writePageFile(appRoot, targetFile);
|
|
213
213
|
const customSectionShellSource = `<template><section class="custom-shell"><slot /></section></template>\n`;
|
|
214
|
-
const
|
|
214
|
+
const customSurfaceAwareLinkSource = `<template><button class="custom-surface-aware-link"><slot /></button></template>\n`;
|
|
215
215
|
await writeFile(
|
|
216
216
|
path.join(appRoot, "src", "components", "SectionContainerShell.vue"),
|
|
217
217
|
customSectionShellSource,
|
|
@@ -219,8 +219,8 @@ test("ui-generator add-subpages does not rewrite existing scaffold support compo
|
|
|
219
219
|
);
|
|
220
220
|
await mkdir(path.join(appRoot, "src", "components", "menus"), { recursive: true });
|
|
221
221
|
await writeFile(
|
|
222
|
-
path.join(appRoot, "src", "components", "menus", "
|
|
223
|
-
|
|
222
|
+
path.join(appRoot, "src", "components", "menus", "SurfaceAwareMenuLinkItem.vue"),
|
|
223
|
+
customSurfaceAwareLinkSource,
|
|
224
224
|
"utf8"
|
|
225
225
|
);
|
|
226
226
|
|
|
@@ -242,8 +242,8 @@ test("ui-generator add-subpages does not rewrite existing scaffold support compo
|
|
|
242
242
|
customSectionShellSource
|
|
243
243
|
);
|
|
244
244
|
assert.equal(
|
|
245
|
-
await readFile(path.join(appRoot, "src", "components", "menus", "
|
|
246
|
-
|
|
245
|
+
await readFile(path.join(appRoot, "src", "components", "menus", "SurfaceAwareMenuLinkItem.vue"), "utf8"),
|
|
246
|
+
customSurfaceAwareLinkSource
|
|
247
247
|
);
|
|
248
248
|
});
|
|
249
249
|
});
|
|
@@ -332,7 +332,7 @@ test("ui-generator add-subpages accepts target files with a src/pages prefix", a
|
|
|
332
332
|
const pageSource = await readFile(path.join(appRoot, targetFile), "utf8");
|
|
333
333
|
assert.match(
|
|
334
334
|
pageSource,
|
|
335
|
-
/<ShellOutlet target="practice:sub-pages" default-link-component-token="local\.main\.ui\.
|
|
335
|
+
/<ShellOutlet target="practice:sub-pages" default-link-component-token="local\.main\.ui\.surface-aware-menu-link-item" \/>/
|
|
336
336
|
);
|
|
337
337
|
assert.match(pageSource, /<RouterView \/>/);
|
|
338
338
|
});
|
|
@@ -250,6 +250,7 @@ test("buildUiPageTemplateContext supports explicit link component token and link
|
|
|
250
250
|
}
|
|
251
251
|
});
|
|
252
252
|
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.tab-link-item");
|
|
253
|
+
assert.equal(context.__JSKIT_UI_LINK_ICON__, "mdi-view-list-outline");
|
|
253
254
|
assert.equal(context.__JSKIT_UI_LINK_WORKSPACE_SUFFIX__, "/contacts/[contactId]/notes");
|
|
254
255
|
assert.equal(context.__JSKIT_UI_LINK_NON_WORKSPACE_SUFFIX__, "/contacts/[contactId]/notes");
|
|
255
256
|
assert.equal(context.__JSKIT_UI_LINK_TO_PROP_LINE__, " to: \"./notes\",\n");
|
|
@@ -314,7 +315,8 @@ test("buildUiPageTemplateContext infers subpage link placement, tab token, and l
|
|
|
314
315
|
});
|
|
315
316
|
|
|
316
317
|
assert.equal(context.__JSKIT_UI_LINK_PLACEMENT_TARGET__, "contact-view:sub-pages");
|
|
317
|
-
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.
|
|
318
|
+
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
|
|
319
|
+
assert.equal(context.__JSKIT_UI_LINK_ICON__, "mdi-view-list-outline");
|
|
318
320
|
assert.equal(context.__JSKIT_UI_LINK_TO_PROP_LINE__, " to: \"./notes\",\n");
|
|
319
321
|
});
|
|
320
322
|
});
|
|
@@ -352,7 +354,7 @@ test("buildUiPageTemplateContext inherits a file-route parent host for deeper de
|
|
|
352
354
|
});
|
|
353
355
|
|
|
354
356
|
assert.equal(context.__JSKIT_UI_LINK_PLACEMENT_TARGET__, "contact-view:sub-pages");
|
|
355
|
-
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.
|
|
357
|
+
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
|
|
356
358
|
assert.equal(context.__JSKIT_UI_LINK_TO_PROP_LINE__, " to: \"./notes/history\",\n");
|
|
357
359
|
});
|
|
358
360
|
});
|
|
@@ -390,7 +392,8 @@ test("buildUiPageTemplateContext infers subpage link placement from an index-rou
|
|
|
390
392
|
});
|
|
391
393
|
|
|
392
394
|
assert.equal(context.__JSKIT_UI_LINK_PLACEMENT_TARGET__, "catalog:sub-pages");
|
|
393
|
-
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.
|
|
395
|
+
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
|
|
396
|
+
assert.equal(context.__JSKIT_UI_LINK_ICON__, "mdi-view-list-outline");
|
|
394
397
|
assert.equal(context.__JSKIT_UI_LINK_TO_PROP_LINE__, " to: \"./products\",\n");
|
|
395
398
|
});
|
|
396
399
|
});
|
|
@@ -441,7 +444,7 @@ test("buildUiPageTemplateContext finds the nearest index-route parent host", asy
|
|
|
441
444
|
});
|
|
442
445
|
|
|
443
446
|
assert.equal(context.__JSKIT_UI_LINK_PLACEMENT_TARGET__, "catalog-products:sub-pages");
|
|
444
|
-
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.
|
|
447
|
+
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
|
|
445
448
|
assert.equal(context.__JSKIT_UI_LINK_TO_PROP_LINE__, " to: \"./variants\",\n");
|
|
446
449
|
});
|
|
447
450
|
});
|
|
@@ -479,7 +482,7 @@ test("buildUiPageTemplateContext infers subpage link placement from an index rou
|
|
|
479
482
|
});
|
|
480
483
|
|
|
481
484
|
assert.equal(context.__JSKIT_UI_LINK_PLACEMENT_TARGET__, "customer-view:sub-pages");
|
|
482
|
-
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.
|
|
485
|
+
assert.equal(context.__JSKIT_UI_LINK_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
|
|
483
486
|
assert.equal(context.__JSKIT_UI_LINK_TO_PROP_LINE__, " to: \"./pets\",\n");
|
|
484
487
|
assert.equal(context.__JSKIT_UI_LINK_WORKSPACE_SUFFIX__, "/customers/[customerId]/pets");
|
|
485
488
|
});
|
|
@@ -162,6 +162,7 @@ test("ui-generator page subcommand supports link placement options", async () =>
|
|
|
162
162
|
const placementSource = await readFile(path.join(appRoot, "src", "placement.js"), "utf8");
|
|
163
163
|
assert.match(placementSource, /target: "shell-layout:top-right"/);
|
|
164
164
|
assert.match(placementSource, /componentToken: "local\.main\.ui\.tab-link-item"/);
|
|
165
|
+
assert.match(placementSource, /icon: "mdi-view-list-outline"/);
|
|
165
166
|
assert.match(placementSource, /to: "\.\/notes"/);
|
|
166
167
|
});
|
|
167
168
|
});
|
|
@@ -196,7 +197,8 @@ test("ui-generator page subcommand infers subpage link placement, tab token, and
|
|
|
196
197
|
|
|
197
198
|
const placementSource = await readFile(path.join(appRoot, "src", "placement.js"), "utf8");
|
|
198
199
|
assert.match(placementSource, /target: "contact-view:sub-pages"/);
|
|
199
|
-
assert.match(placementSource, /componentToken: "local\.main\.ui\.
|
|
200
|
+
assert.match(placementSource, /componentToken: "local\.main\.ui\.surface-aware-menu-link-item"/);
|
|
201
|
+
assert.match(placementSource, /icon: "mdi-view-list-outline"/);
|
|
200
202
|
assert.match(placementSource, /to: "\.\/notes"/);
|
|
201
203
|
});
|
|
202
204
|
});
|
|
@@ -246,7 +248,7 @@ test("ui-generator page subcommand prefers the nearest index-route parent host",
|
|
|
246
248
|
|
|
247
249
|
const placementSource = await readFile(path.join(appRoot, "src", "placement.js"), "utf8");
|
|
248
250
|
assert.match(placementSource, /target: "catalog-products:sub-pages"/);
|
|
249
|
-
assert.match(placementSource, /componentToken: "local\.main\.ui\.
|
|
251
|
+
assert.match(placementSource, /componentToken: "local\.main\.ui\.surface-aware-menu-link-item"/);
|
|
250
252
|
assert.match(placementSource, /to: "\.\/variants"/);
|
|
251
253
|
});
|
|
252
254
|
});
|