Files
Claude-Code-Workflow/ccw/frontend/src/App.tsx
catlog22 46989dcbad fix(frontend): add missing i18n keys and improve workspace switch cache invalidation
- Add common.status.ready i18n key for zh/en locales
- Add ready/initialized/archived/failed status colors to dashboard widgets
- Expand QueryInvalidator to invalidate projectOverview, workflowStatusCounts,
  and dashboardStats queries on workspace switch
2026-02-28 10:00:36 +08:00

94 lines
2.9 KiB
TypeScript

// ========================================
// App Component
// ========================================
// Root application component with Router provider
import { QueryClientProvider } from '@tanstack/react-query';
import { RouterProvider } from 'react-router-dom';
import { IntlProvider } from 'react-intl';
import { useEffect } from 'react';
import { Toaster } from 'sonner';
import { router } from './router';
import queryClient from './lib/query-client';
import type { Locale } from './lib/i18n';
import { useWorkflowStore } from '@/stores/workflowStore';
import { useActiveCliExecutions } from '@/hooks/useActiveCliExecutions';
import { DialogStyleProvider } from '@/contexts/DialogStyleContext';
import { initializeCsrfToken } from './lib/api';
interface AppProps {
locale: Locale;
messages: Record<string, string>;
}
/**
* Root App component
* Provides routing and global providers
*/
function App({ locale, messages }: AppProps) {
// Initialize CSRF token on app mount
useEffect(() => {
initializeCsrfToken().catch(console.error);
}, []);
return (
<IntlProvider locale={locale} messages={messages}>
<QueryClientProvider client={queryClient}>
<DialogStyleProvider>
<QueryInvalidator />
<CliExecutionSync />
<RouterProvider router={router} />
<Toaster richColors position="top-right" />
</DialogStyleProvider>
</QueryClientProvider>
</IntlProvider>
);
}
/**
* Query invalidator component
* Registers callback with workflowStore to invalidate workspace queries on workspace switch
*/
function QueryInvalidator() {
const registerQueryInvalidator = useWorkflowStore((state) => state.registerQueryInvalidator);
useEffect(() => {
// Register callback to invalidate all workspace-related queries on workspace switch
const callback = () => {
queryClient.invalidateQueries({
predicate: (query) => {
const queryKey = query.queryKey;
if (!Array.isArray(queryKey)) return false;
const prefix = queryKey[0];
// Invalidate all query families that depend on workspace data
return prefix === 'workspace'
|| prefix === 'projectOverview'
|| prefix === 'workflowStatusCounts'
|| prefix === 'dashboardStats';
},
});
};
registerQueryInvalidator(callback);
}, [registerQueryInvalidator]);
return null;
}
/**
* CLI Execution Sync component
* Syncs active CLI executions in the background to keep the count updated in Header
*/
function CliExecutionSync() {
// Always sync active CLI executions with a longer polling interval
// This ensures the activeCliCount badge in Header shows correct count on initial load
useActiveCliExecutions(
true, // enabled: always sync
15000 // refetchInterval: 15 seconds (longer than monitor's 5 seconds to reduce load)
);
return null;
}
export default App;