@uxland/primary-shell 7.37.1 → 7.38.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/{component-BHhqZswN.js → component-BnGIF_Io.js} +2 -2
- package/dist/{component-BHhqZswN.js.map → component-BnGIF_Io.js.map} +1 -1
- package/dist/{index-B-kHRe1g.js → index-CqHIFgjZ.js} +477 -467
- package/dist/index-CqHIFgjZ.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.umd.cjs +30 -30
- package/dist/index.umd.cjs.map +1 -1
- package/dist/primary/shell/src/api/api.d.ts +2 -0
- package/dist/primary/shell/src/api/exit-guard-manager/exit-guard-manager.d.ts +12 -0
- package/dist/primary/shell/src/api/exit-guard-manager/exit-guard-manager.test.d.ts +1 -0
- package/dist/primary/shell/src/api/plugin-busy-manager/plugin-busy-manager.d.ts +6 -0
- package/dist/primary/shell/src/features/exit/handler.d.ts +0 -1
- package/package.json +1 -1
- package/src/api/api.ts +8 -19
- package/src/api/exit-guard-manager/exit-guard-manager.test.ts +75 -0
- package/src/api/exit-guard-manager/exit-guard-manager.ts +31 -0
- package/src/api/pdf-viewer-manager/pdf-visor/pdf-visor.ts +7 -8
- package/src/api/plugin-busy-manager/plugin-busy-manager.ts +6 -0
- package/src/features/exit/handler.test.ts +20 -52
- package/src/features/exit/handler.ts +2 -16
- package/dist/index-B-kHRe1g.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ApiFactory, HarmonixApi } from '@uxland/harmonix';
|
|
2
2
|
import { PrimariaBroker } from './broker/primaria-broker';
|
|
3
3
|
import { EcapEventManager } from './ecap-event-manager/ecap-event-manager';
|
|
4
|
+
import { ExitGuardManager } from './exit-guard-manager/exit-guard-manager';
|
|
4
5
|
import { PrimariaGlobalStateManager } from './global-state/global-state';
|
|
5
6
|
import { HttpClient } from './http-client/http-client';
|
|
6
7
|
import { PrimariaInteractionService } from './interaction-service';
|
|
@@ -25,6 +26,7 @@ export interface PrimariaApi extends HarmonixApi {
|
|
|
25
26
|
userManager: UserManager;
|
|
26
27
|
ecapEventManager: EcapEventManager;
|
|
27
28
|
pluginBusyManager: PluginBusyManager;
|
|
29
|
+
exitGuardManager: ExitGuardManager;
|
|
28
30
|
quickActionBusyManager: QuickActionBusyManager;
|
|
29
31
|
pdfViewerManager: PdfViewerManager;
|
|
30
32
|
importDataManager: PrimariaImportDataManager;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ExitGuardCanDispose = () => Promise<boolean>;
|
|
2
|
+
export declare abstract class ExitGuardManager {
|
|
3
|
+
abstract register(id: string, canDispose: ExitGuardCanDispose): void;
|
|
4
|
+
abstract unregister(id: string): void;
|
|
5
|
+
abstract canExit(): Promise<boolean>;
|
|
6
|
+
}
|
|
7
|
+
export declare class ExitGuardManagerImpl implements ExitGuardManager {
|
|
8
|
+
private guards;
|
|
9
|
+
register(id: string, canDispose: ExitGuardCanDispose): void;
|
|
10
|
+
unregister(id: string): void;
|
|
11
|
+
canExit(): Promise<boolean>;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,6 +2,11 @@ export interface PluginTask {
|
|
|
2
2
|
taskId: string;
|
|
3
3
|
taskDescription: string;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated Use the `canDispose(api)` plugin lifecycle hook instead. Plugins should
|
|
7
|
+
* decide whether they can be disposed (e.g. show their own confirmation modal) rather
|
|
8
|
+
* than relying on shell-level busy tasks. This API is kept for backwards compatibility.
|
|
9
|
+
*/
|
|
5
10
|
export declare abstract class PluginBusyManager {
|
|
6
11
|
abstract addTask(task: PluginTask): void;
|
|
7
12
|
abstract removeTask(taskId: string): void;
|
|
@@ -9,6 +14,7 @@ export declare abstract class PluginBusyManager {
|
|
|
9
14
|
abstract isBusy(): boolean;
|
|
10
15
|
abstract getTasks(): PluginTask[];
|
|
11
16
|
}
|
|
17
|
+
/** @deprecated See {@link PluginBusyManager}. */
|
|
12
18
|
export declare class PluginBusyManagerImpl implements PluginBusyManager {
|
|
13
19
|
private tasks;
|
|
14
20
|
constructor();
|
package/package.json
CHANGED
package/src/api/api.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ApiFactory,
|
|
3
|
-
HarmonixApi,
|
|
4
|
-
PluginInfo,
|
|
5
|
-
RegionManager,
|
|
6
|
-
createRegionHost,
|
|
7
|
-
createRegionManager,
|
|
8
|
-
} from "@uxland/harmonix";
|
|
1
|
+
import { ApiFactory, HarmonixApi, PluginInfo, RegionManager, createRegionHost, createRegionManager } from "@uxland/harmonix";
|
|
9
2
|
import { primariaShellId } from "../constants";
|
|
10
3
|
import { createBroker } from "./broker/factory";
|
|
11
4
|
import { PrimariaBroker } from "./broker/primaria-broker";
|
|
12
5
|
import { EcapEventManager, createEcapEventManager } from "./ecap-event-manager/ecap-event-manager";
|
|
6
|
+
import { ExitGuardManager, ExitGuardManagerImpl } from "./exit-guard-manager/exit-guard-manager";
|
|
13
7
|
import { PrimariaGlobalStateManager, createGlobalStateManager } from "./global-state/global-state";
|
|
14
8
|
import { HttpClient, createHttpClient } from "./http-client/http-client";
|
|
15
9
|
import { PrimariaInteractionService } from "./interaction-service";
|
|
@@ -18,14 +12,8 @@ import { createLocaleManager } from "./localization/localization";
|
|
|
18
12
|
import { PrimariaNotificationService } from "./notification-service/notification-service";
|
|
19
13
|
import { PrimariaNotificationServiceImpl } from "./notification-service/notification.service-impl";
|
|
20
14
|
import { PdfViewerManager, createPdfViewerManager } from "./pdf-viewer-manager/pdf-viewer-manager";
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
PluginBusyManagerImpl,
|
|
24
|
-
} from "./plugin-busy-manager/plugin-busy-manager";
|
|
25
|
-
import {
|
|
26
|
-
QuickActionBusyManager,
|
|
27
|
-
QuickActionBusyManagerImpl,
|
|
28
|
-
} from "./quick-action-busy-manager/quick-action-busy-manager";
|
|
15
|
+
import { PluginBusyManager, PluginBusyManagerImpl } from "./plugin-busy-manager/plugin-busy-manager";
|
|
16
|
+
import { QuickActionBusyManager, QuickActionBusyManagerImpl } from "./quick-action-busy-manager/quick-action-busy-manager";
|
|
29
17
|
import { PrimariaRegionManager, createRegionManagerProxy } from "./region-manager/region-manager";
|
|
30
18
|
import { TokenManager, createTokenManager } from "./token-manager/token-manager";
|
|
31
19
|
import { UserManager, createUserManager } from "./user-manager/user-manager";
|
|
@@ -46,6 +34,7 @@ export interface PrimariaApi extends HarmonixApi {
|
|
|
46
34
|
userManager: UserManager;
|
|
47
35
|
ecapEventManager: EcapEventManager;
|
|
48
36
|
pluginBusyManager: PluginBusyManager;
|
|
37
|
+
exitGuardManager: ExitGuardManager;
|
|
49
38
|
quickActionBusyManager: QuickActionBusyManager;
|
|
50
39
|
pdfViewerManager: PdfViewerManager;
|
|
51
40
|
importDataManager: PrimariaImportDataManager;
|
|
@@ -58,6 +47,7 @@ const userManager = createUserManager(tokenManager);
|
|
|
58
47
|
const globalStateManager: PrimariaGlobalStateManager = createGlobalStateManager(broker);
|
|
59
48
|
const contextManager = createContextManager();
|
|
60
49
|
const pluginBusyManager = new PluginBusyManagerImpl();
|
|
50
|
+
const exitGuardManager = new ExitGuardManagerImpl();
|
|
61
51
|
const quickActionBusyManager = new QuickActionBusyManagerImpl(broker);
|
|
62
52
|
const interactionService = new ParimariaInteractionServiceImpl();
|
|
63
53
|
const notificationService = new PrimariaNotificationServiceImpl();
|
|
@@ -71,9 +61,7 @@ const importDataManager = new ImportDataManagerImpl(interactionService);
|
|
|
71
61
|
* @param {PluginInfo} pluginInfo - Information about the plugin
|
|
72
62
|
* @return {PrimariaApi} The created Primaria API instance
|
|
73
63
|
*/
|
|
74
|
-
export const primariaApiFactory: ApiFactory<PrimariaApi> = (
|
|
75
|
-
pluginInfo: PluginInfo,
|
|
76
|
-
): PrimariaApi => {
|
|
64
|
+
export const primariaApiFactory: ApiFactory<PrimariaApi> = (pluginInfo: PluginInfo): PrimariaApi => {
|
|
77
65
|
const regionManagerProxy = createRegionManagerProxy(pluginInfo, regionManager, broker);
|
|
78
66
|
|
|
79
67
|
return {
|
|
@@ -88,6 +76,7 @@ export const primariaApiFactory: ApiFactory<PrimariaApi> = (
|
|
|
88
76
|
userManager,
|
|
89
77
|
ecapEventManager,
|
|
90
78
|
pluginBusyManager,
|
|
79
|
+
exitGuardManager,
|
|
91
80
|
quickActionBusyManager,
|
|
92
81
|
interactionService,
|
|
93
82
|
notificationService,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { ExitGuardManagerImpl } from "./exit-guard-manager";
|
|
3
|
+
|
|
4
|
+
describe("ExitGuardManagerImpl", () => {
|
|
5
|
+
let manager: ExitGuardManagerImpl;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
manager = new ExitGuardManagerImpl();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("canExit resolves true when no guards are registered", async () => {
|
|
12
|
+
await expect(manager.canExit()).resolves.toBe(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("canExit resolves true when every guard returns true", async () => {
|
|
16
|
+
manager.register("a", async () => true);
|
|
17
|
+
manager.register("b", async () => true);
|
|
18
|
+
|
|
19
|
+
await expect(manager.canExit()).resolves.toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("canExit resolves false when any guard returns false", async () => {
|
|
23
|
+
manager.register("a", async () => true);
|
|
24
|
+
manager.register("b", async () => false);
|
|
25
|
+
|
|
26
|
+
await expect(manager.canExit()).resolves.toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("canExit short-circuits and does not run guards after a false", async () => {
|
|
30
|
+
const guardA = vi.fn(async () => false);
|
|
31
|
+
const guardB = vi.fn(async () => true);
|
|
32
|
+
|
|
33
|
+
manager.register("a", guardA);
|
|
34
|
+
manager.register("b", guardB);
|
|
35
|
+
|
|
36
|
+
await manager.canExit();
|
|
37
|
+
|
|
38
|
+
expect(guardA).toHaveBeenCalled();
|
|
39
|
+
expect(guardB).not.toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("unregister removes the guard", async () => {
|
|
43
|
+
const guard = vi.fn(async () => false);
|
|
44
|
+
manager.register("a", guard);
|
|
45
|
+
manager.unregister("a");
|
|
46
|
+
|
|
47
|
+
await expect(manager.canExit()).resolves.toBe(true);
|
|
48
|
+
expect(guard).not.toHaveBeenCalled();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("register overwrites an existing guard with the same id", async () => {
|
|
52
|
+
manager.register("a", async () => false);
|
|
53
|
+
manager.register("a", async () => true);
|
|
54
|
+
|
|
55
|
+
await expect(manager.canExit()).resolves.toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("swallows errors in guards and continues with the remaining ones", async () => {
|
|
59
|
+
const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
60
|
+
const failing = vi.fn(async () => {
|
|
61
|
+
throw new Error("boom");
|
|
62
|
+
});
|
|
63
|
+
const allowing = vi.fn(async () => true);
|
|
64
|
+
|
|
65
|
+
manager.register("a", failing);
|
|
66
|
+
manager.register("b", allowing);
|
|
67
|
+
|
|
68
|
+
await expect(manager.canExit()).resolves.toBe(true);
|
|
69
|
+
expect(failing).toHaveBeenCalled();
|
|
70
|
+
expect(allowing).toHaveBeenCalled();
|
|
71
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("Exit guard failed:", expect.any(Error));
|
|
72
|
+
|
|
73
|
+
consoleErrorSpy.mockRestore();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type ExitGuardCanDispose = () => Promise<boolean>;
|
|
2
|
+
|
|
3
|
+
export abstract class ExitGuardManager {
|
|
4
|
+
abstract register(id: string, canDispose: ExitGuardCanDispose): void;
|
|
5
|
+
abstract unregister(id: string): void;
|
|
6
|
+
abstract canExit(): Promise<boolean>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class ExitGuardManagerImpl implements ExitGuardManager {
|
|
10
|
+
private guards = new Map<string, ExitGuardCanDispose>();
|
|
11
|
+
|
|
12
|
+
register(id: string, canDispose: ExitGuardCanDispose): void {
|
|
13
|
+
this.guards.set(id, canDispose);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
unregister(id: string): void {
|
|
17
|
+
this.guards.delete(id);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async canExit(): Promise<boolean> {
|
|
21
|
+
for (const guard of this.guards.values()) {
|
|
22
|
+
try {
|
|
23
|
+
const can = await guard();
|
|
24
|
+
if (!can) return false;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error("Exit guard failed:", e);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -46,10 +46,12 @@ export class PdfVisor extends LitElement {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
private _getPdfSrc(pdf: IPdfDocument) {
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
49
|
+
private _getPdfSrc(pdf: IPdfDocument): string {
|
|
50
|
+
const src = pdf.data.url || (pdf.data.b64 ? createUrlFromBase64(pdf.data.b64) : "") || "";
|
|
51
|
+
if (!src) return "";
|
|
52
|
+
|
|
53
|
+
const separator = src.includes("#") ? "&" : "#";
|
|
54
|
+
return `${src}${separator}navpanes=0`;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
private _subscribeEvents() {
|
|
@@ -101,10 +103,7 @@ export class PdfVisor extends LitElement {
|
|
|
101
103
|
<div class="pdf-container">
|
|
102
104
|
${
|
|
103
105
|
this.activePdfs.length > 0
|
|
104
|
-
? this.activePdfs.map(
|
|
105
|
-
(pdf) =>
|
|
106
|
-
html`<iframe height="100%" src=${this._getPdfSrc(pdf)} frameborder="0"></iframe>`,
|
|
107
|
-
)
|
|
106
|
+
? this.activePdfs.map((pdf) => html`<iframe height="100%" src=${this._getPdfSrc(pdf)} frameborder="0"></iframe>`)
|
|
108
107
|
: html`
|
|
109
108
|
<div class="no-pdf">
|
|
110
109
|
<p>${translate("pdfVisor.noPdfSelected")}</p>
|
|
@@ -6,6 +6,11 @@ export interface PluginTask {
|
|
|
6
6
|
taskDescription: string;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Use the `canDispose(api)` plugin lifecycle hook instead. Plugins should
|
|
11
|
+
* decide whether they can be disposed (e.g. show their own confirmation modal) rather
|
|
12
|
+
* than relying on shell-level busy tasks. This API is kept for backwards compatibility.
|
|
13
|
+
*/
|
|
9
14
|
export abstract class PluginBusyManager {
|
|
10
15
|
abstract addTask(task: PluginTask): void;
|
|
11
16
|
abstract removeTask(taskId: string): void;
|
|
@@ -14,6 +19,7 @@ export abstract class PluginBusyManager {
|
|
|
14
19
|
abstract getTasks(): PluginTask[];
|
|
15
20
|
}
|
|
16
21
|
|
|
22
|
+
/** @deprecated See {@link PluginBusyManager}. */
|
|
17
23
|
export class PluginBusyManagerImpl implements PluginBusyManager {
|
|
18
24
|
private tasks: PluginTask[] = [];
|
|
19
25
|
|
|
@@ -3,9 +3,7 @@ import { ExitShellHandler } from "./handler";
|
|
|
3
3
|
import { ExitShell } from "./request";
|
|
4
4
|
import { disposePlugins } from "../../handle-plugins";
|
|
5
5
|
import { disposeShell, raiseCloseEvent, raiseCustomCloseEvent } from "../../disposer";
|
|
6
|
-
import { PluginBusyTask } from "../../api/plugin-busy-manager/plugin-busy-manager";
|
|
7
6
|
import { PrimariaApi } from "../../api/api";
|
|
8
|
-
import { PluginBusyList } from "../../api/plugin-busy-manager/plugin-busy-list/component";
|
|
9
7
|
|
|
10
8
|
vi.mock("../../handle-plugins", () => ({
|
|
11
9
|
disposePlugins: vi.fn(),
|
|
@@ -19,11 +17,8 @@ vi.mock("../../disposer", () => ({
|
|
|
19
17
|
|
|
20
18
|
const createMockApi = (): PrimariaApi =>
|
|
21
19
|
({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
25
|
-
interactionService: {
|
|
26
|
-
confirm: vi.fn(),
|
|
20
|
+
exitGuardManager: {
|
|
21
|
+
canExit: vi.fn(),
|
|
27
22
|
},
|
|
28
23
|
notificationService: {
|
|
29
24
|
error: vi.fn(),
|
|
@@ -40,21 +35,22 @@ describe("ExitShellHandler", () => {
|
|
|
40
35
|
vi.clearAllMocks();
|
|
41
36
|
});
|
|
42
37
|
|
|
43
|
-
it("
|
|
38
|
+
it("disposes and raises custom close event when canExit resolves true and message has ecapEvent", async () => {
|
|
44
39
|
const message = { ecapEvent: {} } as ExitShell;
|
|
45
|
-
mockApi.
|
|
40
|
+
(mockApi.exitGuardManager.canExit as any).mockResolvedValue(true);
|
|
46
41
|
(disposePlugins as any).mockResolvedValue(undefined);
|
|
47
42
|
|
|
48
43
|
await handler.handle(message);
|
|
49
44
|
|
|
45
|
+
expect(mockApi.exitGuardManager.canExit).toHaveBeenCalled();
|
|
50
46
|
expect(disposePlugins).toHaveBeenCalled();
|
|
51
47
|
expect(disposeShell).toHaveBeenCalled();
|
|
52
48
|
expect(raiseCustomCloseEvent).toHaveBeenCalledWith(message);
|
|
53
49
|
});
|
|
54
50
|
|
|
55
|
-
it("
|
|
51
|
+
it("raises default close event when no ecapEvent is present", async () => {
|
|
56
52
|
const message = {} as ExitShell;
|
|
57
|
-
mockApi.
|
|
53
|
+
(mockApi.exitGuardManager.canExit as any).mockResolvedValue(true);
|
|
58
54
|
(disposePlugins as any).mockResolvedValue(undefined);
|
|
59
55
|
|
|
60
56
|
await handler.handle(message);
|
|
@@ -65,50 +61,23 @@ describe("ExitShellHandler", () => {
|
|
|
65
61
|
expect(raiseCustomCloseEvent).not.toHaveBeenCalled();
|
|
66
62
|
});
|
|
67
63
|
|
|
68
|
-
it("
|
|
69
|
-
const busyTasks: PluginBusyTask[] = [{ pluginId: "x" }] as any;
|
|
70
|
-
const message = { ecapEvent: {} } as ExitShell;
|
|
71
|
-
mockApi.pluginBusyManager.getTasks = vi.fn().mockReturnValue(busyTasks);
|
|
72
|
-
mockApi.interactionService.confirm = vi.fn().mockResolvedValue({ confirmed: true });
|
|
73
|
-
(disposePlugins as any).mockResolvedValue(undefined);
|
|
74
|
-
|
|
75
|
-
await handler.handle(message);
|
|
76
|
-
|
|
77
|
-
expect(mockApi.interactionService.confirm).toHaveBeenCalledWith(
|
|
78
|
-
{ busyTasks },
|
|
79
|
-
{ component: PluginBusyList },
|
|
80
|
-
{
|
|
81
|
-
title: "actions.askExit",
|
|
82
|
-
state: "error",
|
|
83
|
-
confirmButtonText: "Sí",
|
|
84
|
-
cancelButtonText: "No",
|
|
85
|
-
},
|
|
86
|
-
);
|
|
87
|
-
expect(disposePlugins).toHaveBeenCalled();
|
|
88
|
-
expect(disposeShell).toHaveBeenCalled();
|
|
89
|
-
expect(raiseCustomCloseEvent).toHaveBeenCalledWith(message);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it("should not continue if confirmation is declined", async () => {
|
|
93
|
-
const busyTasks: PluginBusyTask[] = [{ pluginId: "x" }] as any;
|
|
64
|
+
it("aborts the exit when any guard returns false", async () => {
|
|
94
65
|
const message = { ecapEvent: {} } as ExitShell;
|
|
95
|
-
mockApi.
|
|
96
|
-
mockApi.interactionService.confirm = vi.fn().mockResolvedValue({ confirmed: false });
|
|
66
|
+
(mockApi.exitGuardManager.canExit as any).mockResolvedValue(false);
|
|
97
67
|
|
|
98
68
|
await handler.handle(message);
|
|
99
69
|
|
|
100
|
-
expect(mockApi.
|
|
70
|
+
expect(mockApi.exitGuardManager.canExit).toHaveBeenCalled();
|
|
101
71
|
expect(disposePlugins).not.toHaveBeenCalled();
|
|
102
72
|
expect(disposeShell).not.toHaveBeenCalled();
|
|
103
73
|
expect(raiseCustomCloseEvent).not.toHaveBeenCalled();
|
|
104
74
|
expect(raiseCloseEvent).not.toHaveBeenCalled();
|
|
105
75
|
});
|
|
106
76
|
|
|
107
|
-
it("
|
|
108
|
-
const error = new Error("Something went wrong");
|
|
77
|
+
it("notifies and raises custom close event when dispose throws and ecapEvent is present", async () => {
|
|
109
78
|
const message = { ecapEvent: {} } as ExitShell;
|
|
110
|
-
mockApi.
|
|
111
|
-
(disposePlugins as any).mockRejectedValue(
|
|
79
|
+
(mockApi.exitGuardManager.canExit as any).mockResolvedValue(true);
|
|
80
|
+
(disposePlugins as any).mockRejectedValue(new Error("boom"));
|
|
112
81
|
|
|
113
82
|
await handler.handle(message);
|
|
114
83
|
|
|
@@ -117,11 +86,10 @@ describe("ExitShellHandler", () => {
|
|
|
117
86
|
expect(raiseCloseEvent).not.toHaveBeenCalled();
|
|
118
87
|
});
|
|
119
88
|
|
|
120
|
-
it("
|
|
121
|
-
const error = new Error("Something went wrong");
|
|
89
|
+
it("notifies and raises default close event when dispose throws and no ecapEvent", async () => {
|
|
122
90
|
const message = {} as ExitShell;
|
|
123
|
-
mockApi.
|
|
124
|
-
(disposePlugins as any).mockRejectedValue(
|
|
91
|
+
(mockApi.exitGuardManager.canExit as any).mockResolvedValue(true);
|
|
92
|
+
(disposePlugins as any).mockRejectedValue(new Error("boom"));
|
|
125
93
|
|
|
126
94
|
await handler.handle(message);
|
|
127
95
|
|
|
@@ -130,9 +98,9 @@ describe("ExitShellHandler", () => {
|
|
|
130
98
|
expect(raiseCustomCloseEvent).not.toHaveBeenCalled();
|
|
131
99
|
});
|
|
132
100
|
|
|
133
|
-
it("
|
|
101
|
+
it("proceeds if disposePlugins exceeds the 10s timeout", async () => {
|
|
134
102
|
const message = { ecapEvent: {} } as ExitShell;
|
|
135
|
-
mockApi.
|
|
103
|
+
(mockApi.exitGuardManager.canExit as any).mockResolvedValue(true);
|
|
136
104
|
(disposePlugins as any).mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 11000)));
|
|
137
105
|
|
|
138
106
|
await handler.handle(message);
|
|
@@ -142,8 +110,8 @@ describe("ExitShellHandler", () => {
|
|
|
142
110
|
expect(raiseCustomCloseEvent).toHaveBeenCalledWith(message);
|
|
143
111
|
}, 15000);
|
|
144
112
|
|
|
145
|
-
it("
|
|
146
|
-
mockApi.
|
|
113
|
+
it("raises raiseCloseEvent when no exitEvent is passed", async () => {
|
|
114
|
+
(mockApi.exitGuardManager.canExit as any).mockResolvedValue(true);
|
|
147
115
|
(disposePlugins as any).mockResolvedValue(undefined);
|
|
148
116
|
|
|
149
117
|
await handler.handle(undefined as any);
|
|
@@ -4,8 +4,6 @@ import { inject } from "inversify";
|
|
|
4
4
|
import { ExitShell } from "./request";
|
|
5
5
|
import { disposeShell, raiseCloseEvent, raiseCustomCloseEvent } from "../../disposer";
|
|
6
6
|
import { disposePlugins } from "../../handle-plugins";
|
|
7
|
-
import { PluginBusyTask } from "../../api/plugin-busy-manager/plugin-busy-manager";
|
|
8
|
-
import { PluginBusyList } from "../../api/plugin-busy-manager/plugin-busy-list/component";
|
|
9
7
|
import { translate } from "../../locales";
|
|
10
8
|
|
|
11
9
|
export class ExitShellHandler {
|
|
@@ -14,11 +12,8 @@ export class ExitShellHandler {
|
|
|
14
12
|
const evt = exitEvent && exitEvent.ecapEvent !== undefined ? exitEvent : undefined;
|
|
15
13
|
|
|
16
14
|
try {
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
const { confirmed } = await this.askForClose(busyTasks);
|
|
20
|
-
if (!confirmed) return;
|
|
21
|
-
}
|
|
15
|
+
const canExit = await this.api.exitGuardManager.canExit();
|
|
16
|
+
if (!canExit) return;
|
|
22
17
|
|
|
23
18
|
// Per si un plugin tarda molt en fer dispose, màxim deixarem 5 segons, per no interrompre el tancar infinitament
|
|
24
19
|
await Promise.race([
|
|
@@ -33,15 +28,6 @@ export class ExitShellHandler {
|
|
|
33
28
|
}
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
private askForClose(busyTasks: PluginBusyTask[]) {
|
|
37
|
-
return this.api.interactionService.confirm({ busyTasks }, {component: PluginBusyList}, {
|
|
38
|
-
title: translate("actions.askExit"),
|
|
39
|
-
state: "error",
|
|
40
|
-
confirmButtonText: "Sí",
|
|
41
|
-
cancelButtonText: "No",
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
31
|
private timeout(ms: number) {
|
|
46
32
|
return new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
47
33
|
}
|