Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default function OidcTokenHandler() {
window.dispatchEvent(new Event('oidc-login-success'));
}, 100);
}
}, [router, searchParams]);
}, [router, searchParams, t]);

return null;
}
8 changes: 4 additions & 4 deletions frontend/src/features/onboarding/useOnboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0

import { useEffect, useRef, useState } from 'react';
import { useEffect, useRef, useState, useCallback } from 'react';
import { useRouter } from 'next/navigation';
import { driver, Driver, AllowedButtons, Config } from 'driver.js';
import { useTranslation } from 'react-i18next';
Expand Down Expand Up @@ -64,7 +64,7 @@ export const useOnboarding = ({
localStorage.setItem(ONBOARDING_CURRENT_STEP_KEY, step.toString());
};

const startTour = () => {
const startTour = useCallback(() => {
if (isLoading) {
return;
}
Expand Down Expand Up @@ -129,7 +129,7 @@ export const useOnboarding = ({
}

setOnboardingInProgress(true);
};
}, [isLoading, t, hasTeams, hasGitToken, currentPage, router]);

const restartTour = () => {
localStorage.removeItem(ONBOARDING_COMPLETED_KEY);
Expand Down Expand Up @@ -163,7 +163,7 @@ export const useOnboarding = ({
}, 500);
return () => clearTimeout(timer);
}
}, [isReady, isLoading, hasShareId, currentPage]);
}, [isReady, isLoading, hasShareId, currentPage, startTour]);

// Cleanup on unmount
useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/features/settings/components/BotList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function BotList() {
}
}
loadBots();
}, []);
}, [message, setBotsSorted, t]);

const handleCreateBot = () => {
setCloningBot(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function GitHubIntegration() {
}
}
loadGitInfo();
}, [user]);
}, [user, message, t]);

const platforms = gitInfo || [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const McpConfigImportModal: React.FC<McpConfigImportModalProps> = ({
message.error(t('bot.errors.mcp_config_invalid'));
}
}
}, [importConfig, importMode, message, onImport, t]);
}, [importConfig, importMode, message, onImport, t, agentType]);

// Reset state when closing modal
const handleCancel = () => {
Expand Down
15 changes: 8 additions & 7 deletions frontend/src/features/settings/components/TabParamSync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ interface TabParamSyncProps {
export default function TabParamSync({ tabIndex: _tabIndex, setTabIndex }: TabParamSyncProps) {
const searchParams = useSearchParams();

// Tab name to index mapping parameterization
const tabNameToIndex: Record<string, number> = {
integrations: 0,
bots: 1,
bot: 1,
team: 2,
};
useEffect(() => {
// Tab name to index mapping parameterization
const tabNameToIndex: Record<string, number> = {
integrations: 0,
bots: 1,
bot: 1,
team: 2,
};

const tab = searchParams?.get('tab');
if (tab && tabNameToIndex.hasOwnProperty(tab)) {
const newIndex = tabNameToIndex[tab];
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/features/settings/components/TeamList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default function TeamList() {
}
}
loadData();
}, []);
}, [message, setBotsSorted, setTeamsSorted, t]);

useEffect(() => {
if (editingTeamId === null) {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/features/tasks/components/ChatArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export default function ChatArea({
setSelectedTeam(teams[0]);
}
setHasRestoredPreferences(true);
}, [teams, hasRestoredPreferences]);
}, [teams, hasRestoredPreferences, selectedTeam]);

// Handle external team selection for new tasks (from team sharing)
useEffect(() => {
Expand Down Expand Up @@ -276,7 +276,7 @@ export default function ChatArea({
// Force scroll to bottom when opening a historical task
setTimeout(() => scrollToBottom(true), 100);
}
}, [selectedTaskDetail?.id]);
}, [selectedTaskDetail?.id, hasMessages]);

