@abgov/nx-adsp 13.31.0 → 13.31.1

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.
Files changed (68) hide show
  1. package/README.md +41 -32
  2. package/package.json +1 -1
  3. package/src/generators/angular-app/angular-app.js +2 -2
  4. package/src/generators/angular-app/files/AGENTS.md__tmpl__ +16 -0
  5. package/src/generators/express-service/express-service.spec.ts +26 -13
  6. package/src/generators/express-service/schema.json +1 -1
  7. package/src/generators/react-app/files/AGENTS.md__tmpl__ +16 -0
  8. package/src/generators/react-app/react-app.js +2 -2
  9. package/src/generators/vue-admin-crud/files/src/views/__editViewFileName__.vue__tmpl__ +1 -3
  10. package/src/generators/vue-admin-crud/files/src/views/__listViewFileName__.vue__tmpl__ +33 -4
  11. package/src/generators/vue-admin-crud/schema.d.ts +2 -0
  12. package/src/generators/vue-admin-crud/schema.json +7 -8
  13. package/src/generators/vue-admin-crud/vue-admin-crud.js +6 -1
  14. package/src/generators/vue-admin-crud/vue-admin-crud.js.map +1 -1
  15. package/src/generators/vue-admin-crud/vue-admin-crud.spec.ts +74 -13
  16. package/src/generators/vue-app/files/AGENTS.md__tmpl__ +56 -11
  17. package/src/generators/vue-app/files/src/App.vue__tmpl__ +2 -1
  18. package/src/generators/vue-app/files/src/composables/useApi.spec.ts__tmpl__ +5 -3
  19. package/src/generators/vue-app/files/src/composables/useApi.ts__tmpl__ +14 -2
  20. package/src/generators/vue-app/vue-app.js +33 -6
  21. package/src/generators/vue-app/vue-app.js.map +1 -1
  22. package/src/generators/vue-app/vue-app.spec.ts +133 -13
  23. package/src/generators/vue-components/files/AGENTS.md__tmpl__ +35 -16
  24. package/src/generators/vue-components/files/src/index.ts__tmpl__ +3 -0
  25. package/src/generators/vue-components/files/src/lib/formatters.ts__tmpl__ +58 -0
  26. package/src/generators/vue-components/files/src/lib/patterns/AppSideMenu.vue__tmpl__ +14 -3
  27. package/src/generators/vue-components/files/src/lib/patterns/FilterBar.vue__tmpl__ +7 -1
  28. package/src/generators/vue-components/files/src/lib/patterns/WorkspaceTable.vue__tmpl__ +7 -1
  29. package/src/generators/vue-components/vue-components.d.ts +1 -0
  30. package/src/generators/vue-components/vue-components.js +18 -39
  31. package/src/generators/vue-components/vue-components.js.map +1 -1
  32. package/src/generators/vue-components/vue-components.spec.ts +94 -2
  33. package/src/generators/vue-detail-view/files/src/views/__viewFileName__.vue__tmpl__ +51 -2
  34. package/src/generators/vue-detail-view/schema.d.ts +18 -0
  35. package/src/generators/vue-detail-view/schema.json +2 -2
  36. package/src/generators/vue-detail-view/vue-detail-view.js +4 -1
  37. package/src/generators/vue-detail-view/vue-detail-view.js.map +1 -1
  38. package/src/generators/vue-detail-view/vue-detail-view.spec.ts +36 -6
  39. package/src/generators/vue-intake-view/files/shared/src/views/__confirmationViewFileName__.vue__tmpl__ +60 -6
  40. package/src/generators/vue-intake-view/files/shared/src/views/__reviewViewFileName__.vue__tmpl__ +21 -0
  41. package/src/generators/vue-intake-view/schema.d.ts +10 -0
  42. package/src/generators/vue-intake-view/schema.json +12 -9
  43. package/src/generators/vue-intake-view/vue-intake-view.js +9 -3
  44. package/src/generators/vue-intake-view/vue-intake-view.js.map +1 -1
  45. package/src/generators/vue-intake-view/vue-intake-view.spec.ts +81 -12
  46. package/src/generators/vue-workspace-view/files/src/views/__viewFileName__.vue__tmpl__ +49 -1
  47. package/src/generators/vue-workspace-view/schema.d.ts +22 -0
  48. package/src/generators/vue-workspace-view/schema.json +8 -9
  49. package/src/generators/vue-workspace-view/vue-workspace-view.js +7 -1
  50. package/src/generators/vue-workspace-view/vue-workspace-view.js.map +1 -1
  51. package/src/generators/vue-workspace-view/vue-workspace-view.spec.ts +73 -7
  52. package/src/utils/paired-project.d.ts +10 -0
  53. package/src/utils/paired-project.js +125 -18
  54. package/src/utils/paired-project.js.map +1 -1
  55. package/src/utils/paired-project.spec.ts +126 -0
  56. package/src/utils/quality.js +43 -9
  57. package/src/utils/quality.js.map +1 -1
  58. package/src/utils/quality.spec.ts +35 -2
  59. package/src/utils/vue-eslint.d.ts +2 -0
  60. package/src/utils/vue-eslint.js +48 -0
  61. package/src/utils/vue-eslint.js.map +1 -0
  62. package/src/utils/vue-side-menu.d.ts +13 -1
  63. package/src/utils/vue-side-menu.js +50 -5
  64. package/src/utils/vue-side-menu.js.map +1 -1
  65. package/src/utils/vue-side-menu.spec.ts +100 -0
  66. package/src/utils/vue-tsconfig.d.ts +26 -0
  67. package/src/utils/vue-tsconfig.js +49 -0
  68. package/src/utils/vue-tsconfig.js.map +1 -0
