mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-21 07:27:58 +00:00
Improve Audit Logs permissions
This commit is contained in:
+8
-1
@@ -5,6 +5,7 @@ import { OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgGatewayPermissionActions,
|
||||
OrgPermissionAppConnectionActions,
|
||||
OrgPermissionAuditLogsActions,
|
||||
OrgPermissionBillingActions,
|
||||
OrgPermissionGroupActions,
|
||||
OrgPermissionIdentityActions,
|
||||
@@ -23,6 +24,12 @@ const generalPermissionSchema = z
|
||||
})
|
||||
.optional();
|
||||
|
||||
const auditLogsPermissionSchema = z
|
||||
.object({
|
||||
[OrgPermissionAuditLogsActions.Read]: z.boolean().optional()
|
||||
})
|
||||
.optional();
|
||||
|
||||
const billingPermissionSchema = z
|
||||
.object({
|
||||
[OrgPermissionBillingActions.Read]: z.boolean().optional(),
|
||||
@@ -121,7 +128,7 @@ export const formSchema = z.object({
|
||||
})
|
||||
.optional(),
|
||||
|
||||
"audit-logs": generalPermissionSchema,
|
||||
"audit-logs": auditLogsPermissionSchema,
|
||||
member: generalPermissionSchema,
|
||||
groups: groupPermissionSchema,
|
||||
role: generalPermissionSchema,
|
||||
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { Control, Controller, UseFormSetValue, useWatch } from "react-hook-form";
|
||||
import { faChevronDown, faChevronRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Checkbox, Select, SelectItem, Td, Tr } from "@app/components/v2";
|
||||
import { OrgPermissionAuditLogsActions } from "@app/context/OrgPermissionContext/types";
|
||||
import { useToggle } from "@app/hooks";
|
||||
|
||||
import { TFormSchema } from "../OrgRoleModifySection.utils";
|
||||
|
||||
type Props = {
|
||||
isEditable: boolean;
|
||||
setValue: UseFormSetValue<TFormSchema>;
|
||||
control: Control<TFormSchema>;
|
||||
};
|
||||
|
||||
enum Permission {
|
||||
NoAccess = "no-access",
|
||||
ReadOnly = "read-only",
|
||||
FullAccess = "full-access",
|
||||
Custom = "custom"
|
||||
}
|
||||
|
||||
const PERMISSION_ACTIONS = [
|
||||
{
|
||||
action: OrgPermissionAuditLogsActions.Read,
|
||||
label: "View"
|
||||
}
|
||||
] as const;
|
||||
|
||||
export const OrgPermissionAuditLogsRow = ({ isEditable, control, setValue }: Props) => {
|
||||
const [isRowExpanded, setIsRowExpanded] = useToggle();
|
||||
const [isCustom, setIsCustom] = useToggle();
|
||||
|
||||
const rule = useWatch({
|
||||
control,
|
||||
name: "permissions.audit-logs"
|
||||
});
|
||||
|
||||
const selectedPermissionCategory = useMemo(() => {
|
||||
const actions = Object.keys(rule || {}) as Array<keyof typeof rule>;
|
||||
const totalActions = PERMISSION_ACTIONS.length;
|
||||
const score = actions.map((key) => (rule?.[key] ? 1 : 0)).reduce((a, b) => a + b, 0 as number);
|
||||
|
||||
if (isCustom) return Permission.Custom;
|
||||
if (score === 0) return Permission.NoAccess;
|
||||
if (score === totalActions) return Permission.FullAccess;
|
||||
if (score === 1 && rule?.[OrgPermissionAuditLogsActions.Read]) return Permission.ReadOnly;
|
||||
|
||||
return Permission.Custom;
|
||||
}, [rule, isCustom]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedPermissionCategory === Permission.Custom) setIsCustom.on();
|
||||
else setIsCustom.off();
|
||||
}, [selectedPermissionCategory]);
|
||||
|
||||
useEffect(() => {
|
||||
const isRowCustom = selectedPermissionCategory === Permission.Custom;
|
||||
if (isRowCustom) {
|
||||
setIsRowExpanded.on();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handlePermissionChange = (val: Permission) => {
|
||||
if (!val) return;
|
||||
if (val === Permission.Custom) {
|
||||
setIsRowExpanded.on();
|
||||
setIsCustom.on();
|
||||
return;
|
||||
}
|
||||
setIsCustom.off();
|
||||
|
||||
switch (val) {
|
||||
case Permission.FullAccess:
|
||||
case Permission.ReadOnly:
|
||||
// For audit logs, both full access and read-only are the same - just read access
|
||||
setValue(
|
||||
"permissions.audit-logs",
|
||||
{
|
||||
[OrgPermissionAuditLogsActions.Read]: true
|
||||
},
|
||||
{ shouldDirty: true }
|
||||
);
|
||||
break;
|
||||
|
||||
case Permission.NoAccess:
|
||||
default:
|
||||
setValue(
|
||||
"permissions.audit-logs",
|
||||
{
|
||||
[OrgPermissionAuditLogsActions.Read]: false
|
||||
},
|
||||
{ shouldDirty: true }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tr
|
||||
className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
||||
onClick={() => setIsRowExpanded.toggle()}
|
||||
>
|
||||
<Td className="w-4">
|
||||
<FontAwesomeIcon className="w-4" icon={isRowExpanded ? faChevronDown : faChevronRight} />
|
||||
</Td>
|
||||
<Td className="w-full select-none">Audit Logs</Td>
|
||||
<Td>
|
||||
<Select
|
||||
value={selectedPermissionCategory}
|
||||
className="h-8 w-40 bg-mineshaft-700"
|
||||
dropdownContainerClassName="border text-left border-mineshaft-600 bg-mineshaft-800"
|
||||
onValueChange={handlePermissionChange}
|
||||
isDisabled={!isEditable}
|
||||
position="popper"
|
||||
>
|
||||
<SelectItem value={Permission.NoAccess}>No Access</SelectItem>
|
||||
<SelectItem value={Permission.ReadOnly}>Read Only</SelectItem>
|
||||
<SelectItem value={Permission.FullAccess}>Full Access</SelectItem>
|
||||
<SelectItem value={Permission.Custom}>Custom</SelectItem>
|
||||
</Select>
|
||||
</Td>
|
||||
</Tr>
|
||||
{isRowExpanded && (
|
||||
<Tr>
|
||||
<Td colSpan={3} className="border-mineshaft-500 bg-mineshaft-900 p-8">
|
||||
<div className="flex flex-grow flex-wrap justify-start gap-x-8 gap-y-4">
|
||||
{PERMISSION_ACTIONS.map(({ action, label }) => {
|
||||
return (
|
||||
<Controller
|
||||
name={`permissions.audit-logs.${action}`}
|
||||
key={`permissions.audit-logs.${action}`}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Checkbox
|
||||
isChecked={Boolean(field.value)}
|
||||
onCheckedChange={(e) => {
|
||||
if (!isEditable) {
|
||||
createNotification({
|
||||
type: "error",
|
||||
text: "Failed to update default role"
|
||||
});
|
||||
return;
|
||||
}
|
||||
field.onChange(e);
|
||||
}}
|
||||
id={`permissions.audit-logs.${action}`}
|
||||
>
|
||||
{label}
|
||||
</Checkbox>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
+1
@@ -71,6 +71,7 @@ type Props = {
|
||||
| "gateway"
|
||||
| "secret-share"
|
||||
| "billing"
|
||||
| "audit-logs"
|
||||
| "machine-identity-auth-template"
|
||||
>;
|
||||
setValue: UseFormSetValue<TFormSchema>;
|
||||
|
||||
+6
-4
@@ -16,6 +16,7 @@ import {
|
||||
TFormSchema
|
||||
} from "../OrgRoleModifySection.utils";
|
||||
import { OrgPermissionAdminConsoleRow } from "./OrgPermissionAdminConsoleRow";
|
||||
import { OrgPermissionAuditLogsRow } from "./OrgPermissionAuditLogsRow";
|
||||
import { OrgPermissionBillingRow } from "./OrgPermissionBillingRow";
|
||||
import { OrgGatewayPermissionRow } from "./OrgPermissionGatewayRow";
|
||||
import { OrgPermissionGroupRow } from "./OrgPermissionGroupRow";
|
||||
@@ -39,10 +40,6 @@ const SIMPLE_PERMISSION_OPTIONS = [
|
||||
title: "Incident Contacts",
|
||||
formName: "incident-contact"
|
||||
},
|
||||
{
|
||||
title: "Audit Logs",
|
||||
formName: "audit-logs"
|
||||
},
|
||||
{
|
||||
title: "Organization Profile",
|
||||
formName: "settings"
|
||||
@@ -166,6 +163,11 @@ export const RolePermissionsSection = ({ roleId }: Props) => {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<OrgPermissionAuditLogsRow
|
||||
control={control}
|
||||
setValue={setValue}
|
||||
isEditable={isCustomRole}
|
||||
/>
|
||||
<OrgPermissionIdentityRow
|
||||
control={control}
|
||||
setValue={setValue}
|
||||
|
||||
Reference in New Issue
Block a user