@abgov/nx-adsp 13.18.1 → 13.18.3
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.json +1 -1
- package/src/generators/angular-app/angular-app.js +28 -17
- package/src/generators/angular-app/angular-app.js.map +1 -1
- package/src/generators/vue-admin-crud/files/src/views/__editViewFileName__.vue__tmpl__ +4 -2
- package/src/generators/vue-admin-crud/files/src/views/__listViewFileName__.vue__tmpl__ +3 -1
- package/src/generators/vue-admin-crud/vue-admin-crud.spec.ts +2 -2
- package/src/generators/vue-app/files/src/router/index.ts__tmpl__ +14 -2
- package/src/generators/vue-app/vue-app.spec.ts +12 -0
- package/src/generators/vue-components/files/src/lib/patterns/AppSideMenu.vue__tmpl__ +2 -0
- package/src/generators/vue-components/vue-components.spec.ts +3 -0
- package/src/generators/vue-detail-view/files/src/views/__viewFileName__.vue__tmpl__ +3 -1
- package/src/generators/vue-detail-view/vue-detail-view.spec.ts +6 -1
- package/src/generators/vue-intake-view/files/shared/src/views/__reviewViewFileName__.vue__tmpl__ +4 -2
- package/src/generators/vue-intake-view/files/steps/src/views/__stepViewFileName__.vue__tmpl__ +4 -2
- package/src/generators/vue-intake-view/vue-intake-view.spec.ts +1 -1
- package/src/generators/vue-workspace-view/files/src/views/__viewFileName__.vue__tmpl__ +4 -1
- package/src/generators/vue-workspace-view/vue-workspace-view.spec.ts +1 -1
- package/src/index.js +1 -0
package/package.json
CHANGED
|
@@ -68,7 +68,7 @@ function addFiles(host, options) {
|
|
|
68
68
|
}
|
|
69
69
|
function default_1(host, options) {
|
|
70
70
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
71
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
71
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
72
72
|
// Checked before normalizeOptions, which resolves ADSP auth and can trigger
|
|
73
73
|
// an interactive login — a missing peer shouldn't surface only after that.
|
|
74
74
|
const { applicationGenerator: initAngular } = yield Promise.resolve().then(() => require('@nx/angular/generators')).catch(() => {
|
|
@@ -83,6 +83,17 @@ function default_1(host, options) {
|
|
|
83
83
|
directory: normalizedOptions.projectRoot,
|
|
84
84
|
skipFormat: true,
|
|
85
85
|
});
|
|
86
|
+
// TypeScript 6 defaults noUncheckedSideEffectImports to true, which causes
|
|
87
|
+
// TS2882 on side-effect imports in test-setup.ts (zone.js/dist/zone-testing,
|
|
88
|
+
// jest-preset-angular, @angular/localize/init). Pin false in tsconfig.base.json
|
|
89
|
+
// so the generated Angular workspace compiles without needing the nx migrate
|
|
90
|
+
// TS6 migration to have been run in the consuming workspace first.
|
|
91
|
+
if (host.exists('tsconfig.base.json')) {
|
|
92
|
+
const rootTsconfig = (0, devkit_1.readJson)(host, 'tsconfig.base.json');
|
|
93
|
+
if (((_a = rootTsconfig.compilerOptions) === null || _a === void 0 ? void 0 : _a.noUncheckedSideEffectImports) === undefined) {
|
|
94
|
+
(0, devkit_1.writeJson)(host, 'tsconfig.base.json', Object.assign(Object.assign({}, rootTsconfig), { compilerOptions: Object.assign(Object.assign({}, rootTsconfig.compilerOptions), { noUncheckedSideEffectImports: false }) }));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
86
97
|
// Let the Playwright e2e target the deployed URL (BASE_URL) in CI instead of
|
|
87
98
|
// always starting a local dev server — see the nx-oc pipeline's e2e jobs.
|
|
88
99
|
(0, quality_1.guardPlaywrightWebServer)(host, `${normalizedOptions.projectRoot}-e2e`);
|
|
@@ -122,11 +133,11 @@ function default_1(host, options) {
|
|
|
122
133
|
const config = (0, devkit_1.readProjectConfiguration)(host, options.name);
|
|
123
134
|
// Remove the generated fileReplacements for production — single environment.ts
|
|
124
135
|
// is pre-populated from tenant config at generation time.
|
|
125
|
-
if ((
|
|
136
|
+
if ((_c = (_b = config.targets.build.configurations) === null || _b === void 0 ? void 0 : _b.production) === null || _c === void 0 ? void 0 : _c.fileReplacements) {
|
|
126
137
|
delete config.targets.build.configurations.production.fileReplacements;
|
|
127
138
|
}
|
|
128
139
|
// keycloak-js pushes the initial bundle above Angular's default 1 MB error budget.
|
|
129
|
-
if ((
|
|
140
|
+
if ((_d = config.targets.build.configurations) === null || _d === void 0 ? void 0 : _d.production) {
|
|
130
141
|
config.targets.build.configurations.production.budgets = [
|
|
131
142
|
{ type: 'initial', maximumWarning: '2mb', maximumError: '4mb' },
|
|
132
143
|
{
|
|
@@ -152,17 +163,17 @@ function default_1(host, options) {
|
|
|
152
163
|
// Lets the sandbox generator ensure the paired backend's Service exists before this
|
|
153
164
|
// frontend's nginx starts — see utils/paired-project.ts for why.
|
|
154
165
|
if (normalizedOptions.pairedProjectTag) {
|
|
155
|
-
config.tags = [...((
|
|
166
|
+
config.tags = [...((_e = config.tags) !== null && _e !== void 0 ? _e : []), normalizedOptions.pairedProjectTag];
|
|
156
167
|
}
|
|
157
168
|
config.tags = [
|
|
158
|
-
...((
|
|
169
|
+
...((_f = config.tags) !== null && _f !== void 0 ? _f : []),
|
|
159
170
|
...(0, nx_oc_1.adspProjectTags)(normalizedOptions.env, normalizedOptions.adsp.tenant).filter((tag) => { var _a; return !((_a = config.tags) !== null && _a !== void 0 ? _a : []).includes(tag); }),
|
|
160
171
|
];
|
|
161
172
|
(0, devkit_1.updateProjectConfiguration)(host, options.name, config);
|
|
162
173
|
(0, quality_1.addSemgrepTarget)(host, options.name);
|
|
163
174
|
yield (0, devkit_1.formatFiles)(host);
|
|
164
175
|
if (normalizedOptions.adsp) {
|
|
165
|
-
const accessToken = (
|
|
176
|
+
const accessToken = (_g = normalizedOptions.adsp.accessToken) !== null && _g !== void 0 ? _g : options.accessToken;
|
|
166
177
|
const clientId = `urn:ads:${normalizedOptions.adsp.tenant}:${normalizedOptions.projectName}`;
|
|
167
178
|
yield (0, keycloak_admin_1.ensurePublicClient)(normalizedOptions.adsp.accessServiceUrl, normalizedOptions.adsp.tenantRealm, clientId, accessToken);
|
|
168
179
|
if (options.serviceClientId) {
|
|
@@ -171,17 +182,17 @@ function default_1(host, options) {
|
|
|
171
182
|
}
|
|
172
183
|
}
|
|
173
184
|
if (normalizedOptions.adsp && !options.skipAgent) {
|
|
174
|
-
const accessToken = (
|
|
175
|
-
const appComponentTs = (
|
|
176
|
-
.read(`${normalizedOptions.projectRoot}/src/app/app.component.ts`)) === null ||
|
|
177
|
-
const appComponentHtml = (
|
|
178
|
-
.read(`${normalizedOptions.projectRoot}/src/app/app.component.html`)) === null ||
|
|
179
|
-
const appConfigTs = (
|
|
180
|
-
.read(`${normalizedOptions.projectRoot}/src/app/app.config.ts`)) === null ||
|
|
181
|
-
const appRoutesTs = (
|
|
182
|
-
.read(`${normalizedOptions.projectRoot}/src/app/app.routes.ts`)) === null ||
|
|
183
|
-
const environmentTs = (
|
|
184
|
-
.read(`${normalizedOptions.projectRoot}/src/environments/environment.ts`)) === null ||
|
|
185
|
+
const accessToken = (_h = normalizedOptions.adsp.accessToken) !== null && _h !== void 0 ? _h : options.accessToken;
|
|
186
|
+
const appComponentTs = (_k = (_j = host
|
|
187
|
+
.read(`${normalizedOptions.projectRoot}/src/app/app.component.ts`)) === null || _j === void 0 ? void 0 : _j.toString()) !== null && _k !== void 0 ? _k : '';
|
|
188
|
+
const appComponentHtml = (_m = (_l = host
|
|
189
|
+
.read(`${normalizedOptions.projectRoot}/src/app/app.component.html`)) === null || _l === void 0 ? void 0 : _l.toString()) !== null && _m !== void 0 ? _m : '';
|
|
190
|
+
const appConfigTs = (_p = (_o = host
|
|
191
|
+
.read(`${normalizedOptions.projectRoot}/src/app/app.config.ts`)) === null || _o === void 0 ? void 0 : _o.toString()) !== null && _p !== void 0 ? _p : '';
|
|
192
|
+
const appRoutesTs = (_r = (_q = host
|
|
193
|
+
.read(`${normalizedOptions.projectRoot}/src/app/app.routes.ts`)) === null || _q === void 0 ? void 0 : _q.toString()) !== null && _r !== void 0 ? _r : '';
|
|
194
|
+
const environmentTs = (_t = (_s = host
|
|
195
|
+
.read(`${normalizedOptions.projectRoot}/src/environments/environment.ts`)) === null || _s === void 0 ? void 0 : _s.toString()) !== null && _t !== void 0 ? _t : '';
|
|
185
196
|
yield (0, agent_1.confirmAfterAgentInterrupt)(yield (0, agent_1.consultAgent)(normalizedOptions.adsp.directoryServiceUrl, accessToken, {
|
|
186
197
|
projectName: normalizedOptions.projectName,
|
|
187
198
|
projectType: 'angular-app',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/angular-app/angular-app.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"angular-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/angular-app/angular-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,10 +3,12 @@ import { reactive, ref, computed, onMounted } from 'vue';
|
|
|
3
3
|
import { useRoute, useRouter } from 'vue-router';
|
|
4
4
|
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
5
5
|
import { GoabInput, GoabCheckbox } from '<%= goaImportPath %>';
|
|
6
|
+
import { useApi } from '../composables/useApi';
|
|
6
7
|
|
|
7
8
|
const route = useRoute();
|
|
8
9
|
const router = useRouter();
|
|
9
10
|
const kc = useKeycloak();
|
|
11
|
+
const { apiFetch } = useApi();
|
|
10
12
|
|
|
11
13
|
const idParam = computed(() => String(route.params.id ?? ''));
|
|
12
14
|
const isNew = computed(() => idParam.value === 'new' || idParam.value === '');
|
|
@@ -32,7 +34,7 @@ async function load() {
|
|
|
32
34
|
loading.value = true;
|
|
33
35
|
loadError.value = null;
|
|
34
36
|
try {
|
|
35
|
-
const res = await
|
|
37
|
+
const res = await apiFetch(`/api/<%= resource %>/${idParam.value}`);
|
|
36
38
|
if (!res.ok) throw new Error(`Failed to load (${res.status})`);
|
|
37
39
|
const data = await res.json();
|
|
38
40
|
<% fields.forEach(function (field) { -%>
|
|
@@ -67,7 +69,7 @@ async function onSubmit() {
|
|
|
67
69
|
saving.value = true;
|
|
68
70
|
saveError.value = null;
|
|
69
71
|
try {
|
|
70
|
-
const res = await
|
|
72
|
+
const res = await apiFetch(
|
|
71
73
|
isNew.value ? '/api/<%= resource %>' : `/api/<%= resource %>/${idParam.value}`,
|
|
72
74
|
{
|
|
73
75
|
method: isNew.value ? 'POST' : 'PUT',
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import { ref, onMounted } from 'vue';
|
|
3
3
|
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
4
4
|
import { WorkspaceTable } from '<%= goaImportPath %>';
|
|
5
|
+
import { useApi } from '../composables/useApi';
|
|
5
6
|
|
|
6
7
|
const kc = useKeycloak();
|
|
8
|
+
const { apiFetch } = useApi();
|
|
7
9
|
|
|
8
10
|
const columns = [
|
|
9
11
|
<% fields.forEach(function (field) { -%>
|
|
@@ -21,7 +23,7 @@ async function load() {
|
|
|
21
23
|
loading.value = true;
|
|
22
24
|
error.value = null;
|
|
23
25
|
try {
|
|
24
|
-
const res = await
|
|
26
|
+
const res = await apiFetch('/api/<%= resource %>');
|
|
25
27
|
if (!res.ok) throw new Error(`Failed to load (${res.status})`);
|
|
26
28
|
const data = await res.json();
|
|
27
29
|
// Accept either a bare array or a { results } envelope.
|
|
@@ -61,7 +61,7 @@ describe('Vue Admin CRUD Generator', () => {
|
|
|
61
61
|
.read('apps/test/src/views/RegionsListView.vue')
|
|
62
62
|
.toString();
|
|
63
63
|
expect(view).toContain('<h1>Regions</h1>');
|
|
64
|
-
expect(view).toContain("
|
|
64
|
+
expect(view).toContain("apiFetch('/api/regions')");
|
|
65
65
|
expect(view).toContain("import { WorkspaceTable } from '@proj/vue-components';");
|
|
66
66
|
expect(view).toContain('<WorkspaceTable');
|
|
67
67
|
// No pagination props bound -- this is the "reused without its pagination/
|
|
@@ -92,7 +92,7 @@ describe('Vue Admin CRUD Generator', () => {
|
|
|
92
92
|
expect(view).not.toContain('errors.active');
|
|
93
93
|
expect(view).toContain("method: isNew.value ? 'POST' : 'PUT'");
|
|
94
94
|
expect(view).toContain("isNew.value ? '/api/regions'");
|
|
95
|
-
expect(view).toContain('
|
|
95
|
+
expect(view).toContain('apiFetch(`/api/regions/${idParam.value}`');
|
|
96
96
|
expect(view).toContain("router.push('/regions')");
|
|
97
97
|
expect(view).toContain('Create Regions');
|
|
98
98
|
expect(view).toContain('Edit Regions');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { watch } from 'vue';
|
|
1
2
|
import { createRouter, createWebHistory } from 'vue-router';
|
|
2
3
|
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
3
4
|
import HomeView from '../views/HomeView.vue';
|
|
@@ -14,12 +15,23 @@ const router = createRouter({
|
|
|
14
15
|
],
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
router.beforeEach((to) => {
|
|
18
|
+
router.beforeEach(async (to) => {
|
|
18
19
|
if (to.meta.requiresAuth) {
|
|
19
20
|
// Read fields off the reactive instance (don't destructure) — consistent with
|
|
20
21
|
// the views and safe if this ever moves out of the per-navigation callback.
|
|
21
22
|
const kc = useKeycloak();
|
|
22
|
-
if (!kc.ready)
|
|
23
|
+
if (!kc.ready) {
|
|
24
|
+
// Keycloak init is async and may not have settled before the initial navigation
|
|
25
|
+
// fires (app.mount() triggers navigation synchronously). Block and wait rather
|
|
26
|
+
// than allowing through — a direct-URL load to a protected route would otherwise
|
|
27
|
+
// render the page unauthenticated with no login redirect.
|
|
28
|
+
await new Promise<void>((resolve) => {
|
|
29
|
+
const stop = watch(
|
|
30
|
+
() => kc.ready,
|
|
31
|
+
(ready) => { if (ready) { stop(); resolve() } },
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
}
|
|
23
35
|
if (!kc.authenticated) {
|
|
24
36
|
kc.keycloak?.login({ redirectUri: window.location.origin + to.fullPath });
|
|
25
37
|
return false;
|
|
@@ -314,6 +314,18 @@ describe('Vue App Generator', () => {
|
|
|
314
314
|
expect(homeView).not.toContain('Authorization');
|
|
315
315
|
}, 30000);
|
|
316
316
|
|
|
317
|
+
it('router guard waits for Keycloak readiness before making auth decisions', async () => {
|
|
318
|
+
await generator(host, options);
|
|
319
|
+
const router = host.read('apps/test/src/router/index.ts').toString();
|
|
320
|
+
// Returning `true` when !kc.ready lets unauthenticated direct-URL loads through
|
|
321
|
+
// to protected routes before Keycloak has finished init. The guard must block
|
|
322
|
+
// and wait (async watch) instead of allowing.
|
|
323
|
+
expect(router).toContain('async');
|
|
324
|
+
expect(router).toContain('kc.ready');
|
|
325
|
+
expect(router).not.toMatch(/if\s*\(!kc\.ready\)\s*return\s*true/);
|
|
326
|
+
expect(router).toContain('watch');
|
|
327
|
+
}, 30000);
|
|
328
|
+
|
|
317
329
|
it('index.html is at the Vite entry root and its mount target matches main.ts', async () => {
|
|
318
330
|
await generator(host, options);
|
|
319
331
|
// Vite's entry is <projectRoot>/index.html, not src/index.html — a template
|
|
@@ -18,6 +18,9 @@ describe('Vue Components Generator', () => {
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
it('creates the shared wrapper library with all wrappers and a barrel', async () => {
|
|
21
|
+
// Simulate a legacy-ESLint workspace so useFlatConfig() returns false and
|
|
22
|
+
// the generator creates .eslintrc.json rather than eslint.config.mjs.
|
|
23
|
+
host.write('.eslintrc.json', '{}');
|
|
21
24
|
await generator(host);
|
|
22
25
|
|
|
23
26
|
const config = readProjectConfiguration(host, 'vue-components');
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ref, onMounted } from 'vue';
|
|
3
3
|
import { useRoute, useRouter } from 'vue-router';
|
|
4
4
|
import { RecordDetailShell } from '<%= goaImportPath %>';
|
|
5
|
+
import { useApi } from '../composables/useApi';
|
|
5
6
|
|
|
6
7
|
// The fetched record's shape isn't known to this generator -- read fields
|
|
7
8
|
// defensively rather than declaring (and likely getting wrong) a fake interface.
|
|
@@ -11,12 +12,13 @@ const error = ref<string | null>(null);
|
|
|
11
12
|
|
|
12
13
|
const route = useRoute();
|
|
13
14
|
const router = useRouter();
|
|
15
|
+
const { apiFetch } = useApi();
|
|
14
16
|
|
|
15
17
|
async function load() {
|
|
16
18
|
loading.value = true;
|
|
17
19
|
error.value = null;
|
|
18
20
|
try {
|
|
19
|
-
const res = await
|
|
21
|
+
const res = await apiFetch(`/api/<%= resource %>/${route.params.id}`);
|
|
20
22
|
if (!res.ok) throw new Error(`Failed to load (${res.status})`);
|
|
21
23
|
record.value = await res.json();
|
|
22
24
|
} catch (e) {
|
|
@@ -7,6 +7,11 @@ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
|
7
7
|
import generator from './vue-detail-view';
|
|
8
8
|
import { Schema } from './schema';
|
|
9
9
|
|
|
10
|
+
jest.mock('@nx/devkit', () => ({
|
|
11
|
+
...jest.requireActual('@nx/devkit'),
|
|
12
|
+
formatFiles: jest.fn().mockResolvedValue(undefined),
|
|
13
|
+
}));
|
|
14
|
+
|
|
10
15
|
// Mirrors the shape vue-app's own template generates -- vue-detail-view retrofits
|
|
11
16
|
// into this file, so the fixture must match what it actually looks for.
|
|
12
17
|
const ROUTER_FIXTURE = `import { createRouter, createWebHistory } from 'vue-router';
|
|
@@ -97,7 +102,7 @@ describe('Vue Detail View Generator', () => {
|
|
|
97
102
|
.read('apps/test/src/views/ApplicationDetailView.vue')
|
|
98
103
|
.toString();
|
|
99
104
|
expect(view).toContain('heading="Application Detail"');
|
|
100
|
-
expect(view).toContain("
|
|
105
|
+
expect(view).toContain("apiFetch(`/api/applications/${route.params.id}`)");
|
|
101
106
|
expect(view).toContain(
|
|
102
107
|
"<goa-badge type=\"information\" :content=\"String(record['status'] ?? '—')\" />",
|
|
103
108
|
);
|
package/src/generators/vue-intake-view/files/shared/src/views/__reviewViewFileName__.vue__tmpl__
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
import { ref, computed, onMounted } from 'vue';
|
|
3
3
|
import { useRoute, useRouter } from 'vue-router';
|
|
4
4
|
import { GoabCheckbox } from '<%= goaImportPath %>';
|
|
5
|
+
import { useApi } from '../composables/useApi';
|
|
5
6
|
|
|
6
7
|
const route = useRoute();
|
|
7
8
|
const router = useRouter();
|
|
9
|
+
const { apiFetch } = useApi();
|
|
8
10
|
|
|
9
11
|
const idParam = computed(() => String(route.params.id ?? ''));
|
|
10
12
|
|
|
@@ -21,7 +23,7 @@ async function load() {
|
|
|
21
23
|
loading.value = true;
|
|
22
24
|
loadError.value = null;
|
|
23
25
|
try {
|
|
24
|
-
const res = await
|
|
26
|
+
const res = await apiFetch(`/api/<%= resource %>/${idParam.value}`);
|
|
25
27
|
if (!res.ok) throw new Error(`Failed to load (${res.status})`);
|
|
26
28
|
record.value = await res.json();
|
|
27
29
|
} catch (e) {
|
|
@@ -42,7 +44,7 @@ async function onSubmit() {
|
|
|
42
44
|
submitting.value = true;
|
|
43
45
|
submitError.value = null;
|
|
44
46
|
try {
|
|
45
|
-
const res = await
|
|
47
|
+
const res = await apiFetch(`/api/<%= resource %>/${idParam.value}/submit`, {
|
|
46
48
|
method: 'POST',
|
|
47
49
|
});
|
|
48
50
|
if (!res.ok) throw new Error(`Failed to submit (${res.status})`);
|
package/src/generators/vue-intake-view/files/steps/src/views/__stepViewFileName__.vue__tmpl__
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { reactive, ref, computed, onMounted } from 'vue';
|
|
3
3
|
import { useRoute, useRouter } from 'vue-router';
|
|
4
4
|
import { Stepper, StepErrorSummary, GoabInput } from '<%= goaImportPath %>';
|
|
5
|
+
import { useApi } from '../composables/useApi';
|
|
5
6
|
|
|
6
7
|
const STEPS = [
|
|
7
8
|
<% stepperSteps.forEach(function (step) { -%>
|
|
@@ -11,6 +12,7 @@ const STEPS = [
|
|
|
11
12
|
|
|
12
13
|
const route = useRoute();
|
|
13
14
|
const router = useRouter();
|
|
15
|
+
const { apiFetch } = useApi();
|
|
14
16
|
|
|
15
17
|
const idParam = computed(() => String(route.params.id ?? ''));
|
|
16
18
|
const isNew = computed(() => idParam.value === 'new' || idParam.value === '');
|
|
@@ -48,7 +50,7 @@ async function load() {
|
|
|
48
50
|
loading.value = true;
|
|
49
51
|
loadError.value = null;
|
|
50
52
|
try {
|
|
51
|
-
const res = await
|
|
53
|
+
const res = await apiFetch(`/api/<%= resource %>/${idParam.value}`);
|
|
52
54
|
if (!res.ok) throw new Error(`Failed to load (${res.status})`);
|
|
53
55
|
const data = await res.json();
|
|
54
56
|
completedSteps.value = Array.isArray(data.completedSteps) ? data.completedSteps : [];
|
|
@@ -96,7 +98,7 @@ async function onSaveAndContinue() {
|
|
|
96
98
|
...form,
|
|
97
99
|
completedSteps: [...new Set([...completedSteps.value, '<%- stepKey %>'])],
|
|
98
100
|
};
|
|
99
|
-
const res = await
|
|
101
|
+
const res = await apiFetch(
|
|
100
102
|
isNew.value ? '/api/<%= resource %>' : `/api/<%= resource %>/${idParam.value}`,
|
|
101
103
|
{
|
|
102
104
|
method: isNew.value ? 'POST' : 'PUT',
|
|
@@ -123,7 +123,7 @@ describe('Vue Intake View Generator', () => {
|
|
|
123
123
|
expect(review).toContain("record['fullName'] ?? '—'");
|
|
124
124
|
expect(review).toContain("record['email'] ?? '—'");
|
|
125
125
|
expect(review).toContain(':disabled="!declared || submitting || undefined"');
|
|
126
|
-
expect(review).toContain("
|
|
126
|
+
expect(review).toContain("apiFetch(`/api/applications/${idParam.value}/submit`");
|
|
127
127
|
expect(review).toContain('/applications/${idParam.value}/confirmation');
|
|
128
128
|
}, 30000);
|
|
129
129
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, onMounted } from 'vue';
|
|
3
3
|
import { WorkspaceTable } from '<%= goaImportPath %>';
|
|
4
|
+
import { useApi } from '../composables/useApi';
|
|
5
|
+
|
|
6
|
+
const { apiFetch } = useApi();
|
|
4
7
|
|
|
5
8
|
const columns = [
|
|
6
9
|
<% columns.forEach(function (column) { -%>
|
|
@@ -39,7 +42,7 @@ async function load() {
|
|
|
39
42
|
params.set('sortBy', sortBy.value);
|
|
40
43
|
params.set('sortDir', sortDir.value);
|
|
41
44
|
}
|
|
42
|
-
const res = await
|
|
45
|
+
const res = await apiFetch(`/api/<%= resource %>?${params.toString()}`);
|
|
43
46
|
if (!res.ok) throw new Error(`Failed to load (${res.status})`);
|
|
44
47
|
const data = await res.json();
|
|
45
48
|
// Accept either a bare array or a { results, total } page envelope.
|
|
@@ -99,7 +99,7 @@ describe('Vue Workspace View Generator', () => {
|
|
|
99
99
|
expect(view).toContain(
|
|
100
100
|
"{ key: 'lastSaved', label: 'Last saved', sortable: true }",
|
|
101
101
|
);
|
|
102
|
-
expect(view).toContain('
|
|
102
|
+
expect(view).toContain('apiFetch(`/api/applications?${params.toString()}`)');
|
|
103
103
|
expect(view).toContain(
|
|
104
104
|
"<goa-badge type=\"information\" :content=\"String(row['status'] ?? '—')\" />",
|
|
105
105
|
);
|
package/src/index.js
CHANGED