graphwise-reactodia 0.0.1-TR16 → 0.0.1-TR18

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.
Files changed (48) hide show
  1. package/README.md +57 -0
  2. package/dist/cjs/error-code-BdRU0RQ9.js +36 -0
  3. package/dist/cjs/graphwise-reactodia.cjs.entry.js +270 -65
  4. package/dist/cjs/graphwise-reactodia.cjs.js +1 -1
  5. package/dist/cjs/{index-CII9aUQC.js → index-DtzCybH4.js} +16 -0
  6. package/dist/cjs/index.cjs.js +14 -4
  7. package/dist/cjs/loader.cjs.js +1 -1
  8. package/dist/collection/components/graphwise-reactodia/graphwise-reactodia.js +46 -4
  9. package/dist/collection/components/graphwise-reactodia/menu/graphwise-menu.js +4 -1
  10. package/dist/collection/components/graphwise-reactodia/models/error/error-cause.js +1 -0
  11. package/dist/collection/components/graphwise-reactodia/models/error/error-code.js +18 -0
  12. package/dist/collection/components/graphwise-reactodia/models/error/error-report.js +1 -0
  13. package/dist/collection/components/graphwise-reactodia/models/event/event-callback.js +1 -0
  14. package/dist/collection/components/graphwise-reactodia/models/event/event-detail.js +4 -0
  15. package/dist/collection/components/graphwise-reactodia/models/event/event-type.js +7 -0
  16. package/dist/collection/components/graphwise-reactodia/reactodia-app.js +53 -19
  17. package/dist/collection/components/graphwise-reactodia/services/diagram-storage/diagram-storage.service.js +20 -4
  18. package/dist/collection/components/graphwise-reactodia/services/error/error.service.js +78 -0
  19. package/dist/collection/components/graphwise-reactodia/services/event/event.service.js +23 -0
  20. package/dist/collection/index.js +3 -0
  21. package/dist/collection/pages/graphwise-reactodia/main.js +41 -0
  22. package/dist/esm/error-code-DHI2bePh.js +34 -0
  23. package/dist/esm/graphwise-reactodia.entry.js +268 -63
  24. package/dist/esm/graphwise-reactodia.js +2 -2
  25. package/dist/esm/{index-Cypw7ydc.js → index-DpCR6zMg.js} +16 -1
  26. package/dist/esm/index.js +5 -4
  27. package/dist/esm/loader.js +2 -2
  28. package/dist/graphwise-reactodia/graphwise-reactodia.esm.js +1 -1
  29. package/dist/graphwise-reactodia/index.esm.js +1 -1
  30. package/dist/graphwise-reactodia/p-DHI2bePh.js +1 -0
  31. package/dist/graphwise-reactodia/p-DpCR6zMg.js +2 -0
  32. package/dist/graphwise-reactodia/p-abfb5091.entry.js +1 -0
  33. package/dist/types/components/graphwise-reactodia/graphwise-reactodia.d.ts +9 -0
  34. package/dist/types/components/graphwise-reactodia/models/error/error-cause.d.ts +10 -0
  35. package/dist/types/components/graphwise-reactodia/models/error/error-code.d.ts +17 -0
  36. package/dist/types/components/graphwise-reactodia/models/error/error-report.d.ts +13 -0
  37. package/dist/types/components/graphwise-reactodia/models/event/event-callback.d.ts +5 -0
  38. package/dist/types/components/graphwise-reactodia/models/event/event-detail.d.ts +48 -0
  39. package/dist/types/components/graphwise-reactodia/models/event/event-type.d.ts +6 -0
  40. package/dist/types/components/graphwise-reactodia/reactodia-app.d.ts +1 -1
  41. package/dist/types/components/graphwise-reactodia/services/diagram-storage/diagram-storage.service.d.ts +1 -0
  42. package/dist/types/components/graphwise-reactodia/services/error/error.service.d.ts +41 -0
  43. package/dist/types/components/graphwise-reactodia/services/event/event.service.d.ts +16 -0
  44. package/dist/types/components.d.ts +21 -0
  45. package/dist/types/index.d.ts +5 -0
  46. package/package.json +1 -1
  47. package/dist/graphwise-reactodia/p-20637a6f.entry.js +0 -1
  48. package/dist/graphwise-reactodia/p-Cypw7ydc.js +0 -2
