Skip to content

Commit

Permalink
feat: graceful handling of instance related actions for restricted pe…
Browse files Browse the repository at this point in the history
…rmissions

Signed-off-by: Mason Hu <[email protected]>
  • Loading branch information
MasWho committed Feb 19, 2025
1 parent fe63069 commit ff8e933
Show file tree
Hide file tree
Showing 69 changed files with 824 additions and 211 deletions.
10 changes: 9 additions & 1 deletion src/api/instances.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ import axios, { AxiosResponse } from "axios";
import type { UploadState } from "types/storage";
import { withEntitlementsQuery } from "util/entitlements/api";

export const instanceEntitlements = ["can_update_state"];
export const instanceEntitlements = [
"can_update_state",
"can_delete",
"can_edit",
"can_manage_backups",
"can_manage_snapshots",
"can_exec",
"can_access_console",
];

export const fetchInstance = (
name: string,
Expand Down
1 change: 1 addition & 0 deletions src/api/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const projectEntitlements = [
"can_create_images",
"can_create_image_aliases",
"can_create_instances",
"can_create_storage_volumes",
];

export const fetchProjects = (
Expand Down
42 changes: 27 additions & 15 deletions src/components/ConfigurationRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ export const getConfigurationRow = ({
}
};

const isDisabled = () => {
return disabled || !!formik.values.editRestriction;
};

const getDisabledReasonOrTitle = (title?: string) => {
if (formik.values.editRestriction) {
return formik.values.editRestriction;
}

if (disabledReason) {
return disabledReason;
}

return title;
};

const getForm = (): ReactNode => {
return (
<div className="override-form">
Expand All @@ -86,7 +102,7 @@ export const getConfigurationRow = ({
onBlur: formik.handleBlur,
onChange: formik.handleChange,
value,
disabled,
disabled: isDisabled(),
help: (
<ConfigFieldDescription
description={
Expand All @@ -104,8 +120,8 @@ export const getConfigurationRow = ({
onClick={toggleDefault}
type="button"
appearance="base"
title={disabled ? disabledReason : "Clear override"}
disabled={disabled}
title={getDisabledReasonOrTitle("Clear override")}
disabled={isDisabled()}
hasIcon
className="u-no-margin--bottom"
>
Expand All @@ -124,9 +140,9 @@ export const getConfigurationRow = ({
);

const wrapDisabledTooltip = (children: ReactNode): ReactNode => {
if (disabled && disabledReason) {
if ((disabled && disabledReason) || formik.values.editRestriction) {
return (
<Tooltip message={disabledReason} position="right">
<Tooltip message={getDisabledReasonOrTitle()} position="right">
{children}
</Tooltip>
);
Expand All @@ -150,14 +166,10 @@ export const getConfigurationRow = ({
className="u-no-margin--bottom"
type="button"
appearance="base"
title={
disabled
? disabledReason
: isOverridden
? "Edit"
: "Create override"
}
disabled={disabled}
title={getDisabledReasonOrTitle(
isOverridden ? "Edit" : "Create override",
)}
disabled={isDisabled()}
hasIcon
>
<Icon name="edit" />
Expand All @@ -173,9 +185,9 @@ export const getConfigurationRow = ({
onClick={toggleDefault}
className="u-no-margin--bottom"
type="button"
disabled={disabled}
disabled={isDisabled()}
appearance="base"
title="Create override"
title={formik.values.editRestriction ?? "Create override"}
hasIcon
>
<Icon name="edit" />
Expand Down
47 changes: 31 additions & 16 deletions src/components/NetworkListTable.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC } from "react";
import { useQuery } from "@tanstack/react-query";
import { queryKeys } from "util/queryKeys";
import { MainTable } from "@canonical/react-components";
import { MainTable, Notification } from "@canonical/react-components";
import Loader from "components/Loader";
import { fetchNetworks } from "api/networks";
import { isNicDevice } from "util/devices";
Expand Down Expand Up @@ -34,7 +34,8 @@ const NetworkListTable: FC<Props> = ({ onFailure, devices }) => {
.filter(isNicDevice)
.map((network) => network.network);

const hasNetworks = networkDevices.length > 0;
const instanceHasNetworks = networkDevices.length > 0;
const userHasNetworks = networks.length > 0;

const networksHeaders = [
{ content: "Name", sortKey: "name", className: "u-text--muted" },
Expand Down Expand Up @@ -100,20 +101,34 @@ const NetworkListTable: FC<Props> = ({ onFailure, devices }) => {
};
});

return (
<>
{isLoading && <Loader text="Loading networks..." />}
{!isLoading && hasNetworks && (
<MainTable
headers={networksHeaders}
rows={networksRows}
sortable
className={"network-table"}
/>
)}
{!isLoading && !hasNetworks && <>-</>}
</>
);
const getContent = () => {
if (isLoading) {
return <Loader text="Loading networks..." />;
}

if (instanceHasNetworks && !userHasNetworks) {
return (
<Notification severity="caution" title="Restricted permissions">
You do not have permission to view network details.
</Notification>
);
}

if (!instanceHasNetworks) {
return <>-</>;
}

return (
<MainTable
headers={networksHeaders}
rows={networksRows}
sortable
className={"network-table"}
/>
);
};

return getContent();
};

export default NetworkListTable;
6 changes: 4 additions & 2 deletions src/components/forms/CloudInitForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ const CloudInitForm: FC<Props> = ({ formik }) => {
}}
type="button"
appearance="base"
title={"Clear override"}
title={formik.values.editRestriction ?? "Clear override"}
disabled={!!formik.values.editRestriction}
hasIcon
className="u-no-margin--bottom"
>
Expand All @@ -92,8 +93,9 @@ const CloudInitForm: FC<Props> = ({ formik }) => {
className="u-no-margin--bottom"
type="button"
appearance="base"
title="Create override"
title={formik.values.editRestriction ?? "Create override"}
hasIcon
disabled={!!formik.values.editRestriction}
>
<Icon name="edit" />
</Button>
Expand Down
8 changes: 6 additions & 2 deletions src/components/forms/DiskDeviceFormCustom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ const DiskDeviceFormCustom: FC<Props> = ({ formik, project, profiles }) => {
className="u-no-margin--bottom"
hasIcon
dense
title="Edit"
title={formik.values.editRestriction ?? "Edit"}
onClick={() => {
ensureEditMode(formik);
focusField(fieldName);
}}
disabled={!!formik.values.editRestriction}
>
<Icon name="edit" />
</Button>
Expand All @@ -108,6 +109,7 @@ const DiskDeviceFormCustom: FC<Props> = ({ formik, project, profiles }) => {
ensureEditMode(formik);
void formik.setFieldValue(`devices.${index}.name`, name);
}}
disableReason={formik.values.editRestriction}
/>
),
inherited: "",
Expand All @@ -117,6 +119,7 @@ const DiskDeviceFormCustom: FC<Props> = ({ formik, project, profiles }) => {
ensureEditMode(formik);
removeDevice(index, formik);
}}
disabledReason={formik.values.editRestriction}
/>
),
}),
Expand Down Expand Up @@ -149,8 +152,9 @@ const DiskDeviceFormCustom: FC<Props> = ({ formik, project, profiles }) => {
id: `devices.${index}.pool`,
appearance: "base",
className: "u-no-margin--bottom",
title: "Select storage volume",
title: formik.values.editRestriction ?? "Select storage volume",
dense: true,
disabled: !!formik.values.editRestriction,
}}
>
<Icon name="edit" />
Expand Down
7 changes: 6 additions & 1 deletion src/components/forms/DiskDeviceFormInherited.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ const DiskDeviceFormInherited: FC<Props> = ({
<Button
appearance="base"
type="button"
title="Reattach device"
title={formik.values.editRestriction ?? "Reattach device"}
onClick={() => {
ensureEditMode(formik);
removeDevice(noneDeviceId, formik);
}}
className="has-icon u-no-margin--bottom"
disabled={!!formik.values.editRestriction}
>
<Icon name="connected"></Icon>
<span>Reattach</span>
Expand All @@ -70,6 +71,7 @@ const DiskDeviceFormInherited: FC<Props> = ({
ensureEditMode(formik);
addNoneDevice(item.key, formik);
}}
disabledReason={formik.values.editRestriction}
/>
),
}),
Expand All @@ -82,6 +84,7 @@ const DiskDeviceFormInherited: FC<Props> = ({
inheritValue: item.disk.source,
readOnly: readOnly,
isDeactivated: isNoneDevice,
disabledReason: formik.values.editRestriction,
}),
);
} else {
Expand All @@ -95,6 +98,7 @@ const DiskDeviceFormInherited: FC<Props> = ({
),
readOnly: readOnly,
isDeactivated: isNoneDevice,
disabledReason: formik.values.editRestriction,
}),
);
}
Expand All @@ -105,6 +109,7 @@ const DiskDeviceFormInherited: FC<Props> = ({
inheritValue: item.disk.path,
readOnly: readOnly,
isDeactivated: isNoneDevice,
disabledReason: formik.values.editRestriction,
}),
);
});
Expand Down
11 changes: 8 additions & 3 deletions src/components/forms/DiskDeviceFormRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ const DiskDeviceFormRoot: FC<Props> = ({ formik, pools, profiles }) => {
}}
type="button"
appearance="base"
title="Clear override"
title={formik.values.editRestriction ?? "Clear override"}
hasIcon
className="u-no-margin--bottom"
disabled={!!formik.values.editRestriction}
>
<Icon name="close" className="clear-configuration-icon" />
</Button>
Expand All @@ -81,9 +82,10 @@ const DiskDeviceFormRoot: FC<Props> = ({ formik, pools, profiles }) => {
}}
type="button"
appearance="base"
title="Create override"
title={formik.values.editRestriction ?? "Create override"}
className="u-no-margin--bottom"
hasIcon
disabled={!!formik.values.editRestriction}
>
<Icon name="edit" />
</Button>
Expand All @@ -97,6 +99,7 @@ const DiskDeviceFormRoot: FC<Props> = ({ formik, pools, profiles }) => {
inheritValue: inheritValue?.pool ?? "",
inheritSource,
readOnly: readOnly,
disabledReason: formik.values.editRestriction,
overrideValue: hasRootStorage && (
<>
{formRootDevice?.pool}
Expand Down Expand Up @@ -148,6 +151,7 @@ const DiskDeviceFormRoot: FC<Props> = ({ formik, pools, profiles }) => {
inheritValue?.size ?? (inheritValue ? "unlimited" : ""),
inheritSource,
readOnly: readOnly,
disabledReason: formik.values.editRestriction,
overrideValue: hasRootStorage && (
<>
{formRootDevice?.size ?? "unlimited"}
Expand All @@ -158,9 +162,10 @@ const DiskDeviceFormRoot: FC<Props> = ({ formik, pools, profiles }) => {
}}
type="button"
appearance="base"
title="Edit"
title={formik.values.editRestriction ?? "Edit"}
className="u-no-margin--bottom"
hasIcon
disabled={!!formik.values.editRestriction}
>
<Icon name="edit" />
</Button>
Expand Down
10 changes: 8 additions & 2 deletions src/components/forms/GPUDeviceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const GPUDevicesForm: FC<Props> = ({ formik, project }) => {
<Button
appearance="base"
type="button"
title="Reattach volume"
title="Reattach GPU"
onClick={() => {
ensureEditMode(formik);
removeDevice(noneDeviceId, formik);
Expand All @@ -123,6 +123,8 @@ const GPUDevicesForm: FC<Props> = ({ formik, project }) => {
}}
className="has-icon u-no-margin--bottom"
dense
title={formik.values.editRestriction ?? "Detach GPU"}
disabled={!!formik.values.editRestriction}
>
<Icon name="disconnect"></Icon>
<span>Detach</span>
Expand Down Expand Up @@ -165,6 +167,7 @@ const GPUDevicesForm: FC<Props> = ({ formik, project }) => {
ensureEditMode(formik);
void formik.setFieldValue(`devices.${index}.name`, name);
}}
disableReason={formik.values.editRestriction}
/>
),
inherited: "",
Expand All @@ -179,7 +182,8 @@ const GPUDevicesForm: FC<Props> = ({ formik, project }) => {
appearance="base"
hasIcon
dense
title="Detach GPU"
title={formik.values.editRestriction ?? "Detach GPU"}
disabled={!!formik.values.editRestriction}
>
<Icon name="disconnect" />
<span>Detach</span>
Expand Down Expand Up @@ -213,6 +217,7 @@ const GPUDevicesForm: FC<Props> = ({ formik, project }) => {
void formik.setFieldValue(`devices.${index}.pci`, pci);
void formik.setFieldValue(`devices.${index}.id`, id);
}}
disableReason={formik.values.editRestriction}
/>
),
readOnly: false,
Expand Down Expand Up @@ -269,6 +274,7 @@ const GPUDevicesForm: FC<Props> = ({ formik, project }) => {
ensureEditMode(formik);
addGPUCard(card);
}}
disabledReason={formik.values.editRestriction}
/>
</ScrollableForm>
);
Expand Down
Loading

0 comments on commit ff8e933

Please sign in to comment.