Skip to content

Commit e8665df

Browse files
committed
Update docs for @reactodia/workspace@0.34.0
1 parent cac6d62 commit e8665df

File tree

13 files changed

+326
-35
lines changed

13 files changed

+326
-35
lines changed

.github/workflows/ci-checks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ on:
1010
branches: [ "main" ]
1111

1212
env:
13-
reactodia_workspace_ref: 'v0.33.0'
13+
reactodia_workspace_ref: 'v0.34.0'
1414

1515
jobs:
1616
build:

.github/workflows/deploy-pages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
workflow_dispatch:
99

1010
env:
11-
reactodia_workspace_ref: 'v0.33.0'
11+
reactodia_workspace_ref: 'v0.34.0'
1212

1313
jobs:
1414
build:

docs/components/form-input.md

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: <FormInput* />
2+
title: <Forms.Input* />
33
---
44

55
# Form input components
@@ -8,8 +8,10 @@ Reactodia provides basic built-in components to edit entity or relation properti
88

99
| Form input component | Description |
1010
|----------------------|-------------|
11-
| [`<FormInputList />`](/docs/api/workspace/variables/FormInputList.md) | Form input to edit multiple values in a list of specified single value inputs. |
12-
| [`<FormInputText />`](/docs/api/workspace/functions/FormInputText.md) | Form input to edit a single value as a plain string with an optional language. |
11+
| [`<Forms.InputList />`](/docs/api/forms/functions/InputList.md) | Form input to edit multiple values in a list of specified single value inputs. |
12+
| [`<Forms.InputText />`](/docs/api/forms/functions/InputText.md) | Form input to edit a single value as a plain string with an optional language. |
13+
| [`<Forms.InputSelect />`](/docs/api/forms/functions/InputSelect.md) | Form input to select a value from a predefined list of variants. |
14+
| [`<Forms.InputFile />`](/docs/api/forms/functions/InputFile.md) | Form input to upload files and display previously uploaded files. |
1315

1416
:::warning
1517
Currently form input components are considered **unstable** so there might be breaking changes in their API in the future.
@@ -60,10 +62,17 @@ function Example() {
6062
search={null}
6163
navigator={{expanded: false}}
6264
visualAuthoring={{
63-
inputResolver: (property, inputProps) =>
64-
property === RDF_COMMENT
65-
? <Reactodia.FormInputList {...inputProps} valueInput={MultilineTextInput} />
66-
: undefined,
65+
propertyEditor: options => (
66+
<Reactodia.DefaultPropertyEditor options={options}
67+
resolveInput={(property, inputProps) => (
68+
<Forms.InputList {...inputProps}
69+
valueInput={
70+
property === RDF_COMMENT ? MultilineTextInput : Forms.InputText
71+
}
72+
/>
73+
)}
74+
/>
75+
),
6776
}}
6877
/>
6978
</Reactodia.Workspace>
@@ -72,7 +81,7 @@ function Example() {
7281
}
7382

7483
function MultilineTextInput(props: Reactodia.FormInputSingleProps) {
75-
return <Reactodia.FormInputText {...props} multiline />;
84+
return <Forms.InputText {...props} multiline />;
7685
}
7786

7887
render(<Example />);

docs/components/unified-search.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,15 @@ function SearchWithNpm() {
100100
},
101101
], []);
102102

