@uxland/primary-shell 4.3.1 → 5.1.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 +13397 -12875
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1748 -1506
- package/dist/index.umd.cjs.map +1 -1
- package/dist/primary/shell/src/UI/components/primaria-shell/primaria-shell.d.ts +4 -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/plugin-busy-manager/plugin-busy-manager.d.ts +17 -1
- package/dist/primary/shell/src/api/region-manager/region-manager.d.ts +1 -0
- package/dist/primary/shell/src/events.d.ts +2 -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/dist/style.css +1 -1
- package/package.json +5 -2
- package/src/UI/components/clinical-monitoring/styles.css +4 -2
- package/src/UI/components/primaria-shell/primaria-shell.ts +33 -7
- package/src/UI/components/primaria-shell/styles.css +15 -2
- package/src/UI/components/primaria-shell/template.ts +7 -3
- package/src/UI/components/quick-actions-menu/quick-actions-menu.ts +13 -3
- package/src/UI/components/shell-header/template.ts +1 -1
- package/src/UI/shared-components/index.ts +0 -1
- package/src/api/api.ts +12 -9
- 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 +203 -0
- package/src/api/interaction-service/interaction-service.ts +46 -0
- package/src/api/interaction-service/modal-styles.css +69 -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/plugin-busy-manager/plugin-busy-manager.test.ts +93 -31
- package/src/api/plugin-busy-manager/plugin-busy-manager.ts +44 -1
- package/src/api/region-manager/region-manager.ts +5 -0
- package/src/disposer.ts +1 -1
- package/src/events.ts +2 -0
- package/src/features/bootstrapper.ts +6 -3
- package/src/features/exit/handler.ts +7 -12
- 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
|
@@ -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,203 @@
|
|
|
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
|
+
import modalStyles from './modal-styles.css?raw';
|
|
13
|
+
|
|
14
|
+
const defaultOptions: ConfirmationOptions = {
|
|
15
|
+
title: "Confirmació",
|
|
16
|
+
showConfirmButton: true,
|
|
17
|
+
showCancelButton: true,
|
|
18
|
+
confirmButtonText: "Acceptar",
|
|
19
|
+
cancelButtonText: "Cancel·lar",
|
|
20
|
+
showCloseButton: true,
|
|
21
|
+
fullCustomization: false,
|
|
22
|
+
closeOnOutsideClick: false,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class ParimariaInteractionServiceImpl extends PrimariaInteractionService {
|
|
26
|
+
confirm<TData = undefined, TResult = undefined>(
|
|
27
|
+
data: TData | undefined,
|
|
28
|
+
DialogComponent:
|
|
29
|
+
| React.ComponentType<ConfirmationContentProps<TData, TResult> | ConfirmationWithResultContentProps<TData, TResult>>
|
|
30
|
+
| (new () => HTMLElement),
|
|
31
|
+
options?: ConfirmationOptions | undefined,
|
|
32
|
+
): Promise<ConfirmationResult<TResult | undefined>> {
|
|
33
|
+
const finalOptions: ConfirmationOptions = { ...defaultOptions, ...(options || {}) };
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const div = document.createElement("div");
|
|
36
|
+
document.body.appendChild(div);
|
|
37
|
+
const style = document.createElement("style");
|
|
38
|
+
style.textContent = modalStyles;
|
|
39
|
+
|
|
40
|
+
document.head.appendChild(style);
|
|
41
|
+
|
|
42
|
+
const DialogWrapper = () => {
|
|
43
|
+
const [result, setResult] = useState<ConfirmationResult<TResult | undefined>>();
|
|
44
|
+
const [isValid, setIsValid] = useState(true);
|
|
45
|
+
const dialogComponentRef = useRef(null);
|
|
46
|
+
const dialogRef = useRef<HTMLDivElement>(null);
|
|
47
|
+
const modalRef = useRef<HTMLDivElement>(null);
|
|
48
|
+
|
|
49
|
+
const isWebComponent =
|
|
50
|
+
typeof DialogComponent === "function" && DialogComponent.prototype instanceof HTMLElement;
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
window.addEventListener('keydown', handleKeydown);
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
const handleKeydown = (event: KeyboardEvent) => {
|
|
57
|
+
if (event.key === 'Escape') {
|
|
58
|
+
handleClose(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const handleOutsideClick = (event: Event) => {
|
|
62
|
+
if (dialogRef.current) {
|
|
63
|
+
if (event.target === modalRef.current && finalOptions.closeOnOutsideClick) {
|
|
64
|
+
handleClose(false);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (isWebComponent && dialogComponentRef.current) {
|
|
71
|
+
const parent = dialogComponentRef.current;
|
|
72
|
+
|
|
73
|
+
// ⚠ Aquí creamos la instancia del Web Component manualmente
|
|
74
|
+
const wcElement = new (DialogComponent as any)();
|
|
75
|
+
|
|
76
|
+
// Asignar propiedades manualmente
|
|
77
|
+
(wcElement as any).data = data;
|
|
78
|
+
(wcElement as any).setResult = setResult;
|
|
79
|
+
(wcElement as any).setIsValid = setIsValid;
|
|
80
|
+
(wcElement as any).confirm = () => isValid && handleClose(true);
|
|
81
|
+
(wcElement as any).confirmResult = (result) => isValid && handleCloseWithResult(result);
|
|
82
|
+
(wcElement as any).cancel = () => handleClose(false);
|
|
83
|
+
|
|
84
|
+
// Agregar el Web Component al DOM
|
|
85
|
+
parent.appendChild(wcElement);
|
|
86
|
+
|
|
87
|
+
return () => {
|
|
88
|
+
parent.removeChild(wcElement);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}, [DialogComponent, data]);
|
|
92
|
+
|
|
93
|
+
const handleClose = (confirmed: boolean) => {
|
|
94
|
+
resolvePromise(result, confirmed);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const handleCloseWithResult = (finalResult: TResult) => {
|
|
98
|
+
resolvePromise(finalResult, true);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const resolvePromise = (finalResult: TResult, confirmed: boolean) => {
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
const confirmationResult = {
|
|
104
|
+
result: confirmed ? finalResult : undefined,
|
|
105
|
+
confirmed: confirmed,
|
|
106
|
+
};
|
|
107
|
+
resolve(confirmationResult);
|
|
108
|
+
document.body.removeChild(div);
|
|
109
|
+
document.head.removeChild(style);
|
|
110
|
+
window.removeEventListener('keydown', handleKeydown);
|
|
111
|
+
}, 300);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const getConfirmButtonVariant = () => {
|
|
115
|
+
if (finalOptions.state === "error") return "error";
|
|
116
|
+
if (finalOptions.state === "success") return "success";
|
|
117
|
+
if (finalOptions.state === "info") return "primary";
|
|
118
|
+
if (finalOptions.state === "alert") return "warning";
|
|
119
|
+
return "primary";
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const getCancelButtonVariant = () => {
|
|
123
|
+
if (finalOptions.state) return "alternative-dark";
|
|
124
|
+
return "secondary";
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const _renderContent = () => {
|
|
128
|
+
return isWebComponent ? (
|
|
129
|
+
<div ref={dialogComponentRef} />
|
|
130
|
+
) : (
|
|
131
|
+
<DialogComponent
|
|
132
|
+
{...{
|
|
133
|
+
data,
|
|
134
|
+
setResult,
|
|
135
|
+
setIsValid,
|
|
136
|
+
confirm: () => isValid && handleClose(true),
|
|
137
|
+
cancel: () => handleClose(false),
|
|
138
|
+
}}
|
|
139
|
+
/>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
return (
|
|
143
|
+
<div className="modal" ref={modalRef} onClick={handleOutsideClick} >
|
|
144
|
+
<div className="dialog" ref={dialogRef}>
|
|
145
|
+
{!finalOptions.fullCustomization && (
|
|
146
|
+
<div className="dss-dialog-header">
|
|
147
|
+
<div className="dss-dialog-header-title">{finalOptions.title}</div>
|
|
148
|
+
{finalOptions.showCloseButton && (
|
|
149
|
+
<dss-icon-button
|
|
150
|
+
class="dss-dialog-header-close"
|
|
151
|
+
size="md"
|
|
152
|
+
variant="neutral"
|
|
153
|
+
icon="close"
|
|
154
|
+
onClick={() => handleClose(false)}
|
|
155
|
+
></dss-icon-button>
|
|
156
|
+
)}
|
|
157
|
+
</div>
|
|
158
|
+
)}
|
|
159
|
+
<div className={`modal-content ${finalOptions.fullCustomization ? 'full-customization' : ''}`}>
|
|
160
|
+
{_renderContent()}
|
|
161
|
+
</div>
|
|
162
|
+
{!finalOptions.fullCustomization && (
|
|
163
|
+
<div
|
|
164
|
+
className="dss-modal-footer"
|
|
165
|
+
hidden={!finalOptions.showCancelButton && !finalOptions.showConfirmButton}
|
|
166
|
+
>
|
|
167
|
+
{finalOptions.showCancelButton && (
|
|
168
|
+
<dss-button
|
|
169
|
+
label={finalOptions.cancelButtonText}
|
|
170
|
+
onClick={() => handleClose(false)}
|
|
171
|
+
size="md"
|
|
172
|
+
variant={getCancelButtonVariant()}
|
|
173
|
+
/>
|
|
174
|
+
)}
|
|
175
|
+
{finalOptions.showConfirmButton && (
|
|
176
|
+
<dss-button
|
|
177
|
+
onClick={() => isValid && handleClose(true)}
|
|
178
|
+
label={finalOptions.confirmButtonText}
|
|
179
|
+
disabled={!isValid}
|
|
180
|
+
size="md"
|
|
181
|
+
variant={getConfirmButtonVariant()}
|
|
182
|
+
/>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
const root = createRoot(div);
|
|
193
|
+
root.render(<DialogWrapper />);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
confirmMessage(
|
|
198
|
+
message: string,
|
|
199
|
+
options?: ConfirmationOptions | undefined,
|
|
200
|
+
): Promise<ConfirmationResult> {
|
|
201
|
+
return this.confirm(message, ConfirmationMessage, options);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface ConfirmationResult<T = undefined> {
|
|
4
|
+
confirmed: boolean;
|
|
5
|
+
result: T | undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ConfirmationContentProps<TData, TResult = undefined> {
|
|
9
|
+
data: TData | undefined;
|
|
10
|
+
setResult: (result: TResult) => void;
|
|
11
|
+
setIsValid: (isValid: boolean) => void;
|
|
12
|
+
confirm: () => void;
|
|
13
|
+
cancel: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ConfirmationWithResultContentProps<TData, TResult = undefined> {
|
|
17
|
+
data: TData | undefined;
|
|
18
|
+
confirmResult: (result: TResult) => void;
|
|
19
|
+
cancel: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ConfirmationOptions {
|
|
23
|
+
title?: string | undefined;
|
|
24
|
+
showConfirmButton?: boolean | undefined;
|
|
25
|
+
showCancelButton?: boolean | undefined;
|
|
26
|
+
confirmButtonText?: string | undefined;
|
|
27
|
+
cancelButtonText?: string | undefined;
|
|
28
|
+
showCloseButton?: boolean | undefined;
|
|
29
|
+
fullCustomization?: boolean | undefined;
|
|
30
|
+
closeOnOutsideClick?: boolean | undefined;
|
|
31
|
+
state?: "success" | "info" | "alert" | "error";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export abstract class PrimariaInteractionService {
|
|
35
|
+
abstract confirm<TData = undefined, TResult = undefined>(
|
|
36
|
+
data: TData | undefined,
|
|
37
|
+
dialogComponent:
|
|
38
|
+
| React.ComponentType<ConfirmationContentProps<TData, TResult> | ConfirmationWithResultContentProps<TData, TResult>>
|
|
39
|
+
| (new () => HTMLElement),
|
|
40
|
+
options?: ConfirmationOptions | undefined,
|
|
41
|
+
): Promise<ConfirmationResult<TResult | undefined>>;
|
|
42
|
+
abstract confirmMessage(
|
|
43
|
+
message: string,
|
|
44
|
+
options?: ConfirmationOptions | undefined,
|
|
45
|
+
): Promise<ConfirmationResult>;
|
|
46
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.modal {
|
|
2
|
+
font-family: "Open Sans";
|
|
3
|
+
display: block;
|
|
4
|
+
position: fixed;
|
|
5
|
+
z-index: 400;
|
|
6
|
+
left: 0;
|
|
7
|
+
top: 0;
|
|
8
|
+
width: 100%;
|
|
9
|
+
height: 100%;
|
|
10
|
+
background-color: rgba(0, 0, 0, 0.65);
|
|
11
|
+
}
|
|
12
|
+
.dialog {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
position: absolute;
|
|
16
|
+
top: 50%;
|
|
17
|
+
left: 50%;
|
|
18
|
+
transform: translate(-50%, -50%);
|
|
19
|
+
z-index: 21;
|
|
20
|
+
background: #fff;
|
|
21
|
+
border-radius: 16px;
|
|
22
|
+
width: auto;
|
|
23
|
+
height: auto;
|
|
24
|
+
max-height: 95%;
|
|
25
|
+
min-width: 400px;
|
|
26
|
+
box-shadow: 0 8px 12px 6px rgba(0 0 0 / 5%), 0 4px 4px rgba(0 0 0 / 10%);
|
|
27
|
+
}
|
|
28
|
+
.dss-dialog-header {
|
|
29
|
+
position: relative;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
align-items: center;
|
|
34
|
+
padding: 24px;
|
|
35
|
+
border-top-left-radius: 16px;
|
|
36
|
+
border-top-right-radius: 16px;
|
|
37
|
+
}
|
|
38
|
+
.dss-dialog-header-title {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: var(--dss-spacing-xs);
|
|
44
|
+
font-size: 20px;
|
|
45
|
+
line-height: 30px;
|
|
46
|
+
font-weight: var(--font-bold);
|
|
47
|
+
color: var(--color-neutral-900);
|
|
48
|
+
}
|
|
49
|
+
.dss-dialog-header-close {
|
|
50
|
+
position: absolute;
|
|
51
|
+
top: var(--dss-spacing-lg);
|
|
52
|
+
right: calc(var(--dss-spacing-lg) - 4px);
|
|
53
|
+
}
|
|
54
|
+
.modal-content {
|
|
55
|
+
flex: 1;
|
|
56
|
+
padding: 0 24px;
|
|
57
|
+
}
|
|
58
|
+
.modal-content.full-customization {
|
|
59
|
+
padding: 0;
|
|
60
|
+
}
|
|
61
|
+
.dss-modal-footer {
|
|
62
|
+
display: flex;
|
|
63
|
+
justify-content: center;
|
|
64
|
+
align-items: center;
|
|
65
|
+
gap: 16px;
|
|
66
|
+
padding: 24px;
|
|
67
|
+
border-bottom-left-radius: 16px;
|
|
68
|
+
border-bottom-right-radius: 16px;
|
|
69
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { PrimariaNotificationService } from "./notification-service";
|
|
2
|
+
|
|
3
|
+
export class PrimariaNotificationServiceImpl extends PrimariaNotificationService {
|
|
4
|
+
private notify(
|
|
5
|
+
message: string,
|
|
6
|
+
state: "info" | "warning" | "error" | "success",
|
|
7
|
+
duration = 3000,
|
|
8
|
+
): void {
|
|
9
|
+
// Crear el Web Component
|
|
10
|
+
const toast = document.createElement("dss-toast");
|
|
11
|
+
toast.setAttribute("isshow", "true");
|
|
12
|
+
toast.setAttribute("state", state);
|
|
13
|
+
toast.setAttribute("position", "bottom-left");
|
|
14
|
+
toast.setAttribute("text", message);
|
|
15
|
+
toast.setAttribute("hasicon", "true");
|
|
16
|
+
toast.setAttribute("duration", duration.toString());
|
|
17
|
+
|
|
18
|
+
// Agregar al body
|
|
19
|
+
document.body.appendChild(toast);
|
|
20
|
+
|
|
21
|
+
// Remover después del tiempo de duración
|
|
22
|
+
setTimeout(() => {
|
|
23
|
+
toast.setAttribute("isshow", "false");
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
toast.remove();
|
|
26
|
+
}, 300); // Espera un poco para animación de salida (ajustable)
|
|
27
|
+
}, duration);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
info(message: string, duration?: number): void {
|
|
31
|
+
this.notify(message, "info", duration);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
warning(message: string, duration?: number): void {
|
|
35
|
+
this.notify(message, "warning", duration);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
error(message: string, duration?: number): void {
|
|
39
|
+
this.notify(message, "error", duration);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
success(message: string, duration?: number): void {
|
|
43
|
+
this.notify(message, "success", duration);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { LitElement, css, html, unsafeCSS } from "lit";
|
|
2
2
|
import { customElement } from "lit/decorators.js";
|
|
3
|
+
import { PluginBusyTask } from "../plugin-busy-manager";
|
|
3
4
|
import styles from "./styles.css?inline";
|
|
4
5
|
import { template } from "./template";
|
|
5
|
-
import { confirmMixin } from "../../../UI/shared-components/primaria-interaction/confirm-mixin";
|
|
6
|
-
import { PluginBusyTask } from "../plugin-busy-manager";
|
|
7
6
|
|
|
8
7
|
@customElement("plugin-busy-list")
|
|
9
|
-
export class PluginBusyList extends
|
|
8
|
+
export class PluginBusyList extends LitElement {
|
|
10
9
|
static styles = css`
|
|
11
10
|
${unsafeCSS(styles)}
|
|
12
11
|
`;
|
|
@@ -15,5 +14,5 @@ export class PluginBusyList extends confirmMixin(LitElement) {
|
|
|
15
14
|
return html`${template(this)}`;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
data: { busyTasks: PluginBusyTask[] };
|
|
19
18
|
}
|
|
@@ -7,7 +7,7 @@ export const template = (props: PluginBusyList) => html`
|
|
|
7
7
|
<div class="container">
|
|
8
8
|
<div class="title">${translate("busyManager.title")}</div>
|
|
9
9
|
<div class="list">
|
|
10
|
-
${props.
|
|
10
|
+
${props.data?.busyTasks?.map((item: PluginBusyTask) => html`<div class="plugin-busy-item">${item.taskDescription}</div>`)}
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
13
13
|
`;
|
|
@@ -1,49 +1,111 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
2
|
import { PluginBusyManagerImpl } from "./plugin-busy-manager";
|
|
3
|
+
import { shellEvents } from "../../events";
|
|
3
4
|
|
|
4
5
|
describe("PluginBusyManagerImpl", () => {
|
|
6
|
+
let brokerMock: any;
|
|
5
7
|
let manager: PluginBusyManagerImpl;
|
|
6
8
|
|
|
7
9
|
beforeEach(() => {
|
|
8
|
-
|
|
10
|
+
brokerMock = {
|
|
11
|
+
publish: vi.fn(),
|
|
12
|
+
};
|
|
13
|
+
manager = new PluginBusyManagerImpl(brokerMock);
|
|
9
14
|
});
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
describe("addBusyPluginTask", () => {
|
|
17
|
+
it("should add a plugin busy task", () => {
|
|
18
|
+
const task = { taskId: "1", taskDescription: "Loading plugin" };
|
|
19
|
+
manager.addBusyPluginTask(task);
|
|
20
|
+
expect(manager.getBusyPluginTasks()).toContain(task);
|
|
21
|
+
});
|
|
14
22
|
});
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
describe("removeBusyPluginTask", () => {
|
|
25
|
+
it("should remove a plugin busy task if it exists", () => {
|
|
26
|
+
const task = { taskId: "1", taskDescription: "Loading plugin" };
|
|
27
|
+
manager.addBusyPluginTask(task);
|
|
28
|
+
manager.removeBusyPluginTask("1");
|
|
29
|
+
expect(manager.getBusyPluginTasks()).not.toContain(task);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should do nothing if task does not exist", () => {
|
|
33
|
+
const task = { taskId: "1", taskDescription: "Loading plugin" };
|
|
34
|
+
manager.addBusyPluginTask(task);
|
|
35
|
+
manager.removeBusyPluginTask("non-existent");
|
|
36
|
+
expect(manager.getBusyPluginTasks()).toContain(task);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("addBusyQuickActionTask", () => {
|
|
41
|
+
it("should add a quick action busy task and emit event", () => {
|
|
42
|
+
const task = { taskId: "qa1" };
|
|
43
|
+
manager.addBusyQuickActionTask(task);
|
|
44
|
+
expect(brokerMock.publish).toHaveBeenCalledWith(shellEvents.quickActionBusyChanged, {
|
|
45
|
+
busy: true,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("removeBusyQuickActionTask", () => {
|
|
51
|
+
it("should remove a quick action task and emit event", () => {
|
|
52
|
+
const task = { taskId: "qa1" };
|
|
53
|
+
manager.addBusyQuickActionTask(task);
|
|
54
|
+
manager.removeBusyQuickActionTask("qa1");
|
|
55
|
+
expect(brokerMock.publish).toHaveBeenCalledWith(shellEvents.quickActionBusyChanged, {
|
|
56
|
+
busy: false,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should do nothing and not emit event if task does not exist", () => {
|
|
61
|
+
manager.removeBusyQuickActionTask("non-existent");
|
|
62
|
+
expect(brokerMock.publish).not.toHaveBeenCalled();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("isAnyPluginBusy", () => {
|
|
67
|
+
it("should return false when no plugin tasks exist", () => {
|
|
68
|
+
expect(manager.isAnyPluginBusy()).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should return true when plugin tasks exist", () => {
|
|
72
|
+
manager.addBusyPluginTask({ taskId: "1", taskDescription: "Busy" });
|
|
73
|
+
expect(manager.isAnyPluginBusy()).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("isAnyQuickActionBusy", () => {
|
|
78
|
+
it("should return false when no quick action tasks exist", () => {
|
|
79
|
+
expect(manager.isAnyQuickActionBusy()).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should return true when quick action tasks exist", () => {
|
|
83
|
+
manager.addBusyQuickActionTask({ taskId: "qa1" });
|
|
84
|
+
expect(manager.isAnyQuickActionBusy()).toBe(true);
|
|
85
|
+
});
|
|
21
86
|
});
|
|
22
87
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(manager.getBusyPluginTasks()).not.toContainEqual(task1);
|
|
30
|
-
expect(manager.getBusyPluginTasks()).toContainEqual(task2);
|
|
88
|
+
describe("clearAllBusyPlugins", () => {
|
|
89
|
+
it("should clear all plugin busy tasks", () => {
|
|
90
|
+
manager.addBusyPluginTask({ taskId: "1", taskDescription: "Busy" });
|
|
91
|
+
manager.clearAllBusyPlugins();
|
|
92
|
+
expect(manager.getBusyPluginTasks()).toHaveLength(0);
|
|
93
|
+
});
|
|
31
94
|
});
|
|
32
95
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
96
|
+
describe("clearAllBusyQuickActions", () => {
|
|
97
|
+
it("should clear all quick action busy tasks", () => {
|
|
98
|
+
manager.addBusyQuickActionTask({ taskId: "qa1" });
|
|
99
|
+
manager.clearAllBusyQuickActions();
|
|
100
|
+
expect(manager.isAnyQuickActionBusy()).toBe(false);
|
|
101
|
+
});
|
|
38
102
|
});
|
|
39
103
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
expect(manager.getBusyPluginTasks()).toEqual([]);
|
|
47
|
-
expect(manager.isAnyPluginBusy()).toBe(false);
|
|
104
|
+
describe("getBusyPluginTasks", () => {
|
|
105
|
+
it("should return current plugin tasks", () => {
|
|
106
|
+
const task = { taskId: "1", taskDescription: "Loading plugin" };
|
|
107
|
+
manager.addBusyPluginTask(task);
|
|
108
|
+
expect(manager.getBusyPluginTasks()).toEqual([task]);
|
|
109
|
+
});
|
|
48
110
|
});
|
|
49
111
|
});
|