From a4fa043cafb0ce2e2e1d5d10e0cb8ee5f332c6be Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Wed, 31 Jan 2024 09:51:46 +0100 Subject: [PATCH 01/12] initial commit --- .../src/components/Properties/Content.tsx | 2 + .../src/components/Properties/Properties.tsx | 2 + .../PropertiesHeader.module.css | 0 .../PropertiesHeader/PropertiesHeader.tsx | 37 +++++++++++++++++++ .../Properties/PropertiesHeader/index.ts | 1 + 5 files changed, 42 insertions(+) create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/index.ts diff --git a/frontend/packages/ux-editor/src/components/Properties/Content.tsx b/frontend/packages/ux-editor/src/components/Properties/Content.tsx index 1629e6e1ec3..f5c1f3c1749 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Content.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Content.tsx @@ -10,6 +10,8 @@ import { useTranslation } from 'react-i18next'; export const Content = () => { const { formId, form, handleUpdate, debounceSave } = useFormContext(); + + console.log('FORM', form); const editId = useSelector(getCurrentEditId); const { t } = useTranslation(); diff --git a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx index 5879dff6ebd..43126d02fa9 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx @@ -6,6 +6,7 @@ import { Accordion } from '@digdir/design-system-react'; import { useFormContext } from '../../containers/FormContext'; import classes from './Properties.module.css'; import { Dynamics } from './Dynamics'; +import { PropertiesHeader } from './PropertiesHeader'; export const Properties = () => { const { t } = useTranslation(); @@ -31,6 +32,7 @@ export const Properties = () => { return (
+ toggleOpen('content')}> diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx new file mode 100644 index 00000000000..1117dea6383 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import classes from './PropertiesHeader.module.css'; +import { Divider, Heading, HelpText } from '@digdir/design-system-react'; +import { useFormContext } from '../../../containers/FormContext'; + +type PropertiesHeaderProps = {}; + +export const PropertiesHeader = ({}: PropertiesHeaderProps): React.JSX.Element => { + const { formId, form } = useFormContext(); + console.log('FORM ID', formId); + console.log('FORM', form); + + // getComponentHelperTextByComponentType + + return ( +
+
+
+

Icon

+ + component name + +
+ + CONTENT + +
+ +
+
+

icon

+
+
+
+
+ ); +}; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/index.ts b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/index.ts new file mode 100644 index 00000000000..dc00e5c7c10 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/index.ts @@ -0,0 +1 @@ +export { PropertiesHeader } from './PropertiesHeader'; From 7d5cd79a7be9b74e1ef53e57bb8f4f76b3b8a721 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Wed, 31 Jan 2024 10:58:01 +0100 Subject: [PATCH 02/12] adding header stuff --- .../src/components/Properties/Properties.tsx | 4 +-- .../PropertiesHeader.module.css | 27 ++++++++++++++++ .../PropertiesHeader/PropertiesHeader.tsx | 32 ++++++++++++------- .../DesignView/FormTree/FormItem/FormItem.tsx | 2 +- .../ux-editor/src/hooks/useItemTitle/index.ts | 1 + .../useItemTitle}/useItemTitle.test.ts | 0 .../useItemTitle}/useItemTitle.ts | 12 +++---- 7 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 frontend/packages/ux-editor/src/hooks/useItemTitle/index.ts rename frontend/packages/ux-editor/src/{containers/DesignView/FormTree/FormItem => hooks/useItemTitle}/useItemTitle.test.ts (100%) rename frontend/packages/ux-editor/src/{containers/DesignView/FormTree/FormItem => hooks/useItemTitle}/useItemTitle.ts (75%) diff --git a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx index 43126d02fa9..2232c932a5b 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx @@ -10,7 +10,7 @@ import { PropertiesHeader } from './PropertiesHeader'; export const Properties = () => { const { t } = useTranslation(); - const { formId } = useFormContext(); + const { formId, form } = useFormContext(); const formIdRef = React.useRef(formId); const [openList, setOpenList] = React.useState([]); @@ -32,7 +32,7 @@ export const Properties = () => { return (
- + {form && } toggleOpen('content')}> diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css index e69de29bb2d..f0e16076d02 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css @@ -0,0 +1,27 @@ +.wrapper { +} + +.header { + display: flex; + justify-content: space-between; + padding-inline: var(--fds-spacing-3); + padding-block: var(--fds-spacing-2); + background-color: var(--fds-semantic-surface-neutral-selected); +} + +.iconAndTextWrapper { + display: flex; + align-items: center; + gap: var(--fds-spacing-2); +} + +.divider { + margin: 0; + padding: 0; +} + +.content { + padding-inline: var(--fds-spacing-3); + padding-block: var(--fds-spacing-2); + background-color: var(--fds-semantic-surface-neutral-default); +} diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx index 1117dea6383..80801729bcb 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -1,31 +1,41 @@ import React from 'react'; import classes from './PropertiesHeader.module.css'; import { Divider, Heading, HelpText } from '@digdir/design-system-react'; -import { useFormContext } from '../../../containers/FormContext'; +import { formItemConfigs } from '../../../data/formItemConfig'; +import { QuestionmarkDiamondIcon } from '@studio/icons'; +import type { FormComponent } from '../../../types/FormComponent'; +import type { FormContainer } from '../../../types/FormContainer'; +import { useItemTitle } from '../../../hooks/useItemTitle'; +import { getComponentHelperTextByComponentType } from '../../../utils/language'; +import { useTranslation } from 'react-i18next'; -type PropertiesHeaderProps = {}; +type PropertiesHeaderProps = { + form: FormContainer | FormComponent; +}; -export const PropertiesHeader = ({}: PropertiesHeaderProps): React.JSX.Element => { - const { formId, form } = useFormContext(); - console.log('FORM ID', formId); - console.log('FORM', form); +export const PropertiesHeader = ({ form }: PropertiesHeaderProps): React.JSX.Element => { + const { t } = useTranslation(); + const itemTitle = useItemTitle(); - // getComponentHelperTextByComponentType + const isUnknownInternalComponent: boolean = !formItemConfigs[form.type]; + const Icon = isUnknownInternalComponent + ? QuestionmarkDiamondIcon + : formItemConfigs[form.type]?.icon; return (
-

Icon

+ {Icon && } - component name + {itemTitle(form)}
- CONTENT + {getComponentHelperTextByComponentType(form.type, t)}
- +

icon

diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItem.tsx b/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItem.tsx index fd08c719ed5..f1783f41960 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItem.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItem.tsx @@ -5,7 +5,7 @@ import { renderItemList } from '../renderItemList'; import { DragAndDropTree } from 'app-shared/components/DragAndDropTree'; import { FormItemTitle } from './FormItemTitle'; import { formItemConfigs } from '../../../../data/formItemConfig'; -import { useItemTitle } from './useItemTitle'; +import { useItemTitle } from '../../../../hooks/useItemTitle'; import { useTranslation } from 'react-i18next'; import { UnknownReferencedItem } from '../UnknownReferencedItem'; import { QuestionmarkDiamondIcon } from '@studio/icons'; diff --git a/frontend/packages/ux-editor/src/hooks/useItemTitle/index.ts b/frontend/packages/ux-editor/src/hooks/useItemTitle/index.ts new file mode 100644 index 00000000000..47419a7ed7c --- /dev/null +++ b/frontend/packages/ux-editor/src/hooks/useItemTitle/index.ts @@ -0,0 +1 @@ +export { useItemTitle } from './useItemTitle'; diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/useItemTitle.test.ts b/frontend/packages/ux-editor/src/hooks/useItemTitle/useItemTitle.test.ts similarity index 100% rename from frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/useItemTitle.test.ts rename to frontend/packages/ux-editor/src/hooks/useItemTitle/useItemTitle.test.ts diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/useItemTitle.ts b/frontend/packages/ux-editor/src/hooks/useItemTitle/useItemTitle.ts similarity index 75% rename from frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/useItemTitle.ts rename to frontend/packages/ux-editor/src/hooks/useItemTitle/useItemTitle.ts index f7e2f613129..1615bbdc0b8 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/useItemTitle.ts +++ b/frontend/packages/ux-editor/src/hooks/useItemTitle/useItemTitle.ts @@ -1,13 +1,13 @@ import type { ITextResource } from 'app-shared/types/global'; -import { useTextResourcesSelector } from '../../../../hooks'; -import { textResourcesByLanguageSelector } from '../../../../selectors/textResourceSelectors'; +import { useTextResourcesSelector } from '../useTextResourcesSelector'; +import { textResourcesByLanguageSelector } from '../../selectors/textResourceSelectors'; import { DEFAULT_LANGUAGE } from 'app-shared/constants'; import { useTranslation } from 'react-i18next'; import { useCallback } from 'react'; -import { getTextResource } from '../../../../utils/language'; -import { useComponentTypeName } from '../../../../hooks/useComponentTypeName'; -import type { FormComponent } from '../../../../types/FormComponent'; -import type { FormContainer } from '../../../../types/FormContainer'; +import { getTextResource } from '../../utils/language'; +import { useComponentTypeName } from '../../hooks/useComponentTypeName'; +import type { FormComponent } from '../../types/FormComponent'; +import type { FormContainer } from '../../types/FormContainer'; export const useItemTitle = (): ((item: FormComponent | FormContainer) => string) => { const containerTitle = useContainerTitle(); From 8f7afab483ba542280985fe299e35c03d8dd0930 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Wed, 31 Jan 2024 12:10:41 +0100 Subject: [PATCH 03/12] test --- .../PropertiesHeader/PropertiesHeader.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx index 80801729bcb..0421547e5a6 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -8,12 +8,14 @@ import type { FormContainer } from '../../../types/FormContainer'; import { useItemTitle } from '../../../hooks/useItemTitle'; import { getComponentHelperTextByComponentType } from '../../../utils/language'; import { useTranslation } from 'react-i18next'; +import { EditDataModelBindings } from '../../config/editModal/EditDataModelBindings'; type PropertiesHeaderProps = { form: FormContainer | FormComponent; + schema: any; }; -export const PropertiesHeader = ({ form }: PropertiesHeaderProps): React.JSX.Element => { +export const PropertiesHeader = ({ form, schema }: PropertiesHeaderProps): React.JSX.Element => { const { t } = useTranslation(); const itemTitle = useItemTitle(); @@ -22,6 +24,8 @@ export const PropertiesHeader = ({ form }: PropertiesHeaderProps): React.JSX.Ele ? QuestionmarkDiamondIcon : formItemConfigs[form.type]?.icon; + const { dataModelBindings } = schema.properties; + return (
@@ -40,7 +44,30 @@ export const PropertiesHeader = ({ form }: PropertiesHeaderProps): React.JSX.Ele

icon

-
+
+ {dataModelBindings?.properties && ( + <> + + {t('top_menu.datamodel')} + + {Object.keys(dataModelBindings?.properties).map((propertyKey: any) => { + return ( + + ); + })} + + )} +
); From 6dcf0219c76c2ba4a70ef05a1f9da5aa7f8a9e84 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Thu, 1 Feb 2024 15:55:44 +0100 Subject: [PATCH 04/12] Moving datamodel button --- .../src/components/Properties/Properties.tsx | 16 +++++- .../PropertiesHeader/DataModelBindingRow.tsx | 41 ++++++++++++++ .../PropertiesHeader.module.css | 9 +++ .../PropertiesHeader/PropertiesHeader.tsx | 55 +++++++++---------- .../components/config/FormComponentConfig.tsx | 23 -------- 5 files changed, 90 insertions(+), 54 deletions(-) create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow.tsx diff --git a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx index 2232c932a5b..f7573e4fed9 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx @@ -7,10 +7,11 @@ import { useFormContext } from '../../containers/FormContext'; import classes from './Properties.module.css'; import { Dynamics } from './Dynamics'; import { PropertiesHeader } from './PropertiesHeader'; +import { isContainer } from '../../utils/formItemUtils'; export const Properties = () => { const { t } = useTranslation(); - const { formId, form } = useFormContext(); + const { formId, form, handleUpdate, debounceSave } = useFormContext(); const formIdRef = React.useRef(formId); const [openList, setOpenList] = React.useState([]); @@ -30,9 +31,20 @@ export const Properties = () => { } }; + console.log('hei'); + return (
- {form && } + {form && !isContainer(form) && ( + { + handleUpdate(updatedComponent); + debounceSave(formId, updatedComponent); + }} + /> + )} toggleOpen('content')}> diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow.tsx new file mode 100644 index 00000000000..fe218990973 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { EditDataModelBindings } from '../../config/editModal/EditDataModelBindings'; +import type { FormComponent } from '../../../types/FormComponent'; + +type DataModelBindingRowProps = { + schema: any; + component: FormComponent; + formId: string; + handleComponentUpdate: (component: FormComponent) => void; +}; + +export const DataModelBindingRow = ({ + schema, + component, + formId, + handleComponentUpdate, +}: DataModelBindingRowProps): React.JSX.Element => { + const { dataModelBindings } = schema.properties; + + return ( + dataModelBindings?.properties && ( + <> + {Object.keys(dataModelBindings?.properties).map((propertyKey: any) => { + return ( + + ); + })} + + ) + ); +}; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css index f0e16076d02..802f93eae69 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css @@ -24,4 +24,13 @@ padding-inline: var(--fds-spacing-3); padding-block: var(--fds-spacing-2); background-color: var(--fds-semantic-surface-neutral-default); + display: flex; + flex-direction: column; + gap: var(--fds-spacing-2); +} + +.contentRow { + display: flex; + align-items: center; + gap: var(--fds-spacing-1); } diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx index 0421547e5a6..c242f083a97 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -1,21 +1,28 @@ import React from 'react'; import classes from './PropertiesHeader.module.css'; -import { Divider, Heading, HelpText } from '@digdir/design-system-react'; +import { Divider, Heading, HelpText, Paragraph } from '@digdir/design-system-react'; import { formItemConfigs } from '../../../data/formItemConfig'; import { QuestionmarkDiamondIcon } from '@studio/icons'; import type { FormComponent } from '../../../types/FormComponent'; -import type { FormContainer } from '../../../types/FormContainer'; import { useItemTitle } from '../../../hooks/useItemTitle'; import { getComponentHelperTextByComponentType } from '../../../utils/language'; import { useTranslation } from 'react-i18next'; -import { EditDataModelBindings } from '../../config/editModal/EditDataModelBindings'; +import { useLayoutSchemaQuery } from '../../../hooks/queries/useLayoutSchemaQuery'; +import { useComponentSchemaQuery } from '../../../hooks/queries/useComponentSchemaQuery'; +import { DataModelBindingRow } from './DataModelBindingRow'; +import { KeyVerticalIcon } from '@studio/icons'; type PropertiesHeaderProps = { - form: FormContainer | FormComponent; - schema: any; + form: FormComponent; + formId: string; + handleComponentUpdate: (component: FormComponent) => void; }; -export const PropertiesHeader = ({ form, schema }: PropertiesHeaderProps): React.JSX.Element => { +export const PropertiesHeader = ({ + form, + formId, + handleComponentUpdate, +}: PropertiesHeaderProps): React.JSX.Element => { const { t } = useTranslation(); const itemTitle = useItemTitle(); @@ -24,7 +31,8 @@ export const PropertiesHeader = ({ form, schema }: PropertiesHeaderProps): React ? QuestionmarkDiamondIcon : formItemConfigs[form.type]?.icon; - const { dataModelBindings } = schema.properties; + useLayoutSchemaQuery(); // Ensure we load the layout schemas so that component schemas can be loaded + const { data: schema } = useComponentSchemaQuery(form.type); return (
@@ -42,30 +50,19 @@ export const PropertiesHeader = ({ form, schema }: PropertiesHeaderProps): React
-

icon

+ {/* TODO - FIX Textfield / tekst komponent */} + + ID: {formId}
- {dataModelBindings?.properties && ( - <> - - {t('top_menu.datamodel')} - - {Object.keys(dataModelBindings?.properties).map((propertyKey: any) => { - return ( - - ); - })} - + {schema && ( + // TODO - Change the design of the datamodel + )}
diff --git a/frontend/packages/ux-editor/src/components/config/FormComponentConfig.tsx b/frontend/packages/ux-editor/src/components/config/FormComponentConfig.tsx index f7570be49b2..f0cd12ff456 100644 --- a/frontend/packages/ux-editor/src/components/config/FormComponentConfig.tsx +++ b/frontend/packages/ux-editor/src/components/config/FormComponentConfig.tsx @@ -3,7 +3,6 @@ import { EditComponentId } from './editModal/EditComponentId'; import { Alert, Heading, Paragraph } from '@digdir/design-system-react'; import type { FormComponent } from '../../types/FormComponent'; import { selectedLayoutNameSelector } from '../../selectors/formLayoutSelectors'; -import { EditDataModelBindings } from './editModal/EditDataModelBindings'; import { EditTextResourceBindings } from './editModal/EditTextResourceBindings'; import { EditBooleanValue } from './editModal/EditBooleanValue'; import { EditNumberValue } from './editModal/EditNumberValue'; @@ -81,28 +80,6 @@ export const FormComponentConfig = ({ /> )} - {dataModelBindings?.properties && ( - <> - - {t('top_menu.datamodel')} - - {Object.keys(dataModelBindings?.properties).map((propertyKey: any) => { - return ( - - ); - })} - - )} {grid && (
From faf5e9888f2c817366cc76fd9f745dba10feba0a Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Thu, 1 Feb 2024 16:37:01 +0100 Subject: [PATCH 05/12] Addig component for handling edit id --- .../EditableTextField.module.css | 34 +++++++++++++ .../EditableTextField/EditableTextField.tsx | 50 +++++++++++++++++++ .../EditableTextField/index.ts | 1 + .../PropertiesHeader/PropertiesHeader.tsx | 17 +++++-- 4 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css new file mode 100644 index 00000000000..021a11ef35b --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css @@ -0,0 +1,34 @@ +.wrapper { + display: flex; + align-items: center; + gap: var(--fds-spacing-1); + height: var(--fds-spacing-8); + width: 100%; +} + +.wrapper:hover { + background-color: var(--fds-semantic-surface-action-first-subtle-hover); +} + +.iconAndIdWrapper { + display: flex; + align-items: center; + gap: var(--fds-spacing-1); +} + +.textField { + width: 100%; +} + +.valueWrapper { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + background-color: transparent; + border: none; +} + +.pencilIcon { + color: var(--fds-semantic-text-action-first-default); +} diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx new file mode 100644 index 00000000000..a716d19c6fd --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx @@ -0,0 +1,50 @@ +import React, { useState } from 'react'; +import classes from './EditableTextField.module.css'; +import cn from 'classnames'; +import { Textfield, Divider, Heading, HelpText, Paragraph } from '@digdir/design-system-react'; +import { KeyVerticalIcon, PencilIcon } from '@studio/icons'; + +type EditableTextFieldProps = { + value: string; + onChange: (value: string) => void; + onLeaveTextField: () => void; + //label: string; +}; + +export const EditableTextField = ({ + value, + onChange, + onLeaveTextField, +}: EditableTextFieldProps): React.JSX.Element => { + const [isActive, setIsActive] = useState(false); + + const handleLeaveTextField = () => { + onLeaveTextField(); + setIsActive(false); + }; + + // Find out how to handle error + return ( +
+
+ + ID: +
+ {isActive ? ( + onChange(e.target.value)} + onBlur={handleLeaveTextField} + onMouseLeave={handleLeaveTextField} + /> + ) : ( + + )} +
+ ); +}; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts new file mode 100644 index 00000000000..fd961951526 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts @@ -0,0 +1 @@ +export { EditableTextField } from './EditableTextField'; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx index c242f083a97..046749902c9 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import classes from './PropertiesHeader.module.css'; import { Divider, Heading, HelpText, Paragraph } from '@digdir/design-system-react'; import { formItemConfigs } from '../../../data/formItemConfig'; @@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next'; import { useLayoutSchemaQuery } from '../../../hooks/queries/useLayoutSchemaQuery'; import { useComponentSchemaQuery } from '../../../hooks/queries/useComponentSchemaQuery'; import { DataModelBindingRow } from './DataModelBindingRow'; -import { KeyVerticalIcon } from '@studio/icons'; +import { EditableTextField } from './EditableTextField'; type PropertiesHeaderProps = { form: FormComponent; @@ -26,6 +26,8 @@ export const PropertiesHeader = ({ const { t } = useTranslation(); const itemTitle = useItemTitle(); + const [id, setId] = useState(formId); + const isUnknownInternalComponent: boolean = !formItemConfigs[form.type]; const Icon = isUnknownInternalComponent ? QuestionmarkDiamondIcon @@ -34,6 +36,10 @@ export const PropertiesHeader = ({ useLayoutSchemaQuery(); // Ensure we load the layout schemas so that component schemas can be loaded const { data: schema } = useComponentSchemaQuery(form.type); + const handleLeaveIdField = (newId: string) => { + handleComponentUpdate({ ...form, id: newId }); + }; + return (
@@ -51,8 +57,11 @@ export const PropertiesHeader = ({
{/* TODO - FIX Textfield / tekst komponent */} - - ID: {formId} + setId(value)} + onLeaveTextField={() => handleLeaveIdField(id)} + />
{schema && ( From 313dc9c37ca8202e816ef98cb6d48de871aad948 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Thu, 1 Feb 2024 17:23:59 +0100 Subject: [PATCH 06/12] Moving the content --- .../DataModelBindingRow.tsx | 4 +- .../DataModelBindingRow/index.ts | 1 + .../EditComponentIdRow.tsx} | 14 +++--- .../EditComponentIdRow/index.ts | 1 + .../EditableTextField.module.css | 34 ------------- .../EditableTextField/EditableTextField.tsx | 50 ------------------- .../EditableTextField/index.ts | 1 - .../PropertiesHeader.module.css | 3 -- .../PropertiesHeader/PropertiesHeader.tsx | 24 +++------ .../components/config/EditFormComponent.tsx | 2 - .../components/config/FormComponentConfig.tsx | 8 --- .../src/components/config/componentConfig.tsx | 2 - .../hooks/useItemTitle/useItemTitle.test.ts | 8 +-- 13 files changed, 21 insertions(+), 131 deletions(-) rename frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/{ => DataModelBindingRow}/DataModelBindingRow.tsx (87%) create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/index.ts rename frontend/packages/ux-editor/src/components/{config/editModal/EditComponentId.tsx => Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx} (81%) create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/index.ts delete mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css delete mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx delete mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx similarity index 87% rename from frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow.tsx rename to frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx index fe218990973..05df84b246e 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { EditDataModelBindings } from '../../config/editModal/EditDataModelBindings'; -import type { FormComponent } from '../../../types/FormComponent'; +import { EditDataModelBindings } from '../../../config/editModal/EditDataModelBindings'; +import type { FormComponent } from '../../../../types/FormComponent'; type DataModelBindingRowProps = { schema: any; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/index.ts b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/index.ts new file mode 100644 index 00000000000..9975575ae65 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/index.ts @@ -0,0 +1 @@ +export { DataModelBindingRow } from './DataModelBindingRow'; diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditComponentId.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx similarity index 81% rename from frontend/packages/ux-editor/src/components/config/editModal/EditComponentId.tsx rename to frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx index d1f79a55558..d08853d346b 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditComponentId.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx @@ -1,21 +1,21 @@ import React from 'react'; -import { idExists } from '../../../utils/formLayoutUtils'; +import { idExists } from '../../../../utils/formLayoutUtils'; import { useTranslation } from 'react-i18next'; -import { useSelectedFormLayout } from '../../../hooks'; -import type { FormComponent } from '../../../types/FormComponent'; -import { FormField } from '../../FormField'; +import { useSelectedFormLayout } from '../../../../hooks'; +import type { FormComponent } from '../../../../types/FormComponent'; +import { FormField } from '../../../FormField'; import { Textfield } from '@digdir/design-system-react'; -export interface IEditComponentId { +export interface EditComponentIdRowProps { handleComponentUpdate: (component: FormComponent) => void; component: FormComponent; helpText?: string; } -export const EditComponentId = ({ +export const EditComponentIdRow = ({ component, handleComponentUpdate, helpText, -}: IEditComponentId) => { +}: EditComponentIdRowProps) => { const { components, containers } = useSelectedFormLayout(); const { t } = useTranslation(); diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/index.ts b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/index.ts new file mode 100644 index 00000000000..e07b8bd9586 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/index.ts @@ -0,0 +1 @@ +export { EditComponentIdRow } from './EditComponentIdRow'; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css deleted file mode 100644 index 021a11ef35b..00000000000 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.module.css +++ /dev/null @@ -1,34 +0,0 @@ -.wrapper { - display: flex; - align-items: center; - gap: var(--fds-spacing-1); - height: var(--fds-spacing-8); - width: 100%; -} - -.wrapper:hover { - background-color: var(--fds-semantic-surface-action-first-subtle-hover); -} - -.iconAndIdWrapper { - display: flex; - align-items: center; - gap: var(--fds-spacing-1); -} - -.textField { - width: 100%; -} - -.valueWrapper { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - background-color: transparent; - border: none; -} - -.pencilIcon { - color: var(--fds-semantic-text-action-first-default); -} diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx deleted file mode 100644 index a716d19c6fd..00000000000 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/EditableTextField.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React, { useState } from 'react'; -import classes from './EditableTextField.module.css'; -import cn from 'classnames'; -import { Textfield, Divider, Heading, HelpText, Paragraph } from '@digdir/design-system-react'; -import { KeyVerticalIcon, PencilIcon } from '@studio/icons'; - -type EditableTextFieldProps = { - value: string; - onChange: (value: string) => void; - onLeaveTextField: () => void; - //label: string; -}; - -export const EditableTextField = ({ - value, - onChange, - onLeaveTextField, -}: EditableTextFieldProps): React.JSX.Element => { - const [isActive, setIsActive] = useState(false); - - const handleLeaveTextField = () => { - onLeaveTextField(); - setIsActive(false); - }; - - // Find out how to handle error - return ( -
-
- - ID: -
- {isActive ? ( - onChange(e.target.value)} - onBlur={handleLeaveTextField} - onMouseLeave={handleLeaveTextField} - /> - ) : ( - - )} -
- ); -}; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts deleted file mode 100644 index fd961951526..00000000000 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditableTextField/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { EditableTextField } from './EditableTextField'; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css index 802f93eae69..854e368f8c8 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.module.css @@ -1,6 +1,3 @@ -.wrapper { -} - .header { display: flex; justify-content: space-between; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx index 046749902c9..b5401bcea90 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -1,6 +1,6 @@ -import React, { useState } from 'react'; +import React from 'react'; import classes from './PropertiesHeader.module.css'; -import { Divider, Heading, HelpText, Paragraph } from '@digdir/design-system-react'; +import { Divider, Heading, HelpText } from '@digdir/design-system-react'; import { formItemConfigs } from '../../../data/formItemConfig'; import { QuestionmarkDiamondIcon } from '@studio/icons'; import type { FormComponent } from '../../../types/FormComponent'; @@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next'; import { useLayoutSchemaQuery } from '../../../hooks/queries/useLayoutSchemaQuery'; import { useComponentSchemaQuery } from '../../../hooks/queries/useComponentSchemaQuery'; import { DataModelBindingRow } from './DataModelBindingRow'; -import { EditableTextField } from './EditableTextField'; +import { EditComponentIdRow } from './EditComponentIdRow'; type PropertiesHeaderProps = { form: FormComponent; @@ -26,8 +26,6 @@ export const PropertiesHeader = ({ const { t } = useTranslation(); const itemTitle = useItemTitle(); - const [id, setId] = useState(formId); - const isUnknownInternalComponent: boolean = !formItemConfigs[form.type]; const Icon = isUnknownInternalComponent ? QuestionmarkDiamondIcon @@ -36,12 +34,8 @@ export const PropertiesHeader = ({ useLayoutSchemaQuery(); // Ensure we load the layout schemas so that component schemas can be loaded const { data: schema } = useComponentSchemaQuery(form.type); - const handleLeaveIdField = (newId: string) => { - handleComponentUpdate({ ...form, id: newId }); - }; - return ( -
+ <>
{Icon && } @@ -56,16 +50,10 @@ export const PropertiesHeader = ({
- {/* TODO - FIX Textfield / tekst komponent */} - setId(value)} - onLeaveTextField={() => handleLeaveIdField(id)} - /> +
{schema && ( - // TODO - Change the design of the datamodel
-
+ ); }; diff --git a/frontend/packages/ux-editor/src/components/config/EditFormComponent.tsx b/frontend/packages/ux-editor/src/components/config/EditFormComponent.tsx index 8dd32ed7128..ea6dacd95db 100644 --- a/frontend/packages/ux-editor/src/components/config/EditFormComponent.tsx +++ b/frontend/packages/ux-editor/src/components/config/EditFormComponent.tsx @@ -10,7 +10,6 @@ import { selectedLayoutNameSelector } from '../../selectors/formLayoutSelectors' import { useComponentSchemaQuery } from '../../hooks/queries/useComponentSchemaQuery'; import { StudioSpinner } from '@studio/components'; import { FormComponentConfig } from './FormComponentConfig'; -import { EditComponentId } from './editModal/EditComponentId'; import { useLayoutSchemaQuery } from '../../hooks/queries/useLayoutSchemaQuery'; import { useSelector } from 'react-redux'; import { getComponentTitleByComponentType } from '../../utils/language'; @@ -106,7 +105,6 @@ export const EditFormComponent = ({ )} {!showComponentConfigBeta && ( <> - {renderFromComponentSpecificDefinition(getConfigDefinitionForComponent())} - {id && ( - - )} {textResourceBindings?.properties && ( <> diff --git a/frontend/packages/ux-editor/src/components/config/componentConfig.tsx b/frontend/packages/ux-editor/src/components/config/componentConfig.tsx index b3c62acfa6a..3be1eb8f9ab 100644 --- a/frontend/packages/ux-editor/src/components/config/componentConfig.tsx +++ b/frontend/packages/ux-editor/src/components/config/componentConfig.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { ComponentType } from 'app-shared/types/ComponentType'; import { EditCodeList } from './editModal/EditCodeList'; -import { EditDataModelBindings } from './editModal/EditDataModelBindings'; import { EditHeaderSize } from './editModal/EditHeaderSize'; import { EditOptions } from './editModal/EditOptions'; import { EditPreselectedIndex } from './editModal/EditPreselectedIndex'; @@ -87,7 +86,6 @@ export const componentSpecificEditConfig: IComponentEditConfig = { }; export const configComponents: IConfigComponents = { - [EditSettings.DataModelBindings]: EditDataModelBindings, [EditSettings.Size]: EditHeaderSize, [EditSettings.Title]: ({ component, handleComponentChange }: IGenericEditComponent) => ( Date: Thu, 1 Feb 2024 17:27:12 +0100 Subject: [PATCH 07/12] deleting console.log --- .../packages/ux-editor/src/components/Properties/Content.tsx | 1 - .../packages/ux-editor/src/components/Properties/Properties.tsx | 2 -- 2 files changed, 3 deletions(-) diff --git a/frontend/packages/ux-editor/src/components/Properties/Content.tsx b/frontend/packages/ux-editor/src/components/Properties/Content.tsx index 860a0d91856..396a8c59056 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Content.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Content.tsx @@ -11,7 +11,6 @@ import { isContainer } from '../../utils/formItemUtils'; export const Content = () => { const { formId, form, handleUpdate, debounceSave } = useFormContext(); - console.log('FORM', form); const editId = useSelector(getCurrentEditId); const { t } = useTranslation(); diff --git a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx index f7573e4fed9..996cfd65c7d 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Properties.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Properties.tsx @@ -31,8 +31,6 @@ export const Properties = () => { } }; - console.log('hei'); - return (
{form && !isContainer(form) && ( From 52be9debaa191c562a3425a8e922a6ac6c15e617 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Thu, 1 Feb 2024 17:52:28 +0100 Subject: [PATCH 08/12] removing broken tests --- .../components/Properties/Content.test.tsx | 27 ------------------- .../src/components/Properties/Content.tsx | 1 - .../PropertiesHeader/PropertiesHeader.tsx | 2 +- .../config/EditFormComponent.test.tsx | 15 ----------- .../config/FormComponentConfig.test.tsx | 3 --- 5 files changed, 1 insertion(+), 47 deletions(-) diff --git a/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx b/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx index aabed980cfd..af0847bbe50 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx @@ -60,33 +60,6 @@ describe('ContentTab', () => { expect(formContextProviderMock.debounceSave).toHaveBeenCalledTimes(4); }); }); - - describe('when editing a component', () => { - const props = { - formId: component1IdMock, - form: { ...component1Mock, dataModelBindings: {} }, - }; - - it('should render the component', async () => { - jest.spyOn(console, 'error').mockImplementation(); // Silence error from Select component - await render({ props }); - expect( - screen.getByText(textMock('ux_editor.modal_properties_component_change_id')), - ).toBeInTheDocument(); - }); - - it('should auto-save when updating a field', async () => { - await render({ props }); - - const idInput = screen.getByLabelText( - textMock('ux_editor.modal_properties_component_change_id'), - ); - await act(() => user.type(idInput, 'test')); - - expect(formContextProviderMock.handleUpdate).toHaveBeenCalledTimes(4); - expect(formContextProviderMock.debounceSave).toHaveBeenCalledTimes(4); - }); - }); }); const waitForData = async () => { diff --git a/frontend/packages/ux-editor/src/components/Properties/Content.tsx b/frontend/packages/ux-editor/src/components/Properties/Content.tsx index 396a8c59056..32744d080dd 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Content.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Content.tsx @@ -10,7 +10,6 @@ import { isContainer } from '../../utils/formItemUtils'; export const Content = () => { const { formId, form, handleUpdate, debounceSave } = useFormContext(); - const editId = useSelector(getCurrentEditId); const { t } = useTranslation(); diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx index b5401bcea90..7d9eaff29e6 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -12,7 +12,7 @@ import { useComponentSchemaQuery } from '../../../hooks/queries/useComponentSche import { DataModelBindingRow } from './DataModelBindingRow'; import { EditComponentIdRow } from './EditComponentIdRow'; -type PropertiesHeaderProps = { +export type PropertiesHeaderProps = { form: FormComponent; formId: string; handleComponentUpdate: (component: FormComponent) => void; diff --git a/frontend/packages/ux-editor/src/components/config/EditFormComponent.test.tsx b/frontend/packages/ux-editor/src/components/config/EditFormComponent.test.tsx index 969a11680a1..adc3f1b788c 100644 --- a/frontend/packages/ux-editor/src/components/config/EditFormComponent.test.tsx +++ b/frontend/packages/ux-editor/src/components/config/EditFormComponent.test.tsx @@ -89,19 +89,6 @@ describe('EditFormComponent', () => { }, }); - const labels = { - 'ux_editor.modal_properties_component_change_id': 'textbox', - 'ux_editor.modal_properties_data_model_helper': 'combobox', - 'ux_editor.modal_configure_read_only': 'checkbox', - }; - - const linkIcon = screen.getByText(/ux_editor.modal_properties_data_model_link/i); - await act(() => user.click(linkIcon)); - - Object.keys(labels).map(async (label) => - expect(await screen.findByRole(labels[label], { name: label })), - ); - expect(screen.getByRole('combobox')); expect(screen.getByLabelText('Autocomplete (WCAG)')); }); @@ -112,7 +99,6 @@ describe('EditFormComponent', () => { }, }); - expect(screen.getByLabelText('ux_editor.modal_properties_component_change_id')); await waitFor(() => expect(screen.getByRole('combobox', { name: 'ux_editor.modal_header_type_helper' })), ); @@ -126,7 +112,6 @@ describe('EditFormComponent', () => { }); const labels = [ - 'ux_editor.modal_properties_component_change_id', 'ux_editor.modal_properties_file_upload_simple', 'ux_editor.modal_properties_file_upload_list', 'ux_editor.modal_properties_valid_file_endings_all', diff --git a/frontend/packages/ux-editor/src/components/config/FormComponentConfig.test.tsx b/frontend/packages/ux-editor/src/components/config/FormComponentConfig.test.tsx index d6dc6aa6174..65a9e3c7ffc 100644 --- a/frontend/packages/ux-editor/src/components/config/FormComponentConfig.test.tsx +++ b/frontend/packages/ux-editor/src/components/config/FormComponentConfig.test.tsx @@ -11,9 +11,6 @@ import { textMock } from '../../../../../testing/mocks/i18nMock'; describe('FormComponentConfig', () => { it('should render expected components', async () => { render({}); - expect( - screen.getByText(textMock('ux_editor.modal_properties_component_change_id')), - ).toBeInTheDocument(); ['title', 'description', 'help'].forEach(async (key) => { expect( screen.getByText(textMock(`ux_editor.modal_properties_textResourceBindings_${key}`)), From 14ebacc6fc523da0ad0a9f1432de4a030d40524f Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Fri, 2 Feb 2024 13:30:22 +0100 Subject: [PATCH 09/12] adding one test --- .../components/Properties/Content.test.tsx | 7 +-- .../components/Properties/Properties.test.tsx | 61 ++++++++++++++----- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx b/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx index af0847bbe50..e7f015c9c2f 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx @@ -4,12 +4,7 @@ import { act, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { textMock } from '../../../../../testing/mocks/i18nMock'; import { FormContext } from '../../containers/FormContext'; -import { - component1IdMock, - component1Mock, - container1IdMock, - layoutMock, -} from '../../testing/layoutMock'; +import { container1IdMock, layoutMock } from '../../testing/layoutMock'; import type { IAppDataState } from '../../features/appData/appDataReducers'; import type { ITextResourcesState } from '../../features/appData/textResources/textResourcesSlice'; import { renderWithMockStore, renderHookWithMockStore } from '../../testing/mocks'; diff --git a/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx b/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx index 57bbe9cd464..ec2898d6386 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { Properties } from './Properties'; -import { render as rtlRender, act, screen, waitFor } from '@testing-library/react'; +import { act, screen, waitFor } from '@testing-library/react'; import { mockUseTranslation } from '../../../../../testing/mocks/i18nMock'; import { FormContext } from '../../containers/FormContext'; import userEvent from '@testing-library/user-event'; import { formContextProviderMock } from '../../testing/formContextMocks'; - -const user = userEvent.setup(); +import { component1Mock, component1IdMock } from '../../testing/layoutMock'; +import { renderWithProviders } from '../../testing/mocks'; // Test data: const contentText = 'Innhold'; @@ -39,15 +39,44 @@ jest.mock('./Calculations', () => ({ jest.mock('react-i18next', () => ({ useTranslation: () => mockUseTranslation(texts) })); describe('Properties', () => { + describe('Default config', () => { + it('hides the properties header when the form is undefined', () => { + renderProperties({ form: undefined }); + + const heading = screen.queryByRole('heading', { level: 2 }); + expect(heading).not.toBeInTheDocument(); + }); + + it('saves the component when changes are made in the properties header', async () => { + const user = userEvent.setup(); + renderProperties({ form: component1Mock, formId: component1IdMock }); + + const heading = screen.getByRole('heading', { + name: component1Mock.type, + level: 2, + }); + expect(heading).toBeInTheDocument(); + + const textbox = screen.getByRole('textbox', { + name: 'ux_editor.modal_properties_component_change_id', + }); + + await act(() => user.type(textbox, '2')); + expect(formContextProviderMock.handleUpdate).toHaveBeenCalledTimes(1); + expect(formContextProviderMock.debounceSave).toHaveBeenCalledTimes(1); + }); + }); + describe('Content', () => { it('Closes content on load', () => { - render(); + renderProperties(); const button = screen.queryByRole('button', { name: contentText }); expect(button).toHaveAttribute('aria-expanded', 'false'); }); it('Toggles content when clicked', async () => { - render(); + const user = userEvent.setup(); + renderProperties(); const button = screen.queryByRole('button', { name: contentText }); await act(() => user.click(button)); expect(button).toHaveAttribute('aria-expanded', 'true'); @@ -56,7 +85,7 @@ describe('Properties', () => { }); it('Opens content when a component is selected', async () => { - const { rerender } = render(); + const { rerender } = renderProperties(); rerender(getComponent({ formId: 'test' })); const button = screen.queryByRole('button', { name: contentText }); await waitFor(() => expect(button).toHaveAttribute('aria-expanded', 'true')); @@ -65,13 +94,14 @@ describe('Properties', () => { describe('Dynamics', () => { it('Closes dynamics on load', () => { - render(); + renderProperties(); const button = screen.queryByRole('button', { name: dynamicsText }); expect(button).toHaveAttribute('aria-expanded', 'false'); }); it('Toggles dynamics when clicked', async () => { - render(); + const user = userEvent.setup(); + renderProperties(); const button = screen.queryByRole('button', { name: dynamicsText }); await act(() => user.click(button)); expect(button).toHaveAttribute('aria-expanded', 'true'); @@ -80,7 +110,8 @@ describe('Properties', () => { }); it('Shows new dynamics by default', async () => { - const { rerender } = render(); + const user = userEvent.setup(); + const { rerender } = renderProperties(); rerender(getComponent({ formId: 'test' })); const dynamicsButton = screen.queryByRole('button', { name: dynamicsText }); await act(() => user.click(dynamicsButton)); @@ -91,13 +122,14 @@ describe('Properties', () => { describe('Calculations', () => { it('Closes calculations on load', () => { - render(); + renderProperties(); const button = screen.queryByRole('button', { name: calculationsText }); expect(button).toHaveAttribute('aria-expanded', 'false'); }); it('Toggles calculations when clicked', async () => { - render(); + const user = userEvent.setup(); + renderProperties(); const button = screen.queryByRole('button', { name: calculationsText }); await act(() => user.click(button)); expect(button).toHaveAttribute('aria-expanded', 'true'); @@ -108,7 +140,7 @@ describe('Properties', () => { it('Renders accordion', () => { const formIdMock = 'test-id'; - render({ formId: formIdMock }); + renderProperties({ formId: formIdMock }); expect(screen.getByText(contentText)).toBeInTheDocument(); expect(screen.getByText(dynamicsText)).toBeInTheDocument(); expect(screen.getByText(calculationsText)).toBeInTheDocument(); @@ -129,5 +161,6 @@ const getComponent = (formContextProps: Partial = {}) => ( ); -const render = (formContextProps: Partial = {}) => - rtlRender(getComponent(formContextProps)); +const renderProperties = (formContextProps: Partial = {}) => + renderWithProviders(getComponent(formContextProps)); +// render(getComponent(formContextProps)); From c3ef69689aa052cb6c3994620c0b63e1f684e22c Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Mon, 5 Feb 2024 08:35:43 +0100 Subject: [PATCH 10/12] adding properties header tests --- frontend/app-development/router/routes.tsx | 3 +- frontend/language/src/nb.json | 1 + .../components/Properties/Properties.test.tsx | 1 - .../PropertiesHeader.test.tsx | 75 +++++++++++++++++++ .../PropertiesHeader/PropertiesHeader.tsx | 10 +-- 5 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx diff --git a/frontend/app-development/router/routes.tsx b/frontend/app-development/router/routes.tsx index a53f0659f67..ddcc5d9162d 100644 --- a/frontend/app-development/router/routes.tsx +++ b/frontend/app-development/router/routes.tsx @@ -37,7 +37,8 @@ const isLatestFrontendVersion = (version: AppVersion): boolean => const UiEditor = () => { const { org, app } = useStudioUrlParams(); const { data } = useAppVersionQuery(org, app); - return isLatestFrontendVersion(data) ? : ; + //return isLatestFrontendVersion(data) ? : ; + return ; }; export const routerRoutes: RouterRoute[] = [ diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 81f83324557..7042870fa22 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -1378,6 +1378,7 @@ "ux_editor.component_help_text.Summary": "Komponent som viser informasjon som oppsummering. Brukes ofte på slutten av et skjema for å vise brukeren hva som er fylt ut.", "ux_editor.component_help_text.TextArea": "Stort tekstfelt benyttes når brukeren skal fylle inn en lengre beskrivelse.", "ux_editor.component_help_text.default": "Mer informasjon om denne komponenten vil komme på et senere tidspunkt.", + "ux_editor.component_help_text_general_title": "Åpne hjelpetekst for komponenten", "ux_editor.component_properties.action": "Aksjon", "ux_editor.component_properties.align": "Plassering*", "ux_editor.component_properties.attribution": "Opphav", diff --git a/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx b/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx index ec2898d6386..e67b3f8c01a 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Properties.test.tsx @@ -163,4 +163,3 @@ const getComponent = (formContextProps: Partial = {}) => ( const renderProperties = (formContextProps: Partial = {}) => renderWithProviders(getComponent(formContextProps)); -// render(getComponent(formContextProps)); diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx new file mode 100644 index 00000000000..cebcee0fb49 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { act, screen } from '@testing-library/react'; +import { PropertiesHeader, type PropertiesHeaderProps } from './PropertiesHeader'; +import { FormContext } from '../../../containers/FormContext'; +import userEvent from '@testing-library/user-event'; +import { formContextProviderMock } from '../../../testing/formContextMocks'; +import { component1Mock, component1IdMock } from '../../../testing/layoutMock'; +import { renderWithProviders } from '../../../testing/mocks'; +import { textMock } from '../../../../../../testing/mocks/i18nMock'; + +const mockHandleComponentUpdate = jest.fn(); + +const defaultProps: PropertiesHeaderProps = { + form: component1Mock, + formId: component1IdMock, + handleComponentUpdate: mockHandleComponentUpdate, +}; + +describe('PropertiesHeader Component', () => { + afterEach(jest.clearAllMocks); + + it('renders the header name for the component', () => { + renderProperties({ form: component1Mock, formId: component1IdMock }); + + const heading = screen.getByRole('heading', { + name: textMock(`ux_editor.component_title.${component1Mock.type}`), + level: 2, + }); + expect(heading).toBeInTheDocument(); + }); + + it('displays the help text when the help text button is clicked', async () => { + const user = userEvent.setup(); + renderProperties({ form: component1Mock, formId: component1IdMock }); + + const helpTextButton = screen.getByRole('button', { + name: textMock('ux_editor.component_help_text_general_title'), + }); + + expect( + screen.queryByText(textMock(`ux_editor.component_help_text.${component1Mock.type}`)), + ).not.toBeInTheDocument(); + + await act(() => user.click(helpTextButton)); + + expect( + screen.getByText(textMock(`ux_editor.component_help_text.${component1Mock.type}`)), + ).toBeInTheDocument(); + }); + + it('calls "handleComponentUpdate" when the id changes', async () => { + const user = userEvent.setup(); + renderProperties({ form: component1Mock, formId: component1IdMock }); + + const textbox = screen.getByRole('textbox', { + name: textMock('ux_editor.modal_properties_component_change_id'), + }); + + await act(() => user.type(textbox, '2')); + expect(mockHandleComponentUpdate).toHaveBeenCalledTimes(1); + }); +}); + +const renderProperties = (formContextProps: Partial = {}) => { + return renderWithProviders( + + + , + ); +}; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx index 7d9eaff29e6..2a01811d4fc 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.tsx @@ -43,7 +43,7 @@ export const PropertiesHeader = ({ {itemTitle(form)}
- + {getComponentHelperTextByComponentType(form.type, t)}
@@ -52,16 +52,16 @@ export const PropertiesHeader = ({
-
- {schema && ( + {schema && ( +
- )} -
+
+ )}
); From 91dfb9a75b2d91a184e8e5cfe42d569fff265ddf Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Mon, 5 Feb 2024 08:58:38 +0100 Subject: [PATCH 11/12] writing more tests --- frontend/app-development/router/routes.tsx | 3 +- .../DataModelBindingRow.test.tsx | 101 ++++++++++++++++++ .../DataModelBindingRow.tsx | 2 +- .../PropertiesHeader.test.tsx | 2 +- 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.test.tsx diff --git a/frontend/app-development/router/routes.tsx b/frontend/app-development/router/routes.tsx index ddcc5d9162d..a53f0659f67 100644 --- a/frontend/app-development/router/routes.tsx +++ b/frontend/app-development/router/routes.tsx @@ -37,8 +37,7 @@ const isLatestFrontendVersion = (version: AppVersion): boolean => const UiEditor = () => { const { org, app } = useStudioUrlParams(); const { data } = useAppVersionQuery(org, app); - //return isLatestFrontendVersion(data) ? : ; - return ; + return isLatestFrontendVersion(data) ? : ; }; export const routerRoutes: RouterRoute[] = [ diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.test.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.test.tsx new file mode 100644 index 00000000000..0523b4e6336 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.test.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import { act, screen } from '@testing-library/react'; +import { DataModelBindingRow, type DataModelBindingRowProps } from './DataModelBindingRow'; +import { FormContext } from '../../../../containers/FormContext'; +import userEvent from '@testing-library/user-event'; +import { formContextProviderMock } from '../../../../testing/formContextMocks'; +import { component1Mock, component1IdMock } from '../../../../testing/layoutMock'; +import { renderWithProviders } from '../../../../testing/mocks'; +import { textMock } from '../../../../../../../testing/mocks/i18nMock'; + +const mockSchema = { + properties: { + dataModelBindings: { + properties: { + simpleBinding: { + description: 'Description for simpleBinding', + }, + }, + }, + }, +}; + +const mockSchemaUndefined = { + properties: { + dataModelBindings: { + properties: undefined, + }, + }, +}; + +const mockHandleComponentUpdate = jest.fn(); + +const defaultProps: DataModelBindingRowProps = { + schema: mockSchema, + component: component1Mock, + formId: component1IdMock, + handleComponentUpdate: mockHandleComponentUpdate, +}; + +describe('DataModelBindingRow', () => { + afterEach(jest.clearAllMocks); + + it('renders EditDataModelBindings component when schema is present', () => { + renderProperties({ form: component1Mock, formId: component1IdMock }); + + const datamodelButton = screen.getByRole('button', { + name: textMock('ux_editor.modal_properties_data_model_link'), + }); + expect(datamodelButton).toBeInTheDocument(); + }); + + it('does not render EditDataModelBindings component when schema.properties is undefined', () => { + renderProperties( + { form: component1Mock, formId: component1IdMock }, + { schema: mockSchemaUndefined }, + ); + + const datamodelButton = screen.queryByRole('button', { + name: textMock('ux_editor.modal_properties_data_model_link'), + }); + expect(datamodelButton).not.toBeInTheDocument(); + }); + + it('calls handleComponentUpdate when EditDataModelBindings component is updated', async () => { + const user = userEvent.setup(); + renderProperties({ form: component1Mock, formId: component1IdMock }); + + const datamodelButton = screen.getByRole('button', { + name: textMock('ux_editor.modal_properties_data_model_link'), + }); + expect( + screen.queryByRole('button', { name: textMock('general.delete') }), + ).not.toBeInTheDocument(); + + await act(() => user.click(datamodelButton)); + + const deleteButton = screen.getByRole('button', { + name: textMock('general.delete'), + }); + expect(deleteButton).toBeInTheDocument(); + + await act(() => user.click(deleteButton)); + expect(mockHandleComponentUpdate).toHaveBeenCalledTimes(1); + }); +}); + +const renderProperties = ( + formContextProps: Partial = {}, + props: Partial = {}, +) => { + return renderWithProviders( + + + , + ); +}; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx index 05df84b246e..c718894159f 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { EditDataModelBindings } from '../../../config/editModal/EditDataModelBindings'; import type { FormComponent } from '../../../../types/FormComponent'; -type DataModelBindingRowProps = { +export type DataModelBindingRowProps = { schema: any; component: FormComponent; formId: string; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx index cebcee0fb49..beb520ff606 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/PropertiesHeader.test.tsx @@ -16,7 +16,7 @@ const defaultProps: PropertiesHeaderProps = { handleComponentUpdate: mockHandleComponentUpdate, }; -describe('PropertiesHeader Component', () => { +describe('PropertiesHeader', () => { afterEach(jest.clearAllMocks); it('renders the header name for the component', () => { From 4e58765e74b142c8bc880484ba12556f9a1a0335 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt Date: Fri, 9 Feb 2024 08:55:24 +0100 Subject: [PATCH 12/12] fixing feecback from PR --- .../DataModelBindingRow/DataModelBindingRow.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx index c718894159f..860e68a935f 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/DataModelBindingRow/DataModelBindingRow.tsx @@ -20,7 +20,7 @@ export const DataModelBindingRow = ({ return ( dataModelBindings?.properties && ( <> - {Object.keys(dataModelBindings?.properties).map((propertyKey: any) => { + {Object.keys(dataModelBindings?.properties).map((propertyKey: string) => { return (