- {!isDataModelRoot &&
}
-
+
+ {/*{!isDataModelRoot &&
}*/}
+
+ {isNodeValidParent(node) && }
- {isNodeValidParent(node) &&
}
>
);
};
-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/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) => (
{
/>
))}
-
+ >
);
};
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..ac9f3bf2703
--- /dev/null
+++ b/frontend/packages/schema-editor/src/contexts/DataModelToolbarContext.tsx
@@ -0,0 +1,60 @@
+import React, { createContext, useContext, useState } from 'react';
+import type { MetadataOption } from '../../../../app-development/types/MetadataOption';
+
+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 DataModelContext = createContext(null);
+
+export type DataModelToolbarContextProviderProps = {
+ children: React.ReactNode;
+};
+
+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);
+
+ const value = {
+ selectedTypePointer,
+ setSelectedTypePointer,
+ selectedUniquePointer,
+ setSelectedUniquePointer,
+ selectedOption,
+ setSelectedOption,
+ modelPath,
+ selectedModelName,
+ selectedTypeName,
+ };
+
+ 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 useDataModelContextProvider');
+ }
+ return context;
+};