fix: lint errors + redundant css

This commit is contained in:
Siddhant Rai committed 2026-03-28 15:02:16 +05:30
1 parent 174dee0fe6
commit 193ca6fd63
65 files changed
+561 -543

No files matched your search

+1 -1
View File
@@ -44,7 +44,7 @@ export default function Hero({
<button <button
key={key} key={key}
onClick={() => handleQuestion({ question: demo.query })} onClick={() => handleQuestion({ question: demo.query })}
className={`border-border text-foreground hover:bg-muted dark:hover:bg-muted/50 bg-card dark:bg-transparent w-full rounded-[66px] border px-6 py-3.5 text-left transition-colors ${key >= 2 ? 'hidden md:block' : ''}`} className={`border-border text-foreground hover:bg-muted dark:hover:bg-muted/50 bg-card w-full rounded-[66px] border px-6 py-3.5 text-left transition-colors dark:bg-transparent ${key >= 2 ? 'hidden md:block' : ''}`}
> >
<p className="text-black-1000 dark:text-foreground mb-2 font-semibold"> <p className="text-black-1000 dark:text-foreground mb-2 font-semibold">
{demo.header} {demo.header}
+8 -12
View File
@@ -394,7 +394,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
</NavLink> </NavLink>
<div <div
id="conversationsMainDiv" id="conversationsMainDiv"
className="mb-auto h-[78vh] overflow-x-hidden overflow-y-auto scrollbar-overlay dark:text-white" className="scrollbar-overlay mb-auto h-[78vh] overflow-x-hidden overflow-y-auto dark:text-white"
> >
{conversations?.loading && !isDeletingConversation && ( {conversations?.loading && !isDeletingConversation && (
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform"> <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform">
@@ -540,7 +540,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
}} }}
to="/settings" to="/settings"
className={({ isActive }) => className={({ isActive }) =>
`mx-4 my-auto flex h-9 cursor-pointer items-center gap-4 rounded-3xl hover:bg-sidebar-accent ${ `hover:bg-sidebar-accent mx-4 my-auto flex h-9 cursor-pointer items-center gap-4 rounded-3xl ${
isActive ? 'bg-sidebar-accent' : '' isActive ? 'bg-sidebar-accent' : ''
}` }`
} }
@@ -565,9 +565,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<NavLink <NavLink
target="_blank" target="_blank"
to={'https://discord.gg/vN7YFfdMpj'} to={'https://discord.gg/vN7YFfdMpj'}
className={ className={'hover:bg-sidebar-accent rounded-full'}
'rounded-full hover:bg-sidebar-accent'
}
> >
<img <img
src={Discord} src={Discord}
@@ -580,9 +578,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<NavLink <NavLink
target="_blank" target="_blank"
to={'https://x.com/docsgptai'} to={'https://x.com/docsgptai'}
className={ className={'hover:bg-sidebar-accent rounded-full'}
'rounded-full hover:bg-sidebar-accent'
}
> >
<img <img
src={Twitter} src={Twitter}
@@ -595,9 +591,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<NavLink <NavLink
target="_blank" target="_blank"
to={'https://github.com/arc53/docsgpt'} to={'https://github.com/arc53/docsgpt'}
className={ className={'hover:bg-sidebar-accent rounded-full'}
'rounded-full hover:bg-sidebar-accent'
}
> >
<img <img
src={Github} src={Github}
@@ -624,7 +618,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
className="w-7 filter dark:invert" className="w-7 filter dark:invert"
/> />
</button> </button>
<div className="text-muted-foreground text-[20px] font-medium">DocsGPT</div> <div className="text-muted-foreground text-[20px] font-medium">
DocsGPT
</div>
</div> </div>
</div> </div>
<DeleteConvModal <DeleteConvModal
+1 -1
View File
@@ -6,7 +6,7 @@ export default function PageNotFound() {
return ( return (
<div className="bg-background grid min-h-screen"> <div className="bg-background grid min-h-screen">
<p className="text-foreground mx-auto my-auto mt-20 flex w-full max-w-6xl flex-col place-items-center gap-6 rounded-3xl bg-gray-100 p-6 lg:p-10 xl:p-16 dark:bg-card"> <p className="text-foreground dark:bg-card mx-auto my-auto mt-20 flex w-full max-w-6xl flex-col place-items-center gap-6 rounded-3xl bg-gray-100 p-6 lg:p-10 xl:p-16">
<h1>{t('pageNotFound.title')}</h1> <h1>{t('pageNotFound.title')}</h1>
<p>{t('pageNotFound.message')}</p> <p>{t('pageNotFound.message')}</p>
<button className="pointer-cursor bg-blue-1000 hover:bg-blue-3000 mr-4 flex cursor-pointer items-center justify-center rounded-full px-4 py-2 text-white transition-colors duration-100"> <button className="pointer-cursor bg-blue-1000 hover:bg-blue-3000 mr-4 flex cursor-pointer items-center justify-center rounded-full px-4 py-2 text-white transition-colors duration-100">
+5 -5
View File
@@ -251,7 +251,7 @@ export default function AgentCard({
}; };
return ( return (
<div <div
className={`relative flex h-44 flex-col justify-between rounded-[1.2rem] bg-muted px-4 py-5 hover:bg-accent sm:w-48 sm:px-6 ${agent.status === 'published' && 'cursor-pointer'}`} className={`bg-muted hover:bg-accent relative flex h-44 flex-col justify-between rounded-[1.2rem] px-4 py-5 sm:w-48 sm:px-6 ${agent.status === 'published' && 'cursor-pointer'}`}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
handleClick(); handleClick();
@@ -283,17 +283,17 @@ export default function AgentCard({
className="h-7 w-7 rounded-full object-contain" className="h-7 w-7 rounded-full object-contain"
/> />
{agent.status === 'draft' && ( {agent.status === 'draft' && (
<p className="text-xs text-foreground opacity-50">{`(Draft)`}</p> <p className="text-foreground text-xs opacity-50">{`(Draft)`}</p>
)} )}
</div> </div>
<div className="mt-2"> <div className="mt-2">
<p <p
title={agent.name} title={agent.name}
className="truncate px-1 text-[13px] leading-relaxed font-semibold text-foreground capitalize" className="text-foreground truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
> >
{agent.name} {agent.name}
</p> </p>
<p className="dark:text-muted-foreground mt-1 h-20 overflow-auto px-1 text-[12px] leading-relaxed text-muted-foreground"> <p className="dark:text-muted-foreground text-muted-foreground mt-1 h-20 overflow-auto px-1 text-[12px] leading-relaxed">
{agent.description} {agent.description}
</p> </p>
</div> </div>
@@ -320,4 +320,4 @@ export default function AgentCard({
/> />
</div> </div>
); );
} }
+2 -2
View File
@@ -41,7 +41,7 @@ export default function AgentLogs() {
<div className="p-4 md:p-12"> <div className="p-4 md:p-12">
<div className="flex items-center gap-3 px-4"> <div className="flex items-center gap-3 px-4">
<button <button
className="rounded-full border border-border p-3 text-sm text-muted-foreground hover:bg-accent" className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
onClick={() => navigate('/agents')} onClick={() => navigate('/agents')}
> >
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" /> <img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
@@ -59,7 +59,7 @@ export default function AgentLogs() {
{agent && ( {agent && (
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<p className="text-foreground">{agent.name}</p> <p className="text-foreground">{agent.name}</p>
<p className="text-xs text-muted-foreground"> <p className="text-muted-foreground text-xs">
{agent.last_used_at {agent.last_used_at
? t('agents.logs.lastUsedAt') + ? t('agents.logs.lastUsedAt') +
' ' + ' ' +
+12 -12
View File
@@ -162,7 +162,7 @@ export default function AgentsList() {
<h1 className="text-foreground mb-0 text-[32px] font-bold lg:text-[40px]"> <h1 className="text-foreground mb-0 text-[32px] font-bold lg:text-[40px]">
{t('agents.title')} {t('agents.title')}
</h1> </h1>
<p className="mt-5 text-[15px] leading-6 text-muted-foreground"> <p className="text-muted-foreground mt-5 text-[15px] leading-6">
{t('agents.description')} {t('agents.description')}
</p> </p>
@@ -178,7 +178,7 @@ export default function AgentsList() {
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
placeholder={t('agents.searchPlaceholder')} placeholder={t('agents.searchPlaceholder')}
className="h-11 w-full rounded-full border border-border bg-card py-2 pr-5 pl-11 text-sm text-foreground shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none placeholder:text-muted-foreground focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none" className="border-border bg-card text-foreground placeholder:text-muted-foreground h-11 w-full rounded-full border py-2 pr-5 pl-11 text-sm shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none"
/> />
</div> </div>
@@ -190,7 +190,7 @@ export default function AgentsList() {
className={`rounded-full px-4 py-2 text-sm transition-colors ${ className={`rounded-full px-4 py-2 text-sm transition-colors ${
activeFilter === tab.id activeFilter === tab.id
? 'bg-border text-foreground dark:bg-accent dark:text-white' ? 'bg-border text-foreground dark:bg-accent dark:text-white'
: 'dark:text-gray bg-transparent text-muted-foreground hover:bg-accent/50' : 'dark:text-gray text-muted-foreground hover:bg-accent/50 bg-transparent'
}`} }`}
> >
{t(tab.labelKey)} {t(tab.labelKey)}
@@ -224,7 +224,7 @@ export default function AgentsList() {
))} ))}
{showSearchEmptyState && ( {showSearchEmptyState && (
<div className="mt-12 flex flex-col items-center justify-center gap-2 text-muted-foreground"> <div className="text-muted-foreground mt-12 flex flex-col items-center justify-center gap-2">
<p className="text-lg">{t('agents.noSearchResults')}</p> <p className="text-lg">{t('agents.noSearchResults')}</p>
<p className="text-sm">{t('agents.tryDifferentSearch')}</p> <p className="text-sm">{t('agents.tryDifferentSearch')}</p>
</div> </div>
@@ -399,7 +399,7 @@ function AgentSection({
if (isFilteredView && isSearchingWithNoResults) { if (isFilteredView && isSearchingWithNoResults) {
return ( return (
<div className="mt-12 flex flex-col items-center justify-center gap-2 text-muted-foreground"> <div className="text-muted-foreground mt-12 flex flex-col items-center justify-center gap-2">
<p className="text-lg">{t('agents.noSearchResults')}</p> <p className="text-lg">{t('agents.noSearchResults')}</p>
<p className="text-sm">{t('agents.tryDifferentSearch')}</p> <p className="text-sm">{t('agents.tryDifferentSearch')}</p>
</div> </div>
@@ -408,7 +408,7 @@ function AgentSection({
if (isFilteredView && hasNoAgentsAtAll) { if (isFilteredView && hasNoAgentsAtAll) {
return ( return (
<div className="mt-12 flex flex-col items-center justify-center gap-3 text-muted-foreground"> <div className="text-muted-foreground mt-12 flex flex-col items-center justify-center gap-3">
<p>{t(`agents.sections.${config.id}.emptyState`)}</p> <p>{t(`agents.sections.${config.id}.emptyState`)}</p>
{config.showNewAgentButton && ( {config.showNewAgentButton && (
<button <button
@@ -456,7 +456,7 @@ function AgentSection({
<div className="mt-8 flex flex-col gap-4"> <div className="mt-8 flex flex-col gap-4">
<div className="flex w-full flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"> <div className="flex w-full flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<h2 className="flex flex-wrap items-center gap-2 text-[18px] font-semibold text-foreground"> <h2 className="text-foreground flex flex-wrap items-center gap-2 text-[18px] font-semibold">
{config.id === 'user' && folderPath.length > 0 ? ( {config.id === 'user' && folderPath.length > 0 ? (
<> <>
<button <button
@@ -485,7 +485,7 @@ function AgentSection({
t(`agents.sections.${config.id}.title`) t(`agents.sections.${config.id}.title`)
)} )}
</h2> </h2>
<p className="text-[13px] text-muted-foreground"> <p className="text-muted-foreground text-[13px]">
{t(`agents.sections.${config.id}.description`)} {t(`agents.sections.${config.id}.description`)}
</p> </p>
</div> </div>
@@ -513,12 +513,12 @@ function AgentSection({
} }
}} }}
placeholder={t('agents.folders.newFolder')} placeholder={t('agents.folders.newFolder')}
className="w-28 rounded-full border border-border bg-card px-4 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground sm:w-auto" className="border-border bg-card text-foreground placeholder:text-muted-foreground w-28 rounded-full border px-4 py-2 text-sm outline-none sm:w-auto"
autoFocus autoFocus
/> />
) : ( ) : (
<button <button
className="shrink-0 rounded-full border border-border bg-card px-4 py-2 text-sm whitespace-nowrap text-foreground hover:bg-accent" className="border-border bg-card text-foreground hover:bg-accent shrink-0 rounded-full border px-4 py-2 text-sm whitespace-nowrap"
onClick={() => { onClick={() => {
setIsCreatingFolder(true); setIsCreatingFolder(true);
setTimeout(() => newFolderInputRef.current?.focus(), 0); setTimeout(() => newFolderInputRef.current?.focus(), 0);
@@ -579,7 +579,7 @@ function AgentSection({
))} ))}
</div> </div>
) : hasNoAgentsAtAll && currentLevelFolders.length === 0 ? ( ) : hasNoAgentsAtAll && currentLevelFolders.length === 0 ? (
<div className="flex h-40 w-full flex-col items-center justify-center gap-3 text-muted-foreground"> <div className="text-muted-foreground flex h-40 w-full flex-col items-center justify-center gap-3">
<p> <p>
{currentFolderId {currentFolderId
? t('agents.folders.empty') ? t('agents.folders.empty')
@@ -603,4 +603,4 @@ function AgentSection({
</div> </div>
</div> </div>
); );
} }
+3 -5
View File
@@ -70,17 +70,15 @@ export default function FolderCard({
<> <>
<div <div
className={`relative flex cursor-pointer items-center justify-between rounded-[1.2rem] px-4 py-3 sm:w-48 ${ className={`relative flex cursor-pointer items-center justify-between rounded-[1.2rem] px-4 py-3 sm:w-48 ${
isExpanded isExpanded ? 'bg-accent' : 'bg-muted hover:bg-accent'
? 'bg-accent'
: 'bg-muted hover:bg-accent'
}`} }`}
onClick={() => onToggleExpand(folder.id)} onClick={() => onToggleExpand(folder.id)}
> >
<div className="flex items-center gap-2 overflow-hidden"> <div className="flex items-center gap-2 overflow-hidden">
<span className="truncate text-sm font-medium text-foreground"> <span className="text-foreground truncate text-sm font-medium">
{folder.name} {folder.name}
</span> </span>
<span className="shrink-0 text-xs text-muted-foreground"> <span className="text-muted-foreground shrink-0 text-xs">
({agentCount}) ({agentCount})
</span> </span>
</div> </div>
+1 -1
View File
@@ -143,7 +143,7 @@ export default function SharedAgent() {
alt="No agent found" alt="No agent found"
className="mx-auto mb-6 h-32 w-32" className="mx-auto mb-6 h-32 w-32"
/> />
<p className="text-center text-lg text-muted-foreground"> <p className="text-muted-foreground text-center text-lg">
{t('agents.shared.notFound')} {t('agents.shared.notFound')}
</p> </p>
</div> </div>
+2 -2
View File
@@ -21,7 +21,7 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
<h2 className="text-foreground text-base font-semibold sm:text-lg"> <h2 className="text-foreground text-base font-semibold sm:text-lg">
{agent.name} {agent.name}
</h2> </h2>
<p className="overflow-y-auto text-xs text-wrap break-all text-muted-foreground sm:text-sm"> <p className="text-muted-foreground overflow-y-auto text-xs text-wrap break-all sm:text-sm">
{agent.description} {agent.description}
</p> </p>
</div> </div>
@@ -34,7 +34,7 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
</p> </p>
)} )}
{agent.shared_metadata?.shared_at && ( {agent.shared_metadata?.shared_at && (
<p className="text-xs font-light text-muted-foreground sm:text-sm"> <p className="text-muted-foreground text-xs font-light sm:text-sm">
Shared on{' '} Shared on{' '}
{new Date(agent.shared_metadata.shared_at).toLocaleString( {new Date(agent.shared_metadata.shared_at).toLocaleString(
'en-US', 'en-US',
+27 -30
View File
@@ -575,12 +575,12 @@ function WorkflowBuilderInner() {
]); ]);
return ( return (
<div className="flex h-screen w-full flex-col bg-background"> <div className="bg-background flex h-screen w-full flex-col">
<div className="flex items-center justify-between border-b border-border bg-card px-6 py-4"> <div className="border-border bg-card flex items-center justify-between border-b px-6 py-4">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<button <button
onClick={() => navigate('/agents')} onClick={() => navigate('/agents')}
className="rounded-full border border-border p-3 text-sm text-muted-foreground hover:bg-accent" className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
> >
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" /> <img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button> </button>
@@ -609,7 +609,7 @@ function WorkflowBuilderInner() {
{showWorkflowSettings && ( {showWorkflowSettings && (
<div <div
ref={workflowSettingsRef} ref={workflowSettingsRef}
className="absolute top-full left-0 z-50 mt-2 w-80 rounded-xl border border-border bg-card p-4 shadow-lg" className="border-border bg-card absolute top-full left-0 z-50 mt-2 w-80 rounded-xl border p-4 shadow-lg"
> >
<div className="mb-3"> <div className="mb-3">
<label className="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300"> <label className="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">
@@ -619,7 +619,7 @@ function WorkflowBuilderInner() {
type="text" type="text"
value={workflowName} value={workflowName}
onChange={(e) => setWorkflowName(e.target.value)} onChange={(e) => setWorkflowName(e.target.value)}
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm outline-none focus:ring-2"
placeholder="Enter workflow name" placeholder="Enter workflow name"
/> />
</div> </div>
@@ -630,14 +630,14 @@ function WorkflowBuilderInner() {
<textarea <textarea
value={workflowDescription} value={workflowDescription}
onChange={(e) => setWorkflowDescription(e.target.value)} onChange={(e) => setWorkflowDescription(e.target.value)}
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm outline-none focus:ring-2"
rows={3} rows={3}
placeholder="Describe what this workflow does" placeholder="Describe what this workflow does"
/> />
</div> </div>
<button <button
onClick={() => setShowWorkflowSettings(false)} onClick={() => setShowWorkflowSettings(false)}
className="w-full rounded-lg bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90" className="bg-primary text-primary-foreground hover:bg-primary/90 w-full rounded-lg px-3 py-2 text-sm font-medium"
> >
Done Done
</button> </button>
@@ -656,7 +656,7 @@ function WorkflowBuilderInner() {
} }
setShowPreview(true); setShowPreview(true);
}} }}
className="flex items-center gap-2 rounded-full border border-border bg-card px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-accent" className="border-border bg-card text-foreground hover:bg-accent flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium transition-colors"
> >
<Play size={16} /> <Play size={16} />
Preview Preview
@@ -664,7 +664,7 @@ function WorkflowBuilderInner() {
<button <button
onClick={handlePublish} onClick={handlePublish}
disabled={isPublishing} disabled={isPublishing}
className="rounded-full bg-primary px-6 py-2 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90 disabled:opacity-50" className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-full px-6 py-2 text-sm font-medium shadow-sm transition-colors disabled:opacity-50"
> >
{isPublishing ? 'Publishing...' : 'Publish'} {isPublishing ? 'Publishing...' : 'Publish'}
</button> </button>
@@ -701,20 +701,20 @@ function WorkflowBuilderInner() {
)} )}
<div className="flex flex-1 overflow-hidden"> <div className="flex flex-1 overflow-hidden">
<div className="flex w-64 flex-col gap-6 border-r border-border bg-muted p-4"> <div className="border-border bg-muted flex w-64 flex-col gap-6 border-r p-4">
<div> <div>
<h3 className="mb-3 text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400"> <h3 className="mb-3 text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400">
Core Nodes Core Nodes
</h3> </h3>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div <div
className="group flex cursor-move items-center gap-3 rounded-full border border-border bg-card px-4 py-3 shadow-sm transition-all hover:bg-accent hover:shadow-md" className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable draggable
onDragStart={(e) => onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'agent') e.dataTransfer.setData('application/reactflow', 'agent')
} }
> >
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary transition-colors group-hover:bg-primary group-hover:text-primary-foreground"> <div className="bg-primary/10 text-primary group-hover:bg-primary group-hover:text-primary-foreground flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition-colors">
<Bot size={18} /> <Bot size={18} />
</div> </div>
<span className="text-sm font-medium text-gray-700 dark:text-gray-200"> <span className="text-sm font-medium text-gray-700 dark:text-gray-200">
@@ -722,7 +722,7 @@ function WorkflowBuilderInner() {
</span> </span>
</div> </div>
<div <div
className="group flex cursor-move items-center gap-3 rounded-full border border-border bg-card px-4 py-3 shadow-sm transition-all hover:bg-accent hover:shadow-md" className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable draggable
onDragStart={(e) => onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'end') e.dataTransfer.setData('application/reactflow', 'end')
@@ -736,7 +736,7 @@ function WorkflowBuilderInner() {
</span> </span>
</div> </div>
<div <div
className="group flex cursor-move items-center gap-3 rounded-full border border-border bg-card px-4 py-3 shadow-sm transition-all hover:bg-accent hover:shadow-md" className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable draggable
onDragStart={(e) => onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'note') e.dataTransfer.setData('application/reactflow', 'note')
@@ -758,7 +758,7 @@ function WorkflowBuilderInner() {
</h3> </h3>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div <div
className="group flex cursor-move items-center gap-3 rounded-full border border-border bg-card px-4 py-3 shadow-sm transition-all hover:bg-accent hover:shadow-md" className="group border-border bg-card hover:bg-accent flex cursor-move items-center gap-3 rounded-full border px-4 py-3 shadow-sm transition-all hover:shadow-md"
draggable draggable
onDragStart={(e) => onDragStart={(e) =>
e.dataTransfer.setData('application/reactflow', 'state') e.dataTransfer.setData('application/reactflow', 'state')
@@ -780,10 +780,7 @@ function WorkflowBuilderInner() {
</div> </div>
</div> </div>
<div <div ref={reactFlowWrapper} className="bg-muted relative flex-1">
ref={reactFlowWrapper}
className="relative flex-1 bg-muted"
>
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}
@@ -803,9 +800,9 @@ function WorkflowBuilderInner() {
{showNodeConfig && selectedNode && ( {showNodeConfig && selectedNode && (
<div <div
ref={configPanelRef} ref={configPanelRef}
className="absolute top-4 right-4 w-96 rounded-2xl border border-border bg-card shadow-[0px_4px_40px_-3px_#0000001A]" className="border-border bg-card absolute top-4 right-4 w-96 rounded-2xl border shadow-[0px_4px_40px_-3px_#0000001A]"
> >
<div className="flex items-center justify-between border-b border-border p-4"> <div className="border-border flex items-center justify-between border-b p-4">
<h3 className="font-semibold text-gray-900 dark:text-white"> <h3 className="font-semibold text-gray-900 dark:text-white">
{selectedNode.type === 'start' && 'Start Node'} {selectedNode.type === 'start' && 'Start Node'}
{selectedNode.type === 'end' && 'End Node'} {selectedNode.type === 'end' && 'End Node'}
@@ -823,7 +820,7 @@ function WorkflowBuilderInner() {
<div className="max-h-[calc(100vh-200px)] overflow-y-auto p-4"> <div className="max-h-[calc(100vh-200px)] overflow-y-auto p-4">
<div className="mb-4 flex flex-col gap-2"> <div className="mb-4 flex flex-col gap-2">
<div className="rounded-lg bg-muted p-3"> <div className="bg-muted rounded-lg p-3">
<div className="mb-1 text-xs text-gray-500 dark:text-gray-400"> <div className="mb-1 text-xs text-gray-500 dark:text-gray-400">
Node ID Node ID
</div> </div>
@@ -852,7 +849,7 @@ function WorkflowBuilderInner() {
label: e.target.value, label: e.target.value,
}) })
} }
className="w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground transition-all outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="Enter node title" placeholder="Enter node title"
/> />
</div> </div>
@@ -936,7 +933,7 @@ function WorkflowBuilderInner() {
}, },
}) })
} }
className="w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground transition-all outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
rows={3} rows={3}
placeholder="System prompt for the agent" placeholder="System prompt for the agent"
/> />
@@ -958,7 +955,7 @@ function WorkflowBuilderInner() {
}, },
}) })
} }
className="w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground transition-all outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
rows={4} rows={4}
placeholder="Use {{variable}} for dynamic content" placeholder="Use {{variable}} for dynamic content"
/> />
@@ -981,7 +978,7 @@ function WorkflowBuilderInner() {
}, },
}) })
} }
className="w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground transition-all outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="Variable name for output" placeholder="Variable name for output"
/> />
</div> </div>
@@ -1048,7 +1045,7 @@ function WorkflowBuilderInner() {
content: e.target.value, content: e.target.value,
}) })
} }
className="w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground transition-all outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
rows={4} rows={4}
placeholder="Enter note content" placeholder="Enter note content"
/> />
@@ -1069,7 +1066,7 @@ function WorkflowBuilderInner() {
variable: e.target.value, variable: e.target.value,
}) })
} }
className="w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground transition-all outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="e.g. analysis_type" placeholder="e.g. analysis_type"
/> />
</div> </div>
@@ -1085,7 +1082,7 @@ function WorkflowBuilderInner() {
value: e.target.value, value: e.target.value,
}) })
} }
className="w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground transition-all outline-none focus:ring-2 focus:ring-ring" className="border-border bg-card text-foreground focus:ring-ring w-full rounded-xl border px-3 py-2 text-sm transition-all outline-none focus:ring-2"
placeholder="e.g. price_check" placeholder="e.g. price_check"
/> />
</div> </div>
@@ -1116,7 +1113,7 @@ function WorkflowBuilderInner() {
<SheetContent <SheetContent
side="right" side="right"
showCloseButton={false} showCloseButton={false}
className="w-full max-w-none border-border bg-card p-0 sm:max-w-[600px] md:max-w-[700px] lg:max-w-[800px]" className="border-border bg-card w-full max-w-none p-0 sm:max-w-[600px] md:max-w-[700px] lg:max-w-[800px]"
> >
<WorkflowPreview <WorkflowPreview
workflowData={{ workflowData={{
+1 -1
View File
@@ -41,4 +41,4 @@ export const agentSectionsConfig = [
selectData: selectSharedAgents, selectData: selectSharedAgents,
updateAction: setSharedAgents, updateAction: setSharedAgents,
}, },
]; ];
@@ -33,7 +33,7 @@ export default function AgentTypeModal({
onClick={onClose} onClick={onClose}
> >
<div <div
className="relative w-full max-w-lg rounded-xl bg-card p-8 shadow-2xl" className="bg-card relative w-full max-w-lg rounded-xl p-8 shadow-2xl"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<button <button
@@ -53,7 +53,7 @@ export default function AgentTypeModal({
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<button <button
onClick={() => handleSelect('normal')} onClick={() => handleSelect('normal')}
className="hover:border-primary hover:bg-primary/5 dark:hover:border-primary dark:hover:bg-primary/10 group flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all dark:border-border" className="hover:border-primary hover:bg-primary/5 dark:hover:border-primary dark:hover:bg-primary/10 group dark:border-border flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all"
> >
<div className="dark:bg-primary/20 bg-primary/10 text-primary group-hover:bg-primary/90 flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300"> <div className="dark:bg-primary/20 bg-primary/10 text-primary group-hover:bg-primary/90 flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300">
<Bot size={28} /> <Bot size={28} />
@@ -71,7 +71,7 @@ export default function AgentTypeModal({
<button <button
onClick={() => handleSelect('workflow')} onClick={() => handleSelect('workflow')}
className="hover:border-primary hover:bg-primary/5 dark:hover:border-primary dark:hover:bg-primary/10 group flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all dark:border-border" className="hover:border-primary hover:bg-primary/5 dark:hover:border-primary dark:hover:bg-primary/10 group dark:border-border flex items-start gap-5 rounded-xl border-2 border-gray-200 p-5 text-left transition-all"
> >
<div className="dark:bg-primary/20 bg-primary/10 text-primary group-hover:bg-primary flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300"> <div className="dark:bg-primary/20 bg-primary/10 text-primary group-hover:bg-primary flex h-14 w-14 shrink-0 items-center justify-center rounded-xl transition-colors group-hover:text-white dark:text-purple-300">
<Workflow size={28} /> <Workflow size={28} />
+1 -1
View File
@@ -18,4 +18,4 @@ export default function Agents() {
<Route path="/workflow/edit/:agentId" element={<WorkflowBuilder />} /> <Route path="/workflow/edit/:agentId" element={<WorkflowBuilder />} />
</Routes> </Routes>
); );
} }
+7 -1
View File
@@ -1,4 +1,10 @@
export type NodeType = 'start' | 'end' | 'agent' | 'note' | 'state' | 'condition'; export type NodeType =
| 'start'
| 'end'
| 'agent'
| 'note'
| 'state'
| 'condition';
export interface ConditionCase { export interface ConditionCase {
name?: string; name?: string;
@@ -1428,7 +1428,7 @@ function WorkflowBuilderInner() {
]} ]}
className="border-border rounded-lg border-2 border-dashed p-3 text-center transition-colors" className="border-border rounded-lg border-2 border-dashed p-3 text-center transition-colors"
/> />
<p className="mt-1 text-[11px] text-muted-foreground"> <p className="text-muted-foreground mt-1 text-[11px]">
Image updates are included the next time you save. Image updates are included the next time you save.
</p> </p>
</div> </div>
@@ -1608,10 +1608,10 @@ function WorkflowBuilderInner() {
<Database size={18} /> <Database size={18} />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-sm font-medium text-foreground"> <span className="text-foreground text-sm font-medium">
Set State Set State
</span> </span>
<span className="text-[10px] text-muted-foreground"> <span className="text-muted-foreground text-[10px]">
Modify workflow variables Modify workflow variables
</span> </span>
</div> </div>
@@ -1625,10 +1625,10 @@ function WorkflowBuilderInner() {
<GitBranch size={18} /> <GitBranch size={18} />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-sm font-medium text-foreground"> <span className="text-foreground text-sm font-medium">
If / Else If / Else
</span> </span>
<span className="text-[10px] text-muted-foreground"> <span className="text-muted-foreground text-[10px]">
Conditional branching Conditional branching
</span> </span>
</div> </div>
@@ -2041,7 +2041,7 @@ function WorkflowBuilderInner() {
rows={2} rows={2}
placeholder="input.foo + 1" placeholder="input.foo + 1"
/> />
<p className="mb-3 text-[10px] text-muted-foreground"> <p className="text-muted-foreground mb-3 text-[10px]">
Use Common Expression Language to create Use Common Expression Language to create
a custom expression.{' '} a custom expression.{' '}
<a <a
@@ -2376,7 +2376,7 @@ function WorkflowBuilderInner() {
rows={2} rows={2}
placeholder="Enter condition, e.g. input == 5" placeholder="Enter condition, e.g. input == 5"
/> />
<p className="mt-1 text-[10px] text-muted-foreground"> <p className="text-muted-foreground mt-1 text-[10px]">
Use Common Expression Language to Use Common Expression Language to
create a custom expression.{' '} create a custom expression.{' '}
<a <a
@@ -150,7 +150,7 @@ function ExecutionDetails({
ref={(el) => { ref={(el) => {
if (el && stepRefs) stepRefs.current.set(step.nodeId, el); if (el && stepRefs) stepRefs.current.set(step.nodeId, el);
}} }}
className="rounded-xl bg-muted p-3 dark:bg-accent" className="bg-muted dark:bg-accent rounded-xl p-3"
> >
<div className="flex items-center gap-2 text-sm"> <div className="flex items-center gap-2 text-sm">
<span className="flex h-5 w-5 shrink-0 items-center justify-center text-xs font-medium text-gray-500 dark:text-gray-400"> <span className="flex h-5 w-5 shrink-0 items-center justify-center text-xs font-medium text-gray-500 dark:text-gray-400">
@@ -181,7 +181,7 @@ function ExecutionDetails({
{(hasOutput || step.error || stateVars.length > 0) && ( {(hasOutput || step.error || stateVars.length > 0) && (
<div className="mt-3 space-y-2 text-sm"> <div className="mt-3 space-y-2 text-sm">
{hasOutput && ( {hasOutput && (
<div className="rounded-lg bg-muted p-2"> <div className="bg-muted rounded-lg p-2">
<span className="font-medium text-gray-600 dark:text-gray-400"> <span className="font-medium text-gray-600 dark:text-gray-400">
Output:{' '} Output:{' '}
</span> </span>
@@ -205,7 +205,7 @@ function ExecutionDetails({
{stateVars.map(([key, value]) => ( {stateVars.map(([key, value]) => (
<span <span
key={key} key={key}
className="inline-flex items-center rounded-lg bg-muted px-2 py-1 text-xs" className="bg-muted inline-flex items-center rounded-lg px-2 py-1 text-xs"
> >
<span className="max-w-[100px] truncate font-medium text-gray-600 dark:text-gray-400"> <span className="max-w-[100px] truncate font-medium text-gray-600 dark:text-gray-400">
{key}: {key}:
@@ -487,10 +487,10 @@ export default function WorkflowPreview({
queries.length > 0 ? queries[queries.length - 1].executionSteps || [] : []; queries.length > 0 ? queries[queries.length - 1].executionSteps || [] : [];
return ( return (
<div className="flex h-full flex-col bg-card"> <div className="bg-card flex h-full flex-col">
<div className="border-border flex h-[77px] items-center justify-between border-b px-6"> <div className="border-border flex h-[77px] items-center justify-between border-b px-6">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="flex items-center justify-center rounded-full bg-muted p-3 text-gray-600 dark:text-gray-300"> <div className="bg-muted flex items-center justify-center rounded-full p-3 text-gray-600 dark:text-gray-300">
<Play className="h-4 w-4" /> <Play className="h-4 w-4" />
</div> </div>
<div> <div>
@@ -512,7 +512,7 @@ export default function WorkflowPreview({
</div> </div>
<div className="flex min-h-0 flex-1"> <div className="flex min-h-0 flex-1">
<div className="flex w-64 shrink-0 flex-col border-r border-border"> <div className="border-border flex w-64 shrink-0 flex-col border-r">
<div className="flex items-center justify-between px-4 py-3"> <div className="flex items-center justify-between px-4 py-3">
<h3 className="text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400"> <h3 className="text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400">
Workflow Workflow
@@ -537,7 +537,7 @@ export default function WorkflowPreview({
> >
{queries.length === 0 ? ( {queries.length === 0 ? (
<div className="flex h-full flex-col items-center justify-center"> <div className="flex h-full flex-col items-center justify-center">
<div className="mb-2 flex size-14 shrink-0 items-center justify-center rounded-xl bg-muted"> <div className="bg-muted mb-2 flex size-14 shrink-0 items-center justify-center rounded-xl">
<MessageSquare className="size-6 text-gray-600 dark:text-gray-300" /> <MessageSquare className="size-6 text-gray-600 dark:text-gray-300" />
</div> </div>
<p className="text-xl font-semibold text-gray-700 dark:text-gray-200"> <p className="text-xl font-semibold text-gray-700 dark:text-gray-200">
@@ -618,7 +618,7 @@ export default function WorkflowPreview({
</div> </div>
)} )}
</div> </div>
<div className="absolute right-0 bottom-0 left-0 flex w-full flex-col gap-2 bg-card px-4 pt-2 pb-4"> <div className="bg-card absolute right-0 bottom-0 left-0 flex w-full flex-col gap-2 px-4 pt-2 pb-4">
<MessageInput <MessageInput
onSubmit={(text) => handleQuestionSubmission(text)} onSubmit={(text) => handleQuestionSubmission(text)}
loading={status === 'loading'} loading={status === 'loading'}
@@ -6,10 +6,10 @@ export default function MobileBlocker() {
<div className="bg-primary/10 dark:bg-primary/20 mb-6 flex h-20 w-20 items-center justify-center rounded-2xl"> <div className="bg-primary/10 dark:bg-primary/20 mb-6 flex h-20 w-20 items-center justify-center rounded-2xl">
<Monitor className="text-primary h-10 w-10" /> <Monitor className="text-primary h-10 w-10" />
</div> </div>
<h2 className="mb-2 text-xl font-bold text-foreground"> <h2 className="text-foreground mb-2 text-xl font-bold">
Desktop Required Desktop Required
</h2> </h2>
<p className="max-w-sm text-sm leading-relaxed text-muted-foreground"> <p className="text-muted-foreground max-w-sm text-sm leading-relaxed">
The Workflow Builder requires a larger screen for the best experience. The Workflow Builder requires a larger screen for the best experience.
Please open this page on a desktop or laptop computer. Please open this page on a desktop or laptop computer.
</p> </p>
@@ -222,7 +222,7 @@ function VariableListWithSearch({
return ( return (
<div className="flex w-full flex-col overflow-hidden"> <div className="flex w-full flex-col overflow-hidden">
<div className="flex items-center gap-2 border-b border-border px-3 py-2"> <div className="border-border flex items-center gap-2 border-b px-3 py-2">
<Search className="text-muted-foreground h-3.5 w-3.5 shrink-0" /> <Search className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
<input <input
type="text" type="text"
@@ -252,7 +252,7 @@ function VariableListWithSearch({
e.stopPropagation(); e.stopPropagation();
onSelect(v.templatePath); onSelect(v.templatePath);
}} }}
className="flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-left text-sm transition-colors hover:bg-accent" className="hover:bg-accent flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-left text-sm transition-colors"
> >
<Braces className="text-primary h-3.5 w-3.5 shrink-0" /> <Braces className="text-primary h-3.5 w-3.5 shrink-0" />
<span className="truncate font-medium text-gray-800 dark:text-gray-200"> <span className="truncate font-medium text-gray-800 dark:text-gray-200">
@@ -412,7 +412,7 @@ export default function PromptTextArea({
)} )}
<div <div
ref={wrapperRef} ref={wrapperRef}
className="border-border focus-within:ring-ring relative rounded-xl border bg-card transition-all focus-within:ring-2" className="border-border focus-within:ring-ring bg-card relative rounded-xl border transition-all focus-within:ring-2"
> >
<div <div
ref={overlayRef} ref={overlayRef}
@@ -472,7 +472,7 @@ export default function PromptTextArea({
<PopoverContent <PopoverContent
align="end" align="end"
side="top" side="top"
className="w-60 rounded-xl border border-border bg-card p-0 shadow-lg" className="border-border bg-card w-60 rounded-xl border p-0 shadow-lg"
onOpenAutoFocus={(e) => e.preventDefault()} onOpenAutoFocus={(e) => e.preventDefault()}
> >
<VariableListWithSearch <VariableListWithSearch
@@ -486,7 +486,7 @@ export default function PromptTextArea({
{showDropdown && filtered.length > 0 && ( {showDropdown && filtered.length > 0 && (
<div <div
ref={dropdownRef} ref={dropdownRef}
className="absolute z-50 w-64 rounded-xl border border-border bg-card shadow-lg" className="border-border bg-card absolute z-50 w-64 rounded-xl border shadow-lg"
style={{ top: dropdownPos.top, left: dropdownPos.left }} style={{ top: dropdownPos.top, left: dropdownPos.left }}
> >
<VariableListWithSearch <VariableListWithSearch
@@ -27,8 +27,7 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
let iconColor = 'text-gray-600 dark:text-gray-400'; let iconColor = 'text-gray-600 dark:text-gray-400';
if (selected) { if (selected) {
borderColor = borderColor = 'border-primary ring-2 ring-primary';
'border-primary ring-2 ring-primary';
} }
if (type === 'start') { if (type === 'start') {
@@ -56,7 +55,7 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
type="target" type="target"
position={Position.Left} position={Position.Left}
isConnectable={true} isConnectable={true}
className="hover:bg-primary/90! -left-1! h-3! w-3! rounded-full! border-2! border-card! bg-gray-400! transition-colors!" className="hover:bg-primary/90! border-card! -left-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/> />
)} )}
@@ -86,7 +85,7 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
type="source" type="source"
position={Position.Right} position={Position.Right}
isConnectable={true} isConnectable={true}
className="hover:bg-primary/90! -right-1! h-3! w-3! rounded-full! border-2! border-card! bg-gray-400! transition-colors!" className="hover:bg-primary/90! border-card! -right-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/> />
)} )}
</div> </div>
@@ -36,7 +36,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
return ( return (
<div <div
className={`relative rounded-2xl border bg-card shadow-md transition-all ${ className={`bg-card relative rounded-2xl border shadow-md transition-all ${
selected selected
? 'border-primary dark:ring-primary scale-105 ring-2 ring-purple-300' ? 'border-primary dark:ring-primary scale-105 ring-2 ring-purple-300'
: 'border-border hover:shadow-lg' : 'border-border hover:shadow-lg'
@@ -47,7 +47,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
type="target" type="target"
position={Position.Left} position={Position.Left}
isConnectable isConnectable
className="hover:bg-primary/90! top-1/2! -left-1! h-3! w-3! rounded-full! border-2! border-card! bg-gray-400! transition-colors!" className="hover:bg-primary/90! border-card! top-1/2! -left-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/> />
<div className="flex items-center gap-3 px-3 py-2"> <div className="flex items-center gap-3 px-3 py-2">
@@ -100,7 +100,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
id={c.sourceHandle} id={c.sourceHandle}
isConnectable isConnectable
style={{ top: getHandleTop(i, totalOutputs) }} style={{ top: getHandleTop(i, totalOutputs) }}
className="hover:bg-primary/90! -right-1! h-3! w-3! rounded-full! border-2! border-white! bg-orange-400! transition-colors dark:border-border!" className="hover:bg-primary/90! dark:border-border! -right-1! h-3! w-3! rounded-full! border-2! border-white! bg-orange-400! transition-colors"
/> />
))} ))}
<Handle <Handle
@@ -109,7 +109,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
id="else" id="else"
isConnectable isConnectable
style={{ top: getHandleTop(cases.length, totalOutputs) }} style={{ top: getHandleTop(cases.length, totalOutputs) }}
className="hover:bg-primary/90! -right-1! h-3! w-3! rounded-full! border-2! border-card! bg-gray-400! transition-colors!" className="hover:bg-primary/90! border-card! -right-1! h-3! w-3! rounded-full! border-2! bg-gray-400! transition-colors!"
/> />
</div> </div>
); );
+2 -2
View File
@@ -53,7 +53,7 @@ export default function ActionButtons({
<button <button
title={t('actionButtons.openNewChat')} title={t('actionButtons.openNewChat')}
onClick={newChat} onClick={newChat}
className="hover:bg-accent flex items-center gap-1 rounded-full p-2 lg:hidden dark:hover:bg-accent" className="hover:bg-accent dark:hover:bg-accent flex items-center gap-1 rounded-full p-2 lg:hidden"
> >
<img <img
className="filter dark:invert" className="filter dark:invert"
@@ -70,7 +70,7 @@ export default function ActionButtons({
<button <button
title={t('actionButtons.share')} title={t('actionButtons.share')}
onClick={() => setShareModalState(true)} onClick={() => setShareModalState(true)}
className="hover:bg-accent rounded-full p-2 dark:hover:bg-accent" className="hover:bg-accent dark:hover:bg-accent rounded-full p-2"
> >
<img <img
className="filter dark:invert" className="filter dark:invert"
+3 -3
View File
@@ -547,7 +547,7 @@ const Chunks: React.FC<ChunksProps> = ({
<> <>
<div className="mb-3 flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center"> <div className="mb-3 flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center">
<div className="border-border dark:border-border flex h-[38px] w-full flex-1 items-center overflow-hidden rounded-md border"> <div className="border-border dark:border-border flex h-[38px] w-full flex-1 items-center overflow-hidden rounded-md border">
<div className="flex h-full items-center px-4 font-medium whitespace-nowrap text-gray-700 dark:text-foreground"> <div className="dark:text-foreground flex h-full items-center px-4 font-medium whitespace-nowrap text-gray-700">
{totalChunks > 999999 {totalChunks > 999999
? `${(totalChunks / 1000000).toFixed(2)}M` ? `${(totalChunks / 1000000).toFixed(2)}M`
: totalChunks > 999 : totalChunks > 999
@@ -606,7 +606,7 @@ const Chunks: React.FC<ChunksProps> = ({
> >
<div className="w-full"> <div className="w-full">
<div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3"> <div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3">
<div className="text-sm text-[#59636E] dark:text-muted-foreground"> <div className="dark:text-muted-foreground text-sm text-[#59636E]">
{chunk.metadata.token_count {chunk.metadata.token_count
? chunk.metadata.token_count.toLocaleString() ? chunk.metadata.token_count.toLocaleString()
: '-'}{' '} : '-'}{' '}
@@ -641,7 +641,7 @@ const Chunks: React.FC<ChunksProps> = ({
<div className="w-full"> <div className="w-full">
<div className="border-border dark:border-border relative flex w-full flex-col overflow-hidden rounded-[5.86px] border"> <div className="border-border dark:border-border relative flex w-full flex-col overflow-hidden rounded-[5.86px] border">
<div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3"> <div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3">
<div className="text-sm text-[#59636E] dark:text-muted-foreground"> <div className="dark:text-muted-foreground text-sm text-[#59636E]">
{editingChunk.metadata.token_count {editingChunk.metadata.token_count
? editingChunk.metadata.token_count.toLocaleString() ? editingChunk.metadata.token_count.toLocaleString()
: '-'}{' '} : '-'}{' '}
+11 -11
View File
@@ -68,9 +68,7 @@ export default function ConfigFields({
<div key={key} className="flex flex-col gap-1.5"> <div key={key} className="flex flex-col gap-1.5">
<Label htmlFor={key}> <Label htmlFor={key}>
{spec.label || key} {spec.label || key}
{spec.required && ( {spec.required && <span className="text-red-500">*</span>}
<span className="text-red-500">*</span>
)}
</Label> </Label>
<Select <Select
value={value || spec.default || ''} value={value || spec.default || ''}
@@ -82,7 +80,8 @@ export default function ConfigFields({
size="lg" size="lg"
className={cn( className={cn(
'w-full rounded-xl', 'w-full rounded-xl',
hasError && 'border-destructive aria-invalid:ring-destructive/20', hasError &&
'border-destructive aria-invalid:ring-destructive/20',
)} )}
> >
<SelectValue placeholder={spec.label || key} /> <SelectValue placeholder={spec.label || key} />
@@ -90,13 +89,14 @@ export default function ConfigFields({
<SelectContent> <SelectContent>
{spec.enum.map((v) => ( {spec.enum.map((v) => (
<SelectItem key={v} value={v}> <SelectItem key={v} value={v}>
{v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, ' ')} {v.charAt(0).toUpperCase() +
v.slice(1).replace(/_/g, ' ')}
</SelectItem> </SelectItem>
))} ))}
</SelectContent> </SelectContent>
</Select> </Select>
{hasError && ( {hasError && (
<p className="text-xs text-destructive">{errors[key]}</p> <p className="text-destructive text-xs">{errors[key]}</p>
)} )}
</div> </div>
); );
@@ -106,9 +106,7 @@ export default function ConfigFields({
<div key={key} className="flex flex-col gap-1.5"> <div key={key} className="flex flex-col gap-1.5">
<Label htmlFor={key}> <Label htmlFor={key}>
{spec.label || key} {spec.label || key}
{spec.required && ( {spec.required && <span className="text-red-500">*</span>}
<span className="text-red-500">*</span>
)}
</Label> </Label>
<Input <Input
id={key} id={key}
@@ -134,12 +132,14 @@ export default function ConfigFields({
}} }}
placeholder={placeholder || spec.description || ''} placeholder={placeholder || spec.description || ''}
min={spec.type === 'number' ? 1 : undefined} min={spec.type === 'number' ? 1 : undefined}
max={spec.type === 'number' && key === 'timeout' ? 300 : undefined} max={
spec.type === 'number' && key === 'timeout' ? 300 : undefined
}
aria-invalid={hasError || undefined} aria-invalid={hasError || undefined}
className={cn('rounded-xl', hasError && 'border-destructive')} className={cn('rounded-xl', hasError && 'border-destructive')}
/> />
{hasError && ( {hasError && (
<p className="text-xs text-destructive">{errors[key]}</p> <p className="text-destructive text-xs">{errors[key]}</p>
)} )}
</div> </div>
); );
+1 -2
View File
@@ -39,8 +39,7 @@ export default function CopyButton({
'flex items-center justify-center rounded-full transition-colors duration-150 ease-in-out', 'flex items-center justify-center rounded-full transition-colors duration-150 ease-in-out',
padding, padding,
{ {
[`bg-transparent hover:bg-muted`]: [`bg-transparent hover:bg-muted`]: !isCopied,
!isCopied,
'bg-green-100 dark:bg-green-900 hover:bg-green-100 dark:hover:bg-green-900': 'bg-green-100 dark:bg-green-900 hover:bg-green-100 dark:hover:bg-green-900':
isCopied, isCopied,
}, },
@@ -61,12 +61,12 @@ const Pagination: React.FC<PaginationProps> = ({
<div className="relative"> <div className="relative">
<button <button
onClick={toggleDropdown} onClick={toggleDropdown}
className="dark:bg-card dark:text-foreground rounded border px-3 py-1 hover:bg-accent dark:hover:bg-accent" className="dark:bg-card dark:text-foreground hover:bg-accent dark:hover:bg-accent rounded border px-3 py-1"
> >
{rowsPerPage} {rowsPerPage}
</button> </button>
<div <div
className={`ring-opacity-5 dark:bg-card absolute right-0 z-50 mt-1 w-28 transform bg-card shadow-lg ring-1 ring-black transition-all duration-200 ease-in-out ${ className={`ring-opacity-5 dark:bg-card bg-card absolute right-0 z-50 mt-1 w-28 transform shadow-lg ring-1 ring-black transition-all duration-200 ease-in-out ${
isDropdownOpen isDropdownOpen
? 'block scale-100 opacity-100' ? 'block scale-100 opacity-100'
: 'hidden scale-95 opacity-0' : 'hidden scale-95 opacity-0'
@@ -76,7 +76,7 @@ const Pagination: React.FC<PaginationProps> = ({
<div <div
key={option} key={option}
onClick={() => handleSelectRowsPerPage(option)} onClick={() => handleSelectRowsPerPage(option)}
className={`cursor-pointer px-4 py-2 text-xs hover:bg-accent dark:hover:bg-accent ${ className={`hover:bg-accent dark:hover:bg-accent cursor-pointer px-4 py-2 text-xs ${
rowsPerPage === option rowsPerPage === option
? 'dark:text-foreground bg-gray-100 dark:bg-neutral-700' ? 'dark:text-foreground bg-gray-100 dark:bg-neutral-700'
: 'bg-card dark:text-foreground' : 'bg-card dark:text-foreground'
+15 -14
View File
@@ -110,7 +110,7 @@ function Dropdown<T extends DropdownOption>({
<button <button
type="button" type="button"
onClick={() => setOpen((v) => !v)} onClick={() => setOpen((v) => !v)}
className={`flex w-full cursor-pointer items-center justify-between border border-border bg-card px-5 py-3 text-foreground ${open ? radiusTop : radius}`} className={`border-border bg-card text-foreground flex w-full cursor-pointer items-center justify-between border px-5 py-3 ${open ? radiusTop : radius}`}
> >
<span <span
className={`truncate ${contentSize} ${displayValue ? '' : 'text-muted-foreground'}`} className={`truncate ${contentSize} ${displayValue ? '' : 'text-muted-foreground'}`}
@@ -118,24 +118,24 @@ function Dropdown<T extends DropdownOption>({
{displayValue ?? placeholder} {displayValue ?? placeholder}
</span> </span>
<ChevronDown <ChevronDown
className={`ml-2 h-4 w-4 shrink-0 text-muted-foreground transition-transform ${open ? 'rotate-180' : ''}`} className={`text-muted-foreground ml-2 h-4 w-4 shrink-0 transition-transform ${open ? 'rotate-180' : ''}`}
/> />
</button> </button>
{open && ( {open && (
<div <div
className={`absolute inset-x-0 z-20 -mt-px overflow-hidden border border-t-0 border-border bg-card shadow-lg ${radiusBottom}`} className={`border-border bg-card absolute inset-x-0 z-20 -mt-px overflow-hidden border border-t-0 shadow-lg ${radiusBottom}`}
> >
{searchable && ( {searchable && (
<div className="flex items-center border-b border-border px-3 py-2"> <div className="border-border flex items-center border-b px-3 py-2">
<Search className="mr-2 h-4 w-4 shrink-0 text-muted-foreground" /> <Search className="text-muted-foreground mr-2 h-4 w-4 shrink-0" />
<input <input
ref={searchRef} ref={searchRef}
type="text" type="text"
value={query} value={query}
onChange={(e) => setQuery(e.target.value)} onChange={(e) => setQuery(e.target.value)}
placeholder="Search..." placeholder="Search..."
className="w-full bg-transparent text-sm text-foreground placeholder:text-muted-foreground focus:outline-none" className="text-foreground placeholder:text-muted-foreground w-full bg-transparent text-sm focus:outline-none"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
/> />
</div> </div>
@@ -143,7 +143,7 @@ function Dropdown<T extends DropdownOption>({
<div className="max-h-48 overflow-y-auto"> <div className="max-h-48 overflow-y-auto">
{filtered.length === 0 ? ( {filtered.length === 0 ? (
<div className="px-4 py-3 text-center text-sm text-muted-foreground"> <div className="text-muted-foreground px-4 py-3 text-center text-sm">
No results found No results found
</div> </div>
) : ( ) : (
@@ -157,7 +157,7 @@ function Dropdown<T extends DropdownOption>({
return ( return (
<div <div
key={i} key={i}
className={`flex cursor-pointer items-center justify-between hover:bg-accent ${active ? 'bg-accent' : ''}`} className={`hover:bg-accent flex cursor-pointer items-center justify-between ${active ? 'bg-accent' : ''}`}
> >
<span <span
onClick={() => { onClick={() => {
@@ -165,7 +165,7 @@ function Dropdown<T extends DropdownOption>({
setOpen(false); setOpen(false);
setQuery(''); setQuery('');
}} }}
className={`flex-1 truncate px-4 py-2.5 text-foreground ${contentSize}`} className={`text-foreground flex-1 truncate px-4 py-2.5 ${contentSize}`}
> >
{getOptionText(option)} {getOptionText(option)}
</span> </span>
@@ -185,9 +185,9 @@ function Dropdown<T extends DropdownOption>({
setOpen(false); setOpen(false);
setQuery(''); setQuery('');
}} }}
className="mr-1 rounded p-1 hover:bg-accent" className="hover:bg-accent mr-1 rounded p-1"
> >
<Pencil className="h-3.5 w-3.5 text-muted-foreground" /> <Pencil className="text-muted-foreground h-3.5 w-3.5" />
</button> </button>
)} )}
@@ -202,13 +202,14 @@ function Dropdown<T extends DropdownOption>({
: ((optObj?.id as string) ?? ''), : ((optObj?.id as string) ?? ''),
); );
}} }}
className={`mr-1 rounded p-1 hover:bg-accent ${ className={`hover:bg-accent mr-1 rounded p-1 ${
typeof showDelete === 'function' && !showDelete(option) typeof showDelete === 'function' &&
!showDelete(option)
? 'hidden' ? 'hidden'
: '' : ''
} ${optObj?.type === 'public' ? 'pointer-events-none opacity-30' : ''}`} } ${optObj?.type === 'public' ? 'pointer-events-none opacity-30' : ''}`}
> >
<Trash2 className="h-3.5 w-3.5 text-muted-foreground" /> <Trash2 className="text-muted-foreground h-3.5 w-3.5" />
</button> </button>
)} )}
</div> </div>
+3 -5
View File
@@ -88,7 +88,7 @@ export default function DropdownMenu({
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div <div
className={`w-28 transform rounded-md border border-border bg-card shadow-lg transition-all duration-200 ease-in-out ${className}`} className={`border-border bg-card w-28 transform rounded-md border shadow-lg transition-all duration-200 ease-in-out ${className}`}
> >
<div <div
role="menu" role="menu"
@@ -99,10 +99,8 @@ export default function DropdownMenu({
{options.map((option, idx) => ( {options.map((option, idx) => (
<div <div
id={`option-${idx}`} id={`option-${idx}`}
className={`dark:text-foreground cursor-pointer px-4 py-2 text-xs hover:bg-muted ${ className={`dark:text-foreground hover:bg-muted cursor-pointer px-4 py-2 text-xs ${
selectedOption.value === option.value selectedOption.value === option.value ? 'bg-muted' : 'bg-card'
? 'bg-muted'
: 'bg-card'
}`} }`}
role="menuitem" role="menuitem"
key={option.value} key={option.value}
+3 -1
View File
@@ -128,7 +128,9 @@ export default function DropdownModel() {
)) ))
) : ( ) : (
<div className="border-border/30 flex h-10 w-full items-center border-t"> <div className="border-border/30 flex h-10 w-full items-center border-t">
<p className="pl-5 text-sm text-muted-foreground">No models available</p> <p className="text-muted-foreground pl-5 text-sm">
No models available
</p>
</div> </div>
)} )}
</div> </div>
+14 -19
View File
@@ -93,9 +93,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
const [isConnected, setIsConnected] = useState(false); const [isConnected, setIsConnected] = useState(false);
const [userEmail, setUserEmail] = useState<string>(''); const [userEmail, setUserEmail] = useState<string>('');
const [allowsSharedContent, setAllowsSharedContent] = useState(false); const [allowsSharedContent, setAllowsSharedContent] = useState(false);
const [activeTab, setActiveTab] = useState<'my_files' | 'shared'>( const [activeTab, setActiveTab] = useState<'my_files' | 'shared'>('my_files');
'my_files',
);
const scrollContainerRef = useRef<HTMLDivElement>(null); const scrollContainerRef = useRef<HTMLDivElement>(null);
const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -214,9 +212,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
setIsConnected(true); setIsConnected(true);
setAuthError(''); setAuthError('');
if (provider === 'share_point') { if (provider === 'share_point') {
setAllowsSharedContent( setAllowsSharedContent(validateData.allows_shared_content ?? false);
validateData.allows_shared_content ?? false,
);
} }
setFiles([]); setFiles([]);
@@ -369,9 +365,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
{ {
id: null, id: null,
name: name:
tab === 'shared' tab === 'shared' ? 'Shared' : getProviderConfig(provider).rootName,
? 'Shared'
: getProviderConfig(provider).rootName,
}, },
]); ]);
const sessionToken = getSessionToken(provider); const sessionToken = getSessionToken(provider);
@@ -380,8 +374,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
} }
}; };
const handleFileSelect = (fileId: string, isFolder: boolean) => { const handleFileSelect = (fileId: string, isFolder: boolean) => {
if (isFolder) { if (isFolder) {
const newSelectedFolders = selectedFolders.includes(fileId) const newSelectedFolders = selectedFolders.includes(fileId)
@@ -459,10 +451,10 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
/> />
{isConnected && ( {isConnected && (
<div className="mt-3 overflow-hidden rounded-lg border border-border dark:border-border"> <div className="border-border dark:border-border mt-3 overflow-hidden rounded-lg border">
<div className="rounded-t-lg border-border dark:border-border"> <div className="border-border dark:border-border rounded-t-lg">
{provider === 'share_point' && allowsSharedContent && ( {provider === 'share_point' && allowsSharedContent && (
<div className="flex border-b border-border dark:border-border"> <div className="border-border dark:border-border flex border-b">
<button <button
onClick={() => handleTabChange('my_files')} onClick={() => handleTabChange('my_files')}
className={`px-4 py-2 text-sm font-medium ${ className={`px-4 py-2 text-sm font-medium ${
@@ -485,7 +477,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
</button> </button>
</div> </div>
)} )}
<div className="rounded-t-lg bg-[#EEE6FF78] px-4 pt-4 dark:bg-muted"> <div className="dark:bg-muted rounded-t-lg bg-[#EEE6FF78] px-4 pt-4">
<div className="mb-2 flex items-center gap-1"> <div className="mb-2 flex items-center gap-1">
{folderPath.map((path, index) => ( {folderPath.map((path, index) => (
<div <div
@@ -531,7 +523,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
</div> </div>
</div> </div>
<div className="h-72 border-t border-border dark:border-border"> <div className="border-border dark:border-border h-72 border-t">
<TableContainer <TableContainer
ref={scrollContainerRef} ref={scrollContainerRef}
height="288px" height="288px"
@@ -586,7 +578,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
> >
<TableCell width="40px" align="center"> <TableCell width="40px" align="center">
<div <div
className="mx-auto flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center border border-border p-[0.5px] text-sm dark:border-border" className="border-border dark:border-border mx-auto flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center border p-[0.5px] text-sm"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
handleFileSelect(file.id, isFolder(file)); handleFileSelect(file.id, isFolder(file));
@@ -615,7 +607,9 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
className="h-6 w-6" className="h-6 w-6"
/> />
</div> </div>
<span className="truncate">{file.name}</span> <span className="truncate">
{file.name}
</span>
</div> </div>
</TableCell> </TableCell>
<TableCell className="text-xs"> <TableCell className="text-xs">
@@ -626,7 +620,8 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
{isLoading && files.length > 0 && {isLoading &&
files.length > 0 &&
Array.from({ length: 3 }).map((_, i) => ( Array.from({ length: 3 }).map((_, i) => (
<TableRow key={`load-more-skeleton-${i}`}> <TableRow key={`load-more-skeleton-${i}`}>
<TableCell width="40px" align="center"> <TableCell width="40px" align="center">
@@ -1,5 +1,5 @@
const FilesSectionSkeleton = () => ( const FilesSectionSkeleton = () => (
<div className="rounded-lg border border-border dark:border-border"> <div className="border-border dark:border-border rounded-lg border">
<div className="p-4"> <div className="p-4">
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<div className="h-5 w-24 animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div> <div className="h-5 w-24 animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
+6 -6
View File
@@ -599,7 +599,7 @@ const FileTree: React.FC<FileTreeProps> = ({
<div ref={menuRef} className="relative"> <div ref={menuRef} className="relative">
<button <button
onClick={(e) => handleMenuClick(e, itemId)} onClick={(e) => handleMenuClick(e, itemId)}
className="inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB] dark:hover:bg-muted" className="dark:hover:bg-muted inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')} aria-label={t('settings.sources.menuAlt')}
> >
<img <img
@@ -656,7 +656,7 @@ const FileTree: React.FC<FileTreeProps> = ({
<div ref={menuRef} className="relative"> <div ref={menuRef} className="relative">
<button <button
onClick={(e) => handleMenuClick(e, itemId)} onClick={(e) => handleMenuClick(e, itemId)}
className="inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB] dark:hover:bg-muted" className="dark:hover:bg-muted inline-flex h-[35px] w-[24px] shrink-0 items-center justify-center rounded-md font-medium transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')} aria-label={t('settings.sources.menuAlt')}
> >
<img <img
@@ -754,11 +754,11 @@ const FileTree: React.FC<FileTreeProps> = ({
} }
}} }}
placeholder={t('settings.sources.searchFiles')} placeholder={t('settings.sources.searchFiles')}
className={`h-[38px] w-full border border-border px-4 py-2 dark:border-border ${searchQuery ? 'rounded-t-[24px]' : 'rounded-[24px]'} bg-transparent focus:outline-none`} className={`border-border dark:border-border h-[38px] w-full border px-4 py-2 ${searchQuery ? 'rounded-t-[24px]' : 'rounded-[24px]'} bg-transparent focus:outline-none`}
/> />
{searchQuery && ( {searchQuery && (
<div className="absolute top-full right-0 left-0 z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-[12px] border border-t-0 border-border bg-card shadow-lg transition-all duration-200 dark:border-border dark:bg-card"> <div className="border-border bg-card dark:border-border dark:bg-card absolute top-full right-0 left-0 z-10 max-h-[calc(100vh-200px)] w-full overflow-hidden rounded-b-[12px] border border-t-0 shadow-lg transition-all duration-200">
<div className="max-h-[calc(100vh-200px)] overflow-x-hidden overflow-y-auto overscroll-contain"> <div className="max-h-[calc(100vh-200px)] overflow-x-hidden overflow-y-auto overscroll-contain">
{searchResults.length === 0 ? ( {searchResults.length === 0 ? (
<div className="py-2 text-center text-sm text-gray-500 dark:text-gray-400"> <div className="py-2 text-center text-sm text-gray-500 dark:text-gray-400">
@@ -770,9 +770,9 @@ const FileTree: React.FC<FileTreeProps> = ({
key={index} key={index}
onClick={() => handleSearchSelect(result)} onClick={() => handleSearchSelect(result)}
title={result.path} title={result.path}
className={`flex min-w-0 cursor-pointer items-center px-3 py-2 hover:bg-muted dark:hover:bg-muted ${ className={`hover:bg-muted dark:hover:bg-muted flex min-w-0 cursor-pointer items-center px-3 py-2 ${
index !== searchResults.length - 1 index !== searchResults.length - 1
? 'border-b border-border dark:border-border' ? 'border-border dark:border-border border-b'
: '' : ''
}`} }`}
> >
@@ -262,7 +262,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
/> />
{isConnected && ( {isConnected && (
<div className="rounded-lg border border-border dark:border-border"> <div className="border-border dark:border-border rounded-lg border">
<div className="p-4"> <div className="p-4">
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<h3 className="text-sm font-medium"> <h3 className="text-sm font-medium">
+4 -4
View File
@@ -36,20 +36,20 @@ const Help = () => {
<button <button
ref={buttonRef} ref={buttonRef}
onClick={toggleDropdown} onClick={toggleDropdown}
className="mx-4 my-auto flex h-9 w-full items-center gap-4 rounded-3xl hover:bg-sidebar-accent" className="hover:bg-sidebar-accent mx-4 my-auto flex h-9 w-full items-center gap-4 rounded-3xl"
> >
<img src={Info} alt="info" className="ml-2 w-5 filter dark:invert" /> <img src={Info} alt="info" className="ml-2 w-5 filter dark:invert" />
{t('help')} {t('help')}
</button> </button>
{isOpen && ( {isOpen && (
<div <div
className={`dark:bg-card absolute z-10 w-48 translate-x-4 -translate-y-28 rounded-xl bg-card shadow-lg`} className={`dark:bg-card bg-card absolute z-10 w-48 translate-x-4 -translate-y-28 rounded-xl shadow-lg`}
> >
<a <a
href="https://docs.docsgpt.cloud/" href="https://docs.docsgpt.cloud/"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="hover:bg-muted flex items-start gap-4 rounded-t-xl px-4 py-2 text-foreground" className="hover:bg-muted text-foreground flex items-start gap-4 rounded-t-xl px-4 py-2"
> >
<img <img
src={PageIcon} src={PageIcon}
@@ -61,7 +61,7 @@ const Help = () => {
</a> </a>
<a <a
href="mailto:support@docsgpt.cloud" href="mailto:support@docsgpt.cloud"
className="hover:bg-muted flex items-start gap-4 rounded-b-xl px-4 py-2 text-foreground" className="hover:bg-muted text-foreground flex items-start gap-4 rounded-b-xl px-4 py-2"
> >
<img <img
src={EmailIcon} src={EmailIcon}
+2 -2
View File
@@ -1438,7 +1438,7 @@ export default function MessageInput({
onChange={handleVoiceFileAttachment} onChange={handleVoiceFileAttachment}
/> />
<div className="border-border bg-card dark:bg-transparent relative flex w-full flex-col rounded-[23px] border"> <div className="border-border bg-card relative flex w-full flex-col rounded-[23px] border dark:bg-transparent">
<div className="flex flex-wrap gap-1.5 px-2 py-2 sm:gap-2 sm:px-3"> <div className="flex flex-wrap gap-1.5 px-2 py-2 sm:gap-2 sm:px-3">
{attachments.map((attachment) => { {attachments.map((attachment) => {
return ( return (
@@ -1620,7 +1620,7 @@ export default function MessageInput({
className={`xs:px-3 xs:py-1.5 dark:border-purple-taupe flex items-center rounded-[32px] border px-2 py-1 transition-colors ${ className={`xs:px-3 xs:py-1.5 dark:border-purple-taupe flex items-center rounded-[32px] border px-2 py-1 transition-colors ${
recordingState === 'recording' recordingState === 'recording'
? 'border-[#B42318] bg-[#FEE4E2] text-[#B42318] dark:bg-[#4A2323]' ? 'border-[#B42318] bg-[#FEE4E2] text-[#B42318] dark:bg-[#4A2323]'
: 'border-border hover:bg-gray-100 dark:hover:bg-accent' : 'border-border dark:hover:bg-accent hover:bg-gray-100'
} ${ } ${
loading || recordingState === 'transcribing' loading || recordingState === 'transcribing'
? 'cursor-not-allowed opacity-60' ? 'cursor-not-allowed opacity-60'
+3 -3
View File
@@ -212,7 +212,7 @@ export default function MultiSelectPopup({
<div className="h-6 w-6 animate-spin rounded-full border-b-2 border-gray-900 dark:border-white"></div> <div className="h-6 w-6 animate-spin rounded-full border-b-2 border-gray-900 dark:border-white"></div>
</div> </div>
) : ( ) : (
<div className="h-full overflow-y-auto scrollbar-overlay"> <div className="scrollbar-overlay h-full overflow-y-auto">
{filteredOptions.length === 0 ? ( {filteredOptions.length === 0 ? (
<div className="flex h-full flex-col items-center justify-center px-4 py-8 text-center"> <div className="flex h-full flex-col items-center justify-center px-4 py-8 text-center">
<img <img
@@ -233,7 +233,7 @@ export default function MultiSelectPopup({
<div <div
key={option.id} key={option.id}
onClick={() => handleOptionClick(option.id)} onClick={() => handleOptionClick(option.id)}
className="dark:border-border dark:hover:bg-accent flex cursor-pointer items-center justify-between border-b border-[#D9D9D9] p-3 last:border-b-0 hover:bg-accent" className="dark:border-border dark:hover:bg-accent hover:bg-accent flex cursor-pointer items-center justify-between border-b border-[#D9D9D9] p-3 last:border-b-0"
role="option" role="option"
aria-selected={isSelected} aria-selected={isSelected}
> >
@@ -248,7 +248,7 @@ export default function MultiSelectPopup({
</div> </div>
<div className="shrink-0"> <div className="shrink-0">
<div <div
className={`flex h-4 w-4 items-center justify-center rounded-xs border-2 border-border bg-card`} className={`border-border bg-card flex h-4 w-4 items-center justify-center rounded-xs border-2`}
aria-hidden="true" aria-hidden="true"
> >
{isSelected && ( {isSelected && (
+2 -2
View File
@@ -87,7 +87,7 @@ export default function Notification({
))} ))}
</div> </div>
<p className="text-white relative z-10 text-xs leading-6 font-semibold xl:text-sm xl:leading-7"> <p className="relative z-10 text-xs leading-6 font-semibold text-white xl:text-sm xl:leading-7">
{notificationText} {notificationText}
</p> </p>
<span className="relative z-10 flex items-center"> <span className="relative z-10 flex items-center">
@@ -132,4 +132,4 @@ export default function Notification({
</a> </a>
</> </>
); );
} }
+2 -2
View File
@@ -60,7 +60,7 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => {
<div className="z-10 md:hidden"> <div className="z-10 md:hidden">
<button <button
onClick={() => scrollTabs(-1)} onClick={() => scrollTabs(-1)}
className="flex h-6 w-6 items-center justify-center rounded-full transition-all hover:bg-muted dark:hover:bg-accent" className="hover:bg-muted dark:hover:bg-accent flex h-6 w-6 items-center justify-center rounded-full transition-all"
aria-label={t('settings.scrollTabsLeft')} aria-label={t('settings.scrollTabsLeft')}
> >
<img src={ArrowLeft} alt="left-arrow" className="h-3" /> <img src={ArrowLeft} alt="left-arrow" className="h-3" />
@@ -93,7 +93,7 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => {
<div className="z-10 md:hidden"> <div className="z-10 md:hidden">
<button <button
onClick={() => scrollTabs(1)} onClick={() => scrollTabs(1)}
className="flex h-6 w-6 items-center justify-center rounded-full hover:bg-muted dark:hover:bg-accent" className="hover:bg-muted dark:hover:bg-accent flex h-6 w-6 items-center justify-center rounded-full"
aria-label={t('settings.scrollTabsRight')} aria-label={t('settings.scrollTabsRight')}
> >
<img src={ArrowRight} alt="right-arrow" className="h-3" /> <img src={ArrowRight} alt="right-arrow" className="h-3" />
+1 -1
View File
@@ -33,7 +33,7 @@ export default function Sidebar({
return ( return (
<div ref={sidebarRef} className="h-vh relative"> <div ref={sidebarRef} className="h-vh relative">
<div <div
className={`fixed top-0 right-0 z-50 h-full w-64 transform bg-card shadow-xl transition-all duration-300 sm:w-80 ${ className={`bg-card fixed top-0 right-0 z-50 h-full w-64 transform shadow-xl transition-all duration-300 sm:w-80 ${
isOpen ? 'translate-x-[10px]' : 'translate-x-full' isOpen ? 'translate-x-[10px]' : 'translate-x-full'
} border-l border-[#9ca3af]/10`} } border-l border-[#9ca3af]/10`}
> >
+5 -8
View File
@@ -97,7 +97,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
{[...Array(8)].map((_, idx) => ( {[...Array(8)].map((_, idx) => (
<div <div
key={idx} key={idx}
className="dark:hover:bg-accent flex w-full items-start p-2 hover:bg-muted" className="dark:hover:bg-accent hover:bg-muted flex w-full items-start p-2"
> >
<div className="flex w-full items-center gap-2"> <div className="flex w-full items-center gap-2">
<div className="h-3 w-3 rounded-lg bg-gray-300 dark:bg-gray-600"></div> <div className="h-3 w-3 rounded-lg bg-gray-300 dark:bg-gray-600"></div>
@@ -154,10 +154,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
const renderAnalysis = () => ( const renderAnalysis = () => (
<> <>
{[...Array(skeletonCount)].map((_, idx) => ( {[...Array(skeletonCount)].map((_, idx) => (
<div <div key={idx} className="bg-card w-full animate-pulse rounded-3xl p-6">
key={idx}
className="bg-card w-full animate-pulse rounded-3xl p-6"
>
<div className="space-y-6"> <div className="space-y-6">
<div className="space-y-2"> <div className="space-y-2">
<div className="mb-4 h-4 w-1/3 rounded-sm bg-gray-300 dark:bg-gray-600"></div> <div className="mb-4 h-4 w-1/3 rounded-sm bg-gray-300 dark:bg-gray-600"></div>
@@ -189,10 +186,10 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
{Array.from({ length: count }).map((_, index) => ( {Array.from({ length: count }).map((_, index) => (
<div <div
key={`chunk-skel-${index}`} key={`chunk-skel-${index}`}
className="relative flex h-[197px] w-full max-w-[487px] animate-pulse flex-col overflow-hidden rounded-[5.86px] border border-border dark:border-border" className="border-border dark:border-border relative flex h-[197px] w-full max-w-[487px] animate-pulse flex-col overflow-hidden rounded-[5.86px] border"
> >
<div className="w-full"> <div className="w-full">
<div className="flex w-full items-center justify-between border-b border-border bg-muted px-4 py-3 dark:border-border dark:bg-card"> <div className="border-border bg-muted dark:border-border dark:bg-card flex w-full items-center justify-between border-b px-4 py-3">
<div className="h-4 w-20 rounded bg-gray-300 dark:bg-gray-600"></div> <div className="h-4 w-20 rounded bg-gray-300 dark:bg-gray-600"></div>
</div> </div>
<div className="space-y-3 px-4 pt-4 pb-6"> <div className="space-y-3 px-4 pt-4 pb-6">
@@ -214,7 +211,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
{Array.from({ length: count }).map((_, idx) => ( {Array.from({ length: count }).map((_, idx) => (
<div <div
key={`source-skel-${idx}`} key={`source-skel-${idx}`}
className="flex h-[130px] w-full animate-pulse flex-col rounded-2xl bg-muted p-3 dark:bg-accent" className="bg-muted dark:bg-accent flex h-[130px] w-full animate-pulse flex-col rounded-2xl p-3"
> >
<div className="w-full flex-1"> <div className="w-full flex-1">
<div className="flex w-full items-center justify-between gap-2"> <div className="flex w-full items-center justify-between gap-2">
+3 -3
View File
@@ -139,7 +139,7 @@ export default function SourcesPopup({
/> />
</div> </div>
<div className="dark:border-border mx-4 grow overflow-y-auto rounded-md border border-[#D9D9D9] scrollbar-overlay"> <div className="dark:border-border scrollbar-overlay mx-4 grow overflow-y-auto rounded-md border border-[#D9D9D9]">
{options ? ( {options ? (
<> <>
{filteredOptions?.map((option: any, index: number) => { {filteredOptions?.map((option: any, index: number) => {
@@ -154,7 +154,7 @@ export default function SourcesPopup({
return ( return (
<div <div
key={index} key={index}
className="border-opacity-80 dark:border-border flex cursor-pointer items-center border-b border-[#D9D9D9] p-3 transition-colors hover:bg-muted dark:text-[14px]" className="border-opacity-80 dark:border-border hover:bg-muted flex cursor-pointer items-center border-b border-[#D9D9D9] p-3 transition-colors dark:text-[14px]"
onClick={() => { onClick={() => {
if (isSelected) { if (isSelected) {
const updatedDocs = const updatedDocs =
@@ -190,7 +190,7 @@ export default function SourcesPopup({
{option.name} {option.name}
</span> </span>
<div <div
className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px] dark:border-border`} className={`dark:border-border flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px]`}
> >
{isSelected && ( {isSelected && (
<img <img
+2 -2
View File
@@ -46,7 +46,7 @@ const TableContainer = React.forwardRef<HTMLDivElement, TableContainerProps>(
<div className={`relative rounded-[6px] ${className}`}> <div className={`relative rounded-[6px] ${className}`}>
<div <div
ref={ref} ref={ref}
className={`w-full overflow-x-auto rounded-[6px] bg-transparent ${bordered ? 'border border-border dark:border-border' : ''}`} className={`w-full overflow-x-auto rounded-[6px] bg-transparent ${bordered ? 'border-border dark:border-border border' : ''}`}
style={{ style={{
maxHeight: height === 'auto' ? undefined : height, maxHeight: height === 'auto' ? undefined : height,
overflowY: height === 'auto' ? 'hidden' : 'auto', overflowY: height === 'auto' ? 'hidden' : 'auto',
@@ -75,7 +75,7 @@ const Table: React.FC<TableProps> = ({
const TableHead: React.FC<TableHeadProps> = ({ children, className = '' }) => { const TableHead: React.FC<TableHeadProps> = ({ children, className = '' }) => {
return ( return (
<thead <thead
className={`sticky top-0 z-10 bg-gray-100 dark:bg-card ${className} `} className={`dark:bg-card sticky top-0 z-10 bg-gray-100 ${className} `}
> >
{children} {children}
</thead> </thead>
@@ -176,9 +176,7 @@ export default function SpeakButton({ text }: { text: string }) {
<button <button
type="button" type="button"
className={`flex cursor-pointer items-center justify-center rounded-full p-2 ${ className={`flex cursor-pointer items-center justify-center rounded-full p-2 ${
isSpeaking || isLoading isSpeaking || isLoading ? 'bg-accent' : 'hover:bg-accent bg-transparent'
? 'bg-accent'
: 'bg-transparent hover:bg-accent'
}`} }`}
onClick={handleSpeakClick} onClick={handleSpeakClick}
aria-label={ aria-label={
+3 -3
View File
@@ -175,7 +175,7 @@ export default function ToolsPopup({
</div> </div>
) : ( ) : (
<div className="dark:border-border mx-4 grow overflow-hidden rounded-md border border-[#D9D9D9]"> <div className="dark:border-border mx-4 grow overflow-hidden rounded-md border border-[#D9D9D9]">
<div className="h-full overflow-y-auto scrollbar-overlay"> <div className="scrollbar-overlay h-full overflow-y-auto">
{filteredTools.length === 0 ? ( {filteredTools.length === 0 ? (
<div className="flex h-full flex-col items-center justify-center py-8"> <div className="flex h-full flex-col items-center justify-center py-8">
<img <img
@@ -192,7 +192,7 @@ export default function ToolsPopup({
<div <div
key={tool.id} key={tool.id}
onClick={() => updateToolStatus(tool.id, !tool.status)} onClick={() => updateToolStatus(tool.id, !tool.status)}
className="dark:border-border dark:hover:bg-accent flex items-center justify-between border-b border-[#D9D9D9] p-3 hover:bg-accent" className="dark:border-border dark:hover:bg-accent hover:bg-accent flex items-center justify-between border-b border-[#D9D9D9] p-3"
> >
<div className="mr-3 flex grow items-center"> <div className="mr-3 flex grow items-center">
<img <img
@@ -208,7 +208,7 @@ export default function ToolsPopup({
</div> </div>
<div className="flex shrink-0 items-center"> <div className="flex shrink-0 items-center">
<div <div
className={`flex h-4 w-4 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px] dark:border-border`} className={`dark:border-border flex h-4 w-4 items-center justify-center rounded-xs border-2 border-[#C6C6C6] p-[0.5px]`}
> >
{tool.status && ( {tool.status && (
<img <img
+2 -2
View File
@@ -70,7 +70,7 @@ export function MultiSelect({
role="combobox" role="combobox"
aria-expanded={open} aria-expanded={open}
className={cn( className={cn(
'w-full justify-between border-border bg-card hover:bg-accent', 'border-border bg-card hover:bg-accent w-full justify-between',
!selected.length && 'text-gray-500 dark:text-gray-400', !selected.length && 'text-gray-500 dark:text-gray-400',
className, className,
)} )}
@@ -124,7 +124,7 @@ export function MultiSelect({
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent <PopoverContent
className="w-(--radix-popover-trigger-width) border-border bg-card p-0" className="border-border bg-card w-(--radix-popover-trigger-width) p-0"
align="start" align="start"
> >
<Command className="bg-transparent"> <Command className="bg-transparent">
+3 -3
View File
@@ -37,11 +37,11 @@ function SelectTrigger({
data-slot="select-trigger" data-slot="select-trigger"
data-size={size} data-size={size}
className={cn( className={cn(
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 data-[size=lg]:h-[42px] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-gray-600 dark:[&_svg:not([class*='text-'])]:text-gray-400", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=lg]:h-[42px] data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-gray-600 dark:[&_svg:not([class*='text-'])]:text-gray-400",
variant === 'default' && variant === 'default' &&
'border-border bg-card focus-visible:ring-ring/50 hover:bg-accent data-placeholder:text-muted-foreground', 'border-border bg-card focus-visible:ring-ring/50 hover:bg-accent data-placeholder:text-muted-foreground',
variant === 'ghost' && variant === 'ghost' &&
'border-border bg-transparent focus-visible:ring-ring/50 hover:bg-accent data-[state=open]:bg-muted data-placeholder:text-muted-foreground dark:border-border dark:hover:bg-accent dark:data-[state=open]:bg-muted', 'border-border focus-visible:ring-ring/50 hover:bg-accent data-[state=open]:bg-muted data-placeholder:text-muted-foreground dark:border-border dark:hover:bg-accent dark:data-[state=open]:bg-muted bg-transparent',
className, className,
)} )}
{...props} {...props}
@@ -113,7 +113,7 @@ function SelectItem({
<SelectPrimitive.Item <SelectPrimitive.Item
data-slot="select-item" data-slot="select-item"
className={cn( className={cn(
"[&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none hover:bg-muted data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", "[&_svg:not([class*='text-'])]:text-muted-foreground hover:bg-muted relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
className, className,
)} )}
{...props} {...props}
+36 -36
View File
@@ -1,29 +1,29 @@
import * as React from "react" import * as React from 'react';
import * as SheetPrimitive from "@radix-ui/react-dialog" import * as SheetPrimitive from '@radix-ui/react-dialog';
import { XIcon } from "lucide-react" import { XIcon } from 'lucide-react';
import { cn } from "@/lib/utils" import { cn } from '@/lib/utils';
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) { function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
return <SheetPrimitive.Root data-slot="sheet" {...props} /> return <SheetPrimitive.Root data-slot="sheet" {...props} />;
} }
function SheetTrigger({ function SheetTrigger({
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) { }: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} /> return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
} }
function SheetClose({ function SheetClose({
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Close>) { }: React.ComponentProps<typeof SheetPrimitive.Close>) {
return <SheetPrimitive.Close data-slot="sheet-close" {...props} /> return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
} }
function SheetPortal({ function SheetPortal({
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Portal>) { }: React.ComponentProps<typeof SheetPrimitive.Portal>) {
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} /> return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
} }
function SheetOverlay({ function SheetOverlay({
@@ -34,23 +34,23 @@ function SheetOverlay({
<SheetPrimitive.Overlay <SheetPrimitive.Overlay
data-slot="sheet-overlay" data-slot="sheet-overlay"
className={cn( className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
className className,
)} )}
{...props} {...props}
/> />
) );
} }
function SheetContent({ function SheetContent({
className, className,
children, children,
side = "right", side = 'right',
showCloseButton = true, showCloseButton = true,
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Content> & { }: React.ComponentProps<typeof SheetPrimitive.Content> & {
side?: "top" | "right" | "bottom" | "left" side?: 'top' | 'right' | 'bottom' | 'left';
showCloseButton?: boolean showCloseButton?: boolean;
}) { }) {
return ( return (
<SheetPortal> <SheetPortal>
@@ -58,16 +58,16 @@ function SheetContent({
<SheetPrimitive.Content <SheetPrimitive.Content
data-slot="sheet-content" data-slot="sheet-content"
className={cn( className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500", 'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
side === "right" && side === 'right' &&
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm", 'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
side === "left" && side === 'left' &&
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm", 'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
side === "top" && side === 'top' &&
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b", 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
side === "bottom" && side === 'bottom' &&
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t", 'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
className className,
)} )}
{...props} {...props}
> >
@@ -80,27 +80,27 @@ function SheetContent({
)} )}
</SheetPrimitive.Content> </SheetPrimitive.Content>
</SheetPortal> </SheetPortal>
) );
} }
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="sheet-header" data-slot="sheet-header"
className={cn("flex flex-col gap-1.5 p-4", className)} className={cn('flex flex-col gap-1.5 p-4', className)}
{...props} {...props}
/> />
) );
} }
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
return ( return (
<div <div
data-slot="sheet-footer" data-slot="sheet-footer"
className={cn("mt-auto flex flex-col gap-2 p-4", className)} className={cn('mt-auto flex flex-col gap-2 p-4', className)}
{...props} {...props}
/> />
) );
} }
function SheetTitle({ function SheetTitle({
@@ -110,10 +110,10 @@ function SheetTitle({
return ( return (
<SheetPrimitive.Title <SheetPrimitive.Title
data-slot="sheet-title" data-slot="sheet-title"
className={cn("text-foreground font-semibold", className)} className={cn('text-foreground font-semibold', className)}
{...props} {...props}
/> />
) );
} }
function SheetDescription({ function SheetDescription({
@@ -123,10 +123,10 @@ function SheetDescription({
return ( return (
<SheetPrimitive.Description <SheetPrimitive.Description
data-slot="sheet-description" data-slot="sheet-description"
className={cn("text-muted-foreground text-sm", className)} className={cn('text-muted-foreground text-sm', className)}
{...props} {...props}
/> />
) );
} }
export { export {
@@ -138,4 +138,4 @@ export {
SheetFooter, SheetFooter,
SheetTitle, SheetTitle,
SheetDescription, SheetDescription,
} };
+103 -103
View File
@@ -137,7 +137,7 @@ const ConversationBubble = forwardRef<
<div <div
key={index} key={index}
title={file.fileName} title={file.fileName}
className="dark:text-foreground flex items-center rounded-xl bg-[#EFF3F4] p-2 text-[14px] text-[#5D5D5D] dark:bg-accent" className="dark:text-foreground dark:bg-accent flex items-center rounded-xl bg-[#EFF3F4] p-2 text-[14px] text-[#5D5D5D]"
> >
<div className="bg-primary mr-2 items-center justify-center rounded-lg p-[5.5px]"> <div className="bg-primary mr-2 items-center justify-center rounded-lg p-[5.5px]">
<img <img
@@ -198,7 +198,7 @@ const ConversationBubble = forwardRef<
setIsEditClicked(true); setIsEditClicked(true);
setEditInputBox(message ?? ''); setEditInputBox(message ?? '');
}} }}
className={`hover:bg-accent mt-3 flex h-fit shrink-0 cursor-pointer items-center rounded-full p-2 pt-1.5 pl-1.5 dark:hover:bg-accent ${isEditClicked ? 'visible' : 'invisible group-hover:visible'}`} className={`hover:bg-accent dark:hover:bg-accent mt-3 flex h-fit shrink-0 cursor-pointer items-center rounded-full p-2 pt-1.5 pl-1.5 ${isEditClicked ? 'visible' : 'invisible group-hover:visible'}`}
> >
<img src={Edit} alt="Edit" className="cursor-pointer" /> <img src={Edit} alt="Edit" className="cursor-pointer" />
</button> </button>
@@ -227,7 +227,7 @@ const ConversationBubble = forwardRef<
/> />
<div className="flex items-center justify-end gap-2"> <div className="flex items-center justify-end gap-2">
<button <button
className="text-primary hover:bg-muted hover:text-foreground dark:hover:bg-accent rounded-full px-4 py-2 text-sm font-semibold transition-colors dark:hover:text-foreground" className="text-primary hover:bg-muted hover:text-foreground dark:hover:bg-accent dark:hover:text-foreground rounded-full px-4 py-2 text-sm font-semibold transition-colors"
onClick={() => setIsEditClicked(false)} onClick={() => setIsEditClicked(false)}
> >
{t('conversation.edit.cancel')} {t('conversation.edit.cancel')}
@@ -322,7 +322,7 @@ const ConversationBubble = forwardRef<
{sources?.slice(0, 3)?.map((source, index) => ( {sources?.slice(0, 3)?.map((source, index) => (
<div key={index} className="relative"> <div key={index} className="relative">
<div <div
className="bg-muted dark:bg-answer-bubble h-28 cursor-pointer rounded-4xl p-4 hover:bg-muted dark:hover:bg-muted" className="bg-muted hover:bg-accent dark:bg-answer-bubble dark:hover:bg-muted h-28 cursor-pointer rounded-4xl p-4"
onMouseOver={() => setActiveTooltip(index)} onMouseOver={() => setActiveTooltip(index)}
onMouseOut={() => setActiveTooltip(null)} onMouseOut={() => setActiveTooltip(null)}
> >
@@ -379,7 +379,7 @@ const ConversationBubble = forwardRef<
))} ))}
{(sources?.length ?? 0) > 3 && ( {(sources?.length ?? 0) > 3 && (
<div <div
className="bg-muted text-primary dark:bg-answer-bubble flex h-28 cursor-pointer flex-col-reverse rounded-4xl p-4 hover:bg-muted hover:text-primary dark:hover:bg-muted dark:hover:text-primary" className="bg-muted text-primary hover:bg-accent hover:text-primary dark:bg-answer-bubble dark:hover:bg-muted dark:hover:text-primary flex h-28 cursor-pointer flex-col-reverse rounded-4xl p-4"
onClick={() => setIsSidebarOpen(true)} onClick={() => setIsSidebarOpen(true)}
> >
<p className="ellipsis-text h-22 text-xs"> <p className="ellipsis-text h-22 text-xs">
@@ -458,7 +458,7 @@ const ConversationBubble = forwardRef<
<div <div
className={`fade-in-bubble bg-answer-bubble mr-5 flex max-w-full rounded-[18px] px-6 py-4.5 ${ className={`fade-in-bubble bg-answer-bubble mr-5 flex max-w-full rounded-[18px] px-6 py-4.5 ${
type === 'ERROR' type === 'ERROR'
? 'text-destructive/80 dark:border-destructive relative flex-row items-center rounded-full border border-transparent bg-[#FFE7E7] p-2 py-5 text-sm font-normal dark:bg-destructive/15 dark:text-white' ? 'text-destructive/80 dark:border-destructive dark:bg-destructive/15 relative flex-row items-center rounded-full border border-transparent bg-[#FFE7E7] p-2 py-5 text-sm font-normal dark:text-white'
: 'flex-col rounded-3xl' : 'flex-col rounded-3xl'
}`} }`}
> >
@@ -551,14 +551,14 @@ const ConversationBubble = forwardRef<
}, },
thead({ children }) { thead({ children }) {
return ( return (
<thead className="bg-muted text-xs text-foreground uppercase"> <thead className="bg-muted text-foreground text-xs uppercase">
{children} {children}
</thead> </thead>
); );
}, },
tr({ children }) { tr({ children }) {
return ( return (
<tr className="border-b border-border odd:bg-card even:bg-muted"> <tr className="border-border odd:bg-card even:bg-muted border-b">
{children} {children}
</tr> </tr>
); );
@@ -657,7 +657,7 @@ const ConversationBubble = forwardRef<
<div className="relative mr-2 flex items-center justify-center"> <div className="relative mr-2 flex items-center justify-center">
<button <button
type="button" type="button"
className="bg-transparent hover:bg-accent flex cursor-pointer items-center justify-center rounded-full p-2" className="hover:bg-accent flex cursor-pointer items-center justify-center rounded-full bg-transparent p-2"
onClick={() => { onClick={() => {
if (feedback === 'LIKE') { if (feedback === 'LIKE') {
handleFeedback?.(null); handleFeedback?.(null);
@@ -670,7 +670,7 @@ const ConversationBubble = forwardRef<
} }
> >
<Like <Like
className={`${feedback === 'LIKE' ? 'fill-white stroke-primary dark:fill-transparent' : 'stroke-muted-foreground fill-none'}`} className={`${feedback === 'LIKE' ? 'stroke-primary fill-white dark:fill-transparent' : 'stroke-muted-foreground fill-none'}`}
></Like> ></Like>
</button> </button>
</div> </div>
@@ -678,7 +678,7 @@ const ConversationBubble = forwardRef<
<div className="relative mr-2 flex items-center justify-center"> <div className="relative mr-2 flex items-center justify-center">
<button <button
type="button" type="button"
className="bg-transparent hover:bg-accent flex cursor-pointer items-center justify-center rounded-full p-2" className="hover:bg-accent flex cursor-pointer items-center justify-center rounded-full bg-transparent p-2"
onClick={() => { onClick={() => {
if (feedback === 'DISLIKE') { if (feedback === 'DISLIKE') {
handleFeedback?.(null); handleFeedback?.(null);
@@ -693,7 +693,7 @@ const ConversationBubble = forwardRef<
} }
> >
<Dislike <Dislike
className={`${feedback === 'DISLIKE' ? 'fill-white stroke-destructive dark:fill-transparent' : 'stroke-muted-foreground fill-none'}`} className={`${feedback === 'DISLIKE' ? 'stroke-destructive fill-white dark:fill-transparent' : 'stroke-muted-foreground fill-none'}`}
></Dislike> ></Dislike>
</button> </button>
</div> </div>
@@ -746,7 +746,7 @@ function AllSources(sources: AllSourcesProps) {
return ( return (
<div <div
key={index} key={index}
className={`group/card bg-muted relative w-full rounded-4xl p-4 transition-colors hover:bg-muted dark:bg-card dark:hover:bg-muted ${ className={`group/card bg-muted hover:bg-accent dark:bg-card dark:hover:bg-muted relative w-full rounded-4xl p-4 transition-colors ${
isExternalSource ? 'cursor-pointer' : '' isExternalSource ? 'cursor-pointer' : ''
}`} }`}
onClick={() => onClick={() =>
@@ -790,105 +790,105 @@ function ToolCalls({ toolCalls }: { toolCalls: ToolCallsType[] }) {
const [isToolCallsOpen, setIsToolCallsOpen] = useState(false); const [isToolCallsOpen, setIsToolCallsOpen] = useState(false);
return ( return (
<div className="mb-4 flex w-full flex-col flex-wrap items-start self-start lg:flex-nowrap"> <div className="mb-4 flex w-full flex-col flex-wrap items-start self-start lg:flex-nowrap">
<div className="my-2 flex flex-row items-center justify-center gap-3"> <div className="my-2 flex flex-row items-center justify-center gap-3">
<Avatar <Avatar
className="h-[26px] w-[30px] text-xl" className="h-[26px] w-[30px] text-xl"
avatar={ avatar={
<img
src={Sources}
alt={'ToolCalls'}
className="h-full w-full object-fill"
/>
}
/>
<button
className="flex flex-row items-center gap-2"
onClick={() => setIsToolCallsOpen(!isToolCallsOpen)}
>
<p className="text-base font-semibold">Tool Calls</p>
<img <img
src={ChevronDown} src={Sources}
alt="ChevronDown" alt={'ToolCalls'}
className={`h-4 w-4 transform transition-transform duration-200 dark:invert ${isToolCallsOpen ? 'rotate-180' : ''}`} className="h-full w-full object-fill"
/> />
</button> }
</div> />
{isToolCallsOpen && ( <button
<div className="fade-in mr-5 ml-3 w-[90vw] md:w-[70vw] lg:w-full"> className="flex flex-row items-center gap-2"
<div className="grid grid-cols-1 gap-2"> onClick={() => setIsToolCallsOpen(!isToolCallsOpen)}
{toolCalls.map((toolCall, index) => ( >
<Accordion <p className="text-base font-semibold">Tool Calls</p>
key={`tool-call-${index}`} <img
title={`${toolCall.tool_name} - ${toolCall.action_name.substring(0, toolCall.action_name.lastIndexOf('_'))}`} src={ChevronDown}
className="bg-muted dark:bg-answer-bubble w-full rounded-4xl" alt="ChevronDown"
titleClassName="px-6 py-2 text-sm font-semibold" className={`h-4 w-4 transform transition-transform duration-200 dark:invert ${isToolCallsOpen ? 'rotate-180' : ''}`}
> />
<div className="flex flex-col gap-1"> </button>
<div className="border-border flex flex-col rounded-2xl border"> </div>
<p className="dark:bg-background flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word"> {isToolCallsOpen && (
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}> <div className="fade-in mr-5 ml-3 w-[90vw] md:w-[70vw] lg:w-full">
Arguments <div className="grid grid-cols-1 gap-2">
</span>{' '} {toolCalls.map((toolCall, index) => (
<CopyButton <Accordion
textToCopy={JSON.stringify(toolCall.arguments, null, 2)} key={`tool-call-${index}`}
/> title={`${toolCall.tool_name} - ${toolCall.action_name.substring(0, toolCall.action_name.lastIndexOf('_'))}`}
</p> className="bg-muted dark:bg-answer-bubble w-full rounded-4xl"
titleClassName="px-6 py-2 text-sm font-semibold"
>
<div className="flex flex-col gap-1">
<div className="border-border flex flex-col rounded-2xl border">
<p className="dark:bg-background flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word">
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
Arguments
</span>{' '}
<CopyButton
textToCopy={JSON.stringify(toolCall.arguments, null, 2)}
/>
</p>
<p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="dark:text-muted-foreground leading-[23px] text-black"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{JSON.stringify(toolCall.arguments, null, 2)}
</span>
</p>
</div>
<div className="border-border flex flex-col rounded-2xl border">
<p className="dark:bg-background flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word">
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
Response
</span>{' '}
<CopyButton
textToCopy={
toolCall.status === 'error'
? toolCall.error || 'Unknown error'
: JSON.stringify(toolCall.result, null, 2)
}
/>
</p>
{toolCall.status === 'pending' && (
<span className="dark:bg-card flex w-full items-center justify-center rounded-b-2xl p-2">
<Spinner size="small" />
</span>
)}
{toolCall.status === 'completed' && (
<p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word"> <p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span <span
className="leading-[23px] text-black dark:text-muted-foreground" className="dark:text-muted-foreground leading-[23px] text-black"
style={{ fontFamily: 'IBMPlexMono-Medium' }} style={{ fontFamily: 'IBMPlexMono-Medium' }}
> >
{JSON.stringify(toolCall.arguments, null, 2)} {JSON.stringify(toolCall.result, null, 2)}
</span> </span>
</p> </p>
</div> )}
<div className="border-border flex flex-col rounded-2xl border"> {toolCall.status === 'error' && (
<p className="dark:bg-background flex flex-row items-center justify-between rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold wrap-break-word"> <p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}> <span
Response className="leading-[23px] text-red-500 dark:text-red-400"
</span>{' '} style={{ fontFamily: 'IBMPlexMono-Medium' }}
<CopyButton >
textToCopy={ {toolCall.error}
toolCall.status === 'error'
? toolCall.error || 'Unknown error'
: JSON.stringify(toolCall.result, null, 2)
}
/>
</p>
{toolCall.status === 'pending' && (
<span className="dark:bg-card flex w-full items-center justify-center rounded-b-2xl p-2">
<Spinner size="small" />
</span> </span>
)} </p>
{toolCall.status === 'completed' && ( )}
<p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="leading-[23px] text-black dark:text-muted-foreground"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{JSON.stringify(toolCall.result, null, 2)}
</span>
</p>
)}
{toolCall.status === 'error' && (
<p className="dark:bg-card rounded-b-2xl p-2 font-mono text-sm wrap-break-word">
<span
className="leading-[23px] text-red-500 dark:text-red-400"
style={{ fontFamily: 'IBMPlexMono-Medium' }}
>
{toolCall.error}
</span>
</p>
)}
</div>
</div> </div>
</Accordion> </div>
))} </Accordion>
</div> ))}
</div> </div>
)} </div>
</div> )}
</div>
); );
} }
@@ -998,14 +998,14 @@ function Thought({
}, },
thead({ children }) { thead({ children }) {
return ( return (
<thead className="bg-muted text-xs text-foreground uppercase"> <thead className="bg-muted text-foreground text-xs uppercase">
{children} {children}
</thead> </thead>
); );
}, },
tr({ children }) { tr({ children }) {
return ( return (
<tr className="border-b border-border odd:bg-card even:bg-muted"> <tr className="border-border odd:bg-card even:bg-muted border-b">
{children} {children}
</tr> </tr>
); );
@@ -240,7 +240,7 @@ export default function ConversationMessages({
scrollConversationToBottom(); scrollConversationToBottom();
}} }}
aria-label={t('Scroll to bottom') || 'Scroll to bottom'} aria-label={t('Scroll to bottom') || 'Scroll to bottom'}
className="border-border fixed right-14 bottom-40 z-10 flex h-7 w-7 items-center justify-center rounded-full border bg-card md:h-9 md:w-9" className="border-border bg-card fixed right-14 bottom-40 z-10 flex h-7 w-7 items-center justify-center rounded-full border md:h-9 md:w-9"
> >
<img <img
src={ArrowDown} src={ArrowDown}
@@ -203,7 +203,7 @@ export default function ConversationTile({
<input <input
autoFocus autoFocus
type="text" type="text"
className="h-6 w-full bg-transparent px-1 text-sm leading-6 rounded-2xl font-normal outline-none" className="h-6 w-full rounded-2xl bg-transparent px-1 text-sm leading-6 font-normal outline-none"
value={conversationName} value={conversationName}
onChange={(e) => setConversationsName(e.target.value)} onChange={(e) => setConversationsName(e.target.value)}
onKeyDown={handleRenameKeyDown} onKeyDown={handleRenameKeyDown}
@@ -215,7 +215,10 @@ export default function ConversationTile({
)} )}
</div> </div>
{(conversationId === conversation.id || isHovered || isOpen) && ( {(conversationId === conversation.id || isHovered || isOpen) && (
<div className="dark:text-muted-foreground flex text-white" ref={menuRef}> <div
className="dark:text-muted-foreground flex text-white"
ref={menuRef}
>
{isEdit ? ( {isEdit ? (
<div className="flex gap-1"> <div className="flex gap-1">
<img <img
@@ -248,7 +251,7 @@ export default function ConversationTile({
event.stopPropagation(); event.stopPropagation();
setOpen(!isOpen); setOpen(!isOpen);
}} }}
className="mr-2 flex h-6 w-6 items-center justify-center rounded-full transition-colors duration-200 hover:bg-accent dark:hover:bg-accent" className="hover:bg-accent dark:hover:bg-accent mr-2 flex h-6 w-6 items-center justify-center rounded-full transition-colors duration-200"
> >
<img src={threeDots} width={8} alt="menu" /> <img src={threeDots} width={8} alt="menu" />
</button> </button>
+1 -1
View File
@@ -80,7 +80,7 @@ export default function AddActionModal({
setModalState('INACTIVE'); setModalState('INACTIVE');
setActionName(''); setActionName('');
}} }}
className="dark:text-foreground cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-accent dark:hover:bg-accent" className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
> >
{t('modals.configTool.closeButton')} {t('modals.configTool.closeButton')}
</button> </button>
+1 -1
View File
@@ -131,7 +131,7 @@ export default function AddToolModal({
role="button" role="button"
tabIndex={0} tabIndex={0}
key={index} key={index}
className="border-border bg-card flex h-52 w-full cursor-pointer flex-col justify-between rounded-2xl border p-6 hover:bg-accent hover:border-border/80" className="border-border bg-card hover:bg-accent hover:border-border/80 flex h-52 w-full cursor-pointer flex-col justify-between rounded-2xl border p-6"
onClick={() => { onClick={() => {
setSelectedTool(tool); setSelectedTool(tool);
handleAddTool(tool); handleAddTool(tool);
+10 -8
View File
@@ -140,19 +140,21 @@ export default function ConfigToolModal({
/> />
</div> </div>
{hasConfig && <ConfigFields {hasConfig && (
configRequirements={configRequirements} <ConfigFields
values={configValues} configRequirements={configRequirements}
onChange={handleFieldChange} values={configValues}
errors={errors} onChange={handleFieldChange}
/>} errors={errors}
/>
)}
</div> </div>
<div className="mt-8 flex flex-row-reverse gap-2"> <div className="mt-8 flex flex-row-reverse gap-2">
<button <button
onClick={handleAddTool} onClick={handleAddTool}
disabled={saving} disabled={saving}
className="bg-primary hover:bg-primary/90 disabled:opacity-60 rounded-full px-5 py-2 text-sm font-medium text-white transition-colors" className="bg-primary hover:bg-primary/90 rounded-full px-5 py-2 text-sm font-medium text-white transition-colors disabled:opacity-60"
> >
{saving {saving
? t('modals.configTool.addButton') + '…' ? t('modals.configTool.addButton') + '…'
@@ -160,7 +162,7 @@ export default function ConfigToolModal({
</button> </button>
<button <button
onClick={handleClose} onClick={handleClose}
className="dark:text-foreground cursor-pointer rounded-full px-5 py-2 text-sm font-medium hover:bg-accent dark:hover:bg-accent" className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-full px-5 py-2 text-sm font-medium"
> >
{t('modals.configTool.closeButton')} {t('modals.configTool.closeButton')}
</button> </button>
@@ -59,7 +59,7 @@ export default function FolderNameModal({
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder={t('agents.folders.folderName')} placeholder={t('agents.folders.folderName')}
autoFocus autoFocus
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm outline-none dark:text-white" className="border-border bg-card w-full rounded-lg border px-3 py-2 text-sm outline-none dark:text-white"
/> />
<div className="mt-6 flex justify-end gap-2"> <div className="mt-6 flex justify-end gap-2">
<button <button
@@ -67,7 +67,7 @@ export default function FolderNameModal({
setModalState('INACTIVE'); setModalState('INACTIVE');
setName(''); setName('');
}} }}
className="dark:text-foreground cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-accent dark:hover:bg-accent" className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
> >
{t('cancel')} {t('cancel')}
</button> </button>
+5 -5
View File
@@ -206,7 +206,7 @@ export default function ImportSpecModal({
</div> </div>
) : ( ) : (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div className="rounded-xl bg-muted p-4"> <div className="bg-muted rounded-xl p-4">
<h3 className="text-foreground dark:text-foreground font-medium"> <h3 className="text-foreground dark:text-foreground font-medium">
{parsedResult.metadata.title} {parsedResult.metadata.title}
</h3> </h3>
@@ -215,7 +215,7 @@ export default function ImportSpecModal({
{parsedResult.metadata.description} {parsedResult.metadata.description}
</p> </p>
)} )}
<p className="mt-2 text-xs text-muted-foreground"> <p className="text-muted-foreground mt-2 text-xs">
{t('modals.importSpec.version')}:{' '} {t('modals.importSpec.version')}:{' '}
{parsedResult.metadata.version} {parsedResult.metadata.version}
</p> </p>
@@ -227,7 +227,7 @@ export default function ImportSpecModal({
type="text" type="text"
value={baseUrl} value={baseUrl}
onChange={(e) => setBaseUrl(e.target.value)} onChange={(e) => setBaseUrl(e.target.value)}
className="border-border dark:border-border text-foreground dark:text-foreground w-full rounded-lg border bg-card px-3 py-2 text-sm outline-hidden" className="border-border dark:border-border text-foreground dark:text-foreground bg-card w-full rounded-lg border px-3 py-2 text-sm outline-hidden"
placeholder={ placeholder={
parsedResult.metadata.base_url || 'https://api.example.com' parsedResult.metadata.base_url || 'https://api.example.com'
} }
@@ -255,7 +255,7 @@ export default function ImportSpecModal({
{parsedResult.actions.map((action, index) => ( {parsedResult.actions.map((action, index) => (
<label <label
key={index} key={index}
className="border-border dark:border-border flex cursor-pointer items-start gap-3 rounded-xl border p-3 transition-colors hover:bg-muted dark:hover:bg-muted" className="border-border dark:border-border hover:bg-muted dark:hover:bg-muted flex cursor-pointer items-start gap-3 rounded-xl border p-3 transition-colors"
> >
<input <input
type="checkbox" type="checkbox"
@@ -310,7 +310,7 @@ export default function ImportSpecModal({
)} )}
<button <button
onClick={handleClose} onClick={handleClose}
className="dark:text-foreground cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-accent dark:hover:bg-accent" className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
> >
{t('modals.importSpec.cancel')} {t('modals.importSpec.cancel')}
</button> </button>
+2 -2
View File
@@ -753,7 +753,7 @@ export default function MCPServerModal({
<button <button
onClick={testConnection} onClick={testConnection}
disabled={testing} disabled={testing}
className="border-border dark:border-border dark:text-foreground w-full rounded-3xl border px-6 py-2 text-sm font-medium transition-all hover:bg-accent disabled:opacity-50 sm:w-auto dark:hover:bg-muted/50" className="border-border dark:border-border dark:text-foreground hover:bg-accent dark:hover:bg-muted/50 w-full rounded-3xl border px-6 py-2 text-sm font-medium transition-all disabled:opacity-50 sm:w-auto"
> >
{testing ? ( {testing ? (
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
@@ -773,7 +773,7 @@ export default function MCPServerModal({
setModalState('INACTIVE'); setModalState('INACTIVE');
resetForm(); resetForm();
}} }}
className="dark:text-foreground w-full cursor-pointer rounded-3xl px-6 py-2 text-sm font-medium hover:bg-accent sm:w-auto dark:hover:bg-muted/50" className="dark:text-foreground hover:bg-accent dark:hover:bg-muted/50 w-full cursor-pointer rounded-3xl px-6 py-2 text-sm font-medium sm:w-auto"
> >
{t('settings.tools.mcp.cancel')} {t('settings.tools.mcp.cancel')}
</button> </button>
+11 -11
View File
@@ -151,7 +151,7 @@ export default function MoveToFolderModal({
</h2> </h2>
</div> </div>
<div <div
className="flex items-center gap-1 bg-muted px-8 py-2 text-xs font-semibold text-[#59636E] dark:bg-muted dark:text-gray-400" className="bg-muted dark:bg-muted flex items-center gap-1 px-8 py-2 text-xs font-semibold text-[#59636E] dark:text-gray-400"
style={{ fontFamily: "'Segoe UI', sans-serif" }} style={{ fontFamily: "'Segoe UI', sans-serif" }}
> >
<button <button
@@ -180,7 +180,7 @@ export default function MoveToFolderModal({
) : ( ) : (
<button <button
onClick={() => handleNavigateToPath(index)} onClick={() => handleNavigateToPath(index)}
className="opacity-70 hover:text-foreground dark:hover:text-white" className="hover:text-foreground opacity-70 dark:hover:text-white"
> >
{item.name} {item.name}
</button> </button>
@@ -188,10 +188,10 @@ export default function MoveToFolderModal({
</span> </span>
))} ))}
</div> </div>
<div className="max-h-60 min-h-[200px] overflow-y-auto border-t border-gray-200 dark:border-border"> <div className="dark:border-border max-h-60 min-h-[200px] overflow-y-auto border-t border-gray-200">
{isLoading ? ( {isLoading ? (
<div className="flex h-[200px] items-center justify-center"> <div className="flex h-[200px] items-center justify-center">
<span className="text-[14px] text-muted-foreground"> <span className="text-muted-foreground text-[14px]">
{t('loading')}... {t('loading')}...
</span> </span>
</div> </div>
@@ -204,7 +204,7 @@ export default function MoveToFolderModal({
e.stopPropagation(); e.stopPropagation();
setSelectedFolderId(null); setSelectedFolderId(null);
}} }}
className={`flex w-full items-center gap-2 border-b border-gray-200 dark:border-border px-8 py-2 text-left text-[14px] ${ className={`dark:border-border flex w-full items-center gap-2 border-b border-gray-200 px-8 py-2 text-left text-[14px] ${
selectedFolderId === null selectedFolderId === null
? 'bg-[#7D54D1] text-white' ? 'bg-[#7D54D1] text-white'
: 'bg-muted hover:bg-accent dark:bg-muted' : 'bg-muted hover:bg-accent dark:bg-muted'
@@ -226,7 +226,7 @@ export default function MoveToFolderModal({
<button <button
key={folder.id} key={folder.id}
onClick={() => setSelectedFolderId(folder.id)} onClick={() => setSelectedFolderId(folder.id)}
className={`flex w-full cursor-pointer items-center justify-between border-b border-gray-200 dark:border-border px-8 py-2 text-left text-[14px] ${ className={`dark:border-border flex w-full cursor-pointer items-center justify-between border-b border-gray-200 px-8 py-2 text-left text-[14px] ${
selectedFolderId === folder.id selectedFolderId === folder.id
? 'bg-[#7D54D1] text-white' ? 'bg-[#7D54D1] text-white'
: 'bg-muted hover:bg-accent dark:bg-muted' : 'bg-muted hover:bg-accent dark:bg-muted'
@@ -271,14 +271,14 @@ export default function MoveToFolderModal({
</button> </button>
))} ))}
{currentLevelFolders.length === 0 && folderPath.length > 0 && ( {currentLevelFolders.length === 0 && folderPath.length > 0 && (
<div className="flex h-[200px] items-center justify-center text-sm text-muted-foreground"> <div className="text-muted-foreground flex h-[200px] items-center justify-center text-sm">
{t('agents.folders.noSubfolders')} {t('agents.folders.noSubfolders')}
</div> </div>
)} )}
{currentLevelFolders.length === 0 && {currentLevelFolders.length === 0 &&
folderPath.length === 0 && folderPath.length === 0 &&
!currentFolderId && ( !currentFolderId && (
<div className="flex h-[200px] items-center justify-center text-sm text-muted-foreground"> <div className="text-muted-foreground flex h-[200px] items-center justify-center text-sm">
{t('agents.folders.noFolders')} {t('agents.folders.noFolders')}
</div> </div>
)} )}
@@ -286,7 +286,7 @@ export default function MoveToFolderModal({
)} )}
</div> </div>
<div className="flex items-center justify-between border-t border-gray-200 dark:border-border px-8 py-4"> <div className="dark:border-border flex items-center justify-between border-t border-gray-200 px-8 py-4">
{isCreatingFolder ? ( {isCreatingFolder ? (
<input <input
ref={newFolderInputRef} ref={newFolderInputRef}
@@ -309,7 +309,7 @@ export default function MoveToFolderModal({
} }
}} }}
placeholder={t('agents.folders.newFolder')} placeholder={t('agents.folders.newFolder')}
className="rounded-full border border-[#7D54D1] bg-transparent px-6 py-2 text-sm font-medium text-[#7D54D1] outline-none placeholder:text-[#7D54D1]/60 dark:text-primary dark:placeholder:text-[#B794F4]/60" className="dark:text-primary rounded-full border border-[#7D54D1] bg-transparent px-6 py-2 text-sm font-medium text-[#7D54D1] outline-none placeholder:text-[#7D54D1]/60 dark:placeholder:text-[#B794F4]/60"
autoFocus autoFocus
/> />
) : ( ) : (
@@ -336,7 +336,7 @@ export default function MoveToFolderModal({
setModalState('INACTIVE'); setModalState('INACTIVE');
} }
}} }}
className="dark:text-foreground cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-accent dark:hover:bg-accent" className="dark:text-foreground hover:bg-accent dark:hover:bg-accent cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium"
> >
{t('cancel')} {t('cancel')}
</button> </button>
+3 -4
View File
@@ -32,8 +32,7 @@ export default function WrapperModal({
) )
return; return;
if (document.querySelector('[data-radix-select-content]')) return; if (document.querySelector('[data-radix-select-content]')) return;
if (modalRef.current && !modalRef.current.contains(target)) if (modalRef.current && !modalRef.current.contains(target)) close();
close();
}; };
const handleEscapePress = (event: KeyboardEvent) => { const handleEscapePress = (event: KeyboardEvent) => {
@@ -61,7 +60,7 @@ export default function WrapperModal({
/> />
<div <div
ref={modalRef} ref={modalRef}
className={`relative rounded-2xl bg-card p-8 shadow-[0px_4px_40px_-3px_#0000001A] dark:bg-card ${className}`} className={`bg-card dark:bg-card relative rounded-2xl p-8 shadow-[0px_4px_40px_-3px_#0000001A] ${className}`}
> >
{!isPerformingTask && ( {!isPerformingTask && (
<button <button
@@ -72,7 +71,7 @@ export default function WrapperModal({
</button> </button>
)} )}
<div <div
className={`no-scrollbar overflow-y-auto text-foreground dark:text-foreground ${contentClassName}`} className={`no-scrollbar text-foreground dark:text-foreground overflow-y-auto ${contentClassName}`}
> >
{children} {children}
</div> </div>
+8 -8
View File
@@ -120,7 +120,7 @@ function PromptTextarea({
return ( return (
<> <>
<div <div
className="pointer-events-none absolute inset-0 z-0 overflow-hidden rounded bg-card px-3 py-2" className="bg-card pointer-events-none absolute inset-0 z-0 overflow-hidden rounded px-3 py-2"
aria-hidden="true" aria-hidden="true"
> >
<div <div
@@ -239,7 +239,7 @@ function AddPrompt({
<p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white"> <p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white">
{t('modals.prompts.addPrompt')} {t('modals.prompts.addPrompt')}
</p> </p>
<p className="mb-6 text-sm text-[#6B6B6B] dark:text-muted-foreground"> <p className="dark:text-muted-foreground mb-6 text-sm text-[#6B6B6B]">
{t('modals.prompts.addDescription')} {t('modals.prompts.addDescription')}
</p> </p>
<div> <div>
@@ -266,7 +266,7 @@ function AddPrompt({
htmlFor="new-prompt-content" htmlFor="new-prompt-content"
className={`absolute z-20 select-none ${ className={`absolute z-20 select-none ${
newPromptContent ? '-top-2.5 left-3 text-xs' : '' newPromptContent ? '-top-2.5 left-3 text-xs' : ''
} text-muted-foreground pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden bg-card px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs`} } text-muted-foreground bg-card pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs`}
> >
{t('modals.prompts.promptText')} {t('modals.prompts.promptText')}
</label> </label>
@@ -278,7 +278,7 @@ function AddPrompt({
<span className="font-bold"> <span className="font-bold">
{t('modals.prompts.variablesLabel')} {t('modals.prompts.variablesLabel')}
</span> </span>
<span className="text-xs text-[10px] font-medium text-muted-foreground"> <span className="text-muted-foreground text-xs text-[10px] font-medium">
{t('modals.prompts.variablesDescription')} {t('modals.prompts.variablesDescription')}
</span> </span>
</p> </p>
@@ -446,7 +446,7 @@ function EditPrompt({
<p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white"> <p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white">
{t('modals.prompts.editPrompt')} {t('modals.prompts.editPrompt')}
</p> </p>
<p className="mb-6 text-sm text-[#6B6B6B] dark:text-muted-foreground"> <p className="dark:text-muted-foreground mb-6 text-sm text-[#6B6B6B]">
{t('modals.prompts.editDescription')} {t('modals.prompts.editDescription')}
</p> </p>
<div> <div>
@@ -473,7 +473,7 @@ function EditPrompt({
htmlFor="edit-prompt-content" htmlFor="edit-prompt-content"
className={`absolute z-20 select-none ${ className={`absolute z-20 select-none ${
editPromptContent ? '-top-2.5 left-3 text-xs' : '' editPromptContent ? '-top-2.5 left-3 text-xs' : ''
} text-muted-foreground pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden bg-card px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs`} } text-muted-foreground bg-card pointer-events-none max-w-[calc(100%-24px)] cursor-none overflow-hidden px-2 text-ellipsis whitespace-nowrap transition-all peer-placeholder-shown:top-2.5 peer-placeholder-shown:left-3 peer-placeholder-shown:text-base peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs`}
> >
{t('modals.prompts.promptText')} {t('modals.prompts.promptText')}
</label> </label>
@@ -485,7 +485,7 @@ function EditPrompt({
<span className="font-bold"> <span className="font-bold">
{t('modals.prompts.variablesLabel')} {t('modals.prompts.variablesLabel')}
</span> </span>
<span className="text-xs text-[10px] font-medium text-muted-foreground"> <span className="text-muted-foreground text-xs text-[10px] font-medium">
{t('modals.prompts.variablesDescription')} {t('modals.prompts.variablesDescription')}
</span> </span>
</p> </p>
@@ -759,7 +759,7 @@ export default function PromptsModal({
setNewPromptContent(''); setNewPromptContent('');
} }
}} }}
className="mx-4 mt-16 w-[95vw] max-w-[650px] rounded-2xl bg-card px-4 py-4 sm:px-6 sm:py-6 md:max-w-[860px] md:px-8 md:py-6 lg:max-w-[980px] dark:bg-card" className="bg-card dark:bg-card mx-4 mt-16 w-[95vw] max-w-[650px] rounded-2xl px-4 py-4 sm:px-6 sm:py-6 md:max-w-[860px] md:px-8 md:py-6 lg:max-w-[980px]"
contentClassName="!overflow-visible" contentClassName="!overflow-visible"
> >
{view} {view}
+1 -1
View File
@@ -175,7 +175,7 @@ export default function Analytics({ agentId }: AnalyticsProps) {
}, [agentId, feedbackFilter]); }, [agentId, feedbackFilter]);
return ( return (
<div className="mt-8"> <div className="mt-8">
<p className="mb-5 text-[15px] leading-6 text-muted-foreground"> <p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.analytics.subtitle')} {t('settings.analytics.subtitle')}
</p> </p>
{/* Messages Analytics */} {/* Messages Analytics */}
+7 -7
View File
@@ -58,7 +58,7 @@ export default function Logs({ agentId, tableHeader }: LogsProps) {
}, [page, agentId]); }, [page, agentId]);
return ( return (
<div className="mt-8"> <div className="mt-8">
<p className="mb-5 text-[15px] leading-6 text-muted-foreground"> <p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.logs.subtitle')} {t('settings.logs.subtitle')}
</p> </p>
<div> <div>
@@ -117,9 +117,9 @@ function LogsTable({ logs, setPage, loading, tableHeader }: LogsTableProps) {
}, []); }, []);
return ( return (
<div className="logs-table border-border h-[55vh] w-full overflow-hidden rounded-xl border bg-card dark:bg-black"> <div className="logs-table border-border bg-card h-[55vh] w-full overflow-hidden rounded-xl border dark:bg-black">
<div className="flex h-8 flex-col items-start justify-center bg-black/10 dark:bg-white/5"> <div className="flex h-8 flex-col items-start justify-center bg-black/10 dark:bg-white/5">
<p className="px-3 text-xs text-muted-foreground"> <p className="text-muted-foreground px-3 text-xs">
{tableHeader ? tableHeader : t('settings.logs.tableHeader')} {tableHeader ? tableHeader : t('settings.logs.tableHeader')}
</p> </p>
</div> </div>
@@ -168,11 +168,11 @@ function Log({
const { id, action, timestamp, ...filteredLog } = log; const { id, action, timestamp, ...filteredLog } = log;
return ( return (
<div className="group dark:hover:bg-accent w-full rounded-xl bg-transparent hover:bg-muted"> <div className="group dark:hover:bg-accent hover:bg-muted w-full rounded-xl bg-transparent">
<div <div
onClick={() => onToggle(log.id)} onClick={() => onToggle(log.id)}
className={`flex cursor-pointer flex-row items-start gap-2 p-2 px-4 py-3 text-foreground ${ className={`text-foreground flex cursor-pointer flex-row items-start gap-2 p-2 px-4 py-3 ${
isOpen ? 'rounded-t-xl bg-[#F1F1F1] dark:bg-background' : '' isOpen ? 'dark:bg-background rounded-t-xl bg-[#F1F1F1]' : ''
}`} }`}
> >
<img <img
@@ -193,7 +193,7 @@ function Log({
</span> </span>
</div> </div>
{isOpen && ( {isOpen && (
<div className="rounded-b-xl bg-[#F1F1F1] px-4 py-3 dark:bg-background"> <div className="dark:bg-background rounded-b-xl bg-[#F1F1F1] px-4 py-3">
<div className="scrollbar-overlay overflow-y-auto"> <div className="scrollbar-overlay overflow-y-auto">
<pre className="px-2 font-mono text-xs leading-relaxed wrap-break-word whitespace-pre-wrap text-gray-700 dark:text-gray-400"> <pre className="px-2 font-mono text-xs leading-relaxed wrap-break-word whitespace-pre-wrap text-gray-700 dark:text-gray-400">
{JSON.stringify(filteredLog, null, 2)} {JSON.stringify(filteredLog, null, 2)}
+13 -13
View File
@@ -362,7 +362,7 @@ export default function Sources({
) : ( ) : (
<div className="mt-8 flex w-full max-w-full flex-col overflow-hidden"> <div className="mt-8 flex w-full max-w-full flex-col overflow-hidden">
<div className="relative flex grow flex-col"> <div className="relative flex grow flex-col">
<p className="mb-5 text-[15px] leading-6 text-muted-foreground"> <p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.sources.subtitle')} {t('settings.sources.subtitle')}
</p> </p>
<div className="mb-6 flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center"> <div className="mb-6 flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center">
@@ -371,7 +371,11 @@ export default function Sources({
{t('settings.sources.searchPlaceholder')} {t('settings.sources.searchPlaceholder')}
</label> </label>
<div className="relative w-full max-w-md"> <div className="relative w-full max-w-md">
<img src={SearchIcon} alt="" className="absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 opacity-40" /> <img
src={SearchIcon}
alt=""
className="absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 opacity-40"
/>
<input <input
maxLength={256} maxLength={256}
placeholder={t('settings.sources.searchPlaceholder')} placeholder={t('settings.sources.searchPlaceholder')}
@@ -383,7 +387,7 @@ export default function Sources({
setSearchTerm(e.target.value); setSearchTerm(e.target.value);
setCurrentPage(1); setCurrentPage(1);
}} }}
className="h-11 w-full rounded-full border border-border bg-card py-2 pr-5 pl-11 text-sm text-foreground shadow-[0_1px_4px_rgba(0,0,0,0.06)] outline-none transition-shadow placeholder:text-muted-foreground focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none" className="border-border bg-card text-foreground placeholder:text-muted-foreground h-11 w-full rounded-full border py-2 pr-5 pl-11 text-sm shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none"
/> />
</div> </div>
</div> </div>
@@ -422,7 +426,7 @@ export default function Sources({
return ( return (
<div key={docId} className="relative"> <div key={docId} className="relative">
<div <div
className={`flex h-[130px] w-full flex-col rounded-2xl bg-muted p-3 transition-all duration-200 dark:bg-accent ${ className={`bg-muted dark:bg-accent flex h-[130px] w-full flex-col rounded-2xl p-3 transition-all duration-200 ${
activeMenuId === docId || syncMenuState.docId === docId activeMenuId === docId || syncMenuState.docId === docId
? 'scale-[1.05]' ? 'scale-[1.05]'
: 'hover:scale-[1.05]' : 'hover:scale-[1.05]'
@@ -431,7 +435,7 @@ export default function Sources({
<div className="w-full flex-1"> <div className="w-full flex-1">
<div className="flex w-full items-center justify-between gap-2"> <div className="flex w-full items-center justify-between gap-2">
<h3 <h3
className="font-inter dark:text-foreground line-clamp-3 text-[13px] leading-[18px] font-semibold wrap-break-word text-foreground" className="font-inter dark:text-foreground text-foreground line-clamp-3 text-[13px] leading-[18px] font-semibold wrap-break-word"
title={document.name} title={document.name}
> >
{document.name} {document.name}
@@ -472,7 +476,7 @@ export default function Sources({
e.stopPropagation(); e.stopPropagation();
handleMenuClick(e, docId); handleMenuClick(e, docId);
}} }}
className="inline-flex h-[35px] w-6 shrink-0 items-center justify-center rounded-md transition-colors hover:bg-[#EBEBEB] dark:hover:bg-muted" className="dark:hover:bg-muted inline-flex h-[35px] w-6 shrink-0 items-center justify-center rounded-md transition-colors hover:bg-[#EBEBEB]"
aria-label={t('settings.sources.menuAlt')} aria-label={t('settings.sources.menuAlt')}
data-testid={`menu-button-${docId}`} data-testid={`menu-button-${docId}`}
> >
@@ -493,17 +497,13 @@ export default function Sources({
alt="" alt=""
className="h-3.5 w-3.5" className="h-3.5 w-3.5"
/> />
<span className="font-inter text-[12px] leading-[18px] font-medium text-muted-foreground"> <span className="font-inter text-muted-foreground text-[12px] leading-[18px] font-medium">
{document.date ? formatDate(document.date) : ''} {document.date ? formatDate(document.date) : ''}
</span> </span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<img <img src={DiscIcon} alt="" className="h-3.5 w-3.5" />
src={DiscIcon} <span className="font-inter text-muted-foreground text-[12px] leading-[18px] font-medium">
alt=""
className="h-3.5 w-3.5"
/>
<span className="font-inter text-[12px] leading-[18px] font-medium text-muted-foreground">
{document.tokens {document.tokens
? formatTokens(+document.tokens) ? formatTokens(+document.tokens)
: ''} : ''}
+27 -7
View File
@@ -332,7 +332,7 @@ export default function ToolConfig({
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<div className="text-foreground dark:text-foreground flex items-center gap-3 text-sm"> <div className="text-foreground dark:text-foreground flex items-center gap-3 text-sm">
<button <button
className="rounded-full border border-border p-3 text-sm text-muted-foreground hover:bg-accent" className="border-border text-muted-foreground hover:bg-accent rounded-full border p-3 text-sm"
onClick={handleBackClick} onClick={handleBackClick}
> >
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" /> <img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
@@ -434,13 +434,23 @@ export default function ToolConfig({
{'actions' in tool && tool.actions && tool.actions.length > 0 ? ( {'actions' in tool && tool.actions && tool.actions.length > 0 ? (
<> <>
<div className="relative"> <div className="relative">
<svg className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor"><circle cx="11" cy="11" r="8"/><path strokeLinecap="round" d="m21 21-4.35-4.35"/></svg> <svg
className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="currentColor"
>
<circle cx="11" cy="11" r="8" />
<path strokeLinecap="round" d="m21 21-4.35-4.35" />
</svg>
<input <input
type="text" type="text"
value={userActionsSearch} value={userActionsSearch}
onChange={(e) => setUserActionsSearch(e.target.value)} onChange={(e) => setUserActionsSearch(e.target.value)}
placeholder={t('settings.tools.searchActions')} placeholder={t('settings.tools.searchActions')}
className="h-10 w-full rounded-full border border-border bg-transparent pl-10 pr-4 text-sm text-foreground outline-none placeholder:text-muted-foreground" className="border-border text-foreground placeholder:text-muted-foreground h-10 w-full rounded-full border bg-transparent pr-4 pl-10 text-sm outline-none"
/> />
</div> </div>
@@ -843,13 +853,23 @@ function APIToolConfig({
return ( return (
<div className="scrollbar-overlay flex flex-col gap-4"> <div className="scrollbar-overlay flex flex-col gap-4">
<div className="relative"> <div className="relative">
<svg className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor"><circle cx="11" cy="11" r="8"/><path strokeLinecap="round" d="m21 21-4.35-4.35"/></svg> <svg
className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="currentColor"
>
<circle cx="11" cy="11" r="8" />
<path strokeLinecap="round" d="m21 21-4.35-4.35" />
</svg>
<input <input
type="text" type="text"
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
placeholder={t('settings.tools.searchActions')} placeholder={t('settings.tools.searchActions')}
className="h-10 w-full rounded-full border border-border bg-transparent pl-10 pr-4 text-sm text-foreground outline-none placeholder:text-muted-foreground" className="border-border text-foreground placeholder:text-muted-foreground h-10 w-full rounded-full border bg-transparent pr-4 pl-10 text-sm outline-none"
/> />
</div> </div>
@@ -945,7 +965,7 @@ function APIToolConfig({
</div> </div>
<div className="mt-4 px-5 py-2"> <div className="mt-4 px-5 py-2">
<div className="relative w-full"> <div className="relative w-full">
<span className="text-muted-foreground absolute -top-2 left-5 z-10 bg-card px-2 text-xs"> <span className="text-muted-foreground bg-card absolute -top-2 left-5 z-10 px-2 text-xs">
{t('settings.tools.method')} {t('settings.tools.method')}
</span> </span>
<Dropdown <Dropdown
@@ -1024,7 +1044,7 @@ function APIToolConfig({
action.method === 'OPTIONS') && ( action.method === 'OPTIONS') && (
<div className="mt-4 px-5 py-2"> <div className="mt-4 px-5 py-2">
<div className="relative w-full"> <div className="relative w-full">
<span className="text-muted-foreground absolute -top-2 left-5 z-10 bg-card px-2 text-xs"> <span className="text-muted-foreground bg-card absolute -top-2 left-5 z-10 px-2 text-xs">
{t('settings.tools.bodyContentType')} {t('settings.tools.bodyContentType')}
</span> </span>
<Dropdown <Dropdown
+119 -111
View File
@@ -210,12 +210,16 @@ export default function Tools() {
) : ( ) : (
<div className="mt-8"> <div className="mt-8">
<div className="relative flex flex-col"> <div className="relative flex flex-col">
<p className="mb-5 text-[15px] leading-6 text-muted-foreground"> <p className="text-muted-foreground mb-5 text-[15px] leading-6">
{t('settings.tools.subtitle')} {t('settings.tools.subtitle')}
</p> </p>
<div className="my-3 flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between"> <div className="my-3 flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="relative w-full max-w-md"> <div className="relative w-full max-w-md">
<img src={SearchIcon} alt="" className="absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 opacity-40" /> <img
src={SearchIcon}
alt=""
className="absolute top-1/2 left-4 h-5 w-5 -translate-y-1/2 opacity-40"
/>
<input <input
maxLength={256} maxLength={256}
placeholder={t('settings.tools.searchPlaceholder')} placeholder={t('settings.tools.searchPlaceholder')}
@@ -224,7 +228,7 @@ export default function Tools() {
id="tool-search-input" id="tool-search-input"
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="h-11 w-full rounded-full border border-border bg-card py-2 pr-5 pl-11 text-sm text-foreground shadow-[0_1px_4px_rgba(0,0,0,0.06)] outline-none transition-shadow placeholder:text-muted-foreground focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none" className="border-border bg-card text-foreground placeholder:text-muted-foreground h-11 w-full rounded-full border py-2 pr-5 pl-11 text-sm shadow-[0_1px_4px_rgba(0,0,0,0.06)] transition-shadow outline-none focus:shadow-[0_2px_8px_rgba(0,0,0,0.1)] dark:shadow-none"
/> />
</div> </div>
<button <button
@@ -256,115 +260,119 @@ export default function Tools() {
{t('settings.tools.noToolsFound')} {t('settings.tools.noToolsFound')}
</p> </p>
</div> </div>
) : (() => { ) : (
const filtered = userTools.filter((tool) => (() => {
(tool.customName || tool.displayName) const filtered = userTools.filter((tool) =>
.toLowerCase() (tool.customName || tool.displayName)
.includes(searchTerm.toLowerCase()), .toLowerCase()
); .includes(searchTerm.toLowerCase()),
return filtered.length === 0 ? ( );
<div className="flex w-full flex-col items-center justify-center py-12"> return filtered.length === 0 ? (
<img <div className="flex w-full flex-col items-center justify-center py-12">
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon} <img
alt={t('settings.tools.noToolsFound')} src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
className="mx-auto mb-6 h-32 w-32" alt={t('settings.tools.noToolsFound')}
/> className="mx-auto mb-6 h-32 w-32"
<p className="text-center text-lg text-gray-500 dark:text-gray-400"> />
{t('settings.tools.noToolsFound')} <p className="text-center text-lg text-gray-500 dark:text-gray-400">
</p> {t('settings.tools.noToolsFound')}
</div> </p>
) : (
filtered.map((tool, index) => (
<div
key={index}
className="relative flex h-52 w-[300px] flex-col justify-between overflow-hidden rounded-2xl bg-muted p-6 hover:bg-accent"
>
<div
ref={menuRefs.current[tool.id]}
onClick={(e) => {
e.stopPropagation();
setActiveMenuId(
activeMenuId === tool.id ? null : tool.id,
);
}}
className="absolute top-4 right-4 z-10 cursor-pointer"
>
<img
src={ThreeDotsIcon}
alt={t('settings.tools.settingsIconAlt')}
className="h-[19px] w-[19px]"
/>
<ContextMenu
isOpen={activeMenuId === tool.id}
setIsOpen={(isOpen) => {
setActiveMenuId(isOpen ? tool.id : null);
}}
options={getMenuOptions(tool)}
anchorRef={menuRefs.current[tool.id]}
position="bottom-right"
offset={{ x: 0, y: 0 }}
/>
</div>
<div className="w-full">
<div className="flex w-full items-center gap-2 px-1">
<img
src={`/toolIcons/tool_${tool.name}.svg`}
alt={`${tool.displayName} icon`}
className="h-6 w-6"
/>
{tool.name === 'mcp_tool' &&
mcpStatuses[tool.id] && (
<span
className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium leading-none ${
mcpStatuses[tool.id] === 'connected'
? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
: mcpStatuses[tool.id] === 'needs_auth'
? 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300'
: 'bg-gray-100 text-gray-600 dark:bg-gray-700/40 dark:text-gray-300'
}`}
>
{mcpStatuses[tool.id] === 'connected'
? t('settings.tools.authStatus.connected')
: mcpStatuses[tool.id] === 'needs_auth'
? t('settings.tools.authStatus.needsAuth')
: t(
'settings.tools.authStatus.configured',
)}
</span>
)}
</div>
<div className="mt-[9px]">
<p
title={tool.customName || tool.displayName}
className="text-foreground dark:text-foreground truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
>
{tool.customName || tool.displayName}
</p>
<p
className="text-muted-foreground mt-1 line-clamp-4 max-h-24 overflow-hidden px-1 text-[12px] leading-relaxed break-all"
title={tool.description}
>
{tool.description}
</p>
</div>
</div>
<div className="absolute right-4 bottom-4">
<ToggleSwitch
checked={tool.status}
onChange={(checked) =>
updateToolStatus(tool.id, checked)
}
size="small"
id={`toolToggle-${index}`}
ariaLabel={t('settings.tools.toggleToolAria', {
toolName: tool.customName || tool.displayName,
})}
/>
</div>
</div> </div>
)) ) : (
); filtered.map((tool, index) => (
})()} <div
key={index}
className="bg-muted hover:bg-accent relative flex h-52 w-[300px] flex-col justify-between overflow-hidden rounded-2xl p-6"
>
<div
ref={menuRefs.current[tool.id]}
onClick={(e) => {
e.stopPropagation();
setActiveMenuId(
activeMenuId === tool.id ? null : tool.id,
);
}}
className="absolute top-4 right-4 z-10 cursor-pointer"
>
<img
src={ThreeDotsIcon}
alt={t('settings.tools.settingsIconAlt')}
className="h-[19px] w-[19px]"
/>
<ContextMenu
isOpen={activeMenuId === tool.id}
setIsOpen={(isOpen) => {
setActiveMenuId(isOpen ? tool.id : null);
}}
options={getMenuOptions(tool)}
anchorRef={menuRefs.current[tool.id]}
position="bottom-right"
offset={{ x: 0, y: 0 }}
/>
</div>
<div className="w-full">
<div className="flex w-full items-center gap-2 px-1">
<img
src={`/toolIcons/tool_${tool.name}.svg`}
alt={`${tool.displayName} icon`}
className="h-6 w-6"
/>
{tool.name === 'mcp_tool' &&
mcpStatuses[tool.id] && (
<span
className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] leading-none font-medium ${
mcpStatuses[tool.id] === 'connected'
? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
: mcpStatuses[tool.id] === 'needs_auth'
? 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300'
: 'bg-gray-100 text-gray-600 dark:bg-gray-700/40 dark:text-gray-300'
}`}
>
{mcpStatuses[tool.id] === 'connected'
? t('settings.tools.authStatus.connected')
: mcpStatuses[tool.id] === 'needs_auth'
? t(
'settings.tools.authStatus.needsAuth',
)
: t(
'settings.tools.authStatus.configured',
)}
</span>
)}
</div>
<div className="mt-[9px]">
<p
title={tool.customName || tool.displayName}
className="text-foreground dark:text-foreground truncate px-1 text-[13px] leading-relaxed font-semibold capitalize"
>
{tool.customName || tool.displayName}
</p>
<p
className="text-muted-foreground mt-1 line-clamp-4 max-h-24 overflow-hidden px-1 text-[12px] leading-relaxed break-all"
title={tool.description}
>
{tool.description}
</p>
</div>
</div>
<div className="absolute right-4 bottom-4">
<ToggleSwitch
checked={tool.status}
onChange={(checked) =>
updateToolStatus(tool.id, checked)
}
size="small"
id={`toolToggle-${index}`}
ariaLabel={t('settings.tools.toggleToolAria', {
toolName: tool.customName || tool.displayName,
})}
/>
</div>
</div>
))
);
})()
)}
</div> </div>
)} )}
</div> </div>
+1 -1
View File
@@ -78,4 +78,4 @@ export default store;
// TODO : use https://redux-toolkit.js.org/tutorials/typescript#define-typed-hooks everywere instead of direct useDispatch // TODO : use https://redux-toolkit.js.org/tutorials/typescript#define-typed-hooks everywere instead of direct useDispatch
// TODO : streamline async state management // TODO : streamline async state management
+5 -5
View File
@@ -203,7 +203,7 @@ function Upload({
{files.map((file) => ( {files.map((file) => (
<p <p
key={file.name} key={file.name}
className="truncate overflow-hidden text-ellipsis text-muted-foreground" className="text-muted-foreground truncate overflow-hidden text-ellipsis"
title={file.name} title={file.name}
> >
{file.name} {file.name}
@@ -812,7 +812,7 @@ function Upload({
className={`relative mx-auto flex h-[91.2px] w-full cursor-pointer flex-col justify-between gap-2 rounded-2xl border border-solid pt-[21.1px] pr-[21px] pb-[15px] pl-[21px] transition-colors duration-300 ease-out ${ className={`relative mx-auto flex h-[91.2px] w-full cursor-pointer flex-col justify-between gap-2 rounded-2xl border border-solid pt-[21.1px] pr-[21px] pb-[15px] pl-[21px] transition-colors duration-300 ease-out ${
ingestor.type === option.value ingestor.type === option.value
? 'border-[#7D54D1] bg-[#7D54D1] text-white' ? 'border-[#7D54D1] bg-[#7D54D1] text-white'
: 'border-border bg-transparent transition-shadow duration-300 hover:bg-accent/30 hover:shadow-[0_0_15px_0_#00000026] dark:border-border/30' : 'border-border hover:bg-accent/30 dark:border-border/30 bg-transparent transition-shadow duration-300 hover:shadow-[0_0_15px_0_#00000026]'
}`} }`}
onClick={() => onClick={() =>
handleIngestorTypeChange(option.value as IngestorType) handleIngestorTypeChange(option.value as IngestorType)
@@ -843,7 +843,7 @@ function Upload({
> >
<div className="flex w-full flex-col gap-6"> <div className="flex w-full flex-col gap-6">
{!ingestor.type && ( {!ingestor.type && (
<p className="font-inter text-left text-[20px] leading-7 font-semibold tracking-[0.15px] text-foreground dark:text-foreground"> <p className="font-inter text-foreground dark:text-foreground text-left text-[20px] leading-7 font-semibold tracking-[0.15px]">
{t('modals.uploadDoc.selectSource')} {t('modals.uploadDoc.selectSource')}
</p> </p>
)} )}
@@ -865,7 +865,7 @@ function Upload({
<span>{t('modals.uploadDoc.back')}</span> <span>{t('modals.uploadDoc.back')}</span>
</button> </button>
<h2 className="font-inter text-[22px] leading-7 font-semibold tracking-[0.15px] text-foreground"> <h2 className="font-inter text-foreground text-[22px] leading-7 font-semibold tracking-[0.15px]">
{ingestor.type && {ingestor.type &&
t(`modals.uploadDoc.ingestors.${ingestor.type}.heading`)} t(`modals.uploadDoc.ingestors.${ingestor.type}.heading`)}
</h2> </h2>
@@ -913,7 +913,7 @@ function Upload({
disabled={isUploadDisabled()} disabled={isUploadDisabled()}
className={`rounded-3xl px-4 py-2 text-[14px] font-medium ${ className={`rounded-3xl px-4 py-2 text-[14px] font-medium ${
isUploadDisabled() isUploadDisabled()
? 'cursor-not-allowed bg-gray-300 text-gray-500 dark:bg-muted dark:text-muted-foreground' ? 'dark:bg-muted dark:text-muted-foreground cursor-not-allowed bg-gray-300 text-gray-500'
: 'bg-primary hover:bg-primary/90 cursor-pointer text-white' : 'bg-primary hover:bg-primary/90 cursor-pointer text-white'
}`} }`}
> >