Skip to content

Commit dec7372

Browse files
feat: [UIE-8806, UIE-8881, UIE-8882, UIE-8931 ] - IAM RBAC: fix bugs (linode#12371)
* feat: [UIE-8806, UIE-8881, UIE-8882, UIE-8931 ] - IAM RBAC: fix bugs * changeset
1 parent 0d70ae8 commit dec7372

File tree

12 files changed

+95
-39
lines changed

12 files changed

+95
-39
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Upcoming Features
3+
---
4+
5+
IAM RBAC: Standardize drawer error messages, add an error message for the lasc account admin ([#12371](https://github.com/linode/manager/pull/12371))

packages/manager/src/features/IAM/Roles/RolesTable/AssignSelectedRolesDrawer.tsx

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ import { LinkButton } from 'src/components/LinkButton';
2222
import { StyledLinkButtonBox } from 'src/components/SelectFirewallPanel/SelectFirewallPanel';
2323
import { AssignSingleSelectedRole } from 'src/features/IAM/Roles/RolesTable/AssignSingleSelectedRole';
2424

25-
import {
26-
INTERNAL_ERROR_UPDATE_PERMISSION,
27-
NO_CHANGES_SAVED,
28-
} from '../../Shared/constants';
25+
import { INTERNAL_ERROR_NO_CHANGES_SAVED } from '../../Shared/constants';
2926
import { mergeAssignedRolesIntoExistingRoles } from '../../Shared/utilities';
3027

3128
import type { AssignNewRoleFormValues } from '../../Shared/utilities';
@@ -109,7 +106,9 @@ export const AssignSelectedRolesDrawer = ({
109106

110107
handleClose();
111108
} catch (error) {
112-
setError(error.field ?? 'root', { message: error[0].reason });
109+
setError(error.field ?? 'root', {
110+
message: INTERNAL_ERROR_NO_CHANGES_SAVED,
111+
});
113112
}
114113
};
115114

@@ -127,13 +126,7 @@ export const AssignSelectedRolesDrawer = ({
127126
<FormProvider {...form}>
128127
<form onSubmit={handleSubmit(onSubmit)}>
129128
{formState.errors.root?.message && (
130-
<Notice variant="error">
131-
<Typography>
132-
{INTERNAL_ERROR_UPDATE_PERMISSION}
133-
<br />
134-
{NO_CHANGES_SAVED}
135-
</Typography>
136-
</Notice>
129+
<Notice text={formState.errors.root?.message} variant="error" />
137130
)}
138131
<Typography sx={{ marginBottom: 2.5 }}>
139132
Select the user you want to assign selected roles to. Some roles

packages/manager/src/features/IAM/Shared/AssignedRolesTable/ChangeRoleDrawer.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ import { Controller, useForm } from 'react-hook-form';
1818
import { Link } from 'src/components/Link';
1919

2020
import { AssignedPermissionsPanel } from '../AssignedPermissionsPanel/AssignedPermissionsPanel';
21-
import { changeUserRole, getAllRoles, getRoleByName } from '../utilities';
21+
import {
22+
changeUserRole,
23+
getAllRoles,
24+
getErrorMessage,
25+
getRoleByName,
26+
} from '../utilities';
2227

2328
import type { DrawerModes, EntitiesOption, ExtendedRoleView } from '../types';
2429
import type { RolesType } from '../utilities';
@@ -110,9 +115,9 @@ export const ChangeRoleDrawer = ({ mode, onClose, open, role }: Props) => {
110115

111116
handleClose();
112117
} catch (errors) {
113-
for (const error of errors) {
114-
setError(error?.field ?? 'root', { message: error.reason });
115-
}
118+
setError('root', {
119+
message: getErrorMessage(errors),
120+
});
116121
}
117122
};
118123

packages/manager/src/features/IAM/Shared/AssignedRolesTable/UnassignRoleConfirmationDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import React from 'react';
66

77
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
88

9-
import { deleteUserRole } from '../utilities';
9+
import { deleteUserRole, getErrorMessage } from '../utilities';
1010

1111
import type { ExtendedRoleView } from '../types';
1212

@@ -74,7 +74,7 @@ export const UnassignRoleConfirmationDialog = (props: Props) => {
7474
style={{ padding: 0 }}
7575
/>
7676
}
77-
error={error?.[0].reason}
77+
error={getErrorMessage(error)}
7878
onClose={onClose}
7979
open={open}
8080
title={`Unassign the ${role?.name} role?`}

packages/manager/src/features/IAM/Shared/AssignedRolesTable/UpdateEntitiesDrawer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import React from 'react';
66
import { Controller, FormProvider, useForm } from 'react-hook-form';
77

88
import { AssignedPermissionsPanel } from '../AssignedPermissionsPanel/AssignedPermissionsPanel';
9+
import { INTERNAL_ERROR_NO_CHANGES_SAVED } from '../constants';
910
import { toEntityAccess } from '../utilities';
1011

1112
import type { EntitiesOption, ExtendedRoleView } from '../types';
@@ -92,7 +93,9 @@ export const UpdateEntitiesDrawer = ({ onClose, open, role }: Props) => {
9293
handleClose();
9394
} catch (errors) {
9495
for (const error of errors) {
95-
setError(error?.field ?? 'root', { message: error.reason });
96+
setError(error?.field ?? 'root', {
97+
message: INTERNAL_ERROR_NO_CHANGES_SAVED,
98+
});
9699
}
97100
}
98101
};

packages/manager/src/features/IAM/Shared/Entities/utils.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ describe('getCreateLinkForEntityType', () => {
1515
expect(getCreateLinkForEntityType('placement_group')).toBe(
1616
'/placement-groups/create'
1717
);
18-
expect(getCreateLinkForEntityType('lkecluster')).toBe(
19-
'/kubernetes/clusters'
20-
);
18+
expect(getCreateLinkForEntityType('lkecluster')).toBe('/kubernetes/create');
2119
});
2220
});
2321

packages/manager/src/features/IAM/Shared/Entities/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const getCreateLinkForEntityType = (
3333
}
3434

3535
if (entityType === 'lkecluster') {
36-
return '/kubernetes/clusters';
36+
return '/kubernetes/create';
3737
}
3838

3939
return `/${entityType}s/create`;

packages/manager/src/features/IAM/Shared/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export const NO_ASSIGNED_ROLES_TEXT = `The user doesn't have any roles assigned
77

88
export const NO_ASSIGNED_ENTITIES_TEXT = `The user doesn't have any entity access roles assigned yet. Once you assign the user a role on specific entities, these entities will show up here.`;
99

10-
export const INTERNAL_ERROR_UPDATE_PERMISSION = `Internal Error - Issue with updating permissions.`;
10+
export const INTERNAL_ERROR_NO_CHANGES_SAVED = `Internal Error. No changes were saved.`;
1111

12-
export const NO_CHANGES_SAVED = `No changes were saved.`;
12+
export const LAST_ACCOUNT_ADMIN_ERROR = `Failed to unassigned the role. You need to have at least one user with the account_admin role on your acount.`;
1313

1414
export const ERROR_STATE_TEXT =
1515
'An unexpected error occurred. Refresh the page or try again later.';

packages/manager/src/features/IAM/Shared/utilities.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import { accountRolesFactory } from 'src/factories/accountRoles';
22
import { userRolesFactory } from 'src/factories/userRoles';
33

4+
import {
5+
INTERNAL_ERROR_NO_CHANGES_SAVED,
6+
LAST_ACCOUNT_ADMIN_ERROR,
7+
} from './constants';
48
import {
59
changeRoleForEntity,
610
changeUserRole,
711
deleteUserEntity,
812
deleteUserRole,
913
getAllRoles,
14+
getErrorMessage,
1015
getFacadeRoleDescription,
1116
getFormattedEntityType,
1217
getRoleByName,
@@ -817,3 +822,37 @@ describe('mapEntityTypesForSelect', () => {
817822
]);
818823
});
819824
});
825+
826+
describe('getErrorMessage', () => {
827+
it('should return LAST_ACCOUNT_ADMIN_ERROR if the error contains "Removing last account admin"', () => {
828+
const errors = [
829+
{
830+
reason: 'Request made to janus is invalid',
831+
field: 'Bad janus request',
832+
},
833+
{
834+
reason:
835+
'Can not remove account admin access from the last account admin on the account',
836+
field: 'Removing last account admin',
837+
},
838+
];
839+
const result = getErrorMessage(errors);
840+
expect(result).toBe(LAST_ACCOUNT_ADMIN_ERROR);
841+
});
842+
843+
it('should return INTERNAL_ERROR_NO_CHANGES_SAVED if the error does not contain "Removing last account admin"', () => {
844+
const errors = [
845+
{
846+
field: 'An unexpected error occurred.',
847+
reason: 'An unexpected error occurred.',
848+
},
849+
];
850+
const result = getErrorMessage(errors);
851+
expect(result).toBe(INTERNAL_ERROR_NO_CHANGES_SAVED);
852+
});
853+
854+
it('should return undefined if there are no errors', () => {
855+
const result = getErrorMessage(null);
856+
expect(result).toBeUndefined();
857+
});
858+
});

