Skip to content

Commit

Permalink
Expose validation errors and improve unsaved changes modal (superdesk…
Browse files Browse the repository at this point in the history
  • Loading branch information
thecalcc authored Jan 21, 2025
1 parent 5dc82cf commit 2e1f329
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 43 deletions.
26 changes: 23 additions & 3 deletions scripts/apps/authoring-react/authoring-react.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {createRef, RefObject} from 'react';
import {
IArticle,
IAuthoringFieldV2,
Expand All @@ -22,8 +22,7 @@ import {Loader, SubNav} from 'superdesk-ui-framework/react';
import * as Layout from 'superdesk-ui-framework/react/components/Layouts';
import {gettext} from 'core/utils';
import {AuthoringSection} from './authoring-section/authoring-section';
import {EditorTest} from './ui-framework-authoring-test';
import {uiFrameworkAuthoringPanelTest, appConfig} from 'appConfig';
import {appConfig} from 'appConfig';
import {
PINNED_WIDGET_USER_PREFERENCE_SETTINGS,
closedIntentionally,
Expand Down Expand Up @@ -284,6 +283,7 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
private cleanupFunctionsToRunBeforeUnmounting: Array<() => void>;
private _mounted: boolean;
private componentRef: HTMLElement | null;
fieldRefs: {[fieldId: string]: RefObject<HTMLDivElement> | null};

constructor(props: IPropsAuthoring<T>) {
super(props);
Expand Down Expand Up @@ -312,6 +312,7 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
this.setRef = this.setRef.bind(this);
this.getItemAndAutosave = this.getItemAndAutosave.bind(this);

this.fieldRefs = {};
const setStateOriginal = this.setState.bind(this);

this.setState = (...args) => {
Expand Down Expand Up @@ -575,6 +576,10 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
?? userPreferences[SPELLCHECKER_PREFERENCE].default
?? true;

profile.header.merge(profile.content).forEach(({id}) => {
this.fieldRefs[id] = createRef();
});

const initialState = getInitialState(
item,
profile,
Expand Down Expand Up @@ -933,6 +938,11 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
if (this.state.initialized) {
resolve(this.state.itemOriginal);
}
}).catch((e) => {
// Since we don't give modal control to the developer using authoring react
// we close the prompt and return an error
closePromptFn();
reject();
});
} else {
assertNever(action);
Expand Down Expand Up @@ -1175,6 +1185,10 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
autosaved: itemWithUpdates,
};

newProfile.header.merge(newProfile.header).forEach((x) => {
this.fieldRefs[x.id] = createRef();
});

this.setState(getInitialState(
item,
newProfile ?? state.profile,
Expand Down Expand Up @@ -1207,6 +1221,7 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
handleFieldsDataChange: this.handleFieldsDataChange,
hasUnsavedChanges: () => this.hasUnsavedChanges(),
handleUnsavedChanges: () => this.handleUnsavedChanges(state),
discardUnsavedChanges: () => this.discardUnsavedChanges(state),
save: () => this.save(state),
initiateClosing: () => this.initiateClosing(state),
keepChangesAndClose: () => onClose(),
Expand Down Expand Up @@ -1250,6 +1265,9 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
},
});
},
getValidationErrors: () => {
return state.validationErrors;
},
};
}

