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 @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [Unreleased]
#### 🐛 Fixed
- Fix unable to scroll inside canvas components and templates when `requireCtrl` in `zoomOptions` is set `false`.
- Disable changing an entity IRI in a form when `MetadataProvider.canModifyEntity()` disallows it.

#### 💅 Polish
- Remove superfluous "Type" fields from the default "Edit entity" dialog.

## [0.32.0] - 2026-03-10
#### 🐛 Fixed
Expand Down
1 change: 0 additions & 1 deletion i18n/i18n.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,6 @@
"edit_entity.dialog.caption": { "$ref": "#/$defs/Value" },
"edit_entity.iri.label": { "$ref": "#/$defs/Value" },
"edit_entity.label.label": { "$ref": "#/$defs/Value" },
"edit_entity.type.label": { "$ref": "#/$defs/Value" },
"edit_relation.dialog.caption": { "$ref": "#/$defs/Value" },
"edit_relation.dialog.caption_new": { "$ref": "#/$defs/Value" },
"edit_relation.validation_progress.title": { "$ref": "#/$defs/Value" },
Expand Down
1 change: 0 additions & 1 deletion i18n/translations/en.reactodia-translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@
"dialog.cancel.title": "Cancel the dialog",
"edit_entity.dialog.caption": "Edit entity",
"edit_entity.iri.label": "IRI",
"edit_entity.type.label": "Type",
"edit_relation.dialog.caption": "Edit relation",
"edit_relation.dialog.caption_new": "Establish new relation",
"edit_relation.validation_progress.title": "Validating selected link type",
Expand Down
64 changes: 28 additions & 36 deletions src/forms/editEntityForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { mapAbortedToNull } from '../coreUtils/async';

import { ElementModel, ElementIri, PropertyTypeIri } from '../data/model';
import type {
MetadataProvider, MetadataEntityShape, MetadataPropertyShape,
MetadataProvider, MetadataCanModifyEntity, MetadataEntityShape, MetadataPropertyShape,
} from '../data/metadataProvider';

import { HtmlSpinner } from '../diagram/spinner';
Expand All @@ -32,7 +32,7 @@ export function EditEntityForm(props: {
setData(entity);
}, [entity]);

const [shape, shapeError] = useEntityShape(editor.metadataProvider, entity);
const [metadata, metadataError] = useEntityMetadata(editor.metadataProvider, entity);
const languages = React.useMemo(
() => editor.metadataProvider?.getLiteralLanguages() ?? [], []
);
Expand Down Expand Up @@ -69,11 +69,11 @@ export function EditEntityForm(props: {
});
}, []);

