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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Changed
---

IAM RBAC: replace grants with usePermission hook in Linodes ([#12932](https://github.com/linode/manager/pull/12932))
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import {
useAllLinodeDisksQuery,
useAllVolumesQuery,
useGrants,
useLinodeQuery,
useLinodeRescueMutation,
useProfile,
} from '@linode/queries';
import {
ActionsPanel,
Expand All @@ -20,6 +18,7 @@ import { styled, useTheme } from '@mui/material/styles';
import { useSnackbar } from 'notistack';
import * as React from 'react';

import { usePermissions } from 'src/features/IAM/hooks/usePermissions';
import { useEventsPollingActions } from 'src/queries/events/events';

import { deviceSlots } from '../LinodeConfigs/constants';
Expand Down Expand Up @@ -95,13 +94,12 @@ export const StandardRescueDialog = (props: Props) => {
} = useAllVolumesQuery({}, { region: linode?.region }, open);
const isLoading = isLoadingLinodes || isLoadingDisks || isLoadingVolumes;

const { data: profile } = useProfile();
const { data: grants } = useGrants();

const isReadOnly =
Boolean(profile?.restricted) &&
grants?.linode.find((grant) => grant.id === linodeId)?.permissions ===
'read_only';
const { data: permissions } = usePermissions(
'linode',
['rescue_linode'],
linodeId,
open
);

// We need the API to allow us to filter on `linode_id`
// const { data: volumes } = useAllVolumesQuery(
Expand Down Expand Up @@ -173,7 +171,7 @@ export const StandardRescueDialog = (props: Props) => {
})) ?? [],
};

const disabled = isReadOnly;
const disabled = !permissions.rescue_linode;

const onSubmit = () => {
rescueLinode(createDevicesFromStrings(rescueDevices))
Expand Down Expand Up @@ -224,7 +222,7 @@ export const StandardRescueDialog = (props: Props) => {
) : (
<div>
<StyledPaper>
{isReadOnly && <LinodePermissionsError />}
{!permissions.rescue_linode && <LinodePermissionsError />}
{linodeId ? <RescueDescription linodeId={linodeId} /> : null}
<DeviceSelection
counter={counter}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const queryMocks = vi.hoisted(() => ({
resize_linode: false,
delete_linode: false,
clone_linode: false,
create_image: true,
},
})),
}));
Expand Down Expand Up @@ -209,6 +210,7 @@ describe('LinodeDiskActionMenu', () => {
resize_linode: false,
delete_linode: false,
clone_linode: false,
create_image: false,
},
});

Expand Down Expand Up @@ -242,6 +244,7 @@ describe('LinodeDiskActionMenu', () => {
resize_linode: true,
delete_linode: true,
clone_linode: true,
create_image: true,
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,13 @@ interface Props {
onDelete: () => void;
onRename: () => void;
onResize: () => void;
readOnly?: boolean;
}

export const LinodeDiskActionMenu = (props: Props) => {
const navigate = useNavigate();
const [isOpen, setIsOpen] = React.useState<boolean>(false);

const {
disk,
linodeId,
linodeStatus,
onDelete,
onRename,
onResize,
readOnly,
} = props;
const { disk, linodeId, linodeStatus, onDelete, onRename, onResize } = props;

const { data: permissions, isLoading } = usePermissions(
'linode',
Expand All @@ -38,6 +29,10 @@ export const LinodeDiskActionMenu = (props: Props) => {
isOpen
);

const { data: imagePermissions } = usePermissions('account', [
'create_image',
]);

const poweredOnTooltip =
linodeStatus !== 'offline'
? 'Your Linode must be fully powered down in order to perform this action.'
Expand Down Expand Up @@ -67,7 +62,7 @@ export const LinodeDiskActionMenu = (props: Props) => {
: poweredOnTooltip,
},
{
disabled: readOnly || !!swapTooltip,
disabled: !imagePermissions.create_image || !!swapTooltip,
onClick: () =>
navigate({
to: `/images/create/disk`,
Expand All @@ -77,7 +72,9 @@ export const LinodeDiskActionMenu = (props: Props) => {
},
}),
title: 'Create Disk Image',
tooltip: readOnly ? noPermissionTooltip : swapTooltip,
tooltip: !imagePermissions.create_image
? noPermissionTooltip
: swapTooltip,
},
{
disabled: !permissions.clone_linode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,11 @@ interface Props {
onDelete: () => void;
onRename: () => void;
onResize: () => void;
readOnly: boolean;
}

export const LinodeDiskRow = React.memo((props: Props) => {
const { data: events } = useInProgressEvents();
const {
disk,
linodeId,
linodeStatus,
onDelete,
onRename,
onResize,
readOnly,
} = props;
const { disk, linodeId, linodeStatus, onDelete, onRename, onResize } = props;

const diskEventLabelMap: Partial<Record<EventAction, string>> = {
disk_create: 'Creating',
Expand Down Expand Up @@ -80,7 +71,6 @@ export const LinodeDiskRow = React.memo((props: Props) => {
onDelete={onDelete}
onRename={onRename}
onResize={onResize}
readOnly={readOnly}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just don't confirm we don't need to replace those with permissions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, all permissions are handled in LinodeDiskActionMenu

/>
</TableCell>
</TableRow>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
useAllLinodeDisksQuery,
useGrants,
useLinodeQuery,
} from '@linode/queries';
import { useAllLinodeDisksQuery, useLinodeQuery } from '@linode/queries';
import { Box, Button, Paper, Stack, Typography } from '@linode/ui';
import { Hidden } from '@linode/ui';
import Grid from '@mui/material/Grid';
Expand Down Expand Up @@ -41,7 +37,6 @@ export const LinodeDisks = () => {

const { data: disks, error, isLoading } = useAllLinodeDisksQuery(id);
const { data: linode } = useLinodeQuery(id);
const { data: grants } = useGrants();

const { data: permissions } = usePermissions(
'linode',
Expand All @@ -59,10 +54,6 @@ export const LinodeDisks = () => {

const linodeTotalDisk = linode?.specs.disk ?? 0;

const readOnly =
grants !== undefined &&
grants.linode.some((g) => g.id === id && g.permissions === 'read_only');

const usedDiskSpace = addUsedDiskSpace(disks ?? []);

const hasFreeDiskSpace = linodeTotalDisk > usedDiskSpace;
Expand Down Expand Up @@ -107,7 +98,6 @@ export const LinodeDisks = () => {
onDelete={() => onDelete(disk)}
onRename={() => onRename(disk)}
onResize={() => onResize(disk)}
readOnly={readOnly}
/>
));
};
Expand Down