Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
* Add `CanvasPlaceAt` component to render its children at specified non-viewport canvas layer instead;
* Support new placement layers: `underlay` layer to place components under all canvas content, `overLinkGeometry` layer to place components above link geometry (connections) but under link labels;
* **[💥Breaking]** Remove `defineCanvasWidget()` and `SharedCanvasState.setCanvasWidget()` (use `CanvasPlaceAt` to display components at canvas layers instead).
- Support to import and export diagram layout with custom element and link cell types (derived from `Element` or `Link`):
* Introduce an optional contract for `Element` or `Link`-derived cell types to be serializable: `SerializableElementCell` and `SerializableLinkCell`;
* When implemented, the corresponding cell types can be exported and later imported with the diagram;
* `DataDiagramModel.importLayout()` will accept known cell types via `elementCellTypes` and `linkCellTypes` to import.
- Add `EditorController.applyAuthoringChanges()` method to apply current authoring changes to the diagram (i.e. change entity data, delete relations, etc) and reset the change state to be empty.

#### ⏱ Performance
Expand Down
16 changes: 14 additions & 2 deletions examples/resources/common.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { HashMap } from '@reactodia/hashmap';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { saveAs } from 'file-saver';
Expand Down Expand Up @@ -35,8 +36,18 @@ export function ExampleToolbarMenu() {
onSelect={async file => {
const preloadedElements = new Map<Reactodia.ElementIri, Reactodia.ElementModel>();
for (const element of model.elements) {
if (element instanceof Reactodia.EntityElement) {
preloadedElements.set(element.iri, element.data);
for (const entity of Reactodia.iterateEntitiesOf(element)) {
preloadedElements.set(entity.id, entity);
}
}

const preloadedLinks = new HashMap<Reactodia.LinkKey, Reactodia.LinkModel>(
Reactodia.hashLink,
Reactodia.equalLinks
);
for (const link of model.links) {
for (const relation of Reactodia.iterateRelationsOf(link)) {
preloadedLinks.set(relation, relation);
}
}

Expand All @@ -48,6 +59,7 @@ export function ExampleToolbarMenu() {
dataProvider: model.dataProvider,
diagram: diagramLayout,
preloadedElements,
preloadedLinks,
validateLinks: true,
});
} catch (err) {
Expand Down
54 changes: 50 additions & 4 deletions src/editor/dataDiagramModel.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { ReadonlyHashMap } from '@reactodia/hashmap';

import { AbortScope } from '../coreUtils/async';
import { AnyEvent, EventSource, Events } from '../coreUtils/events';
import { Translation, TranslatedText } from '../coreUtils/i18n';

import {
ElementIri, ElementModel, ElementTypeIri, LinkModel, LinkTypeModel,
ElementIri, ElementModel, ElementTypeIri, LinkKey, LinkModel, LinkTypeModel,
LinkTypeIri, PropertyTypeIri, equalLinks,
} from '../data/model';
import { EmptyDataProvider } from '../data/decorated/emptyDataProvider';
Expand Down Expand Up @@ -34,6 +36,7 @@ import { type DataLocaleProvider, DefaultDataLocaleProvider } from './dataLocale
import {
SerializedDiagram, SerializedLinkOptions, emptyDiagram,
serializeDiagram, deserializeDiagram, markLayoutOnly,
SerializableElementCell, SerializableLinkCell,
} from './serializedDiagram';
import { DataGraph } from './dataGraph';

Expand Down Expand Up @@ -316,10 +319,35 @@ export class DataDiagramModel extends DiagramModel implements DataGraphStructure
*/
diagram?: SerializedDiagram;
/**
* Pre-cached data for the elements which should be used instead of
* Element cell types to deserialize from the imported diagram state.
*
* Any element cell type not from this list will be silently ignored.
*
* **Unstable**: this feature is likely to be changed in the future.
*
* @default [EntityElement, EntityGroup]
*/
elementCellTypes?: readonly SerializableElementCell[];
/**
* Link cell types to deserialize from the imported diagram state.
*
* Any link cell type not from this list will be silently ignored.
*
* **Unstable**: this feature is likely to be changed in the future.
*
* @default [RelationLink, RelationGroup]
*/
linkCellTypes?: readonly SerializableLinkCell[];
/**
* Pre-cached data for the entities which should be used instead of
* being requested from the data provider on import.
*/
preloadedElements?: ReadonlyMap<ElementIri, ElementModel>;
/**
* Pre-cached data for the relations which should be used instead of
* being requested from the data provider on import.
*/
preloadedLinks?: ReadonlyHashMap<LinkKey, LinkModel>;
/**
* Whether links for the between imported elements should be requested
* from the data provider on import.
Expand All @@ -343,7 +371,10 @@ export class DataDiagramModel extends DiagramModel implements DataGraphStructure
dataProvider,
locale,
diagram = emptyDiagram(),
elementCellTypes = [EntityElement, EntityGroup],
linkCellTypes = [RelationLink, RelationGroup],
preloadedElements,
preloadedLinks,
validateLinks = false,
hideUnusedLinkTypes = false,
signal: parentSignal,
Expand All @@ -368,7 +399,10 @@ export class DataDiagramModel extends DiagramModel implements DataGraphStructure

this.createGraphElements({
diagram,
elementCellTypes,
linkCellTypes,
preloadedElements,
preloadedLinks,
markLinksAsLayoutOnly: validateLinks,
});

Expand Down Expand Up @@ -477,16 +511,28 @@ export class DataDiagramModel extends DiagramModel implements DataGraphStructure

private createGraphElements(params: {
diagram: SerializedDiagram;
elementCellTypes: readonly SerializableElementCell[];
linkCellTypes: readonly SerializableLinkCell[];
preloadedElements?: ReadonlyMap<ElementIri, ElementModel>;
preloadedLinks?: ReadonlyHashMap<LinkKey, LinkModel>;
markLinksAsLayoutOnly: boolean;
}): void {
const {diagram, preloadedElements, markLinksAsLayoutOnly} = params;
const {
diagram, elementCellTypes, linkCellTypes,
preloadedElements, preloadedLinks, markLinksAsLayoutOnly,
} = params;

const {
elements,
links,
linkTypeVisibility,
} = deserializeDiagram(diagram, {preloadedElements, markLinksAsLayoutOnly});
} = deserializeDiagram(diagram, {
elementCellTypes,
linkCellTypes,
preloadedElements,
preloadedLinks,
markLinksAsLayoutOnly,
});

const batch = this.history.startBatch(
TranslatedText.text('data_diagram_model.import_layout.command')
Expand Down
Loading