diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaGenerationErrorsPanel.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaGenerationErrorsPanel.tsx index df41c0494cb..e4158409049 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaGenerationErrorsPanel.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SchemaGenerationErrorsPanel.tsx @@ -2,7 +2,7 @@ import classes from './SchemaGenerationErrorsPanel.module.css'; import React from 'react'; import { Alert, ErrorMessage, Paragraph } from '@digdir/design-system-react'; import { Trans, useTranslation } from 'react-i18next'; -import { XMarkIcon } from '@navikt/aksel-icons'; +import { XMarkIcon } from '@studio/icons'; import { StudioButton } from '@studio/components'; export interface SchemaGenerationErrorsPanelProps { diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/CreateNewWrapper.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/CreateNewWrapper.tsx index f95b44e1004..e2485ec668c 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/CreateNewWrapper.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/CreateNewWrapper.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { ErrorMessage, Textfield, LegacyPopover } from '@digdir/design-system-react'; import { useTranslation } from 'react-i18next'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { extractModelNamesFromMetadataList } from '../../../../utils/metadataUtils'; import type { DatamodelMetadata } from 'app-shared/types/DatamodelMetadata'; import { StudioButton } from '@studio/components'; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/DeleteWrapper.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/DeleteWrapper.tsx index 170599f8cfc..69b3f34ebed 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/DeleteWrapper.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/DeleteWrapper.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { StudioButton } from '@studio/components'; -import { TrashIcon } from '@navikt/aksel-icons'; +import { TrashIcon } from '@studio/icons'; import { useDeleteDatamodelMutation } from '../../../../hooks/mutations'; import type { MetadataOption } from '../../../../types/MetadataOption'; import { AltinnConfirmDialog } from 'app-shared/components'; diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/GenerateModelsButton.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/GenerateModelsButton.tsx index 99fefe66440..e4ff00351e6 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/GenerateModelsButton.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/TopToolbar/GenerateModelsButton.tsx @@ -1,5 +1,5 @@ import { Spinner } from '@digdir/design-system-react'; -import { CogIcon } from '@navikt/aksel-icons'; +import { CogIcon } from '@studio/icons'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { useSchemaQuery } from '../../../../hooks/queries'; diff --git a/frontend/app-development/features/overview/components/Documentation.tsx b/frontend/app-development/features/overview/components/Documentation.tsx index 134ba577315..331b88f4986 100644 --- a/frontend/app-development/features/overview/components/Documentation.tsx +++ b/frontend/app-development/features/overview/components/Documentation.tsx @@ -1,7 +1,7 @@ import React from 'react'; import classes from './Documentation.module.css'; import { Heading, Link } from '@digdir/design-system-react'; -import { ExternalLinkIcon } from '@navikt/aksel-icons'; +import { ExternalLinkIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; export const Documentation = () => { diff --git a/frontend/app-development/layout/AppBar/appBarConfig.test.ts b/frontend/app-development/layout/AppBar/appBarConfig.test.ts index 789fdddf411..8e3f7b4a05f 100644 --- a/frontend/app-development/layout/AppBar/appBarConfig.test.ts +++ b/frontend/app-development/layout/AppBar/appBarConfig.test.ts @@ -4,7 +4,7 @@ import { typedLocalStorage } from 'app-shared/utils/webStorage'; import { TopBarMenu } from 'app-shared/enums/TopBarMenu'; import type { TopBarMenuItem } from 'app-shared/types/TopBarMenuItem'; import { RoutePaths } from 'app-development/enums/RoutePaths'; -import { DatabaseIcon } from '@navikt/aksel-icons'; +import { DatabaseIcon } from '@studio/icons'; describe('getTopBarMenu', () => { it('should return all items when provided repository type is "App" which is not hidden behind feature-flags', () => { diff --git a/frontend/app-development/layout/AppBar/appBarConfig.ts b/frontend/app-development/layout/AppBar/appBarConfig.ts index 9cc07b78311..1196b02f5eb 100644 --- a/frontend/app-development/layout/AppBar/appBarConfig.ts +++ b/frontend/app-development/layout/AppBar/appBarConfig.ts @@ -1,6 +1,6 @@ import { RepositoryType } from 'app-shared/types/global'; import { shouldDisplayFeature } from 'app-shared/utils/featureToggleUtils'; -import { DatabaseIcon, Density3Icon, PencilIcon, TenancyIcon } from '@navikt/aksel-icons'; +import { DatabaseIcon, Density3Icon, PencilIcon, TenancyIcon } from '@studio/icons'; import { RoutePaths } from 'app-development/enums/RoutePaths'; import { TopBarMenu } from 'app-shared/enums/TopBarMenu'; import type { TopBarMenuItem } from 'app-shared/types/TopBarMenuItem'; diff --git a/frontend/app-development/layout/SettingsModalButton/SettingsModal/SettingsModal.tsx b/frontend/app-development/layout/SettingsModalButton/SettingsModal/SettingsModal.tsx index b760acb10d7..e44fda9d731 100644 --- a/frontend/app-development/layout/SettingsModalButton/SettingsModal/SettingsModal.tsx +++ b/frontend/app-development/layout/SettingsModalButton/SettingsModal/SettingsModal.tsx @@ -8,7 +8,7 @@ import { TimerStartIcon, ShieldLockIcon, SidebarBothIcon, -} from '@navikt/aksel-icons'; +} from '@studio/icons'; import { StudioModal } from '@studio/components'; import type { LeftNavigationTab } from 'app-shared/types/LeftNavigationTab'; import { LeftNavigationBar } from 'app-shared/components/LeftNavigationBar'; diff --git a/frontend/app-development/layout/SettingsModalButton/SettingsModal/components/Tabs/AboutTab/CreatedFor/CreatedFor.tsx b/frontend/app-development/layout/SettingsModalButton/SettingsModal/components/Tabs/AboutTab/CreatedFor/CreatedFor.tsx index 6de40df82f1..5ef652a8efa 100644 --- a/frontend/app-development/layout/SettingsModalButton/SettingsModal/components/Tabs/AboutTab/CreatedFor/CreatedFor.tsx +++ b/frontend/app-development/layout/SettingsModalButton/SettingsModal/components/Tabs/AboutTab/CreatedFor/CreatedFor.tsx @@ -5,7 +5,7 @@ import { Paragraph } from '@digdir/design-system-react'; import { useTranslation } from 'react-i18next'; import { RepositoryType } from 'app-shared/types/global'; import type { Repository } from 'app-shared/types/Repository'; -import { PersonCircleIcon } from '@navikt/aksel-icons'; +import { PersonCircleIcon } from '@studio/icons'; import { formatDateToDateAndTimeString } from 'app-development/utils/dateUtils'; import { StudioLabelAsParagraph } from '@studio/components'; diff --git a/frontend/app-development/layout/SettingsModalButton/SettingsModal/utils/settingsModalUtils.test.tsx b/frontend/app-development/layout/SettingsModalButton/SettingsModal/utils/settingsModalUtils.test.tsx index 96926c79b76..d000e2d4356 100644 --- a/frontend/app-development/layout/SettingsModalButton/SettingsModal/utils/settingsModalUtils.test.tsx +++ b/frontend/app-development/layout/SettingsModalButton/SettingsModal/utils/settingsModalUtils.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { SettingsModalTab } from 'app-development/types/SettingsModalTab'; import { createNavigationTab } from './index'; -import { TestFlaskIcon } from '@navikt/aksel-icons'; +import { TestFlaskIcon } from '@studio/icons'; import type { LeftNavigationTab } from 'app-shared/types/LeftNavigationTab'; const mockTabId1: SettingsModalTab = 'about'; diff --git a/frontend/app-development/layout/SettingsModalButton/SettingsModalButton.tsx b/frontend/app-development/layout/SettingsModalButton/SettingsModalButton.tsx index 617f1e489de..208a96574ff 100644 --- a/frontend/app-development/layout/SettingsModalButton/SettingsModalButton.tsx +++ b/frontend/app-development/layout/SettingsModalButton/SettingsModalButton.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from 'react'; import React, { useState } from 'react'; import { StudioButton } from '@studio/components'; -import { CogIcon } from '@navikt/aksel-icons'; +import { CogIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { SettingsModal } from './SettingsModal'; diff --git a/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx b/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx index 1ea60fc434b..56f3dd4ff90 100644 --- a/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx +++ b/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx @@ -4,7 +4,7 @@ import type { TFunction } from 'i18next'; import { LegacyToggleButtonGroup, LegacySelect } from '@digdir/design-system-react'; import type { AltinnButtonActionItem } from 'app-shared/components/altinnHeader/types'; import classes from '../AppPreviewSubMenu.module.css'; -import { ArrowCirclepathIcon, EyeIcon, LinkIcon } from '@navikt/aksel-icons'; +import { ArrowCirclepathIcon, EyeIcon, LinkIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import type { AppPreviewSubMenuProps } from '../AppPreviewSubMenu'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; diff --git a/frontend/dashboard/components/RepoList/RepoList.tsx b/frontend/dashboard/components/RepoList/RepoList.tsx index 23ab9ed0a0c..65bcf103a3f 100644 --- a/frontend/dashboard/components/RepoList/RepoList.tsx +++ b/frontend/dashboard/components/RepoList/RepoList.tsx @@ -21,13 +21,7 @@ import classes from './RepoList.module.css'; import type { User } from 'app-shared/types/Repository'; import { useSetStarredRepoMutation, useUnsetStarredRepoMutation } from '../../hooks/mutations'; -import { - PencilIcon, - FilesIcon, - ExternalLinkIcon, - StarIcon, - StarFillIcon, -} from '@navikt/aksel-icons'; +import { PencilIcon, FilesIcon, ExternalLinkIcon, StarIcon, StarFillIcon } from '@studio/icons'; export interface IRepoListProps { isLoading: boolean; diff --git a/frontend/dashboard/pages/Dashboard/Dashboard.tsx b/frontend/dashboard/pages/Dashboard/Dashboard.tsx index e1c8cafa82f..a6e204bd8dd 100644 --- a/frontend/dashboard/pages/Dashboard/Dashboard.tsx +++ b/frontend/dashboard/pages/Dashboard/Dashboard.tsx @@ -4,7 +4,7 @@ import cn from 'classnames'; import type { ChangeEvent, KeyboardEvent } from 'react'; import { Textfield } from '@digdir/design-system-react'; import { StudioButton } from '@studio/components'; -import { XMarkIcon } from '@navikt/aksel-icons'; +import { XMarkIcon } from '@studio/icons'; import { CenterContainer } from '../../components/CenterContainer'; import { DatamodelsReposList } from '../../components/DataModelsRepoList'; import { OrgReposList } from '../../components/OrgRepoList'; diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 45abb6dd9c8..faf23b52e06 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -1692,6 +1692,14 @@ "ux_editor.component_title.TextArea": "Langt svar", "ux_editor.component_unknown": "Ukjent komponent", "ux_editor.conditional_rendering_connection_header": "Betingede renderingstilkoblinger", + "ux_editor.config.warning_duplicates.heading": "Du har den samme ID-en på flere komponenter", + "ux_editor.config.warning_duplicates.solution_gitea": "Gå til Gitea for å endre filen med feil.", + "ux_editor.config.warning_duplicates.solution_gitea_commit": "Klikk på 'Commit endringer' nederst på siden.", + "ux_editor.config.warning_duplicates.solution_gitea_edit": "Endre en eller flere ID-er, slik at hver av dem blir unike.", + "ux_editor.config.warning_duplicates.solution_gitea_locate": "Finn de ID-ene som er like flere steder: ", + "ux_editor.config.warning_duplicates.solution_gitea_pencel": "I filen, velg blyanten øverst til høyre for å redigere filen.", + "ux_editor.config.warning_duplicates.solution_heading": "For å fikse problemet, må du gjøre dette:", + "ux_editor.config.warning_duplicates.solution_studio_import": "Gå tilbake til Altinn Studio og velg 'Hent endringer' for å laste inn endringene du har gjort i koden.", "ux_editor.container_empty": "Tomt, dra noe inn her...", "ux_editor.container_not_editable_info": "Noen egenskaper for denne komponenten er ikke redigerbare for øyeblikket. Du kan legge til underkomponenter i kolonnen til venstre.", "ux_editor.edit_component.id_help_text": "The component ID. Must be unique within all layouts/pages in a layout-set. Cannot end with .", @@ -1705,6 +1713,8 @@ "ux_editor.file_upload_component.display_mode": "Type", "ux_editor.file_upload_component.settings": "Innstillinger for filopplastingskomponent", "ux_editor.file_upload_component.valid_file_endings": "Innstillinger for filopplastingskomponent", + "ux_editor.formLayout.warning_duplicates": "Du har den samme ID-en på flere komponenter: ", + "ux_editor.formLayout.warning_duplicates.cannot_publish": "Du kan ikke publisere appen eller konfigurere komponentene før du har rettet opp feilen.", "ux_editor.form_designer": "Skjemadesigner", "ux_editor.id_identifier": "ID: {{item}}", "ux_editor.image_component.settings": "Innstillinger for bilde", diff --git a/frontend/libs/studio-components/src/components/StudioIconTextfield/StudioIconTextfield.test.tsx b/frontend/libs/studio-components/src/components/StudioIconTextfield/StudioIconTextfield.test.tsx index 6398f2d67cb..b455fe2cef8 100644 --- a/frontend/libs/studio-components/src/components/StudioIconTextfield/StudioIconTextfield.test.tsx +++ b/frontend/libs/studio-components/src/components/StudioIconTextfield/StudioIconTextfield.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { StudioIconTextfield } from './StudioIconTextfield'; import type { StudioIconTextfieldProps } from './StudioIconTextfield'; -import { KeyVerticalIcon } from '@navikt/aksel-icons'; +import { KeyVerticalIcon } from '@studio/icons'; import userEvent from '@testing-library/user-event'; describe('StudioIconTextfield', () => { diff --git a/frontend/libs/studio-components/src/components/StudioToggleableTextfield/StudioToggleableTextfield.stories.tsx b/frontend/libs/studio-components/src/components/StudioToggleableTextfield/StudioToggleableTextfield.stories.tsx index e3fec31f1df..baed75ef7dc 100644 --- a/frontend/libs/studio-components/src/components/StudioToggleableTextfield/StudioToggleableTextfield.stories.tsx +++ b/frontend/libs/studio-components/src/components/StudioToggleableTextfield/StudioToggleableTextfield.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { Meta, StoryFn } from '@storybook/react'; import { StudioToggleableTextfield } from './StudioToggleableTextfield'; -import { KeyVerticalIcon } from '@navikt/aksel-icons'; +import { KeyVerticalIcon } from '@studio/icons'; type Story = StoryFn; diff --git a/frontend/libs/studio-components/src/components/StudioToggleableTextfieldSchema/StudioToggleableTextfieldSchema.stories.tsx b/frontend/libs/studio-components/src/components/StudioToggleableTextfieldSchema/StudioToggleableTextfieldSchema.stories.tsx index d4cb59ae894..a674556dc95 100644 --- a/frontend/libs/studio-components/src/components/StudioToggleableTextfieldSchema/StudioToggleableTextfieldSchema.stories.tsx +++ b/frontend/libs/studio-components/src/components/StudioToggleableTextfieldSchema/StudioToggleableTextfieldSchema.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { Meta, StoryFn } from '@storybook/react'; import { StudioToggleableTextfieldSchema } from './StudioToggleableTextfieldSchema'; -import { KeyVerticalIcon } from '@navikt/aksel-icons'; +import { KeyVerticalIcon } from '@studio/icons'; type Story = StoryFn; diff --git a/frontend/libs/studio-icons/src/react/icons/SectionHeaderWarningIcon.tsx b/frontend/libs/studio-icons/src/react/icons/SectionHeaderWarningIcon.tsx new file mode 100644 index 00000000000..710f072d135 --- /dev/null +++ b/frontend/libs/studio-icons/src/react/icons/SectionHeaderWarningIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import type { IconProps } from '../types'; +import { SvgTemplate } from './SvgTemplate'; + +export const SectionHeaderWarningIcon = (props: IconProps): React.ReactElement => { + return ( + + + + + ); +}; diff --git a/frontend/libs/studio-icons/src/react/icons/index.ts b/frontend/libs/studio-icons/src/react/icons/index.ts index f0a23826a93..812529c094f 100644 --- a/frontend/libs/studio-icons/src/react/icons/index.ts +++ b/frontend/libs/studio-icons/src/react/icons/index.ts @@ -20,6 +20,7 @@ export { PropertyIcon } from './PropertyIcon'; export { RadioButtonIcon } from './RadioButtonIcon'; export { ReferenceIcon } from './ReferenceIcon'; export { RepeatingGroupIcon } from './RepeatingGroupIcon'; +export { SectionHeaderWarningIcon } from './SectionHeaderWarningIcon'; export { SelectIcon } from './SelectIcon'; export { ShortTextIcon } from './ShortTextIcon'; export { SignTaskIcon } from './SignTaskIcon'; diff --git a/frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx b/frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx index 1f8950ce672..2ccd9488cb1 100644 --- a/frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx +++ b/frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import classes from './CardButton.module.css'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { Paragraph } from '@digdir/design-system-react'; export type CardButtonProps = { diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx index 309fa391cb1..2a8ebb09b4e 100644 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx +++ b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx @@ -6,7 +6,7 @@ import { Textarea, LegacySelect, } from '@digdir/design-system-react'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import classes from './ExpandablePolicyCard.module.css'; import { ActionAndSubjectListItem } from './ActionAndSubjectListItem'; import { ResourceNarrowingList } from './ResourceNarrowingList'; diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyElement/ExpandablePolicyElement.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyElement/ExpandablePolicyElement.tsx index 674f1fa8345..4f02516961e 100644 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyElement/ExpandablePolicyElement.tsx +++ b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyElement/ExpandablePolicyElement.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from 'react'; import React, { useState } from 'react'; import classes from './ExpandablePolicyElement.module.css'; -import { ChevronDownIcon, ChevronUpIcon } from '@navikt/aksel-icons'; +import { ChevronDownIcon, ChevronUpIcon } from '@studio/icons'; import { PolicyEditorDropdownMenu } from './PolicyEditorDropdownMenu'; import { useTranslation } from 'react-i18next'; import { StudioLabelAsParagraph } from '@studio/components'; diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.tsx index 7d12cec03a8..fd9c1354c92 100644 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.tsx +++ b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.tsx @@ -1,7 +1,7 @@ import React from 'react'; import classes from './PolicyResourceFields.module.css'; import { Textfield } from '@digdir/design-system-react'; -import { MultiplyIcon } from '@navikt/aksel-icons'; +import { MultiplyIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { StudioButton, StudioLabelAsParagraph } from '@studio/components'; diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/ResourceNarrowingList.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/ResourceNarrowingList.tsx index ec3d2f22eea..33a0964eb04 100644 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/ResourceNarrowingList.tsx +++ b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/ResourceNarrowingList.tsx @@ -3,7 +3,7 @@ import classes from './ResourceNarrowingList.module.css'; import { PolicyResourceFields } from './PolicyResourceFields'; import { ExpandablePolicyElement } from '../ExpandablePolicyElement'; import { StudioButton } from '@studio/components'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import type { PolicyEditorUsage, PolicyRuleResource } from '../../../types'; import { useTranslation } from 'react-i18next'; diff --git a/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/ConfigEndEvent.tsx b/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/ConfigEndEvent.tsx index 0186c3ef32f..b30b50f69a9 100644 --- a/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/ConfigEndEvent.tsx +++ b/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/ConfigEndEvent.tsx @@ -2,7 +2,7 @@ import React from 'react'; import type { LayoutSetConfig } from 'app-shared/types/api/LayoutSetsResponse'; import { StudioSectionHeader, StudioToggleableTextfield } from '@studio/components'; import { Paragraph } from '@digdir/design-system-react'; -import { PencilWritingIcon } from '@navikt/aksel-icons'; +import { PencilWritingIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import classes from './ConfigEndEvent.module.css'; import { PROTECTED_TASK_NAME_CUSTOM_RECEIPT } from 'app-shared/constants'; diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/CustomProperties.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/CustomProperties.tsx index d477f5d0f91..cc258a82e77 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/CustomProperties.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/CustomProperties.tsx @@ -8,7 +8,7 @@ import { setCustomProperties, setProperty, } from '@altinn/schema-model'; -import { TrashIcon } from '@navikt/aksel-icons'; +import { TrashIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import classes from './CustomProperties.module.css'; import { useSchemaEditorAppContext } from '@altinn/schema-editor/hooks/useSchemaEditorAppContext'; diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/ItemFieldsTab/ItemFieldsTab.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/ItemFieldsTab/ItemFieldsTab.tsx index 6c1c253fcaa..0920befdacf 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/ItemFieldsTab/ItemFieldsTab.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/ItemFieldsTab/ItemFieldsTab.tsx @@ -4,7 +4,7 @@ import type { FieldNode } from '@altinn/schema-model'; import { FieldType, isField, isReference, ObjectKind } from '@altinn/schema-model'; import classes from './ItemFieldsTab.module.css'; import { StudioButton, usePrevious } from '@studio/components'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { ItemFieldsTable } from './ItemFieldsTable'; import { useAddProperty } from '@altinn/schema-editor/hooks/useAddProperty'; diff --git a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx index a758671f3e6..fe720b2c7a9 100644 --- a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx @@ -3,9 +3,8 @@ import { useTranslation } from 'react-i18next'; import { useAddProperty } from '../../../../hooks/useAddProperty'; import { ObjectKind } from '@altinn/schema-model'; import { ActionButton } from './ActionButton'; -import { PlusIcon } from '@navikt/aksel-icons'; import { DropdownMenu } from '@digdir/design-system-react'; -import { CombinationIcon, PropertyIcon, ReferenceIcon } from '@studio/icons'; +import { CombinationIcon, PropertyIcon, ReferenceIcon, PlusIcon } from '@studio/icons'; interface AddPropertyMenuProps { pointer: string; diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypeItem.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypeItem.tsx index 6b0b0b4f447..4e6991f1a51 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypeItem.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypeItem.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { UiSchemaNode } from '@altinn/schema-model'; import { extractNameFromPointer } from '@altinn/schema-model'; -import { CogIcon, FileJsonIcon } from '@navikt/aksel-icons'; +import { CogIcon, FileJsonIcon } from '@studio/icons'; import classes from './TypeItem.module.css'; import classNames from 'classnames'; import * as testids from '../../../../../testing/testids'; diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index 9ee81278afc..e61ecb89bfa 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -1,7 +1,7 @@ import type { MouseEvent } from 'react'; import React from 'react'; import { StudioButton } from '@studio/components'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import type { UiSchemaNode } from '@altinn/schema-model'; import classes from './TypesInspector.module.css'; import { Divider } from 'app-shared/primitives'; diff --git a/frontend/packages/schema-editor/src/components/common/ActionMenu.tsx b/frontend/packages/schema-editor/src/components/common/ActionMenu.tsx index 08a86849698..6e0d24c0a58 100644 --- a/frontend/packages/schema-editor/src/components/common/ActionMenu.tsx +++ b/frontend/packages/schema-editor/src/components/common/ActionMenu.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { PlusCircleIcon } from '@navikt/aksel-icons'; +import { PlusCircleIcon } from '@studio/icons'; import type { IconImage } from './Icon'; import { Icon } from './Icon'; import classes from './ActionMenu.module.css'; diff --git a/frontend/packages/shared/src/api/paths.js b/frontend/packages/shared/src/api/paths.js index ae80ccdba21..655ffd87a60 100644 --- a/frontend/packages/shared/src/api/paths.js +++ b/frontend/packages/shared/src/api/paths.js @@ -48,6 +48,7 @@ export const frontendLangPath = (locale) => `/designer/frontend/lang/${locale}.j export const gitCommitPath = (org, app, commitId) => `/repos/${org}/${app}/commit/${commitId}`; export const repositoryGitPath = (org, app) => `/repos/${org}/${app}.git`; export const repositoryPath = (org, app) => `/repos/${org}/${app}`; +export const repositoryLayoutPath = (org, app, layout) => `/repos/${org}/${app}/src/branch/master/App/ui/form/layouts/${layout}.json`; export const publishPath = (org, app) => `/editor/${org}/${app}/deploy`; export const repositoryOwnerPath = (org) => `/repos/${org}`; export const repositoryBasePath = () => `/repos`; diff --git a/frontend/packages/shared/src/components/FileSelector.tsx b/frontend/packages/shared/src/components/FileSelector.tsx index c425dca4a37..bd517b2e942 100644 --- a/frontend/packages/shared/src/components/FileSelector.tsx +++ b/frontend/packages/shared/src/components/FileSelector.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { StudioButton } from '@studio/components'; -import { UploadIcon } from '@navikt/aksel-icons'; +import { UploadIcon } from '@studio/icons'; import * as testids from '../../../../testing/testids'; export interface IFileSelectorProps { diff --git a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/DeleteModal/DeleteModal.tsx b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/DeleteModal/DeleteModal.tsx index 3e7ce6da7b3..2b8321bc7cb 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/DeleteModal/DeleteModal.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/DeleteModal/DeleteModal.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import classes from './DeleteModal.module.css'; import { useTranslation } from 'react-i18next'; import { StudioButton, StudioModal, StudioSpinner } from '@studio/components'; -import { TrashIcon } from '@navikt/aksel-icons'; +import { TrashIcon } from '@studio/icons'; import { useResetRepositoryMutation } from 'app-development/hooks/mutations/useResetRepositoryMutation'; import { toast } from 'react-toastify'; import { Heading, Paragraph, Textfield } from '@digdir/design-system-react'; diff --git a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChanges/LocalChanges.tsx b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChanges/LocalChanges.tsx index 958e6cb6e10..0285fb09284 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChanges/LocalChanges.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChanges/LocalChanges.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import classes from './LocalChanges.module.css'; import { useTranslation } from 'react-i18next'; import { Paragraph } from '@digdir/design-system-react'; -import { DownloadIcon, TrashIcon } from '@navikt/aksel-icons'; +import { DownloadIcon, TrashIcon } from '@studio/icons'; import { LocalChangesActionButton } from '../LocalChangesActionButton'; import { DeleteModal } from '../DeleteModal'; import { repoDownloadPath } from 'app-shared/api/paths'; diff --git a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesActionButton/LocalChangesActionButton.test.tsx b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesActionButton/LocalChangesActionButton.test.tsx index 67744dd7282..33f4c07ad2f 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesActionButton/LocalChangesActionButton.test.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesActionButton/LocalChangesActionButton.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import type { Action, LocalChangesActionButtonProps } from './LocalChangesActionButton'; import { LocalChangesActionButton } from './LocalChangesActionButton'; -import { TestFlaskIcon } from '@navikt/aksel-icons'; +import { TestFlaskIcon } from '@studio/icons'; import userEvent from '@testing-library/user-event'; const mockLabel: string = 'Test label'; diff --git a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesModal.tsx b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesModal.tsx index 04181c439c5..99c3df063ec 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesModal.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/LocalChangesModal/LocalChangesModal.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from 'react'; import React from 'react'; import classes from './LocalChangesModal.module.css'; import { Heading } from '@digdir/design-system-react'; -import { MonitorIcon } from '@navikt/aksel-icons'; +import { MonitorIcon } from '@studio/icons'; import { StudioModal } from '@studio/components'; import { useTranslation } from 'react-i18next'; import { LocalChanges } from './LocalChanges/LocalChanges'; diff --git a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/ThreeDotsMenu.tsx b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/ThreeDotsMenu.tsx index 3f8703f3284..892f3153e48 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/ThreeDotsMenu.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/ThreeDotsMenu.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import classes from './ThreeDotsMenu.module.css'; -import { MonitorIcon, TabsIcon, MenuElipsisVerticalIcon } from '@navikt/aksel-icons'; +import { MonitorIcon, TabsIcon, MenuElipsisVerticalIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { repositoryPath } from 'app-shared/api/paths'; import { GiteaIcon } from 'app-shared/icons'; diff --git a/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/FetchChangesButton/FetchChangesButton.tsx b/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/FetchChangesButton/FetchChangesButton.tsx index 0c26bb509c0..43676982a07 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/FetchChangesButton/FetchChangesButton.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/FetchChangesButton/FetchChangesButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { StudioButton } from '@studio/components'; -import { DownloadIcon } from '@navikt/aksel-icons'; +import { DownloadIcon } from '@studio/icons'; import classes from './FetchChangesButton.module.css'; import { useTranslation } from 'react-i18next'; import { Notification } from '../Notification'; diff --git a/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/ShareChangesButton/ShareChangesButton.tsx b/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/ShareChangesButton/ShareChangesButton.tsx index 7cdf2ddb90d..cf41ad85c17 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/ShareChangesButton/ShareChangesButton.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/VersionControlButtons/ShareChangesButton/ShareChangesButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { StudioButton } from '@studio/components'; -import { UploadIcon, XMarkIcon } from '@navikt/aksel-icons'; +import { UploadIcon, XMarkIcon } from '@studio/icons'; import classes from './ShareChangesButton.module.css'; import { useTranslation } from 'react-i18next'; import { Notification } from '../Notification'; diff --git a/frontend/packages/shared/src/components/LeftNavigationBar/GoBackButton/GoBackButton.tsx b/frontend/packages/shared/src/components/LeftNavigationBar/GoBackButton/GoBackButton.tsx index f159398c6e7..c87e3dbe846 100644 --- a/frontend/packages/shared/src/components/LeftNavigationBar/GoBackButton/GoBackButton.tsx +++ b/frontend/packages/shared/src/components/LeftNavigationBar/GoBackButton/GoBackButton.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from 'react'; import React from 'react'; import classes from './GoBackButton.module.css'; import cn from 'classnames'; -import { ArrowLeftIcon } from '@navikt/aksel-icons'; +import { ArrowLeftIcon } from '@studio/icons'; import { Paragraph } from '@digdir/design-system-react'; import { NavLink } from 'react-router-dom'; diff --git a/frontend/packages/shared/src/components/LeftNavigationBar/LeftNavigationBar.test.tsx b/frontend/packages/shared/src/components/LeftNavigationBar/LeftNavigationBar.test.tsx index ce3aae915fb..445ed260f0d 100644 --- a/frontend/packages/shared/src/components/LeftNavigationBar/LeftNavigationBar.test.tsx +++ b/frontend/packages/shared/src/components/LeftNavigationBar/LeftNavigationBar.test.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import type { LeftNavigationBarProps } from './LeftNavigationBar'; import { LeftNavigationBar } from './LeftNavigationBar'; import type { LeftNavigationTab, TabAction } from 'app-shared/types/LeftNavigationTab'; -import { TestFlaskIcon } from '@navikt/aksel-icons'; +import { TestFlaskIcon } from '@studio/icons'; import { MemoryRouter } from 'react-router-dom'; import { textMock } from '../../../../../testing/mocks/i18nMock'; diff --git a/frontend/packages/shared/src/components/LeftNavigationBar/Tab/Tab.test.tsx b/frontend/packages/shared/src/components/LeftNavigationBar/Tab/Tab.test.tsx index facf37ba2fa..775844ff10a 100644 --- a/frontend/packages/shared/src/components/LeftNavigationBar/Tab/Tab.test.tsx +++ b/frontend/packages/shared/src/components/LeftNavigationBar/Tab/Tab.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { render as rtlRender, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import type { LeftNavigationTab, TabAction } from 'app-shared/types/LeftNavigationTab'; -import { TestFlaskIcon } from '@navikt/aksel-icons'; +import { TestFlaskIcon } from '@studio/icons'; import type { TabProps } from './Tab'; import { Tab } from './Tab'; import { MemoryRouter } from 'react-router-dom'; diff --git a/frontend/packages/shared/src/components/PreviewLimitationsInfo/PreviewLimitationsInfo.tsx b/frontend/packages/shared/src/components/PreviewLimitationsInfo/PreviewLimitationsInfo.tsx index 04a1d01e2fc..ac9f8c59836 100644 --- a/frontend/packages/shared/src/components/PreviewLimitationsInfo/PreviewLimitationsInfo.tsx +++ b/frontend/packages/shared/src/components/PreviewLimitationsInfo/PreviewLimitationsInfo.tsx @@ -3,7 +3,7 @@ import classes from './PreviewLimitationsInfo.module.css'; import cn from 'classnames'; import { useTranslation } from 'react-i18next'; import { Alert, LegacyPopover } from '@digdir/design-system-react'; -import { XMarkIcon } from '@navikt/aksel-icons'; +import { XMarkIcon } from '@studio/icons'; import { typedLocalStorage } from 'app-shared/utils/webStorage'; import { StudioButton } from '@studio/components'; diff --git a/frontend/packages/shared/src/utils/objectUtils.test.ts b/frontend/packages/shared/src/utils/objectUtils.test.ts index 06b58f50f35..811cb426854 100644 --- a/frontend/packages/shared/src/utils/objectUtils.test.ts +++ b/frontend/packages/shared/src/utils/objectUtils.test.ts @@ -1,4 +1,4 @@ -import { areObjectsEqual, mapByProperty } from 'app-shared/utils/objectUtils'; +import { areObjectsEqual, mapByProperty, flattenObjectValues } from 'app-shared/utils/objectUtils'; describe('objectUtils', () => { describe('areObjectsEqual', () => { @@ -33,13 +33,16 @@ describe('objectUtils', () => { [value3]: object3, }); }); + }); - it('Throws an error if the values of the given property are not unique', () => { - const object4 = { [property]: value1 }; - const objectList = [object1, object2, object3, object4]; - const expectedError = - 'The values of the given property in the mapByProperty function should be unique.'; - expect(() => mapByProperty(objectList, property)).toThrowError(expectedError); + describe('flattenObjectValues', () => { + it('Flattens the values of an object', () => { + const object = { + a: 'value1', + b: 'value2', + c: 'value3', + }; + expect(flattenObjectValues(object)).toEqual(['value1', 'value2', 'value3']); }); }); }); diff --git a/frontend/packages/shared/src/utils/objectUtils.ts b/frontend/packages/shared/src/utils/objectUtils.ts index 6567f40a8f0..0c061aed290 100644 --- a/frontend/packages/shared/src/utils/objectUtils.ts +++ b/frontend/packages/shared/src/utils/objectUtils.ts @@ -1,5 +1,4 @@ import type { KeyValuePairs } from 'app-shared/types/KeyValuePairs'; -import { areItemsUnique } from 'app-shared/utils/arrayUtils'; /** * Checks if two objects are equal (shallow comparison). @@ -19,19 +18,26 @@ export const areObjectsEqual = (obj1: T, obj2: T): boolean => /** * Maps an array of objects to a key-value pair object, where the key is the value of the given property. - * Requires that the values of the given property are unique. * @param objectList * @param property + * @returns An object with the values of the given property as keys and the objects as values. */ export const mapByProperty = ( objectList: T[], property: keyof T, ): KeyValuePairs => { - const keys = objectList.map((object) => object[property]); - if (!areItemsUnique(keys)) { - throw new Error( - 'The values of the given property in the mapByProperty function should be unique.', - ); - } return Object.fromEntries(objectList.map((object) => [object[property], object])); }; + +/** + * Flattens the values of an object. + * @param object The object to flatten. + * @returns An array of the values of the object. + */ +export const flattenObjectValues = (object: T): string[] => { + return Object.entries(object) + .map(([, value]) => { + return value; + }) + .flat(); +}; diff --git a/frontend/packages/text-editor/src/Variables.tsx b/frontend/packages/text-editor/src/Variables.tsx index 1c5946d4d5f..2f6ae723923 100644 --- a/frontend/packages/text-editor/src/Variables.tsx +++ b/frontend/packages/text-editor/src/Variables.tsx @@ -1,7 +1,7 @@ import classes from './Variables.module.css'; import { PanelVariant, PopoverPanel } from '@altinn/altinn-design-system'; import { StudioButton } from '@studio/components'; -import { InformationSquareFillIcon } from '@navikt/aksel-icons'; +import { InformationSquareFillIcon } from '@studio/icons'; import React, { useState } from 'react'; import type { TextResourceVariable } from './types'; import { useTranslation, Trans } from 'react-i18next'; diff --git a/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx b/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx index 1a0e2049a7d..30a96f5b8ae 100644 --- a/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx @@ -8,7 +8,7 @@ import type { ConnectDragSource } from 'react-dnd'; import { DEFAULT_LANGUAGE } from 'app-shared/constants'; import { DragHandle } from './DragHandle'; import type { ITextResource } from 'app-shared/types/global'; -import { TrashIcon } from '@navikt/aksel-icons'; +import { TrashIcon } from '@studio/icons'; import { formItemConfigs } from '../../data/formItemConfig'; import { getComponentTitleByComponentType, getTextResource, truncate } from '../../utils/language'; import { textResourcesByLanguageSelector } from '../../selectors/textResourceSelectors'; diff --git a/frontend/packages/ux-editor-v3/src/components/Properties/Calculations.tsx b/frontend/packages/ux-editor-v3/src/components/Properties/Calculations.tsx index b4c49431248..18b11e43d1a 100644 --- a/frontend/packages/ux-editor-v3/src/components/Properties/Calculations.tsx +++ b/frontend/packages/ux-editor-v3/src/components/Properties/Calculations.tsx @@ -1,7 +1,7 @@ import React from 'react'; import classes from './Calculations.module.css'; import { StudioButton } from '@studio/components'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { RuleModal } from '../toolbar/RuleModal'; import { OldDynamicsInfo } from './OldDynamicsInfo'; import { Divider } from 'app-shared/primitives'; diff --git a/frontend/packages/ux-editor-v3/src/components/Properties/ConditionalRendering.tsx b/frontend/packages/ux-editor-v3/src/components/Properties/ConditionalRendering.tsx index ceea68a4037..540f3559cd5 100644 --- a/frontend/packages/ux-editor-v3/src/components/Properties/ConditionalRendering.tsx +++ b/frontend/packages/ux-editor-v3/src/components/Properties/ConditionalRendering.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { Alert } from '@digdir/design-system-react'; import classes from './ConditionalRendering.module.css'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { ConditionalRenderingModal } from '../toolbar/ConditionalRenderingModal'; import { OldDynamicsInfo } from './OldDynamicsInfo'; import { Divider } from 'app-shared/primitives'; diff --git a/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx b/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx index 61b5aac15d5..6194b9d0b4d 100644 --- a/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx +++ b/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx @@ -1,6 +1,6 @@ import React from 'react'; import classes from './OldDynamicsInfo.module.css'; -import { ExternalLinkIcon } from '@navikt/aksel-icons'; +import { ExternalLinkIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { giteaEditLink, altinnDocsUrl } from 'app-shared/ext-urls'; import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; diff --git a/frontend/packages/ux-editor-v3/src/components/TextResource.tsx b/frontend/packages/ux-editor-v3/src/components/TextResource.tsx index 87c480e9edb..d11514f6471 100644 --- a/frontend/packages/ux-editor-v3/src/components/TextResource.tsx +++ b/frontend/packages/ux-editor-v3/src/components/TextResource.tsx @@ -1,13 +1,7 @@ import React, { useState } from 'react'; import type { LegacySingleSelectOption } from '@digdir/design-system-react'; import { LegacySelect, Paragraph } from '@digdir/design-system-react'; -import { - MagnifyingGlassIcon, - PencilIcon, - PlusIcon, - TrashIcon, - XMarkIcon, -} from '@navikt/aksel-icons'; +import { MagnifyingGlassIcon, PencilIcon, PlusIcon, TrashIcon, XMarkIcon } from '@studio/icons'; import classes from './TextResource.module.css'; import { useDispatch, useSelector } from 'react-redux'; import { setCurrentEditId } from '../features/appData/textResources/textResourcesSlice'; diff --git a/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx b/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx index 58867d71994..598892a5d43 100644 --- a/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx +++ b/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import classes from './TextResourceEdit.module.css'; import type { ITextResource } from 'app-shared/types/global'; import { Fieldset, LegacyTextArea } from '@digdir/design-system-react'; -import { XMarkIcon } from '@navikt/aksel-icons'; +import { XMarkIcon } from '@studio/icons'; import { getAllLanguages, getCurrentEditId } from '../selectors/textResourceSelectors'; import { setCurrentEditId } from '../features/appData/textResources/textResourcesSlice'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/frontend/packages/ux-editor-v3/src/components/config/ConditionalRenderingComponent.tsx b/frontend/packages/ux-editor-v3/src/components/config/ConditionalRenderingComponent.tsx index 31dfd01a7f0..05d7da4a41e 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/ConditionalRenderingComponent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/ConditionalRenderingComponent.tsx @@ -18,7 +18,7 @@ import type { } from 'app-shared/types/RuleConfig'; import type i18next from 'i18next'; import type { FormComponent } from '../../types/FormComponent'; -import { Buldings2Icon, XMarkOctagonFillIcon } from '@navikt/aksel-icons'; +import { Buldings2Icon, XMarkOctagonFillIcon } from '@studio/icons'; import type { FormContainer } from '../../types/FormContainer'; export interface IConditionalRenderingComponentProps { diff --git a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/ExpressionEditMode.tsx b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/ExpressionEditMode.tsx index 9001ffce3c3..875d170f57b 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/ExpressionEditMode.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/ExpressionEditMode.tsx @@ -15,7 +15,7 @@ import { import { ComplexExpression } from '../ComplexExpression'; import { SimpleExpression } from './SimpleExpression'; import { Switch } from '@digdir/design-system-react'; -import { CheckmarkIcon, PlusCircleIcon, TrashIcon } from '@navikt/aksel-icons'; +import { CheckmarkIcon, PlusCircleIcon, TrashIcon } from '@studio/icons'; import { Trans } from 'react-i18next'; import classes from '../ExpressionContent.module.css'; import { stringifyData } from '../../../../../utils/jsonUtils'; diff --git a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/SubExpressionContent.tsx b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/SubExpressionContent.tsx index adbed525647..a587db42541 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/SubExpressionContent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/SubExpressionContent.tsx @@ -7,7 +7,7 @@ import { ExpressionFunction, expressionFunctionTexts, } from '../../../../../../types/Expressions'; -import { TrashIcon } from '@navikt/aksel-icons'; +import { TrashIcon } from '@studio/icons'; import classes from './SubExpressionContent.module.css'; import { DataSourceValue } from './DataSourceValue'; import { diff --git a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/ExpressionPreview.tsx b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/ExpressionPreview.tsx index b2d50c0734c..0930478a81e 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/ExpressionPreview.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/ExpressionPreview.tsx @@ -6,7 +6,7 @@ import { complexExpressionIsSet } from '../../../../../utils/expressionsUtils'; import { ComplexExpression } from '../ComplexExpression'; import { SimpleExpressionPreview } from './SimpleExpressionPreview'; import { StudioButton } from '@studio/components'; -import { PencilIcon, TrashIcon } from '@navikt/aksel-icons'; +import { PencilIcon, TrashIcon } from '@studio/icons'; import { useText } from '../../../../../hooks'; import cn from 'classnames'; import { Trans } from 'react-i18next'; diff --git a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/SimpleExpressionPreview.tsx b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/SimpleExpressionPreview.tsx index 710f9febd2c..740880a40a6 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/SimpleExpressionPreview.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionPreview/SimpleExpressionPreview.tsx @@ -6,7 +6,7 @@ import { expressionFunctionTexts, Operator, } from '../../../../../types/Expressions'; -import { ArrowRightIcon } from '@navikt/aksel-icons'; +import { ArrowRightIcon } from '@studio/icons'; import { useText } from '../../../../../hooks'; import { stringifyValueForDisplay } from '../../../../../utils/expressionsUtils'; diff --git a/frontend/packages/ux-editor-v3/src/components/config/Expressions/NewExpressionButton.tsx b/frontend/packages/ux-editor-v3/src/components/config/Expressions/NewExpressionButton.tsx index 90ff947f4c3..af9eed656e4 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/Expressions/NewExpressionButton.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/Expressions/NewExpressionButton.tsx @@ -1,6 +1,6 @@ import React, { useRef } from 'react'; import { DropdownMenu } from '@digdir/design-system-react'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { useText } from '../../../hooks'; import type { ExpressionProperty } from '../../../types/Expressions'; import { expressionPropertyTexts } from '../../../types/Expressions'; diff --git a/frontend/packages/ux-editor-v3/src/components/config/RuleComponent.tsx b/frontend/packages/ux-editor-v3/src/components/config/RuleComponent.tsx index e4d540cc39d..07b4d283c05 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/RuleComponent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/RuleComponent.tsx @@ -7,7 +7,7 @@ import classes from './RuleComponent.module.css'; import Modal from 'react-modal'; import type { RuleConnection, RuleConnections } from 'app-shared/types/RuleConfig'; import type i18next from 'i18next'; -import { Buldings2Icon } from '@navikt/aksel-icons'; +import { Buldings2Icon } from '@studio/icons'; export interface IRuleComponentProps { connectionId?: string; diff --git a/frontend/packages/ux-editor-v3/src/components/config/componentSpecificContent/Map/MapComponent.tsx b/frontend/packages/ux-editor-v3/src/components/config/componentSpecificContent/Map/MapComponent.tsx index 8153b6f846c..a8713119b9f 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/componentSpecificContent/Map/MapComponent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/componentSpecificContent/Map/MapComponent.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { PlusIcon, XMarkIcon } from '@navikt/aksel-icons'; +import { PlusIcon, XMarkIcon } from '@studio/icons'; import { LegacyFieldSet, LegacyTextField } from '@digdir/design-system-react'; import type { IGenericEditComponent } from '../../componentConfig'; import { FormField } from '../../../FormField'; diff --git a/frontend/packages/ux-editor-v3/src/components/config/editModal/EditOptions.tsx b/frontend/packages/ux-editor-v3/src/components/config/editModal/EditOptions.tsx index 52fad15fec7..3725f1e21ca 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/editModal/EditOptions.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/editModal/EditOptions.tsx @@ -4,7 +4,7 @@ import { Fieldset, Radio, Textfield, ErrorMessage } from '@digdir/design-system- import classes from './EditOptions.module.css'; import type { IGenericEditComponent } from '../componentConfig'; import { EditCodeList } from './EditCodeList'; -import { PlusIcon, XMarkIcon } from '@navikt/aksel-icons'; +import { PlusIcon, XMarkIcon } from '@studio/icons'; import { TextResource } from '../../TextResource'; import { useText, useComponentErrorMessage } from '../../../hooks'; import { addOptionToComponent, generateRandomOption } from '../../../utils/component'; diff --git a/frontend/packages/ux-editor-v3/src/components/toolbar/RuleButton.tsx b/frontend/packages/ux-editor-v3/src/components/toolbar/RuleButton.tsx index ef2e25c2067..44c6ac47081 100644 --- a/frontend/packages/ux-editor-v3/src/components/toolbar/RuleButton.tsx +++ b/frontend/packages/ux-editor-v3/src/components/toolbar/RuleButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { StudioButton } from '@studio/components'; -import { CogIcon } from '@navikt/aksel-icons'; +import { CogIcon } from '@studio/icons'; export interface IRuleButtonProps { onClick: () => void; diff --git a/frontend/packages/ux-editor-v3/src/components/toolbar/ToolbarItemComponent.tsx b/frontend/packages/ux-editor-v3/src/components/toolbar/ToolbarItemComponent.tsx index 30fc68aff40..41003e41105 100644 --- a/frontend/packages/ux-editor-v3/src/components/toolbar/ToolbarItemComponent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/toolbar/ToolbarItemComponent.tsx @@ -2,7 +2,7 @@ import type { MouseEvent } from 'react'; import React from 'react'; import classes from './ToolbarItemComponent.module.css'; import { StudioButton } from '@studio/components'; -import { InformationIcon } from '@navikt/aksel-icons'; +import { InformationIcon } from '@studio/icons'; import { getComponentTitleByComponentType } from '../../utils/language'; import { useTranslation } from 'react-i18next'; import type { ComponentTypeV3 } from 'app-shared/types/ComponentTypeV3'; diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx b/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx index bfed9bb9fc0..09faedd0d6a 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx @@ -12,7 +12,7 @@ import { FormLayoutActions } from '../../features/formDesigner/formLayout/formLa import { useInstanceIdQuery } from 'app-shared/hooks/queries'; import { useSearchParams } from 'react-router-dom'; import { useFormLayoutSettingsQuery } from '../../hooks/queries/useFormLayoutSettingsQuery'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { useAddLayoutMutation } from '../../hooks/mutations/useAddLayoutMutation'; import { setSelectedLayoutInLocalStorage } from '../../utils/localStorageUtils'; import { PageAccordion } from './PageAccordion'; diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx index fabed5c6a05..6d0993c50a7 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx @@ -1,7 +1,7 @@ import React, { useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { DropdownMenu } from '@digdir/design-system-react'; -import { MenuElipsisVerticalIcon, ArrowUpIcon, ArrowDownIcon } from '@navikt/aksel-icons'; +import { MenuElipsisVerticalIcon, ArrowUpIcon, ArrowDownIcon } from '@studio/icons'; import { useFormLayoutSettingsQuery } from '../../../../hooks/queries/useFormLayoutSettingsQuery'; import { useUpdateLayoutOrderMutation } from '../../../../hooks/mutations/useUpdateLayoutOrderMutation'; import { useUpdateLayoutNameMutation } from '../../../../hooks/mutations/useUpdateLayoutNameMutation'; diff --git a/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx b/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx index 4abb1f46d2a..f52d3f25270 100644 --- a/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx +++ b/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx @@ -8,7 +8,7 @@ import type { ConnectDragSource } from 'react-dnd'; import { DEFAULT_LANGUAGE } from 'app-shared/constants'; import { DragHandle } from './DragHandle'; import type { ITextResource } from 'app-shared/types/global'; -import { TrashIcon } from '@navikt/aksel-icons'; +import { TrashIcon } from '@studio/icons'; import { formItemConfigs } from '../../data/formItemConfig'; import { getComponentTitleByComponentType, getTextResource, truncate } from '../../utils/language'; import { textResourcesByLanguageSelector } from '../../selectors/textResourceSelectors'; diff --git a/frontend/packages/ux-editor/src/components/Properties/Calculations.tsx b/frontend/packages/ux-editor/src/components/Properties/Calculations.tsx index b4c49431248..18b11e43d1a 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Calculations.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Calculations.tsx @@ -1,7 +1,7 @@ import React from 'react'; import classes from './Calculations.module.css'; import { StudioButton } from '@studio/components'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { RuleModal } from '../toolbar/RuleModal'; import { OldDynamicsInfo } from './OldDynamicsInfo'; import { Divider } from 'app-shared/primitives'; diff --git a/frontend/packages/ux-editor/src/components/Properties/ConditionalRendering.tsx b/frontend/packages/ux-editor/src/components/Properties/ConditionalRendering.tsx index ceea68a4037..540f3559cd5 100644 --- a/frontend/packages/ux-editor/src/components/Properties/ConditionalRendering.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/ConditionalRendering.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { Alert } from '@digdir/design-system-react'; import classes from './ConditionalRendering.module.css'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { ConditionalRenderingModal } from '../toolbar/ConditionalRenderingModal'; import { OldDynamicsInfo } from './OldDynamicsInfo'; import { Divider } from 'app-shared/primitives'; diff --git a/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx b/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx index 0e49f37d81a..91385ac2201 100644 --- a/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx @@ -1,6 +1,6 @@ import React from 'react'; import classes from './OldDynamicsInfo.module.css'; -import { ExternalLinkIcon } from '@navikt/aksel-icons'; +import { ExternalLinkIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { giteaEditLink, altinnDocsUrl } from 'app-shared/ext-urls'; import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; diff --git a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx index bf5a308569e..a1d7443a9fd 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx @@ -1,6 +1,6 @@ import React from 'react'; import classes from './EditPageId.module.css'; -import { KeyVerticalIcon } from '@navikt/aksel-icons'; +import { KeyVerticalIcon } from '@studio/icons'; import { getPageNameErrorKey } from '../../../utils/designViewUtils'; import { useUpdateLayoutNameMutation } from '../../../hooks/mutations/useUpdateLayoutNameMutation'; import { StudioToggleableTextfield } from '@studio/components'; diff --git a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.test.tsx b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.test.tsx index 0c145bc960e..2311cac453d 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.test.tsx @@ -14,6 +14,7 @@ import { layout1NameMock, layoutMock, layoutSetsMock } from '../../../testing/la const app = 'app'; const org = 'org'; const layoutSet = layoutSetsMock.sets[0].id; +const duplicatedLayout = 'duplicatedLayout'; const defaultTexts: ITextResources = { [DEFAULT_LANGUAGE]: [ @@ -24,6 +25,16 @@ const defaultTexts: ITextResources = { }; const layouts: IFormLayouts = { [layout1NameMock]: layoutMock, + [duplicatedLayout]: { + components: {}, + containers: {}, + order: { + ['idContainer']: ['idContainer1', 'idContainer2', 'idContainer3'], + ['idContainer1']: ['idContainer', 'idContainer1', 'idContainer2'], + }, + customRootProperties: {}, + customDataProperties: {}, + }, }; describe('PageConfigPanel', () => { @@ -60,6 +71,21 @@ describe('PageConfigPanel', () => { screen.getByRole('heading', { name: newVisualPageName }); screen.getByRole('button', { name: textMock('ux_editor.id_identifier') }); }); + + it('render warning when layout is selected and has duplicated ids', () => { + renderPageConfigPanel(duplicatedLayout); + screen.getByRole('heading', { name: textMock('ux_editor.config.warning_duplicates.heading') }); + }); + + it('should display duplicated ids in the document', () => { + renderPageConfigPanel(duplicatedLayout); + + const duplicatedIds = screen.getByText(/, /i); + expect(duplicatedIds).toBeInTheDocument(); + + const uniqueIds = screen.queryByText(/, /i); + expect(uniqueIds).not.toBeInTheDocument(); + }); }); const renderPageConfigPanel = ( diff --git a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.tsx b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.tsx index 1e3715f4960..d093ce90252 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigPanel.tsx @@ -1,14 +1,16 @@ import React from 'react'; import { Accordion } from '@digdir/design-system-react'; -import { FileIcon } from '@navikt/aksel-icons'; +import { FileIcon } from '@studio/icons'; import { StudioSectionHeader } from '@studio/components'; -import { useText, useTextResourcesSelector, useAppContext } from '../../../hooks'; +import { useText, useTextResourcesSelector, useAppContext, useFormLayouts } from '../../../hooks'; import { DEFAULT_LANGUAGE, DEFAULT_SELECTED_LAYOUT_NAME } from 'app-shared/constants'; import { HiddenExpressionOnLayout } from './HiddenExpressionOnLayout'; import { TextResource } from '../../TextResource/TextResource'; import { EditPageId } from './EditPageId'; import { textResourceByLanguageAndIdSelector } from '../../../selectors/textResourceSelectors'; import type { ITextResource } from 'app-shared/types/global'; +import { duplicatedIdsExistsInLayout } from '../../../utils/formLayoutUtils'; +import { PageConfigWarning } from './PageConfigWarning'; export const PageConfigPanel = () => { const { selectedFormLayoutName } = useAppContext(); @@ -30,6 +32,13 @@ export const PageConfigPanel = () => { ? t('right_menu.content_empty') : layoutNameText ?? selectedFormLayoutName; + const layout = useFormLayouts()[selectedFormLayoutName]; + const hasDuplicatedIds = duplicatedIdsExistsInLayout(layout); + + if (layoutIsSelected && hasDuplicatedIds) { + return ; + } + return ( <> { + const { org, app } = useStudioUrlParams(); + const { t } = useTranslation(); + const duplicatedIds = getDuplicatedIds(layout) + .map((id) => `<${id}>`) + .join(', '); + + return ( +
+ } + heading={{ + text: t('ux_editor.config.warning_duplicates.heading'), + level: 2, + }} + className={classes.configWarningHeader} + /> +
+ + {t('ux_editor.config.warning_duplicates.solution_heading')} + + + + + + {t('ux_editor.config.warning_duplicates.solution_gitea')} + + + {t('ux_editor.config.warning_duplicates.solution_gitea_pencel')} + + {t('ux_editor.config.warning_duplicates.solution_gitea_locate')} + {duplicatedIds}. + + {t('ux_editor.config.warning_duplicates.solution_gitea_edit')} + {t('ux_editor.config.warning_duplicates.solution_gitea_commit')} + {t('ux_editor.config.warning_duplicates.solution_studio_import')} + + +
+
+ ); +}; diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx index ca35ee1464d..03949842341 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditComponentIdRow/EditComponentIdRow.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { StudioToggleableTextfieldSchema, type SchemaValidationError } from '@studio/components'; -import { KeyVerticalIcon } from '@navikt/aksel-icons'; +import { KeyVerticalIcon } from '@studio/icons'; import classes from './EditComponentIdRow.module.css'; import { idExists } from '../../../../utils/formLayoutsUtils'; import { Trans, useTranslation } from 'react-i18next'; diff --git a/frontend/packages/ux-editor/src/components/TextResource/TextResource.tsx b/frontend/packages/ux-editor/src/components/TextResource/TextResource.tsx index 224426b0dad..513b5c96567 100644 --- a/frontend/packages/ux-editor/src/components/TextResource/TextResource.tsx +++ b/frontend/packages/ux-editor/src/components/TextResource/TextResource.tsx @@ -3,7 +3,7 @@ import { generateRandomId } from 'app-shared/utils/generateRandomId'; import { generateTextResourceId } from '../../utils/generateId'; import { TextResourceEditor } from './TextResourceEditor'; import { StudioButton, StudioDeleteButton, StudioProperty } from '@studio/components'; -import { XMarkIcon } from '@navikt/aksel-icons'; +import { XMarkIcon } from '@studio/icons'; import { TextResourceValue } from './TextResourceValue'; import { useTranslation } from 'react-i18next'; import { DEFAULT_LANGUAGE } from 'app-shared/constants'; diff --git a/frontend/packages/ux-editor/src/components/config/ConditionalRenderingComponent.tsx b/frontend/packages/ux-editor/src/components/config/ConditionalRenderingComponent.tsx index 31dfd01a7f0..05d7da4a41e 100644 --- a/frontend/packages/ux-editor/src/components/config/ConditionalRenderingComponent.tsx +++ b/frontend/packages/ux-editor/src/components/config/ConditionalRenderingComponent.tsx @@ -18,7 +18,7 @@ import type { } from 'app-shared/types/RuleConfig'; import type i18next from 'i18next'; import type { FormComponent } from '../../types/FormComponent'; -import { Buldings2Icon, XMarkOctagonFillIcon } from '@navikt/aksel-icons'; +import { Buldings2Icon, XMarkOctagonFillIcon } from '@studio/icons'; import type { FormContainer } from '../../types/FormContainer'; export interface IConditionalRenderingComponentProps { diff --git a/frontend/packages/ux-editor/src/components/config/Expressions/NewExpressionButton/NewExpressionButton.tsx b/frontend/packages/ux-editor/src/components/config/Expressions/NewExpressionButton/NewExpressionButton.tsx index 529868cb93d..9a21f9b9b75 100644 --- a/frontend/packages/ux-editor/src/components/config/Expressions/NewExpressionButton/NewExpressionButton.tsx +++ b/frontend/packages/ux-editor/src/components/config/Expressions/NewExpressionButton/NewExpressionButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { DropdownMenu } from '@digdir/design-system-react'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { useText } from '../../../../hooks'; import { StudioDropdownMenu } from '@studio/components'; import { useFormItemContext } from '../../../../containers/FormItemContext'; diff --git a/frontend/packages/ux-editor/src/components/config/RuleComponent.tsx b/frontend/packages/ux-editor/src/components/config/RuleComponent.tsx index e4d540cc39d..07b4d283c05 100644 --- a/frontend/packages/ux-editor/src/components/config/RuleComponent.tsx +++ b/frontend/packages/ux-editor/src/components/config/RuleComponent.tsx @@ -7,7 +7,7 @@ import classes from './RuleComponent.module.css'; import Modal from 'react-modal'; import type { RuleConnection, RuleConnections } from 'app-shared/types/RuleConfig'; import type i18next from 'i18next'; -import { Buldings2Icon } from '@navikt/aksel-icons'; +import { Buldings2Icon } from '@studio/icons'; export interface IRuleComponentProps { connectionId?: string; diff --git a/frontend/packages/ux-editor/src/components/config/componentSpecificContent/Map/MapComponent.tsx b/frontend/packages/ux-editor/src/components/config/componentSpecificContent/Map/MapComponent.tsx index 5dc24aa5a1e..ea4752c7fb4 100644 --- a/frontend/packages/ux-editor/src/components/config/componentSpecificContent/Map/MapComponent.tsx +++ b/frontend/packages/ux-editor/src/components/config/componentSpecificContent/Map/MapComponent.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { PlusIcon, XMarkIcon } from '@navikt/aksel-icons'; +import { PlusIcon, XMarkIcon } from '@studio/icons'; import { LegacyFieldSet, LegacyTextField } from '@digdir/design-system-react'; import type { IGenericEditComponent } from '../../componentConfig'; import { FormField } from '../../../FormField'; diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOption/EditOption.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOption/EditOption.tsx index ae5a9d63f4a..6dc7e3b4629 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOption/EditOption.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOption/EditOption.tsx @@ -7,7 +7,7 @@ import { } from '@studio/components'; import { useTranslation } from 'react-i18next'; import type { Option } from 'app-shared/types/Option'; -import { XMarkIcon } from '@navikt/aksel-icons'; +import { XMarkIcon } from '@studio/icons'; import { TextResource } from '../../../TextResource/TextResource'; import { deleteDescription, diff --git a/frontend/packages/ux-editor/src/components/toolbar/RuleButton.tsx b/frontend/packages/ux-editor/src/components/toolbar/RuleButton.tsx index ef2e25c2067..44c6ac47081 100644 --- a/frontend/packages/ux-editor/src/components/toolbar/RuleButton.tsx +++ b/frontend/packages/ux-editor/src/components/toolbar/RuleButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { StudioButton } from '@studio/components'; -import { CogIcon } from '@navikt/aksel-icons'; +import { CogIcon } from '@studio/icons'; export interface IRuleButtonProps { onClick: () => void; diff --git a/frontend/packages/ux-editor/src/components/toolbar/ToolbarItemComponent.tsx b/frontend/packages/ux-editor/src/components/toolbar/ToolbarItemComponent.tsx index 9a736de000b..42151228802 100644 --- a/frontend/packages/ux-editor/src/components/toolbar/ToolbarItemComponent.tsx +++ b/frontend/packages/ux-editor/src/components/toolbar/ToolbarItemComponent.tsx @@ -2,7 +2,7 @@ import type { MouseEvent } from 'react'; import React from 'react'; import classes from './ToolbarItemComponent.module.css'; import { StudioButton } from '@studio/components'; -import { InformationIcon } from '@navikt/aksel-icons'; +import { InformationIcon } from '@studio/icons'; import { getComponentTitleByComponentType } from '../../utils/language'; import { useTranslation } from 'react-i18next'; import type { ComponentType } from 'app-shared/types/ComponentType'; diff --git a/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx b/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx index 2803f272b16..285024a6d87 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx @@ -1,6 +1,5 @@ import type { ReactNode } from 'react'; import React from 'react'; -import { useFormLayoutsQuery } from '../../hooks/queries/useFormLayoutsQuery'; import classes from './DesignView.module.css'; import { useTranslation } from 'react-i18next'; import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; @@ -8,13 +7,14 @@ import { Accordion } from '@digdir/design-system-react'; import type { IFormLayouts } from '../../types/global'; import type { FormLayoutPage } from '../../types/FormLayoutPage'; import { useFormLayoutSettingsQuery } from '../../hooks/queries/useFormLayoutSettingsQuery'; -import { PlusIcon } from '@navikt/aksel-icons'; +import { PlusIcon } from '@studio/icons'; import { useAddLayoutMutation } from '../../hooks/mutations/useAddLayoutMutation'; import { PageAccordion } from './PageAccordion'; import { ReceiptContent } from './ReceiptContent'; -import { useAppContext } from '../../hooks'; +import { useAppContext, useFormLayouts } from '../../hooks'; import { FormLayout } from './FormLayout'; import { StudioButton } from '@studio/components'; +import { duplicatedIdsExistsInLayout } from '../../utils/formLayoutUtils'; /** * Maps the IFormLayouts object to a list of FormLayouts @@ -41,7 +41,7 @@ export const DesignView = (): ReactNode => { app, selectedFormLayoutSetName, ); - const { data: layouts } = useFormLayoutsQuery(org, app, selectedFormLayoutSetName); + const layouts = useFormLayouts(); const { data: formLayoutSettings } = useFormLayoutSettingsQuery( org, app, @@ -53,7 +53,6 @@ export const DesignView = (): ReactNode => { const { t } = useTranslation(); const formLayoutData = mapFormLayoutsToFormLayoutPages(layouts); - /** * Handles the click of an accordion. It updates the URL and sets the * local storage for which page view that is open @@ -88,14 +87,19 @@ export const DesignView = (): ReactNode => { // If the layout does not exist, return null if (layout === undefined) return null; + // Check if the layout has unique component IDs + const isValidLayout = !duplicatedIdsExistsInLayout(layout.data); return ( handleClickAccordion(layout.page)} + isValid={isValidLayout} > - {layout.page === selectedFormLayoutName && } + {layout.page === selectedFormLayoutName && ( + + )} ); }); diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.test.tsx b/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.test.tsx index 1c3c628b803..c7aa2a40381 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.test.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.test.tsx @@ -12,6 +12,7 @@ import { internalLayoutWithMultiPageGroup } from '../../testing/layoutWithMultiP const defaultProps: FormLayoutProps = { layout: layoutMock, + isValid: true, }; describe('FormLayout', () => { @@ -29,6 +30,31 @@ describe('FormLayout', () => { render(); expect(screen.queryByText(textMock('ux_editor.multi_page_warning'))).not.toBeInTheDocument(); }); + + it('Displays warning about duplicated ids when the layout has such ids', () => { + const layoutWithDuplicatedIds = { + ...layoutMock, + order: { + ['idContainer']: ['idContainer1', 'idContainer2', 'idContainer3'], + ['idContainer1']: ['idContainer1', 'idContainer2', 'idContainer2'], + }, + }; + + render({ layout: layoutWithDuplicatedIds, isValid: false }); + + expect( + screen.getByText(textMock('ux_editor.formLayout.warning_duplicates')), + ).toBeInTheDocument(); + expect( + screen.getByText(textMock('ux_editor.formLayout.warning_duplicates.cannot_publish')), + ).toBeInTheDocument(); + + const duplicatedIds = screen.getByText(/idContainer1, idContainer2/i); + expect(duplicatedIds).toBeInTheDocument(); + + const uniqueIds = screen.queryByText(/idContainer3/i); + expect(uniqueIds).not.toBeInTheDocument(); + }); }); const render = (props?: Partial) => diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.tsx b/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.tsx index c75842d45ca..bbf62e760f9 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/FormLayout.tsx @@ -4,17 +4,24 @@ import React from 'react'; import { hasMultiPageGroup } from '../../utils/formLayoutUtils'; import { useTranslation } from 'react-i18next'; import { Alert, Paragraph } from '@digdir/design-system-react'; +import { FormLayoutWarning } from './FormLayoutWarning'; export interface FormLayoutProps { layout: IInternalLayout; + isValid: boolean; } -export const FormLayout = ({ layout }: FormLayoutProps) => ( - <> - {hasMultiPageGroup(layout) && } - - -); +export const FormLayout = ({ layout, isValid }: FormLayoutProps) => { + if (!isValid) { + return ; + } + return ( + <> + {hasMultiPageGroup(layout) && } + + + ); +}; const MultiPageWarning = () => { const { t } = useTranslation(); diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormLayoutWarning.module.css b/frontend/packages/ux-editor/src/containers/DesignView/FormLayoutWarning.module.css new file mode 100644 index 00000000000..fce30fa3057 --- /dev/null +++ b/frontend/packages/ux-editor/src/containers/DesignView/FormLayoutWarning.module.css @@ -0,0 +1,10 @@ +.warningWrapper { + display: flex; + flex-direction: column; + gap: var(--fds-spacing-4); + padding: var(--fds-spacing-4); +} + +.duplicatedId { + color: var(--fds-semantic-text-danger-default); +} diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormLayoutWarning.tsx b/frontend/packages/ux-editor/src/containers/DesignView/FormLayoutWarning.tsx new file mode 100644 index 00000000000..87c618e1bdc --- /dev/null +++ b/frontend/packages/ux-editor/src/containers/DesignView/FormLayoutWarning.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import type { IInternalLayout } from '../../types/global'; +import { getDuplicatedIds } from '../../utils/formLayoutUtils'; +import { Paragraph } from '@digdir/design-system-react'; +import { useTranslation } from 'react-i18next'; +import classes from './FormLayoutWarning.module.css'; + +interface FormLayoutWarningProps { + layout: IInternalLayout; +} + +export const FormLayoutWarning = ({ layout }: FormLayoutWarningProps) => { + const duplicatedIds = getDuplicatedIds(layout).join(', '); + const { t } = useTranslation(); + return ( +
+ + {t('ux_editor.formLayout.warning_duplicates')} + {duplicatedIds} + + + {t('ux_editor.formLayout.warning_duplicates.cannot_publish')} + +
+ ); +}; diff --git a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx index 542a9e0143d..92331301952 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx @@ -1,7 +1,7 @@ import React, { useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { DropdownMenu } from '@digdir/design-system-react'; -import { MenuElipsisVerticalIcon, ArrowUpIcon, ArrowDownIcon } from '@navikt/aksel-icons'; +import { MenuElipsisVerticalIcon, ArrowUpIcon, ArrowDownIcon } from '@studio/icons'; import { useFormLayoutSettingsQuery } from '../../../../hooks/queries/useFormLayoutSettingsQuery'; import { useUpdateLayoutOrderMutation } from '../../../../hooks/mutations/useUpdateLayoutOrderMutation'; import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; diff --git a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.module.css b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.module.css index 0ccb840c02a..cd2f4365f14 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.module.css +++ b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.module.css @@ -1,23 +1,22 @@ .navigationMenu { display: flex; - justify-content: flex-start; - align-items: stretch; - padding-block: 12px; - margin-left: 10px; + align-items: center; + padding: var(--fds-spacing-1); background-color: var(--background-color); } -.accordionHeader { +.accordionHeader, +.accordionHeaderWarning { flex: 1; } -.accordionHeader button { - border: none; - background-color: var(--background-color); +.accordionHeaderWarning button { + background-color: var(--fds-semantic-surface-danger-subtle) !important; } .accordionContent { padding: 0; + background-color: var(--fds-semantic-surface-neutral-default); } .accordionItem { @@ -31,5 +30,4 @@ .accordionHeaderRow { display: flex; - background-color: var(--background-color); } diff --git a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx index a58b89afcb4..c6bc8dfdd61 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx @@ -18,6 +18,7 @@ export type PageAccordionProps = { isOpen: boolean; onClick: () => void; pageIsReceipt?: boolean; + isValid?: boolean; }; /** @@ -39,6 +40,7 @@ export const PageAccordion = ({ isOpen, onClick, pageIsReceipt, + isValid, }: PageAccordionProps): ReactNode => { const { t } = useTranslation(); const { org, app } = useStudioUrlParams(); @@ -62,7 +64,11 @@ export const PageAccordion = ({ open={isOpen} >
- + {pageName}
diff --git a/frontend/packages/ux-editor/src/utils/formLayoutUtils.test.tsx b/frontend/packages/ux-editor/src/utils/formLayoutUtils.test.tsx index 3aa6fc32b2d..e4d4123f7c9 100644 --- a/frontend/packages/ux-editor/src/utils/formLayoutUtils.test.tsx +++ b/frontend/packages/ux-editor/src/utils/formLayoutUtils.test.tsx @@ -4,9 +4,11 @@ import { addItemOfType, addNavigationButtons, createEmptyLayout, + duplicatedIdsExistsInLayout, findParentId, getChildIds, getDepth, + getDuplicatedIds, getItem, hasMultiPageGroup, hasNavigationButtons, @@ -575,4 +577,35 @@ describe('formLayoutUtils', () => { expect(hasMultiPageGroup(mockInternal)).toBe(false); }); }); + + describe('duplicatedIdsExistsInLayout', () => { + it('Returns true if the layout contains duplicated ids', () => { + const layout = { + ...mockInternal, + order: { + ...mockInternal.order, + [groupId]: [paragraphInGroupId, paragraphInGroupId], + }, + }; + expect(duplicatedIdsExistsInLayout(layout)).toBe(true); + }); + + it('Returns false if the layout does not contain duplicated ids', () => { + expect(duplicatedIdsExistsInLayout(mockInternal)).toBe(false); + }); + }); + + describe('getDuplicatedIds', () => { + it('Returns the duplicated ids in the layout', () => { + const layout = { + ...mockInternal, + order: { + ...mockInternal.order, + [groupId]: [paragraphInGroupId, paragraphInGroupId, paragraphInGroupId], + }, + }; + const duplicatedIds = getDuplicatedIds(layout); + expect(duplicatedIds).toEqual([paragraphInGroupId]); + }); + }); }); diff --git a/frontend/packages/ux-editor/src/utils/formLayoutUtils.ts b/frontend/packages/ux-editor/src/utils/formLayoutUtils.ts index 8b9e8c0fdef..ac8c800f73a 100644 --- a/frontend/packages/ux-editor/src/utils/formLayoutUtils.ts +++ b/frontend/packages/ux-editor/src/utils/formLayoutUtils.ts @@ -5,7 +5,7 @@ import type { IToolbarElement, } from '../types/global'; import { BASE_CONTAINER_ID, MAX_NESTED_GROUP_LEVEL } from 'app-shared/constants'; -import { insertArrayElementAtPos } from 'app-shared/utils/arrayUtils'; +import { insertArrayElementAtPos, areItemsUnique } from 'app-shared/utils/arrayUtils'; import { ArrayUtils, ObjectUtils } from '@studio/pure-functions'; import { ComponentType } from 'app-shared/types/ComponentType'; import type { FormComponent } from '../types/FormComponent'; @@ -16,6 +16,7 @@ import type { FormContainer } from '../types/FormContainer'; import type { FormItem } from '../types/FormItem'; import * as formItemUtils from './formItemUtils'; import type { ContainerComponentType } from '../types/ContainerComponent'; +import { flattenObjectValues } from 'app-shared/utils/objectUtils'; export const mapComponentToToolbarElement = ( c: FormItemConfigs[T], @@ -412,3 +413,26 @@ export const isItemChildOfContainer = ( export const idExistsInLayout = (id: string, layout: IInternalLayout): boolean => Object.keys(layout.components || {}).some((key) => key.toUpperCase() === id.toUpperCase()) || Object.keys(layout.containers || {}).some((key) => key.toUpperCase() === id.toUpperCase()); + +/** + * Checks if there are components with duplicated ids in the layout. + * @param layout The layout to check. + * @returns True if some items in the array are duplicated and false otherwise. + */ +export const duplicatedIdsExistsInLayout = (layout: IInternalLayout): boolean => { + if (!layout?.order) return false; + const idsInLayout = flattenObjectValues(layout.order); + return !areItemsUnique(idsInLayout); +}; + +/** + * Get the duplicated ids in the layout + * @param layout The layout to check + * @returns An array of unique duplicated ids + */ +export const getDuplicatedIds = (layout: IInternalLayout): string[] => { + const idsInLayout = flattenObjectValues(layout.order); + const duplicatedIds = idsInLayout.filter((id, index) => idsInLayout.indexOf(id) !== index); + const uniqueDuplicatedIds = Array.from(new Set(duplicatedIds)); + return uniqueDuplicatedIds; +}; diff --git a/frontend/packages/ux-editor/src/utils/formLayoutsUtils.ts b/frontend/packages/ux-editor/src/utils/formLayoutsUtils.ts index 3585120d6b3..c312b4810ba 100644 --- a/frontend/packages/ux-editor/src/utils/formLayoutsUtils.ts +++ b/frontend/packages/ux-editor/src/utils/formLayoutsUtils.ts @@ -75,11 +75,7 @@ export const convertExternalLayoutsToInternalFormat = ( if (!layout || !layout.data) { convertedLayouts[name] = createEmptyLayout(); } else { - try { - convertedLayouts[name] = externalLayoutToInternal(layouts[name]); - } catch (err) { - console.error(err); - } + convertedLayouts[name] = externalLayoutToInternal(layouts[name]); } }); return convertedLayouts; diff --git a/frontend/studio-root/pages/Contact/Contact.tsx b/frontend/studio-root/pages/Contact/Contact.tsx index 7fbac840373..fe70070a59e 100644 --- a/frontend/studio-root/pages/Contact/Contact.tsx +++ b/frontend/studio-root/pages/Contact/Contact.tsx @@ -2,7 +2,7 @@ import React from 'react'; import classes from './Contact.module.css'; import { Heading, Link, Paragraph } from '@digdir/design-system-react'; import { Trans, useTranslation } from 'react-i18next'; -import { EnvelopeClosedIcon } from '@navikt/aksel-icons'; +import { EnvelopeClosedIcon } from '@studio/icons'; import { PageContainer } from 'app-shared/components/PageContainer/PageContainer'; import Slack from 'app-shared/icons/Slack.svg'; import GitHub from 'app-shared/icons/GitHub.svg';