Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: logs v2 data fetching #2825

Merged
merged 81 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
fc8fec6
fix: style issues
ogzhanolguncu Jan 15, 2025
01ceecc
fix: focus issues of filters
ogzhanolguncu Jan 15, 2025
df73530
fix: search focus issue
ogzhanolguncu Jan 15, 2025
bebcf77
feat: add focus to control cloud
ogzhanolguncu Jan 15, 2025
150987a
feat: adjust rows for dynamic selection
ogzhanolguncu Jan 15, 2025
b59a1c7
feat: add accessbility to display
ogzhanolguncu Jan 15, 2025
c7f877d
fix: show xx instead of direct status
ogzhanolguncu Jan 15, 2025
9744826
fix: duplicate filter when querying openai
ogzhanolguncu Jan 15, 2025
bf54d05
feat: add optional bottom content for table
ogzhanolguncu Jan 16, 2025
9d637bf
feat: add initial paginated data fetching
ogzhanolguncu Jan 16, 2025
57083fa
fix: no need to send all the status variations its already handled on…
ogzhanolguncu Jan 17, 2025
542711c
feat: add different variants for searching path
ogzhanolguncu Jan 17, 2025
58bc61a
refactor: improve ai query
ogzhanolguncu Jan 17, 2025
4efd937
Merge branch 'main' of github.com:unkeyed/unkey into feat/logs-v2-dat…
ogzhanolguncu Jan 17, 2025
e8f1976
chore: run formatter
ogzhanolguncu Jan 17, 2025
cbf91c0
feat: add ability to return datetimes from ai
ogzhanolguncu Jan 20, 2025
a58b8fc
fix: overflow issue of log details
ogzhanolguncu Jan 20, 2025
fcda52f
fix: update prompt and allow multiple requestID and host pass
ogzhanolguncu Jan 20, 2025
50fcb07
tests: add for filters
ogzhanolguncu Jan 20, 2025
3fb6835
feat: fetch paths for logs page
ogzhanolguncu Jan 20, 2025
37bb636
chore: get rid of old logs page
ogzhanolguncu Jan 20, 2025
78d80cd
refactor: move datetime components to audit for temporarily
ogzhanolguncu Jan 20, 2025
1b2ab57
refactor: add components to audit
ogzhanolguncu Jan 20, 2025
ce22698
feat: add realtime data fetching
ogzhanolguncu Jan 21, 2025
ebcfc1c
feat: add new param for relative time search
ogzhanolguncu Jan 21, 2025
a11b5c7
fix: filter reset
ogzhanolguncu Jan 22, 2025
ef39643
feat: fix rendering issues when live enabled
ogzhanolguncu Jan 22, 2025
716f09a
refacor: use maps to prevent array merges
ogzhanolguncu Jan 22, 2025
f9d779b
refactor: only allow refresh if relative time is around
ogzhanolguncu Jan 22, 2025
02d022a
refactor: move since logic to trpc
ogzhanolguncu Jan 22, 2025
cff009f
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 22, 2025
ea6ce68
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Jan 22, 2025
d0c31d7
[autofix.ci] apply automated fixes (attempt 3/3)
autofix-ci[bot] Jan 22, 2025
c045256
refactor: allow llm to return relative times
ogzhanolguncu Jan 22, 2025
b048018
Merge branch 'feat/logs-v2-data-fetching' of github.com:unkeyed/unkey…
ogzhanolguncu Jan 22, 2025
041c786
Merge branch 'main' into feat/logs-v2-data-fetching
ogzhanolguncu Jan 22, 2025
b4fb5ba
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 22, 2025
186dd56
Merge branch 'main' of github.com:unkeyed/unkey into feat/logs-v2-dat…
ogzhanolguncu Jan 22, 2025
198671e
Merge branch 'feat/logs-v2-data-fetching' of github.com:unkeyed/unkey…
ogzhanolguncu Jan 22, 2025
36adadf
feat: introduce new params for timeseries fetch
ogzhanolguncu Jan 23, 2025
a3344a0
feat: add proper data fetching
ogzhanolguncu Jan 23, 2025
6d80b1a
test: add tests for hooks
ogzhanolguncu Jan 23, 2025
97ff534
feat: add timestamp explainer for control pills
ogzhanolguncu Jan 23, 2025
7ff3f49
fix: detail dock issue
ogzhanolguncu Jan 23, 2025
d1025dd
feat: add a hook to track applied filters
ogzhanolguncu Jan 23, 2025
cdd36f7
fix: visual bugs
ogzhanolguncu Jan 24, 2025
50a82de
fix: ui issues
ogzhanolguncu Jan 24, 2025
8d9d293
fix: audit style issues after logs page refactor
ogzhanolguncu Jan 24, 2025
3649939
chore: enable logs page flag
ogzhanolguncu Jan 24, 2025
9efb202
fix: use same window for reseting and initial fetch
ogzhanolguncu Jan 24, 2025
fbdeead
working filter
MichaelUnkey Jan 24, 2025
13f476a
gh comment changes
MichaelUnkey Jan 24, 2025
2700833
style changes
MichaelUnkey Jan 27, 2025
1352deb
refactor: improve search prompt
ogzhanolguncu Jan 28, 2025
4d7a7cf
Merge branch 'feat/logs-v2-data-fetching' into datetime-into-logs-v2
MichaelUnkey Jan 28, 2025
5f89271
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 28, 2025
7373818
styles and icon
MichaelUnkey Jan 28, 2025
86bba82
fix: calendar range selection
ogzhanolguncu Jan 30, 2025
f39d241
fix: bunch of fixes
ogzhanolguncu Jan 30, 2025
2586a43
refactor: change how we show since filter
ogzhanolguncu Jan 30, 2025
a937c86
refactor: if
ogzhanolguncu Jan 30, 2025
2fc1fc5
fix: wrap function call
ogzhanolguncu Jan 30, 2025
1d93c9c
fix: datetime input alignment
chronark Jan 30, 2025
9271b71
Merge pull request #2836 from unkeyed/datetime-into-logs-v2
ogzhanolguncu Jan 30, 2025
583f46f
Merge branch 'main' of github.com:unkeyed/unkey into feat/logs-v2-dat…
ogzhanolguncu Jan 30, 2025
5401d32
rename logs
ogzhanolguncu Jan 30, 2025
d4aaab2
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 30, 2025
2684a29
Merge branch 'main' into feat/logs-v2-data-fetching
chronark Jan 30, 2025
0c9d5a2
fix: empty content
chronark Jan 30, 2025
4424656
fix: import paths
ogzhanolguncu Jan 30, 2025
0f35bc3
Merge branch 'feat/logs-v2-data-fetching' of github.com:unkeyed/unkey…
ogzhanolguncu Jan 30, 2025
0654dea
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 30, 2025
cb19e5f
fix: broken tests
ogzhanolguncu Jan 30, 2025
36ee64a
Merge branch 'feat/logs-v2-data-fetching' of github.com:unkeyed/unkey…
ogzhanolguncu Jan 30, 2025
023aa6b
fix: minor grammar issues
ogzhanolguncu Jan 30, 2025
62e635a
fix: table spacing issues
ogzhanolguncu Jan 31, 2025
adbc345
feat: add outcomes to table
ogzhanolguncu Jan 31, 2025
118b79b
fix: spacing
ogzhanolguncu Jan 31, 2025
07d530e
Merge branch 'main' into feat/logs-v2-data-fetching
ogzhanolguncu Jan 31, 2025
ea6e34b
fix: wrap issue for outcome
ogzhanolguncu Jan 31, 2025
d05a0c4
Merge branch 'feat/logs-v2-data-fetching' of github.com:unkeyed/unkey…
ogzhanolguncu Jan 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ArrowRight, Calendar as CalendarIcon } from "lucide-react";
import { parseAsInteger, useQueryStates } from "nuqs";
import { useEffect, useState } from "react";
import type { DateRange } from "react-day-picker";
import TimeSplitInput from "./time-split";
import { TimeSplitInput } from "./timesplit-input";