if (!shape) {
if (!metadata) {
return (
<div className={cx(FORM_CLASS, CLASS_NAME, `${CLASS_NAME}--loading`)}>
<HtmlSpinner width={30} height={30}
errorOccurred={Boolean(shapeError)}
errorOccurred={Boolean(metadataError)}
/>
</div>
);
Expand All @@ -90,31 +90,17 @@ export function EditEntityForm(props: {
values: iriValues,
updateValues: onChangeIri,
factory: model.factory,
readonly: !metadata.editable.canChangeIri,
})}
</div>
<div className={`${FORM_CLASS}__row`}>
<label>
{t.text('visual_authoring.edit_entity.type.label')}
{data.types.map(type => (
<input key={type}
className='reactodia-form-control'
name='reactodia-edit-entity-type'
title={type}
value={t.formatLabel(
model.getElementType(type)?.data?.label, type, model.language
)}
disabled={true}
/>
))}
</label>
</div>
<FormInputGroup className={`${CLASS_NAME}__properties`}
languages={languages}
extraPropertyShape={shape.extraProperty}
propertyShapes={shape.properties}
extraPropertyShape={metadata.shape.extraProperty}
propertyShapes={metadata.shape.properties}
propertyValues={data.properties}
onChangeData={onChangeProperty}
resolveInput={resolveInput}
readonly={!metadata.editable.canEdit}
/>
</div>
<div className={`${FORM_CLASS}__controls`}>
Expand Down Expand Up @@ -143,43 +129,49 @@ const IRI_SHAPE: MetadataPropertyShape = {
minCount: 1,
maxCount: 1,
};
const LABEL_SHAPE: MetadataPropertyShape = {
valueShape: {termType: 'Literal'},
};

function useEntityShape(
interface EntityMetadata {
readonly editable: MetadataCanModifyEntity;
readonly shape: MetadataEntityShape;
}

function useEntityMetadata(
metadataProvider: MetadataProvider | undefined,
entity: ElementModel
): readonly [shape: MetadataEntityShape | undefined, error?: unknown] {
const [shape, setShape] = React.useState<MetadataEntityShape>();
const [shapeError, setShapeError] = React.useState<unknown>();
): readonly [shape: EntityMetadata | undefined, error?: unknown] {
const [metadata, setMetadata] = React.useState<EntityMetadata>();
const [metadataError, setMetadataError] = React.useState<unknown>();

React.useEffect(() => {
if (metadataProvider) {
setShape(undefined);
setShapeError(undefined);
setMetadata(undefined);
setMetadataError(undefined);
const cancellation = new AbortController();
const signal = cancellation.signal;
mapAbortedToNull(
metadataProvider.getEntityShape(entity.types, {signal}),
Promise.all([
metadataProvider.canModifyEntity(entity, {signal}),
metadataProvider.getEntityShape(entity.types, {signal}),
]),
signal
).then(
result => {
if (result === null) {
return;
}
setShape(result);
const [editable, shape] = result;
setMetadata({editable, shape});
},
error => {
console.error('Failed to load entity shape:', error);
setShapeError(error);
setMetadataError(error);
}
);
return () => cancellation.abort();
} else {
setShape(DEFAULT_ENTITY_SHAPE);
setMetadata({editable: {}, shape: DEFAULT_ENTITY_SHAPE});
}
}, [entity]);

return [shape, shapeError];
return [metadata, metadataError];
}
6 changes: 5 additions & 1 deletion src/forms/input/formInputGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ export interface FormInputGroupProps {
onChangeData: (property: PropertyTypeIri, updater: FormInputMultiUpdater) => void;
resolveInput: (property: PropertyTypeIri, props: FormInputMultiProps) =>
React.ReactElement | null;
readonly?: boolean;
}

export function FormInputGroup(props: FormInputGroupProps) {
const {
className, languages, propertyShapes, extraPropertyShape, propertyValues, onChangeData, resolveInput,
className, languages, propertyShapes, extraPropertyShape, propertyValues,
onChangeData, resolveInput, readonly,
} = props;
const {model, translation: t} = useWorkspace();
const language = useObservedProperty(model.events, 'changeLanguage', () => model.language);
Expand Down Expand Up @@ -85,6 +87,7 @@ export function FormInputGroup(props: FormInputGroupProps) {
onChange={onChangeData}
factory={model.factory}
resolveInput={resolveInput}
readonly={Boolean(readonly)}
/>
)}
</div>
Expand All @@ -107,6 +110,7 @@ function Property(props: {
onChange: (iri: PropertyTypeIri, updater: FormInputMultiUpdater) => void;
factory: Rdf.DataFactory;
resolveInput: FormInputGroupProps['resolveInput'];
readonly: boolean;
}) {
const {iri, label, shape, languages, values, onChange, factory, resolveInput} = props;
const {model, translation: t} = useWorkspace();
Expand Down
9 changes: 6 additions & 3 deletions src/forms/input/formInputList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export interface FormInputListProps extends FormInputMultiProps {
}

function FormInputListInner(props: FormInputListProps) {
const {shape, languages, values, updateValues, factory, valueInput: ValueInput} = props;
const {
shape, languages, values, updateValues, factory, valueInput: ValueInput, readonly,
} = props;
const t = useTranslation();

const {minCount = 0, maxCount = Infinity} = shape;
Expand Down Expand Up @@ -56,8 +58,9 @@ function FormInputListInner(props: FormInputListProps) {
});
}}
factory={factory}
readonly={readonly}
/>
{values.length <= minCount ? null : (
{readonly || values.length <= minCount ? null : (
<button type='button'
className={cx(
'reactodia-btn',
Expand All @@ -78,7 +81,7 @@ function FormInputListInner(props: FormInputListProps) {
)}
</div>
))}
{values.length >= maxCount ? null : (
{readonly || values.length >= maxCount ? null : (
<div key='add' className={`${CLASS_NAME}__row`}>
<button type='button'
className={cx(
Expand Down
10 changes: 7 additions & 3 deletions src/forms/input/formInputText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface FormInputTextProps extends FormInputSingleProps {
*/
export function FormInputText(props: FormInputTextProps) {
const {
shape: {valueShape}, languages, value: term, setValue, factory,
shape: {valueShape}, languages, value: term, setValue, factory, readonly,
multiline, placeholder,
} = props;

Expand All @@ -64,11 +64,13 @@ export function FormInputText(props: FormInputTextProps) {
const changedValue = e.currentTarget.value;
setValue(setTermValue(term, changedValue, factory));
}}
disabled={readonly}
/>
{hasLanguageSelector ? (
<LanguageSelector language={term.termType === 'Literal' ? term.language : ''}
languages={languages}
onChangeLanguage={language => setValue(setTermLanguage(term, language, factory))}
disabled={readonly}
/>
) : null}
</>
Expand All @@ -79,15 +81,17 @@ function LanguageSelector(props: {
language: string;
languages: ReadonlyArray<string>;
onChangeLanguage: (language: string) => void;
disabled?: boolean;
}) {
const {language, languages, onChangeLanguage} = props;
const {language, languages, onChangeLanguage, disabled} = props;
if (languages.length === 0 && !language) {
return null;
}
return (
<select className={cx('reactodia-form-control', `${CLASS_NAME}__language`)}
value={language}
onChange={e => onChangeLanguage(e.currentTarget.value)}>
onChange={e => onChangeLanguage(e.currentTarget.value)}
disabled={disabled}>
<option value=''>—</option>
{language && !languages.includes(language) ? (
<option value={language}>{language}</option>
Expand Down
8 changes: 8 additions & 0 deletions src/forms/input/inputCommon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export interface FormInputSingleProps {
* RDF/JS-compatible term factory to create RDF terms.
*/
factory: Rdf.DataFactory;
/**
* Whether the property input should be read-only (disabled).
*/
readonly?: boolean;
}

/**
Expand Down Expand Up @@ -75,6 +79,10 @@ export interface FormInputMultiProps {
* RDF/JS-compatible term factory to create RDF terms.
*/
factory: Rdf.DataFactory;
/**
* Whether the property input should be read-only (disabled).
*/
readonly?: boolean;
}

/**
Expand Down
Loading