@@ -7,7 +7,7 @@ Generated by `nx g @abgov/nx-adsp:vue-app`.
7
7
 
8
8
  This app is paired with **`<%= pairedProject %>`** — the Express backend it talks to.
9
9
  API calls use the `/api/` prefix which the Vite dev proxy rewrites to `/<%= pairedProject %>/` on port 3333.
10
- When working on a feature that spans both projects, read `apps/<%= pairedProject %>/AGENTS.md` for the service context.
10
+ When working on a feature that spans both projects, read `<%= pairedProjectRoot %>/AGENTS.md` for the service context.
11
11
  <% } %>
12
12
  ## Running Nx commands (coding agents)
13
13
 
@@ -157,9 +157,9 @@ Extra props/events fall through to the underlying `goa-*` element, so anything
157
157
  the design system supports still works. For components without a wrapper, use the
158
158
  `goa-*` element directly with the manual wiring above. The library is shared
159
159
  across every Vue app in this workspace — fix or extend a wrapper once in
160
- `libs/vue-components` (or run `nx g @abgov/nx-adsp:vue-components` to restore it).
160
+ `<%= goaLibRoot %>` (or run `nx g @abgov/nx-adsp:vue-components` to restore it).
161
161
 
162
- > **Interim:** these wrappers (`libs/vue-components/src/lib/primitives/`) are a
162
+ > **Interim:** these wrappers (`<%= goaLibRoot %>/src/lib/primitives/`) are a
163
163
  > stopgap until GoA DS ships an official `@abgov/vue-components`. When it lands,
164
164
  > delete `primitives/` and repoint imports at that package — the names/props are
165
165
  > intended to match, so it's a scope swap. This does **not** apply to the
@@ -176,7 +176,7 @@ from **`<%= goaImportPath %>`**, not hand-rolled markup:
176
176
 
177
177
  | Component | Purpose |
178
178
  |---|---|
179
- | `AppSideMenu` | `goa-work-side-menu`. Takes `heading`/`primaryItems`/`secondaryItems`/`accountItems` props (each item: `{ label, to?, icon?, badge?, current? }`) and emits `itemClick` — it doesn't know about routing or auth, so `App.vue` computes `current`/handles the click itself. `App.vue` currently only populates `accountItems` (a single Sign in/out item); add real nav items to `primaryItems`/`secondaryItems` as routes are added. **`icon` is effectively required** — `goa-work-side-menu-item` renders a blank item without it; use a GoA icon name (see [design.alberta.ca/components/icons](https://design.alberta.ca/components/icons)). Also owns the skip-to-main-content landmark for this layout — `AppLayout` deliberately doesn't duplicate it. Also takes an optional `#topbar` slot — a slim row above the routed content, for something like a notification bell; only renders when given content, unused by default |
179
+ | `AppSideMenu` | `goa-work-side-menu`. Takes `heading`/`primaryItems`/`secondaryItems`/`accountItems` props (each item: `{ label, to?, icon?, badge?, current? }`) and emits `itemClick` — it doesn't know about routing or auth, so `App.vue` computes `current`/handles the click itself. `App.vue` seeds `primaryItems` with Home and an `accountItems` Sign in/out item; the `vue-*-view` generators append their own entries, and you can add more by hand. **`icon` is effectively required** — `goa-work-side-menu-item` renders a blank item without it; use a GoA icon name (see [design.alberta.ca/components/icons](https://design.alberta.ca/components/icons)). Also owns the skip-to-main-content landmark for this layout — `AppLayout` deliberately doesn't duplicate it. Also takes an optional `#topbar` slot — a slim row above the routed content, for something like a notification bell; only renders when given content, unused by default |
180
180
  | `AppLayout` | The content gutter every view renders inside (see the key files table) |
181
181
  | `SessionExpiredBanner` | A `v-model:show` banner with `signIn`/`dismiss` emits. Bound to the `useSessionStore()` Pinia store (`src/stores/session.ts`), which `main.ts`'s `onAuthRefreshError` hook flips when the refresh token itself has expired |
182
182
 
@@ -195,7 +195,7 @@ marketing chrome around a staff tool).
195
195
  | `SessionExpiredBanner` | A `v-model:show` banner with `signIn`/`dismiss` emits. Bound to the `useSessionStore()` Pinia store (`src/stores/session.ts`), which `main.ts`'s `onAuthRefreshError` hook flips when the refresh token itself has expired |
196
196
  <% } %>
197
197
  These are shared across every Vue app in this workspace — fix or extend one once
198
- in `libs/vue-components/src/lib/patterns/`, the same way as the `Goab*` wrappers.
198
+ in `<%= goaLibRoot %>/src/lib/patterns/`, the same way as the `Goab*` wrappers.
199
199
 
200
200
  A second, **`--layout=<%= layout === 'internal' ? 'header' : 'internal' %>`** frontend
