@openmrs/esm-framework 4.0.0-pre.0 → 4.0.1-pre.206

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/.turbo/turbo-build.log +21 -116
  2. package/dist/openmrs-esm-framework.js +1 -1
  3. package/dist/openmrs-esm-framework.js.LICENSE.txt +0 -9
  4. package/dist/openmrs-esm-framework.js.map +1 -1
  5. package/docs/API.md +566 -714
  6. package/docs/classes/OpenmrsFetchError.md +4 -10
  7. package/docs/enums/Type.md +20 -20
  8. package/docs/enums/VisitMode.md +8 -8
  9. package/docs/enums/VisitStatus.md +6 -6
  10. package/docs/interfaces/AssignedExtension.md +7 -9
  11. package/docs/interfaces/BreadcrumbRegistration.md +2 -2
  12. package/docs/interfaces/BreadcrumbSettings.md +4 -22
  13. package/docs/interfaces/CancelLoading.md +1 -1
  14. package/docs/interfaces/ClearDynamicRoutesMessage.md +1 -1
  15. package/docs/interfaces/ComponentDefinition.md +7 -19
  16. package/docs/interfaces/Config.md +3 -17
  17. package/docs/interfaces/ConfigObject.md +14 -17
  18. package/docs/interfaces/ConfigSchema.md +3 -3
  19. package/docs/interfaces/ConfigurableLinkProps.md +12 -1
  20. package/docs/interfaces/ConnectedExtension.md +4 -6
  21. package/docs/interfaces/ConnectivityChangedEvent.md +1 -1
  22. package/docs/interfaces/CurrentPatientOptions.md +1 -1
  23. package/docs/interfaces/DisplayConditionsConfigObject.md +19 -0
  24. package/docs/interfaces/DynamicOfflineData.md +63 -0
  25. package/docs/interfaces/DynamicOfflineDataHandler.md +88 -0
  26. package/docs/interfaces/DynamicOfflineDataSyncState.md +63 -0
  27. package/docs/interfaces/ErrorStateProps.md +30 -0
  28. package/docs/interfaces/ExtensionData.md +3 -3
  29. package/docs/interfaces/ExtensionDefinition.md +13 -37
  30. package/docs/interfaces/ExtensionProps.md +2 -2
  31. package/docs/interfaces/ExtensionRegistration.md +18 -7
  32. package/docs/interfaces/ExtensionSlotBaseProps.md +15 -4
  33. package/docs/interfaces/ExtensionSlotConfig.md +4 -4
  34. package/docs/interfaces/ExtensionSlotConfigObject.md +3 -9
  35. package/docs/interfaces/ExtensionSlotState.md +2 -2
  36. package/docs/interfaces/ExtensionStore.md +1 -1
  37. package/docs/interfaces/FHIRCode.md +13 -2
  38. package/docs/interfaces/FHIRRequestObj.md +3 -3
  39. package/docs/interfaces/FHIRRequestOptions.md +41 -0
  40. package/docs/interfaces/FHIRResource.md +4 -1
  41. package/docs/interfaces/FetchResponse.md +1 -1
  42. package/docs/interfaces/FetchResponseJson.md +7 -0
  43. package/docs/interfaces/ImportMap.md +1 -1
  44. package/docs/interfaces/Lifecycle.md +4 -4
  45. package/docs/interfaces/Location.md +3 -3
  46. package/docs/interfaces/LoggedInUser.md +11 -11
  47. package/docs/interfaces/LoggedInUserFetchResponse.md +1 -1
  48. package/docs/interfaces/MessageServiceWorkerResult.md +3 -3
  49. package/docs/interfaces/NavigateOptions.md +12 -1
  50. package/docs/interfaces/NewVisitPayload.md +6 -6
  51. package/docs/interfaces/NotificationDescriptor.md +6 -6
  52. package/docs/interfaces/OfflineModeResult.md +3 -3
  53. package/docs/interfaces/OfflinePatientArgs.md +2 -6
  54. package/docs/interfaces/OfflinePatientDataSyncHandler.md +5 -14
  55. package/docs/interfaces/OfflinePatientDataSyncState.md +6 -24
  56. package/docs/interfaces/OfflinePatientDataSyncStore.md +2 -9
  57. package/docs/interfaces/OldExtensionSlotBaseProps.md +65 -0
  58. package/docs/interfaces/OmrsServiceWorkerMessage.md +1 -1
  59. package/docs/interfaces/OnImportMapChangedMessage.md +2 -2
  60. package/docs/interfaces/OnlyThePatient.md +1 -1
  61. package/docs/interfaces/OpenmrsResource.md +2 -2
  62. package/docs/interfaces/PageDefinition.md +9 -25
  63. package/docs/interfaces/PatientWithFullResponse.md +1 -1
  64. package/docs/interfaces/Person.md +3 -3
  65. package/docs/interfaces/Privilege.md +3 -3
  66. package/docs/interfaces/QueueItemDescriptor.md +4 -9
  67. package/docs/interfaces/RegisterDynamicRouteMessage.md +4 -4
  68. package/docs/interfaces/ResourceLoader.md +1 -1
  69. package/docs/interfaces/RetryOptions.md +7 -18
  70. package/docs/interfaces/Role.md +3 -3
  71. package/docs/interfaces/Session.md +7 -7
  72. package/docs/interfaces/SessionLocation.md +3 -3
  73. package/docs/interfaces/ShowNotificationEvent.md +5 -5
  74. package/docs/interfaces/ShowToastEvent.md +4 -4
  75. package/docs/interfaces/SpaConfig.md +5 -19
  76. package/docs/interfaces/SyncItem.md +7 -11
  77. package/docs/interfaces/SyncProcessOptions.md +5 -7
  78. package/docs/interfaces/ToastDescriptor.md +5 -5
  79. package/docs/interfaces/ToastNotificationMeta.md +6 -6
  80. package/docs/interfaces/UserHasAccessProps.md +14 -3
  81. package/docs/interfaces/Visit.md +9 -9
  82. package/docs/interfaces/VisitItem.md +4 -4
  83. package/docs/interfaces/VisitType.md +3 -3
  84. package/jest.config.js +3 -0
  85. package/mock.tsx +9 -15
  86. package/package.json +13 -13
  87. package/src/integration-tests/extension-config.test.tsx +215 -17
  88. package/typedoc.json +1 -1
  89. package/.turbo/turbo-lint.log +0 -2
  90. package/.turbo/turbo-test.log +0 -451
  91. package/.turbo/turbo-typescript.log +0 -2
