From 8485fdc1cd0f2e4eb4f3eee9d9fabf1660b8cbd7 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Tue, 23 Apr 2024 20:52:38 +0530 Subject: [PATCH] feat(ui): audit log page completed --- .../ProjectSettingsPage.tsx | 12 +- .../AuditLogStreamTab/AuditLogStreamForm.tsx | 136 ++++++++++++ .../AuditLogStreamTab/AuditLogStreamTab.tsx | 200 ++++++++++++++++++ .../components/AuditLogStreamTab/index.tsx | 1 + .../ProjectSettingsPage/components/index.tsx | 1 + 5 files changed, 346 insertions(+), 4 deletions(-) create mode 100644 frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamForm.tsx create mode 100644 frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamTab.tsx create mode 100644 frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/index.tsx diff --git a/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx b/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx index da87da755..cc521d813 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx @@ -4,10 +4,12 @@ import { Tab } from "@headlessui/react"; import { ProjectGeneralTab } from "./components/ProjectGeneralTab"; import { WebhooksTab } from "./components/WebhooksTab"; +import { AuditLogStreamsTab } from "./components"; const tabs = [ { name: "General", key: "tab-project-general" }, - { name: "Webhooks", key: "tab-project-webhooks" } + { name: "Webhooks", key: "tab-project-webhooks" }, + { name: "Audit Log Streams", key: "tab-project-audit-log-stream" } ]; export const ProjectSettingsPage = () => { @@ -25,9 +27,8 @@ export const ProjectSettingsPage = () => { {({ selected }) => ( @@ -42,6 +43,9 @@ export const ProjectSettingsPage = () => { + + + diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamForm.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamForm.tsx new file mode 100644 index 000000000..d5f9c5cfd --- /dev/null +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamForm.tsx @@ -0,0 +1,136 @@ +import { Controller, useForm } from "react-hook-form"; +import { z } from "zod"; + +import { createNotification } from "@app/components/notifications"; +import { Button, FormControl, Input, Spinner } from "@app/components/v2"; +import { useWorkspace } from "@app/context"; +import { + useCreateAuditLogStream, + useGetAuditLogStreamDetails, + useUpdateAuditLogStream +} from "@app/hooks/api"; + +type Props = { + id?: string; + onClose: () => void; +}; + +const formSchema = z.object({ + url: z.string().url().min(1), + token: z.string().optional() +}); +type TForm = z.infer; + +export const AuditLogStreamForm = ({ id = "", onClose }: Props) => { + const isEdit = Boolean(id); + const { currentWorkspace } = useWorkspace(); + const projectSlug = currentWorkspace?.slug || ""; + + const auditLogStream = useGetAuditLogStreamDetails(id); + const createAuditLogStream = useCreateAuditLogStream(); + const updateAuditLogStream = useUpdateAuditLogStream(); + + const { + handleSubmit, + control, + formState: { isSubmitting } + } = useForm({ + values: auditLogStream?.data + }); + + const handleAuditLogStreamEdit = async ({ token, url }: TForm) => { + if (!id) return; + try { + await updateAuditLogStream.mutateAsync({ + id, + projectSlug, + token, + url + }); + createNotification({ + type: "success", + text: "Successfully updated stream" + }); + onClose(); + } catch (err) { + console.log(err); + createNotification({ + type: "error", + text: "Failed to update stream" + }); + } + }; + + const handleFormSubmit = async ({ token, url }: TForm) => { + if (isSubmitting) return; + if (isEdit) { + handleAuditLogStreamEdit({ token, url }); + return; + } + try { + await createAuditLogStream.mutateAsync({ + projectSlug, + token, + url + }); + createNotification({ + type: "success", + text: "Successfully created stream" + }); + onClose(); + } catch (err) { + console.log(err); + createNotification({ + type: "error", + text: "Failed to create stream" + }); + } + }; + + if (isEdit && auditLogStream.isLoading) { + return ( +
+ +
+ ); + } + + return ( +
+
+ ( + + + + )} + /> + ( + + + + )} + /> +
+
+ + +
+
+ ); +}; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamTab.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamTab.tsx new file mode 100644 index 000000000..2c3234c10 --- /dev/null +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/AuditLogStreamTab.tsx @@ -0,0 +1,200 @@ +import { faPlug, faPlus } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import { createNotification } from "@app/components/notifications"; +import { ProjectPermissionCan } from "@app/components/permissions"; +import { + Button, + DeleteActionModal, + EmptyState, + Modal, + ModalContent, + Table, + TableContainer, + TableSkeleton, + TBody, + Td, + THead, + Tr, + UpgradePlanModal +} from "@app/components/v2"; +import { + ProjectPermissionActions, + ProjectPermissionSub, + useSubscription, + useWorkspace +} from "@app/context"; +import { withProjectPermission } from "@app/hoc"; +import { usePopUp } from "@app/hooks"; +import { useDeleteAuditLogStream, useGetAuditLogStreams } from "@app/hooks/api"; + +import { AuditLogStreamForm } from "./AuditLogStreamForm"; + +export const AuditLogStreamsTab = withProjectPermission( + () => { + const { currentWorkspace } = useWorkspace(); + const projectSlug = currentWorkspace?.slug || ""; + const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ + "auditLogStreamForm", + "deleteAuditLogStream", + "upgradePlan" + ] as const); + const { subscription } = useSubscription(); + + const { data: auditLogStreams, isLoading: isAuditLogStreamsLoading } = + useGetAuditLogStreams(projectSlug); + + // mutation + const { mutateAsync: deleteAuditLogStream } = useDeleteAuditLogStream(); + + const handleAuditLogStreamDelete = async () => { + try { + const auditLogStreamId = popUp?.deleteAuditLogStream?.data as string; + await deleteAuditLogStream({ + id: auditLogStreamId, + projectSlug + }); + handlePopUpClose("deleteAuditLogStream"); + createNotification({ + type: "success", + text: "Successfully deleted stream" + }); + } catch (err) { + console.log(err); + createNotification({ + type: "error", + text: "Failed to delete stream" + }); + } + }; + + return ( +
+
+

Audit Log Streams

+ + {(isAllowed) => ( + + )} + +
+

+ Manage audit log streams to send audit log to any logging providers with syslog support. +

+
+ + + + + + + + + + {isAuditLogStreamsLoading && ( + + )} + {!isAuditLogStreamsLoading && auditLogStreams && auditLogStreams?.length === 0 && ( + + + + )} + {!isAuditLogStreamsLoading && + auditLogStreams?.map(({ id, url }) => ( + + + + + ))} + +
URLAction
+ +
+ {url} + +
+ + {(isAllowed) => ( + + )} + + + {(isAllowed) => ( + + )} + +
+
+
+
+ { + handlePopUpToggle("auditLogStreamForm", isModalOpen); + }} + > + + handlePopUpToggle("auditLogStreamForm")} + /> + + + handlePopUpToggle("upgradePlan", isOpen)} + text="You can add audit log streams if you switch to Infisical's Enterprise plan." + /> + handlePopUpToggle("deleteAuditLogStream", isOpen)} + onClose={() => handlePopUpClose("deleteAuditLogStream")} + onDeleteApproved={handleAuditLogStreamDelete} + /> +
+ ); + }, + { action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.Settings } +); diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/index.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/index.tsx new file mode 100644 index 000000000..ecce21f3b --- /dev/null +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/AuditLogStreamTab/index.tsx @@ -0,0 +1 @@ +export { AuditLogStreamsTab } from "./AuditLogStreamTab"; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx index 72ac106a3..a3524152f 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/index.tsx @@ -1,3 +1,4 @@ +export { AuditLogStreamsTab } from "./AuditLogStreamTab"; export { AutoCapitalizationSection } from "./AutoCapitalizationSection"; export { DeleteProjectSection } from "./DeleteProjectSection"; export { E2EESection } from "./E2EESection";