@jskit-ai/crud-ui-generator 0.1.39 → 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.
@@ -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.39",
4
+ version: "0.1.41",
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: {
@@ -168,7 +168,7 @@ export default Object.freeze({
168
168
  mutations: {
169
169
  dependencies: {
170
170
  runtime: {
171
- "@jskit-ai/users-web": "0.1.71"
171
+ "@jskit-ai/users-web": "0.1.73"
172
172
  },
173
173
  dev: {}
174
174
  },
@@ -353,7 +353,7 @@ export default Object.freeze({
353
353
  position: "bottom",
354
354
  skipIfContains: "__JSKIT_UI_MENU_MARKER__",
355
355
  value:
356
- "\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 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",
356
+ "\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",
357
357
  reason: "Append generated CRUD list-page placement.",
358
358
  category: "crud-ui-generator",
359
359
  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.39",
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/crud-core": "0.1.64",
10
- "@jskit-ai/kernel": "0.1.56",
11
- "@jskit-ai/resource-crud-core": "0.1.1"
9
+ "@jskit-ai/crud-core": "0.1.66",
10
+ "@jskit-ai/kernel": "0.1.58",
11
+ "@jskit-ai/resource-crud-core": "0.1.3"
12
12
  },
13
13
  "exports": {
14
14
  "./server/buildTemplateContext": "./src/server/buildTemplateContext.js"
@@ -59,6 +59,7 @@ const DEFAULT_OPERATIONS = normalizeText(descriptor?.options?.operations?.defaul
59
59
  const DEFAULT_LIST_HIDDEN_FIELD_KEYS = new Set(["createdAt", "updatedAt"]);
60
60
  const DEFAULT_FORM_COMPONENT_FILE = "CrudAddEditForm.vue";
61
61
  const DEFAULT_FORM_FIELDS_FILE = "CrudAddEditFormFields.js";
62
+ const DEFAULT_GENERATED_LINK_ICON = "mdi-view-list-outline";
62
63
 
63
64
  function splitTextIntoWords(value = "") {
64
65
  const normalized = String(value || "")
@@ -659,6 +660,7 @@ async function buildUiTemplateContext({ appRoot, options } = {}) {
659
660
  __JSKIT_UI_MENU_PLACEMENT_ID__: String(pageLinkTarget?.pageTarget?.placementId || ""),
660
661
  __JSKIT_UI_MENU_PLACEMENT_TARGET__: String(pageLinkTarget?.placementTarget?.id || ""),
661
662
  __JSKIT_UI_MENU_COMPONENT_TOKEN__: String(pageLinkTarget?.componentToken || ""),
663
+ __JSKIT_UI_MENU_ICON__: DEFAULT_GENERATED_LINK_ICON,
662
664
  __JSKIT_UI_MENU_WORKSPACE_SUFFIX__: String(pageLinkTarget?.pageTarget?.routeUrlSuffix || ""),
663
665
  __JSKIT_UI_MENU_NON_WORKSPACE_SUFFIX__: String(pageLinkTarget?.pageTarget?.routeUrlSuffix || ""),
664
666
  __JSKIT_UI_MENU_WHEN_LINE__: String(pageLinkTarget?.whenLine || ""),
@@ -63,12 +63,6 @@ const UI_VIEW_URL = __JSKIT_UI_EDIT_PAGE_VIEW_URL__;
63
63
  const UI_CANCEL_URL = UI_VIEW_URL || UI_LIST_URL;
64
64
  const UI_RECORD_CHANGED_EVENT = __JSKIT_UI_RECORD_CHANGED_EVENT__;
65
65
  const UI_EDIT_FORM_FIELDS = [];
66
- const UI_EDIT_TRANSPORT = Object.freeze({
67
- kind: "jsonapi-resource",
68
- requestType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
69
- responseType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
70
- responseKind: "record"
71
- });
72
66
 
73
67
  // @jskit-contract crud.ui.form-fields.__JSKIT_UI_RESOURCE_NAMESPACE__.edit.v1
74
68
  void UI_EDIT_FORM_FIELDS;
@@ -105,7 +99,6 @@ const formRuntime = useCrudAddEdit({
105
99
  routeRecordId.value
106
100
  ],
107
101
  placementSource: "ui-generator.__JSKIT_UI_RESOURCE_NAMESPACE__.edit",
108
- transport: UI_EDIT_TRANSPORT,
109
102
  writeMethod: "PATCH",
110
103
  fallbackLoadError: "Unable to load record.",
111
104
  fallbackSaveError: "Unable to save record.",
@@ -26,12 +26,6 @@ const UI_LIST_URL = __JSKIT_UI_EDIT_PAGE_LIST_URL__;
26
26
  const UI_VIEW_URL = __JSKIT_UI_EDIT_PAGE_VIEW_URL__;
27
27
  const UI_CANCEL_URL = UI_VIEW_URL || UI_LIST_URL;
28
28
  const UI_RECORD_CHANGED_EVENT = __JSKIT_UI_RECORD_CHANGED_EVENT__;
29
- const UI_EDIT_TRANSPORT = Object.freeze({
30
- kind: "jsonapi-resource",
31
- requestType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
32
- responseType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
33
- responseKind: "record"
34
- });
35
29
  const route = useRoute();
36
30
 
37
31
  // jskit:crud-ui-fields-target ../_components/__JSKIT_UI_FORM_COMPONENT_FILE__
@@ -64,7 +58,6 @@ const formRuntime = useCrudAddEdit({
64
58
  routeRecordId.value
65
59
  ],
66
60
  placementSource: "ui-generator.__JSKIT_UI_RESOURCE_NAMESPACE__.edit",
67
- transport: UI_EDIT_TRANSPORT,
68
61
  writeMethod: "PATCH",
69
62
  fallbackLoadError: "Unable to load record.",
70
63
  fallbackSaveError: "Unable to save record.",
@@ -101,11 +101,6 @@ const UI_EDIT_URL = __JSKIT_UI_LIST_PAGE_EDIT_URL__;
101
101
  const UI_NEW_URL = __JSKIT_UI_LIST_PAGE_NEW_URL__;
102
102
  const UI_RECORD_CHANGED_EVENTS = __JSKIT_UI_LIST_REALTIME_EVENTS__;
103
103
  const UI_ROUTE_QUERY_BLACKLIST = Object.freeze(["include", "cursor", "limit"]);
104
- const UI_LIST_TRANSPORT = Object.freeze({
105
- kind: "jsonapi-resource",
106
- responseType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
107
- responseKind: "collection"
108
- });
109
104
 
110
105
  const records = useCrudList({
111
106
  adapter: UI_OPERATION_ADAPTER || undefined,
@@ -131,7 +126,6 @@ const records = useCrudList({
131
126
  },
132
127
  placementSource: "ui-generator.__JSKIT_UI_RESOURCE_NAMESPACE__.list",
133
128
  fallbackLoadError: "Unable to load records.",
134
- transport: UI_LIST_TRANSPORT,
135
129
  recordIdParam: UI_RECORD_ID_PARAM,
136
130
  recordIdSelector: (item = {}) => __JSKIT_UI_LIST_RECORD_ID_EXPR__,
137
131
  viewUrlTemplate: UI_VIEW_URL,
@@ -50,12 +50,6 @@ const UI_LIST_URL = __JSKIT_UI_NEW_PAGE_LIST_URL__;
50
50
  const UI_VIEW_URL = __JSKIT_UI_NEW_PAGE_VIEW_URL__;
51
51
  const UI_RECORD_CHANGED_EVENT = __JSKIT_UI_RECORD_CHANGED_EVENT__;
52
52
  const UI_CREATE_FORM_FIELDS = [];
53
- const UI_CREATE_TRANSPORT = Object.freeze({
54
- kind: "jsonapi-resource",
55
- requestType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
56
- responseType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
57
- responseKind: "record"
58
- });
59
53
 
60
54
  // @jskit-contract crud.ui.form-fields.__JSKIT_UI_RESOURCE_NAMESPACE__.new.v1
61
55
  void UI_CREATE_FORM_FIELDS;
@@ -81,7 +75,6 @@ const formRuntime = useCrudAddEdit({
81
75
  ],
82
76
  placementSource: "ui-generator.__JSKIT_UI_RESOURCE_NAMESPACE__.new",
83
77
  readEnabled: false,
84
- transport: UI_CREATE_TRANSPORT,
85
78
  writeMethod: "POST",
86
79
  fallbackSaveError: "Unable to save record.",
87
80
  recordIdParam: UI_RECORD_ID_PARAM,
@@ -23,12 +23,6 @@ const UI_LIST_URL = __JSKIT_UI_NEW_PAGE_LIST_URL__;
23
23
  const UI_VIEW_URL = __JSKIT_UI_NEW_PAGE_VIEW_URL__;
24
24
  const UI_CANCEL_URL = UI_LIST_URL;
25
25
  const UI_RECORD_CHANGED_EVENT = __JSKIT_UI_RECORD_CHANGED_EVENT__;
26
- const UI_CREATE_TRANSPORT = Object.freeze({
27
- kind: "jsonapi-resource",
28
- requestType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
29
- responseType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
30
- responseKind: "record"
31
- });
32
26
 
33
27
  // jskit:crud-ui-fields-target ./_components/__JSKIT_UI_FORM_COMPONENT_FILE__
34
28
  // jskit:crud-ui-form-fields-target ./_components/__JSKIT_UI_FORM_FIELDS_FILE__
@@ -51,7 +45,6 @@ const formRuntime = useCrudAddEdit({
51
45
  ],
52
46
  placementSource: "ui-generator.__JSKIT_UI_RESOURCE_NAMESPACE__.new",
53
47
  readEnabled: false,
54
- transport: UI_CREATE_TRANSPORT,
55
48
  writeMethod: "POST",
56
49
  fallbackSaveError: "Unable to save record.",
57
50
  recordIdParam: UI_RECORD_ID_PARAM,
@@ -57,6 +57,7 @@ __JSKIT_UI_VIEW_COLUMNS__
57
57
 
58
58
  <script setup>
59
59
  import { useCrudView } from "@jskit-ai/users-web/client/composables/useCrudView";
60
+ import { resource as uiResource } from "__JSKIT_UI_RESOURCE_IMPORT_PATH__";
60
61
 
61
62
  const UI_OPERATION_ADAPTER = null;
62
63
  const UI_RECORD_ID_PARAM = "__JSKIT_UI_RECORD_ID_PARAM__";
@@ -66,14 +67,10 @@ const UI_LIST_URL = __JSKIT_UI_VIEW_PAGE_LIST_URL__;
66
67
  const UI_EDIT_URL = __JSKIT_UI_VIEW_PAGE_EDIT_URL__;
67
68
  const UI_VIEW_TITLE_FALLBACK_FIELD_KEY = __JSKIT_UI_VIEW_TITLE_FALLBACK_FIELD_KEY__;
68
69
  const UI_RECORD_CHANGED_EVENT = __JSKIT_UI_RECORD_CHANGED_EVENT__;
69
- const UI_VIEW_TRANSPORT = Object.freeze({
70
- kind: "jsonapi-resource",
71
- responseType: "__JSKIT_UI_RESOURCE_NAMESPACE__",
72
- responseKind: "record"
73
- });
74
70
 
75
71
  const view = useCrudView({
76
72
  adapter: UI_OPERATION_ADAPTER || undefined,
73
+ resource: uiResource,
77
74
  apiUrlTemplate: UI_VIEW_API_URL,
78
75
  recordIdParam: UI_RECORD_ID_PARAM,
79
76
  includeRecordIdInQueryKey: true,
@@ -85,7 +82,6 @@ const view = useCrudView({
85
82
  String(workspaceSlug || "")
86
83
  ],
87
84
  placementSource: "ui-generator.__JSKIT_UI_RESOURCE_NAMESPACE__.view",
88
- transport: UI_VIEW_TRANSPORT,
89
85
  fallbackLoadError: "Unable to load record.",
90
86
  notFoundMessage: "Record not found.",
91
87
  listUrlTemplate: UI_LIST_URL,
@@ -628,7 +628,8 @@ test("buildUiTemplateContext infers tab placement and relative link-to from the
628
628
  });
629
629
 
630
630
  assert.equal(context.__JSKIT_UI_MENU_PLACEMENT_TARGET__, "catalog:sub-pages");
631
- assert.equal(context.__JSKIT_UI_MENU_COMPONENT_TOKEN__, "local.main.ui.tab-link-item");
631
+ assert.equal(context.__JSKIT_UI_MENU_COMPONENT_TOKEN__, "local.main.ui.surface-aware-menu-link-item");
632
+ assert.equal(context.__JSKIT_UI_MENU_ICON__, "mdi-view-list-outline");
632
633
  assert.equal(context.__JSKIT_UI_MENU_TO_PROP_LINE__, " to: \"./products\",\n");
633
634
  assert.equal(context.__JSKIT_UI_MENU_WORKSPACE_SUFFIX__, "/catalog/products");
634
635
  });
@@ -714,7 +715,7 @@ test("buildUiTemplateContext validates operations against the supported CRUD set
714
715
  });
715
716
  });
716
717
 
717
- test("crud ui templates opt into shared JSON:API client transport", async () => {
718
+ test("crud ui templates derive JSON:API transport from the shared CRUD resource", async () => {
718
719
  const testDirectory = path.dirname(fileURLToPath(import.meta.url));
719
720
  const templateRoot = path.resolve(testDirectory, "..", "templates", "src", "pages", "admin", "ui-generator");
720
721
 
@@ -725,25 +726,28 @@ test("crud ui templates opt into shared JSON:API client transport", async () =>
725
726
  const newWrapperTemplateSource = await readFile(path.join(templateRoot, "NewWrapperElement.vue"), "utf8");
726
727
  const editWrapperTemplateSource = await readFile(path.join(templateRoot, "EditWrapperElement.vue"), "utf8");
727
728
 
728
- assert.match(listTemplateSource, /const UI_LIST_TRANSPORT = Object\.freeze\(\{/);
729
- assert.match(listTemplateSource, /responseKind: "collection"/);
730
- assert.match(listTemplateSource, /transport: UI_LIST_TRANSPORT,/);
729
+ assert.match(listTemplateSource, /resource: uiResource,/);
730
+ assert.doesNotMatch(listTemplateSource, /const UI_LIST_TRANSPORT = Object\.freeze\(\{/);
731
+ assert.doesNotMatch(listTemplateSource, /transport:\s*UI_LIST_TRANSPORT,/);
731
732
 
732
- assert.match(viewTemplateSource, /const UI_VIEW_TRANSPORT = Object\.freeze\(\{/);
733
- assert.match(viewTemplateSource, /responseKind: "record"/);
734
- assert.match(viewTemplateSource, /transport: UI_VIEW_TRANSPORT,/);
733
+ assert.match(viewTemplateSource, /import \{ resource as uiResource \} from/);
734
+ assert.match(viewTemplateSource, /resource: uiResource,/);
735
+ assert.doesNotMatch(viewTemplateSource, /const UI_VIEW_TRANSPORT = Object\.freeze\(\{/);
736
+ assert.doesNotMatch(viewTemplateSource, /transport:\s*UI_VIEW_TRANSPORT,/);
735
737
 
736
- assert.match(newTemplateSource, /const UI_CREATE_TRANSPORT = Object\.freeze\(\{/);
737
- assert.match(newTemplateSource, /requestType: "__JSKIT_UI_RESOURCE_NAMESPACE__"/);
738
- assert.match(newTemplateSource, /transport: UI_CREATE_TRANSPORT,/);
738
+ assert.match(newTemplateSource, /resource: uiResource,/);
739
+ assert.doesNotMatch(newTemplateSource, /const UI_CREATE_TRANSPORT = Object\.freeze\(\{/);
740
+ assert.doesNotMatch(newTemplateSource, /transport:\s*UI_CREATE_TRANSPORT,/);
739
741
 
740
- assert.match(editTemplateSource, /const UI_EDIT_TRANSPORT = Object\.freeze\(\{/);
741
- assert.match(editTemplateSource, /requestType: "__JSKIT_UI_RESOURCE_NAMESPACE__"/);
742
- assert.match(editTemplateSource, /transport: UI_EDIT_TRANSPORT,/);
742
+ assert.match(editTemplateSource, /resource: uiResource,/);
743
+ assert.doesNotMatch(editTemplateSource, /const UI_EDIT_TRANSPORT = Object\.freeze\(\{/);
744
+ assert.doesNotMatch(editTemplateSource, /transport:\s*UI_EDIT_TRANSPORT,/);
743
745
 
744
- assert.match(newWrapperTemplateSource, /const UI_CREATE_TRANSPORT = Object\.freeze\(\{/);
745
- assert.match(newWrapperTemplateSource, /transport: UI_CREATE_TRANSPORT,/);
746
+ assert.match(newWrapperTemplateSource, /resource: uiResource,/);
747
+ assert.doesNotMatch(newWrapperTemplateSource, /const UI_CREATE_TRANSPORT = Object\.freeze\(\{/);
748
+ assert.doesNotMatch(newWrapperTemplateSource, /transport:\s*UI_CREATE_TRANSPORT,/);
746
749
 
747
- assert.match(editWrapperTemplateSource, /const UI_EDIT_TRANSPORT = Object\.freeze\(\{/);
748
- assert.match(editWrapperTemplateSource, /transport: UI_EDIT_TRANSPORT,/);
750
+ assert.match(editWrapperTemplateSource, /resource: uiResource,/);
751
+ assert.doesNotMatch(editWrapperTemplateSource, /const UI_EDIT_TRANSPORT = Object\.freeze\(\{/);
752
+ assert.doesNotMatch(editWrapperTemplateSource, /transport:\s*UI_EDIT_TRANSPORT,/);
749
753
  });
@@ -12,3 +12,10 @@ test("crud-ui-generator operations option exposes structured csv-enum metadata",
12
12
  assert.equal(descriptor.options?.operations?.defaultValue, "list,view,new,edit");
13
13
  assert.equal(descriptor.metadata?.generatorSubcommands?.crud?.optionNames?.includes("operations"), true);
14
14
  });
15
+
16
+ test("crud-ui-generator placement scaffold includes an explicit stock icon prop", () => {
17
+ const placementMutation = descriptor?.mutations?.text?.find(
18
+ (entry) => String(entry?.id || "").trim() === "crud-ui-placement-menu"
19
+ );
20
+ assert.match(String(placementMutation?.value || ""), /icon: "__JSKIT_UI_MENU_ICON__"/);
21
+ });