package/mock.tsx CHANGED
@@ -3,6 +3,7 @@ import type {} from "@openmrs/esm-globals";
3
3
  import createStore, { Store } from "unistore";
4
4
  import { never, of } from "rxjs";
5
5
  import { interpolateUrl } from "@openmrs/esm-config";
6
+ import { SessionStore } from "@openmrs/esm-api";
6
7
  export {
7
8
  parseDate,
8
9
  formatDate,
@@ -10,7 +11,13 @@ export {
10
11
  formatTime,
11
12
  age,
12
13
  } from "@openmrs/esm-utils";
13
- export { interpolateString, interpolateUrl } from "@openmrs/esm-config";
14
+ export {
15
+ interpolateString,
16
+ interpolateUrl,
17
+ validators,
18
+ validator,
19
+ } from "@openmrs/esm-config";
20
+ export { isDesktop } from "@openmrs/esm-react-utils";
14
21
 
15
22
  window.i18next = { ...window.i18next, language: "en" };
16
23
 
@@ -46,7 +53,7 @@ export function getCurrentUser() {
46
53
  return of({ authenticated: false });
47
54
  }
48
55
 
49
- export const mockSessionStore = createGlobalStore("mock-session-store", {
56
+ export const mockSessionStore = createGlobalStore<SessionStore>("mock-session-store", {
50
57
  loaded: false,
51
58
  session: null,
52
59
  });
@@ -149,13 +156,6 @@ export enum Type {
149
156
  UUID = "UUID",
150
157
  }
151
158
 
152
- export const validators = {
153
- isBoolean: jest.fn(),
154
- isString: jest.fn(),
155
- isUuid: jest.fn(),
156
- isObject: jest.fn(),
157
- };
158
-
159
159
  let configSchema = {};
160
160
  function getDefaults(schema) {
161
161
  let tmp = {};
@@ -250,12 +250,6 @@ export const useSession = jest.fn(() => ({
250
250
 
251
251
  export const useLayoutType = jest.fn(() => "desktop");
252
252
 
253
- export const useExtensionSlot = jest.fn(() => ({
254
- extensionSlotModuleName: "",
255
- attachedExtensionSlotName: "",
256
- extensionIdsToRender: [],
257
- }));
258
-
259
253
  export const useExtensionSlotMeta = jest.fn(() => ({}));
260
254
 
261
255
  export const UserHasAccess = jest.fn().mockImplementation((props: any) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-framework",
3
- "version": "4.0.0-pre.0",
3
+ "version": "4.0.1-pre.206",
4
4
  "license": "MPL-2.0",
5
5
  "browser": "dist/openmrs-esm-framework.js",
6
6
  "main": "src/index.ts",
@@ -35,18 +35,18 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@openmrs/esm-api": "^4.0.0-pre.0",
39
- "@openmrs/esm-breadcrumbs": "^4.0.0-pre.0",
40
- "@openmrs/esm-config": "^4.0.0-pre.0",
41
- "@openmrs/esm-error-handling": "^4.0.0-pre.0",
42
- "@openmrs/esm-extensions": "^4.0.0-pre.0",
43
- "@openmrs/esm-globals": "^4.0.0-pre.0",
44
- "@openmrs/esm-offline": "^4.0.0-pre.0",
45
- "@openmrs/esm-react-utils": "^4.0.0-pre.0",
46
- "@openmrs/esm-state": "^4.0.0-pre.0",
47
- "@openmrs/esm-styleguide": "^4.0.0-pre.0",
48
- "@openmrs/esm-utils": "^4.0.0-pre.0",
38
+ "@openmrs/esm-api": "^4.0.1-pre.206",
39
+ "@openmrs/esm-breadcrumbs": "^4.0.1-pre.206",
40
+ "@openmrs/esm-config": "^4.0.1-pre.206",
41
+ "@openmrs/esm-error-handling": "^4.0.1-pre.206",
42
+ "@openmrs/esm-extensions": "^4.0.1-pre.206",
43
+ "@openmrs/esm-globals": "^4.0.1-pre.206",
44
+ "@openmrs/esm-offline": "^4.0.1-pre.206",
45
+ "@openmrs/esm-react-utils": "^4.0.1-pre.206",
46
+ "@openmrs/esm-state": "^4.0.1-pre.206",
47
+ "@openmrs/esm-styleguide": "^4.0.1-pre.206",
48
+ "@openmrs/esm-utils": "^4.0.1-pre.206",
49
49
  "dayjs": "^1.10.7"
50
50
  },
51
- "gitHead": "254a7226212aac82df4434639b2584e24ac240e4"
51
+ "gitHead": "7ac6e01b41238739cdf5d20efdff50062f46f500"
52
52
  }
@@ -20,6 +20,17 @@ import {
20
20
  getExtensionSlotsConfigStore,
21
21
  } from "../../../esm-config/src";
22
22
  import { act, render, screen, waitFor } from "@testing-library/react";
23
+ import { Person } from "@openmrs/esm-api";
24
+ import { mockSessionStore } from "../../mock";
25
+
26
+ jest.mock("@openmrs/esm-api", () => {
27
+ const original = jest.requireActual("@openmrs/esm-api");
28
+ return {
29
+ ...original,
30
+ getSessionStore: () => mockSessionStore,
31
+ refetchCurrentUser: jest.fn(),
32
+ };
33
+ });
23
34
 
24
35
  describe("Interaction between configuration and extension systems", () => {
25
36
  beforeEach(() => {
@@ -52,9 +63,12 @@ describe("Interaction between configuration and extension systems", () => {
52
63
  moduleName: "esm-flintstone",
53
64
  featureName: "The Flintstones",
54
65
  disableTranslations: true,
55
- })(() => <ExtensionSlot data-testid="slot" extensionSlotName="A slot" />);
66
+ })(() => <ExtensionSlot data-testid="slot" name="A slot" />);
67
+
56
68
  render(<App />);
69
+
57
70
  await waitFor(() => expect(screen.getByText("Betty")).toBeInTheDocument());
71
+
58
72
  const slot = screen.getByTestId("slot");
59
73
  const extensions = slot.childNodes;
60
74
  expect(extensions[0]).toHaveTextContent("Betty");
@@ -90,18 +104,15 @@ describe("Interaction between configuration and extension systems", () => {
90
104
  disableTranslations: true,
91
105
  })(() => (
92
106
  <>
93
- <ExtensionSlot
94
- data-testid="flintstone-slot"
95
- extensionSlotName="Flintstone slot"
96
- />
97
- <ExtensionSlot
98
- data-testid="future-slot"
99
- extensionSlotName="Future slot"
100
- />
107
+ <ExtensionSlot data-testid="flintstone-slot" name="Flintstone slot" />
108
+ <ExtensionSlot data-testid="future-slot" name="Future slot" />
101
109
  </>
102
110
  ));
111
+
103
112
  render(<App />);
113
+
104
114
  await screen.findAllByText(/.*Pebbles.*/);
115
+
105
116
  const flintstonePebbles = screen.getByTestId("flintstone-slot");
106
117
  expect(flintstonePebbles).toHaveTextContent(/Pebbles:.*Springfield/);
107
118
  const futurePebbles = screen.getByTestId("future-slot");
@@ -137,14 +148,14 @@ describe("Interaction between configuration and extension systems", () => {
137
148
  disableTranslations: true,
138
149
  })(() => (
139
150
  <>
140
- <ExtensionSlot
141
- data-testid="flintstone-slot"
142
- extensionSlotName="Flintstone slot"
143
- />
151
+ <ExtensionSlot data-testid="flintstone-slot" name="Flintstone slot" />
144
152
  </>
145
153
  ));
154
+
146
155
  render(<App />);
156
+
147
157
  await screen.findAllByText(/.*Dino.*/);
158
+
148
159
  const slot = screen.getByTestId("flintstone-slot");
149
160
  expect(slot.firstChild).toHaveTextContent(/Dino/);
150
161
  expect(slot.lastChild).toHaveTextContent(/Baby Puss/);
@@ -158,9 +169,12 @@ describe("Interaction between configuration and extension systems", () => {
158
169
  moduleName: "esm-slaghoople",
159
170
  featureName: "The Slaghooples",
160
171
  disableTranslations: true,
161
- })(() => <ExtensionSlot data-testid="slot" extensionSlotName="A slot" />);
172
+ })(() => <ExtensionSlot data-testid="slot" name="A slot" />);
173
+
162
174
  render(<App />);
175
+
163
176
  await waitFor(() => expect(screen.getByText("Pearl")).toBeInTheDocument());
177
+
164
178
  act(() => {
165
179
  temporaryConfigStore.setState({
166
180
  config: {
@@ -174,6 +188,7 @@ describe("Interaction between configuration and extension systems", () => {
174
188
  },
175
189
  });
176
190
  });
191
+
177
192
  expect(screen.queryByText("Pearl")).not.toBeInTheDocument();
178
193
  });
179
194
 
@@ -185,12 +200,16 @@ describe("Interaction between configuration and extension systems", () => {
185
200
  moduleName: "esm-quarry",
186
201
  featureName: "The Flintstones",
187
202
  disableTranslations: true,
188
- })(() => <ExtensionSlot data-testid="slot" extensionSlotName="A slot" />);
203
+ })(() => <ExtensionSlot data-testid="slot" name="A slot" />);
204
+
189
205
  render(<App />);
206
+
190
207
  await waitFor(() =>
191
208
  expect(screen.getByText(/Mr. Slate/)).toBeInTheDocument()
192
209
  );
210
+
193
211
  expect(screen.getByTestId("slot")).toHaveTextContent(/green/);
212
+
194
213
  act(() => {
195
214
  temporaryConfigStore.setState({
196
215
  config: {
@@ -206,6 +225,7 @@ describe("Interaction between configuration and extension systems", () => {
206
225
  },
207
226
  });
208
227
  });
228
+
209
229
  expect(screen.queryByText("green")).not.toBeInTheDocument();
210
230
  waitFor(() =>
211
231
  expect(screen.getByTestId("slot")).toHaveTextContent(/black/)
@@ -220,7 +240,7 @@ describe("Interaction between configuration and extension systems", () => {
220
240
  const store = useExtensionStore();
221
241
  return (
222
242
  <div>
223
- <ExtensionSlot data-testid="slot" extensionSlotName="A slot" />
243
+ <ExtensionSlot data-testid="slot" name="A slot" />
224
244
  {store.slots["A slot"].assignedExtensions.map((e) => (
225
245
  <div key={e.name}>{JSON.stringify(e.config)}</div>
226
246
  ))}
@@ -232,9 +252,13 @@ describe("Interaction between configuration and extension systems", () => {
232
252
  featureName: "The Flintstones",
233
253
  disableTranslations: true,
234
254
  })(RootComponent);
255
+
235
256
  render(<App />);
257
+
236
258
  await waitFor(() => expect(screen.getByTestId(/slot/)).toBeInTheDocument());
259
+
237
260
  expect(screen.getByText(/clothes/)).toHaveTextContent(/leopard/);
261
+
238
262
  act(() => {
239
263
  temporaryConfigStore.setState({
240
264
  config: {
@@ -250,14 +274,187 @@ describe("Interaction between configuration and extension systems", () => {
250
274
  },
251
275
  });
252
276
  });
277
+
253
278
  expect(screen.getByText(/clothes/)).toHaveTextContent(/tiger/);
254
279
  });
280
+
281
+ test("should not show extension when user lacks configured privilege", async () => {
282
+ mockSessionStore.setState({
283
+ loaded: true,
284
+ session: {
285
+ authenticated: true,
286
+ sessionId: "1",
287
+ user: {
288
+ uuid: "1",
289
+ display: "Non-Admin",
290
+ username: "nonadmin",
291
+ systemId: "nonadmin",
292
+ userProperties: {},
293
+ person: {} as Person,
294
+ privileges: [],
295
+ roles: [],
296
+ retired: false,
297
+ locale: "en",
298
+ allowedLocales: ["en"],
299
+ },
300
+ },
301
+ });
302
+
303
+ registerSimpleExtension("Schmoo", "esm-bedrock", true);
304
+ registerSimpleExtension("Wilma", "esm-flintstones", true);
305
+ attach("A slot", "Schmoo");
306
+ attach("A slot", "Wilma");
307
+ defineConfigSchema("esm-bedrock", {});
308
+ defineConfigSchema("esm-flintstones", {});
309
+ provide({
310
+ "esm-bedrock": {
311
+ "Display conditions": {
312
+ privileges: ["Yabadabadoo!"],
313
+ },
314
+ },
315
+ });
316
+ provide({
317
+ "esm-flintstones": {},
318
+ });
319
+
320
+ function RootComponent() {
321
+ return (
322
+ <div>
323
+ <ExtensionSlot data-testid="slot" name="A slot" />
324
+ </div>
325
+ );
326
+ }
327
+ const App = openmrsComponentDecorator({
328
+ moduleName: "esm-bedrock",
329
+ featureName: "Bedrock",
330
+ disableTranslations: true,
331
+ })(RootComponent);
332
+
333
+ render(<App />);
334
+
335
+ await waitFor(() => expect(screen.getByTestId(/slot/)).toBeInTheDocument());
336
+ expect(screen.getByTestId("slot").firstChild).toHaveAttribute(
337
+ "data-extension-id",
338
+ "Wilma"
339
+ );
340
+ expect(screen.queryAllByText(/\bSchmoo\b/)).toHaveLength(0);
341
+ });
342
+
343
+ test("should show extension when user has configured privilege", async () => {
344
+ mockSessionStore.setState({
345
+ loaded: true,
346
+ session: {
347
+ authenticated: true,
348
+ sessionId: "1",
349
+ user: {
350
+ uuid: "1",
351
+ display: "Non-Admin",
352
+ username: "nonadmin",
353
+ systemId: "nonadmin",
354
+ userProperties: {},
355
+ person: {} as Person,
356
+ privileges: [{ uuid: "1", display: "Yabadabadoo!" }],
357
+ roles: [],
358
+ retired: false,
359
+ locale: "en",
360
+ allowedLocales: ["en"],
361
+ },
362
+ },
363
+ });
364
+
365
+ registerSimpleExtension("Schmoo", "esm-bedrock", true);
366
+ attach("A slot", "Schmoo");
367
+ defineConfigSchema("esm-bedrock", {});
368
+ provide({
369
+ "esm-bedrock": {
370
+ "Display conditions": {
371
+ privileges: ["Yabadabadoo!"],
372
+ },
373
+ },
374
+ });
375
+
376
+ function RootComponent() {
377
+ return (
378
+ <div>
379
+ <ExtensionSlot data-testid="slot" name="A slot" />
380
+ </div>
381
+ );
382
+ }
383
+ const App = openmrsComponentDecorator({
384
+ moduleName: "esm-bedrock",
385
+ featureName: "Bedrock",
386
+ disableTranslations: true,
387
+ })(RootComponent);
388
+
389
+ render(<App />);
390
+
391
+ await waitFor(() => expect(screen.getByTestId(/slot/)).toBeInTheDocument());
392
+ expect(screen.getByTestId("slot").firstChild).toHaveAttribute(
393
+ "data-extension-id",
394
+ "Schmoo"
395
+ );
396
+ });
397
+
398
+ test("should only show extensions users have default privilege for", async () => {
399
+ mockSessionStore.setState({
400
+ loaded: true,
401
+ session: {
402
+ authenticated: true,
403
+ sessionId: "1",
404
+ user: {
405
+ uuid: "1",
406
+ display: "Non-Admin",
407
+ username: "nonadmin",
408
+ systemId: "nonadmin",
409
+ userProperties: {},
410
+ person: {} as Person,
411
+ privileges: [{ uuid: "1", display: "YOWTCH!" }],
412
+ roles: [],
413
+ retired: false,
414
+ locale: "en",
415
+ allowedLocales: ["en"],
416
+ },
417
+ },
418
+ });
419
+
420
+ registerSimpleExtension("Schmoo", "esm-bedrock", true, "Yabadabadoo!");
421
+ registerSimpleExtension("Wilma", "esm-flintstones", true, "YOWTCH!");
422
+ attach("A slot", "Schmoo");
423
+ attach("A slot", "Wilma");
424
+ defineConfigSchema("esm-bedrock", {});
425
+ defineConfigSchema("esm-flintstones", {});
426
+ provide({ "esm-bedrock": {} });
427
+ provide({ "esm-flintstones": {} });
428
+
429
+ function RootComponent() {
430
+ return (
431
+ <div>
432
+ <ExtensionSlot data-testid="slot" name="A slot" />
433
+ </div>
434
+ );
435
+ }
436
+ const App = openmrsComponentDecorator({
437
+ moduleName: "esm-bedrock",
438
+ featureName: "Bedrock",
439
+ disableTranslations: true,
440
+ })(RootComponent);
441
+
442
+ render(<App />);
443
+
444
+ await waitFor(() => expect(screen.getByTestId(/slot/)).toBeInTheDocument());
445
+ expect(screen.getByTestId("slot").firstChild).toHaveAttribute(
446
+ "data-extension-id",
447
+ "Wilma"
448
+ );
449
+ expect(screen.queryAllByText(/\bSchmoo\b/)).toHaveLength(0);
450
+ });
255
451
  });
256
452
 
257
453
  function registerSimpleExtension(
258
454
  name: string,
259
455
  moduleName: string,
260
- takesConfig: boolean = false
456
+ takesConfig: boolean = false,
457
+ privileges?: string | string[]
261
458
  ) {
262
459
  const SimpleComponent = () => <div>{name}</div>;
263
460
  const ConfigurableComponent = () => {
@@ -280,5 +477,6 @@ function registerSimpleExtension(
280
477
  }
281
478
  ),
282
479
  meta: {},
480
+ privileges,
283
481
  });
284
482
  }
package/typedoc.json CHANGED
@@ -2,6 +2,6 @@
2
2
  "out": "docs",
3
3
  "readme": "none",
4
4
  "excludeInternal": true,
5
- "gitRevision": "master",
5
+ "gitRevision": "main",
6
6
  "entryDocument": "API.md"
7
7
  }
@@ -1,2 +0,0 @@
1
- @openmrs/esm-framework:lint: cache hit, replaying output 68fa5c864bd166d0
2
- @openmrs/esm-framework:lint: $ eslint src --ext ts,tsx