mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 09:27:50 +00:00
fix: update day picker to handle utc display
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
import { ChangeEventHandler, useState } from "react";
|
import { ChangeEventHandler, useState } from "react";
|
||||||
import { DayPicker, DayPickerProps, getDefaultClassNames, UI } from "react-day-picker";
|
import { DayPicker, DayPickerProps, getDefaultClassNames, TZDate, 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";
|
||||||
@@ -19,6 +21,31 @@ export type DatePickerProps = Omit<DayPickerProps, "selected"> & {
|
|||||||
popUpContentProps: PopoverContentProps;
|
popUpContentProps: PopoverContentProps;
|
||||||
dateFormat?: "PPP" | "PP" | "P"; // extend as needed
|
dateFormat?: "PPP" | "PP" | "P"; // extend as needed
|
||||||
buttonClassName?: string;
|
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/
|
||||||
@@ -29,12 +56,15 @@ export const DatePicker = ({
|
|||||||
popUpContentProps,
|
popUpContentProps,
|
||||||
dateFormat = "PPP",
|
dateFormat = "PPP",
|
||||||
buttonClassName,
|
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 = e.target.value;
|
const time = displayUtc ? utcTimeToLocal(e.target.value) : e.target.value;
|
||||||
|
|
||||||
if (time) {
|
if (time) {
|
||||||
setTimeValue(time);
|
setTimeValue(time);
|
||||||
if (value) {
|
if (value) {
|
||||||
@@ -64,7 +94,9 @@ export const DatePicker = ({
|
|||||||
variant="outline_bg"
|
variant="outline_bg"
|
||||||
leftIcon={<FontAwesomeIcon icon={faCalendar} />}
|
leftIcon={<FontAwesomeIcon icon={faCalendar} />}
|
||||||
>
|
>
|
||||||
{value ? format(value, dateFormat) : "Pick a date and time"}
|
{value
|
||||||
|
? formatDateTime({ timestamp: value, timezone, dateFormat })
|
||||||
|
: "Pick a date and time"}
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
@@ -78,9 +110,10 @@ export const DatePicker = ({
|
|||||||
<DayPicker
|
<DayPicker
|
||||||
{...props}
|
{...props}
|
||||||
mode="single"
|
mode="single"
|
||||||
selected={value}
|
selected={value ? new TZDate(value, displayUtc ? "UTC" : undefined) : undefined}
|
||||||
onSelect={handleDaySelect}
|
onSelect={(date) => handleDaySelect(date ? new TZDate(date, undefined) : undefined)}
|
||||||
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",
|
||||||
@@ -94,7 +127,7 @@ export const DatePicker = ({
|
|||||||
<div className="mx-4 my-4">
|
<div className="mx-4 my-4">
|
||||||
<Input
|
<Input
|
||||||
type="time"
|
type="time"
|
||||||
value={timeValue}
|
value={displayUtc ? localTimeToUTC(timeValue) : timeValue}
|
||||||
onChange={handleTimeChange}
|
onChange={handleTimeChange}
|
||||||
className="bg-mineshaft-700 text-white [color-scheme:dark]"
|
className="bg-mineshaft-700 text-white [color-scheme:dark]"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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);
|
||||||
|
};
|
||||||
@@ -18,12 +18,12 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
SelectItem
|
SelectItem
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
|
import { Timezone } from "@app/helpers/datetime";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
auditLogDateFilterFormSchema,
|
auditLogDateFilterFormSchema,
|
||||||
AuditLogDateFilterType,
|
AuditLogDateFilterType,
|
||||||
TAuditLogDateFilterFormData,
|
TAuditLogDateFilterFormData
|
||||||
Timezone
|
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -233,6 +233,7 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
|
|||||||
<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"
|
buttonClassName="w-44 h-8 font-normal"
|
||||||
popUpProps={{
|
popUpProps={{
|
||||||
@@ -266,6 +267,7 @@ export const LogsDateFilter = ({ setFilter, filter, timezone, setTimezone }: Pro
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
dateFormat="P"
|
dateFormat="P"
|
||||||
buttonClassName="w-44 h-8 font-normal"
|
buttonClassName="w-44 h-8 font-normal"
|
||||||
|
timezone={timezone}
|
||||||
popUpProps={{
|
popUpProps={{
|
||||||
open: isEndDatePickerOpen,
|
open: isEndDatePickerOpen,
|
||||||
onOpenChange: setIsEndDatePickerOpen
|
onOpenChange: setIsEndDatePickerOpen
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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";
|
||||||
|
|
||||||
@@ -15,8 +16,7 @@ import {
|
|||||||
AuditLogDateFilterType,
|
AuditLogDateFilterType,
|
||||||
Presets,
|
Presets,
|
||||||
TAuditLogDateFilterFormData,
|
TAuditLogDateFilterFormData,
|
||||||
TAuditLogFilterFormData,
|
TAuditLogFilterFormData
|
||||||
Timezone
|
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
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";
|
||||||
|
|
||||||
import { Timezone } from "./types";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
auditLog: AuditLog;
|
auditLog: AuditLog;
|
||||||
rowNumber: number;
|
rowNumber: number;
|
||||||
@@ -30,16 +28,6 @@ const Tag = ({ label, value }: TagProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatDateTime = (timestamp: string | Date, timezone: Timezone) => {
|
|
||||||
const date = new Date(timestamp);
|
|
||||||
|
|
||||||
if (timezone === Timezone.UTC) {
|
|
||||||
const utcDate = new Date(date.getTime() + date.getTimezoneOffset() * 60000);
|
|
||||||
return `${format(utcDate, "MMM do yyyy, hh:mm a")} UTC`;
|
|
||||||
}
|
|
||||||
return format(date, "MMM do yyyy, hh:mm a");
|
|
||||||
};
|
|
||||||
|
|
||||||
export const LogsTableRow = ({ auditLog, rowNumber, timezone }: Props) => {
|
export const LogsTableRow = ({ auditLog, rowNumber, timezone }: Props) => {
|
||||||
const [isOpen, setIsOpen] = useToggle();
|
const [isOpen, setIsOpen] = useToggle();
|
||||||
|
|
||||||
@@ -59,7 +47,7 @@ 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(auditLog.createdAt, timezone)}</Td>
|
<Td className="align-top">{formatDateTime({ timestamp: auditLog.createdAt, timezone })}</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} />
|
||||||
|
|||||||
@@ -8,11 +8,6 @@ export enum AuditLogDateFilterType {
|
|||||||
Absolute = "absolute"
|
Absolute = "absolute"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Timezone {
|
|
||||||
Local = "local",
|
|
||||||
UTC = "UTC"
|
|
||||||
}
|
|
||||||
|
|
||||||
export const auditLogFilterFormSchema = z.object({
|
export const auditLogFilterFormSchema = z.object({
|
||||||
eventMetadata: z.object({}).optional(),
|
eventMetadata: z.object({}).optional(),
|
||||||
project: z
|
project: z
|
||||||
|
|||||||
Reference in New Issue
Block a user