mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-20 02:53:42 +00:00
Merge pull request #4228 from Infisical/project-audit-logs-page
feature(project-audit-logs): add project audit logs pages
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
} from "@app/hooks/api/auditLogs/constants";
|
||||
import { EventType } from "@app/hooks/api/auditLogs/enums";
|
||||
import { UserAgentType } from "@app/hooks/api/auth/types";
|
||||
import { Workspace } from "@app/hooks/api/workspace/types";
|
||||
|
||||
import { LogFilterItem } from "./LogFilterItem";
|
||||
import { auditLogFilterFormSchema, Presets, TAuditLogFilterFormData } from "./types";
|
||||
@@ -43,6 +44,7 @@ type Props = {
|
||||
presets?: Presets;
|
||||
setFilter: (data: TAuditLogFilterFormData) => void;
|
||||
filter: TAuditLogFilterFormData;
|
||||
project?: Workspace;
|
||||
};
|
||||
|
||||
const getActiveFilterCount = (filter: TAuditLogFilterFormData) => {
|
||||
@@ -69,7 +71,7 @@ const getActiveFilterCount = (filter: TAuditLogFilterFormData) => {
|
||||
return filterCount;
|
||||
};
|
||||
|
||||
export const LogsFilter = ({ presets, setFilter, filter }: Props) => {
|
||||
export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
|
||||
const { data: workspaces = [] } = useGetUserWorkspaces();
|
||||
const { currentOrg } = useOrganization();
|
||||
|
||||
@@ -90,7 +92,7 @@ export const LogsFilter = ({ presets, setFilter, filter }: Props) => {
|
||||
values: filter
|
||||
});
|
||||
const selectedEventTypes = watch("eventType") as EventType[] | undefined;
|
||||
const selectedProject = watch("project");
|
||||
const selectedProject = project ?? watch("project");
|
||||
|
||||
const showSecretsSection =
|
||||
selectedEventTypes?.some(
|
||||
@@ -270,48 +272,50 @@ export const LogsFilter = ({ presets, setFilter, filter }: Props) => {
|
||||
)}
|
||||
/>
|
||||
</LogFilterItem>
|
||||
<LogFilterItem
|
||||
label="Project"
|
||||
onClear={() => {
|
||||
resetField("project");
|
||||
resetField("environment");
|
||||
setValue("secretPath", "");
|
||||
setValue("secretKey", "");
|
||||
}}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name="project"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
className="mb-0 w-full"
|
||||
>
|
||||
<FilterableSelect
|
||||
value={value}
|
||||
isClearable
|
||||
onChange={(e) => {
|
||||
if (e === null) {
|
||||
setValue("secretPath", "");
|
||||
setValue("secretKey", "");
|
||||
}
|
||||
resetField("environment");
|
||||
onChange(e);
|
||||
}}
|
||||
placeholder="All projects"
|
||||
options={workspacesInOrg.map(({ name, id, type }) => ({
|
||||
name,
|
||||
id,
|
||||
type
|
||||
}))}
|
||||
getOptionValue={(option) => option.id}
|
||||
getOptionLabel={(option) => option.name}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</LogFilterItem>
|
||||
{!project && (
|
||||
<LogFilterItem
|
||||
label="Project"
|
||||
onClear={() => {
|
||||
resetField("project");
|
||||
resetField("environment");
|
||||
setValue("secretPath", "");
|
||||
setValue("secretKey", "");
|
||||
}}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name="project"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
className="mb-0 w-full"
|
||||
>
|
||||
<FilterableSelect
|
||||
value={value}
|
||||
isClearable
|
||||
onChange={(e) => {
|
||||
if (e === null) {
|
||||
setValue("secretPath", "");
|
||||
setValue("secretKey", "");
|
||||
}
|
||||
resetField("environment");
|
||||
onChange(e);
|
||||
}}
|
||||
placeholder="All projects"
|
||||
options={workspacesInOrg.map(({ name, id, type }) => ({
|
||||
name,
|
||||
id,
|
||||
type
|
||||
}))}
|
||||
getOptionValue={(option) => option.id}
|
||||
getOptionLabel={(option) => option.name}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</LogFilterItem>
|
||||
)}
|
||||
<AnimatePresence initial={false}>
|
||||
{showSecretsSection && (
|
||||
<motion.div
|
||||
|
||||
@@ -7,6 +7,7 @@ import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
|
||||
import { Timezone } from "@app/helpers/datetime";
|
||||
import { withPermission } from "@app/hoc";
|
||||
import { Workspace } from "@app/hooks/api/workspace/types";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { LogsDateFilter } from "./LogsDateFilter";
|
||||
@@ -24,10 +25,11 @@ type Props = {
|
||||
refetchInterval?: number;
|
||||
showFilters?: boolean;
|
||||
pageView?: boolean;
|
||||
project?: Workspace;
|
||||
};
|
||||
|
||||
export const LogsSection = withPermission(
|
||||
({ presets, refetchInterval, showFilters = true, pageView = false }: Props) => {
|
||||
({ presets, refetchInterval, showFilters = true, pageView = false, project }: Props) => {
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const);
|
||||
@@ -83,7 +85,12 @@ export const LogsSection = withPermission(
|
||||
/>
|
||||
)}
|
||||
{showFilters && (
|
||||
<LogsFilter presets={presets} setFilter={setLogFilter} filter={logFilter} />
|
||||
<LogsFilter
|
||||
project={project}
|
||||
presets={presets}
|
||||
setFilter={setLogFilter}
|
||||
filter={logFilter}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,7 +101,7 @@ export const LogsSection = withPermission(
|
||||
secretPath: logFilter.secretPath || undefined,
|
||||
secretKey: logFilter.secretKey || undefined,
|
||||
eventMetadata: logFilter?.eventMetadata,
|
||||
projectId: logFilter?.project?.id,
|
||||
projectId: project?.id || logFilter?.project?.id,
|
||||
actorType: presets?.actorType,
|
||||
limit: 15,
|
||||
eventType: logFilter?.eventType,
|
||||
@@ -119,7 +126,7 @@ export const LogsSection = withPermission(
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="flex w-full justify-end">
|
||||
<div className="flex flex-wrap items-center gap-2 lg:justify-end">
|
||||
{showFilters && (
|
||||
<LogsDateFilter
|
||||
filter={dateFilter}
|
||||
|
||||
@@ -52,7 +52,7 @@ export const ProjectsPage = () => {
|
||||
<title>{t("common.head-title", { title: t("settings.members.title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Helmet>
|
||||
|
||||
|
||||
{!isLoading && !serverDetails?.redisConfigured && (
|
||||
<div className="mb-4 flex flex-col items-start justify-start text-3xl">
|
||||
<p className="mb-4 mr-4 font-semibold text-white">Announcements</p>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { LogsSection } from "@app/pages/organization/AuditLogsPage/components";
|
||||
|
||||
export const AuditLogsPage = () => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
|
||||
return (
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<Helmet>
|
||||
<title>Project Audit Logs</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Helmet>
|
||||
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
|
||||
<div className="w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Audit logs"
|
||||
description="Audit logs for security and compliance teams to monitor information access."
|
||||
/>
|
||||
<LogsSection pageView project={currentWorkspace} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { AuditLogsPage } from "./AuditLogsPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/audit-logs"
|
||||
)({
|
||||
component: AuditLogsPage,
|
||||
beforeLoad: ({ context }) => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
...context.breadcrumbs,
|
||||
{
|
||||
label: "Audit Logs"
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { AuditLogsPage } from "./AuditLogsPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/kms/$projectId/_kms-layout/audit-logs"
|
||||
)({
|
||||
component: AuditLogsPage,
|
||||
beforeLoad: ({ context }) => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
...context.breadcrumbs,
|
||||
{
|
||||
label: "Audit Logs"
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { AuditLogsPage } from "./AuditLogsPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/audit-logs"
|
||||
)({
|
||||
component: AuditLogsPage,
|
||||
beforeLoad: ({ context }) => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
...context.breadcrumbs,
|
||||
{
|
||||
label: "Audit Logs"
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { AuditLogsPage } from "./AuditLogsPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-scanning/$projectId/_secret-scanning-layout/audit-logs"
|
||||
)({
|
||||
component: AuditLogsPage,
|
||||
beforeLoad: ({ context }) => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
...context.breadcrumbs,
|
||||
{
|
||||
label: "Audit Logs"
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { AuditLogsPage } from "./AuditLogsPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/ssh/$projectId/_ssh-layout/audit-logs"
|
||||
)({
|
||||
component: AuditLogsPage,
|
||||
beforeLoad: ({ context }) => {
|
||||
return {
|
||||
breadcrumbs: [
|
||||
...context.breadcrumbs,
|
||||
{
|
||||
label: "Audit Logs"
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user