Expand Down Expand Up @@ -1472,6 +1490,7 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
/>
)}
<AuthoringSection
fieldRefs={this.fieldRefs}
fields={state.profile.header}
fieldsData={state.fieldsDataWithChanges}
onChange={this.handleFieldChange}
Expand All @@ -1495,6 +1514,7 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
>
{state.profile.content.count() < 1 ? null : (
<AuthoringSection
fieldRefs={this.fieldRefs}
uiTheme={uiTheme}
padding="3.2rem 4rem 5.2rem 4rem"
fields={state.profile.content}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import {IAuthoringFieldV2, IAuthoringSectionTheme, IAuthoringSectionClassNames, IFieldsData} from 'superdesk-api';
import React, {RefObject} from 'react';
import {IAuthoringFieldV2, IAuthoringSectionTheme, IFieldsData} from 'superdesk-api';
import {getField} from 'apps/fields';
import {getFieldContainer} from './get-field-container';
import {IPropsAuthoringSection} from './authoring-section';
Expand All @@ -21,6 +21,7 @@ interface IProps<T> {
getVocabularyItems: IPropsAuthoringSection<T>['getVocabularyItems'];
validationError?: string;
uiTheme?: IAuthoringSectionTheme;
fieldRef: RefObject<HTMLDivElement>;
item: T;
computeLatestEntity(options?: {preferIncomplete?: boolean}): any;
}
Expand All @@ -47,42 +48,42 @@ export class AuthoringSectionField<T> extends React.PureComponent<IProps<T>> {
this.props.validationError,
);

if (canBeToggled && toggledOn === false) {
return (
<Container key={field.id} />
);
} else {
return (
<FieldEditorConfig.editorComponent
uiTheme={this.props.uiTheme == null ? undefined : {
backgroundColor: this.props.uiTheme.backgroundColor,
backgroundColorSecondary: this.props.uiTheme.backgroundColorSecondary,
textColor: this.props.uiTheme.textColor,
fontSize: this.props.uiTheme.fieldTheme[field.id]?.fontSize,
fontFamily: this.props.uiTheme.fontFamily,
}}
key={field.id}
editorId={field.id}
container={Container}
language={this.props.language}
value={fieldsData.get(field.id)}
fieldsData={fieldsData}
onChange={(val) => {
this.props.onChange(field.id, val);
}}
reinitialize={this.props.reinitialize}
readOnly={this.props.readOnly}
config={field.fieldConfig}
fieldId={field.id}
editorPreferences={this.props.editorPreferences}
onEditorPreferencesChange={(fieldPreferences) => {
this.props.onEditorPreferencesChange(field.id, fieldPreferences);
}}
getVocabularyItems={this.props.getVocabularyItems}
item={this.props.item}
computeLatestEntity={this.props.computeLatestEntity}
/>
);
}
return (
<div ref={this.props.fieldRef}>
{canBeToggled && toggledOn === false ? (
<Container key={field.id} />
) : (
<FieldEditorConfig.editorComponent
uiTheme={this.props.uiTheme == null ? undefined : {
backgroundColor: this.props.uiTheme.backgroundColor,
backgroundColorSecondary: this.props.uiTheme.backgroundColorSecondary,
textColor: this.props.uiTheme.textColor,
fontSize: this.props.uiTheme.fieldTheme[field.id]?.fontSize,
fontFamily: this.props.uiTheme.fontFamily,
}}
key={field.id}
editorId={field.id}
container={Container}
language={this.props.language}
value={fieldsData.get(field.id)}
fieldsData={fieldsData}
onChange={(val) => {
this.props.onChange(field.id, val);
}}
reinitialize={this.props.reinitialize}
readOnly={this.props.readOnly}
config={field.fieldConfig}
fieldId={field.id}
editorPreferences={this.props.editorPreferences}
onEditorPreferencesChange={(fieldPreferences) => {
this.props.onEditorPreferencesChange(field.id, fieldPreferences);
}}
getVocabularyItems={this.props.getVocabularyItems}
item={this.props.item}
computeLatestEntity={this.props.computeLatestEntity}
/>
)}
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import React, {RefObject} from 'react';
import {IAuthoringSectionTheme, IFieldsV2, IVocabularyItem, IAuthoringValidationErrors} from 'superdesk-api';
import {Map} from 'immutable';
import {IToggledFields} from '../authoring-react';
import {AuthoringSectionField} from './authoring-section-field';

export interface IPropsAuthoringSection<T> {
fieldRefs: {[fieldId: string]: RefObject<HTMLDivElement>};
language: string;
fieldsData: Map<string, unknown>;
fields: IFieldsV2;
Expand Down Expand Up @@ -112,6 +113,7 @@ export class AuthoringSection<T> extends React.PureComponent<IPropsAuthoringSect
return (
<div key={field.id} style={{width: `${field.fieldConfig.width}%`}}>
<AuthoringSectionField
fieldRef={this.props.fieldRefs[field.id]}
uiTheme={themeApplies ? this.props.uiTheme : undefined}
field={field}
fieldsData={this.props.fieldsData}
Expand Down
2 changes: 2 additions & 0 deletions scripts/core/superdesk-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ declare module 'superdesk-api' {
fieldsAdapter: IFieldsAdapter<T>;
hasUnsavedChanges(): boolean;
handleUnsavedChanges(): Promise<T>;
discardUnsavedChanges(): Promise<void>;
handleFieldsDataChange(fieldsData: IFieldsData): void;
onItemChange(item: T): void;
save(): Promise<T>;
Expand All @@ -173,6 +174,7 @@ declare module 'superdesk-api' {
stealLock(): void;
reinitialize(item: T, profile?: IContentProfileV2): void;
addValidationErrors(validationErrors: IAuthoringValidationErrors): void;
getValidationErrors(): IAuthoringValidationErrors;
}

export interface IAuthoringOptions<T> {
Expand Down

0 comments on commit 2e1f329

Please sign in to comment.