diff --git a/app/src/components/settings/hooks/__tests__/useSettingsNavigation.test.tsx b/app/src/components/settings/hooks/__tests__/useSettingsNavigation.test.tsx index 1a5c56d63..e2715e6a5 100644 --- a/app/src/components/settings/hooks/__tests__/useSettingsNavigation.test.tsx +++ b/app/src/components/settings/hooks/__tests__/useSettingsNavigation.test.tsx @@ -30,6 +30,11 @@ describe('useSettingsNavigation breadcrumbs', () => { ); }); + test('tasks returns Settings > Developer Options', () => { + renderWithProviders(, { initialEntries: ['/settings/tasks'] }); + expect(screen.getByTestId('breadcrumbs')).toHaveTextContent('Settings > Developer Options'); + }); + test('developer-options returns Settings (section page)', () => { renderWithProviders(, { initialEntries: ['/settings/developer-options'] }); expect(screen.getByTestId('breadcrumbs')).toHaveTextContent('Settings'); diff --git a/app/src/components/settings/hooks/useSettingsNavigation.ts b/app/src/components/settings/hooks/useSettingsNavigation.ts index 2011b6c44..b6b511551 100644 --- a/app/src/components/settings/hooks/useSettingsNavigation.ts +++ b/app/src/components/settings/hooks/useSettingsNavigation.ts @@ -47,6 +47,7 @@ export type SettingsRoute = | 'composio-triggers' | 'composio-routing' | 'task-sources' + | 'tasks' | 'mcp-server' | 'dev-workflow' | 'sandbox-settings' @@ -135,6 +136,10 @@ export const useSettingsNavigation = (): SettingsNavigationHook => { if (path.includes('/settings/composio-triggers')) return 'composio-triggers'; if (path.includes('/settings/composio-routing')) return 'composio-routing'; if (path.includes('/settings/task-sources')) return 'task-sources'; + // `tasks` is checked after `task-sources` so the longer, hyphenated route + // isn't shadowed (the two prefixes don't actually overlap, but ordering + // here keeps the intent obvious). + if (path.includes('/settings/tasks')) return 'tasks'; if (path.includes('/settings/intelligence')) return 'intelligence'; if (path.includes('/settings/crypto')) return 'crypto'; if (path.includes('/settings/recovery-phrase')) return 'recovery-phrase'; @@ -326,6 +331,7 @@ export const useSettingsNavigation = (): SettingsNavigationHook => { case 'webhooks-triggers': case 'composio-triggers': case 'composio-routing': + case 'tasks': case 'notification-routing': case 'mcp-server': case 'dev-workflow': diff --git a/app/src/components/settings/panels/DeveloperOptionsPanel.tsx b/app/src/components/settings/panels/DeveloperOptionsPanel.tsx index 0de78361c..55a333088 100644 --- a/app/src/components/settings/panels/DeveloperOptionsPanel.tsx +++ b/app/src/components/settings/panels/DeveloperOptionsPanel.tsx @@ -381,6 +381,22 @@ const modelsInferenceGroup: DevGroup = { const automationIntegrationsGroup: DevGroup = { labelKey: 'settings.devGroups.automationIntegrations', items: [ + { + id: 'tasks', + titleKey: 'settings.developerMenu.tasks.title', + descriptionKey: 'settings.developerMenu.tasks.desc', + route: 'tasks', + icon: ( + + + + ), + }, { id: 'cron-jobs', titleKey: 'settings.developerMenu.cronJobs.title', diff --git a/app/src/components/settings/panels/TasksPanel.tsx b/app/src/components/settings/panels/TasksPanel.tsx new file mode 100644 index 000000000..30e1c69c4 --- /dev/null +++ b/app/src/components/settings/panels/TasksPanel.tsx @@ -0,0 +1,38 @@ +import { useT } from '../../../lib/i18n/I18nContext'; +import IntelligenceTasksTab from '../../intelligence/IntelligenceTasksTab'; +import SettingsHeader from '../components/SettingsHeader'; +import { useSettingsNavigation } from '../hooks/useSettingsNavigation'; + +/** + * Settings → Developer Options → Tasks. + * + * Hosts the {@link IntelligenceTasksTab} task-board surface that previously + * lived as a tab on the Activity page. The board (personal to-dos, task-source + * boards, and the per-agent boards built across conversations) is unchanged — + * this panel only re-homes it under the developer menu with the standard + * SettingsHeader + breadcrumb chrome. + */ +const TasksPanel = () => { + const { t } = useT(); + const { navigateBack, breadcrumbs } = useSettingsNavigation(); + + return ( +
+ + +
+

+ {t('memory.tab.tasksDescription')} +

+ +
+
+ ); +}; + +export default TasksPanel; diff --git a/app/src/components/settings/panels/__tests__/TasksPanel.test.tsx b/app/src/components/settings/panels/__tests__/TasksPanel.test.tsx new file mode 100644 index 000000000..401420650 --- /dev/null +++ b/app/src/components/settings/panels/__tests__/TasksPanel.test.tsx @@ -0,0 +1,42 @@ +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; +import { describe, expect, it, vi } from 'vitest'; + +// i18n stub — return the key verbatim so we can assert on label keys. +vi.mock('../../../../lib/i18n/I18nContext', () => ({ useT: () => ({ t: (key: string) => key }) })); + +// The task-board surface is heavy (Redux + RPC); stub it to a sentinel so the +// panel test stays focused on the re-homing chrome. +vi.mock('../../../intelligence/IntelligenceTasksTab', () => ({ + default: () =>
, +})); + +const navigateBack = vi.fn(); +vi.mock('../../hooks/useSettingsNavigation', () => ({ + useSettingsNavigation: () => ({ + navigateBack, + breadcrumbs: [{ label: 'Settings' }, { label: 'Developer Options' }], + }), +})); + +const TasksPanel = (await import('../TasksPanel')).default; + +function renderPanel() { + return render( + + + + ); +} + +describe('TasksPanel', () => { + it('renders the panel shell, title, description and the task board', () => { + renderPanel(); + expect(screen.getByTestId('tasks-panel')).toBeInTheDocument(); + // SettingsHeader title + the descriptive blurb both come from i18n keys. + expect(screen.getAllByText('memory.tab.tasks').length).toBeGreaterThan(0); + expect(screen.getByText('memory.tab.tasksDescription')).toBeInTheDocument(); + // The re-homed task board is mounted unchanged. + expect(screen.getByTestId('intelligence-tasks-tab')).toBeInTheDocument(); + }); +}); diff --git a/app/src/lib/i18n/ar.ts b/app/src/lib/i18n/ar.ts index 0984fcd30..875d69882 100644 --- a/app/src/lib/i18n/ar.ts +++ b/app/src/lib/i18n/ar.ts @@ -3838,6 +3838,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'كل ساعتين', 'settings.devWorkflow.schedule.every6hours': 'كل 6 ساعات', 'settings.devWorkflow.schedule.onceDaily': 'يوم واحد (9 صباحا)', + 'settings.developerMenu.tasks.title': 'المهام', + 'settings.developerMenu.tasks.desc': + 'تصفّح لوحات المهام وإدارتها — مهامك الخاصة إضافةً إلى اللوحات التي تنشئها الوكلاء عبر المحادثات.', 'settings.developerMenu.cronJobs.title': 'مهام Cron', 'settings.developerMenu.cronJobs.desc': 'عرض وتكوين المهام المجدولة لمهارات وقت التشغيل', 'settings.developerMenu.localModelDebug.title': 'تصحيح النموذج المحلي', diff --git a/app/src/lib/i18n/bn.ts b/app/src/lib/i18n/bn.ts index 33be093a8..bd63551e6 100644 --- a/app/src/lib/i18n/bn.ts +++ b/app/src/lib/i18n/bn.ts @@ -3914,6 +3914,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'প্রতি ২ ঘন্টা', 'settings.devWorkflow.schedule.every6hours': 'প্রতি ৬ ঘন্টা', 'settings.devWorkflow.schedule.onceDaily': 'প্রতিদিন (৯.', + 'settings.developerMenu.tasks.title': 'কাজ', + 'settings.developerMenu.tasks.desc': + 'টাস্ক বোর্ড ব্রাউজ ও পরিচালনা করুন — আপনার নিজের কাজ এবং কথোপকথন জুড়ে এজেন্টদের তৈরি করা বোর্ড।', 'settings.developerMenu.cronJobs.title': 'Cron জব', 'settings.developerMenu.cronJobs.desc': 'রানটাইম স্কিলের জন্য নির্ধারিত জব দেখুন এবং কনফিগার করুন', diff --git a/app/src/lib/i18n/de.ts b/app/src/lib/i18n/de.ts index f185f38b5..635683f56 100644 --- a/app/src/lib/i18n/de.ts +++ b/app/src/lib/i18n/de.ts @@ -4014,6 +4014,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Alle 2 Stunden', 'settings.devWorkflow.schedule.every6hours': 'Alle 6 Stunden', 'settings.devWorkflow.schedule.onceDaily': 'Einmal täglich (09:00 Uhr)', + 'settings.developerMenu.tasks.title': 'Aufgaben', + 'settings.developerMenu.tasks.desc': + 'Aufgaben-Boards durchsuchen und verwalten — deine eigenen To-dos sowie die Boards, die Agenten über Unterhaltungen hinweg erstellen.', 'settings.developerMenu.cronJobs.title': 'Cron-Jobs', 'settings.developerMenu.cronJobs.desc': 'Zeige geplante Jobs für Laufzeitfähigkeiten an und konfiguriere sie', diff --git a/app/src/lib/i18n/en.ts b/app/src/lib/i18n/en.ts index bd9020fe7..b0ed65106 100644 --- a/app/src/lib/i18n/en.ts +++ b/app/src/lib/i18n/en.ts @@ -4457,6 +4457,9 @@ const en: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Every 2 hours', 'settings.devWorkflow.schedule.every6hours': 'Every 6 hours', 'settings.devWorkflow.schedule.onceDaily': 'Once daily (9 AM)', + 'settings.developerMenu.tasks.title': 'Tasks', + 'settings.developerMenu.tasks.desc': + 'Browse and manage task boards — your own to-dos plus the boards agents build across conversations.', 'settings.developerMenu.cronJobs.title': 'Cron Jobs', 'settings.developerMenu.cronJobs.desc': 'View and configure scheduled jobs for runtime skills', 'settings.developerMenu.localModelDebug.title': 'Local Model Debug', diff --git a/app/src/lib/i18n/es.ts b/app/src/lib/i18n/es.ts index 3f7b176a1..03183cc83 100644 --- a/app/src/lib/i18n/es.ts +++ b/app/src/lib/i18n/es.ts @@ -3988,6 +3988,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Cada 2 horas', 'settings.devWorkflow.schedule.every6hours': 'Cada 6 horas', 'settings.devWorkflow.schedule.onceDaily': 'Una vez al día (9 AM)', + 'settings.developerMenu.tasks.title': 'Tareas', + 'settings.developerMenu.tasks.desc': + 'Explora y gestiona los tableros de tareas: tus pendientes y los tableros que los agentes crean en las conversaciones.', 'settings.developerMenu.cronJobs.title': 'Tareas cron', 'settings.developerMenu.cronJobs.desc': 'Ver y configurar tareas programadas para habilidades en tiempo de ejecución', diff --git a/app/src/lib/i18n/fr.ts b/app/src/lib/i18n/fr.ts index 1eba2a393..0bc68b560 100644 --- a/app/src/lib/i18n/fr.ts +++ b/app/src/lib/i18n/fr.ts @@ -4004,6 +4004,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Toutes les 2 heures', 'settings.devWorkflow.schedule.every6hours': 'Toutes les 6 heures', 'settings.devWorkflow.schedule.onceDaily': 'Une fois par jour (9 h)', + 'settings.developerMenu.tasks.title': 'Tâches', + 'settings.developerMenu.tasks.desc': + 'Parcourez et gérez les tableaux de tâches — vos propres to-dos ainsi que les tableaux créés par les agents au fil des conversations.', 'settings.developerMenu.cronJobs.title': 'Tâches cron', 'settings.developerMenu.cronJobs.desc': "Afficher et configurer les tâches planifiées des compétences d'exécution", diff --git a/app/src/lib/i18n/hi.ts b/app/src/lib/i18n/hi.ts index f2680e583..0d8ccaed1 100644 --- a/app/src/lib/i18n/hi.ts +++ b/app/src/lib/i18n/hi.ts @@ -3921,6 +3921,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'हर 2 घंटे', 'settings.devWorkflow.schedule.every6hours': '6 घंटे', 'settings.devWorkflow.schedule.onceDaily': 'एक बार दैनिक (9 AM)', + 'settings.developerMenu.tasks.title': 'कार्य', + 'settings.developerMenu.tasks.desc': + 'टास्क बोर्ड ब्राउज़ करें और प्रबंधित करें — आपके अपने काम और बातचीत के दौरान एजेंट द्वारा बनाए गए बोर्ड।', 'settings.developerMenu.cronJobs.title': 'Cron जॉब्स', 'settings.developerMenu.cronJobs.desc': 'रनटाइम स्किल्स के लिए शेड्यूल किए गए जॉब देखें और कॉन्फ़िगर करें', diff --git a/app/src/lib/i18n/id.ts b/app/src/lib/i18n/id.ts index 933098a95..06e6faafb 100644 --- a/app/src/lib/i18n/id.ts +++ b/app/src/lib/i18n/id.ts @@ -3932,6 +3932,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Setiap 2 jam', 'settings.devWorkflow.schedule.every6hours': 'Setiap 6 jam', 'settings.devWorkflow.schedule.onceDaily': 'Setiap hari (jam 9 pagi)', + 'settings.developerMenu.tasks.title': 'Tugas', + 'settings.developerMenu.tasks.desc': + 'Jelajahi dan kelola papan tugas — daftar tugas Anda sendiri serta papan yang dibuat agen di seluruh percakapan.', 'settings.developerMenu.cronJobs.title': 'Pekerjaan Cron', 'settings.developerMenu.cronJobs.desc': 'Lihat dan atur pekerjaan terjadwal untuk skill runtime', 'settings.developerMenu.localModelDebug.title': 'Debug Model Lokal', diff --git a/app/src/lib/i18n/it.ts b/app/src/lib/i18n/it.ts index 505e30495..c9f710ac9 100644 --- a/app/src/lib/i18n/it.ts +++ b/app/src/lib/i18n/it.ts @@ -3982,6 +3982,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Ogni 2 ore', 'settings.devWorkflow.schedule.every6hours': 'Ogni 6 ore', 'settings.devWorkflow.schedule.onceDaily': 'Una volta al giorno (ore 9)', + 'settings.developerMenu.tasks.title': 'Attività', + 'settings.developerMenu.tasks.desc': + 'Esplora e gestisci le bacheche delle attività — i tuoi to-do e le bacheche create dagli agenti nelle conversazioni.', 'settings.developerMenu.cronJobs.title': 'Processi cron', 'settings.developerMenu.cronJobs.desc': 'Visualizza e configura processi pianificati per le skill di runtime', diff --git a/app/src/lib/i18n/ko.ts b/app/src/lib/i18n/ko.ts index 0dcec2d23..13e43fd06 100644 --- a/app/src/lib/i18n/ko.ts +++ b/app/src/lib/i18n/ko.ts @@ -3881,6 +3881,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': '2시간마다', 'settings.devWorkflow.schedule.every6hours': '6시간마다', 'settings.devWorkflow.schedule.onceDaily': '하루 한 번(오전 9시)', + 'settings.developerMenu.tasks.title': '작업', + 'settings.developerMenu.tasks.desc': + '작업 보드를 둘러보고 관리하세요 — 내 할 일과 대화 전반에서 에이전트가 만든 보드를 함께 확인합니다.', 'settings.developerMenu.cronJobs.title': '크론 작업', 'settings.developerMenu.cronJobs.desc': '예약 보기 및 구성 런타임 기술용 작업', 'settings.developerMenu.localModelDebug.title': '로컬 모델 디버그', diff --git a/app/src/lib/i18n/pl.ts b/app/src/lib/i18n/pl.ts index be180eb20..fbdb95734 100644 --- a/app/src/lib/i18n/pl.ts +++ b/app/src/lib/i18n/pl.ts @@ -3980,6 +3980,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Co 2 godziny', 'settings.devWorkflow.schedule.every6hours': 'Co 6 godzin', 'settings.devWorkflow.schedule.onceDaily': 'Raz dziennie (9:00)', + 'settings.developerMenu.tasks.title': 'Zadania', + 'settings.developerMenu.tasks.desc': + 'Przeglądaj tablice zadań i zarządzaj nimi — Twoje własne zadania oraz tablice tworzone przez agentów w rozmowach.', 'settings.developerMenu.cronJobs.title': 'Zadania cron', 'settings.developerMenu.cronJobs.desc': 'Przeglądaj i konfiguruj zaplanowane zadania dla umiejętności runtime', diff --git a/app/src/lib/i18n/pt.ts b/app/src/lib/i18n/pt.ts index 8bf34e9a3..53216707c 100644 --- a/app/src/lib/i18n/pt.ts +++ b/app/src/lib/i18n/pt.ts @@ -3982,6 +3982,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'A cada 2 horas', 'settings.devWorkflow.schedule.every6hours': 'A cada 6 horas', 'settings.devWorkflow.schedule.onceDaily': 'Uma vez ao dia (9h)', + 'settings.developerMenu.tasks.title': 'Tarefas', + 'settings.developerMenu.tasks.desc': + 'Navegue e gerencie os quadros de tarefas — suas próprias pendências e os quadros que os agentes criam nas conversas.', 'settings.developerMenu.cronJobs.title': 'Tarefas cron', 'settings.developerMenu.cronJobs.desc': 'Veja e configure tarefas agendadas para habilidades em tempo de execução', diff --git a/app/src/lib/i18n/ru.ts b/app/src/lib/i18n/ru.ts index ed3f9894e..d9bcc3214 100644 --- a/app/src/lib/i18n/ru.ts +++ b/app/src/lib/i18n/ru.ts @@ -3952,6 +3952,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': 'Каждые 2 часа', 'settings.devWorkflow.schedule.every6hours': 'Каждые 6 часов', 'settings.devWorkflow.schedule.onceDaily': 'Один раз в день (9 утра)', + 'settings.developerMenu.tasks.title': 'Задачи', + 'settings.developerMenu.tasks.desc': + 'Просматривайте доски задач и управляйте ими — ваши собственные дела и доски, которые агенты создают в разговорах.', 'settings.developerMenu.cronJobs.title': 'Задачи cron', 'settings.developerMenu.cronJobs.desc': 'Просмотр и настройка запланированных задач для runtime-навыков', diff --git a/app/src/lib/i18n/zh-CN.ts b/app/src/lib/i18n/zh-CN.ts index e63a0d543..71d3b08c3 100644 --- a/app/src/lib/i18n/zh-CN.ts +++ b/app/src/lib/i18n/zh-CN.ts @@ -3731,6 +3731,9 @@ const messages: TranslationMap = { 'settings.devWorkflow.schedule.every2hours': '每 2 小时', 'settings.devWorkflow.schedule.every6hours': '每 6 小时', 'settings.devWorkflow.schedule.onceDaily': '每天一次(上午 9 点)', + 'settings.developerMenu.tasks.title': '任务', + 'settings.developerMenu.tasks.desc': + '浏览和管理任务看板——你的待办事项以及智能体在对话中创建的看板。', 'settings.developerMenu.cronJobs.title': '定时任务', 'settings.developerMenu.cronJobs.desc': '查看并配置运行时技能的计划任务', 'settings.developerMenu.localModelDebug.title': '本地模型调试', diff --git a/app/src/pages/Activity.tsx b/app/src/pages/Activity.tsx index aaa5e7b08..459f8cf05 100644 --- a/app/src/pages/Activity.tsx +++ b/app/src/pages/Activity.tsx @@ -3,7 +3,6 @@ import { useSearchParams } from 'react-router-dom'; import { ConfirmationModal } from '../components/intelligence/ConfirmationModal'; import IntelligenceSubconsciousTab from '../components/intelligence/IntelligenceSubconsciousTab'; -import IntelligenceTasksTab from '../components/intelligence/IntelligenceTasksTab'; import { ToastContainer } from '../components/intelligence/Toast'; import WorkflowsTab from '../components/intelligence/WorkflowsTab'; import PillTabBar from '../components/PillTabBar'; @@ -20,18 +19,18 @@ import type { import Notifications from './Notifications'; // Visible tab IDs for the Activity surface. -// memory, agents, and council have moved to Settings → Developer & Diagnostics -// (routes: /settings/intelligence, /settings/agents). -// Back-compat: ?tab=memory / ?tab=agents / ?tab=council are unknown to the -// visible set and therefore fall back to 'tasks' (see makeIsVisibleTab below). -type ActivityTab = 'tasks' | 'automations' | 'backgroundActivity' | 'alerts'; +// memory, agents, council and tasks have moved to Settings → Developer & Diagnostics +// (routes: /settings/intelligence, /settings/agents, /settings/tasks). +// Back-compat: ?tab=memory / ?tab=agents / ?tab=council / ?tab=tasks are unknown +// to the visible set and therefore fall back to 'automations' (see isVisibleTab). +type ActivityTab = 'automations' | 'backgroundActivity' | 'alerts'; -const ACTIVITY_TABS: ActivityTab[] = ['tasks', 'automations', 'backgroundActivity', 'alerts']; +const ACTIVITY_TABS: ActivityTab[] = ['automations', 'backgroundActivity', 'alerts']; /** * Returns a type-guard predicate for the currently visible tabs. - * Unknown values (including old deep-link tabs like ?tab=memory) fall back to - * the default tab rather than erroring. + * Unknown values (including old deep-link tabs like ?tab=memory or ?tab=tasks) + * fall back to the default tab rather than erroring. */ const isVisibleTab = (tab: string | null | undefined): tab is ActivityTab => (ACTIVITY_TABS as string[]).includes(tab ?? ''); @@ -43,7 +42,7 @@ export default function Activity() { // restores the same tab. `replace` so switching tabs doesn't stack history. const [searchParams, setSearchParams] = useSearchParams(); const tabParam = searchParams.get('tab'); - const activeTab: ActivityTab = isVisibleTab(tabParam) ? tabParam : 'tasks'; + const activeTab: ActivityTab = isVisibleTab(tabParam) ? tabParam : 'automations'; const setActiveTab = useCallback( (tab: ActivityTab) => { setSearchParams( @@ -95,7 +94,6 @@ export default function Activity() { }, [socketConnected, socketManager]); const tabs: { id: ActivityTab; label: string; description?: string; comingSoon?: boolean }[] = [ - { id: 'tasks', label: t('memory.tab.tasks'), description: t('memory.tab.tasksDescription') }, { id: 'automations', label: t('activity.tabs.automations'), @@ -159,8 +157,6 @@ export default function Activity() {
{/* Tab content */} - {activeTab === 'tasks' && } - {activeTab === 'automations' && } {activeTab === 'backgroundActivity' && ( diff --git a/app/src/pages/Settings.tsx b/app/src/pages/Settings.tsx index 8ed6fc491..016356c8b 100644 --- a/app/src/pages/Settings.tsx +++ b/app/src/pages/Settings.tsx @@ -47,6 +47,7 @@ import ScreenIntelligencePanel from '../components/settings/panels/ScreenIntelli import SearchPanel from '../components/settings/panels/SearchPanel'; import SecurityPanel from '../components/settings/panels/SecurityPanel'; import TaskSourcesPanel from '../components/settings/panels/TaskSourcesPanel'; +import TasksPanel from '../components/settings/panels/TasksPanel'; import TeamInvitesPanel from '../components/settings/panels/TeamInvitesPanel'; import TeamManagementPanel from '../components/settings/panels/TeamManagementPanel'; import TeamMembersPanel from '../components/settings/panels/TeamMembersPanel'; @@ -634,6 +635,7 @@ const Settings = () => { )} /> )} /> )} /> + )} /> )} /> )} /> ({ useT: () => ({ t: (key: string) = vi.mock('../../components/intelligence/IntelligenceSubconsciousTab', () => ({ default: () =>
, })); -vi.mock('../../components/intelligence/IntelligenceTasksTab', () => ({ - default: () =>
, -})); vi.mock('../../components/intelligence/WorkflowsTab', () => ({ default: () =>
, })); @@ -63,14 +60,9 @@ describe('Activity URL-backed tab', () => { vi.clearAllMocks(); }); - it('defaults to the tasks tab when no ?tab is present', async () => { + it('defaults to the automations tab when no ?tab is present', async () => { renderAt('/activity'); - await waitFor(() => expect(screen.getByTestId('tab-tasks')).toBeInTheDocument()); - }); - - it('honours ?tab=tasks from the URL', async () => { - renderAt('/activity?tab=tasks'); - await waitFor(() => expect(screen.getByTestId('tab-tasks')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByTestId('tab-automations')).toBeInTheDocument()); }); it('honours ?tab=automations from the URL', async () => { @@ -88,28 +80,34 @@ describe('Activity URL-backed tab', () => { await waitFor(() => expect(screen.getByTestId('tab-alerts')).toBeInTheDocument()); }); - it('falls back to tasks for an unknown ?tab value', async () => { + it('falls back to automations for an unknown ?tab value', async () => { renderAt('/activity?tab=bogus'); - await waitFor(() => expect(screen.getByTestId('tab-tasks')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByTestId('tab-automations')).toBeInTheDocument()); }); - // Back-compat: old deep links (?tab=memory|agents|council) are no longer - // visible Activity tabs — they should fall back to tasks rather than error. - it('falls back to tasks for ?tab=memory (relocated to Settings)', async () => { + // Back-compat: old deep links (?tab=tasks|memory|agents|council) are no longer + // visible Activity tabs — they should fall back to automations rather than error. + it('falls back to automations for ?tab=tasks (relocated to Settings → Developer Options)', async () => { + renderAt('/activity?tab=tasks'); + await waitFor(() => expect(screen.getByTestId('tab-automations')).toBeInTheDocument()); + expect(screen.queryByTestId('tab-tasks')).not.toBeInTheDocument(); + }); + + it('falls back to automations for ?tab=memory (relocated to Settings)', async () => { renderAt('/activity?tab=memory'); - await waitFor(() => expect(screen.getByTestId('tab-tasks')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByTestId('tab-automations')).toBeInTheDocument()); expect(screen.queryByTestId('tab-memory')).not.toBeInTheDocument(); }); - it('falls back to tasks for ?tab=agents (relocated to Settings)', async () => { + it('falls back to automations for ?tab=agents (relocated to Settings)', async () => { renderAt('/activity?tab=agents'); - await waitFor(() => expect(screen.getByTestId('tab-tasks')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByTestId('tab-automations')).toBeInTheDocument()); expect(screen.queryByTestId('tab-agents')).not.toBeInTheDocument(); }); - it('falls back to tasks for ?tab=council (relocated to Settings)', async () => { + it('falls back to automations for ?tab=council (relocated to Settings)', async () => { renderAt('/activity?tab=council'); - await waitFor(() => expect(screen.getByTestId('tab-tasks')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByTestId('tab-automations')).toBeInTheDocument()); expect(screen.queryByTestId('tab-council')).not.toBeInTheDocument(); }); @@ -126,31 +124,24 @@ describe('Activity tab — tab set', () => { vi.clearAllMocks(); }); - it('renders exactly four tab pills: tasks, automations, backgroundActivity, alerts', async () => { + it('renders exactly three tab pills: automations, backgroundActivity, alerts', async () => { renderAt('/activity'); - await waitFor(() => screen.getByTestId('tab-tasks')); + await waitFor(() => screen.getByTestId('tab-automations')); // Each label key is returned as-is by the stub t() function. - expect(screen.getAllByText('memory.tab.tasks').length).toBeGreaterThan(0); expect(screen.getAllByText('activity.tabs.automations').length).toBeGreaterThan(0); expect(screen.getAllByText('activity.tabs.backgroundActivity').length).toBeGreaterThan(0); expect(screen.getAllByText('activity.tabs.alerts').length).toBeGreaterThan(0); }); - it('does not render memory, agents, or council pills', async () => { + it('does not render tasks, memory, agents, or council pills', async () => { renderAt('/activity'); - await waitFor(() => screen.getByTestId('tab-tasks')); + await waitFor(() => screen.getByTestId('tab-automations')); + expect(screen.queryByText('memory.tab.tasks')).not.toBeInTheDocument(); expect(screen.queryByText('memory.tab.memory')).not.toBeInTheDocument(); expect(screen.queryByText('memory.tab.agents')).not.toBeInTheDocument(); expect(screen.queryByText('memory.tab.council')).not.toBeInTheDocument(); }); - it('clicking the automations pill switches to the automations tab', async () => { - renderAt('/activity'); - await waitFor(() => screen.getAllByText('activity.tabs.automations')); - fireEvent.click(screen.getAllByText('activity.tabs.automations')[0]); - await waitFor(() => expect(screen.getByTestId('tab-automations')).toBeInTheDocument()); - }); - it('clicking the backgroundActivity pill switches to the backgroundActivity tab', async () => { renderAt('/activity'); await waitFor(() => screen.getAllByText('activity.tabs.backgroundActivity')); @@ -169,6 +160,6 @@ describe('Activity tab — tab set', () => { renderAt('/activity?tab=alerts'); await waitFor(() => expect(screen.getByTestId('tab-alerts')).toBeInTheDocument()); // The card wrapper is NOT rendered in the alerts tab. - expect(screen.queryByTestId('tab-tasks')).not.toBeInTheDocument(); + expect(screen.queryByTestId('tab-automations')).not.toBeInTheDocument(); }); });