From b35434813a4fae42fc585340fd7f00083b5a8a1e Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Mon, 8 Apr 2024 12:51:28 +0200 Subject: [PATCH 1/9] add broker service resource --- frontend/language/src/nb.json | 1 + frontend/packages/shared/src/types/ResourceAdm.ts | 6 +++++- frontend/resourceadm/utils/resourceUtils/resourceUtils.ts | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index b30371db873..0268e119c62 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -872,6 +872,7 @@ "resourceadm.about_resource_resource_title_label": "Navn på tjenesten (Bokmål)", "resourceadm.about_resource_resource_title_text": "Navnet vil synes for brukere, og må være gjenkjennelig og beskrivende for hva tjenesten handler om. Pass på å skille tjenester som har like eller nesten like navn, slik at det blir lett for brukere å forstå.", "resourceadm.about_resource_resource_type": "Ressurstype", + "resourceadm.about_resource_resource_type_brokerservice": "Formidlingstjeneste", "resourceadm.about_resource_resource_type_error": "Du mangler å legge til ressurstype.", "resourceadm.about_resource_resource_type_generic_access_resource": "Generisk tilgangsressurs", "resourceadm.about_resource_resource_type_label": "Velg en ressurstype fra listen under.", diff --git a/frontend/packages/shared/src/types/ResourceAdm.ts b/frontend/packages/shared/src/types/ResourceAdm.ts index c05a9e269ae..5baf13a46cc 100644 --- a/frontend/packages/shared/src/types/ResourceAdm.ts +++ b/frontend/packages/shared/src/types/ResourceAdm.ts @@ -33,7 +33,11 @@ export interface ResourceContactPoint { contactPage: string; } -export type ResourceTypeOption = 'GenericAccessResource' | 'Systemresource' | 'MaskinportenSchema'; +export type ResourceTypeOption = + | 'GenericAccessResource' + | 'Systemresource' + | 'MaskinportenSchema' + | 'BrokerService'; export type ResourceStatusOption = 'Completed' | 'Deprecated' | 'UnderDevelopment' | 'Withdrawn'; diff --git a/frontend/resourceadm/utils/resourceUtils/resourceUtils.ts b/frontend/resourceadm/utils/resourceUtils/resourceUtils.ts index 5c0da2b5f55..fa6ae0bd01c 100644 --- a/frontend/resourceadm/utils/resourceUtils/resourceUtils.ts +++ b/frontend/resourceadm/utils/resourceUtils/resourceUtils.ts @@ -19,6 +19,7 @@ export const resourceTypeMap: Record = { GenericAccessResource: 'resourceadm.about_resource_resource_type_generic_access_resource', Systemresource: 'resourceadm.about_resource_resource_type_system_resource', MaskinportenSchema: 'resourceadm.about_resource_resource_type_maskinporten', + BrokerService: 'resourceadm.about_resource_resource_type_brokerservice', }; /** From 7702240eeb45831c29d02c368d82ec043fb5f409 Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Mon, 8 Apr 2024 12:52:18 +0200 Subject: [PATCH 2/9] do not allow empty space as resource version --- frontend/resourceadm/pages/ResourcePage/ResourcePage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/resourceadm/pages/ResourcePage/ResourcePage.tsx b/frontend/resourceadm/pages/ResourcePage/ResourcePage.tsx index 363ae6ee18f..c8f4f852ce6 100644 --- a/frontend/resourceadm/pages/ResourcePage/ResourcePage.tsx +++ b/frontend/resourceadm/pages/ResourcePage/ResourcePage.tsx @@ -286,7 +286,7 @@ export const ResourcePage = (): React.JSX.Element => { onSaveVersion={(version: string) => handleSaveResource({ ...resourceData, - version, + version: version?.trim(), // empty version is not allowed }) } id='page-content-deploy' From a7e13646ac405fab49af5d89ceeb062ca1f7ddbf Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Mon, 8 Apr 2024 14:38:23 +0200 Subject: [PATCH 3/9] sort link services for import + show service owner code in import combobox --- .../packages/shared/src/types/Altinn2LinkService.ts | 1 + .../ImportResourceModal/ImportResourceModal.test.tsx | 3 ++- .../ServiceContent/ServiceContent.test.tsx | 6 ++++-- .../resourceadm/utils/mapperUtils/mapperUtils.test.ts | 8 +++++--- frontend/resourceadm/utils/mapperUtils/mapperUtils.ts | 10 ++++++++-- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/frontend/packages/shared/src/types/Altinn2LinkService.ts b/frontend/packages/shared/src/types/Altinn2LinkService.ts index dec93277f47..e0247e66581 100644 --- a/frontend/packages/shared/src/types/Altinn2LinkService.ts +++ b/frontend/packages/shared/src/types/Altinn2LinkService.ts @@ -1,4 +1,5 @@ export interface Altinn2LinkService { + serviceOwnerCode: string; serviceName: string; externalServiceCode: string; externalServiceEditionCode: string; diff --git a/frontend/resourceadm/components/ImportResourceModal/ImportResourceModal.test.tsx b/frontend/resourceadm/components/ImportResourceModal/ImportResourceModal.test.tsx index 2e917b3a6c5..16ea5aa2b67 100644 --- a/frontend/resourceadm/components/ImportResourceModal/ImportResourceModal.test.tsx +++ b/frontend/resourceadm/components/ImportResourceModal/ImportResourceModal.test.tsx @@ -13,12 +13,13 @@ import type { Altinn2LinkService } from 'app-shared/types/Altinn2LinkService'; import { ServerCodes } from 'app-shared/enums/ServerCodes'; const mockAltinn2LinkService: Altinn2LinkService = { + serviceOwnerCode: 'ttd', externalServiceCode: 'code1', externalServiceEditionCode: 'edition1', serviceName: 'TestService', }; const mockAltinn2LinkServices: Altinn2LinkService[] = [mockAltinn2LinkService]; -const mockOption: string = `${mockAltinn2LinkService.externalServiceCode}-${mockAltinn2LinkService.externalServiceEditionCode}-${mockAltinn2LinkService.serviceName}`; +const mockOption: string = `${mockAltinn2LinkService.serviceOwnerCode}: ${mockAltinn2LinkService.externalServiceCode}-${mockAltinn2LinkService.externalServiceEditionCode}-${mockAltinn2LinkService.serviceName}`; const mockOnClose = jest.fn(); const getAltinn2LinkServices = jest diff --git a/frontend/resourceadm/components/ImportResourceModal/ServiceContent/ServiceContent.test.tsx b/frontend/resourceadm/components/ImportResourceModal/ServiceContent/ServiceContent.test.tsx index 12937896521..5620b1c6f60 100644 --- a/frontend/resourceadm/components/ImportResourceModal/ServiceContent/ServiceContent.test.tsx +++ b/frontend/resourceadm/components/ImportResourceModal/ServiceContent/ServiceContent.test.tsx @@ -15,11 +15,13 @@ const mockSelectedContext: string = 'selectedContext'; const mockEnv: string = 'env1'; const mockAltinn2LinkService: Altinn2LinkService = { + serviceOwnerCode: 'ttd', externalServiceCode: 'code1', externalServiceEditionCode: 'edition1', serviceName: 'TestService', }; const mockAltinn2HyphenLinkService: Altinn2LinkService = { + serviceOwnerCode: 'ttd', externalServiceCode: 'code2', externalServiceEditionCode: 'edition2', serviceName: 'test-med---hyphens', @@ -28,8 +30,8 @@ const mockAltinn2LinkServices: Altinn2LinkService[] = [ mockAltinn2LinkService, mockAltinn2HyphenLinkService, ]; -const mockOption: string = `${mockAltinn2LinkService.externalServiceCode}-${mockAltinn2LinkService.externalServiceEditionCode}-${mockAltinn2LinkService.serviceName}`; -const mockHyphenOption: string = `${mockAltinn2HyphenLinkService.externalServiceCode}-${mockAltinn2HyphenLinkService.externalServiceEditionCode}-${mockAltinn2HyphenLinkService.serviceName}`; +const mockOption: string = `${mockAltinn2LinkService.serviceOwnerCode}: ${mockAltinn2LinkService.externalServiceCode}-${mockAltinn2LinkService.externalServiceEditionCode}-${mockAltinn2LinkService.serviceName}`; +const mockHyphenOption: string = `${mockAltinn2HyphenLinkService.serviceOwnerCode}: ${mockAltinn2HyphenLinkService.externalServiceCode}-${mockAltinn2HyphenLinkService.externalServiceEditionCode}-${mockAltinn2HyphenLinkService.serviceName}`; const mockOnSelectService = jest.fn(); diff --git a/frontend/resourceadm/utils/mapperUtils/mapperUtils.test.ts b/frontend/resourceadm/utils/mapperUtils/mapperUtils.test.ts index 23e01921ee0..38eff0b40fc 100644 --- a/frontend/resourceadm/utils/mapperUtils/mapperUtils.test.ts +++ b/frontend/resourceadm/utils/mapperUtils/mapperUtils.test.ts @@ -5,23 +5,25 @@ describe('mapperUtils', () => { describe('mapAltinn2LinkServiceToSelectOption', () => { const mockLinkServices: Altinn2LinkService[] = [ { + serviceOwnerCode: 'ttd', externalServiceCode: 'code1', externalServiceEditionCode: 'edition1', serviceName: 'name1', }, { + serviceOwnerCode: 'acn', externalServiceCode: 'code2', externalServiceEditionCode: 'edition2', serviceName: 'name2', }, ]; - it('should map Altinn2LinkService to SelectOption correctly', () => { + it('should map and sort Altinn2LinkService to SelectOption correctly', () => { const result = mapAltinn2LinkServiceToSelectOption(mockLinkServices); expect(result).toHaveLength(mockLinkServices.length); - expect(result[0].value).toBe(JSON.stringify(mockLinkServices[0])); - expect(result[0].label).toBe('code1-edition1-name1'); + expect(result[0].value).toBe(JSON.stringify(mockLinkServices[1])); + expect(result[0].label).toBe('acn: code2-edition2-name2'); }); }); }); diff --git a/frontend/resourceadm/utils/mapperUtils/mapperUtils.ts b/frontend/resourceadm/utils/mapperUtils/mapperUtils.ts index 486a27a1e41..421b83a3e5c 100644 --- a/frontend/resourceadm/utils/mapperUtils/mapperUtils.ts +++ b/frontend/resourceadm/utils/mapperUtils/mapperUtils.ts @@ -23,9 +23,15 @@ export const sortResourceListByDate = (resourceList: ResourceListItem[]): Resour * @returns an object that looks like this: { value: string, label: string } */ export const mapAltinn2LinkServiceToSelectOption = (linkServices: Altinn2LinkService[]) => { - return linkServices.map((ls: Altinn2LinkService) => ({ + const sortedServices = [...linkServices].sort((a, b) => { + const serviceOwnerValue = a.serviceOwnerCode.localeCompare(b.serviceOwnerCode); + return serviceOwnerValue === 0 + ? a.externalServiceCode.localeCompare(b.externalServiceCode) + : serviceOwnerValue; + }); + return sortedServices.map((ls: Altinn2LinkService) => ({ value: JSON.stringify(ls), - label: `${ls.externalServiceCode}-${ls.externalServiceEditionCode}-${ls.serviceName}`, + label: `${ls.serviceOwnerCode}: ${ls.externalServiceCode}-${ls.externalServiceEditionCode}-${ls.serviceName}`, })); }; From 2558f2f2d12dd4a8e0543fcaaecb2250c10ee943 Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Tue, 9 Apr 2024 10:43:56 +0200 Subject: [PATCH 4/9] show resource id as readonly field --- frontend/language/src/nb.json | 3 +++ .../components/ResourcePageInputs/ResourceTextField.tsx | 7 +++++++ .../pages/AboutResourcePage/AboutResourcePage.tsx | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 0268e119c62..1fdcb5c2bea 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -844,6 +844,8 @@ "resourceadm.about_resource_error_usage_string_title": "tittel", "resourceadm.about_resource_homepage_label": "Hjemmeside", "resourceadm.about_resource_homepage_text": "Lenke til informasjon om hvor sluttbruker kan finne tjenesten og informasjon om den.", + "resourceadm.about_resource_identifier_description": "Dette er en unik ID for ressursen både i URler og i APIer.", + "resourceadm.about_resource_identifier_label": "Ressurs-id", "resourceadm.about_resource_keywords_label": "Nøkkelord", "resourceadm.about_resource_keywords_text": "Ord som er enkle å søke på. Separer hvert ord med komma \",\".", "resourceadm.about_resource_langauge_error_missing_1": "Du mangler oversettelse for {{usageString}} på {{lang}}.", @@ -934,6 +936,7 @@ "resourceadm.dashboard_table_header_last_changed": "Sist endret", "resourceadm.dashboard_table_header_name": "Navn", "resourceadm.dashboard_table_header_policy_rules": "Tilgangsregler", + "resourceadm.dashboard_table_header_resourceid": "Ressurs-id", "resourceadm.dashboard_table_row_edit": "Rediger ressurs", "resourceadm.dashboard_table_row_has_policy": "Har tilgangsregler", "resourceadm.dashboard_table_row_missing_policy": "Mangler tilgangsregler", diff --git a/frontend/resourceadm/components/ResourcePageInputs/ResourceTextField.tsx b/frontend/resourceadm/components/ResourcePageInputs/ResourceTextField.tsx index 719c604d286..01f02ebaab7 100644 --- a/frontend/resourceadm/components/ResourcePageInputs/ResourceTextField.tsx +++ b/frontend/resourceadm/components/ResourcePageInputs/ResourceTextField.tsx @@ -44,6 +44,10 @@ type ResourceTextFieldProps = { * Whether this field is required or not */ required?: boolean; + /** + * Whether this field is read only or not + */ + readOnly?: boolean; }; /** @@ -59,6 +63,7 @@ type ResourceTextFieldProps = { * @property {boolean}[showErrorMessage] - Flag for if the error message should be shown * @property {string}[errorText] - The text to be shown * @property {boolean}[required] - Whether this field is required or not + * @property {boolean}[readOnly] - Whether this field is read only or not * * @returns {React.JSX.Element} - The rendered component */ @@ -74,6 +79,7 @@ export const ResourceTextField = forwardRef { @@ -94,6 +100,7 @@ export const ResourceTextField = forwardRef onBlur(val)} required={required} + readOnly={readOnly} /> {showErrorMessage && } diff --git a/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.tsx b/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.tsx index d2b981d914f..d9ea74c2ea4 100644 --- a/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.tsx +++ b/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.tsx @@ -102,6 +102,14 @@ export const AboutResourcePage = ({ {t('resourceadm.about_resource_title')} + setTranslationType('none')} + onBlur={() => {}} + /> Date: Tue, 9 Apr 2024 10:50:41 +0200 Subject: [PATCH 5/9] show list id field as readonly instead of disabled --- .../components/AccessListDetails/AccessListDetail.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/resourceadm/components/AccessListDetails/AccessListDetail.tsx b/frontend/resourceadm/components/AccessListDetails/AccessListDetail.tsx index c4acb02981b..c4a11c5e7f5 100644 --- a/frontend/resourceadm/components/AccessListDetails/AccessListDetail.tsx +++ b/frontend/resourceadm/components/AccessListDetails/AccessListDetail.tsx @@ -84,7 +84,7 @@ export const AccessListDetail = ({ label={t('resourceadm.listadmin_list_id')} description={t('resourceadm.listadmin_list_id_description')} > - + Date: Tue, 9 Apr 2024 10:51:19 +0200 Subject: [PATCH 6/9] show resource identifier in resource table --- .../resourceadm/components/ResourceTable/ResourceTable.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/resourceadm/components/ResourceTable/ResourceTable.tsx b/frontend/resourceadm/components/ResourceTable/ResourceTable.tsx index 27e8d4b95ca..033dd865c0e 100644 --- a/frontend/resourceadm/components/ResourceTable/ResourceTable.tsx +++ b/frontend/resourceadm/components/ResourceTable/ResourceTable.tsx @@ -71,6 +71,11 @@ export const ResourceTable = ({ headerName: t('resourceadm.dashboard_table_header_name'), width: 200, }, + { + field: 'identifier', + headerName: t('resourceadm.dashboard_table_header_resourceid'), + width: 200, + }, { field: 'createdBy', headerName: t('resourceadm.dashboard_table_header_createdby'), From 0fad6f190193805ffff5f35b7b55596c21938f72 Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Tue, 9 Apr 2024 11:28:32 +0200 Subject: [PATCH 7/9] add UU improvements to RRR table --- frontend/language/src/nb.json | 2 ++ .../AccessListMembers/AccessListMembers.tsx | 16 +++---------- .../AccessListMembersTable.tsx | 24 +++++++++++++++---- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 1fdcb5c2bea..d11dd9e5e68 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -980,6 +980,7 @@ "resourceadm.left_nav_bar_organization_access": "Organisasjonstilganger", "resourceadm.left_nav_bar_policy": "Tilgangsregler", "resourceadm.listadmin_add_to_list": "Legg til i liste", + "resourceadm.listadmin_add_to_list_org": "Legg til {{org}} i liste", "resourceadm.listadmin_back": "Tilbake til dashboard", "resourceadm.listadmin_confirm_create_list": "Opprett tilgangsliste", "resourceadm.listadmin_create_list": "Opprett ny tilgangsliste", @@ -1013,6 +1014,7 @@ "resourceadm.listadmin_parties": "Enheter", "resourceadm.listadmin_party": "Enhet", "resourceadm.listadmin_remove_from_list": "Fjern fra liste", + "resourceadm.listadmin_remove_from_list_org": "Fjern {{org}} fra liste", "resourceadm.listadmin_resource_header": "Tilgangslister for {{resourceTitle}} - {{env}}", "resourceadm.listadmin_resource_list_checkbox_header": "Alle enheter og underenheter i valgte liste(r) kan bruke ressursen", "resourceadm.listadmin_search": "Søk for å legge til ny enhet eller underenhet", diff --git a/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx b/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx index 746747fbdb3..9af76f25410 100644 --- a/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx +++ b/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx @@ -11,7 +11,7 @@ import { usePartiesRegistryQuery } from '../../hooks/queries/usePartiesRegistryQ import { useSubPartiesRegistryQuery } from '../../hooks/queries/useSubPartiesRegistryQuery'; import { getPartiesQueryUrl } from '../../utils/urlUtils'; import { StudioSpinner, StudioButton } from '@studio/components'; -import { PlusIcon, PlusCircleIcon, MinusCircleIcon } from '@studio/icons'; +import { PlusIcon } from '@studio/icons'; import { AccessListMembersPaging } from './AccessListMembersPaging'; import { AccessListMembersTable } from './AccessListMembersTable'; @@ -71,12 +71,7 @@ export const AccessListMembers = ({ > - {t('resourceadm.listadmin_remove_from_list')} - - - } + isAdd={false} onButtonClick={(item: AccessListMember) => handleRemoveMember(item.orgNr)} /> {listItems.length === 0 && ( @@ -118,12 +113,7 @@ export const AccessListMembers = ({ disableButtonFn={(disableItem: AccessListMember) => !!listItems.find((listItem) => disableItem.orgNr === listItem.orgNr) } - buttonNode={ - <> - {t('resourceadm.listadmin_add_to_list')} - - - } + isAdd={true} onButtonClick={handleAddMember} /> {(isLoadingParties || isLoadingSubParties) && ( diff --git a/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx b/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx index bf3d4826fff..8d4553948fd 100644 --- a/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx +++ b/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx @@ -4,10 +4,11 @@ import { Table } from '@digdir/design-system-react'; import type { AccessListMember } from 'app-shared/types/ResourceAdm'; import { StudioButton } from '@studio/components'; import classes from './AccessListMembers.module.css'; +import { PlusCircleIcon, MinusCircleIcon } from '@studio/icons'; interface AccessListMembersTableProps { listItems: AccessListMember[]; - buttonNode: React.JSX.Element; + isAdd: boolean; isHeaderHidden?: boolean; disableButtonFn?: (member: AccessListMember) => boolean; onButtonClick: (member: AccessListMember) => void; @@ -15,7 +16,7 @@ interface AccessListMembersTableProps { export const AccessListMembersTable = ({ listItems, - buttonNode, + isAdd, isHeaderHidden, disableButtonFn, onButtonClick, @@ -42,7 +43,7 @@ export const AccessListMembersTable = ({ {listItems.map((item) => { return ( - {item.orgNr} + {item.orgNr} {item.orgName || t('resourceadm.listadmin_empty_name')} {item.isSubParty @@ -51,12 +52,27 @@ export const AccessListMembersTable = ({ onButtonClick(item)} disabled={disableButtonFn ? disableButtonFn(item) : false} variant='tertiary' size='small' > - {buttonNode} + {isAdd ? ( + <> + {t('resourceadm.listadmin_add_to_list')} + + + ) : ( + <> + {t('resourceadm.listadmin_remove_from_list')} + + + )} From bc469e299c6b6e9c8434b8b885a3b22061cc09db Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Tue, 9 Apr 2024 13:00:04 +0200 Subject: [PATCH 8/9] improve coverage --- .../pages/AboutResourcePage/AboutResourcePage.test.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx b/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx index a290706b53f..de9dd14883c 100644 --- a/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx +++ b/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx @@ -86,6 +86,16 @@ describe('AboutResourcePage', () => { id: mockId, }; + it('handles resource id field blur', async () => { + render(); + + const idInput = screen.getByLabelText(textMock('resourceadm.about_resource_identifier_label')); + + await act(() => idInput.blur()); + + expect(mockOnSaveResource).not.toHaveBeenCalled(); + }); + it('handles resource type change', async () => { const user = userEvent.setup(); render(); From e3f24f6b495efdfbae32355aa53ba79823a40f67 Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Tue, 9 Apr 2024 14:52:22 +0200 Subject: [PATCH 9/9] code review changes --- .../AccessListErrorMessage.tsx | 4 +- .../AccessListMembers/AccessListMembers.tsx | 7 +- .../AccessListMembersTable.tsx | 66 +++++++++++-------- .../AboutResourcePage.test.tsx | 1 + .../pages/ListAdminPage/ListAdminPage.tsx | 2 +- .../resourceadm/utils/stringUtils/index.ts | 2 +- .../utils/stringUtils/stringUtils.ts | 11 ++++ 7 files changed, 55 insertions(+), 38 deletions(-) diff --git a/frontend/resourceadm/components/AccessListErrorMessage/AccessListErrorMessage.tsx b/frontend/resourceadm/components/AccessListErrorMessage/AccessListErrorMessage.tsx index 0a016b81441..db7764463b8 100644 --- a/frontend/resourceadm/components/AccessListErrorMessage/AccessListErrorMessage.tsx +++ b/frontend/resourceadm/components/AccessListErrorMessage/AccessListErrorMessage.tsx @@ -2,8 +2,8 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import type { AxiosError } from 'axios'; import { Alert } from '@digdir/design-system-react'; -import { getEnvLabel } from 'resourceadm/utils/resourceUtils'; -import { type EnvId } from 'resourceadm/utils/resourceUtils'; +import { getEnvLabel } from '../../utils/resourceUtils'; +import { type EnvId } from '../../utils/resourceUtils'; interface AccessListErrorMessageProps { error: AxiosError; diff --git a/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx b/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx index 9af76f25410..9e6e727c249 100644 --- a/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx +++ b/frontend/resourceadm/components/AccessListMembers/AccessListMembers.tsx @@ -71,7 +71,6 @@ export const AccessListMembers = ({ > handleRemoveMember(item.orgNr)} /> {listItems.length === 0 && ( @@ -110,10 +109,8 @@ export const AccessListMembers = ({ - !!listItems.find((listItem) => disableItem.orgNr === listItem.orgNr) - } - isAdd={true} + disabledItems={listItems} + isAdd onButtonClick={handleAddMember} /> {(isLoadingParties || isLoadingSubParties) && ( diff --git a/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx b/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx index 8d4553948fd..8e4025878c3 100644 --- a/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx +++ b/frontend/resourceadm/components/AccessListMembers/AccessListMembersTable.tsx @@ -5,12 +5,13 @@ import type { AccessListMember } from 'app-shared/types/ResourceAdm'; import { StudioButton } from '@studio/components'; import classes from './AccessListMembers.module.css'; import { PlusCircleIcon, MinusCircleIcon } from '@studio/icons'; +import { stringNumberToAriaLabel } from '../../utils/stringUtils'; interface AccessListMembersTableProps { listItems: AccessListMember[]; - isAdd: boolean; + isAdd?: boolean; isHeaderHidden?: boolean; - disableButtonFn?: (member: AccessListMember) => boolean; + disabledItems?: AccessListMember[]; onButtonClick: (member: AccessListMember) => void; } @@ -18,11 +19,42 @@ export const AccessListMembersTable = ({ listItems, isAdd, isHeaderHidden, - disableButtonFn, + disabledItems, onButtonClick, }: AccessListMembersTableProps): React.JSX.Element => { const { t } = useTranslation(); + const renderActionButton = (item: AccessListMember): React.JSX.Element => { + let buttonAriaLabel: string; + let buttonIcon: React.JSX.Element; + let buttonText: string; + if (isAdd) { + buttonAriaLabel = t('resourceadm.listadmin_add_to_list_org', { org: item.orgName }); + buttonIcon = ; + buttonText = t('resourceadm.listadmin_add_to_list'); + } else { + buttonAriaLabel = t('resourceadm.listadmin_remove_from_list_org', { + org: item.orgName, + }); + buttonIcon = ; + buttonText = t('resourceadm.listadmin_remove_from_list'); + } + return ( + onButtonClick(item)} + disabled={ + disabledItems && disabledItems.some((existingItem) => existingItem.orgNr === item.orgNr) + } + variant='tertiary' + size='small' + > + {buttonText} + {buttonIcon} + + ); + }; + return ( @@ -43,38 +75,14 @@ export const AccessListMembersTable = ({ {listItems.map((item) => { return ( - {item.orgNr} + {item.orgNr} {item.orgName || t('resourceadm.listadmin_empty_name')} {item.isSubParty ? t('resourceadm.listadmin_sub_party') : t('resourceadm.listadmin_party')} - - onButtonClick(item)} - disabled={disableButtonFn ? disableButtonFn(item) : false} - variant='tertiary' - size='small' - > - {isAdd ? ( - <> - {t('resourceadm.listadmin_add_to_list')} - - - ) : ( - <> - {t('resourceadm.listadmin_remove_from_list')} - - - )} - - + {renderActionButton(item)} ); })} diff --git a/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx b/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx index de9dd14883c..4f5991274dd 100644 --- a/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx +++ b/frontend/resourceadm/pages/AboutResourcePage/AboutResourcePage.test.tsx @@ -91,6 +91,7 @@ describe('AboutResourcePage', () => { const idInput = screen.getByLabelText(textMock('resourceadm.about_resource_identifier_label')); + await act(() => idInput.focus()); await act(() => idInput.blur()); expect(mockOnSaveResource).not.toHaveBeenCalled(); diff --git a/frontend/resourceadm/pages/ListAdminPage/ListAdminPage.tsx b/frontend/resourceadm/pages/ListAdminPage/ListAdminPage.tsx index ab4249494fd..bea09e091b7 100644 --- a/frontend/resourceadm/pages/ListAdminPage/ListAdminPage.tsx +++ b/frontend/resourceadm/pages/ListAdminPage/ListAdminPage.tsx @@ -12,7 +12,7 @@ import { getAccessListPageUrl, getResourceDashboardURL } from '../../utils/urlUt import { useUrlParams } from '../../hooks/useSelectedContext'; import type { EnvId } from '../../utils/resourceUtils'; import { getAvailableEnvironments, getEnvLabel } from '../../utils/resourceUtils'; -import { AccessListErrorMessage } from 'resourceadm/components/AccessListErrorMessage'; +import { AccessListErrorMessage } from '../../components/AccessListErrorMessage'; export const ListAdminPage = (): React.JSX.Element => { const { t } = useTranslation(); diff --git a/frontend/resourceadm/utils/stringUtils/index.ts b/frontend/resourceadm/utils/stringUtils/index.ts index ed5b957f98a..75bf35bfce0 100644 --- a/frontend/resourceadm/utils/stringUtils/index.ts +++ b/frontend/resourceadm/utils/stringUtils/index.ts @@ -1 +1 @@ -export { formatIdString, isAppPrefix, isSePrefix } from './stringUtils'; +export { formatIdString, isAppPrefix, isSePrefix, stringNumberToAriaLabel } from './stringUtils'; diff --git a/frontend/resourceadm/utils/stringUtils/stringUtils.ts b/frontend/resourceadm/utils/stringUtils/stringUtils.ts index b52664fc057..58758509a9c 100644 --- a/frontend/resourceadm/utils/stringUtils/stringUtils.ts +++ b/frontend/resourceadm/utils/stringUtils/stringUtils.ts @@ -15,3 +15,14 @@ export const isAppPrefix = (s: string): boolean => { export const isSePrefix = (s: string): boolean => { return s.substring(0, 3) === 'se_'; }; + +/** + * Numbers with a specific meaning (postal numbers, phone numbers etc) should not be + * read by screen readers as millons-thousands etc, but rather as groups of numbers. + * + * @param s the string to format + * @returns the string formatted + */ +export const stringNumberToAriaLabel = (s: string): string => { + return s.split('').join(' '); +};