useEffect(() => {
if (!hasMessages || !lastSubtaskId) return;
Expand Down
105 changes: 54 additions & 51 deletions frontend/src/features/tasks/components/ResizableSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,102 @@
//
// SPDX-License-Identifier: Apache-2.0

'use client'
'use client';

import React, { useState, useEffect, useRef, ReactNode } from 'react'
import React, { useState, useEffect, useRef, ReactNode } from 'react';

interface ResizableSidebarProps {
children: ReactNode
minWidth?: number
maxWidth?: number
defaultWidth?: number
storageKey?: string
children: ReactNode;
minWidth?: number;
maxWidth?: number;
defaultWidth?: number;
storageKey?: string;
}

export default function ResizableSidebar({
children,
minWidth = 200,
maxWidth = 500,
defaultWidth = 224, // 56 * 4 = 224px (w-56 equivalent)
storageKey = 'task-sidebar-width'
storageKey = 'task-sidebar-width',
}: ResizableSidebarProps) {
const [sidebarWidth, setSidebarWidth] = useState(defaultWidth)
const [isResizing, setIsResizing] = useState(false)
const sidebarRef = useRef<HTMLDivElement>(null)
const widthRef = useRef(defaultWidth)
const [sidebarWidth, setSidebarWidth] = useState(defaultWidth);
const [isResizing, setIsResizing] = useState(false);
const sidebarRef = useRef<HTMLDivElement>(null);
const widthRef = useRef(defaultWidth);

// Keep widthRef in sync with sidebarWidth
useEffect(() => {
widthRef.current = sidebarWidth
}, [sidebarWidth])
widthRef.current = sidebarWidth;
}, [sidebarWidth]);

// Load saved width from localStorage
useEffect(() => {
const savedWidth = localStorage.getItem(storageKey)
const savedWidth = localStorage.getItem(storageKey);
if (savedWidth) {
const width = parseInt(savedWidth, 10)
const width = parseInt(savedWidth, 10);
if (width >= minWidth && width <= maxWidth) {
setSidebarWidth(width)
setSidebarWidth(width);
}
}
}, [storageKey, minWidth, maxWidth])
}, [storageKey, minWidth, maxWidth]);

// Save width to localStorage
const saveWidth = (width: number) => {
localStorage.setItem(storageKey, width.toString())
}
const saveWidth = React.useCallback(
(width: number) => {
localStorage.setItem(storageKey, width.toString());
},
[storageKey]
);

// Handle mouse down on resizer
const handleMouseDown = (e: React.MouseEvent) => {
e.preventDefault()
setIsResizing(true)
}
e.preventDefault();
setIsResizing(true);
};

// Handle mouse move and mouse up
useEffect(() => {
if (!isResizing) return
if (!isResizing) return;

const handleMouseMove = (e: MouseEvent) => {
if (!sidebarRef.current) return
if (!sidebarRef.current) return;

// Calculate width based on mouse position relative to sidebar's left edge
const sidebarLeft = sidebarRef.current.getBoundingClientRect().left
const newWidth = e.clientX - sidebarLeft
const sidebarLeft = sidebarRef.current.getBoundingClientRect().left;
const newWidth = e.clientX - sidebarLeft;

if (newWidth >= minWidth && newWidth <= maxWidth) {
setSidebarWidth(newWidth)
setSidebarWidth(newWidth);
}
}
};

const handleMouseUp = () => {
setIsResizing(false)
saveWidth(widthRef.current)
}
setIsResizing(false);
saveWidth(widthRef.current);
};

document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
// Prevent text selection while resizing
document.body.style.userSelect = 'none'
document.body.style.cursor = 'col-resize'
document.body.style.userSelect = 'none';
document.body.style.cursor = 'col-resize';

return () => {
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
document.body.style.userSelect = ''
document.body.style.cursor = ''
}
}, [isResizing, minWidth, maxWidth])
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
document.body.style.userSelect = '';
document.body.style.cursor = '';
};
}, [isResizing, minWidth, maxWidth, saveWidth]);

return (
<div className="hidden lg:flex relative border-r border-border" style={{ width: `${sidebarWidth}px` }}>
<div
className="hidden lg:flex relative border-r border-border"
style={{ width: `${sidebarWidth}px` }}
>
{/* Sidebar content container */}
<div
ref={sidebarRef}
className="flex flex-col w-full h-full"
>
<div ref={sidebarRef} className="flex flex-col w-full h-full">
{children}
</div>

Expand All @@ -103,7 +106,7 @@ export default function ResizableSidebar({
className="absolute top-0 right-0 bottom-0 w-1 cursor-col-resize hover:bg-primary/30 transition-colors group"
onMouseDown={handleMouseDown}
style={{
zIndex: 10
zIndex: 10,
}}
>
{/* Visual indicator on hover */}
Expand All @@ -116,10 +119,10 @@ export default function ResizableSidebar({
className="fixed inset-0 z-50"
style={{
cursor: 'col-resize',
userSelect: 'none'
userSelect: 'none',
}}
/>
)}
</div>
)
);
}
2 changes: 1 addition & 1 deletion frontend/src/features/tasks/components/TaskParamSync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default function TaskParamSync() {
};

verifyAndSetTask();
}, [searchParams, selectedTaskDetail, router, setSelectedTask]);
}, [searchParams, selectedTaskDetail, router, setSelectedTask, message]);

return null; // Only responsible for synchronization, does not render any content
}
2 changes: 1 addition & 1 deletion frontend/src/features/tasks/components/TeamSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export default function TeamSelector({
value: team.id,
};
});
}, [teams, sharedBadgeStyle]);
}, [teams, sharedBadgeStyle, t]);

const filterOption = (input: string, option?: { label: React.ReactNode; value: number }) => {
if (!option) return false;
Expand Down