103+
const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => {
104+
const {getCommandBus} = context;
105+
getCommandBus(Reactodia.UnifiedSearchTopic)
106+
.trigger('focus', { sectionKey: 'entities' });
107+
}, []);
108+
103109
return (
104110
<div className='reactodia-live-editor'>
105-
<Reactodia.Workspace defaultLayout={defaultLayout}>
111+
<Reactodia.Workspace ref={onMount} defaultLayout={defaultLayout}>
106112
<Reactodia.DefaultWorkspace
107113
mainToolbar={{dock: 'n'}}
108114
navigator={{expanded: false}}

docs/concepts/data-provider.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,158 @@ function ExampleRdfProviderProvisionFromJGF() {
139139
);
140140
}
141141
```
142+
143+
## Loading data from a data provider
144+
145+
When exploring the graph data, Reactodia components track which data needs to be loaded and requests to fetch it based on currently displayed [diagram content](/docs/concepts/graph-model#diagram-content). For example, when an [`EntityElement`](/docs/api/workspace/classes/EntityElement.md) is added to the canvas and rendered with the[default template](/docs/components/canvas.md#customization), the library will load corresponding entity types to display correct labels.
146+
147+
The library includes a number of hooks and methods to simplify data loading from a custom component which are listed below.
148+
149+
### Request data for entities and/or relations on the canvas
150+
151+
After adding one or more [`EntityElement`](/docs/api/workspace/classes/EntityElement.md) elements to the canvas e.g. with [`model.createElement()`](/docs/api/workspace/classes/DataDiagramModel.md#createelement) (see [Manipulating the diagram](/docs/concepts/graph-model.md#manipulating-the-diagram)), it is necessary to call one or several of the following methods to initiate loading entity data and relations between them:
152+
153+
| Method | Description |
154+
|-----------------|-------------|
155+
| [`model.requestData()`](/docs/api/workspace/classes/DataDiagramModel.md#requestdata) | Requests to load all non-loaded ([placeholder](/docs/api/workspace/classes/EntityElement.md#isplaceholderdata)) entity elements and links connected to them. |
156+
| [`model.requestElementData()`](/docs/api/workspace/classes/DataDiagramModel.md#requestelementdata) | Requests to load (or reload) data for the specified set of entities. |
157+
| [`model.requestLinks()`](/docs/api/workspace/classes/DataDiagramModel.md#requestlinks) | Requests to load (or reload) all relations connected to the specified sets of entities. |
158+
159+
It is also possible to use [`requestElementData()`](/docs/api/workspace/functions/requestElementData.md) and [`restoreLinksBetweenElements()`](/docs/api/workspace/functions/restoreLinksBetweenElements.md) command effects to re-request the data on [undo/redo](/docs/concepts/command-history.md) if needed.
160+
161+
### Manually request data for entity, relation or property types
162+
163+
In some cases it is easier to manually trigger a request to load data for an entity, relation or property type:
164+
165+
| Method | Description |
166+
|-----------------|-------------|
167+
| [`model.createElementType()`](/docs/api/workspace/classes/DataDiagramModel.md#createelementtype) | Requests to load an entity type if it has not been loaded yet. <br/> [`model.getElementType()`](/docs/api/workspace/classes/DataDiagramModel.md#getelementtype) can be used to get the placeholder or loaded data. |
168+
| [`model.createLinkType()`](/docs/api/workspace/classes/DataDiagramModel.md#createlinktype) | Requests to load a relation type if it has not been loaded yet. <br/> [`model.getLinkType()`](/docs/api/workspace/classes/DataDiagramModel.md#getlinktype) can be used to get the placeholder or loaded data. |
169+
| [`model.createPropertyType()`](/docs/api/workspace/classes/DataDiagramModel.md#createpropertytype) | Requests to load a property type if it has not been loaded yet. <br/> [`model.getPropertyType()`](/docs/api/workspace/classes/DataDiagramModel.md#getpropertytype) can be used to get the placeholder or loaded data. |
170+
171+
#### Example: manual request and subscription for an entity type
172+
173+
```ts
174+
function MyElementTypeBadge(props: { elementTypeIri }) {
175+
const {elementTypeIri} = props;
176+
const {model} = Reactodia.useWorkspace();
177+
const t = Reactodia.useTranslation();
178+
const language = Reactodia.useObservedProperty(
179+
model.events, 'changeLanguage', () => model.language
180+
);
181+
182+
const [elementType, setElementType] = React.useState<Reactodia.ElementType>();
183+
React.useEffect(() => {
184+
setElementType(model.createElementType(elementTypeIri));
185+
}, [elementTypeIri]);
186+
187+
const data = Reactodia.useSyncStore(
188+
Reactodia.useEventStore(elementType?.events, 'changeData'),
189+
() => elementType?.data
190+
);
191+
return (
192+
<div className="my-badge">
193+
{t.formatLabel(data?.label, elementTypeIri, language)}
194+
</div>
195+
);
196+
}
197+
```
198+
199+
:::note
200+
When requesting the data manually, make sure to subscribe to created instances to re-render when the data loads via [`useObservedProperty()`](/docs/api/workspace/functions/useObservedProperty.md), [`useEventStore()`](/docs/api/workspace/functions/useEventStore.md) or manual [event subscription](/docs/concepts/event-system.md).
201+
:::
202+
203+
### `useKeyedSyncStore()`
204+
205+
[`useKeyedSyncStore`](/docs/api/workspace/functions/useKeyedSyncStore.md) hook allows to subscribe to a set of targets and fetch the data for each:
206+
207+
| Store | Description |
208+
|-----------------|-------------|
209+
| [`subscribeElementTypes`](/docs/api/workspace/variables/subscribeElementTypes.md) | Subscribe and fetch entity types. |
210+
| [`subscribeLinkTypes`](/docs/api/workspace/variables/subscribeLinkTypes.md) | Subscribe and fetch relation types. |
211+
| [`subscribeElementTypes`](/docs/api/workspace/variables/subscribePropertyTypes.md) | Subscribe and fetch property types. |
212+
213+
#### Example: subscribe to property types from an [element template](/docs/components/canvas.md#customization)
214+
215+
```ts
216+
function MyElement(props: Reactodia.TemplateProps) {
217+
const {model} = Reactodia.useWorkspace();
218+
const t = Reactodia.useTranslation();
219+
const language = Reactodia.useObservedProperty(
220+
model.events, 'changeLanguage', () => model.language
221+
);
222+
223+
const data = props.element instanceof Reactodia.EntityElement
224+
? props.element.data : undefined;
225+
// Select only properties with at least one value
226+
const properties = Object.entries(data?.properties ?? {})
227+
.filter(([iri, values]) => values.length > 0);
228+
// Subscribe and fetch property types
229+
Reactodia.useKeyedSyncStore(
230+
Reactodia.subscribePropertyTypes,
231+
properties.map(([iri]) => iri),
232+
model
233+
);
234+
235+
return (
236+
<ul>
237+
{properties.map(([iri, values])) => {
238+
// Get property type to display
239+
const property = model.getPropertyType(iri);
240+
return (
241+
<li>
242+
{t.formatLabel(property?.data?.label, iri, language)}{': '}
243+
{values.map(v => v.value).join(', ')}
244+
</li>
245+
);
246+
}}
247+
</ul>
248+
);
249+
}
250+
```
251+
252+
### `useProvidedEntities()`
253+
254+
[`useProvidedEntities`](/docs/api/workspace/functions/useProvidedEntities.md) hook allows to loads entity data for a target set of IRIs even when the entities are not displayed on the canvas at all.
255+
256+
#### Example: load entity variants for a [select input](/docs/components/form-input.md)
257+
258+
```ts
259+
function MyInputForShape(props: Forms.InputSingleProps) {
260+
const {factory} = props;
261+
const {model} = Reactodia.useWorkspace();
262+
263+
const {data: entities} = Reactodia.useProvidedEntities(
264+
model.dataProvider,
265+
[shapes.Square, shapes.Circle, shapes.Triangle]
266+
);
267+
const language = Reactodia.useObservedProperty(
268+
model.events, 'changeLanguage', () => model.language
269+
);
270+
const variants = React.useMemo(
271+
() => Array.from(entities.values(), (item): Forms.InputSelectVariant => ({
272+
value: factory.namedNode(item.id),
273+
label: model.locale.formatEntityLabel(item, language),
274+
})),
275+
[entities, language, factory]
276+
);
277+
278+
return (
279+
<Forms.InputSelect {...props} variants={variants} />
280+
);
281+
}
282+
```
283+
284+
## Data Locale
285+
286+
It is possible to customize how library components display graph data by supplying a custom [`DataLocaleProvider`](/docs/api/workspace/interfaces/DataLocaleProvider.md) when calling [model.importLayout()](/docs/api/workspace/classes/DataDiagramModel.md#importlayout).
287+
288+
Data locale provider can be used to alter the following behavior:
289+
- [locale.selectEntityLabel()](/docs/api/workspace/interfaces/DataLocaleProvider.md#selectentitylabel) and [locale.formatEntityLabel()](/docs/api/workspace/interfaces/DataLocaleProvider.md#formatentitylabel) to select or format default entity label from its properties (by default it looks for `rdfs:label` property values);
290+
- [locale.selectEntityImageUrl()](/docs/api/workspace/interfaces/DataLocaleProvider.md#selectentityimageurl) to select default entity thumbnail image IRI from its properties (by default it looks for `schema:thumbnailUrl` property value);
291+
- [locale.prepareAnchor()](/docs/api/workspace/interfaces/DataLocaleProvider.md#prepareanchor) to provide props for an anchor (`<a>` link) to a resource IRI;
292+
- [locale.resolveAssetUrl()](/docs/api/workspace/interfaces/DataLocaleProvider.md#resolveasseturl) to resolve an IRI/URL to referenced data asset for display or download, e.g. an image (thumbnail) or a downloadable file.
293+
294+
:::tip
295+
It is possible to extend [`DefaultDataLocaleProvider`](/docs/api/workspace/classes/DefaultDataLocaleProvider.md) to slightly alter its behavior instead of implementing the full [`DataLocaleProvider`](/docs/api/workspace/interfaces/DataLocaleProvider.md) interface.
296+
:::

docusaurus.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const config: Config = {
5555
{
5656
entryPoints: [
5757
`${libraryPathPrefix}/reactodia-workspace/src/workspace.ts`,
58+
`${libraryPathPrefix}/reactodia-workspace/src/forms/index.ts`,
5859
`${libraryPathPrefix}/reactodia-workspace/src/layout-sync.ts`,
5960
`${libraryPathPrefix}/reactodia-workspace/src/layout.worker.ts`,
6061
`${libraryPathPrefix}/reactodia-workspace/src/legacy-styles.tsx`,

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"@easyops-cn/docusaurus-search-local": "^0.51.0",
2222
"@mdx-js/react": "^3.1.0",
2323
"@reactodia/hashmap": "^0.2.1",
24-
"@reactodia/workspace": "^0.33.0",
24+
"@reactodia/workspace": "^0.34.0",
2525
"clsx": "^2.1.1",
2626
"n3": "^1.17.2",
2727
"prism-react-renderer": "^2.4.1",

sidebars.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ const sidebars: SidebarsConfig = {
7878
label: '@reactodia/workspace',
7979
collapsed: false,
8080
},
81+
{
82+
...findSidebarCategory(typedocItems, 'forms'),
83+
label: '/forms',
84+
},
8185
{
8286
...findSidebarCategory(typedocItems, 'layout-sync'),
8387
label: '/layout-sync',

src/examples/ExampleMetadata.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const owl = vocabulary('http://www.w3.org/2002/07/owl#', [
77
'ObjectProperty',
88
]);
99

10-
const rdfs = vocabulary('http://www.w3.org/2000/01/rdf-schema#', [
10+
export const rdfs = vocabulary('http://www.w3.org/2000/01/rdf-schema#', [
1111
'comment',
1212
'domain',
1313
'range',
@@ -16,6 +16,10 @@ const rdfs = vocabulary('http://www.w3.org/2000/01/rdf-schema#', [
1616
'subPropertyOf',
1717
]);
1818

19+
export const example = vocabulary('http://www.example.com/', [
20+
'workflowStatus',
21+
]);
22+
1923
const SIMULATED_DELAY: number = 50; /* ms */
2024

2125
export class ExampleMetadataProvider extends Reactodia.BaseMetadataProvider {
@@ -149,18 +153,22 @@ export class ExampleMetadataProvider extends Reactodia.BaseMetadataProvider {
149153
valueShape: {termType: 'Literal'},
150154
order: 1,
151155
});
152-
properties.set(rdfs.comment, {
156+
properties.set(example.workflowStatus, {
153157
valueShape: {termType: 'Literal'},
154158
order: 2,
155159
});
160+
properties.set(rdfs.comment, {
161+
valueShape: {termType: 'Literal'},
162+
order: 3,
163+
});
156164
properties.set(Reactodia.schema.thumbnailUrl, {
157165
valueShape: {termType: 'NamedNode'},
158166
maxCount: 1,
159-
order: 3,
167+
order: 4,
160168
});
161169
properties.set(rdfs.seeAlso, {
162170
valueShape: {termType: 'NamedNode'},
163-
order: 4,
171+
order: 5,
164172
});
165173
}
166174
return {properties};
@@ -169,8 +177,13 @@ export class ExampleMetadataProvider extends Reactodia.BaseMetadataProvider {
169177
await Reactodia.delay(SIMULATED_DELAY, {signal});
170178
const properties = new Map<Reactodia.PropertyTypeIri, Reactodia.MetadataPropertyShape>();
171179
if (this.editableRelations.has(linkType)) {
180+
properties.set(example.workflowStatus, {
181+
valueShape: {termType: 'Literal'},
182+
order: 1,
183+
});
172184
properties.set(rdfs.comment, {
173185
valueShape: {termType: 'Literal'},
186+
order: 2,
174187
});
175188
}
176189
return {properties};

0 commit comments

Comments
 (0)