@medplum/react 0.9.30 → 0.9.31
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/auth/AuthenticationForm.d.ts +14 -0
- package/dist/cjs/auth/ChooseProfileForm.d.ts +8 -0
- package/dist/cjs/auth/NewProjectForm.d.ts +7 -0
- package/dist/cjs/auth/NewUserForm.d.ts +10 -0
- package/dist/cjs/auth/RegisterForm.d.ts +12 -0
- package/dist/cjs/{SignInForm.d.ts → auth/SignInForm.d.ts} +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +671 -648
- 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/styles.css +197 -197
- package/dist/esm/MedplumLink.js +29 -14
- package/dist/esm/MedplumLink.js.map +1 -1
- package/dist/esm/ResourceHistoryTable.js +15 -11
- package/dist/esm/ResourceHistoryTable.js.map +1 -1
- package/dist/esm/ResourceTimeline.js +3 -1
- package/dist/esm/ResourceTimeline.js.map +1 -1
- package/dist/esm/auth/AuthenticationForm.d.ts +14 -0
- package/dist/esm/auth/AuthenticationForm.js +67 -0
- package/dist/esm/auth/AuthenticationForm.js.map +1 -0
- package/dist/esm/auth/ChooseProfileForm.d.ts +8 -0
- package/dist/esm/auth/ChooseProfileForm.js +32 -0
- package/dist/esm/auth/ChooseProfileForm.js.map +1 -0
- package/dist/esm/auth/NewProjectForm.d.ts +7 -0
- package/dist/esm/auth/NewProjectForm.js +42 -0
- package/dist/esm/auth/NewProjectForm.js.map +1 -0
- package/dist/esm/auth/NewUserForm.d.ts +10 -0
- package/dist/esm/auth/NewUserForm.js +87 -0
- package/dist/esm/auth/NewUserForm.js.map +1 -0
- package/dist/esm/auth/RegisterForm.d.ts +12 -0
- package/dist/esm/auth/RegisterForm.js +39 -0
- package/dist/esm/auth/RegisterForm.js.map +1 -0
- package/dist/esm/{SignInForm.d.ts → auth/SignInForm.d.ts} +1 -1
- package/dist/esm/auth/SignInForm.js +52 -0
- package/dist/esm/auth/SignInForm.js.map +1 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/esm/styles.css +197 -197
- package/package.json +16 -18
- package/dist/cjs/RegisterForm.d.ts +0 -18
- package/dist/esm/RegisterForm.d.ts +0 -18
- package/dist/esm/RegisterForm.js +0 -121
- package/dist/esm/RegisterForm.js.map +0 -1
- package/dist/esm/SignInForm.js +0 -167
- package/dist/esm/SignInForm.js.map +0 -1
package/dist/cjs/index.js
CHANGED
|
@@ -329,6 +329,578 @@
|
|
|
329
329
|
return React__default["default"].createElement(UploadButton, { onUpload: setValueWrapper });
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
function Document(props) {
|
|
333
|
+
return (React__default["default"].createElement("main", { className: "medplum-document" },
|
|
334
|
+
React__default["default"].createElement("article", { style: { maxWidth: props.width } }, props.children)));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/******************************************************************************
|
|
338
|
+
Copyright (c) Microsoft Corporation.
|
|
339
|
+
|
|
340
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
341
|
+
purpose with or without fee is hereby granted.
|
|
342
|
+
|
|
343
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
344
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
345
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
346
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
347
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
348
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
349
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
350
|
+
***************************************************************************** */
|
|
351
|
+
|
|
352
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
353
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
354
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
355
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
356
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
357
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
358
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Parses an HTML form and returns the result as a JavaScript object.
|
|
364
|
+
* @param form The HTML form element.
|
|
365
|
+
*/
|
|
366
|
+
function parseForm(form) {
|
|
367
|
+
const result = {};
|
|
368
|
+
for (const element of Array.from(form.elements)) {
|
|
369
|
+
if (element instanceof HTMLInputElement) {
|
|
370
|
+
parseInputElement(result, element);
|
|
371
|
+
}
|
|
372
|
+
else if (element instanceof HTMLTextAreaElement) {
|
|
373
|
+
result[element.name] = element.value;
|
|
374
|
+
}
|
|
375
|
+
else if (element instanceof HTMLSelectElement) {
|
|
376
|
+
parseSelectElement(result, element);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Parses an HTML input element.
|
|
383
|
+
* Sets the name/value pair in the result,
|
|
384
|
+
* but only if the element is enabled and checked.
|
|
385
|
+
* @param el The input element.
|
|
386
|
+
* @param result The result builder.
|
|
387
|
+
*/
|
|
388
|
+
function parseInputElement(result, el) {
|
|
389
|
+
if (el.disabled) {
|
|
390
|
+
// Ignore disabled elements
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if ((el.type === 'checkbox' || el.type === 'radio') && !el.checked) {
|
|
394
|
+
// Ignore unchecked radio or checkbox elements
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
result[el.name] = el.value;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Parses an HTML select element.
|
|
401
|
+
* Sets the name/value pair if one is selected.
|
|
402
|
+
* @param result The result builder.
|
|
403
|
+
* @param el The select element.
|
|
404
|
+
*/
|
|
405
|
+
function parseSelectElement(result, el) {
|
|
406
|
+
result[el.name] = el.value;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function Form(props) {
|
|
410
|
+
return (React__default["default"].createElement("form", { style: props.style, "data-testid": props.testid, onSubmit: (e) => {
|
|
411
|
+
e.preventDefault();
|
|
412
|
+
const formData = parseForm(e.target);
|
|
413
|
+
if (props.onSubmit) {
|
|
414
|
+
props.onSubmit(formData);
|
|
415
|
+
}
|
|
416
|
+
} }, props.children));
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function FormSection(props) {
|
|
420
|
+
const issues = getIssuesForExpression(props.outcome, props.htmlFor);
|
|
421
|
+
const invalid = issues && issues.length > 0;
|
|
422
|
+
return (React__default["default"].createElement("fieldset", { className: "medplum-form-section" },
|
|
423
|
+
props.title && React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
|
|
424
|
+
props.description && React__default["default"].createElement("p", null, props.description),
|
|
425
|
+
props.children,
|
|
426
|
+
invalid && (React__default["default"].createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
|
|
427
|
+
var _a, _b;
|
|
428
|
+
return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
|
|
429
|
+
})))));
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function Logo(props) {
|
|
433
|
+
return (React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 491 491", style: { width: props.size, height: props.size } },
|
|
434
|
+
React__default["default"].createElement("title", null, "Medplum Logo"),
|
|
435
|
+
React__default["default"].createElement("path", { fill: props.fill || '#ad7136', d: "M282 67c6-16 16-29 29-40L289 0c-22 17-37 41-43 68l17 23 19-24z" }),
|
|
436
|
+
React__default["default"].createElement("path", { fill: props.fill || '#654b87', d: "M311 63c-17 0-33 4-48 11-16-7-32-11-49-11-87 0-158 96-158 214s71 214 158 214c17 0 33-4 49-11 15 7 31 11 48 11 87 0 158-96 158-214S398 63 311 63z" }),
|
|
437
|
+
React__default["default"].createElement("path", { fill: props.fill || '#463068', d: "M231 489l-17 2c-87 0-158-96-158-214S127 63 214 63l17 1c-39 12-70 102-70 213s31 201 70 212z" }),
|
|
438
|
+
React__default["default"].createElement("path", { fill: props.fill || '#70d65b', d: "M207 220a176 176 0 01-177 43A176 176 0 01251 43l1 5c17 59 2 125-45 172z" }),
|
|
439
|
+
React__default["default"].createElement("path", { fill: props.fill || '#58b741', d: "M252 48A421 421 0 0057 270l-27-7A176 176 0 01251 43l1 5z" })));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function NewProjectForm(props) {
|
|
443
|
+
const medplum = useMedplum();
|
|
444
|
+
const [outcome, setOutcome] = React.useState();
|
|
445
|
+
return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
|
|
446
|
+
try {
|
|
447
|
+
props.handleAuthResponse(yield medplum.startNewProject({
|
|
448
|
+
login: props.login,
|
|
449
|
+
projectName: formData.projectName,
|
|
450
|
+
}));
|
|
451
|
+
}
|
|
452
|
+
catch (err) {
|
|
453
|
+
setOutcome(err);
|
|
454
|
+
}
|
|
455
|
+
}) },
|
|
456
|
+
React__default["default"].createElement("div", { className: "medplum-center" },
|
|
457
|
+
React__default["default"].createElement(Logo, { size: 32 }),
|
|
458
|
+
React__default["default"].createElement("h1", null, "Create project")),
|
|
459
|
+
React__default["default"].createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
|
|
460
|
+
React__default["default"].createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome })),
|
|
461
|
+
React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
|
|
462
|
+
"By clicking submit you agree to the Medplum ",
|
|
463
|
+
React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
|
|
464
|
+
' and ',
|
|
465
|
+
React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
|
|
466
|
+
"."),
|
|
467
|
+
React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
|
|
468
|
+
React__default["default"].createElement("div", null),
|
|
469
|
+
React__default["default"].createElement("div", null,
|
|
470
|
+
React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create project")))));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Dynamically creates a script tag for the specified JavaScript file.
|
|
475
|
+
* @param src The JavaScript file URL.
|
|
476
|
+
*/
|
|
477
|
+
function createScriptTag(src, onload) {
|
|
478
|
+
const head = document.getElementsByTagName('head')[0];
|
|
479
|
+
const script = document.createElement('script');
|
|
480
|
+
script.async = true;
|
|
481
|
+
script.src = src;
|
|
482
|
+
script.onload = onload || null;
|
|
483
|
+
head.appendChild(script);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function GoogleButton(props) {
|
|
487
|
+
const medplum = useMedplum();
|
|
488
|
+
const { googleClientId, handleGoogleCredential } = props;
|
|
489
|
+
const parentRef = React.useRef(null);
|
|
490
|
+
const [scriptLoaded, setScriptLoaded] = React.useState(typeof google !== 'undefined');
|
|
491
|
+
const [initialized, setInitialized] = React.useState(false);
|
|
492
|
+
const [buttonRendered, setButtonRendered] = React.useState(false);
|
|
493
|
+
React.useEffect(() => {
|
|
494
|
+
if (typeof google === 'undefined') {
|
|
495
|
+
createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (!initialized) {
|
|
499
|
+
google.accounts.id.initialize({
|
|
500
|
+
client_id: googleClientId,
|
|
501
|
+
callback: handleGoogleCredential,
|
|
502
|
+
});
|
|
503
|
+
setInitialized(true);
|
|
504
|
+
}
|
|
505
|
+
if (parentRef.current && !buttonRendered) {
|
|
506
|
+
google.accounts.id.renderButton(parentRef.current, {});
|
|
507
|
+
setButtonRendered(true);
|
|
508
|
+
}
|
|
509
|
+
}, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
|
|
510
|
+
if (!googleClientId) {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
return React__default["default"].createElement("div", { ref: parentRef });
|
|
514
|
+
}
|
|
515
|
+
function getGoogleClientId(clientId) {
|
|
516
|
+
var _a, _b;
|
|
517
|
+
if (clientId) {
|
|
518
|
+
return clientId;
|
|
519
|
+
}
|
|
520
|
+
const origin = window.location.protocol + '//' + window.location.host;
|
|
521
|
+
const authorizedOrigins = (_b = (_a = "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") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
|
|
522
|
+
if (authorizedOrigins.includes(origin)) {
|
|
523
|
+
return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
|
|
524
|
+
}
|
|
525
|
+
return undefined;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Dynamically loads the recaptcha script.
|
|
530
|
+
* We do not want to load the script on page load unless the user needs it.
|
|
531
|
+
* @param siteKey The reCAPTCHA site key, available from the reCAPTCHA admin page.
|
|
532
|
+
*/
|
|
533
|
+
function initRecaptcha(siteKey) {
|
|
534
|
+
if (typeof grecaptcha === 'undefined') {
|
|
535
|
+
createScriptTag('https://www.google.com/recaptcha/api.js?render=' + siteKey);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Starts a request to generate a recapcha token.
|
|
540
|
+
* @param siteKey The reCAPTCHA site key, available from the reCAPTCHA admin page.
|
|
541
|
+
* @returns Promise to a recaptcha token for the current user.
|
|
542
|
+
*/
|
|
543
|
+
function getRecaptcha(siteKey) {
|
|
544
|
+
return new Promise((resolve, reject) => {
|
|
545
|
+
grecaptcha.ready(() => __awaiter(this, void 0, void 0, function* () {
|
|
546
|
+
try {
|
|
547
|
+
resolve(yield grecaptcha.execute(siteKey, { action: 'submit' }));
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
reject(err);
|
|
551
|
+
}
|
|
552
|
+
}));
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function NewUserForm(props) {
|
|
557
|
+
const googleClientId = getGoogleClientId(props.googleClientId);
|
|
558
|
+
const recaptchaSiteKey = props.recaptchaSiteKey;
|
|
559
|
+
const medplum = useMedplum();
|
|
560
|
+
const [outcome, setOutcome] = React.useState();
|
|
561
|
+
const issues = getIssuesForExpression(outcome, undefined);
|
|
562
|
+
React.useEffect(() => initRecaptcha(recaptchaSiteKey), [recaptchaSiteKey]);
|
|
563
|
+
return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
|
|
564
|
+
try {
|
|
565
|
+
const recaptchaToken = yield getRecaptcha(recaptchaSiteKey);
|
|
566
|
+
props.handleAuthResponse(yield medplum.startNewUser({
|
|
567
|
+
projectId: props.projectId,
|
|
568
|
+
firstName: formData.firstName,
|
|
569
|
+
lastName: formData.lastName,
|
|
570
|
+
email: formData.email,
|
|
571
|
+
password: formData.password,
|
|
572
|
+
remember: formData.remember === 'true',
|
|
573
|
+
recaptchaSiteKey,
|
|
574
|
+
recaptchaToken,
|
|
575
|
+
}));
|
|
576
|
+
}
|
|
577
|
+
catch (err) {
|
|
578
|
+
setOutcome(err);
|
|
579
|
+
}
|
|
580
|
+
}) },
|
|
581
|
+
React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
|
|
582
|
+
issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
|
|
583
|
+
var _a, _b;
|
|
584
|
+
return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
|
|
585
|
+
}))),
|
|
586
|
+
googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
587
|
+
React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
|
|
588
|
+
React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => __awaiter(this, void 0, void 0, function* () {
|
|
589
|
+
try {
|
|
590
|
+
props.handleAuthResponse(yield medplum.startGoogleLogin({
|
|
591
|
+
googleClientId: response.clientId,
|
|
592
|
+
googleCredential: response.credential,
|
|
593
|
+
createUser: true,
|
|
594
|
+
}));
|
|
595
|
+
}
|
|
596
|
+
catch (err) {
|
|
597
|
+
setOutcome(err);
|
|
598
|
+
}
|
|
599
|
+
}) })),
|
|
600
|
+
React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
|
|
601
|
+
React__default["default"].createElement(FormSection, { title: "First Name", htmlFor: "firstName", outcome: outcome },
|
|
602
|
+
React__default["default"].createElement(Input, { name: "firstName", type: "text", testid: "firstName", placeholder: "First name", required: true, autoFocus: true, outcome: outcome })),
|
|
603
|
+
React__default["default"].createElement(FormSection, { title: "Last Name", htmlFor: "lastName", outcome: outcome },
|
|
604
|
+
React__default["default"].createElement(Input, { name: "lastName", type: "text", testid: "lastName", placeholder: "Last name", required: true, outcome: outcome })),
|
|
605
|
+
React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
|
|
606
|
+
React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", placeholder: "name@domain.com", required: true, outcome: outcome })),
|
|
607
|
+
React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
|
|
608
|
+
React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
|
|
609
|
+
React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
|
|
610
|
+
"By clicking submit you agree to the Medplum ",
|
|
611
|
+
React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
|
|
612
|
+
' and ',
|
|
613
|
+
React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
|
|
614
|
+
"."),
|
|
615
|
+
React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
|
|
616
|
+
"This site is protected by reCAPTCHA and the Google",
|
|
617
|
+
' ',
|
|
618
|
+
React__default["default"].createElement("a", { href: "https://policies.google.com/privacy" }, "Privacy\u00A0Policy"),
|
|
619
|
+
' and ',
|
|
620
|
+
React__default["default"].createElement("a", { href: "https://policies.google.com/terms" }, "Terms\u00A0of\u00A0Service"),
|
|
621
|
+
" apply."),
|
|
622
|
+
React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
|
|
623
|
+
React__default["default"].createElement("div", null,
|
|
624
|
+
React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
|
|
625
|
+
React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
|
|
626
|
+
React__default["default"].createElement("div", null,
|
|
627
|
+
React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create account")))));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function RegisterForm(props) {
|
|
631
|
+
const { type, projectId, googleClientId, recaptchaSiteKey, onSuccess } = props;
|
|
632
|
+
const medplum = useMedplum();
|
|
633
|
+
const [login, setLogin] = React.useState(undefined);
|
|
634
|
+
const [outcome, setOutcome] = React.useState();
|
|
635
|
+
React.useEffect(() => {
|
|
636
|
+
if (type === 'patient' && login) {
|
|
637
|
+
medplum
|
|
638
|
+
.startNewPatient({ login, projectId: projectId })
|
|
639
|
+
.then((response) => medplum.processCode(response.code))
|
|
640
|
+
.then(() => onSuccess())
|
|
641
|
+
.catch((err) => setOutcome(err));
|
|
642
|
+
}
|
|
643
|
+
}, [medplum, type, projectId, login, onSuccess]);
|
|
644
|
+
function handleAuthResponse(response) {
|
|
645
|
+
if (response.code) {
|
|
646
|
+
medplum
|
|
647
|
+
.processCode(response.code)
|
|
648
|
+
.then(() => onSuccess())
|
|
649
|
+
.catch(console.log);
|
|
650
|
+
}
|
|
651
|
+
else if (response.login) {
|
|
652
|
+
setLogin(response.login);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return (React__default["default"].createElement(Document, { width: 450 },
|
|
656
|
+
outcome && React__default["default"].createElement("pre", null, JSON.stringify(outcome, null, 2)),
|
|
657
|
+
!login && (React__default["default"].createElement(NewUserForm, { projectId: projectId, googleClientId: googleClientId, recaptchaSiteKey: recaptchaSiteKey, handleAuthResponse: handleAuthResponse })),
|
|
658
|
+
login && type === 'project' && React__default["default"].createElement(NewProjectForm, { login: login, handleAuthResponse: handleAuthResponse })));
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function MedplumLink(props) {
|
|
662
|
+
const navigate = reactRouterDom.useNavigate();
|
|
663
|
+
let href = getHref(props.to);
|
|
664
|
+
if (props.suffix) {
|
|
665
|
+
href += '/' + props.suffix;
|
|
666
|
+
}
|
|
667
|
+
return (React__default["default"].createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
|
|
668
|
+
killEvent(e);
|
|
669
|
+
if (props.onClick) {
|
|
670
|
+
props.onClick();
|
|
671
|
+
}
|
|
672
|
+
else if (props.to) {
|
|
673
|
+
navigate(href);
|
|
674
|
+
}
|
|
675
|
+
} }, props.children));
|
|
676
|
+
}
|
|
677
|
+
function getHref(to) {
|
|
678
|
+
if (to) {
|
|
679
|
+
if (typeof to === 'string') {
|
|
680
|
+
return getStringHref(to);
|
|
681
|
+
}
|
|
682
|
+
else if ('resourceType' in to) {
|
|
683
|
+
return getResourceHref(to);
|
|
684
|
+
}
|
|
685
|
+
else if ('reference' in to) {
|
|
686
|
+
return getReferenceHref(to);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return '#';
|
|
690
|
+
}
|
|
691
|
+
function getStringHref(to) {
|
|
692
|
+
if (to.startsWith('http://') || to.startsWith('https://') || to.startsWith('/')) {
|
|
693
|
+
return to;
|
|
694
|
+
}
|
|
695
|
+
return '/' + to;
|
|
696
|
+
}
|
|
697
|
+
function getResourceHref(to) {
|
|
698
|
+
return `/${to.resourceType}/${to.id}`;
|
|
699
|
+
}
|
|
700
|
+
function getReferenceHref(to) {
|
|
701
|
+
return `/${to.reference}`;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function AuthenticationForm(props) {
|
|
705
|
+
const medplum = useMedplum();
|
|
706
|
+
const googleClientId = getGoogleClientId(props.googleClientId);
|
|
707
|
+
const [outcome, setOutcome] = React.useState();
|
|
708
|
+
const issues = getIssuesForExpression(outcome, undefined);
|
|
709
|
+
return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
|
|
710
|
+
medplum
|
|
711
|
+
.startLogin({
|
|
712
|
+
projectId: props.projectId,
|
|
713
|
+
clientId: props.clientId,
|
|
714
|
+
scope: props.scope,
|
|
715
|
+
nonce: props.nonce,
|
|
716
|
+
email: formData.email,
|
|
717
|
+
password: formData.password,
|
|
718
|
+
remember: formData.remember === 'true',
|
|
719
|
+
})
|
|
720
|
+
.then(props.handleAuthResponse)
|
|
721
|
+
.catch(setOutcome);
|
|
722
|
+
} },
|
|
723
|
+
React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
|
|
724
|
+
issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
|
|
725
|
+
var _a, _b;
|
|
726
|
+
return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
|
|
727
|
+
}))),
|
|
728
|
+
googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
729
|
+
React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
|
|
730
|
+
React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => {
|
|
731
|
+
medplum
|
|
732
|
+
.startGoogleLogin({
|
|
733
|
+
projectId: props.projectId,
|
|
734
|
+
clientId: props.clientId,
|
|
735
|
+
scope: props.scope,
|
|
736
|
+
nonce: props.nonce,
|
|
737
|
+
googleClientId: response.clientId,
|
|
738
|
+
googleCredential: response.credential,
|
|
739
|
+
})
|
|
740
|
+
.then(props.handleAuthResponse)
|
|
741
|
+
.catch(setOutcome);
|
|
742
|
+
} })),
|
|
743
|
+
React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
|
|
744
|
+
React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
|
|
745
|
+
React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", required: true, autoFocus: true, outcome: outcome })),
|
|
746
|
+
React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
|
|
747
|
+
React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
|
|
748
|
+
React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
|
|
749
|
+
(props.onForgotPassword || props.onRegister) && (React__default["default"].createElement("div", null,
|
|
750
|
+
props.onForgotPassword && (React__default["default"].createElement(MedplumLink, { testid: "forgotpassword", onClick: props.onForgotPassword }, "Forgot password")),
|
|
751
|
+
props.onRegister && (React__default["default"].createElement(MedplumLink, { testid: "register", onClick: props.onRegister }, "Register")))),
|
|
752
|
+
React__default["default"].createElement("div", null,
|
|
753
|
+
React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
|
|
754
|
+
React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
|
|
755
|
+
React__default["default"].createElement("div", null,
|
|
756
|
+
React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Sign in")))));
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const system = {
|
|
760
|
+
resourceType: 'Device',
|
|
761
|
+
id: 'system',
|
|
762
|
+
deviceName: [
|
|
763
|
+
{
|
|
764
|
+
name: 'System',
|
|
765
|
+
},
|
|
766
|
+
],
|
|
767
|
+
};
|
|
768
|
+
/**
|
|
769
|
+
* React Hook to use a FHIR reference.
|
|
770
|
+
* Handles the complexity of resolving references and caching resources.
|
|
771
|
+
* @param value The resource or reference to resource.
|
|
772
|
+
* @returns The resolved resource.
|
|
773
|
+
*/
|
|
774
|
+
function useResource(value) {
|
|
775
|
+
const medplum = useMedplum();
|
|
776
|
+
const [resource, setResource] = React.useState(getInitialResource(medplum, value));
|
|
777
|
+
React.useEffect(() => {
|
|
778
|
+
let subscribed = true;
|
|
779
|
+
if (!resource && value && 'reference' in value && value.reference) {
|
|
780
|
+
medplum
|
|
781
|
+
.readReference(value)
|
|
782
|
+
.then((r) => {
|
|
783
|
+
if (subscribed) {
|
|
784
|
+
setResource(r);
|
|
785
|
+
}
|
|
786
|
+
})
|
|
787
|
+
.catch(() => setResource(undefined));
|
|
788
|
+
}
|
|
789
|
+
return (() => (subscribed = false));
|
|
790
|
+
}, [medplum, resource, value]);
|
|
791
|
+
return resource;
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Returns the initial resource value based on the input value.
|
|
795
|
+
* If the input value is a resource, returns the resource.
|
|
796
|
+
* If the input value is a reference to system, returns the system resource.
|
|
797
|
+
* If the input value is a reference to a resource available in the cache, returns the resource.
|
|
798
|
+
* Otherwise, returns undefined.
|
|
799
|
+
* @param medplum The medplum client.
|
|
800
|
+
* @param value The resource or reference to resource.
|
|
801
|
+
* @returns An initial resource if available; undefined otherwise.
|
|
802
|
+
*/
|
|
803
|
+
function getInitialResource(medplum, value) {
|
|
804
|
+
if (!value) {
|
|
805
|
+
return undefined;
|
|
806
|
+
}
|
|
807
|
+
if ('resourceType' in value) {
|
|
808
|
+
return value;
|
|
809
|
+
}
|
|
810
|
+
if ('reference' in value) {
|
|
811
|
+
if (value.reference === 'system') {
|
|
812
|
+
return system;
|
|
813
|
+
}
|
|
814
|
+
return medplum.getCachedReference(value);
|
|
815
|
+
}
|
|
816
|
+
return undefined;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function Avatar(props) {
|
|
820
|
+
var _a, _b;
|
|
821
|
+
const resource = useResource(props.value);
|
|
822
|
+
const className = props.size ? 'medplum-avatar ' + props.size : 'medplum-avatar';
|
|
823
|
+
const text = resource ? core.getDisplayString(resource) : (_a = props.alt) !== null && _a !== void 0 ? _a : '';
|
|
824
|
+
const initials = text && getInitials(text);
|
|
825
|
+
const imageUrl = (_b = (resource && core.getImageSrc(resource))) !== null && _b !== void 0 ? _b : props.src;
|
|
826
|
+
const innerContent = imageUrl ? React__default["default"].createElement("img", { src: imageUrl, alt: text }) : initials;
|
|
827
|
+
return (React__default["default"].createElement("div", { className: className, style: { backgroundColor: props.color }, "data-testid": "avatar" }, props.link && resource ? React__default["default"].createElement(MedplumLink, { to: resource }, innerContent) : innerContent));
|
|
828
|
+
}
|
|
829
|
+
function getInitials(text) {
|
|
830
|
+
return text
|
|
831
|
+
.split(' ')
|
|
832
|
+
.map((n) => n[0])
|
|
833
|
+
.join('');
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function ChooseProfileForm(props) {
|
|
837
|
+
const medplum = useMedplum();
|
|
838
|
+
return (React__default["default"].createElement("div", null,
|
|
839
|
+
React__default["default"].createElement("div", { className: "medplum-center" },
|
|
840
|
+
React__default["default"].createElement(Logo, { size: 32 }),
|
|
841
|
+
React__default["default"].createElement("h1", null, "Choose profile")),
|
|
842
|
+
props.memberships.map((membership) => {
|
|
843
|
+
var _a, _b, _c;
|
|
844
|
+
return (React__default["default"].createElement("div", { className: "medplum-nav-menu-profile", key: membership.id, onClick: () => {
|
|
845
|
+
medplum
|
|
846
|
+
.post('auth/profile', {
|
|
847
|
+
login: props.login,
|
|
848
|
+
profile: membership.id,
|
|
849
|
+
})
|
|
850
|
+
.then(props.handleAuthResponse)
|
|
851
|
+
.catch(console.log);
|
|
852
|
+
} },
|
|
853
|
+
React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
|
|
854
|
+
React__default["default"].createElement(Avatar, { alt: (_a = membership.profile) === null || _a === void 0 ? void 0 : _a.display })),
|
|
855
|
+
React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-label" }, (_b = membership.profile) === null || _b === void 0 ? void 0 :
|
|
856
|
+
_b.display,
|
|
857
|
+
React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-help-text" }, (_c = membership.project) === null || _c === void 0 ? void 0 : _c.display))));
|
|
858
|
+
})));
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
function SignInForm(props) {
|
|
862
|
+
const medplum = useMedplum();
|
|
863
|
+
const [login, setLogin] = React.useState(undefined);
|
|
864
|
+
const [memberships, setMemberships] = React.useState(undefined);
|
|
865
|
+
function handleAuthResponse(response) {
|
|
866
|
+
if (response.login) {
|
|
867
|
+
setLogin(response.login);
|
|
868
|
+
}
|
|
869
|
+
if (response.memberships) {
|
|
870
|
+
setMemberships(response.memberships);
|
|
871
|
+
}
|
|
872
|
+
if (response.code) {
|
|
873
|
+
if (props.onCode) {
|
|
874
|
+
props.onCode(response.code);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
medplum
|
|
878
|
+
.processCode(response.code)
|
|
879
|
+
.then(() => {
|
|
880
|
+
if (props.onSuccess) {
|
|
881
|
+
props.onSuccess();
|
|
882
|
+
}
|
|
883
|
+
})
|
|
884
|
+
.catch(console.log);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return (React__default["default"].createElement(Document, { width: 450 }, (() => {
|
|
889
|
+
if (!login) {
|
|
890
|
+
return (React__default["default"].createElement(AuthenticationForm, { projectId: props.projectId, clientId: props.clientId, scope: props.scope, nonce: props.nonce, googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
|
|
891
|
+
}
|
|
892
|
+
else if (memberships) {
|
|
893
|
+
return React__default["default"].createElement(ChooseProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
|
|
894
|
+
}
|
|
895
|
+
else if (props.projectId === 'new') {
|
|
896
|
+
return React__default["default"].createElement(NewProjectForm, { login: login, handleAuthResponse: handleAuthResponse });
|
|
897
|
+
}
|
|
898
|
+
else {
|
|
899
|
+
return React__default["default"].createElement("div", null, "Success");
|
|
900
|
+
}
|
|
901
|
+
})()));
|
|
902
|
+
}
|
|
903
|
+
|
|
332
904
|
function Autocomplete(props) {
|
|
333
905
|
var _a, _b;
|
|
334
906
|
const inputRef = React.useRef(null);
|
|
@@ -580,134 +1152,29 @@
|
|
|
580
1152
|
addOption(option);
|
|
581
1153
|
}
|
|
582
1154
|
/**
|
|
583
|
-
* Dismisses the drop down menu after a slight delay.
|
|
584
|
-
*/
|
|
585
|
-
function dismissOnDelay() {
|
|
586
|
-
window.setTimeout(() => {
|
|
587
|
-
setDropDownVisible(false);
|
|
588
|
-
}, 200);
|
|
589
|
-
}
|
|
590
|
-
const baseClassName = (_b = props.className) !== null && _b !== void 0 ? _b : 'medplum-autocomplete-container';
|
|
591
|
-
return (React__default["default"].createElement("div", { "data-testid": "autocomplete", className: baseClassName + (focused ? ' focused' : ''), onClick: () => handleClick() },
|
|
592
|
-
React__default["default"].createElement("ul", { onClick: () => handleClick() },
|
|
593
|
-
values.map((value) => (React__default["default"].createElement("li", { key: props.getId(value), "data-testid": "selected", className: "medplum-autocomplete-item choice" }, props.getDisplay(value)))),
|
|
594
|
-
React__default["default"].createElement("li", { className: "medplum-autocomplete-item" },
|
|
595
|
-
React__default["default"].createElement("input", { type: "text", autoFocus: props.autofocus, placeholder: values.length === 0 ? props.placeholder : undefined, autoComplete: "off", autoCapitalize: "off", spellCheck: "true", onFocus: () => handleFocus(), onBlur: () => handleBlur(), onChange: () => handleInput(), onInput: () => handleInput(), onKeyDown: (e) => handleKeyDown(e), ref: inputRef, "data-testid": "input-element" }))),
|
|
596
|
-
dropDownVisible && (React__default["default"].createElement("div", { className: "medplum-autocomplete", "data-testid": "dropdown" },
|
|
597
|
-
options.map((option, index) => (React__default["default"].createElement("div", { key: props.getId(option), className: index === selectedIndex
|
|
598
|
-
? 'medplum-autocomplete-row medplum-autocomplete-active'
|
|
599
|
-
: 'medplum-autocomplete-row', onMouseOver: (e) => handleDropDownHover(e, index), onClick: (e) => handleDropDownClick(e, option) },
|
|
600
|
-
props.getIcon && React__default["default"].createElement("div", { className: "medplum-autocomplete-icon" }, props.getIcon(option)),
|
|
601
|
-
React__default["default"].createElement("div", { className: "medplum-autocomplete-label" },
|
|
602
|
-
props.getDisplay(option),
|
|
603
|
-
props.getHelpText && React__default["default"].createElement("div", { className: "medplum-autocomplete-help-text" }, props.getHelpText(option)))))),
|
|
604
|
-
props.onCreateNew && (React__default["default"].createElement("div", { className: "medplum-autocomplete-row", onClick: props.onCreateNew },
|
|
605
|
-
React__default["default"].createElement("div", { className: "medplum-autocomplete-label" }, "Create new...")))))));
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
function MedplumLink(props) {
|
|
609
|
-
const navigate = reactRouterDom.useNavigate();
|
|
610
|
-
let href = '#';
|
|
611
|
-
if (props.to) {
|
|
612
|
-
if (typeof props.to === 'string') {
|
|
613
|
-
href = props.to;
|
|
614
|
-
}
|
|
615
|
-
else if ('resourceType' in props.to) {
|
|
616
|
-
href = `/${props.to.resourceType}/${props.to.id}`;
|
|
617
|
-
}
|
|
618
|
-
else if ('reference' in props.to) {
|
|
619
|
-
href = `/${props.to.reference}`;
|
|
620
|
-
}
|
|
621
|
-
if (props.suffix) {
|
|
622
|
-
href += '/' + props.suffix;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
return (React__default["default"].createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
|
|
626
|
-
killEvent(e);
|
|
627
|
-
if (props.onClick) {
|
|
628
|
-
props.onClick();
|
|
629
|
-
}
|
|
630
|
-
else if (props.to) {
|
|
631
|
-
navigate(href);
|
|
632
|
-
}
|
|
633
|
-
} }, props.children));
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
const system = {
|
|
637
|
-
resourceType: 'Device',
|
|
638
|
-
id: 'system',
|
|
639
|
-
deviceName: [
|
|
640
|
-
{
|
|
641
|
-
name: 'System',
|
|
642
|
-
},
|
|
643
|
-
],
|
|
644
|
-
};
|
|
645
|
-
/**
|
|
646
|
-
* React Hook to use a FHIR reference.
|
|
647
|
-
* Handles the complexity of resolving references and caching resources.
|
|
648
|
-
* @param value The resource or reference to resource.
|
|
649
|
-
* @returns The resolved resource.
|
|
650
|
-
*/
|
|
651
|
-
function useResource(value) {
|
|
652
|
-
const medplum = useMedplum();
|
|
653
|
-
const [resource, setResource] = React.useState(getInitialResource(medplum, value));
|
|
654
|
-
React.useEffect(() => {
|
|
655
|
-
let subscribed = true;
|
|
656
|
-
if (!resource && value && 'reference' in value && value.reference) {
|
|
657
|
-
medplum
|
|
658
|
-
.readReference(value)
|
|
659
|
-
.then((r) => {
|
|
660
|
-
if (subscribed) {
|
|
661
|
-
setResource(r);
|
|
662
|
-
}
|
|
663
|
-
})
|
|
664
|
-
.catch(() => setResource(undefined));
|
|
665
|
-
}
|
|
666
|
-
return (() => (subscribed = false));
|
|
667
|
-
}, [medplum, resource, value]);
|
|
668
|
-
return resource;
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* Returns the initial resource value based on the input value.
|
|
672
|
-
* If the input value is a resource, returns the resource.
|
|
673
|
-
* If the input value is a reference to system, returns the system resource.
|
|
674
|
-
* If the input value is a reference to a resource available in the cache, returns the resource.
|
|
675
|
-
* Otherwise, returns undefined.
|
|
676
|
-
* @param medplum The medplum client.
|
|
677
|
-
* @param value The resource or reference to resource.
|
|
678
|
-
* @returns An initial resource if available; undefined otherwise.
|
|
679
|
-
*/
|
|
680
|
-
function getInitialResource(medplum, value) {
|
|
681
|
-
if (!value) {
|
|
682
|
-
return undefined;
|
|
683
|
-
}
|
|
684
|
-
if ('resourceType' in value) {
|
|
685
|
-
return value;
|
|
686
|
-
}
|
|
687
|
-
if ('reference' in value) {
|
|
688
|
-
if (value.reference === 'system') {
|
|
689
|
-
return system;
|
|
690
|
-
}
|
|
691
|
-
return medplum.getCachedReference(value);
|
|
692
|
-
}
|
|
693
|
-
return undefined;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
function Avatar(props) {
|
|
697
|
-
var _a, _b;
|
|
698
|
-
const resource = useResource(props.value);
|
|
699
|
-
const className = props.size ? 'medplum-avatar ' + props.size : 'medplum-avatar';
|
|
700
|
-
const text = resource ? core.getDisplayString(resource) : (_a = props.alt) !== null && _a !== void 0 ? _a : '';
|
|
701
|
-
const initials = text && getInitials(text);
|
|
702
|
-
const imageUrl = (_b = (resource && core.getImageSrc(resource))) !== null && _b !== void 0 ? _b : props.src;
|
|
703
|
-
const innerContent = imageUrl ? React__default["default"].createElement("img", { src: imageUrl, alt: text }) : initials;
|
|
704
|
-
return (React__default["default"].createElement("div", { className: className, style: { backgroundColor: props.color }, "data-testid": "avatar" }, props.link && resource ? React__default["default"].createElement(MedplumLink, { to: resource }, innerContent) : innerContent));
|
|
705
|
-
}
|
|
706
|
-
function getInitials(text) {
|
|
707
|
-
return text
|
|
708
|
-
.split(' ')
|
|
709
|
-
.map((n) => n[0])
|
|
710
|
-
.join('');
|
|
1155
|
+
* Dismisses the drop down menu after a slight delay.
|
|
1156
|
+
*/
|
|
1157
|
+
function dismissOnDelay() {
|
|
1158
|
+
window.setTimeout(() => {
|
|
1159
|
+
setDropDownVisible(false);
|
|
1160
|
+
}, 200);
|
|
1161
|
+
}
|
|
1162
|
+
const baseClassName = (_b = props.className) !== null && _b !== void 0 ? _b : 'medplum-autocomplete-container';
|
|
1163
|
+
return (React__default["default"].createElement("div", { "data-testid": "autocomplete", className: baseClassName + (focused ? ' focused' : ''), onClick: () => handleClick() },
|
|
1164
|
+
React__default["default"].createElement("ul", { onClick: () => handleClick() },
|
|
1165
|
+
values.map((value) => (React__default["default"].createElement("li", { key: props.getId(value), "data-testid": "selected", className: "medplum-autocomplete-item choice" }, props.getDisplay(value)))),
|
|
1166
|
+
React__default["default"].createElement("li", { className: "medplum-autocomplete-item" },
|
|
1167
|
+
React__default["default"].createElement("input", { type: "text", autoFocus: props.autofocus, placeholder: values.length === 0 ? props.placeholder : undefined, autoComplete: "off", autoCapitalize: "off", spellCheck: "true", onFocus: () => handleFocus(), onBlur: () => handleBlur(), onChange: () => handleInput(), onInput: () => handleInput(), onKeyDown: (e) => handleKeyDown(e), ref: inputRef, "data-testid": "input-element" }))),
|
|
1168
|
+
dropDownVisible && (React__default["default"].createElement("div", { className: "medplum-autocomplete", "data-testid": "dropdown" },
|
|
1169
|
+
options.map((option, index) => (React__default["default"].createElement("div", { key: props.getId(option), className: index === selectedIndex
|
|
1170
|
+
? 'medplum-autocomplete-row medplum-autocomplete-active'
|
|
1171
|
+
: 'medplum-autocomplete-row', onMouseOver: (e) => handleDropDownHover(e, index), onClick: (e) => handleDropDownClick(e, option) },
|
|
1172
|
+
props.getIcon && React__default["default"].createElement("div", { className: "medplum-autocomplete-icon" }, props.getIcon(option)),
|
|
1173
|
+
React__default["default"].createElement("div", { className: "medplum-autocomplete-label" },
|
|
1174
|
+
props.getDisplay(option),
|
|
1175
|
+
props.getHelpText && React__default["default"].createElement("div", { className: "medplum-autocomplete-help-text" }, props.getHelpText(option)))))),
|
|
1176
|
+
props.onCreateNew && (React__default["default"].createElement("div", { className: "medplum-autocomplete-row", onClick: props.onCreateNew },
|
|
1177
|
+
React__default["default"].createElement("div", { className: "medplum-autocomplete-label" }, "Create new...")))))));
|
|
711
1178
|
}
|
|
712
1179
|
|
|
713
1180
|
function CheckboxFormSection(props) {
|
|
@@ -728,19 +1195,6 @@
|
|
|
728
1195
|
'modifierExtension',
|
|
729
1196
|
];
|
|
730
1197
|
|
|
731
|
-
function FormSection(props) {
|
|
732
|
-
const issues = getIssuesForExpression(props.outcome, props.htmlFor);
|
|
733
|
-
const invalid = issues && issues.length > 0;
|
|
734
|
-
return (React__default["default"].createElement("fieldset", { className: "medplum-form-section" },
|
|
735
|
-
props.title && React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
|
|
736
|
-
props.description && React__default["default"].createElement("p", null, props.description),
|
|
737
|
-
props.children,
|
|
738
|
-
invalid && (React__default["default"].createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
|
|
739
|
-
var _a, _b;
|
|
740
|
-
return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
|
|
741
|
-
})))));
|
|
742
|
-
}
|
|
743
|
-
|
|
744
1198
|
function ResourceForm(props) {
|
|
745
1199
|
const medplum = useMedplum();
|
|
746
1200
|
const defaultValue = useResource(props.defaultValue);
|
|
@@ -1473,31 +1927,6 @@
|
|
|
1473
1927
|
React__default["default"].createElement(QuantityInput, { name: props.name + '-denominator', defaultValue: value === null || value === void 0 ? void 0 : value.denominator, onChange: (v) => setValueWrapper(Object.assign(Object.assign({}, value), { denominator: v })) })));
|
|
1474
1928
|
}
|
|
1475
1929
|
|
|
1476
|
-
/******************************************************************************
|
|
1477
|
-
Copyright (c) Microsoft Corporation.
|
|
1478
|
-
|
|
1479
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
1480
|
-
purpose with or without fee is hereby granted.
|
|
1481
|
-
|
|
1482
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
1483
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
1484
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
1485
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
1486
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
1487
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
1488
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
1489
|
-
***************************************************************************** */
|
|
1490
|
-
|
|
1491
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
1492
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
1493
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
1494
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
1495
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
1496
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
1497
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
1498
|
-
});
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
1930
|
function ResourceName(props) {
|
|
1502
1931
|
const resource = useResource(props.value);
|
|
1503
1932
|
if (!resource) {
|
|
@@ -1985,63 +2414,6 @@
|
|
|
1985
2414
|
return React__default["default"].createElement(RangeDisplay, { value: range });
|
|
1986
2415
|
}
|
|
1987
2416
|
|
|
1988
|
-
/**
|
|
1989
|
-
* Parses an HTML form and returns the result as a JavaScript object.
|
|
1990
|
-
* @param form The HTML form element.
|
|
1991
|
-
*/
|
|
1992
|
-
function parseForm(form) {
|
|
1993
|
-
const result = {};
|
|
1994
|
-
for (const element of Array.from(form.elements)) {
|
|
1995
|
-
if (element instanceof HTMLInputElement) {
|
|
1996
|
-
parseInputElement(result, element);
|
|
1997
|
-
}
|
|
1998
|
-
else if (element instanceof HTMLTextAreaElement) {
|
|
1999
|
-
result[element.name] = element.value;
|
|
2000
|
-
}
|
|
2001
|
-
else if (element instanceof HTMLSelectElement) {
|
|
2002
|
-
parseSelectElement(result, element);
|
|
2003
|
-
}
|
|
2004
|
-
}
|
|
2005
|
-
return result;
|
|
2006
|
-
}
|
|
2007
|
-
/**
|
|
2008
|
-
* Parses an HTML input element.
|
|
2009
|
-
* Sets the name/value pair in the result,
|
|
2010
|
-
* but only if the element is enabled and checked.
|
|
2011
|
-
* @param el The input element.
|
|
2012
|
-
* @param result The result builder.
|
|
2013
|
-
*/
|
|
2014
|
-
function parseInputElement(result, el) {
|
|
2015
|
-
if (el.disabled) {
|
|
2016
|
-
// Ignore disabled elements
|
|
2017
|
-
return;
|
|
2018
|
-
}
|
|
2019
|
-
if ((el.type === 'checkbox' || el.type === 'radio') && !el.checked) {
|
|
2020
|
-
// Ignore unchecked radio or checkbox elements
|
|
2021
|
-
return;
|
|
2022
|
-
}
|
|
2023
|
-
result[el.name] = el.value;
|
|
2024
|
-
}
|
|
2025
|
-
/**
|
|
2026
|
-
* Parses an HTML select element.
|
|
2027
|
-
* Sets the name/value pair if one is selected.
|
|
2028
|
-
* @param result The result builder.
|
|
2029
|
-
* @param el The select element.
|
|
2030
|
-
*/
|
|
2031
|
-
function parseSelectElement(result, el) {
|
|
2032
|
-
result[el.name] = el.value;
|
|
2033
|
-
}
|
|
2034
|
-
|
|
2035
|
-
function Form(props) {
|
|
2036
|
-
return (React__default["default"].createElement("form", { style: props.style, "data-testid": props.testid, onSubmit: (e) => {
|
|
2037
|
-
e.preventDefault();
|
|
2038
|
-
const formData = parseForm(e.target);
|
|
2039
|
-
if (props.onSubmit) {
|
|
2040
|
-
props.onSubmit(formData);
|
|
2041
|
-
}
|
|
2042
|
-
} }, props.children));
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
2417
|
function Loading() {
|
|
2046
2418
|
return (React__default["default"].createElement("div", { role: "progressbar", "aria-busy": "true", className: "medplum-loading" },
|
|
2047
2419
|
React__default["default"].createElement("div", { className: "medplum-loading-container" },
|
|
@@ -2331,7 +2703,9 @@
|
|
|
2331
2703
|
}
|
|
2332
2704
|
if (bundle.entry) {
|
|
2333
2705
|
for (const entry of bundle.entry) {
|
|
2334
|
-
|
|
2706
|
+
if (entry.resource) {
|
|
2707
|
+
newItems.push(entry.resource);
|
|
2708
|
+
}
|
|
2335
2709
|
}
|
|
2336
2710
|
}
|
|
2337
2711
|
}
|
|
@@ -2518,11 +2892,6 @@
|
|
|
2518
2892
|
}) }));
|
|
2519
2893
|
}
|
|
2520
2894
|
|
|
2521
|
-
function Document(props) {
|
|
2522
|
-
return (React__default["default"].createElement("main", { className: "medplum-document" },
|
|
2523
|
-
React__default["default"].createElement("article", { style: { maxWidth: props.width } }, props.children)));
|
|
2524
|
-
}
|
|
2525
|
-
|
|
2526
2895
|
function EncounterTimeline(props) {
|
|
2527
2896
|
return (React__default["default"].createElement(ResourceTimeline, { value: props.encounter, buildSearchRequests: (resource) => ({
|
|
2528
2897
|
resourceType: 'Bundle',
|
|
@@ -4301,16 +4670,6 @@
|
|
|
4301
4670
|
React__default["default"].createElement(MedplumLink, { to: "/changepassword" }, "Change password"))))));
|
|
4302
4671
|
}
|
|
4303
4672
|
|
|
4304
|
-
function Logo(props) {
|
|
4305
|
-
return (React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 491 491", style: { width: props.size, height: props.size } },
|
|
4306
|
-
React__default["default"].createElement("title", null, "Medplum Logo"),
|
|
4307
|
-
React__default["default"].createElement("path", { fill: props.fill || '#ad7136', d: "M282 67c6-16 16-29 29-40L289 0c-22 17-37 41-43 68l17 23 19-24z" }),
|
|
4308
|
-
React__default["default"].createElement("path", { fill: props.fill || '#654b87', d: "M311 63c-17 0-33 4-48 11-16-7-32-11-49-11-87 0-158 96-158 214s71 214 158 214c17 0 33-4 49-11 15 7 31 11 48 11 87 0 158-96 158-214S398 63 311 63z" }),
|
|
4309
|
-
React__default["default"].createElement("path", { fill: props.fill || '#463068', d: "M231 489l-17 2c-87 0-158-96-158-214S127 63 214 63l17 1c-39 12-70 102-70 213s31 201 70 212z" }),
|
|
4310
|
-
React__default["default"].createElement("path", { fill: props.fill || '#70d65b', d: "M207 220a176 176 0 01-177 43A176 176 0 01251 43l1 5c17 59 2 125-45 172z" }),
|
|
4311
|
-
React__default["default"].createElement("path", { fill: props.fill || '#58b741', d: "M252 48A421 421 0 0057 270l-27-7A176 176 0 01251 43l1 5z" })));
|
|
4312
|
-
}
|
|
4313
|
-
|
|
4314
4673
|
const searches = [
|
|
4315
4674
|
'$/_history',
|
|
4316
4675
|
'Communication?subject=$',
|
|
@@ -4980,262 +5339,73 @@
|
|
|
4980
5339
|
var _a;
|
|
4981
5340
|
const property = core.globalSchema.types['QuestionnaireItemAnswerOption'].properties['value[x]'];
|
|
4982
5341
|
const options = (_a = props.options) !== null && _a !== void 0 ? _a : [];
|
|
4983
|
-
return (React__default["default"].createElement("div", null,
|
|
4984
|
-
options.map((option) => {
|
|
4985
|
-
const [propertyValue, propertyType] = getValueAndType({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
|
|
4986
|
-
return (React__default["default"].createElement("div", { key: option.id, style: {
|
|
4987
|
-
display: 'flex',
|
|
4988
|
-
flexDirection: 'row',
|
|
4989
|
-
justifyContent: 'space-between',
|
|
4990
|
-
alignItems: 'center',
|
|
4991
|
-
width: '80%',
|
|
4992
|
-
} },
|
|
4993
|
-
React__default["default"].createElement("div", null,
|
|
4994
|
-
React__default["default"].createElement(ResourcePropertyInput, { key: option.id, name: "value[x]", property: property, defaultPropertyType: propertyType, defaultValue: propertyValue, onChange: (newValue, propName) => {
|
|
4995
|
-
const newOptions = [...options];
|
|
4996
|
-
const index = newOptions.findIndex((o) => o.id === option.id);
|
|
4997
|
-
newOptions[index] = { id: option.id, [propName]: newValue };
|
|
4998
|
-
props.onChange(newOptions);
|
|
4999
|
-
} })),
|
|
5000
|
-
React__default["default"].createElement("div", null,
|
|
5001
|
-
React__default["default"].createElement("a", { href: "#", onClick: (e) => {
|
|
5002
|
-
killEvent(e);
|
|
5003
|
-
props.onChange(options.filter((o) => o.id !== option.id));
|
|
5004
|
-
} }, "Remove"))));
|
|
5005
|
-
}),
|
|
5006
|
-
React__default["default"].createElement("a", { href: "#", onClick: (e) => {
|
|
5007
|
-
killEvent(e);
|
|
5008
|
-
props.onChange([
|
|
5009
|
-
...options,
|
|
5010
|
-
{
|
|
5011
|
-
id: generateId(),
|
|
5012
|
-
},
|
|
5013
|
-
]);
|
|
5014
|
-
} }, "Add choice")));
|
|
5015
|
-
}
|
|
5016
|
-
let nextLinkId = 1;
|
|
5017
|
-
let nextId = 1;
|
|
5018
|
-
/**
|
|
5019
|
-
* Generates a link ID for an item.
|
|
5020
|
-
* Link IDs are required properties on QuestionnaireItem objects.
|
|
5021
|
-
* @return A unique link ID.
|
|
5022
|
-
*/
|
|
5023
|
-
function generateLinkId(prefix) {
|
|
5024
|
-
return prefix + nextLinkId++;
|
|
5025
|
-
}
|
|
5026
|
-
/**
|
|
5027
|
-
* Generates a unique ID.
|
|
5028
|
-
* React needs unique IDs for components for rendering performance.
|
|
5029
|
-
* All of the important components in the questionnaire builder have id properties for this:
|
|
5030
|
-
* Questionnaire, QuestionnaireItem, and QuestionnaireItemAnswerOption.
|
|
5031
|
-
* @return A unique key.
|
|
5032
|
-
*/
|
|
5033
|
-
function generateId() {
|
|
5034
|
-
return 'id-' + nextId++;
|
|
5035
|
-
}
|
|
5036
|
-
function ensureQuestionnaireKeys(questionnaire) {
|
|
5037
|
-
return Object.assign(Object.assign({}, questionnaire), { id: questionnaire.id || generateId(), item: ensureQuestionnaireItemKeys(questionnaire.item) });
|
|
5038
|
-
}
|
|
5039
|
-
function ensureQuestionnaireItemKeys(items) {
|
|
5040
|
-
if (!items) {
|
|
5041
|
-
return undefined;
|
|
5042
|
-
}
|
|
5043
|
-
return items.map((item) => (Object.assign(Object.assign({}, item), { id: item.id || generateId(), item: ensureQuestionnaireItemKeys(item.item), answerOption: ensureQuestionnaireOptionKeys(item.answerOption) })));
|
|
5044
|
-
}
|
|
5045
|
-
function ensureQuestionnaireOptionKeys(options) {
|
|
5046
|
-
if (!options) {
|
|
5047
|
-
return undefined;
|
|
5048
|
-
}
|
|
5049
|
-
return options.map((option) => (Object.assign(Object.assign({}, option), { id: option.id || generateId() })));
|
|
5050
|
-
}
|
|
5051
|
-
|
|
5052
|
-
/**
|
|
5053
|
-
* Dynamically creates a script tag for the specified JavaScript file.
|
|
5054
|
-
* @param src The JavaScript file URL.
|
|
5055
|
-
*/
|
|
5056
|
-
function createScriptTag(src, onload) {
|
|
5057
|
-
const head = document.getElementsByTagName('head')[0];
|
|
5058
|
-
const script = document.createElement('script');
|
|
5059
|
-
script.async = true;
|
|
5060
|
-
script.src = src;
|
|
5061
|
-
script.onload = onload || null;
|
|
5062
|
-
head.appendChild(script);
|
|
5063
|
-
}
|
|
5064
|
-
|
|
5065
|
-
function GoogleButton(props) {
|
|
5066
|
-
const medplum = useMedplum();
|
|
5067
|
-
const { googleClientId, handleGoogleCredential } = props;
|
|
5068
|
-
const parentRef = React.useRef(null);
|
|
5069
|
-
const [scriptLoaded, setScriptLoaded] = React.useState(typeof google !== 'undefined');
|
|
5070
|
-
const [initialized, setInitialized] = React.useState(false);
|
|
5071
|
-
const [buttonRendered, setButtonRendered] = React.useState(false);
|
|
5072
|
-
React.useEffect(() => {
|
|
5073
|
-
if (typeof google === 'undefined') {
|
|
5074
|
-
createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));
|
|
5075
|
-
return;
|
|
5076
|
-
}
|
|
5077
|
-
if (!initialized) {
|
|
5078
|
-
google.accounts.id.initialize({
|
|
5079
|
-
client_id: googleClientId,
|
|
5080
|
-
callback: handleGoogleCredential,
|
|
5081
|
-
});
|
|
5082
|
-
setInitialized(true);
|
|
5083
|
-
}
|
|
5084
|
-
if (parentRef.current && !buttonRendered) {
|
|
5085
|
-
google.accounts.id.renderButton(parentRef.current, {});
|
|
5086
|
-
setButtonRendered(true);
|
|
5087
|
-
}
|
|
5088
|
-
}, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
|
|
5089
|
-
if (!googleClientId) {
|
|
5090
|
-
return null;
|
|
5091
|
-
}
|
|
5092
|
-
return React__default["default"].createElement("div", { ref: parentRef });
|
|
5093
|
-
}
|
|
5094
|
-
function getGoogleClientId(clientId) {
|
|
5095
|
-
var _a, _b;
|
|
5096
|
-
if (clientId) {
|
|
5097
|
-
return clientId;
|
|
5098
|
-
}
|
|
5099
|
-
const origin = window.location.protocol + '//' + window.location.host;
|
|
5100
|
-
const authorizedOrigins = (_b = (_a = "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") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
|
|
5101
|
-
if (authorizedOrigins.includes(origin)) {
|
|
5102
|
-
return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
|
|
5103
|
-
}
|
|
5104
|
-
return undefined;
|
|
5342
|
+
return (React__default["default"].createElement("div", null,
|
|
5343
|
+
options.map((option) => {
|
|
5344
|
+
const [propertyValue, propertyType] = getValueAndType({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
|
|
5345
|
+
return (React__default["default"].createElement("div", { key: option.id, style: {
|
|
5346
|
+
display: 'flex',
|
|
5347
|
+
flexDirection: 'row',
|
|
5348
|
+
justifyContent: 'space-between',
|
|
5349
|
+
alignItems: 'center',
|
|
5350
|
+
width: '80%',
|
|
5351
|
+
} },
|
|
5352
|
+
React__default["default"].createElement("div", null,
|
|
5353
|
+
React__default["default"].createElement(ResourcePropertyInput, { key: option.id, name: "value[x]", property: property, defaultPropertyType: propertyType, defaultValue: propertyValue, onChange: (newValue, propName) => {
|
|
5354
|
+
const newOptions = [...options];
|
|
5355
|
+
const index = newOptions.findIndex((o) => o.id === option.id);
|
|
5356
|
+
newOptions[index] = { id: option.id, [propName]: newValue };
|
|
5357
|
+
props.onChange(newOptions);
|
|
5358
|
+
} })),
|
|
5359
|
+
React__default["default"].createElement("div", null,
|
|
5360
|
+
React__default["default"].createElement("a", { href: "#", onClick: (e) => {
|
|
5361
|
+
killEvent(e);
|
|
5362
|
+
props.onChange(options.filter((o) => o.id !== option.id));
|
|
5363
|
+
} }, "Remove"))));
|
|
5364
|
+
}),
|
|
5365
|
+
React__default["default"].createElement("a", { href: "#", onClick: (e) => {
|
|
5366
|
+
killEvent(e);
|
|
5367
|
+
props.onChange([
|
|
5368
|
+
...options,
|
|
5369
|
+
{
|
|
5370
|
+
id: generateId(),
|
|
5371
|
+
},
|
|
5372
|
+
]);
|
|
5373
|
+
} }, "Add choice")));
|
|
5105
5374
|
}
|
|
5106
|
-
|
|
5375
|
+
let nextLinkId = 1;
|
|
5376
|
+
let nextId = 1;
|
|
5107
5377
|
/**
|
|
5108
|
-
*
|
|
5109
|
-
*
|
|
5110
|
-
* @
|
|
5378
|
+
* Generates a link ID for an item.
|
|
5379
|
+
* Link IDs are required properties on QuestionnaireItem objects.
|
|
5380
|
+
* @return A unique link ID.
|
|
5111
5381
|
*/
|
|
5112
|
-
function
|
|
5113
|
-
|
|
5114
|
-
createScriptTag('https://www.google.com/recaptcha/api.js?render=' + siteKey);
|
|
5115
|
-
}
|
|
5382
|
+
function generateLinkId(prefix) {
|
|
5383
|
+
return prefix + nextLinkId++;
|
|
5116
5384
|
}
|
|
5117
5385
|
/**
|
|
5118
|
-
*
|
|
5119
|
-
*
|
|
5120
|
-
*
|
|
5386
|
+
* Generates a unique ID.
|
|
5387
|
+
* React needs unique IDs for components for rendering performance.
|
|
5388
|
+
* All of the important components in the questionnaire builder have id properties for this:
|
|
5389
|
+
* Questionnaire, QuestionnaireItem, and QuestionnaireItemAnswerOption.
|
|
5390
|
+
* @return A unique key.
|
|
5121
5391
|
*/
|
|
5122
|
-
function
|
|
5123
|
-
return
|
|
5124
|
-
grecaptcha.ready(() => __awaiter(this, void 0, void 0, function* () {
|
|
5125
|
-
try {
|
|
5126
|
-
resolve(yield grecaptcha.execute(siteKey, { action: 'submit' }));
|
|
5127
|
-
}
|
|
5128
|
-
catch (err) {
|
|
5129
|
-
reject(err);
|
|
5130
|
-
}
|
|
5131
|
-
}));
|
|
5132
|
-
});
|
|
5392
|
+
function generateId() {
|
|
5393
|
+
return 'id-' + nextId++;
|
|
5133
5394
|
}
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
const issues = getIssuesForExpression(outcome, undefined);
|
|
5141
|
-
React.useEffect(() => initRecaptcha(recaptchaSiteKey), [recaptchaSiteKey]);
|
|
5142
|
-
function handleAuthResponse(registerRequest, partialLogin) {
|
|
5143
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
5144
|
-
try {
|
|
5145
|
-
let login;
|
|
5146
|
-
if (props.type === 'patient') {
|
|
5147
|
-
login = yield medplum.startNewPatient(registerRequest, partialLogin);
|
|
5148
|
-
}
|
|
5149
|
-
else {
|
|
5150
|
-
login = yield medplum.startNewProject(registerRequest, partialLogin);
|
|
5151
|
-
}
|
|
5152
|
-
yield medplum.processCode(login.code);
|
|
5153
|
-
props.onSuccess();
|
|
5154
|
-
}
|
|
5155
|
-
catch (err) {
|
|
5156
|
-
setOutcome(err);
|
|
5157
|
-
}
|
|
5158
|
-
});
|
|
5395
|
+
function ensureQuestionnaireKeys(questionnaire) {
|
|
5396
|
+
return Object.assign(Object.assign({}, questionnaire), { id: questionnaire.id || generateId(), item: ensureQuestionnaireItemKeys(questionnaire.item) });
|
|
5397
|
+
}
|
|
5398
|
+
function ensureQuestionnaireItemKeys(items) {
|
|
5399
|
+
if (!items) {
|
|
5400
|
+
return undefined;
|
|
5159
5401
|
}
|
|
5160
|
-
return (
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
firstName: formData.firstName,
|
|
5168
|
-
lastName: formData.lastName,
|
|
5169
|
-
email: formData.email,
|
|
5170
|
-
password: formData.password,
|
|
5171
|
-
remember: formData.remember === 'true',
|
|
5172
|
-
recaptchaSiteKey,
|
|
5173
|
-
recaptchaToken,
|
|
5174
|
-
};
|
|
5175
|
-
const userLogin = yield medplum.startNewUser(registerRequest);
|
|
5176
|
-
yield handleAuthResponse(registerRequest, userLogin);
|
|
5177
|
-
}
|
|
5178
|
-
catch (err) {
|
|
5179
|
-
setOutcome(err);
|
|
5180
|
-
}
|
|
5181
|
-
}) },
|
|
5182
|
-
React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
|
|
5183
|
-
issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
|
|
5184
|
-
var _a, _b;
|
|
5185
|
-
return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
|
|
5186
|
-
}))),
|
|
5187
|
-
googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
5188
|
-
React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
|
|
5189
|
-
React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => __awaiter(this, void 0, void 0, function* () {
|
|
5190
|
-
try {
|
|
5191
|
-
const loginRequest = {
|
|
5192
|
-
googleClientId: response.clientId,
|
|
5193
|
-
googleCredential: response.credential,
|
|
5194
|
-
};
|
|
5195
|
-
const userLogin = yield medplum.startGoogleLogin(loginRequest);
|
|
5196
|
-
const googleClaims = core.parseJWTPayload(loginRequest.googleCredential);
|
|
5197
|
-
const registerRequest = {
|
|
5198
|
-
projectId: props.projectId,
|
|
5199
|
-
firstName: googleClaims.given_name,
|
|
5200
|
-
lastName: googleClaims.family_name,
|
|
5201
|
-
email: googleClaims.email,
|
|
5202
|
-
};
|
|
5203
|
-
yield handleAuthResponse(registerRequest, userLogin);
|
|
5204
|
-
}
|
|
5205
|
-
catch (err) {
|
|
5206
|
-
setOutcome(err);
|
|
5207
|
-
}
|
|
5208
|
-
}) })),
|
|
5209
|
-
React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
|
|
5210
|
-
React__default["default"].createElement(FormSection, { title: "First Name", htmlFor: "firstName", outcome: outcome },
|
|
5211
|
-
React__default["default"].createElement(Input, { name: "firstName", type: "text", testid: "firstName", placeholder: "First name", required: true, autoFocus: true, outcome: outcome })),
|
|
5212
|
-
React__default["default"].createElement(FormSection, { title: "Last Name", htmlFor: "lastName", outcome: outcome },
|
|
5213
|
-
React__default["default"].createElement(Input, { name: "lastName", type: "text", testid: "lastName", placeholder: "Last name", required: true, outcome: outcome })),
|
|
5214
|
-
props.type === 'project' && (React__default["default"].createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
|
|
5215
|
-
React__default["default"].createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome }))),
|
|
5216
|
-
React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
|
|
5217
|
-
React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", placeholder: "name@domain.com", required: true, outcome: outcome })),
|
|
5218
|
-
React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
|
|
5219
|
-
React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
|
|
5220
|
-
React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
|
|
5221
|
-
"By clicking submit you agree to the Medplum ",
|
|
5222
|
-
React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
|
|
5223
|
-
' and ',
|
|
5224
|
-
React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
|
|
5225
|
-
"."),
|
|
5226
|
-
React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
|
|
5227
|
-
"This site is protected by reCAPTCHA and the Google",
|
|
5228
|
-
' ',
|
|
5229
|
-
React__default["default"].createElement("a", { href: "https://policies.google.com/privacy" }, "Privacy\u00A0Policy"),
|
|
5230
|
-
' and ',
|
|
5231
|
-
React__default["default"].createElement("a", { href: "https://policies.google.com/terms" }, "Terms\u00A0of\u00A0Service"),
|
|
5232
|
-
" apply."),
|
|
5233
|
-
React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
|
|
5234
|
-
React__default["default"].createElement("div", null,
|
|
5235
|
-
React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
|
|
5236
|
-
React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
|
|
5237
|
-
React__default["default"].createElement("div", null,
|
|
5238
|
-
React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create account"))))));
|
|
5402
|
+
return items.map((item) => (Object.assign(Object.assign({}, item), { id: item.id || generateId(), item: ensureQuestionnaireItemKeys(item.item), answerOption: ensureQuestionnaireOptionKeys(item.answerOption) })));
|
|
5403
|
+
}
|
|
5404
|
+
function ensureQuestionnaireOptionKeys(options) {
|
|
5405
|
+
if (!options) {
|
|
5406
|
+
return undefined;
|
|
5407
|
+
}
|
|
5408
|
+
return options.map((option) => (Object.assign(Object.assign({}, option), { id: option.id || generateId() })));
|
|
5239
5409
|
}
|
|
5240
5410
|
|
|
5241
5411
|
function StatusBadge(props) {
|
|
@@ -5588,19 +5758,23 @@
|
|
|
5588
5758
|
React__default["default"].createElement("th", null, "Author"),
|
|
5589
5759
|
React__default["default"].createElement("th", null, "Date"),
|
|
5590
5760
|
React__default["default"].createElement("th", null, "Version"))),
|
|
5591
|
-
React__default["default"].createElement("tbody", null, (_a = value.entry) === null || _a === void 0 ? void 0 : _a.map((entry) => {
|
|
5592
|
-
var _a, _b;
|
|
5593
|
-
return (React__default["default"].createElement(HistoryRow, { key: (_b = (_a = entry.resource) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.versionId, version: entry.resource }));
|
|
5594
|
-
}))));
|
|
5761
|
+
React__default["default"].createElement("tbody", null, (_a = value.entry) === null || _a === void 0 ? void 0 : _a.map((entry, index) => (React__default["default"].createElement(HistoryRow, { key: 'entry-' + index, entry: entry }))))));
|
|
5595
5762
|
}
|
|
5596
5763
|
function HistoryRow(props) {
|
|
5597
5764
|
var _a, _b, _c;
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
React__default["default"].createElement(
|
|
5765
|
+
const { response, resource } = props.entry;
|
|
5766
|
+
if (resource) {
|
|
5767
|
+
return (React__default["default"].createElement("tr", null,
|
|
5768
|
+
React__default["default"].createElement("td", null,
|
|
5769
|
+
React__default["default"].createElement(ResourceBadge, { value: (_a = resource.meta) === null || _a === void 0 ? void 0 : _a.author, link: true })),
|
|
5770
|
+
React__default["default"].createElement("td", null, core.formatDateTime((_b = resource.meta) === null || _b === void 0 ? void 0 : _b.lastUpdated)),
|
|
5771
|
+
React__default["default"].createElement("td", null,
|
|
5772
|
+
React__default["default"].createElement(MedplumLink, { to: getVersionUrl(resource) }, (_c = resource.meta) === null || _c === void 0 ? void 0 : _c.versionId))));
|
|
5773
|
+
}
|
|
5774
|
+
else {
|
|
5775
|
+
return (React__default["default"].createElement("tr", null,
|
|
5776
|
+
React__default["default"].createElement("td", { colSpan: 3 }, core.normalizeErrorString(response === null || response === void 0 ? void 0 : response.outcome))));
|
|
5777
|
+
}
|
|
5604
5778
|
}
|
|
5605
5779
|
function getVersionUrl(resource) {
|
|
5606
5780
|
var _a;
|
|
@@ -5821,157 +5995,6 @@
|
|
|
5821
5995
|
}) }));
|
|
5822
5996
|
}
|
|
5823
5997
|
|
|
5824
|
-
function SignInForm(props) {
|
|
5825
|
-
const medplum = useMedplum();
|
|
5826
|
-
const [login, setLogin] = React.useState(undefined);
|
|
5827
|
-
const [memberships, setMemberships] = React.useState(undefined);
|
|
5828
|
-
function handleAuthResponse(response) {
|
|
5829
|
-
if (response.login) {
|
|
5830
|
-
setLogin(response.login);
|
|
5831
|
-
}
|
|
5832
|
-
if (response.memberships) {
|
|
5833
|
-
setMemberships(response.memberships);
|
|
5834
|
-
}
|
|
5835
|
-
if (response.code) {
|
|
5836
|
-
if (props.onCode) {
|
|
5837
|
-
props.onCode(response.code);
|
|
5838
|
-
}
|
|
5839
|
-
else {
|
|
5840
|
-
medplum
|
|
5841
|
-
.processCode(response.code)
|
|
5842
|
-
.then(() => {
|
|
5843
|
-
if (props.onSuccess) {
|
|
5844
|
-
props.onSuccess();
|
|
5845
|
-
}
|
|
5846
|
-
})
|
|
5847
|
-
.catch(console.log);
|
|
5848
|
-
}
|
|
5849
|
-
}
|
|
5850
|
-
}
|
|
5851
|
-
return (React__default["default"].createElement(Document, { width: 450 }, (() => {
|
|
5852
|
-
if (!login) {
|
|
5853
|
-
return (React__default["default"].createElement(AuthenticationForm, { projectId: props.projectId, clientId: props.clientId, scope: props.scope, nonce: props.nonce, googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
|
|
5854
|
-
}
|
|
5855
|
-
else if (memberships) {
|
|
5856
|
-
return React__default["default"].createElement(ProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
|
|
5857
|
-
}
|
|
5858
|
-
else if (props.projectId === 'new') {
|
|
5859
|
-
return React__default["default"].createElement(NewProjectForm, { login: login, handleAuthResponse: handleAuthResponse });
|
|
5860
|
-
}
|
|
5861
|
-
else {
|
|
5862
|
-
return React__default["default"].createElement("div", null, "Success");
|
|
5863
|
-
}
|
|
5864
|
-
})()));
|
|
5865
|
-
}
|
|
5866
|
-
function AuthenticationForm(props) {
|
|
5867
|
-
const medplum = useMedplum();
|
|
5868
|
-
const googleClientId = getGoogleClientId(props.googleClientId);
|
|
5869
|
-
const [outcome, setOutcome] = React.useState();
|
|
5870
|
-
const issues = getIssuesForExpression(outcome, undefined);
|
|
5871
|
-
return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
|
|
5872
|
-
medplum
|
|
5873
|
-
.startLogin({
|
|
5874
|
-
projectId: props.projectId,
|
|
5875
|
-
clientId: props.clientId,
|
|
5876
|
-
scope: props.scope,
|
|
5877
|
-
nonce: props.nonce,
|
|
5878
|
-
email: formData.email,
|
|
5879
|
-
password: formData.password,
|
|
5880
|
-
remember: formData.remember === 'true',
|
|
5881
|
-
})
|
|
5882
|
-
.then(props.handleAuthResponse)
|
|
5883
|
-
.catch(setOutcome);
|
|
5884
|
-
} },
|
|
5885
|
-
React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
|
|
5886
|
-
issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
|
|
5887
|
-
var _a, _b;
|
|
5888
|
-
return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
|
|
5889
|
-
}))),
|
|
5890
|
-
googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
5891
|
-
React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
|
|
5892
|
-
React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => {
|
|
5893
|
-
medplum
|
|
5894
|
-
.startGoogleLogin({
|
|
5895
|
-
projectId: props.projectId,
|
|
5896
|
-
clientId: props.clientId,
|
|
5897
|
-
scope: props.scope,
|
|
5898
|
-
nonce: props.nonce,
|
|
5899
|
-
googleClientId: response.clientId,
|
|
5900
|
-
googleCredential: response.credential,
|
|
5901
|
-
})
|
|
5902
|
-
.then(props.handleAuthResponse)
|
|
5903
|
-
.catch(setOutcome);
|
|
5904
|
-
} })),
|
|
5905
|
-
React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
|
|
5906
|
-
React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
|
|
5907
|
-
React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", required: true, autoFocus: true, outcome: outcome })),
|
|
5908
|
-
React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
|
|
5909
|
-
React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
|
|
5910
|
-
React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
|
|
5911
|
-
(props.onForgotPassword || props.onRegister) && (React__default["default"].createElement("div", null,
|
|
5912
|
-
props.onForgotPassword && (React__default["default"].createElement(MedplumLink, { testid: "forgotpassword", onClick: props.onForgotPassword }, "Forgot password")),
|
|
5913
|
-
props.onRegister && (React__default["default"].createElement(MedplumLink, { testid: "register", onClick: props.onRegister }, "Register")))),
|
|
5914
|
-
React__default["default"].createElement("div", null,
|
|
5915
|
-
React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
|
|
5916
|
-
React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
|
|
5917
|
-
React__default["default"].createElement("div", null,
|
|
5918
|
-
React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Sign in")))));
|
|
5919
|
-
}
|
|
5920
|
-
function ProfileForm(props) {
|
|
5921
|
-
const medplum = useMedplum();
|
|
5922
|
-
return (React__default["default"].createElement("div", null,
|
|
5923
|
-
React__default["default"].createElement("div", { className: "medplum-center" },
|
|
5924
|
-
React__default["default"].createElement(Logo, { size: 32 }),
|
|
5925
|
-
React__default["default"].createElement("h1", null, "Choose profile")),
|
|
5926
|
-
props.memberships.map((membership) => {
|
|
5927
|
-
var _a, _b, _c;
|
|
5928
|
-
return (React__default["default"].createElement("div", { className: "medplum-nav-menu-profile", key: membership.id, onClick: () => {
|
|
5929
|
-
medplum
|
|
5930
|
-
.post('auth/profile', {
|
|
5931
|
-
login: props.login,
|
|
5932
|
-
profile: membership.id,
|
|
5933
|
-
})
|
|
5934
|
-
.then(props.handleAuthResponse)
|
|
5935
|
-
.catch(console.log);
|
|
5936
|
-
} },
|
|
5937
|
-
React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
|
|
5938
|
-
React__default["default"].createElement(Avatar, { alt: (_a = membership.profile) === null || _a === void 0 ? void 0 : _a.display })),
|
|
5939
|
-
React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-label" }, (_b = membership.profile) === null || _b === void 0 ? void 0 :
|
|
5940
|
-
_b.display,
|
|
5941
|
-
React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-help-text" }, (_c = membership.project) === null || _c === void 0 ? void 0 : _c.display))));
|
|
5942
|
-
})));
|
|
5943
|
-
}
|
|
5944
|
-
function NewProjectForm(props) {
|
|
5945
|
-
const medplum = useMedplum();
|
|
5946
|
-
const [outcome, setOutcome] = React.useState();
|
|
5947
|
-
return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
|
|
5948
|
-
try {
|
|
5949
|
-
const registerRequest = { projectName: formData.projectName };
|
|
5950
|
-
const partialLogin = { login: props.login };
|
|
5951
|
-
const login = yield medplum.startNewProject(registerRequest, partialLogin);
|
|
5952
|
-
props.handleAuthResponse(login);
|
|
5953
|
-
}
|
|
5954
|
-
catch (err) {
|
|
5955
|
-
setOutcome(err);
|
|
5956
|
-
}
|
|
5957
|
-
}) },
|
|
5958
|
-
React__default["default"].createElement("div", { className: "medplum-center" },
|
|
5959
|
-
React__default["default"].createElement(Logo, { size: 32 }),
|
|
5960
|
-
React__default["default"].createElement("h1", null, "Create project")),
|
|
5961
|
-
React__default["default"].createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
|
|
5962
|
-
React__default["default"].createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome })),
|
|
5963
|
-
React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
|
|
5964
|
-
"By clicking submit you agree to the Medplum ",
|
|
5965
|
-
React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
|
|
5966
|
-
' and ',
|
|
5967
|
-
React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
|
|
5968
|
-
"."),
|
|
5969
|
-
React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
|
|
5970
|
-
React__default["default"].createElement("div", null),
|
|
5971
|
-
React__default["default"].createElement("div", null,
|
|
5972
|
-
React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create project")))));
|
|
5973
|
-
}
|
|
5974
|
-
|
|
5975
5998
|
function Tab(props) {
|
|
5976
5999
|
let className = 'medplum-tab';
|
|
5977
6000
|
if (props.selected) {
|