Skip to content

Commit 2fb2315

Browse files
chore(RBAC): add permission's info (#6617)
Co-authored-by: Pablo Lara <[email protected]>
1 parent a9e4754 commit 2fb2315

File tree

6 files changed

+121
-61
lines changed

6 files changed

+121
-61
lines changed

ui/actions/manage-groups/manage-groups.ts

-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,6 @@ export const updateProviderGroup = async (
192192
});
193193

194194
if (!response.ok) {
195-
const errorResponse = await response.json();
196195
throw new Error(
197196
`Failed to update provider group: ${response.status} ${response.statusText}`,
198197
);
@@ -202,7 +201,6 @@ export const updateProviderGroup = async (
202201
revalidatePath("/manage-groups");
203202
return parseStringify(data);
204203
} catch (error) {
205-
console.error("Unexpected error:", error);
206204
return {
207205
error: getErrorMessage(error),
208206
};

ui/components/roles/workflow/forms/add-role-form.tsx

+36-29
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use client";
22

33
import { zodResolver } from "@hookform/resolvers/zod";
4-
import { Checkbox, Divider } from "@nextui-org/react";
5-
import { SaveIcon } from "lucide-react";
4+
import { Checkbox, Divider, Tooltip } from "@nextui-org/react";
5+
import clsx from "clsx";
6+
import { InfoIcon, SaveIcon } from "lucide-react";
67
import { useRouter } from "next/navigation";
78
import { useEffect } from "react";
89
import { Controller, useForm } from "react-hook-form";
@@ -16,6 +17,7 @@ import {
1617
CustomInput,
1718
} from "@/components/ui/custom";
1819
import { Form } from "@/components/ui/form";
20+
import { permissionFormFields } from "@/lib";
1921
import { addRoleFormSchema, ApiError } from "@/types";
2022

2123
type FormValues = z.infer<typeof addRoleFormSchema>;
@@ -138,19 +140,6 @@ export const AddRoleForm = ({
138140
}
139141
};
140142

141-
const permissions = [
142-
{ field: "manage_users", label: "Invite and Manage Users" },
143-
...(process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true"
144-
? [{ field: "manage_billing", label: "Manage Billing" }]
145-
: []),
146-
{ field: "manage_providers", label: "Manage Cloud Providers" },
147-
{ field: "manage_account", label: "Manage Account" },
148-
// TODO: Add back when we have integrations ready
149-
// { field: "manage_integrations", label: "Manage Integrations" },
150-
{ field: "manage_scans", label: "Manage Scans" },
151-
{ field: "unlimited_visibility", label: "Unlimited Visibility" },
152-
];
153-
154143
return (
155144
<Form {...form}>
156145
<form
@@ -174,7 +163,7 @@ export const AddRoleForm = ({
174163

175164
{/* Select All Checkbox */}
176165
<Checkbox
177-
isSelected={permissions.every((perm) =>
166+
isSelected={permissionFormFields.every((perm) =>
178167
form.watch(perm.field as keyof FormValues),
179168
)}
180169
onChange={(e) => onSelectAllChange(e.target.checked)}
@@ -188,19 +177,37 @@ export const AddRoleForm = ({
188177

189178
{/* Permissions Grid */}
190179
<div className="grid grid-cols-2 gap-4">
191-
{permissions.map(({ field, label }) => (
192-
<Checkbox
193-
key={field}
194-
{...form.register(field as keyof FormValues)}
195-
isSelected={!!form.watch(field as keyof FormValues)}
196-
classNames={{
197-
label: "text-small",
198-
wrapper: "checkbox-update",
199-
}}
200-
>
201-
{label}
202-
</Checkbox>
203-
))}
180+
{permissionFormFields
181+
.filter(
182+
(permission) =>
183+
permission.field !== "manage_billing" ||
184+
process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true",
185+
)
186+
.map(({ field, label, description }) => (
187+
<div key={field} className="flex items-center gap-2">
188+
<Checkbox
189+
{...form.register(field as keyof FormValues)}
190+
isSelected={!!form.watch(field as keyof FormValues)}
191+
classNames={{
192+
label: "text-small",
193+
wrapper: "checkbox-update",
194+
}}
195+
>
196+
{label}
197+
</Checkbox>
198+
<Tooltip content={description} placement="right">
199+
<div className="flex w-fit items-center justify-center">
200+
<InfoIcon
201+
className={clsx(
202+
"cursor-pointer text-default-400 group-data-[selected=true]:text-foreground",
203+
)}
204+
aria-hidden={"true"}
205+
width={16}
206+
/>
207+
</div>
208+
</Tooltip>
209+
</div>
210+
))}
204211
</div>
205212
</div>
206213
<Divider className="my-4" />

ui/components/roles/workflow/forms/edit-role-form.tsx

+36-29
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use client";
22

33
import { zodResolver } from "@hookform/resolvers/zod";
4-
import { Checkbox, Divider } from "@nextui-org/react";
5-
import { SaveIcon } from "lucide-react";
4+
import { Checkbox, Divider, Tooltip } from "@nextui-org/react";
5+
import { clsx } from "clsx";
6+
import { InfoIcon, SaveIcon } from "lucide-react";
67
import { useRouter } from "next/navigation";
78
import { useEffect } from "react";
89
import { Controller, useForm } from "react-hook-form";
@@ -16,6 +17,7 @@ import {
1617
CustomInput,
1718
} from "@/components/ui/custom";
1819
import { Form } from "@/components/ui/form";
20+
import { permissionFormFields } from "@/lib";
1921
import { ApiError, editRoleFormSchema } from "@/types";
2022

2123
type FormValues = z.infer<typeof editRoleFormSchema>;
@@ -162,19 +164,6 @@ export const EditRoleForm = ({
162164
}
163165
};
164166

165-
const permissions = [
166-
{ field: "manage_users", label: "Invite and Manage Users" },
167-
...(process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true"
168-
? [{ field: "manage_billing", label: "Manage Billing" }]
169-
: []),
170-
{ field: "manage_account", label: "Manage Account" },
171-
{ field: "manage_providers", label: "Manage Cloud Providers" },
172-
// TODO: Add back when we have integrations ready
173-
// { field: "manage_integrations", label: "Manage Integrations" },
174-
{ field: "manage_scans", label: "Manage Scans" },
175-
{ field: "unlimited_visibility", label: "Unlimited Visibility" },
176-
];
177-
178167
return (
179168
<Form {...form}>
180169
<form
@@ -198,7 +187,7 @@ export const EditRoleForm = ({
198187

199188
{/* Select All Checkbox */}
200189
<Checkbox
201-
isSelected={permissions.every((perm) =>
190+
isSelected={permissionFormFields.every((perm) =>
202191
form.watch(perm.field as keyof FormValues),
203192
)}
204193
onChange={(e) => onSelectAllChange(e.target.checked)}
@@ -212,19 +201,37 @@ export const EditRoleForm = ({
212201

213202
{/* Permissions Grid */}
214203
<div className="grid grid-cols-2 gap-4">
215-
{permissions.map(({ field, label }) => (
216-
<Checkbox
217-
key={field}
218-
{...form.register(field as keyof FormValues)}
219-
isSelected={!!form.watch(field as keyof FormValues)}
220-
classNames={{
221-
label: "text-small",
222-
wrapper: "checkbox-update",
223-
}}
224-
>
225-
{label}
226-
</Checkbox>
227-
))}
204+
{permissionFormFields
205+
.filter(
206+
(permission) =>
207+
permission.field !== "manage_billing" ||
208+
process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true",
209+
)
210+
.map(({ field, label, description }) => (
211+
<div key={field} className="flex items-center gap-2">
212+
<Checkbox
213+
{...form.register(field as keyof FormValues)}
214+
isSelected={!!form.watch(field as keyof FormValues)}
215+
classNames={{
216+
label: "text-small",
217+
wrapper: "checkbox-update",
218+
}}
219+
>
220+
{label}
221+
</Checkbox>
222+
<Tooltip content={description} placement="right">
223+
<div className="flex w-fit items-center justify-center">
224+
<InfoIcon
225+
className={clsx(
226+
"cursor-pointer text-default-400 group-data-[selected=true]:text-foreground",
227+
)}
228+
aria-hidden={"true"}
229+
width={16}
230+
/>
231+
</div>
232+
</Tooltip>
233+
</div>
234+
))}
228235
</div>
229236
</div>
230237
<Divider className="my-4" />

ui/lib/helper.ts

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getTask } from "@/actions/task";
2-
import { MetaDataProps } from "@/types";
2+
import { MetaDataProps, PermissionInfo } from "@/types";
33

44
export async function checkTaskStatus(
55
taskId: string,
@@ -183,3 +183,45 @@ export const regions = [
183183
{ key: "us-west2", label: "GCP - US West (Los Angeles)" },
184184
{ key: "us-east4", label: "GCP - US East (Northern Virginia)" },
185185
];
186+
187+
export const permissionFormFields: PermissionInfo[] = [
188+
{
189+
field: "manage_users",
190+
label: "Invite and Manage Users",
191+
description: "Allows inviting new users and managing existing user details",
192+
},
193+
{
194+
field: "manage_account",
195+
label: "Manage Account",
196+
description: "Provides access to account settings and RBAC configuration",
197+
},
198+
{
199+
field: "unlimited_visibility",
200+
label: "Unlimited Visibility",
201+
description:
202+
"Provides complete visibility across all the providers and its related resources",
203+
},
204+
{
205+
field: "manage_providers",
206+
label: "Manage Cloud Providers",
207+
description:
208+
"Allows configuration and management of cloud provider connections",
209+
},
210+
// {
211+
// field: "manage_integrations",
212+
// label: "Manage Integrations",
213+
// description:
214+
// "Controls the setup and management of third-party integrations",
215+
// },
216+
{
217+
field: "manage_scans",
218+
label: "Manage Scans",
219+
description: "Allows launching and configuring scans security scans",
220+
},
221+
222+
{
223+
field: "manage_billing",
224+
label: "Manage Billing",
225+
description: "Provides access to billing settings and invoices",
226+
},
227+
];

ui/tailwind.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ module.exports = {
122122
"0px -6px 24px #FFFFFF, 0px 7px 16px rgba(104, 132, 157, 0.5)",
123123
up: "0.3rem 0.3rem 0.6rem #c8d0e7, -0.2rem -0.2rem 0.5rem #fff",
124124
down: "inset 0.2rem 0.2rem 0.5rem #c8d0e7, inset -0.2rem -0.2rem 0.5rem #fff",
125+
box: "rgba(0, 0, 0, 0.05) 0px 0px 0px 1px",
125126
},
126127
animation: {
127128
"fade-in": "fade-in 200ms ease-out 0s 1 normal forwards running",

ui/types/components.ts

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ export type NextUIColors =
2626
| "danger"
2727
| "default";
2828

29+
export interface PermissionInfo {
30+
field: string;
31+
label: string;
32+
description: string;
33+
}
2934
export interface FindingsByStatusData {
3035
data: {
3136
type: "findings-overview";

0 commit comments

Comments
 (0)