Skip to main content

Classic Workspace

Example demonstrating classic workspace with collapsible layout panels.

/src/examples/PlaygroundClassicWorkspace.tsx
import * as React from 'react';
import * as Reactodia from '@reactodia/workspace';
import { SemanticTypeStyles, makeOntologyLinkTemplates } from '@reactodia/workspace/legacy-styles';
import * as N3 from 'n3';

import { ExampleToolbarMenu } from './ExampleCommon';

const OntologyLinkTemplates = makeOntologyLinkTemplates(Reactodia);
const Layouts = Reactodia.defineLayoutWorker(() => new Worker(
new URL('@reactodia/workspace/layout.worker', import.meta.url)
));

type TurtleDataSource =
| { type: 'url'; url: string }
| { type: 'data'; data: string };

export function PlaygroundClassicWorkspace() {
const {defaultLayout} = Reactodia.useWorker(Layouts);

const [dataSource, setDataSource] = React.useState<TurtleDataSource>({
type: 'url',
url: 'https://reactodia.github.io/resources/orgOntology.ttl',
});

const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
const {model, editor, getCommandBus} = context;
editor.setAuthoringMode(true);

let turtleData: string;
if (dataSource.type === 'url') {
const response = await fetch(dataSource.url, {signal});
turtleData = await response.text();
} else {
turtleData = dataSource.data;
}

const dataProvider = new Reactodia.RdfDataProvider();
try {
dataProvider.addGraph(new N3.Parser().parse(turtleData));
} catch (err) {
throw new Error('Error parsing RDF graph data', {cause: err});
}

await model.importLayout({dataProvider, signal});

getCommandBus(Reactodia.UnifiedSearchTopic)
.trigger('focus', {sectionKey: 'elementTypes'});
}, [dataSource]);

return (
<Reactodia.Workspace ref={onMount}
defaultLayout={defaultLayout}
typeStyleResolver={SemanticTypeStyles}>
<Reactodia.ClassicWorkspace
canvas={{
elementTemplateResolver: types => {
if (types.includes('http://www.w3.org/2002/07/owl#DatatypeProperty')) {
return Reactodia.ClassicTemplate;
}
return undefined;
},
linkTemplateResolver: type => {
if (type === 'http://www.w3.org/2000/01/rdf-schema#subClassOf') {
return Reactodia.DefaultLinkTemplate;
}
return OntologyLinkTemplates(type);
},
}}
toolbar={{
menu: (
<>
<ToolbarActionOpenTurtleGraph onOpen={setDataSource} />
<ExampleToolbarMenu />
</>
)
}}
/>
</Reactodia.Workspace>
);
}

function ToolbarActionOpenTurtleGraph(props: {
onOpen: (dataSource: TurtleDataSource) => void;
}) {
const {onOpen} = props;
return (
<Reactodia.ToolbarActionOpen
fileAccept='.ttl'
onSelect={async file => {
const turtleText = await file.text();
onOpen({type: 'data', data: turtleText});
}}>
Load RDF (Turtle) data
</Reactodia.ToolbarActionOpen>
);
}

ExampleCommon.tsx
/src/examples/ExampleCommon.tsx
import * as React from 'react';
import * as Reactodia from '@reactodia/workspace';
import { saveAs } from 'file-saver';

export function ExampleToolbarMenu() {
const {model, editor, overlay} = Reactodia.useWorkspace();
return (
<>
<Reactodia.ToolbarActionOpen
fileAccept='.json'
onSelect={async file => {
const preloadedElements = new Map<Reactodia.ElementIri, Reactodia.ElementModel>();
for (const element of model.elements) {
for (const data of Reactodia.iterateEntitiesOf(element)) {
preloadedElements.set(data.id, data);
}
}

const task = overlay.startTask({title: 'Importing a layout from file'});
try {
const json = await file.text();
const diagramLayout = JSON.parse(json);
await model.importLayout({
dataProvider: model.dataProvider,
diagram: diagramLayout,
preloadedElements,
validateLinks: true,
});
} catch (err) {
task.setError(new Error(
'Failed to load specified file with a diagram layout.',
{cause: err}
));
} finally {
task.end();
}
}}>
Open diagram from file
</Reactodia.ToolbarActionOpen>
<Reactodia.ToolbarActionSave mode='layout'
onSelect={() => {
const diagramLayout = model.exportLayout();
const layoutString = JSON.stringify(diagramLayout);
const blob = new Blob([layoutString], {type: 'application/json'});
const timestamp = new Date().toISOString().replaceAll(/[Z\s:-]/g, '');
saveAs(blob, `reactodia-diagram-${timestamp}.json`);
}}>
Save diagram to file
</Reactodia.ToolbarActionSave>
{editor.inAuthoringMode ? (
<Reactodia.ToolbarActionSave mode='authoring'
onSelect={() => {
const state = editor.authoringState;
console.log('Authoring state:', state);
alert('Please check browser console for result');
}}>
Persist changes to data
</Reactodia.ToolbarActionSave>
) : null}
<Reactodia.ToolbarActionClearAll />
<Reactodia.ToolbarActionExport kind='exportRaster' />
<Reactodia.ToolbarActionExport kind='exportSvg' />
<Reactodia.ToolbarActionExport kind='print' />
</>
);
}