@medplum/react 0.9.32 → 0.9.35
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/README.md +1 -1
- package/dist/cjs/QuestionnaireForm.d.ts +4 -1
- package/dist/cjs/Scheduler.d.ts +2 -1
- package/dist/cjs/SearchControlField.d.ts +2 -3
- package/dist/cjs/SearchFieldEditor.d.ts +1 -2
- package/dist/cjs/SearchFilterEditor.d.ts +1 -2
- package/dist/cjs/SearchFilterValueDialog.d.ts +1 -2
- package/dist/cjs/SearchFilterValueInput.d.ts +0 -2
- package/dist/cjs/SearchPopupMenu.d.ts +1 -2
- package/dist/cjs/auth/AuthenticationForm.d.ts +2 -0
- package/dist/cjs/auth/SignInForm.d.ts +2 -0
- package/dist/cjs/index.js +125 -71
- 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/QuestionnaireForm.stories.d.ts +1 -0
- package/dist/cjs/styles.css +51 -51
- package/dist/esm/GoogleButton.js +2 -2
- package/dist/esm/GoogleButton.js.map +1 -1
- package/dist/esm/Popup.js +5 -1
- package/dist/esm/Popup.js.map +1 -1
- package/dist/esm/QuestionnaireBuilder.js +1 -1
- package/dist/esm/QuestionnaireBuilder.js.map +1 -1
- package/dist/esm/QuestionnaireForm.d.ts +4 -1
- package/dist/esm/QuestionnaireForm.js +49 -10
- package/dist/esm/QuestionnaireForm.js.map +1 -1
- package/dist/esm/Scheduler.d.ts +2 -1
- package/dist/esm/Scheduler.js +18 -24
- package/dist/esm/Scheduler.js.map +1 -1
- package/dist/esm/SearchControl.js +10 -14
- package/dist/esm/SearchControl.js.map +1 -1
- package/dist/esm/SearchControlField.d.ts +2 -3
- package/dist/esm/SearchControlField.js +6 -8
- package/dist/esm/SearchControlField.js.map +1 -1
- package/dist/esm/SearchFieldEditor.d.ts +1 -2
- package/dist/esm/SearchFieldEditor.js +2 -2
- package/dist/esm/SearchFieldEditor.js.map +1 -1
- package/dist/esm/SearchFilterEditor.d.ts +1 -2
- package/dist/esm/SearchFilterEditor.js +5 -6
- package/dist/esm/SearchFilterEditor.js.map +1 -1
- package/dist/esm/SearchFilterValueDialog.d.ts +1 -2
- package/dist/esm/SearchFilterValueDialog.js +1 -1
- package/dist/esm/SearchFilterValueDialog.js.map +1 -1
- package/dist/esm/SearchFilterValueInput.d.ts +0 -2
- package/dist/esm/SearchFilterValueInput.js +1 -1
- package/dist/esm/SearchFilterValueInput.js.map +1 -1
- package/dist/esm/SearchPopupMenu.d.ts +1 -2
- package/dist/esm/SearchPopupMenu.js.map +1 -1
- package/dist/esm/ServiceRequestTimeline.js +3 -3
- package/dist/esm/ServiceRequestTimeline.js.map +1 -1
- package/dist/esm/auth/AuthenticationForm.d.ts +2 -0
- package/dist/esm/auth/AuthenticationForm.js +4 -0
- package/dist/esm/auth/AuthenticationForm.js.map +1 -1
- package/dist/esm/auth/SignInForm.d.ts +2 -0
- package/dist/esm/auth/SignInForm.js +1 -1
- package/dist/esm/auth/SignInForm.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/esm/stories/QuestionnaireForm.stories.d.ts +1 -0
- package/dist/esm/styles.css +51 -51
- package/dist/esm/utils/blame.js +1 -0
- package/dist/esm/utils/blame.js.map +1 -1
- package/dist/esm/utils/outcomes.js +19 -1
- package/dist/esm/utils/outcomes.js.map +1 -1
- package/package.json +13 -13
- package/stats.html +4034 -0
package/dist/cjs/index.js
CHANGED
|
@@ -18,7 +18,25 @@
|
|
|
18
18
|
|
|
19
19
|
function getIssuesForExpression(outcome, expression) {
|
|
20
20
|
var _a;
|
|
21
|
-
return (_a = outcome === null || outcome === void 0 ? void 0 : outcome.issue) === null || _a === void 0 ? void 0 : _a.filter((issue) => { var _a; return ((_a = issue.expression) === null || _a === void 0 ? void 0 : _a[0]
|
|
21
|
+
return (_a = outcome === null || outcome === void 0 ? void 0 : outcome.issue) === null || _a === void 0 ? void 0 : _a.filter((issue) => { var _a; return isExpressionMatch((_a = issue.expression) === null || _a === void 0 ? void 0 : _a[0], expression); });
|
|
22
|
+
}
|
|
23
|
+
function isExpressionMatch(expr1, expr2) {
|
|
24
|
+
// Expression can be either "fieldName" or "resourceType.fieldName"
|
|
25
|
+
if (expr1 === expr2) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (!expr1 || !expr2) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const dot1 = expr1.indexOf('.');
|
|
32
|
+
if (dot1 >= 0 && expr1.substring(dot1 + 1) === expr2) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
const dot2 = expr2.indexOf('.');
|
|
36
|
+
if (dot2 >= 0 && expr2.substring(dot2 + 1) === expr1) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
22
40
|
}
|
|
23
41
|
|
|
24
42
|
function Input(props) {
|
|
@@ -518,9 +536,9 @@
|
|
|
518
536
|
return clientId;
|
|
519
537
|
}
|
|
520
538
|
const origin = window.location.protocol + '//' + window.location.host;
|
|
521
|
-
const authorizedOrigins = (_b = (_a = "
|
|
539
|
+
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,https://storybook.medplum.com,https://graphiql.medplum.com,https://www.medplum.com") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
|
|
522
540
|
if (authorizedOrigins.includes(origin)) {
|
|
523
|
-
return "
|
|
541
|
+
return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
|
|
524
542
|
}
|
|
525
543
|
return undefined;
|
|
526
544
|
}
|
|
@@ -713,6 +731,8 @@
|
|
|
713
731
|
clientId: props.clientId,
|
|
714
732
|
scope: props.scope,
|
|
715
733
|
nonce: props.nonce,
|
|
734
|
+
codeChallenge: props.codeChallenge,
|
|
735
|
+
codeChallengeMethod: props.codeChallengeMethod,
|
|
716
736
|
email: formData.email,
|
|
717
737
|
password: formData.password,
|
|
718
738
|
remember: formData.remember === 'true',
|
|
@@ -734,6 +754,8 @@
|
|
|
734
754
|
clientId: props.clientId,
|
|
735
755
|
scope: props.scope,
|
|
736
756
|
nonce: props.nonce,
|
|
757
|
+
codeChallenge: props.codeChallenge,
|
|
758
|
+
codeChallengeMethod: props.codeChallengeMethod,
|
|
737
759
|
googleClientId: response.clientId,
|
|
738
760
|
googleCredential: response.credential,
|
|
739
761
|
})
|
|
@@ -887,7 +909,7 @@
|
|
|
887
909
|
}
|
|
888
910
|
return (React__default["default"].createElement(Document, { width: 450 }, (() => {
|
|
889
911
|
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));
|
|
912
|
+
return (React__default["default"].createElement(AuthenticationForm, { projectId: props.projectId, clientId: props.clientId, scope: props.scope, nonce: props.nonce, googleClientId: props.googleClientId, codeChallenge: props.codeChallenge, codeChallengeMethod: props.codeChallengeMethod, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
|
|
891
913
|
}
|
|
892
914
|
else if (memberships) {
|
|
893
915
|
return React__default["default"].createElement(ChooseProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
|
|
@@ -2546,11 +2568,14 @@
|
|
|
2546
2568
|
((_b = propsRef.current) === null || _b === void 0 ? void 0 : _b.autoClose) &&
|
|
2547
2569
|
(ref === null || ref === void 0 ? void 0 : ref.current) &&
|
|
2548
2570
|
!ref.current.contains(e.target)) {
|
|
2571
|
+
killEvent(e);
|
|
2549
2572
|
props.onClose();
|
|
2550
2573
|
}
|
|
2551
2574
|
}
|
|
2552
2575
|
document.addEventListener('click', handleClick, true);
|
|
2553
|
-
return () =>
|
|
2576
|
+
return () => {
|
|
2577
|
+
document.removeEventListener('click', handleClick, true);
|
|
2578
|
+
};
|
|
2554
2579
|
}, [props]);
|
|
2555
2580
|
// Listen for changes in the location
|
|
2556
2581
|
// If the browser navigates to a new page, close the popup
|
|
@@ -2952,27 +2977,25 @@
|
|
|
2952
2977
|
|
|
2953
2978
|
/**
|
|
2954
2979
|
* Returns the collection of field definitions for the search request.
|
|
2955
|
-
* @param typeSchema The schema for the resource type
|
|
2956
2980
|
* @param search The search request definition.
|
|
2957
2981
|
* @returns An array of field definitions.
|
|
2958
2982
|
*/
|
|
2959
|
-
function getFieldDefinitions(
|
|
2983
|
+
function getFieldDefinitions(search) {
|
|
2960
2984
|
const resourceType = search.resourceType;
|
|
2961
2985
|
const fields = [];
|
|
2962
2986
|
for (const name of search.fields || ['id', '_lastUpdated']) {
|
|
2963
|
-
fields.push(getFieldDefinition(
|
|
2987
|
+
fields.push(getFieldDefinition(resourceType, name));
|
|
2964
2988
|
}
|
|
2965
2989
|
return fields;
|
|
2966
2990
|
}
|
|
2967
2991
|
/**
|
|
2968
2992
|
* Return the field definition for a given field name.
|
|
2969
2993
|
* Field names can be either property names or search parameter codes.
|
|
2970
|
-
* @param typeSchema The schema for the resource type
|
|
2971
2994
|
* @param resourceType The resource type.
|
|
2972
2995
|
* @param name The search field name (either property name or search parameter code).
|
|
2973
2996
|
* @returns The field definition.
|
|
2974
2997
|
*/
|
|
2975
|
-
function getFieldDefinition(
|
|
2998
|
+
function getFieldDefinition(resourceType, name) {
|
|
2976
2999
|
var _a;
|
|
2977
3000
|
if (name === '_lastUpdated') {
|
|
2978
3001
|
return {
|
|
@@ -3004,7 +3027,7 @@
|
|
|
3004
3027
|
],
|
|
3005
3028
|
};
|
|
3006
3029
|
}
|
|
3007
|
-
const typeSchema =
|
|
3030
|
+
const typeSchema = core.globalSchema.types[resourceType];
|
|
3008
3031
|
const exactElementDefinition = typeSchema.properties[name];
|
|
3009
3032
|
const exactSearchParam = (_a = typeSchema.searchParams) === null || _a === void 0 ? void 0 : _a[name.toLowerCase()];
|
|
3010
3033
|
// Best case: Exact match of element definition or search parameter.
|
|
@@ -3035,7 +3058,7 @@
|
|
|
3035
3058
|
// Patient.email is a search parameter for the Patient.telecom element.
|
|
3036
3059
|
// So we need to walk backwards to find the element definition.
|
|
3037
3060
|
if (exactSearchParam) {
|
|
3038
|
-
const details = core.getSearchParameterDetails(
|
|
3061
|
+
const details = core.getSearchParameterDetails(resourceType, exactSearchParam);
|
|
3039
3062
|
return { name, elementDefinition: details.elementDefinition, searchParams: [exactSearchParam] };
|
|
3040
3063
|
}
|
|
3041
3064
|
// Worst case: no element definition and no search parameter.
|
|
@@ -3651,7 +3674,7 @@
|
|
|
3651
3674
|
return null;
|
|
3652
3675
|
}
|
|
3653
3676
|
const resourceType = props.search.resourceType;
|
|
3654
|
-
const typeDef =
|
|
3677
|
+
const typeDef = core.globalSchema.types[resourceType];
|
|
3655
3678
|
const selected = (_a = state.search.fields) !== null && _a !== void 0 ? _a : [];
|
|
3656
3679
|
const available = getFieldsList(typeDef)
|
|
3657
3680
|
.filter((field) => !(selected === null || selected === void 0 ? void 0 : selected.includes(field)))
|
|
@@ -3726,7 +3749,7 @@
|
|
|
3726
3749
|
|
|
3727
3750
|
function SearchFilterValueInput(props) {
|
|
3728
3751
|
var _a;
|
|
3729
|
-
const details = core.getSearchParameterDetails(props.
|
|
3752
|
+
const details = core.getSearchParameterDetails(props.resourceType, props.searchParam);
|
|
3730
3753
|
const name = 'filter-value';
|
|
3731
3754
|
switch (details.type) {
|
|
3732
3755
|
case core.SearchParameterType.REFERENCE:
|
|
@@ -3787,9 +3810,8 @@
|
|
|
3787
3810
|
if (!props.visible) {
|
|
3788
3811
|
return null;
|
|
3789
3812
|
}
|
|
3790
|
-
const schema = props.schema;
|
|
3791
3813
|
const resourceType = props.search.resourceType;
|
|
3792
|
-
const searchParams =
|
|
3814
|
+
const searchParams = core.globalSchema.types[resourceType].searchParams;
|
|
3793
3815
|
const filters = search.filters || [];
|
|
3794
3816
|
return (React__default["default"].createElement(Dialog, { title: "Filters", visible: props.visible, onOk: () => props.onOk(searchRef.current), onCancel: props.onCancel },
|
|
3795
3817
|
React__default["default"].createElement("div", { className: "medplum-filter-editor" },
|
|
@@ -3808,7 +3830,7 @@
|
|
|
3808
3830
|
React__default["default"].createElement("tbody", null,
|
|
3809
3831
|
filters.map((filter, index) => {
|
|
3810
3832
|
if (index === editingIndex) {
|
|
3811
|
-
return (React__default["default"].createElement(FilterRowInput, { key: `filter-${index}-${filters.length}-input`,
|
|
3833
|
+
return (React__default["default"].createElement(FilterRowInput, { key: `filter-${index}-${filters.length}-input`, resourceType: resourceType, searchParams: searchParams, defaultValue: filter, okText: "Save", onOk: (newFilter) => {
|
|
3812
3834
|
const newFilters = [...filters];
|
|
3813
3835
|
newFilters[index] = newFilter;
|
|
3814
3836
|
setSearch(setFilters(searchRef.current, newFilters));
|
|
@@ -3819,7 +3841,7 @@
|
|
|
3819
3841
|
return (React__default["default"].createElement(FilterRowDisplay, { key: `filter-${index}-${filters.length}-display`, resourceType: resourceType, searchParams: searchParams, filter: filter, onEdit: () => setEditingIndex(index), onDelete: () => setSearch(deleteFilter(searchRef.current, index)) }));
|
|
3820
3842
|
}
|
|
3821
3843
|
}),
|
|
3822
|
-
React__default["default"].createElement(FilterRowInput, {
|
|
3844
|
+
React__default["default"].createElement(FilterRowInput, { resourceType: resourceType, searchParams: searchParams, okText: "Add", onOk: onAddFilter }))))));
|
|
3823
3845
|
}
|
|
3824
3846
|
function FilterRowDisplay(props) {
|
|
3825
3847
|
const { filter } = props;
|
|
@@ -3856,7 +3878,7 @@
|
|
|
3856
3878
|
React__default["default"].createElement("td", null, operators && (React__default["default"].createElement(Select, { testid: "filter-operation", defaultValue: value.operator, onChange: setFilterOperator },
|
|
3857
3879
|
React__default["default"].createElement("option", { value: "" }),
|
|
3858
3880
|
operators.map((operator) => (React__default["default"].createElement("option", { key: operator, value: operator }, getOpString(operator))))))),
|
|
3859
|
-
React__default["default"].createElement("td", null, searchParam && value.operator && (React__default["default"].createElement(SearchFilterValueInput, {
|
|
3881
|
+
React__default["default"].createElement("td", null, searchParam && value.operator && (React__default["default"].createElement(SearchFilterValueInput, { resourceType: props.resourceType, searchParam: searchParam, defaultValue: value.value, onChange: setFilterValue }))),
|
|
3860
3882
|
React__default["default"].createElement("td", null,
|
|
3861
3883
|
value.code && value.operator && value.value && (React__default["default"].createElement(Button, { size: "small", onClick: () => {
|
|
3862
3884
|
props.onOk(valueRef.current);
|
|
@@ -3877,7 +3899,7 @@
|
|
|
3877
3899
|
return (React__default["default"].createElement(Dialog, { title: props.title, visible: props.visible, onOk: onOk, onCancel: props.onCancel },
|
|
3878
3900
|
React__default["default"].createElement("div", { style: { width: 500 } },
|
|
3879
3901
|
React__default["default"].createElement(Form, { onSubmit: onOk },
|
|
3880
|
-
React__default["default"].createElement(SearchFilterValueInput, {
|
|
3902
|
+
React__default["default"].createElement(SearchFilterValueInput, { resourceType: props.resourceType, searchParam: props.searchParam, defaultValue: value, autoFocus: true, onChange: setValue })))));
|
|
3881
3903
|
}
|
|
3882
3904
|
|
|
3883
3905
|
function MenuSeparator() {
|
|
@@ -4073,7 +4095,7 @@
|
|
|
4073
4095
|
function SearchControl(props) {
|
|
4074
4096
|
var _a, _b, _c, _d;
|
|
4075
4097
|
const medplum = useMedplum();
|
|
4076
|
-
const [
|
|
4098
|
+
const [schemaLoaded, setSchemaLoaded] = React.useState(false);
|
|
4077
4099
|
const [outcome, setOutcome] = React.useState();
|
|
4078
4100
|
const { search, onLoad } = props;
|
|
4079
4101
|
const [state, setState] = React.useState({
|
|
@@ -4091,7 +4113,7 @@
|
|
|
4091
4113
|
React.useEffect(() => {
|
|
4092
4114
|
setOutcome(undefined);
|
|
4093
4115
|
medplum
|
|
4094
|
-
.search(search.resourceType, core.formatSearchQuery(Object.assign(Object.assign({}, search), { total: 'accurate' })))
|
|
4116
|
+
.search(search.resourceType, core.formatSearchQuery(Object.assign(Object.assign({}, search), { total: 'accurate', fields: undefined })))
|
|
4095
4117
|
.then((response) => {
|
|
4096
4118
|
setState(Object.assign(Object.assign({}, stateRef.current), { searchResponse: response }));
|
|
4097
4119
|
if (onLoad) {
|
|
@@ -4185,19 +4207,15 @@
|
|
|
4185
4207
|
React.useEffect(() => {
|
|
4186
4208
|
medplum
|
|
4187
4209
|
.requestSchema(props.search.resourceType)
|
|
4188
|
-
.then((
|
|
4189
|
-
// The schema could have the same object identity,
|
|
4190
|
-
// so need to use the spread operator to kick React re-render.
|
|
4191
|
-
setSchema(Object.assign({}, newSchema));
|
|
4192
|
-
})
|
|
4210
|
+
.then(() => setSchemaLoaded(true))
|
|
4193
4211
|
.catch(console.log);
|
|
4194
4212
|
}, [medplum, props.search.resourceType]);
|
|
4195
|
-
const typeSchema = (_a =
|
|
4213
|
+
const typeSchema = schemaLoaded && ((_a = core.globalSchema === null || core.globalSchema === void 0 ? void 0 : core.globalSchema.types) === null || _a === void 0 ? void 0 : _a[props.search.resourceType]);
|
|
4196
4214
|
if (!typeSchema) {
|
|
4197
4215
|
return React__default["default"].createElement(Loading, null);
|
|
4198
4216
|
}
|
|
4199
4217
|
const checkboxColumn = props.checkboxesEnabled;
|
|
4200
|
-
const fields = getFieldDefinitions(
|
|
4218
|
+
const fields = getFieldDefinitions(search);
|
|
4201
4219
|
const resourceType = search.resourceType;
|
|
4202
4220
|
const lastResult = state.searchResponse;
|
|
4203
4221
|
const entries = lastResult === null || lastResult === void 0 ? void 0 : lastResult.entry;
|
|
@@ -4221,9 +4239,9 @@
|
|
|
4221
4239
|
props.onBulk && (React__default["default"].createElement(Button, { size: "small", onClick: () => props.onBulk(Object.keys(state.selected)) }, "Bulk..."))),
|
|
4222
4240
|
lastResult && (React__default["default"].createElement("div", null,
|
|
4223
4241
|
React__default["default"].createElement("span", { className: "medplum-search-summary" },
|
|
4224
|
-
getStart(search, lastResult.total),
|
|
4242
|
+
getStart$1(search, lastResult.total),
|
|
4225
4243
|
"-",
|
|
4226
|
-
getEnd(search, lastResult.total),
|
|
4244
|
+
getEnd$1(search, lastResult.total),
|
|
4227
4245
|
" of",
|
|
4228
4246
|
' ', (_d = lastResult.total) === null || _d === void 0 ? void 0 :
|
|
4229
4247
|
_d.toLocaleString()),
|
|
@@ -4247,7 +4265,7 @@
|
|
|
4247
4265
|
(resources === null || resources === void 0 ? void 0 : resources.length) === 0 && (React__default["default"].createElement("div", { "data-testid": "empty-search", className: "medplum-empty-search" }, "No results")),
|
|
4248
4266
|
outcome && (React__default["default"].createElement("div", { "data-testid": "search-error", className: "medplum-empty-search" },
|
|
4249
4267
|
React__default["default"].createElement("pre", { style: { textAlign: 'left' } }, JSON.stringify(outcome, undefined, 2)))),
|
|
4250
|
-
React__default["default"].createElement(SearchPopupMenu, {
|
|
4268
|
+
React__default["default"].createElement(SearchPopupMenu, { search: props.search, visible: state.popupVisible, x: state.popupX, y: state.popupY, searchParams: state.popupSearchParams, onPrompt: (searchParam, filter) => {
|
|
4251
4269
|
setState(Object.assign(Object.assign({}, stateRef.current), { popupVisible: false, filterDialogVisible: true, filterDialogSearchParam: searchParam, filterDialogFilter: filter }));
|
|
4252
4270
|
}, onChange: (result) => {
|
|
4253
4271
|
emitSearchChange(result);
|
|
@@ -4255,19 +4273,19 @@
|
|
|
4255
4273
|
}, onClose: () => {
|
|
4256
4274
|
setState(Object.assign(Object.assign({}, stateRef.current), { popupVisible: false, popupSearchParams: undefined }));
|
|
4257
4275
|
} }),
|
|
4258
|
-
React__default["default"].createElement(SearchFieldEditor, {
|
|
4276
|
+
React__default["default"].createElement(SearchFieldEditor, { search: props.search, visible: stateRef.current.fieldEditorVisible, onOk: (result) => {
|
|
4259
4277
|
emitSearchChange(result);
|
|
4260
4278
|
setState(Object.assign(Object.assign({}, stateRef.current), { fieldEditorVisible: false }));
|
|
4261
4279
|
}, onCancel: () => {
|
|
4262
4280
|
setState(Object.assign(Object.assign({}, stateRef.current), { fieldEditorVisible: false }));
|
|
4263
4281
|
} }),
|
|
4264
|
-
React__default["default"].createElement(SearchFilterEditor, {
|
|
4282
|
+
React__default["default"].createElement(SearchFilterEditor, { search: props.search, visible: stateRef.current.filterEditorVisible, onOk: (result) => {
|
|
4265
4283
|
emitSearchChange(result);
|
|
4266
4284
|
setState(Object.assign(Object.assign({}, stateRef.current), { filterEditorVisible: false }));
|
|
4267
4285
|
}, onCancel: () => {
|
|
4268
4286
|
setState(Object.assign(Object.assign({}, stateRef.current), { filterEditorVisible: false }));
|
|
4269
4287
|
} }),
|
|
4270
|
-
React__default["default"].createElement(SearchFilterValueDialog, { visible: stateRef.current.filterDialogVisible, title: 'Input',
|
|
4288
|
+
React__default["default"].createElement(SearchFilterValueDialog, { visible: stateRef.current.filterDialogVisible, title: 'Input', resourceType: resourceType, searchParam: state.filterDialogSearchParam, filter: state.filterDialogFilter, defaultValue: '', onOk: (filter) => {
|
|
4271
4289
|
emitSearchChange(addFilter(props.search, filter.code, filter.operator, filter.value));
|
|
4272
4290
|
setState(Object.assign(Object.assign({}, stateRef.current), { filterDialogVisible: false }));
|
|
4273
4291
|
}, onCancel: () => {
|
|
@@ -4290,11 +4308,11 @@
|
|
|
4290
4308
|
return (React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "rgba(0, 0, 0, 0.3)", strokeWidth: 2 },
|
|
4291
4309
|
React__default["default"].createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16m-7 6h7" })));
|
|
4292
4310
|
}
|
|
4293
|
-
function getStart(search, total) {
|
|
4311
|
+
function getStart$1(search, total) {
|
|
4294
4312
|
var _a;
|
|
4295
4313
|
return Math.min(total, ((_a = search.offset) !== null && _a !== void 0 ? _a : 0) + 1);
|
|
4296
4314
|
}
|
|
4297
|
-
function getEnd(search, total) {
|
|
4315
|
+
function getEnd$1(search, total) {
|
|
4298
4316
|
var _a, _b;
|
|
4299
4317
|
return Math.min(total, (((_a = search.offset) !== null && _a !== void 0 ? _a : 0) + 1) * ((_b = search.count) !== null && _b !== void 0 ? _b : core.DEFAULT_SEARCH_COUNT));
|
|
4300
4318
|
}
|
|
@@ -5015,17 +5033,24 @@
|
|
|
5015
5033
|
const [schema, setSchema] = React.useState();
|
|
5016
5034
|
const questionnaire = useResource(props.questionnaire);
|
|
5017
5035
|
const [response, setResponse] = React.useState();
|
|
5036
|
+
const [answers, setAnswers] = React.useState({});
|
|
5018
5037
|
React.useEffect(() => {
|
|
5019
|
-
medplum
|
|
5038
|
+
medplum
|
|
5039
|
+
.requestSchema('Questionnaire')
|
|
5040
|
+
.then(() => medplum.requestSchema('QuestionnaireResponse'))
|
|
5041
|
+
.then(setSchema)
|
|
5042
|
+
.catch(console.log);
|
|
5020
5043
|
}, [medplum]);
|
|
5021
5044
|
React.useEffect(() => {
|
|
5022
5045
|
setResponse(questionnaire ? buildInitialResponse(questionnaire) : undefined);
|
|
5023
5046
|
}, [questionnaire]);
|
|
5024
5047
|
function setItems(newResponseItems) {
|
|
5025
|
-
|
|
5048
|
+
const newResponse = {
|
|
5026
5049
|
resourceType: 'QuestionnaireResponse',
|
|
5027
5050
|
item: newResponseItems,
|
|
5028
|
-
}
|
|
5051
|
+
};
|
|
5052
|
+
setResponse(newResponse);
|
|
5053
|
+
setAnswers(core.getQuestionnaireAnswers(newResponse));
|
|
5029
5054
|
}
|
|
5030
5055
|
if (!schema || !questionnaire) {
|
|
5031
5056
|
return null;
|
|
@@ -5036,8 +5061,8 @@
|
|
|
5036
5061
|
}
|
|
5037
5062
|
} },
|
|
5038
5063
|
questionnaire.title && React__default["default"].createElement("h1", null, questionnaire.title),
|
|
5039
|
-
questionnaire.item && React__default["default"].createElement(QuestionnaireFormItemArray, { items: questionnaire.item, onChange: setItems }),
|
|
5040
|
-
React__default["default"].createElement(Button, { type: "submit", size: "large" },
|
|
5064
|
+
questionnaire.item && (React__default["default"].createElement(QuestionnaireFormItemArray, { items: questionnaire.item, answers: answers, onChange: setItems })),
|
|
5065
|
+
React__default["default"].createElement(Button, { type: "submit", size: "large" }, props.submitButtonText || 'OK')));
|
|
5041
5066
|
}
|
|
5042
5067
|
function QuestionnaireFormItemArray(props) {
|
|
5043
5068
|
const [responseItems, setResponseItems] = React.useState(buildInitialResponseItems(props.items));
|
|
@@ -5048,11 +5073,14 @@
|
|
|
5048
5073
|
props.onChange(newResponseItems);
|
|
5049
5074
|
}
|
|
5050
5075
|
return (React__default["default"].createElement(React__default["default"].Fragment, null, props.items.map((item, index) => {
|
|
5076
|
+
if (!isQuestionEnabled(item, props.answers)) {
|
|
5077
|
+
return null;
|
|
5078
|
+
}
|
|
5051
5079
|
if (item.type === exports.QuestionnaireItemType.display) {
|
|
5052
5080
|
return React__default["default"].createElement("p", { key: item.linkId }, item.text);
|
|
5053
5081
|
}
|
|
5054
5082
|
if (item.type === exports.QuestionnaireItemType.group) {
|
|
5055
|
-
return (React__default["default"].createElement(QuestionnaireFormItem, { key: item.linkId, item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) }));
|
|
5083
|
+
return (React__default["default"].createElement(QuestionnaireFormItem, { key: item.linkId, item: item, answers: props.answers, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) }));
|
|
5056
5084
|
}
|
|
5057
5085
|
if (item.type === exports.QuestionnaireItemType.boolean) {
|
|
5058
5086
|
const initial = item.initial && item.initial.length > 0 ? item.initial[0] : undefined;
|
|
@@ -5064,7 +5092,7 @@
|
|
|
5064
5092
|
}) })));
|
|
5065
5093
|
}
|
|
5066
5094
|
return (React__default["default"].createElement(FormSection, { key: item.linkId, htmlFor: item.linkId, title: item.text || '' },
|
|
5067
|
-
React__default["default"].createElement(QuestionnaireFormItem, { item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) })));
|
|
5095
|
+
React__default["default"].createElement(QuestionnaireFormItem, { item: item, answers: props.answers, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) })));
|
|
5068
5096
|
})));
|
|
5069
5097
|
}
|
|
5070
5098
|
function QuestionnaireFormItem(props) {
|
|
@@ -5096,7 +5124,7 @@
|
|
|
5096
5124
|
case exports.QuestionnaireItemType.group:
|
|
5097
5125
|
return (React__default["default"].createElement("div", null,
|
|
5098
5126
|
React__default["default"].createElement("h3", null, item.text),
|
|
5099
|
-
item.item && React__default["default"].createElement(QuestionnaireFormItemArray, { items: item.item, onChange: onChangeItem })));
|
|
5127
|
+
item.item && (React__default["default"].createElement(QuestionnaireFormItemArray, { items: item.item, answers: props.answers, onChange: onChangeItem }))));
|
|
5100
5128
|
case exports.QuestionnaireItemType.boolean:
|
|
5101
5129
|
return (React__default["default"].createElement(Checkbox, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => onChangeAnswer({ valueBoolean: newValue }) }));
|
|
5102
5130
|
case exports.QuestionnaireItemType.decimal:
|
|
@@ -5207,6 +5235,35 @@
|
|
|
5207
5235
|
((_c = (_b = (_a = e.valueCodeableConcept) === null || _a === void 0 ? void 0 : _a.coding) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.code) === 'drop-down';
|
|
5208
5236
|
}));
|
|
5209
5237
|
}
|
|
5238
|
+
function isQuestionEnabled(item, answers) {
|
|
5239
|
+
if (!item.enableWhen) {
|
|
5240
|
+
return true;
|
|
5241
|
+
}
|
|
5242
|
+
const enableBehavior = item.enableBehavior || 'any';
|
|
5243
|
+
for (const enableWhen of item.enableWhen) {
|
|
5244
|
+
const expectedAnswer = core.getTypedPropertyValue({
|
|
5245
|
+
type: 'QuestionnaireItemEnableWhen',
|
|
5246
|
+
value: enableWhen,
|
|
5247
|
+
}, 'answer[x]');
|
|
5248
|
+
const actualAnswer = core.getTypedPropertyValue({
|
|
5249
|
+
type: 'QuestionnaireResponseItemAnswer',
|
|
5250
|
+
value: answers[enableWhen.question],
|
|
5251
|
+
}, 'value[x]');
|
|
5252
|
+
const match = core.deepEquals(expectedAnswer, actualAnswer);
|
|
5253
|
+
if (enableBehavior === 'any' && match) {
|
|
5254
|
+
return true;
|
|
5255
|
+
}
|
|
5256
|
+
if (enableBehavior === 'all' && !match) {
|
|
5257
|
+
return false;
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
5260
|
+
if (enableBehavior === 'any') {
|
|
5261
|
+
return false;
|
|
5262
|
+
}
|
|
5263
|
+
else {
|
|
5264
|
+
return true;
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5210
5267
|
|
|
5211
5268
|
function QuestionnaireBuilder(props) {
|
|
5212
5269
|
const medplum = useMedplum();
|
|
@@ -5303,7 +5360,7 @@
|
|
|
5303
5360
|
isChoiceQuestion(item) && (React__default["default"].createElement(AnswerBuilder, { options: item.answerOption, onChange: (newOptions) => changeProperty('answerOption', newOptions) })))) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
5304
5361
|
resource.title && React__default["default"].createElement("h1", null, resource.title),
|
|
5305
5362
|
item.text && React__default["default"].createElement("p", null, item.text),
|
|
5306
|
-
!isContainer && React__default["default"].createElement(QuestionnaireFormItem, { item: item, onChange: () => undefined }))),
|
|
5363
|
+
!isContainer && React__default["default"].createElement(QuestionnaireFormItem, { item: item, answers: {}, onChange: () => undefined }))),
|
|
5307
5364
|
item.item &&
|
|
5308
5365
|
item.item.map((i) => (React__default["default"].createElement("div", { key: i.id },
|
|
5309
5366
|
React__default["default"].createElement(ItemBuilder, { item: i, selectedKey: props.selectedKey, setSelectedKey: props.setSelectedKey, hoverKey: props.hoverKey, setHoverKey: props.setHoverKey, onChange: changeItem, onRemove: () => removeItem(i) })))),
|
|
@@ -5593,6 +5650,7 @@
|
|
|
5593
5650
|
function blame(history) {
|
|
5594
5651
|
// Convert to array of array of lines
|
|
5595
5652
|
const versions = history.entry
|
|
5653
|
+
.filter((entry) => !!entry.resource)
|
|
5596
5654
|
.map((entry) => {
|
|
5597
5655
|
var _a;
|
|
5598
5656
|
return ({
|
|
@@ -5876,22 +5934,23 @@
|
|
|
5876
5934
|
var _a;
|
|
5877
5935
|
const medplum = useMedplum();
|
|
5878
5936
|
const schedule = useResource(props.schedule);
|
|
5937
|
+
const questionnaire = useResource(props.questionnaire);
|
|
5879
5938
|
const [slots, setSlots] = React.useState();
|
|
5880
5939
|
const slotsRef = React.useRef();
|
|
5881
5940
|
slotsRef.current = slots;
|
|
5882
5941
|
const [month, setMonth] = React.useState(getStartMonth());
|
|
5883
5942
|
const [date, setDate] = React.useState();
|
|
5884
5943
|
const [slot, setSlot] = React.useState();
|
|
5885
|
-
const [
|
|
5886
|
-
const [form, setForm] = React.useState();
|
|
5944
|
+
const [response, setResponse] = React.useState();
|
|
5887
5945
|
React.useEffect(() => {
|
|
5888
5946
|
if (schedule) {
|
|
5889
5947
|
setSlots([]);
|
|
5890
5948
|
medplum
|
|
5891
5949
|
.searchResources('Slot', new URLSearchParams([
|
|
5950
|
+
['_count', (30 * 24).toString()],
|
|
5892
5951
|
['schedule', core.getReferenceString(schedule)],
|
|
5893
|
-
['start', 'gt' + month
|
|
5894
|
-
['start', 'lt' +
|
|
5952
|
+
['start', 'gt' + getStart(month)],
|
|
5953
|
+
['start', 'lt' + getEnd(month)],
|
|
5895
5954
|
]))
|
|
5896
5955
|
.then(setSlots)
|
|
5897
5956
|
.catch(console.log);
|
|
@@ -5900,7 +5959,7 @@
|
|
|
5900
5959
|
setSlots(undefined);
|
|
5901
5960
|
}
|
|
5902
5961
|
}, [medplum, schedule, month]);
|
|
5903
|
-
if (!schedule || !slots) {
|
|
5962
|
+
if (!schedule || !slots || !questionnaire) {
|
|
5904
5963
|
return null;
|
|
5905
5964
|
}
|
|
5906
5965
|
const actor = (_a = schedule.actor) === null || _a === void 0 ? void 0 : _a[0];
|
|
@@ -5924,26 +5983,20 @@
|
|
|
5924
5983
|
slotStart.getTime() < date.getTime() + 24 * 3600 * 1000 && (React__default["default"].createElement("div", { key: s.id },
|
|
5925
5984
|
React__default["default"].createElement(Button, { style: { width: 150 }, onClick: () => setSlot(s) }, formatTime(slotStart)))));
|
|
5926
5985
|
}))),
|
|
5927
|
-
date && slot && !
|
|
5928
|
-
|
|
5929
|
-
React__default["default"].createElement(FormSection, { title: "Name", htmlFor: "name" },
|
|
5930
|
-
React__default["default"].createElement(Input, { name: "name" })),
|
|
5931
|
-
React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email" },
|
|
5932
|
-
React__default["default"].createElement(Input, { name: "email" })),
|
|
5933
|
-
React__default["default"].createElement(Button, { primary: true, onClick: () => setInfo('info') }, "Next"))),
|
|
5934
|
-
date && slot && info && !form && (React__default["default"].createElement("div", null,
|
|
5935
|
-
React__default["default"].createElement("h3", null, "Custom questions"),
|
|
5936
|
-
React__default["default"].createElement(FormSection, { title: "Question 1", htmlFor: "q1" },
|
|
5937
|
-
React__default["default"].createElement(Input, { name: "q1" })),
|
|
5938
|
-
React__default["default"].createElement(FormSection, { title: "Question 2", htmlFor: "q2" },
|
|
5939
|
-
React__default["default"].createElement(Input, { name: "email" })),
|
|
5940
|
-
React__default["default"].createElement(FormSection, { title: "Question 3", htmlFor: "q3" },
|
|
5941
|
-
React__default["default"].createElement(Input, { name: "email" })),
|
|
5942
|
-
React__default["default"].createElement(Button, { primary: true, onClick: () => setForm('form') }, "Next"))),
|
|
5943
|
-
date && slot && info && form && (React__default["default"].createElement("div", null,
|
|
5986
|
+
date && slot && !response && (React__default["default"].createElement(QuestionnaireForm, { questionnaire: questionnaire, submitButtonText: 'Next', onSubmit: setResponse })),
|
|
5987
|
+
date && slot && response && (React__default["default"].createElement("div", null,
|
|
5944
5988
|
React__default["default"].createElement("h3", null, "You're all set!"),
|
|
5945
5989
|
React__default["default"].createElement("p", null, "Check your email for a calendar invite."))))));
|
|
5946
5990
|
}
|
|
5991
|
+
function getStart(month) {
|
|
5992
|
+
return formatSlotInstant(month.getTime());
|
|
5993
|
+
}
|
|
5994
|
+
function getEnd(month) {
|
|
5995
|
+
return formatSlotInstant(month.getTime() + 31 * 24 * 60 * 60 * 1000);
|
|
5996
|
+
}
|
|
5997
|
+
function formatSlotInstant(time) {
|
|
5998
|
+
return new Date(Math.max(Date.now(), time)).toISOString();
|
|
5999
|
+
}
|
|
5947
6000
|
function formatTime(date) {
|
|
5948
6001
|
return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
|
|
5949
6002
|
}
|
|
@@ -5962,19 +6015,19 @@
|
|
|
5962
6015
|
{
|
|
5963
6016
|
request: {
|
|
5964
6017
|
method: 'GET',
|
|
5965
|
-
url: `Communication?based-on=${core.getReferenceString(resource)}`,
|
|
6018
|
+
url: `Communication?based-on=${core.getReferenceString(resource)}&_sort=-_lastUpdated`,
|
|
5966
6019
|
},
|
|
5967
6020
|
},
|
|
5968
6021
|
{
|
|
5969
6022
|
request: {
|
|
5970
6023
|
method: 'GET',
|
|
5971
|
-
url: `Media?_count=100&based-on=${core.getReferenceString(resource)}`,
|
|
6024
|
+
url: `Media?_count=100&based-on=${core.getReferenceString(resource)}&_sort=-_lastUpdated`,
|
|
5972
6025
|
},
|
|
5973
6026
|
},
|
|
5974
6027
|
{
|
|
5975
6028
|
request: {
|
|
5976
6029
|
method: 'GET',
|
|
5977
|
-
url: `DiagnosticReport?based-on=${core.getReferenceString(resource)}`,
|
|
6030
|
+
url: `DiagnosticReport?based-on=${core.getReferenceString(resource)}&_sort=-_lastUpdated`,
|
|
5978
6031
|
},
|
|
5979
6032
|
},
|
|
5980
6033
|
],
|
|
@@ -6163,6 +6216,7 @@
|
|
|
6163
6216
|
exports.hasFilterOnField = hasFilterOnField;
|
|
6164
6217
|
exports.initRecaptcha = initRecaptcha;
|
|
6165
6218
|
exports.isChoiceQuestion = isChoiceQuestion;
|
|
6219
|
+
exports.isQuestionEnabled = isQuestionEnabled;
|
|
6166
6220
|
exports.isSortDescending = isSortDescending;
|
|
6167
6221
|
exports.movePage = movePage;
|
|
6168
6222
|
exports.parseForm = parseForm;
|