@medplum/react 1.0.4 → 1.0.5
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/cjs/AsyncAutocomplete/AsyncAutocomplete.d.ts +14 -0
- package/dist/cjs/DiagnosticReportDisplay/DiagnosticReportDisplay.stories.d.ts +1 -0
- package/dist/cjs/FhirPathTable/FhirPathTable.d.ts +2 -2
- package/dist/cjs/ValueSetAutocomplete/ValueSetAutocomplete.d.ts +3 -6
- package/dist/cjs/auth/ChooseProfileForm.d.ts +2 -1
- package/dist/cjs/auth/ChooseScopeForm.d.ts +2 -1
- package/dist/cjs/auth/MfaForm.d.ts +7 -0
- package/dist/cjs/auth/OktaButton.d.ts +5 -0
- package/dist/cjs/auth/SignInForm.d.ts +10 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +319 -181
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index.min.js +1 -1
- package/dist/cjs/index.min.js.map +1 -1
- package/dist/cjs/stories/referenceLab.d.ts +3 -1
- package/dist/esm/AsyncAutocomplete/AsyncAutocomplete.d.ts +14 -0
- package/dist/esm/AsyncAutocomplete/AsyncAutocomplete.js +116 -0
- package/dist/esm/AsyncAutocomplete/AsyncAutocomplete.js.map +1 -0
- package/dist/esm/CodeInput/CodeInput.js +3 -2
- package/dist/esm/CodeInput/CodeInput.js.map +1 -1
- package/dist/esm/CodeableConceptInput/CodeableConceptInput.js +18 -18
- package/dist/esm/CodeableConceptInput/CodeableConceptInput.js.map +1 -1
- package/dist/esm/CodingInput/CodingInput.js +3 -2
- package/dist/esm/CodingInput/CodingInput.js.map +1 -1
- package/dist/esm/DiagnosticReportDisplay/DiagnosticReportDisplay.js +8 -2
- package/dist/esm/DiagnosticReportDisplay/DiagnosticReportDisplay.js.map +1 -1
- package/dist/esm/DiagnosticReportDisplay/DiagnosticReportDisplay.stories.d.ts +1 -0
- package/dist/esm/FhirPathTable/FhirPathTable.d.ts +2 -2
- package/dist/esm/FhirPathTable/FhirPathTable.js.map +1 -1
- package/dist/esm/QuestionnaireForm/QuestionnaireForm.js +1 -0
- package/dist/esm/QuestionnaireForm/QuestionnaireForm.js.map +1 -1
- package/dist/esm/ResourceInput/ResourceInput.js +2 -2
- package/dist/esm/ResourceInput/ResourceInput.js.map +1 -1
- package/dist/esm/StatusBadge/StatusBadge.js +2 -1
- package/dist/esm/StatusBadge/StatusBadge.js.map +1 -1
- package/dist/esm/ValueSetAutocomplete/ValueSetAutocomplete.d.ts +3 -6
- package/dist/esm/ValueSetAutocomplete/ValueSetAutocomplete.js +24 -44
- package/dist/esm/ValueSetAutocomplete/ValueSetAutocomplete.js.map +1 -1
- package/dist/esm/auth/ChooseProfileForm.d.ts +2 -1
- package/dist/esm/auth/ChooseProfileForm.js.map +1 -1
- package/dist/esm/auth/ChooseScopeForm.d.ts +2 -1
- package/dist/esm/auth/ChooseScopeForm.js.map +1 -1
- package/dist/esm/auth/MfaForm.d.ts +7 -0
- package/dist/esm/auth/MfaForm.js +34 -0
- package/dist/esm/auth/MfaForm.js.map +1 -0
- package/dist/esm/auth/OktaButton.d.ts +5 -0
- package/dist/esm/auth/SignInForm.d.ts +10 -0
- package/dist/esm/auth/SignInForm.js +16 -0
- package/dist/esm/auth/SignInForm.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/esm/stories/referenceLab.d.ts +3 -1
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -131,26 +131,41 @@
|
|
|
131
131
|
return (React.createElement(core$1.TextInput, { name: props.name, placeholder: "Annotation text", defaultValue: value.text, onChange: (e) => setText(e.currentTarget.value) }));
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
134
|
+
/******************************************************************************
|
|
135
|
+
Copyright (c) Microsoft Corporation.
|
|
136
|
+
|
|
137
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
138
|
+
purpose with or without fee is hereby granted.
|
|
139
|
+
|
|
140
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
141
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
142
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
143
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
144
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
145
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
146
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
147
|
+
***************************************************************************** */
|
|
148
|
+
|
|
149
|
+
function __rest(s, e) {
|
|
150
|
+
var t = {};
|
|
151
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
152
|
+
t[p] = s[p];
|
|
153
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
154
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
155
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
156
|
+
t[p[i]] = s[p[i]];
|
|
157
|
+
}
|
|
158
|
+
return t;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
162
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
163
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
164
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
165
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
166
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
167
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
168
|
+
});
|
|
154
169
|
}
|
|
155
170
|
|
|
156
171
|
/**
|
|
@@ -185,6 +200,137 @@
|
|
|
185
200
|
return el instanceof HTMLInputElement && el.type === 'checkbox';
|
|
186
201
|
}
|
|
187
202
|
|
|
203
|
+
function AsyncAutocomplete(props) {
|
|
204
|
+
const { defaultValue, toKey, toOption, loadOptions, onChange, onCreate } = props, rest = __rest(props, ["defaultValue", "toKey", "toOption", "loadOptions", "onChange", "onCreate"]);
|
|
205
|
+
const defaultItems = toDefaultItems(defaultValue);
|
|
206
|
+
const inputRef = React.useRef(null);
|
|
207
|
+
const [lastValue, setLastValue] = React.useState(undefined);
|
|
208
|
+
const [timer, setTimer] = React.useState();
|
|
209
|
+
const [abortController, setAbortController] = React.useState();
|
|
210
|
+
const [autoSubmit, setAutoSubmit] = React.useState();
|
|
211
|
+
const [options, setOptions] = React.useState(defaultItems === null || defaultItems === void 0 ? void 0 : defaultItems.map(toOption));
|
|
212
|
+
const lastValueRef = React.useRef();
|
|
213
|
+
lastValueRef.current = lastValue;
|
|
214
|
+
const timerRef = React.useRef();
|
|
215
|
+
timerRef.current = timer;
|
|
216
|
+
const abortControllerRef = React.useRef();
|
|
217
|
+
abortControllerRef.current = abortController;
|
|
218
|
+
const autoSubmitRef = React.useRef();
|
|
219
|
+
autoSubmitRef.current = autoSubmit;
|
|
220
|
+
const optionsRef = React.useRef();
|
|
221
|
+
optionsRef.current = options;
|
|
222
|
+
const handleTimer = React.useCallback(() => {
|
|
223
|
+
var _a, _b;
|
|
224
|
+
setTimer(undefined);
|
|
225
|
+
const value = ((_b = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.trim()) || '';
|
|
226
|
+
if (value === lastValueRef.current) {
|
|
227
|
+
// Nothing has changed, move on
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
setLastValue(value);
|
|
231
|
+
const newAbortController = new AbortController();
|
|
232
|
+
setAbortController(newAbortController);
|
|
233
|
+
loadOptions(value, newAbortController.signal)
|
|
234
|
+
.then((newValues) => {
|
|
235
|
+
if (!newAbortController.signal.aborted) {
|
|
236
|
+
setOptions(newValues.map(toOption));
|
|
237
|
+
setAbortController(undefined);
|
|
238
|
+
if (autoSubmitRef.current) {
|
|
239
|
+
if (newValues.length > 0) {
|
|
240
|
+
onChange(newValues.slice(0, 1));
|
|
241
|
+
}
|
|
242
|
+
setAutoSubmit(false);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
.catch(console.log);
|
|
247
|
+
}, [loadOptions, onChange, toOption]);
|
|
248
|
+
const handleSearchChange = React.useCallback(() => {
|
|
249
|
+
if (abortControllerRef.current) {
|
|
250
|
+
abortControllerRef.current.abort();
|
|
251
|
+
setAbortController(undefined);
|
|
252
|
+
}
|
|
253
|
+
if (timerRef.current !== undefined) {
|
|
254
|
+
window.clearTimeout(timerRef.current);
|
|
255
|
+
}
|
|
256
|
+
const newTimer = window.setTimeout(() => handleTimer(), 100);
|
|
257
|
+
setTimer(newTimer);
|
|
258
|
+
}, [handleTimer]);
|
|
259
|
+
const handleChange = React.useCallback((values) => {
|
|
260
|
+
var _a, _b;
|
|
261
|
+
const result = [];
|
|
262
|
+
for (const value of values) {
|
|
263
|
+
let item = (_b = (_a = optionsRef.current) === null || _a === void 0 ? void 0 : _a.find((option) => option.value === value)) === null || _b === void 0 ? void 0 : _b.resource;
|
|
264
|
+
if (!item) {
|
|
265
|
+
item = onCreate(value);
|
|
266
|
+
}
|
|
267
|
+
result.push(item);
|
|
268
|
+
}
|
|
269
|
+
onChange(result);
|
|
270
|
+
}, [onChange, onCreate]);
|
|
271
|
+
const handleKeyDown = React.useCallback((e) => {
|
|
272
|
+
if (e.key === 'Enter') {
|
|
273
|
+
if (!timerRef.current && !abortControllerRef.current) {
|
|
274
|
+
killEvent(e);
|
|
275
|
+
if (optionsRef.current && optionsRef.current.length > 0) {
|
|
276
|
+
setOptions(optionsRef.current.slice(0, 1));
|
|
277
|
+
handleChange([optionsRef.current[0].value]);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
// The user pressed enter, but we don't have results yet.
|
|
282
|
+
// We need to wait for the results to come in.
|
|
283
|
+
setAutoSubmit(true);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}, [handleChange]);
|
|
287
|
+
const handleCreate = React.useCallback((input) => {
|
|
288
|
+
const option = toOption(onCreate(input));
|
|
289
|
+
setOptions([...optionsRef.current, option]);
|
|
290
|
+
return option;
|
|
291
|
+
}, [onCreate, setOptions, toOption]);
|
|
292
|
+
const handleFilter = React.useCallback((_value, selected) => !selected, []);
|
|
293
|
+
React.useEffect(() => {
|
|
294
|
+
return () => {
|
|
295
|
+
if (abortControllerRef.current) {
|
|
296
|
+
abortControllerRef.current.abort();
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}, []);
|
|
300
|
+
return (React.createElement(core$1.MultiSelect, Object.assign({}, rest, { ref: inputRef, defaultValue: defaultItems.map(toKey), searchable: true, onKeyDown: handleKeyDown, onSearchChange: handleSearchChange, data: options, onFocus: handleTimer, onChange: handleChange, onCreate: handleCreate, rightSectionWidth: 40, rightSection: abortController ? React.createElement(core$1.Loader, { size: 16 }) : null, filter: handleFilter })));
|
|
301
|
+
}
|
|
302
|
+
function toDefaultItems(defaultValue) {
|
|
303
|
+
if (!defaultValue) {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
if (Array.isArray(defaultValue)) {
|
|
307
|
+
return defaultValue;
|
|
308
|
+
}
|
|
309
|
+
return [defaultValue];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function AttachmentDisplay(props) {
|
|
313
|
+
const value = props.value;
|
|
314
|
+
const { contentType, url, title } = value !== null && value !== void 0 ? value : {};
|
|
315
|
+
if (!url) {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
return (React.createElement("div", { "data-testid": "attachment-display" },
|
|
319
|
+
(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('image/')) && (React.createElement("img", { "data-testid": "attachment-image", style: { maxWidth: props.maxWidth }, src: url, alt: value === null || value === void 0 ? void 0 : value.title })),
|
|
320
|
+
(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('video/')) && (React.createElement("video", { "data-testid": "attachment-video", style: { maxWidth: props.maxWidth }, controls: true },
|
|
321
|
+
React.createElement("source", { type: contentType, src: url }))),
|
|
322
|
+
contentType === 'application/pdf' && !(title === null || title === void 0 ? void 0 : title.endsWith('.pdf')) && (React.createElement("div", { "data-testid": "attachment-pdf", style: { maxWidth: props.maxWidth, minHeight: 400 } },
|
|
323
|
+
React.createElement("iframe", { width: "100%", height: "400", src: url + '#navpanes=0', allowFullScreen: true, frameBorder: 0, seamless: true }))),
|
|
324
|
+
React.createElement("div", { "data-testid": "download-link", style: { padding: '2px 16px 16px 16px' } },
|
|
325
|
+
React.createElement(core$1.Anchor, { href: value === null || value === void 0 ? void 0 : value.url, "data-testid": "attachment-details", target: "_blank", rel: "noopener noreferrer" }, (value === null || value === void 0 ? void 0 : value.title) || 'Download'))));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function AttachmentArrayDisplay(props) {
|
|
329
|
+
return (React.createElement("div", null, props.values &&
|
|
330
|
+
props.values.map((v, index) => (React.createElement("div", { key: 'attatchment-' + index },
|
|
331
|
+
React.createElement(AttachmentDisplay, { value: v, maxWidth: props.maxWidth }))))));
|
|
332
|
+
}
|
|
333
|
+
|
|
188
334
|
function AttachmentButton(props) {
|
|
189
335
|
const medplum = useMedplum();
|
|
190
336
|
const fileInputRef = React.useRef(null);
|
|
@@ -292,43 +438,6 @@
|
|
|
292
438
|
return (React.createElement(AttachmentButton, { onUpload: setValueWrapper }, (props) => React.createElement(core$1.Button, Object.assign({}, props), "Upload...")));
|
|
293
439
|
}
|
|
294
440
|
|
|
295
|
-
/******************************************************************************
|
|
296
|
-
Copyright (c) Microsoft Corporation.
|
|
297
|
-
|
|
298
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
299
|
-
purpose with or without fee is hereby granted.
|
|
300
|
-
|
|
301
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
302
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
303
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
304
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
305
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
306
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
307
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
308
|
-
***************************************************************************** */
|
|
309
|
-
|
|
310
|
-
function __rest(s, e) {
|
|
311
|
-
var t = {};
|
|
312
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
313
|
-
t[p] = s[p];
|
|
314
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
315
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
316
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
317
|
-
t[p[i]] = s[p[i]];
|
|
318
|
-
}
|
|
319
|
-
return t;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
323
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
324
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
325
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
326
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
327
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
328
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
441
|
const useStyles$d = core$1.createStyles(() => ({
|
|
333
442
|
root: {
|
|
334
443
|
'@media (max-width: 800px)': {
|
|
@@ -774,12 +883,48 @@
|
|
|
774
883
|
React.createElement(core$1.Button, { type: "submit" }, "Set scope")))));
|
|
775
884
|
}
|
|
776
885
|
|
|
886
|
+
function MfaForm(props) {
|
|
887
|
+
const medplum = useMedplum();
|
|
888
|
+
const [errorMessage, setErrorMessage] = React.useState(undefined);
|
|
889
|
+
return (React.createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
|
|
890
|
+
setErrorMessage(undefined);
|
|
891
|
+
medplum
|
|
892
|
+
.post('auth/mfa/verify', {
|
|
893
|
+
login: props.login,
|
|
894
|
+
token: formData.token,
|
|
895
|
+
})
|
|
896
|
+
.then(props.handleAuthResponse)
|
|
897
|
+
.catch((err) => setErrorMessage(core.normalizeErrorString(err)));
|
|
898
|
+
} },
|
|
899
|
+
React.createElement(core$1.Stack, null,
|
|
900
|
+
React.createElement(core$1.Center, { sx: { flexDirection: 'column' } },
|
|
901
|
+
React.createElement(Logo, { size: 32 }),
|
|
902
|
+
React.createElement(core$1.Title, null, "Enter MFA code")),
|
|
903
|
+
errorMessage && (React.createElement(core$1.Alert, { icon: React.createElement(icons.IconAlertCircle, { size: 16 }), title: "Error", color: "red" }, errorMessage)),
|
|
904
|
+
React.createElement(core$1.Stack, null,
|
|
905
|
+
React.createElement(core$1.TextInput, { name: "token", label: "MFA code", required: true })),
|
|
906
|
+
React.createElement(core$1.Group, { position: "right", mt: "xl" },
|
|
907
|
+
React.createElement(core$1.Button, { type: "submit" }, "Submit code")))));
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* The SignInForm component allows users to sign in to Medplum.
|
|
912
|
+
*
|
|
913
|
+
* "Signing in" is a multi-step process:
|
|
914
|
+
* 1) Authentication - identify the user
|
|
915
|
+
* 2) MFA - If MFA is enabled, prompt for MFA code
|
|
916
|
+
* 3) Choose profile - If the user has multiple profiles, prompt to choose one
|
|
917
|
+
* 4) Choose scope - If the user has multiple scopes, prompt to choose one
|
|
918
|
+
* 5) Success - Return to the caller with either a code or a redirect
|
|
919
|
+
*/
|
|
777
920
|
function SignInForm(props) {
|
|
778
921
|
const { chooseScopes, onSuccess, onForgotPassword, onRegister, onCode } = props, baseLoginRequest = __rest(props, ["chooseScopes", "onSuccess", "onForgotPassword", "onRegister", "onCode"]);
|
|
779
922
|
const medplum = useMedplum();
|
|
780
923
|
const [login, setLogin] = React.useState(undefined);
|
|
924
|
+
const [mfaRequired, setAuthenticatorRequired] = React.useState(false);
|
|
781
925
|
const [memberships, setMemberships] = React.useState(undefined);
|
|
782
926
|
function handleAuthResponse(response) {
|
|
927
|
+
setAuthenticatorRequired(!!response.mfaRequired);
|
|
783
928
|
if (response.login) {
|
|
784
929
|
setLogin(response.login);
|
|
785
930
|
}
|
|
@@ -817,6 +962,9 @@
|
|
|
817
962
|
if (!login) {
|
|
818
963
|
return (React.createElement(AuthenticationForm, Object.assign({ generatePkce: !onCode, onForgotPassword: onForgotPassword, onRegister: onRegister, handleAuthResponse: handleAuthResponse }, baseLoginRequest), props.children));
|
|
819
964
|
}
|
|
965
|
+
else if (mfaRequired) {
|
|
966
|
+
return React.createElement(MfaForm, { login: login, handleAuthResponse: handleAuthResponse });
|
|
967
|
+
}
|
|
820
968
|
else if (memberships) {
|
|
821
969
|
return React.createElement(ChooseProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
|
|
822
970
|
}
|
|
@@ -1269,59 +1417,39 @@
|
|
|
1269
1417
|
return obj;
|
|
1270
1418
|
}
|
|
1271
1419
|
|
|
1272
|
-
function
|
|
1420
|
+
function toKey(element) {
|
|
1421
|
+
return element.code;
|
|
1422
|
+
}
|
|
1423
|
+
function toOption(element) {
|
|
1273
1424
|
return {
|
|
1274
1425
|
value: element.code,
|
|
1275
1426
|
label: getDisplay(element),
|
|
1276
|
-
element,
|
|
1427
|
+
resource: element,
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
function createValue(input) {
|
|
1431
|
+
return {
|
|
1432
|
+
code: input,
|
|
1433
|
+
display: input,
|
|
1277
1434
|
};
|
|
1278
1435
|
}
|
|
1279
1436
|
function ValueSetAutocomplete(props) {
|
|
1280
1437
|
const medplum = useMedplum();
|
|
1281
|
-
const {
|
|
1282
|
-
const
|
|
1283
|
-
const [data, setData] = React.useState((defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.code) ? [valueSetElementToAutocompleteItem(defaultValue)] : []);
|
|
1284
|
-
const dataRef = React.useRef();
|
|
1285
|
-
dataRef.current = data;
|
|
1286
|
-
const loadValues = React.useCallback((input) => __awaiter(this, void 0, void 0, function* () {
|
|
1438
|
+
const { elementDefinition } = props, rest = __rest(props, ["elementDefinition"]);
|
|
1439
|
+
const loadValues = React.useCallback((input, signal) => __awaiter(this, void 0, void 0, function* () {
|
|
1287
1440
|
var _a, _b;
|
|
1288
|
-
const system = (_a =
|
|
1289
|
-
const valueSet = yield medplum.searchValueSet(system, input);
|
|
1441
|
+
const system = (_a = elementDefinition.binding) === null || _a === void 0 ? void 0 : _a.valueSet;
|
|
1442
|
+
const valueSet = yield medplum.searchValueSet(system, input, { signal });
|
|
1290
1443
|
const valueSetElements = (_b = valueSet.expansion) === null || _b === void 0 ? void 0 : _b.contains;
|
|
1291
|
-
const newData = [
|
|
1444
|
+
const newData = [];
|
|
1292
1445
|
for (const valueSetElement of valueSetElements) {
|
|
1293
|
-
if (valueSetElement.code && !newData.some((item) => item.
|
|
1294
|
-
newData.push(
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
setData(newData);
|
|
1298
|
-
}), [medplum, property, dataRef]);
|
|
1299
|
-
function handleChange(values) {
|
|
1300
|
-
setTextValues(values);
|
|
1301
|
-
const textValue = values[0];
|
|
1302
|
-
let currentItem = undefined;
|
|
1303
|
-
if (textValue) {
|
|
1304
|
-
currentItem = dataRef.current.find((item) => item.value === values[0]);
|
|
1305
|
-
if (!currentItem) {
|
|
1306
|
-
const newElement = { code: textValue, display: textValue };
|
|
1307
|
-
currentItem = valueSetElementToAutocompleteItem(newElement);
|
|
1308
|
-
setData([...dataRef.current, currentItem]);
|
|
1446
|
+
if (valueSetElement.code && !newData.some((item) => item.code === valueSetElement.code)) {
|
|
1447
|
+
newData.push(valueSetElement);
|
|
1309
1448
|
}
|
|
1310
1449
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
}
|
|
1315
|
-
React.useEffect(() => {
|
|
1316
|
-
loadValues('').catch(console.log);
|
|
1317
|
-
}, [loadValues]);
|
|
1318
|
-
return (React.createElement(core$1.MultiSelect, { data: data, placeholder: props.placeholder, searchable: true, creatable: true, clearable: true, value: textValues, filter: (value, selected, item) => {
|
|
1319
|
-
var _a, _b;
|
|
1320
|
-
return !!(textValues.length === 0 &&
|
|
1321
|
-
!selected &&
|
|
1322
|
-
(((_a = item.element.display) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(value.toLowerCase().trim())) ||
|
|
1323
|
-
((_b = item.element.code) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(value.toLowerCase().trim()))));
|
|
1324
|
-
}, onChange: handleChange, getCreateLabel: (query) => `+ Create ${query}`, onCreate: (query) => valueSetElementToAutocompleteItem({ code: query, display: query }) }));
|
|
1450
|
+
return newData;
|
|
1451
|
+
}), [medplum, elementDefinition]);
|
|
1452
|
+
return (React.createElement(AsyncAutocomplete, Object.assign({}, rest, { creatable: true, clearable: true, toKey: toKey, toOption: toOption, loadOptions: loadValues, getCreateLabel: (query) => `+ Create ${query}`, onCreate: createValue })));
|
|
1325
1453
|
}
|
|
1326
1454
|
function getDisplay(item) {
|
|
1327
1455
|
return item.display || item.code || '';
|
|
@@ -1329,46 +1457,47 @@
|
|
|
1329
1457
|
|
|
1330
1458
|
function CodeableConceptInput(props) {
|
|
1331
1459
|
const [value, setValue] = React.useState(props.defaultValue);
|
|
1332
|
-
function handleChange(
|
|
1333
|
-
const newConcept =
|
|
1460
|
+
function handleChange(newValues) {
|
|
1461
|
+
const newConcept = valueSetElementToCodeableConcept(newValues);
|
|
1334
1462
|
setValue(newConcept);
|
|
1335
1463
|
if (props.onChange) {
|
|
1336
1464
|
props.onChange(newConcept);
|
|
1337
1465
|
}
|
|
1338
1466
|
}
|
|
1339
|
-
return (React.createElement(ValueSetAutocomplete, {
|
|
1467
|
+
return (React.createElement(ValueSetAutocomplete, { elementDefinition: props.property, name: props.name, placeholder: props.placeholder, defaultValue: value && codeableConceptToValueSetElement(value), onChange: handleChange }));
|
|
1340
1468
|
}
|
|
1341
1469
|
function codeableConceptToValueSetElement(concept) {
|
|
1342
|
-
var _a
|
|
1343
|
-
return {
|
|
1344
|
-
system:
|
|
1345
|
-
code:
|
|
1346
|
-
display:
|
|
1347
|
-
};
|
|
1470
|
+
var _a;
|
|
1471
|
+
return (_a = concept.coding) === null || _a === void 0 ? void 0 : _a.map((c) => ({
|
|
1472
|
+
system: c.system,
|
|
1473
|
+
code: c.code,
|
|
1474
|
+
display: c.display,
|
|
1475
|
+
}));
|
|
1348
1476
|
}
|
|
1349
|
-
function valueSetElementToCodeableConcept(
|
|
1477
|
+
function valueSetElementToCodeableConcept(elements) {
|
|
1478
|
+
if (elements.length === 0) {
|
|
1479
|
+
return undefined;
|
|
1480
|
+
}
|
|
1350
1481
|
return {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
display: element.display,
|
|
1357
|
-
},
|
|
1358
|
-
],
|
|
1482
|
+
coding: elements.map((e) => ({
|
|
1483
|
+
system: e.system,
|
|
1484
|
+
code: e.code,
|
|
1485
|
+
display: e.display,
|
|
1486
|
+
})),
|
|
1359
1487
|
};
|
|
1360
1488
|
}
|
|
1361
1489
|
|
|
1362
1490
|
function CodeInput(props) {
|
|
1363
1491
|
const [value, setValue] = React.useState(props.defaultValue);
|
|
1364
|
-
function handleChange(
|
|
1492
|
+
function handleChange(newValues) {
|
|
1493
|
+
const newValue = newValues[0];
|
|
1365
1494
|
const newCode = valueSetElementToCode(newValue);
|
|
1366
1495
|
setValue(newCode);
|
|
1367
1496
|
if (props.onChange) {
|
|
1368
1497
|
props.onChange(newCode);
|
|
1369
1498
|
}
|
|
1370
1499
|
}
|
|
1371
|
-
return (React.createElement(ValueSetAutocomplete, {
|
|
1500
|
+
return (React.createElement(ValueSetAutocomplete, { elementDefinition: props.property, name: props.name, placeholder: props.placeholder, defaultValue: codeToValueSetElement(value), onChange: handleChange }));
|
|
1372
1501
|
}
|
|
1373
1502
|
function codeToValueSetElement(code) {
|
|
1374
1503
|
return code ? { code } : undefined;
|
|
@@ -1379,14 +1508,15 @@
|
|
|
1379
1508
|
|
|
1380
1509
|
function CodingInput(props) {
|
|
1381
1510
|
const [value, setValue] = React.useState(props.defaultValue);
|
|
1382
|
-
function handleChange(
|
|
1511
|
+
function handleChange(newValues) {
|
|
1512
|
+
const newValue = newValues[0];
|
|
1383
1513
|
const newConcept = newValue && valueSetElementToCoding(newValue);
|
|
1384
1514
|
setValue(newConcept);
|
|
1385
1515
|
if (props.onChange) {
|
|
1386
1516
|
props.onChange(newConcept);
|
|
1387
1517
|
}
|
|
1388
1518
|
}
|
|
1389
|
-
return (React.createElement(ValueSetAutocomplete, {
|
|
1519
|
+
return (React.createElement(ValueSetAutocomplete, { elementDefinition: props.property, name: props.name, placeholder: props.placeholder, defaultValue: value && codingToValueSetElement(value), onChange: handleChange }));
|
|
1390
1520
|
}
|
|
1391
1521
|
function codingToValueSetElement(coding) {
|
|
1392
1522
|
return {
|
|
@@ -1694,7 +1824,7 @@
|
|
|
1694
1824
|
Observation: 'code',
|
|
1695
1825
|
RequestGroup: '_id',
|
|
1696
1826
|
ActivityDefinition: 'name',
|
|
1697
|
-
User: 'email',
|
|
1827
|
+
User: 'email:contains',
|
|
1698
1828
|
};
|
|
1699
1829
|
function ResourceInput(props) {
|
|
1700
1830
|
const medplum = useMedplum();
|
|
@@ -1712,7 +1842,7 @@
|
|
|
1712
1842
|
setLoading(true);
|
|
1713
1843
|
const searchCode = SEARCH_CODES[props.resourceType] || 'name';
|
|
1714
1844
|
const searchParams = new URLSearchParams({
|
|
1715
|
-
[searchCode]:
|
|
1845
|
+
[searchCode]: input,
|
|
1716
1846
|
_count: '10',
|
|
1717
1847
|
});
|
|
1718
1848
|
const resources = yield medplum.searchResources(props.resourceType, searchParams);
|
|
@@ -2225,6 +2355,64 @@
|
|
|
2225
2355
|
React.createElement(ResourceName, { value: props.value, link: props.link })));
|
|
2226
2356
|
}
|
|
2227
2357
|
|
|
2358
|
+
/*
|
|
2359
|
+
* Request status: https://hl7.org/fhir/valueset-request-status.html
|
|
2360
|
+
* draft, active, on-hold, revoked, completed, entered-in-error, unknown
|
|
2361
|
+
*
|
|
2362
|
+
* Publication status: https://hl7.org/fhir/valueset-publication-status.html
|
|
2363
|
+
* draft, active, retired, unknown
|
|
2364
|
+
*
|
|
2365
|
+
* Observation status: https://www.hl7.org/fhir/valueset-observation-status.html
|
|
2366
|
+
* registered, preliminary, final, amended, corrected, cancelled, entered-in-error, unknown
|
|
2367
|
+
*
|
|
2368
|
+
* DiagnosticReport status: https://hl7.org/fhir/valueset-diagnostic-report-status.html
|
|
2369
|
+
* registered, preliminary, final, amended, corrected, appended, cancelled, entered-in-error, unknown
|
|
2370
|
+
*
|
|
2371
|
+
* Task status: https://hl7.org/fhir/valueset-task-status.html
|
|
2372
|
+
* draft, requested, received, accepted, rejected, ready, cancelled, in-progress, on-hold, failed, completed, entered-in-error
|
|
2373
|
+
*
|
|
2374
|
+
* Appointment status: https://www.hl7.org/fhir/valueset-appointmentstatus.html
|
|
2375
|
+
* proposed, pending, booked, arrived, fulfilled, cancelled, noshow, entered-in-error, chcked-in, waitlist
|
|
2376
|
+
*/
|
|
2377
|
+
const statusToColor = {
|
|
2378
|
+
draft: 'blue',
|
|
2379
|
+
active: 'blue',
|
|
2380
|
+
'on-hold': 'yellow',
|
|
2381
|
+
revoked: 'red',
|
|
2382
|
+
completed: 'green',
|
|
2383
|
+
'entered-in-error': 'red',
|
|
2384
|
+
unknown: 'gray',
|
|
2385
|
+
retired: 'gray',
|
|
2386
|
+
registered: 'blue',
|
|
2387
|
+
preliminary: 'blue',
|
|
2388
|
+
final: 'green',
|
|
2389
|
+
amended: 'yellow',
|
|
2390
|
+
corrected: 'yellow',
|
|
2391
|
+
cancelled: 'red',
|
|
2392
|
+
requested: 'blue',
|
|
2393
|
+
received: 'blue',
|
|
2394
|
+
accepted: 'blue',
|
|
2395
|
+
rejected: 'red',
|
|
2396
|
+
ready: 'blue',
|
|
2397
|
+
'in-progress': 'blue',
|
|
2398
|
+
failed: 'red',
|
|
2399
|
+
proposed: 'blue',
|
|
2400
|
+
pending: 'blue',
|
|
2401
|
+
booked: 'blue',
|
|
2402
|
+
arrived: 'blue',
|
|
2403
|
+
fulfilled: 'green',
|
|
2404
|
+
noshow: 'red',
|
|
2405
|
+
'checked-in': 'blue',
|
|
2406
|
+
waitlist: 'gray',
|
|
2407
|
+
routine: 'gray',
|
|
2408
|
+
urgent: 'red',
|
|
2409
|
+
asap: 'red',
|
|
2410
|
+
stat: 'red',
|
|
2411
|
+
};
|
|
2412
|
+
function StatusBadge(props) {
|
|
2413
|
+
return React.createElement(core$1.Badge, { color: statusToColor[props.status] }, props.status);
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2228
2416
|
const useStyles$9 = core$1.createStyles((theme) => ({
|
|
2229
2417
|
table: {
|
|
2230
2418
|
border: `0.1px solid ${theme.colors.gray[5]}`,
|
|
@@ -2293,7 +2481,9 @@
|
|
|
2293
2481
|
React.createElement("th", null, "Test"),
|
|
2294
2482
|
React.createElement("th", null, "Value"),
|
|
2295
2483
|
React.createElement("th", null, "Reference Range"),
|
|
2296
|
-
React.createElement("th", null, "Interpretation")
|
|
2484
|
+
React.createElement("th", null, "Interpretation"),
|
|
2485
|
+
React.createElement("th", null, "Category"),
|
|
2486
|
+
React.createElement("th", null, "Status"))),
|
|
2297
2487
|
React.createElement("tbody", null, (_a = props.value) === null || _a === void 0 ? void 0 : _a.map((observation, index) => (React.createElement(ObservationRow, { key: 'obs-' + index, value: observation }))))));
|
|
2298
2488
|
}
|
|
2299
2489
|
function ObservationRow(props) {
|
|
@@ -2311,7 +2501,10 @@
|
|
|
2311
2501
|
React.createElement(ObservationValueDisplay, { value: observation })),
|
|
2312
2502
|
React.createElement("td", null,
|
|
2313
2503
|
React.createElement(ReferenceRangeDisplay, { value: observation.referenceRange })),
|
|
2314
|
-
React.createElement("td", null, observation.interpretation && observation.interpretation.length > 0 && (React.createElement(CodeableConceptDisplay, { value: observation.interpretation[0] })))
|
|
2504
|
+
React.createElement("td", null, observation.interpretation && observation.interpretation.length > 0 && (React.createElement(CodeableConceptDisplay, { value: observation.interpretation[0] }))),
|
|
2505
|
+
React.createElement("td", null, observation.category && observation.category.length > 0 && (React.createElement("ul", null, observation.category.map((concept) => (React.createElement("li", null,
|
|
2506
|
+
React.createElement(CodeableConceptDisplay, { value: concept }))))))),
|
|
2507
|
+
React.createElement("td", null, observation.status && React.createElement(StatusBadge, { status: observation.status }))));
|
|
2315
2508
|
}
|
|
2316
2509
|
function ObservationValueDisplay(props) {
|
|
2317
2510
|
const obs = props.value;
|
|
@@ -4586,6 +4779,7 @@
|
|
|
4586
4779
|
function setItems(newResponseItems) {
|
|
4587
4780
|
const newResponse = {
|
|
4588
4781
|
resourceType: 'QuestionnaireResponse',
|
|
4782
|
+
status: 'completed',
|
|
4589
4783
|
item: newResponseItems,
|
|
4590
4784
|
};
|
|
4591
4785
|
setResponse(newResponse);
|
|
@@ -5339,63 +5533,6 @@
|
|
|
5339
5533
|
return ((_b = (_a = interval.range) === null || _a === void 0 ? void 0 : _a.low) === null || _b === void 0 ? void 0 : _b.value) === undefined && ((_d = (_c = interval.range) === null || _c === void 0 ? void 0 : _c.high) === null || _d === void 0 ? void 0 : _d.value) === undefined;
|
|
5340
5534
|
}
|
|
5341
5535
|
|
|
5342
|
-
/*
|
|
5343
|
-
* Request status: https://hl7.org/fhir/valueset-request-status.html
|
|
5344
|
-
* draft, active, on-hold, revoked, completed, entered-in-error, unknown
|
|
5345
|
-
*
|
|
5346
|
-
* Publication status: https://hl7.org/fhir/valueset-publication-status.html
|
|
5347
|
-
* draft, active, retired, unknown
|
|
5348
|
-
*
|
|
5349
|
-
* Observation status: https://www.hl7.org/fhir/valueset-observation-status.html
|
|
5350
|
-
* registered, preliminary, final, amended, cancelled, entered-in-error, unknown
|
|
5351
|
-
*
|
|
5352
|
-
* DiagnosticReport status: https://hl7.org/fhir/valueset-diagnostic-report-status.html
|
|
5353
|
-
* registered, preliminary, final, amended, corrected, appended, cancelled, entered-in-error, unknown
|
|
5354
|
-
*
|
|
5355
|
-
* Task status: https://hl7.org/fhir/valueset-task-status.html
|
|
5356
|
-
* draft, requested, received, accepted, rejected, ready, cancelled, in-progress, on-hold, failed, completed, entered-in-error
|
|
5357
|
-
*
|
|
5358
|
-
* Appointment status: https://www.hl7.org/fhir/valueset-appointmentstatus.html
|
|
5359
|
-
* proposed, pending, booked, arrived, fulfilled, cancelled, noshow, entered-in-error, chcked-in, waitlist
|
|
5360
|
-
*/
|
|
5361
|
-
const statusToColor = {
|
|
5362
|
-
draft: 'blue',
|
|
5363
|
-
active: 'blue',
|
|
5364
|
-
'on-hold': 'yellow',
|
|
5365
|
-
revoked: 'red',
|
|
5366
|
-
completed: 'green',
|
|
5367
|
-
'entered-in-error': 'red',
|
|
5368
|
-
unknown: 'gray',
|
|
5369
|
-
retired: 'gray',
|
|
5370
|
-
registered: 'blue',
|
|
5371
|
-
preliminary: 'blue',
|
|
5372
|
-
final: 'green',
|
|
5373
|
-
amended: 'yellow',
|
|
5374
|
-
cancelled: 'red',
|
|
5375
|
-
requested: 'blue',
|
|
5376
|
-
received: 'blue',
|
|
5377
|
-
accepted: 'blue',
|
|
5378
|
-
rejected: 'red',
|
|
5379
|
-
ready: 'blue',
|
|
5380
|
-
'in-progress': 'blue',
|
|
5381
|
-
failed: 'red',
|
|
5382
|
-
proposed: 'blue',
|
|
5383
|
-
pending: 'blue',
|
|
5384
|
-
booked: 'blue',
|
|
5385
|
-
arrived: 'blue',
|
|
5386
|
-
fulfilled: 'green',
|
|
5387
|
-
noshow: 'red',
|
|
5388
|
-
'checked-in': 'blue',
|
|
5389
|
-
waitlist: 'gray',
|
|
5390
|
-
routine: 'gray',
|
|
5391
|
-
urgent: 'red',
|
|
5392
|
-
asap: 'red',
|
|
5393
|
-
stat: 'red',
|
|
5394
|
-
};
|
|
5395
|
-
function StatusBadge(props) {
|
|
5396
|
-
return React.createElement(core$1.Badge, { color: statusToColor[props.status] }, props.status);
|
|
5397
|
-
}
|
|
5398
|
-
|
|
5399
5536
|
function RequestGroupDisplay(props) {
|
|
5400
5537
|
var _a;
|
|
5401
5538
|
const medplum = useMedplum();
|
|
@@ -5965,6 +6102,7 @@
|
|
|
5965
6102
|
exports.AddressDisplay = AddressDisplay;
|
|
5966
6103
|
exports.AddressInput = AddressInput;
|
|
5967
6104
|
exports.AnnotationInput = AnnotationInput;
|
|
6105
|
+
exports.AsyncAutocomplete = AsyncAutocomplete;
|
|
5968
6106
|
exports.AttachmentArrayDisplay = AttachmentArrayDisplay;
|
|
5969
6107
|
exports.AttachmentArrayInput = AttachmentArrayInput;
|
|
5970
6108
|
exports.AttachmentButton = AttachmentButton;
|