@abgov/nx-adsp 5.9.0-beta.5 → 5.9.0-beta.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/nx-adsp",
3
- "version": "5.9.0-beta.5",
3
+ "version": "5.9.0-beta.6",
4
4
  "license": "Apache-2.0",
5
5
  "main": "src/index.js",
6
6
  "description": "Government of Alberta - Nx plugin for ADSP apps.",
@@ -3,6 +3,7 @@
3
3
 
4
4
  > fieldset {
5
5
  display: none;
6
+ padding-bottom: 64px;
6
7
  }
7
8
 
8
9
  > fieldset.show {
@@ -10,6 +11,15 @@
10
11
  }
11
12
  }
12
13
 
14
+ .formFile {
15
+ display: flex;
16
+ align-items: center;
17
+
18
+ > a {
19
+ display: none;
20
+ }
21
+ }
22
+
13
23
  .formActions {
14
24
  display: flex;
15
25
  margin-top: 16px;
@@ -13,6 +13,9 @@ import { CONFIG_FEATURE_KEY, ConfigState } from '../config.slice';
13
13
  export const <%= constantName %>_FEATURE_KEY = '<%= fileName %>';
14
14
  const FORM_DEFINITION_ID = '<%= id %>';
15
15
  const FORM_SERVICE_ID = 'urn:ads:platform:form-service';
16
+ const FILE_TYPE_ID = '<%= fileName %>-files';
17
+ const FILE_SERVICE_ID = 'urn:ads:platform:file-service';
18
+ const FILE_SERVICE_RESOURCE_PREFIX = `${FILE_SERVICE_ID}:v1:`;
16
19
 
17
20
  /*
18
21
  * Update these interfaces according to your requirements.
@@ -38,15 +41,26 @@ const required: Record<string, string[]> = {
38
41
  type FormStatus = 'draft' | 'locked' | 'submitted';
39
42
  type SectionCompletion = 'complete' | 'incomplete' | null;
40
43
 
44
+ export interface FileInformation {
45
+ urn?: string;
46
+ filename: string;
47
+ progress: number;
48
+ size: number;
49
+ dataUri?: string;
50
+ }
51
+
41
52
  export interface <%= className %>State {
42
53
  formId: string;
43
54
  status: FormStatus;
44
55
  step: number;
45
56
  values: <%= className %>;
57
+ files: Record<string, FileInformation>;
46
58
  errors: Record<string, Record<string, boolean>>;
47
59
  complete: Record<string, SectionCompletion>;
48
60
  busy: {
49
61
  loading: boolean;
62
+ loadingFiles: boolean;
63
+ uploadingFile: boolean;
50
64
  saving: boolean;
51
65
  submitting: boolean;
52
66
  };
@@ -88,6 +102,13 @@ function areSectionsComplete(
88
102
  return complete;
89
103
  }
90
104
 
105
+ function getFileUrl(directory: Record<string, string>, urn: string): URL {
106
+ return new URL(
107
+ urn.replace(FILE_SERVICE_RESOURCE_PREFIX, 'v1'),
108
+ `${directory[FILE_SERVICE_ID]}/file/v1`
109
+ );
110
+ }
111
+
91
112
  /**
92
113
  * Export an effect using createAsyncThunk from
93
114
  * the Redux Toolkit: https://redux-toolkit.js.org/api/createAsyncThunk
@@ -107,7 +128,7 @@ function areSectionsComplete(
107
128
  */
108
129
  export const initializeForm = createAsyncThunk(
109
130
  '<%= propertyName %>/initialize',
110
- async (_, { getState }) => {
131
+ async (_, { dispatch, getState }) => {
111
132
  const state = getState();
112
133
  const { user }: UserState = state['user'];
113
134
  if (!user) {
@@ -160,18 +181,80 @@ export const initializeForm = createAsyncThunk(
160
181
  const { data } = await axios.get<{
161
182
  id: string;
162
183
  data: <%= className %>;
184
+ files: Record<string, string>;
163
185
  }>(`${directory[FORM_SERVICE_ID]}/form/v1/forms/${form.id}/data`, {
164
186
  headers: {
165
187
  Authorization: `Bearer ${user.access_token}`,
166
188
  },
167
189
  });
168
190
 
191
+ dispatch(getFileMetadata(data.files));
192
+
169
193
  const complete = areSectionsComplete(data.data);
170
194
 
171
195
  return { ...form, ...data, complete };
172
196
  }
173
197
  );
174
198
 
199
+ export const getFileMetadata = createAsyncThunk(
200
+ '<%= propertyName %>/get-file-metadata',
201
+ async (files: Record<string, string>, { getState }) => {
202
+ const state = getState();
203
+ const { user }: UserState = state['user'];
204
+ const { directory }: ConfigState = state[CONFIG_FEATURE_KEY];
205
+
206
+ const metadata: Record<string, FileInformation> = {};
207
+ for (const [key, urn] of Object.entries(files)) {
208
+ const { data } = await axios.get<FileInformation>(
209
+ getFileUrl(directory, urn).href,
210
+ {
211
+ headers: { Authorization: `Bearer ${user.access_token}` },
212
+ }
213
+ );
214
+
215
+ metadata[key] = {
216
+ urn: data.urn,
217
+ filename: data.filename,
218
+ size: data.size,
219
+ progress: 100,
220
+ };
221
+ }
222
+
223
+ return metadata;
224
+ }
225
+ );
226
+
227
+ export const downloadFile = createAsyncThunk(
228
+ '<%= propertyName %>/download-file',
229
+ async (
230
+ { key, file }: { key: string; file: FileInformation },
231
+ { getState }
232
+ ) => {
233
+ const state = getState();
234
+ const { user }: UserState = state['user'];
235
+ const { directory }: ConfigState = state[CONFIG_FEATURE_KEY];
236
+
237
+ let uri = file.dataUri;
238
+ if (!uri) {
239
+ const { data } = await axios.get(
240
+ `${getFileUrl(directory, file.urn).href}/download`,
241
+ {
242
+ responseType: 'arraybuffer',
243
+ headers: { Authorization: `Bearer ${user.access_token}` },
244
+ }
245
+ );
246
+ uri = URL.createObjectURL(new Blob([data]));
247
+
248
+ const anchor = document.createElement('a');
249
+ anchor.href = uri;
250
+ anchor.setAttribute('download', file.filename);
251
+ anchor.click();
252
+ }
253
+
254
+ return uri;
255
+ }
256
+ );
257
+
175
258
  const formSaved = createAction(
176
259
  '<%= propertyName %>/saved',
177
260
  (values: <%= className %>) => ({ payload: values })
@@ -185,7 +268,13 @@ const formSaveRejected = createAction(
185
268
  const queueSaveForm = createAsyncThunk(
186
269
  '<%= propertyName %>/queue-save',
187
270
  debounce(
188
- async (values: <%= className %>, { dispatch, getState }) => {
271
+ async (
272
+ {
273
+ values,
274
+ files,
275
+ }: { values: <%= className %>; files: Record<string, FileInformation> },
276
+ { dispatch, getState }
277
+ ) => {
189
278
  const state = getState();
190
279
  const { user }: UserState = state['user'];
191
280
  const { directory }: ConfigState = state[CONFIG_FEATURE_KEY];
@@ -194,7 +283,16 @@ const queueSaveForm = createAsyncThunk(
194
283
  try {
195
284
  await axios.put(
196
285
  `${directory[FORM_SERVICE_ID]}/form/v1/forms/${formId}/data`,
197
- { data: values },
286
+ {
287
+ data: values,
288
+ files: Object.entries(files).reduce((fileValues, [key, file]) => {
289
+ if (file) {
290
+ fileValues[key] = file.urn;
291
+ }
292
+
293
+ return fileValues;
294
+ }, {} as Record<string, string>),
295
+ },
198
296
  { headers: { Authorization: `Bearer ${user.access_token}` } }
199
297
  );
200
298
 
@@ -215,7 +313,7 @@ const queueSaveForm = createAsyncThunk(
215
313
 
216
314
  export const updateForm = createAsyncThunk(
217
315
  '<%= propertyName %>/update',
218
- async (values: <%= className %>, { dispatch }) => {
316
+ async (values: <%= className %>, { dispatch, getState }) => {
219
317
  const errors: Record<string, Record<string, boolean>> = {};
220
318
  let hasError = false;
221
319
  Object.entries(rules).forEach(([section, sectionRules]) => {
@@ -236,13 +334,73 @@ export const updateForm = createAsyncThunk(
236
334
  const complete = areSectionsComplete(values, errors);
237
335
 
238
336
  if (!hasError) {
239
- dispatch(queueSaveForm(values));
337
+ const { files }: <%= className %>State = getState()[<%= constantName %>_FEATURE_KEY];
338
+ dispatch(queueSaveForm({ values, files }));
240
339
  }
241
340
 
242
341
  return { values, complete, errors };
243
342
  }
244
343
  );
245
344
 
345
+ const setFileProgress = createAction(
346
+ '<%= propertyName %>/set-file-progress',
347
+ (key: string, progress: number) => {
348
+ return { payload: { key, progress } };
349
+ }
350
+ );
351
+
352
+ export const updateFile = createAsyncThunk(
353
+ '<%= propertyName %>/update-file',
354
+ async (
355
+ { key, old, file }: { key: string; old?: FileInformation; file?: File },
356
+ { dispatch, getState }
357
+ ) => {
358
+ const state = getState();
359
+ const { user }: UserState = state['user'];
360
+ const { directory }: ConfigState = state[CONFIG_FEATURE_KEY];
361
+ const { formId }: <%= className %>State = state[<%= constantName %>_FEATURE_KEY];
362
+
363
+ let newFile: FileInformation = null;
364
+ if (file) {
365
+ const formData = new FormData();
366
+ formData.append('type', FILE_TYPE_ID);
367
+ formData.append('recordId', formId);
368
+ formData.append('file', file);
369
+
370
+ const { data } = await axios.post<Omit<FileInformation, 'progress'>>(
371
+ `${directory[FILE_SERVICE_ID]}/file/v1/files`,
372
+ formData,
373
+ {
374
+ headers: { Authorization: `Bearer ${user.access_token}` },
375
+ onUploadProgress: ({ loaded, total }: ProgressEvent) => {
376
+ const progress = Math.floor((loaded * 100) / total);
377
+ dispatch(setFileProgress(key, progress));
378
+ },
379
+ }
380
+ );
381
+
382
+ newFile = {
383
+ urn: data.urn,
384
+ filename: data.filename,
385
+ size: data.size,
386
+ progress: 100,
387
+ };
388
+ }
389
+
390
+ if (old?.urn) {
391
+ await axios.delete(getFileUrl(directory, old.urn).href, {
392
+ headers: { Authorization: `Bearer ${user.access_token}` },
393
+ });
394
+ }
395
+
396
+ const { values, files }: <%= className %>State = getState()[<%= constantName %>_FEATURE_KEY];
397
+
398
+ dispatch(queueSaveForm({ values, files: { ...files, [key]: newFile } }));
399
+
400
+ return { key, file: newFile };
401
+ }
402
+ );
403
+
246
404
  export const submitForm = createAsyncThunk(
247
405
  '<%= propertyName %>/submit',
248
406
  async (_, { getState }) => {
@@ -269,10 +427,13 @@ export const initial<%= className %>State: <%= className %>State = {
269
427
  status: null,
270
428
  step: 1,
271
429
  values: {} as <%= className %>,
430
+ files: {},
272
431
  errors: {},
273
432
  complete: {},
274
433
  busy: {
275
434
  loading: false,
435
+ loadingFiles: false,
436
+ uploadingFile: false,
276
437
  saving: false,
277
438
  submitting: false,
278
439
  },
@@ -302,11 +463,49 @@ export const <%= propertyName %>Slice = createSlice({
302
463
  .addCase(initializeForm.rejected, (state) => {
303
464
  state.busy.loading = false;
304
465
  })
466
+ .addCase(getFileMetadata.pending, (state) => {
467
+ state.busy.loadingFiles = true;
468
+ })
469
+ .addCase(getFileMetadata.fulfilled, (state, action) => {
470
+ state.busy.loadingFiles = false;
471
+ state.files = action.payload;
472
+ })
473
+ .addCase(getFileMetadata.rejected, (state) => {
474
+ state.busy.loadingFiles = false;
475
+ })
476
+ .addCase(downloadFile.fulfilled, (state, action) => {
477
+ if (state.files[action.meta.arg.key]) {
478
+ state.files[action.meta.arg.key].dataUri = action.payload;
479
+ }
480
+ })
305
481
  .addCase(updateForm.fulfilled, (state, action) => {
306
482
  state.values = action.payload.values;
307
483
  state.complete = action.payload.complete;
308
484
  state.errors = action.payload.errors;
309
485
  })
486
+ .addCase(updateFile.pending, (state, action) => {
487
+ const file = action.meta.arg.file;
488
+ state.busy.uploadingFile = true;
489
+ state.files[action.meta.arg.key] = file
490
+ ? {
491
+ filename: file.name,
492
+ size: file.size,
493
+ progress: 0,
494
+ }
495
+ : null;
496
+ })
497
+ .addCase(updateFile.fulfilled, (state, action) => {
498
+ state.busy.uploadingFile = false;
499
+ state.files[action.payload.key] = action.payload.file;
500
+ })
501
+ .addCase(updateFile.rejected, (state) => {
502
+ state.busy.uploadingFile = false;
503
+ })
504
+ .addCase(setFileProgress, (state, action) => {
505
+ if (state.files[action.payload.key]) {
506
+ state.files[action.payload.key].progress = action.payload.progress;
507
+ }
508
+ })
310
509
  .addCase(queueSaveForm.pending, (state) => {
311
510
  state.busy.saving = true;
312
511
  })
@@ -393,6 +592,11 @@ export const getFormValues = createSelector(
393
592
  (state) => state.values
394
593
  );
395
594
 
595
+ export const getFormFiles = createSelector(
596
+ get<%= className %>State,
597
+ (state) => state.files
598
+ );
599
+
396
600
  export const getFormErrors = createSelector(
397
601
  get<%= className %>State,
398
602
  (state) => state.errors
@@ -6,9 +6,12 @@ import {
6
6
  GoADivider,
7
7
  GoADropdown,
8
8
  GoADropdownItem,
9
+ GoAFileUploadCard,
10
+ GoAFileUploadInput,
9
11
  GoAFormItem,
10
12
  GoAFormStep,
11
13
  GoAFormStepper,
14
+ GoAIconButton,
12
15
  GoAInput,
13
16
  GoAInputDate,
14
17
  GoAInputDateTime,
@@ -17,14 +20,20 @@ import {
17
20
  GoASpinner,
18
21
  GoATextArea,
19
22
  } from '@abgov/react-components';
20
- import { FunctionComponent, useEffect } from 'react';
23
+ import {
24
+ FunctionComponent,
25
+ useEffect,
26
+ useRef,
27
+ } from 'react';
21
28
  import { useDispatch, useSelector } from 'react-redux';
22
29
  import { AppDispatch } from '../../store';
23
30
  import {
31
+ FileInformation,
24
32
  getFormBusy,
25
33
  getFormCanSubmit,
26
34
  getFormComplete,
27
35
  getFormErrors,
36
+ getFormFiles,
28
37
  getFormInReview,
29
38
  getFormStatus,
30
39
  getFormStep,
@@ -33,6 +42,8 @@ import {
33
42
  submitForm,
34
43
  <%= propertyName %>Actions,
35
44
  updateForm,
45
+ updateFile,
46
+ downloadFile,
36
47
  } from './<%= fileName %>.slice';
37
48
  import styles from './<%= fileName %>.module.css';
38
49
 
@@ -50,13 +61,44 @@ function onArrayItemChange(
50
61
  onChange({ ...value, [arrayProperty]: updatedArray });
51
62
  }
52
63
 
64
+ interface FormFileProps {
65
+ property: string;
66
+ file: FileInformation;
67
+ }
68
+
69
+ const FormFile: FunctionComponent<FormFileProps> = ({ property, file }) => {
70
+ const anchorRef = useRef<HTMLAnchorElement>();
71
+ const dispatch = useDispatch<AppDispatch>();
72
+ return (
73
+ <div className={styles.formFile}>
74
+ <span>{file.filename}</span>
75
+ <GoAIconButton
76
+ ml="s"
77
+ icon="download"
78
+ onClick={() => {
79
+ if (file.dataUri) {
80
+ anchorRef.current.click();
81
+ } else {
82
+ dispatch(downloadFile({ key: property, file }));
83
+ }
84
+ }}
85
+ />
86
+ <a ref={anchorRef} href={file.dataUri} download={file.filename}>
87
+ Download
88
+ </a>
89
+ </div>
90
+ );
91
+ };
92
+
53
93
  interface FieldSetProps {
54
94
  className?: string;
55
95
  inReview: boolean;
56
96
  isReadOnly: boolean;
57
97
  value: Record<string, unknown>;
98
+ files: Record<string, FileInformation>;
58
99
  errors: Record<string, boolean>;
59
100
  onChange: (value: Record<string, unknown>) => void;
101
+ onFileChange: (key: string, old?: FileInformation, file?: File) => void;
60
102
  onEdit: () => void;
61
103
  }
62
104
 
@@ -66,8 +108,10 @@ const <%= section.className %>FieldSet: FunctionComponent<FieldSetProps> = ({
66
108
  inReview,
67
109
  isReadOnly,
68
110
  value,
111
+ files,
69
112
  errors,
70
113
  onChange,
114
+ onFileChange,
71
115
  onEdit,
72
116
  }) => {
73
117
  return (
@@ -95,6 +139,7 @@ export const <%= className %>Form: FunctionComponent = () => {
95
139
  const formStatus = useSelector(getFormStatus);
96
140
  const formStep = useSelector(getFormStep);
97
141
  const formData = useSelector(getFormValues);
142
+ const formFiles = useSelector(getFormFiles);
98
143
  const formErrors = useSelector(getFormErrors);
99
144
  const formBusy = useSelector(getFormBusy);
100
145
  const formComplete = useSelector(getFormComplete);
@@ -137,10 +182,14 @@ export const <%= className %>Form: FunctionComponent = () => {
137
182
  inReview={inReview}
138
183
  isReadOnly={formStatus !== 'draft'}
139
184
  value={formData.<%= sectionKey %> as any || {}}
185
+ files={formFiles}
140
186
  errors={formErrors['<%= sectionKey %>'] || {}}
141
187
  onChange={(value) =>
142
188
  dispatch(updateForm({ ...formData, '<%= sectionKey %>': value as any }))
143
189
  }
190
+ onFileChange={(key, old, file) =>
191
+ dispatch(updateFile({ key, old, file }))
192
+ }
144
193
  onEdit={() => dispatch(<%= propertyName %>Actions.setStep(<%= idx + 1 %>))}
145
194
  />
146
195
  <%_ }); _%>
@@ -44,6 +44,32 @@
44
44
  value={<%= valueVar %>.<%= key %> ? new Date(<%= valueVar %>.<%= key %> as string) : null}
45
45
  onChange={(name, updated) => <%- inArray ? `onArrayItemChange(onChange, value, '${parent}', idx, ` : 'onChange(' %>{ ...<%= valueVar %>, [name]: (updated as Date)?.toISOString() })}
46
46
  />
47
+ <%_ break;
48
+ case 'uri': _%>
49
+ <% if (!inArray) { %>
50
+ {files['<%= key %>'] ? (
51
+ isReadOnly || inReview ? (
52
+ <FormFile property="<%= key %>" file={files['<%= key %>']} />
53
+ ) : (
54
+ <GoAFileUploadCard
55
+ filename={files['<%= key %>'].filename}
56
+ size={files['<%= key %>'].size}
57
+ progress={files['<%= key %>'].progress}
58
+ onDelete={() => onFileChange('<%= key %>', files['<%= key %>'])}
59
+ />
60
+ )
61
+ ) : (
62
+ !isReadOnly &&
63
+ !inReview && (
64
+ <GoAFileUploadInput
65
+ variant="dragdrop"
66
+ onSelectFile={(file) =>
67
+ onFileChange('<%= key %>', files['<%= key %>'], file)
68
+ }
69
+ />
70
+ )
71
+ )}
72
+ <% } %>
47
73
  <%_ break;
48
74
  default: _%>
49
75
  <% if (property.maxLength > 100) { %>
@@ -20,13 +20,13 @@ function getFormDefinition(configurationServiceUrl, token) {
20
20
  if (choices.length < 1) {
21
21
  throw new Error('No form definitions with data schema found.');
22
22
  }
23
- const result = yield (0, enquirer_1.prompt)({
23
+ const { definition } = yield (0, enquirer_1.prompt)({
24
24
  type: 'autocomplete',
25
25
  name: 'definition',
26
26
  message: 'Which form definition do you want to generate a component for?',
27
27
  choices,
28
28
  });
29
- const formDefinition = definitions.find((r) => r.name === result.definition);
29
+ const formDefinition = definitions.find((r) => r.name === definition);
30
30
  const general = {
31
31
  type: 'object',
32
32
  className: 'General',
@@ -46,6 +46,29 @@ function getFormDefinition(configurationServiceUrl, token) {
46
46
  if (addGeneral) {
47
47
  formDefinition.dataSchema.properties = Object.assign({ general }, formDefinition.dataSchema.properties);
48
48
  }
49
+ const fileTypeName = `${formDefinition.name} files`;
50
+ const fileTypeId = `${(0, devkit_1.names)(formDefinition.name).fileName}-files`;
51
+ const { addFileType } = yield (0, enquirer_1.prompt)({
52
+ type: 'confirm',
53
+ name: 'addFileType',
54
+ message: `Create file type (${fileTypeName}) for form files?`,
55
+ });
56
+ if (addFileType) {
57
+ yield axios_1.default.patch(new URL('configuration/v2/configuration/platform/file-service', configurationServiceUrl).href, {
58
+ operation: 'UPDATE',
59
+ update: {
60
+ [fileTypeId]: {
61
+ id: fileTypeId,
62
+ name: fileTypeName,
63
+ readRoles: formDefinition.assessorRoles,
64
+ updateRoles: formDefinition.applicantRoles,
65
+ anonymousRead: false,
66
+ },
67
+ },
68
+ }, {
69
+ headers: { Authorization: `Bearer ${token}` },
70
+ });
71
+ }
49
72
  return formDefinition;
50
73
  });
51
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"react-form.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/react-form/react-form.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"react-form.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/react-form/react-form.ts"],"names":[],"mappings":"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"}
@@ -48,6 +48,8 @@ const formDefinition: FormDefinition = {
48
48
  },
49
49
  },
50
50
  },
51
+ assessorRoles: [],
52
+ applicantRoles: [],
51
53
  };
52
54
 
53
55
  jest.mock('@abgov/nx-oc');
@@ -69,7 +71,8 @@ axiosMock.get.mockResolvedValueOnce({
69
71
 
70
72
  jest.mock('enquirer', () => ({ prompt: jest.fn() }));
71
73
  const promptMock = prompt as jest.Mock;
72
- promptMock.mockResolvedValue({ definition: 'Some Intake' });
74
+ promptMock.mockResolvedValueOnce({ definition: 'Some Intake' });
75
+ promptMock.mockResolvedValueOnce({ addFileType: false });
73
76
 
74
77
  describe('React Form Generator', () => {
75
78
  const options: Schema = {
@@ -91,7 +94,9 @@ describe('React Form Generator', () => {
91
94
  });
92
95
 
93
96
  await generator(host, options);
94
- expect(host.exists('apps/test/src/app/some-intake/some-intake.tsx')).toBeTruthy();
97
+ expect(
98
+ host.exists('apps/test/src/app/some-intake/some-intake.tsx')
99
+ ).toBeTruthy();
95
100
  expect(
96
101
  host.exists('apps/test/src/app/some-intake/some-intake.slice.ts')
97
102
  ).toBeTruthy();
@@ -2,5 +2,7 @@ export interface FormDefinition {
2
2
  id: string;
3
3
  name: string;
4
4
  dataSchema: Record<string, unknown>;
5
+ assessorRoles: string[];
6
+ applicantRoles: string[];
5
7
  }
6
8
  export declare function generateFormInterface({ name, dataSchema, }: FormDefinition): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","sourceRoot":"","sources":["../../../../../packages/nx-adsp/src/utils/form.ts"],"names":[],"mappings":";;;;AAAA,yEAAoD;AAQpD,SAAsB,qBAAqB,CAAC,EAC1C,IAAI,EACJ,UAAU,GACK;;QACf,MAAM,KAAK,GAAG,MAAM,IAAA,mCAAO,EAAC,UAAU,EAAE,IAAI,EAAE;YAC5C,oBAAoB,EAAE,KAAK;YAC3B,aAAa,EAAE,EAAE;YACjB,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC;IACf,CAAC;CAAA;AAXD,sDAWC"}
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../../../../../packages/nx-adsp/src/utils/form.ts"],"names":[],"mappings":";;;;AAAA,yEAAoD;AAUpD,SAAsB,qBAAqB,CAAC,EAC1C,IAAI,EACJ,UAAU,GACK;;QACf,MAAM,KAAK,GAAG,MAAM,IAAA,mCAAO,EAAC,UAAU,EAAE,IAAI,EAAE;YAC5C,oBAAoB,EAAE,KAAK;YAC3B,aAAa,EAAE,EAAE;YACjB,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC;IACf,CAAC;CAAA;AAXD,sDAWC"}