From 019583cf93e434044433daa5f080c5ba64f1118a Mon Sep 17 00:00:00 2001 From: Stefano Ricci Date: Fri, 10 Nov 2023 11:47:10 +0100 Subject: [PATCH 01/13] Node def header type (WIP) --- core/i18n/resources/en.js | 8 ++ core/survey/nodeDef.js | 8 ++ .../survey/NodeDefDetails/TextProps.js | 91 ++++++++++++------- .../SurveyForm/components/addNodeDefPanel.js | 5 +- .../NodeDefFormItem/NodeDefFormItem.js | 2 +- .../nodeDefs/components/types/nodeDefText.js | 34 +++++-- .../SurveyForm/nodeDefs/nodeDefUIProps.js | 8 ++ webapp/store/survey/nodeDefs/actions.js | 14 ++- 8 files changed, 125 insertions(+), 45 deletions(-) diff --git a/core/i18n/resources/en.js b/core/i18n/resources/en.js index d47f26959e..b62d9f76f4 100644 --- a/core/i18n/resources/en.js +++ b/core/i18n/resources/en.js @@ -1153,6 +1153,14 @@ E.g. this.region = region_attribute_name }, }, textProps: { + headerColorLabel: 'Header color', + headerColor: { + blue: 'Blue', + green: 'Green', + orange: 'Orange', + red: 'Red', + yellow: 'Yellow', + }, textInputType: 'Text input type', textInputTypes: { singleLine: 'Single line', diff --git a/core/survey/nodeDef.js b/core/survey/nodeDef.js index 78bb5689d9..bb081c4752 100644 --- a/core/survey/nodeDef.js +++ b/core/survey/nodeDef.js @@ -20,6 +20,10 @@ import { valuePropsTaxon } from './nodeValueProps' export { nodeDefType } +export const NodeDefLayoutElementTypes = { + header: 'header', +} + export const keys = { id: ObjectUtils.keys.id, uuid: ObjectUtils.keys.uuid, @@ -63,6 +67,8 @@ export const propKeys = { // Text textInputType: 'textInputType', textTransform: 'textTransform', + isHeader: 'isHeader', + headerColor: 'headerColor', // Decimal maxNumberDecimalDigits: 'maxNumberDecimalDigits', @@ -249,6 +255,8 @@ export const getTextInputType = getProp(propKeys.textInputType, textInputTypes.s export const getTextTransform = getProp(propKeys.textTransform, textTransformValues.none) export const getTextTransformFunction = (nodeDef) => TextUtils.transform({ transformFunction: getTextTransform(nodeDef) }) +export const isHeader = ObjectUtils.isPropTrue(propKeys.isHeader) +export const getHeaderColor = getProp(propKeys.headerColor) // ==== READ meta export const getMeta = R.propOr({}, keys.meta) diff --git a/webapp/components/survey/NodeDefDetails/TextProps.js b/webapp/components/survey/NodeDefDetails/TextProps.js index 7484bd8b8a..4dd85890d3 100644 --- a/webapp/components/survey/NodeDefDetails/TextProps.js +++ b/webapp/components/survey/NodeDefDetails/TextProps.js @@ -3,25 +3,34 @@ import PropTypes from 'prop-types' import * as A from '@core/arena' +import * as NodeDef from '@core/survey/nodeDef' + import { useI18n } from '@webapp/store/system' import { FormItem } from '@webapp/components/form/Input' - -import * as NodeDef from '@core/survey/nodeDef' import ButtonGroup from '@webapp/components/form/buttonGroup' +import { headerColors } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' + import { State } from './store' -const textInputTypes = ({ i18n }) => - Object.keys(NodeDef.textInputTypes).map((key) => ({ +const toButtonGroupItems = ({ i18n, object, labelPrefix }) => + Object.keys(object).map((key) => ({ key, - label: i18n.t(`nodeDefEdit.textProps.textInputTypes.${key}`), + label: i18n.t(`${labelPrefix}${key}`), })) +const headerColorItems = ({ i18n }) => + toButtonGroupItems({ i18n, object: headerColors, labelPrefix: 'nodeDefEdit.textProps.headerColor.' }) + +const textInputTypes = ({ i18n }) => + toButtonGroupItems({ i18n, object: NodeDef.textInputTypes, labelPrefix: 'nodeDefEdit.textProps.textInputTypes.' }) + const textTransformTypes = ({ i18n }) => - Object.keys(NodeDef.textTransformValues).map((labelKey) => ({ - key: labelKey, - label: i18n.t(`nodeDefEdit.textProps.textTransformTypes.${labelKey}`), - })) + toButtonGroupItems({ + i18n, + object: NodeDef.textTransformValues, + labelPrefix: 'nodeDefEdit.textProps.textTransformTypes.', + }) const TextProps = (props) => { const { state, Actions } = props @@ -30,37 +39,55 @@ const TextProps = (props) => { const nodeDef = State.getNodeDef(state) - const selectLabelValue = useCallback( + const onLabelValueChange = useCallback( (value) => { Actions.setProp({ state, key: NodeDef.propKeys.textTransform, value }) }, - [state] + [Actions, state] ) - useEffect(() => { - if (A.isEmpty(NodeDef.getTextTransform(nodeDef))) { - selectLabelValue(NodeDef.textTransformValues.none) - } - }, []) + const headerColor = NodeDef.getHeaderColor(nodeDef) + const selectedHeaderColorKey = Object.keys(headerColors).find((key) => headerColors[key] === headerColor) + + const onHeaderColorChange = useCallback( + (value) => { + Actions.setProp({ state, key: NodeDef.propKeys.headerColor, value: headerColors[value] }) + }, + [Actions, state] + ) return ( <> - - - - - { - Actions.setProp({ state, key: NodeDef.propKeys.textInputType, value }) - }} - items={textInputTypes({ i18n })} - /> - + {NodeDef.isHeader(nodeDef) ? ( + <> + + + + + ) : ( + <> + + + + + { + Actions.setProp({ state, key: NodeDef.propKeys.textInputType, value }) + }} + items={textInputTypes({ i18n })} + /> + + + )} ) } diff --git a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js index cf6e717dd6..7a0fa88905 100644 --- a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js +++ b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js @@ -2,7 +2,6 @@ import './addNodeDefPanel.scss' import React from 'react' import { connect } from 'react-redux' -import * as R from 'ramda' import { useNavigate } from 'react-router' import { useI18n } from '@webapp/store/system' @@ -20,9 +19,11 @@ const AddNodeDefButtons = (props) => { const i18n = useI18n() + const types = [...Object.values(NodeDef.nodeDefType), 'header'] + return ( <> - {R.values(NodeDef.nodeDefType).map((type) => { + {types.map((type) => { const nodeDefProps = NodeDefUIProps.getDefaultPropsByType(type, surveyCycleKey) // Cannot add entities when entity is rendered as table diff --git a/webapp/components/survey/SurveyForm/nodeDefs/components/NodeDefFormItem/NodeDefFormItem.js b/webapp/components/survey/SurveyForm/nodeDefs/components/NodeDefFormItem/NodeDefFormItem.js index 181d613aa4..2b8643518e 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/components/NodeDefFormItem/NodeDefFormItem.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/components/NodeDefFormItem/NodeDefFormItem.js @@ -12,7 +12,7 @@ const NodeDefFormItem = (props) => { const { edit, entry, label, lang, nodeDef, nodes, parentNode } = props const nodeDefComponent = React.createElement(NodeDefUiProps.getComponent(nodeDef), { ...props }) - if (NodeDef.isEntity(nodeDef)) { + if (NodeDef.isEntity(nodeDef) || NodeDef.isHeader(nodeDef)) { return nodeDefComponent } diff --git a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.js b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.js index da93458169..b18ee76781 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.js @@ -3,15 +3,28 @@ import './nodeDefText.scss' import React from 'react' import classNames from 'classnames' +import * as NodeDef from '@core/survey/nodeDef' +import * as Node from '@core/record/node' + import { Input } from '@webapp/components/form/Input' import * as NodeDefUIProps from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' +import Markdown from '@webapp/components/markdown' -import * as NodeDef from '@core/survey/nodeDef' -import * as Node from '@core/record/node' +import { useSurveyPreferredLang } from '@webapp/store/survey' import NodeDefErrorBadge from '../nodeDefErrorBadge' import NodeDeleteButton from '../nodeDeleteButton' +const Header = ({ nodeDef }) => { + const lang = useSurveyPreferredLang() + + return ( +
+ +
+ ) +} + const TextInput = ({ nodeDef, readOnly, node, edit, updateNode, canEditRecord }) => { const multiline = NodeDef.getTextInputType(nodeDef) === NodeDef.textInputTypes.multiLine return ( @@ -59,13 +72,16 @@ const MultipleTextInput = (props) => { const NodeDefText = (props) => { const { edit, entryDataQuery, nodeDef, nodes } = props - return edit ? ( - - ) : NodeDef.isMultiple(nodeDef) && !entryDataQuery ? ( - - ) : ( - - ) + if (NodeDef.isHeader(nodeDef)) { + return
+ } + if (edit) { + return + } + if (NodeDef.isMultiple(nodeDef) && !entryDataQuery) { + return + } + return } export default NodeDefText diff --git a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js index 6e58496786..aee1623a65 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js @@ -167,3 +167,11 @@ export const getDefaultPropsByType = (type, cycle) => { const fn = getPropByType('defaultProps')(type) return fn ? fn(cycle) : {} } + +export const headerColors = { + blue: '#b3e5fc', + green: '#b2dfdb', + orange: '#ffe0b2', + red: '#ffcdd2', + yellow: '#f0f4c3', +} diff --git a/webapp/store/survey/nodeDefs/actions.js b/webapp/store/survey/nodeDefs/actions.js index 0ac6bf3274..f42e1dbc5a 100644 --- a/webapp/store/survey/nodeDefs/actions.js +++ b/webapp/store/survey/nodeDefs/actions.js @@ -17,6 +17,7 @@ import { NotificationActions } from '@webapp/store/ui/notification' import * as SurveyState from '../state' import { surveyDefsIndexUpdate } from '../actions/actionTypes' +import { NodeDefExpressionFactory } from '@openforis/arena-core/dist/nodeDef/nodeDef' export const nodeDefCreate = 'survey/nodeDef/create' export const nodeDefUpdate = 'survey/nodeDef/update' @@ -48,11 +49,22 @@ export const cancelEdit = ({ nodeDef, nodeDefOriginal }) => ({ // ==== CREATE +const createHeader = ({ parent, cycle, props: propsParam }) => { + const props = { ...propsParam, [NodeDef.propKeys.isHeader]: true, [NodeDef.propKeys.readOnly]: true } + const propsAdvanced = { + [NodeDef.keysPropsAdvanced.defaultValues]: [NodeDefExpressionFactory.createInstance({ expression: '0' })], + } + return NodeDef.newNodeDef(parent, NodeDef.nodeDefType.text, [cycle], props, propsAdvanced) +} + export const createNodeDef = (parent, type, props, navigate) => async (dispatch, getState) => { const state = getState() const cycle = SurveyState.getSurveyCycleKey(state) - const nodeDef = NodeDef.newNodeDef(parent, type, [cycle], props) + const nodeDef = + type === NodeDef.NodeDefLayoutElementTypes.header + ? createHeader({ parent, cycle, props }) + : NodeDef.newNodeDef(parent, type, [cycle], props) dispatch({ type: nodeDefCreate, nodeDef }) From b59b4186538f3e4c8fb75effa2876239a66c438d Mon Sep 17 00:00:00 2001 From: Stefano Ricci Date: Fri, 10 Nov 2023 21:17:15 +0100 Subject: [PATCH 02/13] layout adjustments --- core/i18n/resources/en.js | 2 ++ core/survey/_survey/surveyNodeDefs.js | 12 ++++++++---- core/survey/nodeDef.js | 18 +++++++++++++----- test/e2e/tests/utils/formUtils.js | 2 +- .../survey/NodeDefDetails/NodeDefDetails.js | 2 +- .../SurveyForm/components/addNodeDefPanel.js | 2 +- .../SurveyForm/components/addNodeDefPanel.scss | 3 ++- .../components/types/nodeDefEntitySwitch.js | 7 +++++-- .../nodeDefs/components/types/nodeDefText.scss | 7 +++++++ .../SurveyForm/nodeDefs/nodeDefUIProps.js | 4 ++++ webapp/views/App/Header/Header.js | 12 ++++++------ webapp/views/App/Header/Header.scss | 12 ++++++------ 12 files changed, 56 insertions(+), 27 deletions(-) diff --git a/core/i18n/resources/en.js b/core/i18n/resources/en.js index b62d9f76f4..d68da09140 100644 --- a/core/i18n/resources/en.js +++ b/core/i18n/resources/en.js @@ -1243,6 +1243,8 @@ E.g. this.region = region_attribute_name taxon: 'Taxon', text: 'Text', time: 'Time', + // layout elments + header: 'Form Header', }, clone: `Clone '{{nodeDefLabel}}'`, compressFormItems: `Compress form items for '{{nodeDefLabel}}'`, diff --git a/core/survey/_survey/surveyNodeDefs.js b/core/survey/_survey/surveyNodeDefs.js index c0d6b08e34..26451db432 100644 --- a/core/survey/_survey/surveyNodeDefs.js +++ b/core/survey/_survey/surveyNodeDefs.js @@ -41,27 +41,31 @@ const filterNodeDefsWithoutSiblings = (nodeDefs) => ).length > 1 ) +const filterNodeDefsNotLayoutElements = (nodeDefs) => nodeDefs.filter((nodeDef) => !NodeDef.isLayoutElement(nodeDef)) + export const getNodeDefChildren = - (nodeDef, includeAnalysis = true) => + (nodeDef, includeAnalysis = true, includeLayoutElements = false) => (survey) => { const surveyIndexed = survey.nodeDefsIndex ? survey : SurveyNodeDefsIndex.initAndAssocNodeDefsIndex(survey) let childDefs = Surveys.getNodeDefChildren({ survey: surveyIndexed, nodeDef, includeAnalysis }) childDefs = filterNodeDefsWithoutSiblings(childDefs) + childDefs = includeLayoutElements ? childDefs : filterNodeDefsNotLayoutElements(childDefs) return childDefs } export const getNodeDefChildrenSorted = - ({ nodeDef, includeAnalysis = false, cycle = null }) => + ({ nodeDef, includeAnalysis = false, cycle = null, includeLayoutElements = false }) => (survey) => { let childDefs = Surveys.getNodeDefChildrenSorted({ survey, nodeDef, includeAnalysis, cycle }) childDefs = filterNodeDefsWithoutSiblings(childDefs) + childDefs = includeLayoutElements ? childDefs : filterNodeDefsNotLayoutElements(childDefs) return childDefs } export const getNodeDefChildrenInOwnPage = - ({ nodeDef, cycle }) => + ({ nodeDef, cycle, includeAnalysis = true, includeLayoutElements = false }) => (survey) => { - const children = getNodeDefChildren(nodeDef)(survey) + const children = getNodeDefChildren(nodeDef, includeAnalysis, includeLayoutElements)(survey) const childrenInOwnPage = children.filter(NodeDefLayout.hasPage(cycle)) const childrenIndex = NodeDefLayout.getIndexChildren(cycle)(nodeDef) if (childrenIndex.length === 0) return childrenInOwnPage diff --git a/core/survey/nodeDef.js b/core/survey/nodeDef.js index bb081c4752..69c2641612 100644 --- a/core/survey/nodeDef.js +++ b/core/survey/nodeDef.js @@ -67,8 +67,6 @@ export const propKeys = { // Text textInputType: 'textInputType', textTransform: 'textTransform', - isHeader: 'isHeader', - headerColor: 'headerColor', // Decimal maxNumberDecimalDigits: 'maxNumberDecimalDigits', @@ -93,6 +91,10 @@ export const propKeys = { includeAccuracy: 'includeAccuracy', includeAltitude: 'includeAltitude', includeAltitudeAccuracy: 'includeAltitudeAccuracy', + + // layout elements + isHeader: 'isHeader', + headerColor: 'headerColor', } export const textInputTypes = { @@ -255,8 +257,12 @@ export const getTextInputType = getProp(propKeys.textInputType, textInputTypes.s export const getTextTransform = getProp(propKeys.textTransform, textTransformValues.none) export const getTextTransformFunction = (nodeDef) => TextUtils.transform({ transformFunction: getTextTransform(nodeDef) }) + +// layout elements + export const isHeader = ObjectUtils.isPropTrue(propKeys.isHeader) export const getHeaderColor = getProp(propKeys.headerColor) +export const isLayoutElement = isHeader // ==== READ meta export const getMeta = R.propOr({}, keys.meta) @@ -505,8 +511,9 @@ export const keepOnlyOneCycle = export const canNodeDefBeMultiple = (nodeDef) => // Entity def but not root (isEntity(nodeDef) && !isRoot(nodeDef)) || - // Attribute def but not analysis - (!isAnalysis(nodeDef) && + // Attribute def but not layout element and not analysis + (!isLayoutElement(nodeDef) && + !isAnalysis(nodeDef) && R.includes(getType(nodeDef), [ nodeDefType.decimal, nodeDefType.code, @@ -526,7 +533,8 @@ export const canNodeDefTypeBeKey = (type) => nodeDefType.time, ]) -export const canNodeDefBeKey = (nodeDef) => !isAnalysis(nodeDef) && canNodeDefTypeBeKey(getType(nodeDef)) +export const canNodeDefBeKey = (nodeDef) => + !isLayoutElement(nodeDef) && !isAnalysis(nodeDef) && canNodeDefTypeBeKey(getType(nodeDef)) export const canHaveDefaultValue = (nodeDef) => isSingleAttribute(nodeDef) && diff --git a/test/e2e/tests/utils/formUtils.js b/test/e2e/tests/utils/formUtils.js index f0569112ea..efae2150cc 100644 --- a/test/e2e/tests/utils/formUtils.js +++ b/test/e2e/tests/utils/formUtils.js @@ -61,7 +61,7 @@ const expectDropdownValue = async ({ testId = null, parentSelector = '', value } const waitForLoaderToDisappear = async () => page.waitForSelector('.loader', { state: 'hidden', timeout: 5000 }) const waitForHeaderLoaderToDisappear = async () => - page.waitForSelector('.header__loader-wrapper', { state: 'hidden', timeout: 5000 }) + page.waitForSelector('.app-header__loader-wrapper', { state: 'hidden', timeout: 5000 }) export const FormUtils = { selectDropdownItem, diff --git a/webapp/components/survey/NodeDefDetails/NodeDefDetails.js b/webapp/components/survey/NodeDefDetails/NodeDefDetails.js index a67ddf65e4..f192240f5e 100644 --- a/webapp/components/survey/NodeDefDetails/NodeDefDetails.js +++ b/webapp/components/survey/NodeDefDetails/NodeDefDetails.js @@ -58,7 +58,7 @@ const NodeDefDetails = () => { { const i18n = useI18n() - const types = [...Object.values(NodeDef.nodeDefType), 'header'] + const types = [...Object.values(NodeDef.nodeDefType), ...Object.values(NodeDef.NodeDefLayoutElementTypes)] return ( <> diff --git a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss index 03177e9658..added1564c 100644 --- a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss +++ b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss @@ -25,7 +25,8 @@ background-color: rgba($green, 0.85); } - &.entity { + &.entity, + &.header { margin-top: 0.7rem; } } diff --git a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefEntitySwitch.js b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefEntitySwitch.js index 81d2f3d385..6ab7bfd49d 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefEntitySwitch.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefEntitySwitch.js @@ -27,8 +27,11 @@ const NodeDefEntitySwitch = (props) => { return null } - const includeAnalysis = false - const childDefs = Survey.getNodeDefChildrenSorted({ nodeDef, includeAnalysis, cycle: surveyCycleKey })(survey) + const childDefs = Survey.getNodeDefChildrenSorted({ + nodeDef, + cycle: surveyCycleKey, + includeLayoutElements: true, + })(survey) const nodeDefName = NodeDef.getName(nodeDef) const childUuids = NodeDefLayout.getLayoutChildrenUuids(surveyCycleKey)(nodeDef) diff --git a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.scss b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.scss index 2dded45c10..641eaacfdc 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.scss +++ b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefText.scss @@ -39,3 +39,10 @@ background-color: $blueLightFocus; } } + +.survey-form__node-def-header { + border: $formBorder; + padding: 0.3rem; + display: flex; + align-items: center; +} diff --git a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js index aee1623a65..b075f88805 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js @@ -121,6 +121,10 @@ const propsUI = { [NodeDefLayout.keys.layout]: NodeDefLayout.newLayout(cycle, NodeDefLayout.renderType.table), }), }, + + [NodeDef.NodeDefLayoutElementTypes.header]: { + icon: , + }, } const getPropByType = diff --git a/webapp/views/App/Header/Header.js b/webapp/views/App/Header/Header.js index 0f6506849a..5f9164e2b6 100644 --- a/webapp/views/App/Header/Header.js +++ b/webapp/views/App/Header/Header.js @@ -51,8 +51,8 @@ const Header = () => { const surveyTitle = surveyLabel ? `${surveyLabel} [${surveyName}]` : surveyName return ( -
-
+
+
Open Foris @@ -60,7 +60,7 @@ const Header = () => { -
+
{Survey.isValid(surveyInfo) && ( <> { to={appModuleUri(homeModules.surveyInfo)} className="btn-s btn-transparent" > - + { /> {canEditSurvey && Survey.isDraft(surveyInfo) && } -
{appSaving && }
+
{appSaving && }
)}
@@ -89,7 +89,7 @@ const Header = () => {
) +export const toButtonGroupItems = ({ i18n, object, labelPrefix }) => + Object.keys(object).map((key) => ({ + key, + label: i18n.t(`${labelPrefix}${key}`), + })) + ButtonGroup.propTypes = { items: PropTypes.array, groupName: PropTypes.string, diff --git a/webapp/components/survey/NodeDefDetails/BasicProps/BasicProps.js b/webapp/components/survey/NodeDefDetails/BasicProps/BasicProps.js index e4c38d1665..a5eb5ebbea 100644 --- a/webapp/components/survey/NodeDefDetails/BasicProps/BasicProps.js +++ b/webapp/components/survey/NodeDefDetails/BasicProps/BasicProps.js @@ -27,6 +27,7 @@ import CodeProps from '../CodeProps' import CoordinateProps from '../CoordinateProps' import DecimalProps from '../DecimalProps' import FileProps from '../FileProps' +import FormHeaderProps from '../FormHeaderProps' import TaxonProps from '../TaxonProps' import TextProps from '../TextProps' import AnalysisProps from '../AnalysisProps' @@ -37,6 +38,7 @@ const basicPropsComponentByType = { [NodeDef.nodeDefType.coordinate]: CoordinateProps, [NodeDef.nodeDefType.decimal]: DecimalProps, [NodeDef.nodeDefType.file]: FileProps, + [NodeDef.nodeDefType.formHeader]: FormHeaderProps, [NodeDef.nodeDefType.taxon]: TaxonProps, [NodeDef.nodeDefType.text]: TextProps, } diff --git a/webapp/components/survey/NodeDefDetails/FormHeaderProps.js b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js new file mode 100644 index 0000000000..da7aa8151a --- /dev/null +++ b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js @@ -0,0 +1,52 @@ +import React, { useCallback } from 'react' +import PropTypes from 'prop-types' + +import * as NodeDef from '@core/survey/nodeDef' + +import { useI18n } from '@webapp/store/system' +import { FormItem } from '@webapp/components/form/Input' +import ButtonGroup, { toButtonGroupItems } from '@webapp/components/form/buttonGroup' + +import { headerColors } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' + +import { State } from './store' + +const headerColorItems = ({ i18n }) => + toButtonGroupItems({ i18n, object: headerColors, labelPrefix: 'nodeDefEdit.formHeaderProps.headerColor.' }) + +const FormHeaderProps = (props) => { + const { state, Actions } = props + + const i18n = useI18n() + + const nodeDef = State.getNodeDef(state) + + const headerColor = NodeDef.getHeaderColor(nodeDef) + const selectedHeaderColorKey = Object.keys(headerColors).find((key) => headerColors[key] === headerColor) + + const onHeaderColorChange = useCallback( + (value) => { + Actions.setProp({ state, key: NodeDef.propKeys.headerColor, value: headerColors[value] }) + }, + [Actions, state] + ) + + return ( + <> + + + + + ) +} + +FormHeaderProps.propTypes = { + state: PropTypes.object.isRequired, + Actions: PropTypes.object.isRequired, +} + +export default FormHeaderProps diff --git a/webapp/components/survey/NodeDefDetails/TextProps.js b/webapp/components/survey/NodeDefDetails/TextProps.js index dd895283bf..35ef2058cc 100644 --- a/webapp/components/survey/NodeDefDetails/TextProps.js +++ b/webapp/components/survey/NodeDefDetails/TextProps.js @@ -5,21 +5,10 @@ import * as NodeDef from '@core/survey/nodeDef' import { useI18n } from '@webapp/store/system' import { FormItem } from '@webapp/components/form/Input' -import ButtonGroup from '@webapp/components/form/buttonGroup' - -import { headerColors } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' +import ButtonGroup, { toButtonGroupItems } from '@webapp/components/form/buttonGroup' import { State } from './store' -const toButtonGroupItems = ({ i18n, object, labelPrefix }) => - Object.keys(object).map((key) => ({ - key, - label: i18n.t(`${labelPrefix}${key}`), - })) - -const headerColorItems = ({ i18n }) => - toButtonGroupItems({ i18n, object: headerColors, labelPrefix: 'nodeDefEdit.textProps.headerColor.' }) - const textInputTypes = ({ i18n }) => toButtonGroupItems({ i18n, object: NodeDef.textInputTypes, labelPrefix: 'nodeDefEdit.textProps.textInputTypes.' }) @@ -44,48 +33,24 @@ const TextProps = (props) => { [Actions, state] ) - const headerColor = NodeDef.getHeaderColor(nodeDef) - const selectedHeaderColorKey = Object.keys(headerColors).find((key) => headerColors[key] === headerColor) - - const onHeaderColorChange = useCallback( - (value) => { - Actions.setProp({ state, key: NodeDef.propKeys.headerColor, value: headerColors[value] }) - }, - [Actions, state] - ) - return ( <> - {NodeDef.isFormHeader(nodeDef) ? ( - <> - - - - - ) : ( - <> - - - - - { - Actions.setProp({ state, key: NodeDef.propKeys.textInputType, value }) - }} - items={textInputTypes({ i18n })} - /> - - - )} + + + + + { + Actions.setProp({ state, key: NodeDef.propKeys.textInputType, value }) + }} + items={textInputTypes({ i18n })} + /> + ) } diff --git a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js index 24a484c130..ec8137515d 100644 --- a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js +++ b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.js @@ -19,11 +19,9 @@ const AddNodeDefButtons = (props) => { const i18n = useI18n() - const types = [...Object.values(NodeDef.nodeDefType), ...NodeDef.NodeDefLayoutElementTypes] - return ( <> - {types.map((type) => { + {Object.values(NodeDef.nodeDefType).map((type) => { const nodeDefProps = NodeDefUIProps.getDefaultPropsByType(type, surveyCycleKey) // Cannot add entities when entity is rendered as table diff --git a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss index added1564c..93c2a0fe19 100644 --- a/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss +++ b/webapp/components/survey/SurveyForm/components/addNodeDefPanel.scss @@ -26,7 +26,7 @@ } &.entity, - &.header { + &.formHeader { margin-top: 0.7rem; } } diff --git a/yarn.lock b/yarn.lock index 2cbacce57c..0213817a1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2543,22 +2543,6 @@ proj4 "^2.9.0" uuid "^9.0.1" -"@openforis/arena-core@^0.0.175": - version "0.0.175" - resolved "https://npm.pkg.github.com/download/@openforis/arena-core/0.0.175/b809386fed529e0b20c82c7d70fa8f3d8c935db9#b809386fed529e0b20c82c7d70fa8f3d8c935db9" - integrity sha512-NKOKCTQchJMmQFYYt7g9wcKOBb+eeFKCdHd8aOFGDt4I+4oEzF77t8wnRgXh3X00dLSTrUY9U8OU3wZuTToFnw== - dependencies: - "@jsep-plugin/regex" "^1.0.3" - bignumber.js "^9.1.2" - date-fns "^2.30.0" - jsep "^1.3.8" - lodash.differencewith "^4.5.0" - lodash.frompairs "^4.0.1" - lodash.isequal "^4.5.0" - lodash.topairs "^4.3.0" - proj4 "^2.9.0" - uuid "^9.0.1" - "@openforis/arena-server@^0.1.30": version "0.1.30" resolved "https://npm.pkg.github.com/download/@openforis/arena-server/0.1.30/fd5f62c57cffe8694c1d962b4a41ea0e154c7735#fd5f62c57cffe8694c1d962b4a41ea0e154c7735" From 98527d7bb700119f923e19879d2fe5593442e7ce Mon Sep 17 00:00:00 2001 From: Stefano Ricci Date: Mon, 13 Nov 2023 23:04:04 +0100 Subject: [PATCH 09/13] layout adjustments --- webapp/components/form/buttonGroup.js | 30 +++++++++++++------ .../survey/NodeDefDetails/FormHeaderProps.js | 30 ++++++++++++------- .../NodeDefDetails/FormHeaderProps.scss | 11 +++++++ .../survey/NodeDefDetails/NodeDefDetails.js | 2 +- .../components/types/nodeDefFormHeader.js | 14 +++++++-- .../SurveyForm/nodeDefs/nodeDefUIProps.js | 18 +++++++---- 6 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 webapp/components/survey/NodeDefDetails/FormHeaderProps.scss diff --git a/webapp/components/form/buttonGroup.js b/webapp/components/form/buttonGroup.js index 87a205db22..ab1cf87d26 100644 --- a/webapp/components/form/buttonGroup.js +++ b/webapp/components/form/buttonGroup.js @@ -5,40 +5,52 @@ import PropTypes from 'prop-types' import * as R from 'ramda' -const ButtonGroup = ({ items, groupName, multiple, selectedItemKey, onChange, disabled, deselectable, className }) => ( +const ButtonGroup = ({ + items, + groupName, + multiple, + selectedItemKey, + onChange, + disabled: disabledProp, + deselectable, + className, +}) => (
{items.map((item) => { - const selected = selectedItemKey === item.key || (multiple && R.includes(item.key, selectedItemKey)) + const { key, disabled, icon, label } = item + const selected = selectedItemKey === key || (multiple && R.includes(key, selectedItemKey)) return ( ) })}
) -export const toButtonGroupItems = ({ i18n, object, labelPrefix }) => +export const toButtonGroupItems = ({ i18n, object, labelPrefix, icon = null }) => Object.keys(object).map((key) => ({ key, label: i18n.t(`${labelPrefix}${key}`), + icon, })) ButtonGroup.propTypes = { diff --git a/webapp/components/survey/NodeDefDetails/FormHeaderProps.js b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js index da7aa8151a..72dfb0cb73 100644 --- a/webapp/components/survey/NodeDefDetails/FormHeaderProps.js +++ b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js @@ -1,3 +1,5 @@ +import './FormHeaderProps.scss' + import React, { useCallback } from 'react' import PropTypes from 'prop-types' @@ -7,12 +9,19 @@ import { useI18n } from '@webapp/store/system' import { FormItem } from '@webapp/components/form/Input' import ButtonGroup, { toButtonGroupItems } from '@webapp/components/form/buttonGroup' -import { headerColors } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' +import { headerColors, headerColorCodesByColor } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' import { State } from './store' const headerColorItems = ({ i18n }) => - toButtonGroupItems({ i18n, object: headerColors, labelPrefix: 'nodeDefEdit.formHeaderProps.headerColor.' }) + toButtonGroupItems({ + i18n, + object: headerColors, + labelPrefix: 'nodeDefEdit.formHeaderProps.headerColor.', + icon: ({ key }) => ( + + ), + }) const FormHeaderProps = (props) => { const { state, Actions } = props @@ -32,15 +41,14 @@ const FormHeaderProps = (props) => { ) return ( - <> - - - - + + + ) } diff --git a/webapp/components/survey/NodeDefDetails/FormHeaderProps.scss b/webapp/components/survey/NodeDefDetails/FormHeaderProps.scss new file mode 100644 index 0000000000..c77d674582 --- /dev/null +++ b/webapp/components/survey/NodeDefDetails/FormHeaderProps.scss @@ -0,0 +1,11 @@ +.btn-group.form-header-color-btn-group { + button { + display: flex; + gap: 1rem; + + .form-header-color-icon { + height: 1rem; + width: 1rem; + } + } +} diff --git a/webapp/components/survey/NodeDefDetails/NodeDefDetails.js b/webapp/components/survey/NodeDefDetails/NodeDefDetails.js index f192240f5e..adad293ec4 100644 --- a/webapp/components/survey/NodeDefDetails/NodeDefDetails.js +++ b/webapp/components/survey/NodeDefDetails/NodeDefDetails.js @@ -53,7 +53,7 @@ const NodeDefDetails = () => { } />
- {nodeDefType} {NodeDefUIProps.getIconByType(nodeDefType)} + {i18n.t(`surveyForm.addChildToTypes.${nodeDefType}`)} {NodeDefUIProps.getIconByType(nodeDefType)}
diff --git a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js index d7fb5ff8d0..800a979bf6 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js @@ -1,21 +1,31 @@ import './nodeDefFormHeader.scss' import React from 'react' +import PropTypes from 'prop-types' import * as NodeDef from '@core/survey/nodeDef' import Markdown from '@webapp/components/markdown' +import * as NodeDefUIProps from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' import { useSurveyPreferredLang } from '@webapp/store/survey' -const NodeDefFormHeader = ({ nodeDef }) => { +const NodeDefFormHeader = (props) => { + const { nodeDef } = props + const lang = useSurveyPreferredLang() + const backgroundColor = NodeDefUIProps.headerColorCodesByColor[NodeDef.getHeaderColor(nodeDef)] + return ( -
+
) } +NodeDefFormHeader.propTypes = { + nodeDef: PropTypes.object.isRequired, +} + export default NodeDefFormHeader diff --git a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js index 8c5c8a134a..8678c08b72 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js @@ -176,9 +176,17 @@ export const getDefaultPropsByType = (type, cycle) => { } export const headerColors = { - blue: '#b3e5fc', - green: '#b2dfdb', - orange: '#ffe0b2', - red: '#ffcdd2', - yellow: '#f0f4c3', + blue: 'blue', + green: 'green', + orange: 'orange', + red: 'red', + yellow: 'yellow', +} + +export const headerColorCodesByColor = { + [headerColors.blue]: '#b3e5fc', + [headerColors.green]: '#b2dfdb', + [headerColors.orange]: '#ffe0b2', + [headerColors.red]: '#ffcdd2', + [headerColors.yellow]: '#f0f4c3', } From 90668ff5e5118b797745ece6ea87817933344ee1 Mon Sep 17 00:00:00 2001 From: Stefano Ricci Date: Tue, 14 Nov 2023 10:43:33 +0100 Subject: [PATCH 10/13] layout adjustments --- .../survey/NodeDefDetails/FormHeaderProps.js | 7 ++-- .../components/types/nodeDefFormHeader.js | 2 +- .../components/types/nodeDefFormHeader.scss | 2 ++ .../SurveyForm/nodeDefs/nodeDefUIProps.js | 35 ++++++++++--------- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/webapp/components/survey/NodeDefDetails/FormHeaderProps.js b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js index 72dfb0cb73..4d617916ae 100644 --- a/webapp/components/survey/NodeDefDetails/FormHeaderProps.js +++ b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js @@ -9,7 +9,7 @@ import { useI18n } from '@webapp/store/system' import { FormItem } from '@webapp/components/form/Input' import ButtonGroup, { toButtonGroupItems } from '@webapp/components/form/buttonGroup' -import { headerColors, headerColorCodesByColor } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' +import { headerColors, headerColorRgbCodesByColor } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' import { State } from './store' @@ -19,7 +19,7 @@ const headerColorItems = ({ i18n }) => object: headerColors, labelPrefix: 'nodeDefEdit.formHeaderProps.headerColor.', icon: ({ key }) => ( - + ), }) @@ -31,7 +31,6 @@ const FormHeaderProps = (props) => { const nodeDef = State.getNodeDef(state) const headerColor = NodeDef.getHeaderColor(nodeDef) - const selectedHeaderColorKey = Object.keys(headerColors).find((key) => headerColors[key] === headerColor) const onHeaderColorChange = useCallback( (value) => { @@ -44,7 +43,7 @@ const FormHeaderProps = (props) => { diff --git a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js index 800a979bf6..9dc68b1863 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.js @@ -15,7 +15,7 @@ const NodeDefFormHeader = (props) => { const lang = useSurveyPreferredLang() - const backgroundColor = NodeDefUIProps.headerColorCodesByColor[NodeDef.getHeaderColor(nodeDef)] + const backgroundColor = NodeDefUIProps.headerColorRgbCodesByColor[NodeDef.getHeaderColor(nodeDef)] return (
diff --git a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.scss b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.scss index f93d2b5b16..110719f8e5 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.scss +++ b/webapp/components/survey/SurveyForm/nodeDefs/components/types/nodeDefFormHeader.scss @@ -5,4 +5,6 @@ padding: 0.3rem; display: flex; align-items: center; + font-size: 1.1rem; + font-weight: bold; } diff --git a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js index 8678c08b72..e787e7853e 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js @@ -21,6 +21,22 @@ import NodeDefTime from './components/types/nodeDefTime' const { integer, decimal, text, date, time, boolean, code, coordinate, taxon, file, entity, formHeader } = NodeDef.nodeDefType +export const headerColors = { + blue: 'blue', + green: 'green', + orange: 'orange', + red: 'red', + yellow: 'yellow', +} + +export const headerColorRgbCodesByColor = { + [headerColors.blue]: '#b3e5fc', + [headerColors.green]: '#b2dfdb', + [headerColors.orange]: '#ffb38a', + [headerColors.red]: '#f97c7c', + [headerColors.yellow]: '#fffdaf', +} + const propsUI = { [integer]: { icon: 123, @@ -127,6 +143,9 @@ const propsUI = { [formHeader]: { component: NodeDefFormHeader, icon: , + defaultProps: () => ({ + [NodeDef.propKeys.headerColor]: headerColors.blue, + }), }, } @@ -174,19 +193,3 @@ export const getDefaultPropsByType = (type, cycle) => { const fn = getPropByType('defaultProps')(type) return fn ? fn(cycle) : {} } - -export const headerColors = { - blue: 'blue', - green: 'green', - orange: 'orange', - red: 'red', - yellow: 'yellow', -} - -export const headerColorCodesByColor = { - [headerColors.blue]: '#b3e5fc', - [headerColors.green]: '#b2dfdb', - [headerColors.orange]: '#ffe0b2', - [headerColors.red]: '#ffcdd2', - [headerColors.yellow]: '#f0f4c3', -} From 73c0103a0a17d4ea2f0246ebb12dd914f750a6d1 Mon Sep 17 00:00:00 2001 From: Stefano Ricci Date: Wed, 15 Nov 2023 11:33:53 +0100 Subject: [PATCH 11/13] use form header colors from arena-core --- .../survey/NodeDefDetails/FormHeaderProps.js | 8 ++++--- .../SurveyForm/nodeDefs/nodeDefUIProps.js | 22 +++++++------------ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/webapp/components/survey/NodeDefDetails/FormHeaderProps.js b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js index 4d617916ae..bb258c326d 100644 --- a/webapp/components/survey/NodeDefDetails/FormHeaderProps.js +++ b/webapp/components/survey/NodeDefDetails/FormHeaderProps.js @@ -3,20 +3,22 @@ import './FormHeaderProps.scss' import React, { useCallback } from 'react' import PropTypes from 'prop-types' +import { FormHeaderColor } from '@openforis/arena-core' + import * as NodeDef from '@core/survey/nodeDef' import { useI18n } from '@webapp/store/system' import { FormItem } from '@webapp/components/form/Input' import ButtonGroup, { toButtonGroupItems } from '@webapp/components/form/buttonGroup' -import { headerColors, headerColorRgbCodesByColor } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' +import { headerColorRgbCodesByColor } from '@webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps' import { State } from './store' const headerColorItems = ({ i18n }) => toButtonGroupItems({ i18n, - object: headerColors, + object: FormHeaderColor, labelPrefix: 'nodeDefEdit.formHeaderProps.headerColor.', icon: ({ key }) => ( @@ -34,7 +36,7 @@ const FormHeaderProps = (props) => { const onHeaderColorChange = useCallback( (value) => { - Actions.setProp({ state, key: NodeDef.propKeys.headerColor, value: headerColors[value] }) + Actions.setProp({ state, key: NodeDef.propKeys.headerColor, value: FormHeaderColor[value] }) }, [Actions, state] ) diff --git a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js index e787e7853e..3f9c8afd6c 100644 --- a/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js +++ b/webapp/components/survey/SurveyForm/nodeDefs/nodeDefUIProps.js @@ -1,6 +1,8 @@ import React from 'react' import * as R from 'ramda' +import { FormHeaderColor } from '@openforis/arena-core' + import * as NodeDef from '@core/survey/nodeDef' import * as NodeDefLayout from '@core/survey/nodeDefLayout' import { valuePropsCoordinate, valuePropsTaxon } from '@core/survey/nodeValueProps' @@ -21,20 +23,12 @@ import NodeDefTime from './components/types/nodeDefTime' const { integer, decimal, text, date, time, boolean, code, coordinate, taxon, file, entity, formHeader } = NodeDef.nodeDefType -export const headerColors = { - blue: 'blue', - green: 'green', - orange: 'orange', - red: 'red', - yellow: 'yellow', -} - export const headerColorRgbCodesByColor = { - [headerColors.blue]: '#b3e5fc', - [headerColors.green]: '#b2dfdb', - [headerColors.orange]: '#ffb38a', - [headerColors.red]: '#f97c7c', - [headerColors.yellow]: '#fffdaf', + [FormHeaderColor.blue]: '#b3e5fc', + [FormHeaderColor.green]: '#b2dfdb', + [FormHeaderColor.orange]: '#ffb38a', + [FormHeaderColor.red]: '#f97c7c', + [FormHeaderColor.yellow]: '#fffdaf', } const propsUI = { @@ -144,7 +138,7 @@ const propsUI = { component: NodeDefFormHeader, icon: , defaultProps: () => ({ - [NodeDef.propKeys.headerColor]: headerColors.blue, + [NodeDef.propKeys.headerColor]: FormHeaderColor.blue, }), }, } From c3692fb31e8c81c8f18da93ae14566c4ee2526e9 Mon Sep 17 00:00:00 2001 From: Stefano Ricci Date: Thu, 30 Nov 2023 11:37:06 +0100 Subject: [PATCH 12/13] code cleanup --- webapp/components/form/buttonGroup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/components/form/buttonGroup.js b/webapp/components/form/buttonGroup.js index ab1cf87d26..4a2f1b7097 100644 --- a/webapp/components/form/buttonGroup.js +++ b/webapp/components/form/buttonGroup.js @@ -38,7 +38,7 @@ const ButtonGroup = ({ }} aria-disabled={Boolean(disabled) || disabledProp} > - {icon && icon({ key })} + {icon?.({ key })} {label} ) From 524e8078482bb6d8b996ca0fcef127688141bde3 Mon Sep 17 00:00:00 2001 From: Stefano Ricci Date: Thu, 30 Nov 2023 11:42:42 +0100 Subject: [PATCH 13/13] fixed tests --- test/e2e/tests/login.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/tests/login.js b/test/e2e/tests/login.js index d62fe9e856..0771de7820 100644 --- a/test/e2e/tests/login.js +++ b/test/e2e/tests/login.js @@ -25,7 +25,7 @@ export default () => page.click('text="Login"'), ]) - const header = await page.$('.header') + const header = await page.$('.app-header') await expect(header).not.toBe(null) }) })