Skip to content

Commit

Permalink
Add navRoot to the equation, this enables Add form correct checks, an…
Browse files Browse the repository at this point in the history
…d Slots under that route.
  • Loading branch information
sneridagh committed Feb 26, 2024
1 parent d73cb36 commit ba356c3
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 141 deletions.
7 changes: 3 additions & 4 deletions packages/registry/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {
ComponentsConfig,
ExperimentalConfig,
SettingsConfig,
GetSlotArgs,
GetSlotReturn,
SlotComponent,
SlotPredicate,
SlotsConfig,
Expand Down Expand Up @@ -184,10 +186,7 @@ class Config {
}
}

getSlot<T>(
name: string,
args: T,
): { component: SlotComponent['component']; name: string }[] | undefined {
getSlot(name: string, args: GetSlotArgs): GetSlotReturn {
if (!this._data.slots[name]) {
return;
}
Expand Down
25 changes: 25 additions & 0 deletions packages/types/src/config/Slots.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Content } from '../content';

export type SlotPredicate = (args: any) => boolean;

export type GetSlotArgs = {
content: Content;
pathname: string;
navRoot?: Content;
};

export type GetSlotReturn =
| { component: SlotComponent['component']; name: string }[]
| undefined;

export type SlotComponent = {
component: React.ComponentType<any>;
predicates?: SlotPredicate[];
};

export type SlotManager = {
slots: string[];
data: Record<string, SlotComponent[]>;
};

export type SlotsConfig = Record<string, SlotManager>;
16 changes: 2 additions & 14 deletions packages/types/src/config/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { SettingsConfig } from './Settings';
import type { BlocksConfig } from './Blocks';
import type { ViewsConfig } from './Views';
import type { WidgetsConfig } from './Widgets';
import type { SlotsConfig } from './Slots';

export type AddonReducersConfig = Record<string, Function>;

Expand All @@ -11,20 +12,6 @@ export type AddonRoutesConfig = {
component: React.ComponentType;
}[];

export type SlotPredicate = (args: any) => boolean;

export type SlotComponent = {
component: React.ComponentType<any>;
predicates?: SlotPredicate[];
};

export type SlotManager = {
slots: string[];
data: Record<string, SlotComponent[]>;
};

export type SlotsConfig = Record<string, SlotManager>;

export type ComponentsConfig = Record<
string,
{ component: React.ComponentType }
Expand All @@ -46,3 +33,4 @@ export type ConfigData = {

export { SettingsConfig, BlocksConfig, ViewsConfig, WidgetsConfig };
export * from './Blocks';
export * from './Slots';
2 changes: 2 additions & 0 deletions packages/types/src/content/common.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { BreadcrumbsResponse } from '../services/breadcrumbs';
import type { NavigationResponse } from '../services/navigation';
import type { ActionsResponse } from '../services/actions';
import type { GetTypesResponse } from '../services/types';
import type { GetNavrootResponse } from '../services/navroot';
import type { GetAliasesResponse } from '../services/aliases';
import type { ContextNavigationResponse } from '../services/contextnavigation';
import type { WorkflowResponse } from '../services/workflow';
Expand All @@ -13,6 +14,7 @@ export interface Expanders {
breadcrumbs: BreadcrumbsResponse;
contextnavigation: ContextNavigationResponse;
navigation: NavigationResponse;
navroot: GetNavrootResponse;
types: GetTypesResponse;
workflow: WorkflowResponse;
}
Expand Down
258 changes: 138 additions & 120 deletions packages/volto/src/components/manage/Form/Form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
} from '@plone/volto/actions';
import { compose } from 'redux';
import config from '@plone/volto/registry';
import SlotRenderer from '../../theme/SlotRenderer/SlotRenderer';

/**
* Form container class.
Expand Down Expand Up @@ -641,131 +642,147 @@ class Form extends Component {
// Removing this from SSR is important, since react-beautiful-dnd supports SSR,
// but draftJS don't like it much and the hydration gets messed up
this.state.isClient && (
<Container>
<BlocksToolbar
formData={formData}
selectedBlock={this.state.selected}
selectedBlocks={this.state.multiSelected}
onChangeBlocks={(newBlockData) => {
const newFormData = {
...formData,
...newBlockData,
};
this.setState({
formData: newFormData,
});
if (this.props.global) {
this.props.setFormData(newFormData);
}
}}
onSetSelectedBlocks={(blockIds) =>
this.setState({ multiSelected: blockIds })
}
onSelectBlock={this.onSelectBlock}
/>
<UndoToolbar
state={{
formData,
selected: this.state.selected,
multiSelected: this.state.multiSelected,
}}
enableHotKeys
onUndoRedo={({ state }) => {
if (this.props.global) {
this.props.setFormData(state.formData);
}
return this.setState(state);
}}
/>
<BlocksForm
onChangeFormData={(newData) => {
const newFormData = {
...formData,
...newData,
};
this.setState({
formData: newFormData,
});
if (this.props.global) {
this.props.setFormData(newFormData);
}
}}
onChangeField={this.onChangeField}
onSelectBlock={this.onSelectBlock}
properties={formData}
<>
<SlotRenderer
name="aboveContent"
content={this.props.content}
navRoot={navRoot}
type={type}
pathname={this.props.pathname}
selectedBlock={this.state.selected}
multiSelected={this.state.multiSelected}
manage={this.props.isAdminForm}
allowedBlocks={this.props.allowedBlocks}
showRestricted={this.props.showRestricted}
editable={this.props.editable}
isMainForm={this.props.editable}
/>
{this.state.isClient && this.props.editable && (
<Portal
node={__CLIENT__ && document.getElementById('sidebar-metadata')}
>
<UiForm
method="post"
onSubmit={this.onSubmit}
error={keys(this.state.errors).length > 0}

<Container>
<BlocksToolbar
formData={formData}
selectedBlock={this.state.selected}
selectedBlocks={this.state.multiSelected}
onChangeBlocks={(newBlockData) => {
const newFormData = {
...formData,
...newBlockData,
};
this.setState({
formData: newFormData,
});
if (this.props.global) {
this.props.setFormData(newFormData);
}
}}
onSetSelectedBlocks={(blockIds) =>
this.setState({ multiSelected: blockIds })
}
onSelectBlock={this.onSelectBlock}
/>
<UndoToolbar
state={{
formData,
selected: this.state.selected,
multiSelected: this.state.multiSelected,
}}
enableHotKeys
onUndoRedo={({ state }) => {
if (this.props.global) {
this.props.setFormData(state.formData);
}
return this.setState(state);
}}
/>
<BlocksForm
onChangeFormData={(newData) => {
const newFormData = {
...formData,
...newData,
};
this.setState({
formData: newFormData,
});
if (this.props.global) {
this.props.setFormData(newFormData);
}
}}
onChangeField={this.onChangeField}
onSelectBlock={this.onSelectBlock}
properties={formData}
navRoot={navRoot}
type={type}
pathname={this.props.pathname}
selectedBlock={this.state.selected}
multiSelected={this.state.multiSelected}
manage={this.props.isAdminForm}
allowedBlocks={this.props.allowedBlocks}
showRestricted={this.props.showRestricted}
editable={this.props.editable}
isMainForm={this.props.editable}
/>
{this.state.isClient && this.props.editable && (
<Portal
node={__CLIENT__ && document.getElementById('sidebar-metadata')}
>
{schema &&
map(schema.fieldsets, (fieldset) => (
<Accordion
fluid
styled
className="form"
key={fieldset.title}
>
<div
key={fieldset.id}
id={`metadataform-fieldset-${fieldset.id}`}
<UiForm
method="post"
onSubmit={this.onSubmit}
error={keys(this.state.errors).length > 0}
>
{schema &&
map(schema.fieldsets, (fieldset) => (
<Accordion
fluid
styled
className="form"
key={fieldset.title}
>
<Accordion.Title
active={metadataFieldsets.includes(fieldset.id)}
index={fieldset.id}
onClick={this.onToggleMetadataFieldset}
>
{fieldset.title}
{metadataFieldsets.includes(fieldset.id) ? (
<Icon name={upSVG} size="20px" />
) : (
<Icon name={downSVG} size="20px" />
)}
</Accordion.Title>
<Accordion.Content
active={metadataFieldsets.includes(fieldset.id)}
<div
key={fieldset.id}
id={`metadataform-fieldset-${fieldset.id}`}
>
<Segment className="attached">
{map(fieldset.fields, (field, index) => (
<Field
{...schema.properties[field]}
id={field}
fieldSet={fieldset.title.toLowerCase()}
formData={formData}
focus={this.state.inFocus[field]}
value={formData?.[field]}
required={schema.required.indexOf(field) !== -1}
onChange={this.onChangeField}
onBlur={this.onBlurField}
onClick={this.onClickInput}
key={field}
error={this.state.errors[field]}
/>
))}
</Segment>
</Accordion.Content>
</div>
</Accordion>
))}
</UiForm>
</Portal>
)}
</Container>
<Accordion.Title
active={metadataFieldsets.includes(fieldset.id)}
index={fieldset.id}
onClick={this.onToggleMetadataFieldset}
>
{fieldset.title}
{metadataFieldsets.includes(fieldset.id) ? (
<Icon name={upSVG} size="20px" />
) : (
<Icon name={downSVG} size="20px" />
)}
</Accordion.Title>
<Accordion.Content
active={metadataFieldsets.includes(fieldset.id)}
>
<Segment className="attached">
{map(fieldset.fields, (field, index) => (
<Field
{...schema.properties[field]}
id={field}
fieldSet={fieldset.title.toLowerCase()}
formData={formData}
focus={this.state.inFocus[field]}
value={formData?.[field]}
required={
schema.required.indexOf(field) !== -1
}
onChange={this.onChangeField}
onBlur={this.onBlurField}
onClick={this.onClickInput}
key={field}
error={this.state.errors[field]}
/>
))}
</Segment>
</Accordion.Content>
</div>
</Accordion>
))}
</UiForm>
</Portal>
)}

<SlotRenderer
name="belowContent"
content={this.props.content}
navRoot={navRoot}
/>
</Container>
</>
)
) : (
<Container>
Expand Down Expand Up @@ -931,6 +948,7 @@ const FormIntl = injectIntl(Form, { forwardRef: true });
export default compose(
connect(
(state, props) => ({
content: state.content.data,
globalData: state.form?.global,
metadataFieldsets: state.sidebar?.metadataFieldsets,
metadataFieldFocus: state.sidebar?.metadataFieldFocus,
Expand Down
Loading

0 comments on commit ba356c3

Please sign in to comment.