@jskit-ai/crud-ui-generator 0.1.48 → 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.
@@ -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.48",
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: host:position)."
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.80"
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 componentToken: \"__JSKIT_UI_MENU_COMPONENT_TOKEN__\",\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",
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.48",
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.73",
10
- "@jskit-ai/kernel": "0.1.65",
11
- "@jskit-ai/resource-crud-core": "0.1.10"
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
- __JSKIT_UI_MENU_COMPONENT_TOKEN__: String(pageLinkTarget?.componentToken || ""),
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-layout:primary-menu");
618
- assert.equal(context.__JSKIT_UI_MENU_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
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__, "catalog:sub-pages");
652
- assert.equal(context.__JSKIT_UI_MENU_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
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__, "admin-settings:primary-menu");
685
- assert.equal(context.__JSKIT_UI_MENU_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
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-layout:secondary-menu"
770
+ "link-placement": "shell.secondary-nav"
698
771
  })
699
772
  });
700
773
 
701
- assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "shell-layout:secondary-menu");
702
- assert.equal(context.__JSKIT_UI_MENU_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
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