Unverified 提交 c599f4e5 authored 作者: Mohamed Aziz Mejri's avatar Mohamed Aziz Mejri 提交者: GitHub

Adding clear logs button (#2118)

<!-- This is an auto-generated description by cubic. --> ## Summary by cubic Added a Clear Logs button to the System Messages console to remove all logs for the selected app. Renamed the filters button to “Clear Filters” and updated e2e tests. - **New Features** - Console adds onClearLogs handler that calls IpcClient.clearLogs(selectedAppId), then clears appConsoleEntriesAtom; shows a toast on error. - E2E test verifies “Clear Logs” removes all entries; existing test updated to expect “Clear Filters” label. <sup>Written for commit cc7cafc267e13e05cdb6cc45b3122ac572fcb048. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. -->
上级 e99cf759
......@@ -235,7 +235,7 @@ testSkipIfWindows("clear filters button works", async ({ po }) => {
await levelFilter.selectOption("error");
// Check that clear button appears
const clearButton = po.page.getByRole("button", { name: "Clear" });
const clearButton = po.page.getByRole("button", { name: "Clear Filters" });
await expect(clearButton).toBeVisible();
// Click clear button
......@@ -245,3 +245,50 @@ testSkipIfWindows("clear filters button works", async ({ po }) => {
const filterValue = await levelFilter.inputValue();
expect(filterValue).toBe("all");
});
testSkipIfWindows("clear logs button clears all logs", async ({ po }) => {
await po.setUp();
// Create an app with console logs
await po.sendPrompt("tc=console-logs");
await po.approveProposal();
// Wait for app to run
const picker = po.page.getByTestId("preview-pick-element-button");
await expect(picker).toBeEnabled({ timeout: Timeout.EXTRA_LONG });
// Wait for iframe to load
const iframe = po.getPreviewIframeElement();
await expect(
iframe.contentFrame().getByText("Console Logs Test App"),
).toBeVisible({ timeout: Timeout.MEDIUM });
// Open the system messages console
const consoleHeader = po.page.locator('text="System Messages"').first();
await consoleHeader.click();
// Wait for logs to appear
await expect(async () => {
const allLogs = po.page.getByTestId("console-entry");
const count = await allLogs.count();
expect(count).toBeGreaterThan(0);
await expect(allLogs.first()).toBeVisible();
}).toPass({ timeout: Timeout.MEDIUM });
// Verify we have multiple logs before clearing
const logsBeforeClear = po.page.getByTestId("console-entry");
const countBeforeClear = await logsBeforeClear.count();
expect(countBeforeClear).toBeGreaterThan(0);
// Click the Clear Logs button
const clearLogsButton = po.page.getByTestId("clear-logs-button");
await expect(clearLogsButton).toBeVisible();
await clearLogsButton.click();
// Verify all logs are cleared
await expect(async () => {
const logsAfterClear = po.page.getByTestId("console-entry");
const countAfterClear = await logsAfterClear.count();
expect(countAfterClear).toBe(0);
}).toPass({ timeout: Timeout.MEDIUM });
});
import { appConsoleEntriesAtom } from "@/atoms/appAtoms";
import { appConsoleEntriesAtom, selectedAppIdAtom } from "@/atoms/appAtoms";
import type { ConsoleEntry } from "@/ipc/ipc_types";
import { useAtomValue } from "jotai";
import { useAtomValue, useSetAtom } from "jotai";
import { IpcClient } from "@/ipc/ipc_client";
import { useEffect, useRef, useState, useMemo, useCallback, memo } from "react";
import { Virtuoso, VirtuosoHandle } from "react-virtuoso";
import { ConsoleEntryComponent } from "./ConsoleEntry";
import { ConsoleFilters } from "./ConsoleFilters";
import { useSettings } from "@/hooks/useSettings";
import { showError } from "@/lib/toast";
// Placeholder component shown during fast scrolling
const ScrollSeekPlaceholder = () => {
......@@ -64,6 +66,8 @@ ConsoleItem.displayName = "ConsoleItem";
// Console component
export const Console = () => {
const consoleEntries = useAtomValue(appConsoleEntriesAtom);
const setConsoleEntries = useSetAtom(appConsoleEntriesAtom);
const selectedAppId = useAtomValue(selectedAppIdAtom);
const { settings } = useSettings();
const virtuosoRef = useRef<VirtuosoHandle>(null);
const containerRef = useRef<HTMLDivElement>(null);
......@@ -104,6 +108,21 @@ export const Console = () => {
setSourceFilter("");
};
const handleClearLogs = useCallback(async () => {
if (selectedAppId) {
try {
// Clear logs from backend store
await IpcClient.getInstance().clearLogs(selectedAppId);
// Clear logs from UI
setConsoleEntries([]);
} catch (error) {
showError(
error instanceof Error ? error.message : "Failed to clear logs",
);
}
}
}, [selectedAppId, setConsoleEntries]);
useEffect(() => {
const container = containerRef.current?.parentElement;
if (!container) return;
......@@ -219,6 +238,7 @@ export const Console = () => {
onTypeFilterChange={setTypeFilter}
onSourceFilterChange={setSourceFilter}
onClearFilters={handleClearFilters}
onClearLogs={handleClearLogs}
uniqueSources={uniqueSources}
totalLogs={filteredEntries.length}
showFilters={showFilters}
......
import { Filter, X } from "lucide-react";
import { Filter, X, Trash2 } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
interface ConsoleFiltersProps {
levelFilter: "all" | "info" | "warn" | "error";
......@@ -22,6 +28,7 @@ interface ConsoleFiltersProps {
) => void;
onSourceFilterChange: (value: string) => void;
onClearFilters: () => void;
onClearLogs: () => void;
uniqueSources: string[];
totalLogs: number;
showFilters: boolean;
......@@ -35,6 +42,7 @@ export const ConsoleFilters = ({
onTypeFilterChange,
onSourceFilterChange,
onClearFilters,
onClearLogs,
uniqueSources,
totalLogs,
showFilters,
......@@ -111,10 +119,26 @@ export const ConsoleFilters = ({
className="text-xs px-2 py-1 flex items-center gap-1 border border-border rounded bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
>
<X size={12} />
Clear
Clear Filters
</button>
)}
{/* Clear logs button */}
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<button
onClick={onClearLogs}
className="p-1 border border-border rounded bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
data-testid="clear-logs-button"
>
<Trash2 size={14} />
</button>
</TooltipTrigger>
<TooltipContent>Clear logs</TooltipContent>
</Tooltip>
</TooltipProvider>
<div className="ml-auto text-xs text-gray-500">{totalLogs} logs</div>
</div>
);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论