From ba0567016df73b3bfad4cb90d771cff0fd1985ae Mon Sep 17 00:00:00 2001 From: Karolina Przerwa Date: Wed, 31 Jan 2024 14:14:01 +0100 Subject: [PATCH] custom_fields: add remove discovered field button * chore: renaming to improve readability --- package-lock.json | 2 +- ...sions.js => AddDiscoverableFieldsModal.js} | 48 ++++++++++++------- .../widgets/custom_fields/CustomFields.js | 29 ++++++----- ...poseFields.js => DiscoverFieldsSection.js} | 38 +++++++++++---- .../ListAndFilterCustomFields.js | 1 - .../widgets/custom_fields/RemoveField.js | 30 ++++++++++++ src/lib/forms/widgets/custom_fields/index.js | 1 - 7 files changed, 107 insertions(+), 42 deletions(-) rename src/lib/forms/widgets/custom_fields/{Extensions.js => AddDiscoverableFieldsModal.js} (78%) rename src/lib/forms/widgets/custom_fields/{ComposeFields.js => DiscoverFieldsSection.js} (72%) create mode 100644 src/lib/forms/widgets/custom_fields/RemoveField.js diff --git a/package-lock.json b/package-lock.json index 5d932791..74ad62fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "react-invenio-forms", - "version": "2.8.4", + "version": "3.0.0", "license": "MIT", "devDependencies": { "@babel/cli": "^7.5.0", diff --git a/src/lib/forms/widgets/custom_fields/Extensions.js b/src/lib/forms/widgets/custom_fields/AddDiscoverableFieldsModal.js similarity index 78% rename from src/lib/forms/widgets/custom_fields/Extensions.js rename to src/lib/forms/widgets/custom_fields/AddDiscoverableFieldsModal.js index 7e745095..403fde7c 100644 --- a/src/lib/forms/widgets/custom_fields/Extensions.js +++ b/src/lib/forms/widgets/custom_fields/AddDiscoverableFieldsModal.js @@ -6,6 +6,7 @@ // under the terms of the MIT License; see LICENSE file for more details. import React, { Component } from "react"; +import { RemoveField } from "./RemoveField"; import { ListAndFilterCustomFields } from "./ListAndFilterCustomFields"; import { importWidget } from "../loader"; @@ -13,7 +14,7 @@ import { Button, Icon, Modal, Divider } from "semantic-ui-react"; import PropTypes from "prop-types"; -export class Extensions extends Component { +export class AddDiscoverableFieldsModal extends Component { constructor(props) { super(props); const { existingFields } = props; @@ -61,20 +62,26 @@ export class Extensions extends Component { } = this.state; const { fieldPath, templateLoaders, addFieldCallback } = this.props; this.setState({ loading: true }); + selectedField["props"]["label"] = ( + + ); + const field = await importWidget(templateLoaders, { ...selectedField, fieldPath: `${fieldPath}.${selectedField.field}`, }); - - const performCallback = (selectedFieldTarget) => { + const performCallback = () => { const { addFields } = this.state; - - if (withClose) { - addFieldCallback(addFields); - this.setState({ addFields: [], existingFields: [] }); - this.handleModalClosed(); - } + addFieldCallback(addFields); + this.setState({ addFields: [] }); + this.handleModalClosed(); }; + selectedFieldTarget.classList.toggle("selected-background"); this.setState( { @@ -84,7 +91,7 @@ export class Extensions extends Component { selectedFieldTarget: undefined, loading: false, }, - () => performCallback(selectedFieldTarget) + () => (withClose ? performCallback() : null) ); }; @@ -96,6 +103,13 @@ export class Extensions extends Component { this.handleModalClosed(); }; + handleRemoveField = (field) => { + const { existingFields: prevExisting } = this.state; + const { removeFieldCallback } = this.props; + const updatedFields = prevExisting.filter((n) => field.key !== n); + this.setState({ existingFields: [...updatedFields] }); + removeFieldCallback(field); + }; render() { const { fieldPath, // injected by the custom field loader via the `field` config property @@ -104,11 +118,12 @@ export class Extensions extends Component { record, templateLoaders, addFieldCallback, + removeFieldCallback, sections, - existingFields: selected, + existingFields: _, ...fieldsList } = this.props; - const { modalOpen, existingFields, loading } = this.state; + const { modalOpen, existingFields, loading, selectedField } = this.state; return ( <> @@ -137,7 +152,7 @@ export class Extensions extends Component { icon labelPosition="left" onClick={() => this.handleAddField(false)} - disabled={loading} + disabled={loading || !selectedField} loading={loading} > @@ -147,7 +162,7 @@ export class Extensions extends Component { icon labelPosition="left" onClick={() => this.handleAddField(true)} - disabled={loading} + disabled={loading || !selectedField} loading={loading} > @@ -160,18 +175,19 @@ export class Extensions extends Component { } } -Extensions.propTypes = { +AddDiscoverableFieldsModal.propTypes = { fieldPath: PropTypes.string.isRequired, record: PropTypes.object.isRequired, icon: PropTypes.string, label: PropTypes.string, templateLoaders: PropTypes.array.isRequired, addFieldCallback: PropTypes.func.isRequired, + removeFieldCallback: PropTypes.func.isRequired, sections: PropTypes.array, existingFields: PropTypes.array.isRequired, }; -Extensions.defaultProps = { +AddDiscoverableFieldsModal.defaultProps = { icon: undefined, label: undefined, sections: undefined, diff --git a/src/lib/forms/widgets/custom_fields/CustomFields.js b/src/lib/forms/widgets/custom_fields/CustomFields.js index 84afd6e9..04c4d4b1 100644 --- a/src/lib/forms/widgets/custom_fields/CustomFields.js +++ b/src/lib/forms/widgets/custom_fields/CustomFields.js @@ -7,14 +7,14 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; -import { ComposeFields } from "./ComposeFields"; +import { DiscoverFieldsSection } from "./DiscoverFieldsSection"; import { AccordionField } from "../../AccordionField"; import { loadWidgetsFromConfig } from "../loader"; export class CustomFields extends Component { constructor(props) { super(props); - this.state = { sections: undefined, composeSections: undefined }; + this.state = { sections: undefined, discoverFieldsSections: undefined }; } componentDidMount() { @@ -24,19 +24,22 @@ export class CustomFields extends Component { populateConfig = async () => { const { includesPaths, fieldPathPrefix } = this.props; try { - const { sectionsConfig, composeSectionConfig } = + const { sectionsConfig, discoverFieldsConfig } = await this.loadCustomFieldsWidgets(); const sections = sectionsConfig.map((sectionCfg) => { const paths = includesPaths(sectionCfg.fields, fieldPathPrefix); return { ...sectionCfg, paths }; }); - const composeSections = composeSectionConfig.map((sectionCfg) => { + const discoverFieldsSections = discoverFieldsConfig.map((sectionCfg) => { const paths = includesPaths(sectionCfg.fields, fieldPathPrefix); return { ...sectionCfg, paths }; }); - this.setState({ sections: sections, composeSections: composeSections }); + this.setState({ + sections: sections, + discoverFieldsSections: discoverFieldsSections, + }); } catch (error) { console.error("Couldn't load custom fields widgets.", error); } @@ -46,7 +49,7 @@ export class CustomFields extends Component { const { config, fieldPathPrefix, templateLoaders, record } = this.props; const sections = []; - const composeFieldSections = []; + const discoverFieldsSections = []; // finds sections with discoverable fields for (const sectionCfg of config) { // Path to end user's folder defining custom fields ui widgets const fields = await loadWidgetsFromConfig({ @@ -55,8 +58,8 @@ export class CustomFields extends Component { fields: sectionCfg.fields, record: record, }); - if (sectionCfg.compose_fields) { - composeFieldSections.push({ + if (sectionCfg.discoverable_fields) { + discoverFieldsSections.push({ ...sectionCfg, fields: fields, fieldsConfig: sectionCfg.fields, @@ -65,11 +68,11 @@ export class CustomFields extends Component { sections.push({ ...sectionCfg, fields }); } } - return { sectionsConfig: sections, composeSectionConfig: composeFieldSections }; + return { sectionsConfig: sections, discoverFieldsConfig: discoverFieldsSections }; } render() { - const { sections, composeSections } = this.state; + const { sections, discoverFieldsSections } = this.state; const { templateLoaders, record } = this.props; return ( <> @@ -84,10 +87,10 @@ export class CustomFields extends Component { {fields} ))} - {composeSections && composeSections && ( - )} diff --git a/src/lib/forms/widgets/custom_fields/ComposeFields.js b/src/lib/forms/widgets/custom_fields/DiscoverFieldsSection.js similarity index 72% rename from src/lib/forms/widgets/custom_fields/ComposeFields.js rename to src/lib/forms/widgets/custom_fields/DiscoverFieldsSection.js index b789969d..6ffdf20a 100644 --- a/src/lib/forms/widgets/custom_fields/ComposeFields.js +++ b/src/lib/forms/widgets/custom_fields/DiscoverFieldsSection.js @@ -4,18 +4,18 @@ import PropTypes from "prop-types"; import { Divider } from "semantic-ui-react"; import { AccordionField } from "../../AccordionField"; import { FieldLabel } from "../../FieldLabel"; -import { Extensions } from "./Extensions"; +import { AddDiscoverableFieldsModal } from "./AddDiscoverableFieldsModal"; -export class ComposeFields extends Component { +export class DiscoverFieldsSection extends Component { constructor(props) { super(props); - const { composeSections, record } = props; + const { sections, record } = props; // sections = fields grouping, usually by domain const filled = Object.keys(record.custom_fields).map( (key) => `custom_fields.${key}` ); - this.state = { sections: composeSections, tempFields: [], recordFields: filled }; - this.fieldsCfg = this.getFieldsConfig(composeSections); - this.sectionsList = composeSections.map((section) => section.section); + this.state = { sections: sections, tempFields: [], recordFields: filled }; + this.fieldsCfg = this.getFieldsConfig(sections); + this.sectionsList = sections.map((section) => section.section); } getFieldsConfig = (sectionCfg) => { @@ -74,6 +74,23 @@ export class ComposeFields extends Component { }); }; + removeFieldCallback = (field) => { + const { sections: prevSections, tempFields: prevTempFields } = this.state; + const sections = [...prevSections]; + let tempFields = [...prevTempFields]; + const sectionToUpdate = this.getSectionOfField(field); + for (const section of sections) { + if (section.section === sectionToUpdate) { + section["fields"] = section.fields.filter((n) => field.key !== n.key); + tempFields = tempFields.filter((n) => field.key !== n.key); + } + } + this.setState({ + sections: [...sections], + tempFields: [...tempFields], + }); + }; + render() { const { templateLoaders, record } = this.props; const { sections, tempFields, recordFields } = this.state; @@ -83,7 +100,7 @@ export class ComposeFields extends Component { ]; return ( - + {sections.map(({ fields, paths, ...sectionConfig }) => { const recordCustomFields = this.getFieldsWithValues(fields); if (_isEmpty(recordCustomFields)) { @@ -101,11 +118,12 @@ export class ComposeFields extends Component { ); })} - {Object.entries(filteredFieldsList).map(([key, value]) => { const names = key.split(":"); - const isDisabled = alreadyAddedFields.includes(`${fieldPath}.${key}`); return ( diff --git a/src/lib/forms/widgets/custom_fields/RemoveField.js b/src/lib/forms/widgets/custom_fields/RemoveField.js new file mode 100644 index 00000000..1c28787d --- /dev/null +++ b/src/lib/forms/widgets/custom_fields/RemoveField.js @@ -0,0 +1,30 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, Icon, Popup } from "semantic-ui-react"; +import { FieldLabel } from "../../FieldLabel"; + +export class RemoveField extends Component { + render() { + const { removeFieldCallback, fieldPath, field, label } = this.props; + return ( + <> + + removeFieldCallback(field)}> + + + } + /> + + ); + } +} + +RemoveField.propTypes = { + field: PropTypes.object.isRequired, + fieldPath: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + removeFieldCallback: PropTypes.func.isRequired, +}; diff --git a/src/lib/forms/widgets/custom_fields/index.js b/src/lib/forms/widgets/custom_fields/index.js index a8c85b78..b57a438d 100644 --- a/src/lib/forms/widgets/custom_fields/index.js +++ b/src/lib/forms/widgets/custom_fields/index.js @@ -1,2 +1 @@ export { CustomFields } from "./CustomFields"; -export { Extensions } from "./Extensions";