Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-13030-fixed-1761674529303.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

IAM: Linodes without required permissions visible and selectable in Assign/Unassign Linodes selector ([#13030](https://github.com/linode/manager/pull/13030))
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ const queryMocks = vi.hoisted(() => ({
useFirewallSettingsQuery: vi.fn().mockReturnValue({}),
}));

const iamMocks = vi.hoisted(() => ({
usePermissions: vi.fn().mockReturnValue({ data: { update_vpc: true } }),
useQueryWithPermissions: vi.fn().mockReturnValue({
data: [],
isLoading: false,
error: null,
isError: false,
hasFiltered: false,
}),
}));

vi.mock('@linode/queries', async () => {
const actual = await vi.importActual('@linode/queries');
return {
Expand All @@ -25,6 +36,11 @@ vi.mock('@linode/queries', async () => {
};
});

vi.mock('src/features/IAM/hooks/usePermissions', () => ({
usePermissions: iamMocks.usePermissions,
useQueryWithPermissions: iamMocks.useQueryWithPermissions,
}));

const props = {
isFetching: false,
onClose: vi.fn(),
Expand All @@ -48,6 +64,17 @@ describe('Subnet Assign Linodes Drawer', () => {
region: props.vpcRegion,
});

beforeEach(() => {
// Set up the default mock to return the linode
iamMocks.useQueryWithPermissions.mockReturnValue({
data: [linode],
isLoading: false,
error: null,
isError: false,
hasFiltered: false,
});
});

server.use(
http.get('*/linode/instances', () => {
return HttpResponse.json(makeResourcePage([linode]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,40 +149,44 @@
const [allowPublicIPv6Access, setAllowPublicIPv6Access] =
React.useState<boolean>(false);

const { data: permissions } = usePermissions('vpc', ['update_vpc'], vpcId);
// TODO: change update_linode to create_linode_config_profile_interface once it's available
// TODO: change delete_linode to delete_linode_config_profile_interface once it's available
// TODO: refactor useQueryWithPermissions once API filter is available
const { data: filteredLinodes } = useQueryWithPermissions<Linode>(
useAllLinodesQuery(),
'linode',
['update_linode', 'delete_linode'],
// We only want the linodes from the same region as the VPC
const query = useAllLinodesQuery(
{},
{
region: vpcRegion,
},
open
);

const userCanAssignLinodes =
permissions?.update_vpc && filteredLinodes?.length > 0;

const downloadCSV = async () => {
await getCSVData();
// getCSVData
await query.refetch();
csvRef.current.link.click();
};

// We only want the linodes from the same region as the VPC
const { data: linodes, refetch: getCSVData } = useAllLinodesQuery(
{},
{
region: vpcRegion,
}
);
const { data: permissions } = usePermissions('vpc', ['update_vpc'], vpcId);
// TODO: change update_linode to create_linode_config_profile_interface once it's available

Check warning on line 168 in packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":168,"column":6,"nodeType":null,"messageId":"completeTODO","endLine":168,"endColumn":10}
// TODO: change delete_linode to delete_linode_config_profile_interface once it's available

Check warning on line 169 in packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":169,"column":6,"nodeType":null,"messageId":"completeTODO","endLine":169,"endColumn":10}
// TODO: refactor useQueryWithPermissions once API filter is available

Check warning on line 170 in packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":170,"column":6,"nodeType":null,"messageId":"completeTODO","endLine":170,"endColumn":10}
const { data: filteredLinodes, isLoading: isLoadingFilteredLinodes } =
useQueryWithPermissions<Linode>(
query,
'linode',
['update_linode', 'delete_linode'],
open
);

const userCanAssignLinodes =
permissions?.update_vpc && filteredLinodes?.length > 0;
// We need to filter to the linodes from this region that are not already
// assigned to this subnet
const findUnassignedLinodes = React.useCallback(() => {
return linodes?.filter((linode) => {
if (!filteredLinodes) return [];

return filteredLinodes?.filter((linode) => {
return !subnet?.linodes.some((linodeInfo) => linodeInfo.id === linode.id);
});
}, [subnet, linodes]);
}, [subnet, filteredLinodes]);

const [linodeOptionsToAssign, setLinodeOptionsToAssign] = React.useState<
Linode[]
Expand All @@ -192,10 +196,10 @@
// and update that list whenever this subnet or the list of all linodes in this subnet's region changes. This takes
// care of the MUI invalid value warning that was occurring before in the Linodes autocomplete [M3-6752]
React.useEffect(() => {
if (linodes) {
if (filteredLinodes) {
setLinodeOptionsToAssign(findUnassignedLinodes() ?? []);
}
}, [linodes, setLinodeOptionsToAssign, findUnassignedLinodes]);
}, [filteredLinodes, setLinodeOptionsToAssign, findUnassignedLinodes]);

// Determine the configId based on the number of configurations
function getConfigId(inputs: {
Expand Down Expand Up @@ -551,7 +555,7 @@
try {
const data = await getAllLinodeConfigs(linode.id);
setLinodeConfigs(data);
} catch (errors) {
} catch {
// force error to appear at top of drawer
setAssignLinodesErrors({
none: 'Could not load configurations for selected linode',
Expand Down Expand Up @@ -585,7 +589,7 @@
return (
<Drawer
error={subnetError}
isFetching={isFetching}
isFetching={isFetching || isLoadingFilteredLinodes}
onClose={handleOnClose}
open={open}
title={`Assign Linodes to subnet: ${subnet?.label ?? 'Unknown'}`}
Expand Down