@@ -1,9 +1,19 @@
1
1
  'use strict';
2
2
 
3
+ var errorCode = require('./error-code-BdRU0RQ9.js');
4
+
3
5
  /**
4
- * Event name for clearing the local store state of the diagram. There is an event listener listening for it, which
5
- * will clear the local store state, whenever this event is fired.
6
+ * Name of the DOM event the `graphwise-reactodia` element dispatches for every event.
6
7
  */
7
- const CLEAR_DIAGRAM_STORAGE_EVENT = 'graphwise-reactodia:clear-diagram-storage';
8
+ const GRAPHWISE_REACTODIA_EVENT = 'graphwiseReactodiaEvent';
8
9
 
9
- exports.CLEAR_DIAGRAM_STORAGE_EVENT = CLEAR_DIAGRAM_STORAGE_EVENT;
10
+ exports.CLEAR_DIAGRAM_STORAGE_EVENT = errorCode.CLEAR_DIAGRAM_STORAGE_EVENT;
11
+ Object.defineProperty(exports, "ErrorCode", {
12
+ enumerable: true,
13
+ get: function () { return errorCode.ErrorCode; }
14
+ });
15
+ Object.defineProperty(exports, "EventType", {
16
+ enumerable: true,
17
+ get: function () { return errorCode.EventType; }
18
+ });
19
+ exports.GRAPHWISE_REACTODIA_EVENT = GRAPHWISE_REACTODIA_EVENT;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CII9aUQC.js');
3
+ var index = require('./index-DtzCybH4.js');
4
4
  var appGlobals = require('./app-globals-CcJr5lkF.js');
5
5
 
