feat/renaming files

This commit is contained in:
Douglas 2026-06-17 16:31:01 +01:00
parent 97d7554438
commit 58dbd49f5e
53 changed files with 330 additions and 330 deletions

View file

@ -22,7 +22,7 @@ type Props = {
};
};
export default function FolderComponent({ selectedFile }: Props) {
export default function ContextComponent({ selectedFile }: Props) {
const sanitizedHtml = useMemo(() => {
const raw = selectedFile?.content || '';
if (!raw) return '';

View file

@ -51,7 +51,7 @@ import {
useRef,
useState,
} from 'react';
import FolderComponent from './FolderComponent';
import ContextComponent from './ContextComponent';
import { fetchGet, getBaseURL } from '@/api/http';
import { MarkDown } from '@/components/ChatBox/MessageItem/MarkDown';
@ -530,14 +530,14 @@ export const FileTree: React.FC<FileTreeProps> = ({
onSelectFile(fileInfo);
}
}}
className={`mb-1 flex w-full min-w-0 flex-row items-center justify-start gap-2 rounded-lg px-2 py-1.5 text-left transition-colors hover:bg-ds-bg-neutral-subtle-hover ${
className={`mb-1 min-w-0 gap-2 rounded-lg px-2 py-1.5 hover:bg-ds-bg-neutral-subtle-hover flex w-full flex-row items-center justify-start text-left transition-colors ${
isRowSelected
? 'bg-ds-bg-neutral-default-default text-ds-text-neutral-default-default'
: 'bg-transparent text-ds-text-neutral-muted-default'
: 'text-ds-text-neutral-muted-default bg-transparent'
}`}
>
{child.isFolder ? (
<span className="inline-flex w-4 shrink-0 items-center justify-start">
<span className="w-4 inline-flex shrink-0 items-center justify-start">
{isExpanded ? (
<ChevronDown className={rowIconClass} />
) : (
@ -556,13 +556,13 @@ export const FileTree: React.FC<FileTreeProps> = ({
)
)}
<span className="min-w-0 flex-1 truncate text-left text-body-sm font-medium leading-normal">
<span className="min-w-0 text-body-sm font-medium leading-normal flex-1 truncate text-left">
{child.name}
</span>
</button>
{hasNested ? (
<div className="ml-4 border-y-0 border-l border-r-0 border-solid border-ds-border-neutral-subtle-default pl-1">
<div className="ml-4 border-ds-border-neutral-subtle-default pl-1 border-y-0 border-r-0 border-l border-solid">
<FileTree
node={child}
level={level + 1}
@ -1598,15 +1598,15 @@ export default function Folder({ data: _data }: { data?: Agent }) {
return (
<div className="flex h-full w-full flex-col overflow-hidden">
{/* header */}
<div className="border-b-1 flex w-full shrink-0 items-center gap-2 border-x-0 border-t-0 border-solid border-ds-border-neutral-subtle-default p-2">
<div className="flex min-w-0 max-w-[min(20rem,45%)] items-center">
<div className="gap-2 border-ds-border-neutral-subtle-default p-2 flex w-full shrink-0 items-center border-x-0 border-t-0 border-b-1 border-solid">
<div className="min-w-0 flex max-w-[min(20rem,45%)] items-center">
<Button
type="button"
variant="ghost"
size="sm"
buttonContent="icon-only"
aria-pressed={isFileSidebarOpen}
className="shrink-0 text-ds-icon-neutral-default-default"
className="text-ds-icon-neutral-default-default shrink-0"
aria-label={
isFileSidebarOpen
? t('chat.hide-file-sidebar', {
@ -1634,21 +1634,21 @@ export default function Folder({ data: _data }: { data?: Agent }) {
)}
</Button>
<span
className="min-w-0 truncate text-body-sm font-semibold leading-none text-ds-text-neutral-default-default"
className="min-w-0 text-body-sm font-semibold text-ds-text-neutral-default-default truncate leading-none"
title={folderHeaderTitle}
>
{folderHeaderTitle}
</span>
</div>
<div className="ml-auto flex min-w-0 items-center gap-2">
<div className="relative h-7 w-32 min-w-[10rem] max-w-xs shrink-0 rounded-lg">
<Search className="pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-ds-text-brand-default-default" />
<div className="min-w-0 gap-2 ml-auto flex items-center">
<div className="h-7 w-32 max-w-xs rounded-lg relative min-w-[10rem] shrink-0">
<Search className="left-2 h-3.5 w-3.5 text-ds-text-brand-default-default pointer-events-none absolute top-1/2 -translate-y-1/2" />
<input
type="text"
value={fileSearchQuery}
onChange={(e) => setFileSearchQuery(e.target.value)}
placeholder={t('chat.search')}
className="h-7 w-full rounded-lg border border-solid border-ds-border-neutral-subtle-default py-0 pl-7 pr-2 text-sm leading-none focus:outline-none focus:ring-2 focus:ring-ds-ring-brand-default-focus focus:ring-offset-0"
className="h-7 rounded-lg border-ds-border-neutral-subtle-default py-0 pl-7 pr-2 text-sm focus:ring-ds-ring-brand-default-focus w-full border border-solid leading-none focus:ring-2 focus:ring-offset-0 focus:outline-none"
aria-label={t('chat.search')}
/>
</div>
@ -1669,18 +1669,18 @@ export default function Folder({ data: _data }: { data?: Agent }) {
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="z-50 border-ds-border-neutral-default-default bg-ds-bg-neutral-strong-default"
className="border-ds-border-neutral-default-default bg-ds-bg-neutral-strong-default z-50"
>
<DropdownMenuItem
onClick={() => handleOpenInIDE('system')}
className="cursor-pointer bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover"
className="bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover cursor-pointer"
>
<FolderIcon className="size-4 shrink-0" aria-hidden />
{t('chat.open-in-file-manager')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleOpenInIDE('cursor')}
className="cursor-pointer bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover"
className="bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover cursor-pointer"
>
<img
src={cursorIcon}
@ -1692,7 +1692,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleOpenInIDE('vscode')}
className="cursor-pointer bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover"
className="bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover cursor-pointer"
>
<img
src={vsCodeIcon}
@ -1708,11 +1708,11 @@ export default function Folder({ data: _data }: { data?: Agent }) {
</div>
</div>
<div className="flex min-h-0 flex-1 overflow-hidden">
<div className="min-h-0 flex flex-1 overflow-hidden">
{/* sidebar */}
{isFileSidebarOpen ? (
<div className="flex h-full w-64 flex-shrink-0 flex-col border-y-0 border-l-0 border-r border-solid border-ds-border-neutral-subtle-default">
<div className="flex h-8 items-center px-1">
<div className="w-64 border-ds-border-neutral-subtle-default flex h-full flex-shrink-0 flex-col border-y-0 border-r border-l-0 border-solid">
<div className="h-8 px-1 flex items-center">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
@ -1721,7 +1721,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
size="sm"
buttonContent="text"
>
<span className="min-w-0 truncate text-left font-bold">
<span className="min-w-0 font-bold truncate text-left">
{t('chat.files')}
</span>
<ChevronDown className="size-3.5 shrink-0 opacity-70" />
@ -1730,7 +1730,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
<DropdownMenuContent
side="bottom"
align="start"
className="z-50 min-w-[10rem] border-ds-border-neutral-default-default bg-ds-bg-neutral-strong-default"
className="border-ds-border-neutral-default-default bg-ds-bg-neutral-strong-default z-50 min-w-[10rem]"
>
<DropdownMenuRadioGroup
value={fileTreeScope}
@ -1740,7 +1740,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
>
<DropdownMenuRadioItem
value="all"
className="cursor-pointer bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover"
className="bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover cursor-pointer"
>
{t('folder.files-scope-all', {
defaultValue: 'All files',
@ -1748,7 +1748,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
</DropdownMenuRadioItem>
<DropdownMenuRadioItem
value="new"
className="cursor-pointer bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover"
className="bg-dropdown-item-bg-default hover:bg-dropdown-item-bg-hover cursor-pointer"
>
{t('folder.files-scope-new', {
defaultValue: 'New files',
@ -1759,7 +1759,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
</DropdownMenu>
</div>
<div className="scrollbar-always-visible min-h-0 flex-1 overflow-y-auto">
<div className="h-full pl-1.5">
<div className="pl-1.5 h-full">
<FileTree
node={sidebarFileTree}
selectedFile={selectedFile}
@ -1776,10 +1776,10 @@ export default function Folder({ data: _data }: { data?: Agent }) {
) : null}
{/* content */}
<div className="flex min-w-0 flex-1 flex-col overflow-hidden bg-ds-bg-neutral-subtle-default">
<div className="min-w-0 bg-ds-bg-neutral-subtle-default flex flex-1 flex-col overflow-hidden">
{/* head */}
{selectedFile && (
<div className="flex h-8 flex-shrink-0 items-center justify-between gap-2 pl-3 pr-2">
<div className="h-8 gap-2 pl-3 pr-2 flex flex-shrink-0 items-center justify-between">
<div
onClick={() => {
// if file is remote, don't call reveal-in-folder
@ -1789,10 +1789,10 @@ export default function Folder({ data: _data }: { data?: Agent }) {
}
ipcRenderer?.invoke('reveal-in-folder', selectedFile.path);
}}
className="flex min-w-0 flex-1 cursor-pointer items-center overflow-hidden"
className="min-w-0 flex flex-1 cursor-pointer items-center overflow-hidden"
>
<nav
className="scrollbar-always-visible flex min-w-0 max-w-full items-center gap-1 overflow-x-auto text-body-sm text-ds-text-neutral-muted-default"
className="scrollbar-always-visible min-w-0 gap-1 text-body-sm text-ds-text-neutral-muted-default flex max-w-full items-center overflow-x-auto"
aria-label={t('folder.file-path-breadcrumb', {
defaultValue: 'File path',
})}
@ -1803,15 +1803,15 @@ export default function Folder({ data: _data }: { data?: Agent }) {
<Fragment key={`${index}-${segment}`}>
{index > 0 ? (
<ChevronRight
className="h-3.5 w-3.5 shrink-0 text-ds-icon-neutral-muted-default"
className="h-3.5 w-3.5 text-ds-icon-neutral-muted-default shrink-0"
aria-hidden
/>
) : null}
<span
className={
isLast
? 'shrink-0 font-bold text-ds-text-neutral-default-default'
: 'shrink-0 font-normal'
? 'font-bold text-ds-text-neutral-default-default shrink-0'
: 'font-normal shrink-0'
}
>
{segment}
@ -1821,7 +1821,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
})}
</nav>
</div>
<div className="flex flex-shrink-0 items-center gap-0.5">
<div className="gap-0.5 flex flex-shrink-0 items-center">
<Button
size="icon"
variant="ghost"
@ -1850,7 +1850,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
{/* content */}
<div
className={`flex min-h-0 flex-1 flex-col ${
className={`min-h-0 flex flex-1 flex-col ${
selectedFile?.type === 'html' && !isShowSourceCode
? 'overflow-hidden'
: 'scrollbar-always-visible overflow-y-auto'
@ -1859,8 +1859,8 @@ export default function Folder({ data: _data }: { data?: Agent }) {
<div
className={`flex flex-col ${
selectedFile?.type === 'html' && !isShowSourceCode
? 'h-full min-h-0'
: 'min-h-full py-2 pl-4 pr-2'
? 'min-h-0 h-full'
: 'py-2 pl-4 pr-2 min-h-full'
} file-viewer-content`}
>
{selectedFile ? (
@ -1886,7 +1886,7 @@ export default function Folder({ data: _data }: { data?: Agent }) {
) : ['csv', 'doc', 'docx', 'pptx', 'xlsx'].includes(
selectedFile.type
) ? (
<FolderComponent selectedFile={selectedFile} />
<ContextComponent selectedFile={selectedFile} />
) : selectedFile.type === 'html' ? (
isShowSourceCode ? (
<>{selectedFile.content}</>
@ -1897,9 +1897,9 @@ export default function Folder({ data: _data }: { data?: Agent }) {
/>
)
) : selectedFile.type === 'zip' ? (
<div className="flex h-full w-full items-center justify-center text-ds-text-neutral-muted-default">
<div className="text-ds-text-neutral-muted-default flex h-full w-full items-center justify-center">
<div className="text-center">
<FileText className="mx-auto mb-4 h-12 w-12 text-ds-text-neutral-muted-default" />
<FileText className="mb-4 h-12 w-12 text-ds-text-neutral-muted-default mx-auto" />
<p className="text-sm">
{t('folder.zip-file-is-not-supported-yet')}
</p>
@ -1918,14 +1918,14 @@ export default function Folder({ data: _data }: { data?: Agent }) {
<ImageLoader selectedFile={selectedFile} />
</div>
) : (
<pre className="overflow-auto whitespace-pre-wrap break-words font-mono text-sm text-ds-text-neutral-default-default">
<pre className="font-mono text-sm text-ds-text-neutral-default-default overflow-auto break-words whitespace-pre-wrap">
{selectedFile.content}
</pre>
)
) : (
<div className="flex h-full w-full items-center justify-center">
<div className="text-center">
<div className="mx-auto mb-4 h-8 w-8 animate-spin rounded-full"></div>
<div className="mb-4 h-8 w-8 animate-spin mx-auto rounded-full"></div>
<p className="text-body-sm text-ds-text-neutral-muted-default">
{t('chat.loading')}
</p>
@ -1933,9 +1933,9 @@ export default function Folder({ data: _data }: { data?: Agent }) {
</div>
)
) : (
<div className="flex h-full w-full flex-1 items-center justify-center text-ds-text-neutral-muted-default">
<div className="text-ds-text-neutral-muted-default flex h-full w-full flex-1 items-center justify-center">
<div className="text-center">
<FileText className="mx-auto mb-4 h-12 w-12 text-ds-text-neutral-muted-default" />
<FileText className="mb-4 h-12 w-12 text-ds-text-neutral-muted-default mx-auto" />
<p className="text-sm">
{t('chat.select-a-file-to-view-its-contents')}
</p>
@ -2029,7 +2029,7 @@ function ImageLoader({ selectedFile }: { selectedFile: FileInfo }) {
if (!src) {
return (
<div className="flex h-full w-full items-center justify-center">
<div className="mx-auto h-8 w-8 animate-spin rounded-full" />
<div className="h-8 w-8 animate-spin mx-auto rounded-full" />
</div>
);
}
@ -2058,7 +2058,7 @@ function AudioLoader({ selectedFile }: { selectedFile: FileInfo }) {
}, [selectedFile]);
return (
<div className="flex w-full flex-col items-center gap-4 px-8">
<div className="gap-4 px-8 flex w-full flex-col items-center">
<p className="text-sm font-medium text-ds-text-neutral-default-default">
{selectedFile.name}
</p>
@ -2948,7 +2948,7 @@ function HtmlRenderer({
if (selectedFile.content && !processedHtml) {
return (
<div className="flex h-full w-full items-center justify-center">
<div className="mx-auto mb-4 h-8 w-8 animate-spin rounded-full" />
<div className="mb-4 h-8 w-8 animate-spin mx-auto rounded-full" />
</div>
);
}
@ -2965,7 +2965,7 @@ function HtmlRenderer({
{/* Content area with zoom */}
<div
className="min-h-0 flex-1 overflow-hidden bg-code-surface"
className="min-h-0 bg-code-surface flex-1 overflow-hidden"
onWheel={handleWheel}
>
<div

View file

@ -16,7 +16,7 @@ import larkIcon from '@/assets/icon/lark.png';
import telegramIcon from '@/assets/icon/telegram.svg';
import whatsappIcon from '@/assets/icon/whatsapp.svg';
import { isDesktop } from '@/client/platform';
import { SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS } from '@/components/Session/sessionSidePanelLayout';
import { PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS } from '@/components/Project/projectSidePanelLayout';
import { Button } from '@/components/ui/button';
import {
createRemoteControlSession,
@ -77,15 +77,15 @@ function BentoSessionGrid({
if (count === 1) {
return (
<div className="flex h-full min-h-0 w-full flex-col">
<div className="h-1/2 min-h-0 w-full">{renderCard(sessions[0])}</div>
<div className="min-h-0 flex h-full w-full flex-col">
<div className="min-h-0 h-1/2 w-full">{renderCard(sessions[0])}</div>
</div>
);
}
if (count === 2) {
return (
<div className="flex h-full min-h-0 w-full flex-col gap-3">
<div className="min-h-0 gap-3 flex h-full w-full flex-col">
{sessions.map((session) => (
<div key={session.sessionId} className="min-h-0 flex-1">
{renderCard(session)}
@ -103,7 +103,7 @@ function BentoSessionGrid({
return (
<div className={gridClassName}>
{sessions.map((session) => (
<div key={session.sessionId} className="h-full min-h-0">
<div key={session.sessionId} className="min-h-0 h-full">
{renderCard(session)}
</div>
))}
@ -121,14 +121,14 @@ function BentoCard({
const { t } = useTranslation();
return (
<div className="flex h-full min-h-0 flex-col gap-2 rounded-2xl border border-ds-border-neutral-subtle-default bg-ds-bg-neutral-default-default p-3">
<div className="min-h-0 gap-2 rounded-2xl border-ds-border-neutral-subtle-default bg-ds-bg-neutral-default-default p-3 flex h-full flex-col border">
{/* Header */}
<div className="flex min-w-0 items-center gap-2">
<div className="min-w-0 gap-2 flex items-center">
<MonitorSmartphone
className="h-4 w-4 shrink-0 text-ds-text-neutral-muted-default"
className="h-4 w-4 text-ds-text-neutral-muted-default shrink-0"
aria-hidden
/>
<span className="min-w-0 flex-1 truncate text-body-sm font-semibold text-ds-text-neutral-default-default">
<span className="min-w-0 text-body-sm font-semibold text-ds-text-neutral-default-default flex-1 truncate">
{session.title}
</span>
<Button
@ -136,7 +136,7 @@ function BentoCard({
variant="primary"
size="xs"
buttonContent="text"
className="no-drag shrink-0 gap-1.5"
className="no-drag gap-1.5 shrink-0"
onClick={onCopy}
>
<Copy className="h-3 w-3" aria-hidden />
@ -148,7 +148,7 @@ function BentoCard({
tone="error"
size="xs"
buttonContent="text"
className="no-drag shrink-0 gap-1"
className="no-drag gap-1 shrink-0"
disabled={stopping}
onClick={onStop}
>
@ -162,7 +162,7 @@ function BentoCard({
</div>
{/* Log */}
<div className="min-h-0 flex-1 border-t border-ds-border-neutral-subtle-default pt-2">
<div className="min-h-0 border-ds-border-neutral-subtle-default pt-2 flex-1 border-t">
<LogPanel logs={logs} />
</div>
</div>
@ -195,8 +195,8 @@ function ChannelRow({
return (
<div
className={cn(
'group/row flex h-[44px] w-full cursor-default select-none items-center gap-3 rounded-xl',
'border border-transparent bg-ds-bg-neutral-default-default px-3',
'group/row gap-3 rounded-xl flex h-[44px] w-full cursor-default items-center select-none',
'bg-ds-bg-neutral-default-default px-3 border border-transparent',
'transition-colors duration-150',
!disabled && 'hover:border-ds-border-neutral-subtle-default',
hasActiveSessions && 'border-ds-border-neutral-subtle-default',
@ -214,20 +214,20 @@ function ChannelRow({
/>
)}
</div>
<span className="flex-1 truncate text-body-sm font-medium text-ds-text-neutral-default-default">
<span className="text-body-sm font-medium text-ds-text-neutral-default-default flex-1 truncate">
{name}
</span>
{/* Right slot — always the same reserved width so all rows stay the same height */}
<div className="flex h-6 w-[72px] shrink-0 items-center justify-end">
<div className="h-6 flex w-[72px] shrink-0 items-center justify-end">
{comingSoon && (
<span className="shrink-0 rounded-full bg-ds-bg-neutral-muted-default px-2 py-0.5 text-label-xs text-ds-text-neutral-muted-default">
<span className="bg-ds-bg-neutral-muted-default px-2 py-0.5 text-label-xs text-ds-text-neutral-muted-default shrink-0 rounded-full">
{t('layout.dispatch-coming-soon', { defaultValue: 'Coming soon' })}
</span>
)}
{!disabled && !comingSoon && hasActiveSessions && (
<span className="shrink-0 rounded-full bg-ds-bg-success-subtle-default px-2 py-0.5 text-label-xs text-ds-text-success-strong-default">
<span className="bg-ds-bg-success-subtle-default px-2 py-0.5 text-label-xs text-ds-text-success-strong-default shrink-0 rounded-full">
{t('layout.dispatch-connected', { defaultValue: 'Connected' })}
</span>
)}
@ -238,7 +238,7 @@ function ChannelRow({
variant="secondary"
size="xs"
buttonContent="text"
className="no-drag shrink-0 gap-1"
className="no-drag gap-1 shrink-0"
disabled={loading}
onClick={onStart}
>
@ -286,12 +286,12 @@ function LogPanel({ logs }: { logs: RemoteControlLogEntry[] }) {
{[...logs].reverse().map((entry) => (
<div
key={entry.id}
className="flex min-w-0 items-center gap-3 px-1 py-1.5 text-label-xs"
className="min-w-0 gap-3 px-1 py-1.5 text-label-xs flex items-center"
>
<span className="w-[72px] shrink-0 tabular-nums text-ds-text-neutral-muted-default">
<span className="text-ds-text-neutral-muted-default w-[72px] shrink-0 tabular-nums">
{formatLogTime(entry.time)}
</span>
<span className="min-w-0 flex-1 truncate text-ds-text-neutral-default-default">
<span className="min-w-0 text-ds-text-neutral-default-default flex-1 truncate">
{entry.name}
</span>
<span
@ -538,14 +538,14 @@ export function WorkspaceDispatch() {
);
const channelList = (
<div className="flex w-full flex-col gap-1">
<div className="gap-1 flex w-full flex-col">
<ChannelRow
name={t('layout.workspace-work-with-remote-control', {
defaultValue: 'Remote Control',
})}
icon={
<MonitorSmartphone
className="h-4 w-4 shrink-0 text-ds-text-neutral-muted-default"
className="h-4 w-4 text-ds-text-neutral-muted-default shrink-0"
aria-hidden
/>
}
@ -554,7 +554,7 @@ export function WorkspaceDispatch() {
onStart={() => void handleCreateRemoteControl()}
/>
<div className="mx-1 border-t border-ds-border-neutral-subtle-default" />
<div className="mx-1 border-ds-border-neutral-subtle-default border-t" />
<ChannelRow
name={t('layout.channels-telegram', { defaultValue: 'Telegram' })}
@ -578,28 +578,28 @@ export function WorkspaceDispatch() {
);
return (
<div className="flex h-full min-h-0 w-full flex-col overflow-hidden">
<div className="min-h-0 flex h-full w-full flex-col overflow-hidden">
{/* Header */}
<div className="border-b-1 box-border flex h-[45.5px] w-full shrink-0 items-center gap-2 border-x-0 border-t-0 border-solid border-ds-border-neutral-subtle-default px-3">
<div className="gap-2 border-ds-border-neutral-subtle-default px-3 box-border flex h-[45.5px] w-full shrink-0 items-center border-x-0 border-t-0 border-b-1 border-solid">
<span className="text-body-md font-bold text-ds-text-neutral-muted-default">
{t('layout.workspace-work-with-title', { defaultValue: 'Work with' })}
</span>
</div>
{/* Body */}
<div className="relative flex min-h-0 w-full flex-1 overflow-hidden">
<div className="min-h-0 relative flex w-full flex-1 overflow-hidden">
{/* Centered default state */}
<AnimatePresence initial={false}>
{!hasSessions && (
<motion.div
key="centered"
className="absolute inset-0 flex items-start justify-center overflow-y-auto p-6"
className="inset-0 p-6 absolute flex items-start justify-center overflow-y-auto"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0, transition: { duration: 0.15 } }}
transition={{ duration: 0.2 }}
>
<div className="w-full max-w-xl">{channelList}</div>
<div className="max-w-xl w-full">{channelList}</div>
</motion.div>
)}
</AnimatePresence>
@ -609,14 +609,14 @@ export function WorkspaceDispatch() {
{hasSessions && (
<motion.div
key="split"
className="absolute inset-0 flex overflow-hidden"
className="inset-0 absolute flex overflow-hidden"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0, transition: { duration: 0.15 } }}
transition={{ duration: 0.2 }}
>
{/* Left column: dynamic bento layout by session count */}
<div className="flex min-h-0 flex-1 flex-col overflow-hidden p-3">
<div className="min-h-0 p-3 flex flex-1 flex-col overflow-hidden">
<BentoSessionGrid
sessions={activeSessions}
logs={logs}
@ -629,8 +629,8 @@ export function WorkspaceDispatch() {
{/* Right panel — same width as session side panel */}
<motion.div
className={cn(
'flex shrink-0 flex-col gap-1 overflow-y-auto border-l border-ds-border-neutral-subtle-default p-3',
SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS
'gap-1 border-ds-border-neutral-subtle-default p-3 flex shrink-0 flex-col overflow-y-auto border-l',
PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS
)}
initial={{ x: 40, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}

View file

@ -82,8 +82,8 @@ export function NavTabReconnectSuffix({
<button
type="button"
className={cn(
'no-drag flex h-8 w-8 shrink-0 items-center justify-center rounded-xl text-ds-icon-neutral-muted-default outline-none transition-colors hover:bg-ds-bg-neutral-strong-default',
'focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ds-ring-neutral-subtle-default'
'no-drag h-8 w-8 rounded-xl text-ds-icon-neutral-muted-default hover:bg-ds-bg-neutral-strong-default flex shrink-0 items-center justify-center transition-colors outline-none',
'focus-visible:ring-ds-ring-neutral-subtle-default focus-visible:z-10 focus-visible:ring-2 focus-visible:outline-none'
)}
aria-label={reconnectLabel}
onClick={(e) => {
@ -163,7 +163,7 @@ function tabMainInner({
<>
{leading}
<motion.div
className="flex min-w-0 flex-1 items-center gap-3 overflow-hidden"
className="min-w-0 gap-3 flex flex-1 items-center overflow-hidden"
initial={false}
animate={{
opacity: folded ? 0 : 1,
@ -267,7 +267,7 @@ export function NavTab({
</button>
{suffix || endAction ? (
<motion.div
className="flex min-h-8 min-w-0 items-stretch overflow-hidden"
className="min-h-8 min-w-0 flex items-stretch overflow-hidden"
initial={false}
animate={{
opacity: folded ? 0 : 1,
@ -281,7 +281,7 @@ export function NavTab({
{endAction ? (
<div
className={cn(
'flex max-w-0 shrink-0 items-center justify-end overflow-hidden opacity-0 transition-[max-width,opacity] duration-150 ease-out',
'max-w-0 ease-out flex shrink-0 items-center justify-end overflow-hidden opacity-0 transition-[max-width,opacity] duration-150',
'pointer-events-none opacity-0',
'group-hover:pointer-events-auto group-hover:opacity-100',
endActionMaxWidthClass ??

View file

@ -15,7 +15,7 @@
import {
NavListSessionRows,
type NavListSession,
} from '@/components/ProjectPageSidebar/NavList';
} from '@/components/PageSidebar/NavList';
import { Button } from '@/components/ui/button';
import { TooltipSimple } from '@/components/ui/tooltip';
import { taskIdToCreatedMs } from '@/lib/chatTaskIdTime';
@ -30,7 +30,7 @@ import { useTranslation } from 'react-i18next';
export { default as SessionWorkspace } from '.';
type SessionsProps = {
type ProjectGroupProps = {
className?: string;
tasks: ChatStore['tasks'];
activeSessionId?: string | null;
@ -38,13 +38,13 @@ type SessionsProps = {
onDeleteSession: (sessionId: string) => void;
};
export default function Sessions({
export default function ProjectGroup({
className,
tasks,
activeSessionId,
onSelectSession,
onDeleteSession,
}: SessionsProps) {
}: ProjectGroupProps) {
const { t } = useTranslation();
const setActiveWorkspaceTab = usePageTabStore((s) => s.setActiveWorkspaceTab);
const backToWorkspaceTooltip = t('layout.back-to-workspace-tooltip');
@ -73,11 +73,11 @@ export default function Sessions({
return (
<div
className={cn(
'flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden',
'min-h-0 min-w-0 flex h-full w-full flex-col overflow-hidden',
className
)}
>
<div className="border-b-1 flex w-full shrink-0 items-center gap-2 border-x-0 border-t-0 border-solid border-ds-border-neutral-subtle-default px-2 py-2">
<div className="gap-2 border-ds-border-neutral-subtle-default px-2 py-2 flex w-full shrink-0 items-center border-x-0 border-t-0 border-b-1 border-solid">
<TooltipSimple content={backToWorkspaceTooltip}>
<Button
type="button"
@ -85,19 +85,19 @@ export default function Sessions({
size="sm"
buttonContent="icon-only"
onClick={() => setActiveWorkspaceTab('workforce')}
className="no-drag shrink-0 text-ds-text-neutral-muted-default hover:bg-ds-bg-neutral-strong-default"
className="no-drag text-ds-text-neutral-muted-default hover:bg-ds-bg-neutral-strong-default shrink-0"
aria-label={backToWorkspaceTooltip}
>
<ArrowLeft className="h-4 w-4" aria-hidden />
</Button>
</TooltipSimple>
<div className="flex min-w-0 flex-1 items-center gap-2 px-1 text-body-md font-bold text-ds-text-neutral-default-default">
<div className="min-w-0 gap-2 px-1 text-body-md font-bold text-ds-text-neutral-default-default flex flex-1 items-center">
<span className="truncate">{t('layout.sessions-full-title')}</span>
</div>
</div>
<div className="m-0 mx-auto flex min-h-0 w-full max-w-[800px] flex-1 flex-col gap-0.5 overflow-y-auto p-2">
<div className="m-0 min-h-0 gap-0.5 p-2 mx-auto flex w-full max-w-[800px] flex-1 flex-col overflow-y-auto">
{sessions.length === 0 ? (
<p className="m-0 px-3 py-6 text-center text-body-sm text-ds-text-neutral-muted-default">
<p className="m-0 px-3 py-6 text-body-sm text-ds-text-neutral-muted-default text-center">
{t('layout.sessions-create-task-hint')}
</p>
) : (

View file

@ -12,12 +12,12 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { SessionSidePanelHeader } from '@/components/Session/SessionSidePanelHeader';
import { SingleAgentSidePanel } from '@/components/Session/SingleAgent/SingleAgentSidePanel';
import { TurnTabs } from '@/components/Session/TurnTabs';
import { WorkforceSidePanel } from '@/components/Session/Workforce/WorkforceSidePanel';
import { WorkforceSidePanelHeaderEnd } from '@/components/Session/Workforce/WorkforceSidePanelHeaderEnd';
import { SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS } from '@/components/Session/sessionSidePanelLayout';
import { ProjectSidePanelHeader } from '@/components/Project/ProjectSidePanelHeader';
import { SingleAgentSidePanel } from '@/components/Project/SingleAgent/SingleAgentSidePanel';
import { TurnTabs } from '@/components/Project/TurnTabs';
import { WorkforceSidePanel } from '@/components/Project/Workforce/WorkforceSidePanel';
import { WorkforceSidePanelHeaderEnd } from '@/components/Project/Workforce/WorkforceSidePanelHeaderEnd';
import { PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS } from '@/components/Project/projectSidePanelLayout';
import { TooltipSimple } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
import { SessionMode, type SessionModeType } from '@/types/constants';
@ -35,7 +35,7 @@ export interface SessionSidePanelProps {
onCloseExpandedOverlay: () => void;
}
export function SessionSidePanel({
export function ProjectSidePanel({
mode,
workforcePanelKey,
hasAnyMessages,
@ -68,12 +68,12 @@ export function SessionSidePanel({
<div
className={cn(
'min-h-0 flex h-full flex-shrink-0 flex-col overflow-hidden',
SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS,
PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS,
isFolded &&
'pointer-events-none opacity-40 transition-opacity duration-200 group-hover:opacity-80'
)}
>
<SessionSidePanelHeader
<ProjectSidePanelHeader
title={headerTitle}
mode={mode}
isSidePanelVisible={isSidePanelVisible}

View file

@ -19,19 +19,19 @@ import type { SessionModeType } from '@/types/constants';
import { PanelRight, PanelRightClose } from 'lucide-react';
import { useTranslation } from 'react-i18next';
export interface SessionSidePanelFoldButtonProps {
export interface ProjectSidePanelFoldButtonProps {
sessionSidePanelMode: SessionModeType;
isSidePanelVisible: boolean;
onToggle: () => void;
className?: string;
}
export function SessionSidePanelFoldButton({
export function ProjectSidePanelFoldButton({
sessionSidePanelMode,
isSidePanelVisible,
onToggle,
className,
}: SessionSidePanelFoldButtonProps) {
}: ProjectSidePanelFoldButtonProps) {
const { t } = useTranslation();
const sessionSidePanelTooltip =
sessionSidePanelMode === 'single-agent'

View file

@ -12,11 +12,11 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { SessionSidePanelFoldButton } from '@/components/Session/SessionSidePanelFoldButton';
import { ProjectSidePanelFoldButton } from '@/components/Project/ProjectSidePanelFoldButton';
import type { SessionModeType } from '@/types/constants';
import type { ReactNode } from 'react';
export interface SessionSidePanelHeaderProps {
export interface ProjectSidePanelHeaderProps {
title: string;
mode: SessionModeType;
isSidePanelVisible: boolean;
@ -27,18 +27,18 @@ export interface SessionSidePanelHeaderProps {
end?: ReactNode;
}
export function SessionSidePanelHeader({
export function ProjectSidePanelHeader({
title,
mode,
isSidePanelVisible,
onToggle,
start,
end,
}: SessionSidePanelHeaderProps) {
}: ProjectSidePanelHeaderProps) {
return (
<div className="p-2 min-w-0 relative z-50 flex w-full shrink-0 items-center">
<div className="min-w-0 gap-1 flex flex-1 items-center justify-start">
<SessionSidePanelFoldButton
<ProjectSidePanelFoldButton
sessionSidePanelMode={mode}
isSidePanelVisible={isSidePanelVisible}
onToggle={onToggle}

View file

@ -12,8 +12,8 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { SidePanelAccordionBox } from '@/components/Session/SidePanelAccordionBox';
import { SidePanelListRow } from '@/components/Session/SidePanelSections/primitives';
import { SidePanelAccordionBox } from '@/components/Project/SidePanelAccordionBox';
import { SidePanelListRow } from '@/components/Project/SidePanelSections/primitives';
import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion';
import {

View file

@ -12,7 +12,7 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { SidePanelAccordionBox } from '@/components/Session/SidePanelAccordionBox';
import { SidePanelAccordionBox } from '@/components/Project/SidePanelAccordionBox';
import ShinyText from '@/components/ui/ShinyText/ShinyText';
import { agentMap, type WorkflowAgentType } from '@/components/WorkFlow/agents';
import { getToolkitIcon } from '@/lib/toolkitIcons';

View file

@ -12,11 +12,11 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { SidePanelAccordionBox } from '@/components/Session/SidePanelAccordionBox';
import { SidePanelAccordionBox } from '@/components/Project/SidePanelAccordionBox';
import {
CategoryLabel,
SidePanelListRow,
} from '@/components/Session/SidePanelSections/primitives';
} from '@/components/Project/SidePanelSections/primitives';
import { AnimatePresence, motion } from 'framer-motion';
import type { ReactNode } from 'react';
import { useMemo } from 'react';

View file

@ -12,13 +12,13 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { SidePanelAccordionBox } from '@/components/Session/SidePanelAccordionBox';
import { SidePanelAccordionBox } from '@/components/Project/SidePanelAccordionBox';
import {
CountPill,
ProgressCircle,
ProgressConnector,
SidePanelListRow,
} from '@/components/Session/SidePanelSections/primitives';
} from '@/components/Project/SidePanelSections/primitives';
import { cn } from '@/lib/utils';
import { usePageTabStore } from '@/store/pageTabStore';
import { TaskStatus } from '@/types/constants';

View file

@ -12,15 +12,15 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { AgentFolderSection } from '@/components/Session/SidePanelSections/AgentFolderSection';
import { ExecutionContextSection } from '@/components/Session/SidePanelSections/ExecutionContextSection';
import { ProgressSection } from '@/components/Session/SidePanelSections/ProgressSection';
import { buildContextItems } from '@/components/Session/SidePanelSections/buildContextItems';
import { AgentFolderSection } from '@/components/Project/SidePanelSections/AgentFolderSection';
import { ExecutionContextSection } from '@/components/Project/SidePanelSections/ExecutionContextSection';
import { ProgressSection } from '@/components/Project/SidePanelSections/ProgressSection';
import { buildContextItems } from '@/components/Project/SidePanelSections/buildContextItems';
import {
collectSidePanelOutputFiles,
mergeSidePanelOutputFiles,
} from '@/components/Session/SidePanelSections/collectSidePanelOutputFiles';
import { useProjectOutputFiles } from '@/components/Session/SidePanelSections/useProjectOutputFiles';
} from '@/components/Project/SidePanelSections/collectSidePanelOutputFiles';
import { useProjectOutputFiles } from '@/components/Project/SidePanelSections/useProjectOutputFiles';
import useChatStoreAdapter from '@/hooks/useChatStoreAdapter';
import { useSelectedProjectTurn } from '@/hooks/useSelectedProjectTurn';
import { cn } from '@/lib/utils';

View file

@ -12,11 +12,11 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import BrowserAgentWorkspace from '@/components/BrowserAgentWorkspace';
import Folder from '@/components/Folder';
import TerminalAgentWorkspace from '@/components/TerminalAgentWorkspace';
import Context from '@/components/Context';
import Workflow from '@/components/WorkFlow';
import WorkforceMenu from '@/components/WorkforceMenu';
import BrowserAgentWorkspace from '@/components/WorkFlow/BrowserAgentWorkspace';
import TerminalAgentWorkspace from '@/components/WorkFlow/TerminalAgentWorkspace';
import WorkflowMenu from '@/components/WorkFlow/WorkflowMenu';
import { Button } from '@/components/ui/button';
import { TooltipSimple } from '@/components/ui/tooltip';
import type { SelectedProjectTurn } from '@/hooks/useSelectedProjectTurn';
@ -90,7 +90,7 @@ function WorkforceOverlayCanvas({
<div className="relative flex h-full w-full flex-col">
<div className="backdrop-blur-sm inset-0 rounded-xl bg-ds-bg-neutral-default-default pointer-events-none absolute"></div>
<div className="relative z-10 h-full w-full">
<Folder />
<Context />
</div>
</div>
</div>
@ -102,7 +102,7 @@ function WorkforceOverlayCanvas({
<div className="relative flex h-full w-full flex-col">
<div className="backdrop-blur-sm inset-0 rounded-xl bg-ds-bg-neutral-default-default pointer-events-none absolute"></div>
<div className="relative z-10 h-full w-full">
<Folder
<Context
data={activeTask.taskAssigning?.find(
(agent) => agent.agent_id === activeWorkSpace
)}
@ -116,7 +116,7 @@ function WorkforceOverlayCanvas({
<div className="relative flex h-full w-full flex-col">
<div className="backdrop-blur-sm inset-0 rounded-xl bg-ds-bg-neutral-default-default pointer-events-none absolute"></div>
<div className="relative z-10 h-full w-full">
<Folder />
<Context />
</div>
</div>
</div>
@ -239,7 +239,7 @@ export default function ExpandedOverlay({
</div>
<div className="relative z-50 shrink-0">
<div className="pointer-events-auto">
<WorkforceMenu
<WorkflowMenu
onToggleChatBox={onToggleSidePanel}
isChatBoxVisible={!isSidePanelVisible}
/>

View file

@ -12,7 +12,7 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import Folder from '@/components/Folder';
import Context from '@/components/Context';
import { TaskState, type TaskStateType } from '@/components/TaskState';
import Terminal from '@/components/Terminal';
import { TaskLogPanelContent } from '@/components/WorkFlow/TaskLogPanelContent';
@ -190,10 +190,10 @@ export function AgentDetailPane({
}
return (
<div className="flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden rounded-xl bg-ds-bg-neutral-strong-default">
<div className="min-h-0 min-w-0 rounded-xl bg-ds-bg-neutral-strong-default flex h-full w-full flex-col overflow-hidden">
<div
className={cn(
'top-0 min-h-0 w-full min-w-0 max-w-full shrink-0 bg-ds-bg-neutral-strong-default pb-2 pt-2'
'top-0 min-h-0 min-w-0 bg-ds-bg-neutral-strong-default pb-2 pt-2 w-full max-w-full shrink-0'
)}
>
<div
@ -205,7 +205,7 @@ export function AgentDetailPane({
{preset?.name ?? agent.name}
</div>
<div
className="mt-sm min-h-4 w-full min-w-0 max-w-full px-3"
className="mt-sm min-h-4 min-w-0 px-3 w-full max-w-full"
onPointerEnter={() => setToolkitHovered(true)}
onPointerLeave={() => setToolkitHovered(false)}
>
@ -217,7 +217,7 @@ export function AgentDetailPane({
/>
</div>
{agent.tasks && agent.tasks.length > 0 && (
<div className="flex flex-col items-start justify-between gap-1 border-0 border-b border-solid border-ds-border-neutral-default-default px-3 py-sm">
<div className="gap-1 border-ds-border-neutral-default-default px-3 py-sm flex flex-col items-start justify-between border-0 border-b border-solid">
<div className="flex w-full flex-1 justify-start">
<TaskState
all={agent.tasks?.length || 0}
@ -268,26 +268,26 @@ export function AgentDetailPane({
</div>
{/* Content: agent summary + task list; task log slides in from the right */}
<div className="relative min-h-0 flex-1 overflow-hidden">
<div className="min-h-0 relative flex-1 overflow-hidden">
<div
className="scrollbar scrollbar-always-visible h-full min-h-0 overflow-y-auto"
className="scrollbar scrollbar-always-visible min-h-0 h-full overflow-y-auto"
onWheel={(e) => e.stopPropagation()}
>
<div
className="mb-2 mt-1 max-h-[180px] w-full pl-3"
className="mb-2 mt-1 pl-3 max-h-[180px] w-full"
onClick={focusAgent}
>
{browserImages.length > 0 && (
<div
className={`grid h-[180px] w-full gap-1 overflow-hidden ${browserImageGridClass}`}
className={`gap-1 grid h-[180px] w-full overflow-hidden ${browserImageGridClass}`}
>
{browserImages.map((img, index) => (
<div
key={`${img.img}-${index}`}
className="relative h-full w-full overflow-hidden rounded-lg"
className="rounded-lg relative h-full w-full overflow-hidden"
>
<img
className="absolute left-0 top-0 h-[250%] w-[250%] origin-top-left scale-[0.4] object-cover"
className="left-0 top-0 absolute h-[250%] w-[250%] origin-top-left scale-[0.4] object-cover"
src={img.img}
alt={agent.type}
/>
@ -297,7 +297,7 @@ export function AgentDetailPane({
(_, index) => (
<div
key={`browser-placeholder-${index}`}
className="h-full w-full rounded-sm bg-ds-bg-neutral-subtle-default"
className="rounded-sm bg-ds-bg-neutral-subtle-default h-full w-full"
/>
)
)}
@ -306,23 +306,23 @@ export function AgentDetailPane({
{agent.type === 'document_agent' &&
agent.tasks &&
agent.tasks.length > 0 && (
<div className="relative h-[180px] w-full overflow-hidden rounded-sm">
<div className="absolute left-0 top-0 h-[500px] w-[900px] origin-top-left scale-[0.36]">
<Folder data={agent} />
<div className="rounded-sm relative h-[180px] w-full overflow-hidden">
<div className="left-0 top-0 absolute h-[500px] w-[900px] origin-top-left scale-[0.36]">
<Context data={agent} />
</div>
</div>
)}
{agent.type === 'developer_agent' && terminalTasks.length > 0 && (
<div
className={`grid h-[180px] w-full gap-1 overflow-hidden ${terminalGridClass}`}
className={`gap-1 grid h-[180px] w-full overflow-hidden ${terminalGridClass}`}
>
{terminalTasks.map((task) => (
<div
key={task.id}
className="relative h-full w-full overflow-hidden rounded-lg object-cover"
className="rounded-lg relative h-full w-full overflow-hidden object-cover"
>
<div className="absolute left-0 top-0 h-[250%] w-[250%] origin-top-left scale-[0.4]">
<div className="left-0 top-0 absolute h-[250%] w-[250%] origin-top-left scale-[0.4]">
<Terminal content={task.terminal} />
</div>
</div>
@ -331,7 +331,7 @@ export function AgentDetailPane({
(_, index) => (
<div
key={`terminal-placeholder-${index}`}
className="h-full w-full rounded-lg bg-ds-bg-neutral-subtle-default"
className="rounded-lg bg-ds-bg-neutral-subtle-default h-full w-full"
/>
)
)}
@ -339,7 +339,7 @@ export function AgentDetailPane({
)}
</div>
<div className="flex flex-col gap-2 pb-3 pl-3">
<div className="gap-2 pb-3 pl-3 flex flex-col">
{agent.tasks &&
filterTasks.map((task) => {
const lastActiveToolkit = task.toolkits
@ -363,7 +363,7 @@ export function AgentDetailPane({
}
}}
className={cn(
'flex cursor-pointer flex-col gap-1 rounded-xl border border-solid px-6 py-sm transition-all duration-300',
'gap-1 rounded-xl px-6 py-sm flex cursor-pointer flex-col border border-solid transition-all duration-300',
task.reAssignTo
? 'bg-ds-bg-status-blocked-subtle-default'
: task.status === TaskStatus.COMPLETED
@ -395,9 +395,9 @@ export function AgentDetailPane({
'border-transparent'
)}
>
<div className="flex w-full items-center justify-between gap-2">
<div className="flex min-w-0 items-center gap-x-2 gap-y-0.5">
<div className="flex h-4 shrink-0 items-center justify-center">
<div className="gap-2 flex w-full items-center justify-between">
<div className="min-w-0 gap-x-2 gap-y-0.5 flex items-center">
<div className="h-4 flex shrink-0 items-center justify-center">
{task.reAssignTo ? (
<CircleSlash2
size={16}
@ -451,12 +451,12 @@ export function AgentDetailPane({
</>
)}
</div>
<div className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5">
<span className="shrink-0 text-xs font-bold leading-13 text-ds-text-neutral-default-default">
<div className="min-w-0 gap-x-2 gap-y-0.5 flex flex-wrap items-center">
<span className="text-xs font-bold leading-13 text-ds-text-neutral-default-default shrink-0">
No. {getTaskIdDisplay(task.id)}
</span>
{task.reAssignTo ? (
<div className="rounded-lg bg-ds-bg-document-subtle-default px-1 py-0.5 text-xs font-bold leading-none text-ds-text-warning-strong-default">
<div className="rounded-lg bg-ds-bg-document-subtle-default px-1 py-0.5 text-xs font-bold text-ds-text-warning-strong-default leading-none">
Reassigned to {task.reAssignTo}
</div>
) : (
@ -483,7 +483,7 @@ export function AgentDetailPane({
size="xxs"
buttonContent="icon-only"
buttonRadius="lg"
className="shrink-0 text-ds-icon-neutral-muted-default opacity-50"
className="text-ds-icon-neutral-muted-default shrink-0 opacity-50"
aria-expanded={isExpanded}
aria-label={
isExpanded ? 'Collapse task details' : 'Expand task'
@ -507,7 +507,7 @@ export function AgentDetailPane({
</div>
<div
className={cn(
'mt-0.5 w-full min-w-0 max-w-full pl-4 text-left',
'mt-0.5 min-w-0 pl-4 w-full max-w-full text-left',
task.status === TaskStatus.FAILED
? 'text-ds-text-status-error-strong-default'
: task.status === TaskStatus.BLOCKED
@ -517,7 +517,7 @@ export function AgentDetailPane({
>
<div
className={cn(
'block select-text break-words text-label-xs font-medium',
'text-label-xs font-medium block break-words select-text',
!isExpanded && 'line-clamp-2 overflow-hidden',
isExpanded && 'whitespace-pre-line'
)}
@ -526,17 +526,17 @@ export function AgentDetailPane({
</div>
</div>
{task.status === TaskStatus.RUNNING && isExpanded && (
<div className="duration-400 ml-4 mt-0.5 flex items-center gap-2">
<div className="ml-4 mt-0.5 gap-2 flex items-center duration-400">
{lastActiveToolkit?.toolkitStatus ===
AgentStatusValue.RUNNING && (
<div className="flex min-w-0 flex-1 items-center justify-start gap-sm duration-300">
<div className="min-w-0 gap-sm flex flex-1 items-center justify-start duration-300">
{getToolkitIcon(
lastActiveToolkit.toolkitName ?? ''
)}
<div className="min-w-0 max-w-full flex-shrink flex-grow-0 overflow-hidden text-ellipsis whitespace-nowrap pt-1 text-xs leading-17 text-ds-text-neutral-default-default">
<div className="min-w-0 pt-1 text-xs leading-17 text-ds-text-neutral-default-default max-w-full flex-shrink flex-grow-0 overflow-hidden text-ellipsis whitespace-nowrap">
<ShinyText
text={task.toolkits?.[0]?.toolkitName ?? ''}
className="pointer-events-auto w-full select-text overflow-hidden text-ellipsis whitespace-nowrap text-xs font-bold leading-17 text-ds-text-neutral-default-default"
className="text-xs font-bold leading-17 text-ds-text-neutral-default-default pointer-events-auto w-full overflow-hidden text-ellipsis whitespace-nowrap select-text"
/>
</div>
</div>
@ -557,28 +557,28 @@ export function AgentDetailPane({
initial="initial"
animate="animate"
exit="exit"
className="absolute inset-0 z-20 flex flex-col overflow-hidden rounded-br-xl bg-ds-bg-neutral-strong-default will-change-transform"
className="inset-0 rounded-br-xl bg-ds-bg-neutral-strong-default absolute z-20 flex flex-col overflow-hidden will-change-transform"
>
<div className="flex shrink-0 items-center gap-1 px-2 pb-2">
<div className="gap-1 px-2 pb-2 flex shrink-0 items-center">
<Button
type="button"
variant="ghost"
size="xxs"
buttonContent="icon-only"
buttonRadius="lg"
className="shrink-0 text-ds-icon-neutral-muted-default"
className="text-ds-icon-neutral-muted-default shrink-0"
aria-label="Back to agent details"
onClick={() => setDetailTask(null)}
>
<ChevronLeft className="size-4" aria-hidden />
</Button>
<span className="min-w-0 truncate text-label-sm font-bold text-ds-text-neutral-default-default">
<span className="min-w-0 text-label-sm font-bold text-ds-text-neutral-default-default truncate">
No. {getTaskIdDisplay(detailTask.id)}
</span>
</div>
<div
onWheel={(e) => e.stopPropagation()}
className="scrollbar scrollbar-always-visible min-h-0 flex-1 overflow-y-auto pb-2 pl-3 pr-1"
className="scrollbar scrollbar-always-visible min-h-0 pb-2 pl-3 pr-1 flex-1 overflow-y-auto"
>
<AnimatePresence mode="wait">
<motion.div
@ -587,7 +587,7 @@ export function AgentDetailPane({
initial="initial"
animate="animate"
exit="exit"
className="flex w-full flex-col gap-sm"
className="gap-sm flex w-full flex-col"
>
<TaskLogPanelContent
selectedTask={detailTask}

View file

@ -12,17 +12,17 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { AgentFolderSection } from '@/components/Session/SidePanelSections/AgentFolderSection';
import { AgentPoolSection } from '@/components/Session/SidePanelSections/AgentPoolSection';
import { buildContextItems } from '@/components/Session/SidePanelSections/buildContextItems';
import { AgentFolderSection } from '@/components/Project/SidePanelSections/AgentFolderSection';
import { AgentPoolSection } from '@/components/Project/SidePanelSections/AgentPoolSection';
import { buildContextItems } from '@/components/Project/SidePanelSections/buildContextItems';
import {
collectSidePanelOutputFiles,
mergeSidePanelOutputFiles,
} from '@/components/Session/SidePanelSections/collectSidePanelOutputFiles';
import { ExecutionContextSection } from '@/components/Session/SidePanelSections/ExecutionContextSection';
import { ProgressSection } from '@/components/Session/SidePanelSections/ProgressSection';
import { useProjectOutputFiles } from '@/components/Session/SidePanelSections/useProjectOutputFiles';
import ExpandedOverlay from '@/components/Session/Workforce/ExpandedOverlay';
} from '@/components/Project/SidePanelSections/collectSidePanelOutputFiles';
import { ExecutionContextSection } from '@/components/Project/SidePanelSections/ExecutionContextSection';
import { ProgressSection } from '@/components/Project/SidePanelSections/ProgressSection';
import { useProjectOutputFiles } from '@/components/Project/SidePanelSections/useProjectOutputFiles';
import ExpandedOverlay from '@/components/Project/Workforce/ExpandedOverlay';
import useChatStoreAdapter from '@/hooks/useChatStoreAdapter';
import { useSelectedProjectTurn } from '@/hooks/useSelectedProjectTurn';
import { cn } from '@/lib/utils';
@ -31,7 +31,7 @@ import { useSkillsStore } from '@/store/skillsStore';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
/** Main column under `SessionSidePanel` header: fills remaining height in flex parent */
/** Main column under `ProjectSidePanel` header: fills remaining height in flex parent */
export const WORKFORCE_MAIN_SURFACE_CLASS =
'min-w-0 flex w-full min-h-0 flex-1 flex-col overflow-hidden';

View file

@ -13,7 +13,7 @@
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import ChatBox from '@/components/ChatBox';
import { HeaderBox } from '@/components/Session/HeaderBox';
import { HeaderBox } from '@/components/Project/HeaderBox';
import Workspace from '@/components/Workspace';
import useChatStoreAdapter from '@/hooks/useChatStoreAdapter';
import { inferSessionModeFromTask } from '@/lib/sessionMode';
@ -27,23 +27,23 @@ import {
type SessionModeType,
} from '@/types/constants';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { SessionSidePanel } from './SessionSidePanel';
import { ProjectSidePanel } from './ProjectSidePanel';
import {
SESSION_SIDE_PANEL_EXPANDED_OUTER_CLASS,
SESSION_SIDE_PANEL_FOLDED_OUTER_CLASS,
} from './sessionSidePanelLayout';
PROJECT_SIDE_PANEL_EXPANDED_OUTER_CLASS,
PROJECT_SIDE_PANEL_FOLDED_OUTER_CLASS,
} from './projectSidePanelLayout';
/**
* Active Project: header + chat (left) and a mode-dependent side panel (right).
* The side panel is selected from Project.mode. Task/session mode fields are
* retained only to render legacy runs that do not have a Project mode yet.
*/
interface SessionProps {
interface ProjectProps {
/** New Project shell: empty Project that promotes to a live Project on send. */
isNewProject?: boolean;
}
export default function Session({ isNewProject = false }: SessionProps) {
export default function Project({ isNewProject = false }: ProjectProps) {
const { chatStore, projectStore } = useChatStoreAdapter();
const activeWorkspaceTab = usePageTabStore((s) => s.activeWorkspaceTab);
const setActiveWorkspaceTab = usePageTabStore((s) => s.setActiveWorkspaceTab);
@ -226,7 +226,7 @@ export default function Session({ isNewProject = false }: SessionProps) {
}
const sessionSidePanel = displaySessionMode ? (
<SessionSidePanel
<ProjectSidePanel
key={displaySessionMode}
mode={displaySessionMode}
workforcePanelKey={workforcePanelKey}
@ -241,10 +241,10 @@ export default function Session({ isNewProject = false }: SessionProps) {
if (isNewProject) {
return (
<div className="flex h-full min-h-0 w-full min-w-0 flex-1 flex-row overflow-hidden">
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
<div className="min-h-0 min-w-0 flex h-full w-full flex-1 flex-row overflow-hidden">
<div className="min-h-0 min-w-0 flex flex-1 flex-col overflow-hidden">
<HeaderBox empty />
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
<div className="min-h-0 min-w-0 flex flex-1 flex-col overflow-hidden">
<Workspace
variant="new-project"
embedded
@ -257,10 +257,10 @@ export default function Session({ isNewProject = false }: SessionProps) {
<div
id="session-side-panel"
className={cn(
'flex min-h-0 shrink-0 flex-col overflow-hidden transition-[width] duration-200 ease-out',
'min-h-0 ease-out flex shrink-0 flex-col overflow-hidden transition-[width] duration-200',
isSidePanelVisible
? SESSION_SIDE_PANEL_EXPANDED_OUTER_CLASS
: cn(SESSION_SIDE_PANEL_FOLDED_OUTER_CLASS, 'rounded-l-xl')
? PROJECT_SIDE_PANEL_EXPANDED_OUTER_CLASS
: cn(PROJECT_SIDE_PANEL_FOLDED_OUTER_CLASS, 'rounded-l-xl')
)}
>
{sessionSidePanel}
@ -270,14 +270,14 @@ export default function Session({ isNewProject = false }: SessionProps) {
}
return (
<div className="flex h-full min-h-0 w-full min-w-0 flex-1 flex-row overflow-hidden">
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
<div className="min-h-0 min-w-0 flex h-full w-full flex-1 flex-row overflow-hidden">
<div className="min-h-0 min-w-0 flex flex-1 flex-col overflow-hidden">
{chatStore.activeTaskId && hasAnyMessages && (
<HeaderBox
totalTokens={chatStore.tasks[chatStore.activeTaskId]?.tokens || 0}
/>
)}
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
<div className="min-h-0 min-w-0 flex flex-1 flex-col overflow-hidden">
<ChatBox />
</div>
</div>
@ -285,10 +285,10 @@ export default function Session({ isNewProject = false }: SessionProps) {
<div
id="session-side-panel"
className={cn(
'flex min-h-0 shrink-0 flex-col overflow-hidden transition-[width] duration-200 ease-out',
'min-h-0 ease-out flex shrink-0 flex-col overflow-hidden transition-[width] duration-200',
isSidePanelVisible
? SESSION_SIDE_PANEL_EXPANDED_OUTER_CLASS
: cn(SESSION_SIDE_PANEL_FOLDED_OUTER_CLASS, 'rounded-l-xl')
? PROJECT_SIDE_PANEL_EXPANDED_OUTER_CLASS
: cn(PROJECT_SIDE_PANEL_FOLDED_OUTER_CLASS, 'rounded-l-xl')
)}
>
{sessionSidePanel}

View file

@ -13,12 +13,12 @@
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
/** Full logical width of the session side panel content (clipped by the outer when folded to 40px). */
export const SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS =
export const PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS =
'w-[min(360px,40vw)] max-w-[400px]';
/** Outer `#session-side-panel` when expanded (same as content width; no extra clip). */
export const SESSION_SIDE_PANEL_EXPANDED_OUTER_CLASS =
SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS;
export const PROJECT_SIDE_PANEL_EXPANDED_OUTER_CLASS =
PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS;
/** Outer shell when folded: fixed 40px; content layer keeps `SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS`. */
export const SESSION_SIDE_PANEL_FOLDED_OUTER_CLASS = 'w-[40px]';
/** Outer shell when folded: fixed 40px; content layer keeps `PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS`. */
export const PROJECT_SIDE_PANEL_FOLDED_OUTER_CLASS = 'w-[40px]';

View file

@ -215,8 +215,8 @@ export default function SpacesHub() {
if (spaceSections.length === 0) {
return (
<div className="flex h-full min-h-0 items-center justify-center px-6">
<div className="flex max-w-md flex-col items-center gap-3 text-center">
<div className="min-h-0 px-6 flex h-full items-center justify-center">
<div className="max-w-md gap-3 flex flex-col items-center text-center">
<FolderKanban
className="h-10 w-10 text-ds-icon-neutral-muted-default"
aria-hidden
@ -233,8 +233,8 @@ export default function SpacesHub() {
}
return (
<div className="relative flex h-full min-h-0 flex-col overflow-hidden">
<div className="flex shrink-0 items-end justify-between gap-4 border-0 border-b border-solid border-ds-border-neutral-subtle-default px-8 py-6">
<div className="min-h-0 relative flex h-full flex-col overflow-hidden">
<div className="gap-4 border-ds-border-neutral-subtle-default px-8 py-6 flex shrink-0 items-end justify-between border-0 border-b border-solid">
<div className="min-w-0">
<h1 className="text-heading-2xl m-0 font-semibold text-ds-text-neutral-default-default">
{t('layout.spaces-hub-title')}
@ -243,7 +243,7 @@ export default function SpacesHub() {
{t('layout.spaces-hub-description')}
</p>
</div>
<div className="hidden shrink-0 items-center gap-2 text-body-sm text-ds-text-neutral-subtle-default md:flex">
<div className="gap-2 text-body-sm text-ds-text-neutral-subtle-default md:flex hidden shrink-0 items-center">
<FolderKanban className="h-4 w-4" aria-hidden />
<span>
{t('layout.spaces-hub-space-count', {
@ -253,8 +253,8 @@ export default function SpacesHub() {
</div>
</div>
<div className="min-h-0 flex-1 overflow-y-auto px-8 py-6">
<div className="grid grid-cols-1 gap-4 xl:grid-cols-2 2xl:grid-cols-3">
<div className="min-h-0 px-8 py-6 flex-1 overflow-y-auto">
<div className="gap-4 xl:grid-cols-2 2xl:grid-cols-3 grid grid-cols-1">
{spaceSections.map(({ space, projects }) => {
const isActive = space.id === activeSpaceId;
const canCreate = canCreateProjectInSpace(space);
@ -271,15 +271,15 @@ export default function SpacesHub() {
isActive && 'border-ds-border-brand-default-default'
)}
>
<div className="flex shrink-0 items-start justify-between gap-3 border-0 border-b border-solid border-ds-border-neutral-subtle-default p-4">
<div className="gap-3 border-ds-border-neutral-subtle-default p-4 flex shrink-0 items-start justify-between border-0 border-b border-solid">
<button
type="button"
className="flex min-w-0 flex-1 cursor-pointer flex-col items-start gap-1 rounded-md text-left outline-none focus-visible:ring-2 focus-visible:ring-ds-border-brand-default-focus"
className="min-w-0 gap-1 rounded-md focus-visible:ring-ds-border-brand-default-focus flex flex-1 cursor-pointer flex-col items-start text-left outline-none focus-visible:ring-2"
onClick={() => openSpace(space.id)}
>
<span className="flex min-w-0 max-w-full items-center gap-2">
<Folder className="h-4 w-4 shrink-0 text-ds-icon-neutral-muted-default" />
<span className="truncate text-body-md font-semibold text-ds-text-neutral-default-default">
<span className="min-w-0 gap-2 flex max-w-full items-center">
<Folder className="h-4 w-4 text-ds-icon-neutral-muted-default shrink-0" />
<span className="text-body-md font-semibold text-ds-text-neutral-default-default truncate">
{space.name?.trim() || t('layout.spaces-untitled')}
</span>
{isLegacySpace(space) ? (
@ -291,7 +291,7 @@ export default function SpacesHub() {
/>
) : null}
</span>
<span className="max-w-full truncate text-body-xs text-ds-text-neutral-muted-default">
<span className="text-body-xs text-ds-text-neutral-muted-default max-w-full truncate">
{subtitle}
</span>
</button>
@ -314,12 +314,12 @@ export default function SpacesHub() {
) : null}
</div>
<div className="flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto p-2">
<div className="min-h-0 gap-1 p-2 flex flex-1 flex-col overflow-y-auto">
{projects.length === 0 ? (
canCreate ? (
<button
type="button"
className="flex min-h-20 cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-ds-border-neutral-subtle-default px-4 py-5 text-center text-body-sm text-ds-text-neutral-muted-default transition-colors hover:bg-ds-bg-neutral-subtle-default"
className="min-h-20 gap-2 rounded-lg border-ds-border-neutral-subtle-default px-4 py-5 text-body-sm text-ds-text-neutral-muted-default hover:bg-ds-bg-neutral-subtle-default flex cursor-pointer flex-col items-center justify-center border border-dashed text-center transition-colors"
onClick={() => void createProject(space)}
>
<Plus className="h-4 w-4" aria-hidden />
@ -328,7 +328,7 @@ export default function SpacesHub() {
</span>
</button>
) : (
<div className="flex min-h-20 flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-ds-border-neutral-subtle-default px-4 py-5 text-center text-body-sm text-ds-text-neutral-muted-default">
<div className="min-h-20 gap-2 rounded-lg border-ds-border-neutral-subtle-default px-4 py-5 text-body-sm text-ds-text-neutral-muted-default flex flex-col items-center justify-center border border-dashed text-center">
<span>
{t('layout.spaces-legacy-readonly-hint', {
defaultValue:
@ -347,8 +347,8 @@ export default function SpacesHub() {
key={project.id}
type="button"
className={cn(
'group flex min-h-11 w-full cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-left transition-colors',
'hover:bg-ds-bg-neutral-subtle-default focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ds-border-brand-default-focus',
'group min-h-11 gap-3 rounded-md px-3 py-2 flex w-full cursor-pointer items-center text-left transition-colors',
'hover:bg-ds-bg-neutral-subtle-default focus-visible:ring-ds-border-brand-default-focus focus-visible:ring-2 focus-visible:outline-none',
isActiveProject &&
'bg-ds-bg-neutral-subtle-default text-ds-text-neutral-default-default'
)}
@ -356,23 +356,23 @@ export default function SpacesHub() {
>
{isProjectLoading ? (
<Loader2
className="h-4 w-4 shrink-0 animate-spin text-ds-icon-neutral-muted-default"
className="h-4 w-4 animate-spin text-ds-icon-neutral-muted-default shrink-0"
aria-hidden
/>
) : (
<History
className="h-4 w-4 shrink-0 text-ds-icon-neutral-muted-default"
className="h-4 w-4 text-ds-icon-neutral-muted-default shrink-0"
aria-hidden
/>
)}
<span className="min-w-0 flex-1 truncate text-body-sm text-ds-text-neutral-default-default">
<span className="min-w-0 text-body-sm text-ds-text-neutral-default-default flex-1 truncate">
{projectTitle(
project,
t('layout.sessions-start-new')
)}
</span>
<ArrowRight
className="h-4 w-4 shrink-0 text-ds-icon-neutral-subtle-default opacity-0 transition-opacity group-hover:opacity-100"
className="h-4 w-4 text-ds-icon-neutral-subtle-default shrink-0 opacity-0 transition-opacity group-hover:opacity-100"
aria-hidden
/>
</button>

View file

@ -20,7 +20,7 @@ import eigentAppIconWhite from '@/assets/logo/icon_white.svg';
import { type HistoryTabId } from '@/components/Dashboard/HistoryTabsNav';
import InviteCodeDialog from '@/components/Dialog/InviteCodeDialog';
import ReportBugDialog from '@/components/Dialog/ReportBugDialog';
import { SpaceSwitchDropdown } from '@/components/ProjectPageSidebar/SpaceSwitchDropdown';
import { SpaceSwitchDropdown } from '@/components/PageSidebar/SpaceSwitchDropdown';
import AlertDialog from '@/components/ui/alertDialog';
import { Blocks } from '@/components/ui/animate-ui/icons/blocks';
import { Bot } from '@/components/ui/animate-ui/icons/bot';

View file

@ -30,8 +30,8 @@ import {
Image,
} from 'lucide-react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { TaskState } from '../TaskState';
import { Button } from '../ui/button';
import { TaskState } from '../../TaskState';
import { Button } from '../../ui/button';
export default function BrowserAgentWorkspace({
selectedTurn,

View file

@ -32,7 +32,7 @@ import {
} from 'lucide-react';
import { useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from '../ui/button';
import { Button } from '../../ui/button';
export default function TerminalAgentWorkspace({
selectedTurn,

View file

@ -37,7 +37,7 @@ export interface WorkforceMenuProps {
isChatBoxVisible?: boolean;
}
export default function WorkforceMenu({
export default function WorkflowMenu({
onToggleChatBox: _onToggleChatBox,
isChatBoxVisible: _isChatBoxVisible = true,
}: WorkforceMenuProps) {

View file

@ -38,7 +38,7 @@ import {
TriangleAlert,
} from 'lucide-react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Folder from '../Folder';
import Context from '../Context';
import { TaskState, TaskStateType } from '../TaskState';
import Terminal from '../Terminal';
import {
@ -406,18 +406,18 @@ export function Node({ id, data }: NodeProps) {
: 'w-[342px]'
} ${
data.isEditMode ? 'h-full' : 'max-h-[calc(100vh-200px)]'
} flex overflow-hidden rounded-xl border border-solid border-ds-border-neutral-subtle-default bg-ds-bg-neutral-subtle-default shadow-sm ${
} rounded-xl border-ds-border-neutral-subtle-default bg-ds-bg-neutral-subtle-default shadow-sm flex overflow-hidden border border-solid ${
getCurrentTask()?.activeAgent === id
? `${displayInfo?.borderColor} z-50`
: 'z-10 border-ds-border-neutral-default-default'
} transition-all duration-300 ease-in-out ${
: 'border-ds-border-neutral-default-default z-10'
} ease-in-out transition-all duration-300 ${
(data.agent?.tasks?.length ?? 0) === 0 && 'opacity-30'
}`}
>
<div className="flex w-[342px] shrink-0 flex-col border-y-0 border-l-0 border-r-[0.5px] border-solid border-ds-border-neutral-default-default">
<div className="border-ds-border-neutral-default-default flex w-[342px] shrink-0 flex-col border-y-0 border-r-[0.5px] border-l-0 border-solid">
{/* header */}
<div className="flex items-center justify-between gap-sm px-3 pb-1 pt-2">
<div className="flex items-center justify-between gap-md">
<div className="gap-sm px-3 pb-1 pt-2 flex items-center justify-between">
<div className="gap-md flex items-center justify-between">
<div
className={`text-base font-bold leading-relaxed ${
displayInfo?.textColor
@ -426,7 +426,7 @@ export function Node({ id, data }: NodeProps) {
{displayInfo?.name || data.agent?.name}
</div>
</div>
<div className="flex items-center gap-xs">
<div className="gap-xs flex items-center">
<Button
onClick={handleShowLog}
variant="ghost"
@ -448,7 +448,7 @@ export function Node({ id, data }: NodeProps) {
<Ellipsis />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[98px] rounded-[12px] border border-solid border-ds-border-neutral-default-default bg-ds-bg-neutral-strong-default p-sm">
<PopoverContent className="border-ds-border-neutral-default-default bg-ds-bg-neutral-strong-default p-sm w-[98px] rounded-[12px] border border-solid">
<div className="space-y-1">
<PopoverClose asChild>
<AddWorker
@ -460,7 +460,7 @@ export function Node({ id, data }: NodeProps) {
<Button
variant="ghost"
size="sm"
className="w-full justify-start gap-2"
className="gap-2 w-full justify-start"
onClick={(e) => {
e.stopPropagation();
const newWorkerList = workerList.filter(
@ -485,7 +485,7 @@ export function Node({ id, data }: NodeProps) {
{/* tools */}
<div
ref={toolsRef}
className="mb-sm flex min-h-4 flex-shrink-0 flex-wrap px-3 text-xs font-normal leading-tight text-ds-text-neutral-muted-default"
className="mb-sm min-h-4 px-3 text-xs font-normal leading-tight text-ds-text-neutral-muted-default flex flex-shrink-0 flex-wrap"
>
{/* {JSON.stringify(data.agent)} */}
{toolkitLabels.map((toolkit, index) => (
@ -496,7 +496,7 @@ export function Node({ id, data }: NodeProps) {
</div>
{/* workspace */}
<div
className="mb-2 max-h-[180px] px-3"
className="mb-2 px-3 max-h-[180px]"
onClick={() => {
chatStore.setActiveWorkspace(
chatStore.activeTaskId as string,
@ -508,15 +508,15 @@ export function Node({ id, data }: NodeProps) {
>
{browserImages.length > 0 && (
<div
className={`grid h-[180px] w-full gap-1 overflow-hidden ${browserImageGridClass}`}
className={`gap-1 grid h-[180px] w-full overflow-hidden ${browserImageGridClass}`}
>
{browserImages.map((img, index) => (
<div
key={`${img.img}-${index}`}
className="relative h-full w-full overflow-hidden rounded-lg"
className="rounded-lg relative h-full w-full overflow-hidden"
>
<img
className="absolute left-0 top-0 h-[250%] w-[250%] origin-top-left scale-[0.4] object-cover"
className="left-0 top-0 absolute h-[250%] w-[250%] origin-top-left scale-[0.4] object-cover"
src={img.img}
alt={data.type}
/>
@ -526,7 +526,7 @@ export function Node({ id, data }: NodeProps) {
(_, index) => (
<div
key={`browser-placeholder-${index}`}
className="h-full w-full rounded-sm bg-ds-bg-neutral-subtle-default"
className="rounded-sm bg-ds-bg-neutral-subtle-default h-full w-full"
/>
)
)}
@ -535,23 +535,23 @@ export function Node({ id, data }: NodeProps) {
{data.type === 'document_agent' &&
data?.agent?.tasks &&
data.agent.tasks.length > 0 && (
<div className="relative h-[180px] w-full overflow-hidden rounded-sm">
<div className="absolute left-0 top-0 h-[500px] w-[900px] origin-top-left scale-[0.36]">
<Folder data={data.agent as Agent} />
<div className="rounded-sm relative h-[180px] w-full overflow-hidden">
<div className="left-0 top-0 absolute h-[500px] w-[900px] origin-top-left scale-[0.36]">
<Context data={data.agent as Agent} />
</div>
</div>
)}
{data.type === 'developer_agent' && terminalTasks.length > 0 && (
<div
className={`grid h-[180px] w-full gap-1 overflow-hidden ${terminalGridClass}`}
className={`gap-1 grid h-[180px] w-full overflow-hidden ${terminalGridClass}`}
>
{terminalTasks.map((task) => (
<div
key={task.id}
className="relative h-full w-full overflow-hidden rounded-lg object-cover"
className="rounded-lg relative h-full w-full overflow-hidden object-cover"
>
<div className="absolute left-0 top-0 h-[250%] w-[250%] origin-top-left scale-[0.4]">
<div className="left-0 top-0 absolute h-[250%] w-[250%] origin-top-left scale-[0.4]">
<Terminal content={task.terminal} />
</div>
</div>
@ -560,7 +560,7 @@ export function Node({ id, data }: NodeProps) {
(_, index) => (
<div
key={`terminal-placeholder-${index}`}
className="h-full w-full rounded-lg bg-ds-bg-neutral-subtle-default"
className="rounded-lg bg-ds-bg-neutral-subtle-default h-full w-full"
/>
)
)}
@ -569,7 +569,7 @@ export function Node({ id, data }: NodeProps) {
</div>
{/* subtasks */}
{data.agent?.tasks && data.agent?.tasks.length > 0 && (
<div className="flex flex-col items-start justify-between gap-1 border-[0px] border-t border-solid border-ds-border-neutral-default-default px-3 py-sm">
<div className="gap-1 border-ds-border-neutral-default-default px-3 py-sm flex flex-col items-start justify-between border-[0px] border-t border-solid">
{/* <div className="font-bold leading-tight text-xs">Subtasks</div> */}
<div className="flex flex-1 justify-end">
<TaskState
@ -621,7 +621,7 @@ export function Node({ id, data }: NodeProps) {
onWheel={(e) => {
e.stopPropagation();
}}
className="scrollbar scrollbar-always-visible flex flex-col gap-2 overflow-y-auto px-3 pb-2 duration-500 ease-out animate-in fade-in-0 slide-in-from-bottom-4"
className="scrollbar scrollbar-always-visible gap-2 px-3 pb-2 ease-out animate-in fade-in-0 slide-in-from-bottom-4 flex flex-col overflow-y-auto duration-500"
style={{
maxHeight:
data.img && data.img.length > 0
@ -682,7 +682,7 @@ export function Node({ id, data }: NodeProps) {
}
}}
key={`taskList-${task.id}-${task.failure_count}`}
className={`flex gap-2 rounded-xl px-sm py-sm transition-all duration-300 ease-in-out animate-in fade-in-0 slide-in-from-left-2 ${taskRowBgHover} cursor-pointer border border-solid border-transparent ${
className={`gap-2 rounded-xl px-sm py-sm ease-in-out animate-in fade-in-0 slide-in-from-left-2 flex transition-all duration-300 ${taskRowBgHover} cursor-pointer border border-solid border-transparent ${
task.status === TaskStatus.COMPLETED
? 'hover:border-ds-border-status-completed-subtle-focus'
: task.status === TaskStatus.FAILED
@ -767,16 +767,16 @@ export function Node({ id, data }: NodeProps) {
</div>
<div className="flex flex-1 flex-col items-start justify-center">
<div
className={`w-full flex-grow-0 ${taskTextClass} pointer-events-auto select-text whitespace-pre-line text-wrap break-all text-xs font-medium leading-13`}
className={`w-full flex-grow-0 ${taskTextClass} text-xs font-medium leading-13 pointer-events-auto text-wrap break-all whitespace-pre-line select-text`}
>
<div className="flex items-center gap-sm">
<div className="gap-sm flex items-center">
<div
className={`text-xs font-bold leading-13 ${taskTextClass}`}
>
No. {getTaskId(task.id)}
</div>
{task.reAssignTo ? (
<div className="rounded-lg bg-ds-bg-document-subtle-default px-1 py-0.5 text-xs font-bold leading-none text-ds-text-document-default-default hover:bg-ds-bg-document-subtle-hover">
<div className="rounded-lg bg-ds-bg-document-subtle-default px-1 py-0.5 text-xs font-bold text-ds-text-document-default-default hover:bg-ds-bg-document-subtle-hover leading-none">
Reassigned to {task.reAssignTo}
</div>
) : (
@ -798,11 +798,11 @@ export function Node({ id, data }: NodeProps) {
<div>{task.content}</div>
</div>
{task?.status === TaskStatus.RUNNING && (
<div className="duration-400 mt-xs flex items-center gap-2 animate-in fade-in-0 slide-in-from-bottom-2">
<div className="mt-xs gap-2 animate-in fade-in-0 slide-in-from-bottom-2 flex items-center duration-400">
{/* active toolkit */}
{lastActiveToolkit?.toolkitStatus ===
AgentStatusValue.RUNNING && (
<div className="flex min-w-0 flex-1 items-center justify-start gap-sm duration-300 animate-in fade-in-0 slide-in-from-right-2">
<div className="min-w-0 gap-sm animate-in fade-in-0 slide-in-from-right-2 flex flex-1 items-center justify-start duration-300">
{getToolkitIcon(
lastActiveToolkit.toolkitName ?? ''
)}
@ -813,11 +813,11 @@ export function Node({ id, data }: NodeProps) {
].activeWorkspace
? '!w-[100px]'
: '!w-[500px]'
} min-w-0 flex-shrink-0 flex-grow-0 overflow-hidden text-ellipsis whitespace-nowrap pt-1 text-xs leading-17 text-ds-text-status-running-default-default`}
} min-w-0 pt-1 text-xs leading-17 text-ds-text-status-running-default-default flex-shrink-0 flex-grow-0 overflow-hidden text-ellipsis whitespace-nowrap`}
>
<ShinyText
text={task.toolkits?.[0].toolkitName}
className="pointer-events-auto w-full select-text overflow-hidden text-ellipsis whitespace-nowrap text-xs font-bold leading-17 text-ds-text-status-running-default-default"
className="text-xs font-bold leading-17 text-ds-text-status-running-default-default pointer-events-auto w-full overflow-hidden text-ellipsis whitespace-nowrap select-text"
/>
</div>
</div>
@ -838,14 +838,14 @@ export function Node({ id, data }: NodeProps) {
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 24 }}
transition={{ duration: 0.3, ease: 'easeIn' }}
className="flex w-[342px] shrink-0 flex-col gap-sm overflow-hidden rounded-r-xl bg-ds-bg-neutral-subtle-default py-2 pl-sm"
className="gap-sm rounded-r-xl bg-ds-bg-neutral-subtle-default py-2 pl-sm flex w-[342px] shrink-0 flex-col overflow-hidden"
>
<div
ref={logRef}
onWheel={(e) => {
e.stopPropagation();
}}
className="scrollbar scrollbar-always-visible max-h-[calc(100vh-200px)] overflow-y-scroll rounded-xl pr-sm"
className="scrollbar scrollbar-always-visible rounded-xl pr-sm max-h-[calc(100vh-200px)] overflow-y-scroll"
>
<AnimatePresence mode="wait">
{selectedTask && (
@ -855,7 +855,7 @@ export function Node({ id, data }: NodeProps) {
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -16 }}
transition={{ duration: 0.25, ease: 'easeIn' }}
className="flex w-full flex-col gap-sm"
className="gap-sm flex w-full flex-col"
>
<TaskLogPanelContent
selectedTask={selectedTask}

View file

@ -51,7 +51,7 @@ import {
import { type ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
/** Sub icons aligned with `WorkforceMenu` / `ui/menu-button` → `MenuToggleItem` (top-right badge, 10px). */
/** Sub icons aligned with `WorkflowMenu` / `ui/menu-button` → `MenuToggleItem` (top-right badge, 10px). */
function getWorkforceMenuStyleSubIcon(agentType: string): ReactNode {
const key = agentType as WorkflowAgentType;
const iconClass = WORKFLOW_AGENT_SUB_ICON_CLASS[key];

View file

@ -15,7 +15,7 @@
import {
ProjectNavListRows,
type ProjectNavItem,
} from '@/components/ProjectPageSidebar/ProjectNavListRows';
} from '@/components/PageSidebar/ProjectNavListRows';
import { useTranslation } from 'react-i18next';
interface WorkspaceAllSessionsProps {
@ -32,10 +32,10 @@ export function WorkspaceAllSessions({
const { t } = useTranslation();
return (
<div className="flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden">
<div className="m-0 mx-auto flex min-h-0 w-full max-w-3xl flex-1 flex-col gap-0.5 overflow-y-auto p-2">
<div className="min-h-0 min-w-0 flex h-full w-full flex-col overflow-hidden">
<div className="m-0 min-h-0 max-w-3xl gap-0.5 p-2 mx-auto flex w-full flex-1 flex-col overflow-y-auto">
{projects.length === 0 ? (
<p className="m-0 px-3 py-6 text-center text-body-sm text-ds-text-neutral-muted-default">
<p className="m-0 px-3 py-6 text-body-sm text-ds-text-neutral-muted-default text-center">
{t('layout.sessions-create-task-hint')}
</p>
) : (

View file

@ -12,7 +12,7 @@
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { SpaceSwitchDropdown } from '@/components/ProjectPageSidebar/SpaceSwitchDropdown';
import { SpaceSwitchDropdown } from '@/components/PageSidebar/SpaceSwitchDropdown';
import AlertDialog from '@/components/ui/alertDialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@ -537,7 +537,7 @@ export function WorkspaceProjectPicker({
aria-label={activeSpaceTitle}
>
<FolderIcon className="size-4 shrink-0" aria-hidden />
<span className="min-w-0 truncate text-label-sm text-ds-text-neutral-default-default">
<span className="min-w-0 text-label-sm text-ds-text-neutral-default-default truncate">
{activeSpaceTitle}
</span>
</div>
@ -607,13 +607,13 @@ export function WorkspaceProjectPicker({
buttonRadius="full"
className={cn(
PROJECT_PICKER_SHELL_CLASS,
'no-drag justify-between hover:bg-ds-bg-neutral-default-hover'
'no-drag hover:bg-ds-bg-neutral-default-hover justify-between'
)}
aria-expanded={menuOpen}
aria-haspopup="menu"
>
<FolderIcon className="size-4 shrink-0" aria-hidden />
<span className="min-w-0 truncate text-label-sm text-ds-text-neutral-default-default">
<span className="min-w-0 text-label-sm text-ds-text-neutral-default-default truncate">
{activeSpaceTitle}
</span>
<ChevronsUpDown

View file

@ -16,7 +16,7 @@ import {
NAV_LIST_PROJECTS_RECENT_MAX,
ProjectNavListRows,
type ProjectNavItem,
} from '@/components/ProjectPageSidebar/ProjectNavListRows';
} from '@/components/PageSidebar/ProjectNavListRows';
import { ArrowRight } from 'lucide-react';
import { useTranslation } from 'react-i18next';
@ -45,26 +45,26 @@ export function WorkspaceRecentSessions({
}
return (
<div className="mx-auto flex min-h-full w-full max-w-[600px] flex-col pb-4">
<div className="mb-3 flex w-full min-w-0 items-center justify-between gap-2 px-3 text-ds-text-neutral-muted-default">
<h2 className="min-w-0 text-left text-body-sm font-semibold">
<div className="pb-4 mx-auto flex min-h-full w-full max-w-[600px] flex-col">
<div className="mb-3 min-w-0 gap-2 px-3 text-ds-text-neutral-muted-default flex w-full items-center justify-between">
<h2 className="min-w-0 text-body-sm font-semibold text-left">
{t('layout.workspace-recent-sessions-heading')}
</h2>
<button
type="button"
onClick={onOpenAllProjects}
className="group inline-flex shrink-0 items-center gap-0.5 text-body-sm font-medium text-ds-text-neutral-muted-default outline-none transition-colors hover:underline focus-visible:rounded focus-visible:ring-2 focus-visible:ring-ds-ring-neutral-default-focus"
className="group gap-0.5 text-body-sm font-medium text-ds-text-neutral-muted-default focus-visible:rounded focus-visible:ring-ds-ring-neutral-default-focus inline-flex shrink-0 items-center transition-colors outline-none hover:underline focus-visible:ring-2"
>
{t('layout.all', { defaultValue: 'All' })}
<span
className="inline-flex max-w-0 overflow-hidden transition-[max-width] duration-200 ease-out group-hover:max-w-4"
className="max-w-0 ease-out group-hover:max-w-4 inline-flex overflow-hidden transition-[max-width] duration-200"
aria-hidden
>
<ArrowRight className="h-3.5 w-3.5 shrink-0" />
</span>
</button>
</div>
<div className="m-0 flex min-h-0 w-full flex-col gap-0.5 p-0">
<div className="m-0 min-h-0 gap-0.5 p-0 flex w-full flex-col">
<ProjectNavListRows
projects={projects}
activeProjectId={activeProjectId}

View file

@ -14,7 +14,7 @@
import { AddWorker } from '@/components/AddWorker';
import BottomBox, { type FileAttachment } from '@/components/ChatBox/BottomBox';
import { SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS } from '@/components/Session/sessionSidePanelLayout';
import { PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS } from '@/components/Project/projectSidePanelLayout';
import { Button } from '@/components/ui/button';
import { BASE_WORKFLOW_AGENTS } from '@/components/WorkFlow/baseWorkers';
import { isBaseWorkflowAgent } from '@/components/Workspace/FoldedAgentCard';
@ -482,12 +482,12 @@ export default function Workspace({
const composerTop = (
<>
<div className="mb-8 flex w-full justify-center">{projectPicker}</div>
<span className="mb-8 w-full text-center text-heading-lg font-bold text-ds-text-neutral-default-default">
<span className="mb-8 text-heading-lg font-bold text-ds-text-neutral-default-default w-full text-center">
{effectiveSessionMode === SessionMode.SINGLE_AGENT
? t('layout.workspace-cowork-single-agent')
: t('layout.workspace-cowork-workforce')}
</span>
<div className="mb-8 flex w-full justify-center px-5">
<div className="mb-8 px-5 flex w-full justify-center">
{effectiveSessionMode === SessionMode.SINGLE_AGENT ? (
<SingleAgentList />
) : (
@ -536,7 +536,7 @@ export default function Workspace({
const composer = (
<div className="mx-auto my-auto flex w-full max-w-[600px] shrink-0 flex-col">
<div className="flex min-h-[50vh] w-full min-w-0 flex-col justify-end">
<div className="min-w-0 flex min-h-[50vh] w-full flex-col justify-end">
{composerTop}
{composerInput}
</div>
@ -551,10 +551,10 @@ export default function Workspace({
if (embedded && isNewProjectVariant) {
return (
<div className="relative z-[1] flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden px-3">
<div className="min-h-0 min-w-0 px-3 relative z-[1] flex flex-1 flex-col overflow-hidden">
{composer}
<div
className="flex min-h-0 w-full flex-1 flex-col overflow-y-auto pt-6"
className="min-h-0 pt-6 flex w-full flex-1 flex-col overflow-y-auto"
id="workspace-bottom-group"
aria-hidden
/>
@ -568,7 +568,7 @@ export default function Workspace({
<div
className={cn(
'flex h-full flex-col overflow-hidden',
SESSION_SIDE_PANEL_CONTENT_WIDTH_CLASS
PROJECT_SIDE_PANEL_CONTENT_WIDTH_CLASS
)}
>
<WorkspaceCoworkPanel
@ -580,13 +580,13 @@ export default function Workspace({
) : null;
return (
<div className="relative z-[1] flex h-full min-h-0 w-full min-w-0 flex-row overflow-hidden">
<div className="min-h-0 min-w-0 relative z-[1] flex h-full w-full flex-row overflow-hidden">
{/* Center section: header + content */}
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
<div className="min-h-0 min-w-0 flex flex-1 flex-col overflow-hidden">
{/* Header toolbar */}
<div
className={cn(
'relative flex h-[44px] w-full shrink-0 flex-row items-center justify-start gap-1',
'gap-1 relative flex h-[44px] w-full shrink-0 flex-row items-center justify-start',
!isNewProjectVariant && 'px-3'
)}
>
@ -605,8 +605,8 @@ export default function Workspace({
</Button>
)}
{!isNewProjectVariant && workspaceSubPage !== null && (
<div className="pointer-events-none absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
<span className="block max-w-[60vw] truncate text-center !text-label-sm font-semibold text-ds-text-neutral-default-default">
<div className="pointer-events-none absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<span className="!text-label-sm font-semibold text-ds-text-neutral-default-default block max-w-[60vw] truncate text-center">
{SUB_PAGE_TITLES[workspaceSubPage]}
</span>
</div>
@ -635,7 +635,7 @@ export default function Workspace({
</div>
{/* Content */}
<div className="flex min-h-0 w-full flex-1 flex-col overflow-hidden">
<div className="min-h-0 flex w-full flex-1 flex-col overflow-hidden">
{/* Sub-pages */}
{!isNewProjectVariant && workspaceSubPage === 'all-sessions' && (
<WorkspaceAllSessions
@ -658,17 +658,17 @@ export default function Workspace({
{/* Main content (hidden when a sub-page is active) */}
{workspaceSubPage === null && (
<div className="relative flex min-h-0 min-w-0 flex-1 flex-col items-stretch overflow-hidden">
<div className="min-h-0 min-w-0 relative flex flex-1 flex-col items-stretch overflow-hidden">
<div
className={cn(
'flex min-h-0 w-full flex-1 flex-col',
'min-h-0 flex w-full flex-1 flex-col',
!isNewProjectVariant && 'px-3'
)}
>
{composer}
<div
className="flex min-h-0 w-full flex-1 flex-col overflow-y-auto pt-6"
className="min-h-0 pt-6 flex w-full flex-1 flex-col overflow-y-auto"
id="workspace-bottom-group"
>
{showBottomExamplePrompts ? (

View file

@ -13,7 +13,7 @@
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
/**
* Scoped font style for HTML fragments rendered in the main document (e.g. CSV in FolderComponent).
* Scoped font style for HTML fragments rendered in the main document (e.g. CSV in ContextComponent).
* Uses a wrapper class so styles do not leak to the rest of the app (sidebar, file list, etc.).
*/
const SCOPED_FONT_STYLE = `<style data-eigent-fonts>

View file

@ -36,7 +36,7 @@ const TAB_ALIASES: Record<string, HistoryTabId> = {
spaces: 'home',
};
export default function History() {
export default function HomePage() {
const { t } = useTranslation();
const navigate = useNavigate();
const [searchParams] = useSearchParams();
@ -123,10 +123,10 @@ export default function History() {
};
return (
<div className="flex h-full w-full flex-1 flex-col px-1 pb-1 pt-10">
<div className="px-1 pb-1 pt-10 flex h-full w-full flex-1 flex-col">
<div
ref={scrollContainerRef}
className="scrollbar-hide h-full overflow-y-auto rounded-2xl bg-ds-bg-neutral-subtle-default"
className="scrollbar-hide rounded-2xl bg-ds-bg-neutral-subtle-default h-full overflow-y-auto"
>
{/* alert dialog */}
<AlertDialog
@ -139,17 +139,17 @@ export default function History() {
cancelText={t('layout.cancel')}
/>
{/* welcome text */}
<div className="flex w-full flex-row bg-gradient-to-b from-ds-bg-neutral-default-default to-ds-bg-neutral-default-default px-[74px] py-8">
<p className="m-0 inline-flex flex-wrap items-baseline gap-2">
<div className="from-ds-bg-neutral-default-default to-ds-bg-neutral-default-default py-8 flex w-full flex-row bg-gradient-to-b px-[74px]">
<p className="m-0 gap-2 inline-flex flex-wrap items-baseline">
<WordCarousel
words={[t(timeGreetingKey)]}
className="history-welcome-headline text-heading-xl font-bold not-italic tracking-tight"
className="history-welcome-headline text-heading-xl font-bold tracking-tight not-italic"
rotateIntervalMs={100}
sweepDurationMs={2000}
sweepOnce
gradient="linear-gradient(90deg, var(--ds-text-brand-subtle-default) 0%, var(--ds-text-brand-muted-default) 100%)"
/>
<span className="history-welcome-headline text-heading-xl font-bold italic tracking-tight text-ds-text-brand-default-default">
<span className="history-welcome-headline text-heading-xl font-bold tracking-tight text-ds-text-brand-default-default italic">
{`, ${welcomeName} !`}
</span>
</p>
@ -157,7 +157,7 @@ export default function History() {
{/* Navbar */}
{/* -top-px avoids a visible hairline: at top-0 subpixel rounding can leave a gap; */}
<div
className={`border-b-1 sticky -top-px z-20 flex flex-col items-center justify-between border-x-0 border-t-0 border-solid border-ds-border-neutral-subtle-disabled bg-ds-bg-neutral-default-default px-[70px] pt-2`}
className={`border-ds-border-neutral-subtle-disabled bg-ds-bg-neutral-default-default pt-2 sticky -top-px z-20 flex flex-col items-center justify-between border-x-0 border-t-0 border-b-1 border-solid px-[70px]`}
>
<div className="mx-auto flex w-full flex-row items-center">
<HistoryTabsNav activeTab={activeTab} onChange={handleTabChange} />
@ -176,7 +176,7 @@ export default function History() {
</div>
)}
<div className="m-auto flex h-auto w-full max-w-[1020px] flex-1 flex-col">
<div className="flex h-auto w-full px-6 pb-[120px] [--home-hub-history-tabs-offset:49px]">
<div className="px-6 flex h-auto w-full pb-[120px] [--home-hub-history-tabs-offset:49px]">
{visitedTabs.includes('agents') && (
<div
className={activeTab === 'agents' ? 'contents' : 'hidden'}

View file

@ -20,14 +20,14 @@ import {
GridPatternBackground,
RuledLinesBackground,
} from '@/components/Background';
import Context from '@/components/Context';
import { WorkspaceDispatch } from '@/components/Dispatch';
import Folder from '@/components/Folder';
import ProjectPageSidebar from '@/components/ProjectPageSidebar';
import PageSidebar from '@/components/PageSidebar';
import {
PROJECT_SIDEBAR_FOLD_SPRING,
PROJECT_SIDEBAR_RAIL_WIDTH_PX,
} from '@/components/ProjectPageSidebar/constants';
import SessionGroup from '@/components/Session/SessionGroup';
} from '@/components/PageSidebar/constants';
import ProjectGroup from '@/components/Project/ProjectGroup';
import TriggerPanel from '@/components/Trigger';
import UpdateElectron from '@/components/update';
import Workspace from '@/components/Workspace';
@ -56,7 +56,7 @@ import {
type TriggerSortKey,
} from '../components/Trigger/Triggers';
import Session from '@/components/Session';
import Project from '@/components/Project';
import {
ResizableHandle,
ResizablePanel,
@ -692,7 +692,7 @@ export default function WorkspacePage() {
<div className={workspaceMainContentClass}>
{workspacePatternOverlayEl}
<div className={workspaceMainForegroundClass}>
<Session />
<Project />
</div>
</div>
);
@ -701,7 +701,7 @@ export default function WorkspacePage() {
<div className={workspaceMainContentClass}>
{workspacePatternOverlayEl}
<div className={workspaceMainForegroundClass}>
<Session isNewProject />
<Project isNewProject />
</div>
</div>
);
@ -714,7 +714,7 @@ export default function WorkspacePage() {
case 'inbox':
return (
<div className={mainPanelContentClass}>
<Folder />
<Context />
</div>
);
case 'triggers':
@ -733,7 +733,7 @@ export default function WorkspacePage() {
);
case 'runs':
return (
<SessionGroup
<ProjectGroup
className={mainPanelContentClass}
tasks={chatStore?.tasks ?? {}}
activeSessionId={chatStore?.activeTaskId ?? undefined}
@ -771,7 +771,7 @@ export default function WorkspacePage() {
maxSize={sidebarPct.max}
className="min-h-0 min-w-0 pl-1 py-1"
>
<ProjectPageSidebar chatStore={chatStore} />
<PageSidebar chatStore={chatStore} />
</ResizablePanel>
<ResizableHandle
className={cn(

View file

@ -23,7 +23,7 @@ import Layout from '@/components/Layout';
const Login = lazy(() => import('@/pages/Login'));
const Signup = lazy(() => import('@/pages/SignUp'));
const Workspace = lazy(() => import('@/pages/Workspace'));
const History = lazy(() => import('@/pages/History'));
const HomePage = lazy(() => import('@/pages/HomePage'));
const NotFound = lazy(() => import('@/pages/NotFound'));
const RemoteControl = lazy(() => import('@/pages/RemoteControl'));
@ -138,7 +138,7 @@ const ProtectedRoute = () => {
if (state.loading || !state.initialized) {
return (
<div className="flex h-screen items-center justify-center">
<div className="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600"></div>
<div className="h-8 w-8 animate-spin border-blue-600 rounded-full border-b-2"></div>
</div>
);
}
@ -163,14 +163,14 @@ const AppRoutes = () => (
<Route element={<ProtectedRoute />}>
<Route element={<Layout />}>
<Route path="/" element={<Workspace />} />
<Route path="/history" element={<History />} />
<Route path="/home" element={<HomePage />} />
<Route
path="/setting"
element={<Navigate to="/history?tab=settings" replace />}
element={<Navigate to="/home?tab=settings" replace />}
/>
<Route
path="/setting/*"
element={<Navigate to="/history?tab=settings" replace />}
element={<Navigate to="/home?tab=settings" replace />}
/>
</Route>
</Route>