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..721450e4cb7 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,19 @@ .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; + align-items: center; + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); + padding-inline: var(--fds-spacing-6); + gap: var(--fds-spacing-2); } -.toolbar button[class*='toggle'] { - font-size: 1em; - padding-top: 4px; +.blueBackground { + background: var(--fds-colors-blue-100); } -.generateButtonWrapper { - flex: 1; +.modelName { + /*font-weight: 400;*/ } @keyframes fadeOut { @@ -42,14 +34,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..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,29 +50,37 @@ export function TopToolbar({ setCreateNewOpen(false); }; + const showTypeToolbar = false; + return ( -
- - - - -
-
+
+ {showTypeToolbar ? ( + + ) : ( + <> + + + + + {/**/} {modelPath && ( )} -
-
+ + )}
); } + +const VerticalDivider = () => { + return ( +
+ ); +}; + +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.module.css b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.module.css index b0c067040c8..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 @@ -1,26 +1,30 @@ .root { - --gap: var(--fds-spacing-1); - align-items: center; display: flex; - padding: var(--gap) 0; - gap: var(--gap); + align-items: center; + height: var(--subtoolbar-height); + gap: var(--fds-spacing-3); + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); } -.heading { - display: contents; +.headingButton { + display: flex; + font: var(--fds-typography-paragraph-short-large); + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border: 0; } -.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; - font: var(--fds-typography-paragraph-short-large); - min-height: var(--fds-sizing-12); +.headingButton:hover { + background-color: var(--fds-colors-blue-100); } -.root.selected .headingButton { - background-color: var(--studio-treeitem-selected-background-colour); - border-left-color: var(--studio-treeitem-vertical-line-colour-root); +.selected .headingButton { + /*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);*/ } 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..3b9168c6bcd 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, @@ -26,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; @@ -44,7 +49,7 @@ export const HeadingRow = ({ schemaPointer }: HeadingRowProps) => { return (
- + { > {title} - + {isValidParent && } - {!isDataModelRoot && } + + {/*{!isDataModelRoot && }*/}
); }; @@ -171,3 +177,13 @@ const DeleteButton = ({ schemaPointer }: DeleteButtonProps) => { ); }; + +const BackButton = () => ( +
+ }>Tilbake til datamodell +
+); 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..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 { - box-shadow: var(--fds-shadow-small); -} - .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 918c678d557..1cd57aef35f 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/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%; -} diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx b/frontend/packages/schema-editor/src/components/SchemaEditor/SchemaEditor.tsx index 6b287d5be74..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(); @@ -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 2ea6be75947..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,16 @@ height: 100%; } -.noItem { - font-weight: 500; - margin: 18px; +.noSelectionHeadingContainer { + display: flex; + flex-direction: column; + justify-content: center; + padding-inline: var(--fds-spacing-6); + height: var(--subtoolbar-height); + border-bottom: 1px solid var(--fds-semantic-border-neutral-subtle); +} + +.tabHeader { + height: var(--subtoolbar-height); + font-size: var(--fds-typography-heading-small); } 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..9583775cde0 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 propertiesHeader = screen.getByRole('heading', { + name: textMock('schema_editor.properties'), + }); + const noSelectionParagraph = screen.getByText(textMock('schema_editor.no_item_selected')); + + expect(propertiesHeader).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 9480c520805..5bfbe303a77 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/SchemaInspector.tsx @@ -1,3 +1,4 @@ +import type { ReactElement } from 'react'; import React from 'react'; import { Alert, Tabs } from '@digdir/designsystemet-react'; import type { UiSchemaNode } from '@altinn/schema-model'; @@ -5,44 +6,55 @@ 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 { StudioCenter, StudioHeading, StudioParagraph } from '@studio/components'; -export const SchemaInspector = () => { +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.no_item_selected')}

- -
+ <> +
+ + {t('schema_editor.properties')} + +
+ + {t('schema_editor.no_item_selected')} + + ); } - const selectedItem: UiSchemaNode = savableModel.getNodeByUniquePointer(selectedUniquePointer); - const shouldDisplayFieldsTab = isField(selectedItem) && isObject(selectedItem); - return ( - + - {t('schema_editor.properties')} - {t('schema_editor.fields')} + + {t('schema_editor.properties')} + + + {t('schema_editor.fields')} + - {shouldDisplayFieldsTab ? ( - + + {shouldDisplayFieldsTab ? ( - - ) : ( - {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 26856e71376..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,37 +1,20 @@ -.root { - box-sizing: border-box; - padding: 24px 24px; - min-height: 100%; - background: rgba(224, 224, 224, 0.3); - border-right: 1px solid var(--fds-semantic-border-neutral-subtle); -} - -.types { +.headingContainer { display: flex; - flex-direction: column; - align-items: stretch; - gap: 8px; -} - -.addRow { - display: grid; - grid-template-columns: repeat(3, 1fr); + 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); } -.addRowText { - grid-column: 1 / 3; - font-size: 18px; +.addTypeButton { + color: var(--fds-semantic-surface-neutral-inverted); } -.addRowButton { - grid-column: 3; - margin-left: auto; - margin-right: 0; - color: #000000; -} - -.noItem { - font-weight: 500; - margin: 18px; +.typesList { + display: flex; + flex-direction: column; + 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 54e6a29226d..e6f0d463224 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -1,11 +1,10 @@ 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'; 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'; @@ -38,31 +37,21 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { save(schemaModel); }; - if (!schemaItems) { - return ( -
-

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

- -
- ); - } - 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) => ( { /> ))}
-
+ ); };