Compare commits

..

1 Commits

Author SHA1 Message Date
=
08e0074b10 fix: resolved oracle failing in app connection 2025-07-17 16:23:52 +05:30
10 changed files with 169 additions and 411 deletions

View File

@ -106,7 +106,7 @@ export const validateSqlConnectionCredentials = async (config: TSqlConnectionCon
try { try {
client = await getSqlConnectionClient({ app, credentials }); client = await getSqlConnectionClient({ app, credentials });
await client.raw(`Select 1`); await client.raw(config.app === AppConnection.OracleDB ? `SELECT 1 FROM DUAL` : `Select 1`);
return credentials; return credentials;
} catch (error) { } catch (error) {

View File

@ -1,13 +1,11 @@
import { ChangeEventHandler, useState } from "react"; import { ChangeEventHandler, useState } from "react";
import { DayPicker, DayPickerProps, getDefaultClassNames, TZDate, UI } from "react-day-picker"; import { DayPicker, DayPickerProps, getDefaultClassNames, UI } from "react-day-picker";
import { faCalendar } from "@fortawesome/free-solid-svg-icons"; import { faCalendar } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { PopoverContentProps, PopoverProps } from "@radix-ui/react-popover"; import { PopoverContentProps, PopoverProps } from "@radix-ui/react-popover";
import { format, setHours, setMinutes } from "date-fns"; import { format, setHours, setMinutes } from "date-fns";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { formatDateTime, Timezone } from "@app/helpers/datetime";
import { Button } from "../Button"; import { Button } from "../Button";
import { Input } from "../Input"; import { Input } from "../Input";
import { Popover, PopoverContent, PopoverTrigger } from "../Popoverv2"; import { Popover, PopoverContent, PopoverTrigger } from "../Popoverv2";
@ -20,32 +18,6 @@ export type DatePickerProps = Omit<DayPickerProps, "selected"> & {
popUpProps: PopoverProps; popUpProps: PopoverProps;
popUpContentProps: PopoverContentProps; popUpContentProps: PopoverContentProps;
dateFormat?: "PPP" | "PP" | "P"; // extend as needed dateFormat?: "PPP" | "PP" | "P"; // extend as needed
buttonClassName?: string;
timezone?: Timezone;
};
const localTimeToUTC = (timeString: string) => {
const today = new Date();
const [hours, minutes] = timeString.split(":").map(Number);
today.setHours(hours, minutes, 0, 0);
const utcHours = today.getUTCHours().toString().padStart(2, "0");
const utcMinutes = today.getUTCMinutes().toString().padStart(2, "0");
return `${utcHours}:${utcMinutes}`;
};
const utcTimeToLocal = (utcTimeString: string) => {
const today = new Date();
const [hours, minutes] = utcTimeString.split(":").map(Number);
today.setUTCHours(hours, minutes, 0, 0);
const localHours = today.getHours().toString().padStart(2, "0");
const localMinutes = today.getMinutes().toString().padStart(2, "0");
return `${localHours}:${localMinutes}`;
}; };
// Doc: https://react-day-picker.js.org/ // Doc: https://react-day-picker.js.org/
@ -55,16 +27,12 @@ export const DatePicker = ({
popUpProps, popUpProps,
popUpContentProps, popUpContentProps,
dateFormat = "PPP", dateFormat = "PPP",
buttonClassName,
timezone,
...props ...props
}: DatePickerProps) => { }: DatePickerProps) => {
const [timeValue, setTimeValue] = useState<string>(value ? format(value, "HH:mm") : "00:00"); const [timeValue, setTimeValue] = useState<string>(value ? format(value, "HH:mm") : "00:00");
const displayUtc = timezone === Timezone.UTC;
const handleTimeChange: ChangeEventHandler<HTMLInputElement> = (e) => { const handleTimeChange: ChangeEventHandler<HTMLInputElement> = (e) => {
const time = displayUtc ? utcTimeToLocal(e.target.value) : e.target.value; const time = e.target.value;
if (time) { if (time) {
setTimeValue(time); setTimeValue(time);
if (value) { if (value) {
@ -89,14 +57,8 @@ export const DatePicker = ({
return ( return (
<Popover {...popUpProps}> <Popover {...popUpProps}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button <Button variant="outline_bg" leftIcon={<FontAwesomeIcon icon={faCalendar} />}>
className={buttonClassName} {value ? format(value, dateFormat) : "Pick a date and time"}
variant="outline_bg"
leftIcon={<FontAwesomeIcon icon={faCalendar} />}
>
{value
? formatDateTime({ timestamp: value, timezone, dateFormat })
: "Pick a date and time"}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent <PopoverContent
@ -110,10 +72,9 @@ export const DatePicker = ({
<DayPicker <DayPicker
{...props} {...props}
mode="single" mode="single"
selected={value ? new TZDate(value, displayUtc ? "UTC" : undefined) : undefined} selected={value}
onSelect={(date) => handleDaySelect(date ? new TZDate(date, undefined) : undefined)} onSelect={handleDaySelect}
className="font-inter text-mineshaft-200" className="font-inter text-mineshaft-200"
timeZone={displayUtc ? "UTC" : undefined}
classNames={{ classNames={{
today: "text-primary border-primary", today: "text-primary border-primary",
selected: " text-mineshaft-100 bg-mineshaft-500", selected: " text-mineshaft-100 bg-mineshaft-500",
@ -127,7 +88,7 @@ export const DatePicker = ({
<div className="mx-4 my-4"> <div className="mx-4 my-4">
<Input <Input
type="time" type="time"
value={displayUtc ? localTimeToUTC(timeValue) : timeValue} value={timeValue}
onChange={handleTimeChange} onChange={handleTimeChange}
className="bg-mineshaft-700 text-white [color-scheme:dark]" className="bg-mineshaft-700 text-white [color-scheme:dark]"
/> />

View File

@ -19,7 +19,6 @@ type Props = {
icon?: IconProp; icon?: IconProp;
isMulti?: boolean; isMulti?: boolean;
iconClassName?: string; iconClassName?: string;
dropdownContainerStyle?: React.CSSProperties;
}; };
export type SelectProps = Omit<SelectPrimitive.SelectProps, "disabled"> & Props; export type SelectProps = Omit<SelectPrimitive.SelectProps, "disabled"> & Props;
@ -36,7 +35,6 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
position, position,
containerClassName, containerClassName,
iconClassName, iconClassName,
dropdownContainerStyle,
...props ...props
}, },
ref ref
@ -84,7 +82,7 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
dropdownContainerClassName dropdownContainerClassName
)} )}
position={position} position={position}
style={dropdownContainerStyle ?? { width: "var(--radix-select-trigger-width)" }} style={{ width: "var(--radix-select-trigger-width)" }}
> >
<SelectPrimitive.ScrollUpButton> <SelectPrimitive.ScrollUpButton>
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">

View File

@ -1,24 +0,0 @@
import { format } from "date-fns";
export enum Timezone {
Local = "local",
UTC = "UTC"
}
export const formatDateTime = ({
timezone,
timestamp,
dateFormat = "MMM do yyyy, hh:mm a"
}: {
timestamp: string | Date;
timezone?: Timezone;
dateFormat?: string;
}) => {
const date = new Date(timestamp);
if (timezone === Timezone.UTC) {
const utcDate = new Date(date.getTime() + date.getTimezoneOffset() * 60000);
return `${format(utcDate, dateFormat)} UTC`;
}
return format(date, dateFormat);
};

View File

@ -57,7 +57,6 @@ export const useGetAuditLogs = (
}, },
getNextPageParam: (lastPage, pages) => getNextPageParam: (lastPage, pages) =>
lastPage.length !== 0 ? pages.length * filters.limit : undefined, lastPage.length !== 0 ? pages.length * filters.limit : undefined,
placeholderData: (prev) => prev,
...options ...options
}); });
}; };

View File

@ -18,7 +18,7 @@ export const AuditLogsPage = () => {
title="Audit logs" title="Audit logs"
description="Audit logs for security and compliance teams to monitor information access." description="Audit logs for security and compliance teams to monitor information access."
/> />
<LogsSection pageView /> <LogsSection />
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
import { useState } from "react"; import { useState } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { faCalendar, faChevronRight } from "@fortawesome/free-solid-svg-icons"; import { faArrowRight, faCalendar, faChevronRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns"; import { format } from "date-fns";
@ -18,7 +18,6 @@ import {
Select, Select,
SelectItem SelectItem
} from "@app/components/v2"; } from "@app/components/v2";
import { Timezone } from "@app/helpers/datetime";
import { import {
auditLogDateFilterFormSchema, auditLogDateFilterFormSchema,
@ -29,19 +28,9 @@ import {
type Props = { type Props = {
setFilter: (data: TAuditLogDateFilterFormData) => void; setFilter: (data: TAuditLogDateFilterFormData) => void;
filter: TAuditLogDateFilterFormData; filter: TAuditLogDateFilterFormData;
setTimezone: (timezone: Timezone) => void;
timezone: Timezone;
}; };
const RELATIVE_VALUES = ["5m", "30m", "1h", "3h", "12h"]; const RELATIVE_VALUES = ["5m", "30m", "1h", "3h", "12h"];
export const LogsDateFilter = ({ setFilter, filter }: Props) => {
const RELATIVE_OPTIONS = [
{ label: "Minutes", unit: "m", values: [5, 10, 15, 30, 45] },
{ label: "Hours", unit: "h", values: [1, 2, 3, 6, 8, 12] },
{ label: "Days", unit: "d", values: [1, 2, 3, 4, 5, 6] },
{ label: "Weeks", unit: "w", values: [1, 2, 3, 4] }
];
export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Props) => {
const [isStartDatePickerOpen, setIsStartDatePickerOpen] = useState(false); const [isStartDatePickerOpen, setIsStartDatePickerOpen] = useState(false);
const [isEndDatePickerOpen, setIsEndDatePickerOpen] = useState(false); const [isEndDatePickerOpen, setIsEndDatePickerOpen] = useState(false);
const [isPopupOpen, setIsPopOpen] = useState(false); const [isPopupOpen, setIsPopOpen] = useState(false);
@ -70,16 +59,15 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
}; };
return ( return (
<>
<DropdownMenu open={isPopupOpen} onOpenChange={(el) => setIsPopOpen(el)}> <DropdownMenu open={isPopupOpen} onOpenChange={(el) => setIsPopOpen(el)}>
<div className="flex items-center"> <div className="mr-2 flex items-center">
{filter.type === AuditLogDateFilterType.Relative ? ( {filter.type === AuditLogDateFilterType.Relative ? (
<> <>
{RELATIVE_VALUES.map((el) => ( {RELATIVE_VALUES.map((el) => (
<Button <Button
variant="outline_bg" variant="outline_bg"
className={twMerge( className={twMerge(
"w-[3.82rem] rounded-none px-3 py-2 font-normal first:rounded-l-md", "rounded-none px-3 py-2 first:rounded-l-md",
filter.type === AuditLogDateFilterType.Relative && filter.type === AuditLogDateFilterType.Relative &&
filter.relativeModeValue === el && filter.relativeModeValue === el &&
"border-primary/40 bg-primary/[0.1]" "border-primary/40 bg-primary/[0.1]"
@ -99,126 +87,65 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
))} ))}
</> </>
) : ( ) : (
<div className="flex w-[19.1rem] items-center justify-between rounded-l-md border border-transparent bg-mineshaft-600 px-5 py-2 text-sm text-bunker-200"> <>
<div>{format(filter.startDate, "yyyy-MM-dd HH:mm")}</div> <div className="rounded-l-md border border-transparent bg-mineshaft-600 px-3 py-2 text-sm text-bunker-200">
<div> {format(filter.startDate, "yyyy-MM-dd HH:mm")}
<FontAwesomeIcon className="text-bunker-300" size="sm" icon={faChevronRight} />
</div> </div>
<div>{format(filter.endDate, "yyyy-MM-dd HH:mm")}</div> <div className="border border-transparent bg-mineshaft-600 px-3 py-2 text-sm text-bunker-200">
<FontAwesomeIcon icon={faChevronRight} />
</div> </div>
<div className="border border-transparent bg-mineshaft-600 px-3 py-2 text-sm text-bunker-200">
{format(filter.endDate, "yyyy-MM-dd HH:mm")}
</div>
</>
)} )}
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Button <Button
variant="outline_bg" variant="outline_bg"
className={twMerge( className={twMerge(
"w-[8rem] rounded-none rounded-r-md px-3 py-2 font-normal", "rounded-none rounded-r-md px-3 py-2",
(filter.type === AuditLogDateFilterType.Absolute || isCustomRelative) && (filter.type === AuditLogDateFilterType.Absolute || isCustomRelative) &&
"border-primary/40 bg-primary/[0.1]" "border-primary/40 bg-primary/[0.1]"
)} )}
> >
<span>Custom</span> <FontAwesomeIcon className="ml-1" icon={faCalendar} /> <FontAwesomeIcon icon={faCalendar} />
{filter.type === AuditLogDateFilterType.Relative && isCustomRelative && ( {filter.type === AuditLogDateFilterType.Relative && isCustomRelative && (
<span className="ml-1">({filter.relativeModeValue})</span> <span className="ml-1">({filter.relativeModeValue})</span>
)} )}
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
</div> </div>
<DropdownMenuContent <DropdownMenuContent className="min-w-80 p-4" align="center" alignOffset={16}>
className="!min-w-[434px] bg-mineshaft-800 p-4"
align="end"
sideOffset={8}
>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Controller <Controller
control={control} control={control}
name="type" name="type"
render={({ field }) => ( render={({ field }) => (
<div className="mb-7"> <FormControl className="mb-2 w-full">
<Button <Select
onClick={() => field.onChange(AuditLogDateFilterType.Absolute)} value={field.value}
variant="outline_bg" onValueChange={(el) => field.onChange(el)}
className={twMerge( className="w-full"
"h-8 rounded-r-none font-normal",
field.value === AuditLogDateFilterType.Absolute &&
"border-primary/40 bg-primary/[0.1]"
)}
> >
Absolute <SelectItem value={AuditLogDateFilterType.Relative}>Relative</SelectItem>
</Button> <SelectItem value={AuditLogDateFilterType.Absolute}>Absolute</SelectItem>
<Button </Select>
onClick={() => field.onChange(AuditLogDateFilterType.Relative)} </FormControl>
variant="outline_bg"
className={twMerge(
"h-8 rounded-l-none font-normal",
field.value === AuditLogDateFilterType.Relative &&
"border-primary/40 bg-primary/[0.1]"
)}
>
Relative
</Button>
</div>
)} )}
/> />
{selectType === AuditLogDateFilterType.Relative && ( {selectType === AuditLogDateFilterType.Relative && (
<Controller <Controller
control={control} control={control}
name="relativeModeValue" name="relativeModeValue"
render={({ field }) => { render={({ field }) => (
const duration = field.value?.substring(0, field.value.length - 1); <FormControl className="mb-0 w-full" helperText="Example: 1h, 1d, 2d">
const unitOfTime = field.value?.at(-1); <Input {...field} value={field.value || ""} />
return ( </FormControl>
<div className="flex flex-col gap-4">
{RELATIVE_OPTIONS.map(({ label, unit, values }) => (
<div key={unit} className="flex items-center gap-2">
<div className="w-16">{label}</div>
{values.map((v) => {
const value = `${v}${unit}`;
return (
<Button
key={value}
variant="outline_bg"
onClick={() => field.onChange(value)}
className={twMerge(
"h-8 w-12",
field.value === value && "border-primary/40 bg-primary/[0.1]"
)} )}
>
{v}
</Button>
);
})}
</div>
))}
<div className="flex items-center gap-2">
<FormControl className="mb-0 w-28" label="Duration">
<Input
type="number"
value={duration || "1"}
onChange={(val) => field.onChange(`${val}${unitOfTime}`)}
max={60}
min={1}
/>
</FormControl>
<FormControl className="mb-0 w-36" label="Unit of Time">
<Select
value={unitOfTime}
onValueChange={(val) => field.onChange(`${duration}${val}`)}
className="w-full"
position="popper"
>
{RELATIVE_OPTIONS.map((opt) => (
<SelectItem value={opt.unit}>{opt.label}</SelectItem>
))}
</Select>
</FormControl>
</div>
</div>
);
}}
/> />
)} )}
{selectType === AuditLogDateFilterType.Absolute && ( {selectType === AuditLogDateFilterType.Absolute && (
<div className="flex h-10 w-full items-center justify-between gap-2"> <div className="mb-2 flex h-10 w-full items-center justify-between gap-2">
<Controller <Controller
name="startDate" name="startDate"
control={control} control={control}
@ -228,14 +155,11 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
className="relative top-2" className="relative top-2"
errorText={error?.message} errorText={error?.message}
isError={Boolean(error)} isError={Boolean(error)}
label="Start Date"
> >
<DatePicker <DatePicker
value={field.value || undefined} value={field.value || undefined}
onChange={onChange} onChange={onChange}
timezone={timezone}
dateFormat="P" dateFormat="P"
buttonClassName="w-44 h-8 font-normal"
popUpProps={{ popUpProps={{
open: isStartDatePickerOpen, open: isStartDatePickerOpen,
onOpenChange: setIsStartDatePickerOpen onOpenChange: setIsStartDatePickerOpen
@ -246,11 +170,10 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
); );
}} }}
/> />
<FontAwesomeIcon <div className="flex items-center -space-x-3">
icon={faChevronRight} <div className="h-[2px] w-[20px] rounded-full bg-mineshaft-500" />
size="xs" <FontAwesomeIcon icon={faArrowRight} className="text-mineshaft-500" />
className="mt-6 text-mineshaft-400" </div>
/>
<Controller <Controller
name="endDate" name="endDate"
control={control} control={control}
@ -260,14 +183,11 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
className="relative top-2" className="relative top-2"
errorText={error?.message} errorText={error?.message}
isError={Boolean(error)} isError={Boolean(error)}
label="End Date"
> >
<DatePicker <DatePicker
value={field.value || undefined} value={field.value || undefined}
onChange={onChange} onChange={onChange}
dateFormat="P" dateFormat="P"
buttonClassName="w-44 h-8 font-normal"
timezone={timezone}
popUpProps={{ popUpProps={{
open: isEndDatePickerOpen, open: isEndDatePickerOpen,
onOpenChange: setIsEndDatePickerOpen onOpenChange: setIsEndDatePickerOpen
@ -280,36 +200,13 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
/> />
</div> </div>
)} )}
<div className="mt-8 w-full justify-end"> <div className="mt-4">
<Button <Button size="xs" type="submit" isDisabled={!formState.isDirty}>
size="sm"
type="submit"
className="h-9 w-24 font-normal"
variant="outline_bg"
isDisabled={!formState.isDirty}
>
Apply Apply
</Button> </Button>
</div> </div>
</form> </form>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<Select
value={timezone}
onValueChange={(val) => setTimezone(val as Timezone)}
className="w-[10.6rem] border !border-mineshaft-500 !bg-mineshaft-600 capitalize"
dropdownContainerClassName="max-w-none"
position="popper"
dropdownContainerStyle={{
width: "100%"
}}
>
{Object.values(Timezone).map((tz) => (
<SelectItem value={tz} className="capitalize" key={tz}>
{tz} Timezone
</SelectItem>
))}
</Select>
</>
); );
}; };

View File

@ -1,11 +1,8 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import ms from "ms"; import ms from "ms";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context"; import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
import { Timezone } from "@app/helpers/datetime";
import { withPermission } from "@app/hoc"; import { withPermission } from "@app/hoc";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
@ -23,11 +20,10 @@ type Props = {
presets?: Presets; presets?: Presets;
refetchInterval?: number; refetchInterval?: number;
showFilters?: boolean; showFilters?: boolean;
pageView?: boolean;
}; };
export const LogsSection = withPermission( export const LogsSection = withPermission(
({ presets, refetchInterval, showFilters = true, pageView = false }: Props) => { ({ presets, refetchInterval, showFilters = true }: Props) => {
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const);
@ -35,8 +31,6 @@ export const LogsSection = withPermission(
eventType: presets?.eventType || [], eventType: presets?.eventType || [],
actor: presets?.actorId actor: presets?.actorId
}); });
const [timezone, setTimezone] = useState<Timezone>(Timezone.Local);
const [dateFilter, setDateFilter] = useState<TAuditLogDateFilterFormData>({ const [dateFilter, setDateFilter] = useState<TAuditLogDateFilterFormData>({
startDate: new Date(Number(new Date()) - ms("1h")), startDate: new Date(Number(new Date()) - ms("1h")),
endDate: new Date(), endDate: new Date(),
@ -49,85 +43,10 @@ export const LogsSection = withPermission(
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
} }
}, [subscription]); }, [subscription]);
if (pageView)
return (
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-y-2">
<div>
<div className="flex items-center gap-1 whitespace-nowrap">
<p className="text-xl font-semibold text-mineshaft-100">Audit History</p>
<a
href="https://infisical.com/docs/documentation/platform/audit-logs"
target="_blank"
rel="noopener noreferrer"
>
<div className="ml-1 mt-[0.1rem] inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
</div>
</div>
<div className="flex flex-wrap items-center gap-2 lg:justify-end">
{showFilters && (
<LogsDateFilter
filter={dateFilter}
setFilter={setDateFilter}
timezone={timezone}
setTimezone={setTimezone}
/>
)}
{showFilters && (
<LogsFilter presets={presets} setFilter={setLogFilter} filter={logFilter} />
)}
</div>
</div>
<div className="space-y-2">
<LogsTable
refetchInterval={refetchInterval}
filter={{
secretPath: logFilter.secretPath || undefined,
secretKey: logFilter.secretKey || undefined,
eventMetadata: logFilter?.eventMetadata,
projectId: logFilter?.project?.id,
actorType: presets?.actorType,
limit: 15,
eventType: logFilter?.eventType,
userAgentType: logFilter?.userAgentType,
startDate: dateFilter?.startDate,
endDate: dateFilter?.endDate,
environment: logFilter?.environment?.slug,
actor: logFilter?.actor
}}
timezone={timezone}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => {
handlePopUpToggle("upgradePlan", isOpen);
}}
text="You can use audit logs if you switch to a paid Infisical plan."
/>
</div>
</div>
);
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<div className="flex w-full justify-end"> <div className="flex w-full justify-end">
{showFilters && ( {showFilters && <LogsDateFilter filter={dateFilter} setFilter={setDateFilter} />}
<LogsDateFilter
filter={dateFilter}
setFilter={setDateFilter}
timezone={timezone}
setTimezone={setTimezone}
/>
)}
{showFilters && ( {showFilters && (
<LogsFilter presets={presets} setFilter={setLogFilter} filter={logFilter} /> <LogsFilter presets={presets} setFilter={setLogFilter} filter={logFilter} />
)} )}
@ -148,7 +67,6 @@ export const LogsSection = withPermission(
environment: logFilter?.environment?.slug, environment: logFilter?.environment?.slug,
actor: logFilter?.actor actor: logFilter?.actor
}} }}
timezone={timezone}
/> />
<UpgradePlanModal <UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen} isOpen={popUp.upgradePlan.isOpen}

View File

@ -1,5 +1,6 @@
import { Fragment } from "react"; import { Fragment } from "react";
import { faFile } from "@fortawesome/free-solid-svg-icons"; import { faFile, faInfoCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { import {
@ -13,9 +14,9 @@ import {
Td, Td,
Th, Th,
THead, THead,
Tooltip,
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { Timezone } from "@app/helpers/datetime";
import { useGetAuditLogs } from "@app/hooks/api"; import { useGetAuditLogs } from "@app/hooks/api";
import { TGetAuditLogsFilter } from "@app/hooks/api/auditLogs/types"; import { TGetAuditLogsFilter } from "@app/hooks/api/auditLogs/types";
@ -24,12 +25,11 @@ import { LogsTableRow } from "./LogsTableRow";
type Props = { type Props = {
filter: TGetAuditLogsFilter; filter: TGetAuditLogsFilter;
refetchInterval?: number; refetchInterval?: number;
timezone: Timezone;
}; };
const AUDIT_LOG_LIMIT = 30; const AUDIT_LOG_LIMIT = 30;
export const LogsTable = ({ filter, refetchInterval, timezone }: Props) => { export const LogsTable = ({ filter, refetchInterval }: Props) => {
// Determine the project ID for filtering // Determine the project ID for filtering
const filterProjectId = const filterProjectId =
// Use the projectId from the filter if it exists // Use the projectId from the filter if it exists
@ -57,7 +57,16 @@ export const LogsTable = ({ filter, refetchInterval, timezone }: Props) => {
<Th className="w-24"> <Th className="w-24">
<Spinner size="xs" className={twMerge(isPending ? "opacity-100" : "opacity-0")} /> <Spinner size="xs" className={twMerge(isPending ? "opacity-100" : "opacity-0")} />
</Th> </Th>
<Th className="w-64">Timestamp</Th> <Th className="w-64">
Timestamp
<Tooltip
className="normal-case"
content="Time displayed in your system's time zone."
sideOffset={10}
>
<FontAwesomeIcon icon={faInfoCircle} className="ml-1" />
</Tooltip>
</Th>
<Th>Event</Th> <Th>Event</Th>
</Tr> </Tr>
</THead> </THead>
@ -70,7 +79,6 @@ export const LogsTable = ({ filter, refetchInterval, timezone }: Props) => {
rowNumber={index + i * AUDIT_LOG_LIMIT + 1} rowNumber={index + i * AUDIT_LOG_LIMIT + 1}
auditLog={auditLog} auditLog={auditLog}
key={`audit-log-${auditLog.id}`} key={`audit-log-${auditLog.id}`}
timezone={timezone}
/> />
))} ))}
</Fragment> </Fragment>
@ -88,7 +96,7 @@ export const LogsTable = ({ filter, refetchInterval, timezone }: Props) => {
</TableContainer> </TableContainer>
{!isEmpty && ( {!isEmpty && (
<Button <Button
className="mt-4 px-4 py-3 text-sm" className="mb-20 mt-4 px-4 py-3 text-sm"
isFullWidth isFullWidth
variant="outline_bg" variant="outline_bg"
isLoading={isFetchingNextPage} isLoading={isFetchingNextPage}

View File

@ -1,8 +1,8 @@
import { faCaretDown, faCaretRight } from "@fortawesome/free-solid-svg-icons"; import { faCaretDown, faCaretRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import { Td, Tr } from "@app/components/v2"; import { Td, Tr } from "@app/components/v2";
import { formatDateTime, Timezone } from "@app/helpers/datetime";
import { useToggle } from "@app/hooks"; import { useToggle } from "@app/hooks";
import { ActorType } from "@app/hooks/api/auditLogs/enums"; import { ActorType } from "@app/hooks/api/auditLogs/enums";
import { AuditLog } from "@app/hooks/api/auditLogs/types"; import { AuditLog } from "@app/hooks/api/auditLogs/types";
@ -10,7 +10,6 @@ import { AuditLog } from "@app/hooks/api/auditLogs/types";
type Props = { type Props = {
auditLog: AuditLog; auditLog: AuditLog;
rowNumber: number; rowNumber: number;
timezone: Timezone;
}; };
type TagProps = { type TagProps = {
@ -28,7 +27,7 @@ const Tag = ({ label, value }: TagProps) => {
); );
}; };
export const LogsTableRow = ({ auditLog, rowNumber, timezone }: Props) => { export const LogsTableRow = ({ auditLog, rowNumber }: Props) => {
const [isOpen, setIsOpen] = useToggle(); const [isOpen, setIsOpen] = useToggle();
return ( return (
@ -47,7 +46,9 @@ export const LogsTableRow = ({ auditLog, rowNumber, timezone }: Props) => {
<FontAwesomeIcon icon={isOpen ? faCaretDown : faCaretRight} /> <FontAwesomeIcon icon={isOpen ? faCaretDown : faCaretRight} />
{rowNumber} {rowNumber}
</Td> </Td>
<Td className="align-top">{formatDateTime({ timestamp: auditLog.createdAt, timezone })}</Td> <Td className="align-top">
{format(new Date(auditLog.createdAt), "MMM do yyyy, hh:mm a")}
</Td>
<Td> <Td>
<div className="flex flex-wrap gap-4 text-sm"> <div className="flex flex-wrap gap-4 text-sm">
<Tag label="event" value={auditLog.event.type} /> <Tag label="event" value={auditLog.event.type} />