chore(RBAC): add permission's info (#6612)

This commit is contained in:
Pablo Lara
2025-01-20 16:14:48 +01:00
committed by GitHub
parent 465a758770
commit f56aaa791e
6 changed files with 121 additions and 61 deletions
@@ -192,7 +192,6 @@ export const updateProviderGroup = async (
});
if (!response.ok) {
const errorResponse = await response.json();
throw new Error(
`Failed to update provider group: ${response.status} ${response.statusText}`,
);
@@ -202,7 +201,6 @@ export const updateProviderGroup = async (
revalidatePath("/manage-groups");
return parseStringify(data);
} catch (error) {
console.error("Unexpected error:", error);
return {
error: getErrorMessage(error),
};
@@ -1,8 +1,9 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { Checkbox, Divider } from "@nextui-org/react";
import { SaveIcon } from "lucide-react";
import { Checkbox, Divider, Tooltip } from "@nextui-org/react";
import clsx from "clsx";
import { InfoIcon, SaveIcon } from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
@@ -16,6 +17,7 @@ import {
CustomInput,
} from "@/components/ui/custom";
import { Form } from "@/components/ui/form";
import { permissionFormFields } from "@/lib";
import { addRoleFormSchema, ApiError } from "@/types";
type FormValues = z.infer<typeof addRoleFormSchema>;
@@ -138,19 +140,6 @@ export const AddRoleForm = ({
}
};
const permissions = [
{ field: "manage_users", label: "Invite and Manage Users" },
...(process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true"
? [{ field: "manage_billing", label: "Manage Billing" }]
: []),
{ field: "manage_providers", label: "Manage Cloud Providers" },
{ field: "manage_account", label: "Manage Account" },
// TODO: Add back when we have integrations ready
// { field: "manage_integrations", label: "Manage Integrations" },
{ field: "manage_scans", label: "Manage Scans" },
{ field: "unlimited_visibility", label: "Unlimited Visibility" },
];
return (
<Form {...form}>
<form
@@ -174,7 +163,7 @@ export const AddRoleForm = ({
{/* Select All Checkbox */}
<Checkbox
isSelected={permissions.every((perm) =>
isSelected={permissionFormFields.every((perm) =>
form.watch(perm.field as keyof FormValues),
)}
onChange={(e) => onSelectAllChange(e.target.checked)}
@@ -188,19 +177,37 @@ export const AddRoleForm = ({
{/* Permissions Grid */}
<div className="grid grid-cols-2 gap-4">
{permissions.map(({ field, label }) => (
<Checkbox
key={field}
{...form.register(field as keyof FormValues)}
isSelected={!!form.watch(field as keyof FormValues)}
classNames={{
label: "text-small",
wrapper: "checkbox-update",
}}
>
{label}
</Checkbox>
))}
{permissionFormFields
.filter(
(permission) =>
permission.field !== "manage_billing" ||
process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true",
)
.map(({ field, label, description }) => (
<div key={field} className="flex items-center gap-2">
<Checkbox
{...form.register(field as keyof FormValues)}
isSelected={!!form.watch(field as keyof FormValues)}
classNames={{
label: "text-small",
wrapper: "checkbox-update",
}}
>
{label}
</Checkbox>
<Tooltip content={description} placement="right">
<div className="flex w-fit items-center justify-center">
<InfoIcon
className={clsx(
"cursor-pointer text-default-400 group-data-[selected=true]:text-foreground",
)}
aria-hidden={"true"}
width={16}
/>
</div>
</Tooltip>
</div>
))}
</div>
</div>
<Divider className="my-4" />
@@ -1,8 +1,9 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { Checkbox, Divider } from "@nextui-org/react";
import { SaveIcon } from "lucide-react";
import { Checkbox, Divider, Tooltip } from "@nextui-org/react";
import { clsx } from "clsx";
import { InfoIcon, SaveIcon } from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
@@ -16,6 +17,7 @@ import {
CustomInput,
} from "@/components/ui/custom";
import { Form } from "@/components/ui/form";
import { permissionFormFields } from "@/lib";
import { ApiError, editRoleFormSchema } from "@/types";
type FormValues = z.infer<typeof editRoleFormSchema>;
@@ -162,19 +164,6 @@ export const EditRoleForm = ({
}
};
const permissions = [
{ field: "manage_users", label: "Invite and Manage Users" },
...(process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true"
? [{ field: "manage_billing", label: "Manage Billing" }]
: []),
{ field: "manage_account", label: "Manage Account" },
{ field: "manage_providers", label: "Manage Cloud Providers" },
// TODO: Add back when we have integrations ready
// { field: "manage_integrations", label: "Manage Integrations" },
{ field: "manage_scans", label: "Manage Scans" },
{ field: "unlimited_visibility", label: "Unlimited Visibility" },
];
return (
<Form {...form}>
<form
@@ -198,7 +187,7 @@ export const EditRoleForm = ({
{/* Select All Checkbox */}
<Checkbox
isSelected={permissions.every((perm) =>
isSelected={permissionFormFields.every((perm) =>
form.watch(perm.field as keyof FormValues),
)}
onChange={(e) => onSelectAllChange(e.target.checked)}
@@ -212,19 +201,37 @@ export const EditRoleForm = ({
{/* Permissions Grid */}
<div className="grid grid-cols-2 gap-4">
{permissions.map(({ field, label }) => (
<Checkbox
key={field}
{...form.register(field as keyof FormValues)}
isSelected={!!form.watch(field as keyof FormValues)}
classNames={{
label: "text-small",
wrapper: "checkbox-update",
}}
>
{label}
</Checkbox>
))}
{permissionFormFields
.filter(
(permission) =>
permission.field !== "manage_billing" ||
process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true",
)
.map(({ field, label, description }) => (
<div key={field} className="flex items-center gap-2">
<Checkbox
{...form.register(field as keyof FormValues)}
isSelected={!!form.watch(field as keyof FormValues)}
classNames={{
label: "text-small",
wrapper: "checkbox-update",
}}
>
{label}
</Checkbox>
<Tooltip content={description} placement="right">
<div className="flex w-fit items-center justify-center">
<InfoIcon
className={clsx(
"cursor-pointer text-default-400 group-data-[selected=true]:text-foreground",
)}
aria-hidden={"true"}
width={16}
/>
</div>
</Tooltip>
</div>
))}
</div>
</div>
<Divider className="my-4" />
+43 -1
View File
@@ -1,5 +1,5 @@
import { getTask } from "@/actions/task";
import { MetaDataProps } from "@/types";
import { MetaDataProps, PermissionInfo } from "@/types";
export async function checkTaskStatus(
taskId: string,
@@ -183,3 +183,45 @@ export const regions = [
{ key: "us-west2", label: "GCP - US West (Los Angeles)" },
{ key: "us-east4", label: "GCP - US East (Northern Virginia)" },
];
export const permissionFormFields: PermissionInfo[] = [
{
field: "manage_users",
label: "Invite and Manage Users",
description: "Allows inviting new users and managing existing user details",
},
{
field: "manage_account",
label: "Manage Account",
description: "Provides access to account settings and RBAC configuration",
},
{
field: "unlimited_visibility",
label: "Unlimited Visibility",
description:
"Provides complete visibility across all the providers and its related resources",
},
{
field: "manage_providers",
label: "Manage Cloud Providers",
description:
"Allows configuration and management of cloud provider connections",
},
// {
// field: "manage_integrations",
// label: "Manage Integrations",
// description:
// "Controls the setup and management of third-party integrations",
// },
{
field: "manage_scans",
label: "Manage Scans",
description: "Allows launching and configuring scans security scans",
},
{
field: "manage_billing",
label: "Manage Billing",
description: "Provides access to billing settings and invoices",
},
];
+1
View File
@@ -122,6 +122,7 @@ module.exports = {
"0px -6px 24px #FFFFFF, 0px 7px 16px rgba(104, 132, 157, 0.5)",
up: "0.3rem 0.3rem 0.6rem #c8d0e7, -0.2rem -0.2rem 0.5rem #fff",
down: "inset 0.2rem 0.2rem 0.5rem #c8d0e7, inset -0.2rem -0.2rem 0.5rem #fff",
box: "rgba(0, 0, 0, 0.05) 0px 0px 0px 1px",
},
animation: {
"fade-in": "fade-in 200ms ease-out 0s 1 normal forwards running",
+5
View File
@@ -26,6 +26,11 @@ export type NextUIColors =
| "danger"
| "default";
export interface PermissionInfo {
field: string;
label: string;
description: string;
}
export interface FindingsByStatusData {
data: {
type: "findings-overview";