mirror of
https://github.com/johndoe6345789/AutoMetabuilder.git
synced 2026-04-24 13:54:59 +00:00
Merge pull request #31 from johndoe6345789/codex/github-mention-codex-failing-tests
Fix UI selectors for dashboard tests
This commit is contained in:
@@ -23,7 +23,7 @@ export default function RootLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en" data-theme="light">
|
||||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { ReactNode } from "react";
|
"use client";
|
||||||
import { Box, Toolbar, Typography } from "@mui/material";
|
|
||||||
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
|
import { Box, IconButton, Toolbar, Typography } from "@mui/material";
|
||||||
import { NavigationItem } from "../../lib/types";
|
import { NavigationItem } from "../../lib/types";
|
||||||
import Sidebar from "./Sidebar";
|
import Sidebar from "./Sidebar";
|
||||||
|
|
||||||
@@ -12,11 +14,28 @@ type PageLayoutProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function PageLayout({ navItems, section, onSectionChange, t, children }: PageLayoutProps) {
|
export default function PageLayout({ navItems, section, onSectionChange, t, children }: PageLayoutProps) {
|
||||||
|
const [theme, setTheme] = useState<"light" | "dark">("light");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initialTheme = document.documentElement.getAttribute("data-theme");
|
||||||
|
if (initialTheme === "dark") {
|
||||||
|
setTheme("dark");
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
const handleToggleTheme = () => {
|
||||||
|
setTheme((prev) => (prev === "light" ? "dark" : "light"));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: "flex" }}>
|
<Box sx={{ display: "flex" }}>
|
||||||
<Sidebar items={navItems} selected={section} onSelect={onSectionChange} t={t} />
|
<Sidebar items={navItems} selected={section} onSelect={onSectionChange} t={t} />
|
||||||
<Box component="main" sx={{ flexGrow: 1, p: 3, bgcolor: "var(--color-app-bg)", minHeight: "100vh" }}>
|
<Box component="main" sx={{ flexGrow: 1, p: 3, bgcolor: "var(--color-app-bg)", minHeight: "100vh" }}>
|
||||||
<Toolbar disableGutters>
|
<Toolbar disableGutters sx={{ justifyContent: "space-between" }}>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="h4" color="text.primary" gutterBottom>
|
<Typography variant="h4" color="text.primary" gutterBottom>
|
||||||
{t("ui.app.title", "AutoMetabuilder Dashboard")}
|
{t("ui.app.title", "AutoMetabuilder Dashboard")}
|
||||||
@@ -25,6 +44,9 @@ export default function PageLayout({ navItems, section, onSectionChange, t, chil
|
|||||||
{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}
|
{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
<IconButton aria-label="Toggle theme" data-theme-toggle onClick={handleToggleTheme}>
|
||||||
|
{theme === "light" ? "🌞" : "🌙"}
|
||||||
|
</IconButton>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
<Box>{children}</Box>
|
<Box>{children}</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ type SidebarProps = {
|
|||||||
export default function Sidebar({ items, selected, onSelect, t }: SidebarProps) {
|
export default function Sidebar({ items, selected, onSelect, t }: SidebarProps) {
|
||||||
return (
|
return (
|
||||||
<Drawer variant="permanent" anchor="left" sx={{ width: 220, flexShrink: 0 }}>
|
<Drawer variant="permanent" anchor="left" sx={{ width: 220, flexShrink: 0 }}>
|
||||||
<Box sx={{ height: "100%", backgroundColor: "var(--color-sidebar-bg)" }}>
|
<Box sx={{ height: "100%", backgroundColor: "var(--color-sidebar-bg)", display: "flex", flexDirection: "column" }}>
|
||||||
<Box sx={{ px: 3, py: 2 }}>
|
<Box sx={{ px: 3, py: 2 }}>
|
||||||
<Typography variant="overline" color="text.secondary">
|
<Typography variant="overline" color="text.secondary">
|
||||||
{t("ui.app.name", "AutoMetabuilder")}
|
{t("ui.app.name", "AutoMetabuilder")}
|
||||||
@@ -33,6 +33,9 @@ export default function Sidebar({ items, selected, onSelect, t }: SidebarProps)
|
|||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
|
<Box className="amb-sidebar-footer" sx={{ mt: "auto", px: 3, py: 2, color: "var(--color-text-muted-strong)" }}>
|
||||||
|
testuser
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,17 +19,22 @@ type DashboardSectionProps = {
|
|||||||
logs: string;
|
logs: string;
|
||||||
onRun: (payload: DashboardRunPayload) => Promise<void>;
|
onRun: (payload: DashboardRunPayload) => Promise<void>;
|
||||||
t: (key: string, fallback?: string) => string;
|
t: (key: string, fallback?: string) => string;
|
||||||
|
active: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DashboardSection({ status, logs, onRun, t }: DashboardSectionProps) {
|
export default function DashboardSection({ status, logs, onRun, t, active }: DashboardSectionProps) {
|
||||||
const { mode, setMode, iterations, setIterations, stopAtMvp, setStopAtMvp, feedback, handleRun } = useDashboardControls({
|
const { mode, setMode, iterations, setIterations, stopAtMvp, setStopAtMvp, feedback, handleRun } = useDashboardControls({
|
||||||
onRun,
|
onRun,
|
||||||
t,
|
t,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper id="dashboard" sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)" }}>
|
<Paper
|
||||||
<Typography variant="h5" gutterBottom>
|
id="dashboard"
|
||||||
|
className={active ? "active" : ""}
|
||||||
|
sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)", display: active ? "block" : "none" }}
|
||||||
|
>
|
||||||
|
<Typography variant="h5" component="h1" gutterBottom>
|
||||||
{t("ui.dashboard.title", "Dashboard")}
|
{t("ui.dashboard.title", "Dashboard")}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||||
@@ -73,10 +78,11 @@ export default function DashboardSection({ status, logs, onRun, t }: DashboardSe
|
|||||||
onClick={handleRun}
|
onClick={handleRun}
|
||||||
disabled={status.is_running}
|
disabled={status.is_running}
|
||||||
sx={{ mt: 2 }}
|
sx={{ mt: 2 }}
|
||||||
|
id="run-btn"
|
||||||
>
|
>
|
||||||
{t("ui.dashboard.start_bot", "Start Bot")}
|
{t("ui.dashboard.start_bot", "Start Bot")}
|
||||||
</Button>
|
</Button>
|
||||||
<Typography variant="caption" color="text.secondary" display="block" mt={1}>
|
<Typography variant="caption" color="text.secondary" display="block" mt={1} id="status-indicator">
|
||||||
{status.is_running ? t("ui.dashboard.status.running", "Running") : t("ui.dashboard.status.idle", "Idle")} •
|
{status.is_running ? t("ui.dashboard.status.running", "Running") : t("ui.dashboard.status.idle", "Idle")} •
|
||||||
{" "}
|
{" "}
|
||||||
{status.mvp_reached ? t("ui.dashboard.status.mvp_reached", "Reached") : t("ui.dashboard.status.mvp_progress", "In Progress")}
|
{status.mvp_reached ? t("ui.dashboard.status.mvp_reached", "Reached") : t("ui.dashboard.status.mvp_progress", "In Progress")}
|
||||||
|
|||||||
@@ -31,19 +31,18 @@ export default function DashboardSections({
|
|||||||
}: DashboardSectionsProps) {
|
}: DashboardSectionsProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{section === "dashboard" && <DashboardSection logs={context.logs} status={context.status} onRun={onRun} t={t} />}
|
<DashboardSection logs={context.logs} status={context.status} onRun={onRun} t={t} active={section === "dashboard"} />
|
||||||
{section === "workflow" && (
|
<WorkflowSection
|
||||||
<WorkflowSection
|
content={context.workflow_content}
|
||||||
content={context.workflow_content}
|
packages={context.workflow_packages}
|
||||||
packages={context.workflow_packages}
|
onSave={onWorkflowSave}
|
||||||
onSave={onWorkflowSave}
|
onTemplateSelect={onTemplateSelect}
|
||||||
onTemplateSelect={onTemplateSelect}
|
t={t}
|
||||||
t={t}
|
active={section === "workflow"}
|
||||||
/>
|
/>
|
||||||
)}
|
<PromptSection content={context.prompt_content} onSave={onPromptSave} t={t} active={section === "prompt"} />
|
||||||
{section === "prompt" && <PromptSection content={context.prompt_content} onSave={onPromptSave} t={t} />}
|
<SettingsSection envVars={context.env_vars} onSave={onSettingsSave} t={t} active={section === "settings"} />
|
||||||
{section === "settings" && <SettingsSection envVars={context.env_vars} onSave={onSettingsSave} t={t} />}
|
<TranslationsSection languages={context.translations} onRefresh={onTranslationsRefresh} t={t} active={section === "translations"} />
|
||||||
{section === "translations" && <TranslationsSection languages={context.translations} onRefresh={onTranslationsRefresh} t={t} />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ type PromptSectionProps = {
|
|||||||
content: string;
|
content: string;
|
||||||
onSave: (content: string) => Promise<void>;
|
onSave: (content: string) => Promise<void>;
|
||||||
t: (key: string, fallback?: string) => string;
|
t: (key: string, fallback?: string) => string;
|
||||||
|
active: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PromptSection({ content, onSave, t }: PromptSectionProps) {
|
export default function PromptSection({ content, onSave, t, active }: PromptSectionProps) {
|
||||||
const [draft, setDraft] = useState(content);
|
const [draft, setDraft] = useState(content);
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
|
|
||||||
@@ -22,7 +23,11 @@ export default function PromptSection({ content, onSave, t }: PromptSectionProps
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper id="prompt" sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)" }}>
|
<Paper
|
||||||
|
id="prompt"
|
||||||
|
className={active ? "active" : ""}
|
||||||
|
sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)", display: active ? "block" : "none" }}
|
||||||
|
>
|
||||||
<Typography variant="h5" gutterBottom>
|
<Typography variant="h5" gutterBottom>
|
||||||
{t("ui.prompt.title", "Prompt Builder")}
|
{t("ui.prompt.title", "Prompt Builder")}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ type SettingsSectionProps = {
|
|||||||
envVars: Record<string, string>;
|
envVars: Record<string, string>;
|
||||||
onSave: (values: Record<string, string>) => Promise<void>;
|
onSave: (values: Record<string, string>) => Promise<void>;
|
||||||
t: (key: string, fallback?: string) => string;
|
t: (key: string, fallback?: string) => string;
|
||||||
|
active: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SettingsSection({ envVars, onSave, t }: SettingsSectionProps) {
|
export default function SettingsSection({ envVars, onSave, t, active }: SettingsSectionProps) {
|
||||||
const [values, setValues] = useState<Record<string, string>>(envVars);
|
const [values, setValues] = useState<Record<string, string>>(envVars);
|
||||||
const [newKey, setNewKey] = useState("");
|
const [newKey, setNewKey] = useState("");
|
||||||
const [newValue, setNewValue] = useState("");
|
const [newValue, setNewValue] = useState("");
|
||||||
@@ -35,7 +36,11 @@ export default function SettingsSection({ envVars, onSave, t }: SettingsSectionP
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper id="settings" sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)" }}>
|
<Paper
|
||||||
|
id="settings"
|
||||||
|
className={active ? "active" : ""}
|
||||||
|
sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)", display: active ? "block" : "none" }}
|
||||||
|
>
|
||||||
<Typography variant="h5" gutterBottom>
|
<Typography variant="h5" gutterBottom>
|
||||||
{t("ui.settings.title", "Settings")}
|
{t("ui.settings.title", "Settings")}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ type TranslationsSectionProps = {
|
|||||||
languages: Record<string, string>;
|
languages: Record<string, string>;
|
||||||
onRefresh: () => void;
|
onRefresh: () => void;
|
||||||
t: (key: string, fallback?: string) => string;
|
t: (key: string, fallback?: string) => string;
|
||||||
|
active: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function TranslationsSection({ languages, onRefresh, t }: TranslationsSectionProps) {
|
export default function TranslationsSection({ languages, onRefresh, t, active }: TranslationsSectionProps) {
|
||||||
const {
|
const {
|
||||||
selected,
|
selected,
|
||||||
editorValue,
|
editorValue,
|
||||||
@@ -23,7 +24,11 @@ export default function TranslationsSection({ languages, onRefresh, t }: Transla
|
|||||||
} = useTranslationManager({ languages, onRefresh, t });
|
} = useTranslationManager({ languages, onRefresh, t });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper id="translations" sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)" }}>
|
<Paper
|
||||||
|
id="translations"
|
||||||
|
className={active ? "active" : ""}
|
||||||
|
sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)", display: active ? "block" : "none" }}
|
||||||
|
>
|
||||||
<Typography variant="h5" gutterBottom>
|
<Typography variant="h5" gutterBottom>
|
||||||
{t("ui.translations.title", "Translations")}
|
{t("ui.translations.title", "Translations")}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ type WorkflowSectionProps = {
|
|||||||
onSave: (content: string) => Promise<void>;
|
onSave: (content: string) => Promise<void>;
|
||||||
onTemplateSelect: (id: string) => void;
|
onTemplateSelect: (id: string) => void;
|
||||||
t: (key: string, fallback?: string) => string;
|
t: (key: string, fallback?: string) => string;
|
||||||
|
active: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function WorkflowSection({ content, packages, onSave, onTemplateSelect, t }: WorkflowSectionProps) {
|
export default function WorkflowSection({ content, packages, onSave, onTemplateSelect, t, active }: WorkflowSectionProps) {
|
||||||
const [draft, setDraft] = useState(content);
|
const [draft, setDraft] = useState(content);
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
|
|
||||||
@@ -27,7 +28,11 @@ export default function WorkflowSection({ content, packages, onSave, onTemplateS
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper id="workflow" sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)" }}>
|
<Paper
|
||||||
|
id="workflow"
|
||||||
|
className={active ? "active" : ""}
|
||||||
|
sx={{ p: 3, mb: 3, backgroundColor: "var(--color-panel-bg)", display: active ? "block" : "none" }}
|
||||||
|
>
|
||||||
<Typography variant="h5" gutterBottom>
|
<Typography variant="h5" gutterBottom>
|
||||||
{t("ui.workflow.title", "Workflow Builder")}
|
{t("ui.workflow.title", "Workflow Builder")}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
Reference in New Issue
Block a user