@medplum/react 0.9.17 → 0.9.20

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/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { formatAddress, getDisplayString, getImageSrc, globalSchema, getPropertyDisplayName, formatHumanName, stringify, buildTypeName, PropertyType, getTypedPropertyValue, createReference, capitalize, toTypedValue, getReferenceString, evalFhirPath, getSearchParameterDetails, Operator, evalFhirPathTyped, SearchParameterType, formatSearchQuery, parseSearchDefinition, DEFAULT_SEARCH_COUNT, isUUID } from '@medplum/core';
1
+ import { formatAddress, getDisplayString, getImageSrc, capitalize, globalSchema, getPropertyDisplayName, formatHumanName, stringify, buildTypeName, PropertyType, getTypedPropertyValue, createReference, toTypedValue, getReferenceString, evalFhirPath, getSearchParameterDetails, Operator, evalFhirPathTyped, SearchParameterType, formatSearchQuery, parseSearchDefinition, DEFAULT_SEARCH_COUNT, isUUID } from '@medplum/core';
2
2
  import React, { useState, useRef, createContext, useEffect, useContext, useCallback } from 'react';
3
3
  import { useNavigate, useLocation } from 'react-router-dom';
4
4
 
@@ -16,10 +16,10 @@ function getIssuesForExpression(outcome, expression) {
16
16
  }
17
17
 