packages/manager/src/features/IAM/Shared/utilities.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { capitalize, capitalizeAllWords } from '@linode/utilities';
22

3-
import { PAID_ENTITY_TYPES } from './constants';
3+
import {
4+
INTERNAL_ERROR_NO_CHANGES_SAVED,
5+
LAST_ACCOUNT_ADMIN_ERROR,
6+
PAID_ENTITY_TYPES,
7+
} from './constants';
48

59
import type {
610
EntitiesOption,
@@ -12,6 +16,7 @@ import type {
1216
import type {
1317
AccountAccessRole,
1418
AccountEntity,
19+
APIError,
1520
EntityAccess,
1621
EntityAccessRole,
1722
EntityType,
@@ -515,3 +520,15 @@ export const mergeAssignedRolesIntoExistingRoles = (
515520
});
516521
return selectedPlusExistingRoles;
517522
};
523+
524+
export const getErrorMessage = (error: APIError[] | null) => {
525+
const isLastAccountAdmin = error?.some(
526+
(err) => err.field === 'Removing last account admin'
527+
);
528+
529+
const errorMessage = isLastAccountAdmin
530+
? LAST_ACCOUNT_ADMIN_ERROR
531+
: INTERNAL_ERROR_NO_CHANGES_SAVED;
532+
533+
return error ? errorMessage : undefined;
534+
};

0 commit comments

Comments
 (0)