201
201
  can be scaffolded against the same backend with `nx g @abgov/nx-adsp:vue-app <name>
@@ -222,6 +222,22 @@ generator's own schema description for why). Only hand-author a view when none o
222
222
  match, or once a generator's output needs customization it doesn't cover — its own comments
223
223
  mark what's meant to be edited.
224
224
 
225
+ ### Options that decide what a person sees
226
+
227
+ These are easy to omit and the result looks plausible until someone reads the screen, so
228
+ they are worth getting right on the first run:
229
+
230
+ | Pass | On | Or else |
231
+ |---|---|---|
232
+ | `options: [{ value, label }]` on a field/column | any generator, for any value stored as a code | the view renders the raw code — `northwest`, `cattle-mature` — including on the check-your-answers page, whose whole purpose is that the person can read back what they entered |
233
+ | `badgeMap: { approved: 'success', declined: 'emergency' }` | a `badge` column/field | every status renders the same neutral blue, so a declined claim reads as routine |
234
+ | `--referenceField=<key>` | `vue-intake-view` | the confirmation page falls back to the route id, presenting a storage id as "your reference number" (defaults to `reference`) |
235
+ | `--icon=<name>` | `vue-workspace-view`, `vue-admin-crud` | defaults (`list`, `settings`) are used; pick one that suits the screen |
236
+
237
+ The lookup itself is shared — `optionLabel` and `badgeType` in `<%= goaLibRoot %>/src/lib/formatters.ts`
238
+ — so a hand-authored view should use them too rather than re-deriving a mapping. See that
239
+ lib's own AGENTS.md for the full component catalog.
240
+
225
241
  1. Create `src/views/MyFeatureView.vue` as a `<script setup>` SFC. **Don't add your
226
242
  own page margins/centering** — every view renders inside `AppLayout`'s gutter, so
227
243
  any top-level tag (`<div>`, `<section>`, …) is already centered and padded.
@@ -247,15 +263,17 @@ mark what's meant to be edited.
247
263
  ```typescript
248
264
  const primaryItems = [
249
265
  { label: 'Home', to: '/', icon: 'home' },
250
- { label: 'Review queue', to: '/queue' }, // added by vue-workspace-view
266
+ { label: 'Review queue', to: '/queue', icon: 'list' }, // added by vue-workspace-view
251
267
  ];
252
268
  ```
253
269
 
254
- Two things worth adding by hand: **`icon`** is effectively required —
255
- `goa-work-side-menu-item` renders a blank item without one, and the generators can't guess it
256
- (icon names: [design.alberta.ca/components/icons](https://design.alberta.ca/components/icons)).
257
- And **`current`** for active highlighting, e.g. `current: route.path.startsWith('/queue')`,
258
- which needs the `route` already in scope.
270
+ **`icon`** is effectively required — `goa-work-side-menu-item` renders a blank item without
271
+ one so the generators supply it: `vue-workspace-view` defaults to `list` and
272
+ `vue-admin-crud` to `settings`. Pass `--icon=<name>` to choose a better one for the screen
273
+ (names: [design.alberta.ca/components/icons](https://design.alberta.ca/components/icons)).
274
+
275
+ Still worth adding by hand: **`current`** for active highlighting, e.g.
276
+ `current: route.path.startsWith('/queue')`, which needs the `route` already in scope.
259
277
 
260
278
  The `header` layout has no side menu, so it has no `primaryItems` array and the generators
261
279
  skip the step silently — use route-level breadcrumbs or a nav inside the view instead.
@@ -304,6 +322,17 @@ await save('my-resource', id, payload) // an id = update
304
322
  await action('my-resource', id, 'submit') // POST /:id/submit
305
323
  ```
306
324
 
325
+ These build their URL through `apiConvention.path()`, which resolves to
326
+ `/api/v1/<resource>`. `/api/` is the dev-proxy and nginx location; `v1` is the version the
327
+ paired `express-service` mounts its routers under (`/<service>/v1`), and the proxy rewrites
328
+ `/api/` to `/<service>/`. If your API is versioned differently — or not at all — change
329
+ `apiConvention` and nothing else: the views only ever call through that seam, so no view
330
+ needs editing.
331
+
332
+ In dev the rewrite lives in `vite.proxy.cjs`. That file is a CommonJS module rather than
333
+ JSON on purpose: Vite rewrites a proxied path with a `rewrite` function, and a JSON config
334
+ cannot hold a function. Add a route by appending a row to its `routes` array.
335
+
307
336
  Every wire-level detail these hide — the base path, whether paging is `page`/`limit` or
308
337
  `limit`/`offset`, whether rows arrive bare or under `results`/`entries`, whether an update is PUT
309
338
  or PATCH — lives in the **API convention adapter** at the top of
@@ -373,6 +402,22 @@ describe('MyComponent', () => {
373
402
  });
374
403
  ```
375
404
 
405
+ ### Accessibility check — expand its route list
406
+
407
+ The generated e2e project ships `src/a11y.spec.ts`: an axe-core check scoped to WCAG 2.1
408
+ A/AA, run as part of the normal `e2e` target. **It only covers the routes named in its own
409
+ `ROUTES` array, which ships as `['/']`.**
410
+
411
+ Add an entry whenever you add a route — whether a generator added it or you hand-edited the
412
+ router. Nothing does this for you: no generator writes to that file (it is left alone once it
413
+ exists so your edits survive), so a router that has grown past `/` while `ROUTES` has not is
414
+ a check that has quietly stopped covering the app. `/` is mostly app shell, so it exercises
415
+ almost none of the elements the rest of the app is built from.
416
+
417
+ Expect real failures when you expand it, and triage before fixing: some violations originate
418
+ inside `@abgov/web-components`' own shadow DOM and cannot be addressed from app code. Those
419
+ need an upstream fix or a documented exclusion, not a workaround in your view.
420
+
376
421
  ## OpenShift targets
377
422
 
378
423
  ```bash
