feat: refactor sign-in prompts to use SignedOutPanel component
This commit is contained in:
@@ -34,6 +34,8 @@ from app.models.board_memory import BoardMemory
|
|||||||
from app.models.board_onboarding import BoardOnboardingSession
|
from app.models.board_onboarding import BoardOnboardingSession
|
||||||
from app.models.boards import Board
|
from app.models.boards import Board
|
||||||
from app.models.gateways import Gateway
|
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_dependencies import TaskDependency
|
||||||
from app.models.task_fingerprints import TaskFingerprint
|
from app.models.task_fingerprints import TaskFingerprint
|
||||||
from app.models.tasks import Task
|
from app.models.tasks import Task
|
||||||
@@ -316,6 +318,10 @@ async def delete_board(
|
|||||||
await session.execute(
|
await session.execute(
|
||||||
delete(BoardOnboardingSession).where(col(BoardOnboardingSession.board_id) == board.id)
|
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
|
# Tasks reference agents (assigned_agent_id) and have dependents (fingerprints/dependencies), so
|
||||||
# delete tasks before agents.
|
# delete tasks before agents.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import Link from "next/link";
|
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 { ArrowUpRight, Activity as ActivityIcon } from "lucide-react";
|
||||||
|
|
||||||
import { ApiError } from "@/api/mutator";
|
import { ApiError } from "@/api/mutator";
|
||||||
@@ -15,9 +15,9 @@ import {
|
|||||||
import type { ActivityTaskCommentFeedItemRead } from "@/api/generated/model";
|
import type { ActivityTaskCommentFeedItemRead } from "@/api/generated/model";
|
||||||
import { Markdown } from "@/components/atoms/Markdown";
|
import { Markdown } from "@/components/atoms/Markdown";
|
||||||
import { ActivityFeed } from "@/components/activity/ActivityFeed";
|
import { ActivityFeed } from "@/components/activity/ActivityFeed";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { createExponentialBackoff } from "@/lib/backoff";
|
import { createExponentialBackoff } from "@/lib/backoff";
|
||||||
import { apiDatetimeToMs, parseApiDatetime } from "@/lib/datetime";
|
import { apiDatetimeToMs, parseApiDatetime } from "@/lib/datetime";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
@@ -295,20 +295,13 @@ export default function ActivityPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to view the feed."
|
||||||
<p className="text-sm text-slate-600">Sign in to view the feed.</p>
|
forceRedirectUrl="/activity"
|
||||||
<SignInButton
|
signUpForceRedirectUrl="/activity"
|
||||||
mode="redirect"
|
mode="redirect"
|
||||||
forceRedirectUrl="/activity"
|
buttonTestId="activity-signin"
|
||||||
signUpForceRedirectUrl="/activity"
|
/>
|
||||||
>
|
|
||||||
<Button className="mt-4" data-testid="activity-signin">
|
|
||||||
Sign in
|
|
||||||
</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const dynamic = "force-dynamic";
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
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 { ApiError } from "@/api/mutator";
|
||||||
import {
|
import {
|
||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
useListBoardsApiV1BoardsGet,
|
useListBoardsApiV1BoardsGet,
|
||||||
} from "@/api/generated/boards/boards";
|
} from "@/api/generated/boards/boards";
|
||||||
import type { AgentRead, AgentUpdate, BoardRead } from "@/api/generated/model";
|
import type { AgentRead, AgentUpdate, BoardRead } from "@/api/generated/model";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -273,18 +274,11 @@ export default function EditAgentPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to edit agents."
|
||||||
<p className="text-sm text-slate-600">Sign in to edit agents.</p>
|
forceRedirectUrl={`/agents/${agentId}/edit`}
|
||||||
<SignInButton
|
signUpForceRedirectUrl={`/agents/${agentId}/edit`}
|
||||||
mode="modal"
|
/>
|
||||||
forceRedirectUrl={`/agents/${agentId}/edit`}
|
|
||||||
signUpForceRedirectUrl={`/agents/${agentId}/edit`}
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const dynamic = "force-dynamic";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
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 { ApiError } from "@/api/mutator";
|
||||||
import {
|
import {
|
||||||
@@ -18,6 +18,8 @@ import {
|
|||||||
useGetMyMembershipApiV1OrganizationsMeMemberGet,
|
useGetMyMembershipApiV1OrganizationsMeMemberGet,
|
||||||
} from "@/api/generated/organizations/organizations";
|
} from "@/api/generated/organizations/organizations";
|
||||||
import type { BoardRead } from "@/api/generated/model";
|
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 { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -170,20 +172,11 @@ export default function NewAgentPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to create an agent."
|
||||||
<p className="text-sm text-slate-600">
|
forceRedirectUrl="/agents/new"
|
||||||
Sign in to create an agent.
|
signUpForceRedirectUrl="/agents/new"
|
||||||
</p>
|
/>
|
||||||
<SignInButton
|
|
||||||
mode="modal"
|
|
||||||
forceRedirectUrl="/agents/new"
|
|
||||||
signUpForceRedirectUrl="/agents/new"
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
@@ -201,9 +194,7 @@ export default function NewAgentPage() {
|
|||||||
|
|
||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
{!isAdmin ? (
|
{!isAdmin ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-6 py-5 text-sm text-slate-600 shadow-sm">
|
<AdminOnlyNotice message="Only organization owners and admins can create agents." />
|
||||||
Only organization owners and admins can create agents.
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useMemo, useState } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
||||||
import {
|
import {
|
||||||
type ColumnDef,
|
type ColumnDef,
|
||||||
type SortingState,
|
type SortingState,
|
||||||
@@ -47,6 +47,8 @@ import {
|
|||||||
useGetMyMembershipApiV1OrganizationsMeMemberGet,
|
useGetMyMembershipApiV1OrganizationsMeMemberGet,
|
||||||
} from "@/api/generated/organizations/organizations";
|
} from "@/api/generated/organizations/organizations";
|
||||||
import type { AgentRead } from "@/api/generated/model";
|
import type { AgentRead } from "@/api/generated/model";
|
||||||
|
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
|
|
||||||
const parseTimestamp = (value?: string | null) => {
|
const parseTimestamp = (value?: string | null) => {
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
@@ -304,18 +306,11 @@ export default function AgentsPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to view agents."
|
||||||
<p className="text-sm text-slate-600">Sign in to view agents.</p>
|
forceRedirectUrl="/agents"
|
||||||
<SignInButton
|
signUpForceRedirectUrl="/agents"
|
||||||
mode="modal"
|
/>
|
||||||
forceRedirectUrl="/agents"
|
|
||||||
signUpForceRedirectUrl="/agents"
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
@@ -342,9 +337,7 @@ export default function AgentsPage() {
|
|||||||
|
|
||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
{!isAdmin ? (
|
{!isAdmin ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-6 py-5 text-sm text-slate-600 shadow-sm">
|
<AdminOnlyNotice message="Only organization owners and admins can access agents." />
|
||||||
Only organization owners and admins can access agents.
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const dynamic = "force-dynamic";
|
|||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
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 { ApiError } from "@/api/mutator";
|
||||||
import {
|
import {
|
||||||
@@ -23,6 +23,7 @@ import type {
|
|||||||
BoardGroupUpdate,
|
BoardGroupUpdate,
|
||||||
BoardRead,
|
BoardRead,
|
||||||
} from "@/api/generated/model";
|
} from "@/api/generated/model";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -281,19 +282,10 @@ export default function EditBoardGroupPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to edit board groups."
|
||||||
<p className="text-sm text-slate-600">
|
forceRedirectUrl={`/board-groups/${groupId ?? ""}/edit`}
|
||||||
Sign in to edit board groups.
|
/>
|
||||||
</p>
|
|
||||||
<SignInButton
|
|
||||||
mode="modal"
|
|
||||||
forceRedirectUrl={`/board-groups/${groupId ?? ""}/edit`}
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
|
|
||||||
import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
||||||
import {
|
import {
|
||||||
ArrowUpRight,
|
ArrowUpRight,
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
@@ -38,6 +38,7 @@ import type {
|
|||||||
} from "@/api/generated/model";
|
} from "@/api/generated/model";
|
||||||
import type { BoardGroupBoardSnapshot } from "@/api/generated/model";
|
import type { BoardGroupBoardSnapshot } from "@/api/generated/model";
|
||||||
import { Markdown } from "@/components/atoms/Markdown";
|
import { Markdown } from "@/components/atoms/Markdown";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { BoardChatComposer } from "@/components/BoardChatComposer";
|
import { BoardChatComposer } from "@/components/BoardChatComposer";
|
||||||
@@ -721,19 +722,10 @@ export default function BoardGroupDetailPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to view board groups."
|
||||||
<p className="text-sm text-slate-600">
|
forceRedirectUrl={`/board-groups/${groupId ?? ""}`}
|
||||||
Sign in to view board groups.
|
/>
|
||||||
</p>
|
|
||||||
<SignInButton
|
|
||||||
mode="modal"
|
|
||||||
forceRedirectUrl={`/board-groups/${groupId ?? ""}`}
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useState } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
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 { ApiError } from "@/api/mutator";
|
||||||
import {
|
import {
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
} from "@/api/generated/boards/boards";
|
} from "@/api/generated/boards/boards";
|
||||||
import { useCreateBoardGroupApiV1BoardGroupsPost } from "@/api/generated/board-groups/board-groups";
|
import { useCreateBoardGroupApiV1BoardGroupsPost } from "@/api/generated/board-groups/board-groups";
|
||||||
import type { BoardRead } from "@/api/generated/model";
|
import type { BoardRead } from "@/api/generated/model";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -126,16 +127,10 @@ export default function NewBoardGroupPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to create a board group."
|
||||||
<p className="text-sm text-slate-600">
|
forceRedirectUrl="/board-groups/new"
|
||||||
Sign in to create a board group.
|
/>
|
||||||
</p>
|
|
||||||
<SignInButton mode="modal" forceRedirectUrl="/board-groups/new">
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const dynamic = "force-dynamic";
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
||||||
import {
|
import {
|
||||||
type ColumnDef,
|
type ColumnDef,
|
||||||
flexRender,
|
flexRender,
|
||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
|
|
||||||
const formatTimestamp = (value?: string | null) => {
|
const formatTimestamp = (value?: string | null) => {
|
||||||
if (!value) return "—";
|
if (!value) return "—";
|
||||||
@@ -190,16 +191,10 @@ export default function BoardGroupsPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to view board groups."
|
||||||
<p className="text-sm text-slate-600">
|
forceRedirectUrl="/board-groups"
|
||||||
Sign in to view board groups.
|
/>
|
||||||
</p>
|
|
||||||
<SignInButton mode="modal" forceRedirectUrl="/board-groups">
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const dynamic = "force-dynamic";
|
|||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
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 { X } from "lucide-react";
|
||||||
|
|
||||||
import { ApiError } from "@/api/mutator";
|
import { ApiError } from "@/api/mutator";
|
||||||
@@ -32,6 +32,8 @@ import type {
|
|||||||
BoardUpdate,
|
BoardUpdate,
|
||||||
} from "@/api/generated/model";
|
} from "@/api/generated/model";
|
||||||
import { BoardOnboardingChat } from "@/components/BoardOnboardingChat";
|
import { BoardOnboardingChat } from "@/components/BoardOnboardingChat";
|
||||||
|
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -308,18 +310,11 @@ export default function EditBoardPage() {
|
|||||||
<>
|
<>
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to edit boards."
|
||||||
<p className="text-sm text-slate-600">Sign in to edit boards.</p>
|
forceRedirectUrl={`/boards/${boardId}/edit`}
|
||||||
<SignInButton
|
signUpForceRedirectUrl={`/boards/${boardId}/edit`}
|
||||||
mode="modal"
|
/>
|
||||||
forceRedirectUrl={`/boards/${boardId}/edit`}
|
|
||||||
signUpForceRedirectUrl={`/boards/${boardId}/edit`}
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
@@ -337,9 +332,7 @@ export default function EditBoardPage() {
|
|||||||
|
|
||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
{!isAdmin ? (
|
{!isAdmin ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-6 py-5 text-sm text-slate-600 shadow-sm">
|
<AdminOnlyNotice message="Only organization owners and admins can edit board settings." />
|
||||||
Only organization owners and admins can edit board settings.
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<form
|
<form
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useMemo, useState } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
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 { ApiError } from "@/api/mutator";
|
||||||
import { useCreateBoardApiV1BoardsPost } from "@/api/generated/boards/boards";
|
import { useCreateBoardApiV1BoardsPost } from "@/api/generated/boards/boards";
|
||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
useGetMyMembershipApiV1OrganizationsMeMemberGet,
|
useGetMyMembershipApiV1OrganizationsMeMemberGet,
|
||||||
} from "@/api/generated/organizations/organizations";
|
} from "@/api/generated/organizations/organizations";
|
||||||
import type { BoardGroupRead } from "@/api/generated/model";
|
import type { BoardGroupRead } from "@/api/generated/model";
|
||||||
|
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -156,18 +158,11 @@ export default function NewBoardPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to create a board."
|
||||||
<p className="text-sm text-slate-600">Sign in to create a board.</p>
|
forceRedirectUrl="/boards/new"
|
||||||
<SignInButton
|
signUpForceRedirectUrl="/boards/new"
|
||||||
mode="modal"
|
/>
|
||||||
forceRedirectUrl="/boards/new"
|
|
||||||
signUpForceRedirectUrl="/boards/new"
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
@@ -185,9 +180,7 @@ export default function NewBoardPage() {
|
|||||||
|
|
||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
{!isAdmin ? (
|
{!isAdmin ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-6 py-5 text-sm text-slate-600 shadow-sm">
|
<AdminOnlyNotice message="Only organization owners and admins can create boards." />
|
||||||
Only organization owners and admins can create boards.
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const dynamic = "force-dynamic";
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
||||||
import {
|
import {
|
||||||
type ColumnDef,
|
type ColumnDef,
|
||||||
flexRender,
|
flexRender,
|
||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
|
|
||||||
const formatTimestamp = (value?: string | null) => {
|
const formatTimestamp = (value?: string | null) => {
|
||||||
if (!value) return "—";
|
if (!value) return "—";
|
||||||
@@ -254,18 +255,11 @@ export default function BoardsPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to view boards."
|
||||||
<p className="text-sm text-slate-600">Sign in to view boards.</p>
|
forceRedirectUrl="/boards"
|
||||||
<SignInButton
|
signUpForceRedirectUrl="/boards"
|
||||||
mode="modal"
|
/>
|
||||||
forceRedirectUrl="/boards"
|
|
||||||
signUpForceRedirectUrl="/boards"
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export const dynamic = "force-dynamic";
|
|||||||
|
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
|
||||||
import {
|
import {
|
||||||
Area,
|
Area,
|
||||||
AreaChart,
|
AreaChart,
|
||||||
@@ -22,8 +22,8 @@ import { Activity, Clock, PenSquare, Timer, Users } from "lucide-react";
|
|||||||
|
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import MetricSparkline from "@/components/charts/metric-sparkline";
|
import MetricSparkline from "@/components/charts/metric-sparkline";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { ApiError } from "@/api/mutator";
|
import { ApiError } from "@/api/mutator";
|
||||||
import {
|
import {
|
||||||
type dashboardMetricsApiV1MetricsDashboardGetResponse,
|
type dashboardMetricsApiV1MetricsDashboardGetResponse,
|
||||||
@@ -319,20 +319,11 @@ export default function DashboardPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to access the dashboard."
|
||||||
<p className="text-sm text-slate-600">
|
forceRedirectUrl="/onboarding"
|
||||||
Sign in to access the dashboard.
|
signUpForceRedirectUrl="/onboarding"
|
||||||
</p>
|
/>
|
||||||
<SignInButton
|
|
||||||
mode="modal"
|
|
||||||
forceRedirectUrl="/onboarding"
|
|
||||||
signUpForceRedirectUrl="/onboarding"
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export const dynamic = "force-dynamic";
|
|||||||
|
|
||||||
import { useMemo, useState } from "react";
|
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 { useQueryClient } from "@tanstack/react-query";
|
||||||
import { Building2, Copy, UserPlus, Users } from "lucide-react";
|
import { Building2, Copy, UserPlus, Users } from "lucide-react";
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ import type {
|
|||||||
OrganizationInviteRead,
|
OrganizationInviteRead,
|
||||||
OrganizationMemberRead,
|
OrganizationMemberRead,
|
||||||
} from "@/api/generated/model";
|
} from "@/api/generated/model";
|
||||||
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -721,20 +722,11 @@ export default function OrganizationPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<SignedOutPanel
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
message="Sign in to manage your organization."
|
||||||
<p className="text-sm text-slate-600">
|
forceRedirectUrl="/organization"
|
||||||
Sign in to manage your organization.
|
signUpForceRedirectUrl="/organization"
|
||||||
</p>
|
/>
|
||||||
<SignInButton
|
|
||||||
mode="modal"
|
|
||||||
forceRedirectUrl="/organization"
|
|
||||||
signUpForceRedirectUrl="/organization"
|
|
||||||
>
|
|
||||||
<Button className="mt-4">Sign in</Button>
|
|
||||||
</SignInButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
|
|||||||
@@ -5,20 +5,32 @@ import { Button } from "@/components/ui/button";
|
|||||||
type SignedOutPanelProps = {
|
type SignedOutPanelProps = {
|
||||||
message: string;
|
message: string;
|
||||||
forceRedirectUrl: string;
|
forceRedirectUrl: string;
|
||||||
|
signUpForceRedirectUrl?: string;
|
||||||
|
mode?: "modal" | "redirect";
|
||||||
buttonLabel?: string;
|
buttonLabel?: string;
|
||||||
|
buttonTestId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function SignedOutPanel({
|
export function SignedOutPanel({
|
||||||
message,
|
message,
|
||||||
forceRedirectUrl,
|
forceRedirectUrl,
|
||||||
|
signUpForceRedirectUrl,
|
||||||
|
mode = "modal",
|
||||||
buttonLabel = "Sign in",
|
buttonLabel = "Sign in",
|
||||||
|
buttonTestId,
|
||||||
}: SignedOutPanelProps) {
|
}: SignedOutPanelProps) {
|
||||||
return (
|
return (
|
||||||
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<div className="col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
<div className="rounded-xl border border-slate-200 bg-white px-8 py-6 shadow-sm">
|
||||||
<p className="text-sm text-slate-600">{message}</p>
|
<p className="text-sm text-slate-600">{message}</p>
|
||||||
<SignInButton mode="modal" forceRedirectUrl={forceRedirectUrl}>
|
<SignInButton
|
||||||
<Button className="mt-4">{buttonLabel}</Button>
|
mode={mode}
|
||||||
|
forceRedirectUrl={forceRedirectUrl}
|
||||||
|
signUpForceRedirectUrl={signUpForceRedirectUrl}
|
||||||
|
>
|
||||||
|
<Button className="mt-4" data-testid={buttonTestId}>
|
||||||
|
{buttonLabel}
|
||||||
|
</Button>
|
||||||
</SignInButton>
|
</SignInButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user