@medplum/react 2.0.20 → 2.0.21

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.
Files changed (32) hide show
  1. package/dist/cjs/index.cjs +51 -29
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.min.cjs +1 -1
  4. package/dist/esm/AppShell/AppShell.mjs +2 -2
  5. package/dist/esm/AppShell/AppShell.mjs.map +1 -1
  6. package/dist/esm/AppShell/Header.mjs +1 -1
  7. package/dist/esm/AppShell/Header.mjs.map +1 -1
  8. package/dist/esm/AppShell/HeaderSearchInput.mjs +1 -1
  9. package/dist/esm/AppShell/HeaderSearchInput.mjs.map +1 -1
  10. package/dist/esm/AsyncAutocomplete/AsyncAutocomplete.mjs +2 -1
  11. package/dist/esm/AsyncAutocomplete/AsyncAutocomplete.mjs.map +1 -1
  12. package/dist/esm/GoogleButton/GoogleButton.mjs +2 -2
  13. package/dist/esm/GoogleButton/GoogleButton.mjs.map +1 -1
  14. package/dist/esm/MedplumProvider/MedplumProvider.mjs +8 -0
  15. package/dist/esm/MedplumProvider/MedplumProvider.mjs.map +1 -1
  16. package/dist/esm/ResourceTimeline/ResourceTimeline.mjs +1 -1
  17. package/dist/esm/ResourceTimeline/ResourceTimeline.mjs.map +1 -1
  18. package/dist/esm/SearchControl/SearchControl.mjs +1 -1
  19. package/dist/esm/SearchControl/SearchControl.mjs.map +1 -1
  20. package/dist/esm/Timeline/Timeline.mjs +2 -1
  21. package/dist/esm/Timeline/Timeline.mjs.map +1 -1
  22. package/dist/esm/ValueSetAutocomplete/ValueSetAutocomplete.mjs +11 -5
  23. package/dist/esm/ValueSetAutocomplete/ValueSetAutocomplete.mjs.map +1 -1
  24. package/dist/esm/auth/SignInForm.mjs +8 -4
  25. package/dist/esm/auth/SignInForm.mjs.map +1 -1
  26. package/dist/esm/index.min.mjs +1 -1
  27. package/dist/esm/utils/date.mjs +9 -6
  28. package/dist/esm/utils/date.mjs.map +1 -1
  29. package/dist/types/AppShell/Header.d.ts +2 -0
  30. package/dist/types/AppShell/HeaderSearchInput.d.ts +1 -0
  31. package/dist/types/Timeline/Timeline.d.ts +1 -0
  32. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@medplum/core'), require('react'), require('@mantine/core'), require('prop-types'), require('@mantine/notifications')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@medplum/core', 'react', '@mantine/core', 'prop-types', '@mantine/notifications'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.medplum = global.medplum || {}, global.medplum.react = {}), global.medplum.core, global.React, global.mantine.core, global.PropTypes, global.mantine.notifications));
5
- })(this, (function (exports, core, React, core$1, PropTypes, notifications) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@medplum/core'), require('react'), require('@mantine/core'), require('@mantine/notifications'), require('prop-types')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@medplum/core', 'react', '@mantine/core', '@mantine/notifications', 'prop-types'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.medplum = global.medplum || {}, global.medplum.react = {}), global.medplum.core, global.React, global.mantine.core, global.mantine.notifications, global.PropTypes));
5
+ })(this, (function (exports, core, React, core$1, notifications, PropTypes) { 'use strict';
6
6
 
7
7
  function AddressDisplay(props) {
8
8
  const address = props.value;
@@ -89,6 +89,13 @@
89
89
  medplum.addEventListener('change', eventListener);
90
90
  return () => medplum.removeEventListeneer('change', eventListener);
91
91
  }, [medplum, state]);
92
+ React.useEffect(() => {
93
+ function eventListener() {
94
+ notifications.showNotification({ color: 'red', message: 'No connection to server', autoClose: false });
95
+ }
96
+ medplum.addEventListener('offline', eventListener);
97
+ return () => medplum.removeEventListeneer('offline', eventListener);
98
+ }, [medplum]);
92
99
  const medplumContext = {
93
100
  ...state,
94
101
  medplum,
@@ -1101,8 +1108,9 @@
1101
1108
  if (!item && creatable !== false) {
1102
1109
  item = onCreate(value);
1103
1110
  }
1104
- if (item)
1111
+ if (item) {
1105
1112
  result.push(item);
1113
+ }
1106
1114
  }
1107
1115
  onChange(result);
1108
1116
  }, [creatable, onChange, onCreate]);
