diff --git a/backend/app/api/boards.py b/backend/app/api/boards.py index 2f1c8bb8..d0393313 100644 --- a/backend/app/api/boards.py +++ b/backend/app/api/boards.py @@ -34,6 +34,8 @@ from app.models.board_memory import BoardMemory from app.models.board_onboarding import BoardOnboardingSession from app.models.boards import Board from app.models.gateways import Gateway +from app.models.organization_board_access import OrganizationBoardAccess +from app.models.organization_invite_board_access import OrganizationInviteBoardAccess from app.models.task_dependencies import TaskDependency from app.models.task_fingerprints import TaskFingerprint from app.models.tasks import Task @@ -316,6 +318,10 @@ async def delete_board( await session.execute( delete(BoardOnboardingSession).where(col(BoardOnboardingSession.board_id) == board.id) ) + await session.execute(delete(OrganizationBoardAccess).where(col(OrganizationBoardAccess.board_id) == board.id)) + await session.execute( + delete(OrganizationInviteBoardAccess).where(col(OrganizationInviteBoardAccess.board_id) == board.id) + ) # Tasks reference agents (assigned_agent_id) and have dependents (fingerprints/dependencies), so # delete tasks before agents. diff --git a/frontend/src/app/activity/page.tsx b/frontend/src/app/activity/page.tsx index 2c585672..a6fbfc47 100644 --- a/frontend/src/app/activity/page.tsx +++ b/frontend/src/app/activity/page.tsx @@ -3,7 +3,7 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; import Link from "next/link"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ArrowUpRight, Activity as ActivityIcon } from "lucide-react"; import { ApiError } from "@/api/mutator"; @@ -15,9 +15,9 @@ import { import type { ActivityTaskCommentFeedItemRead } from "@/api/generated/model"; import { Markdown } from "@/components/atoms/Markdown"; import { ActivityFeed } from "@/components/activity/ActivityFeed"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; -import { Button } from "@/components/ui/button"; import { createExponentialBackoff } from "@/lib/backoff"; import { apiDatetimeToMs, parseApiDatetime } from "@/lib/datetime"; import { cn } from "@/lib/utils"; @@ -295,20 +295,13 @@ export default function ActivityPage() { return ( -
-
-

Sign in to view the feed.

- - - -
-
+
diff --git a/frontend/src/app/agents/[agentId]/edit/page.tsx b/frontend/src/app/agents/[agentId]/edit/page.tsx index cb0d0043..0e349aab 100644 --- a/frontend/src/app/agents/[agentId]/edit/page.tsx +++ b/frontend/src/app/agents/[agentId]/edit/page.tsx @@ -5,7 +5,7 @@ export const dynamic = "force-dynamic"; import { useMemo, useState } from "react"; import { useParams, useRouter } from "next/navigation"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { @@ -18,6 +18,7 @@ import { useListBoardsApiV1BoardsGet, } from "@/api/generated/boards/boards"; import type { AgentRead, AgentUpdate, BoardRead } from "@/api/generated/model"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; @@ -273,18 +274,11 @@ export default function EditAgentPage() { return ( -
-
-

Sign in to edit agents.

- - - -
-
+
diff --git a/frontend/src/app/agents/new/page.tsx b/frontend/src/app/agents/new/page.tsx index cbf81435..ddfd3fb8 100644 --- a/frontend/src/app/agents/new/page.tsx +++ b/frontend/src/app/agents/new/page.tsx @@ -5,7 +5,7 @@ export const dynamic = "force-dynamic"; import { useState } from "react"; import { useRouter } from "next/navigation"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { @@ -18,6 +18,8 @@ import { useGetMyMembershipApiV1OrganizationsMeMemberGet, } from "@/api/generated/organizations/organizations"; import type { BoardRead } from "@/api/generated/model"; +import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; @@ -170,20 +172,11 @@ export default function NewAgentPage() { return ( -
-
-

- Sign in to create an agent. -

- - - -
-
+
@@ -201,9 +194,7 @@ export default function NewAgentPage() {
{!isAdmin ? ( -
- Only organization owners and admins can create agents. -
+ ) : (
{ if (!value) return null; @@ -304,18 +306,11 @@ export default function AgentsPage() { return ( -
-
-

Sign in to view agents.

- - - -
-
+
@@ -342,9 +337,7 @@ export default function AgentsPage() {
{!isAdmin ? ( -
- Only organization owners and admins can access agents. -
+ ) : ( <>
diff --git a/frontend/src/app/board-groups/[groupId]/edit/page.tsx b/frontend/src/app/board-groups/[groupId]/edit/page.tsx index eb86febe..772c706f 100644 --- a/frontend/src/app/board-groups/[groupId]/edit/page.tsx +++ b/frontend/src/app/board-groups/[groupId]/edit/page.tsx @@ -5,7 +5,7 @@ export const dynamic = "force-dynamic"; import { useEffect, useMemo, useRef, useState } from "react"; import { useParams, useRouter, useSearchParams } from "next/navigation"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { @@ -23,6 +23,7 @@ import type { BoardGroupUpdate, BoardRead, } from "@/api/generated/model"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; @@ -281,19 +282,10 @@ export default function EditBoardGroupPage() { return ( -
-
-

- Sign in to edit board groups. -

- - - -
-
+
diff --git a/frontend/src/app/board-groups/[groupId]/page.tsx b/frontend/src/app/board-groups/[groupId]/page.tsx index c14944b7..2d1be6a1 100644 --- a/frontend/src/app/board-groups/[groupId]/page.tsx +++ b/frontend/src/app/board-groups/[groupId]/page.tsx @@ -6,7 +6,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import Link from "next/link"; import { useParams } from "next/navigation"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ArrowUpRight, MessageSquare, @@ -38,6 +38,7 @@ import type { } from "@/api/generated/model"; import type { BoardGroupBoardSnapshot } from "@/api/generated/model"; import { Markdown } from "@/components/atoms/Markdown"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { BoardChatComposer } from "@/components/BoardChatComposer"; @@ -721,19 +722,10 @@ export default function BoardGroupDetailPage() { return ( -
-
-

- Sign in to view board groups. -

- - - -
-
+
diff --git a/frontend/src/app/board-groups/new/page.tsx b/frontend/src/app/board-groups/new/page.tsx index 4b4d169a..a8023b3c 100644 --- a/frontend/src/app/board-groups/new/page.tsx +++ b/frontend/src/app/board-groups/new/page.tsx @@ -6,7 +6,7 @@ import { useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { @@ -16,6 +16,7 @@ import { } from "@/api/generated/boards/boards"; import { useCreateBoardGroupApiV1BoardGroupsPost } from "@/api/generated/board-groups/board-groups"; import type { BoardRead } from "@/api/generated/model"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; @@ -126,16 +127,10 @@ export default function NewBoardGroupPage() { return ( -
-
-

- Sign in to create a board group. -

- - - -
-
+
diff --git a/frontend/src/app/board-groups/page.tsx b/frontend/src/app/board-groups/page.tsx index 8a2a6835..b7386f45 100644 --- a/frontend/src/app/board-groups/page.tsx +++ b/frontend/src/app/board-groups/page.tsx @@ -5,7 +5,7 @@ export const dynamic = "force-dynamic"; import { useMemo, useState } from "react"; import Link from "next/link"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { type ColumnDef, flexRender, @@ -33,6 +33,7 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; const formatTimestamp = (value?: string | null) => { if (!value) return "—"; @@ -190,16 +191,10 @@ export default function BoardGroupsPage() { return ( -
-
-

- Sign in to view board groups. -

- - - -
-
+
diff --git a/frontend/src/app/boards/[boardId]/edit/page.tsx b/frontend/src/app/boards/[boardId]/edit/page.tsx index 210c8dcc..7468f42f 100644 --- a/frontend/src/app/boards/[boardId]/edit/page.tsx +++ b/frontend/src/app/boards/[boardId]/edit/page.tsx @@ -5,7 +5,7 @@ export const dynamic = "force-dynamic"; import { useEffect, useMemo, useRef, useState } from "react"; import { useParams, useRouter, useSearchParams } from "next/navigation"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { X } from "lucide-react"; import { ApiError } from "@/api/mutator"; @@ -32,6 +32,8 @@ import type { BoardUpdate, } from "@/api/generated/model"; import { BoardOnboardingChat } from "@/components/BoardOnboardingChat"; +import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; @@ -308,18 +310,11 @@ export default function EditBoardPage() { <> -
-
-

Sign in to edit boards.

- - - -
-
+
@@ -337,9 +332,7 @@ export default function EditBoardPage() {
{!isAdmin ? ( -
- Only organization owners and admins can edit board settings. -
+ ) : (
-
-
-

Sign in to create a board.

- - - -
-
+
@@ -185,9 +180,7 @@ export default function NewBoardPage() {
{!isAdmin ? ( -
- Only organization owners and admins can create boards. -
+ ) : ( { if (!value) return "—"; @@ -254,18 +255,11 @@ export default function BoardsPage() { return ( -
-
-

Sign in to view boards.

- - - -
-
+
diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx index dc462ce3..4d6de89c 100644 --- a/frontend/src/app/dashboard/page.tsx +++ b/frontend/src/app/dashboard/page.tsx @@ -4,7 +4,7 @@ export const dynamic = "force-dynamic"; import { useMemo } from "react"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { Area, AreaChart, @@ -22,8 +22,8 @@ import { Activity, Clock, PenSquare, Timer, Users } from "lucide-react"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; -import { Button } from "@/components/ui/button"; import MetricSparkline from "@/components/charts/metric-sparkline"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { ApiError } from "@/api/mutator"; import { type dashboardMetricsApiV1MetricsDashboardGetResponse, @@ -319,20 +319,11 @@ export default function DashboardPage() { return ( -
-
-

- Sign in to access the dashboard. -

- - - -
-
+
diff --git a/frontend/src/app/organization/page.tsx b/frontend/src/app/organization/page.tsx index 6932e133..f039970f 100644 --- a/frontend/src/app/organization/page.tsx +++ b/frontend/src/app/organization/page.tsx @@ -4,7 +4,7 @@ export const dynamic = "force-dynamic"; import { useMemo, useState } from "react"; -import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; +import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { useQueryClient } from "@tanstack/react-query"; import { Building2, Copy, UserPlus, Users } from "lucide-react"; @@ -38,6 +38,7 @@ import type { OrganizationInviteRead, OrganizationMemberRead, } from "@/api/generated/model"; +import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -721,20 +722,11 @@ export default function OrganizationPage() { return ( -
-
-

- Sign in to manage your organization. -

- - - -
-
+
diff --git a/frontend/src/components/auth/SignedOutPanel.tsx b/frontend/src/components/auth/SignedOutPanel.tsx index 062073d6..222dad08 100644 --- a/frontend/src/components/auth/SignedOutPanel.tsx +++ b/frontend/src/components/auth/SignedOutPanel.tsx @@ -5,20 +5,32 @@ import { Button } from "@/components/ui/button"; type SignedOutPanelProps = { message: string; forceRedirectUrl: string; + signUpForceRedirectUrl?: string; + mode?: "modal" | "redirect"; buttonLabel?: string; + buttonTestId?: string; }; export function SignedOutPanel({ message, forceRedirectUrl, + signUpForceRedirectUrl, + mode = "modal", buttonLabel = "Sign in", + buttonTestId, }: SignedOutPanelProps) { return (

{message}

- - + +