18
18
  function Input(props) {
19
- const className = 'medplum-input'; // + (props.size ? ' ' + props.size : '');
19
+ const className = 'medplum-input';
20
20
  const issues = getIssuesForExpression(props.outcome, props.name);
21
21
  const invalid = issues && issues.length > 0;
22
- return (React.createElement("input", { id: props.name, name: props.name, type: getInputType(props.type), size: props.size, step: props.step, className: className, defaultValue: props.defaultValue || '', required: props.required, autoCapitalize: props.autoCapitalize, autoComplete: props.autoComplete, autoFocus: props.autoFocus, ref: props.inputRef, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', placeholder: props.placeholder, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
22
+ return (React.createElement("input", { id: props.name, name: props.name, type: getInputType(props.type), size: props.size, step: props.step, className: className, style: props.style, defaultValue: props.defaultValue || '', required: props.required, autoCapitalize: props.autoCapitalize, autoComplete: props.autoComplete, autoFocus: props.autoFocus, ref: props.inputRef, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', placeholder: props.placeholder, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
23
23
  if (props.onChange) {
24
24
  props.onChange(e.currentTarget.value);
25
25
  }
@@ -281,7 +281,7 @@ function AttachmentArrayInput(props) {
281
281
  props.onChange(newValues);
282
282
  }
283
283
  }
284
- return (React.createElement("table", null,
284
+ return (React.createElement("table", { style: { width: '100%' } },
285
285
  React.createElement("colgroup", null,
286
286
  React.createElement("col", { width: "90%" }),
287
287
  React.createElement("col", { width: "10%" })),
@@ -615,6 +615,9 @@ function MedplumLink(props) {
615
615
  else if ('reference' in props.to) {
616
616
  href = `/${props.to.reference}`;
617
617
  }
618
+ if (props.suffix) {
619
+ href += '/' + props.suffix;
620
+ }
618
621
  }
619
622
  return (React.createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
620
623
  killEvent(e);
@@ -704,6 +707,14 @@ function getInitials(text) {
704
707
  .join('');
705
708
  }
706
709
 
710
+ function CheckboxFormSection(props) {
711
+ return (React.createElement("div", { className: "medplum-checkbox-form-section" },
712
+ React.createElement("div", { className: "medplum-checkbox-form-section-checkbox-container" }, props.children),
713
+ React.createElement("div", { className: "medplum-checkbox-form-section-details-container" },
714
+ React.createElement("label", { htmlFor: props.htmlFor }, props.title),
715
+ React.createElement("p", null, props.description))));
716
+ }
717
+
707
718
  const DEFAULT_IGNORED_PROPERTIES = [
708
719
  'meta',
709
720
  'implicitRules',
@@ -717,9 +728,9 @@ const DEFAULT_IGNORED_PROPERTIES = [
717
728
  function FormSection(props) {
718
729
  const issues = getIssuesForExpression(props.outcome, props.htmlFor);
719
730
  const invalid = issues && issues.length > 0;
720
- return (React.createElement("fieldset", null,
731
+ return (React.createElement("fieldset", { className: "medplum-form-section" },
721
732
  props.title && React.createElement("label", { htmlFor: props.htmlFor }, props.title),
722
- props.description && React.createElement("small", null, props.description),
733
+ props.description && React.createElement("p", null, props.description),
723
734
  props.children,
724
735
  invalid && (React.createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
725
736
  var _a, _b;
@@ -727,6 +738,50 @@ function FormSection(props) {
727
738
  })))));
728
739
  }
729
740
 
741
+ function ResourceForm(props) {
742
+ const medplum = useMedplum();
743
+ const defaultValue = useResource(props.defaultValue);
744
+ const [schema, setSchema] = useState();
745
+ const [value, setValue] = useState();
746
+ useEffect(() => {
747
+ if (defaultValue) {
748
+ setValue(JSON.parse(JSON.stringify(defaultValue)));
749
+ medplum.requestSchema(defaultValue.resourceType).then(setSchema);
750
+ }
751
+ }, [medplum, defaultValue]);
752
+ if (!schema || !value) {
753
+ return React.createElement("div", null, "Loading...");
754
+ }
755
+ return (React.createElement("form", { noValidate: true, autoComplete: "off", onSubmit: (e) => {
756
+ e.preventDefault();
757
+ if (props.onSubmit) {
758
+ props.onSubmit(value);
759
+ }
760
+ } },
761
+ React.createElement(FormSection, { title: "Resource Type" },
762
+ React.createElement(Input, { name: "resourceType", defaultValue: value.resourceType, disabled: true })),
763
+ React.createElement(FormSection, { title: "ID" },
764
+ React.createElement(Input, { name: "id", defaultValue: value.id, disabled: true })),
765
+ React.createElement(BackboneElementInput, { typeName: value.resourceType, defaultValue: value, outcome: props.outcome, onChange: setValue }),
766
+ React.createElement(Button, { type: "submit", size: "large" }, "OK"),
767
+ props.onDelete && (React.createElement(Button, { type: "button", size: "large", onClick: () => {
768
+ props.onDelete(value);
769
+ } }, "Delete"))));
770
+ }
771
+ function setPropertyValue(obj, key, propName, elementDefinition, value) {
772
+ const types = elementDefinition.type;
773
+ if (types.length > 1) {
774
+ for (const type of types) {
775
+ const compoundKey = key.replace('[x]', capitalize(type.code));
776
+ if (compoundKey in obj) {
777
+ delete obj[compoundKey];
778
+ }
779
+ }
780
+ }
781
+ obj[propName] = value;
782
+ return obj;
783
+ }
784
+
730
785
  function DescriptionList(props) {
731
786
  return React.createElement("dl", { className: 'medplum-description-list' + (props.compact ? ' compact' : '') }, props.children);
732
787
  }
@@ -815,6 +870,18 @@ function ContactPointDisplay(props) {
815
870
  return React.createElement(React.Fragment, null, builder.join('').trim());
816
871
  }
817
872
 
873
+ function ContactDetailDisplay(props) {
874
+ var _a;
875
+ const contactDetail = props.value;
876
+ if (!contactDetail) {
877
+ return null;
878
+ }
879
+ return (React.createElement(React.Fragment, null,
880
+ contactDetail.name,
881
+ contactDetail.name && ': ', (_a = contactDetail.telecom) === null || _a === void 0 ? void 0 :
882
+ _a.map((telecom, index) => (React.createElement(ContactPointDisplay, { key: 'telecom-' + index, value: telecom })))));
883
+ }
884
+
818
885
  function DateTimeDisplay(props) {
819
886
  if (!props.value) {
820
887
  return null;
@@ -963,6 +1030,8 @@ function ResourcePropertyDisplay(props) {
963
1030
  return React.createElement(CodeableConceptDisplay, { value: value });
964
1031
  case PropertyType.Coding:
965
1032
  return React.createElement(CodingDisplay, { value: value });
1033
+ case PropertyType.ContactDetail:
1034
+ return React.createElement(ContactDetailDisplay, { value: value });
966
1035
  case PropertyType.ContactPoint:
967
1036
  return React.createElement(ContactPointDisplay, { value: value });
968
1037
  case PropertyType.HumanName:
@@ -1028,6 +1097,15 @@ function AnnotationInput(props) {
1028
1097
  return (React.createElement(Input, { name: props.name, type: "text", placeholder: "Annotation text", defaultValue: value.text, onChange: setText }));
1029
1098
  }
1030
1099
 
1100
+ function Checkbox(props) {
1101
+ const className = 'medplum-checkbox';
1102
+ return (React.createElement("input", { id: props.name, name: props.name, className: className, type: "checkbox", value: "true", defaultChecked: !!props.defaultValue, required: props.required, ref: props.inputRef, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
1103
+ if (props.onChange) {
1104
+ props.onChange(e.currentTarget.checked);
1105
+ }
1106
+ } }));
1107
+ }
1108
+
1031
1109
  function CodeableConceptInput(props) {
1032
1110
  const medplum = useMedplum();
1033
1111
  let defaultValue = undefined;
@@ -1123,19 +1201,34 @@ function ContactPointInput(props) {
1123
1201
  const ref = useRef();
1124
1202
  ref.current = contactPoint;
1125
1203
  function setContactPointWrapper(newValue) {
1204
+ if (newValue && Object.keys(newValue).length === 0) {
1205
+ newValue = undefined;
1206
+ }
1126
1207
  setContactPoint(newValue);
1127
1208
  if (props.onChange) {
1128
1209
  props.onChange(newValue);
1129
1210
  }
1130
1211
  }
1131
1212
  function setSystem(system) {
1132
- setContactPointWrapper(Object.assign(Object.assign({}, ref.current), { system: system ? system : undefined }));
1213
+ const newValue = Object.assign(Object.assign({}, ref.current), { system });
1214
+ if (!system) {
1215
+ delete newValue.system;
1216
+ }
1217
+ setContactPointWrapper(newValue);
1133
1218
  }
1134
1219
  function setUse(use) {
1135
- setContactPointWrapper(Object.assign(Object.assign({}, ref.current), { use: use ? use : undefined }));
1220
+ const newValue = Object.assign(Object.assign({}, ref.current), { use });
1221
+ if (!use) {
1222
+ delete newValue.use;
1223
+ }
1224
+ setContactPointWrapper(newValue);
1136
1225
  }
1137
1226
  function setValue(value) {
1138
- setContactPointWrapper(Object.assign(Object.assign({}, ref.current), { value: value ? value : undefined }));
1227
+ const newValue = Object.assign(Object.assign({}, ref.current), { value });
1228
+ if (!value) {
1229
+ delete newValue.value;
1230
+ }
1231
+ setContactPointWrapper(newValue);
1139
1232
  }
1140
1233
  return (React.createElement(InputRow, null,
1141
1234
  React.createElement(Select, { defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.system, onChange: setSystem, testid: "system" },
@@ -1156,6 +1249,36 @@ function ContactPointInput(props) {
1156
1249
  React.createElement(Input, { placeholder: "Value", defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.value, onChange: setValue })));
1157
1250
  }
1158
1251
 
1252
+ function ContactDetailInput(props) {
1253
+ var _a;
1254
+ const [contactPoint, setContactDetail] = useState(props.defaultValue);
1255
+ const ref = useRef();
1256
+ ref.current = contactPoint;
1257
+ function setContactDetailWrapper(newValue) {
1258
+ setContactDetail(newValue);
1259
+ if (props.onChange) {
1260
+ props.onChange(newValue);
1261
+ }
1262
+ }
1263
+ function setName(name) {
1264
+ const newValue = Object.assign(Object.assign({}, ref.current), { name });
1265
+ if (!name) {
1266
+ delete newValue.name;
1267
+ }
1268
+ setContactDetailWrapper(newValue);
1269
+ }
1270
+ function setTelecom(telecom) {
1271
+ const newValue = Object.assign(Object.assign({}, ref.current), { telecom: telecom && [telecom] });
1272
+ if (!telecom) {
1273
+ delete newValue.telecom;
1274
+ }
1275
+ setContactDetailWrapper(newValue);
1276
+ }
1277
+ return (React.createElement(InputRow, null,
1278
+ React.createElement(Input, { name: props.name + '-name', placeholder: "Name", style: { width: 180 }, defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.name, onChange: setName }),
1279
+ React.createElement(ContactPointInput, { name: props.name + '-telecom', defaultValue: (_a = contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.telecom) === null || _a === void 0 ? void 0 : _a[0], onChange: setTelecom })));
1280
+ }
1281
+
1159
1282
  /**
1160
1283
  * The DateTimeInput component is a wrapper around the HTML5 input type="datetime-local".
1161
1284
  * The main purpose is to reconcile time zones.
@@ -1214,7 +1337,7 @@ function isValidDate(date) {
1214
1337
  }
1215
1338
 
1216
1339
  function TextArea(props) {
1217
- const className = 'medplum-textarea';
1340
+ const className = 'medplum-textarea' + (props.monospace ? ' monospace' : '');
1218
1341
  const issues = getIssuesForExpression(props.outcome, props.name);
1219
1342
  const invalid = issues && issues.length > 0;
1220
1343
  return (React.createElement("textarea", { id: props.name, name: props.name, className: className, defaultValue: props.defaultValue || '', required: props.required, autoComplete: props.autoComplete, autoFocus: props.autoFocus, ref: props.inputRef, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', placeholder: props.placeholder, "data-testid": props.testid, style: props.style, onChange: (e) => {
@@ -1225,7 +1348,7 @@ function TextArea(props) {
1225
1348
  }
1226
1349
 
1227
1350
  function ExtensionInput(props) {
1228
- return (React.createElement(TextArea, { testid: "extension-input", name: props.name, defaultValue: stringify(props.defaultValue), onChange: (newValue) => {
1351
+ return (React.createElement(TextArea, { testid: "extension-input", name: props.name, defaultValue: stringify(props.defaultValue), monospace: true, onChange: (newValue) => {
1229
1352
  if (props.onChange) {
1230
1353
  props.onChange(JSON.parse(newValue));
1231
1354
  }
@@ -1390,7 +1513,7 @@ function ResourceInput(props) {
1390
1513
  }
1391
1514
  return (React.createElement(Autocomplete, { loadOptions: (input) => {
1392
1515
  return medplum
1393
- .search(resourceTypeRef.current, 'name=' + encodeURIComponent(input))
1516
+ .search(resourceTypeRef.current, 'name=' + encodeURIComponent(input) + '&_count=10')
1394
1517
  .then((bundle) => bundle.entry.map((entry) => entry.resource));
1395
1518
  }, getId: (item) => {
1396
1519
  return item.id;
@@ -1448,35 +1571,34 @@ function ResourceArrayInput(props) {
1448
1571
  props.onChange(newValues);
1449
1572
  }
1450
1573
  }
1451
- return (React.createElement("div", null,
1452
- React.createElement("table", { style: { width: '100%' } },
1453
- React.createElement("colgroup", null,
1454
- React.createElement("col", { width: "90%" }),
1455
- React.createElement("col", { width: "10%" })),
1456
- React.createElement("tbody", null,
1457
- values.map((v, index) => (React.createElement("tr", { key: `${index}-${values.length}` },
1458
- React.createElement("td", null,
1459
- React.createElement(ResourcePropertyInput, { arrayElement: true, property: props.property, name: props.name + '.' + index, defaultValue: v, onChange: (newValue) => {
1460
- const copy = [...valuesRef.current];
1461
- copy[index] = newValue;
1462
- setValuesWrapper(copy);
1463
- } })),
1464
- React.createElement("td", { style: { textAlign: 'right' } },
1465
- React.createElement(Button, { onClick: (e) => {
1466
- killEvent(e);
1467
- const copy = [...valuesRef.current];
1468
- copy.splice(index, 1);
1469
- setValuesWrapper(copy);
1470
- } }, "Remove"))))),
1471
- React.createElement("tr", null,
1472
- React.createElement("td", null),
1473
- React.createElement("td", { style: { textAlign: 'right' } },
1474
- React.createElement(Button, { onClick: (e) => {
1475
- killEvent(e);
1476
- const copy = [...valuesRef.current];
1477
- copy.push(undefined);
1478
- setValuesWrapper(copy);
1479
- } }, "Add")))))));
1574
+ return (React.createElement("table", { style: { width: '100%', borderCollapse: 'collapse' } },
1575
+ React.createElement("colgroup", null,
1576
+ React.createElement("col", { width: "90%" }),
1577
+ React.createElement("col", { width: "10%" })),
1578
+ React.createElement("tbody", null,
1579
+ values.map((v, index) => (React.createElement("tr", { key: `${index}-${values.length}` },
1580
+ React.createElement("td", null,
1581
+ React.createElement(ResourcePropertyInput, { arrayElement: true, property: props.property, name: props.name + '.' + index, defaultValue: v, onChange: (newValue) => {
1582
+ const copy = [...valuesRef.current];
1583
+ copy[index] = newValue;
1584
+ setValuesWrapper(copy);
1585
+ } })),
1586
+ React.createElement("td", { style: { textAlign: 'right' } },
1587
+ React.createElement(Button, { onClick: (e) => {
1588
+ killEvent(e);
1589
+ const copy = [...valuesRef.current];
1590
+ copy.splice(index, 1);
1591
+ setValuesWrapper(copy);
1592
+ } }, "Remove"))))),
1593
+ React.createElement("tr", null,
1594
+ React.createElement("td", null),
1595
+ React.createElement("td", { style: { textAlign: 'right' } },
1596
+ React.createElement(Button, { onClick: (e) => {
1597
+ killEvent(e);
1598
+ const copy = [...valuesRef.current];
1599
+ copy.push(undefined);
1600
+ setValuesWrapper(copy);
1601
+ } }, "Add"))))));
1480
1602
  }
1481
1603
 
1482
1604
  function ResourcePropertyInput(props) {
@@ -1520,6 +1642,7 @@ function ElementDefinitionInputSelector(props) {
1520
1642
  } }))));
1521
1643
  }
1522
1644
  function ElementDefinitionTypeInput(props) {
1645
+ var _a;
1523
1646
  const property = props.property;
1524
1647
  const propertyType = props.elementDefinitionType.code;
1525
1648
  const name = props.name;
@@ -1551,7 +1674,11 @@ function ElementDefinitionTypeInput(props) {
1551
1674
  case PropertyType.code:
1552
1675
  return React.createElement(CodeInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
1553
1676
  case PropertyType.boolean:
1554
- return (React.createElement("input", { type: "checkbox", name: name, "data-testid": name, defaultChecked: !!value, value: "true", onChange: (e) => props.onChange && props.onChange(e.target.value === 'true') }));
1677
+ return (React.createElement(Checkbox, { name: name, testid: name, defaultValue: !!value, onChange: (newValue) => {
1678
+ if (props.onChange) {
1679
+ props.onChange(newValue);
1680
+ }
1681
+ } }));
1555
1682
  case PropertyType.markdown:
1556
1683
  return React.createElement(TextArea, { name: name, testid: name, defaultValue: value, onChange: props.onChange });
1557
1684
  // 2.24.0.2 Complex Types
@@ -1566,6 +1693,8 @@ function ElementDefinitionTypeInput(props) {
1566
1693
  return React.createElement(CodeableConceptInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
1567
1694
  case PropertyType.Coding:
1568
1695
  return React.createElement(CodingInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
1696
+ case PropertyType.ContactDetail:
1697
+ return React.createElement(ContactDetailInput, { name: name, defaultValue: value, onChange: props.onChange });
1569
1698
  case PropertyType.ContactPoint:
1570
1699
  return React.createElement(ContactPointInput, { name: name, defaultValue: value, onChange: props.onChange });
1571
1700
  case PropertyType.Extension:
@@ -1585,7 +1714,7 @@ function ElementDefinitionTypeInput(props) {
1585
1714
  case PropertyType.Reference:
1586
1715
  return (React.createElement(ReferenceInput, { name: name, defaultValue: value, targetTypes: getTargetTypes(property), onChange: props.onChange }));
1587
1716
  default:
1588
- return (React.createElement(BackboneElementInput, { property: property, name: name, defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1717
+ return (React.createElement(BackboneElementInput, { typeName: buildTypeName((_a = property.path) === null || _a === void 0 ? void 0 : _a.split('.')), defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1589
1718
  }
1590
1719
  }
1591
1720
  function getTargetTypes(property) {
@@ -1593,65 +1722,8 @@ function getTargetTypes(property) {
1593
1722
  return (_c = (_b = (_a = property === null || property === void 0 ? void 0 : property.type) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.targetProfile) === null || _c === void 0 ? void 0 : _c.map((p) => p.split('/').pop());
1594
1723
  }
1595
1724
 
1596
- function ResourceForm(props) {
1597
- const medplum = useMedplum();
1598
- const defaultValue = useResource(props.defaultValue);
1599
- const [schema, setSchema] = useState();
1600
- const [value, setValue] = useState();
1601
- useEffect(() => {
1602
- if (defaultValue) {
1603
- setValue(JSON.parse(JSON.stringify(defaultValue)));
1604
- medplum.requestSchema(defaultValue.resourceType).then(setSchema);
1605
- }
1606
- }, [medplum, defaultValue]);
1607
- if (!schema || !value) {
1608
- return React.createElement("div", null, "Loading...");
1609
- }
1610
- const typeSchema = schema.types[value.resourceType];
1611
- const typedValue = { type: value.resourceType, value };
1612
- return (React.createElement("form", { noValidate: true, autoComplete: "off", onSubmit: (e) => {
1613
- e.preventDefault();
1614
- if (props.onSubmit) {
1615
- props.onSubmit(value);
1616
- }
1617
- } },
1618
- React.createElement(FormSection, { title: "Resource Type" },
1619
- React.createElement(Input, { name: "resourceType", defaultValue: value.resourceType, disabled: true })),
1620
- React.createElement(FormSection, { title: "ID" },
1621
- React.createElement(Input, { name: "id", defaultValue: value.id, disabled: true })),
1622
- Object.entries(typeSchema.properties).map((entry) => {
1623
- const key = entry[0];
1624
- if (key === 'id' || DEFAULT_IGNORED_PROPERTIES.indexOf(key) >= 0) {
1625
- return null;
1626
- }
1627
- const property = entry[1];
1628
- const [propertyValue, propertyType] = getValueAndType(typedValue, key);
1629
- return (React.createElement(FormSection, { key: key, title: getPropertyDisplayName(key), description: property.definition, htmlFor: key, outcome: props.outcome },
1630
- React.createElement(ResourcePropertyInput, { property: property, name: key, defaultValue: propertyValue, defaultPropertyType: propertyType, outcome: props.outcome, onChange: (newValue, propName) => {
1631
- setValue(setPropertyValue(value, key, propName !== null && propName !== void 0 ? propName : key, entry[1], newValue));
1632
- } })));
1633
- }),
1634
- React.createElement(Button, { type: "submit", size: "large" }, "OK"),
1635
- props.onDelete && (React.createElement(Button, { type: "button", size: "large", onClick: () => {
1636
- props.onDelete(value);
1637
- } }, "Delete"))));
1638
- }
1639
- function setPropertyValue(obj, key, propName, elementDefinition, value) {
1640
- const types = elementDefinition.type;
1641
- if (types.length > 1) {
1642
- for (const type of types) {
1643
- const compoundKey = key.replace('[x]', capitalize(type.code));
1644
- if (compoundKey in obj) {
1645
- delete obj[compoundKey];
1646
- }
1647
- }
1648
- }
1649
- obj[propName] = value;
1650
- return obj;
1651
- }
1652
-
1653
1725
  function BackboneElementInput(props) {
1654
- var _a, _b;
1726
+ var _a;
1655
1727
  const [value, setValue] = useState((_a = props.defaultValue) !== null && _a !== void 0 ? _a : {});
1656
1728
  function setValueWrapper(newValue) {
1657
1729
  setValue(newValue);
@@ -1659,13 +1731,14 @@ function BackboneElementInput(props) {
1659
1731
  props.onChange(newValue);
1660
1732
  }
1661
1733
  }
1662
- const typeName = buildTypeName((_b = props.property.path) === null || _b === void 0 ? void 0 : _b.split('.'));
1734
+ const typeName = props.typeName;
1663
1735
  const typeSchema = globalSchema.types[typeName];
1664
1736
  if (!typeSchema) {
1665
1737
  return React.createElement("div", null,
1666
1738
  typeName,
1667
1739
  "\u00A0not implemented");
1668
1740
  }
1741
+ const typedValue = { type: typeName, value };
1669
1742
  return (React.createElement(React.Fragment, null, Object.entries(typeSchema.properties).map((entry) => {
1670
1743
  const key = entry[0];
1671
1744
  if (key === 'id' || DEFAULT_IGNORED_PROPERTIES.indexOf(key) >= 0) {
@@ -1675,7 +1748,13 @@ function BackboneElementInput(props) {
1675
1748
  if (!property.type) {
1676
1749
  return null;
1677
1750
  }
1678
- const [propertyValue, propertyType] = getValueAndType(value, key);
1751
+ const [propertyValue, propertyType] = getValueAndType(typedValue, key);
1752
+ if (property.type.length === 1 && property.type[0].code === 'boolean') {
1753
+ return (React.createElement(CheckboxFormSection, { key: key, title: getPropertyDisplayName(key), description: property.definition, htmlFor: key },
1754
+ React.createElement(ResourcePropertyInput, { property: property, name: key, defaultValue: propertyValue, defaultPropertyType: propertyType, outcome: props.outcome, onChange: (newValue, propName) => {
1755
+ setValueWrapper(setPropertyValue(value, key, propName !== null && propName !== void 0 ? propName : key, entry[1], newValue));
1756
+ } })));
1757
+ }
1679
1758
  return (React.createElement(FormSection, { key: key, title: getPropertyDisplayName(key), description: property.definition, htmlFor: key, outcome: props.outcome },
1680
1759
  React.createElement(ResourcePropertyInput, { property: property, name: key, defaultValue: propertyValue, defaultPropertyType: propertyType, outcome: props.outcome, onChange: (newValue, propName) => {
1681
1760
  setValueWrapper(setPropertyValue(value, key, propName !== null && propName !== void 0 ? propName : key, entry[1], newValue));
@@ -3193,7 +3272,7 @@ function SearchFilterValueInput(props) {
3193
3272
  }
3194
3273
  } }));
3195
3274
  case SearchParameterType.BOOLEAN:
3196
- return (React.createElement("input", { type: "checkbox", name: name, "data-testid": name, defaultChecked: props.defaultValue === 'true', value: "true", onChange: (e) => props.onChange(e.target.checked ? 'true' : 'false') }));
3275
+ return (React.createElement(Checkbox, { name: name, testid: name, defaultValue: props.defaultValue === 'true', onChange: (newValue) => props.onChange(newValue.toString()) }));
3197
3276
  case SearchParameterType.DATE:
3198
3277
  return React.createElement(Input, { type: "date", testid: name, defaultValue: props.defaultValue, onChange: props.onChange });
3199
3278
  case SearchParameterType.DATETIME:
@@ -3655,7 +3734,7 @@ function SearchControl(props) {
3655
3734
  const resources = entries === null || entries === void 0 ? void 0 : entries.map((e) => e.resource);
3656
3735
  const savedSearches = (_c = (_b = props.userConfig) === null || _b === void 0 ? void 0 : _b.search) === null || _c === void 0 ? void 0 : _c.filter((s) => { var _a; return (_a = s.criteria) === null || _a === void 0 ? void 0 : _a.startsWith(resourceType); });
3657
3736
  return (React.createElement("div", { className: "medplum-search-control", onContextMenu: (e) => killEvent(e), "data-testid": "search-control" },
3658
- React.createElement(TitleBar, null,
3737
+ !props.hideToolbar && (React.createElement(TitleBar, null,
3659
3738
  React.createElement("div", null,
3660
3739
  React.createElement("h1", null,
3661
3740
  React.createElement("a", { href: `https://www.hl7.org/fhir/${resourceType.toLowerCase()}.html`, target: "_blank", rel: "noopener" }, resourceType)),
@@ -3679,7 +3758,7 @@ function SearchControl(props) {
3679
3758
  ' ', (_d = lastResult.total) === null || _d === void 0 ? void 0 :
3680
3759
  _d.toLocaleString()),
3681
3760
  React.createElement(Button, { testid: "prev-page-button", size: "small", onClick: () => emitSearchChange(movePage(search, -1)) }, "<<"),
3682
- React.createElement(Button, { testid: "next-page-button", size: "small", onClick: () => emitSearchChange(movePage(search, 1)) }, ">>")))),
3761
+ React.createElement(Button, { testid: "next-page-button", size: "small", onClick: () => emitSearchChange(movePage(search, 1)) }, ">>"))))),
3683
3762
  React.createElement("table", null,
3684
3763
  React.createElement("thead", null,
3685
3764
  React.createElement("tr", null,
@@ -3688,9 +3767,9 @@ function SearchControl(props) {
3688
3767
  fields.map((field) => (React.createElement("th", { key: field.name, onClick: (e) => handleSortClick(e, field.searchParams) },
3689
3768
  buildFieldNameString(field.name),
3690
3769
  field.searchParams && React.createElement(FilterIcon, null))))),
3691
- React.createElement("tr", null,
3770
+ !props.hideFilters && (React.createElement("tr", null,
3692
3771
  checkboxColumn && React.createElement("th", { className: "filters medplum-search-icon-cell" }),
3693
- fields.map((field) => (React.createElement("th", { key: field.name, className: "filters" }, field.searchParams && (React.createElement(FilterDescription, { resourceType: resourceType, searchParams: field.searchParams, filters: props.search.filters }))))))),
3772
+ fields.map((field) => (React.createElement("th", { key: field.name, className: "filters" }, field.searchParams && (React.createElement(FilterDescription, { resourceType: resourceType, searchParams: field.searchParams, filters: props.search.filters })))))))),
3694
3773
  React.createElement("tbody", null, resources === null || resources === void 0 ? void 0 : resources.map((resource) => resource && (React.createElement("tr", { key: resource.id, "data-testid": "search-control-row", onClick: (e) => handleRowClick(e, resource), onAuxClick: (e) => handleRowClick(e, resource) },
3695
3774
  checkboxColumn && (React.createElement("td", { className: "medplum-search-icon-cell" },
3696
3775
  React.createElement("input", { type: "checkbox", value: "checked", "data-testid": "row-checkbox", "aria-label": `Checkbox for ${resource.id}`, checked: !!state.selected[resource.id], onChange: (e) => handleSingleCheckboxClick(e, resource.id) }))),
@@ -3889,7 +3968,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
3889
3968
  function HeaderSearchInput(props) {
3890
3969
  const medplum = useMedplum();
3891
3970
  return (React.createElement(Autocomplete, { loadOptions: (input, signal) => __awaiter(this, void 0, void 0, function* () {
3892
- return getResourcesFromResponse((yield medplum.graphql(buildGraphQLQuery(input), { signal })), input);
3971
+ return getResourcesFromResponse((yield medplum.graphql(buildGraphQLQuery(input), undefined, undefined, { signal })), input);
3893
3972
  }), getId: (item) => {
3894
3973
  return item.id;
3895
3974
  }, getIcon: (item) => React.createElement(Avatar, { value: item }), getDisplay: (item) => React.createElement(ResourceName, { value: item }), getHelpText: (item) => {
@@ -4463,8 +4542,24 @@ function QuestionnaireFormItemArray(props) {
4463
4542
  setResponseItems(newResponseItems);
4464
4543
  props.onChange(newResponseItems);
4465
4544
  }
4466
- return (React.createElement(React.Fragment, null, props.items.map((item, index) => item.type === QuestionnaireItemType.group ? (React.createElement(QuestionnaireFormItem, { key: item.linkId, item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) })) : (React.createElement(FormSection, { key: item.linkId, htmlFor: item.linkId, title: item.text || '' },
4467
- React.createElement(QuestionnaireFormItem, { item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) }))))));
4545
+ return (React.createElement(React.Fragment, null, props.items.map((item, index) => {
4546
+ if (item.type === QuestionnaireItemType.display) {
4547
+ return React.createElement("p", { key: item.linkId }, item.text);
4548
+ }
4549
+ if (item.type === QuestionnaireItemType.group) {
4550
+ return (React.createElement(QuestionnaireFormItem, { key: item.linkId, item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) }));
4551
+ }
4552
+ if (item.type === QuestionnaireItemType.boolean) {
4553
+ const initial = item.initial && item.initial.length > 0 ? item.initial[0] : undefined;
4554
+ return (React.createElement(CheckboxFormSection, { key: item.linkId, title: item.text, htmlFor: item.linkId },
4555
+ React.createElement(Checkbox, { name: item.linkId, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => setResponseItem(index, {
4556
+ linkId: item.linkId,
4557
+ answer: [{ valueBoolean: newValue }],
4558
+ }) })));
4559
+ }
4560
+ return (React.createElement(FormSection, { key: item.linkId, htmlFor: item.linkId, title: item.text || '' },
4561
+ React.createElement(QuestionnaireFormItem, { item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) })));
4562
+ })));
4468
4563
  }
4469
4564
  function QuestionnaireFormItem(props) {
4470
4565
  const item = props.item;
@@ -4495,7 +4590,7 @@ function QuestionnaireFormItem(props) {
4495
4590
  React.createElement("h3", null, item.text),
4496
4591
  item.item && React.createElement(QuestionnaireFormItemArray, { items: item.item, onChange: onChangeItem })));
4497
4592
  case QuestionnaireItemType.boolean:
4498
- return (React.createElement("input", { type: "checkbox", id: name, name: name, value: "true", defaultChecked: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (e) => onChangeAnswer({ valueBoolean: e.currentTarget.checked }) }));
4593
+ return (React.createElement(Checkbox, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => onChangeAnswer({ valueBoolean: newValue }) }));
4499
4594
  case QuestionnaireItemType.decimal:
4500
4595
  return (React.createElement(Input, { type: "number", step: "any", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDecimal, onChange: (newValue) => onChangeAnswer({ valueDecimal: parseFloat(newValue) }) }));
4501
4596
  case QuestionnaireItemType.integer:
@@ -4800,8 +4895,8 @@ function RequestGroupDisplay(props) {
4800
4895
  "Status: ",
4801
4896
  React.createElement(StatusBadge, { status: (task === null || task === void 0 ? void 0 : task.status) || 'unknown' }))),
4802
4897
  React.createElement("div", { className: "medplum-request-group-task-actions" },
4803
- taskInput && !taskOutput && (React.createElement(MedplumLink, { className: "medplum-button", to: taskInput }, "Start")),
4804
- taskInput && taskOutput && (React.createElement(MedplumLink, { className: "medplum-button", to: taskOutput }, "Edit")))));
4898
+ taskInput && !taskOutput && React.createElement(Button, { onClick: () => props.onStart(task, taskInput) }, "Start"),
4899
+ taskInput && taskOutput && (React.createElement(Button, { onClick: () => props.onEdit(task, taskInput, taskOutput) }, "Edit")))));
4805
4900
  })));
4806
4901
  function buildBatchRequest(request) {
4807
4902
  var _a;
@@ -5192,7 +5287,7 @@ function createScriptTag(src, onload) {
5192
5287
 
5193
5288
  function GoogleButton(props) {
5194
5289
  const medplum = useMedplum();
5195
- const { handleAuthResponse } = props;
5290
+ const { handleGoogleCredential } = props;
5196
5291
  const googleClientId = getGoogleClientId(props.googleClientId);
5197
5292
  const parentRef = useRef(null);
5198
5293
  const [scriptLoaded, setScriptLoaded] = useState(typeof google !== 'undefined');
@@ -5206,7 +5301,7 @@ function GoogleButton(props) {
5206
5301
  if (!initialized) {
5207
5302
  google.accounts.id.initialize({
5208
5303
  client_id: googleClientId,
5209
- callback: (response) => medplum.startGoogleLogin(response).then(handleAuthResponse),
5304
+ callback: handleGoogleCredential,
5210
5305
  });
5211
5306
  setInitialized(true);
5212
5307
  }
@@ -5214,7 +5309,7 @@ function GoogleButton(props) {
5214
5309
  google.accounts.id.renderButton(parentRef.current, {});
5215
5310
  setButtonRendered(true);
5216
5311
  }
5217
- }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleAuthResponse]);
5312
+ }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
5218
5313
  if (!googleClientId) {
5219
5314
  return null;
5220
5315
  }
@@ -5245,19 +5340,24 @@ function SignInForm(props) {
5245
5340
  setMemberships(response.memberships);
5246
5341
  }
5247
5342
  if (response.code) {
5248
- medplum
5249
- .processCode(response.code)
5250
- .then(() => {
5251
- if (props.onSuccess) {
5252
- props.onSuccess();
5253
- }
5254
- })
5255
- .catch(console.log);
5343
+ if (props.onCode) {
5344
+ props.onCode(response.code);
5345
+ }
5346
+ else {
5347
+ medplum
5348
+ .processCode(response.code)
5349
+ .then(() => {
5350
+ if (props.onSuccess) {
5351
+ props.onSuccess();
5352
+ }
5353
+ })
5354
+ .catch(console.log);
5355
+ }
5256
5356
  }
5257
5357
  }
5258
5358
  return (React.createElement(Document, { width: 450 }, (() => {
5259
5359
  if (!login) {
5260
- return (React.createElement(AuthenticationForm, { googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
5360
+ return (React.createElement(AuthenticationForm, { clientId: props.clientId, scope: props.scope, nonce: props.nonce, googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
5261
5361
  }
5262
5362
  else if (memberships) {
5263
5363
  return React.createElement(ProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
@@ -5274,6 +5374,9 @@ function AuthenticationForm(props) {
5274
5374
  return (React.createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
5275
5375
  medplum
5276
5376
  .startLogin({
5377
+ clientId: props.clientId,
5378
+ scope: props.scope,
5379
+ nonce: props.nonce,
5277
5380
  email: formData.email,
5278
5381
  password: formData.password,
5279
5382
  remember: formData.remember === 'true',
@@ -5300,7 +5403,18 @@ function AuthenticationForm(props) {
5300
5403
  React.createElement("div", null,
5301
5404
  React.createElement(Button, { type: "submit", testid: "submit" }, "Sign in"))),
5302
5405
  React.createElement("div", { className: "medplum-signin-google-container" },
5303
- React.createElement(GoogleButton, { googleClientId: props.googleClientId, handleAuthResponse: props.handleAuthResponse }))));
5406
+ React.createElement(GoogleButton, { googleClientId: props.googleClientId, handleGoogleCredential: (response) => {
5407
+ medplum
5408
+ .startGoogleLogin({
5409
+ clientId: props.clientId,
5410
+ scope: props.scope,
5411
+ nonce: props.nonce,
5412
+ googleClientId: response.clientId,
5413
+ googleCredential: response.credential,
5414
+ })
5415
+ .then(props.handleAuthResponse)
5416
+ .catch(setOutcome);
5417
+ } }))));
5304
5418
  }
5305
5419
  function ProfileForm(props) {
5306
5420
  const medplum = useMedplum();
@@ -5372,5 +5486,5 @@ function TabSwitch(props) {
5372
5486
  })));
5373
5487
  }
5374
5488
 
5375
- export { AddressDisplay, AddressInput, AttachmentArrayDisplay, AttachmentArrayInput, AttachmentInput, Autocomplete, Avatar, BackboneElementInput, Button, CodeInput, CodeableConceptDisplay, CodeableConceptInput, ContactPointDisplay, ContactPointInput, DateTimeDisplay, DateTimeInput, DefaultResourceTimeline, DiagnosticReportDisplay, Document, ElementDefinitionInputSelector, ElementDefinitionTypeInput, EncounterTimeline, ErrorBoundary, FhirPathTable, FooterLinks, Form, FormSection, Header, HumanNameDisplay, HumanNameInput, IdentifierInput, Input, Loading, Logo, MedplumLink, MedplumProvider, MemoizedFhirPathTable, MemoizedSearchControl, MenuItem, ObservationTable, PatientTimeline, PlanDefinitionBuilder, Popup, QuestionnaireBuilder, QuestionnaireForm, QuestionnaireFormItem, QuestionnaireItemType, RangeDisplay, RangeInput, ReferenceInput, RequestGroupDisplay, ResourceArrayDisplay, ResourceArrayInput, ResourceBadge, ResourceBlame, ResourceDiff, ResourceForm, ResourceHistoryTable, ResourceInput, ResourceName, ResourcePropertyDisplay, ResourcePropertyInput, ResourceTable, ResourceTimeline, Scrollable, SearchChangeEvent, SearchClickEvent, SearchControl, SearchFieldEditor, SearchFilterEditor, SearchLoadEvent, Select, ServiceRequestTimeline, SignInForm, StatusBadge, Tab, TabList, TabPanel, TabSwitch, TextArea, Timeline, TimelineItem, TitleBar, UploadButton, addDateEqualsFilter, addDateFilter, addDateFilterBetween, addField, addFilter, addLastMonthFilter, addMissingFilter, addNextMonthFilter, addQuestionnaireInitialValues, addThisMonthFilter, addTodayFilter, addTomorrowFilter, addYearToDateFilter, addYesterdayFilter, buildFieldNameString, clearFilters, clearFiltersOnField, convertIsoToLocal, convertLocalToIso, createScriptTag, deleteFilter, formatRangeString, getOpString, getSearchOperators, getSortField, getTimeString, getValueAndType, hasFilterOnField, isChoiceQuestion, isSortDescending, movePage, parseForm, renderValue, setFilters, setOffset, setPropertyValue, setSort, sortByDateAndPriority, toggleSort, useMedplum, useMedplumContext, useMedplumProfile, useResource };
5489
+ export { AddressDisplay, AddressInput, AttachmentArrayDisplay, AttachmentArrayInput, AttachmentInput, Autocomplete, Avatar, BackboneElementInput, Button, Checkbox, CheckboxFormSection, CodeInput, CodeableConceptDisplay, CodeableConceptInput, ContactDetailDisplay, ContactDetailInput, ContactPointDisplay, ContactPointInput, DateTimeDisplay, DateTimeInput, DefaultResourceTimeline, DiagnosticReportDisplay, Document, ElementDefinitionInputSelector, ElementDefinitionTypeInput, EncounterTimeline, ErrorBoundary, FhirPathTable, FooterLinks, Form, FormSection, Header, HumanNameDisplay, HumanNameInput, IdentifierInput, Input, Loading, Logo, MedplumLink, MedplumProvider, MemoizedFhirPathTable, MemoizedSearchControl, MenuItem, ObservationTable, PatientTimeline, PlanDefinitionBuilder, Popup, QuestionnaireBuilder, QuestionnaireForm, QuestionnaireFormItem, QuestionnaireItemType, RangeDisplay, RangeInput, ReferenceInput, RequestGroupDisplay, ResourceArrayDisplay, ResourceArrayInput, ResourceBadge, ResourceBlame, ResourceDiff, ResourceForm, ResourceHistoryTable, ResourceInput, ResourceName, ResourcePropertyDisplay, ResourcePropertyInput, ResourceTable, ResourceTimeline, Scrollable, SearchChangeEvent, SearchClickEvent, SearchControl, SearchFieldEditor, SearchFilterEditor, SearchLoadEvent, Select, ServiceRequestTimeline, SignInForm, StatusBadge, Tab, TabList, TabPanel, TabSwitch, TextArea, Timeline, TimelineItem, TitleBar, UploadButton, addDateEqualsFilter, addDateFilter, addDateFilterBetween, addField, addFilter, addLastMonthFilter, addMissingFilter, addNextMonthFilter, addQuestionnaireInitialValues, addThisMonthFilter, addTodayFilter, addTomorrowFilter, addYearToDateFilter, addYesterdayFilter, buildFieldNameString, clearFilters, clearFiltersOnField, convertIsoToLocal, convertLocalToIso, createScriptTag, deleteFilter, formatRangeString, getOpString, getSearchOperators, getSortField, getTimeString, getValueAndType, hasFilterOnField, isChoiceQuestion, isSortDescending, movePage, parseForm, renderValue, setFilters, setOffset, setPropertyValue, setSort, sortByDateAndPriority, toggleSort, useMedplum, useMedplumContext, useMedplumProfile, useResource };
5376
5490
  //# sourceMappingURL=index.js.map