feat: add Pi management interface

This commit is contained in:
2026-08-05 05:53:28 +02:00
parent 4422568f61
commit 7a8bcacbfe
6 changed files with 606 additions and 10 deletions
+14 -10
View File
@@ -4,6 +4,7 @@ import { WidgetHost } from "./WidgetHost";
import { CentralStatus } from "./CentralStatus";
import { ModelActivityPanel } from "./ModelActivityPanel";
import { WorkspaceManager } from "./WorkspaceManager";
import { PiManagement } from "./PiManagement";
import { useActivityPanelResize } from "./useActivityPanelResize";
import { useSessionPanelResize } from "./useSessionPanelResize";
import { NavSessions } from "./NavSessions";
@@ -32,12 +33,6 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useEffect, useMemo, useRef, useState } from "react";
import type { CSSProperties } from "react";
/**
* The page is designed to live INSIDE the Omics Portal chrome (its left sidebar
* + topbar) once embedded, so this shell intentionally has no left rail and no
* top header of its own. The session rail sits on the RIGHT, mirroring the
* portal's left sidebar, and the workflow phases ride a slim strip above the chat.
*/
export function AppShell() {
const [panelSession, setPanelSession] = useState<SessionSummary | null>(null);
const {
@@ -53,9 +48,8 @@ export function AppShell() {
resizing: sessionResizing,
separatorProps: sessionSeparatorProps,
} = useSessionPanelResize(containerRef, panelSession !== null);
// Publish the app area's horizontal geometry as CSS vars on <html>: when the app
// is embedded beside the portal's left sidebar, viewport-fixed dialogs (dialog.tsx)
// must center on the ThothII area, not on the whole browser window.
// Publish the app area's horizontal geometry so viewport-fixed dialogs center on
// the application area rather than the whole browser window.
useEffect(() => {
const el = containerRef.current;
if (!el) return;
@@ -101,6 +95,7 @@ export function AppShell() {
const queryClient = useQueryClient();
const [showActivity, setShowActivity] = useState(false);
const [workspaceManagerOpen, setWorkspaceManagerOpen] = useState(false);
const [piManagementOpen, setPiManagementOpen] = useState(false);
const [activeOpen, setActiveOpen] = useState(true);
const [archiveOpen, setArchiveOpen] = useState(false);
const [renameTarget, setRenameTarget] = useState<SessionSummary | null>(null);
@@ -587,7 +582,7 @@ export function AppShell() {
</div>
</div>
{/* Right session rail — symmetric to the portal's left sidebar */}
{/* Right session rail */}
{!showActivity && (
<aside className="flex w-[15vw] shrink-0 flex-col border-l border-border bg-sidebar">
<div className="relative px-4 pb-3 pt-5 text-center">
@@ -618,6 +613,14 @@ export function AppShell() {
>
Workspace management
</Button>
<Button
variant="outline"
size="sm"
className="w-full"
onClick={() => setPiManagementOpen(true)}
>
Pi management
</Button>
</div>
{principal?.isAdmin && (
@@ -769,6 +772,7 @@ export function AppShell() {
</aside>
)}
<WorkspaceManager open={workspaceManagerOpen} onClose={() => setWorkspaceManagerOpen(false)} />
<PiManagement open={piManagementOpen} onClose={() => setPiManagementOpen(false)} />
<Toaster />