WitNote / dashboard /src /components /profiles /ProfileDetailsPanel.tsx
AUXteam's picture
Upload folder using huggingface_hub
6a7089a verified
import { useState, useEffect, useCallback } from "react";
import InstanceLogsPanel from "./InstanceLogsPanel";
import ProfileMetaInfoPanel from "./ProfileMetaInfoPanel";
import ProfileBasicInfoPanel from "./ProfileBasicInfoPanel";
import ProfileLiveViewPanel from "./ProfileLiveViewPanel";
import ProfileToolbar from "./ProfileToolbar";
import { InstanceTabsPanel } from "../tabs";
import { TabsLayout, EmptyView } from "../molecules";
import type { Profile, Instance, InstanceTab } from "../../generated/types";
import * as api from "../../services/api";
interface Props {
profile: Profile | null;
instance?: Instance;
onLaunch: () => void;
onStop?: () => void;
onSave?: (name: string, useWhen: string) => void;
onDelete?: () => void;
}
type TabId = "profile" | "live" | "tabs" | "logs";
export default function ProfileDetailsPanel({
profile,
instance,
onLaunch,
onStop,
onSave,
onDelete,
}: Props) {
const [activeTab, setActiveTab] = useState<TabId>("profile");
const [tabs, setTabs] = useState<InstanceTab[]>([]);
const [formValues, setFormValues] = useState({ name: "", useWhen: "" });
const isRunning = instance?.status === "running";
useEffect(() => {
if (profile) {
setFormValues({ name: profile.name, useWhen: profile.useWhen || "" });
} else {
setTabs([]);
setFormValues({ name: "", useWhen: "" });
}
}, [profile]);
const handleProfileChange = useCallback((name: string, useWhen: string) => {
setFormValues({ name, useWhen });
}, []);
const loadTabs = useCallback(async () => {
if (!instance?.id) {
setTabs([]);
return;
}
try {
const instanceTabs = await api
.fetchInstanceTabs(instance.id)
.catch(() => []);
setTabs(instanceTabs);
} catch (e) {
console.error("Failed to load tabs", e);
}
}, [instance]);
useEffect(() => {
if (activeTab === "live" || activeTab === "tabs" || activeTab === "logs") {
loadTabs();
}
}, [activeTab, loadTabs]);
const handleSave = () => {
onSave?.(formValues.name, formValues.useWhen);
};
if (!profile) {
return (
<div className="dashboard-panel h-full min-h-112">
<EmptyView message="Select a profile to inspect its instance, live tabs, and logs." />
</div>
);
}
const hasChanges =
formValues.name.trim() !== profile.name ||
formValues.useWhen !== (profile.useWhen || "");
const profileTabs: { id: TabId; label: string; badge?: string | number }[] = [
{ id: "profile", label: "Profile" },
{ id: "live", label: "Live" },
{ id: "tabs", label: "Tabs", badge: tabs.length },
{ id: "logs", label: "Logs" },
];
return (
<div className="dashboard-panel flex h-full min-h-112 flex-col overflow-hidden">
<div className="border-b border-border-subtle px-4 py-3 lg:px-5">
<ProfileToolbar
profile={profile}
instance={instance}
onLaunch={onLaunch}
onStop={onStop || (() => {})}
onSave={handleSave}
onDelete={onDelete || (() => {})}
isSaveDisabled={!formValues.name.trim() || !hasChanges}
/>
</div>
<div className="min-h-0 flex-1 overflow-hidden">
<TabsLayout
tabs={profileTabs}
activeTab={activeTab}
onChange={(id) => setActiveTab(id)}
>
{activeTab === "profile" && (
<div className="h-full overflow-auto">
<div className="grid gap-4 xl:grid-cols-2">
<ProfileBasicInfoPanel
profile={profile}
onChange={handleProfileChange}
/>
<ProfileMetaInfoPanel profile={profile} instance={instance} />
</div>
</div>
)}
{activeTab === "live" && (
<ProfileLiveViewPanel
instance={instance}
tabs={tabs}
isRunning={isRunning}
/>
)}
{activeTab === "tabs" && (
<div className="flex h-full min-h-0 flex-col">
<InstanceTabsPanel
tabs={tabs}
instanceId={instance?.id}
emptyMessage={
isRunning ? "No tabs open." : "Instance not running."
}
/>
</div>
)}
{activeTab === "logs" && (
<InstanceLogsPanel instanceId={instance?.id} />
)}
</TabsLayout>
</div>
</div>
);
}