@openmrs/esm-form-builder-app 3.5.2-pre.3735 → 3.5.2-pre.3740
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/dist/2403.js +1 -0
- package/dist/2403.js.map +1 -0
- package/dist/3378.js +1 -1
- package/dist/3378.js.map +1 -1
- package/dist/4442.js +1 -0
- package/dist/4442.js.map +1 -0
- package/dist/5789.js +1 -0
- package/dist/5789.js.map +1 -0
- package/dist/{9969.js → 8237.js} +1 -1
- package/dist/8237.js.map +1 -0
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-form-builder-app.js +2 -2
- package/dist/openmrs-esm-form-builder-app.js.buildmanifest.json +106 -55
- package/dist/openmrs-esm-form-builder-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/components/action-buttons/action-buttons.component.tsx +20 -3
- package/src/components/interactive-builder/modals/save-form/save-form.modal.tsx +215 -255
- package/src/components/interactive-builder/modals/save-form/save-form.scss +0 -5
- package/src/components/interactive-builder/modals/save-form/save-form.test.tsx +192 -0
- package/src/index.ts +5 -0
- package/src/routes.json +4 -0
- package/dist/4169.js +0 -1
- package/dist/4169.js.map +0 -1
- package/dist/9969.js.map +0 -1
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { useParams } from 'react-router-dom';
|
|
4
3
|
import {
|
|
5
4
|
Button,
|
|
6
|
-
ComposedModal,
|
|
7
5
|
Form,
|
|
8
6
|
FormGroup,
|
|
9
7
|
InlineLoading,
|
|
@@ -43,22 +41,21 @@ interface FormGroupData {
|
|
|
43
41
|
interface SaveFormModalProps {
|
|
44
42
|
form: FormGroupData;
|
|
45
43
|
schema: Schema;
|
|
44
|
+
formUuid?: string;
|
|
45
|
+
closeModal: () => void;
|
|
46
|
+
onSavingChange?: (isSaving: boolean) => void;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
const SaveFormModal: React.FC<SaveFormModalProps> = ({ form, schema }) => {
|
|
49
|
+
const SaveFormModal: React.FC<SaveFormModalProps> = ({ form, schema, formUuid, closeModal, onSavingChange }) => {
|
|
49
50
|
const { t } = useTranslation();
|
|
50
51
|
const { encounterTypes } = useEncounterTypes();
|
|
51
|
-
const { formUuid } = useParams<{ formUuid: string }>();
|
|
52
52
|
const { mutate } = useForm(formUuid);
|
|
53
|
-
const isSavingNewForm = !formUuid;
|
|
54
53
|
const [description, setDescription] = useState('');
|
|
55
54
|
const [encounterType, setEncounterType] = useState('');
|
|
56
55
|
const [isInvalidVersion, setIsInvalidVersion] = useState(false);
|
|
57
56
|
const [isSavingForm, setIsSavingForm] = useState(false);
|
|
58
57
|
const [name, setName] = useState('');
|
|
59
|
-
const [
|
|
60
|
-
const [openSaveFormModal, setOpenSaveFormModal] = useState(false);
|
|
61
|
-
const [saveState, setSaveState] = useState('');
|
|
58
|
+
const [saveState, setSaveState] = useState<'update' | 'newVersion' | null>(formUuid ? null : 'newVersion');
|
|
62
59
|
const [version, setVersion] = useState('');
|
|
63
60
|
|
|
64
61
|
const clearDraftFormSchema = useCallback(() => localStorage.removeItem('formJSON'), []);
|
|
@@ -78,285 +75,248 @@ const SaveFormModal: React.FC<SaveFormModalProps> = ({ form, schema }) => {
|
|
|
78
75
|
setIsInvalidVersion(!/^[0-9]/.test(version));
|
|
79
76
|
};
|
|
80
77
|
|
|
81
|
-
const openModal = useCallback((option: string) => {
|
|
82
|
-
if (option === 'newVersion') {
|
|
83
|
-
setSaveState('newVersion');
|
|
84
|
-
setOpenConfirmSaveModal(false);
|
|
85
|
-
setOpenSaveFormModal(true);
|
|
86
|
-
} else if (option === 'new') {
|
|
87
|
-
setSaveState('newVersion');
|
|
88
|
-
setOpenSaveFormModal(true);
|
|
89
|
-
} else if (option === 'update') {
|
|
90
|
-
setSaveState('update');
|
|
91
|
-
setOpenConfirmSaveModal(false);
|
|
92
|
-
setOpenSaveFormModal(true);
|
|
93
|
-
}
|
|
94
|
-
}, []);
|
|
95
|
-
|
|
96
78
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
97
79
|
event.preventDefault();
|
|
98
80
|
setIsSavingForm(true);
|
|
81
|
+
onSavingChange?.(true);
|
|
82
|
+
try {
|
|
83
|
+
if (saveState === 'newVersion') {
|
|
84
|
+
try {
|
|
85
|
+
const newForm = await saveNewForm(name, version, false, description, encounterType);
|
|
99
86
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const name = target.name.value,
|
|
109
|
-
version = target.version.value,
|
|
110
|
-
encounterType = target.encounterType.value,
|
|
111
|
-
description = target.description.value;
|
|
87
|
+
const updatedSchema = {
|
|
88
|
+
...schema,
|
|
89
|
+
name: name,
|
|
90
|
+
version: version,
|
|
91
|
+
description: description,
|
|
92
|
+
encounterType: encounterType,
|
|
93
|
+
uuid: newForm.uuid,
|
|
94
|
+
};
|
|
112
95
|
|
|
113
|
-
|
|
114
|
-
|
|
96
|
+
let newValueReference: string | undefined;
|
|
97
|
+
try {
|
|
98
|
+
newValueReference = (await uploadSchema(updatedSchema)).toString();
|
|
99
|
+
await getResourceUuid(newForm.uuid, newValueReference);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
// Clean up the orphaned clobdata and form since schema upload or linking failed
|
|
102
|
+
if (newValueReference) {
|
|
103
|
+
await deleteClobdata(newValueReference).catch(() => {});
|
|
104
|
+
}
|
|
105
|
+
await deleteForm(newForm.uuid).catch(() => {});
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
115
108
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
109
|
+
showSnackbar({
|
|
110
|
+
title: t('formCreated', 'New form created'),
|
|
111
|
+
kind: 'success',
|
|
112
|
+
isLowContrast: true,
|
|
113
|
+
subtitle:
|
|
114
|
+
name +
|
|
115
|
+
' ' +
|
|
116
|
+
t('saveSuccessMessage', 'was created successfully. It is now visible on the Forms dashboard.'),
|
|
117
|
+
});
|
|
118
|
+
clearDraftFormSchema();
|
|
119
|
+
closeModal();
|
|
120
|
+
await mutate();
|
|
124
121
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
await getResourceUuid(newForm.uuid, newValueReference);
|
|
122
|
+
navigate({
|
|
123
|
+
to: `${window.spaBase}/form-builder/edit/${newForm.uuid}`,
|
|
124
|
+
});
|
|
129
125
|
} catch (error) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
126
|
+
if (error instanceof Error) {
|
|
127
|
+
showSnackbar({
|
|
128
|
+
title: t('errorCreatingForm', 'Error creating form'),
|
|
129
|
+
kind: 'error',
|
|
130
|
+
subtitle: error?.message,
|
|
131
|
+
});
|
|
133
132
|
}
|
|
134
|
-
await deleteForm(newForm.uuid).catch(() => {});
|
|
135
|
-
throw error;
|
|
136
133
|
}
|
|
134
|
+
} else {
|
|
135
|
+
try {
|
|
136
|
+
const updatedSchema = {
|
|
137
|
+
...schema,
|
|
138
|
+
name: name,
|
|
139
|
+
version: version,
|
|
140
|
+
description: description,
|
|
141
|
+
encounterType: encounterType,
|
|
142
|
+
};
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
title: t('formCreated', 'New form created'),
|
|
140
|
-
kind: 'success',
|
|
141
|
-
isLowContrast: true,
|
|
142
|
-
subtitle:
|
|
143
|
-
name + ' ' + t('saveSuccessMessage', 'was created successfully. It is now visible on the Forms dashboard.'),
|
|
144
|
-
});
|
|
145
|
-
clearDraftFormSchema();
|
|
146
|
-
setOpenSaveFormModal(false);
|
|
147
|
-
await mutate();
|
|
144
|
+
await updateForm(form.uuid, name, version, description, encounterType);
|
|
148
145
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
const oldResource = form?.resources?.length
|
|
147
|
+
? form.resources.find(({ name }) => name === 'JSON schema')
|
|
148
|
+
: undefined;
|
|
152
149
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (error instanceof Error) {
|
|
156
|
-
showSnackbar({
|
|
157
|
-
title: t('errorCreatingForm', 'Error creating form'),
|
|
158
|
-
kind: 'error',
|
|
159
|
-
subtitle: error?.message,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
setIsSavingForm(false);
|
|
163
|
-
}
|
|
164
|
-
} else {
|
|
165
|
-
try {
|
|
166
|
-
const updatedSchema = {
|
|
167
|
-
...schema,
|
|
168
|
-
name: name,
|
|
169
|
-
version: version,
|
|
170
|
-
description: description,
|
|
171
|
-
encounterType: encounterType,
|
|
172
|
-
};
|
|
150
|
+
// Upload the new clobdata first (doesn't affect the live form yet)
|
|
151
|
+
const newValueReference = (await uploadSchema(updatedSchema)).toString();
|
|
173
152
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
153
|
+
// Swap: remove old resource link, then link the new clobdata.
|
|
154
|
+
// If the swap fails, clean up the newly uploaded clobdata.
|
|
155
|
+
try {
|
|
156
|
+
if (oldResource) {
|
|
157
|
+
await deleteResource(form.uuid, oldResource.uuid);
|
|
158
|
+
}
|
|
159
|
+
await getResourceUuid(form.uuid, newValueReference);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
await deleteClobdata(newValueReference).catch(() => {});
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
182
164
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
try {
|
|
165
|
+
// Clean up old clobdata. If this fails, the form still works
|
|
166
|
+
// (just an orphaned clobdata row in the database).
|
|
186
167
|
if (oldResource) {
|
|
187
|
-
await
|
|
168
|
+
await deleteClobdata(oldResource.valueReference).catch(() => {});
|
|
188
169
|
}
|
|
189
|
-
await getResourceUuid(form.uuid, newValueReference);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
await deleteClobdata(newValueReference).catch(() => {});
|
|
192
|
-
throw error;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Clean up old clobdata. If this fails, the form still works
|
|
196
|
-
// (just an orphaned clobdata row in the database).
|
|
197
|
-
if (oldResource) {
|
|
198
|
-
await deleteClobdata(oldResource.valueReference).catch(() => {});
|
|
199
|
-
}
|
|
200
170
|
|
|
201
|
-
showSnackbar({
|
|
202
|
-
title: t('success', 'Success!'),
|
|
203
|
-
kind: 'success',
|
|
204
|
-
isLowContrast: true,
|
|
205
|
-
subtitle: form?.name + ' ' + t('saveSuccess', 'was updated successfully'),
|
|
206
|
-
});
|
|
207
|
-
setOpenSaveFormModal(false);
|
|
208
|
-
await mutate();
|
|
209
|
-
setIsSavingForm(false);
|
|
210
|
-
} catch (error) {
|
|
211
|
-
if (error instanceof Error) {
|
|
212
171
|
showSnackbar({
|
|
213
|
-
title: t('
|
|
214
|
-
kind: '
|
|
215
|
-
|
|
172
|
+
title: t('success', 'Success!'),
|
|
173
|
+
kind: 'success',
|
|
174
|
+
isLowContrast: true,
|
|
175
|
+
subtitle: form?.name + ' ' + t('saveSuccess', 'was updated successfully'),
|
|
216
176
|
});
|
|
177
|
+
closeModal();
|
|
178
|
+
await mutate();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (error instanceof Error) {
|
|
181
|
+
showSnackbar({
|
|
182
|
+
title: t('errorUpdatingForm', 'Error updating form'),
|
|
183
|
+
kind: 'error',
|
|
184
|
+
subtitle: error?.message,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
217
187
|
}
|
|
218
|
-
|
|
219
|
-
setIsSavingForm(false);
|
|
220
188
|
}
|
|
189
|
+
} finally {
|
|
190
|
+
setIsSavingForm(false);
|
|
191
|
+
onSavingChange?.(false);
|
|
221
192
|
}
|
|
222
193
|
};
|
|
223
194
|
|
|
195
|
+
if (saveState === null) {
|
|
196
|
+
return (
|
|
197
|
+
<>
|
|
198
|
+
<ModalHeader closeModal={closeModal} title={t('saveConfirmation', 'Save or Update form')} />
|
|
199
|
+
<ModalBody>
|
|
200
|
+
<p>
|
|
201
|
+
{t(
|
|
202
|
+
'saveAsModal',
|
|
203
|
+
"A version of the form you're working on already exists on the server. Do you want to update the form or to save it as a new version?",
|
|
204
|
+
)}
|
|
205
|
+
</p>
|
|
206
|
+
</ModalBody>
|
|
207
|
+
<ModalFooter>
|
|
208
|
+
<Button kind={'tertiary'} onClick={() => setSaveState('update')}>
|
|
209
|
+
{t('updateExistingForm', 'Update existing version')}
|
|
210
|
+
</Button>
|
|
211
|
+
<Button kind={'primary'} onClick={() => setSaveState('newVersion')}>
|
|
212
|
+
{t('saveAsNewForm', 'Save as a new form')}
|
|
213
|
+
</Button>
|
|
214
|
+
<Button kind={'secondary'} onClick={closeModal}>
|
|
215
|
+
{t('close', 'Close')}
|
|
216
|
+
</Button>
|
|
217
|
+
</ModalFooter>
|
|
218
|
+
</>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
224
222
|
return (
|
|
225
223
|
<>
|
|
226
|
-
{
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
{t('saveAsNewForm', 'Save as a new form')}
|
|
247
|
-
</Button>
|
|
248
|
-
<Button kind={'secondary'} onClick={() => setOpenConfirmSaveModal(false)}>
|
|
249
|
-
{t('close', 'Close')}
|
|
250
|
-
</Button>
|
|
251
|
-
</ModalFooter>
|
|
252
|
-
</ComposedModal>
|
|
253
|
-
) : null}
|
|
254
|
-
|
|
255
|
-
<ComposedModal open={openSaveFormModal} onClose={() => setOpenSaveFormModal(false)} preventCloseOnClickOutside>
|
|
256
|
-
<ModalHeader title={t('saveFormToServer', 'Save form to server')} />
|
|
257
|
-
<Form onSubmit={handleSubmit} className={styles.saveFormBody}>
|
|
258
|
-
<ModalBody>
|
|
259
|
-
<p>
|
|
260
|
-
{t(
|
|
261
|
-
'saveExplainerText',
|
|
262
|
-
'Clicking the Save button saves your form schema to the database. To see your form in your frontend, you first need to publish it. Click the Publish button to publish your form.',
|
|
263
|
-
)}
|
|
264
|
-
</p>
|
|
265
|
-
<FormGroup legendText={''}>
|
|
266
|
-
<Stack gap={5}>
|
|
224
|
+
<ModalHeader closeModal={closeModal} title={t('saveFormToServer', 'Save form to server')} />
|
|
225
|
+
<ModalBody>
|
|
226
|
+
<Form id="save-form" onSubmit={handleSubmit}>
|
|
227
|
+
<p>
|
|
228
|
+
{t(
|
|
229
|
+
'saveExplainerText',
|
|
230
|
+
'Clicking the Save button saves your form schema to the database. To see your form in your frontend, you first need to publish it. Click the Publish button to publish your form.',
|
|
231
|
+
)}
|
|
232
|
+
</p>
|
|
233
|
+
<FormGroup legendText={''}>
|
|
234
|
+
<Stack gap={5}>
|
|
235
|
+
<TextInput
|
|
236
|
+
id="name"
|
|
237
|
+
labelText={t('formName', 'Form Name')}
|
|
238
|
+
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setName(event.target.value)}
|
|
239
|
+
placeholder={t('formNamePlaceholder', 'e.g. OHRI Express Care Patient Encounter Form')}
|
|
240
|
+
required
|
|
241
|
+
value={name}
|
|
242
|
+
/>
|
|
243
|
+
{saveState === 'update' ? (
|
|
267
244
|
<TextInput
|
|
268
|
-
id="
|
|
269
|
-
labelText={t('
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
required
|
|
273
|
-
value={name}
|
|
245
|
+
id="uuid"
|
|
246
|
+
labelText={t('autogeneratedUuid', 'UUID (auto-generated)')}
|
|
247
|
+
disabled
|
|
248
|
+
value={form?.uuid}
|
|
274
249
|
/>
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
250
|
+
) : null}
|
|
251
|
+
<TextInput
|
|
252
|
+
id="version"
|
|
253
|
+
labelText={t('version', 'Version')}
|
|
254
|
+
placeholder={t('versionPlaceholder', 'e.g. 1.0')}
|
|
255
|
+
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
256
|
+
checkVersionValidity(event.target.value);
|
|
257
|
+
|
|
258
|
+
if (!isInvalidVersion) {
|
|
259
|
+
setVersion(event.target.value);
|
|
260
|
+
}
|
|
261
|
+
}}
|
|
262
|
+
invalid={isInvalidVersion}
|
|
263
|
+
invalidText={t('invalidVersionWarning', 'Version can only start with with a number')}
|
|
264
|
+
required
|
|
265
|
+
value={version}
|
|
266
|
+
/>
|
|
267
|
+
<Select
|
|
268
|
+
id="encounterType"
|
|
269
|
+
labelText={t('encounterType', 'Encounter Type')}
|
|
270
|
+
onChange={(event: React.ChangeEvent<HTMLSelectElement>) => setEncounterType(event.target.value)}
|
|
271
|
+
required
|
|
272
|
+
value={encounterType}
|
|
273
|
+
>
|
|
274
|
+
{!encounterType ? (
|
|
275
|
+
<SelectItem
|
|
276
|
+
text={t('chooseEncounterType', 'Choose an encounter type to link your form to')}
|
|
277
|
+
value=""
|
|
281
278
|
/>
|
|
282
279
|
) : null}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
required
|
|
304
|
-
value={encounterType}
|
|
305
|
-
>
|
|
306
|
-
{!encounterType ? (
|
|
307
|
-
<SelectItem
|
|
308
|
-
text={t('chooseEncounterType', 'Choose an encounter type to link your form to')}
|
|
309
|
-
value=""
|
|
310
|
-
/>
|
|
311
|
-
) : null}
|
|
312
|
-
{encounterTypes?.length > 0 &&
|
|
313
|
-
encounterTypes.map((encounterType) => (
|
|
314
|
-
<SelectItem key={encounterType.uuid} value={encounterType.uuid} text={encounterType.name}>
|
|
315
|
-
{encounterType.name}
|
|
316
|
-
</SelectItem>
|
|
317
|
-
))}
|
|
318
|
-
</Select>
|
|
319
|
-
<TextArea
|
|
320
|
-
labelText={t('description', 'Description')}
|
|
321
|
-
onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => setDescription(event.target.value)}
|
|
322
|
-
id="description"
|
|
323
|
-
placeholder={t(
|
|
324
|
-
'descriptionPlaceholderText',
|
|
325
|
-
'e.g. A form used to collect encounter data for clients in the Express Care program.',
|
|
326
|
-
)}
|
|
327
|
-
required
|
|
328
|
-
value={description}
|
|
329
|
-
/>
|
|
330
|
-
</Stack>
|
|
331
|
-
</FormGroup>
|
|
332
|
-
</ModalBody>
|
|
333
|
-
<ModalFooter>
|
|
334
|
-
<Button kind={'secondary'} onClick={() => setOpenSaveFormModal(false)}>
|
|
335
|
-
{t('close', 'Close')}
|
|
336
|
-
</Button>
|
|
337
|
-
<Button
|
|
338
|
-
disabled={isSavingForm || isInvalidVersion}
|
|
339
|
-
className={styles.spinner}
|
|
340
|
-
type={'submit'}
|
|
341
|
-
kind={'primary'}
|
|
342
|
-
>
|
|
343
|
-
{isSavingForm ? (
|
|
344
|
-
<InlineLoading description={t('saving', 'Saving') + '...'} />
|
|
345
|
-
) : (
|
|
346
|
-
<span>{t('save', 'Save')}</span>
|
|
347
|
-
)}
|
|
348
|
-
</Button>
|
|
349
|
-
</ModalFooter>
|
|
280
|
+
{encounterTypes?.length > 0 &&
|
|
281
|
+
encounterTypes.map((encounterType) => (
|
|
282
|
+
<SelectItem key={encounterType.uuid} value={encounterType.uuid} text={encounterType.name}>
|
|
283
|
+
{encounterType.name}
|
|
284
|
+
</SelectItem>
|
|
285
|
+
))}
|
|
286
|
+
</Select>
|
|
287
|
+
<TextArea
|
|
288
|
+
labelText={t('description', 'Description')}
|
|
289
|
+
onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => setDescription(event.target.value)}
|
|
290
|
+
id="description"
|
|
291
|
+
placeholder={t(
|
|
292
|
+
'descriptionPlaceholderText',
|
|
293
|
+
'e.g. A form used to collect encounter data for clients in the Express Care program.',
|
|
294
|
+
)}
|
|
295
|
+
required
|
|
296
|
+
value={description}
|
|
297
|
+
/>
|
|
298
|
+
</Stack>
|
|
299
|
+
</FormGroup>
|
|
350
300
|
</Form>
|
|
351
|
-
</
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
301
|
+
</ModalBody>
|
|
302
|
+
<ModalFooter>
|
|
303
|
+
<Button kind={'secondary'} onClick={closeModal}>
|
|
304
|
+
{t('close', 'Close')}
|
|
305
|
+
</Button>
|
|
306
|
+
<Button
|
|
307
|
+
disabled={isSavingForm || isInvalidVersion}
|
|
308
|
+
className={styles.spinner}
|
|
309
|
+
type={'submit'}
|
|
310
|
+
form="save-form"
|
|
311
|
+
kind={'primary'}
|
|
312
|
+
>
|
|
313
|
+
{isSavingForm ? (
|
|
314
|
+
<InlineLoading description={t('saving', 'Saving') + '...'} />
|
|
315
|
+
) : (
|
|
316
|
+
<span>{t('save', 'Save')}</span>
|
|
317
|
+
)}
|
|
318
|
+
</Button>
|
|
319
|
+
</ModalFooter>
|
|
360
320
|
</>
|
|
361
321
|
);
|
|
362
322
|
};
|