Skip to content

Commit

Permalink
feat(resource-adm): add better error messages for migrate delegations (
Browse files Browse the repository at this point in the history
  • Loading branch information
mgunnerud authored Dec 9, 2024
1 parent 5565df8 commit f93a1ab
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 25 deletions.
7 changes: 7 additions & 0 deletions backend/src/Designer/Controllers/ResourceAdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,13 @@ public async Task<ActionResult> ImportResource(string org, string serviceCode, i
[Route("designer/api/{org}/resources/altinn2/delegationcount/{serviceCode}/{serviceEdition}/{env}")]
public async Task<ActionResult> GetDelegationCount(string org, string serviceCode, int serviceEdition, string env)
{
List<ServiceResource> allResources = await _resourceRegistry.GetResourceList(env.ToLower(), true);
bool serviceExists = allResources.Any(x => x.Identifier.Equals($"se_{serviceCode}_{serviceEdition}"));
if (!serviceExists)
{
return new NotFoundResult();
}

ServiceResource resource = await _resourceRegistry.GetServiceResourceFromService(serviceCode, serviceEdition, env.ToLower());
if (!IsServiceOwner(resource, org))
{
Expand Down
1 change: 1 addition & 0 deletions frontend/packages/shared/src/enums/ServerCodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export enum ServerCodes {
NotFound = 404,
PreconditionFailed = 412,
TooLargeContent = 413,
InternalServerError = 500,
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { textMock } from '@studio/testing/mocks/i18nMock';
import { MemoryRouter } from 'react-router-dom';
Expand Down Expand Up @@ -47,7 +47,52 @@ describe('MigrationPanel', () => {
}),
},
);
await waitFor(() => screen.findByText(textMock('resourceadm.migration_not_needed')));
expect(
await screen.findByText(textMock('resourceadm.migration_not_needed')),
).toBeInTheDocument();
});

it('should show message if link service does not exist in given environment', async () => {
renderMigrationPanel(
{},
{
getAltinn2DelegationsCount: jest.fn().mockImplementation(() => {
return Promise.reject({ response: { status: ServerCodes.NotFound } });
}),
},
);
expect(
await screen.findByText(textMock('resourceadm.migration_service_not_found')),
).toBeInTheDocument();
});

it('should show message if link service cannot be migrated in given environment', async () => {
renderMigrationPanel(
{},
{
getAltinn2DelegationsCount: jest.fn().mockImplementation(() => {
return Promise.reject({ response: { status: ServerCodes.Forbidden } });
}),
},
);
expect(
await screen.findByText(textMock('resourceadm.migration_cannot_migrate_in_env')),
).toBeInTheDocument();
});

it('should show message if get delegation count fails in given environment', async () => {
renderMigrationPanel(
{},
{
getAltinn2DelegationsCount: jest.fn().mockImplementation(() => {
return Promise.reject({ response: { status: ServerCodes.InternalServerError } });
}),
},
);

expect(
await screen.findByText(textMock('resourceadm.migration_technical_error')),
).toBeInTheDocument();
});

it('should show error when user starts migrate delegations if user has no permission to migrate', async () => {
Expand Down
39 changes: 17 additions & 22 deletions frontend/resourceadm/components/MigrationPanel/MigrationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import { Alert, Checkbox, Heading } from '@digdir/designsystemet-react';
import { useTranslation } from 'react-i18next';
import { StudioButton, StudioModal } from '@studio/components';
import classes from './MigrationPanel.module.css';
import type { Environment } from '../../utils/resourceUtils';
import { getMigrationErrorMessage, type Environment } from '../../utils/resourceUtils';
import { useGetAltinn2DelegationsCount } from '../../hooks/queries/useGetAltinn2DelegationCount';
import { useMigrateDelegationsMutation } from '../../hooks/mutations/useMigrateDelegationsMutation';
import { useUrlParams } from '../../hooks/useUrlParams';
import type { ResourceError } from 'app-shared/types/ResourceAdm';
import { ServerCodes } from 'app-shared/enums/ServerCodes';

export interface MigrationPanelProps {
serviceCode: string;
Expand All @@ -35,12 +33,11 @@ export const MigrationPanel = ({
const { mutate: migrateDelegations, isPending: isSettingMigrateDelegations } =
useMigrateDelegationsMutation(org, env.id);

const { data: numberOfA2Delegations, isFetching: isLoadingDelegationCount } =
useGetAltinn2DelegationsCount(org, serviceCode, serviceEdition, env.id);

const isErrorForbidden = (error: Error) => {
return (error as ResourceError)?.response?.status === ServerCodes.Forbidden;
};
const {
data: numberOfA2Delegations,
isFetching: isLoadingDelegationCount,
error: loadDelegationCountError,
} = useGetAltinn2DelegationsCount(org, serviceCode, serviceEdition, env.id);

const postMigrateDelegations = (): void => {
setMigrateDelegationsError(null);
Expand All @@ -67,6 +64,13 @@ export const MigrationPanel = ({
setServiceExpiredWarningModalRef.current?.close();
};

const errorMessage = getMigrationErrorMessage(
loadDelegationCountError,
migrateDelegationsError,
isPublishedInEnv,
);
const isMigrateButtonDisabled = !!errorMessage || isSettingMigrateDelegations;

return (
<>
<StudioModal.Dialog
Expand Down Expand Up @@ -109,28 +113,19 @@ export const MigrationPanel = ({
<div>
{t('resourceadm.migration_altinn3_delegations')} <strong>N/A</strong>
</div>
{!isPublishedInEnv && (
<Alert severity='warning' size='sm'>
{t('resourceadm.migration_not_published')}
</Alert>
)}
{isPublishedInEnv && numberOfA2Delegations?.numberOfDelegations === 0 && (
<Alert severity='info' size='sm'>
{t('resourceadm.migration_not_needed')}
</Alert>
)}
{migrateDelegationsError && (
<Alert severity='danger' size='small'>
{isErrorForbidden(migrateDelegationsError)
? t('resourceadm.migration_no_migration_access')
: t('resourceadm.migration_post_migration_failed')}
</Alert>
{errorMessage && (
<Alert severity={errorMessage.severity}>{t(errorMessage.errorMessage)}</Alert>
)}
</div>
<StudioButton
aria-disabled={!isPublishedInEnv || isSettingMigrateDelegations}
aria-disabled={isMigrateButtonDisabled}
onClick={() => {
if (isPublishedInEnv && !isSettingMigrateDelegations) {
if (!isMigrateButtonDisabled) {
setServiceExpiredWarningModalRef.current?.showModal();
}
}}
Expand Down
3 changes: 3 additions & 0 deletions frontend/resourceadm/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@
"resourceadm.migration_altinn2_delegations": "Delegeringer i Altinn 2:",
"resourceadm.migration_altinn3_delegations": "Delegeringer i Altinn 3:",
"resourceadm.migration_not_published": "Ressursen må publiseres før migrering kan startes",
"resourceadm.migration_service_not_found": "Tjenesten finnes ikke i dette miljøet, eller er allerede migrert",
"resourceadm.migration_cannot_migrate_in_env": "Du kan ikke migrere tjenesten i dette miljøet",
"resourceadm.migration_technical_error": "Teknisk feil, kunne ikke hente antall delegeringer",
"resourceadm.migration_not_needed": "Migrering er ikke nødvendig i dette miljøet",
"resourceadm.migration_migrate_environment": "Start migrering i {{env}}",
"resourceadm.migration_confirm_migration": "Jeg har testet integrasjonen i Altinn 3 og er klar til å starte migrering",
Expand Down
1 change: 1 addition & 0 deletions frontend/resourceadm/utils/resourceUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export {
resourceTypeMap,
validateResource,
getAltinn2Reference,
getMigrationErrorMessage,
} from './resourceUtils';
export type { EnvId, Environment } from './resourceUtils';
46 changes: 45 additions & 1 deletion frontend/resourceadm/utils/resourceUtils/resourceUtils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
getEnvLabel,
mapKeywordStringToKeywordTypeArray,
validateResource,
getMigrationErrorMessage,
} from './';
import type { EnvId } from './resourceUtils';
import type { Resource, SupportedLanguage } from 'app-shared/types/ResourceAdm';
import type { Resource, ResourceError, SupportedLanguage } from 'app-shared/types/ResourceAdm';
import { ServerCodes } from 'app-shared/enums/ServerCodes';

describe('mapKeywordStringToKeywordTypeArray', () => {
it('should split keywords correctly', () => {
Expand Down Expand Up @@ -219,3 +221,45 @@ describe('deepCompare', () => {
});
});
});

describe('getMigrationErrorMessage', () => {
it('returns no error', () => {
const error = getMigrationErrorMessage(null, null, true);
expect(error).toBeNull();
});

it('returns error when start migration status is forbidden', () => {
const migrateError = { response: { status: ServerCodes.Forbidden } };
const error = getMigrationErrorMessage(null, migrateError as ResourceError, true);
expect(error.errorMessage).toEqual('resourceadm.migration_no_migration_access');
});

it('returns error when start migration failed', () => {
const migrateError = { response: { status: ServerCodes.InternalServerError } };
const error = getMigrationErrorMessage(null, migrateError as ResourceError, true);
expect(error.errorMessage).toEqual('resourceadm.migration_post_migration_failed');
});

it('returns error when service is not found', () => {
const loadDelegationCountError = { response: { status: ServerCodes.NotFound } };
const error = getMigrationErrorMessage(loadDelegationCountError as ResourceError, null, true);
expect(error.errorMessage).toEqual('resourceadm.migration_service_not_found');
});

it('returns error when service cannot be migrated in environment', () => {
const loadDelegationCountError = { response: { status: ServerCodes.Forbidden } };
const error = getMigrationErrorMessage(loadDelegationCountError as ResourceError, null, true);
expect(error.errorMessage).toEqual('resourceadm.migration_cannot_migrate_in_env');
});

it('returns error when unknown error occurs', () => {
const loadDelegationCountError = { response: { status: ServerCodes.InternalServerError } };
const error = getMigrationErrorMessage(loadDelegationCountError as ResourceError, null, true);
expect(error.errorMessage).toEqual('resourceadm.migration_technical_error');
});

it('returns error when resource is not published', () => {
const error = getMigrationErrorMessage(null, null, false);
expect(error.errorMessage).toEqual('resourceadm.migration_not_published');
});
});
45 changes: 45 additions & 0 deletions frontend/resourceadm/utils/resourceUtils/resourceUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import type {
SupportedLanguage,
Resource,
ResourceFormError,
ResourceError,
} from 'app-shared/types/ResourceAdm';
import { isAppPrefix, isSePrefix } from '../stringUtils';
import { ServerCodes } from 'app-shared/enums/ServerCodes';

/**
* The map of resource type
Expand Down Expand Up @@ -396,3 +398,46 @@ export const getAltinn2Reference = (
)?.reference;
return serviceCode && serviceEdition ? [serviceCode, serviceEdition] : null;
};

export const getMigrationErrorMessage = (
loadDelegationCountError: Error | null,
migrateDelegationsError: Error | null,
isPublishedInEnv: boolean,
): {
errorMessage: string;
severity: 'success' | 'warning' | 'danger';
} | null => {
const loadErrorStatus = (loadDelegationCountError as ResourceError)?.response.status;
const isErrorForbidden =
(migrateDelegationsError as ResourceError)?.response?.status === ServerCodes.Forbidden;

if (migrateDelegationsError) {
return {
errorMessage: isErrorForbidden
? 'resourceadm.migration_no_migration_access'
: 'resourceadm.migration_post_migration_failed',
severity: 'danger',
};
} else if (loadErrorStatus === ServerCodes.NotFound) {
return {
errorMessage: 'resourceadm.migration_service_not_found',
severity: 'success',
};
} else if (loadErrorStatus === ServerCodes.Forbidden) {
return {
errorMessage: 'resourceadm.migration_cannot_migrate_in_env',
severity: 'danger',
};
} else if (loadErrorStatus === ServerCodes.InternalServerError) {
return {
errorMessage: 'resourceadm.migration_technical_error',
severity: 'danger',
};
} else if (!isPublishedInEnv) {
return {
errorMessage: 'resourceadm.migration_not_published',
severity: 'warning',
};
}
return null;
};

0 comments on commit f93a1ab

Please sign in to comment.