@openmrs/esm-form-builder-app 2.0.2-pre.559 → 2.0.2-pre.568

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.
@@ -231,344 +231,335 @@ const EditQuestionModal: React.FC<EditQuestionModalProps> = ({
231
231
  onSubmit={(event) => event.preventDefault()}
232
232
  >
233
233
  <ModalBody hasScrollingContent>
234
- <FormGroup legendText={""}>
235
- <Stack gap={5}>
236
- <TextInput
237
- defaultValue={questionToEdit.label}
238
- id={questionToEdit.id}
239
- labelText={t("questionLabel", "Label")}
240
- onChange={(event) => setQuestionLabel(event.target.value)}
241
- required
242
- />
234
+ <Stack gap={5}>
235
+ <TextInput
236
+ defaultValue={questionToEdit.label}
237
+ id={questionToEdit.id}
238
+ labelText={t("questionLabel", "Label")}
239
+ onChange={(event) => setQuestionLabel(event.target.value)}
240
+ required
241
+ />
243
242
 
244
- <TextInput
245
- defaultValue={questionToEdit.id}
246
- id="questionId"
247
- invalid={questionIdExists(questionId)}
248
- invalidText={t(
249
- "questionIdExists",
250
- "This question ID already exists in your schema"
251
- )}
252
- labelText={t(
253
- "questionId",
254
- "Question ID (prefer using camel-case for IDs)"
255
- )}
256
- onChange={(event) => setQuestionId(event.target.value)}
257
- placeholder={t(
258
- "questionIdPlaceholder",
259
- 'Enter a unique ID e.g. "anaesthesiaType" for a question asking about the type of anaesthesia.'
260
- )}
261
- required
243
+ <TextInput
244
+ defaultValue={questionToEdit.id}
245
+ id="questionId"
246
+ invalid={questionIdExists(questionId)}
247
+ invalidText={t(
248
+ "questionIdExists",
249
+ "This question ID already exists in your schema"
250
+ )}
251
+ labelText={t(
252
+ "questionId",
253
+ "Question ID (prefer using camel-case for IDs)"
254
+ )}
255
+ onChange={(event) => setQuestionId(event.target.value)}
256
+ placeholder={t(
257
+ "questionIdPlaceholder",
258
+ 'Enter a unique ID e.g. "anaesthesiaType" for a question asking about the type of anaesthesia.'
259
+ )}
260
+ required
261
+ />
262
+
263
+ <RadioButtonGroup
264
+ defaultSelected={
265
+ /true/.test(questionToEdit?.required?.toString())
266
+ ? "required"
267
+ : "optional"
268
+ }
269
+ name="isQuestionRequired"
270
+ legendText={t(
271
+ "isQuestionRequiredOrOptional",
272
+ "Is this question a required or optional field? Required fields must be answered before the form can be submitted."
273
+ )}
274
+ >
275
+ <RadioButton
276
+ id="questionIsNotRequired"
277
+ defaultChecked={true}
278
+ labelText={t("optional", "Optional")}
279
+ onClick={() => setIsQuestionRequired(false)}
280
+ value="optional"
262
281
  />
282
+ <RadioButton
283
+ id="questionIsRequired"
284
+ defaultChecked={false}
285
+ labelText={t("required", "Required")}
286
+ onClick={() => setIsQuestionRequired(true)}
287
+ value="required"
288
+ />
289
+ </RadioButtonGroup>
263
290
 
264
- <RadioButtonGroup
265
- defaultSelected={
266
- /true/.test(questionToEdit?.required?.toString())
267
- ? "required"
268
- : "optional"
269
- }
270
- name="isQuestionRequired"
271
- legendText={t(
272
- "isQuestionRequiredOrOptional",
273
- "Is this question a required or optional field? Required fields must be answered before the form can be submitted."
274
- )}
275
- >
276
- <RadioButton
277
- id="questionIsNotRequired"
278
- defaultChecked={true}
279
- labelText={t("optional", "Optional")}
280
- onClick={() => setIsQuestionRequired(false)}
281
- value="optional"
291
+ <Select
292
+ defaultValue={questionToEdit.type}
293
+ onChange={(event) => setQuestionType(event.target.value)}
294
+ id={"questionType"}
295
+ invalidText={t("typeRequired", "Type is required")}
296
+ labelText={t("questionType", "Question type")}
297
+ required
298
+ >
299
+ {!questionType && (
300
+ <SelectItem
301
+ text={t("chooseQuestionType", "Choose a question type")}
302
+ value=""
282
303
  />
283
- <RadioButton
284
- id="questionIsRequired"
285
- defaultChecked={false}
286
- labelText={t("required", "Required")}
287
- onClick={() => setIsQuestionRequired(true)}
288
- value="required"
304
+ )}
305
+ {questionTypes.map((questionType, key) => (
306
+ <SelectItem
307
+ text={questionType}
308
+ value={questionType}
309
+ key={key}
289
310
  />
290
- </RadioButtonGroup>
311
+ ))}
312
+ </Select>
291
313
 
292
- <Select
293
- defaultValue={questionToEdit.type}
294
- onChange={(event) => setQuestionType(event.target.value)}
295
- id={"questionType"}
296
- invalidText={t("typeRequired", "Type is required")}
297
- labelText={t("questionType", "Question type")}
298
- required
299
- >
300
- {!questionType && (
301
- <SelectItem
302
- text={t("chooseQuestionType", "Choose a question type")}
303
- value=""
304
- />
305
- )}
306
- {questionTypes.map((questionType, key) => (
307
- <SelectItem
308
- text={questionType}
309
- value={questionType}
310
- key={key}
311
- />
312
- ))}
313
- </Select>
314
-
315
- <Select
316
- defaultValue={questionToEdit.questionOptions.rendering}
317
- onChange={(event) => setFieldType(event.target.value)}
318
- id="renderingType"
319
- invalidText={t(
320
- "validFieldTypeRequired",
321
- "A valid field type value is required"
322
- )}
323
- labelText={t("fieldType", "Field type")}
324
- required
325
- >
326
- {!fieldType && (
327
- <SelectItem
328
- text={t("chooseFieldType", "Choose a field type")}
329
- value=""
330
- />
331
- )}
332
- {fieldTypes.map((fieldType, key) => (
333
- <SelectItem text={fieldType} value={fieldType} key={key} />
334
- ))}
335
- </Select>
314
+ <Select
315
+ defaultValue={questionToEdit.questionOptions.rendering}
316
+ onChange={(event) => setFieldType(event.target.value)}
317
+ id="renderingType"
318
+ invalidText={t(
319
+ "validFieldTypeRequired",
320
+ "A valid field type value is required"
321
+ )}
322
+ labelText={t("fieldType", "Field type")}
323
+ required
324
+ >
325
+ {!fieldType && (
326
+ <SelectItem
327
+ text={t("chooseFieldType", "Choose a field type")}
328
+ value=""
329
+ />
330
+ )}
331
+ {fieldTypes.map((fieldType, key) => (
332
+ <SelectItem text={fieldType} value={fieldType} key={key} />
333
+ ))}
334
+ </Select>
336
335
 
337
- {fieldType === "number" ? (
338
- <>
339
- <TextInput
340
- id="min"
341
- labelText="Min"
342
- value={min || ""}
343
- onChange={(event) => setMin(event.target.value)}
344
- required
345
- />
346
- <TextInput
347
- id="max"
348
- labelText="Max"
349
- value={max || ""}
350
- onChange={(event) => setMax(event.target.value)}
351
- required
352
- />
353
- </>
354
- ) : fieldType === "textarea" ? (
336
+ {fieldType === "number" ? (
337
+ <>
355
338
  <TextInput
356
- id="textAreaRows"
357
- labelText={t("rows", "Rows")}
358
- value={rows || ""}
359
- onChange={(event) => setRows(event.target.value)}
339
+ id="min"
340
+ labelText="Min"
341
+ value={min || ""}
342
+ onChange={(event) => setMin(event.target.value)}
360
343
  required
361
344
  />
362
- ) : null}
345
+ <TextInput
346
+ id="max"
347
+ labelText="Max"
348
+ value={max || ""}
349
+ onChange={(event) => setMax(event.target.value)}
350
+ required
351
+ />
352
+ </>
353
+ ) : fieldType === "textarea" ? (
354
+ <TextInput
355
+ id="textAreaRows"
356
+ labelText={t("rows", "Rows")}
357
+ value={rows || ""}
358
+ onChange={(event) => setRows(event.target.value)}
359
+ required
360
+ />
361
+ ) : null}
363
362
 
364
- {fieldType !== "ui-select-extended" && (
365
- <div>
366
- <FormLabel className={styles.label}>
367
- {t(
368
- "searchForBackingConcept",
369
- "Search for a backing concept"
370
- )}
371
- </FormLabel>
372
- {isLoadingConceptName ? (
373
- <InlineLoading
374
- className={styles.loader}
375
- description={t("loading", "Loading") + "..."}
363
+ {fieldType !== "ui-select-extended" && (
364
+ <div>
365
+ <FormLabel className={styles.label}>
366
+ {t("searchForBackingConcept", "Search for a backing concept")}
367
+ </FormLabel>
368
+ {isLoadingConceptName ? (
369
+ <InlineLoading
370
+ className={styles.loader}
371
+ description={t("loading", "Loading") + "..."}
372
+ />
373
+ ) : (
374
+ <>
375
+ <Search
376
+ defaultValue={conceptName}
377
+ id="conceptLookup"
378
+ onClear={() => setSelectedConcept(null)}
379
+ onChange={(e) =>
380
+ handleConceptChange(e.target.value?.trim())
381
+ }
382
+ placeholder={t(
383
+ "searchConcept",
384
+ "Search using a concept name or UUID"
385
+ )}
386
+ required
387
+ size="md"
388
+ value={selectedConcept?.display}
376
389
  />
377
- ) : (
378
- <>
379
- <Search
380
- defaultValue={conceptName}
381
- id="conceptLookup"
382
- onClear={() => setSelectedConcept(null)}
383
- onChange={(e) =>
384
- handleConceptChange(e.target.value?.trim())
385
- }
386
- placeholder={t(
387
- "searchConcept",
388
- "Search using a concept name or UUID"
389
- )}
390
- required
391
- size="md"
392
- value={selectedConcept?.display}
393
- />
394
- {(() => {
395
- if (!conceptToLookup) return null;
396
- if (isLoadingConcepts)
397
- return (
398
- <InlineLoading
399
- className={styles.loader}
400
- description={t("searching", "Searching") + "..."}
401
- />
402
- );
403
- if (
404
- concepts &&
405
- concepts?.length &&
406
- !isLoadingConcepts
407
- ) {
408
- return (
409
- <ul className={styles.conceptList}>
410
- {concepts?.map((concept, index) => (
411
- <li
412
- role="menuitem"
413
- className={styles.concept}
414
- key={index}
415
- onClick={() => handleConceptSelect(concept)}
416
- >
417
- {concept.display}
418
- </li>
419
- ))}
420
- </ul>
421
- );
422
- }
390
+ {(() => {
391
+ if (!conceptToLookup) return null;
392
+ if (isLoadingConcepts)
423
393
  return (
424
- <Layer>
425
- <Tile className={styles.emptyResults}>
426
- <span>
427
- {t(
428
- "noMatchingConcepts",
429
- "No concepts were found that match"
430
- )}{" "}
431
- <strong>"{conceptToLookup}".</strong>
432
- </span>
433
- </Tile>
434
-
435
- <div className={styles.oclLauncherBanner}>
436
- {
437
- <p className={styles.bodyShort01}>
438
- {t(
439
- "conceptSearchHelpText",
440
- "Can't find a concept?"
441
- )}
442
- </p>
443
- }
444
- <a
445
- className={styles.oclLink}
446
- target="_blank"
447
- rel="noopener noreferrer"
448
- href={"https://app.openconceptlab.org/"}
394
+ <InlineLoading
395
+ className={styles.loader}
396
+ description={t("searching", "Searching") + "..."}
397
+ />
398
+ );
399
+ if (concepts && concepts?.length && !isLoadingConcepts) {
400
+ return (
401
+ <ul className={styles.conceptList}>
402
+ {concepts?.map((concept, index) => (
403
+ <li
404
+ role="menuitem"
405
+ className={styles.concept}
406
+ key={index}
407
+ onClick={() => handleConceptSelect(concept)}
449
408
  >
450
- {t("searchInOCL", "Search in OCL")}
451
- <ArrowUpRight size={16} />
452
- </a>
453
- </div>
454
- </Layer>
409
+ {concept.display}
410
+ </li>
411
+ ))}
412
+ </ul>
455
413
  );
456
- })()}
457
- </>
458
- )}
459
- </div>
460
- )}
414
+ }
415
+ return (
416
+ <Layer>
417
+ <Tile className={styles.emptyResults}>
418
+ <span>
419
+ {t(
420
+ "noMatchingConcepts",
421
+ "No concepts were found that match"
422
+ )}{" "}
423
+ <strong>"{conceptToLookup}".</strong>
424
+ </span>
425
+ </Tile>
461
426
 
462
- {conceptMappings && conceptMappings.length ? (
463
- <FormGroup>
464
- <FormLabel className={styles.label}>
465
- {t("mappings", "Mappings")}
466
- </FormLabel>
467
- <table className={styles.tableStriped}>
468
- <thead>
469
- <tr>
470
- <th>{t("relationship", "Relationship")}</th>
471
- <th>{t("source", "Source")}</th>
472
- <th>{t("code", "Code")}</th>
473
- </tr>
474
- </thead>
475
- <tbody>
476
- {conceptMappings.map((mapping, index) => (
477
- <tr key={`mapping-${index}`}>
478
- <td>{mapping.relationship ?? "--"}</td>
479
- <td>{mapping.type ?? "--"}</td>
480
- <td>{mapping.value ?? "--"}</td>
481
- </tr>
482
- ))}
483
- </tbody>
484
- </table>
485
- </FormGroup>
486
- ) : null}
487
-
488
- {!hasConceptChanged &&
489
- questionToEdit?.questionOptions?.answers &&
490
- questionToEdit?.questionOptions.answers?.length ? (
491
- <MultiSelect
492
- className={styles.multiSelect}
493
- direction="top"
494
- id="selectAnswers"
495
- itemToString={(item) => item.text}
496
- initialSelectedItems={questionToEdit?.questionOptions?.answers?.map(
497
- (answer) => ({
498
- id: answer.concept,
499
- text: answer.label,
500
- })
501
- )}
502
- items={questionToEdit?.questionOptions?.answers?.map(
503
- (answer) => ({
504
- id: answer.concept,
505
- text: answer.label ?? "",
506
- })
507
- )}
508
- onChange={({ selectedItems }) => {
509
- setAnswersChanged(true);
510
- setSelectedAnswers(selectedItems.sort());
511
- }}
512
- size="md"
513
- titleText={t(
514
- "selectAnswersToDisplay",
515
- "Select answers to display"
516
- )}
517
- />
518
- ) : null}
427
+ <div className={styles.oclLauncherBanner}>
428
+ {
429
+ <p className={styles.bodyShort01}>
430
+ {t(
431
+ "conceptSearchHelpText",
432
+ "Can't find a concept?"
433
+ )}
434
+ </p>
435
+ }
436
+ <a
437
+ className={styles.oclLink}
438
+ target="_blank"
439
+ rel="noopener noreferrer"
440
+ href={"https://app.openconceptlab.org/"}
441
+ >
442
+ {t("searchInOCL", "Search in OCL")}
443
+ <ArrowUpRight size={16} />
444
+ </a>
445
+ </div>
446
+ </Layer>
447
+ );
448
+ })()}
449
+ </>
450
+ )}
451
+ </div>
452
+ )}
519
453
 
520
- {!hasConceptChanged &&
521
- questionToEdit?.questionOptions?.answers?.length &&
522
- !answersChanged ? (
523
- <div>
524
- {questionToEdit?.questionOptions?.answers?.map((answer) => (
525
- <Tag
526
- className={styles.tag}
527
- key={answer?.concept}
528
- type={"blue"}
529
- >
530
- {answer?.label}
531
- </Tag>
532
- ))}
533
- </div>
534
- ) : null}
454
+ {conceptMappings && conceptMappings.length ? (
455
+ <FormGroup>
456
+ <FormLabel className={styles.label}>
457
+ {t("mappings", "Mappings")}
458
+ </FormLabel>
459
+ <table className={styles.tableStriped}>
460
+ <thead>
461
+ <tr>
462
+ <th>{t("relationship", "Relationship")}</th>
463
+ <th>{t("source", "Source")}</th>
464
+ <th>{t("code", "Code")}</th>
465
+ </tr>
466
+ </thead>
467
+ <tbody>
468
+ {conceptMappings.map((mapping, index) => (
469
+ <tr key={`mapping-${index}`}>
470
+ <td>{mapping.relationship ?? "--"}</td>
471
+ <td>{mapping.type ?? "--"}</td>
472
+ <td>{mapping.value ?? "--"}</td>
473
+ </tr>
474
+ ))}
475
+ </tbody>
476
+ </table>
477
+ </FormGroup>
478
+ ) : null}
535
479
 
536
- {hasConceptChanged && answersFromConcept.length ? (
537
- <MultiSelect
538
- className={styles.multiSelect}
539
- direction="top"
540
- id="selectAnswers"
541
- itemToString={(item) => item.text}
542
- items={answersFromConcept.map((answer) => ({
480
+ {!hasConceptChanged &&
481
+ questionToEdit?.questionOptions?.answers &&
482
+ questionToEdit?.questionOptions.answers?.length ? (
483
+ <MultiSelect
484
+ className={styles.multiSelect}
485
+ direction="top"
486
+ id="selectAnswers"
487
+ itemToString={(item) => item.text}
488
+ initialSelectedItems={questionToEdit?.questionOptions?.answers?.map(
489
+ (answer) => ({
543
490
  id: answer.concept,
544
491
  text: answer.label,
545
- }))}
546
- onChange={({ selectedItems }) =>
547
- setSelectedAnswers(selectedItems.sort())
548
- }
549
- size="md"
550
- titleText={t(
551
- "selectAnswersToDisplay",
552
- "Select answers to display"
553
- )}
554
- />
555
- ) : null}
492
+ })
493
+ )}
494
+ items={questionToEdit?.questionOptions?.answers?.map(
495
+ (answer) => ({
496
+ id: answer.concept,
497
+ text: answer.label ?? "",
498
+ })
499
+ )}
500
+ onChange={({ selectedItems }) => {
501
+ setAnswersChanged(true);
502
+ setSelectedAnswers(selectedItems.sort());
503
+ }}
504
+ size="md"
505
+ titleText={t(
506
+ "selectAnswersToDisplay",
507
+ "Select answers to display"
508
+ )}
509
+ />
510
+ ) : null}
556
511
 
557
- {(hasConceptChanged || answersChanged) && (
558
- <div>
559
- {selectedAnswers.map((selectedAnswer) => (
560
- <Tag
561
- className={styles.tag}
562
- key={selectedAnswer.id}
563
- type={"blue"}
564
- >
565
- {selectedAnswer.text}
566
- </Tag>
567
- ))}
568
- </div>
569
- )}
570
- </Stack>
571
- </FormGroup>
512
+ {!hasConceptChanged &&
513
+ questionToEdit?.questionOptions?.answers?.length &&
514
+ !answersChanged ? (
515
+ <div>
516
+ {questionToEdit?.questionOptions?.answers?.map((answer) => (
517
+ <Tag
518
+ className={styles.tag}
519
+ key={answer?.concept}
520
+ type={"blue"}
521
+ >
522
+ {answer?.label}
523
+ </Tag>
524
+ ))}
525
+ </div>
526
+ ) : null}
527
+
528
+ {hasConceptChanged && answersFromConcept.length ? (
529
+ <MultiSelect
530
+ className={styles.multiSelect}
531
+ direction="top"
532
+ id="selectAnswers"
533
+ itemToString={(item) => item.text}
534
+ items={answersFromConcept.map((answer) => ({
535
+ id: answer.concept,
536
+ text: answer.label,
537
+ }))}
538
+ onChange={({ selectedItems }) =>
539
+ setSelectedAnswers(selectedItems.sort())
540
+ }
541
+ size="md"
542
+ titleText={t(
543
+ "selectAnswersToDisplay",
544
+ "Select answers to display"
545
+ )}
546
+ />
547
+ ) : null}
548
+
549
+ {(hasConceptChanged || answersChanged) && (
550
+ <div>
551
+ {selectedAnswers.map((selectedAnswer) => (
552
+ <Tag
553
+ className={styles.tag}
554
+ key={selectedAnswer.id}
555
+ type={"blue"}
556
+ >
557
+ {selectedAnswer.text}
558
+ </Tag>
559
+ ))}
560
+ </div>
561
+ )}
562
+ </Stack>
572
563
  </ModalBody>
573
564
  <ModalFooter>
574
565
  <Button onClick={() => onModalChange(false)} kind="secondary">