@uxland/primary-shell 5.0.0 → 5.1.1
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 +27285 -26453
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1799 -1494
- package/dist/index.umd.cjs.map +1 -1
- package/dist/primary/shell/src/UI/components/pdf-visor/pdf-selector/pdf-selector.d.ts +12 -0
- package/dist/primary/shell/src/UI/components/pdf-visor/pdf-selector/template.d.ts +3 -0
- package/dist/primary/shell/src/UI/components/pdf-visor/pdf-visor.d.ts +22 -0
- package/dist/primary/shell/src/UI/components/pdf-visor/utils.d.ts +1 -0
- package/dist/primary/shell/src/UI/components/poc-events-ecap/poc-events-ecap.d.ts +2 -0
- package/dist/primary/shell/src/UI/components/primaria-shell/primaria-shell.d.ts +1 -0
- package/dist/primary/shell/src/api/api.d.ts +2 -0
- package/dist/primary/shell/src/api/interaction-service/interaction-service.d.ts +1 -1
- package/dist/primary/shell/src/api/pdf-viewer-manager/events.d.ts +5 -0
- package/dist/primary/shell/src/api/pdf-viewer-manager/pdf-viewer-manager.d.ts +27 -0
- package/dist/primary/shell/src/api/plugin-busy-manager/plugin-busy-manager.d.ts +17 -1
- package/dist/primary/shell/src/constants.d.ts +1 -0
- package/dist/primary/shell/src/events.d.ts +1 -0
- package/dist/primary/shell/src/locales.d.ts +10 -0
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/UI/components/clinical-monitoring/styles.css +3 -2
- package/src/UI/components/index.ts +1 -0
- package/src/UI/components/pdf-visor/pdf-selector/pdf-selector.ts +40 -0
- package/src/UI/components/pdf-visor/pdf-selector/styles.css +24 -0
- package/src/UI/components/pdf-visor/pdf-selector/template.ts +37 -0
- package/src/UI/components/pdf-visor/pdf-visor.ts +124 -0
- package/src/UI/components/pdf-visor/styles.css +29 -0
- package/src/UI/components/pdf-visor/utils.ts +16 -0
- package/src/UI/components/poc-events-ecap/poc-events-ecap.ts +37 -7
- package/src/UI/components/primaria-shell/primaria-shell.ts +9 -0
- package/src/UI/components/primaria-shell/styles.css +15 -2
- package/src/UI/components/primaria-shell/template.ts +7 -3
- package/src/UI/components/shell-header/template.ts +1 -1
- package/src/api/api.ts +8 -2
- package/src/api/interaction-service/interaction-service-impl.tsx +68 -90
- package/src/api/interaction-service/interaction-service.ts +1 -1
- package/src/api/interaction-service/modal-styles.css +69 -0
- package/src/api/pdf-viewer-manager/events.ts +5 -0
- package/src/api/pdf-viewer-manager/pdf-viewer-manager.ts +97 -0
- 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/constants.ts +1 -0
- package/src/events.ts +1 -0
- package/src/features/exit/handler.ts +2 -4
- package/src/handle-views.ts +12 -7
- package/src/locales.ts +10 -0
|
@@ -9,6 +9,7 @@ import * as React from "react";
|
|
|
9
9
|
import { useEffect, useState, useRef } from "react";
|
|
10
10
|
import { createRoot } from "react-dom/client";
|
|
11
11
|
import { ConfirmationMessage } from "./confirmation-message.tsx";
|
|
12
|
+
import modalStyles from './modal-styles.css?raw';
|
|
12
13
|
|
|
13
14
|
const defaultOptions: ConfirmationOptions = {
|
|
14
15
|
title: "Confirmació",
|
|
@@ -17,8 +18,8 @@ const defaultOptions: ConfirmationOptions = {
|
|
|
17
18
|
confirmButtonText: "Acceptar",
|
|
18
19
|
cancelButtonText: "Cancel·lar",
|
|
19
20
|
showCloseButton: true,
|
|
20
|
-
fullWidth: false,
|
|
21
21
|
fullCustomization: false,
|
|
22
|
+
closeOnOutsideClick: false,
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
export class ParimariaInteractionServiceImpl extends PrimariaInteractionService {
|
|
@@ -32,32 +33,39 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
32
33
|
const finalOptions: ConfirmationOptions = { ...defaultOptions, ...(options || {}) };
|
|
33
34
|
return new Promise((resolve) => {
|
|
34
35
|
const div = document.createElement("div");
|
|
35
|
-
const shadowRoot = div.attachShadow({ mode: "open" });
|
|
36
|
-
|
|
37
36
|
document.body.appendChild(div);
|
|
37
|
+
const style = document.createElement("style");
|
|
38
|
+
style.textContent = modalStyles;
|
|
39
|
+
|
|
40
|
+
document.head.appendChild(style);
|
|
38
41
|
|
|
39
42
|
const DialogWrapper = () => {
|
|
40
|
-
const [open, setOpen] = useState(true);
|
|
41
43
|
const [result, setResult] = useState<ConfirmationResult<TResult | undefined>>();
|
|
42
44
|
const [isValid, setIsValid] = useState(true);
|
|
43
|
-
const dssModalComponentRef = useRef(null);
|
|
44
45
|
const dialogComponentRef = useRef(null);
|
|
46
|
+
const dialogRef = useRef<HTMLDivElement>(null);
|
|
47
|
+
const modalRef = useRef<HTMLDivElement>(null);
|
|
45
48
|
|
|
46
49
|
const isWebComponent =
|
|
47
50
|
typeof DialogComponent === "function" && DialogComponent.prototype instanceof HTMLElement;
|
|
48
51
|
|
|
49
52
|
useEffect(() => {
|
|
50
|
-
|
|
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
|
-
};
|
|
53
|
+
window.addEventListener('keydown', handleKeydown);
|
|
59
54
|
}, []);
|
|
60
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
|
+
|
|
61
69
|
useEffect(() => {
|
|
62
70
|
if (isWebComponent && dialogComponentRef.current) {
|
|
63
71
|
const parent = dialogComponentRef.current;
|
|
@@ -91,7 +99,6 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
91
99
|
};
|
|
92
100
|
|
|
93
101
|
const resolvePromise = (finalResult: TResult, confirmed: boolean) => {
|
|
94
|
-
setOpen(false);
|
|
95
102
|
setTimeout(() => {
|
|
96
103
|
const confirmationResult = {
|
|
97
104
|
result: confirmed ? finalResult : undefined,
|
|
@@ -99,6 +106,8 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
99
106
|
};
|
|
100
107
|
resolve(confirmationResult);
|
|
101
108
|
document.body.removeChild(div);
|
|
109
|
+
document.head.removeChild(style);
|
|
110
|
+
window.removeEventListener('keydown', handleKeydown);
|
|
102
111
|
}, 300);
|
|
103
112
|
};
|
|
104
113
|
|
|
@@ -130,88 +139,57 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
130
139
|
/>
|
|
131
140
|
);
|
|
132
141
|
};
|
|
133
|
-
|
|
134
|
-
if (finalOptions.fullCustomization) {
|
|
135
|
-
return (
|
|
136
|
-
<div className="modal" hidden={!open}>
|
|
137
|
-
<div className="dialog">{_renderContent()}</div>
|
|
138
|
-
</div>
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
142
|
return (
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
<dss-button
|
|
158
|
-
label={finalOptions.cancelButtonText}
|
|
159
|
-
onClick={() => handleClose(false)}
|
|
160
|
-
size="md"
|
|
161
|
-
variant={getCancelButtonVariant()}
|
|
162
|
-
/>
|
|
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>
|
|
163
158
|
)}
|
|
164
|
-
{finalOptions.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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>
|
|
172
185
|
)}
|
|
173
186
|
</div>
|
|
174
|
-
</
|
|
187
|
+
</div>
|
|
175
188
|
);
|
|
176
189
|
};
|
|
177
190
|
|
|
178
|
-
|
|
179
|
-
const
|
|
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);
|
|
191
|
+
|
|
192
|
+
const root = createRoot(div);
|
|
215
193
|
root.render(<DialogWrapper />);
|
|
216
194
|
});
|
|
217
195
|
}
|
|
@@ -26,8 +26,8 @@ export interface ConfirmationOptions {
|
|
|
26
26
|
confirmButtonText?: string | undefined;
|
|
27
27
|
cancelButtonText?: string | undefined;
|
|
28
28
|
showCloseButton?: boolean | undefined;
|
|
29
|
-
fullWidth?: boolean | undefined;
|
|
30
29
|
fullCustomization?: boolean | undefined;
|
|
30
|
+
closeOnOutsideClick?: boolean | undefined;
|
|
31
31
|
state?: "success" | "info" | "alert" | "error";
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -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,97 @@
|
|
|
1
|
+
import { translate } from "../../locales";
|
|
2
|
+
import { PrimariaNavItem } from "../../UI/shared-components/primaria-nav-item/primaria-nav-item";
|
|
3
|
+
import { PrimariaBroker } from "../broker/primaria-broker";
|
|
4
|
+
import { PrimariaNotificationService } from "../notification-service/notification-service";
|
|
5
|
+
import { shellRegions } from "../region-manager/regions";
|
|
6
|
+
import { pdfViwerEvents } from "./events";
|
|
7
|
+
import { pdfViewerId } from "../../constants";
|
|
8
|
+
import { PrimariaRegionManager } from "../region-manager/region-manager";
|
|
9
|
+
import { generateId } from "@primaria/plugins-core";
|
|
10
|
+
|
|
11
|
+
export interface IPdfDocument {
|
|
12
|
+
pdfName: string;
|
|
13
|
+
id: string;
|
|
14
|
+
data: PdfData;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PdfData {
|
|
18
|
+
url?: string;
|
|
19
|
+
b64?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class PdfViewerManager {
|
|
23
|
+
constructor(
|
|
24
|
+
private broker: PrimariaBroker,
|
|
25
|
+
private notificationService: PrimariaNotificationService,
|
|
26
|
+
private regionManager: PrimariaRegionManager,
|
|
27
|
+
) {}
|
|
28
|
+
|
|
29
|
+
private pdfs: IPdfDocument[] = [];
|
|
30
|
+
private activePdf: IPdfDocument | null = null;
|
|
31
|
+
private hasBeenActivated = false;
|
|
32
|
+
|
|
33
|
+
add(pdfName: string, data: PdfData) {
|
|
34
|
+
const id = generateId();
|
|
35
|
+
const pdf: IPdfDocument = { id, pdfName, data };
|
|
36
|
+
|
|
37
|
+
if (!data.url && !data.b64) {
|
|
38
|
+
this.notificationService.error(translate("pdfManager.missingData"));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (data.url && data.b64) {
|
|
42
|
+
this.notificationService.error(translate("pdfManager.duplicatedSource"));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!this.hasBeenActivated) {
|
|
46
|
+
this.registerNavButton();
|
|
47
|
+
this.hasBeenActivated = true;
|
|
48
|
+
}
|
|
49
|
+
if (this.pdfs.some((p) => p.pdfName === pdf.pdfName)) {
|
|
50
|
+
this.notificationService.warning(translate("pdfManager.alreadyUploaded"));
|
|
51
|
+
} else {
|
|
52
|
+
this.pdfs.push(pdf as IPdfDocument);
|
|
53
|
+
this.broker.publish(pdfViwerEvents.added, pdf);
|
|
54
|
+
|
|
55
|
+
this.notificationService.success(translate("pdfManager.uploaded"));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
delete(pdfId: string) {
|
|
60
|
+
this.pdfs = this.pdfs.filter((pdf) => pdf.id !== pdfId);
|
|
61
|
+
|
|
62
|
+
if (this.activePdf?.id === pdfId) {
|
|
63
|
+
this.activePdf = null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.broker.publish(pdfViwerEvents.deleted, { id: pdfId });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getPdfs(): IPdfDocument[] {
|
|
70
|
+
return this.pdfs;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private registerNavButton() {
|
|
74
|
+
this.regionManager.registerView(shellRegions.navigationMenu, {
|
|
75
|
+
id: pdfViewerId,
|
|
76
|
+
factory: () => {
|
|
77
|
+
const menuItem = new PrimariaNavItem({
|
|
78
|
+
icon: "picture_as_pdf",
|
|
79
|
+
label: translate("pdfManager.navButtonLabel"),
|
|
80
|
+
callbackFn: () => {
|
|
81
|
+
this.regionManager.activateMainView(pdfViewerId);
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
return Promise.resolve(menuItem);
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const pdfViewerManager = (broker, interactionManager, regionManager) =>
|
|
91
|
+
new PdfViewerManager(broker, interactionManager, regionManager);
|
|
92
|
+
|
|
93
|
+
export const createPdfViewerManager = (
|
|
94
|
+
broker: PrimariaBroker,
|
|
95
|
+
notificationService: PrimariaNotificationService,
|
|
96
|
+
regionManager: PrimariaRegionManager,
|
|
97
|
+
) => pdfViewerManager(broker, notificationService, regionManager);
|
|
@@ -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
|
});
|
|
@@ -1,22 +1,44 @@
|
|
|
1
|
+
import { shellEvents } from "../../events";
|
|
2
|
+
import { PrimariaBroker } from "../broker/primaria-broker";
|
|
3
|
+
|
|
1
4
|
export interface PluginBusyTask {
|
|
2
5
|
taskId: string;
|
|
3
6
|
taskDescription: string;
|
|
4
7
|
}
|
|
5
8
|
|
|
9
|
+
export interface QuickActionBusyTask {
|
|
10
|
+
taskId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
export abstract class PluginBusyManager {
|
|
7
14
|
abstract addBusyPluginTask(busyTask: PluginBusyTask): void;
|
|
8
|
-
abstract removeBusyPluginTask(taskId: string):
|
|
15
|
+
abstract removeBusyPluginTask(taskId: string): void;
|
|
16
|
+
abstract addBusyQuickActionTask(busyTask: QuickActionBusyTask): void;
|
|
17
|
+
abstract removeBusyQuickActionTask(taskId: string): void;
|
|
9
18
|
abstract clearAllBusyPlugins(): void;
|
|
10
19
|
abstract isAnyPluginBusy(): boolean;
|
|
20
|
+
abstract isAnyQuickActionBusy(): boolean;
|
|
11
21
|
abstract getBusyPluginTasks(): PluginBusyTask[];
|
|
12
22
|
}
|
|
13
23
|
export class PluginBusyManagerImpl implements PluginBusyManager {
|
|
24
|
+
constructor(public broker: PrimariaBroker) {}
|
|
14
25
|
private busyPluginTasks: PluginBusyTask[] = [];
|
|
26
|
+
private busyQuickActionTasks: QuickActionBusyTask[] = [];
|
|
15
27
|
|
|
16
28
|
public addBusyPluginTask(busyTask: PluginBusyTask): void {
|
|
17
29
|
this.busyPluginTasks.push(busyTask);
|
|
18
30
|
}
|
|
19
31
|
|
|
32
|
+
public addBusyQuickActionTask(busyTask: QuickActionBusyTask): void {
|
|
33
|
+
const index = this.busyQuickActionTasks.findIndex((item) => item.taskId === busyTask.taskId);
|
|
34
|
+
if (index > -1) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.busyQuickActionTasks.push(busyTask);
|
|
39
|
+
this.emitQuickActionBusyChanged();
|
|
40
|
+
}
|
|
41
|
+
|
|
20
42
|
public removeBusyPluginTask(taskId: string): any {
|
|
21
43
|
const index = this.busyPluginTasks.findIndex((item) => item.taskId === taskId);
|
|
22
44
|
if (index > -1) {
|
|
@@ -24,15 +46,36 @@ export class PluginBusyManagerImpl implements PluginBusyManager {
|
|
|
24
46
|
}
|
|
25
47
|
}
|
|
26
48
|
|
|
49
|
+
public removeBusyQuickActionTask(taskId: string): any {
|
|
50
|
+
const index = this.busyQuickActionTasks.findIndex((item) => item.taskId === taskId);
|
|
51
|
+
if (index > -1) {
|
|
52
|
+
this.busyQuickActionTasks.splice(index, 1);
|
|
53
|
+
this.emitQuickActionBusyChanged();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
27
57
|
public isAnyPluginBusy(): boolean {
|
|
28
58
|
return this.busyPluginTasks.length > 0;
|
|
29
59
|
}
|
|
30
60
|
|
|
61
|
+
public isAnyQuickActionBusy(): boolean {
|
|
62
|
+
return this.busyQuickActionTasks.length > 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
31
65
|
public clearAllBusyPlugins(): void {
|
|
32
66
|
this.busyPluginTasks = [];
|
|
33
67
|
}
|
|
34
68
|
|
|
69
|
+
public clearAllBusyQuickActions(): void {
|
|
70
|
+
this.busyQuickActionTasks = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
35
73
|
public getBusyPluginTasks(): PluginBusyTask[] {
|
|
36
74
|
return this.busyPluginTasks;
|
|
37
75
|
}
|
|
76
|
+
|
|
77
|
+
private emitQuickActionBusyChanged() {
|
|
78
|
+
const busy = this.isAnyQuickActionBusy();
|
|
79
|
+
this.broker.publish(shellEvents.quickActionBusyChanged, { busy });
|
|
80
|
+
}
|
|
38
81
|
}
|
package/src/constants.ts
CHANGED
package/src/events.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PrimariaApi } from "@uxland/primary-shell";
|
|
2
2
|
import { TYPES } from "../../infrastructure/ioc/types";
|
|
3
3
|
import { inject } from "inversify";
|
|
4
4
|
import { ExitShell } from "./request";
|
|
@@ -27,9 +27,7 @@ export class ExitShellHandler {
|
|
|
27
27
|
|
|
28
28
|
raiseCloseEvent();
|
|
29
29
|
} catch (error) {
|
|
30
|
-
this.api.notificationService.error(
|
|
31
|
-
error.message,
|
|
32
|
-
);
|
|
30
|
+
this.api.notificationService.error(error.message);
|
|
33
31
|
}
|
|
34
32
|
}
|
|
35
33
|
|