graphwise-reactodia 0.0.1-TR2 → 0.0.1-TR20
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/COPYING +674 -0
- package/COPYING.LESSER +165 -0
- package/NOTICE +41 -0
- package/README.md +225 -1
- package/dist/cjs/graphwise-reactodia.cjs.entry.js +28519 -41232
- package/dist/cjs/graphwise-reactodia.cjs.js +2 -2
- package/dist/cjs/{index-CII9aUQC.js → index-DtzCybH4.js} +16 -0
- package/dist/cjs/index.cjs.js +29 -0
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/node-action-DkJ5ct17.js +96 -0
- package/dist/collection/components/graphwise-reactodia/graphwise-reactodia.css +57 -1
- package/dist/collection/components/graphwise-reactodia/graphwise-reactodia.js +135 -40
- package/dist/collection/components/graphwise-reactodia/i18n/language-key.js +5 -0
- package/dist/collection/components/graphwise-reactodia/i18n/translations.js +6 -1
- package/dist/collection/components/graphwise-reactodia/menu/export-diagram-action.js +19 -0
- package/dist/collection/components/graphwise-reactodia/menu/graphwise-menu.js +24 -0
- package/dist/collection/components/graphwise-reactodia/menu/import-diagram-action.js +31 -0
- package/dist/collection/components/graphwise-reactodia/models/clear-diagram-storage-event.js +5 -0
- package/dist/collection/components/graphwise-reactodia/models/error/error-cause.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/error/error-code.js +20 -0
- package/dist/collection/components/graphwise-reactodia/models/error/error-report.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/event/event-callback.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/event/event-detail.js +4 -0
- package/dist/collection/components/graphwise-reactodia/models/event/event-type.js +8 -0
- package/dist/collection/components/graphwise-reactodia/models/reactodia-config.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/sparql/sparql-query-function.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/sparql/sparql-query-params.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/subscription-list.js +35 -0
- package/dist/collection/components/graphwise-reactodia/models/subscription.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/triple.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/menu-config.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/menu-item.js +18 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/node-action.js +22 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/resolved-toolbar-position.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/resolved-ui-config.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/toolbar-dock.js +14 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/toolbar-position.js +1 -0
- package/dist/collection/components/graphwise-reactodia/models/ui/ui-config.js +1 -0
- package/dist/collection/components/graphwise-reactodia/node-action/node-actions.js +22 -0
- package/dist/collection/components/graphwise-reactodia/providers/service/service-inject.js +15 -0
- package/dist/collection/components/graphwise-reactodia/providers/service/service.js +19 -0
- package/dist/collection/components/graphwise-reactodia/providers/service/service.provider.js +20 -0
- package/dist/collection/components/graphwise-reactodia/reactodia-app.js +188 -26
- package/dist/collection/components/graphwise-reactodia/services/diagram/diagram.service.js +71 -0
- package/dist/collection/components/graphwise-reactodia/services/diagram-file/diagram-file.service.js +68 -0
- package/dist/collection/components/graphwise-reactodia/services/diagram-storage/diagram-storage.service.js +71 -0
- package/dist/collection/components/graphwise-reactodia/services/error/error.service.js +78 -0
- package/dist/collection/components/graphwise-reactodia/services/event/event.service.js +58 -0
- package/dist/collection/components/graphwise-reactodia/services/window/window.service.js +24 -0
- package/dist/collection/components/graphwise-reactodia/styles/type-style.resolver.js +52 -0
- package/dist/collection/components/graphwise-reactodia/testing/storage.mock.js +35 -0
- package/dist/collection/components/graphwise-reactodia/ui-config/default-ui-config.js +30 -0
- package/dist/collection/components/graphwise-reactodia/ui-config/ui-config-mapper.js +51 -0
- package/dist/collection/components/graphwise-reactodia/utils/object-util.js +30 -0
- package/dist/collection/index.js +7 -1
- package/dist/collection/pages/graphwise-reactodia/main.js +157 -0
- package/dist/collection/pages/graphwise-reactodia/owl-rdfs-settings.js +195 -0
- package/dist/esm/graphwise-reactodia.entry.js +28519 -41232
- package/dist/esm/graphwise-reactodia.js +3 -3
- package/dist/esm/{index-Cypw7ydc.js → index-DpCR6zMg.js} +16 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/loader.js +3 -3
- package/dist/esm/node-action-fwJ3Zupw.js +94 -0
- package/dist/graphwise-reactodia/graphwise-reactodia.esm.js +1 -1
- package/dist/graphwise-reactodia/index.esm.js +1 -0
- package/dist/graphwise-reactodia/p-DpCR6zMg.js +2 -0
- package/dist/graphwise-reactodia/p-c3d8a69a.entry.js +1 -0
- package/dist/graphwise-reactodia/p-fwJ3Zupw.js +1 -0
- package/dist/types/components/graphwise-reactodia/graphwise-reactodia.d.ts +44 -16
- package/dist/types/components/graphwise-reactodia/i18n/language-key.d.ts +4 -0
- package/dist/types/components/graphwise-reactodia/i18n/translations.d.ts +2 -343
- package/dist/types/components/graphwise-reactodia/menu/export-diagram-action.d.ts +4 -0
- package/dist/types/components/graphwise-reactodia/menu/graphwise-menu.d.ts +6 -0
- package/dist/types/components/graphwise-reactodia/menu/import-diagram-action.d.ts +4 -0
- package/dist/types/components/graphwise-reactodia/models/clear-diagram-storage-event.d.ts +5 -0
- package/dist/types/components/graphwise-reactodia/models/error/error-cause.d.ts +10 -0
- package/dist/types/components/graphwise-reactodia/models/error/error-code.d.ts +19 -0
- package/dist/types/components/graphwise-reactodia/models/error/error-report.d.ts +13 -0
- package/dist/types/components/graphwise-reactodia/models/event/event-callback.d.ts +5 -0
- package/dist/types/components/graphwise-reactodia/models/event/event-detail.d.ts +55 -0
- package/dist/types/components/graphwise-reactodia/models/event/event-type.d.ts +7 -0
- package/dist/types/components/graphwise-reactodia/models/reactodia-app-props.d.ts +20 -15
- package/dist/types/components/graphwise-reactodia/models/reactodia-config.d.ts +36 -0
- package/dist/types/components/graphwise-reactodia/models/sparql/sparql-query-function.d.ts +6 -0
- package/dist/types/components/graphwise-reactodia/models/sparql/sparql-query-params.d.ts +12 -0
- package/dist/types/components/graphwise-reactodia/models/subscription-list.d.ts +26 -0
- package/dist/types/components/graphwise-reactodia/models/subscription.d.ts +4 -0
- package/dist/types/components/graphwise-reactodia/models/triple.d.ts +19 -0
- package/dist/types/components/graphwise-reactodia/models/ui/menu-config.d.ts +8 -0
- package/dist/types/components/graphwise-reactodia/models/ui/menu-item.d.ts +17 -0
- package/dist/types/components/graphwise-reactodia/models/ui/node-action.d.ts +21 -0
- package/dist/types/components/graphwise-reactodia/models/ui/resolved-toolbar-position.d.ts +8 -0
- package/dist/types/components/graphwise-reactodia/models/ui/resolved-ui-config.d.ts +12 -0
- package/dist/types/components/graphwise-reactodia/models/ui/toolbar-dock.d.ts +13 -0
- package/dist/types/components/graphwise-reactodia/models/ui/toolbar-position.d.ts +11 -0
- package/dist/types/components/graphwise-reactodia/models/ui/ui-config.d.ts +17 -0
- package/dist/types/components/graphwise-reactodia/node-action/node-actions.d.ts +6 -0
- package/dist/types/components/graphwise-reactodia/providers/service/service-inject.d.ts +13 -0
- package/dist/types/components/graphwise-reactodia/providers/service/service.d.ts +28 -0
- package/dist/types/components/graphwise-reactodia/providers/service/service.provider.d.ts +16 -0
- package/dist/types/components/graphwise-reactodia/reactodia-app.d.ts +3 -2
- package/dist/types/components/graphwise-reactodia/services/diagram/diagram.service.d.ts +36 -0
- package/dist/types/components/graphwise-reactodia/services/diagram-file/diagram-file.service.d.ts +24 -0
- package/dist/types/components/graphwise-reactodia/services/diagram-storage/diagram-storage.service.d.ts +27 -0
- package/dist/types/components/graphwise-reactodia/services/error/error.service.d.ts +41 -0
- package/dist/types/components/graphwise-reactodia/services/event/event.service.d.ts +30 -0
- package/dist/types/components/graphwise-reactodia/services/window/window.service.d.ts +7 -0
- package/dist/types/components/graphwise-reactodia/styles/type-style.resolver.d.ts +11 -0
- package/dist/types/components/graphwise-reactodia/testing/storage.mock.d.ts +18 -0
- package/dist/types/components/graphwise-reactodia/ui-config/default-ui-config.d.ts +5 -0
- package/dist/types/components/graphwise-reactodia/ui-config/ui-config-mapper.d.ts +14 -0
- package/dist/types/components/graphwise-reactodia/utils/object-util.d.ts +15 -0
- package/dist/types/components.d.ts +60 -27
- package/dist/types/index.d.ts +15 -1
- package/package.json +39 -10
- package/dist/graphwise-reactodia/p-Cypw7ydc.js +0 -2
- package/dist/graphwise-reactodia/p-bafd6be5.entry.js +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
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
|
+
export const CLEAR_DIAGRAM_STORAGE_EVENT = 'graphwise-reactodia:clear-diagram-storage';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
/** The host's UI configuration has an unknown value, which is skipped. */
|
|
19
|
+
ErrorCode["UNKNOWN_UI_CONFIG"] = "unknown-ui-config";
|
|
20
|
+
})(ErrorCode || (ErrorCode = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
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["TEXT_SEARCH"] = "text-search";
|
|
8
|
+
})(EventType || (EventType = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A collection of {@link Subscription}s that can be released together. Components collect the
|
|
3
|
+
* subscriptions they open and call {@link unsubscribeAll} on teardown so nothing is left
|
|
4
|
+
* listening.
|
|
5
|
+
*/
|
|
6
|
+
export class SubscriptionList {
|
|
7
|
+
constructor(subscriptions = []) {
|
|
8
|
+
this.items = subscriptions;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Adds a subscription to the list.
|
|
12
|
+
*/
|
|
13
|
+
add(subscription) {
|
|
14
|
+
this.items.push(subscription);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Adds multiple subscriptions to the list.
|
|
18
|
+
*/
|
|
19
|
+
addAll(subscriptions) {
|
|
20
|
+
this.items.push(...subscriptions);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Removes a subscription from the list without unsubscribing it.
|
|
24
|
+
*/
|
|
25
|
+
remove(subscription) {
|
|
26
|
+
this.items = this.items.filter((sub) => sub !== subscription);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Calls every subscription (unsubscribing it) and clears the list.
|
|
30
|
+
*/
|
|
31
|
+
unsubscribeAll() {
|
|
32
|
+
this.items.forEach((subscription) => subscription());
|
|
33
|
+
this.items = [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An entry of the workspace main menu.
|
|
3
|
+
*/
|
|
4
|
+
export var MenuItem;
|
|
5
|
+
(function (MenuItem) {
|
|
6
|
+
/** Removes all nodes from the diagram. */
|
|
7
|
+
MenuItem["CLEAR_ALL"] = "clear-all";
|
|
8
|
+
/** Exports the diagram as a PNG image. */
|
|
9
|
+
MenuItem["EXPORT_PNG"] = "export-png";
|
|
10
|
+
/** Exports the diagram as an SVG image. */
|
|
11
|
+
MenuItem["EXPORT_SVG"] = "export-svg";
|
|
12
|
+
/** Prints the diagram. */
|
|
13
|
+
MenuItem["PRINT"] = "print";
|
|
14
|
+
/** Exports the diagram as a JSON file. */
|
|
15
|
+
MenuItem["EXPORT_JSON"] = "export-json";
|
|
16
|
+
/** Imports a diagram from a JSON file. */
|
|
17
|
+
MenuItem["IMPORT_JSON"] = "import-json";
|
|
18
|
+
})(MenuItem || (MenuItem = {}));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A button shown around a selected node that acts on it.
|
|
3
|
+
*/
|
|
4
|
+
export var NodeAction;
|
|
5
|
+
(function (NodeAction) {
|
|
6
|
+
/** Groups or ungroups the selected nodes. */
|
|
7
|
+
NodeAction["GROUP"] = "group";
|
|
8
|
+
/** Removes the node from the diagram. */
|
|
9
|
+
NodeAction["REMOVE"] = "remove";
|
|
10
|
+
/** Expands or collapses the node to show its properties. */
|
|
11
|
+
NodeAction["EXPAND"] = "expand";
|
|
12
|
+
/** Opens the node IRI. */
|
|
13
|
+
NodeAction["OPEN_LINK"] = "open-link";
|
|
14
|
+
/** Opens the menu to navigate to connected nodes. */
|
|
15
|
+
NodeAction["CONNECTIONS"] = "connections";
|
|
16
|
+
/** Searches for nodes connected to this one. */
|
|
17
|
+
NodeAction["ADD_TO_FILTER"] = "add-to-filter";
|
|
18
|
+
/** Adds an annotation to the node. */
|
|
19
|
+
NodeAction["ANNOTATE"] = "annotate";
|
|
20
|
+
/** Draws a new link from the node; for an entity, only in authoring mode. */
|
|
21
|
+
NodeAction["ESTABLISH_LINK"] = "establish-link";
|
|
22
|
+
})(NodeAction || (NodeAction = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The side or corner of the canvas a toolbar is docked to.
|
|
3
|
+
*/
|
|
4
|
+
export var ToolbarDock;
|
|
5
|
+
(function (ToolbarDock) {
|
|
6
|
+
ToolbarDock["NW"] = "nw";
|
|
7
|
+
ToolbarDock["N"] = "n";
|
|
8
|
+
ToolbarDock["NE"] = "ne";
|
|
9
|
+
ToolbarDock["E"] = "e";
|
|
10
|
+
ToolbarDock["SE"] = "se";
|
|
11
|
+
ToolbarDock["S"] = "s";
|
|
12
|
+
ToolbarDock["SW"] = "sw";
|
|
13
|
+
ToolbarDock["W"] = "w";
|
|
14
|
+
})(ToolbarDock || (ToolbarDock = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
import { SelectionActionAddToFilter, SelectionActionAnchor, SelectionActionAnnotate, SelectionActionConnections, SelectionActionEstablishLink, SelectionActionExpand, SelectionActionGroup, SelectionActionRemove } from "@reactodia/workspace";
|
|
3
|
+
import { NodeAction } from "../models/ui/node-action";
|
|
4
|
+
/**
|
|
5
|
+
* Each node action at its position in the fork's default `Halo`.
|
|
6
|
+
*/
|
|
7
|
+
const NODE_ACTIONS = {
|
|
8
|
+
[NodeAction.GROUP]: (key) => createElement(SelectionActionGroup, { key, dock: 'nw', dockColumn: 1 }),
|
|
9
|
+
[NodeAction.REMOVE]: (key) => createElement(SelectionActionRemove, { key, dock: 'ne' }),
|
|
10
|
+
[NodeAction.EXPAND]: (key) => createElement(SelectionActionExpand, { key, dock: 's' }),
|
|
11
|
+
[NodeAction.OPEN_LINK]: (key) => createElement(SelectionActionAnchor, { key, dock: 'w' }),
|
|
12
|
+
[NodeAction.CONNECTIONS]: (key) => createElement(SelectionActionConnections, { key, dock: 'e' }),
|
|
13
|
+
[NodeAction.ADD_TO_FILTER]: (key) => createElement(SelectionActionAddToFilter, { key, dock: 'se' }),
|
|
14
|
+
[NodeAction.ANNOTATE]: (key) => createElement(SelectionActionAnnotate, { key, dock: 'se', dockColumn: 1 }),
|
|
15
|
+
[NodeAction.ESTABLISH_LINK]: (key) => createElement(SelectionActionEstablishLink, { key, dock: 'sw' })
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The `Halo` children for the given node actions.
|
|
19
|
+
*/
|
|
20
|
+
export function createNodeActions(actions) {
|
|
21
|
+
return actions.map((action) => NODE_ACTIONS[action](action));
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ServiceProvider } from "./service.provider";
|
|
2
|
+
/**
|
|
3
|
+
* Injects the singleton instance of the given service class from the {@link ServiceProvider}.
|
|
4
|
+
*
|
|
5
|
+
* @param serviceClass The class of the service to inject.
|
|
6
|
+
* @returns The shared instance of the specified service class.
|
|
7
|
+
* @template T The type of the service to inject.
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const diagramStateService = service(DiagramStateService);
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function service(serviceClass) {
|
|
14
|
+
return ServiceProvider.get(serviceClass);
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decorator for a service class.
|
|
3
|
+
* It receives the class and simply type checks it with the {@link Service} interface.
|
|
4
|
+
* Works as a contract, which enforces the service class to have a static ID member.
|
|
5
|
+
* We can't simply implement the interface, since this will enforce the ID to be an instance member, which is not what we want.
|
|
6
|
+
*
|
|
7
|
+
* @param _serviceClass The decorated service class, checked for its ID and discarded.
|
|
8
|
+
* @template T The type of the service instance.
|
|
9
|
+
* @example
|
|
10
|
+
* ```TypeScript
|
|
11
|
+
* @Service
|
|
12
|
+
* export class WindowService {
|
|
13
|
+
* static readonly ID = 'WindowService';
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function Service(_serviceClass) {
|
|
18
|
+
// no implementation needed. We only use the type checking of the parameter
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider for all {@link Service} instances. Services are singletons: there is only one
|
|
3
|
+
* instance of each service, created on demand and cached here so every consumer shares it.
|
|
4
|
+
*/
|
|
5
|
+
export class ServiceProvider {
|
|
6
|
+
/**
|
|
7
|
+
* Returns the instance of the given service type, creating and caching it on first request.
|
|
8
|
+
*
|
|
9
|
+
* @param serviceClass The service type to retrieve.
|
|
10
|
+
* @returns The shared instance of the service.
|
|
11
|
+
* @template T The type of the service to retrieve.
|
|
12
|
+
*/
|
|
13
|
+
static get(serviceClass) {
|
|
14
|
+
if (!ServiceProvider.SERVICE_INSTANCES.has(serviceClass.ID)) {
|
|
15
|
+
ServiceProvider.SERVICE_INSTANCES.set(serviceClass.ID, new serviceClass());
|
|
16
|
+
}
|
|
17
|
+
return ServiceProvider.SERVICE_INSTANCES.get(serviceClass.ID);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
ServiceProvider.SERVICE_INSTANCES = new Map();
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { createElement } from "react";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
|
-
import { DefaultWorkspace, SparqlDataProvider, useLoadedWorkspace, 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
|
+
import { service } from "./providers/service/service-inject";
|
|
7
|
+
import { DiagramService } from "./services/diagram/diagram.service";
|
|
8
|
+
import { DiagramStorageService } from "./services/diagram-storage/diagram-storage.service";
|
|
9
|
+
import { EventService } from "./services/event/event.service";
|
|
10
|
+
import { ErrorService } from "./services/error/error.service";
|
|
11
|
+
import { ErrorCode } from "./models/error/error-code";
|
|
12
|
+
import { EventType } from "./models/event/event-type";
|
|
13
|
+
import { SubscriptionList } from "./models/subscription-list";
|
|
14
|
+
import { resolveTypeStyle } from "./styles/type-style.resolver";
|
|
15
|
+
import { toWorkspaceProps } from "./ui-config/ui-config-mapper";
|
|
6
16
|
/**
|
|
7
|
-
* Reactodia ships English as its built-in default bundle, so English
|
|
17
|
+
* Reactodia ships English as its built-in default bundle, so the English bundle only adds our own keys.
|
|
8
18
|
* Other languages are layered on top as partial bundles; unknown codes fall back to English.
|
|
9
19
|
*
|
|
10
20
|
* Reactodia never re-reads the translations, so the component must be remounted
|
|
@@ -20,41 +30,183 @@ function translationsForLanguage(language) {
|
|
|
20
30
|
* runs outside React and therefore cannot call the `useWorkspace` hook.
|
|
21
31
|
*/
|
|
22
32
|
let workspaceContext = null;
|
|
33
|
+
/**
|
|
34
|
+
* Active listeners that persist diagram edits to local storage. Populated when the workspace
|
|
35
|
+
* mounts and released in {@link unmountReactodia}, so persistence follows the same lifecycle as
|
|
36
|
+
* the React root.
|
|
37
|
+
*/
|
|
38
|
+
const subscriptions = new SubscriptionList();
|
|
39
|
+
let diagramStorageSubscription;
|
|
40
|
+
/**
|
|
41
|
+
* The `DefaultWorkspace` props from the host's UI configuration. Kept across reloads, so unknown values are reported
|
|
42
|
+
* once, and cleared in {@link unmountReactodia}.
|
|
43
|
+
*/
|
|
44
|
+
let uiConfigProps;
|
|
45
|
+
const diagramService = service(DiagramService);
|
|
46
|
+
const diagramStorageService = service(DiagramStorageService);
|
|
47
|
+
const eventService = service(EventService);
|
|
48
|
+
const errorService = service(ErrorService);
|
|
49
|
+
/**
|
|
50
|
+
* Emits a {@link EventType.TEXT_SEARCH} event for each text lookup.
|
|
51
|
+
*/
|
|
52
|
+
function emitTextSearch(method, params) {
|
|
53
|
+
if (method === 'lookup' && params.text) {
|
|
54
|
+
eventService.emit({ type: EventType.TEXT_SEARCH });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reports every failed data provider call, unless the call was aborted, and passes the failure on to the caller.
|
|
59
|
+
*/
|
|
60
|
+
const reportDataFetchError = async (_method, params, body) => {
|
|
61
|
+
var _a;
|
|
62
|
+
try {
|
|
63
|
+
return await body(params);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (!((_a = params.signal) === null || _a === void 0 ? void 0 : _a.aborted)) {
|
|
67
|
+
errorService.report(ErrorCode.DATA_FETCH, error);
|
|
68
|
+
}
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
23
72
|
/**
|
|
24
73
|
* Builds a Reactodia {@link SparqlDataProvider} for the given endpoint using the supplied
|
|
25
|
-
* query preset. The host owns the query configuration and passes it in via props
|
|
26
|
-
* is
|
|
74
|
+
* query preset. The host owns the query configuration and always passes it in via props.
|
|
75
|
+
* The provider is decorated, so its failed calls are reported and its text lookups emit an event.
|
|
27
76
|
*/
|
|
28
|
-
function createDataProvider(
|
|
29
|
-
|
|
77
|
+
function createDataProvider(props) {
|
|
78
|
+
const { currentRepository, config, providerSettings } = props;
|
|
79
|
+
const baseProvider = new SparqlDataProvider({
|
|
30
80
|
endpointUrl: currentRepository,
|
|
31
81
|
queryMethod: 'POST',
|
|
32
|
-
queryFunction
|
|
33
|
-
},
|
|
82
|
+
queryFunction: config.queryFunction
|
|
83
|
+
}, providerSettings);
|
|
84
|
+
return new DecoratedDataProvider({
|
|
85
|
+
baseProvider,
|
|
86
|
+
decorator: (method, params, body) => {
|
|
87
|
+
emitTextSearch(method, params);
|
|
88
|
+
return reportDataFetchError(method, params, body);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Places the seed entities on the canvas. Each IRI is added as a placeholder element, and data is then loaded for the
|
|
94
|
+
* respective nodes using the {@link DataDiagramModel.requestData} method.
|
|
95
|
+
*/
|
|
96
|
+
async function seedIrisToCanvas(context, dataProvider, seed, signal) {
|
|
97
|
+
const { model, performLayout } = context;
|
|
98
|
+
await model.createNewDiagram({ dataProvider, signal });
|
|
99
|
+
for (const iri of seed) {
|
|
100
|
+
model.createElement(iri);
|
|
101
|
+
}
|
|
102
|
+
await model.requestData();
|
|
103
|
+
await performLayout({ signal });
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Places a pre-resolved graph (e.g. a CONSTRUCT query result) on the canvas. The difference between this and
|
|
107
|
+
* {@link seedIrisToCanvas} is that this method does not request link data from the SPARQL endpoint, since describe/construct
|
|
108
|
+
* queries are not persisted in the DB. Here we expect provided links and query for element data only
|
|
109
|
+
*/
|
|
110
|
+
async function seedGraphToCanvas(context, dataProvider, links, signal) {
|
|
111
|
+
const { model, performLayout } = context;
|
|
112
|
+
await model.createNewDiagram({ dataProvider, signal });
|
|
113
|
+
const uniqueIris = new Set();
|
|
114
|
+
links.forEach((link) => {
|
|
115
|
+
var _a;
|
|
116
|
+
uniqueIris.add(link.source);
|
|
117
|
+
uniqueIris.add(link.target);
|
|
118
|
+
// this is a createOrGet, regardless of the name, so we don't need to worry about duplicates.
|
|
119
|
+
model.createElement(link.source);
|
|
120
|
+
model.createElement(link.target);
|
|
121
|
+
(_a = link.rawPredicates) === null || _a === void 0 ? void 0 : _a.forEach((predicate) => {
|
|
122
|
+
model.createLinks({
|
|
123
|
+
linkTypeId: predicate,
|
|
124
|
+
sourceId: link.source,
|
|
125
|
+
targetId: link.target,
|
|
126
|
+
properties: {}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
await model.requestElementData(Array.from(uniqueIris));
|
|
131
|
+
await performLayout({ signal });
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Subscribes to the model's changes so diagram edits are persisted to local storage. The
|
|
135
|
+
* subscription is tracked in {@link subscriptions} so it is released together with the React
|
|
136
|
+
* root in {@link unmountReactodia}.
|
|
137
|
+
*/
|
|
138
|
+
function onDiagramChange(model) {
|
|
139
|
+
subscribeToDiagramChange(model);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Starts persisting the model's edits to local storage, keeping the subscription in {@link diagramStorageSubscription}.
|
|
143
|
+
*/
|
|
144
|
+
function subscribeToDiagramChange(model) {
|
|
145
|
+
diagramStorageSubscription === null || diagramStorageSubscription === void 0 ? void 0 : diagramStorageSubscription();
|
|
146
|
+
diagramStorageSubscription = diagramService.subscribeToDiagramChange(model, (diagram) => diagramStorageService.save(diagram));
|
|
147
|
+
subscriptions.add(diagramStorageSubscription);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Subscribes to the host's "clear persisted diagram" command so the saved layout is dropped on
|
|
151
|
+
* request (e.g. before a fresh seed should take precedence over previously saved edits). The
|
|
152
|
+
* subscription is tracked in {@link subscriptions} so it is released together with the React
|
|
153
|
+
* root in {@link unmountReactodia}.
|
|
154
|
+
*
|
|
155
|
+
* @param model The diagram model whose edits are persisted
|
|
156
|
+
*/
|
|
157
|
+
function onClearDiagramStorage(model) {
|
|
158
|
+
subscriptions.add(eventService.subscribeToClearDiagramStorage(() => {
|
|
159
|
+
// re-subscribe, to avoid any pending debounced saves, which may write over the cleared diagram
|
|
160
|
+
subscribeToDiagramChange(model);
|
|
161
|
+
diagramStorageService.clear();
|
|
162
|
+
}));
|
|
34
163
|
}
|
|
35
164
|
/**
|
|
36
165
|
* The Reactodia workspace React component.
|
|
37
166
|
*
|
|
38
167
|
* Authored with `React.createElement` (no TSX) on purpose, since there are differences in stencil and react
|
|
39
168
|
*
|
|
40
|
-
*
|
|
41
|
-
* (Reactodia's `DefaultWorkspace` unified search),
|
|
42
|
-
*
|
|
169
|
+
* Without a seed the canvas starts empty and the user populates it through the workspace
|
|
170
|
+
* search bar (Reactodia's `DefaultWorkspace` unified search), backed by the SPARQL data
|
|
171
|
+
* provider's lookup. With a seed, the seeded nodes are placed on the canvas on startup.
|
|
43
172
|
*/
|
|
44
173
|
function ReactodiaApp(props) {
|
|
45
|
-
const {
|
|
174
|
+
const { language, config } = props;
|
|
175
|
+
const currentDiagram = props.isReload ? exportReactodiaLayout() : undefined;
|
|
46
176
|
const { onMount } = useLoadedWorkspace(async ({ context, signal }) => {
|
|
177
|
+
var _a, _b;
|
|
47
178
|
workspaceContext = context;
|
|
48
179
|
const { model } = context;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
180
|
+
onDiagramChange(model);
|
|
181
|
+
onClearDiagramStorage(model);
|
|
182
|
+
const dataProvider = createDataProvider(props);
|
|
183
|
+
const isReload = props.isReload;
|
|
184
|
+
const savedDiagram = diagramStorageService.load();
|
|
185
|
+
try {
|
|
186
|
+
if (isReload) {
|
|
187
|
+
// Reload the diagram that is currently on the canvas. This may happen when the host changes the provider
|
|
188
|
+
// settings, or when the user switches the language at runtime, since there is no existing mechanism to
|
|
189
|
+
// re-translate the UI at runtime (not for the UI labels at least)
|
|
190
|
+
await diagramService.importDiagram(model, dataProvider, currentDiagram, signal);
|
|
191
|
+
}
|
|
192
|
+
else if ((_a = config.seedIris) === null || _a === void 0 ? void 0 : _a.length) {
|
|
193
|
+
await seedIrisToCanvas(context, dataProvider, config.seedIris, signal);
|
|
194
|
+
}
|
|
195
|
+
else if ((_b = config.seedGraph) === null || _b === void 0 ? void 0 : _b.length) {
|
|
196
|
+
await seedGraphToCanvas(context, dataProvider, config.seedGraph, signal);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Restore the previously saved layout when present, otherwise start empty. Either way this binds the
|
|
200
|
+
// data provider (savedDiagram is undefined -> empty diagram), so the unified search/lookup works.
|
|
201
|
+
await diagramService.importDiagram(model, dataProvider, savedDiagram, signal);
|
|
202
|
+
}
|
|
55
203
|
}
|
|
56
|
-
|
|
57
|
-
|
|
204
|
+
catch (error) {
|
|
205
|
+
if (!signal.aborted) {
|
|
206
|
+
errorService.report(ErrorCode.DIAGRAM_LOAD, error);
|
|
207
|
+
}
|
|
208
|
+
// rethrow, so the workspace shows the failure on its loading spinner
|
|
209
|
+
throw error;
|
|
58
210
|
}
|
|
59
211
|
}, [language]);
|
|
60
212
|
/**
|
|
@@ -71,28 +223,36 @@ function ReactodiaApp(props) {
|
|
|
71
223
|
ref: onMount,
|
|
72
224
|
defaultLayout: blockingDefaultLayout,
|
|
73
225
|
defaultLanguage: language,
|
|
74
|
-
translations: translationsForLanguage(language)
|
|
75
|
-
|
|
226
|
+
translations: translationsForLanguage(language),
|
|
227
|
+
typeStyleResolver: resolveTypeStyle
|
|
228
|
+
}, createElement(DefaultWorkspace, Object.assign({ colorScheme: props.theme }, uiConfigProps)));
|
|
76
229
|
}
|
|
77
230
|
/**
|
|
78
231
|
* Mounts the Reactodia application into the given container and returns the React root.
|
|
79
232
|
*/
|
|
80
233
|
export function mountReactodia(container, props) {
|
|
234
|
+
uiConfigProps !== null && uiConfigProps !== void 0 ? uiConfigProps : (uiConfigProps = toWorkspaceProps(props.config.ui));
|
|
81
235
|
const root = createRoot(container);
|
|
82
236
|
root.render(createElement(ReactodiaApp, props));
|
|
83
237
|
return root;
|
|
84
238
|
}
|
|
85
239
|
/**
|
|
86
|
-
* Re-points the diagram at a new SPARQL endpoint
|
|
87
|
-
*
|
|
240
|
+
* Re-points the diagram at a new SPARQL endpoint by recreating it with a fresh data provider.
|
|
241
|
+
* The canvas is reset to empty, matching the initial mount, since the data of another repository
|
|
242
|
+
* has nothing to do with the current graph. A failure is reported, not thrown.
|
|
88
243
|
*/
|
|
89
244
|
export async function updateReactodia(props) {
|
|
90
245
|
if (!workspaceContext) {
|
|
91
246
|
return;
|
|
92
247
|
}
|
|
93
248
|
const { model } = workspaceContext;
|
|
94
|
-
const dataProvider = createDataProvider(props
|
|
95
|
-
|
|
249
|
+
const dataProvider = createDataProvider(props);
|
|
250
|
+
try {
|
|
251
|
+
await model.createNewDiagram({ dataProvider });
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
errorService.report(ErrorCode.DIAGRAM_LOAD, error);
|
|
255
|
+
}
|
|
96
256
|
}
|
|
97
257
|
/**
|
|
98
258
|
* Serializes the current diagram so it can be restored after a remount (e.g. when a
|
|
@@ -105,5 +265,7 @@ export function exportReactodiaLayout() {
|
|
|
105
265
|
* Unmounts the Reactodia application.
|
|
106
266
|
*/
|
|
107
267
|
export function unmountReactodia(root) {
|
|
268
|
+
subscriptions.unsubscribeAll();
|
|
269
|
+
uiConfigProps = undefined;
|
|
108
270
|
root.unmount();
|
|
109
271
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
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 DiagramService_1;
|
|
12
|
+
import { Service } from "../../providers/service/service";
|
|
13
|
+
/**
|
|
14
|
+
* Service for diagram related operations and subscriptions
|
|
15
|
+
*/
|
|
16
|
+
let DiagramService = DiagramService_1 = class DiagramService {
|
|
17
|
+
/**
|
|
18
|
+
* Replaces the diagram content with the given serialization. Element data is requested from the data provider and
|
|
19
|
+
* the links between the imported elements are validated against it.
|
|
20
|
+
*
|
|
21
|
+
* @param model The diagram model to import into.
|
|
22
|
+
* @param dataProvider The data provider to bind to the diagram.
|
|
23
|
+
* @param diagram The serialization to import. When `undefined`, the diagram is cleared.
|
|
24
|
+
* @param signal Optional signal to abort the import.
|
|
25
|
+
*/
|
|
26
|
+
importDiagram(model, dataProvider, diagram, signal) {
|
|
27
|
+
// selection is not cleared on import, so we clear it manually to avoid painting the previous selection
|
|
28
|
+
model.setSelection([]);
|
|
29
|
+
return model.importLayout({ dataProvider, diagram, signal, validateLinks: true });
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Subscribes to diagram changes. On every debounced change the current layout is
|
|
33
|
+
* exported and passed to the callback.
|
|
34
|
+
* Debounce time for the callback trigger is needed, because certain events (like moving a node) can trigger
|
|
35
|
+
* multiple `historyChanged` events in a short time.
|
|
36
|
+
*
|
|
37
|
+
* @param model The diagram model to observe.
|
|
38
|
+
* @param onChangeCallback Called with the exported layout when the diagram changes.
|
|
39
|
+
* @returns A {@link Subscription} that, when called, removes the listener and drops any
|
|
40
|
+
* pending notification.
|
|
41
|
+
*/
|
|
42
|
+
subscribeToDiagramChange(model, onChangeCallback) {
|
|
43
|
+
let notifyTimer;
|
|
44
|
+
const onHistoryChange = () => {
|
|
45
|
+
if (notifyTimer) {
|
|
46
|
+
clearTimeout(notifyTimer);
|
|
47
|
+
}
|
|
48
|
+
notifyTimer = setTimeout(() => {
|
|
49
|
+
if (notifyTimer) {
|
|
50
|
+
onChangeCallback(model.exportLayout());
|
|
51
|
+
}
|
|
52
|
+
notifyTimer = undefined;
|
|
53
|
+
}, DiagramService_1.NOTIFY_DEBOUNCE_MS);
|
|
54
|
+
};
|
|
55
|
+
model.history.events.on(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
|
|
56
|
+
return () => {
|
|
57
|
+
model.history.events.off(DiagramService_1.HISTORY_CHANGED_EVENT, onHistoryChange);
|
|
58
|
+
if (notifyTimer) {
|
|
59
|
+
clearTimeout(notifyTimer);
|
|
60
|
+
notifyTimer = undefined;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
DiagramService.ID = 'DiagramService';
|
|
66
|
+
DiagramService.NOTIFY_DEBOUNCE_MS = 300;
|
|
67
|
+
DiagramService.HISTORY_CHANGED_EVENT = 'historyChanged';
|
|
68
|
+
DiagramService = DiagramService_1 = __decorate([
|
|
69
|
+
Service
|
|
70
|
+
], DiagramService);
|
|
71
|
+
export { DiagramService };
|