From fc539da55d5f3dcc5190bb4c8a71acb2c0211bfa Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Sun, 13 Oct 2024 12:02:30 +0200 Subject: [PATCH 01/22] Align datamodel heading and schemaInspector tabs --- .../HeadingRow/HeadingRow.module.css | 3 +++ .../components/NodePanel/NodePanel.module.css | 4 --- .../src/components/NodePanel/NodePanel.tsx | 2 +- .../components/SchemaEditor/SchemaEditor.tsx | 4 +-- .../SchemaInspector.module.css | 19 ++++++++++---- .../SchemaInspector/SchemaInspector.tsx | 26 +++++++++++++------ 6 files changed, 38 insertions(+), 20 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css index b0c067040c8..4acedf957e7 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css @@ -1,5 +1,8 @@ .root { --gap: var(--fds-spacing-1); + height: var(--subtoolbar-height); + box-sizing: border-box; + box-shadow: var(--fds-shadow-small); align-items: center; display: flex; padding: var(--gap) 0; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css index 1f8384e8b2b..1bc72e07643 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css @@ -1,7 +1,3 @@ -.top { - box-shadow: var(--fds-shadow-small); -} - .backButton { background-color: var(--fds-semantic-surface-action-subtle); border: none; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx index 918c678d557..e746f1be991 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx @@ -21,7 +21,7 @@ export const NodePanel = ({ schemaPointer }: NodePanelProps) => { return ( <> -
+
{!isDataModelRoot && }
diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx index 6b287d5be74..7c7b69acf67 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx @@ -35,7 +35,7 @@ export const SchemaEditor = () => { orientation='horizontal' localStorageContext={`datamodel:${user.id}:${org}`} > - + @@ -51,7 +51,7 @@ export const SchemaEditor = () => { collapsedSize={180} > diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css index fe4a1c6dbde..68c268e5d1b 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css @@ -8,6 +8,20 @@ width: 150px; } +.noItem { + font-weight: 500; + padding-inline: var(--fds-spacing-4); +} + +.tabHeader { + height: var(--subtoolbar-height); + font-size: var(--fds-typography-heading-small); +} + +.tabHeaderExtraMargin { + margin-top: var(--fds-sizing-6); +} + .header { font-size: 16px; font-weight: 400; @@ -19,8 +33,3 @@ .header :global(.Mui-focusVisible) { background: gray; } - -.noItem { - font-weight: 500; - margin: 18px; -} diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx index 9480c520805..d857b792051 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx @@ -1,37 +1,47 @@ -import React from 'react'; +import React, { ReactElement } from 'react'; import { Alert, Tabs } from '@digdir/designsystemet-react'; import type { UiSchemaNode } from '@altinn/schema-model'; import { isField, isObject } from '@altinn/schema-model'; import { ItemPropertiesTab } from './ItemPropertiesTab'; import { ItemFieldsTab } from './ItemFieldsTab'; import classes from './SchemaInspector.module.css'; -import { Divider } from 'app-shared/primitives'; import { useTranslation } from 'react-i18next'; import { useSchemaEditorAppContext } from '../../hooks/useSchemaEditorAppContext'; import { useSavableSchemaModel } from '../../hooks/useSavableSchemaModel'; +import cn from 'classnames'; -export const SchemaInspector = () => { +type SchemaInspectorProps = { + isDataModelRoot: boolean; +}; + +export const SchemaInspector = ({ isDataModelRoot }: SchemaInspectorProps): ReactElement => { const { t } = useTranslation(); const { selectedUniquePointer } = useSchemaEditorAppContext(); const savableModel = useSavableSchemaModel(); if (!selectedUniquePointer) { return ( -
-

{t('schema_editor.no_item_selected')}

- +
+

{t('schema_editor.no_item_selected')}

); } const selectedItem: UiSchemaNode = savableModel.getNodeByUniquePointer(selectedUniquePointer); const shouldDisplayFieldsTab = isField(selectedItem) && isObject(selectedItem); + const tabClass = isDataModelRoot + ? classes.tabHeader + : cn(classes.tabHeader, classes.tabHeaderExtraMargin); return ( - {t('schema_editor.properties')} - {t('schema_editor.fields')} + + {t('schema_editor.properties')} + + + {t('schema_editor.fields')} + From 21258a0263020432c6e9af6d0b866f3aa22ad988 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Sun, 13 Oct 2024 13:53:10 +0200 Subject: [PATCH 02/22] Add separate heading and text content when no data model fields are selected --- .../src/components/SchemaEditor/SchemaEditor.tsx | 10 +++------- .../SchemaInspector/SchemaInspector.module.css | 16 ++++++++++++++-- .../SchemaInspector/SchemaInspector.tsx | 12 +++++++++--- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx index 7c7b69acf67..6f14682447c 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx @@ -35,21 +35,17 @@ export const SchemaEditor = () => { orientation='horizontal' localStorageContext={`datamodel:${user.id}:${org}`} > - + - +
- + diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css index 68c268e5d1b..8152e95c154 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css @@ -8,9 +8,21 @@ width: 150px; } -.noItem { - font-weight: 500; +.noItemHeadingWrapper { + display: flex; + flex-direction: column; + justify-content: center; padding-inline: var(--fds-spacing-4); + height: var(--subtoolbar-height); + border-bottom: 1px solid lightgray; +} + +.noItemTextWrapper { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; } .tabHeader { diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx index d857b792051..faf87a0dfa3 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx @@ -8,6 +8,7 @@ import classes from './SchemaInspector.module.css'; import { useTranslation } from 'react-i18next'; import { useSchemaEditorAppContext } from '../../hooks/useSchemaEditorAppContext'; import { useSavableSchemaModel } from '../../hooks/useSavableSchemaModel'; +import { StudioHeading, StudioParagraph } from '@studio/components'; import cn from 'classnames'; type SchemaInspectorProps = { @@ -21,9 +22,14 @@ export const SchemaInspector = ({ isDataModelRoot }: SchemaInspectorProps): Reac if (!selectedUniquePointer) { return ( -
-

{t('schema_editor.no_item_selected')}

-
+ <> +
+ {t('schema_editor.properties')} +
+
+ {t('schema_editor.no_item_selected')} +
+ ); } From a4917a273549c1c6b7dfe12a9f61dbb7e94bd76a Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Sun, 13 Oct 2024 16:29:06 +0200 Subject: [PATCH 03/22] Align TypesInspector heading with the other headings --- .../HeadingRow/HeadingRow.module.css | 1 - .../components/NodePanel/NodePanel.module.css | 4 +++ .../src/components/NodePanel/NodePanel.tsx | 4 +-- .../components/SchemaEditor/SchemaEditor.tsx | 2 +- .../SchemaInspector.module.css | 23 ++-------------- .../SchemaInspector/SchemaInspector.tsx | 26 +++++++------------ .../TypesInspector/TypesInspector.module.css | 23 +++++----------- .../TypesInspector/TypesInspector.tsx | 15 ++--------- 8 files changed, 28 insertions(+), 70 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css index 4acedf957e7..3f0081bc093 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css @@ -2,7 +2,6 @@ --gap: var(--fds-spacing-1); height: var(--subtoolbar-height); box-sizing: border-box; - box-shadow: var(--fds-shadow-small); align-items: center; display: flex; padding: var(--gap) 0; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css index 1bc72e07643..1f8384e8b2b 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css @@ -1,3 +1,7 @@ +.top { + box-shadow: var(--fds-shadow-small); +} + .backButton { background-color: var(--fds-semantic-surface-action-subtle); border: none; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx index e746f1be991..b2bed63e68e 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx @@ -21,9 +21,9 @@ export const NodePanel = ({ schemaPointer }: NodePanelProps) => { return ( <> -
- {!isDataModelRoot && } +
+ {!isDataModelRoot && }
{isNodeValidParent(node) && } diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx index 6f14682447c..4a9946290c9 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx @@ -47,7 +47,7 @@ export const SchemaEditor = () => { diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css index 8152e95c154..33b4dab618b 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css @@ -14,15 +14,7 @@ justify-content: center; padding-inline: var(--fds-spacing-4); height: var(--subtoolbar-height); - border-bottom: 1px solid lightgray; -} - -.noItemTextWrapper { - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } .tabHeader { @@ -30,18 +22,7 @@ font-size: var(--fds-typography-heading-small); } -.tabHeaderExtraMargin { - margin-top: var(--fds-sizing-6); -} - -.header { - font-size: 16px; - font-weight: 400; - margin-bottom: 6px; - margin-top: 24px; - padding: 0; -} - +/* Should this be deleted? */ .header :global(.Mui-focusVisible) { background: gray; } diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx index faf87a0dfa3..e00c14b7e3a 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx @@ -8,14 +8,9 @@ import classes from './SchemaInspector.module.css'; import { useTranslation } from 'react-i18next'; import { useSchemaEditorAppContext } from '../../hooks/useSchemaEditorAppContext'; import { useSavableSchemaModel } from '../../hooks/useSavableSchemaModel'; -import { StudioHeading, StudioParagraph } from '@studio/components'; -import cn from 'classnames'; +import { StudioCenter, StudioHeading, StudioParagraph } from '@studio/components'; -type SchemaInspectorProps = { - isDataModelRoot: boolean; -}; - -export const SchemaInspector = ({ isDataModelRoot }: SchemaInspectorProps): ReactElement => { +export const SchemaInspector = (): ReactElement => { const { t } = useTranslation(); const { selectedUniquePointer } = useSchemaEditorAppContext(); const savableModel = useSavableSchemaModel(); @@ -26,26 +21,23 @@ export const SchemaInspector = ({ isDataModelRoot }: SchemaInspectorProps): Reac
{t('schema_editor.properties')}
-
+ {t('schema_editor.no_item_selected')} -
+ ); } const selectedItem: UiSchemaNode = savableModel.getNodeByUniquePointer(selectedUniquePointer); const shouldDisplayFieldsTab = isField(selectedItem) && isObject(selectedItem); - const tabClass = isDataModelRoot - ? classes.tabHeader - : cn(classes.tabHeader, classes.tabHeaderExtraMargin); return ( - + - + {t('schema_editor.properties')} - + {t('schema_editor.fields')} @@ -57,7 +49,9 @@ export const SchemaInspector = ({ isDataModelRoot }: SchemaInspectorProps): Reac ) : ( - {t('app_data_modelling.fields_information')} + + {t('app_data_modelling.fields_information')} + )} ); diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css index 4456910f3d4..5f299a9ecf0 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css @@ -1,6 +1,7 @@ .root { box-sizing: border-box; - padding: 24px 24px; + padding-inline: var(--fds-spacing-6); + padding-bottom: var(--fds-spacing-6); min-height: 100%; background: rgba(224, 224, 224, 0.3); border-right: 1px solid var(--fds-semantic-border-neutral-subtle); @@ -10,18 +11,19 @@ display: flex; flex-direction: column; align-items: stretch; - gap: 8px; + gap: var(--fds-spacing-2); } .addRow { display: grid; grid-template-columns: repeat(3, 1fr); align-items: center; + height: var(--subtoolbar-height); } .addRowText { grid-column: 1 / 3; - font-size: 18px; + font-size: var(--fds-font-size-f0); } .addRowButton { @@ -31,23 +33,12 @@ color: #000000; } +/* Should this be deleted? */ .root :global(.MuiAutocomplete-input) { width: 150px; } -.header { - font-size: 16px; - font-weight: 400; - margin-bottom: 6px; - margin-top: 24px; - padding: 0; -} - +/* Should this be deleted? */ .header :global(.Mui-focusVisible) { background: gray; } - -.noItem { - font-weight: 500; - margin: 18px; -} diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index 54e6a29226d..4d6b0574b59 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -1,6 +1,6 @@ import type { MouseEvent } from 'react'; import React from 'react'; -import { StudioButton } from '@studio/components'; +import { StudioButton, StudioHeading } from '@studio/components'; import { PlusIcon } from '@studio/icons'; import type { UiSchemaNode } from '@altinn/schema-model'; import { SchemaModel } from '@altinn/schema-model'; @@ -38,22 +38,11 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { save(schemaModel); }; - if (!schemaItems) { - return ( -
-

- {t('schema_editor.no_item_selected')} -

- -
- ); - } - return (
- {t('schema_editor.types')} + {t('schema_editor.types')} Date: Sun, 13 Oct 2024 20:12:08 +0200 Subject: [PATCH 04/22] Create border below headings for types, datamodel and properties --- .../components/NodePanel/NodePanel.module.css | 2 +- .../components/SchemaEditor/SchemaEditor.tsx | 2 +- .../SchemaInspector.module.css | 2 +- .../TypesInspector/TypesInspector.module.css | 25 ++++++++++--------- .../TypesInspector/TypesInspector.tsx | 24 +++++++++--------- .../DragAndDropList.module.css | 1 + 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css index 1f8384e8b2b..b383e15a662 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css @@ -1,5 +1,5 @@ .top { - box-shadow: var(--fds-shadow-small); + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } .backButton { diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx index 4a9946290c9..853d07505de 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx @@ -14,7 +14,7 @@ import { useUserQuery } from 'app-development/hooks/queries'; import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export const SchemaEditor = () => { - const { schemaModel, selectedTypePointer, selectedUniquePointer } = useSchemaEditorAppContext(); + const { schemaModel, selectedTypePointer } = useSchemaEditorAppContext(); const { org } = useStudioEnvironmentParams(); const { data: user } = useUserQuery(); const moveProperty = useMoveProperty(); diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css index 33b4dab618b..da977e8af43 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css @@ -12,7 +12,7 @@ display: flex; flex-direction: column; justify-content: center; - padding-inline: var(--fds-spacing-4); + padding-inline: var(--fds-spacing-6); height: var(--subtoolbar-height); border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css index 5f299a9ecf0..f7624cc9323 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css @@ -1,27 +1,19 @@ .root { box-sizing: border-box; - padding-inline: var(--fds-spacing-6); - padding-bottom: var(--fds-spacing-6); min-height: 100%; background: rgba(224, 224, 224, 0.3); - border-right: 1px solid var(--fds-semantic-border-neutral-subtle); -} - -.types { - display: flex; - flex-direction: column; - align-items: stretch; - gap: var(--fds-spacing-2); } -.addRow { +.typesHeadingWrapper { display: grid; grid-template-columns: repeat(3, 1fr); align-items: center; height: var(--subtoolbar-height); + padding-inline: var(--fds-spacing-6); + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } -.addRowText { +.typesHeading { grid-column: 1 / 3; font-size: var(--fds-font-size-f0); } @@ -33,6 +25,15 @@ color: #000000; } +.types { + padding-inline: var(--fds-spacing-6); + padding-block: var(--fds-spacing-4); + display: flex; + flex-direction: column; + align-items: stretch; + gap: var(--fds-spacing-3); +} + /* Should this be deleted? */ .root :global(.MuiAutocomplete-input) { width: 150px; diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index 4d6b0574b59..6483f0b08e2 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -5,7 +5,6 @@ import { PlusIcon } from '@studio/icons'; import type { UiSchemaNode } from '@altinn/schema-model'; import { SchemaModel } from '@altinn/schema-model'; import classes from './TypesInspector.module.css'; -import { Divider } from 'app-shared/primitives'; import { useTranslation } from 'react-i18next'; import { TypeItem } from './TypeItem'; import { useSchemaEditorAppContext } from '../../hooks/useSchemaEditorAppContext'; @@ -40,18 +39,19 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { return (
+
+ + {t('schema_editor.types')} + + } + onClick={handleAddDefinition} + title={t('schema_editor.add_type')} + /> +
-
- {t('schema_editor.types')} - } - onClick={handleAddDefinition} - title={t('schema_editor.add_type')} - /> -
- {schemaItems.map((item) => ( Date: Wed, 16 Oct 2024 14:34:34 +0200 Subject: [PATCH 05/22] Clean up --- .../HeadingRow/HeadingRow.module.css | 21 +++---------- .../components/NodePanel/NodePanel.module.css | 8 ++--- .../src/components/NodePanel/NodePanel.tsx | 8 ++--- .../SchemaInspector.module.css | 2 +- .../SchemaInspector/SchemaInspector.tsx | 16 +++++----- .../TypesInspector/TypesInspector.module.css | 31 +++++-------------- .../TypesInspector/TypesInspector.tsx | 8 ++--- .../DragAndDropList.module.css | 1 - 8 files changed, 35 insertions(+), 60 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css index 3f0081bc093..2ef7c7d456e 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css @@ -1,25 +1,14 @@ .root { - --gap: var(--fds-spacing-1); - height: var(--subtoolbar-height); - box-sizing: border-box; - align-items: center; display: flex; - padding: var(--gap) 0; - gap: var(--gap); -} - -.heading { - display: contents; + align-items: center; + height: var(--subtoolbar-height); + gap: var(--fds-spacing-3); + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } .heading .headingButton { - border-bottom-left-radius: 0; - border-left-color: transparent; - border-left-style: solid; - border-left-width: var(--studio-treeitem-vertical-line-width); - border-top-left-radius: 0; + display: flex; font: var(--fds-typography-paragraph-short-large); - min-height: var(--fds-sizing-12); } .root.selected .headingButton { diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css index b383e15a662..a52c052e570 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.module.css @@ -1,7 +1,3 @@ -.top { - border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); -} - .backButton { background-color: var(--fds-semantic-surface-action-subtle); border: none; @@ -12,3 +8,7 @@ .backButton:hover { background-color: var(--fds-semantic-surface-action-subtle-hover); } + +.content { + padding-block: var(--fds-spacing-2); +} diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx index b2bed63e68e..47012e7d3ec 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx @@ -21,11 +21,11 @@ export const NodePanel = ({ schemaPointer }: NodePanelProps) => { return ( <> -
- - {!isDataModelRoot && } + + {!isDataModelRoot && } +
+ {isNodeValidParent(node) && }
- {isNodeValidParent(node) && } ); }; diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css index 7094256f0ae..bc949fb4f97 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css @@ -4,7 +4,7 @@ height: 100%; } -.noItemHeadingWrapper { +.noItemHeadingContainer { display: flex; flex-direction: column; justify-content: center; diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx index e00c14b7e3a..5ed263f4292 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx @@ -1,4 +1,5 @@ -import React, { ReactElement } from 'react'; +import type { ReactElement } from 'react'; +import React from 'react'; import { Alert, Tabs } from '@digdir/designsystemet-react'; import type { UiSchemaNode } from '@altinn/schema-model'; import { isField, isObject } from '@altinn/schema-model'; @@ -14,23 +15,24 @@ export const SchemaInspector = (): ReactElement => { const { t } = useTranslation(); const { selectedUniquePointer } = useSchemaEditorAppContext(); const savableModel = useSavableSchemaModel(); + const selectedItem: UiSchemaNode = selectedUniquePointer + ? savableModel.getNodeByUniquePointer(selectedUniquePointer) + : undefined; + const shouldDisplayFieldsTab = selectedItem && isField(selectedItem) && isObject(selectedItem); - if (!selectedUniquePointer) { + if (!selectedItem) { return ( <> -
+
{t('schema_editor.properties')}
- {t('schema_editor.no_item_selected')} + {t('schema_editor.no_item_selected')} ); } - const selectedItem: UiSchemaNode = savableModel.getNodeByUniquePointer(selectedUniquePointer); - const shouldDisplayFieldsTab = isField(selectedItem) && isObject(selectedItem); - return ( diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css index 8243879c3bc..ed69e45b743 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.module.css @@ -1,35 +1,20 @@ -.root { - box-sizing: border-box; - min-height: 100%; - background: rgba(224, 224, 224, 0.3); -} - -.typesHeadingWrapper { - display: grid; - grid-template-columns: repeat(3, 1fr); +.headingContainer { + display: flex; + justify-content: space-between; align-items: center; height: var(--subtoolbar-height); padding-inline: var(--fds-spacing-6); border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } -.typesHeading { - grid-column: 1 / 3; - font-size: var(--fds-font-size-f0); +.addTypeButton { + color: var(--fds-semantic-surface-neutral-inverted); } -.addRowButton { - grid-column: 3; - margin-left: auto; - margin-right: 0; - color: #000000; -} - -.types { - padding-inline: var(--fds-spacing-6); - padding-block: var(--fds-spacing-4); +.typesList { display: flex; flex-direction: column; - align-items: stretch; + padding-block: var(--fds-spacing-5); + padding-inline: var(--fds-spacing-6); gap: var(--fds-spacing-3); } diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index 6483f0b08e2..ea597f7691f 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -39,19 +39,19 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { return (
-
- +
+ {t('schema_editor.types')} } onClick={handleAddDefinition} title={t('schema_editor.add_type')} />
-
+
{schemaItems.map((item) => ( Date: Wed, 16 Oct 2024 14:46:58 +0200 Subject: [PATCH 06/22] Fix selected type being sunk to bottom --- .../SchemaEditor/SchemaEditor.module.css | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.module.css b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.module.css index ed349915d51..b7117d4a636 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.module.css +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.module.css @@ -1,8 +1,8 @@ .editor { + display: flex; + flex-direction: column; + width: 100%; background-color: white; - display: grid; - grid-template-rows: auto 1fr; - flex: 1; min-height: 200px; overflow-y: auto; } @@ -13,15 +13,3 @@ overflow-y: auto; width: 100%; } - -.typeInfo { - display: flex; - flex-direction: row; - background-color: #022f51; - color: #ffffff; - align-items: center; - justify-content: center; - margin-left: auto; - margin-right: auto; - width: 100%; -} From 8687736f89c2f1f067b6abee6a7b108bbc1c7f63 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Thu, 17 Oct 2024 14:21:28 +0200 Subject: [PATCH 07/22] Update headings and add a test for no item selected --- .../NodePanel/HeadingRow/HeadingRow.tsx | 12 ++++++---- .../SchemaInspector.module.css | 2 +- .../SchemaInspector/SchemaInspector.test.tsx | 24 ++++++++++++++----- .../SchemaInspector/SchemaInspector.tsx | 6 +++-- .../TypesInspector/TypesInspector.tsx | 2 +- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index 1c4976365cd..1275e8fbf6e 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -1,5 +1,4 @@ import classes from './HeadingRow.module.css'; -import { Heading } from '@digdir/designsystemet-react'; import { NodeIcon } from '../../NodeIcon'; import type { ReactNode } from 'react'; import React from 'react'; @@ -13,7 +12,12 @@ import { SchemaModel, } from '@altinn/schema-model'; import { useTranslation } from 'react-i18next'; -import { StudioButton, StudioDeleteButton, StudioDropdownMenu } from '@studio/components'; +import { + StudioButton, + StudioDeleteButton, + StudioDropdownMenu, + StudioHeading, +} from '@studio/components'; import { BooleanIcon, CombinationIcon, @@ -44,7 +48,7 @@ export const HeadingRow = ({ schemaPointer }: HeadingRowProps) => { return (
- + { > {title} - + {isValidParent && } {!isDataModelRoot && }
diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css index bc949fb4f97..9bc24f62495 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.module.css @@ -4,7 +4,7 @@ height: 100%; } -.noItemHeadingContainer { +.noSelectionHeadingContainer { display: flex; flex-direction: column; justify-content: center; diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.test.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.test.tsx index e272a513ecb..2d9ee24cb0f 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.test.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.test.tsx @@ -42,7 +42,19 @@ const renderSchemaInspector = (uiSchemaMap: UiSchemaNodes, selectedItem?: UiSche describe('SchemaInspector', () => { afterEach(jest.clearAllMocks); - it('Saves data model when entering text in textboxes', async () => { + it('displays a message when no node is selected', () => { + renderSchemaInspector(mockUiSchema); + + const noSelectionHeader = screen.getByRole('heading', { + name: textMock('schema_editor.properties'), + }); + const noSelectionParagraph = screen.getByText(textMock('schema_editor.no_item_selected')); + + expect(noSelectionHeader).toBeInTheDocument(); + expect(noSelectionParagraph).toBeInTheDocument(); + }); + + it('saves data model when entering text in textboxes', async () => { renderSchemaInspector(mockUiSchema, getMockSchemaByPath('#/$defs/Kommentar2000Restriksjon')); const tablist = screen.getByRole('tablist'); expect(tablist).toBeDefined(); @@ -59,13 +71,13 @@ describe('SchemaInspector', () => { expect(saveDataModel).toHaveBeenCalled(); }); - test('renders no item if nothing is selected', () => { + it('renders no item if nothing is selected', () => { renderSchemaInspector(mockUiSchema); const textboxes = screen.queryAllByRole('textbox'); expect(textboxes).toHaveLength(0); }); - it('Saves data model correctly when changing restriction value', async () => { + it('saves data model correctly when changing restriction value', async () => { const schemaPointer = '#/$defs/Kommentar2000Restriksjon'; renderSchemaInspector(mockUiSchema, getMockSchemaByPath(schemaPointer)); @@ -93,7 +105,7 @@ describe('SchemaInspector', () => { expect(updatedNode.restrictions.minLength).toEqual(parseInt(minLength)); }); - test('Adds new object field when pressing the enter key', async () => { + it('adds new object field when pressing the enter key', async () => { const parentNodePointer = '#/properties/test'; const childNodePointer = '#/properties/test/properties/abc'; const rootNode: FieldNode = { @@ -125,7 +137,7 @@ describe('SchemaInspector', () => { }); }); - test('Adds new valid value field when pressing the enter key', async () => { + it('adds new valid value field when pressing the enter key', async () => { const itemPointer = '#/properties/test'; const enumValue = 'valid value'; const rootNode: FieldNode = { @@ -155,7 +167,7 @@ describe('SchemaInspector', () => { expect(saveDataModel).not.toHaveBeenCalled(); }); - it('Does not display the fields tab when the selected item is a combination', async () => { + it('does not display the fields tab when the selected item is a combination', async () => { const itemPointer = '#/properties/testcombination'; const rootNode: FieldNode = { ...rootNodeMock, diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx index 5ed263f4292..2b6991aaefe 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx @@ -23,8 +23,10 @@ export const SchemaInspector = (): ReactElement => { if (!selectedItem) { return ( <> -
- {t('schema_editor.properties')} +
+ + {t('schema_editor.properties')} +
{t('schema_editor.no_item_selected')} diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index ea597f7691f..27abff95072 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -40,7 +40,7 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { return (
- + {t('schema_editor.types')} Date: Mon, 21 Oct 2024 14:53:42 +0200 Subject: [PATCH 08/22] Fix most PR comments --- .../NodePanel/HeadingRow/HeadingRow.module.css | 11 +++++++++-- .../components/NodePanel/HeadingRow/HeadingRow.tsx | 2 +- .../SchemaInspector/SchemaInspector.test.tsx | 4 ++-- .../components/SchemaInspector/SchemaInspector.tsx | 12 +++++------- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css index 2ef7c7d456e..beef35d7c0c 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css @@ -6,12 +6,19 @@ border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } -.heading .headingButton { +.headingButton { display: flex; font: var(--fds-typography-paragraph-short-large); + border-left: var(--studio-treeitem-vertical-line-width) solid transparent; + border-top-left-radius: 0; + border-bottom-left-radius: 0; } -.root.selected .headingButton { +.headingButton:hover { + background-color: var(--fds-colors-blue-100); +} + +.selected .headingButton { background-color: var(--studio-treeitem-selected-background-colour); border-left-color: var(--studio-treeitem-vertical-line-colour-root); } diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index 1275e8fbf6e..19252a281f2 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -48,7 +48,7 @@ export const HeadingRow = ({ schemaPointer }: HeadingRowProps) => { return (
- + { it('displays a message when no node is selected', () => { renderSchemaInspector(mockUiSchema); - const noSelectionHeader = screen.getByRole('heading', { + const propertiesHeader = screen.getByRole('heading', { name: textMock('schema_editor.properties'), }); const noSelectionParagraph = screen.getByText(textMock('schema_editor.no_item_selected')); - expect(noSelectionHeader).toBeInTheDocument(); + expect(propertiesHeader).toBeInTheDocument(); expect(noSelectionParagraph).toBeInTheDocument(); }); diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx index 2b6991aaefe..5bfbe303a77 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx @@ -48,15 +48,13 @@ export const SchemaInspector = (): ReactElement => { - {shouldDisplayFieldsTab ? ( - + + {shouldDisplayFieldsTab ? ( - - ) : ( - + ) : ( {t('app_data_modelling.fields_information')} - - )} + )} + ); }; From 6353e9074ef90c0e5961aee86a7a64811822b3ac Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Mon, 21 Oct 2024 19:34:31 +0200 Subject: [PATCH 09/22] Add label and vertical divider to toolbar --- .../TopToolbar/SchemaSelect.module.css | 8 +++ .../TopToolbar/SchemaSelect.tsx | 50 +++++++++++-------- .../TopToolbar/TopToolbar.module.css | 39 +++------------ .../TopToolbar/TopToolbar.tsx | 44 +++++++++------- .../HeadingRow/HeadingRow.module.css | 12 +++-- 5 files changed, 77 insertions(+), 76 deletions(-) diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.module.css b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.module.css index 7914b8c1c12..3eeeab9785a 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.module.css +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.module.css @@ -1,4 +1,12 @@ +.selectContainer { + display: flex; + align-items: center; + gap: var(--fds-spacing-4); +} + .select { + display: flex; + flex-direction: row; cursor: pointer; min-width: 20vw; } diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.tsx index d1ff68acf42..36439b1e28b 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/SchemaSelect.tsx @@ -5,7 +5,8 @@ import { groupMetadataOptions, } from '../../../../utils/metadataUtils'; import type { MetadataOption } from '../../../../types/MetadataOption'; -import { NativeSelect } from '@digdir/designsystemet-react'; +import { Label } from '@digdir/designsystemet-react'; +import { StudioNativeSelect } from '@studio/components'; import classes from './SchemaSelect.module.css'; import type { DataModelMetadata } from 'app-shared/types/DataModelMetadata'; import { useTranslation } from 'react-i18next'; @@ -30,26 +31,31 @@ export const SchemaSelect = ({ setSelectedOption(findMetadataOptionByRelativeUrl(options, repositoryUrl)); return ( - handleChange(e.target.value)} - value={selectedOption?.value.repositoryRelativeUrl} - size='small' - > - {optionGroups.map((group) => ( - - {group.options.map((option) => ( - - ))} - - ))} - +
+ + handleChange(e.target.value)} + value={selectedOption?.value.repositoryRelativeUrl} + size='sm' + > + {optionGroups.map((group) => ( + + {group.options.map((option) => ( + + ))} + + ))} + +
); }; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css index 5fdb2d3f0c4..f488cd29804 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css @@ -1,27 +1,11 @@ .toolbar { - align-items: center; - background: #fff; - border-bottom: 1px solid #c9c9c9; + height: var(--subtoolbar-height); + background: white; display: flex; - padding: 8px; -} - -.toolbar > *, -.toolbar > { - margin-right: 1rem; -} - -.toolbar button[class*='selected'] { - color: #fff; -} - -.toolbar button[class*='toggle'] { - font-size: 1em; - padding-top: 4px; -} - -.generateButtonWrapper { - flex: 1; + align-items: center; + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); + padding-inline: var(--fds-spacing-6); + gap: var(--fds-spacing-2); } @keyframes fadeOut { @@ -42,14 +26,3 @@ .statusPopover.success { animation: fadeOut 1.5s; } - -.toggleButtonGroupWrapper { - flex: 0.5; -} - -.right { - display: flex; - flex: 3; - gap: 1rem; - justify-content: flex-end; -} diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index 9139f7af038..ce72e6820cd 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -49,6 +49,12 @@ export function TopToolbar({ return (
+ - + -
-
- {modelPath && ( - - onSetSchemaGenerationErrorMessages(errorMessages) - } - /> - )} -
-
+ {modelPath && ( + + onSetSchemaGenerationErrorMessages(errorMessages) + } + /> + )}
); } + +const VerticalDivider = () => { + return ( +
+ ); +}; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css index beef35d7c0c..b808b23164f 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css @@ -9,9 +9,9 @@ .headingButton { display: flex; font: var(--fds-typography-paragraph-short-large); - border-left: var(--studio-treeitem-vertical-line-width) solid transparent; border-top-left-radius: 0; border-bottom-left-radius: 0; + border: 0; } .headingButton:hover { @@ -19,6 +19,12 @@ } .selected .headingButton { - background-color: var(--studio-treeitem-selected-background-colour); - border-left-color: var(--studio-treeitem-vertical-line-colour-root); + /*background-color: var(--studio-treeitem-selected-background-colour);*/ + background: linear-gradient( + to right, + var(--studio-treeitem-vertical-line-colour-root) 0 var(--studio-treeitem-vertical-line-width), + var(--studio-treeitem-selected-background-colour) var(--studio-treeitem-vertical-line-width) + 100% + ); + /*border-left-color: var(--studio-treeitem-vertical-line-colour-root);*/ } From e30ff3817899f7f3ef52fa9969f7359a12aeede8 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Tue, 22 Oct 2024 09:41:01 +0200 Subject: [PATCH 10/22] Design decided, but not functionally implemented --- .../TopToolbar/TopToolbar.module.css | 8 ++ .../TopToolbar/TopToolbar.tsx | 120 +++++++++++++----- .../NodePanel/HeadingRow/HeadingRow.tsx | 14 +- .../src/components/NodePanel/NodePanel.tsx | 2 +- .../TypesInspector/TypesInspector.tsx | 4 +- 5 files changed, 115 insertions(+), 33 deletions(-) diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css index f488cd29804..721450e4cb7 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css @@ -8,6 +8,14 @@ gap: var(--fds-spacing-2); } +.blueBackground { + background: var(--fds-colors-blue-100); +} + +.modelName { + /*font-weight: 400;*/ +} + @keyframes fadeOut { 0% { opacity: 1; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index ce72e6820cd..a66c827cc82 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -9,9 +9,12 @@ import type { CreateDataModelMutationArgs } from '../../../../hooks/mutations/us import { useCreateDataModelMutation } from '../../../../hooks/mutations'; import type { MetadataOption } from '../../../../types/MetadataOption'; import { GenerateModelsButton } from './GenerateModelsButton'; -import { usePrevious } from '@studio/components'; +import { StudioButton, StudioParagraph, usePrevious } from '@studio/components'; import type { DataModelMetadata } from 'app-shared/types/DataModelMetadata'; import { useTranslation } from 'react-i18next'; +import { Label, Link } from '@digdir/designsystemet-react'; +import { ArrowLeftIcon, ChevronRightIcon } from '@studio/icons'; +import cn from 'classnames'; export interface TopToolbarProps { createNewOpen: boolean; @@ -47,35 +50,46 @@ export function TopToolbar({ setCreateNewOpen(false); }; + const showTypeToolbar = false; + return ( -
- - - - - - {modelPath && ( - - onSetSchemaGenerationErrorMessages(errorMessages) - } - /> +
+ {showTypeToolbar ? ( + + ) : ( + <> + + + + + {/**/} + {modelPath && ( + + onSetSchemaGenerationErrorMessages(errorMessages) + } + /> + )} + )}
); @@ -91,3 +105,51 @@ const VerticalDivider = () => { /> ); }; + +const TypeControls = () => { + const showBreadcrumbs = true; + + return ( +
+ {showBreadcrumbs ? ( + <> +
+ + Datamodell: model + + + + Type: name0 + +
+ {/*}>Tilbake til datamodell*/} + + ) : ( + <> +
+ +
+ }> + Tilbake til datamodell model + + + )} +
+ ); +}; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index 19252a281f2..3b9168c6bcd 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -30,6 +30,7 @@ import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; import type { TranslationKey } from '@altinn-studio/language/type'; import { useAddProperty } from '../../../hooks/useAddProperty'; import cn from 'classnames'; +import { ArrowLeftIcon } from '@studio/icons'; export interface HeadingRowProps { schemaPointer?: string; @@ -60,7 +61,8 @@ export const HeadingRow = ({ schemaPointer }: HeadingRowProps) => { {isValidParent && } - {!isDataModelRoot && } + + {/*{!isDataModelRoot && }*/}
); }; @@ -175,3 +177,13 @@ const DeleteButton = ({ schemaPointer }: DeleteButtonProps) => { ); }; + +const BackButton = () => ( +
+ }>Tilbake til datamodell +
+); diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx index 47012e7d3ec..1cd57aef35f 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx @@ -22,7 +22,7 @@ export const NodePanel = ({ schemaPointer }: NodePanelProps) => { return ( <> - {!isDataModelRoot && } + {/*{!isDataModelRoot && }*/}
{isNodeValidParent(node) && }
diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index 27abff95072..e6f0d463224 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -38,7 +38,7 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { }; return ( -
+ <>
{t('schema_editor.types')} @@ -61,6 +61,6 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { /> ))}
-
+ ); }; From 6d8a17071f8dd31396d2b30e7da36cfee7e3243d Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Tue, 5 Nov 2024 13:29:36 +0100 Subject: [PATCH 11/22] Create context above TopToolbar --- .../SchemaEditorWithToolbar.tsx | 47 ++++++++++--------- .../TopToolbar/TopToolbar.tsx | 20 ++++++-- .../schema-editor/src/SchemaEditorApp.tsx | 13 +++-- .../NodePanel/HeadingRow/HeadingRow.tsx | 19 ++++---- .../src/components/NodePanel/NodePanel.tsx | 39 +++++++-------- .../src/contexts/DataModelToolbarContext.tsx | 42 +++++++++++++++++ 6 files changed, 119 insertions(+), 61 deletions(-) create mode 100644 frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx index 7c6cba15a82..9c665f85f9c 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx @@ -8,6 +8,7 @@ import type { DataModelMetadata } from 'app-shared/types/DataModelMetadata'; import { SchemaGenerationErrorsPanel } from './SchemaGenerationErrorsPanel'; import { useAddXsdMutation } from '../../../hooks/mutations/useAddXsdMutation'; import { isXsdFile } from 'app-shared/utils/filenameUtils'; +import { DataModelToolbarContextProvider } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export interface SchemaEditorWithToolbarProps { createPathOption?: boolean; @@ -39,28 +40,30 @@ export const SchemaEditorWithToolbar = ({ }, [dataModels, addXsdFromRepo]); return ( -
- - setSchemaGenerationErrorMessages(errorMessages) - } - /> - {schemaGenerationErrorMessages.length > 0 && ( - setSchemaGenerationErrorMessages([])} - schemaGenerationErrorMessages={schemaGenerationErrorMessages} + +
+ + setSchemaGenerationErrorMessages(errorMessages) + } /> - )} -
- {!dataModels.length && setCreateNewOpen(true)} />} - {modelPath && } -
-
+ {schemaGenerationErrorMessages.length > 0 && ( + setSchemaGenerationErrorMessages([])} + schemaGenerationErrorMessages={schemaGenerationErrorMessages} + /> + )} +
+ {!dataModels.length && setCreateNewOpen(true)} />} + {modelPath && } +
+
+ ); }; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index a66c827cc82..a476dd182de 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -3,7 +3,7 @@ import classes from './TopToolbar.module.css'; import { CreateNewWrapper } from './CreateNewWrapper'; import { XSDUpload } from './XSDUpload'; import { SchemaSelect } from './SchemaSelect'; -import { DeleteWrapper } from './DeleteWrapper'; +// import { DeleteWrapper } from './DeleteWrapper'; import { computeSelectedOption } from '../../../../utils/metadataUtils'; import type { CreateDataModelMutationArgs } from '../../../../hooks/mutations/useCreateDataModelMutation'; import { useCreateDataModelMutation } from '../../../../hooks/mutations'; @@ -15,6 +15,7 @@ import { useTranslation } from 'react-i18next'; import { Label, Link } from '@digdir/designsystemet-react'; import { ArrowLeftIcon, ChevronRightIcon } from '@studio/icons'; import cn from 'classnames'; +import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export interface TopToolbarProps { createNewOpen: boolean; @@ -41,6 +42,8 @@ export function TopToolbar({ const { mutate: createDataModel } = useCreateDataModelMutation(); const prevDataModels = usePrevious(dataModels); + const { selectedTypePointer } = useDataModelToolbarContext(); + useEffect(() => { setSelectedOption(computeSelectedOption(selectedOption, dataModels, prevDataModels)); }, [selectedOption, dataModels, prevDataModels, setSelectedOption]); @@ -50,7 +53,7 @@ export function TopToolbar({ setCreateNewOpen(false); }; - const showTypeToolbar = false; + const showTypeToolbar = !!selectedTypePointer; return (
{ }; const TypeControls = () => { + const { setSelectedTypePointer, setSelectedUniquePointer, selectedUniquePointer } = + useDataModelToolbarContext(); + const showBreadcrumbs = true; + const navigateToDataModelRoot = () => { + setSelectedUniquePointer(undefined); + setSelectedTypePointer(undefined); + }; return (
{ gap: 'var(--fds-spacing-4)', }} > - - Datamodell: model + navigateToDataModelRoot()}> + Datamodell: {selectedUniquePointer} - Type: name0 + Type: {selectedUniquePointer}
{/*}>Tilbake til datamodell*/} diff --git a/frontend/packages/schema-editor/src/SchemaEditorApp.tsx b/frontend/packages/schema-editor/src/SchemaEditorApp.tsx index 2cd7274210f..4ab1eff3020 100644 --- a/frontend/packages/schema-editor/src/SchemaEditorApp.tsx +++ b/frontend/packages/schema-editor/src/SchemaEditorApp.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import './App.css'; import '@digdir/design-system-tokens/brand/altinn/tokens.css'; @@ -7,6 +7,7 @@ import { SchemaEditorAppContext } from './contexts/SchemaEditorAppContext'; import type { JsonSchema } from 'app-shared/types/JsonSchema'; import { buildJsonSchema, buildUiSchema, SchemaModel } from '@altinn/schema-model'; import { SchemaEditor } from './components/SchemaEditor'; +import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export type SchemaEditorAppProps = { jsonSchema: JsonSchema; @@ -15,8 +16,14 @@ export type SchemaEditorAppProps = { }; export function SchemaEditorApp({ jsonSchema, name, save }: SchemaEditorAppProps) { - const [selectedTypePointer, setSelectedTypePointer] = useState(null); - const [selectedUniquePointer, setSelectedUniquePointer] = useState(null); + // const [selectedTypePointer, setSelectedTypePointer] = useState(null); + // const [selectedUniquePointer, setSelectedUniquePointer] = useState(null); + const { + selectedTypePointer, + setSelectedTypePointer, + selectedUniquePointer, + setSelectedUniquePointer, + } = useDataModelToolbarContext(); const value = useMemo( () => ({ diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index 3b9168c6bcd..542d644c26d 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -30,7 +30,6 @@ import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; import type { TranslationKey } from '@altinn-studio/language/type'; import { useAddProperty } from '../../../hooks/useAddProperty'; import cn from 'classnames'; -import { ArrowLeftIcon } from '@studio/icons'; export interface HeadingRowProps { schemaPointer?: string; @@ -178,12 +177,12 @@ const DeleteButton = ({ schemaPointer }: DeleteButtonProps) => { ); }; -const BackButton = () => ( -
- }>Tilbake til datamodell -
-); +// const BackButton = () => ( +//
+// }>Tilbake til datamodell +//
+// ); diff --git a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx index 1cd57aef35f..f42cde1d9c7 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/NodePanel.tsx @@ -1,9 +1,6 @@ import React from 'react'; import { SchemaTree } from '../SchemaTree'; -import { Link } from '@digdir/designsystemet-react'; import { useSchemaEditorAppContext } from '../../hooks/useSchemaEditorAppContext'; -import { ArrowLeftIcon } from '@studio/icons'; -import { useTranslation } from 'react-i18next'; import classes from './NodePanel.module.css'; import { HeadingRow } from './HeadingRow'; import { isNodeValidParent } from '@altinn/schema-model'; @@ -30,21 +27,21 @@ export const NodePanel = ({ schemaPointer }: NodePanelProps) => { ); }; -const BackButton = () => { - const { setSelectedUniquePointer, setSelectedTypePointer } = useSchemaEditorAppContext(); - const { t } = useTranslation(); - - const navigateToDataModelRoot = () => { - setSelectedUniquePointer(undefined); - setSelectedTypePointer(undefined); - }; - - return ( - - - - ); -}; +// const BackButton = () => { +// const { setSelectedUniquePointer, setSelectedTypePointer } = useSchemaEditorAppContext(); +// const { t } = useTranslation(); +// +// const navigateToDataModelRoot = () => { +// setSelectedUniquePointer(undefined); +// setSelectedTypePointer(undefined); +// }; +// +// return ( +// +// +// +// ); +// }; diff --git a/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx new file mode 100644 index 00000000000..d5bab224b9b --- /dev/null +++ b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx @@ -0,0 +1,42 @@ +import React, { createContext, useContext, useState } from 'react'; + +type DataModelToolbarContextProps = { + selectedTypePointer: string; + setSelectedTypePointer: React.Dispatch>; + selectedUniquePointer: string; + setSelectedUniquePointer: React.Dispatch>; +}; + +const DataModelToolbarContext = createContext(null); + +export type DataModelToolbarContextProviderProps = { + children: React.ReactNode; +}; + +export const DataModelToolbarContextProvider = ({ + children, +}: DataModelToolbarContextProviderProps) => { + const [selectedTypePointer, setSelectedTypePointer] = useState(null); + const [selectedUniquePointer, setSelectedUniquePointer] = useState(null); + + const value = { + selectedTypePointer, + setSelectedTypePointer, + selectedUniquePointer, + setSelectedUniquePointer, + }; + + return ( + {children} + ); +}; + +export const useDataModelToolbarContext = (): Partial => { + const context = useContext(DataModelToolbarContext); + if (context === undefined) { + throw new Error( + 'useDataModelToolbarContext must be used within a useDataModelToolbarContextProvider', + ); + } + return context; +}; From a99df5cdfdbc7049eb79c7a005dfd03a86aed381 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Tue, 5 Nov 2024 16:15:16 +0100 Subject: [PATCH 12/22] Dispay data model name and type name in toolbar --- .../TopToolbar/TopToolbar.module.css | 3 ++- .../TopToolbar/TopToolbar.tsx | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css index 721450e4cb7..00960c35a63 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css @@ -9,7 +9,8 @@ } .blueBackground { - background: var(--fds-colors-blue-100); + background: var(--fds-colors-grey-100); + /*background: var(--fds-colors-yellow-200);*/ } .modelName { diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index a476dd182de..757c7519caf 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -61,7 +61,7 @@ export function TopToolbar({ role='toolbar' > {showTypeToolbar ? ( - + ) : ( <> { ); }; -const TypeControls = () => { +const TypeControls = ({ dataModelName }) => { const { setSelectedTypePointer, setSelectedUniquePointer, selectedUniquePointer } = useDataModelToolbarContext(); - const showBreadcrumbs = true; + const showBreadcrumbs = false; const navigateToDataModelRoot = () => { setSelectedUniquePointer(undefined); setSelectedTypePointer(undefined); }; + const typeName = selectedUniquePointer.substring(selectedUniquePointer.lastIndexOf('/') + 1); + return (
{ }} > navigateToDataModelRoot()}> - Datamodell: {selectedUniquePointer} + Datamodell: {dataModelName} - Type: {selectedUniquePointer} + Type: {typeName}
{/*}>Tilbake til datamodell*/} @@ -151,12 +153,12 @@ const TypeControls = () => { ) : ( <>
-
- }> - Tilbake til datamodell model + navigateToDataModelRoot()} icon={}> + Tilbake til datamodell {dataModelName} )} From 77926aabb9d5e179515e9370b5db6a4c701406f0 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Tue, 5 Nov 2024 16:33:25 +0100 Subject: [PATCH 13/22] Delete vertical divider --- .../TopToolbar/TopToolbar.tsx | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index 757c7519caf..76774296225 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -82,7 +82,7 @@ export function TopToolbar({ selectedOption={selectedOption} uploadButtonText={t('app_data_modelling.upload_xsd')} /> - + {/**/} {/**/} {modelPath && ( { - return ( -
- ); -}; - const TypeControls = ({ dataModelName }) => { const { setSelectedTypePointer, setSelectedUniquePointer, selectedUniquePointer } = useDataModelToolbarContext(); - const showBreadcrumbs = false; + const showBreadcrumbs = true; + const navigateToDataModelRoot = () => { setSelectedUniquePointer(undefined); setSelectedTypePointer(undefined); From e9f314a55c3fa501776e9f9943774ffba9ef091b Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Tue, 5 Nov 2024 17:19:19 +0100 Subject: [PATCH 14/22] Make delete button work for data models --- .../features/dataModelling/DataModelling.tsx | 7 ++- .../SchemaEditorWithToolbar.tsx | 55 ++++++++++--------- .../TopToolbar/TopToolbar.tsx | 3 +- .../NodePanel/HeadingRow/HeadingRow.tsx | 30 +++++++++- .../src/contexts/DataModelToolbarContext.tsx | 6 ++ 5 files changed, 70 insertions(+), 31 deletions(-) diff --git a/frontend/app-development/features/dataModelling/DataModelling.tsx b/frontend/app-development/features/dataModelling/DataModelling.tsx index 3b2077dbbeb..484982a165e 100644 --- a/frontend/app-development/features/dataModelling/DataModelling.tsx +++ b/frontend/app-development/features/dataModelling/DataModelling.tsx @@ -8,6 +8,7 @@ import { useDataModelsJsonQuery, useDataModelsXsdQuery } from 'app-shared/hooks/ import { useParams } from 'react-router-dom'; import { mergeQueryStatuses } from 'app-shared/utils/tanstackQueryUtils'; import { mergeJsonAndXsdData } from '../../utils/metadataUtils'; +import { DataModelToolbarContextProvider } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; interface DataModellingProps { createPathOption?: boolean; @@ -35,7 +36,11 @@ export function DataModelling({ createPathOption = false }: DataModellingProps): ); case 'success': { const data = mergeJsonAndXsdData(jsonData, xsdData); - return ; + return ( + + + + ); } } } diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx index 9c665f85f9c..4e9750e2990 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx @@ -2,13 +2,15 @@ import classes from './SchemaEditorWithToolbar.module.css'; import { TopToolbar } from './TopToolbar'; import { LandingPagePanel } from './LandingPagePanel'; import React, { useEffect, useState } from 'react'; -import type { MetadataOption } from '../../../types/MetadataOption'; import { SelectedSchemaEditor } from './SelectedSchemaEditor'; import type { DataModelMetadata } from 'app-shared/types/DataModelMetadata'; import { SchemaGenerationErrorsPanel } from './SchemaGenerationErrorsPanel'; import { useAddXsdMutation } from '../../../hooks/mutations/useAddXsdMutation'; import { isXsdFile } from 'app-shared/utils/filenameUtils'; -import { DataModelToolbarContextProvider } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; +import { + DataModelToolbarContextProvider, + useDataModelToolbarContext, +} from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export interface SchemaEditorWithToolbarProps { createPathOption?: boolean; @@ -20,7 +22,8 @@ export const SchemaEditorWithToolbar = ({ dataModels, }: SchemaEditorWithToolbarProps) => { const [createNewOpen, setCreateNewOpen] = useState(false); - const [selectedOption, setSelectedOption] = useState(undefined); + // const [selectedOption, setSelectedOption] = useState(undefined); + const { selectedOption, setSelectedOption } = useDataModelToolbarContext(); const [schemaGenerationErrorMessages, setSchemaGenerationErrorMessages] = useState([]); const { mutate: addXsdFromRepo } = useAddXsdMutation(); @@ -40,30 +43,28 @@ export const SchemaEditorWithToolbar = ({ }, [dataModels, addXsdFromRepo]); return ( - -
- - setSchemaGenerationErrorMessages(errorMessages) - } +
+ + setSchemaGenerationErrorMessages(errorMessages) + } + /> + {schemaGenerationErrorMessages.length > 0 && ( + setSchemaGenerationErrorMessages([])} + schemaGenerationErrorMessages={schemaGenerationErrorMessages} /> - {schemaGenerationErrorMessages.length > 0 && ( - setSchemaGenerationErrorMessages([])} - schemaGenerationErrorMessages={schemaGenerationErrorMessages} - /> - )} -
- {!dataModels.length && setCreateNewOpen(true)} />} - {modelPath && } -
-
- + )} +
+ {!dataModels.length && setCreateNewOpen(true)} />} + {modelPath && } +
+
); }; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index 76774296225..0f1614536d5 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -36,8 +36,6 @@ export function TopToolbar({ setSelectedOption, onSetSchemaGenerationErrorMessages, }: TopToolbarProps) { - const modelPath = selectedOption?.value.repositoryRelativeUrl; - const { t } = useTranslation(); const { mutate: createDataModel } = useCreateDataModelMutation(); const prevDataModels = usePrevious(dataModels); @@ -53,6 +51,7 @@ export function TopToolbar({ setCreateNewOpen(false); }; + const modelPath = selectedOption?.value.repositoryRelativeUrl; const showTypeToolbar = !!selectedTypePointer; return ( diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index 542d644c26d..d6d6e17e0ea 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -3,6 +3,7 @@ import { NodeIcon } from '../../NodeIcon'; import type { ReactNode } from 'react'; import React from 'react'; import { useSchemaEditorAppContext } from '../../../hooks/useSchemaEditorAppContext'; +import { useDeleteDataModelMutation } from '../../../../../../app-development/hooks/mutations'; import { extractNameFromPointer, FieldType, @@ -30,6 +31,10 @@ import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; import type { TranslationKey } from '@altinn-studio/language/type'; import { useAddProperty } from '../../../hooks/useAddProperty'; import cn from 'classnames'; +import { removeDataTypeIdsToSign } from 'app-shared/utils/bpmnUtils'; +import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; +import { useUpdateBpmn } from 'app-shared/hooks/useUpdateBpmn'; export interface HeadingRowProps { schemaPointer?: string; @@ -155,15 +160,38 @@ const DeleteButton = ({ schemaPointer }: DeleteButtonProps) => { const { t } = useTranslation(); const savableModel = useSavableSchemaModel(); const { setSelectedUniquePointer, setSelectedTypePointer } = useSchemaEditorAppContext(); + const { selectedOption } = useDataModelToolbarContext(); + const { mutate } = useDeleteDataModelMutation(); + const { org, app } = useStudioEnvironmentParams(); + const updateBpmn = useUpdateBpmn(org, app); const isInUse = savableModel.hasReferringNodes(schemaPointer); + const modelPath = selectedOption?.value.repositoryRelativeUrl; + const schemaName = selectedOption?.value && selectedOption?.label; + + const handleDelete = async () => { + if (schemaPointer) { + deleteType(); + } else { + await deleteModel(); + } + }; - const handleDelete = () => { + const deleteType = () => { setSelectedUniquePointer(null); setSelectedTypePointer(null); savableModel.deleteNode(schemaPointer); }; + const deleteModel = async () => { + mutate(modelPath, { + onSuccess: async () => { + await updateBpmn(removeDataTypeIdsToSign([schemaName])); + }, + }); + }; + + // Needs if checks and custom texts for deleting data models return ( >; selectedUniquePointer: string; setSelectedUniquePointer: React.Dispatch>; + selectedOption: MetadataOption; + setSelectedOption: React.Dispatch>; }; const DataModelToolbarContext = createContext(null); @@ -18,12 +21,15 @@ export const DataModelToolbarContextProvider = ({ }: DataModelToolbarContextProviderProps) => { const [selectedTypePointer, setSelectedTypePointer] = useState(null); const [selectedUniquePointer, setSelectedUniquePointer] = useState(null); + const [selectedOption, setSelectedOption] = useState(null); const value = { selectedTypePointer, setSelectedTypePointer, selectedUniquePointer, setSelectedUniquePointer, + selectedOption, + setSelectedOption, }; return ( From a445af464b66c8525e6c70136291fa7849b29bce Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Wed, 6 Nov 2024 15:37:40 +0100 Subject: [PATCH 15/22] Separate TopToolbar into multiple components --- .../TopToolbar/TopToolbar.module.css | 24 ++- .../TopToolbar/TopToolbar.tsx | 174 ++++++++++-------- 2 files changed, 116 insertions(+), 82 deletions(-) diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css index 00960c35a63..79d96fc8c74 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.module.css @@ -8,11 +8,6 @@ gap: var(--fds-spacing-2); } -.blueBackground { - background: var(--fds-colors-grey-100); - /*background: var(--fds-colors-yellow-200);*/ -} - .modelName { /*font-weight: 400;*/ } @@ -35,3 +30,22 @@ .statusPopover.success { animation: fadeOut 1.5s; } + +.typeToolbar { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} + +.typeToolbarBackground { + background: var(--fds-colors-grey-100); + /*background: var(--fds-colors-yellow-200);*/ +} + +.breadcrumbs { + width: fit-content; + display: flex; + align-items: center; + gap: var(--fds-spacing-4); +} diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index 0f1614536d5..17af03bfb06 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -36,11 +36,10 @@ export function TopToolbar({ setSelectedOption, onSetSchemaGenerationErrorMessages, }: TopToolbarProps) { - const { t } = useTranslation(); const { mutate: createDataModel } = useCreateDataModelMutation(); const prevDataModels = usePrevious(dataModels); - const { selectedTypePointer } = useDataModelToolbarContext(); + const showTypeToolbar: boolean = !!selectedTypePointer; useEffect(() => { setSelectedOption(computeSelectedOption(selectedOption, dataModels, prevDataModels)); @@ -51,58 +50,31 @@ export function TopToolbar({ setCreateNewOpen(false); }; - const modelPath = selectedOption?.value.repositoryRelativeUrl; - const showTypeToolbar = !!selectedTypePointer; - return (
{showTypeToolbar ? ( - + ) : ( - <> - - - - {/**/} - {/**/} - {modelPath && ( - - onSetSchemaGenerationErrorMessages(errorMessages) - } - /> - )} - + )}
); } -const TypeControls = ({ dataModelName }) => { +const TypeToolbar = ({ dataModelName }) => { const { setSelectedTypePointer, setSelectedUniquePointer, selectedUniquePointer } = useDataModelToolbarContext(); - const showBreadcrumbs = true; - const navigateToDataModelRoot = () => { setSelectedUniquePointer(undefined); setSelectedTypePointer(undefined); @@ -110,47 +82,95 @@ const TypeControls = ({ dataModelName }) => { const typeName = selectedUniquePointer.substring(selectedUniquePointer.lastIndexOf('/') + 1); + const showBreadcrumbs = false; + return ( -
+
{showBreadcrumbs ? ( - <> -
- navigateToDataModelRoot()}> - Datamodell: {dataModelName} - - - - Type: {typeName} - -
- {/*}>Tilbake til datamodell*/} - + ) : ( - <> -
- -
- navigateToDataModelRoot()} icon={}> - Tilbake til datamodell {dataModelName} - - + )}
); }; + +const BreadcrumbsToolbar = ({ navigateToDataModelRoot, dataModelName, typeName }) => { + return ( +
+ navigateToDataModelRoot()}> + Datamodell: {dataModelName} + + + + Type: {typeName} + +
+ ); +}; + +const BackButtonToolbar = ({ navigateToDataModelRoot, dataModelName, typeName }) => { + return ( + <> + + navigateToDataModelRoot()} icon={}> + Tilbake til datamodell {dataModelName} + + + ); +}; + +const DataModelToolbar = ({ + dataModels, + createNewOpen, + setCreateNewOpen, + handleCreateSchema, + createPathOption, + onSetSchemaGenerationErrorMessages, +}) => { + const { selectedOption, setSelectedOption } = useDataModelToolbarContext(); + const { t } = useTranslation(); + const modelPath = selectedOption?.value.repositoryRelativeUrl; + + return ( + <> + + + + {/**/} + {modelPath && ( + + onSetSchemaGenerationErrorMessages(errorMessages) + } + /> + )} + + ); +}; From 9fa1199dcb831591b11e37485f9c6ea3234c4b64 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Wed, 6 Nov 2024 17:42:04 +0100 Subject: [PATCH 16/22] Add prop validation to TopToolbar --- .../SchemaEditorWithToolbar.tsx | 5 +- .../TopToolbar/TopToolbar.tsx | 49 ++++++++++++++----- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx index 4e9750e2990..ec575a5a2dc 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx @@ -7,10 +7,7 @@ import type { DataModelMetadata } from 'app-shared/types/DataModelMetadata'; import { SchemaGenerationErrorsPanel } from './SchemaGenerationErrorsPanel'; import { useAddXsdMutation } from '../../../hooks/mutations/useAddXsdMutation'; import { isXsdFile } from 'app-shared/utils/filenameUtils'; -import { - DataModelToolbarContextProvider, - useDataModelToolbarContext, -} from '@altinn/schema-editor/contexts/DataModelToolbarContext'; +import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export interface SchemaEditorWithToolbarProps { createPathOption?: boolean; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index 17af03bfb06..c6dcc659276 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -36,7 +36,6 @@ export function TopToolbar({ setSelectedOption, onSetSchemaGenerationErrorMessages, }: TopToolbarProps) { - const { mutate: createDataModel } = useCreateDataModelMutation(); const prevDataModels = usePrevious(dataModels); const { selectedTypePointer } = useDataModelToolbarContext(); const showTypeToolbar: boolean = !!selectedTypePointer; @@ -45,11 +44,6 @@ export function TopToolbar({ setSelectedOption(computeSelectedOption(selectedOption, dataModels, prevDataModels)); }, [selectedOption, dataModels, prevDataModels, setSelectedOption]); - const handleCreateSchema = (model: CreateDataModelMutationArgs) => { - createDataModel(model); - setCreateNewOpen(false); - }; - return (
@@ -71,7 +64,11 @@ export function TopToolbar({ ); } -const TypeToolbar = ({ dataModelName }) => { +type TypeToolbarProps = { + dataModelName: string; +}; + +const TypeToolbar = ({ dataModelName }: TypeToolbarProps) => { const { setSelectedTypePointer, setSelectedUniquePointer, selectedUniquePointer } = useDataModelToolbarContext(); @@ -103,7 +100,17 @@ const TypeToolbar = ({ dataModelName }) => { ); }; -const BreadcrumbsToolbar = ({ navigateToDataModelRoot, dataModelName, typeName }) => { +type BreadcrumbsToolbarProps = { + navigateToDataModelRoot: () => void; + dataModelName: string; + typeName: string; +}; + +const BreadcrumbsToolbar = ({ + navigateToDataModelRoot, + dataModelName, + typeName, +}: BreadcrumbsToolbarProps) => { return (
navigateToDataModelRoot()}> @@ -117,7 +124,11 @@ const BreadcrumbsToolbar = ({ navigateToDataModelRoot, dataModelName, typeName } ); }; -const BackButtonToolbar = ({ navigateToDataModelRoot, dataModelName, typeName }) => { +const BackButtonToolbar = ({ + navigateToDataModelRoot, + dataModelName, + typeName, +}: BreadcrumbsToolbarProps) => { return ( <>
); }; @@ -154,36 +153,43 @@ const AddNodeMenuItem = ({ titleKey, icon, action }: AddNodeMenuItemProps) => { ); }; -type DeleteButtonProps = HeadingRowProps; - -const DeleteButton = ({ schemaPointer }: DeleteButtonProps) => { +const DeleteTypeButton = ({ schemaPointer }: HeadingRowProps) => { const { t } = useTranslation(); const savableModel = useSavableSchemaModel(); const { setSelectedUniquePointer, setSelectedTypePointer } = useSchemaEditorAppContext(); - const { selectedOption } = useDataModelToolbarContext(); - const { mutate } = useDeleteDataModelMutation(); - const { org, app } = useStudioEnvironmentParams(); - const updateBpmn = useUpdateBpmn(org, app); const isInUse = savableModel.hasReferringNodes(schemaPointer); - const modelPath = selectedOption?.value.repositoryRelativeUrl; - const schemaName = selectedOption?.value && selectedOption?.label; - - const handleDelete = async () => { - if (schemaPointer) { - deleteType(); - } else { - await deleteModel(); - } - }; - const deleteType = () => { + const handleDeleteType = () => { setSelectedUniquePointer(null); setSelectedTypePointer(null); savableModel.deleteNode(schemaPointer); }; - const deleteModel = async () => { + return ( + + {t('general.delete')} + + ); +}; + +const DeleteModelButton = () => { + const { t } = useTranslation(); + const { selectedOption } = useDataModelToolbarContext(); + const { mutate } = useDeleteDataModelMutation(); + const { org, app } = useStudioEnvironmentParams(); + const updateBpmn = useUpdateBpmn(org, app); + + const modelPath = selectedOption?.value.repositoryRelativeUrl; + const schemaName = selectedOption?.value && selectedOption?.label; + + const handleDeleteModel = async () => { mutate(modelPath, { onSuccess: async () => { await updateBpmn(removeDataTypeIdsToSign([schemaName])); @@ -191,26 +197,14 @@ const DeleteButton = ({ schemaPointer }: DeleteButtonProps) => { }); }; - // Needs if checks and custom texts for deleting data models return ( {t('general.delete')} ); }; - -// const BackButton = () => ( -//
-// }>Tilbake til datamodell -//
-// ); From 688f3ccc00644426942f749d0a8f06c45125f961 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Wed, 6 Nov 2024 18:46:31 +0100 Subject: [PATCH 18/22] Move AddNodeMenu into its own tsx file --- .../NodePanel/HeadingRow/AddNodeMenu.tsx | 100 ++++++++++++++++ .../NodePanel/HeadingRow/HeadingRow.tsx | 111 +----------------- 2 files changed, 103 insertions(+), 108 deletions(-) create mode 100644 frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/AddNodeMenu.tsx diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/AddNodeMenu.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/AddNodeMenu.tsx new file mode 100644 index 00000000000..cae5aa0eaa4 --- /dev/null +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/AddNodeMenu.tsx @@ -0,0 +1,100 @@ +import { StudioDropdownMenu } from '@studio/components'; +import type { HeadingRowProps } from './HeadingRow'; +import type { ReactNode } from 'react'; +import { useTranslation } from 'react-i18next'; +import React from 'react'; +import { + BooleanIcon, + CombinationIcon, + NumberIcon, + ObjectIcon, + PlusIcon, + StringIcon, +} from '@studio/icons'; +import { useSchemaEditorAppContext } from '../../../hooks/useSchemaEditorAppContext'; +import { useAddProperty } from '../../../hooks/useAddProperty'; +import { FieldType, ObjectKind, SchemaModel } from '@altinn/schema-model'; +import type { TranslationKey } from '@altinn-studio/language/type'; + +type AddNodeMenuProps = HeadingRowProps; + +type AddNodeMenuItemProps = { + titleKey: TranslationKey; + icon: ReactNode; + action: () => void; +}; + +export const AddNodeMenu = ({ schemaPointer }: AddNodeMenuProps) => { + const { t } = useTranslation(); + const addNodeMenuItems = useAddNodeMenuItems(schemaPointer); + + return ( + , + variant: 'secondary', + children: t('schema_editor.add_node_of_type'), + }} + > + {addNodeMenuItems.map((item) => ( + + ))} + + ); +}; + +const useAddNodeMenuItems = (schemaPointer: string): AddNodeMenuItemProps[] => { + const { setSelectedUniquePointer } = useSchemaEditorAppContext(); + const addNode = useAddProperty(); + + const addAndSelectNode = (...params: Parameters) => { + const newPointer = addNode(...params); + if (newPointer) { + const newUniquePointer = SchemaModel.getUniquePointer(newPointer); + setSelectedUniquePointer(newUniquePointer); + } + }; + + return [ + { + titleKey: 'schema_editor.object', + icon: , + action: () => addAndSelectNode(ObjectKind.Field, FieldType.Object, schemaPointer), + }, + { + titleKey: 'schema_editor.string', + icon: , + action: () => addAndSelectNode(ObjectKind.Field, FieldType.String, schemaPointer), + }, + { + titleKey: 'schema_editor.integer', + icon: , + action: () => addAndSelectNode(ObjectKind.Field, FieldType.Integer, schemaPointer), + }, + { + titleKey: 'schema_editor.number', + icon: , + action: () => addAndSelectNode(ObjectKind.Field, FieldType.Number, schemaPointer), + }, + { + titleKey: 'schema_editor.boolean', + icon: , + action: () => addAndSelectNode(ObjectKind.Field, FieldType.Boolean, schemaPointer), + }, + { + titleKey: 'schema_editor.combination', + icon: , + action: () => addAndSelectNode(ObjectKind.Combination, undefined, schemaPointer), + }, + ]; +}; + +const AddNodeMenuItem = ({ titleKey, icon, action }: AddNodeMenuItemProps) => { + const { t } = useTranslation(); + return ( + + {t(titleKey)} + + ); +}; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index a718d113972..d56b7b629fb 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -1,40 +1,18 @@ import classes from './HeadingRow.module.css'; import { NodeIcon } from '../../NodeIcon'; -import type { ReactNode } from 'react'; import React from 'react'; import { useSchemaEditorAppContext } from '../../../hooks/useSchemaEditorAppContext'; import { useDeleteDataModelMutation } from '../../../../../../app-development/hooks/mutations'; -import { - extractNameFromPointer, - FieldType, - isNodeValidParent, - ObjectKind, - ROOT_POINTER, - SchemaModel, -} from '@altinn/schema-model'; +import { extractNameFromPointer, isNodeValidParent, ROOT_POINTER } from '@altinn/schema-model'; import { useTranslation } from 'react-i18next'; -import { - StudioButton, - StudioDeleteButton, - StudioDropdownMenu, - StudioHeading, -} from '@studio/components'; -import { - BooleanIcon, - CombinationIcon, - NumberIcon, - ObjectIcon, - PlusIcon, - StringIcon, -} from '@studio/icons'; +import { StudioButton, StudioDeleteButton, StudioHeading } from '@studio/components'; import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; -import type { TranslationKey } from '@altinn-studio/language/type'; -import { useAddProperty } from '../../../hooks/useAddProperty'; import cn from 'classnames'; import { removeDataTypeIdsToSign } from 'app-shared/utils/bpmnUtils'; import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useUpdateBpmn } from 'app-shared/hooks/useUpdateBpmn'; +import { AddNodeMenu } from './AddNodeMenu'; export interface HeadingRowProps { schemaPointer?: string; @@ -70,89 +48,6 @@ export const HeadingRow = ({ schemaPointer }: HeadingRowProps) => { ); }; -type AddNodeMenuProps = HeadingRowProps; - -type AddNodeMenuItemProps = { - titleKey: TranslationKey; - icon: ReactNode; - action: () => void; -}; - -const AddNodeMenu = ({ schemaPointer }: AddNodeMenuProps) => { - const { t } = useTranslation(); - const addNodeMenuItems = useAddNodeMenuItems(schemaPointer); - - return ( - , - variant: 'secondary', - children: t('schema_editor.add_node_of_type'), - }} - > - {addNodeMenuItems.map((item) => ( - - ))} - - ); -}; - -const useAddNodeMenuItems = (schemaPointer: string): AddNodeMenuItemProps[] => { - const { setSelectedUniquePointer } = useSchemaEditorAppContext(); - const addNode = useAddProperty(); - - const addAndSelectNode = (...params: Parameters) => { - const newPointer = addNode(...params); - if (newPointer) { - const newUniquePointer = SchemaModel.getUniquePointer(newPointer); - setSelectedUniquePointer(newUniquePointer); - } - }; - - return [ - { - titleKey: 'schema_editor.object', - icon: , - action: () => addAndSelectNode(ObjectKind.Field, FieldType.Object, schemaPointer), - }, - { - titleKey: 'schema_editor.string', - icon: , - action: () => addAndSelectNode(ObjectKind.Field, FieldType.String, schemaPointer), - }, - { - titleKey: 'schema_editor.integer', - icon: , - action: () => addAndSelectNode(ObjectKind.Field, FieldType.Integer, schemaPointer), - }, - { - titleKey: 'schema_editor.number', - icon: , - action: () => addAndSelectNode(ObjectKind.Field, FieldType.Number, schemaPointer), - }, - { - titleKey: 'schema_editor.boolean', - icon: , - action: () => addAndSelectNode(ObjectKind.Field, FieldType.Boolean, schemaPointer), - }, - { - titleKey: 'schema_editor.combination', - icon: , - action: () => addAndSelectNode(ObjectKind.Combination, undefined, schemaPointer), - }, - ]; -}; - -const AddNodeMenuItem = ({ titleKey, icon, action }: AddNodeMenuItemProps) => { - const { t } = useTranslation(); - return ( - - {t(titleKey)} - - ); -}; - const DeleteTypeButton = ({ schemaPointer }: HeadingRowProps) => { const { t } = useTranslation(); const savableModel = useSavableSchemaModel(); From 9d281287fd6230737cd40ea8aa4ff55d2647a390 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Wed, 6 Nov 2024 18:56:57 +0100 Subject: [PATCH 19/22] Move delete buttons into their own tsx files --- .../HeadingRow/DeleteModelButton.tsx | 38 +++++++++++ .../NodePanel/HeadingRow/DeleteTypeButton.tsx | 32 +++++++++ .../NodePanel/HeadingRow/HeadingRow.tsx | 67 +------------------ 3 files changed, 73 insertions(+), 64 deletions(-) create mode 100644 frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx create mode 100644 frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteTypeButton.tsx diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx new file mode 100644 index 00000000000..f2aeeaf2191 --- /dev/null +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx @@ -0,0 +1,38 @@ +import { useDeleteDataModelMutation } from 'app-development/hooks/mutations'; +import { useDataModelToolbarContext } from '../../../contexts/DataModelToolbarContext'; +import { useTranslation } from 'react-i18next'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; +import { useUpdateBpmn } from 'app-shared/hooks/useUpdateBpmn'; +import { removeDataTypeIdsToSign } from 'app-shared/utils/bpmnUtils'; +import { StudioDeleteButton } from '@studio/components'; +import React from 'react'; + +export const DeleteModelButton = () => { + const { t } = useTranslation(); + const { selectedOption } = useDataModelToolbarContext(); + const { mutate } = useDeleteDataModelMutation(); + const { org, app } = useStudioEnvironmentParams(); + const updateBpmn = useUpdateBpmn(org, app); + + const modelPath = selectedOption?.value.repositoryRelativeUrl; + const schemaName = selectedOption?.value && selectedOption?.label; + + const handleDeleteModel = async () => { + mutate(modelPath, { + onSuccess: async () => { + await updateBpmn(removeDataTypeIdsToSign([schemaName])); + }, + }); + }; + + return ( + + {t('general.delete')} + + ); +}; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteTypeButton.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteTypeButton.tsx new file mode 100644 index 00000000000..51ea5415362 --- /dev/null +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteTypeButton.tsx @@ -0,0 +1,32 @@ +import { StudioDeleteButton } from '@studio/components'; +import type { HeadingRowProps } from './HeadingRow'; +import { useTranslation } from 'react-i18next'; +import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; +import { useSchemaEditorAppContext } from '../../../hooks/useSchemaEditorAppContext'; +import React from 'react'; + +export const DeleteTypeButton = ({ schemaPointer }: HeadingRowProps) => { + const { t } = useTranslation(); + const savableModel = useSavableSchemaModel(); + const { setSelectedUniquePointer, setSelectedTypePointer } = useSchemaEditorAppContext(); + + const isInUse = savableModel.hasReferringNodes(schemaPointer); + + const handleDeleteType = () => { + setSelectedUniquePointer(null); + setSelectedTypePointer(null); + savableModel.deleteNode(schemaPointer); + }; + + return ( + + {t('general.delete')} + + ); +}; diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index d56b7b629fb..86cdf9f56c7 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -2,17 +2,12 @@ import classes from './HeadingRow.module.css'; import { NodeIcon } from '../../NodeIcon'; import React from 'react'; import { useSchemaEditorAppContext } from '../../../hooks/useSchemaEditorAppContext'; -import { useDeleteDataModelMutation } from '../../../../../../app-development/hooks/mutations'; import { extractNameFromPointer, isNodeValidParent, ROOT_POINTER } from '@altinn/schema-model'; -import { useTranslation } from 'react-i18next'; -import { StudioButton, StudioDeleteButton, StudioHeading } from '@studio/components'; -import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; +import { StudioButton, StudioHeading } from '@studio/components'; import cn from 'classnames'; -import { removeDataTypeIdsToSign } from 'app-shared/utils/bpmnUtils'; -import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; -import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; -import { useUpdateBpmn } from 'app-shared/hooks/useUpdateBpmn'; import { AddNodeMenu } from './AddNodeMenu'; +import { DeleteTypeButton } from './DeleteTypeButton'; +import { DeleteModelButton } from './DeleteModelButton'; export interface HeadingRowProps { schemaPointer?: string; @@ -47,59 +42,3 @@ export const HeadingRow = ({ schemaPointer }: HeadingRowProps) => {
); }; - -const DeleteTypeButton = ({ schemaPointer }: HeadingRowProps) => { - const { t } = useTranslation(); - const savableModel = useSavableSchemaModel(); - const { setSelectedUniquePointer, setSelectedTypePointer } = useSchemaEditorAppContext(); - - const isInUse = savableModel.hasReferringNodes(schemaPointer); - - const handleDeleteType = () => { - setSelectedUniquePointer(null); - setSelectedTypePointer(null); - savableModel.deleteNode(schemaPointer); - }; - - return ( - - {t('general.delete')} - - ); -}; - -const DeleteModelButton = () => { - const { t } = useTranslation(); - const { selectedOption } = useDataModelToolbarContext(); - const { mutate } = useDeleteDataModelMutation(); - const { org, app } = useStudioEnvironmentParams(); - const updateBpmn = useUpdateBpmn(org, app); - - const modelPath = selectedOption?.value.repositoryRelativeUrl; - const schemaName = selectedOption?.value && selectedOption?.label; - - const handleDeleteModel = async () => { - mutate(modelPath, { - onSuccess: async () => { - await updateBpmn(removeDataTypeIdsToSign([schemaName])); - }, - }); - }; - - return ( - - {t('general.delete')} - - ); -}; From ada7154f904e84fff627ebc8fb5574f6f99daa1a Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Wed, 6 Nov 2024 19:58:10 +0100 Subject: [PATCH 20/22] Move selectedModelName and selectedTypeName into context --- .../SchemaEditorWithToolbar.tsx | 1 - .../SelectedSchemaEditor.tsx | 14 +----- .../TopToolbar/TopToolbar.tsx | 46 ++++++------------- frontend/language/src/nb.json | 2 +- .../schema-editor/src/SchemaEditorApp.tsx | 8 ++-- .../HeadingRow/DeleteModelButton.tsx | 7 ++- .../src/contexts/DataModelToolbarContext.tsx | 17 ++++++- 7 files changed, 40 insertions(+), 55 deletions(-) diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx index ec575a5a2dc..768d376a82b 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx @@ -19,7 +19,6 @@ export const SchemaEditorWithToolbar = ({ dataModels, }: SchemaEditorWithToolbarProps) => { const [createNewOpen, setCreateNewOpen] = useState(false); - // const [selectedOption, setSelectedOption] = useState(undefined); const { selectedOption, setSelectedOption } = useDataModelToolbarContext(); const [schemaGenerationErrorMessages, setSchemaGenerationErrorMessages] = useState([]); const { mutate: addXsdFromRepo } = useAddXsdMutation(); diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx index 7059ac93b0b..7052d91e4f0 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx @@ -16,7 +16,6 @@ import { useQueryClient } from '@tanstack/react-query'; import { QueryKey } from 'app-shared/types/QueryKey'; import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { mergeJsonAndXsdData } from 'app-development/utils/metadataUtils'; -import { extractFilename, removeSchemaExtension } from 'app-shared/utils/filenameUtils'; export interface SelectedSchemaEditorProps { modelPath: string; } @@ -101,16 +100,5 @@ const SchemaEditorWithDebounce = ({ jsonSchema, modelPath }: SchemaEditorWithDeb if (doesModelExist()) saveFunction(); }); - return ( - - ); -}; - -const extractModelNameFromPath = (path: string): string => { - const filename = extractFilename(path); - return removeSchemaExtension(filename); + return ; }; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index c6dcc659276..9a87973ceef 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -38,12 +38,13 @@ export function TopToolbar({ }: TopToolbarProps) { const prevDataModels = usePrevious(dataModels); const { selectedTypePointer } = useDataModelToolbarContext(); - const showTypeToolbar: boolean = !!selectedTypePointer; useEffect(() => { setSelectedOption(computeSelectedOption(selectedOption, dataModels, prevDataModels)); }, [selectedOption, dataModels, prevDataModels, setSelectedOption]); + const showTypeToolbar: boolean = !!selectedTypePointer; + return (
{ - const { setSelectedTypePointer, setSelectedUniquePointer, selectedUniquePointer } = - useDataModelToolbarContext(); + const { setSelectedTypePointer, setSelectedUniquePointer } = useDataModelToolbarContext(); const navigateToDataModelRoot = () => { setSelectedUniquePointer(undefined); setSelectedTypePointer(undefined); }; - const typeName = selectedUniquePointer.substring(selectedUniquePointer.lastIndexOf('/') + 1); - const showBreadcrumbs = false; return (
{showBreadcrumbs ? ( - + ) : ( - + )}
); @@ -102,40 +92,34 @@ const TypeToolbar = ({ dataModelName }: TypeToolbarProps) => { type BreadcrumbsToolbarProps = { navigateToDataModelRoot: () => void; - dataModelName: string; - typeName: string; }; -const BreadcrumbsToolbar = ({ - navigateToDataModelRoot, - dataModelName, - typeName, -}: BreadcrumbsToolbarProps) => { +const BreadcrumbsToolbar = ({ navigateToDataModelRoot }: BreadcrumbsToolbarProps) => { + const { selectedModelName, selectedTypeName } = useDataModelToolbarContext(); + return (
navigateToDataModelRoot()}> - Datamodell: {dataModelName} + Datamodell: {selectedModelName} - Type: {typeName} + Type: {selectedTypeName}
); }; -const BackButtonToolbar = ({ - navigateToDataModelRoot, - dataModelName, - typeName, -}: BreadcrumbsToolbarProps) => { +const BackButtonToolbar = ({ navigateToDataModelRoot }: BreadcrumbsToolbarProps) => { + const { selectedModelName, selectedTypeName } = useDataModelToolbarContext(); + return ( <> navigateToDataModelRoot()} icon={}> - Tilbake til datamodell {dataModelName} + Tilbake til datamodell {selectedModelName} ); diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 802747e24bf..ff07277c6fa 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -833,7 +833,7 @@ "schema_editor.delete": "Slett", "schema_editor.delete_data_model": "Slett datamodell", "schema_editor.delete_field": "Slett felt", - "schema_editor.delete_model_confirm": "Er du sikker på at du vil slette datamodellen {{schemaName}}?", + "schema_editor.delete_model_confirm": "Er du sikker på at du vil slette datamodellen {{selectedModelName}}?", "schema_editor.depth_error": "Du kan ikke plassere gruppen her, fordi skjemaet får for mange nivåer.", "schema_editor.description": "Tekst", "schema_editor.descriptive_fields": "Beskrivende felter", diff --git a/frontend/packages/schema-editor/src/SchemaEditorApp.tsx b/frontend/packages/schema-editor/src/SchemaEditorApp.tsx index 0afc794ac6e..08108994e97 100644 --- a/frontend/packages/schema-editor/src/SchemaEditorApp.tsx +++ b/frontend/packages/schema-editor/src/SchemaEditorApp.tsx @@ -11,16 +11,16 @@ import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataM export type SchemaEditorAppProps = { jsonSchema: JsonSchema; - name: string; save: (model: JsonSchema) => void; }; -export function SchemaEditorApp({ jsonSchema, name, save }: SchemaEditorAppProps) { +export function SchemaEditorApp({ jsonSchema, save }: SchemaEditorAppProps) { const { selectedTypePointer, setSelectedTypePointer, selectedUniquePointer, setSelectedUniquePointer, + selectedModelName, } = useDataModelToolbarContext(); const value = useMemo( @@ -31,7 +31,7 @@ export function SchemaEditorApp({ jsonSchema, name, save }: SchemaEditorAppProps setSelectedTypePointer, selectedUniquePointer, setSelectedUniquePointer, - name, + name: selectedModelName, }), [ jsonSchema, @@ -39,7 +39,7 @@ export function SchemaEditorApp({ jsonSchema, name, save }: SchemaEditorAppProps setSelectedTypePointer, selectedUniquePointer, setSelectedUniquePointer, - name, + selectedModelName, save, ], ); diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx index f2aeeaf2191..f86e3d21d8a 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx @@ -9,18 +9,17 @@ import React from 'react'; export const DeleteModelButton = () => { const { t } = useTranslation(); - const { selectedOption } = useDataModelToolbarContext(); + const { selectedOption, selectedModelName } = useDataModelToolbarContext(); const { mutate } = useDeleteDataModelMutation(); const { org, app } = useStudioEnvironmentParams(); const updateBpmn = useUpdateBpmn(org, app); const modelPath = selectedOption?.value.repositoryRelativeUrl; - const schemaName = selectedOption?.value && selectedOption?.label; const handleDeleteModel = async () => { mutate(modelPath, { onSuccess: async () => { - await updateBpmn(removeDataTypeIdsToSign([schemaName])); + await updateBpmn(removeDataTypeIdsToSign([selectedModelName])); }, }); }; @@ -28,7 +27,7 @@ export const DeleteModelButton = () => { return ( diff --git a/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx index 43301ba6ea1..7ecca860510 100644 --- a/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx +++ b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx @@ -1,5 +1,5 @@ import React, { createContext, useContext, useState } from 'react'; -import { MetadataOption } from '../../../../app-development/types/MetadataOption'; +import type { MetadataOption } from '../../../../app-development/types/MetadataOption'; type DataModelToolbarContextProps = { selectedTypePointer: string; @@ -8,6 +8,8 @@ type DataModelToolbarContextProps = { setSelectedUniquePointer: React.Dispatch>; selectedOption: MetadataOption; setSelectedOption: React.Dispatch>; + selectedModelName: string | undefined; + selectedTypeName: string | undefined; }; const DataModelToolbarContext = createContext(null); @@ -23,6 +25,9 @@ export const DataModelToolbarContextProvider = ({ const [selectedUniquePointer, setSelectedUniquePointer] = useState(null); const [selectedOption, setSelectedOption] = useState(null); + const selectedModelName: string | undefined = selectedOption?.label ?? undefined; + const selectedTypeName: string | undefined = getTypeName(selectedUniquePointer); + const value = { selectedTypePointer, setSelectedTypePointer, @@ -30,6 +35,8 @@ export const DataModelToolbarContextProvider = ({ setSelectedUniquePointer, selectedOption, setSelectedOption, + selectedModelName, + selectedTypeName, }; return ( @@ -46,3 +53,11 @@ export const useDataModelToolbarContext = (): Partial { + if (selectedUniquePointer) { + const indexOfLastDash = selectedUniquePointer.lastIndexOf('/'); + return selectedUniquePointer.substring(indexOfLastDash + 1); + } + return undefined; +}; From 926b904cf8f6073653e5a1c76e31ce2fea93fb40 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Wed, 6 Nov 2024 20:17:52 +0100 Subject: [PATCH 21/22] Move modelPath into context --- .../features/dataModelling/DataModelling.tsx | 6 +++--- .../SchemaEditorWithToolbar.tsx | 5 ++--- .../TopToolbar/TopToolbar.tsx | 14 ++++++-------- .../schema-editor/src/SchemaEditorApp.tsx | 4 ++-- .../HeadingRow/DeleteModelButton.tsx | 6 ++---- .../src/contexts/DataModelToolbarContext.tsx | 19 +++++++++---------- 6 files changed, 24 insertions(+), 30 deletions(-) diff --git a/frontend/app-development/features/dataModelling/DataModelling.tsx b/frontend/app-development/features/dataModelling/DataModelling.tsx index 484982a165e..86efd2a365c 100644 --- a/frontend/app-development/features/dataModelling/DataModelling.tsx +++ b/frontend/app-development/features/dataModelling/DataModelling.tsx @@ -8,7 +8,7 @@ import { useDataModelsJsonQuery, useDataModelsXsdQuery } from 'app-shared/hooks/ import { useParams } from 'react-router-dom'; import { mergeQueryStatuses } from 'app-shared/utils/tanstackQueryUtils'; import { mergeJsonAndXsdData } from '../../utils/metadataUtils'; -import { DataModelToolbarContextProvider } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; +import { DataModelContextProvider } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; interface DataModellingProps { createPathOption?: boolean; @@ -37,9 +37,9 @@ export function DataModelling({ createPathOption = false }: DataModellingProps): case 'success': { const data = mergeJsonAndXsdData(jsonData, xsdData); return ( - + - + ); } } diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx index 768d376a82b..737808cb270 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaEditorWithToolbar.tsx @@ -7,7 +7,7 @@ import type { DataModelMetadata } from 'app-shared/types/DataModelMetadata'; import { SchemaGenerationErrorsPanel } from './SchemaGenerationErrorsPanel'; import { useAddXsdMutation } from '../../../hooks/mutations/useAddXsdMutation'; import { isXsdFile } from 'app-shared/utils/filenameUtils'; -import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; +import { useDataModelContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export interface SchemaEditorWithToolbarProps { createPathOption?: boolean; @@ -19,7 +19,7 @@ export const SchemaEditorWithToolbar = ({ dataModels, }: SchemaEditorWithToolbarProps) => { const [createNewOpen, setCreateNewOpen] = useState(false); - const { selectedOption, setSelectedOption } = useDataModelToolbarContext(); + const { selectedOption, setSelectedOption, modelPath } = useDataModelContext(); const [schemaGenerationErrorMessages, setSchemaGenerationErrorMessages] = useState([]); const { mutate: addXsdFromRepo } = useAddXsdMutation(); @@ -28,7 +28,6 @@ export const SchemaEditorWithToolbar = ({ ) ? selectedOption : undefined; - const modelPath = existingSelectedOption?.value?.repositoryRelativeUrl; useEffect(() => { dataModels.forEach((model) => { diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx index 9a87973ceef..0a7c41f0d03 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/TopToolbar.tsx @@ -15,7 +15,7 @@ import { useTranslation } from 'react-i18next'; import { Label, Link } from '@digdir/designsystemet-react'; import { ArrowLeftIcon, ChevronRightIcon } from '@studio/icons'; import cn from 'classnames'; -import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; +import { useDataModelContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export interface TopToolbarProps { createNewOpen: boolean; @@ -37,7 +37,7 @@ export function TopToolbar({ onSetSchemaGenerationErrorMessages, }: TopToolbarProps) { const prevDataModels = usePrevious(dataModels); - const { selectedTypePointer } = useDataModelToolbarContext(); + const { selectedTypePointer } = useDataModelContext(); useEffect(() => { setSelectedOption(computeSelectedOption(selectedOption, dataModels, prevDataModels)); @@ -70,7 +70,7 @@ type TypeToolbarProps = { }; const TypeToolbar = ({ dataModelName }: TypeToolbarProps) => { - const { setSelectedTypePointer, setSelectedUniquePointer } = useDataModelToolbarContext(); + const { setSelectedTypePointer, setSelectedUniquePointer } = useDataModelContext(); const navigateToDataModelRoot = () => { setSelectedUniquePointer(undefined); @@ -95,7 +95,7 @@ type BreadcrumbsToolbarProps = { }; const BreadcrumbsToolbar = ({ navigateToDataModelRoot }: BreadcrumbsToolbarProps) => { - const { selectedModelName, selectedTypeName } = useDataModelToolbarContext(); + const { selectedModelName, selectedTypeName } = useDataModelContext(); return (
@@ -111,7 +111,7 @@ const BreadcrumbsToolbar = ({ navigateToDataModelRoot }: BreadcrumbsToolbarProps }; const BackButtonToolbar = ({ navigateToDataModelRoot }: BreadcrumbsToolbarProps) => { - const { selectedModelName, selectedTypeName } = useDataModelToolbarContext(); + const { selectedModelName, selectedTypeName } = useDataModelContext(); return ( <> @@ -140,12 +140,10 @@ const DataModelToolbar = ({ createPathOption, onSetSchemaGenerationErrorMessages, }: DataModelToolbarProps) => { - const { selectedOption, setSelectedOption } = useDataModelToolbarContext(); + const { selectedOption, setSelectedOption, modelPath } = useDataModelContext(); const { t } = useTranslation(); const { mutate: createDataModel } = useCreateDataModelMutation(); - const modelPath = selectedOption?.value.repositoryRelativeUrl; - const handleCreateSchema = (model: CreateDataModelMutationArgs) => { createDataModel(model); setCreateNewOpen(false); diff --git a/frontend/packages/schema-editor/src/SchemaEditorApp.tsx b/frontend/packages/schema-editor/src/SchemaEditorApp.tsx index 08108994e97..f8dcd0eb360 100644 --- a/frontend/packages/schema-editor/src/SchemaEditorApp.tsx +++ b/frontend/packages/schema-editor/src/SchemaEditorApp.tsx @@ -7,7 +7,7 @@ import { SchemaEditorAppContext } from './contexts/SchemaEditorAppContext'; import type { JsonSchema } from 'app-shared/types/JsonSchema'; import { buildJsonSchema, buildUiSchema, SchemaModel } from '@altinn/schema-model'; import { SchemaEditor } from './components/SchemaEditor'; -import { useDataModelToolbarContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; +import { useDataModelContext } from '@altinn/schema-editor/contexts/DataModelToolbarContext'; export type SchemaEditorAppProps = { jsonSchema: JsonSchema; @@ -21,7 +21,7 @@ export function SchemaEditorApp({ jsonSchema, save }: SchemaEditorAppProps) { selectedUniquePointer, setSelectedUniquePointer, selectedModelName, - } = useDataModelToolbarContext(); + } = useDataModelContext(); const value = useMemo( () => ({ diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx index f86e3d21d8a..2b1081269ca 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/DeleteModelButton.tsx @@ -1,5 +1,5 @@ import { useDeleteDataModelMutation } from 'app-development/hooks/mutations'; -import { useDataModelToolbarContext } from '../../../contexts/DataModelToolbarContext'; +import { useDataModelContext } from '../../../contexts/DataModelToolbarContext'; import { useTranslation } from 'react-i18next'; import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useUpdateBpmn } from 'app-shared/hooks/useUpdateBpmn'; @@ -9,13 +9,11 @@ import React from 'react'; export const DeleteModelButton = () => { const { t } = useTranslation(); - const { selectedOption, selectedModelName } = useDataModelToolbarContext(); + const { selectedModelName, modelPath } = useDataModelContext(); const { mutate } = useDeleteDataModelMutation(); const { org, app } = useStudioEnvironmentParams(); const updateBpmn = useUpdateBpmn(org, app); - const modelPath = selectedOption?.value.repositoryRelativeUrl; - const handleDeleteModel = async () => { mutate(modelPath, { onSuccess: async () => { diff --git a/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx index 7ecca860510..345fbe60d10 100644 --- a/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx +++ b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx @@ -1,30 +1,30 @@ import React, { createContext, useContext, useState } from 'react'; import type { MetadataOption } from '../../../../app-development/types/MetadataOption'; -type DataModelToolbarContextProps = { +type DataModelContextProps = { selectedTypePointer: string; setSelectedTypePointer: React.Dispatch>; selectedUniquePointer: string; setSelectedUniquePointer: React.Dispatch>; selectedOption: MetadataOption; setSelectedOption: React.Dispatch>; + modelPath: string | undefined; selectedModelName: string | undefined; selectedTypeName: string | undefined; }; -const DataModelToolbarContext = createContext(null); +const DataModelContext = createContext(null); export type DataModelToolbarContextProviderProps = { children: React.ReactNode; }; -export const DataModelToolbarContextProvider = ({ - children, -}: DataModelToolbarContextProviderProps) => { +export const DataModelContextProvider = ({ children }: DataModelToolbarContextProviderProps) => { const [selectedTypePointer, setSelectedTypePointer] = useState(null); const [selectedUniquePointer, setSelectedUniquePointer] = useState(null); const [selectedOption, setSelectedOption] = useState(null); + const modelPath: string | undefined = selectedOption?.value?.repositoryRelativeUrl; const selectedModelName: string | undefined = selectedOption?.label ?? undefined; const selectedTypeName: string | undefined = getTypeName(selectedUniquePointer); @@ -35,17 +35,16 @@ export const DataModelToolbarContextProvider = ({ setSelectedUniquePointer, selectedOption, setSelectedOption, + modelPath, selectedModelName, selectedTypeName, }; - return ( - {children} - ); + return {children}; }; -export const useDataModelToolbarContext = (): Partial => { - const context = useContext(DataModelToolbarContext); +export const useDataModelContext = (): Partial => { + const context = useContext(DataModelContext); if (context === undefined) { throw new Error( 'useDataModelToolbarContext must be used within a useDataModelToolbarContextProvider', From 293f5016ff18e44aee902355b89d07653fdfd414 Mon Sep 17 00:00:00 2001 From: Erling Hauan Date: Wed, 6 Nov 2024 20:59:01 +0100 Subject: [PATCH 22/22] Move SaveSchemaWithDebounce into a hook --- .../SelectedSchemaEditor.tsx | 63 ++---------------- .../useSaveSchemaWithDebounce.ts | 65 +++++++++++++++++++ .../src/contexts/DataModelToolbarContext.tsx | 20 +++--- 3 files changed, 78 insertions(+), 70 deletions(-) create mode 100644 frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/useSaveSchemaWithDebounce.ts diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx index 7052d91e4f0..0ee02a129fe 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx @@ -1,21 +1,12 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import React from 'react'; import { useSchemaQuery } from '../../../hooks/queries'; -import { useSchemaMutation } from '../../../hooks/mutations'; import { StudioCenter, StudioError, StudioPageSpinner } from '@studio/components'; import { ErrorMessage, Paragraph } from '@digdir/designsystemet-react'; import { SchemaEditorApp } from '@altinn/schema-editor/SchemaEditorApp'; import { useTranslation } from 'react-i18next'; -import { AUTOSAVE_DEBOUNCE_INTERVAL_MILLISECONDS } from 'app-shared/constants'; import type { JsonSchema } from 'app-shared/types/JsonSchema'; -import { useOnUnmount } from 'app-shared/hooks/useOnUnmount'; -import type { - DataModelMetadataJson, - DataModelMetadataXsd, -} from 'app-shared/types/DataModelMetadata'; -import { useQueryClient } from '@tanstack/react-query'; -import { QueryKey } from 'app-shared/types/QueryKey'; -import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; -import { mergeJsonAndXsdData } from 'app-development/utils/metadataUtils'; +import { useSaveSchemaWithDebounce } from './useSaveSchemaWithDebounce'; + export interface SelectedSchemaEditorProps { modelPath: string; } @@ -52,53 +43,7 @@ interface SchemaEditorWithDebounceProps { } const SchemaEditorWithDebounce = ({ jsonSchema, modelPath }: SchemaEditorWithDebounceProps) => { - const { org, app } = useStudioEnvironmentParams(); - const { mutate } = useSchemaMutation(); - const queryClient = useQueryClient(); - const [model, setModel] = useState(jsonSchema); - const saveTimeoutRef = useRef>(); - const updatedModel = useRef(jsonSchema); - - useEffect(() => { - setModel(jsonSchema); - }, [jsonSchema]); - - const saveFunction = useCallback( - () => mutate({ modelPath, model: updatedModel.current }), - [modelPath, mutate], - ); - - const saveSchema = useCallback( - (newModel: JsonSchema) => { - setModel(newModel); - updatedModel.current = newModel; - clearTimeout(saveTimeoutRef.current); - saveTimeoutRef.current = setTimeout(() => { - saveFunction(); - }, AUTOSAVE_DEBOUNCE_INTERVAL_MILLISECONDS); - }, - [saveFunction], - ); - - const doesModelExist = useCallback(() => { - const jsonModels: DataModelMetadataJson[] = queryClient.getQueryData([ - QueryKey.DataModelsJson, - org, - app, - ]); - const xsdModels: DataModelMetadataXsd[] = queryClient.getQueryData([ - QueryKey.DataModelsXsd, - org, - app, - ]); - const metadataList = mergeJsonAndXsdData(jsonModels, xsdModels); - return metadataList.some((dataModel) => dataModel.repositoryRelativeUrl === modelPath); - }, [queryClient, org, app, modelPath]); - - useOnUnmount(() => { - clearTimeout(saveTimeoutRef.current); - if (doesModelExist()) saveFunction(); - }); + const { model, saveSchema } = useSaveSchemaWithDebounce(jsonSchema, modelPath); return ; }; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/useSaveSchemaWithDebounce.ts b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/useSaveSchemaWithDebounce.ts new file mode 100644 index 00000000000..0296cd9c688 --- /dev/null +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/useSaveSchemaWithDebounce.ts @@ -0,0 +1,65 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useSchemaMutation } from '../../../hooks/mutations'; +import { AUTOSAVE_DEBOUNCE_INTERVAL_MILLISECONDS } from 'app-shared/constants'; +import type { JsonSchema } from 'app-shared/types/JsonSchema'; +import { useOnUnmount } from 'app-shared/hooks/useOnUnmount'; +import type { + DataModelMetadataJson, + DataModelMetadataXsd, +} from 'app-shared/types/DataModelMetadata'; +import { useQueryClient } from '@tanstack/react-query'; +import { QueryKey } from 'app-shared/types/QueryKey'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; +import { mergeJsonAndXsdData } from 'app-development/utils/metadataUtils'; + +export const useSaveSchemaWithDebounce = (jsonSchema: JsonSchema, modelPath: string) => { + const { org, app } = useStudioEnvironmentParams(); + const { mutate } = useSchemaMutation(); + const queryClient = useQueryClient(); + const [model, setModel] = useState(jsonSchema); + const saveTimeoutRef = useRef>(); + const updatedModel = useRef(jsonSchema); + + useEffect(() => { + setModel(jsonSchema); + }, [jsonSchema]); + + const saveFunction = useCallback( + () => mutate({ modelPath, model: updatedModel.current }), + [modelPath, mutate], + ); + + const saveSchema = useCallback( + (newModel: JsonSchema) => { + setModel(newModel); + updatedModel.current = newModel; + clearTimeout(saveTimeoutRef.current); + saveTimeoutRef.current = setTimeout(() => { + saveFunction(); + }, AUTOSAVE_DEBOUNCE_INTERVAL_MILLISECONDS); + }, + [saveFunction], + ); + + const doesModelExist = useCallback(() => { + const jsonModels: DataModelMetadataJson[] = queryClient.getQueryData([ + QueryKey.DataModelsJson, + org, + app, + ]); + const xsdModels: DataModelMetadataXsd[] = queryClient.getQueryData([ + QueryKey.DataModelsXsd, + org, + app, + ]); + const metadataList = mergeJsonAndXsdData(jsonModels, xsdModels); + return metadataList.some((dataModel) => dataModel.repositoryRelativeUrl === modelPath); + }, [queryClient, org, app, modelPath]); + + useOnUnmount(() => { + clearTimeout(saveTimeoutRef.current); + if (doesModelExist()) saveFunction(); + }); + + return { saveSchema, model }; +}; diff --git a/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx index 345fbe60d10..ac9f3bf2703 100644 --- a/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx +++ b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx @@ -43,20 +43,18 @@ export const DataModelContextProvider = ({ children }: DataModelToolbarContextPr return {children}; }; +const getTypeName = (uniquePointer?: string | undefined): string | undefined => { + if (uniquePointer) { + const indexOfLastDash = uniquePointer.lastIndexOf('/'); + return uniquePointer.substring(indexOfLastDash + 1); + } + return undefined; +}; + export const useDataModelContext = (): Partial => { const context = useContext(DataModelContext); if (context === undefined) { - throw new Error( - 'useDataModelToolbarContext must be used within a useDataModelToolbarContextProvider', - ); + throw new Error('useDataModelToolbarContext must be used within a useDataModelContextProvider'); } return context; }; - -const getTypeName = (selectedUniquePointer?: string | undefined): string | undefined => { - if (selectedUniquePointer) { - const indexOfLastDash = selectedUniquePointer.lastIndexOf('/'); - return selectedUniquePointer.substring(indexOfLastDash + 1); - } - return undefined; -};