@hydranium/glsp-client-theia 1.0.0-next.10
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/LICENSE +21 -0
- package/README.md +134 -0
- package/lib/browser/action-dispatcher.d.ts +85 -0
- package/lib/browser/action-dispatcher.d.ts.map +1 -0
- package/lib/browser/action-dispatcher.js +238 -0
- package/lib/browser/action-dispatcher.js.map +1 -0
- package/lib/browser/client-contribution.d.ts +53 -0
- package/lib/browser/client-contribution.d.ts.map +1 -0
- package/lib/browser/client-contribution.js +111 -0
- package/lib/browser/client-contribution.js.map +1 -0
- package/lib/browser/diagram-loader.d.ts +123 -0
- package/lib/browser/diagram-loader.d.ts.map +1 -0
- package/lib/browser/diagram-loader.js +153 -0
- package/lib/browser/diagram-loader.js.map +1 -0
- package/lib/browser/diagram-only-marker-manager.d.ts +28 -0
- package/lib/browser/diagram-only-marker-manager.d.ts.map +1 -0
- package/lib/browser/diagram-only-marker-manager.js +44 -0
- package/lib/browser/diagram-only-marker-manager.js.map +1 -0
- package/lib/browser/diagram-widget.d.ts +97 -0
- package/lib/browser/diagram-widget.d.ts.map +1 -0
- package/lib/browser/diagram-widget.js +172 -0
- package/lib/browser/diagram-widget.js.map +1 -0
- package/lib/browser/glsp-client-theia-module.d.ts +40 -0
- package/lib/browser/glsp-client-theia-module.d.ts.map +1 -0
- package/lib/browser/glsp-client-theia-module.js +46 -0
- package/lib/browser/glsp-client-theia-module.js.map +1 -0
- package/lib/browser/glsp-diagram-manager.d.ts +46 -0
- package/lib/browser/glsp-diagram-manager.d.ts.map +1 -0
- package/lib/browser/glsp-diagram-manager.js +66 -0
- package/lib/browser/glsp-diagram-manager.js.map +1 -0
- package/lib/browser/glsp-message-service.d.ts +59 -0
- package/lib/browser/glsp-message-service.d.ts.map +1 -0
- package/lib/browser/glsp-message-service.js +97 -0
- package/lib/browser/glsp-message-service.js.map +1 -0
- package/lib/browser/glsp-theia-frontend-module.d.ts +110 -0
- package/lib/browser/glsp-theia-frontend-module.d.ts.map +1 -0
- package/lib/browser/glsp-theia-frontend-module.js +133 -0
- package/lib/browser/glsp-theia-frontend-module.js.map +1 -0
- package/lib/browser/hidden-bounds-updater.d.ts +122 -0
- package/lib/browser/hidden-bounds-updater.d.ts.map +1 -0
- package/lib/browser/hidden-bounds-updater.js +207 -0
- package/lib/browser/hidden-bounds-updater.js.map +1 -0
- package/lib/browser/hydranium-glsp-diagram-configuration.d.ts +52 -0
- package/lib/browser/hydranium-glsp-diagram-configuration.d.ts.map +1 -0
- package/lib/browser/hydranium-glsp-diagram-configuration.js +72 -0
- package/lib/browser/hydranium-glsp-diagram-configuration.js.map +1 -0
- package/lib/browser/index.d.ts +20 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +38 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +39 -0
- package/lib/index.js.map +1 -0
- package/lib/node/connection-container-module.d.ts +22 -0
- package/lib/node/connection-container-module.d.ts.map +1 -0
- package/lib/node/connection-container-module.js +36 -0
- package/lib/node/connection-container-module.js.map +1 -0
- package/lib/node/glsp-server-connection-handler.d.ts +49 -0
- package/lib/node/glsp-server-connection-handler.d.ts.map +1 -0
- package/lib/node/glsp-server-connection-handler.js +64 -0
- package/lib/node/glsp-server-connection-handler.js.map +1 -0
- package/lib/node/index.d.ts +11 -0
- package/lib/node/index.d.ts.map +1 -0
- package/lib/node/index.js +28 -0
- package/lib/node/index.js.map +1 -0
- package/lib/testing/bind-recorder.d.ts +67 -0
- package/lib/testing/bind-recorder.d.ts.map +1 -0
- package/lib/testing/bind-recorder.js +72 -0
- package/lib/testing/bind-recorder.js.map +1 -0
- package/lib/testing/index.d.ts +10 -0
- package/lib/testing/index.d.ts.map +1 -0
- package/lib/testing/index.js +30 -0
- package/lib/testing/index.js.map +1 -0
- package/package.json +114 -0
- package/src/browser/action-dispatcher.ts +257 -0
- package/src/browser/client-contribution.ts +100 -0
- package/src/browser/diagram-loader.ts +173 -0
- package/src/browser/diagram-only-marker-manager.ts +33 -0
- package/src/browser/diagram-widget.ts +178 -0
- package/src/browser/glsp-client-theia-module.ts +54 -0
- package/src/browser/glsp-diagram-manager.ts +67 -0
- package/src/browser/glsp-message-service.ts +90 -0
- package/src/browser/glsp-theia-frontend-module.ts +157 -0
- package/src/browser/hidden-bounds-updater.ts +212 -0
- package/src/browser/hydranium-glsp-diagram-configuration.ts +63 -0
- package/src/browser/index.ts +22 -0
- package/src/index.ts +23 -0
- package/src/node/connection-container-module.ts +34 -0
- package/src/node/glsp-server-connection-handler.ts +69 -0
- package/src/node/index.ts +12 -0
- package/src/testing/bind-recorder.ts +126 -0
- package/src/testing/index.ts +15 -0
- package/style/diagram-loading.css +67 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
11
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
12
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
13
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
14
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
|
+
};
|
|
16
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
17
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
18
|
+
};
|
|
19
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
20
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.HydraniumGlspClientContribution = void 0;
|
|
24
|
+
const theia_integration_1 = require("@eclipse-glsp/theia-integration");
|
|
25
|
+
const promise_util_1 = require("@theia/core/lib/common/promise-util");
|
|
26
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
27
|
+
const output_channel_1 = require("@theia/output/lib/browser/output-channel");
|
|
28
|
+
const browser_1 = require("@theia/workspace/lib/browser");
|
|
29
|
+
/**
|
|
30
|
+
* Theia GLSP client contribution for adopters whose GLSP server runs in a
|
|
31
|
+
* sideloaded VS Code extension process (or any other deferred-start setup).
|
|
32
|
+
* The behaviours adopters reliably need are lifted:
|
|
33
|
+
*
|
|
34
|
+
* 1. `waitForBackendConnected`: tail the OutputChannel for a server-printed
|
|
35
|
+
* ready marker. While a socket connection might open earlier, the GLSP
|
|
36
|
+
* server typically does internal initialisation before it can accept
|
|
37
|
+
* client connections — we wait for it to say so.
|
|
38
|
+
* 2. `start`: defer until a workspace is opened. If Theia starts without a
|
|
39
|
+
* workspace, this prevents the frontend-backend connection (and its
|
|
40
|
+
* "connecting" progress spinner) from firing prematurely.
|
|
41
|
+
*
|
|
42
|
+
* A `GLSPClient` override filtering inbound messages by clientId is
|
|
43
|
+
* deliberately NOT provided: upstream's `BaseJsonrpcGLSPClient.onActionMessage`
|
|
44
|
+
* already filters by clientId, so the `TheiaJsonrpcGLSPClient` returned by
|
|
45
|
+
* `BaseGLSPClientContribution.createGLSPClient` is correct as-is.
|
|
46
|
+
*/
|
|
47
|
+
let HydraniumGlspClientContribution = class HydraniumGlspClientContribution extends theia_integration_1.BaseGLSPClientContribution {
|
|
48
|
+
outputChannelManager;
|
|
49
|
+
workspaceService;
|
|
50
|
+
id;
|
|
51
|
+
channelName;
|
|
52
|
+
readyMarker;
|
|
53
|
+
constructor(options) {
|
|
54
|
+
super();
|
|
55
|
+
this.id = options.languageContributionId;
|
|
56
|
+
this.channelName = options.channelName;
|
|
57
|
+
this.readyMarker = options.readyMarker;
|
|
58
|
+
}
|
|
59
|
+
/** Wait for the server to print its ready marker into the OutputChannel.
|
|
60
|
+
* Resolves immediately if the marker is already present (server started
|
|
61
|
+
* before the client contribution mounted). */
|
|
62
|
+
async waitForBackendConnected() {
|
|
63
|
+
const channel = this.outputChannelManager.getChannel(this.channelName);
|
|
64
|
+
const channelText = channel.resource?.textModel?.getValue() ?? '';
|
|
65
|
+
if (channelText.includes(this.readyMarker)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const deferred = new promise_util_1.Deferred();
|
|
69
|
+
const channelListener = channel.onContentChange(() => {
|
|
70
|
+
const text = channel.resource?.textModel?.getValue() ?? '';
|
|
71
|
+
if (text.includes(this.readyMarker)) {
|
|
72
|
+
channelListener.dispose();
|
|
73
|
+
deferred.resolve();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return deferred.promise;
|
|
77
|
+
}
|
|
78
|
+
async start(glspClient) {
|
|
79
|
+
// Defer starting the GLSP client until a workspace is opened. If Theia
|
|
80
|
+
// starts without a workspace, this prevents creating the frontend-
|
|
81
|
+
// backend connection (and showing the "connecting" progress) prematurely.
|
|
82
|
+
const roots = this.workspaceService.tryGetRoots();
|
|
83
|
+
if (!roots || roots.length === 0) {
|
|
84
|
+
await new Promise(resolve => {
|
|
85
|
+
const disposable = this.workspaceService.onWorkspaceChanged(changedRoots => {
|
|
86
|
+
if (changedRoots && changedRoots.length > 0) {
|
|
87
|
+
disposable.dispose();
|
|
88
|
+
resolve();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
await this.waitForBackendConnected();
|
|
94
|
+
return super.start(glspClient);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
exports.HydraniumGlspClientContribution = HydraniumGlspClientContribution;
|
|
98
|
+
__decorate([
|
|
99
|
+
(0, inversify_1.inject)(output_channel_1.OutputChannelManager),
|
|
100
|
+
__metadata("design:type", output_channel_1.OutputChannelManager)
|
|
101
|
+
], HydraniumGlspClientContribution.prototype, "outputChannelManager", void 0);
|
|
102
|
+
__decorate([
|
|
103
|
+
(0, inversify_1.inject)(browser_1.WorkspaceService),
|
|
104
|
+
__metadata("design:type", browser_1.WorkspaceService)
|
|
105
|
+
], HydraniumGlspClientContribution.prototype, "workspaceService", void 0);
|
|
106
|
+
exports.HydraniumGlspClientContribution = HydraniumGlspClientContribution = __decorate([
|
|
107
|
+
(0, inversify_1.injectable)(),
|
|
108
|
+
__param(0, (0, inversify_1.unmanaged)()),
|
|
109
|
+
__metadata("design:paramtypes", [Object])
|
|
110
|
+
], HydraniumGlspClientContribution);
|
|
111
|
+
//# sourceMappingURL=client-contribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-contribution.js","sourceRoot":"","sources":["../../src/browser/client-contribution.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;AAGlF,uEAA6E;AAC7E,sEAA+D;AAC/D,4DAA6E;AAC7E,6EAAgF;AAChF,0DAAgE;AAYhE;;;;;;;;;;;;;;;;;GAiBG;AAEI,IAAM,+BAA+B,GAArC,MAAM,+BAAgC,SAAQ,8CAA0B;IACpC,oBAAoB,CAAwB;IACvC,gBAAgB,CAAoB;IAExE,EAAE,CAAS;IACD,WAAW,CAAS;IACpB,WAAW,CAAS;IAEvC,YAAyB,OAAkC;QACxD,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAC1C,CAAC;IAED;;mDAE+C;IACrC,KAAK,CAAC,uBAAuB;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvE,MAAM,WAAW,GACb,OAA4E,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACvH,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC1C,OAAO;QACV,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,uBAAQ,EAAQ,CAAC;QACtC,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,EAAE;YAClD,MAAM,IAAI,GAAI,OAA4E,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACjI,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;gBACnC,eAAe,CAAC,OAAO,EAAE,CAAC;gBAC1B,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtB,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC3B,CAAC;IAEkB,KAAK,CAAC,KAAK,CAAC,UAAsB;QAClD,uEAAuE;QACvE,mEAAmE;QACnE,0EAA0E;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC;QAClD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;gBAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE;oBACxE,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC3C,UAAU,CAAC,OAAO,EAAE,CAAC;wBACrB,OAAO,EAAE,CAAC;oBACb,CAAC;gBACJ,CAAC,CAAC,CAAC;YACN,CAAC,CAAC,CAAC;QACN,CAAC;QACD,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;CACH,CAAA;AAtDY,0EAA+B;AACD;IAAvC,IAAA,kBAAM,EAAC,qCAAoB,CAAC;8BAAkC,qCAAoB;6EAAC;AACvC;IAA5C,IAAA,kBAAM,EAAC,0BAAgB,CAAC;8BAAuC,0BAAgB;yEAAC;0CAFvE,+BAA+B;IAD3C,IAAA,sBAAU,GAAE;IASG,WAAA,IAAA,qBAAS,GAAE,CAAA;;GARd,+BAA+B,CAsD3C"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { DiagramLoader, type DiagramLoadingOptions } from '@eclipse-glsp/client';
|
|
10
|
+
import { ChannelLogger } from '@hydranium/client-theia/lib/browser';
|
|
11
|
+
import { Deferred } from '@hydranium/protocol';
|
|
12
|
+
/**
|
|
13
|
+
* How a diagram load ended. A discriminated union rather than a boolean or a
|
|
14
|
+
* string: a consumer showing a pending indicator has to distinguish "not settled
|
|
15
|
+
* yet" (`undefined`) from either terminal state, and the failed arm has to carry
|
|
16
|
+
* enough for that consumer to decide whether *it* is now the only thing that can
|
|
17
|
+
* report the failure — see {@link DiagramLoadFailure.surfaced}.
|
|
18
|
+
*/
|
|
19
|
+
export type DiagramLoadOutcome = DiagramLoadSuccess | DiagramLoadFailure;
|
|
20
|
+
export interface DiagramLoadSuccess {
|
|
21
|
+
readonly status: 'loaded';
|
|
22
|
+
}
|
|
23
|
+
export interface DiagramLoadFailure {
|
|
24
|
+
readonly status: 'failed';
|
|
25
|
+
/** The thrown value, verbatim. `unknown` because a rejection can be anything. */
|
|
26
|
+
readonly error: unknown;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the `severity: 'ERROR'` {@link StatusAction} reached the action
|
|
29
|
+
* dispatcher — i.e. whether GLSP's `StatusOverlay` is now displaying this
|
|
30
|
+
* failure.
|
|
31
|
+
*
|
|
32
|
+
* `false` means the report itself failed, which happens when the action
|
|
33
|
+
* dispatcher is the thing that could not initialize. A consumer that covers
|
|
34
|
+
* the canvas must then render the failure itself: it is the only surface
|
|
35
|
+
* left, and removing its overlay would leave a blank diagram whose only
|
|
36
|
+
* explanation is a line in the Output channel — the exact failure mode this
|
|
37
|
+
* loader exists to prevent.
|
|
38
|
+
*/
|
|
39
|
+
readonly surfaced: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Diagram loader that never lets a load failure vanish.
|
|
43
|
+
*
|
|
44
|
+
* `DiagramLoader.load()` orchestrates the full diagram-init path — action
|
|
45
|
+
* dispatcher init, GLSP-client connect + server `initialize`, the first
|
|
46
|
+
* `RequestModelAction`, and the model-initialization constraint. Of these only
|
|
47
|
+
* the `IDiagramStartup` hooks are wrapped by the base loader (it logs them to
|
|
48
|
+
* `console.error`); the dispatcher-init / connection / request-model steps are
|
|
49
|
+
* not. The widget that drives loading
|
|
50
|
+
* (`@eclipse-glsp/theia-integration`'s `GLSPDiagramWidget.onAfterAttach`)
|
|
51
|
+
* calls `load()` *without awaiting or catching it*, so any rejection becomes an
|
|
52
|
+
* uncaught promise rejection visible only in the browser devtools console —
|
|
53
|
+
* nothing reaches the e2e output, the server log, or a Theia log sink, and the
|
|
54
|
+
* diagram just stays blank.
|
|
55
|
+
*
|
|
56
|
+
* This subclass closes that gap: it catches every load failure, routes it to
|
|
57
|
+
* the framework Output channel (the same {@link ChannelLogger} sink the server
|
|
58
|
+
* log and action traffic share, so it is discoverable where a developer already
|
|
59
|
+
* looks), and surfaces a persistent error to the user via a `severity: 'ERROR'`
|
|
60
|
+
* {@link StatusAction} on the diagram's status overlay. It deliberately does
|
|
61
|
+
* **not** rethrow — the caller drops the promise, so rethrowing would only
|
|
62
|
+
* reproduce the uncaught rejection this exists to prevent.
|
|
63
|
+
*
|
|
64
|
+
* It also publishes the load's terminal state ({@link loadOutcome} /
|
|
65
|
+
* {@link onceLoadSettled}) so a pending indicator has one authority to key on.
|
|
66
|
+
* `HydraniumGlspDiagramWidget` uses it to cover the canvas while loading; see
|
|
67
|
+
* {@link settle} for why the signal cannot be derived from the error
|
|
68
|
+
* `StatusAction` instead.
|
|
69
|
+
*
|
|
70
|
+
* Bound by `createGlspClientTheiaModule` via `rebind(DiagramLoader)`.
|
|
71
|
+
*/
|
|
72
|
+
export declare class HydraniumDiagramLoader extends DiagramLoader {
|
|
73
|
+
protected readonly channel: ChannelLogger;
|
|
74
|
+
protected readonly settled: Deferred<DiagramLoadOutcome>;
|
|
75
|
+
protected outcome?: DiagramLoadOutcome;
|
|
76
|
+
/** Terminal state of the load, or `undefined` while it is still in flight.
|
|
77
|
+
* The synchronous companion of {@link onceLoadSettled}, for a consumer that
|
|
78
|
+
* must decide something in the same tick (e.g. whether to show an indicator
|
|
79
|
+
* at all when re-attaching an already-loaded diagram). */
|
|
80
|
+
get loadOutcome(): DiagramLoadOutcome | undefined;
|
|
81
|
+
/** Resolves once the load reaches a terminal state — on success **and** on
|
|
82
|
+
* failure, so a caller awaiting it cannot hang. Never rejects. */
|
|
83
|
+
onceLoadSettled(): Promise<DiagramLoadOutcome>;
|
|
84
|
+
load(options?: DiagramLoadingOptions): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Record the terminal state and release {@link onceLoadSettled}. Idempotent —
|
|
87
|
+
* the first outcome wins, so a reload cannot flip a settled indicator.
|
|
88
|
+
*
|
|
89
|
+
* This runs unconditionally after {@link reportLoadFailure}, *including* when
|
|
90
|
+
* the status dispatch inside it threw. That is the load-bearing property: when
|
|
91
|
+
* the action dispatcher is itself the thing that failed to initialize — the
|
|
92
|
+
* exact failure this class exists for — no `StatusAction` ever lands, so a
|
|
93
|
+
* consumer observing actions would wait forever. Settling here means a pending
|
|
94
|
+
* indicator always comes down, and `surfaced: false` tells that consumer it is
|
|
95
|
+
* now the only thing that can report the failure.
|
|
96
|
+
*/
|
|
97
|
+
protected settle(outcome: DiagramLoadOutcome): void;
|
|
98
|
+
/**
|
|
99
|
+
* Route a diagram-load failure to the Output channel and the status overlay.
|
|
100
|
+
* The status dispatch is itself guarded: when the action dispatcher is the
|
|
101
|
+
* thing that failed to initialize, dispatching may throw too, and a failure
|
|
102
|
+
* to *report* the failure must not re-escape as an uncaught rejection.
|
|
103
|
+
*
|
|
104
|
+
* @returns whether the `StatusAction` reached the dispatcher — i.e. whether the
|
|
105
|
+
* user can see this failure on the diagram. The channel line always happens, so
|
|
106
|
+
* the return value is specifically about the *user-visible* report; a `false`
|
|
107
|
+
* makes {@link DiagramLoadFailure.surfaced} false and hands the job to whoever
|
|
108
|
+
* is covering the canvas.
|
|
109
|
+
*/
|
|
110
|
+
protected reportLoadFailure(err: unknown): Promise<boolean>;
|
|
111
|
+
/**
|
|
112
|
+
* The sentence a failed load is reported with, on every surface that reports
|
|
113
|
+
* it, and the only seam an adopter rewords or localizes it at. Public
|
|
114
|
+
* because the canvas overlay is one of those surfaces and lives in another
|
|
115
|
+
* class: it renders this failure exactly when the `StatusAction` did not
|
|
116
|
+
* land, so a second copy of the sentence there could only ever drift unseen.
|
|
117
|
+
*/
|
|
118
|
+
loadFailureLabel(err: unknown): string;
|
|
119
|
+
/** Render a thrown value as a message. Shared so the channel line, the status
|
|
120
|
+
* overlay and any consumer rendering {@link DiagramLoadFailure.error} agree. */
|
|
121
|
+
protected formatError(err: unknown): string;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=diagram-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-loader.d.ts","sourceRoot":"","sources":["../../src/browser/diagram-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,aAAa,EAAE,KAAK,qBAAqB,EAAgB,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAEzE,MAAM,WAAW,kBAAkB;IAChC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IAChC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBACa,sBAAuB,SAAQ,aAAa;IAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAG,aAAa,CAAC;IAElE,SAAS,CAAC,QAAQ,CAAC,OAAO,+BAAsC;IAChE,SAAS,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAEvC;;;+DAG2D;IAC3D,IAAI,WAAW,IAAI,kBAAkB,GAAG,SAAS,CAEhD;IAED;uEACmE;IACnE,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAI/B,IAAI,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAcnE;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAQnD;;;;;;;;;;;OAWG;cACa,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAYjE;;;;;;OAMG;IACH,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAItC;qFACiF;IACjF,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;CAG7C"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
11
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
12
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
13
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
14
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
|
+
};
|
|
16
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
17
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.HydraniumDiagramLoader = void 0;
|
|
21
|
+
const client_1 = require("@eclipse-glsp/client");
|
|
22
|
+
const browser_1 = require("@hydranium/client-theia/lib/browser");
|
|
23
|
+
const protocol_1 = require("@hydranium/protocol");
|
|
24
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
25
|
+
/**
|
|
26
|
+
* Diagram loader that never lets a load failure vanish.
|
|
27
|
+
*
|
|
28
|
+
* `DiagramLoader.load()` orchestrates the full diagram-init path — action
|
|
29
|
+
* dispatcher init, GLSP-client connect + server `initialize`, the first
|
|
30
|
+
* `RequestModelAction`, and the model-initialization constraint. Of these only
|
|
31
|
+
* the `IDiagramStartup` hooks are wrapped by the base loader (it logs them to
|
|
32
|
+
* `console.error`); the dispatcher-init / connection / request-model steps are
|
|
33
|
+
* not. The widget that drives loading
|
|
34
|
+
* (`@eclipse-glsp/theia-integration`'s `GLSPDiagramWidget.onAfterAttach`)
|
|
35
|
+
* calls `load()` *without awaiting or catching it*, so any rejection becomes an
|
|
36
|
+
* uncaught promise rejection visible only in the browser devtools console —
|
|
37
|
+
* nothing reaches the e2e output, the server log, or a Theia log sink, and the
|
|
38
|
+
* diagram just stays blank.
|
|
39
|
+
*
|
|
40
|
+
* This subclass closes that gap: it catches every load failure, routes it to
|
|
41
|
+
* the framework Output channel (the same {@link ChannelLogger} sink the server
|
|
42
|
+
* log and action traffic share, so it is discoverable where a developer already
|
|
43
|
+
* looks), and surfaces a persistent error to the user via a `severity: 'ERROR'`
|
|
44
|
+
* {@link StatusAction} on the diagram's status overlay. It deliberately does
|
|
45
|
+
* **not** rethrow — the caller drops the promise, so rethrowing would only
|
|
46
|
+
* reproduce the uncaught rejection this exists to prevent.
|
|
47
|
+
*
|
|
48
|
+
* It also publishes the load's terminal state ({@link loadOutcome} /
|
|
49
|
+
* {@link onceLoadSettled}) so a pending indicator has one authority to key on.
|
|
50
|
+
* `HydraniumGlspDiagramWidget` uses it to cover the canvas while loading; see
|
|
51
|
+
* {@link settle} for why the signal cannot be derived from the error
|
|
52
|
+
* `StatusAction` instead.
|
|
53
|
+
*
|
|
54
|
+
* Bound by `createGlspClientTheiaModule` via `rebind(DiagramLoader)`.
|
|
55
|
+
*/
|
|
56
|
+
let HydraniumDiagramLoader = class HydraniumDiagramLoader extends client_1.DiagramLoader {
|
|
57
|
+
channel;
|
|
58
|
+
settled = new protocol_1.Deferred();
|
|
59
|
+
outcome;
|
|
60
|
+
/** Terminal state of the load, or `undefined` while it is still in flight.
|
|
61
|
+
* The synchronous companion of {@link onceLoadSettled}, for a consumer that
|
|
62
|
+
* must decide something in the same tick (e.g. whether to show an indicator
|
|
63
|
+
* at all when re-attaching an already-loaded diagram). */
|
|
64
|
+
get loadOutcome() {
|
|
65
|
+
return this.outcome;
|
|
66
|
+
}
|
|
67
|
+
/** Resolves once the load reaches a terminal state — on success **and** on
|
|
68
|
+
* failure, so a caller awaiting it cannot hang. Never rejects. */
|
|
69
|
+
onceLoadSettled() {
|
|
70
|
+
return this.settled.promise;
|
|
71
|
+
}
|
|
72
|
+
async load(options) {
|
|
73
|
+
try {
|
|
74
|
+
await super.load(options);
|
|
75
|
+
this.settle({ status: 'loaded' });
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
// Report first, settle second, and carry whether the report landed: a
|
|
79
|
+
// consumer that uncovers the canvas on settle then finds the error
|
|
80
|
+
// already on the status overlay — or learns that it has to render the
|
|
81
|
+
// failure itself because nothing else can.
|
|
82
|
+
const surfaced = await this.reportLoadFailure(err);
|
|
83
|
+
this.settle({ status: 'failed', error: err, surfaced });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Record the terminal state and release {@link onceLoadSettled}. Idempotent —
|
|
88
|
+
* the first outcome wins, so a reload cannot flip a settled indicator.
|
|
89
|
+
*
|
|
90
|
+
* This runs unconditionally after {@link reportLoadFailure}, *including* when
|
|
91
|
+
* the status dispatch inside it threw. That is the load-bearing property: when
|
|
92
|
+
* the action dispatcher is itself the thing that failed to initialize — the
|
|
93
|
+
* exact failure this class exists for — no `StatusAction` ever lands, so a
|
|
94
|
+
* consumer observing actions would wait forever. Settling here means a pending
|
|
95
|
+
* indicator always comes down, and `surfaced: false` tells that consumer it is
|
|
96
|
+
* now the only thing that can report the failure.
|
|
97
|
+
*/
|
|
98
|
+
settle(outcome) {
|
|
99
|
+
if (this.outcome !== undefined) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this.outcome = outcome;
|
|
103
|
+
this.settled.resolve(outcome);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Route a diagram-load failure to the Output channel and the status overlay.
|
|
107
|
+
* The status dispatch is itself guarded: when the action dispatcher is the
|
|
108
|
+
* thing that failed to initialize, dispatching may throw too, and a failure
|
|
109
|
+
* to *report* the failure must not re-escape as an uncaught rejection.
|
|
110
|
+
*
|
|
111
|
+
* @returns whether the `StatusAction` reached the dispatcher — i.e. whether the
|
|
112
|
+
* user can see this failure on the diagram. The channel line always happens, so
|
|
113
|
+
* the return value is specifically about the *user-visible* report; a `false`
|
|
114
|
+
* makes {@link DiagramLoadFailure.surfaced} false and hands the job to whoever
|
|
115
|
+
* is covering the canvas.
|
|
116
|
+
*/
|
|
117
|
+
async reportLoadFailure(err) {
|
|
118
|
+
const label = this.loadFailureLabel(err);
|
|
119
|
+
this.channel.error(label, err);
|
|
120
|
+
try {
|
|
121
|
+
await this.actionDispatcher.dispatch(client_1.StatusAction.create(label, { severity: 'ERROR' }));
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
catch (statusErr) {
|
|
125
|
+
this.channel.error('Failed to surface the diagram-load failure on the status overlay', statusErr);
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The sentence a failed load is reported with, on every surface that reports
|
|
131
|
+
* it, and the only seam an adopter rewords or localizes it at. Public
|
|
132
|
+
* because the canvas overlay is one of those surfaces and lives in another
|
|
133
|
+
* class: it renders this failure exactly when the `StatusAction` did not
|
|
134
|
+
* land, so a second copy of the sentence there could only ever drift unseen.
|
|
135
|
+
*/
|
|
136
|
+
loadFailureLabel(err) {
|
|
137
|
+
return `Diagram failed to load: ${this.formatError(err)}`;
|
|
138
|
+
}
|
|
139
|
+
/** Render a thrown value as a message. Shared so the channel line, the status
|
|
140
|
+
* overlay and any consumer rendering {@link DiagramLoadFailure.error} agree. */
|
|
141
|
+
formatError(err) {
|
|
142
|
+
return err instanceof Error ? err.message : String(err);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
exports.HydraniumDiagramLoader = HydraniumDiagramLoader;
|
|
146
|
+
__decorate([
|
|
147
|
+
(0, inversify_1.inject)(browser_1.ChannelLogger),
|
|
148
|
+
__metadata("design:type", browser_1.ChannelLogger)
|
|
149
|
+
], HydraniumDiagramLoader.prototype, "channel", void 0);
|
|
150
|
+
exports.HydraniumDiagramLoader = HydraniumDiagramLoader = __decorate([
|
|
151
|
+
(0, inversify_1.injectable)()
|
|
152
|
+
], HydraniumDiagramLoader);
|
|
153
|
+
//# sourceMappingURL=diagram-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-loader.js","sourceRoot":"","sources":["../../src/browser/diagram-loader.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;AAElF,iDAA+F;AAC/F,iEAAoE;AACpE,kDAA+C;AAC/C,4DAAkE;AAkClE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEI,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,sBAAa;IACZ,OAAO,CAAiB;IAE/C,OAAO,GAAG,IAAI,mBAAQ,EAAsB,CAAC;IACtD,OAAO,CAAsB;IAEvC;;;+DAG2D;IAC3D,IAAI,WAAW;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC;IACvB,CAAC;IAED;uEACmE;IACnE,eAAe;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAC/B,CAAC;IAEQ,KAAK,CAAC,IAAI,CAAC,OAA+B;QAChD,IAAI,CAAC;YACF,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACZ,sEAAsE;YACtE,mEAAmE;YACnE,sEAAsE;YACtE,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;YACnD,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3D,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;OAWG;IACO,MAAM,CAAC,OAA2B;QACzC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO;QACV,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;;;;;OAWG;IACO,KAAK,CAAC,iBAAiB,CAAC,GAAY;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC;YACF,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,qBAAY,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YACxF,OAAO,IAAI,CAAC;QACf,CAAC;QAAC,OAAO,SAAS,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,kEAAkE,EAAE,SAAS,CAAC,CAAC;YAClG,OAAO,KAAK,CAAC;QAChB,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,gBAAgB,CAAC,GAAY;QAC1B,OAAO,2BAA2B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED;qFACiF;IACvE,WAAW,CAAC,GAAY;QAC/B,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3D,CAAC;CACH,CAAA;AA9FY,wDAAsB;AACU;IAAzC,IAAA,kBAAM,EAAC,uBAAa,CAAC;8BAA8B,uBAAa;uDAAC;iCADxD,sBAAsB;IADlC,IAAA,sBAAU,GAAE;GACA,sBAAsB,CA8FlC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { ExternalMarkerManager, type Marker } from '@eclipse-glsp/client';
|
|
10
|
+
/**
|
|
11
|
+
* {@link ExternalMarkerManager} that drops all marker propagation into Theia's
|
|
12
|
+
* Problems view. GLSP's `SetMarkersActionHandler` still applies the in-diagram
|
|
13
|
+
* decoration through the separate `ValidationFeedbackEmitter` path; only the
|
|
14
|
+
* forward into the `ProblemManager` is suppressed, so the LSP head stays the
|
|
15
|
+
* single source of Problems-view diagnostics.
|
|
16
|
+
*
|
|
17
|
+
* Bound per diagram by `AbstractHydraniumGlspDiagramConfiguration` when its
|
|
18
|
+
* `propagateMarkersToProblemsView` flag is `false`; see that flag for when a
|
|
19
|
+
* head should choose it.
|
|
20
|
+
*
|
|
21
|
+
* Kept in its own module — importing only `@eclipse-glsp/client`, not
|
|
22
|
+
* `@eclipse-glsp/theia-integration` — so it stays unit-testable without pulling
|
|
23
|
+
* the Theia integration into the test graph.
|
|
24
|
+
*/
|
|
25
|
+
export declare class NoOpExternalMarkerManager extends ExternalMarkerManager {
|
|
26
|
+
setMarkers(_markers: Marker[], _reason?: string, _sourceUri?: string): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=diagram-only-marker-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-only-marker-manager.d.ts","sourceRoot":"","sources":["../../src/browser/diagram-only-marker-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,qBAAqB,EAAE,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG1E;;;;;;;;;;;;;;GAcG;AACH,qBACa,yBAA0B,SAAQ,qBAAqB;IACjE,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;CAG7E"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
11
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
12
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
13
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
14
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.NoOpExternalMarkerManager = void 0;
|
|
18
|
+
const client_1 = require("@eclipse-glsp/client");
|
|
19
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
20
|
+
/**
|
|
21
|
+
* {@link ExternalMarkerManager} that drops all marker propagation into Theia's
|
|
22
|
+
* Problems view. GLSP's `SetMarkersActionHandler` still applies the in-diagram
|
|
23
|
+
* decoration through the separate `ValidationFeedbackEmitter` path; only the
|
|
24
|
+
* forward into the `ProblemManager` is suppressed, so the LSP head stays the
|
|
25
|
+
* single source of Problems-view diagnostics.
|
|
26
|
+
*
|
|
27
|
+
* Bound per diagram by `AbstractHydraniumGlspDiagramConfiguration` when its
|
|
28
|
+
* `propagateMarkersToProblemsView` flag is `false`; see that flag for when a
|
|
29
|
+
* head should choose it.
|
|
30
|
+
*
|
|
31
|
+
* Kept in its own module — importing only `@eclipse-glsp/client`, not
|
|
32
|
+
* `@eclipse-glsp/theia-integration` — so it stays unit-testable without pulling
|
|
33
|
+
* the Theia integration into the test graph.
|
|
34
|
+
*/
|
|
35
|
+
let NoOpExternalMarkerManager = class NoOpExternalMarkerManager extends client_1.ExternalMarkerManager {
|
|
36
|
+
setMarkers(_markers, _reason, _sourceUri) {
|
|
37
|
+
// Intentionally empty — the LSP head owns the Problems view.
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.NoOpExternalMarkerManager = NoOpExternalMarkerManager;
|
|
41
|
+
exports.NoOpExternalMarkerManager = NoOpExternalMarkerManager = __decorate([
|
|
42
|
+
(0, inversify_1.injectable)()
|
|
43
|
+
], NoOpExternalMarkerManager);
|
|
44
|
+
//# sourceMappingURL=diagram-only-marker-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-only-marker-manager.js","sourceRoot":"","sources":["../../src/browser/diagram-only-marker-manager.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;AAElF,iDAA0E;AAC1E,4DAA0D;AAE1D;;;;;;;;;;;;;;GAcG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,8BAAqB;IACjE,UAAU,CAAC,QAAkB,EAAE,OAAgB,EAAE,UAAmB;QACjE,6DAA6D;IAChE,CAAC;CACH,CAAA;AAJY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,sBAAU,GAAE;GACA,yBAAyB,CAIrC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { GLSPDiagramWidget } from '@eclipse-glsp/theia-integration';
|
|
10
|
+
import { type Message } from '@theia/core/lib/browser';
|
|
11
|
+
import { type DiagramLoadOutcome, HydraniumDiagramLoader } from './diagram-loader';
|
|
12
|
+
import '../../style/diagram-loading.css';
|
|
13
|
+
/** Class on the overlay root. Adopters style / override via this contract. */
|
|
14
|
+
export declare const DIAGRAM_LOADING_CLASS = "hydranium-diagram-loading";
|
|
15
|
+
/** Added to the overlay root when it switches from pending to reporting a
|
|
16
|
+
* failure, so the spinner can be hidden and the text restyled from CSS alone. */
|
|
17
|
+
export declare const DIAGRAM_LOADING_FAILED_CLASS = "hydranium-diagram-loading-failed";
|
|
18
|
+
/**
|
|
19
|
+
* `GLSPDiagramWidget` that covers the canvas with a spinner until the diagram
|
|
20
|
+
* load reaches a terminal state.
|
|
21
|
+
*
|
|
22
|
+
* **Why.** GLSP renders nothing until the first model arrives, so opening a
|
|
23
|
+
* diagram shows a blank tab for the whole round trip — long enough on a large
|
|
24
|
+
* model to read as a broken editor rather than a slow one.
|
|
25
|
+
*
|
|
26
|
+
* **How the pending state is sourced.** From {@link HydraniumDiagramLoader}, not
|
|
27
|
+
* from `actionDispatcher.onceModelInitialized()`. The loader settles on failure
|
|
28
|
+
* as well as on success, and it does so even when its own error-reporting
|
|
29
|
+
* dispatch throws; `onceModelInitialized()` simply never settles on a failed
|
|
30
|
+
* load. That distinction is not academic here: this overlay is opaque and covers
|
|
31
|
+
* the widget node, while GLSP's `StatusOverlay` — where the loader reports the
|
|
32
|
+
* failure — mounts *inside* the diagram's base div. Keyed on model
|
|
33
|
+
* initialization, a failed load would leave a spinner turning on top of the
|
|
34
|
+
* error message explaining it. Keyed on the loader, exactly one component decides
|
|
35
|
+
* whether the canvas is pending and the two mechanisms compose instead of
|
|
36
|
+
* competing.
|
|
37
|
+
*
|
|
38
|
+
* **The one case where this overlay reports the failure itself.** When
|
|
39
|
+
* `DiagramLoadFailure.surfaced` is `false` the loader could not dispatch its
|
|
40
|
+
* `StatusAction` — the action dispatcher was what failed — so the status overlay
|
|
41
|
+
* shows nothing. Uncovering the canvas would then leave a blank diagram whose only
|
|
42
|
+
* explanation is a line in the Output channel. In that case, and only that case,
|
|
43
|
+
* the overlay stays up and swaps the spinner for the error text.
|
|
44
|
+
*
|
|
45
|
+
* Bound unconditionally by `AbstractHydraniumGlspTheiaFrontendModule`. To opt out,
|
|
46
|
+
* override {@link showLoadingOverlay} to a no-op; to change what is rendered,
|
|
47
|
+
* override {@link createLoadingOverlay} or {@link loadingLabel}.
|
|
48
|
+
*/
|
|
49
|
+
export declare class HydraniumGlspDiagramWidget extends GLSPDiagramWidget {
|
|
50
|
+
protected loadingOverlay?: HTMLElement;
|
|
51
|
+
protected onAfterAttach(msg: Message): void;
|
|
52
|
+
dispose(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Cover the canvas until the load settles.
|
|
55
|
+
*
|
|
56
|
+
* Nothing is created unless there is a signal to take it down again: no
|
|
57
|
+
* overlay without a framework loader, and none when the load has already
|
|
58
|
+
* settled — re-attaching a loaded diagram (a tab switch) skips it entirely
|
|
59
|
+
* rather than creating and immediately removing one, so there is no flash.
|
|
60
|
+
*/
|
|
61
|
+
protected showLoadingOverlay(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Take the overlay down, or keep it as the failure's only reporter.
|
|
64
|
+
*
|
|
65
|
+
* The overlay is retained ONLY for a failure the loader could not surface;
|
|
66
|
+
* anything else uncovers the canvas, so a load that failed *and was reported*
|
|
67
|
+
* reveals GLSP's status overlay rather than double-reporting on top of it.
|
|
68
|
+
*/
|
|
69
|
+
protected onLoadSettled(outcome: DiagramLoadOutcome): void;
|
|
70
|
+
/**
|
|
71
|
+
* Repurpose the pending overlay in place as a failure report: same node, so
|
|
72
|
+
* there is no removal-then-insertion flicker, plus a marker class so the
|
|
73
|
+
* spinner can be hidden from CSS.
|
|
74
|
+
*
|
|
75
|
+
* The wording is {@link HydraniumDiagramLoader.loadFailureLabel}'s, so an
|
|
76
|
+
* adopter rewording a load failure reaches every surface that reports it.
|
|
77
|
+
* Without the framework loader there is no failure to render, so its absence
|
|
78
|
+
* is a no-op rather than a fallback wording.
|
|
79
|
+
*/
|
|
80
|
+
protected showLoadFailure(error: unknown): void;
|
|
81
|
+
protected hideLoadingOverlay(): void;
|
|
82
|
+
/** Build the overlay DOM. Override to change the wording or add content; the
|
|
83
|
+
* root must carry {@link DIAGRAM_LOADING_CLASS} for the shipped styling, and
|
|
84
|
+
* the label element its `-label` class so {@link showLoadFailure} finds it. */
|
|
85
|
+
protected createLoadingOverlay(): HTMLElement;
|
|
86
|
+
/** Text shown under the spinner. Override for a domain-specific wording; the
|
|
87
|
+
* failure text that replaces it is {@link showLoadFailure}'s. */
|
|
88
|
+
protected get loadingLabel(): string;
|
|
89
|
+
/**
|
|
90
|
+
* The framework loader for this diagram, or `undefined` when the container
|
|
91
|
+
* binds a plain `DiagramLoader`. Absence degrades to "no overlay" rather than
|
|
92
|
+
* an error: a head that opted out of the framework loader has no settle signal
|
|
93
|
+
* to key on, and an overlay that never comes down is worse than none.
|
|
94
|
+
*/
|
|
95
|
+
protected get hydraniumDiagramLoader(): HydraniumDiagramLoader | undefined;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=diagram-widget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-widget.d.ts","sourceRoot":"","sources":["../../src/browser/diagram-widget.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAGpE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,KAAK,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAInF,OAAO,iCAAiC,CAAC;AAEzC,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAEjE;kFACkF;AAClF,eAAO,MAAM,4BAA4B,qCAAoC,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBACa,0BAA2B,SAAQ,iBAAiB;IAC9D,SAAS,CAAC,cAAc,CAAC,EAAE,WAAW,CAAC;cAEpB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAO3C,OAAO,IAAI,IAAI;IAKxB;;;;;;;OAOG;IACH,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAmBpC;;;;;;OAMG;IACH,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAQ1D;;;;;;;;;OASG;IACH,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAa/C,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAKpC;;oFAEgF;IAChF,SAAS,CAAC,oBAAoB,IAAI,WAAW;IAa7C;sEACkE;IAClE,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAED;;;;;OAKG;IACH,SAAS,KAAK,sBAAsB,IAAI,sBAAsB,GAAG,SAAS,CAGzE;CACH"}
|