mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-05 06:13:15 +00:00
fix: lint errors + redundant css
This commit is contained in:
1 parent
174dee0fe6
commit
193ca6fd63
65 files changed
+561
-543
No files matched your search
@@ -44,7 +44,7 @@ export default function Hero({
|
||||
<button
|
||||
key={key}
|
||||
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">
|
||||
{demo.header}
|
||||
|
||||
@@ -394,7 +394,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
</NavLink>
|
||||
<div
|
||||
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 && (
|
||||
<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"
|
||||
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' : ''
|
||||
}`
|
||||
}
|
||||
@@ -565,9 +565,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
<NavLink
|
||||
target="_blank"
|
||||
to={'https://discord.gg/vN7YFfdMpj'}
|
||||
className={
|
||||
'rounded-full hover:bg-sidebar-accent'
|
||||
}
|
||||
className={'hover:bg-sidebar-accent rounded-full'}
|
||||
>
|
||||
<img
|
||||
src={Discord}
|
||||
@@ -580,9 +578,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
<NavLink
|
||||
target="_blank"
|
||||
to={'https://x.com/docsgptai'}
|
||||
className={
|
||||
'rounded-full hover:bg-sidebar-accent'
|
||||
}
|
||||
className={'hover:bg-sidebar-accent rounded-full'}
|
||||
>
|
||||
<img
|
||||
src={Twitter}
|
||||
@@ -595,9 +591,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
<NavLink
|
||||
target="_blank"
|
||||
to={'https://github.com/arc53/docsgpt'}
|
||||
className={
|
||||
'rounded-full hover:bg-sidebar-accent'
|
||||
}
|
||||
className={'hover:bg-sidebar-accent rounded-full'}
|
||||
>
|
||||
<img
|
||||
src={Github}
|
||||
@@ -624,7 +618,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
className="w-7 filter dark:invert"
|
||||
/>
|
||||
</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>
|
||||
<DeleteConvModal
|
||||
|
||||
@@ -6,7 +6,7 @@ export default function PageNotFound() {
|
||||
|
||||
return (
|
||||
<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>
|
||||
<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">
|
||||
|
||||
@@ -251,7 +251,7 @@ export default function AgentCard({
|
||||
};
|
||||
return (
|
||||
<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) => {
|
||||
e.stopPropagation();
|
||||
handleClick();
|
||||
@@ -283,17 +283,17 @@ export default function AgentCard({
|
||||
className="h-7 w-7 rounded-full object-contain"
|
||||
/>
|
||||
{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 className="mt-2">
|
||||
<p
|
||||
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}
|
||||
</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}
|
||||
</p>
|
||||
</div>
|
||||
@@ -320,4 +320,4 @@ export default function AgentCard({
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export default function AgentLogs() {
|
||||
<div className="p-4 md:p-12">
|
||||
<div className="flex items-center gap-3 px-4">
|
||||
<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')}
|
||||
>
|
||||
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
|
||||
@@ -59,7 +59,7 @@ export default function AgentLogs() {
|
||||
{agent && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<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
|
||||
? t('agents.logs.lastUsedAt') +
|
||||
' ' +
|
||||
|
||||
@@ -162,7 +162,7 @@ export default function AgentsList() {
|
||||
<h1 className="text-foreground mb-0 text-[32px] font-bold lg:text-[40px]">
|
||||
{t('agents.title')}
|
||||
</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')}
|
||||
</p>
|
||||
|
||||
@@ -178,7 +178,7 @@ export default function AgentsList() {
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
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>
|
||||
|
||||
@@ -190,7 +190,7 @@ export default function AgentsList() {
|
||||
className={`rounded-full px-4 py-2 text-sm transition-colors ${
|
||||
activeFilter === tab.id
|
||||
? '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)}
|
||||
@@ -224,7 +224,7 @@ export default function AgentsList() {
|
||||
))}
|
||||
|
||||
{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-sm">{t('agents.tryDifferentSearch')}</p>
|
||||
</div>
|
||||
@@ -399,7 +399,7 @@ function AgentSection({
|
||||
|
||||
if (isFilteredView && isSearchingWithNoResults) {
|
||||
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-sm">{t('agents.tryDifferentSearch')}</p>
|
||||
</div>
|
||||
@@ -408,7 +408,7 @@ function AgentSection({
|
||||
|
||||
if (isFilteredView && hasNoAgentsAtAll) {
|
||||
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>
|
||||
{config.showNewAgentButton && (
|
||||
<button
|
||||
@@ -456,7 +456,7 @@ function AgentSection({
|
||||
<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 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 ? (
|
||||
<>
|
||||
<button
|
||||
@@ -485,7 +485,7 @@ function AgentSection({
|
||||
t(`agents.sections.${config.id}.title`)
|
||||
)}
|
||||
</h2>
|
||||
<p className="text-[13px] text-muted-foreground">
|
||||
<p className="text-muted-foreground text-[13px]">
|
||||
{t(`agents.sections.${config.id}.description`)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -513,12 +513,12 @@ function AgentSection({
|
||||
}
|
||||
}}
|
||||
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
|
||||
/>
|
||||
) : (
|
||||
<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={() => {
|
||||
setIsCreatingFolder(true);
|
||||
setTimeout(() => newFolderInputRef.current?.focus(), 0);
|
||||
@@ -579,7 +579,7 @@ function AgentSection({
|
||||
))}
|
||||
</div>
|
||||
) : 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>
|
||||
{currentFolderId
|
||||
? t('agents.folders.empty')
|
||||
@@ -603,4 +603,4 @@ function AgentSection({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -70,17 +70,15 @@ export default function FolderCard({
|
||||
<>
|
||||
<div
|
||||
className={`relative flex cursor-pointer items-center justify-between rounded-[1.2rem] px-4 py-3 sm:w-48 ${
|
||||
isExpanded
|
||||
? 'bg-accent'
|
||||
: 'bg-muted hover:bg-accent'
|
||||
isExpanded ? 'bg-accent' : 'bg-muted hover:bg-accent'
|
||||
}`}
|
||||
onClick={() => onToggleExpand(folder.id)}
|
||||
>
|
||||
<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}
|
||||
</span>
|
||||
<span className="shrink-0 text-xs text-muted-foreground">
|
||||
<span className="text-muted-foreground shrink-0 text-xs">
|
||||
({agentCount})
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -143,7 +143,7 @@ export default function SharedAgent() {
|
||||
alt="No agent found"
|
||||
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')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
|
||||
<h2 className="text-foreground text-base font-semibold sm:text-lg">
|
||||
{agent.name}
|
||||
</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}
|
||||
</p>
|
||||
</div>
|
||||
@@ -34,7 +34,7 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
|
||||
</p>
|
||||
)}
|
||||
{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{' '}
|
||||
{new Date(agent.shared_metadata.shared_at).toLocaleString(
|
||||
'en-US',
|
||||
|
||||
@@ -575,12 +575,12 @@ function WorkflowBuilderInner() {
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-full flex-col bg-background">
|
||||
<div className="flex items-center justify-between border-b border-border bg-card px-6 py-4">
|
||||
<div className="bg-background flex h-screen w-full flex-col">
|
||||
<div className="border-border bg-card flex items-center justify-between border-b px-6 py-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<button
|
||||
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" />
|
||||
</button>
|
||||
@@ -609,7 +609,7 @@ function WorkflowBuilderInner() {
|
||||
{showWorkflowSettings && (
|
||||
<div
|
||||
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">
|
||||
<label className="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
@@ -619,7 +619,7 @@ function WorkflowBuilderInner() {
|
||||
type="text"
|
||||
value={workflowName}
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
@@ -630,14 +630,14 @@ function WorkflowBuilderInner() {
|
||||
<textarea
|
||||
value={workflowDescription}
|
||||
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}
|
||||
placeholder="Describe what this workflow does"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
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
|
||||
</button>
|
||||
@@ -656,7 +656,7 @@ function WorkflowBuilderInner() {
|
||||
}
|
||||
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} />
|
||||
Preview
|
||||
@@ -664,7 +664,7 @@ function WorkflowBuilderInner() {
|
||||
<button
|
||||
onClick={handlePublish}
|
||||
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'}
|
||||
</button>
|
||||
@@ -701,20 +701,20 @@ function WorkflowBuilderInner() {
|
||||
)}
|
||||
|
||||
<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>
|
||||
<h3 className="mb-3 text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400">
|
||||
Core Nodes
|
||||
</h3>
|
||||
<div className="flex flex-col gap-2">
|
||||
<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
|
||||
onDragStart={(e) =>
|
||||
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} />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-gray-700 dark:text-gray-200">
|
||||
@@ -722,7 +722,7 @@ function WorkflowBuilderInner() {
|
||||
</span>
|
||||
</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
|
||||
onDragStart={(e) =>
|
||||
e.dataTransfer.setData('application/reactflow', 'end')
|
||||
@@ -736,7 +736,7 @@ function WorkflowBuilderInner() {
|
||||
</span>
|
||||
</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
|
||||
onDragStart={(e) =>
|
||||
e.dataTransfer.setData('application/reactflow', 'note')
|
||||
@@ -758,7 +758,7 @@ function WorkflowBuilderInner() {
|
||||
</h3>
|
||||
<div className="flex flex-col gap-2">
|
||||
<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
|
||||
onDragStart={(e) =>
|
||||
e.dataTransfer.setData('application/reactflow', 'state')
|
||||
@@ -780,10 +780,7 @@ function WorkflowBuilderInner() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ref={reactFlowWrapper}
|
||||
className="relative flex-1 bg-muted"
|
||||
>
|
||||
<div ref={reactFlowWrapper} className="bg-muted relative flex-1">
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
@@ -803,9 +800,9 @@ function WorkflowBuilderInner() {
|
||||
{showNodeConfig && selectedNode && (
|
||||
<div
|
||||
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">
|
||||
{selectedNode.type === 'start' && 'Start 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="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">
|
||||
Node ID
|
||||
</div>
|
||||
@@ -852,7 +849,7 @@ function WorkflowBuilderInner() {
|
||||
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"
|
||||
/>
|
||||
</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}
|
||||
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}
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
@@ -1048,7 +1045,7 @@ function WorkflowBuilderInner() {
|
||||
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}
|
||||
placeholder="Enter note content"
|
||||
/>
|
||||
@@ -1069,7 +1066,7 @@ function WorkflowBuilderInner() {
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
@@ -1085,7 +1082,7 @@ function WorkflowBuilderInner() {
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
@@ -1116,7 +1113,7 @@ function WorkflowBuilderInner() {
|
||||
<SheetContent
|
||||
side="right"
|
||||
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
|
||||
workflowData={{
|
||||
|
||||
@@ -41,4 +41,4 @@ export const agentSectionsConfig = [
|
||||
selectData: selectSharedAgents,
|
||||
updateAction: setSharedAgents,
|
||||
},
|
||||
];
|
||||
];
|
||||
@@ -33,7 +33,7 @@ export default function AgentTypeModal({
|
||||
onClick={onClose}
|
||||
>
|
||||
<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()}
|
||||
>
|
||||
<button
|
||||
@@ -53,7 +53,7 @@ export default function AgentTypeModal({
|
||||
<div className="flex flex-col gap-4">
|
||||
<button
|
||||
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">
|
||||
<Bot size={28} />
|
||||
@@ -71,7 +71,7 @@ export default function AgentTypeModal({
|
||||
|
||||
<button
|
||||
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">
|
||||
<Workflow size={28} />
|
||||
|
||||
@@ -18,4 +18,4 @@ export default function Agents() {
|
||||
<Route path="/workflow/edit/:agentId" element={<WorkflowBuilder />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
name?: string;
|
||||
|
||||
@@ -1428,7 +1428,7 @@ function WorkflowBuilderInner() {
|
||||
]}
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
@@ -1608,10 +1608,10 @@ function WorkflowBuilderInner() {
|
||||
<Database size={18} />
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
<span className="text-foreground text-sm font-medium">
|
||||
Set State
|
||||
</span>
|
||||
<span className="text-[10px] text-muted-foreground">
|
||||
<span className="text-muted-foreground text-[10px]">
|
||||
Modify workflow variables
|
||||
</span>
|
||||
</div>
|
||||
@@ -1625,10 +1625,10 @@ function WorkflowBuilderInner() {
|
||||
<GitBranch size={18} />
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
<span className="text-foreground text-sm font-medium">
|
||||
If / Else
|
||||
</span>
|
||||
<span className="text-[10px] text-muted-foreground">
|
||||
<span className="text-muted-foreground text-[10px]">
|
||||
Conditional branching
|
||||
</span>
|
||||
</div>
|
||||
@@ -2041,7 +2041,7 @@ function WorkflowBuilderInner() {
|
||||
rows={2}
|
||||
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
|
||||
a custom expression.{' '}
|
||||
<a
|
||||
@@ -2376,7 +2376,7 @@ function WorkflowBuilderInner() {
|
||||
rows={2}
|
||||
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
|
||||
create a custom expression.{' '}
|
||||
<a
|
||||
|
||||
@@ -150,7 +150,7 @@ function ExecutionDetails({
|
||||
ref={(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">
|
||||
<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) && (
|
||||
<div className="mt-3 space-y-2 text-sm">
|
||||
{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">
|
||||
Output:{' '}
|
||||
</span>
|
||||
@@ -205,7 +205,7 @@ function ExecutionDetails({
|
||||
{stateVars.map(([key, value]) => (
|
||||
<span
|
||||
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">
|
||||
{key}:
|
||||
@@ -487,10 +487,10 @@ export default function WorkflowPreview({
|
||||
queries.length > 0 ? queries[queries.length - 1].executionSteps || [] : [];
|
||||
|
||||
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="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" />
|
||||
</div>
|
||||
<div>
|
||||
@@ -512,7 +512,7 @@ export default function WorkflowPreview({
|
||||
</div>
|
||||
|
||||
<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">
|
||||
<h3 className="text-xs font-semibold tracking-wider text-gray-500 uppercase dark:text-gray-400">
|
||||
Workflow
|
||||
@@ -537,7 +537,7 @@ export default function WorkflowPreview({
|
||||
>
|
||||
{queries.length === 0 ? (
|
||||
<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" />
|
||||
</div>
|
||||
<p className="text-xl font-semibold text-gray-700 dark:text-gray-200">
|
||||
@@ -618,7 +618,7 @@ export default function WorkflowPreview({
|
||||
</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
|
||||
onSubmit={(text) => handleQuestionSubmission(text)}
|
||||
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">
|
||||
<Monitor className="text-primary h-10 w-10" />
|
||||
</div>
|
||||
<h2 className="mb-2 text-xl font-bold text-foreground">
|
||||
<h2 className="text-foreground mb-2 text-xl font-bold">
|
||||
Desktop Required
|
||||
</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.
|
||||
Please open this page on a desktop or laptop computer.
|
||||
</p>
|
||||
|
||||
@@ -222,7 +222,7 @@ function VariableListWithSearch({
|
||||
|
||||
return (
|
||||
<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" />
|
||||
<input
|
||||
type="text"
|
||||
@@ -252,7 +252,7 @@ function VariableListWithSearch({
|
||||
e.stopPropagation();
|
||||
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" />
|
||||
<span className="truncate font-medium text-gray-800 dark:text-gray-200">
|
||||
@@ -412,7 +412,7 @@ export default function PromptTextArea({
|
||||
)}
|
||||
<div
|
||||
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
|
||||
ref={overlayRef}
|
||||
@@ -472,7 +472,7 @@ export default function PromptTextArea({
|
||||
<PopoverContent
|
||||
align="end"
|
||||
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()}
|
||||
>
|
||||
<VariableListWithSearch
|
||||
@@ -486,7 +486,7 @@ export default function PromptTextArea({
|
||||
{showDropdown && filtered.length > 0 && (
|
||||
<div
|
||||
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 }}
|
||||
>
|
||||
<VariableListWithSearch
|
||||
|
||||
@@ -27,8 +27,7 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
|
||||
let iconColor = 'text-gray-600 dark:text-gray-400';
|
||||
|
||||
if (selected) {
|
||||
borderColor =
|
||||
'border-primary ring-2 ring-primary';
|
||||
borderColor = 'border-primary ring-2 ring-primary';
|
||||
}
|
||||
|
||||
if (type === 'start') {
|
||||
@@ -56,7 +55,7 @@ export const BaseNode: React.FC<BaseNodeProps> = ({
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
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"
|
||||
position={Position.Right}
|
||||
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>
|
||||
|
||||
@@ -36,7 +36,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative rounded-2xl border bg-card shadow-md transition-all ${
|
||||
className={`bg-card relative rounded-2xl border shadow-md transition-all ${
|
||||
selected
|
||||
? 'border-primary dark:ring-primary scale-105 ring-2 ring-purple-300'
|
||||
: 'border-border hover:shadow-lg'
|
||||
@@ -47,7 +47,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
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">
|
||||
@@ -100,7 +100,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
|
||||
id={c.sourceHandle}
|
||||
isConnectable
|
||||
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
|
||||
@@ -109,7 +109,7 @@ const ConditionNode = ({ data, selected }: NodeProps<ConditionNodeData>) => {
|
||||
id="else"
|
||||
isConnectable
|
||||
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>
|
||||
);
|
||||
|
||||
@@ -53,7 +53,7 @@ export default function ActionButtons({
|
||||
<button
|
||||
title={t('actionButtons.openNewChat')}
|
||||
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
|
||||
className="filter dark:invert"
|
||||
@@ -70,7 +70,7 @@ export default function ActionButtons({
|
||||
<button
|
||||
title={t('actionButtons.share')}
|
||||
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
|
||||
className="filter dark:invert"
|
||||
|
||||
@@ -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="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 / 1000000).toFixed(2)}M`
|
||||
: totalChunks > 999
|
||||
@@ -606,7 +606,7 @@ const Chunks: React.FC<ChunksProps> = ({
|
||||
>
|
||||
<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="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.toLocaleString()
|
||||
: '-'}{' '}
|
||||
@@ -641,7 +641,7 @@ const Chunks: React.FC<ChunksProps> = ({
|
||||
<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 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.toLocaleString()
|
||||
: '-'}{' '}
|
||||
|
||||
@@ -68,9 +68,7 @@ export default function ConfigFields({
|
||||
<div key={key} className="flex flex-col gap-1.5">
|
||||
<Label htmlFor={key}>
|
||||
{spec.label || key}
|
||||
{spec.required && (
|
||||
<span className="text-red-500">*</span>
|
||||
)}
|
||||
{spec.required && <span className="text-red-500">*</span>}
|
||||
</Label>
|
||||
<Select
|
||||
value={value || spec.default || ''}
|
||||
@@ -82,7 +80,8 @@ export default function ConfigFields({
|
||||
size="lg"
|
||||
className={cn(
|
||||
'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} />
|
||||
@@ -90,13 +89,14 @@ export default function ConfigFields({
|
||||
<SelectContent>
|
||||
{spec.enum.map((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>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{hasError && (
|
||||
<p className="text-xs text-destructive">{errors[key]}</p>
|
||||
<p className="text-destructive text-xs">{errors[key]}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -106,9 +106,7 @@ export default function ConfigFields({
|
||||
<div key={key} className="flex flex-col gap-1.5">
|
||||
<Label htmlFor={key}>
|
||||
{spec.label || key}
|
||||
{spec.required && (
|
||||
<span className="text-red-500">*</span>
|
||||
)}
|
||||
{spec.required && <span className="text-red-500">*</span>}
|
||||
</Label>
|
||||
<Input
|
||||
id={key}
|
||||
@@ -134,12 +132,14 @@ export default function ConfigFields({
|
||||
}}
|
||||
placeholder={placeholder || spec.description || ''}
|
||||
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}
|
||||
className={cn('rounded-xl', hasError && 'border-destructive')}
|
||||
/>
|
||||
{hasError && (
|
||||
<p className="text-xs text-destructive">{errors[key]}</p>
|
||||
<p className="text-destructive text-xs">{errors[key]}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -39,8 +39,7 @@ export default function CopyButton({
|
||||
'flex items-center justify-center rounded-full transition-colors duration-150 ease-in-out',
|
||||
padding,
|
||||
{
|
||||
[`bg-transparent hover:bg-muted`]:
|
||||
!isCopied,
|
||||
[`bg-transparent hover:bg-muted`]: !isCopied,
|
||||
'bg-green-100 dark:bg-green-900 hover:bg-green-100 dark:hover:bg-green-900':
|
||||
isCopied,
|
||||
},
|
||||
|
||||
@@ -61,12 +61,12 @@ const Pagination: React.FC<PaginationProps> = ({
|
||||
<div className="relative">
|
||||
<button
|
||||
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}
|
||||
</button>
|
||||
<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
|
||||
? 'block scale-100 opacity-100'
|
||||
: 'hidden scale-95 opacity-0'
|
||||
@@ -76,7 +76,7 @@ const Pagination: React.FC<PaginationProps> = ({
|
||||
<div
|
||||
key={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
|
||||
? 'dark:text-foreground bg-gray-100 dark:bg-neutral-700'
|
||||
: 'bg-card dark:text-foreground'
|
||||
|
||||
@@ -110,7 +110,7 @@ function Dropdown<T extends DropdownOption>({
|
||||
<button
|
||||
type="button"
|
||||
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
|
||||
className={`truncate ${contentSize} ${displayValue ? '' : 'text-muted-foreground'}`}
|
||||
@@ -118,24 +118,24 @@ function Dropdown<T extends DropdownOption>({
|
||||
{displayValue ?? placeholder}
|
||||
</span>
|
||||
<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>
|
||||
|
||||
{open && (
|
||||
<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 && (
|
||||
<div className="flex items-center border-b border-border px-3 py-2">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
<div className="border-border flex items-center border-b px-3 py-2">
|
||||
<Search className="text-muted-foreground mr-2 h-4 w-4 shrink-0" />
|
||||
<input
|
||||
ref={searchRef}
|
||||
type="text"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
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()}
|
||||
/>
|
||||
</div>
|
||||
@@ -143,7 +143,7 @@ function Dropdown<T extends DropdownOption>({
|
||||
|
||||
<div className="max-h-48 overflow-y-auto">
|
||||
{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
|
||||
</div>
|
||||
) : (
|
||||
@@ -157,7 +157,7 @@ function Dropdown<T extends DropdownOption>({
|
||||
return (
|
||||
<div
|
||||
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
|
||||
onClick={() => {
|
||||
@@ -165,7 +165,7 @@ function Dropdown<T extends DropdownOption>({
|
||||
setOpen(false);
|
||||
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)}
|
||||
</span>
|
||||
@@ -185,9 +185,9 @@ function Dropdown<T extends DropdownOption>({
|
||||
setOpen(false);
|
||||
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>
|
||||
)}
|
||||
|
||||
@@ -202,13 +202,14 @@ function Dropdown<T extends DropdownOption>({
|
||||
: ((optObj?.id as string) ?? ''),
|
||||
);
|
||||
}}
|
||||
className={`mr-1 rounded p-1 hover:bg-accent ${
|
||||
typeof showDelete === 'function' && !showDelete(option)
|
||||
className={`hover:bg-accent mr-1 rounded p-1 ${
|
||||
typeof showDelete === 'function' &&
|
||||
!showDelete(option)
|
||||
? 'hidden'
|
||||
: ''
|
||||
} ${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>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -88,7 +88,7 @@ export default function DropdownMenu({
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<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
|
||||
role="menu"
|
||||
@@ -99,10 +99,8 @@ export default function DropdownMenu({
|
||||
{options.map((option, idx) => (
|
||||
<div
|
||||
id={`option-${idx}`}
|
||||
className={`dark:text-foreground cursor-pointer px-4 py-2 text-xs hover:bg-muted ${
|
||||
selectedOption.value === option.value
|
||||
? 'bg-muted'
|
||||
: 'bg-card'
|
||||
className={`dark:text-foreground hover:bg-muted cursor-pointer px-4 py-2 text-xs ${
|
||||
selectedOption.value === option.value ? 'bg-muted' : 'bg-card'
|
||||
}`}
|
||||
role="menuitem"
|
||||
key={option.value}
|
||||
|
||||
@@ -128,7 +128,9 @@ export default function DropdownModel() {
|
||||
))
|
||||
) : (
|
||||
<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>
|
||||
|
||||
@@ -93,9 +93,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [userEmail, setUserEmail] = useState<string>('');
|
||||
const [allowsSharedContent, setAllowsSharedContent] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState<'my_files' | 'shared'>(
|
||||
'my_files',
|
||||
);
|
||||
const [activeTab, setActiveTab] = useState<'my_files' | 'shared'>('my_files');
|
||||
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
@@ -214,9 +212,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
setIsConnected(true);
|
||||
setAuthError('');
|
||||
if (provider === 'share_point') {
|
||||
setAllowsSharedContent(
|
||||
validateData.allows_shared_content ?? false,
|
||||
);
|
||||
setAllowsSharedContent(validateData.allows_shared_content ?? false);
|
||||
}
|
||||
|
||||
setFiles([]);
|
||||
@@ -369,9 +365,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
{
|
||||
id: null,
|
||||
name:
|
||||
tab === 'shared'
|
||||
? 'Shared'
|
||||
: getProviderConfig(provider).rootName,
|
||||
tab === 'shared' ? 'Shared' : getProviderConfig(provider).rootName,
|
||||
},
|
||||
]);
|
||||
const sessionToken = getSessionToken(provider);
|
||||
@@ -380,8 +374,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
const handleFileSelect = (fileId: string, isFolder: boolean) => {
|
||||
if (isFolder) {
|
||||
const newSelectedFolders = selectedFolders.includes(fileId)
|
||||
@@ -459,10 +451,10 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
/>
|
||||
|
||||
{isConnected && (
|
||||
<div className="mt-3 overflow-hidden rounded-lg border border-border dark:border-border">
|
||||
<div className="rounded-t-lg border-border dark:border-border">
|
||||
<div className="border-border dark:border-border mt-3 overflow-hidden rounded-lg border">
|
||||
<div className="border-border dark:border-border rounded-t-lg">
|
||||
{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
|
||||
onClick={() => handleTabChange('my_files')}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
@@ -485,7 +477,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
</button>
|
||||
</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">
|
||||
{folderPath.map((path, index) => (
|
||||
<div
|
||||
@@ -531,7 +523,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
</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
|
||||
ref={scrollContainerRef}
|
||||
height="288px"
|
||||
@@ -586,7 +578,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
>
|
||||
<TableCell width="40px" align="center">
|
||||
<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) => {
|
||||
e.stopPropagation();
|
||||
handleFileSelect(file.id, isFolder(file));
|
||||
@@ -615,7 +607,9 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
className="h-6 w-6"
|
||||
/>
|
||||
</div>
|
||||
<span className="truncate">{file.name}</span>
|
||||
<span className="truncate">
|
||||
{file.name}
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-xs">
|
||||
@@ -626,7 +620,8 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{isLoading && files.length > 0 &&
|
||||
{isLoading &&
|
||||
files.length > 0 &&
|
||||
Array.from({ length: 3 }).map((_, i) => (
|
||||
<TableRow key={`load-more-skeleton-${i}`}>
|
||||
<TableCell width="40px" align="center">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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="mb-4 flex items-center justify-between">
|
||||
<div className="h-5 w-24 animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
|
||||
|
||||
@@ -599,7 +599,7 @@ const FileTree: React.FC<FileTreeProps> = ({
|
||||
<div ref={menuRef} className="relative">
|
||||
<button
|
||||
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')}
|
||||
>
|
||||
<img
|
||||
@@ -656,7 +656,7 @@ const FileTree: React.FC<FileTreeProps> = ({
|
||||
<div ref={menuRef} className="relative">
|
||||
<button
|
||||
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')}
|
||||
>
|
||||
<img
|
||||
@@ -754,11 +754,11 @@ const FileTree: React.FC<FileTreeProps> = ({
|
||||
}
|
||||
}}
|
||||
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 && (
|
||||
<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">
|
||||
{searchResults.length === 0 ? (
|
||||
<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}
|
||||
onClick={() => handleSearchSelect(result)}
|
||||
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
|
||||
? 'border-b border-border dark:border-border'
|
||||
? 'border-border dark:border-border border-b'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -262,7 +262,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
/>
|
||||
|
||||
{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="mb-4 flex items-center justify-between">
|
||||
<h3 className="text-sm font-medium">
|
||||
|
||||
@@ -36,20 +36,20 @@ const Help = () => {
|
||||
<button
|
||||
ref={buttonRef}
|
||||
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" />
|
||||
{t('help')}
|
||||
</button>
|
||||
{isOpen && (
|
||||
<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
|
||||
href="https://docs.docsgpt.cloud/"
|
||||
target="_blank"
|
||||
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
|
||||
src={PageIcon}
|
||||
@@ -61,7 +61,7 @@ const Help = () => {
|
||||
</a>
|
||||
<a
|
||||
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
|
||||
src={EmailIcon}
|
||||
|
||||
@@ -1438,7 +1438,7 @@ export default function MessageInput({
|
||||
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">
|
||||
{attachments.map((attachment) => {
|
||||
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 ${
|
||||
recordingState === 'recording'
|
||||
? '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'
|
||||
? 'cursor-not-allowed opacity-60'
|
||||
|
||||
@@ -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>
|
||||
) : (
|
||||
<div className="h-full overflow-y-auto scrollbar-overlay">
|
||||
<div className="scrollbar-overlay h-full overflow-y-auto">
|
||||
{filteredOptions.length === 0 ? (
|
||||
<div className="flex h-full flex-col items-center justify-center px-4 py-8 text-center">
|
||||
<img
|
||||
@@ -233,7 +233,7 @@ export default function MultiSelectPopup({
|
||||
<div
|
||||
key={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"
|
||||
aria-selected={isSelected}
|
||||
>
|
||||
@@ -248,7 +248,7 @@ export default function MultiSelectPopup({
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<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"
|
||||
>
|
||||
{isSelected && (
|
||||
|
||||
@@ -87,7 +87,7 @@ export default function Notification({
|
||||
))}
|
||||
</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}
|
||||
</p>
|
||||
<span className="relative z-10 flex items-center">
|
||||
@@ -132,4 +132,4 @@ export default function Notification({
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => {
|
||||
<div className="z-10 md:hidden">
|
||||
<button
|
||||
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')}
|
||||
>
|
||||
<img src={ArrowLeft} alt="left-arrow" className="h-3" />
|
||||
@@ -93,7 +93,7 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => {
|
||||
<div className="z-10 md:hidden">
|
||||
<button
|
||||
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')}
|
||||
>
|
||||
<img src={ArrowRight} alt="right-arrow" className="h-3" />
|
||||
|
||||
@@ -33,7 +33,7 @@ export default function Sidebar({
|
||||
return (
|
||||
<div ref={sidebarRef} className="h-vh relative">
|
||||
<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'
|
||||
} border-l border-[#9ca3af]/10`}
|
||||
>
|
||||
|
||||
@@ -97,7 +97,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
|
||||
{[...Array(8)].map((_, idx) => (
|
||||
<div
|
||||
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="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 = () => (
|
||||
<>
|
||||
{[...Array(skeletonCount)].map((_, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="bg-card w-full animate-pulse rounded-3xl p-6"
|
||||
>
|
||||
<div key={idx} className="bg-card w-full animate-pulse rounded-3xl p-6">
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-2">
|
||||
<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) => (
|
||||
<div
|
||||
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="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>
|
||||
<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) => (
|
||||
<div
|
||||
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="flex w-full items-center justify-between gap-2">
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function SourcesPopup({
|
||||
/>
|
||||
</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 ? (
|
||||
<>
|
||||
{filteredOptions?.map((option: any, index: number) => {
|
||||
@@ -154,7 +154,7 @@ export default function SourcesPopup({
|
||||
return (
|
||||
<div
|
||||
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={() => {
|
||||
if (isSelected) {
|
||||
const updatedDocs =
|
||||
@@ -190,7 +190,7 @@ export default function SourcesPopup({
|
||||
{option.name}
|
||||
</span>
|
||||
<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 && (
|
||||
<img
|
||||
|
||||
@@ -46,7 +46,7 @@ const TableContainer = React.forwardRef<HTMLDivElement, TableContainerProps>(
|
||||
<div className={`relative rounded-[6px] ${className}`}>
|
||||
<div
|
||||
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={{
|
||||
maxHeight: height === 'auto' ? undefined : height,
|
||||
overflowY: height === 'auto' ? 'hidden' : 'auto',
|
||||
@@ -75,7 +75,7 @@ const Table: React.FC<TableProps> = ({
|
||||
const TableHead: React.FC<TableHeadProps> = ({ children, className = '' }) => {
|
||||
return (
|
||||
<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}
|
||||
</thead>
|
||||
|
||||
@@ -176,9 +176,7 @@ export default function SpeakButton({ text }: { text: string }) {
|
||||
<button
|
||||
type="button"
|
||||
className={`flex cursor-pointer items-center justify-center rounded-full p-2 ${
|
||||
isSpeaking || isLoading
|
||||
? 'bg-accent'
|
||||
: 'bg-transparent hover:bg-accent'
|
||||
isSpeaking || isLoading ? 'bg-accent' : 'hover:bg-accent bg-transparent'
|
||||
}`}
|
||||
onClick={handleSpeakClick}
|
||||
aria-label={
|
||||
|
||||
@@ -175,7 +175,7 @@ export default function ToolsPopup({
|
||||
</div>
|
||||
) : (
|
||||
<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 ? (
|
||||
<div className="flex h-full flex-col items-center justify-center py-8">
|
||||
<img
|
||||
@@ -192,7 +192,7 @@ export default function ToolsPopup({
|
||||
<div
|
||||
key={tool.id}
|
||||
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">
|
||||
<img
|
||||
@@ -208,7 +208,7 @@ export default function ToolsPopup({
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center">
|
||||
<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 && (
|
||||
<img
|
||||
|
||||
@@ -70,7 +70,7 @@ export function MultiSelect({
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
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',
|
||||
className,
|
||||
)}
|
||||
@@ -124,7 +124,7 @@ export function MultiSelect({
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<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"
|
||||
>
|
||||
<Command className="bg-transparent">
|
||||
|
||||
@@ -37,11 +37,11 @@ function SelectTrigger({
|
||||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
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' &&
|
||||
'border-border bg-card focus-visible:ring-ring/50 hover:bg-accent data-placeholder:text-muted-foreground',
|
||||
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,
|
||||
)}
|
||||
{...props}
|
||||
@@ -113,7 +113,7 @@ function SelectItem({
|
||||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
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,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import * as React from "react"
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
||||
import { XIcon } from "lucide-react"
|
||||
import * as React from 'react';
|
||||
import * as SheetPrimitive from '@radix-ui/react-dialog';
|
||||
import { XIcon } from 'lucide-react';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />
|
||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
||||
}
|
||||
|
||||
function SheetTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
||||
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
||||
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
|
||||
}
|
||||
|
||||
function SheetClose({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
||||
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
|
||||
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
|
||||
}
|
||||
|
||||
function SheetPortal({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
||||
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
|
||||
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
|
||||
}
|
||||
|
||||
function SheetOverlay({
|
||||
@@ -34,23 +34,23 @@ function SheetOverlay({
|
||||
<SheetPrimitive.Overlay
|
||||
data-slot="sheet-overlay"
|
||||
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",
|
||||
className
|
||||
'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,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function SheetContent({
|
||||
className,
|
||||
children,
|
||||
side = "right",
|
||||
side = 'right',
|
||||
showCloseButton = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
||||
side?: "top" | "right" | "bottom" | "left"
|
||||
showCloseButton?: boolean
|
||||
side?: 'top' | 'right' | 'bottom' | 'left';
|
||||
showCloseButton?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<SheetPortal>
|
||||
@@ -58,16 +58,16 @@ function SheetContent({
|
||||
<SheetPrimitive.Content
|
||||
data-slot="sheet-content"
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
className
|
||||
'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' &&
|
||||
'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' &&
|
||||
'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' &&
|
||||
'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' &&
|
||||
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -80,27 +80,27 @@ function SheetContent({
|
||||
)}
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
<div
|
||||
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}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
<div
|
||||
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}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function SheetTitle({
|
||||
@@ -110,10 +110,10 @@ function SheetTitle({
|
||||
return (
|
||||
<SheetPrimitive.Title
|
||||
data-slot="sheet-title"
|
||||
className={cn("text-foreground font-semibold", className)}
|
||||
className={cn('text-foreground font-semibold', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function SheetDescription({
|
||||
@@ -123,10 +123,10 @@ function SheetDescription({
|
||||
return (
|
||||
<SheetPrimitive.Description
|
||||
data-slot="sheet-description"
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
className={cn('text-muted-foreground text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
@@ -138,4 +138,4 @@ export {
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription,
|
||||
}
|
||||
};
|
||||
@@ -137,7 +137,7 @@ const ConversationBubble = forwardRef<
|
||||
<div
|
||||
key={index}
|
||||
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]">
|
||||
<img
|
||||
@@ -198,7 +198,7 @@ const ConversationBubble = forwardRef<
|
||||
setIsEditClicked(true);
|
||||
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" />
|
||||
</button>
|
||||
@@ -227,7 +227,7 @@ const ConversationBubble = forwardRef<
|
||||
/>
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<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)}
|
||||
>
|
||||
{t('conversation.edit.cancel')}
|
||||
@@ -322,7 +322,7 @@ const ConversationBubble = forwardRef<
|
||||
{sources?.slice(0, 3)?.map((source, index) => (
|
||||
<div key={index} className="relative">
|
||||
<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)}
|
||||
onMouseOut={() => setActiveTooltip(null)}
|
||||
>
|
||||
@@ -379,7 +379,7 @@ const ConversationBubble = forwardRef<
|
||||
))}
|
||||
{(sources?.length ?? 0) > 3 && (
|
||||
<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)}
|
||||
>
|
||||
<p className="ellipsis-text h-22 text-xs">
|
||||
@@ -458,7 +458,7 @@ const ConversationBubble = forwardRef<
|
||||
<div
|
||||
className={`fade-in-bubble bg-answer-bubble mr-5 flex max-w-full rounded-[18px] px-6 py-4.5 ${
|
||||
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'
|
||||
}`}
|
||||
>
|
||||
@@ -551,14 +551,14 @@ const ConversationBubble = forwardRef<
|
||||
},
|
||||
thead({ children }) {
|
||||
return (
|
||||
<thead className="bg-muted text-xs text-foreground uppercase">
|
||||
<thead className="bg-muted text-foreground text-xs uppercase">
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
tr({ children }) {
|
||||
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}
|
||||
</tr>
|
||||
);
|
||||
@@ -657,7 +657,7 @@ const ConversationBubble = forwardRef<
|
||||
<div className="relative mr-2 flex items-center justify-center">
|
||||
<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={() => {
|
||||
if (feedback === 'LIKE') {
|
||||
handleFeedback?.(null);
|
||||
@@ -670,7 +670,7 @@ const ConversationBubble = forwardRef<
|
||||
}
|
||||
>
|
||||
<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>
|
||||
</button>
|
||||
</div>
|
||||
@@ -678,7 +678,7 @@ const ConversationBubble = forwardRef<
|
||||
<div className="relative mr-2 flex items-center justify-center">
|
||||
<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={() => {
|
||||
if (feedback === 'DISLIKE') {
|
||||
handleFeedback?.(null);
|
||||
@@ -693,7 +693,7 @@ const ConversationBubble = forwardRef<
|
||||
}
|
||||
>
|
||||
<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>
|
||||
</button>
|
||||
</div>
|
||||
@@ -746,7 +746,7 @@ function AllSources(sources: AllSourcesProps) {
|
||||
return (
|
||||
<div
|
||||
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' : ''
|
||||
}`}
|
||||
onClick={() =>
|
||||
@@ -790,105 +790,105 @@ function ToolCalls({ toolCalls }: { toolCalls: ToolCallsType[] }) {
|
||||
const [isToolCallsOpen, setIsToolCallsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<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">
|
||||
<Avatar
|
||||
className="h-[26px] w-[30px] text-xl"
|
||||
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>
|
||||
<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">
|
||||
<Avatar
|
||||
className="h-[26px] w-[30px] text-xl"
|
||||
avatar={
|
||||
<img
|
||||
src={ChevronDown}
|
||||
alt="ChevronDown"
|
||||
className={`h-4 w-4 transform transition-transform duration-200 dark:invert ${isToolCallsOpen ? 'rotate-180' : ''}`}
|
||||
src={Sources}
|
||||
alt={'ToolCalls'}
|
||||
className="h-full w-full object-fill"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
{isToolCallsOpen && (
|
||||
<div className="fade-in mr-5 ml-3 w-[90vw] md:w-[70vw] lg:w-full">
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
{toolCalls.map((toolCall, index) => (
|
||||
<Accordion
|
||||
key={`tool-call-${index}`}
|
||||
title={`${toolCall.tool_name} - ${toolCall.action_name.substring(0, toolCall.action_name.lastIndexOf('_'))}`}
|
||||
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>
|
||||
}
|
||||
/>
|
||||
<button
|
||||
className="flex flex-row items-center gap-2"
|
||||
onClick={() => setIsToolCallsOpen(!isToolCallsOpen)}
|
||||
>
|
||||
<p className="text-base font-semibold">Tool Calls</p>
|
||||
<img
|
||||
src={ChevronDown}
|
||||
alt="ChevronDown"
|
||||
className={`h-4 w-4 transform transition-transform duration-200 dark:invert ${isToolCallsOpen ? 'rotate-180' : ''}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
{isToolCallsOpen && (
|
||||
<div className="fade-in mr-5 ml-3 w-[90vw] md:w-[70vw] lg:w-full">
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
{toolCalls.map((toolCall, index) => (
|
||||
<Accordion
|
||||
key={`tool-call-${index}`}
|
||||
title={`${toolCall.tool_name} - ${toolCall.action_name.substring(0, toolCall.action_name.lastIndexOf('_'))}`}
|
||||
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">
|
||||
<span
|
||||
className="leading-[23px] text-black dark:text-muted-foreground"
|
||||
className="dark:text-muted-foreground leading-[23px] text-black"
|
||||
style={{ fontFamily: 'IBMPlexMono-Medium' }}
|
||||
>
|
||||
{JSON.stringify(toolCall.arguments, null, 2)}
|
||||
{JSON.stringify(toolCall.result, 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" />
|
||||
)}
|
||||
{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>
|
||||
)}
|
||||
{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>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Accordion>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Accordion>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -998,14 +998,14 @@ function Thought({
|
||||
},
|
||||
thead({ children }) {
|
||||
return (
|
||||
<thead className="bg-muted text-xs text-foreground uppercase">
|
||||
<thead className="bg-muted text-foreground text-xs uppercase">
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
tr({ children }) {
|
||||
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}
|
||||
</tr>
|
||||
);
|
||||
|
||||
@@ -240,7 +240,7 @@ export default function ConversationMessages({
|
||||
scrollConversationToBottom();
|
||||
}}
|
||||
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
|
||||
src={ArrowDown}
|
||||
|
||||
@@ -203,7 +203,7 @@ export default function ConversationTile({
|
||||
<input
|
||||
autoFocus
|
||||
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}
|
||||
onChange={(e) => setConversationsName(e.target.value)}
|
||||
onKeyDown={handleRenameKeyDown}
|
||||
@@ -215,7 +215,10 @@ export default function ConversationTile({
|
||||
)}
|
||||
</div>
|
||||
{(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 ? (
|
||||
<div className="flex gap-1">
|
||||
<img
|
||||
@@ -248,7 +251,7 @@ export default function ConversationTile({
|
||||
event.stopPropagation();
|
||||
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" />
|
||||
</button>
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function AddActionModal({
|
||||
setModalState('INACTIVE');
|
||||
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')}
|
||||
</button>
|
||||
|
||||
@@ -131,7 +131,7 @@ export default function AddToolModal({
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
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={() => {
|
||||
setSelectedTool(tool);
|
||||
handleAddTool(tool);
|
||||
|
||||
@@ -140,19 +140,21 @@ export default function ConfigToolModal({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{hasConfig && <ConfigFields
|
||||
configRequirements={configRequirements}
|
||||
values={configValues}
|
||||
onChange={handleFieldChange}
|
||||
errors={errors}
|
||||
/>}
|
||||
{hasConfig && (
|
||||
<ConfigFields
|
||||
configRequirements={configRequirements}
|
||||
values={configValues}
|
||||
onChange={handleFieldChange}
|
||||
errors={errors}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-8 flex flex-row-reverse gap-2">
|
||||
<button
|
||||
onClick={handleAddTool}
|
||||
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
|
||||
? t('modals.configTool.addButton') + '…'
|
||||
@@ -160,7 +162,7 @@ export default function ConfigToolModal({
|
||||
</button>
|
||||
<button
|
||||
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')}
|
||||
</button>
|
||||
|
||||
@@ -59,7 +59,7 @@ export default function FolderNameModal({
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={t('agents.folders.folderName')}
|
||||
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">
|
||||
<button
|
||||
@@ -67,7 +67,7 @@ export default function FolderNameModal({
|
||||
setModalState('INACTIVE');
|
||||
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')}
|
||||
</button>
|
||||
|
||||
@@ -206,7 +206,7 @@ export default function ImportSpecModal({
|
||||
</div>
|
||||
) : (
|
||||
<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">
|
||||
{parsedResult.metadata.title}
|
||||
</h3>
|
||||
@@ -215,7 +215,7 @@ export default function ImportSpecModal({
|
||||
{parsedResult.metadata.description}
|
||||
</p>
|
||||
)}
|
||||
<p className="mt-2 text-xs text-muted-foreground">
|
||||
<p className="text-muted-foreground mt-2 text-xs">
|
||||
{t('modals.importSpec.version')}:{' '}
|
||||
{parsedResult.metadata.version}
|
||||
</p>
|
||||
@@ -227,7 +227,7 @@ export default function ImportSpecModal({
|
||||
type="text"
|
||||
value={baseUrl}
|
||||
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={
|
||||
parsedResult.metadata.base_url || 'https://api.example.com'
|
||||
}
|
||||
@@ -255,7 +255,7 @@ export default function ImportSpecModal({
|
||||
{parsedResult.actions.map((action, index) => (
|
||||
<label
|
||||
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
|
||||
type="checkbox"
|
||||
@@ -310,7 +310,7 @@ export default function ImportSpecModal({
|
||||
)}
|
||||
<button
|
||||
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')}
|
||||
</button>
|
||||
|
||||
@@ -753,7 +753,7 @@ export default function MCPServerModal({
|
||||
<button
|
||||
onClick={testConnection}
|
||||
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 ? (
|
||||
<div className="flex items-center justify-center">
|
||||
@@ -773,7 +773,7 @@ export default function MCPServerModal({
|
||||
setModalState('INACTIVE');
|
||||
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')}
|
||||
</button>
|
||||
|
||||
@@ -151,7 +151,7 @@ export default function MoveToFolderModal({
|
||||
</h2>
|
||||
</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" }}
|
||||
>
|
||||
<button
|
||||
@@ -180,7 +180,7 @@ export default function MoveToFolderModal({
|
||||
) : (
|
||||
<button
|
||||
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}
|
||||
</button>
|
||||
@@ -188,10 +188,10 @@ export default function MoveToFolderModal({
|
||||
</span>
|
||||
))}
|
||||
</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 ? (
|
||||
<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')}...
|
||||
</span>
|
||||
</div>
|
||||
@@ -204,7 +204,7 @@ export default function MoveToFolderModal({
|
||||
e.stopPropagation();
|
||||
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
|
||||
? 'bg-[#7D54D1] text-white'
|
||||
: 'bg-muted hover:bg-accent dark:bg-muted'
|
||||
@@ -226,7 +226,7 @@ export default function MoveToFolderModal({
|
||||
<button
|
||||
key={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
|
||||
? 'bg-[#7D54D1] text-white'
|
||||
: 'bg-muted hover:bg-accent dark:bg-muted'
|
||||
@@ -271,14 +271,14 @@ export default function MoveToFolderModal({
|
||||
</button>
|
||||
))}
|
||||
{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')}
|
||||
</div>
|
||||
)}
|
||||
{currentLevelFolders.length === 0 &&
|
||||
folderPath.length === 0 &&
|
||||
!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')}
|
||||
</div>
|
||||
)}
|
||||
@@ -286,7 +286,7 @@ export default function MoveToFolderModal({
|
||||
)}
|
||||
</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 ? (
|
||||
<input
|
||||
ref={newFolderInputRef}
|
||||
@@ -309,7 +309,7 @@ export default function MoveToFolderModal({
|
||||
}
|
||||
}}
|
||||
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
|
||||
/>
|
||||
) : (
|
||||
@@ -336,7 +336,7 @@ export default function MoveToFolderModal({
|
||||
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')}
|
||||
</button>
|
||||
|
||||
@@ -32,8 +32,7 @@ export default function WrapperModal({
|
||||
)
|
||||
return;
|
||||
if (document.querySelector('[data-radix-select-content]')) return;
|
||||
if (modalRef.current && !modalRef.current.contains(target))
|
||||
close();
|
||||
if (modalRef.current && !modalRef.current.contains(target)) close();
|
||||
};
|
||||
|
||||
const handleEscapePress = (event: KeyboardEvent) => {
|
||||
@@ -61,7 +60,7 @@ export default function WrapperModal({
|
||||
/>
|
||||
<div
|
||||
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 && (
|
||||
<button
|
||||
@@ -72,7 +71,7 @@ export default function WrapperModal({
|
||||
</button>
|
||||
)}
|
||||
<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}
|
||||
</div>
|
||||
|
||||
@@ -120,7 +120,7 @@ function PromptTextarea({
|
||||
return (
|
||||
<>
|
||||
<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"
|
||||
>
|
||||
<div
|
||||
@@ -239,7 +239,7 @@ function AddPrompt({
|
||||
<p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white">
|
||||
{t('modals.prompts.addPrompt')}
|
||||
</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')}
|
||||
</p>
|
||||
<div>
|
||||
@@ -266,7 +266,7 @@ function AddPrompt({
|
||||
htmlFor="new-prompt-content"
|
||||
className={`absolute z-20 select-none ${
|
||||
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')}
|
||||
</label>
|
||||
@@ -278,7 +278,7 @@ function AddPrompt({
|
||||
<span className="font-bold">
|
||||
{t('modals.prompts.variablesLabel')}
|
||||
</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')}
|
||||
</span>
|
||||
</p>
|
||||
@@ -446,7 +446,7 @@ function EditPrompt({
|
||||
<p className="mb-1 text-xl font-semibold text-[#2B2B2B] dark:text-white">
|
||||
{t('modals.prompts.editPrompt')}
|
||||
</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')}
|
||||
</p>
|
||||
<div>
|
||||
@@ -473,7 +473,7 @@ function EditPrompt({
|
||||
htmlFor="edit-prompt-content"
|
||||
className={`absolute z-20 select-none ${
|
||||
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')}
|
||||
</label>
|
||||
@@ -485,7 +485,7 @@ function EditPrompt({
|
||||
<span className="font-bold">
|
||||
{t('modals.prompts.variablesLabel')}
|
||||
</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')}
|
||||
</span>
|
||||
</p>
|
||||
@@ -759,7 +759,7 @@ export default function PromptsModal({
|
||||
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"
|
||||
>
|
||||
{view}
|
||||
|
||||
@@ -175,7 +175,7 @@ export default function Analytics({ agentId }: AnalyticsProps) {
|
||||
}, [agentId, feedbackFilter]);
|
||||
return (
|
||||
<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')}
|
||||
</p>
|
||||
{/* Messages Analytics */}
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function Logs({ agentId, tableHeader }: LogsProps) {
|
||||
}, [page, agentId]);
|
||||
return (
|
||||
<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')}
|
||||
</p>
|
||||
<div>
|
||||
@@ -117,9 +117,9 @@ function LogsTable({ logs, setPage, loading, tableHeader }: LogsTableProps) {
|
||||
}, []);
|
||||
|
||||
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">
|
||||
<p className="px-3 text-xs text-muted-foreground">
|
||||
<p className="text-muted-foreground px-3 text-xs">
|
||||
{tableHeader ? tableHeader : t('settings.logs.tableHeader')}
|
||||
</p>
|
||||
</div>
|
||||
@@ -168,11 +168,11 @@ function Log({
|
||||
const { id, action, timestamp, ...filteredLog } = log;
|
||||
|
||||
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
|
||||
onClick={() => onToggle(log.id)}
|
||||
className={`flex cursor-pointer flex-row items-start gap-2 p-2 px-4 py-3 text-foreground ${
|
||||
isOpen ? 'rounded-t-xl bg-[#F1F1F1] dark:bg-background' : ''
|
||||
className={`text-foreground flex cursor-pointer flex-row items-start gap-2 p-2 px-4 py-3 ${
|
||||
isOpen ? 'dark:bg-background rounded-t-xl bg-[#F1F1F1]' : ''
|
||||
}`}
|
||||
>
|
||||
<img
|
||||
@@ -193,7 +193,7 @@ function Log({
|
||||
</span>
|
||||
</div>
|
||||
{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">
|
||||
<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)}
|
||||
|
||||
@@ -362,7 +362,7 @@ export default function Sources({
|
||||
) : (
|
||||
<div className="mt-8 flex w-full max-w-full flex-col overflow-hidden">
|
||||
<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')}
|
||||
</p>
|
||||
<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')}
|
||||
</label>
|
||||
<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
|
||||
maxLength={256}
|
||||
placeholder={t('settings.sources.searchPlaceholder')}
|
||||
@@ -383,7 +387,7 @@ export default function Sources({
|
||||
setSearchTerm(e.target.value);
|
||||
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>
|
||||
@@ -422,7 +426,7 @@ export default function Sources({
|
||||
return (
|
||||
<div key={docId} className="relative">
|
||||
<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
|
||||
? 'scale-[1.05]'
|
||||
: 'hover:scale-[1.05]'
|
||||
@@ -431,7 +435,7 @@ export default function Sources({
|
||||
<div className="w-full flex-1">
|
||||
<div className="flex w-full items-center justify-between gap-2">
|
||||
<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}
|
||||
>
|
||||
{document.name}
|
||||
@@ -472,7 +476,7 @@ export default function Sources({
|
||||
e.stopPropagation();
|
||||
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')}
|
||||
data-testid={`menu-button-${docId}`}
|
||||
>
|
||||
@@ -493,17 +497,13 @@ export default function Sources({
|
||||
alt=""
|
||||
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) : ''}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<img
|
||||
src={DiscIcon}
|
||||
alt=""
|
||||
className="h-3.5 w-3.5"
|
||||
/>
|
||||
<span className="font-inter text-[12px] leading-[18px] font-medium text-muted-foreground">
|
||||
<img src={DiscIcon} alt="" className="h-3.5 w-3.5" />
|
||||
<span className="font-inter text-muted-foreground text-[12px] leading-[18px] font-medium">
|
||||
{document.tokens
|
||||
? formatTokens(+document.tokens)
|
||||
: ''}
|
||||
|
||||
@@ -332,7 +332,7 @@ export default function ToolConfig({
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div className="text-foreground dark:text-foreground flex items-center gap-3 text-sm">
|
||||
<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}
|
||||
>
|
||||
<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 ? (
|
||||
<>
|
||||
<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
|
||||
type="text"
|
||||
value={userActionsSearch}
|
||||
onChange={(e) => setUserActionsSearch(e.target.value)}
|
||||
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>
|
||||
|
||||
@@ -843,13 +853,23 @@ function APIToolConfig({
|
||||
return (
|
||||
<div className="scrollbar-overlay flex flex-col gap-4">
|
||||
<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
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
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>
|
||||
|
||||
@@ -945,7 +965,7 @@ function APIToolConfig({
|
||||
</div>
|
||||
<div className="mt-4 px-5 py-2">
|
||||
<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')}
|
||||
</span>
|
||||
<Dropdown
|
||||
@@ -1024,7 +1044,7 @@ function APIToolConfig({
|
||||
action.method === 'OPTIONS') && (
|
||||
<div className="mt-4 px-5 py-2">
|
||||
<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')}
|
||||
</span>
|
||||
<Dropdown
|
||||
|
||||
+119
-111
@@ -210,12 +210,16 @@ export default function Tools() {
|
||||
) : (
|
||||
<div className="mt-8">
|
||||
<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')}
|
||||
</p>
|
||||
<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">
|
||||
<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
|
||||
maxLength={256}
|
||||
placeholder={t('settings.tools.searchPlaceholder')}
|
||||
@@ -224,7 +228,7 @@ export default function Tools() {
|
||||
id="tool-search-input"
|
||||
value={searchTerm}
|
||||
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>
|
||||
<button
|
||||
@@ -256,115 +260,119 @@ export default function Tools() {
|
||||
{t('settings.tools.noToolsFound')}
|
||||
</p>
|
||||
</div>
|
||||
) : (() => {
|
||||
const filtered = userTools.filter((tool) =>
|
||||
(tool.customName || tool.displayName)
|
||||
.toLowerCase()
|
||||
.includes(searchTerm.toLowerCase()),
|
||||
);
|
||||
return filtered.length === 0 ? (
|
||||
<div className="flex w-full flex-col items-center justify-center py-12">
|
||||
<img
|
||||
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
|
||||
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>
|
||||
</div>
|
||||
) : (
|
||||
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>
|
||||
) : (
|
||||
(() => {
|
||||
const filtered = userTools.filter((tool) =>
|
||||
(tool.customName || tool.displayName)
|
||||
.toLowerCase()
|
||||
.includes(searchTerm.toLowerCase()),
|
||||
);
|
||||
return filtered.length === 0 ? (
|
||||
<div className="flex w-full flex-col items-center justify-center py-12">
|
||||
<img
|
||||
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
|
||||
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>
|
||||
</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>
|
||||
|
||||
@@ -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 : streamline async state management
|
||||
// TODO : streamline async state management
|
||||
@@ -203,7 +203,7 @@ function Upload({
|
||||
{files.map((file) => (
|
||||
<p
|
||||
key={file.name}
|
||||
className="truncate overflow-hidden text-ellipsis text-muted-foreground"
|
||||
className="text-muted-foreground truncate overflow-hidden text-ellipsis"
|
||||
title={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 ${
|
||||
ingestor.type === option.value
|
||||
? '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={() =>
|
||||
handleIngestorTypeChange(option.value as IngestorType)
|
||||
@@ -843,7 +843,7 @@ function Upload({
|
||||
>
|
||||
<div className="flex w-full flex-col gap-6">
|
||||
{!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')}
|
||||
</p>
|
||||
)}
|
||||
@@ -865,7 +865,7 @@ function Upload({
|
||||
<span>{t('modals.uploadDoc.back')}</span>
|
||||
</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 &&
|
||||
t(`modals.uploadDoc.ingestors.${ingestor.type}.heading`)}
|
||||
</h2>
|
||||
@@ -913,7 +913,7 @@ function Upload({
|
||||
disabled={isUploadDisabled()}
|
||||
className={`rounded-3xl px-4 py-2 text-[14px] font-medium ${
|
||||
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'
|
||||
}`}
|
||||
>
|
||||
|
||||
Reference in new issue
Block a user