diff --git a/src/renderer/locales/de/messages.po b/src/renderer/locales/de/messages.po index c37c5a94f..0aaaa5e8c 100644 --- a/src/renderer/locales/de/messages.po +++ b/src/renderer/locales/de/messages.po @@ -7514,6 +7514,11 @@ msgstr "Neuer Thread — {projectName}" msgid "New thread from this to-do" msgstr "Neuer Thread von dieser Aufgabe" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Neuer Thread in {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "Keine Threads in diesem Projekt" msgid "No threads yet" msgstr "Noch keine Threads" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Noch keine Threads." @@ -9226,6 +9232,7 @@ msgstr "Projektspezifische Überschreibungen zusätzlich zu den globalen Suchein #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/en/messages.po b/src/renderer/locales/en/messages.po index 63ecb9406..8e61d83d8 100644 --- a/src/renderer/locales/en/messages.po +++ b/src/renderer/locales/en/messages.po @@ -7514,6 +7514,11 @@ msgstr "New thread — {projectName}" msgid "New thread from this to-do" msgstr "New thread from this to-do" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "New thread in {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "No threads in this project" msgid "No threads yet" msgstr "No threads yet" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "No threads yet." @@ -9226,6 +9232,7 @@ msgstr "Project-specific overrides on top of the global search settings." #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/es/messages.po b/src/renderer/locales/es/messages.po index 574c8bad4..90275dbcb 100644 --- a/src/renderer/locales/es/messages.po +++ b/src/renderer/locales/es/messages.po @@ -7514,6 +7514,11 @@ msgstr "Nuevo hilo — {projectName}" msgid "New thread from this to-do" msgstr "Nuevo hilo a partir de esta tarea" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Nuevo hilo en {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "No hay hilos en este proyecto" msgid "No threads yet" msgstr "Aún no hay hilos" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Aún no hay hilos." @@ -9226,6 +9232,7 @@ msgstr "Anulaciones específicas del proyecto sobre los ajustes de búsqueda glo #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/fr/messages.po b/src/renderer/locales/fr/messages.po index be6c6128e..ccd43ac7f 100644 --- a/src/renderer/locales/fr/messages.po +++ b/src/renderer/locales/fr/messages.po @@ -7513,6 +7513,11 @@ msgstr "Nouveau fil de discussion — {projectName}" msgid "New thread from this to-do" msgstr "Nouveau fil de cette tâche" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Nouveau fil dans {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7988,6 +7993,7 @@ msgstr "Aucun fil dans ce projet" msgid "No threads yet" msgstr "Aucun fil pour le moment" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Aucun fil pour l'instant." @@ -9225,6 +9231,7 @@ msgstr "Remplacements spécifiques au projet en plus des paramètres de recherch #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/ja/messages.po b/src/renderer/locales/ja/messages.po index 2ef50e1e2..a839d9a4f 100644 --- a/src/renderer/locales/ja/messages.po +++ b/src/renderer/locales/ja/messages.po @@ -7512,6 +7512,11 @@ msgstr "新しいスレッド —{projectName}" msgid "New thread from this to-do" msgstr "この ToDo からの新しいスレッド" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "{0} で新規スレッド" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7987,6 +7992,7 @@ msgstr "このプロジェクトにはスレッドがありません" msgid "No threads yet" msgstr "まだスレッドはありません" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "まだスレッドがありません。" @@ -9224,6 +9230,7 @@ msgstr "グローバル検索設定に加えてプロジェクト固有のオー #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/ko/messages.po b/src/renderer/locales/ko/messages.po index bc6e1cb2a..c36c20024 100644 --- a/src/renderer/locales/ko/messages.po +++ b/src/renderer/locales/ko/messages.po @@ -7514,6 +7514,11 @@ msgstr "새 스레드 — {projectName}" msgid "New thread from this to-do" msgstr "이 할 일의 새 스레드" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "{0}에서 새 스레드" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "이 프로젝트에 스레드가 없음" msgid "No threads yet" msgstr "아직 스레드 없음" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "아직 스레드가 없습니다." @@ -9226,6 +9232,7 @@ msgstr "전역 검색 설정 위에 프로젝트별 재정의가 적용됩니다 #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/pl/messages.po b/src/renderer/locales/pl/messages.po index 13131e8c6..230b25abf 100644 --- a/src/renderer/locales/pl/messages.po +++ b/src/renderer/locales/pl/messages.po @@ -7514,6 +7514,11 @@ msgstr "Nowy wątek — {projectName}" msgid "New thread from this to-do" msgstr "Nowy wątek z tego zadania" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Nowy wątek w {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "Brak wątków w tym projekcie" msgid "No threads yet" msgstr "Nie ma jeszcze wątków" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Brak wątków." @@ -9226,6 +9232,7 @@ msgstr "Zastąpienia specyficzne dla projektu ponad globalnymi ustawieniami wysz #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/pt-BR/messages.po b/src/renderer/locales/pt-BR/messages.po index 015fdbd64..3841aff4c 100644 --- a/src/renderer/locales/pt-BR/messages.po +++ b/src/renderer/locales/pt-BR/messages.po @@ -7514,6 +7514,11 @@ msgstr "Novo tópico —{projectName}" msgid "New thread from this to-do" msgstr "Novo tópico desta tarefa" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Nova thread em {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "Nenhuma thread neste projeto" msgid "No threads yet" msgstr "Ainda não há threads" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Nenhuma thread ainda." @@ -9226,6 +9232,7 @@ msgstr "Substituições específicas do projeto nas configurações de pesquisa #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/ru/messages.po b/src/renderer/locales/ru/messages.po index 9cd14833a..e16b3255e 100644 --- a/src/renderer/locales/ru/messages.po +++ b/src/renderer/locales/ru/messages.po @@ -7514,6 +7514,11 @@ msgstr "Новый тред — {projectName}" msgid "New thread from this to-do" msgstr "Новый тред из этой задачи" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Новый поток в {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "В этом проекте нет потоков" msgid "No threads yet" msgstr "Пока нет потоков" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Тредов пока нет." @@ -9226,6 +9232,7 @@ msgstr "Переопределения для конкретного проек #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/tr/messages.po b/src/renderer/locales/tr/messages.po index 01c3ec0d1..3f70d1b5a 100644 --- a/src/renderer/locales/tr/messages.po +++ b/src/renderer/locales/tr/messages.po @@ -7514,6 +7514,11 @@ msgstr "Yeni konu — {projectName}" msgid "New thread from this to-do" msgstr "Bu yapılacaklardan yeni konu" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "{0} içinde yeni iş parçacığı" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "Bu projede iş parçacığı yok" msgid "No threads yet" msgstr "Henüz iş parçacığı yok" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Henüz konuşma yok." @@ -9226,6 +9232,7 @@ msgstr "Genel arama ayarlarının yanı sıra projeye özel geçersiz kılmalar. #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/uk/messages.po b/src/renderer/locales/uk/messages.po index a8544d68c..a70fc6f49 100644 --- a/src/renderer/locales/uk/messages.po +++ b/src/renderer/locales/uk/messages.po @@ -7514,6 +7514,11 @@ msgstr "Новий тред — {projectName}" msgid "New thread from this to-do" msgstr "Новий тред із цієї задачі" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Новий потік у {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "У цьому проєкті немає потоків" msgid "No threads yet" msgstr "Потоків ще немає" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Гілок ще немає." @@ -9226,6 +9232,7 @@ msgstr "Перевизначення для конкретного проєкт #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/vi/messages.po b/src/renderer/locales/vi/messages.po index 8bf8296db..2d145e51a 100644 --- a/src/renderer/locales/vi/messages.po +++ b/src/renderer/locales/vi/messages.po @@ -7514,6 +7514,11 @@ msgstr "Luồng mới — {projectName}" msgid "New thread from this to-do" msgstr "Luồng mới từ việc cần làm này" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "Luồng mới trong {0}" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7989,6 +7994,7 @@ msgstr "Không có luồng trong dự án này" msgid "No threads yet" msgstr "Chưa có luồng nào" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "Chưa có luồng nào." @@ -9226,6 +9232,7 @@ msgstr "Ghi đè dành riêng cho dự án ở đầu cài đặt tìm kiếm ch #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/locales/zh-CN/messages.po b/src/renderer/locales/zh-CN/messages.po index 98d5d53c4..aaacd5085 100644 --- a/src/renderer/locales/zh-CN/messages.po +++ b/src/renderer/locales/zh-CN/messages.po @@ -7513,6 +7513,11 @@ msgstr "新线程 —{projectName}" msgid "New thread from this to-do" msgstr "基于此待办事项的新线程" +#. placeholder {0}: project.name +#: src/renderer/views/HomeView.tsx +msgid "New thread in {0}" +msgstr "在 {0} 中新建线程" + #: src/mobile/ThreadTitleRow.tsx #: src/mobile/views/threadActionSurfaces.tsx #: src/mobile/views/threadContextMenus.tsx @@ -7988,6 +7993,7 @@ msgstr "此项目中没有线程" msgid "No threads yet" msgstr "还没有线程" +#: src/renderer/views/HomeView.tsx #: src/renderer/views/SettingsOverlay/parts/ProfileSettings.tsx msgid "No threads yet." msgstr "暂无对话。" @@ -9225,6 +9231,7 @@ msgstr "在全局搜索设置基础上的项目特定覆盖。" #: src/mobile/views/ManageProjectsView.tsx #: src/mobile/WideShell.tsx #: src/renderer/components/mcp/McpProjectDestinationDropdown.tsx +#: src/renderer/views/HomeView.tsx #: src/renderer/views/MainView/parts/Sidebar/parts/SidebarProjectFilter.tsx #: src/renderer/views/PullRequestsView/PullRequestsView.tsx #: src/renderer/views/SettingsOverlay/parts/WorkspacesSettings.tsx diff --git a/src/renderer/views/HomeView.test.tsx b/src/renderer/views/HomeView.test.tsx index de2e158fb..58d7cf33b 100644 --- a/src/renderer/views/HomeView.test.tsx +++ b/src/renderer/views/HomeView.test.tsx @@ -1,9 +1,10 @@ -import { screen } from "@testing-library/react"; +import { fireEvent, screen } from "@testing-library/react"; import { renderWithI18n as render } from "@/renderer/testUtils/i18n"; import { beforeEach, describe, expect, it } from "vitest"; import type { AgentStatus, Project, Thread } from "@/shared/contracts"; import { useAppStore } from "@/renderer/state/appStore"; import { useAgentStatusesStore } from "@/renderer/state/agentStatusesStore"; +import { useRemoteServersStore } from "@/renderer/state/remoteServersStore"; import { useSharedSettings } from "@/renderer/state/sharedSettingsStore"; import { HomeView } from "./HomeView"; @@ -26,6 +27,7 @@ describe("HomeView", () => { discoveryScope: undefined, discoveredAgents: [], }); + useRemoteServersStore.setState({ servers: [], runtime: {} }); }); it("does not show archived threads in recent threads", () => { @@ -67,14 +69,92 @@ describe("HomeView", () => { expect(container.querySelector(".poracode-provider-icon--external")).toBeInTheDocument(); expect(container.querySelector(".poracode-provider-icon__generic")).not.toBeInTheDocument(); }); + + it("filters recent threads to the selected workspace and clears on second click", () => { + useAppStore.setState({ + projects: [makeProject(), makeProject({ id: "project-2", name: "side-app" })], + threads: [ + makeThread({ id: "t1", title: "First project thread", projectId: "project-1" }), + makeThread({ id: "t2", title: "Second project thread", projectId: "project-2" }), + ], + }); + + render(); + + expect(screen.getByText("First project thread")).toBeInTheDocument(); + expect(screen.getByText("Second project thread")).toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: "side-app" })); + + expect(screen.queryByText("First project thread")).not.toBeInTheDocument(); + expect(screen.getByText("Second project thread")).toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: "side-app" })); + + expect(screen.getByText("First project thread")).toBeInTheDocument(); + expect(screen.getByText("Second project thread")).toBeInTheDocument(); + }); + + it("opens a draft from the workspace row's new-thread button", () => { + render(); + + fireEvent.click(screen.getByRole("button", { name: "New thread in todo-app" })); + + expect(useAppStore.getState().view).toEqual({ kind: "draft", projectId: "project-1" }); + }); + + it("marks WSL and remote workspaces and their thread tags", () => { + useRemoteServersStore.setState({ + servers: [{ desktopId: "desktop-1", label: "Poracode on MacBook 16" }], + runtime: {}, + } as never); + useAppStore.setState({ + projects: [ + makeProject({ + id: "wsl-1", + name: "Ubuntu Repo", + location: { + kind: "wsl", + distro: "Ubuntu", + linuxPath: "/home/me/repo", + uncPath: "\\\\wsl.localhost\\Ubuntu\\home\\me\\repo", + }, + }), + makeProject({ + id: "remote-1", + name: "Mac Repo", + location: { kind: "posix", path: "/repo", remoteServerId: "desktop-1" }, + }), + ], + threads: [ + makeThread({ id: "w1", title: "WSL thread", projectId: "wsl-1" }), + makeThread({ id: "r1", title: "Remote thread", projectId: "remote-1" }), + ], + }); + + render(); + + // Only the workspace select buttons carry aria-pressed. + const workspaceRows = screen.getAllByRole("button", { pressed: false }); + const wslRow = workspaceRows.find((row) => row.textContent?.includes("Ubuntu Repo")); + expect(wslRow).toHaveTextContent("WSL"); + const remoteRow = workspaceRows.find((row) => row.textContent?.includes("Mac Repo")); + expect(remoteRow).toHaveTextContent("MacBook 16"); + + const wslThread = screen.getByText("WSL thread").closest("button"); + expect(wslThread).toHaveTextContent("WSL"); + const remoteThread = screen.getByText("Remote thread").closest("button"); + expect(remoteThread).toHaveTextContent("MacBook 16"); + }); }); -function makeProject(): Project { +function makeProject(overrides?: Partial): Project { return { id: "project-1", name: "todo-app", location: { kind: "windows", path: "C:\\repo" }, createdAt: "2026-05-26T00:00:00.000Z", + ...overrides, }; } diff --git a/src/renderer/views/HomeView.tsx b/src/renderer/views/HomeView.tsx index 7dafd4283..763767f28 100644 --- a/src/renderer/views/HomeView.tsx +++ b/src/renderer/views/HomeView.tsx @@ -1,14 +1,24 @@ -import { ArrowRight, FolderOpen, House, Plus } from "lucide-react"; +import { useState } from "react"; +import { ArrowRight, Plus } from "lucide-react"; import { useShallow } from "zustand/shallow"; -import { Trans } from "@lingui/react/macro"; +import { Trans, useLingui } from "@lingui/react/macro"; +import type { Project } from "@/shared/contracts"; import { isHomeProject, isHomeProjectId } from "@/shared/homeScope"; import { useAppStore } from "@/renderer/state/appStore"; import { useSharedSettings } from "@/renderer/state/sharedSettingsStore"; import { openThread } from "@/renderer/actions/threadActions"; import { ThreadProviderIcon } from "@/renderer/components/providers/ThreadProviderIcon"; import { RelativeTime } from "@/renderer/components/common/RelativeTime"; +import { + ProjectRemoteServerChip, + ProjectSelectorIcon, + useProjectRemoteServerLookup, + type ProjectRemoteServerInfo, +} from "@/renderer/components/common/ProjectRemoteServer"; +import { TuxIcon } from "@/renderer/components/common/TuxIcon"; export function HomeView() { + const { t } = useLingui(); const homeScopeEnabled = useSharedSettings((state) => state.homeScopeEnabled); const homeProject = useAppStore((state) => state.projects.find(isHomeProject)); const projects = useAppStore( @@ -16,97 +26,149 @@ export function HomeView() { state.projects.filter((project) => !project.disabled && !isHomeProject(project)), ), ); + const [filterProjectId, setFilterProjectId] = useState(null); + const remoteServerFor = useProjectRemoteServerLookup(); + const openDraft = useAppStore((state) => state.openDraft); + + const workspaces = homeScopeEnabled && homeProject ? [homeProject, ...projects] : projects; + const activeFilter = + filterProjectId !== null && workspaces.some((project) => project.id === filterProjectId) + ? filterProjectId + : null; + const recentThreads = useAppStore( - useShallow((state) => - state.threads + useShallow((state) => { + const sorted = state.threads .filter( - (t) => !t.done && !t.archived && (homeScopeEnabled || !isHomeProjectId(t.projectId)), + (thread) => + !thread.done && + !thread.archived && + (homeScopeEnabled || !isHomeProjectId(thread.projectId)) && + (activeFilter === null || thread.projectId === activeFilter), ) - .toSorted((a, b) => b.updatedAt.localeCompare(a.updatedAt)) - .slice(0, 8), - ), + .toSorted((a, b) => b.updatedAt.localeCompare(a.updatedAt)); + return activeFilter === null ? sorted.slice(0, 8) : sorted; + }), ); - const openDraft = useAppStore((state) => state.openDraft); return ( -
-
-
-
-
- {(homeScopeEnabled && homeProject) || projects.length > 0 ? ( -
-
- {homeScopeEnabled && homeProject ? ( - - ) : null} - {projects.map((project) => ( +
+
+
+ {workspaces.length > 0 ? ( +
+

+ Projects +

+
+ {workspaces.map((project) => ( + + setFilterProjectId((current) => (current === project.id ? null : project.id)) + } + onNewThread={() => openDraft(project.id)} + newThreadLabel={t`New thread in ${project.name}`} + /> + ))} +
+
+ ) : null} + + {recentThreads.length > 0 || activeFilter !== null ? ( +
+

+ Recent threads +

+ {recentThreads.length > 0 ? ( +
+ {recentThreads.map((thread) => { + const project = isHomeProjectId(thread.projectId) + ? homeProject + : projects.find((p) => p.id === thread.projectId); + return ( - ))} -
-
- ) : null} - - {recentThreads.length > 0 ? ( -
-

- Recent threads -

-
- {recentThreads.map((thread) => { - const project = isHomeProjectId(thread.projectId) - ? homeProject - : projects.find((p) => p.id === thread.projectId); - return ( - - ); - })} -
-
- ) : null} -
-
+ ); + })} +
+ ) : ( +

+ No threads yet. +

+ )} +
+ ) : null}
); } + +function WorkspaceRow(props: { + project: Project; + remote: ProjectRemoteServerInfo; + selected: boolean; + onSelect: () => void; + onNewThread: () => void; + newThreadLabel: string; +}) { + const { project, remote, selected } = props; + return ( +
+ + +
+ ); +}