diff --git a/desktop/src/app/AppShell.tsx b/desktop/src/app/AppShell.tsx
index 48ddb8a10f..eb5ab5a95d 100644
--- a/desktop/src/app/AppShell.tsx
+++ b/desktop/src/app/AppShell.tsx
@@ -147,6 +147,7 @@ export function AppShell() {
goChannel,
goHome,
goNewMessage,
+ goProjects,
goPulse,
goSettings,
goWorkflows,
@@ -885,6 +886,7 @@ export function AppShell() {
scopeSearchFocusRequest,
]}
onSelectHome={() => void goHome()}
+ onSelectProjects={() => void goProjects()}
onSelectPulse={() => void goPulse()}
onSelectSettings={handleOpenSettings}
onSelectWorkflows={() => void goWorkflows()}
@@ -901,6 +903,9 @@ export function AppShell() {
})
}
profile={profileQuery.data}
+ projectsOverviewActive={
+ location.pathname === "/projects"
+ }
selfUserStatus={
deferredPubkey
? (selfStatusQuery.data?.[
diff --git a/desktop/src/app/routes/projects.tsx b/desktop/src/app/routes/projects.tsx
index 75871c03b4..bd6a7064a9 100644
--- a/desktop/src/app/routes/projects.tsx
+++ b/desktop/src/app/routes/projects.tsx
@@ -1,7 +1,21 @@
-import { createFileRoute, redirect } from "@tanstack/react-router";
+import * as React from "react";
+import { createFileRoute } from "@tanstack/react-router";
+
+import { ViewLoadingFallback } from "@/shared/ui/ViewLoadingFallback";
+
+const ProjectsScreen = React.lazy(async () => {
+ const module = await import("@/features/projects/ui/ProjectsScreen");
+ return { default: module.ProjectsScreen };
+});
export const Route = createFileRoute("/projects")({
- beforeLoad: () => {
- throw redirect({ to: "/" });
- },
+ component: ProjectsRouteComponent,
});
+
+function ProjectsRouteComponent() {
+ return (
+ }>
+
+
+ );
+}
diff --git a/desktop/src/features/sidebar/ui/AppSidebar.tsx b/desktop/src/features/sidebar/ui/AppSidebar.tsx
index bb68e75328..6d9a678659 100644
--- a/desktop/src/features/sidebar/ui/AppSidebar.tsx
+++ b/desktop/src/features/sidebar/ui/AppSidebar.tsx
@@ -91,6 +91,7 @@ export function AppSidebar({
isCreatingChannel,
isCreatingForum,
profile,
+ projectsOverviewActive,
relayConnectionCard,
selfPresenceStatus,
errorMessage,
@@ -116,6 +117,7 @@ export function AppSidebar({
onRemoveCommunity,
onCreateAgent,
onSelectAgents,
+ onSelectProjects,
onSelectPulse,
onSelectWorkflows,
onSelectHome,
@@ -542,8 +544,10 @@ export function AppSidebar({
homeBadgeCount={homeBadgeCount}
onSelectAgents={onSelectAgents}
onSelectHome={onSelectHome}
+ onSelectProjects={onSelectProjects}
onSelectPulse={onSelectPulse}
onSelectWorkflows={onSelectWorkflows}
+ projectsOverviewActive={projectsOverviewActive}
selectedView={selectedView}
/>
diff --git a/desktop/src/features/sidebar/ui/AppSidebar.types.ts b/desktop/src/features/sidebar/ui/AppSidebar.types.ts
index c5c93b7b84..ab35b8b598 100644
--- a/desktop/src/features/sidebar/ui/AppSidebar.types.ts
+++ b/desktop/src/features/sidebar/ui/AppSidebar.types.ts
@@ -32,6 +32,7 @@ export type AppSidebarProps = {
isCreatingChannel: boolean;
isCreatingForum: boolean;
profile?: Profile;
+ projectsOverviewActive: boolean;
relayConnectionCard: ReturnType;
selfPresenceStatus: PresenceStatus;
errorMessage?: string;
@@ -82,6 +83,7 @@ export type AppSidebarProps = {
onRemoveCommunity: (id: string) => Promise;
onCreateAgent: () => void;
onSelectAgents: () => void;
+ onSelectProjects: () => void;
onSelectPulse: () => void;
onSelectWorkflows: () => void;
onSelectHome: () => void;
diff --git a/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx b/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx
index f1a76824a0..cad45ca405 100644
--- a/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx
+++ b/desktop/src/features/sidebar/ui/AppSidebarPinnedHeader.tsx
@@ -1,4 +1,4 @@
-import { Activity, Bot, Inbox, Zap } from "lucide-react";
+import { Activity, Bot, Folders, Inbox, Zap } from "lucide-react";
import { TopbarSearch } from "@/features/search/ui/TopbarSearch";
import { FeatureGate } from "@/shared/features";
@@ -41,8 +41,10 @@ type AppSidebarPrimaryMenuProps = {
homeBadgeCount: number;
onSelectAgents: () => void;
onSelectHome: () => void;
+ onSelectProjects: () => void;
onSelectPulse: () => void;
onSelectWorkflows: () => void;
+ projectsOverviewActive: boolean;
selectedView: SidebarSelectedView;
};
@@ -89,8 +91,10 @@ export function AppSidebarPrimaryMenu({
homeBadgeCount,
onSelectAgents,
onSelectHome,
+ onSelectProjects,
onSelectPulse,
onSelectWorkflows,
+ projectsOverviewActive,
selectedView,
}: AppSidebarPrimaryMenuProps) {
return (
@@ -134,6 +138,18 @@ export function AppSidebarPrimaryMenu({
+
+
+
+ Projects
+
+
(await acceptedProjectEvents(page)).length)
.toBe(0);
- await expect(page.getByTestId("open-projects-view")).toHaveCount(0);
+ await expect(page.getByTestId("open-projects-view")).toBeVisible();
const projectsSection = page.getByTestId("sidebar-projects-section");
await expect(projectsSection).toBeVisible();