@uxland/primary-shell 4.3.1 → 5.0.0
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/index.js +1183 -1237
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +117 -125
- package/dist/index.umd.cjs.map +1 -1
- package/dist/primary/shell/src/UI/components/primaria-shell/primaria-shell.d.ts +3 -0
- package/dist/primary/shell/src/UI/components/quick-actions-menu/quick-actions-menu.d.ts +1 -0
- package/dist/primary/shell/src/UI/shared-components/index.d.ts +0 -1
- package/dist/primary/shell/src/api/api.d.ts +4 -2
- package/dist/primary/shell/src/api/http-client/http-client.d.ts +7 -1
- package/dist/primary/shell/src/api/interaction-service/confirmation-message.d.ts +3 -0
- package/dist/primary/shell/src/api/interaction-service/index.d.ts +1 -0
- package/dist/primary/shell/src/api/interaction-service/interaction-service-impl.d.ts +7 -0
- package/dist/primary/shell/src/api/interaction-service/interaction-service.d.ts +32 -0
- package/dist/primary/shell/src/api/notification-service/notification-service.d.ts +6 -0
- package/dist/primary/shell/src/api/notification-service/notification.service-impl.d.ts +9 -0
- package/dist/primary/shell/src/api/plugin-busy-manager/plugin-busy-list/component.d.ts +2 -4
- package/dist/primary/shell/src/api/region-manager/region-manager.d.ts +1 -0
- package/dist/primary/shell/src/events.d.ts +1 -0
- package/dist/primary/shell/src/features/bootstrapper.d.ts +1 -1
- package/dist/primary/shell/src/index.d.ts +1 -2
- package/dist/primary/shell/src/internal-plugins/activity-history/activity-history-item/export-to-pdf/export-pdf-modal/export-pdf-modal.d.ts +1 -5
- package/dist/primary/shell/src/internal-plugins/activity-history/localization.d.ts +0 -1
- package/dist/primary/shell/src/locales.d.ts +4 -0
- package/package.json +4 -1
- package/src/UI/components/primaria-shell/primaria-shell.ts +24 -7
- package/src/UI/components/quick-actions-menu/quick-actions-menu.ts +13 -3
- package/src/UI/shared-components/index.ts +0 -1
- package/src/api/api.ts +11 -8
- package/src/api/http-client/http-client.test.ts +188 -76
- package/src/api/http-client/http-client.ts +62 -11
- package/src/api/interaction-service/confirmation-message.tsx +5 -0
- package/src/api/interaction-service/index.ts +1 -0
- package/src/api/interaction-service/interaction-service-impl.tsx +225 -0
- package/src/api/interaction-service/interaction-service.ts +46 -0
- package/src/api/notification-service/notification-service.ts +6 -0
- package/src/api/notification-service/notification.service-impl.ts +45 -0
- package/src/api/plugin-busy-manager/plugin-busy-list/component.ts +3 -4
- package/src/api/plugin-busy-manager/plugin-busy-list/template.ts +1 -1
- package/src/api/region-manager/region-manager.ts +5 -0
- package/src/disposer.ts +1 -1
- package/src/events.ts +1 -0
- package/src/features/bootstrapper.ts +6 -3
- package/src/features/exit/handler.ts +8 -11
- package/src/features/get-user-info/handler.ts +3 -4
- package/src/index.ts +1 -2
- package/src/internal-plugins/activity-history/activity-history-item/export-to-pdf/export-pdf-modal/export-pdf-modal.ts +1 -10
- package/src/internal-plugins/activity-history/activity-history-item/export-to-pdf/export-pdf-modal/template.ts +0 -7
- package/src/internal-plugins/activity-history/activity-history-item/export-to-pdf/handler.ts +8 -8
- package/src/internal-plugins/activity-history/activity-history-item/list/UI/main-view/template.ts +1 -1
- package/src/internal-plugins/activity-history/activity-history-item/search/handler.ts +5 -3
- package/src/internal-plugins/activity-history/localization.ts +0 -1
- package/src/locales.ts +5 -0
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/components/dialog-component.d.ts +0 -19
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/components/notifier-component.d.ts +0 -12
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/confirm-mixin.d.ts +0 -11
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/confirm.d.ts +0 -3
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/index.d.ts +0 -5
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/notify.d.ts +0 -4
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/open-dialog.d.ts +0 -3
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/shared.d.ts +0 -3
- package/dist/primary/shell/src/UI/shared-components/primaria-interaction/typings.d.ts +0 -40
- package/dist/primary/shell/src/api/interaction-manager/interaction.d.ts +0 -9
- package/src/UI/shared-components/primaria-interaction/components/dialog-component-styles.css +0 -104
- package/src/UI/shared-components/primaria-interaction/components/dialog-component.ts +0 -138
- package/src/UI/shared-components/primaria-interaction/components/notifier-component-styles.css +0 -136
- package/src/UI/shared-components/primaria-interaction/components/notifier-component.ts +0 -69
- package/src/UI/shared-components/primaria-interaction/confirm-mixin.ts +0 -35
- package/src/UI/shared-components/primaria-interaction/confirm.ts +0 -9
- package/src/UI/shared-components/primaria-interaction/index.ts +0 -5
- package/src/UI/shared-components/primaria-interaction/notify.ts +0 -153
- package/src/UI/shared-components/primaria-interaction/open-dialog.ts +0 -8
- package/src/UI/shared-components/primaria-interaction/shared.ts +0 -29
- package/src/UI/shared-components/primaria-interaction/typings.ts +0 -46
- package/src/api/interaction-manager/interaction.ts +0 -26
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import axios, { AxiosInstance } from "axios";
|
|
2
2
|
import AxiosMockAdapter from "axios-mock-adapter";
|
|
3
|
-
import {
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
4
|
import { TokenManager, createTokenManager } from "../token-manager/token-manager";
|
|
5
5
|
import { createAxiosInstance } from "./http-client";
|
|
6
6
|
import { shellEvents } from "../../events";
|
|
7
7
|
import { createBroker } from "../broker/factory";
|
|
8
8
|
|
|
9
|
-
const access_token =
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const access_token =
|
|
10
|
+
"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJidFZxNnRMWGpmcXdzbm5MR2FXMXdhdU9McDNiTmY4bWZ3Rm1SZ0lBS2VJIn0.eyJleHAiOjE3NDI5MDkxNjMsImlhdCI6MTc0MjkwODI2MywianRpIjoiODRlMWEwYjYtOGNmYS00NzQ3LTk0MDItMjVkM2FlMzM3N2QxIiwiaXNzIjoiaHR0cHM6Ly9wcmVwcm9kdWNjaW8ucGRzLmhlcy5jYXRzYWx1dC5nZW5jYXQuY2F0L2F1dGgvcmVhbG1zL0hFUyIsInN1YiI6Ijk1OGUyZWQ5LTJkNmUtNDZjOC1hOTE5LTU5MDQ0ZTYwMzVjMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImV0Yy1jY2YtcHJlIiwic2Vzc2lvbl9zdGF0ZSI6ImVhNzUwMDg4LWI1NjctNDU4ZC1iOWY5LWQ0OTdjMzlkN2ZkMyIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLWhlcyIsIlJPTEVfSEVTX0VUQyIsIlJPTEVfSEVTX0xBTkRJTkciXX0sInNjb3BlIjoiIiwic2lkIjoiZWE3NTAwODgtYjU2Ny00NThkLWI5ZjktZDQ5N2MzOWQ3ZmQzIiwiY2xpZW50SG9zdCI6IjEwLjUzLjI1NC4xNTAiLCJhY2Nlc3NfcnVsZXMiOnt9LCJhY2Nlc3NfaW5mbyI6eyJtb2R1bGVfY29kZSI6IkEwMDEiLCJyb2xlX3R5cGUiOiJOT1JNIiwidHJhY2VfdXNlcl9pZCI6IlVzZXJfSUQiLCJjZW50ZXJfdHlwZSI6IkUiLCJtcGlfcGF0aWVudF9pZCI6IjVlYzc0YzdiLTVhYTUtNGE4NC1iM2I0LWYwMmVkZGZkZjZkYyIsInVwX2NvZGUiOiIwNzczMyIsInRyYWNlX3VzZXJfZ2l2ZW5fbmFtZSI6IkdpdmVuIE5hbWUiLCJ0cmFjZV91c2VyX2ZhbWlseV9uYW1lIjoiRmFtaWx5IE5hbWUiLCJ1c2VyX3R5cGUiOiJBRE0iLCJjZW50ZXJfY29kZSI6IkUwODU4Njk2MyIsInByb2Zlc3Npb25hbF9jYXRlZ29yeSI6IjMwOTM0MzAwNiIsInNlcnZpY2VfY29kZSI6IjVTMDg5IiwiZXBfY29kZSI6IjAyMDgiLCJpZGVudGlmaWVyIjpbeyJ0eXBlIjoiRE5JIiwidmFsdWUiOiI3MzI4ODIxOUEifSx7InR5cGUiOiJOVU1DT0wiLCJ2YWx1ZSI6IjIifV0sImFsdF9pZGVudGlmaWVyIjpbeyJ0eXBlIjoiTVBJIiwidmFsdWUiOiIwNjIxY2Y3ZC03ZDYzLTQ5ZWMtODAwNi04YzA1NjkyZWQzNzcifV19LCJjbGllbnRBZGRyZXNzIjoiMTAuNTMuMjU0LjE1MCIsImNsaWVudF9pZCI6ImV0Yy1jY2YtcHJlIn0.CgYL3zXbUHHiE7ZtrcxvlDHB3dbY_eI8TsL-0mBOy-JedSZZaGT_JS8Odm_eIo1drWZSnEaNblFZUPE56sCEPH6RYSqtyK0eYwy_aKoprKoRuDjEy2-VfmOJi5gY9wpYnAYpVtuTbncVirQIV9SIZ9st2d7LlfcM_88Yn8NJNTDcUk7ETw7Zy_728X2wjL_UeHT7yuzo3Y-Xm_389Og7UMyYGGrs104CHQNrzIMXiklkRZr4dqjqWU61Csrb8OBI6jCUAbBqgS8vPuUzPUghQXstr-aNn3zicy-Zw5e6RqCmSQXg56aTKx9QIOrQuX-az-urPnqvtWdloQrQJLQGSg";
|
|
11
|
+
const refresh_token =
|
|
12
|
+
"eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIwMjUzZGM1MC1hY2FmLTQ5ZDctYTYzNi0xN2NkMTlmOWEwOTAifQ.eyJleHAiOjE3NDI5MTE4NjMsImlhdCI6MTc0MjkwODI2MywianRpIjoiZjA4MzA1MDktMTA0My00ODI1LTk5YTItOTg1YmNjOGI4MmJmIiwiaXNzIjoiaHR0cHM6Ly9wcmVwcm9kdWNjaW8ucGRzLmhlcy5jYXRzYWx1dC5nZW5jYXQuY2F0L2F1dGgvcmVhbG1zL0hFUyIsImF1ZCI6Imh0dHBzOi8vcHJlcHJvZHVjY2lvLnBkcy5oZXMuY2F0c2FsdXQuZ2VuY2F0LmNhdC9hdXRoL3JlYWxtcy9IRVMiLCJzdWIiOiI5NThlMmVkOS0yZDZlLTQ2YzgtYTkxOS01OTA0NGU2MDM1YzIiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoiZXRjLWNjZi1wcmUiLCJzZXNzaW9uX3N0YXRlIjoiZWE3NTAwODgtYjU2Ny00NThkLWI5ZjktZDQ5N2MzOWQ3ZmQzIiwic2NvcGUiOiIiLCJzaWQiOiJlYTc1MDA4OC1iNTY3LTQ1OGQtYjlmOS1kNDk3YzM5ZDdmZDMifQ.I8u83nfdxbjRrS7dC1k8_f9oBKmSD_Xu4iAxlFqcA3QdHi-L_yY63ENU1LTehh8-2d51f__nv58zPb799hNGhg";
|
|
13
|
+
const newAccessToken =
|
|
14
|
+
"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJidFZxNnRMWGpmcXdzbm5MR2FXMXdhdU9McDNiTmY4bWZ3Rm1SZ0lBS2VJIn0.eyJleHAiOjE3NDI5MTAzNzgsImlhdCI6MTc0MjkwOTQ3OCwianRpIjoiMTg4OTE3ZDYtNmM0OS00YWY0LTlhYjItZjEzYTM4MGY5OTgyIiwiaXNzIjoiaHR0cHM6Ly9wcmVwcm9kdWNjaW8ucGRzLmhlcy5jYXRzYWx1dC5nZW5jYXQuY2F0L2F1dGgvcmVhbG1zL0hFUyIsInN1YiI6Ijk1OGUyZWQ5LTJkNmUtNDZjOC1hOTE5LTU5MDQ0ZTYwMzVjMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImV0Yy1jY2YtcHJlIiwic2Vzc2lvbl9zdGF0ZSI6IjY5ODdhMzExLWM1NzQtNDc1Ni1hMzY0LWY1ZjQzZmViZjNhYiIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLWhlcyIsIlJPTEVfSEVTX0VUQyIsIlJPTEVfSEVTX0xBTkRJTkciXX0sInNjb3BlIjoiIiwic2lkIjoiNjk4N2EzMTEtYzU3NC00NzU2LWEzNjQtZjVmNDNmZWJmM2FiIiwiY2xpZW50SG9zdCI6IjEwLjUzLjI1NC4xNTAiLCJhY2Nlc3NfcnVsZXMiOnt9LCJhY2Nlc3NfaW5mbyI6eyJtb2R1bGVfY29kZSI6IkEwMDEiLCJyb2xlX3R5cGUiOiJOT1JNIiwidHJhY2VfdXNlcl9pZCI6IlVzZXJfSUQiLCJjZW50ZXJfdHlwZSI6IkUiLCJtcGlfcGF0aWVudF9pZCI6IjVlYzc0YzdiLTVhYTUtNGE4NC1iM2I0LWYwMmVkZGZkZjZkYyIsInVwX2NvZGUiOiIwNzczMyIsInRyYWNlX3VzZXJfZ2l2ZW5fbmFtZSI6IkdpdmVuIE5hbWUiLCJ0cmFjZV91c2VyX2ZhbWlseV9uYW1lIjoiRmFtaWx5IE5hbWUiLCJ1c2VyX3R5cGUiOiJBRE0iLCJjZW50ZXJfY29kZSI6IkUwODU4Njk2MyIsInByb2Zlc3Npb25hbF9jYXRlZ29yeSI6IjMwOTM0MzAwNiIsInNlcnZpY2VfY29kZSI6IjVTMDg5IiwiZXBfY29kZSI6IjAyMDgiLCJpZGVudGlmaWVyIjpbeyJ0eXBlIjoiRE5JIiwidmFsdWUiOiI3MzI4ODIxOUEifSx7InR5cGUiOiJOVU1DT0wiLCJ2YWx1ZSI6IjIifV0sImFsdF9pZGVudGlmaWVyIjpbeyJ0eXBlIjoiTVBJIiwidmFsdWUiOiIwNjIxY2Y3ZC03ZDYzLTQ5ZWMtODAwNi04YzA1NjkyZWQzNzcifV19LCJjbGllbnRBZGRyZXNzIjoiMTAuNTMuMjU0LjE1MCIsImNsaWVudF9pZCI6ImV0Yy1jY2YtcHJlIn0.zPxoN5d8_uxdbxeH7ly9sQdlnDxNp8_eWDzNSzjzkUPsRVkLxgjQw_WcjZfns-LNgGr0FToS6uSDIC7uj2hPpKqD7HPWbI6UPa7g-43Jf9rh-KSOXEHJWhlASi2w0n3xQHFSxHDYBwhyXlvWQ_Tr1Vh37MroWmEL84fdwqhcfZHmD9Ek52EuRRrB-XkymCmN1ZvO2GPU04LbBvQxLVzdAaKRzr1cUqHTnsEdgRduyKShPcyth01L_X7m128SIwjJsa1lYxFE_DbSDKz8dPTsxoS1DgwRxeArrkMlIdTHyxmDRezZUGhamyLuWpXLDXJCFfrTUB8-j_JnVlILHeR6O";
|
|
12
15
|
|
|
13
16
|
describe("HTTP Client", () => {
|
|
14
|
-
|
|
15
17
|
let broker = createBroker();
|
|
16
18
|
let tokenManager: TokenManager;
|
|
17
19
|
let axiosInstance: AxiosInstance;
|
|
@@ -19,91 +21,201 @@ describe("HTTP Client", () => {
|
|
|
19
21
|
|
|
20
22
|
beforeEach(() => {
|
|
21
23
|
vi.restoreAllMocks(); // Reset all spies before each test
|
|
22
|
-
vi.spyOn(window,
|
|
23
|
-
search: `?access_token=${access_token}&refresh_token=${refresh_token}
|
|
24
|
+
vi.spyOn(window, "location", "get").mockReturnValue({
|
|
25
|
+
search: `?access_token=${access_token}&refresh_token=${refresh_token}`,
|
|
24
26
|
} as unknown as Location);
|
|
25
|
-
|
|
26
|
-
tokenManager = createTokenManager();
|
|
27
|
-
axiosInstance = createAxiosInstance(tokenManager, broker);
|
|
28
|
-
axiosMockInstance = new AxiosMockAdapter(axiosInstance);
|
|
29
|
-
axiosMockInstance.reset();
|
|
30
27
|
});
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
expect(axiosMockInstance.history.get?.length).toBe(1);
|
|
40
|
-
// @ts-ignore
|
|
41
|
-
expect(axiosMockInstance.history.get?.[0]?.headers.Authorization).toBe(
|
|
42
|
-
`Bearer ${access_token}`,
|
|
43
|
-
);
|
|
44
|
-
});
|
|
29
|
+
describe("Without validateMpid", () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
tokenManager = createTokenManager();
|
|
32
|
+
axiosInstance = createAxiosInstance(tokenManager, broker);
|
|
33
|
+
axiosMockInstance = new AxiosMockAdapter(axiosInstance);
|
|
34
|
+
axiosMockInstance.reset();
|
|
35
|
+
});
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.
|
|
50
|
-
|
|
51
|
-
.
|
|
52
|
-
.
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
access_token: "new-auth-token",
|
|
59
|
-
refresh_token: "new-refresh-token"
|
|
60
|
-
}
|
|
37
|
+
it("should make a request with header", async () => {
|
|
38
|
+
axiosMockInstance.onGet("/api/clinical-course").reply(200, "success");
|
|
39
|
+
// Perform the request
|
|
40
|
+
const response = await axiosInstance.get("/api/clinical-course");
|
|
41
|
+
// Assertions
|
|
42
|
+
expect(response.status).toBe(200);
|
|
43
|
+
expect(response.data).toBe("success");
|
|
44
|
+
expect(axiosMockInstance.history.get?.length).toBe(1);
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
expect(axiosMockInstance.history.get?.[0]?.headers.Authorization).toBe(
|
|
47
|
+
`Bearer ${access_token}`,
|
|
48
|
+
);
|
|
61
49
|
});
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
51
|
+
it("should retry request with new token if failed with 401 after token refresh, and requests after that have new token", async () => {
|
|
52
|
+
axiosMockInstance
|
|
53
|
+
.onGet("/api/clinical-course")
|
|
54
|
+
.replyOnce(401, "Unauthorized")
|
|
55
|
+
.onGet("/api/clinical-course")
|
|
56
|
+
.replyOnce(200, "success")
|
|
57
|
+
.onGet("/api/clinical-course/2")
|
|
58
|
+
.replyOnce(200, "success");
|
|
59
|
+
|
|
60
|
+
vi.spyOn(axios, "post").mockResolvedValueOnce({
|
|
61
|
+
data: {
|
|
62
|
+
access_token: newAccessToken,
|
|
63
|
+
refresh_token: "new-refresh-token",
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Perform the request
|
|
68
|
+
const response = await axiosInstance.get("/api/clinical-course");
|
|
69
|
+
const secondResponse = await axiosInstance.get("/api/clinical-course/2");
|
|
70
|
+
// Assertions
|
|
71
|
+
expect(response.status).toBe(200);
|
|
72
|
+
expect(response.data).toBe("success");
|
|
73
|
+
expect(axiosMockInstance.history.get?.length).toBe(3); // 3 Calls 2 for the first request (request and retry), 1 for the second request
|
|
74
|
+
expect(axiosMockInstance.history.get?.[1]?.headers?.Authorization).toBe(
|
|
75
|
+
"Bearer " + newAccessToken,
|
|
76
|
+
);
|
|
77
|
+
expect(axiosMockInstance.history.get?.[2]?.headers?.Authorization).toBe(
|
|
78
|
+
"Bearer " + newAccessToken,
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should fail request if token refresh fails and publish an event", async () => {
|
|
83
|
+
vi.spyOn(axios, "post").mockRejectedValueOnce({
|
|
84
|
+
response: { status: 400, statusText: "Bad Request" },
|
|
85
|
+
});
|
|
86
|
+
const brokerSpy = vi.spyOn(broker, "publish");
|
|
87
|
+
axiosMockInstance.onGet("/api/clinical-course").replyOnce(401, "Unauthorized");
|
|
88
|
+
|
|
89
|
+
await expect(axiosInstance.get("/api/clinical-course")).rejects.toThrow(
|
|
90
|
+
"Request failed with status code 401",
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expect(axiosMockInstance.history.get?.length).toBe(1); // No retry happened
|
|
94
|
+
expect(brokerSpy).toHaveBeenCalledWith(shellEvents.refreshTokenFailed, expect.any(Object));
|
|
95
|
+
expect(brokerSpy).toHaveBeenCalledWith(shellEvents.refreshTokenFailed, {
|
|
96
|
+
request: expect.objectContaining({ url: "/api/clinical-course" }),
|
|
97
|
+
});
|
|
98
|
+
});
|
|
78
99
|
|
|
100
|
+
it("should fail request with error != 401 and should not retry", async () => {
|
|
101
|
+
const refreshTokenSpy = vi.spyOn(tokenManager, "refreshToken");
|
|
102
|
+
const brokerSpy = vi.spyOn(broker, "publish");
|
|
103
|
+
axiosMockInstance.onGet("/api/clinical-course").replyOnce(500, "Internal Server Error");
|
|
104
|
+
await expect(axiosInstance.get("/api/clinical-course")).rejects.toMatchObject({
|
|
105
|
+
response: { status: 500 },
|
|
106
|
+
});
|
|
107
|
+
expect(axiosMockInstance.history.get?.length).toBe(1);
|
|
108
|
+
expect(refreshTokenSpy).not.toHaveBeenCalled();
|
|
109
|
+
expect(brokerSpy).not.toHaveBeenCalled();
|
|
110
|
+
});
|
|
79
111
|
});
|
|
80
112
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
113
|
+
describe.skip("With validateMpid", () => {
|
|
114
|
+
const validTokenHeaders = { "x-catsalut-mpid": "5ec74c7b-5aa5-4a84-b3b4-f02eddfdf6dc" };
|
|
115
|
+
beforeEach(() => {
|
|
116
|
+
tokenManager = createTokenManager();
|
|
117
|
+
axiosInstance = createAxiosInstance(tokenManager, broker, true);
|
|
118
|
+
axiosMockInstance = new AxiosMockAdapter(axiosInstance);
|
|
119
|
+
axiosMockInstance.reset();
|
|
84
120
|
});
|
|
85
|
-
const brokerSpy = vi.spyOn(broker, "publish")
|
|
86
|
-
axiosMockInstance.onGet("/api/clinical-course").replyOnce(401, "Unauthorized");
|
|
87
121
|
|
|
88
|
-
|
|
122
|
+
it("should throw error if mpid header is missing without sending broker event", async () => {
|
|
123
|
+
axiosMockInstance.onGet("/api/clinical-course").reply(200, "success");
|
|
124
|
+
const brokerSpy = vi.spyOn(broker, "publish");
|
|
89
125
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
126
|
+
// Perform the request
|
|
127
|
+
await expect(axiosInstance.get("/api/clinical-course")).rejects.toThrow(
|
|
128
|
+
"Mpid header is missing",
|
|
129
|
+
);
|
|
130
|
+
expect(brokerSpy).not.toHaveBeenCalled();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should throw error if mpid header value is invalid and send broker event ", async () => {
|
|
134
|
+
axiosMockInstance.onGet("/api/clinical-course").reply(200, "success", {
|
|
135
|
+
"x-catsalut-mpid": "invalid-mpid",
|
|
136
|
+
});
|
|
137
|
+
const brokerSpy = vi.spyOn(broker, "publish");
|
|
138
|
+
// Perform the request
|
|
139
|
+
await expect(axiosInstance.get("/api/clinical-course")).rejects.toThrow(
|
|
140
|
+
"Mpid header value is invalid",
|
|
141
|
+
);
|
|
142
|
+
expect(brokerSpy).toHaveBeenCalledWith(shellEvents.mpidHeaderInvalid, expect.any(Object));
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should make a request with header and respond succesful if x-catsalut-mpid has valid value ", async () => {
|
|
146
|
+
axiosMockInstance.onGet("/api/clinical-course").reply(200, "success", validTokenHeaders);
|
|
147
|
+
// Perform the request
|
|
148
|
+
const response = await axiosInstance.get("/api/clinical-course");
|
|
149
|
+
// Assertions
|
|
150
|
+
expect(response.status).toBe(200);
|
|
151
|
+
expect(response.data).toBe("success");
|
|
152
|
+
expect(axiosMockInstance.history.get?.length).toBe(1);
|
|
153
|
+
// @ts-ignore
|
|
154
|
+
expect(axiosMockInstance.history.get?.[0]?.headers.Authorization).toBe(
|
|
155
|
+
`Bearer ${access_token}`,
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should retry request with new token if failed with 401 after token refresh, and requests after that have new token", async () => {
|
|
160
|
+
axiosMockInstance
|
|
161
|
+
.onGet("/api/clinical-course")
|
|
162
|
+
.replyOnce(401, "Unauthorized")
|
|
163
|
+
.onGet("/api/clinical-course")
|
|
164
|
+
.replyOnce(200, "success", validTokenHeaders)
|
|
165
|
+
.onGet("/api/clinical-course/2")
|
|
166
|
+
.replyOnce(200, "success", validTokenHeaders);
|
|
167
|
+
|
|
168
|
+
vi.spyOn(axios, "post").mockResolvedValueOnce({
|
|
169
|
+
data: {
|
|
170
|
+
access_token: newAccessToken,
|
|
171
|
+
refresh_token: "new-refresh-token",
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Perform the request
|
|
176
|
+
const response = await axiosInstance.get("/api/clinical-course");
|
|
177
|
+
const secondResponse = await axiosInstance.get("/api/clinical-course/2");
|
|
178
|
+
|
|
179
|
+
// Assertions
|
|
180
|
+
expect(response.status).toBe(200);
|
|
181
|
+
expect(response.data).toBe("success");
|
|
182
|
+
expect(axiosMockInstance.history.get?.length).toBe(3); // 3 Calls 2 for the first request (request and retry), 1 for the second request
|
|
183
|
+
expect(axiosMockInstance.history.get?.[1]?.headers?.Authorization).toBe(
|
|
184
|
+
"Bearer " + newAccessToken,
|
|
185
|
+
);
|
|
186
|
+
expect(axiosMockInstance.history.get?.[2]?.headers?.Authorization).toBe(
|
|
187
|
+
"Bearer " + newAccessToken,
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should fail request if token refresh fails and publish an event", async () => {
|
|
192
|
+
vi.spyOn(axios, "post").mockRejectedValueOnce({
|
|
193
|
+
response: { status: 400, statusText: "Bad Request" },
|
|
194
|
+
});
|
|
195
|
+
const brokerSpy = vi.spyOn(broker, "publish");
|
|
196
|
+
axiosMockInstance.onGet("/api/clinical-course").replyOnce(401, "Unauthorized");
|
|
197
|
+
|
|
198
|
+
await expect(axiosInstance.get("/api/clinical-course")).rejects.toThrow(
|
|
199
|
+
"Request failed with status code 401",
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
expect(axiosMockInstance.history.get?.length).toBe(1); // No retry happened
|
|
203
|
+
expect(brokerSpy).toHaveBeenCalledWith(shellEvents.refreshTokenFailed, expect.any(Object));
|
|
204
|
+
expect(brokerSpy).toHaveBeenCalledWith(shellEvents.refreshTokenFailed, {
|
|
205
|
+
request: expect.objectContaining({ url: "/api/clinical-course" }),
|
|
206
|
+
});
|
|
94
207
|
});
|
|
95
|
-
});
|
|
96
208
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
209
|
+
it("should fail request with error != 401 and should not retry", async () => {
|
|
210
|
+
const refreshTokenSpy = vi.spyOn(tokenManager, "refreshToken");
|
|
211
|
+
const brokerSpy = vi.spyOn(broker, "publish");
|
|
212
|
+
axiosMockInstance.onGet("/api/clinical-course").replyOnce(500, "Internal Server Error");
|
|
213
|
+
await expect(axiosInstance.get("/api/clinical-course")).rejects.toMatchObject({
|
|
214
|
+
response: { status: 500 },
|
|
215
|
+
});
|
|
216
|
+
expect(axiosMockInstance.history.get?.length).toBe(1);
|
|
217
|
+
expect(refreshTokenSpy).not.toHaveBeenCalled();
|
|
218
|
+
expect(brokerSpy).not.toHaveBeenCalled();
|
|
103
219
|
});
|
|
104
|
-
expect(axiosMockInstance.history.get?.length).toBe(1);
|
|
105
|
-
expect(refreshTokenSpy).not.toHaveBeenCalled();
|
|
106
|
-
expect(brokerSpy).not.toHaveBeenCalled();
|
|
107
220
|
});
|
|
108
|
-
|
|
109
221
|
});
|
|
@@ -2,28 +2,76 @@ import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
|
2
2
|
import { TokenManager } from "../token-manager/token-manager";
|
|
3
3
|
import { shellEvents } from "../../events";
|
|
4
4
|
import { PrimariaBroker } from "../broker/primaria-broker";
|
|
5
|
+
import { jwtDecode } from "jwt-decode";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
const mpidHeader = "x-catsalut-mpid";
|
|
8
|
+
const obtainMpid = (token: string) => {
|
|
9
|
+
const mpid = (jwtDecode(token) as any).access_info?.mpi_patient_id;
|
|
10
|
+
return mpid;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class MissingMpidHeaderError extends Error {
|
|
14
|
+
constructor(message: string) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "MissingMpidHeaderError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class InvalidMpidHeaderError extends Error {
|
|
21
|
+
constructor(message: string) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "InvalidMpidHeaderError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const validateMpidHeader = (response: AxiosResponse, tokenManager: TokenManager): boolean => {
|
|
27
|
+
const mpidHeaderValue = response.headers[mpidHeader];
|
|
28
|
+
if (!mpidHeaderValue) {
|
|
29
|
+
throw new MissingMpidHeaderError("Mpid header is missing");
|
|
30
|
+
}
|
|
31
|
+
if (mpidHeaderValue !== obtainMpid(tokenManager.getToken())) {
|
|
32
|
+
throw new InvalidMpidHeaderError("Mpid header value is invalid");
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const createAxiosInstance = (
|
|
38
|
+
tokenManager: TokenManager,
|
|
39
|
+
broker: PrimariaBroker,
|
|
40
|
+
validateMpid: boolean = false,
|
|
41
|
+
) => {
|
|
7
42
|
const instance = axios.create();
|
|
8
43
|
instance.interceptors.request.use((config) => {
|
|
9
44
|
config.headers.Authorization = `Bearer ${tokenManager.getToken()}`;
|
|
10
45
|
return config;
|
|
11
46
|
});
|
|
12
|
-
|
|
47
|
+
|
|
13
48
|
instance.interceptors.response.use(
|
|
14
|
-
(response: AxiosResponse) =>
|
|
49
|
+
(response: AxiosResponse) => {
|
|
50
|
+
try {
|
|
51
|
+
if (validateMpid) validateMpidHeader(response, tokenManager);
|
|
52
|
+
return response;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error instanceof InvalidMpidHeaderError) {
|
|
55
|
+
broker.publish(shellEvents.mpidHeaderInvalid, {
|
|
56
|
+
request: response.config,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return Promise.reject(error);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
15
62
|
async (error) => {
|
|
16
63
|
const originalRequest = error.config;
|
|
17
|
-
if (error.response
|
|
64
|
+
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
18
65
|
originalRequest._retry = true;
|
|
19
|
-
// Implement token refresh logic here and update the token in headers
|
|
20
66
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
67
|
+
const newToken = await tokenManager.refreshToken();
|
|
68
|
+
originalRequest.headers.Authorization = `Bearer ${newToken}`;
|
|
69
|
+
return instance(originalRequest);
|
|
24
70
|
} catch (refreshError) {
|
|
25
71
|
console.error("Error refreshing token:", refreshError);
|
|
26
|
-
broker.publish(shellEvents.refreshTokenFailed, {
|
|
72
|
+
broker.publish(shellEvents.refreshTokenFailed, {
|
|
73
|
+
request: originalRequest,
|
|
74
|
+
});
|
|
27
75
|
return Promise.reject(error);
|
|
28
76
|
}
|
|
29
77
|
}
|
|
@@ -41,9 +89,12 @@ let instance;
|
|
|
41
89
|
export interface HttpClient {
|
|
42
90
|
request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
|
|
43
91
|
}
|
|
44
|
-
export const createHttpClient = (
|
|
92
|
+
export const createHttpClient = (
|
|
93
|
+
tokenManager: TokenManager,
|
|
94
|
+
broker: PrimariaBroker,
|
|
95
|
+
): HttpClient => {
|
|
45
96
|
if (!instance) {
|
|
46
97
|
instance = createAxiosInstance(tokenManager, broker);
|
|
47
98
|
}
|
|
48
99
|
return { request: instance.request };
|
|
49
|
-
};
|
|
100
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./interaction-service";
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConfirmationContentProps,
|
|
3
|
+
ConfirmationOptions,
|
|
4
|
+
ConfirmationResult,
|
|
5
|
+
ConfirmationWithResultContentProps,
|
|
6
|
+
PrimariaInteractionService,
|
|
7
|
+
} from "./interaction-service";
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { useEffect, useState, useRef } from "react";
|
|
10
|
+
import { createRoot } from "react-dom/client";
|
|
11
|
+
import { ConfirmationMessage } from "./confirmation-message.tsx";
|
|
12
|
+
|
|
13
|
+
const defaultOptions: ConfirmationOptions = {
|
|
14
|
+
title: "Confirmació",
|
|
15
|
+
showConfirmButton: true,
|
|
16
|
+
showCancelButton: true,
|
|
17
|
+
confirmButtonText: "Acceptar",
|
|
18
|
+
cancelButtonText: "Cancel·lar",
|
|
19
|
+
showCloseButton: true,
|
|
20
|
+
fullWidth: false,
|
|
21
|
+
fullCustomization: false,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class ParimariaInteractionServiceImpl extends PrimariaInteractionService {
|
|
25
|
+
confirm<TData = undefined, TResult = undefined>(
|
|
26
|
+
data: TData | undefined,
|
|
27
|
+
DialogComponent:
|
|
28
|
+
| React.ComponentType<ConfirmationContentProps<TData, TResult> | ConfirmationWithResultContentProps<TData, TResult>>
|
|
29
|
+
| (new () => HTMLElement),
|
|
30
|
+
options?: ConfirmationOptions | undefined,
|
|
31
|
+
): Promise<ConfirmationResult<TResult | undefined>> {
|
|
32
|
+
const finalOptions: ConfirmationOptions = { ...defaultOptions, ...(options || {}) };
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
const div = document.createElement("div");
|
|
35
|
+
const shadowRoot = div.attachShadow({ mode: "open" });
|
|
36
|
+
|
|
37
|
+
document.body.appendChild(div);
|
|
38
|
+
|
|
39
|
+
const DialogWrapper = () => {
|
|
40
|
+
const [open, setOpen] = useState(true);
|
|
41
|
+
const [result, setResult] = useState<ConfirmationResult<TResult | undefined>>();
|
|
42
|
+
const [isValid, setIsValid] = useState(true);
|
|
43
|
+
const dssModalComponentRef = useRef(null);
|
|
44
|
+
const dialogComponentRef = useRef(null);
|
|
45
|
+
|
|
46
|
+
const isWebComponent =
|
|
47
|
+
typeof DialogComponent === "function" && DialogComponent.prototype instanceof HTMLElement;
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const dssModalComponent = dssModalComponentRef.current;
|
|
51
|
+
const handleCloseDialog = (e: Event) => {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
handleClose(false);
|
|
54
|
+
};
|
|
55
|
+
dssModalComponent?.addEventListener("onModalClosed", handleCloseDialog);
|
|
56
|
+
return () => {
|
|
57
|
+
document.body.removeChild(div);
|
|
58
|
+
};
|
|
59
|
+
}, []);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (isWebComponent && dialogComponentRef.current) {
|
|
63
|
+
const parent = dialogComponentRef.current;
|
|
64
|
+
|
|
65
|
+
// ⚠ Aquí creamos la instancia del Web Component manualmente
|
|
66
|
+
const wcElement = new (DialogComponent as any)();
|
|
67
|
+
|
|
68
|
+
// Asignar propiedades manualmente
|
|
69
|
+
(wcElement as any).data = data;
|
|
70
|
+
(wcElement as any).setResult = setResult;
|
|
71
|
+
(wcElement as any).setIsValid = setIsValid;
|
|
72
|
+
(wcElement as any).confirm = () => isValid && handleClose(true);
|
|
73
|
+
(wcElement as any).confirmResult = (result) => isValid && handleCloseWithResult(result);
|
|
74
|
+
(wcElement as any).cancel = () => handleClose(false);
|
|
75
|
+
|
|
76
|
+
// Agregar el Web Component al DOM
|
|
77
|
+
parent.appendChild(wcElement);
|
|
78
|
+
|
|
79
|
+
return () => {
|
|
80
|
+
parent.removeChild(wcElement);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}, [DialogComponent, data]);
|
|
84
|
+
|
|
85
|
+
const handleClose = (confirmed: boolean) => {
|
|
86
|
+
resolvePromise(result, confirmed);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handleCloseWithResult = (finalResult: TResult) => {
|
|
90
|
+
resolvePromise(finalResult, true);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const resolvePromise = (finalResult: TResult, confirmed: boolean) => {
|
|
94
|
+
setOpen(false);
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
const confirmationResult = {
|
|
97
|
+
result: confirmed ? finalResult : undefined,
|
|
98
|
+
confirmed: confirmed,
|
|
99
|
+
};
|
|
100
|
+
resolve(confirmationResult);
|
|
101
|
+
document.body.removeChild(div);
|
|
102
|
+
}, 300);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const getConfirmButtonVariant = () => {
|
|
106
|
+
if (finalOptions.state === "error") return "error";
|
|
107
|
+
if (finalOptions.state === "success") return "success";
|
|
108
|
+
if (finalOptions.state === "info") return "primary";
|
|
109
|
+
if (finalOptions.state === "alert") return "warning";
|
|
110
|
+
return "primary";
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const getCancelButtonVariant = () => {
|
|
114
|
+
if (finalOptions.state) return "alternative-dark";
|
|
115
|
+
return "secondary";
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const _renderContent = () => {
|
|
119
|
+
return isWebComponent ? (
|
|
120
|
+
<div ref={dialogComponentRef} />
|
|
121
|
+
) : (
|
|
122
|
+
<DialogComponent
|
|
123
|
+
{...{
|
|
124
|
+
data,
|
|
125
|
+
setResult,
|
|
126
|
+
setIsValid,
|
|
127
|
+
confirm: () => isValid && handleClose(true),
|
|
128
|
+
cancel: () => handleClose(false),
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
if (finalOptions.fullCustomization) {
|
|
135
|
+
return (
|
|
136
|
+
<div className="modal" hidden={!open}>
|
|
137
|
+
<div className="dialog">{_renderContent()}</div>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return (
|
|
142
|
+
<dss-modal
|
|
143
|
+
modalTitle={finalOptions.title}
|
|
144
|
+
open={open}
|
|
145
|
+
fullWidth={finalOptions.fullWidth}
|
|
146
|
+
ref={dssModalComponentRef}
|
|
147
|
+
hideCloseIcon={!finalOptions.showCloseButton}
|
|
148
|
+
modalStyle="padding:0px;"
|
|
149
|
+
>
|
|
150
|
+
<div slot="body">{_renderContent()}</div>
|
|
151
|
+
<div
|
|
152
|
+
className="dss-modal-footer"
|
|
153
|
+
slot="footer"
|
|
154
|
+
hidden={!finalOptions.showCancelButton && !finalOptions.showConfirmButton}
|
|
155
|
+
>
|
|
156
|
+
{finalOptions.showCancelButton && (
|
|
157
|
+
<dss-button
|
|
158
|
+
label={finalOptions.cancelButtonText}
|
|
159
|
+
onClick={() => handleClose(false)}
|
|
160
|
+
size="md"
|
|
161
|
+
variant={getCancelButtonVariant()}
|
|
162
|
+
/>
|
|
163
|
+
)}
|
|
164
|
+
{finalOptions.showConfirmButton && (
|
|
165
|
+
<dss-button
|
|
166
|
+
onClick={() => isValid && handleClose(true)}
|
|
167
|
+
label={finalOptions.confirmButtonText}
|
|
168
|
+
disabled={!isValid}
|
|
169
|
+
size="md"
|
|
170
|
+
variant={getConfirmButtonVariant()}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
</dss-modal>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Agregar estilos al Shadow DOM
|
|
179
|
+
const style = document.createElement("style");
|
|
180
|
+
style.textContent = `
|
|
181
|
+
.modal {
|
|
182
|
+
font-family: "Open Sans";
|
|
183
|
+
display: block;
|
|
184
|
+
position: fixed;
|
|
185
|
+
z-index: 400;
|
|
186
|
+
left: 0;
|
|
187
|
+
top: 0;
|
|
188
|
+
width: 100%;
|
|
189
|
+
height: 100%;
|
|
190
|
+
background-color: rgba(0, 0, 0, 0.65);
|
|
191
|
+
|
|
192
|
+
.dialog {
|
|
193
|
+
display: flex;
|
|
194
|
+
flex-direction: column;
|
|
195
|
+
position: absolute;
|
|
196
|
+
top: 50%;
|
|
197
|
+
left: 50%;
|
|
198
|
+
transform: translate(-50%, -50%);
|
|
199
|
+
z-index: 21;
|
|
200
|
+
background: #fff;
|
|
201
|
+
border-radius: 16px;
|
|
202
|
+
width: auto;
|
|
203
|
+
height: auto;
|
|
204
|
+
max-height: 95%;
|
|
205
|
+
min-width: 400px;
|
|
206
|
+
box-shadow:
|
|
207
|
+
0px 0px 14px rgb(0 0 0 / 25%),
|
|
208
|
+
0px 1px 10px rgb(0 0 0 / 22%);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
`;
|
|
212
|
+
|
|
213
|
+
shadowRoot.appendChild(style);
|
|
214
|
+
const root = createRoot(shadowRoot);
|
|
215
|
+
root.render(<DialogWrapper />);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
confirmMessage(
|
|
220
|
+
message: string,
|
|
221
|
+
options?: ConfirmationOptions | undefined,
|
|
222
|
+
): Promise<ConfirmationResult> {
|
|
223
|
+
return this.confirm(message, ConfirmationMessage, options);
|
|
224
|
+
}
|
|
225
|
+
}
|