@@ -1193,7 +1201,7 @@
1193
1201
  navigate(`/${core.getReferenceString(item[0])}`);
1194
1202
  }
1195
1203
  }, [navigate]);
1196
- return (React.createElement(AsyncAutocomplete, { key: props.pathname, size: "sm", radius: "md", className: classes.searchInput, icon: React.createElement(IconSearch, { size: 16 }), placeholder: "Search", itemComponent: ItemComponent$1, toKey: toKey$1, toOption: toOption$1, onChange: handleSelect, loadOptions: loadData }));
1204
+ return (React.createElement(AsyncAutocomplete, { key: `${props.pathname}?${props.searchParams}`, size: "sm", radius: "md", className: classes.searchInput, icon: React.createElement(IconSearch, { size: 16 }), placeholder: "Search", itemComponent: ItemComponent$1, toKey: toKey$1, toOption: toOption$1, onChange: handleSelect, loadOptions: loadData, maxSelectedValues: 0, clearSearchOnChange: true, clearable: false }));
1197
1205
  }
1198
1206
  const ItemComponent$1 = React.forwardRef(({ resource, ...others }, ref) => {
1199
1207
  let helpText = undefined;
@@ -1406,7 +1414,7 @@
1406
1414
  React.createElement(core$1.Group, { position: "apart" },
1407
1415
  React.createElement(core$1.Group, { spacing: "xs" },
1408
1416
  React.createElement(core$1.UnstyledButton, { className: classes.logoButton, onClick: props.navbarToggle }, props.logo),
1409
- React.createElement(HeaderSearchInput, null)),
1417
+ React.createElement(HeaderSearchInput, { pathname: props.pathname, searchParams: props.searchParams })),
1410
1418
  React.createElement(core$1.Menu, { width: 260, shadow: "xl", position: "bottom-end", transitionProps: { transition: 'pop-top-right' }, opened: userMenuOpened, onClose: () => setUserMenuOpened(false) },
1411
1419
  React.createElement(core$1.Menu.Target, null,
1412
1420
  React.createElement(core$1.UnstyledButton, { className: cx(classes.user, { [classes.userActive]: userMenuOpened }), onClick: () => setUserMenuOpened((o) => !o) },
@@ -1537,11 +1545,20 @@
1537
1545
  }
1538
1546
 
1539
1547
  function toKey(element) {
1540
- return element.code;
1548
+ if (typeof element.code === 'string') {
1549
+ return element.code;
1550
+ }
1551
+ return JSON.stringify(element);
1552
+ }
1553
+ function getDisplay(item) {
1554
+ if (typeof item.display === 'string') {
1555
+ return item.display;
1556
+ }
1557
+ return toKey(item);
1541
1558
  }
1542
1559
  function toOption(element) {
1543
1560
  return {
1544
- value: element.code,
1561
+ value: toKey(element),
1545
1562
  label: getDisplay(element),
1546
1563
  resource: element,
1547
1564
  };
@@ -1575,9 +1592,6 @@
1575
1592
  }, [medplum, elementDefinition]);
1576
1593
  return (React.createElement(AsyncAutocomplete, { ...rest, creatable: creatable ?? true, clearable: clearable ?? true, toKey: toKey, toOption: toOption, loadOptions: loadValues, onCreate: createValue, getCreateLabel: creatable === false ? undefined : (query) => `+ Create ${query}` }));
1577
1594
  }
1578
- function getDisplay(item) {
1579
- return item.display || item.code || '';
1580
- }
1581
1595
 
1582
1596
  function CodeInput(props) {
1583
1597
  const [value, setValue] = React.useState(props.defaultValue);
@@ -1779,8 +1793,8 @@
1779
1793
  main: {
1780
1794
  background: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.colors.gray[0],
1781
1795
  },
1782
- }, padding: 0, fixed: true, header: profile && React.createElement(Header, { logo: props.logo, version: props.version, navbarToggle: toggleNavbar }), navbar: profile && navbarOpen ? (React.createElement(Navbar, { pathname: props.pathname, searchParams: props.searchParams, menus: props.menus, closeNavbar: closeNavbar, displayAddBookmark: props.displayAddBookmark })) : undefined },
1783
- React.createElement(ErrorBoundary, null,
1796
+ }, padding: 0, fixed: true, header: profile && (React.createElement(Header, { pathname: props.pathname, searchParams: props.searchParams, logo: props.logo, version: props.version, navbarToggle: toggleNavbar })), navbar: profile && navbarOpen ? (React.createElement(Navbar, { pathname: props.pathname, searchParams: props.searchParams, menus: props.menus, closeNavbar: closeNavbar, displayAddBookmark: props.displayAddBookmark })) : undefined },
1797
+ React.createElement(ErrorBoundary, { key: `${props.pathname}?${props.searchParams?.toString()}` },
1784
1798
  React.createElement(React.Suspense, { fallback: React.createElement(Loading, null) }, props.children))));