6
6
  const defineCustomElements = async (win, options) => {
@@ -1,7 +1,14 @@
1
1
  import { h, Host } from "@stencil/core";
2
2
  import { mountReactodia, unmountReactodia, updateReactodia } from "./reactodia-app";
3
3
  import { LanguageKey } from "./i18n/language-key";
4
+ import { ErrorCode } from "./models/error/error-code";
5
+ import { SubscriptionList } from "./models/subscription-list";
6
+ import { service } from "./providers/service/service-inject";
7
+ import { ErrorService } from "./services/error/error.service";
8
+ import { EventService } from "./services/event/event.service";
4
9
  import { resetColors } from "./styles/type-style.resolver";
10
+ const errorService = service(ErrorService);
11
+ const eventService = service(EventService);
5
12
  /**
6
13
  * A web component that renders a graph with the Reactodia workspace.
7
14
  *
@@ -15,6 +22,7 @@ import { resetColors } from "./styles/type-style.resolver";
15
22
  */
16
23
  export class GraphwiseReactodia {
17
24
  constructor() {
25
+ this.subscriptions = new SubscriptionList();
18
26
  /**
19
27
  * UI language code (e.g. `en`, `fr`) for the Reactodia interface. Defaults to English.
20
28
  */
@@ -42,6 +50,7 @@ export class GraphwiseReactodia {
42
50
  this.renderGraph(true);
43
51
  }
44
52
  connectedCallback() {
53
+ this.subscribeToEvents();
45
54
  this.renderGraph();
46
55
  }
47
56
  componentDidLoad() {
@@ -49,13 +58,17 @@ export class GraphwiseReactodia {
49
58
  this.renderGraph();
50
59
  }
51
60
  disconnectedCallback() {
61
+ this.subscriptions.unsubscribeAll();
52
62
  if (this.reactRoot) {
53
63
  unmountReactodia(this.reactRoot);
54
64
  this.reactRoot = undefined;
55
65
  }
56
66
  }
57
67
  render() {
58
- return (h(Host, { key: 'a03aad892cb1947ab2426d77b3229e1324776c2c' }));
68
+ return (h(Host, { key: '2e8541c791f478484c4bad64ad758df99aba2059' }));
69
+ }
70
+ subscribeToEvents() {
71
+ this.subscriptions.add(eventService.subscribe((detail) => this.eventEmitter.emit(detail)));
59
72
  }
60
73
  renderGraph(isReloading) {
61
74
  var _a;
@@ -63,13 +76,13 @@ export class GraphwiseReactodia {
63
76
  return;
64
77
  }
65
78
  if (!this.currentRepository) {
66
- throw new Error('currentRepository is required');
79
+ throw this.reportMissingPropError('currentRepository is required');
67
80
  }
68
81
  if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.queryFunction)) {
69
- throw new Error('config.queryFunction is required');
82
+ throw this.reportMissingPropError('config.queryFunction is required');
70
83
  }
71
84
  if (!this.providerSettings) {
72
- throw new Error('providerSettings is required');
85
+ throw this.reportMissingPropError('providerSettings is required');
73
86
  }
74
87
  if (!this.hostElement) {
75
88
  return;
@@ -89,6 +102,11 @@ export class GraphwiseReactodia {
89
102
  this.reactRoot = mountReactodia(this.hostElement, props);
90
103
  }
91
104
  }
105
+ reportMissingPropError(message) {
106
+ const error = new Error(message);
107
+ errorService.report(ErrorCode.MISSING_REQUIRED_PROP, error);
108
+ return error;
109
+ }
92
110
  static get is() { return "graphwise-reactodia"; }
93
111
  static get originalStyleUrls() {
94
112
  return {
@@ -216,6 +234,30 @@ export class GraphwiseReactodia {
216
234
  }
217
235
  };
218
236
  }
237
+ static get events() {
238
+ return [{
239
+ "method": "eventEmitter",
240
+ "name": "graphwiseReactodiaEvent",
241
+ "bubbles": true,
242
+ "cancelable": true,
243
+ "composed": true,
244
+ "docs": {
245
+ "tags": [],
246
+ "text": "Fires for every event to the host, differentiated by `detail.type`."
247
+ },
248
+ "complexType": {
249
+ "original": "EventDetail",
250
+ "resolved": "{ type: EventType; payload: ErrorReport; }",
251
+ "references": {
252
+ "EventDetail": {
253
+ "location": "import",
254
+ "path": "./models/event/event-detail",
255
+ "id": "src/components/graphwise-reactodia/models/event/event-detail.ts::EventDetail"
256
+ }
257
+ }
258
+ }
259
+ }];
260
+ }
219
261
  static get elementRef() { return "hostElement"; }
220
262
  static get watchers() {
221
263
  return [{
@@ -3,6 +3,8 @@ import { ToolbarAction, ToolbarActionClearAll, ToolbarActionExport, ToolbarActio
3
3
  import { service } from "../providers/service/service-inject";
4
4
  import { DiagramService } from "../services/diagram/diagram.service";
5
5
  import { DiagramFileService } from "../services/diagram-file/diagram-file.service";
6
+ import { ErrorService } from "../services/error/error.service";
7
+ import { ErrorCode } from "../models/error/error-code";
6
8
  /**
7
9
  * The workspace main menu: Reactodia's default actions, followed by the diagram download and upload.
8
10
  *
@@ -14,6 +16,7 @@ export function GraphwiseMenu() {
14
16
  const t = useTranslation();
15
17
  const diagramFileService = service(DiagramFileService);
16
18
  const diagramService = service(DiagramService);
19
+ const errorService = service(ErrorService);
17
20
  const downloadDiagram = () => {
18
21
  const timestamp = new Date().toISOString().replace(/[-:]|\.\d+Z$/g, '');
19
22
  diagramFileService.download(model.exportLayout(), `diagram-${timestamp}${DiagramFileService.FILE_EXTENSION}`);
@@ -24,7 +27,7 @@ export function GraphwiseMenu() {
24
27
  await diagramService.importDiagram(model, model.dataProvider, diagram);
25
28
  }
26
29
  catch (error) {
27
- console.error('Failed to upload the diagram', error);
30
+ errorService.report(ErrorCode.DIAGRAM_IMPORT, error);
28
31
  }
29
32
  };
30
33
  return createElement(Fragment, null, createElement(ToolbarActionClearAll, {}), createElement(ToolbarActionExport, { kind: 'exportRaster' }), createElement(ToolbarActionExport, { kind: 'exportSvg' }), createElement(ToolbarActionExport, { kind: 'print' }), createElement(ToolbarAction,
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The stable category of a reported error. The host uses it to choose its own message.
3
+ */
4
+ export var ErrorCode;
5
+ (function (ErrorCode) {
6
+ /** A required prop is missing. */
7
+ ErrorCode["MISSING_REQUIRED_PROP"] = "missing-required-prop";
8
+ /** A SPARQL data provider call failed. */
9
+ ErrorCode["DATA_FETCH"] = "data-fetch";
10
+ /** The startup load, a reload or a repository switch failed. */
11
+ ErrorCode["DIAGRAM_LOAD"] = "diagram-load";
12
+ /** The uploaded file was rejected or its import failed. */
13
+ ErrorCode["DIAGRAM_IMPORT"] = "diagram-import";
14
+ /** Reading the diagram from local storage failed. */
15
+ ErrorCode["LOCAL_DIAGRAM_READ"] = "local-diagram-read";
16
+ /** Saving the diagram in local storage failed. */
17
+ ErrorCode["LOCAL_DIAGRAM_SAVE"] = "local-diagram-save";
18
+ })(ErrorCode || (ErrorCode = {}));
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Name of the DOM event the `graphwise-reactodia` element dispatches for every event.
3
+ */
4
+ export const GRAPHWISE_REACTODIA_EVENT = 'graphwiseReactodiaEvent';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The kind of event the wrapper announces to the host. It selects the payload of an {@link EventDetail}.
3
+ */
4
+ export var EventType;
5
+ (function (EventType) {
6
+ EventType["ERROR"] = "error";
7
+ })(EventType || (EventType = {}));
@@ -1,12 +1,14 @@
1
1
  import { createElement } from "react";
2
2
  import { createRoot } from "react-dom/client";
3
- import { DefaultWorkspace, SparqlDataProvider, useLoadedWorkspace, Workspace } from "@reactodia/workspace";
3
+ import { DecoratedDataProvider, DefaultWorkspace, SparqlDataProvider, useLoadedWorkspace, Workspace } from "@reactodia/workspace";
4
4
  import { blockingDefaultLayout } from "@reactodia/workspace/layout-sync";
5
5
  import { TRANSLATIONS } from "./i18n/translations";
6
6
  import { service } from "./providers/service/service-inject";
7
7
  import { DiagramService } from "./services/diagram/diagram.service";
8
8
  import { DiagramStorageService } from "./services/diagram-storage/diagram-storage.service";
9
9
  import { EventService } from "./services/event/event.service";
10
+ import { ErrorService } from "./services/error/error.service";
11
+ import { ErrorCode } from "./models/error/error-code";
10
12
  import { SubscriptionList } from "./models/subscription-list";
11
13
  import { resolveTypeStyle } from "./styles/type-style.resolver";
12
14
  import { GraphwiseMenu } from "./menu/graphwise-menu";
@@ -37,17 +39,35 @@ let diagramStorageSubscription;
37
39
  const diagramService = service(DiagramService);
38
40
  const diagramStorageService = service(DiagramStorageService);
39
41
  const eventService = service(EventService);
42
+ const errorService = service(ErrorService);
43
+ /**
44
+ * Reports every failed data provider call, unless the call was aborted, and passes the failure on to the caller.
45
+ */
46
+ const reportDataFetchError = async (_method, params, body) => {
47
+ var _a;
48
+ try {
49
+ return await body(params);
50
+ }
51
+ catch (error) {
52
+ if (!((_a = params.signal) === null || _a === void 0 ? void 0 : _a.aborted)) {
53
+ errorService.report(ErrorCode.DATA_FETCH, error);
54
+ }
55
+ throw error;
56
+ }
57
+ };
40
58
  /**
41
59
  * Builds a Reactodia {@link SparqlDataProvider} for the given endpoint using the supplied
42
60
  * query preset. The host owns the query configuration and always passes it in via props.
61
+ * The provider is decorated, so its failed calls are reported.
43
62
  */
44
63
  function createDataProvider(props) {
45
64
  const { currentRepository, config, providerSettings } = props;
46
- return new SparqlDataProvider({
65
+ const baseProvider = new SparqlDataProvider({
47
66
  endpointUrl: currentRepository,
48
67
  queryMethod: 'POST',
49
68
  queryFunction: config.queryFunction
50
69
  }, providerSettings);
70
+ return new DecoratedDataProvider({ baseProvider, decorator: reportDataFetchError });
51
71
  }
52
72
  /**
53
73
  * Places the seed entities on the canvas. Each IRI is added as a placeholder element, and data is then loaded for the
@@ -142,22 +162,31 @@ function ReactodiaApp(props) {
142
162
  const dataProvider = createDataProvider(props);
143
163
  const isReload = props.isReload;
144
164
  const savedDiagram = diagramStorageService.load();
145
- if (isReload) {
146
- // Reload the diagram that is currently on the canvas. This may happen when the host changes the provider
147
- // settings, or when the user switches the language at runtime, since there is no existing mechanism to
148
- // re-translate the UI at runtime (not for the UI labels at least)
149
- await diagramService.importDiagram(model, dataProvider, currentDiagram, signal);
165
+ try {
166
+ if (isReload) {
167
+ // Reload the diagram that is currently on the canvas. This may happen when the host changes the provider
168
+ // settings, or when the user switches the language at runtime, since there is no existing mechanism to
169
+ // re-translate the UI at runtime (not for the UI labels at least)
170
+ await diagramService.importDiagram(model, dataProvider, currentDiagram, signal);
171
+ }
172
+ else if ((_a = config.seedIris) === null || _a === void 0 ? void 0 : _a.length) {
173
+ await seedIrisToCanvas(context, dataProvider, config.seedIris, signal);
174
+ }
175
+ else if ((_b = config.seedGraph) === null || _b === void 0 ? void 0 : _b.length) {
176
+ await seedGraphToCanvas(context, dataProvider, config.seedGraph, signal);
177
+ }
178
+ else {
179
+ // Restore the previously saved layout when present, otherwise start empty. Either way this binds the
180
+ // data provider (savedDiagram is undefined -> empty diagram), so the unified search/lookup works.
181
+ await diagramService.importDiagram(model, dataProvider, savedDiagram, signal);
182
+ }
150
183
  }
151
- else if ((_a = config.seedIris) === null || _a === void 0 ? void 0 : _a.length) {
152
- await seedIrisToCanvas(context, dataProvider, config.seedIris, signal);
153
- }
154
- else if ((_b = config.seedGraph) === null || _b === void 0 ? void 0 : _b.length) {
155
- await seedGraphToCanvas(context, dataProvider, config.seedGraph, signal);
156
- }
157
- else {
158
- // Restore the previously saved layout when present, otherwise start empty. Either way this binds the
159
- // data provider (savedDiagram is undefined -> empty diagram), so the unified search/lookup works.
160
- await diagramService.importDiagram(model, dataProvider, savedDiagram, signal);
184
+ catch (error) {
185
+ if (!signal.aborted) {
186
+ errorService.report(ErrorCode.DIAGRAM_LOAD, error);
187
+ }
188
+ // rethrow, so the workspace shows the failure on its loading spinner
189
+ throw error;
161
190
  }
162
191
  }, [language]);
163
192
  /**
@@ -194,7 +223,7 @@ export function mountReactodia(container, props) {
194
223
  /**
195
224
  * Re-points the diagram at a new SPARQL endpoint by recreating it with a fresh data provider.
196
225
  * The canvas is reset to empty, matching the initial mount, since the data of another repository
197
- * has nothing to do with the current graph.
226
+ * has nothing to do with the current graph. A failure is reported, not thrown.
198
227
  */
199
228
  export async function updateReactodia(props) {
200
229
  if (!workspaceContext) {
@@ -202,7 +231,12 @@ export async function updateReactodia(props) {
202
231
  }
203
232
  const { model } = workspaceContext;
204
233
  const dataProvider = createDataProvider(props);
205
- await model.createNewDiagram({ dataProvider });
234
+ try {
235
+ await model.createNewDiagram({ dataProvider });
236
+ }
237
+ catch (error) {
238
+ errorService.report(ErrorCode.DIAGRAM_LOAD, error);
239
+ }
206
240
  }
207
241
  /**
208
242
  * Serializes the current diagram so it can be restored after a remount (e.g. when a
@@ -12,26 +12,42 @@ var DiagramStorageService_1;
12
12
  import { Service } from "../../providers/service/service";
13
13
  import { service } from "../../providers/service/service-inject";
14
14
  import { WindowService } from "../window/window.service";
15
+ import { ErrorService } from "../error/error.service";
16
+ import { ErrorCode } from "../../models/error/error-code";
15
17
  /**
16
18
  * Service for local store-related diagram operations
17
19
  */
18
20
  let DiagramStorageService = DiagramStorageService_1 = class DiagramStorageService {
21
+ constructor() {
22
+ this.errorService = service(ErrorService);
23
+ }
19
24
  /**
20
25
  * Load the persisted diagram from the local store, or `undefined` when nothing is stored (or the stored value
21
26
  * is unreadable).
22
27
  */
23
28
  load() {
24
- const raw = this.storage.getItem(DiagramStorageService_1.STORAGE_KEY);
25
- if (!raw) {
29
+ try {
30
+ const raw = this.storage.getItem(DiagramStorageService_1.STORAGE_KEY);
31
+ if (!raw) {
32
+ return undefined;
33
+ }
34
+ return JSON.parse(raw);
35
+ }
36
+ catch (error) {
37
+ this.errorService.report(ErrorCode.LOCAL_DIAGRAM_READ, error);
26
38
  return undefined;
27
39
  }
28
- return JSON.parse(raw);
29
40
  }
30
41
  /**
31
42
  * Persists the given diagram serialization.
32
43
  */
33
44
  save(diagram) {
34
- this.storage.setItem(DiagramStorageService_1.STORAGE_KEY, JSON.stringify(diagram));
45
+ try {
46
+ this.storage.setItem(DiagramStorageService_1.STORAGE_KEY, JSON.stringify(diagram));
47
+ }
48
+ catch (error) {
49
+ this.errorService.report(ErrorCode.LOCAL_DIAGRAM_SAVE, error);
50
+ }
35
51
  }
36
52
  /**
37
53
  * Removes the persisted diagram. Used when a new view (a seed) should take precedence over
@@ -0,0 +1,78 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
4
+ r = Reflect.decorate(decorators, target, key, desc);
5
+ else
6
+ for (var i = decorators.length - 1; i >= 0; i--)
7
+ if (d = decorators[i])
8
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
9
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
10
+ };
11
+ var ErrorService_1;
12
+ import { Service } from "../../providers/service/service";
13
+ import { service } from "../../providers/service/service-inject";
14
+ import { EventType } from "../../models/event/event-type";
15
+ import { EventService } from "../event/event.service";
16
+ /**
17
+ * Service that collects the failures of the wrapper and the fork, so they can be announced to the host.
18
+ */
19
+ let ErrorService = ErrorService_1 = class ErrorService {
20
+ constructor() {
21
+ this.eventService = service(EventService);
22
+ this.reported = new WeakSet();
23
+ }
24
+ /**
25
+ * Reports a failure to the host, unless it's an abort, or this exact error object is already reported
26
+ * from another place.
27
+ *
28
+ * The same error object may be reported from different places. E.g. a query that fails while a diagram loads is
29
+ * reported by the data provider decorator as `data-fetch`, and then reaches the `catch` around the load, which
30
+ * reports it as `diagram-load`. Only the first one is announced.
31
+ *
32
+ * The `cause` is checked because the fork wraps whatever fails during a diagram import in a new error:
33
+ *
34
+ * ```ts
35
+ * // reactodia-workspace/src/editor/dataDiagramModel.ts, importLayout
36
+ * } catch (error) {
37
+ * throw new Error('Reactodia: failed to import a layout', {cause: error});
38
+ * }
39
+ * ```
40
+ *
41
+ * We need to check the cause to make sure we don't report the same error/abort more than once.
42
+ *
43
+ * @param code The category of the failure.
44
+ * @param thrown The thrown value.
45
+ */
46
+ report(code, thrown) {
47
+ const causes = this.causeChain(thrown);
48
+ if (this.isAbortedOrAlreadyReported(causes)) {
49
+ return;
50
+ }
51
+ causes.forEach((cause) => this.reported.add(cause));
52
+ this.eventService.emit({ type: EventType.ERROR, payload: { code, error: thrown } });
53
+ }
54
+ /**
55
+ * Whether any link of the given cause chain is an abort or is already reported.
56
+ */
57
+ isAbortedOrAlreadyReported(causes) {
58
+ return causes.some((cause) => cause.name === ErrorService_1.ABORT_ERROR_NAME || this.reported.has(cause));
59
+ }
60
+ /**
61
+ * The thrown value followed by its `cause`, the cause of that, and so on, for as long as they are objects.
62
+ */
63
+ causeChain(thrown) {
64
+ const causes = [];
65
+ let current = thrown;
66
+ while (typeof current === 'object' && current !== null && !causes.includes(current)) {
67
+ causes.push(current);
68
+ current = current.cause;
69
+ }
70
+ return causes;
71
+ }
72
+ };
73
+ ErrorService.ID = 'ErrorService';
74
+ ErrorService.ABORT_ERROR_NAME = 'AbortError';
75
+ ErrorService = ErrorService_1 = __decorate([
76
+ Service
77
+ ], ErrorService);
78
+ export { ErrorService };
@@ -16,6 +16,29 @@ import { WindowService } from "../window/window.service";
16
16
  * Service for event based operations
17
17
  */
18
18
  let EventService = class EventService {
19
+ /**
20
+ * Announces an event to the host.
21
+ *
22
+ * @param detail The event detail.
23
+ */
24
+ emit(detail) {
25
+ var _a;
26
+ (_a = this.callback) === null || _a === void 0 ? void 0 : _a.call(this, detail);
27
+ }
28
+ /**
29
+ * Subscribes to the emitted events, replacing the previous subscriber.
30
+ *
31
+ * @param callback Called with every emitted event.
32
+ * @returns A {@link Subscription} that, when called, removes the callback, unless it has already been replaced.
33
+ */
34
+ subscribe(callback) {
35
+ this.callback = callback;
36
+ return () => {
37
+ if (this.callback === callback) {
38
+ this.callback = undefined;
39
+ }
40
+ };
41
+ }
19
42
  /**
20
43
  * Subscribes to the host's "clear persisted diagram" command.
21
44
  *
@@ -1 +1,4 @@
1
1
  export { CLEAR_DIAGRAM_STORAGE_EVENT } from './components/graphwise-reactodia/models/clear-diagram-storage-event';
2
+ export { GRAPHWISE_REACTODIA_EVENT } from './components/graphwise-reactodia/models/event/event-detail';
3
+ export { EventType } from './components/graphwise-reactodia/models/event/event-type';
4
+ export { ErrorCode } from './components/graphwise-reactodia/models/error/error-code';
@@ -17,6 +17,39 @@ async function stubQueryFunction(params) {
17
17
  return new Response('', {headers: {'Content-Type': 'text/turtle'}});
18
18
  }
19
19
 
20
+ // A transport that always fails, as an unreachable or misconfigured endpoint would.
21
+ async function failingQueryFunction() {
22
+ throw new Error('Query failed');
23
+ }
24
+
25
+ // A transport that never answers. Once its request is cancelled it fails with an ordinary error, as a transport
26
+ // that does not throw an `AbortError` would. The pending and the cancelled requests are counted.
27
+ window.pendingQueries = 0;
28
+ window.cancelledQueries = 0;
29
+
30
+ function hangingQueryFunction(params) {
31
+ window.pendingQueries++;
32
+ return new Promise((_resolve, reject) => {
33
+ params.signal?.addEventListener('abort', () => {
34
+ window.pendingQueries--;
35
+ window.cancelledQueries++;
36
+ reject(new Error('Request cancelled'));
37
+ });
38
+ });
39
+ }
40
+
41
+ // The errors the component reports are recorded, so the tests can tell what the host was notified of.
42
+ const reportedErrors = [];
43
+ window.reportedErrors = reportedErrors;
44
+ // The listener is on the document, since the tests replace the element.
45
+ document.addEventListener('graphwiseReactodiaEvent', (event) => {
46
+ if (event.detail.type !== 'error') {
47
+ return;
48
+ }
49
+ const {code, error} = event.detail.payload;
50
+ reportedErrors.push({code, message: error.message});
51
+ });
52
+
20
53
  const SEED_NODES = ['http://example.com/alice', 'http://example.com/bob'];
21
54
 
22
55
  const SEED_GRAPH = [
@@ -33,6 +66,14 @@ function setQueryFunction() {
33
66
  reactodia.config = {...reactodia.config, queryFunction: stubQueryFunction};
34
67
  }
35
68
 
69
+ function setFailingQueryFunction() {
70
+ reactodia.config = {...reactodia.config, queryFunction: failingQueryFunction};
71
+ }
72
+
73
+ function setHangingQueryFunction() {
74
+ reactodia.config = {...reactodia.config, queryFunction: hangingQueryFunction};
75
+ }
76
+
36
77
  // The wrapper has no default preset, so the host always passes one. The demo uses Reactodia's generic
37
78
  // OWL/RDFS preset, copied into `owl-rdfs-settings.js`.
38
79
  function setProviderSettings() {
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Event name for clearing the local store state of the diagram. There is an event listener listening for it, which
3
+ * will clear the local store state, whenever this event is fired.
4
+ */
5
+ const CLEAR_DIAGRAM_STORAGE_EVENT = 'graphwise-reactodia:clear-diagram-storage';
6
+
7
+ /**
8
+ * The kind of event the wrapper announces to the host. It selects the payload of an {@link EventDetail}.
9
+ */
10
+ var EventType;
11
+ (function (EventType) {
12
+ EventType["ERROR"] = "error";
13
+ })(EventType || (EventType = {}));
14
+
15
+ /**
16
+ * The stable category of a reported error. The host uses it to choose its own message.
17
+ */
18
+ var ErrorCode;
19
+ (function (ErrorCode) {
20
+ /** A required prop is missing. */
21
+ ErrorCode["MISSING_REQUIRED_PROP"] = "missing-required-prop";
22
+ /** A SPARQL data provider call failed. */
23
+ ErrorCode["DATA_FETCH"] = "data-fetch";
24
+ /** The startup load, a reload or a repository switch failed. */
25
+ ErrorCode["DIAGRAM_LOAD"] = "diagram-load";
26
+ /** The uploaded file was rejected or its import failed. */
27
+ ErrorCode["DIAGRAM_IMPORT"] = "diagram-import";
28
+ /** Reading the diagram from local storage failed. */
29
+ ErrorCode["LOCAL_DIAGRAM_READ"] = "local-diagram-read";
30
+ /** Saving the diagram in local storage failed. */
31
+ ErrorCode["LOCAL_DIAGRAM_SAVE"] = "local-diagram-save";
32
+ })(ErrorCode || (ErrorCode = {}));
33
+
34
+ export { CLEAR_DIAGRAM_STORAGE_EVENT as C, EventType as E, ErrorCode as a };