refactor: unify AI capabilities and workspace integration

This commit is contained in:
yuxuanhui
2026-09-08 19:28:44 +08:00
parent 3d26827b49
commit b604e6050e
23 changed files with 1821 additions and 805 deletions
+42 -46
View File
@@ -18,20 +18,16 @@ import { AlphaPage } from "./pages/AlphaPage";
import { JobPanel } from "./components/JobPanel";
import { BacktestPage } from "./backtests/BacktestPage";
import { ChatPanel } from "./ai/ChatPanel";
import type { PageContext, UIAction } from "./ai/types";
import { actionDestination, pageFromHash } from "./ai/workspace";
import type { WorkspacePage } from "./ai/workspace";
import type { PageContext, Resource, UIAction } from "./ai/types";
export default function App() {
const [authenticated, setAuthenticated] = useState<boolean | null>(null);
const [account, setAccount] = useState<Account | null>(null);
const [jobs, setJobs] = useState<Job[]>([]);
const [page, setPage] = useState(
location.hash === "#backtests"
? "backtests"
: location.hash === "#datasets"
? "datasets"
: location.hash === "#account"
? "account"
: "alphas",
const [page, setPage] = useState<WorkspacePage>(() =>
pageFromHash(location.hash),
);
const [visitedBacktests, setVisitedBacktests] = useState(
page === "backtests",
@@ -42,6 +38,15 @@ export default function App() {
const [catalogModal, setCatalogModal] = useState(false);
const [showJobs, setShowJobs] = useState(false);
const [refreshKey, setRefreshKey] = useState(0);
const [resourceVersions, setResourceVersions] = useState<
Record<Resource, number>
>({
alphas: 0,
datasets: 0,
backtests: 0,
jobs: 0,
account: 0,
});
const [pollError, setPollError] = useState("");
const [chatOpen, setChatOpen] = useState(false);
const [chatWidth, setChatWidth] = useState(420);
@@ -104,16 +109,7 @@ export default function App() {
setShowJobs(false);
};
window.addEventListener("session-expired", expired);
const hash = () =>
setPage(
location.hash === "#backtests"
? "backtests"
: location.hash === "#datasets"
? "datasets"
: location.hash === "#account"
? "account"
: "alphas",
);
const hash = () => setPage(pageFromHash(location.hash));
window.addEventListener("hashchange", hash);
return () => {
window.removeEventListener("session-expired", expired);
@@ -145,31 +141,31 @@ export default function App() {
void refresh();
setRefreshKey((k) => k + 1);
};
const aiChanged = (resources: Resource[]) => {
if (resources.includes("jobs") || resources.includes("account"))
void refresh();
setResourceVersions((old) => {
const next = { ...old };
for (const resource of resources)
if (Object.hasOwn(next, resource)) next[resource] += 1;
return next;
});
};
const taskCreated = () => {
actionDone();
setShowJobs(true);
};
const changePage = (next: string) => {
const changePage = (next: WorkspacePage) => {
location.hash = next;
setPage(next);
};
const handleAction = (action: UIAction) => {
if (action.type === "open_conversation") {
setChatOpen(true);
} else {
focusBusiness();
if (action.type === "open_research_input") {
setChatOpen(false);
changePage("datasets");
} else {
changePage(
action.type === "open_backtest" ||
action.type === "open_backtest_preview"
? "backtests"
: "alphas",
);
}
}
const destination = actionDestination(action);
if (!destination) return;
if (destination.chat === "open") setChatOpen(true);
else if (destination.chat === "close") setChatOpen(false);
else focusBusiness();
if (destination.page) changePage(destination.page);
setAIAction(action);
};
const logout = async () => {
@@ -330,7 +326,7 @@ export default function App() {
account={account}
jobs={jobs}
active={page === "datasets"}
version={`${refreshKey}:${completedVersion}`}
version={`${refreshKey}:${resourceVersions.datasets}:${completedVersion}`}
suspended={showJobs || chatOpen}
onTask={taskCreated}
onModal={setCatalogModal}
@@ -342,7 +338,7 @@ export default function App() {
onAction={handleAction}
taskPanelOpen={showJobs}
account={account}
version={`${refreshKey}:${completedVersion}`}
version={`${refreshKey}:${resourceVersions.alphas}:${completedVersion}`}
onTask={taskCreated}
onAccount={() => changePage("account")}
active={page === "alphas"}
@@ -363,6 +359,7 @@ export default function App() {
<div className="backtest-page-view" hidden={page !== "backtests"}>
{visitedBacktests && (
<BacktestPage
version={resourceVersions.backtests}
active={page === "backtests"}
suspended={showJobs || (viewport < 1440 && chatOpen)}
chatOffset={chatOffset}
@@ -414,13 +411,12 @@ export default function App() {
onWidth={setChatWidth}
onClose={() => setChatOpen(false)}
context={
page === "alphas"
? alphaContext
: page === "backtests"
? backtestContext
: page === "datasets"
? datasetContext
: { page: "account" }
{
alphas: alphaContext,
datasets: datasetContext,
backtests: backtestContext,
account: { page: "account" as const },
}[page]
}
timezone={account?.timezone}
onSettings={() => {
@@ -432,7 +428,7 @@ export default function App() {
?.scrollIntoView({ block: "start" }),
);
}}
onChanged={actionDone}
onChanged={aiChanged}
onAction={handleAction}
/>
</div>