1785
1799
  }
1786
1800
 
@@ -3585,6 +3599,7 @@
3585
3599
  function TimelineItem(props) {
3586
3600
  const { resource, profile, padding, popupMenuItems, ...others } = props;
3587
3601
  const author = profile ?? resource.meta?.author;
3602
+ const dateTime = props.dateTime ?? resource.meta?.lastUpdated;
3588
3603
  return (React.createElement(Panel, { "data-testid": "timeline-item", fill: true, ...others },
3589
3604
  React.createElement(core$1.Group, { position: "apart", spacing: 8, mx: "xs", my: "sm" },
3590
3605
  React.createElement(ResourceAvatar, { value: author, link: true, size: "md" }),
@@ -3592,7 +3607,7 @@
3592
3607
  React.createElement(core$1.Text, { size: "sm" },
3593
3608
  React.createElement(ResourceName, { color: "dark", weight: 500, value: author, link: true })),
3594
3609
  React.createElement(core$1.Text, { size: "xs" },
3595
- React.createElement(MedplumLink, { color: "dimmed", to: props.resource }, core.formatDateTime(props.resource.meta?.lastUpdated)),
3610
+ React.createElement(MedplumLink, { color: "dimmed", to: props.resource }, core.formatDateTime(dateTime)),
3596
3611
  React.createElement(core$1.Text, { component: "span", color: "dimmed", mx: 8 }, "\u00B7"),
3597
3612
  React.createElement(MedplumLink, { color: "dimmed", to: props.resource }, props.resource.resourceType))),
3598
3613
  popupMenuItems && (React.createElement(core$1.Menu, { position: "bottom-end", shadow: "md", width: 200 },
@@ -3612,8 +3627,8 @@
3612
3627
  */
3613
3628
  function sortByDateAndPriority(resources, timelineResource) {
3614
3629
  resources.sort((a, b) => {
3615
- const priority1 = getPriorityScore(a);
3616
- const priority2 = getPriorityScore(b);
3630
+ const priority1 = getPriorityScore(a, timelineResource);
3631
+ const priority2 = getPriorityScore(b, timelineResource);
3617
3632
  if (priority1 > priority2) {
3618
3633
  return 1;
3619
3634
  }
@@ -3623,10 +3638,13 @@
3623
3638
  return getTime(a, timelineResource) - getTime(b, timelineResource);
3624
3639
  });
3625
3640
  }
3626
- function getPriorityScore(resource) {
3627
- const priority = resource.priority;
3628
- if (typeof priority === 'string') {
3629
- return { stat: 4, asap: 3, urgent: 2 }[priority] || 0;
3641
+ function getPriorityScore(resource, timelineResource) {
3642
+ if (!isSameResourceType(resource, timelineResource)) {
3643
+ // Only use priority if not the primary resource of a timeline view.
3644
+ const priority = resource.priority;
3645
+ if (typeof priority === 'string') {
3646
+ return { stat: 4, asap: 3, urgent: 2 }[priority] || 0;
3647
+ }
3630
3648
  }
3631
3649
  return 0;
3632
3650
  }
@@ -3901,7 +3919,7 @@
3901
3919
  const { classes } = useStyles$7();
3902
3920
  const routine = !props.resource.priority || props.resource.priority === 'routine';
3903
3921
  const className = routine ? undefined : classes.pinnedComment;
3904
- return (React.createElement(TimelineItem, { resource: props.resource, profile: props.resource.sender, padding: true, className: className, popupMenuItems: React.createElement(TimelineItemPopupMenu, { ...props }) },
3922
+ return (React.createElement(TimelineItem, { resource: props.resource, profile: props.resource.sender, dateTime: props.resource.sent, padding: true, className: className, popupMenuItems: React.createElement(TimelineItemPopupMenu, { ...props }) },
3905
3923
  React.createElement("p", null, props.resource.payload?.[0]?.contentString)));
3906
3924
  }
3907
3925
  function MediaTimelineItem(props) {
@@ -5113,7 +5131,7 @@
5113
5131
  React.useEffect(() => {
5114
5132
  setOutcome(undefined);
5115
5133
  medplum
5116
- .search(search.resourceType, core.formatSearchQuery({ ...search, total: 'estimate', fields: undefined }))
5134
+ .search(search.resourceType, core.formatSearchQuery({ ...search, total: search.total ?? 'estimate', fields: undefined }))
5117
5135
  .then((response) => {
5118
5136
  setState({ ...stateRef.current, searchResponse: response });
5119
5137
  if (onLoad) {
@@ -7189,9 +7207,9 @@
7189
7207
  }
7190
7208
  if (typeof window !== 'undefined') {
7191
7209
  const origin = window.location.protocol + '//' + window.location.host;
7192
- const authorizedOrigins = "http://localhost:3000,http://127.0.0.1:3000,http://localhost:6006,http://127.0.0.1:6006,https://app.medplum.com,https://docs.medplum.com,https://storybook.medplum.com,https://graphiql.medplum.com,https://www.medplum.com"?.split(',') ?? [];
7210
+ const authorizedOrigins = "undefined"?.split(',') ?? [];
7193
7211
  if (authorizedOrigins.includes(origin)) {
7194
- return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
7212
+ return "undefined";
7195
7213
  }
7196
7214
  }
7197
7215
  return undefined;
@@ -7486,7 +7504,7 @@
7486
7504
  * 5) Success - Return to the caller with either a code or a redirect
7487
7505
  */
7488
7506
  function SignInForm(props) {
7489
- const { chooseScopes, onSuccess, onForgotPassword, onRegister, onCode, ...baseLoginRequest } = props;
7507
+ const { login: loginCode, chooseScopes, onSuccess, onForgotPassword, onRegister, onCode, ...baseLoginRequest } = props;
7490
7508
  const medplum = useMedplum();
7491
7509
  const [login, setLogin] = React.useState(undefined);
7492
7510
  const [mfaRequired, setAuthenticatorRequired] = React.useState(false);
@@ -7527,13 +7545,17 @@
7527
7545
  handleCode(response.code);
7528
7546
  }, [handleCode]);
7529
7547
  React.useEffect(() => {
7530
- if (props.login) {
7548
+ // Beware the race condition here
7549
+ // The `useMedplum` hook will return a new instance of the MedplumClient on login
7550
+ // We do not want to request the login status again in that case
7551
+ // Only request login status once
7552
+ if (loginCode && !login) {
7531
7553
  medplum
7532
- .get('auth/login/' + props.login)
7554
+ .get('auth/login/' + loginCode)
7533
7555
  .then(handleAuthResponse)
7534
7556
  .catch(console.error);
7535
7557
  }
7536
- }, [medplum, props, handleAuthResponse]);
7558
+ }, [medplum, loginCode, login, handleAuthResponse]);
7537
7559
  return (React.createElement(Document, { width: 450 }, (() => {
7538
7560
  if (!login) {
7539
7561
  return (React.createElement(AuthenticationForm, { onForgotPassword: onForgotPassword, onRegister: onRegister, handleAuthResponse: handleAuthResponse, disableGoogleAuth: props.disableGoogleAuth, ...baseLoginRequest }, props.children));