Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion apps/cli/cli-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"react-hot-toast": "^2.4.0",
"superjson": "^1.12.1",
"wouter": "^2.10.0",
"zod": "^3.19.1"
"zod": "^3.19.1",
"zustand": "^4.3.8"
},
"devDependencies": {
"@captain/cli-core": "*",
Expand Down
33 changes: 19 additions & 14 deletions apps/cli/cli-web/src/components/response-viewer.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { LogLevels } from "@captain/logger";
import { useEffect, useRef, useState } from "react";
import { useEffect, useRef } from "react";

import { cliApi } from "../utils/api";
import { classNames } from "../utils/classnames";
import { Tooltip } from "./common/tooltip";
import { useLogs } from "../utils/logsStore";

const colorMap = {
trace: { label: "text-gray-500", body: "text-gray-500" }, // gray
Expand All @@ -14,14 +14,19 @@ const colorMap = {
} as const;

export const ResponseViewer = () => {
const [messages, setMessages] = useState<
{ level: LogLevels; message: string; ts: number }[]
>([]);
const { logs, addLog, currentLog } = useLogs();
/**
* If currentLog is not set, fallbacks to the last log
*
* !!! this lays the groundwork to allow user to select a "currentLog" in preparation to a "history" tab or something like that, does nothing for now 🤷 */
const currentLogWithFallback = currentLog || logs.at(-1);

cliApi.onLog.useSubscription(undefined, {
onData: (data) => {
setMessages((messages) => {
return [...messages, data];
addLog({
level: data.level,
message: data.message,
ts: data.ts,
});
},
});
Expand All @@ -31,7 +36,7 @@ export const ResponseViewer = () => {
useEffect(() => {
// 👇️ scroll to bottom every time messages change
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
}, [currentLogWithFallback]);

return (
<div className="flex max-h-fit w-full flex-col gap-2">
Expand All @@ -42,28 +47,28 @@ export const ResponseViewer = () => {
<div className="h-full w-full overflow-auto rounded-md !bg-gray-800 px-1 py-4">
<table>
<tbody>
{messages.map((message, index) => (
{logs.map((log, index) => (
<tr key={index}>
<Tooltip
content={new Date(message.ts).toLocaleString()}
content={new Date(log.ts).toLocaleString()}
placement="top"
>
<td
className={classNames(
"min-w-[70px] px-1 text-right align-top font-mono text-sm font-semibold",
colorMap[message.level].label
colorMap[log.level].label
)}
>
{`[${message.level.toUpperCase()}]`}
{`[${log.level.toUpperCase()}]`}
</td>
</Tooltip>
<td
className={classNames(
"px-1 font-mono text-sm font-medium text-gray-300",
colorMap[message.level].body
colorMap[log.level].body
)}
>
{message.message}
{log.message}
</td>
</tr>
))}
Expand Down
25 changes: 25 additions & 0 deletions apps/cli/cli-web/src/utils/logsStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { create } from "zustand";
import { LogLevels } from "@captain/logger";

export type Log = {
level: LogLevels;
message: string;
ts: number;
};

export const useLogs = create<{
logs: Log[];
addLog: (log: Log) => void;
clearLogs: () => void;
currentLog: Log | null;
setCurrentLog: (log: Log) => void;
}>((set) => ({
logs: [],
addLog: (log) =>
set((state) => ({
logs: [...state.logs, log],
})),
clearLogs: () => set({ logs: [] }),
currentLog: null,
setCurrentLog: (log) => set({ currentLog: log }),
}));
Loading