@@ -37,7 +37,7 @@ function signInAgain() {
37
37
  // prune -- a generated app is a starting point, not a fixed shell. Items are
38
38
  // `{ label, to }`; add `icon` for a leading icon or `badge` for a count.
39
39
  const primaryItems = [
40
- { label: 'Home', to: '/' },
40
+ { label: 'Home', to: '/', icon: 'home' },
41
41
  ];
42
42
 
43
43
  // AppSideMenu's items are presentational — it doesn't know about Keycloak or
@@ -64,6 +64,7 @@ function onItemClick(item: { to?: string }) {
64
64
  <% if (layout === 'internal') { %>
65
65
  <AppSideMenu
66
66
  heading="<%= projectName %>"
67
+ :user-name="kc.fullName"
67
68
  :primary-items="primaryItems"
68
69
  :account-items="accountItems"
69
70
  @item-click="onItemClick"
@@ -7,9 +7,11 @@ import { apiConvention } from './useApi'
7
7
  // it -- a failure here means a generated view's assumptions moved.
8
8
  describe('apiConvention', () => {
9
9
  it('builds collection, record, and action paths', () => {
10
- expect(apiConvention.path('widgets')).toBe('/api/widgets')
11
- expect(apiConvention.path('widgets', 7)).toBe('/api/widgets/7')
12
- expect(apiConvention.path('widgets', 7, 'submit')).toBe('/api/widgets/7/submit')
10
+ expect(apiConvention.path('widgets')).toBe('/api/v1/widgets')
11
+ expect(apiConvention.path('widgets', 7)).toBe('/api/v1/widgets/7')
12
+ expect(apiConvention.path('widgets', 7, 'submit')).toBe(
13
+ '/api/v1/widgets/7/submit',
14
+ )
13
15
  })
14
16
 
15
17
  it('maps a domain page/pageSize onto this API page/limit parameters', () => {
@@ -32,9 +32,21 @@ export interface ListResult<T = Record<string, unknown>> {
32
32
  }
33
33
 
34
34
  export const apiConvention = {
35
- /** Path to a collection, one record, or a named action on a record. */
35
+ /**
36
+ * Path to a collection, one record, or a named action on a record.
37
+ *
38
+ * `/api/` is the dev-proxy and nginx location; `v1` is the API version the
39
+ * paired express-service mounts its routers under (`/<service>/v1`), and the
40
+ * proxy rewrites `/api/` to `/<service>/`. Dropping the version segment here
41
+ * (an earlier version of this file did) makes every list/get/save 404 against
42
+ * a generated backend, while HomeView and AGENTS.md -- which spell out
43
+ * `/api/v1/...` by hand -- keep working, so the mismatch is easy to miss.
44
+ *
45
+ * This is the one place to change if your API is versioned differently, or not
46
+ * at all: the views only ever call through this seam.
47
+ */
36
48
  path(resource: string, id?: string | number, action?: string): string {
37
- const base = `/api/${resource}`
49
+ const base = `/api/v1/${resource}`
38
50
  if (id === undefined || id === null) return base
39
51
  return action ? `${base}/${id}/${action}` : `${base}/${id}`
40
52
  },
@@ -12,6 +12,8 @@ const devkit_1 = require("@nx/devkit");
12
12
  const path = require("path");
13
13
  const paired_project_1 = require("../../utils/paired-project");
14
14
  const nginx_1 = require("../../utils/nginx");
15
+ const vue_eslint_1 = require("../../utils/vue-eslint");
16
+ const vue_tsconfig_1 = require("../../utils/vue-tsconfig");
15
17
  const vue_components_1 = require("../vue-components/vue-components");
16
18
  function normalizeOptions(host, options) {
17
19
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
@@ -45,12 +47,23 @@ function addFiles(host, options) {
45
47
  var _a;
46
48
  const templateOptions = Object.assign(Object.assign(Object.assign({}, options), options.adsp), { offsetFromRoot: (0, devkit_1.offsetFromRoot)(options.projectRoot), pairedProject: (_a = options.pairedProject) !== null && _a !== void 0 ? _a : null,
47
49
  // Import specifier for the shared GoA wrapper lib (AGENTS.md references it).
48
- goaImportPath: (0, vue_components_1.vueComponentsImportPath)(host), tmpl: '' });
50
+ goaImportPath: (0, vue_components_1.vueComponentsImportPath)(host),
51
+ // Real workspace-relative roots, so AGENTS.md can point at files that exist.
52
+ // Hardcoding `libs/`/`apps/` made every path in the generated guidance wrong
53
+ // in a TS-solution workspace, where projects sit at the workspace root.
54
+ goaLibRoot: (0, vue_components_1.vueComponentsLibRoot)(host), pairedProjectRoot: options.pairedProject
55
+ ? (0, devkit_1.readProjectConfiguration)(host, options.pairedProject).root
56
+ : null, tmpl: '' });
49
57
  (0, devkit_1.generateFiles)(host, path.join(__dirname, 'files'), options.projectRoot, templateOptions);
50
- host.write(`${options.projectRoot}/public/nginx.conf`, (0, nginx_1.generateNginxConf)({ proxyLocations: options.nginxProxies, silentCheckSso: true }));
58
+ host.write(`${options.projectRoot}/public/nginx.conf`, (0, nginx_1.generateNginxConf)({
59
+ proxyLocations: options.nginxProxies,
60
+ silentCheckSso: true,
61
+ }));
51
62
  const addProxyConf = options.nginxProxies.length > 0;
52
63
  if (addProxyConf) {
53
- (0, devkit_1.writeJson)(host, `${options.projectRoot}/vite.proxy.json`, (0, paired_project_1.buildDevProxyConf)(options.nginxProxies));
64
+ // A .cjs module, not JSON: Vite rewrites a proxied path with a `rewrite`
65
+ // function and silently ignores the `pathRewrite` key JSON would carry.
66
+ host.write(`${options.projectRoot}/${paired_project_1.VITE_PROXY_FILENAME}`, (0, paired_project_1.buildViteDevProxyModule)((0, paired_project_1.viteDevProxyRoutes)(options.nginxProxies)));
54
67
  }
55
68
  return addProxyConf;
56
69
  }
@@ -85,9 +98,19 @@ function default_1(host, options) {
85
98
  // real current alternative — and GoA's own design-system docs don't list Vue
86
99
  // as a supported framework at all.
87
100
  yield (0, vue_components_1.default)(host);
101
+ // The shell projects into goa-one-column-layout's native `header`/`footer`
102
+ // slots, and app authors composing goa-* elements need the same attribute
103
+ // (goa-modal's `actions`, goa-app-header's `utilities`). Applied to both
104
+ // layouts, not just the one whose template emits it today -- scoping this to
105
+ // the single known call site is what let `nx lint` start failing on
106
+ // unmodified output when the shell adopted goa-one-column-layout.
107
+ (0, vue_eslint_1.disableSlotAttributeRule)(host, normalizedOptions.projectRoot, "The app shell projects into goa-one-column-layout's native `slot`");
108
+ // @nx/vue can leave the app's tsconfig with a bundler moduleResolution and no
109
+ // `module`, which is invalid against a TS-solution base -- see the util.
110
+ (0, vue_tsconfig_1.ensureBundlerModuleOption)(host, `${normalizedOptions.projectRoot}/tsconfig.json`);
88
111
  (0, devkit_1.addDependenciesToPackageJson)(host, {
89
- '@abgov/design-tokens': '2.12.0',
90
- '@abgov/web-components': '2.3.0',
112
+ '@abgov/design-tokens': '2.12.8',
113
+ '@abgov/web-components': '2.4.0',
91
114
  // keycloak-js is a transitive dependency of @dsb-norge/vue-keycloak-js;
92
115
  // don't pin it directly or the versions diverge into two copies.
93
116
  '@dsb-norge/vue-keycloak-js': '^3.0.0',
@@ -115,6 +138,10 @@ function default_1(host, options) {
115
138
  'src/components/AppLayout.vue',
116
139
  'src/views/AboutView.vue',
117
140
  'vite.config.mts',
141
+ // Superseded by vite.proxy.cjs. The JSON form could not express Vite's
142
+ // `rewrite` function, so it was inert -- leaving it would strand a file
143
+ // that looks like live proxy config but isn't referenced.
144
+ 'vite.proxy.json',
118
145
  ]) {
119
146
  if (host.exists(`${normalizedOptions.projectRoot}/${f}`)) {
120
147
  host.delete(`${normalizedOptions.projectRoot}/${f}`);
@@ -129,7 +156,7 @@ function default_1(host, options) {
129
156
  const config = (0, devkit_1.readProjectConfiguration)(host, options.name);
130
157
  // Wire the vite dev-server proxy when nginx proxy locations are configured.
131
158
  if (addedProxy && ((_a = config.targets.serve) === null || _a === void 0 ? void 0 : _a.options)) {
132
- config.targets.serve.options = Object.assign(Object.assign({}, config.targets.serve.options), { proxyConfig: `${normalizedOptions.projectRoot}/vite.proxy.json` });
159
+ config.targets.serve.options = Object.assign(Object.assign({}, config.targets.serve.options), { proxyConfig: `${normalizedOptions.projectRoot}/${paired_project_1.VITE_PROXY_FILENAME}` });
133
160
  }
134
161
  // nginx.conf lives in the Vite publicDir
135
162
  // (<projectRoot>/public) so it's emitted to the build output root — the
@@ -1 +1 @@
1
- {"version":3,"file":"vue-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/vue-app/vue-app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vue-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/vue-app/vue-app.ts"],"names":[],"mappings":"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"}
@@ -232,7 +232,9 @@ describe('Vue App Generator', () => {
232
232
  // nav order, grouping and labels are the owning team's decisions.
233
233
  expect(app).toContain(':primary-items="primaryItems"');
234
234
  expect(app).toContain('const primaryItems = [');
235
- expect(app).toContain("{ label: 'Home', to: '/' },");
235
+ // The icon is not decoration: goa-work-side-menu-item renders a blank
236
+ // item without one.
237
+ expect(app).toContain("{ label: 'Home', to: '/', icon: 'home' },");
236
238
  expect(app).toContain('@item-click="onItemClick"');
237
239
  // The content gutter is shared regardless of shell choice.
238
240
  expect(app).toContain('<AppLayout');
@@ -327,7 +329,12 @@ describe('Vue App Generator', () => {
327
329
  // response-envelope keys get inlined into every generated view.
328
330
  expect(useApi).toContain('apiConvention');
329
331
  expect(useApi).toContain('THE GLUE LAYER');
330
- for (const method of ['function list', 'function get', 'function save', 'function action']) {
332
+ for (const method of [
333
+ 'function list',
334
+ 'function get',
335
+ 'function save',
336
+ 'function action',
337
+ ]) {
331
338
  expect(useApi).toContain(method);
332
339
  }
333
340
  // The documented escape hatch for a limit/offset backend.
@@ -443,7 +450,9 @@ describe('Vue App Generator', () => {
443
450
  .read('libs/vue-components/src/lib/patterns/AppHeader.vue')
444
451
  .toString();
445
452
  expect(appHeader).toContain('version="2"');
446
- expect(appHeader).toMatch(/<div[^>]*slot="utilities"[^>]*>[\s\S]*<slot name="utilities"/);
453
+ expect(appHeader).toMatch(
454
+ /<div[^>]*slot="utilities"[^>]*>[\s\S]*<slot name="utilities"/,
455
+ );
447
456
 
448
457
  const app = host.read('apps/test/src/App.vue').toString();
449
458
  expect(app).toMatch(/<template #utilities>[\s\S]*<goa-button-group/);
@@ -501,17 +510,36 @@ describe('Vue App Generator', () => {
501
510
  expect(nginxConf).toContain('http://test-service2:3333/');
502
511
  });
503
512
 
504
- it('writes vite dev proxy config when proxy is configured', async () => {
513
+ // Regression: this was a JSON file carrying `pathRewrite`, which is
514
+ // webpack-dev-server syntax. Vite has no such key and ignores unknown ones
515
+ // silently, so the dev server proxied to the right host and forwarded the path
516
+ // unrewritten -- every generated API call 404'd, with no warning. The fix has
517
+ // to be a module because the thing Vite needs is a function.
518
+ it('writes an executable vite dev proxy module whose rewrite actually rewrites', async () => {
505
519
  await generator(host, {
506
520
  ...options,
507
521
  proxy: { location: '/test/', proxyPass: 'http://test-service:3333/api/' },
508
522
  });
509
- expect(host.exists('apps/test/vite.proxy.json')).toBeTruthy();
510
- const proxyConf = JSON.parse(
511
- host.read('apps/test/vite.proxy.json').toString(),
512
- );
513
- expect(proxyConf['/test/'].target).toBe('http://localhost:3333');
514
- expect(proxyConf['/test/'].pathRewrite['^/test/']).toBe('/api/');
523
+ expect(host.exists('apps/test/vite.proxy.cjs')).toBeTruthy();
524
+ // The inert JSON form must not be left beside it.
525
+ expect(host.exists('apps/test/vite.proxy.json')).toBeFalsy();
526
+
527
+ const source = host.read('apps/test/vite.proxy.cjs').toString();
528
+ expect(source).not.toContain('pathRewrite');
529
+
530
+ // Evaluate it the way @nx/vite does (require) and exercise the function,
531
+ // rather than asserting on the text of a config that has to *behave*.
532
+ const module = { exports: {} };
533
+ new Function('module', 'exports', source)(module, module.exports);
534
+ const proxy = module.exports as Record<
535
+ string,
536
+ { target: string; rewrite: (path: string) => string }
537
+ >;
538
+ expect(proxy['/test/'].target).toBe('http://localhost:3333');
539
+ expect(typeof proxy['/test/'].rewrite).toBe('function');
540
+ expect(proxy['/test/'].rewrite('/test/v1/things')).toBe('/api/v1/things');
541
+ // Only the leading location is replaced, not a later occurrence of it.
542
+ expect(proxy['/test/'].rewrite('/test/a/test/b')).toBe('/api/a/test/b');
515
543
  });
516
544
 
517
545
  it('derives the nginx/dev proxy and the sandbox tag from --pairedProject alone', async () => {
@@ -523,10 +551,19 @@ describe('Vue App Generator', () => {
523
551
  const nginxConf = host.read('apps/test/public/nginx.conf').toString();
524
552
  expect(nginxConf).toContain('http://test-service:3333/test-service/');
525
553
 
526
- const proxyConf = JSON.parse(
527
- host.read('apps/test/vite.proxy.json').toString(),
554
+ const source = host.read('apps/test/vite.proxy.cjs').toString();
555
+ const module = { exports: {} };
556
+ new Function('module', 'exports', source)(module, module.exports);
557
+ const proxy = module.exports as Record<
558
+ string,
559
+ { target: string; rewrite: (path: string) => string }
560
+ >;
561
+ expect(proxy['/api/'].target).toBe('http://localhost:3333');
562
+ // /api/v1/... must reach the service's own mount point, which is what
563
+ // useApi's base path is built against.
564
+ expect(proxy['/api/'].rewrite('/api/v1/claims')).toBe(
565
+ '/test-service/v1/claims',
528
566
  );
529
- expect(proxyConf['/api/'].target).toBe('http://localhost:3333');
530
567
 
531
568
  const config = readProjectConfiguration(host, 'test');
532
569
  expect(config.tags).toContain('adsp:proxy-service:test-service:3333');
@@ -565,4 +602,87 @@ describe('Vue App Generator', () => {
565
602
  expect(nginxConf).toContain('http://test-service:3333/test-service/');
566
603
  expect(nginxConf).toContain('http://other-service:9000/');
567
604
  });
605
+
606
+ // Regression: the shell projects into goa-one-column-layout's native `header`
607
+ // and `footer` slots. The rule was only turned off for the vue-components lib,
608
+ // so when the shell adopted the element `nx lint` began failing on unmodified
609
+ // generator output -- two `vue/no-deprecated-slot-attribute` errors in the
610
+ // generator's own App.vue. Asserted for both layouts: the attribute is
611
+ // legitimate custom-element usage in either shell, and scoping the override to
612
+ // the one template that happens to emit it today is what caused the bug.
613
+ it.each(['header', 'internal'] as const)(
614
+ 'disables vue/no-deprecated-slot-attribute for a %s-layout app',
615
+ async (layout) => {
616
+ await generator(host, { ...options, layout });
617
+ // create-nx-workspace's current default is flat config, so that is what
618
+ // @nx/vue writes for the app; read whichever is actually in effect rather
619
+ // than assuming a filename.
620
+ const config =
621
+ host.read('apps/test/eslint.config.mjs')?.toString() ??
622
+ host.read('apps/test/.eslintrc.json')?.toString() ??
623
+ '';
624
+ // Quote style differs between the flat-config writer and the legacy JSON
625
+ // one, so match the rule and its value together rather than a literal.
626
+ expect(config).toMatch(
627
+ /vue\/no-deprecated-slot-attribute["']?\s*:\s*["']off["']/,
628
+ );
629
+ },
630
+ );
631
+
632
+ it('emits native slot attributes the disabled rule would otherwise flag', async () => {
633
+ await generator(host, { ...options, layout: 'header' });
634
+ const app = host.read('apps/test/src/App.vue')?.toString() ?? '';
635
+ expect(app).toContain('slot="header"');
636
+ expect(app).toContain('slot="footer"');
637
+ });
638
+
639
+ // Regression: the generated guidance hardcoded `apps/` and `libs/` prefixes. In a
640
+ // TS-solution workspace projects sit at the workspace root, so every path in the
641
+ // AGENTS.md an agent is told to read was wrong. Asserted against the roots actually
642
+ // in the tree rather than a literal, so this holds under either layout.
643
+ it('points its guidance at the real project roots, not hardcoded apps//libs/', async () => {
644
+ addProjectConfiguration(host, 'test-service', {
645
+ root: 'apps/test-service',
646
+ });
647
+ await generator(host, { ...options, pairedProject: 'test-service' });
648
+
649
+ const agents = host.read('apps/test/AGENTS.md')?.toString() ?? '';
650
+ const libRoot = readProjectConfiguration(host, 'vue-components').root;
651
+ const serviceRoot = readProjectConfiguration(host, 'test-service').root;
652
+
653
+ expect(agents).toContain(`${libRoot}/src/lib/primitives/`);
654
+ expect(agents).toContain(`${serviceRoot}/AGENTS.md`);
655
+ // No path may name the lib without going through its resolved root.
656
+ const strayLibPaths = agents
657
+ .split('\n')
658
+ .filter(
659
+ (line) =>
660
+ line.includes('vue-components/src/') && !line.includes(libRoot),
661
+ );
662
+ expect(strayLibPaths).toEqual([]);
663
+ });
664
+
665
+ it('documents the options that decide what a person sees', async () => {
666
+ await generator(host, options);
667
+ const agents = host.read('apps/test/AGENTS.md')?.toString() ?? '';
668
+ // These live in the vue-components catalog too, but the "Adding a view"
669
+ // decision table is where a generator gets chosen -- an agent that never
670
+ // opens the lib's own docs still has to be told to pass them.
671
+ for (const option of [
672
+ 'badgeMap',
673
+ 'referenceField',
674
+ '--icon',
675
+ 'optionLabel',
676
+ ]) {
677
+ expect(agents).toContain(option);
678
+ }
679
+ });
680
+
681
+ it('feeds the signed-in user into the side menu profile button', async () => {
682
+ await generator(host, { ...options, layout: 'internal' });
683
+ const app = host.read('apps/test/src/App.vue')?.toString() ?? '';
684
+ // AppSideMenu falls back to a generic name, but the real one has to reach it
685
+ // or an authenticated user's own menu never shows who they are.
686
+ expect(app).toContain(':user-name="kc.fullName"');
687
+ });
568
688
  });
@@ -8,24 +8,20 @@ invoked automatically by `vue-app` and by every `vue-*-view` generator.
8
8
  |---|---|---|
9
9
  | `src/lib/primitives/` | Thin `v-model`/idiomatic-event wrappers over individual `goa-*` elements (`GoabInput`, `GoabButton`, …) | **Interim** — see below |
10
10
  | `src/lib/patterns/` | Composite, app-shell components (`AppLayout`, `AppHeader`, `AppFooter`, `AppSideMenu`, `SessionExpiredBanner`, `RecordDetailShell`, `WorkspaceTable`, `Stepper`, `StepErrorSummary`, `FilterBar`) | **Permanent** |
11
- | `src/lib/formatters.ts` | Shared value formatting for views (`formatDate`, `formatDateTime`, `formatNumber`, `formatPercent`) | **Permanent** |
11
+ | `src/lib/formatters.ts` | Shared value formatting for views (`formatDate`, `formatDateTime`, `formatNumber`, `formatPercent`, `optionLabel`, `badgeType`) | **Permanent** |
12
12
 
13
- **Not every pattern component is present in every app.** `AppLayout`, `AppHeader`,
14
- `AppFooter`, `AppSideMenu`, and `SessionExpiredBanner` are base app-shell `vue-app`
15
- provisions and wires all five into `App.vue` for every generated app, unconditionally.
16
- The rest are on-demand: they only exist in a given app's `src/lib/patterns/` if that
17
- app has run the matching view generator at least once.
13
+ **Every pattern component listed above is present in every app.** This lib is generated
14
+ in one shot, so all of `primitives/` and all of `patterns/` exist as soon as any Vue app
15
+ has been generated there is no per-component provisioning step and nothing to check for
16
+ before building on one.
18
17
 
19
- | Component | Provisioned by |
20
- |---|---|
21
- | `RecordDetailShell` | `vue-detail-view` |
22
- | `WorkspaceTable` | `vue-workspace-view`, `vue-admin-crud` |
23
- | `Stepper`, `StepErrorSummary` | `vue-intake-view` |
24
-
25
- Don't assume one of these on-demand components exists in a given app check whether
26
- its generator has actually been run (e.g. `nx list @abgov/nx-adsp` won't tell you;
27
- look for the component file itself, or the view file that would import it) before
28
- building on it.
18
+ Which components are *wired up* does vary: `vue-app` mounts the shell components
19
+ (`AppLayout`, `AppHeader`, `AppFooter`, `AppSideMenu`, `SessionExpiredBanner`) in
20
+ `App.vue`, while the rest are imported by whichever view generator uses them —
21
+ `RecordDetailShell` by `vue-detail-view`, `WorkspaceTable` by `vue-workspace-view` and
22
+ `vue-admin-crud`, `Stepper`/`StepErrorSummary` by `vue-intake-view`, `FilterBar` by a
23
+ filterable workspace view. An unused component is idle, not missing: import it directly
24
+ in a hand-authored view rather than running a generator to "provision" it.
29
25
 
30
26
  > **⚠️ `primitives/` is interim — do not invest in it as permanent.** It exists
31
27
  > only because GoA DS has not yet published an official Vue wrapper package. When
@@ -66,6 +62,7 @@ inline styles.
66
62
  | A loading `<div>` or spinner markup | `<goa-skeleton type="…">` or `<goa-spinner>` | Skeletons match the shape they replace (`card`, `text`, `table`) |
67
63
  | A `<label>` + error `<span>` around an input | `<goa-form-item label="…" error="…">` | Wrap the `Goab*` input in this, don't restyle it |
68
64
  | A row of buttons with flex styling | `<goa-button-group alignment="…">` | |
65
+ | A hand-built multi-select (checkbox list, chips) | `<goa-dropdown-multiselect>` | Added in web-components 2.4.0 |
69
66
  | A hand-built filter row above a table | `<FilterBar>` (this library) | Controls, collapse, active-filter chips and clear-all. It emits a query-ready values object; the *view* owns resetting the page, debouncing, and URL sync |
70
67
 
71
68
  Also available bare and worth knowing before hand-rolling: `goa-accordion`, `goa-details`,
@@ -84,6 +81,28 @@ For values rather than layout, use `formatters.ts` (`formatDate`, `formatDateTim
84
81
  the same way, and each formatter already returns an em dash for a null/unparseable value so a
85
82
  partially-populated record needs no per-field guard.
86
83
 
84
+ ### Never render a stored code to a person
85
+
86
+ Two more formatters exist because rendering a *coded* value is where generated views have most often
87
+ been wrong, and the failure is invisible to a unit test — it only shows up when someone reads the
88
+ screen.
89
+
90
+ | Don't | Do |
91
+ | --- | --- |
92
+ | `{{ record['species'] }}` → shows `cattle-mature` | `{{ optionLabel(fieldOptions['species'], record['species']) }}` → `Cattle (mature)` |
93
+ | `<goa-badge type="information" :content="row['status']" />` — every status the same neutral blue | `<goa-badge :type="badgeType(columnBadgeTypes['status'], row['status'])" :content="optionLabel(...)" />` |
94
+
95
+ `optionLabel` falls back to the raw value for an unmapped code (a data or config problem you want to
96
+ see, not hide); `badgeType` falls back to `information`, which is the honest colour for a value whose
97
+ severity nobody declared.
98
+
99
+ The view generators build these maps for you — but only from what you pass them. Supply `options` on
100
+ any `--fields`/`--columns` entry whose stored value is a code, and `badgeMap` on a `badge` entry, e.g.
101
+ `badgeMap: { approved: 'success', declined: 'emergency' }`. Omit them and the view renders the code.
102
+ A badge's colour is the fastest thing a reader takes in, so a declined claim in neutral blue reads as
103
+ routine — this matters most on a check-your-answers page, whose entire purpose is that the person can
104
+ read back what they entered.
105
+
87
106
  ## What these wrappers do (and why they're needed)
88
107
 
89
108
  `goa-*` are framework-agnostic custom elements (built with Svelte). Three quirks
@@ -37,8 +37,11 @@ export {
37
37
  fromIsoDateString,
38
38
  toIsoDateString,
39
39
  formatCurrency,
40
+ optionLabel,
41
+ badgeType,
40
42
  formatDate,
41
43
  formatDateTime,
42
44
  formatNumber,
43
45
  formatPercent,
44
46
  } from './lib/formatters';
47
+ export type { DisplayOption, BadgeType } from './lib/formatters';