interface DatePickerWithRangeProps extends React.HTMLAttributes<HTMLDivElement> {
initialParams: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { DatePickerWithRange } from "@/app/(app)/logs/components/filters/components/custom-date-filter";
import { DEFAULT_BUCKET_NAME } from "@/lib/trpc/routers/audit/fetch";
import type { auditLogBucket, workspaces } from "@unkey/db/src/schema";
import { unkeyAuditLogEvents } from "@unkey/schema/src/auditlog";
Expand All @@ -7,6 +6,7 @@ import { Suspense } from "react";
import type { ParsedParams } from "../../actions";
import { BucketSelect } from "./bucket-select";
import { ClearButton } from "./clear-button";
import { DatePickerWithRange } from "./datepicker-with-range";
import { Filter } from "./filter";
import { RootKeyFilter } from "./root-key-filter";
import { UserFilter } from "./user-filter";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface TimeSplitInputProps {
endDate: Date;
}

const TimeSplitInput = ({
export const TimeSplitInput = ({
type,
time,
setTime,
Expand Down Expand Up @@ -272,5 +272,3 @@ const TimeSplitInput = ({
</div>
);
};

export default TimeSplitInput;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,32 @@ import { LogDetails } from "./table-details";
import type { Data } from "./types";
import { getEventType } from "./utils";

const STATUS_STYLES: Record<
"create" | "update" | "delete" | "other",
{ base: string; hover: string; selected: string }
> = {
create: {
base: "text-accent-11 ",
hover: "hover:bg-accent-3",
selected: "bg-accent-3",
},
other: {
base: "text-accent-11 ",
hover: "hover:bg-accent-3",
selected: "bg-accent-3",
},
update: {
base: "text-warning-11 ",
hover: "hover:bg-warning-3",
selected: "bg-warning-3",
},
delete: {
base: "text-error-11",
hover: "hover:bg-error-3",
selected: "bg-error-3",
},
};

export const AuditLogTableClient = () => {
const [selectedLog, setSelectedLog] = useState<Data | null>(null);
const { setCursor, searchParams } = useAuditLogParams();
Expand All @@ -28,9 +54,7 @@ export const AuditLogTableClient = () => {
endTime: searchParams.endTime,
},
{
getNextPageParam: (lastPage) => {
return lastPage.nextCursor;
},
getNextPageParam: (lastPage) => lastPage.nextCursor,
initialCursor: searchParams.cursor,
staleTime: Number.POSITIVE_INFINITY,
refetchOnMount: false,
Expand All @@ -42,38 +66,37 @@ export const AuditLogTableClient = () => {

const handleLoadMore = () => {
if (hasNextPage && !isFetchingNextPage && data?.pages.length) {
// Get the current last page before fetching next
const currentLastPage = data.pages[data.pages.length - 1];

fetchNextPage().then(() => {
// Set the cursor to the last page we had before fetching
if (currentLastPage.nextCursor) {
setCursor(currentLastPage.nextCursor);
}
});
}
};

const getRowClassName = (item: Data) => {
const eventType = getEventType(item.auditLog.event);
return cn({
"hover:bg-error-3": eventType === "delete",
"hover:bg-warning-3": eventType === "update",
"hover:bg-success-3": eventType === "create",
});
const style = STATUS_STYLES[eventType];

return cn(
style.base,
style.hover,
"group rounded-md",
"focus:outline-none focus:ring-1 focus:ring-opacity-40 px-1",
selectedLog && {
"opacity-50 z-0": selectedLog.auditLog.id !== item.auditLog.id,
"opacity-100 z-10": selectedLog.auditLog.id === item.auditLog.id,
},
);
};

const getSelectedClassName = (item: Data, isSelected: boolean) => {
if (!isSelected) {
return "";
}

const eventType = getEventType(item.auditLog.event);
return cn({
"bg-error-3": eventType === "delete",
"bg-warning-3": eventType === "update",
"bg-success-3": eventType === "create",
"bg-accent-3": eventType === "other",
});
const style = STATUS_STYLES[getEventType(item.auditLog.event)];
return style.selected;
};

if (isError) {
Expand Down
33 changes: 18 additions & 15 deletions apps/dashboard/app/(app)/audit/components/table/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ export const columns: Column<Data>[] = [
{
key: "time",
header: "Time",
headerClassName: "pl-3",
width: "150px",
headerClassName: "pl-3",
noTruncate: true,
render: (log) => (
<div className="flex items-center gap-3 px-2">
<div className="flex items-center gap-3">
<TimestampInfo
value={log.auditLog.time}
className="font-mono group-hover:underline decoration-dotted"
Expand All @@ -24,25 +25,26 @@ export const columns: Column<Data>[] = [
{
key: "actor",
header: "Actor",
width: "15%",
headerClassName: "pl-3",
width: "7%",
noTruncate: true,
render: (log) => (
<div className="flex items-center gap-3 px-2">
<div className="flex items-center gap-3 truncate">
{log.auditLog.actor.type === "user" && log.user ? (
<div className="flex items-center w-full gap-2 max-sm:m-0 max-sm:gap-1 max-sm:text-xs">
<span className="text-xs whitespace-nowrap">{`${log.user.firstName ?? ""} ${
log.user.lastName ?? ""
}`}</span>
<span className="text-xs whitespace-nowrap">
{`${log.user.firstName ?? ""} ${log.user.lastName ?? ""}`}
</span>
</div>
) : log.auditLog.actor.type === "key" ? (
<div className="flex items-center w-full gap-2 max-sm:m-0 max-sm:gap-1 max-sm:text-xs">
<KeySquare className="w-4 h-4" />
<span className="font-mono text-xs">{log.auditLog.actor.id}</span>
<span className="font-mono text-xs truncate">{log.auditLog.actor.id}</span>
</div>
) : (
<div className="flex items-center w-full gap-2 max-sm:m-0 max-sm:gap-1 max-sm:text-xs">
<FunctionSquare className="w-4 h-4" />
<span className="font-mono text-xs">{log.auditLog.actor.id}</span>
<span className="font-mono text-xs truncate">{log.auditLog.actor.id}</span>
</div>
)}
</div>
Expand All @@ -51,8 +53,9 @@ export const columns: Column<Data>[] = [
{
key: "action",
header: "Action",
width: "15%",
headerClassName: "pl-3",
width: "7%",
noTruncate: true,
render: (log) => {
const eventType = getEventType(log.auditLog.event);
const badgeClassName = cn("font-mono capitalize", {
Expand All @@ -62,7 +65,7 @@ export const columns: Column<Data>[] = [
"bg-accent-3 text-accent-11 hover:bg-accent-4": eventType === "other",
});
return (
<div className="flex items-center gap-3 px-2">
<div className="flex items-center gap-3">
<Badge className={badgeClassName}>{eventType}</Badge>
</div>
);
Expand All @@ -71,21 +74,21 @@ export const columns: Column<Data>[] = [
{
key: "event",
header: "Event",
headerClassName: "pl-2",
width: "20%",
render: (log) => (
<div className="flex items-center gap-2 text-current font-mono text-xs px-2">
<div className="flex items-center gap-2 text-current font-mono text-xs truncate">
<span>{log.auditLog.event}</span>
</div>
),
},
{
key: "event-description",
header: "Description",
headerClassName: "pl-1",
width: "auto",
render: (log) => (
<div className="text-current font-mono px-2 text-xs">{log.auditLog.description}</div>
<div className="text-current font-mono text-xs truncate w-[200px]">
{log.auditLog.description}
</div>
),
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const LogFooter = ({ log }: Props) => {
{
label: "Description",
description: (content) => (
<span className="text-[13px] font-mono text-end">{content}</span>
<span className="text-[13px] font-mono flex text-end">{content}</span>
),
content: log.auditLog.description,
tooltipContent: "Copy Description",
Expand Down
19 changes: 11 additions & 8 deletions apps/dashboard/app/(app)/audit/components/table/log-header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Badge } from "@/components/ui/badge";
import { XMark } from "@unkey/icons";
import { Button } from "@unkey/ui";
import { X } from "lucide-react";
import type { Data } from "./types";

type Props = {
Expand All @@ -10,16 +10,19 @@ type Props = {

export const LogHeader = ({ onClose, log }: Props) => {
return (
<div className="border-b-[1px] px-3 py-4 flex justify-between border-border items-center">
<div className="flex gap-2 items-center overflow-hidden">
<Badge variant="secondary" className="bg-transparent shrink-0">
<div className="border-b-[1px] flex justify-between items-center border-gray-4 pb-3 w-full">
<div className="flex gap-2 items-center flex-1 min-w-0">
<Badge className="uppercase px-[6px] rounded-md font-mono bg-accent-3 text-accent-11 hover:bg-accent-4">
{log.auditLog.event}
</Badge>
</div>
<div className="flex gap-1 items-center shrink-0">
<Button shape="square" variant="ghost" onClick={onClose}>
<X size="22" strokeWidth="1.5" className="text-content/65 cursor-pointer" />
</Button>

<div className="flex gap-1 items-center ">
<div className="flex gap-3">
<Button size="icon" variant="ghost" onClick={onClose} className="[&_svg]:size-3">
<XMark className="text-gray-12 stroke-2" />
</Button>
</div>
</div>
</div>
);
Expand Down
42 changes: 15 additions & 27 deletions apps/dashboard/app/(app)/audit/components/table/table-details.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
"use client";

import { LogSection } from "@/app/(app)/logs/components/table/log-details/components/log-section";
import { memo, useMemo, useState } from "react";
import { useDebounceCallback } from "usehooks-ts";
import ResizablePanel from "../../../logs/components/table/log-details/resizable-panel";
import { ResizablePanel } from "@/app/(app)/logs/components/table/log-details/resizable-panel";
import { useMemo } from "react";
import { LogFooter } from "./log-footer";
import { LogHeader } from "./log-header";
import type { Data } from "./types";
Expand All @@ -14,35 +13,29 @@ type Props = {
distanceToTop: number;
};

const DEFAULT_DRAGGABLE_WIDTH = 450;
const PANEL_WIDTH_SET_DELAY = 150;
const PANEL_MAX_WIDTH = 600;
const PANEL_MIN_WIDTH = 400;

const _LogDetails = ({ log, onClose, distanceToTop }: Props) => {
const [panelWidth, setPanelWidth] = useState(DEFAULT_DRAGGABLE_WIDTH);
const createPanelStyle = (distanceToTop: number) => ({
top: `${distanceToTop}px`,
width: "500px",
height: `calc(100vh - ${distanceToTop}px)`,
paddingBottom: "1rem",
});

const debouncedSetPanelWidth = useDebounceCallback((newWidth) => {
setPanelWidth(newWidth);
}, PANEL_WIDTH_SET_DELAY);

const panelStyle = useMemo(
() => ({
top: `${distanceToTop}px`,
width: `${panelWidth}px`,
height: `calc(100vh - ${distanceToTop}px)`,
paddingBottom: "1rem",
}),
[distanceToTop, panelWidth],
);
export const LogDetails = ({ log, onClose, distanceToTop }: Props) => {
const panelStyle = useMemo(() => createPanelStyle(distanceToTop), [distanceToTop]);

if (!log) {
return null;
}

return (
<ResizablePanel
onResize={debouncedSetPanelWidth}
minW={PANEL_MIN_WIDTH}
maxW={PANEL_MAX_WIDTH}
onClose={onClose}
className="absolute right-0 bg-background border-l border-t border-solid font-mono border-border shadow-md overflow-y-auto z-[3]"
className="absolute right-0 bg-gray-1 dark:bg-black font-mono drop-shadow-2xl overflow-y-auto z-20 p-4"
style={panelStyle}
>
<LogHeader log={log} onClose={onClose} />
Expand All @@ -61,8 +54,3 @@ const _LogDetails = ({ log, onClose, distanceToTop }: Props) => {
</ResizablePanel>
);
};

export const LogDetails = memo(
_LogDetails,
(prev, next) => prev.log?.auditLog.id === next.log?.auditLog.id,
);
Loading