mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 10:33:25 +08:00
Add end-to-end tests for workspace switching and backend tests for ask_question tool
- Implemented E2E tests for workspace switching functionality, covering scenarios such as switching workspaces, data isolation, language preference maintenance, and UI updates. - Added tests to ensure workspace data is cleared on logout and handles unsaved changes during workspace switches. - Created comprehensive backend tests for the ask_question tool, validating question creation, execution, answer handling, cancellation, and timeout scenarios. - Included edge case tests to ensure robustness against duplicate questions and invalid answers.
This commit is contained in:
@@ -10,7 +10,8 @@ import { Sidebar } from './Sidebar';
|
||||
import { MainContent } from './MainContent';
|
||||
import { CliStreamMonitor } from '@/components/shared/CliStreamMonitor';
|
||||
import { NotificationPanel } from '@/components/notification';
|
||||
import { useNotificationStore } from '@/stores';
|
||||
import { AskQuestionDialog } from '@/components/a2ui/AskQuestionDialog';
|
||||
import { useNotificationStore, selectCurrentQuestion } from '@/stores';
|
||||
import { useWebSocketNotifications } from '@/hooks';
|
||||
|
||||
export interface AppShellProps {
|
||||
@@ -57,6 +58,10 @@ export function AppShell({
|
||||
(state) => state.loadPersistentNotifications
|
||||
);
|
||||
|
||||
// Current question dialog state
|
||||
const currentQuestion = useNotificationStore(selectCurrentQuestion);
|
||||
const setCurrentQuestion = useNotificationStore((state) => state.setCurrentQuestion);
|
||||
|
||||
// Initialize WebSocket notifications handler
|
||||
useWebSocketNotifications();
|
||||
|
||||
@@ -106,6 +111,10 @@ export function AppShell({
|
||||
useNotificationStore.getState().setPanelVisible(false);
|
||||
}, []);
|
||||
|
||||
const handleQuestionDialogClose = useCallback(() => {
|
||||
setCurrentQuestion(null);
|
||||
}, [setCurrentQuestion]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen bg-background">
|
||||
{/* Header - fixed at top */}
|
||||
@@ -150,6 +159,14 @@ export function AppShell({
|
||||
isOpen={isNotificationPanelVisible}
|
||||
onClose={handleNotificationPanelClose}
|
||||
/>
|
||||
|
||||
{/* Ask Question Dialog - For ask_question MCP tool */}
|
||||
{currentQuestion && (
|
||||
<AskQuestionDialog
|
||||
payload={currentQuestion}
|
||||
onClose={handleQuestionDialogClose}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
User,
|
||||
LogOut,
|
||||
Terminal,
|
||||
Bell,
|
||||
} from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
@@ -24,6 +25,7 @@ import { useTheme } from '@/hooks';
|
||||
import { LanguageSwitcher } from './LanguageSwitcher';
|
||||
import { WorkspaceSelector } from '@/components/workspace/WorkspaceSelector';
|
||||
import { useCliStreamStore, selectActiveExecutionCount } from '@/stores/cliStreamStore';
|
||||
import { useNotificationStore } from '@/stores';
|
||||
|
||||
export interface HeaderProps {
|
||||
/** Callback to toggle mobile sidebar */
|
||||
@@ -49,6 +51,13 @@ export function Header({
|
||||
const { isDark, toggleTheme } = useTheme();
|
||||
const activeCliCount = useCliStreamStore(selectActiveExecutionCount);
|
||||
|
||||
// Notification state for badge
|
||||
const persistentNotifications = useNotificationStore((state) => state.persistentNotifications);
|
||||
const togglePanel = useNotificationStore((state) => state.togglePanel);
|
||||
|
||||
// Calculate unread count
|
||||
const unreadCount = persistentNotifications.filter((n) => !n.read).length;
|
||||
|
||||
const handleRefresh = useCallback(() => {
|
||||
if (onRefresh && !isRefreshing) {
|
||||
onRefresh();
|
||||
@@ -105,6 +114,23 @@ export function Header({
|
||||
{/* Workspace selector */}
|
||||
{projectPath && <WorkspaceSelector />}
|
||||
|
||||
{/* Notification badge */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={togglePanel}
|
||||
aria-label={formatMessage({ id: 'common.aria.notifications' }) || 'Notifications'}
|
||||
title={formatMessage({ id: 'common.aria.notifications' }) || 'Notifications'}
|
||||
className="relative"
|
||||
>
|
||||
<Bell className="w-5 h-5" />
|
||||
{unreadCount > 0 && (
|
||||
<span className="absolute -top-1 -right-1 h-4 w-4 rounded-full bg-destructive text-[10px] text-destructive-foreground flex items-center justify-center font-medium">
|
||||
{unreadCount > 9 ? '9+' : unreadCount}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
{/* Refresh button */}
|
||||
{onRefresh && (
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user