bug: shadcn ui merge
This commit is contained in:
parent
d45fd42c7f
commit
ad5ca38a86
|
|
@ -242,7 +242,7 @@ const eventLabel = (eventType: FeedEventType): string => {
|
||||||
|
|
||||||
const eventPillClass = (eventType: FeedEventType): string => {
|
const eventPillClass = (eventType: FeedEventType): string => {
|
||||||
if (eventType === "task.comment") {
|
if (eventType === "task.comment") {
|
||||||
return "border-blue-200 bg-blue-50 text-blue-700";
|
return "border-primary/30 bg-primary/10 text-primary";
|
||||||
}
|
}
|
||||||
if (eventType === "task.created") {
|
if (eventType === "task.created") {
|
||||||
return "border-emerald-200 bg-emerald-50 text-emerald-700";
|
return "border-emerald-200 bg-emerald-50 text-emerald-700";
|
||||||
|
|
@ -263,7 +263,7 @@ const eventPillClass = (eventType: FeedEventType): string => {
|
||||||
return "border-lime-200 bg-lime-50 text-lime-700";
|
return "border-lime-200 bg-lime-50 text-lime-700";
|
||||||
}
|
}
|
||||||
if (eventType === "agent.offline") {
|
if (eventType === "agent.offline") {
|
||||||
return "border-slate-300 bg-slate-100 text-slate-700";
|
return "border-input bg-accent text-muted-foreground";
|
||||||
}
|
}
|
||||||
if (eventType === "agent.updated") {
|
if (eventType === "agent.updated") {
|
||||||
return "border-indigo-200 bg-indigo-50 text-indigo-700";
|
return "border-indigo-200 bg-indigo-50 text-indigo-700";
|
||||||
|
|
@ -280,7 +280,7 @@ const eventPillClass = (eventType: FeedEventType): string => {
|
||||||
if (eventType === "approval.rejected") {
|
if (eventType === "approval.rejected") {
|
||||||
return "border-rose-200 bg-rose-50 text-rose-700";
|
return "border-rose-200 bg-rose-50 text-rose-700";
|
||||||
}
|
}
|
||||||
return "border-slate-200 bg-slate-100 text-slate-700";
|
return "border-border bg-accent text-muted-foreground";
|
||||||
};
|
};
|
||||||
|
|
||||||
const FeedCard = memo(function FeedCard({
|
const FeedCard = memo(function FeedCard({
|
||||||
|
|
@ -297,14 +297,14 @@ const FeedCard = memo(function FeedCard({
|
||||||
<div
|
<div
|
||||||
id={feedItemElementId(item.id)}
|
id={feedItemElementId(item.id)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"scroll-mt-28 rounded-xl border bg-white p-4 transition",
|
"scroll-mt-28 rounded-xl border bg-card p-4 transition",
|
||||||
isHighlighted
|
isHighlighted
|
||||||
? "border-blue-300 ring-2 ring-blue-200"
|
? "border-primary/40 ring-2 ring-primary/20"
|
||||||
: "border-slate-200 hover:border-slate-300",
|
: "border-border hover:border-input",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<div className="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-slate-100 text-xs font-semibold text-slate-700">
|
<div className="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-accent text-xs font-semibold text-muted-foreground">
|
||||||
{authorAvatar}
|
{authorAvatar}
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
|
|
@ -312,7 +312,7 @@ const FeedCard = memo(function FeedCard({
|
||||||
{item.context_href ? (
|
{item.context_href ? (
|
||||||
<Link
|
<Link
|
||||||
href={item.context_href}
|
href={item.context_href}
|
||||||
className="block text-sm font-semibold leading-snug text-slate-900 transition hover:text-slate-950 hover:underline"
|
className="block text-sm font-semibold leading-snug text-foreground transition hover:text-foreground hover:underline"
|
||||||
title={item.title}
|
title={item.title}
|
||||||
style={{
|
style={{
|
||||||
display: "-webkit-box",
|
display: "-webkit-box",
|
||||||
|
|
@ -324,11 +324,11 @@ const FeedCard = memo(function FeedCard({
|
||||||
{item.title}
|
{item.title}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm font-semibold leading-snug text-slate-900">
|
<p className="text-sm font-semibold leading-snug text-foreground">
|
||||||
{item.title}
|
{item.title}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[11px] text-slate-500">
|
<div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[11px] text-muted-foreground">
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
"rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
||||||
|
|
@ -340,29 +340,29 @@ const FeedCard = memo(function FeedCard({
|
||||||
{item.board_href && item.board_name ? (
|
{item.board_href && item.board_name ? (
|
||||||
<Link
|
<Link
|
||||||
href={item.board_href}
|
href={item.board_href}
|
||||||
className="font-semibold text-slate-700 hover:text-slate-900 hover:underline"
|
className="font-semibold text-muted-foreground hover:text-foreground hover:underline"
|
||||||
>
|
>
|
||||||
{item.board_name}
|
{item.board_name}
|
||||||
</Link>
|
</Link>
|
||||||
) : item.board_name ? (
|
) : item.board_name ? (
|
||||||
<span className="font-semibold text-slate-700">
|
<span className="font-semibold text-muted-foreground">
|
||||||
{item.board_name}
|
{item.board_name}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
{item.board_name ? (
|
{item.board_name ? (
|
||||||
<span className="text-slate-300">·</span>
|
<span className="text-muted-foreground/50">·</span>
|
||||||
) : null}
|
) : null}
|
||||||
<span className="font-medium text-slate-700">
|
<span className="font-medium text-muted-foreground">
|
||||||
{item.actor_name}
|
{item.actor_name}
|
||||||
</span>
|
</span>
|
||||||
{item.actor_role ? (
|
{item.actor_role ? (
|
||||||
<>
|
<>
|
||||||
<span className="text-slate-300">·</span>
|
<span className="text-muted-foreground/50">·</span>
|
||||||
<span className="text-slate-500">{item.actor_role}</span>
|
<span className="text-muted-foreground">{item.actor_role}</span>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<span className="text-slate-300">·</span>
|
<span className="text-muted-foreground/50">·</span>
|
||||||
<span className="text-slate-400">
|
<span className="text-muted-foreground/70">
|
||||||
{formatShortTimestamp(item.created_at)}
|
{formatShortTimestamp(item.created_at)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -370,11 +370,11 @@ const FeedCard = memo(function FeedCard({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{message ? (
|
{message ? (
|
||||||
<div className="mt-3 select-text cursor-text text-sm leading-relaxed text-slate-900 break-words">
|
<div className="mt-3 select-text cursor-text text-sm leading-relaxed text-foreground break-words">
|
||||||
<Markdown content={message} variant="basic" />
|
<Markdown content={message} variant="basic" />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-3 text-sm text-slate-500">—</p>
|
<p className="mt-3 text-sm text-muted-foreground">—</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -1506,18 +1506,18 @@ export default function ActivityPage() {
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
<main className="flex-1 overflow-y-auto bg-slate-50">
|
<main className="flex-1 overflow-y-auto bg-muted">
|
||||||
<div className="sticky top-0 z-30 border-b border-slate-200 bg-white">
|
<div className="sticky top-0 z-30 border-b border-border bg-card">
|
||||||
<div className="px-4 py-4 md:px-8 md:py-6">
|
<div className="px-4 py-4 md:px-8 md:py-6">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-4">
|
<div className="flex flex-wrap items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ActivityIcon className="h-5 w-5 text-slate-600" />
|
<ActivityIcon className="h-5 w-5 text-muted-foreground" />
|
||||||
<h1 className="text-2xl font-semibold tracking-tight text-slate-900">
|
<h1 className="text-2xl font-semibold tracking-tight text-foreground">
|
||||||
Live feed
|
Live feed
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-1 text-sm text-slate-500">
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
Realtime task, approval, agent, and board-chat activity
|
Realtime task, approval, agent, and board-chat activity
|
||||||
across all boards.
|
across all boards.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -258,16 +258,16 @@ export default function EditAgentPage() {
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="rounded-xl border border-slate-200 bg-white p-6 shadow-sm space-y-6"
|
className="rounded-xl border border-border bg-card p-6 shadow-sm space-y-6"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Basic configuration
|
Basic configuration
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4 space-y-6">
|
<div className="mt-4 space-y-6">
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Agent name <span className="text-red-500">*</span>
|
Agent name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -278,7 +278,7 @@ export default function EditAgentPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Role
|
Role
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -297,10 +297,10 @@ export default function EditAgentPage() {
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Board
|
Board
|
||||||
{resolvedIsGatewayMain ? (
|
{resolvedIsGatewayMain ? (
|
||||||
<span className="ml-2 text-xs font-normal text-slate-500">
|
<span className="ml-2 text-xs font-normal text-muted-foreground">
|
||||||
optional
|
optional
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -310,7 +310,7 @@ export default function EditAgentPage() {
|
||||||
{resolvedBoardId ? (
|
{resolvedBoardId ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="text-xs font-medium text-slate-600 hover:text-slate-900"
|
className="text-xs font-medium text-muted-foreground hover:text-foreground"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setBoardId("");
|
setBoardId("");
|
||||||
}}
|
}}
|
||||||
|
|
@ -338,19 +338,19 @@ export default function EditAgentPage() {
|
||||||
disabled={boards.length === 0}
|
disabled={boards.length === 0}
|
||||||
/>
|
/>
|
||||||
{resolvedIsGatewayMain ? (
|
{resolvedIsGatewayMain ? (
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Main agents are not attached to a board. If a board is
|
Main agents are not attached to a board. If a board is
|
||||||
selected, it is only used to resolve the gateway main
|
selected, it is only used to resolve the gateway main
|
||||||
session key and will be cleared on save.
|
session key and will be cleared on save.
|
||||||
</p>
|
</p>
|
||||||
) : boards.length === 0 ? (
|
) : boards.length === 0 ? (
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Create a board before assigning agents.
|
Create a board before assigning agents.
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Emoji
|
Emoji
|
||||||
</label>
|
</label>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -377,20 +377,20 @@ export default function EditAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 rounded-xl border border-slate-200 bg-slate-50 p-4">
|
<div className="mt-6 rounded-xl border border-border bg-muted p-4">
|
||||||
<label className="flex items-start gap-3 text-sm text-slate-700">
|
<label className="flex items-start gap-3 text-sm text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="mt-1 h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-200"
|
className="mt-1 h-4 w-4 rounded border-input text-primary focus:ring-ring/30"
|
||||||
checked={resolvedIsGatewayMain}
|
checked={resolvedIsGatewayMain}
|
||||||
onChange={(event) => setIsGatewayMain(event.target.checked)}
|
onChange={(event) => setIsGatewayMain(event.target.checked)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
<span>
|
<span>
|
||||||
<span className="block font-medium text-slate-900">
|
<span className="block font-medium text-foreground">
|
||||||
Gateway main agent
|
Gateway main agent
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-xs text-slate-500">
|
<span className="block text-xs text-muted-foreground">
|
||||||
Uses the gateway main session key and is not tied to a single
|
Uses the gateway main session key and is not tied to a single
|
||||||
board.
|
board.
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -400,12 +400,12 @@ export default function EditAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Personality & behavior
|
Personality & behavior
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Communication style
|
Communication style
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -423,12 +423,12 @@ export default function EditAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Schedule & notifications
|
Schedule & notifications
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Interval
|
Interval
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -437,7 +437,7 @@ export default function EditAgentPage() {
|
||||||
placeholder="e.g. 10m"
|
placeholder="e.g. 10m"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Set how often this agent runs HEARTBEAT.md.
|
Set how often this agent runs HEARTBEAT.md.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -445,7 +445,7 @@ export default function EditAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{errorMessage ? (
|
{errorMessage ? (
|
||||||
<div className="rounded-lg border border-slate-200 bg-white p-3 text-sm text-slate-600 shadow-sm">
|
<div className="rounded-lg border border-border bg-card p-3 text-sm text-muted-foreground shadow-sm">
|
||||||
{errorMessage}
|
{errorMessage}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
||||||
|
|
@ -142,16 +142,16 @@ export default function NewAgentPage() {
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="rounded-xl border border-slate-200 bg-white p-6 shadow-sm space-y-6"
|
className="rounded-xl border border-border bg-card p-6 shadow-sm space-y-6"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Basic configuration
|
Basic configuration
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4 space-y-6">
|
<div className="mt-4 space-y-6">
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Agent name <span className="text-red-500">*</span>
|
Agent name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -162,7 +162,7 @@ export default function NewAgentPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Role
|
Role
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -180,7 +180,7 @@ export default function NewAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Board <span className="text-red-500">*</span>
|
Board <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<SearchableSelect
|
<SearchableSelect
|
||||||
|
|
@ -197,13 +197,13 @@ export default function NewAgentPage() {
|
||||||
disabled={boards.length === 0}
|
disabled={boards.length === 0}
|
||||||
/>
|
/>
|
||||||
{boards.length === 0 ? (
|
{boards.length === 0 ? (
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Create a board before adding agents.
|
Create a board before adding agents.
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Emoji
|
Emoji
|
||||||
</label>
|
</label>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -233,12 +233,12 @@ export default function NewAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Personality & behavior
|
Personality & behavior
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Communication style
|
Communication style
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -256,12 +256,12 @@ export default function NewAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Schedule & notifications
|
Schedule & notifications
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Interval
|
Interval
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -270,7 +270,7 @@ export default function NewAgentPage() {
|
||||||
placeholder="e.g. 10m"
|
placeholder="e.g. 10m"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
How often this agent runs HEARTBEAT.md (10m, 30m, 2h).
|
How often this agent runs HEARTBEAT.md (10m, 30m, 2h).
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -278,7 +278,7 @@ export default function NewAgentPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{errorMessage ? (
|
{errorMessage ? (
|
||||||
<div className="rounded-lg border border-slate-200 bg-white p-3 text-sm text-slate-600 shadow-sm">
|
<div className="rounded-lg border border-border bg-card p-3 text-sm text-muted-foreground shadow-sm">
|
||||||
{errorMessage}
|
{errorMessage}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ export default function AgentsPage() {
|
||||||
adminOnlyMessage="Only organization owners and admins can access agents."
|
adminOnlyMessage="Only organization owners and admins can access agents."
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<AgentsTable
|
<AgentsTable
|
||||||
agents={agents}
|
agents={agents}
|
||||||
boards={boards}
|
boards={boards}
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ function GlobalApprovalsInner() {
|
||||||
}, [errorText, warnings]);
|
}, [errorText, warnings]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex-1 overflow-y-auto bg-gradient-to-br from-slate-50 to-slate-100">
|
<main className="flex-1 overflow-y-auto bg-background">
|
||||||
<div className="p-4 md:p-6">
|
<div className="p-4 md:p-6">
|
||||||
<div className="h-[calc(100vh-160px)] min-h-[300px] sm:min-h-[520px]">
|
<div className="h-[calc(100vh-160px)] min-h-[300px] sm:min-h-[520px]">
|
||||||
<BoardApprovalsPanel
|
<BoardApprovalsPanel
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ export default function EditBoardGroupPage() {
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
|
className="space-y-6 rounded-xl border border-border bg-card p-6 shadow-sm"
|
||||||
>
|
>
|
||||||
{assignFailedCount && Number.isFinite(assignFailedCount) ? (
|
{assignFailedCount && Number.isFinite(assignFailedCount) ? (
|
||||||
<div className="rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-900 shadow-sm">
|
<div className="rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-900 shadow-sm">
|
||||||
|
|
@ -298,7 +298,7 @@ export default function EditBoardGroupPage() {
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Group name <span className="text-red-500">*</span>
|
Group name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -311,7 +311,7 @@ export default function EditBoardGroupPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -323,16 +323,16 @@ export default function EditBoardGroupPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2 border-t border-slate-100 pt-6">
|
<div className="space-y-2 border-t border-border pt-6">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-900">Boards</p>
|
<p className="text-sm font-medium text-foreground">Boards</p>
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
Assign boards to this group to share context across related
|
Assign boards to this group to share context across related
|
||||||
work.
|
work.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs text-slate-500">
|
<span className="text-xs text-muted-foreground">
|
||||||
{selectedBoardIds.size} selected
|
{selectedBoardIds.size} selected
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -344,9 +344,9 @@ export default function EditBoardGroupPage() {
|
||||||
disabled={isLoading || !baseGroup}
|
disabled={isLoading || !baseGroup}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="max-h-64 overflow-auto rounded-xl border border-slate-200 bg-slate-50/40">
|
<div className="max-h-64 overflow-auto rounded-xl border border-border bg-muted/40">
|
||||||
{boardsLoading && boards.length === 0 ? (
|
{boardsLoading && boards.length === 0 ? (
|
||||||
<div className="px-4 py-6 text-sm text-slate-500">
|
<div className="px-4 py-6 text-sm text-muted-foreground">
|
||||||
Loading boards…
|
Loading boards…
|
||||||
</div>
|
</div>
|
||||||
) : boardsError ? (
|
) : boardsError ? (
|
||||||
|
|
@ -354,7 +354,7 @@ export default function EditBoardGroupPage() {
|
||||||
{boardsError.message}
|
{boardsError.message}
|
||||||
</div>
|
</div>
|
||||||
) : boards.length === 0 ? (
|
) : boards.length === 0 ? (
|
||||||
<div className="px-4 py-6 text-sm text-slate-500">
|
<div className="px-4 py-6 text-sm text-muted-foreground">
|
||||||
No boards found.
|
No boards found.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -378,7 +378,7 @@ export default function EditBoardGroupPage() {
|
||||||
<label className="flex cursor-pointer items-start gap-3">
|
<label className="flex cursor-pointer items-start gap-3">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="mt-1 h-4 w-4 rounded border-slate-300 text-blue-600"
|
className="mt-1 h-4 w-4 rounded border-input text-primary"
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setSelectedBoardIds((prev) => {
|
setSelectedBoardIds((prev) => {
|
||||||
|
|
@ -394,11 +394,11 @@ export default function EditBoardGroupPage() {
|
||||||
disabled={isLoading || !baseGroup}
|
disabled={isLoading || !baseGroup}
|
||||||
/>
|
/>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="truncate text-sm font-medium text-slate-900">
|
<p className="truncate text-sm font-medium text-foreground">
|
||||||
{board.name}
|
{board.name}
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-slate-500">
|
<div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||||
<span className="font-mono text-[11px] text-slate-400">
|
<span className="font-mono text-[11px] text-muted-foreground/70">
|
||||||
{board.id}
|
{board.id}
|
||||||
</span>
|
</span>
|
||||||
{isAlreadyGrouped ? (
|
{isAlreadyGrouped ? (
|
||||||
|
|
@ -420,7 +420,7 @@ export default function EditBoardGroupPage() {
|
||||||
<p className="text-sm text-rose-700">{assignmentsError}</p>
|
<p className="text-sm text-rose-700">{assignmentsError}</p>
|
||||||
) : null}
|
) : null}
|
||||||
{assignmentsResult ? (
|
{assignmentsResult ? (
|
||||||
<p className="text-sm text-slate-700">
|
<p className="text-sm text-muted-foreground">
|
||||||
Updated {assignmentsResult.updated} board
|
Updated {assignmentsResult.updated} board
|
||||||
{assignmentsResult.updated === 1 ? "" : "s"}, failed{" "}
|
{assignmentsResult.updated === 1 ? "" : "s"}, failed{" "}
|
||||||
{assignmentsResult.failed}.
|
{assignmentsResult.failed}.
|
||||||
|
|
|
||||||
|
|
@ -78,9 +78,9 @@ const statusTone = (value?: string | null) => {
|
||||||
case "review":
|
case "review":
|
||||||
return "bg-amber-50 text-amber-800 border-amber-200";
|
return "bg-amber-50 text-amber-800 border-amber-200";
|
||||||
case "done":
|
case "done":
|
||||||
return "bg-slate-50 text-slate-600 border-slate-200";
|
return "bg-muted text-muted-foreground border-border";
|
||||||
default:
|
default:
|
||||||
return "bg-blue-50 text-blue-700 border-blue-200";
|
return "bg-primary/10 text-primary border-primary/30";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@ const priorityTone = (value?: string | null) => {
|
||||||
case "high":
|
case "high":
|
||||||
return "bg-rose-50 text-rose-700 border-rose-200";
|
return "bg-rose-50 text-rose-700 border-rose-200";
|
||||||
case "low":
|
case "low":
|
||||||
return "bg-slate-50 text-slate-600 border-slate-200";
|
return "bg-muted text-muted-foreground border-border";
|
||||||
default:
|
default:
|
||||||
return "bg-indigo-50 text-indigo-700 border-indigo-200";
|
return "bg-indigo-50 text-indigo-700 border-indigo-200";
|
||||||
}
|
}
|
||||||
|
|
@ -112,24 +112,24 @@ const canWriteGroupBoards = (
|
||||||
|
|
||||||
function GroupChatMessageCard({ message }: { message: BoardGroupMemoryRead }) {
|
function GroupChatMessageCard({ message }: { message: BoardGroupMemoryRead }) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-2xl border border-slate-200 bg-slate-50/60 p-4">
|
<div className="rounded-2xl border border-border bg-muted/60 p-4">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<p className="text-sm font-semibold text-slate-900">
|
<p className="text-sm font-semibold text-foreground">
|
||||||
{message.source ?? "User"}
|
{message.source ?? "User"}
|
||||||
</p>
|
</p>
|
||||||
<span className="text-xs text-slate-400">
|
<span className="text-xs text-muted-foreground/70">
|
||||||
{formatTimestamp(message.created_at)}
|
{formatTimestamp(message.created_at)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 select-text cursor-text text-sm leading-relaxed text-slate-900 break-words">
|
<div className="mt-2 select-text cursor-text text-sm leading-relaxed text-foreground break-words">
|
||||||
<Markdown content={message.content} variant="basic" />
|
<Markdown content={message.content} variant="basic" />
|
||||||
</div>
|
</div>
|
||||||
{message.tags?.length ? (
|
{message.tags?.length ? (
|
||||||
<div className="mt-3 flex flex-wrap gap-2 text-[11px] text-slate-600">
|
<div className="mt-3 flex flex-wrap gap-2 text-[11px] text-muted-foreground">
|
||||||
{message.tags.map((tag) => (
|
{message.tags.map((tag) => (
|
||||||
<span
|
<span
|
||||||
key={tag}
|
key={tag}
|
||||||
className="rounded-full border border-slate-200 bg-white px-2 py-0.5"
|
className="rounded-full border border-border bg-card px-2 py-0.5"
|
||||||
>
|
>
|
||||||
{tag}
|
{tag}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -749,23 +749,23 @@ export default function BoardGroupDetailPage() {
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
<main className="flex-1 overflow-y-auto bg-slate-50">
|
<main className="flex-1 overflow-y-auto bg-muted">
|
||||||
<div className="sticky top-0 z-30 border-b border-slate-200 bg-white shadow-sm">
|
<div className="sticky top-0 z-30 border-b border-border bg-card shadow-sm">
|
||||||
<div className="px-4 py-4 md:px-8 md:py-6">
|
<div className="px-4 py-4 md:px-8 md:py-6">
|
||||||
<div className="flex flex-wrap items-start justify-between gap-4">
|
<div className="flex flex-wrap items-start justify-between gap-4">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Board group
|
Board group
|
||||||
</p>
|
</p>
|
||||||
<h1 className="mt-2 text-2xl font-semibold tracking-tight text-slate-900">
|
<h1 className="mt-2 text-2xl font-semibold tracking-tight text-foreground">
|
||||||
{group?.name ?? "Group"}
|
{group?.name ?? "Group"}
|
||||||
</h1>
|
</h1>
|
||||||
{group?.description ? (
|
{group?.description ? (
|
||||||
<p className="mt-2 max-w-2xl text-sm text-slate-600">
|
<p className="mt-2 max-w-2xl text-sm text-muted-foreground">
|
||||||
{group.description}
|
{group.description}
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-2 text-sm text-slate-400">
|
<p className="mt-2 text-sm text-muted-foreground/70">
|
||||||
No description
|
No description
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
@ -824,18 +824,18 @@ export default function BoardGroupDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-5 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
|
<div className="mt-5 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
|
||||||
<label className="inline-flex items-center gap-2 text-sm text-slate-700">
|
<label className="inline-flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="h-4 w-4 rounded border-slate-300 text-blue-600"
|
className="h-4 w-4 rounded border-input text-primary"
|
||||||
checked={includeDone}
|
checked={includeDone}
|
||||||
onChange={(event) => setIncludeDone(event.target.checked)}
|
onChange={(event) => setIncludeDone(event.target.checked)}
|
||||||
/>
|
/>
|
||||||
Include done
|
Include done
|
||||||
</label>
|
</label>
|
||||||
<div className="flex items-center gap-2 text-sm text-slate-700">
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
<span className="text-slate-500">Top tasks per board</span>
|
<span className="text-muted-foreground">Top tasks per board</span>
|
||||||
<div className="flex items-center gap-1 rounded-lg border border-slate-200 bg-white p-1">
|
<div className="flex items-center gap-1 rounded-lg border border-border bg-card p-1">
|
||||||
{[0, 3, 5, 10].map((value) => (
|
{[0, 3, 5, 10].map((value) => (
|
||||||
<button
|
<button
|
||||||
key={value}
|
key={value}
|
||||||
|
|
@ -843,8 +843,8 @@ export default function BoardGroupDetailPage() {
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-md px-2.5 py-1 text-xs font-semibold transition-colors",
|
"rounded-md px-2.5 py-1 text-xs font-semibold transition-colors",
|
||||||
perBoardLimit === value
|
perBoardLimit === value
|
||||||
? "bg-slate-900 text-white"
|
? "bg-foreground text-background"
|
||||||
: "text-slate-600 hover:bg-slate-100 hover:text-slate-900",
|
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
||||||
)}
|
)}
|
||||||
onClick={() => setPerBoardLimit(value)}
|
onClick={() => setPerBoardLimit(value)}
|
||||||
>
|
>
|
||||||
|
|
@ -854,9 +854,9 @@ export default function BoardGroupDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2 text-sm text-slate-700">
|
<div className="flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
|
||||||
<span className="text-slate-500">Agent pace</span>
|
<span className="text-muted-foreground">Agent pace</span>
|
||||||
<div className="flex flex-wrap items-center gap-1 rounded-lg border border-slate-200 bg-white p-1">
|
<div className="flex flex-wrap items-center gap-1 rounded-lg border border-border bg-card p-1">
|
||||||
{HEARTBEAT_PRESETS.map((preset) => {
|
{HEARTBEAT_PRESETS.map((preset) => {
|
||||||
const value = `${preset.amount}${preset.unit}`;
|
const value = `${preset.amount}${preset.unit}`;
|
||||||
return (
|
return (
|
||||||
|
|
@ -866,8 +866,8 @@ export default function BoardGroupDetailPage() {
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-md px-2.5 py-1 text-xs font-semibold transition-colors",
|
"rounded-md px-2.5 py-1 text-xs font-semibold transition-colors",
|
||||||
heartbeatEvery === value
|
heartbeatEvery === value
|
||||||
? "bg-slate-900 text-white"
|
? "bg-foreground text-background"
|
||||||
: "text-slate-600 hover:bg-slate-100 hover:text-slate-900",
|
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
||||||
!canManageHeartbeat &&
|
!canManageHeartbeat &&
|
||||||
"opacity-50 cursor-not-allowed",
|
"opacity-50 cursor-not-allowed",
|
||||||
)}
|
)}
|
||||||
|
|
@ -886,9 +886,9 @@ export default function BoardGroupDetailPage() {
|
||||||
value={heartbeatAmount}
|
value={heartbeatAmount}
|
||||||
onChange={(event) => setHeartbeatAmount(event.target.value)}
|
onChange={(event) => setHeartbeatAmount(event.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-8 w-20 rounded-md border bg-white px-2 text-xs text-slate-900 shadow-sm",
|
"h-8 w-20 rounded-md border bg-card px-2 text-xs text-foreground shadow-sm",
|
||||||
heartbeatEvery
|
heartbeatEvery
|
||||||
? "border-slate-200"
|
? "border-border"
|
||||||
: "border-rose-300 focus:border-rose-400 focus:ring-2 focus:ring-rose-100",
|
: "border-rose-300 focus:border-rose-400 focus:ring-2 focus:ring-rose-100",
|
||||||
!canManageHeartbeat && "opacity-60 cursor-not-allowed",
|
!canManageHeartbeat && "opacity-60 cursor-not-allowed",
|
||||||
)}
|
)}
|
||||||
|
|
@ -921,10 +921,10 @@ export default function BoardGroupDetailPage() {
|
||||||
<SelectItem value="d">day</SelectItem>
|
<SelectItem value="d">day</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<label className="inline-flex items-center gap-2 text-xs text-slate-700">
|
<label className="inline-flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="h-4 w-4 rounded border-slate-300 text-blue-600"
|
className="h-4 w-4 rounded border-input text-primary"
|
||||||
checked={includeBoardLeads}
|
checked={includeBoardLeads}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setIncludeBoardLeads(event.target.checked)
|
setIncludeBoardLeads(event.target.checked)
|
||||||
|
|
@ -952,7 +952,7 @@ export default function BoardGroupDetailPage() {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{!canManageHeartbeat ? (
|
{!canManageHeartbeat ? (
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Read-only access. You cannot change agent pace for this
|
Read-only access. You cannot change agent pace for this
|
||||||
group.
|
group.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -969,11 +969,11 @@ export default function BoardGroupDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{heartbeatApplyResult ? (
|
{heartbeatApplyResult ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-4 text-sm text-slate-700 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-4 text-sm text-muted-foreground shadow-sm">
|
||||||
<p className="font-semibold text-slate-900">
|
<p className="font-semibold text-foreground">
|
||||||
Heartbeat applied
|
Heartbeat applied
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-slate-600">
|
<p className="mt-1 text-muted-foreground">
|
||||||
Updated {heartbeatApplyResult.updated_agent_ids.length}{" "}
|
Updated {heartbeatApplyResult.updated_agent_ids.length}{" "}
|
||||||
agents, failed{" "}
|
agents, failed{" "}
|
||||||
{heartbeatApplyResult.failed_agent_ids.length}.
|
{heartbeatApplyResult.failed_agent_ids.length}.
|
||||||
|
|
@ -982,7 +982,7 @@ export default function BoardGroupDetailPage() {
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{snapshotQuery.isLoading ? (
|
{snapshotQuery.isLoading ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-600 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
Loading group snapshot…
|
Loading group snapshot…
|
||||||
</div>
|
</div>
|
||||||
) : snapshotQuery.error ? (
|
) : snapshotQuery.error ? (
|
||||||
|
|
@ -990,7 +990,7 @@ export default function BoardGroupDetailPage() {
|
||||||
{snapshotQuery.error.message}
|
{snapshotQuery.error.message}
|
||||||
</div>
|
</div>
|
||||||
) : boards.length === 0 ? (
|
) : boards.length === 0 ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-600 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
No boards in this group yet. Assign boards from the board
|
No boards in this group yet. Assign boards from the board
|
||||||
settings page.
|
settings page.
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -999,9 +999,9 @@ export default function BoardGroupDetailPage() {
|
||||||
{boards.map((item) => (
|
{boards.map((item) => (
|
||||||
<div
|
<div
|
||||||
key={item.board.id}
|
key={item.board.id}
|
||||||
className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm"
|
className="overflow-hidden rounded-xl border border-border bg-card shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="border-b border-slate-200 px-6 py-4">
|
<div className="border-b border-border px-6 py-4">
|
||||||
<div className="flex items-start justify-between gap-4">
|
<div className="flex items-start justify-between gap-4">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<Link
|
<Link
|
||||||
|
|
@ -1009,17 +1009,17 @@ export default function BoardGroupDetailPage() {
|
||||||
className="group inline-flex items-center gap-2"
|
className="group inline-flex items-center gap-2"
|
||||||
title="Open board"
|
title="Open board"
|
||||||
>
|
>
|
||||||
<p className="truncate text-sm font-semibold text-slate-900 group-hover:text-blue-600">
|
<p className="truncate text-sm font-semibold text-foreground group-hover:text-primary">
|
||||||
{item.board.name}
|
{item.board.name}
|
||||||
</p>
|
</p>
|
||||||
<ArrowUpRight className="h-4 w-4 text-slate-400 group-hover:text-blue-600" />
|
<ArrowUpRight className="h-4 w-4 text-muted-foreground/70 group-hover:text-primary" />
|
||||||
</Link>
|
</Link>
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
Updated {formatTimestamp(item.board.updated_at)}
|
Updated {formatTimestamp(item.board.updated_at)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap items-center justify-end gap-2 text-xs">
|
<div className="flex flex-wrap items-center justify-end gap-2 text-xs">
|
||||||
<span className="rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5 text-slate-700">
|
<span className="rounded-full border border-border bg-muted px-2 py-0.5 text-muted-foreground">
|
||||||
Inbox {safeCount(item, "inbox")}
|
Inbox {safeCount(item, "inbox")}
|
||||||
</span>
|
</span>
|
||||||
<span className="rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-emerald-800">
|
<span className="rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-emerald-800">
|
||||||
|
|
@ -1042,7 +1042,7 @@ export default function BoardGroupDetailPage() {
|
||||||
pathname: `/boards/${item.board.id}`,
|
pathname: `/boards/${item.board.id}`,
|
||||||
query: { taskId: task.id },
|
query: { taskId: task.id },
|
||||||
}}
|
}}
|
||||||
className="block rounded-lg border border-slate-200 bg-slate-50/40 p-3 transition hover:border-blue-200 hover:bg-blue-50/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
className="block rounded-lg border border-border bg-muted/40 p-3 transition hover:border-primary/30 hover:bg-primary/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||||
title="Open task on board"
|
title="Open task on board"
|
||||||
>
|
>
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
|
|
@ -1063,22 +1063,22 @@ export default function BoardGroupDetailPage() {
|
||||||
>
|
>
|
||||||
{task.priority}
|
{task.priority}
|
||||||
</span>
|
</span>
|
||||||
<p className="truncate text-sm font-medium text-slate-900">
|
<p className="truncate text-sm font-medium text-foreground">
|
||||||
{task.title}
|
{task.title}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
{formatTimestamp(task.updated_at)}
|
{formatTimestamp(task.updated_at)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex flex-wrap items-center justify-between gap-2 text-xs text-slate-600">
|
<div className="mt-2 flex flex-wrap items-center justify-between gap-2 text-xs text-muted-foreground">
|
||||||
<p className="truncate">
|
<p className="truncate">
|
||||||
Assignee:{" "}
|
Assignee:{" "}
|
||||||
<span className="font-medium text-slate-900">
|
<span className="font-medium text-foreground">
|
||||||
{task.assignee ?? "Unassigned"}
|
{task.assignee ?? "Unassigned"}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p className="font-mono text-[11px] text-slate-400">
|
<p className="font-mono text-[11px] text-muted-foreground/70">
|
||||||
{task.id}
|
{task.id}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1087,7 +1087,7 @@ export default function BoardGroupDetailPage() {
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-slate-500">
|
<p className="text-sm text-muted-foreground">
|
||||||
No tasks in this snapshot.
|
No tasks in this snapshot.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1102,7 +1102,7 @@ export default function BoardGroupDetailPage() {
|
||||||
</SignedIn>
|
</SignedIn>
|
||||||
{isChatOpen || isNotesOpen ? (
|
{isChatOpen || isNotesOpen ? (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-40 bg-slate-900/20"
|
className="fixed inset-0 z-40 bg-foreground/20"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsChatOpen(false);
|
setIsChatOpen(false);
|
||||||
setChatError(null);
|
setChatError(null);
|
||||||
|
|
@ -1113,17 +1113,17 @@ export default function BoardGroupDetailPage() {
|
||||||
) : null}
|
) : null}
|
||||||
<aside
|
<aside
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed right-0 top-0 z-50 h-full w-[560px] max-w-[96vw] transform border-l border-slate-200 bg-white shadow-2xl transition-transform",
|
"fixed right-0 top-0 z-50 h-full w-[560px] max-w-[96vw] transform border-l border-border bg-card shadow-2xl transition-transform",
|
||||||
isChatOpen ? "transform-none" : "translate-x-full",
|
isChatOpen ? "transform-none" : "translate-x-full",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
<div className="flex items-center justify-between border-b border-slate-200 px-6 py-4">
|
<div className="flex items-center justify-between border-b border-border px-6 py-4">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Group chat
|
Group chat
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 truncate text-sm font-medium text-slate-900">
|
<p className="mt-1 truncate text-sm font-medium text-foreground">
|
||||||
Shared across linked boards. Tag @lead, @name, or @all.
|
Shared across linked boards. Tag @lead, @name, or @all.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1133,7 +1133,7 @@ export default function BoardGroupDetailPage() {
|
||||||
setIsChatOpen(false);
|
setIsChatOpen(false);
|
||||||
setChatError(null);
|
setChatError(null);
|
||||||
}}
|
}}
|
||||||
className="rounded-lg border border-slate-200 p-2 text-slate-500 transition hover:bg-slate-50"
|
className="rounded-lg border border-border p-2 text-muted-foreground transition hover:bg-muted"
|
||||||
aria-label="Close group chat"
|
aria-label="Close group chat"
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
|
|
@ -1141,24 +1141,24 @@ export default function BoardGroupDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-1 flex-col overflow-hidden px-6 py-4">
|
<div className="flex flex-1 flex-col overflow-hidden px-6 py-4">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3 pb-3">
|
<div className="flex flex-wrap items-center justify-between gap-3 pb-3">
|
||||||
<label className="inline-flex items-center gap-2 text-sm text-slate-700">
|
<label className="inline-flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="h-4 w-4 rounded border-slate-300 text-blue-600"
|
className="h-4 w-4 rounded border-input text-primary"
|
||||||
checked={chatBroadcast}
|
checked={chatBroadcast}
|
||||||
onChange={(event) => setChatBroadcast(event.target.checked)}
|
onChange={(event) => setChatBroadcast(event.target.checked)}
|
||||||
disabled={!canWriteGroup}
|
disabled={!canWriteGroup}
|
||||||
/>
|
/>
|
||||||
Broadcast
|
Broadcast
|
||||||
</label>
|
</label>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
{chatBroadcast
|
{chatBroadcast
|
||||||
? "Notifies every agent in the group."
|
? "Notifies every agent in the group."
|
||||||
: "Notifies leads + mentions."}
|
: "Notifies leads + mentions."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 space-y-4 overflow-y-auto rounded-2xl border border-slate-200 bg-white p-4">
|
<div className="flex-1 space-y-4 overflow-y-auto rounded-2xl border border-border bg-card p-4">
|
||||||
{chatHistoryQuery.error ? (
|
{chatHistoryQuery.error ? (
|
||||||
<div className="rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
|
<div className="rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
|
||||||
{chatHistoryQuery.error.message}
|
{chatHistoryQuery.error.message}
|
||||||
|
|
@ -1170,9 +1170,9 @@ export default function BoardGroupDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{chatHistoryQuery.isLoading && chatMessages.length === 0 ? (
|
{chatHistoryQuery.isLoading && chatMessages.length === 0 ? (
|
||||||
<p className="text-sm text-slate-500">Loading…</p>
|
<p className="text-sm text-muted-foreground">Loading…</p>
|
||||||
) : chatMessages.length === 0 ? (
|
) : chatMessages.length === 0 ? (
|
||||||
<p className="text-sm text-slate-500">
|
<p className="text-sm text-muted-foreground">
|
||||||
No messages yet. Start the conversation with a broadcast or a
|
No messages yet. Start the conversation with a broadcast or a
|
||||||
mention.
|
mention.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -1200,17 +1200,17 @@ export default function BoardGroupDetailPage() {
|
||||||
</aside>
|
</aside>
|
||||||
<aside
|
<aside
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed right-0 top-0 z-50 h-full w-[560px] max-w-[96vw] transform border-l border-slate-200 bg-white shadow-2xl transition-transform",
|
"fixed right-0 top-0 z-50 h-full w-[560px] max-w-[96vw] transform border-l border-border bg-card shadow-2xl transition-transform",
|
||||||
isNotesOpen ? "transform-none" : "translate-x-full",
|
isNotesOpen ? "transform-none" : "translate-x-full",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
<div className="flex items-center justify-between border-b border-slate-200 px-6 py-4">
|
<div className="flex items-center justify-between border-b border-border px-6 py-4">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Group notes
|
Group notes
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 truncate text-sm font-medium text-slate-900">
|
<p className="mt-1 truncate text-sm font-medium text-foreground">
|
||||||
Shared across linked boards. Tag @lead, @name, or @all.
|
Shared across linked boards. Tag @lead, @name, or @all.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1220,7 +1220,7 @@ export default function BoardGroupDetailPage() {
|
||||||
setIsNotesOpen(false);
|
setIsNotesOpen(false);
|
||||||
setNoteSendError(null);
|
setNoteSendError(null);
|
||||||
}}
|
}}
|
||||||
className="rounded-lg border border-slate-200 p-2 text-slate-500 transition hover:bg-slate-50"
|
className="rounded-lg border border-border p-2 text-muted-foreground transition hover:bg-muted"
|
||||||
aria-label="Close group notes"
|
aria-label="Close group notes"
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
|
|
@ -1228,24 +1228,24 @@ export default function BoardGroupDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-1 flex-col overflow-hidden px-6 py-4">
|
<div className="flex flex-1 flex-col overflow-hidden px-6 py-4">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3 pb-3">
|
<div className="flex flex-wrap items-center justify-between gap-3 pb-3">
|
||||||
<label className="inline-flex items-center gap-2 text-sm text-slate-700">
|
<label className="inline-flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="h-4 w-4 rounded border-slate-300 text-blue-600"
|
className="h-4 w-4 rounded border-input text-primary"
|
||||||
checked={notesBroadcast}
|
checked={notesBroadcast}
|
||||||
onChange={(event) => setNotesBroadcast(event.target.checked)}
|
onChange={(event) => setNotesBroadcast(event.target.checked)}
|
||||||
disabled={!canWriteGroup}
|
disabled={!canWriteGroup}
|
||||||
/>
|
/>
|
||||||
Broadcast
|
Broadcast
|
||||||
</label>
|
</label>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
{notesBroadcast
|
{notesBroadcast
|
||||||
? "Notifies every agent in the group."
|
? "Notifies every agent in the group."
|
||||||
: "Notifies leads + mentions."}
|
: "Notifies leads + mentions."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 space-y-4 overflow-y-auto rounded-2xl border border-slate-200 bg-white p-4">
|
<div className="flex-1 space-y-4 overflow-y-auto rounded-2xl border border-border bg-card p-4">
|
||||||
{notesHistoryQuery.error ? (
|
{notesHistoryQuery.error ? (
|
||||||
<div className="rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
|
<div className="rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
|
||||||
{notesHistoryQuery.error.message}
|
{notesHistoryQuery.error.message}
|
||||||
|
|
@ -1257,9 +1257,9 @@ export default function BoardGroupDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{notesHistoryQuery.isLoading && notesMessages.length === 0 ? (
|
{notesHistoryQuery.isLoading && notesMessages.length === 0 ? (
|
||||||
<p className="text-sm text-slate-500">Loading…</p>
|
<p className="text-sm text-muted-foreground">Loading…</p>
|
||||||
) : notesMessages.length === 0 ? (
|
) : notesMessages.length === 0 ? (
|
||||||
<p className="text-sm text-slate-500">
|
<p className="text-sm text-muted-foreground">
|
||||||
No notes yet. Post a note or a broadcast to share context
|
No notes yet. Post a note or a broadcast to share context
|
||||||
across boards.
|
across boards.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -133,11 +133,11 @@ export default function NewBoardGroupPage() {
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
|
className="space-y-6 rounded-xl border border-border bg-card p-6 shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Group name <span className="text-red-500">*</span>
|
Group name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -150,7 +150,7 @@ export default function NewBoardGroupPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -164,8 +164,8 @@ export default function NewBoardGroupPage() {
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<label className="text-sm font-medium text-slate-900">Boards</label>
|
<label className="text-sm font-medium text-foreground">Boards</label>
|
||||||
<span className="text-xs text-slate-500">
|
<span className="text-xs text-muted-foreground">
|
||||||
{selectedBoardIds.size} selected
|
{selectedBoardIds.size} selected
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -175,9 +175,9 @@ export default function NewBoardGroupPage() {
|
||||||
placeholder="Search boards..."
|
placeholder="Search boards..."
|
||||||
disabled={isCreating}
|
disabled={isCreating}
|
||||||
/>
|
/>
|
||||||
<div className="max-h-64 overflow-auto rounded-xl border border-slate-200 bg-slate-50/40">
|
<div className="max-h-64 overflow-auto rounded-xl border border-border bg-muted/40">
|
||||||
{boardsQuery.isLoading ? (
|
{boardsQuery.isLoading ? (
|
||||||
<div className="px-4 py-6 text-sm text-slate-500">
|
<div className="px-4 py-6 text-sm text-muted-foreground">
|
||||||
Loading boards…
|
Loading boards…
|
||||||
</div>
|
</div>
|
||||||
) : boardsQuery.error ? (
|
) : boardsQuery.error ? (
|
||||||
|
|
@ -185,7 +185,7 @@ export default function NewBoardGroupPage() {
|
||||||
{boardsQuery.error.message}
|
{boardsQuery.error.message}
|
||||||
</div>
|
</div>
|
||||||
) : boards.length === 0 ? (
|
) : boards.length === 0 ? (
|
||||||
<div className="px-4 py-6 text-sm text-slate-500">
|
<div className="px-4 py-6 text-sm text-muted-foreground">
|
||||||
No boards found.
|
No boards found.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -207,7 +207,7 @@ export default function NewBoardGroupPage() {
|
||||||
<label className="flex cursor-pointer items-start gap-3">
|
<label className="flex cursor-pointer items-start gap-3">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="mt-1 h-4 w-4 rounded border-slate-300 text-blue-600"
|
className="mt-1 h-4 w-4 rounded border-input text-primary"
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setSelectedBoardIds((prev) => {
|
setSelectedBoardIds((prev) => {
|
||||||
|
|
@ -223,11 +223,11 @@ export default function NewBoardGroupPage() {
|
||||||
disabled={isCreating}
|
disabled={isCreating}
|
||||||
/>
|
/>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="truncate text-sm font-medium text-slate-900">
|
<p className="truncate text-sm font-medium text-foreground">
|
||||||
{board.name}
|
{board.name}
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-slate-500">
|
<div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||||
<span className="font-mono text-[11px] text-slate-400">
|
<span className="font-mono text-[11px] text-muted-foreground/70">
|
||||||
{board.id}
|
{board.id}
|
||||||
</span>
|
</span>
|
||||||
{isAlreadyGrouped ? (
|
{isAlreadyGrouped ? (
|
||||||
|
|
@ -244,7 +244,7 @@ export default function NewBoardGroupPage() {
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Optional. Selected boards will be assigned to this group after
|
Optional. Selected boards will be assigned to this group after
|
||||||
creation. You can change membership later in group edit or board
|
creation. You can change membership later in group edit or board
|
||||||
settings.
|
settings.
|
||||||
|
|
@ -267,11 +267,11 @@ export default function NewBoardGroupPage() {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-t border-slate-100 pt-4 text-xs text-slate-500">
|
<div className="border-t border-border pt-4 text-xs text-muted-foreground">
|
||||||
Want to assign boards later? Update each board in{" "}
|
Want to assign boards later? Update each board in{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/boards"
|
href="/boards"
|
||||||
className="font-medium text-blue-600 hover:text-blue-700"
|
className="font-medium text-primary hover:text-primary"
|
||||||
>
|
>
|
||||||
Boards
|
Boards
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export default function BoardGroupsPage() {
|
||||||
}
|
}
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<BoardGroupsTable
|
<BoardGroupsTable
|
||||||
groups={groups}
|
groups={groups}
|
||||||
isLoading={groupsQuery.isLoading}
|
isLoading={groupsQuery.isLoading}
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ export function TaskCustomFieldsEditor({
|
||||||
emptyMessage = "No custom fields configured for this board.",
|
emptyMessage = "No custom fields configured for this board.",
|
||||||
}: TaskCustomFieldsEditorProps) {
|
}: TaskCustomFieldsEditorProps) {
|
||||||
if (isLoading)
|
if (isLoading)
|
||||||
return <p className="text-xs text-slate-500">{loadingMessage}</p>;
|
return <p className="text-xs text-muted-foreground">{loadingMessage}</p>;
|
||||||
if (definitions.length === 0) {
|
if (definitions.length === 0) {
|
||||||
return <p className="text-xs text-slate-500">{emptyMessage}</p>;
|
return <p className="text-xs text-muted-foreground">{emptyMessage}</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -51,7 +51,7 @@ export function TaskCustomFieldsEditor({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={definition.id} className="space-y-1">
|
<div key={definition.id} className="space-y-1">
|
||||||
<label className="text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
<label className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
|
||||||
{definition.label || definition.field_key}
|
{definition.label || definition.field_key}
|
||||||
{definition.required === true ? (
|
{definition.required === true ? (
|
||||||
<span className="ml-1 text-rose-600">*</span>
|
<span className="ml-1 text-rose-600">*</span>
|
||||||
|
|
@ -145,7 +145,7 @@ export function TaskCustomFieldsEditor({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{definition.description ? (
|
{definition.description ? (
|
||||||
<p className="text-xs text-slate-500">{definition.description}</p>
|
<p className="text-xs text-muted-foreground">{definition.description}</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export default function BoardApprovalsPage() {
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
<main className="flex-1 overflow-y-auto bg-gradient-to-br from-slate-50 to-slate-100">
|
<main className="flex-1 overflow-y-auto bg-background">
|
||||||
<div className="p-4 md:p-6">
|
<div className="p-4 md:p-6">
|
||||||
{boardId ? (
|
{boardId ? (
|
||||||
<div className="h-[calc(100vh-160px)] min-h-[300px] sm:min-h-[520px]">
|
<div className="h-[calc(100vh-160px)] min-h-[300px] sm:min-h-[520px]">
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ export const formatCustomFieldDetailValue = (
|
||||||
href={parsedUrl.toString()}
|
href={parsedUrl.toString()}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="inline-flex items-center gap-1 text-blue-700 underline decoration-blue-300 underline-offset-2 hover:text-blue-800"
|
className="inline-flex items-center gap-1 text-primary underline decoration-primary/40 underline-offset-2 hover:text-primary"
|
||||||
>
|
>
|
||||||
<span className="break-all">{parsedUrl.toString()}</span>
|
<span className="break-all">{parsedUrl.toString()}</span>
|
||||||
<ArrowUpRight className="h-3.5 w-3.5 flex-shrink-0" />
|
<ArrowUpRight className="h-3.5 w-3.5 flex-shrink-0" />
|
||||||
|
|
@ -157,7 +157,7 @@ export const formatCustomFieldDetailValue = (
|
||||||
try {
|
try {
|
||||||
const normalized = typeof value === "string" ? JSON.parse(value) : value;
|
const normalized = typeof value === "string" ? JSON.parse(value) : value;
|
||||||
return (
|
return (
|
||||||
<pre className="whitespace-pre-wrap break-words rounded border border-slate-200 bg-white px-2 py-1 font-mono text-xs leading-relaxed text-slate-800">
|
<pre className="whitespace-pre-wrap break-words rounded border border-border bg-card px-2 py-1 font-mono text-xs leading-relaxed text-foreground">
|
||||||
{JSON.stringify(normalized, null, 2)}
|
{JSON.stringify(normalized, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -137,10 +137,10 @@ function WebhookCard({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={webhook.id}
|
key={webhook.id}
|
||||||
className="space-y-3 rounded-lg border border-slate-200 px-4 py-4"
|
className="space-y-3 rounded-lg border border-border px-4 py-4"
|
||||||
>
|
>
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
Webhook {webhook.id.slice(0, 8)}
|
Webhook {webhook.id.slice(0, 8)}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|
@ -218,7 +218,7 @@ function WebhookCard({
|
||||||
disabled={isBusy}
|
disabled={isBusy}
|
||||||
/>
|
/>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">Agent</label>
|
<label className="text-sm font-medium text-foreground">Agent</label>
|
||||||
<Select
|
<Select
|
||||||
value={draftAgentValue}
|
value={draftAgentValue}
|
||||||
onValueChange={setDraftAgentValue}
|
onValueChange={setDraftAgentValue}
|
||||||
|
|
@ -243,19 +243,19 @@ function WebhookCard({
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="text-sm text-slate-700">
|
<div className="text-sm text-muted-foreground">
|
||||||
<Markdown
|
<Markdown
|
||||||
content={webhook.description || ""}
|
content={webhook.description || ""}
|
||||||
variant="description"
|
variant="description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-600">
|
<p className="text-xs text-muted-foreground">
|
||||||
Recipient: {mappedAgent?.name ?? "Lead agent"}
|
Recipient: {mappedAgent?.name ?? "Lead agent"}
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="rounded-md bg-slate-50 px-3 py-2">
|
<div className="rounded-md bg-muted px-3 py-2">
|
||||||
<code className="break-all text-xs text-slate-700">
|
<code className="break-all text-xs text-muted-foreground">
|
||||||
{webhook.endpoint_url ?? webhook.endpoint_path}
|
{webhook.endpoint_url ?? webhook.endpoint_path}
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -770,7 +770,7 @@ export default function EditBoardPage() {
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
|
className="space-y-6 rounded-xl border border-border bg-card p-6 shadow-sm"
|
||||||
>
|
>
|
||||||
{resolvedBoardType !== "general" &&
|
{resolvedBoardType !== "general" &&
|
||||||
baseBoard &&
|
baseBoard &&
|
||||||
|
|
@ -796,7 +796,7 @@ export default function EditBoardPage() {
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Board name <span className="text-red-500">*</span>
|
Board name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -807,7 +807,7 @@ export default function EditBoardPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Gateway <span className="text-red-500">*</span>
|
Gateway <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<SearchableSelect
|
<SearchableSelect
|
||||||
|
|
@ -827,7 +827,7 @@ export default function EditBoardPage() {
|
||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Board type
|
Board type
|
||||||
</label>
|
</label>
|
||||||
<Select value={resolvedBoardType} onValueChange={setBoardType}>
|
<Select value={resolvedBoardType} onValueChange={setBoardType}>
|
||||||
|
|
@ -840,7 +840,7 @@ export default function EditBoardPage() {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<div className="space-y-2 pt-1">
|
<div className="space-y-2 pt-1">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Max worker agents
|
Max worker agents
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -861,7 +861,7 @@ export default function EditBoardPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Board group
|
Board group
|
||||||
</label>
|
</label>
|
||||||
<SearchableSelect
|
<SearchableSelect
|
||||||
|
|
@ -877,14 +877,14 @@ export default function EditBoardPage() {
|
||||||
itemClassName="px-4 py-3"
|
itemClassName="px-4 py-3"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Boards in the same group can share cross-board context for
|
Boards in the same group can share cross-board context for
|
||||||
agents.
|
agents.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{resolvedBoardType !== "general" ? (
|
{resolvedBoardType !== "general" ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Target date
|
Target date
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -898,7 +898,7 @@ export default function EditBoardPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Description <span className="text-red-500">*</span>
|
Description <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -913,7 +913,7 @@ export default function EditBoardPage() {
|
||||||
{resolvedBoardType !== "general" ? (
|
{resolvedBoardType !== "general" ? (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Objective
|
Objective
|
||||||
{isGoalFieldsRequired && (
|
{isGoalFieldsRequired && (
|
||||||
<span className="text-red-500"> *</span>
|
<span className="text-red-500"> *</span>
|
||||||
|
|
@ -929,7 +929,7 @@ export default function EditBoardPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Success metrics (JSON)
|
Success metrics (JSON)
|
||||||
{isGoalFieldsRequired && (
|
{isGoalFieldsRequired && (
|
||||||
<span className="text-red-500"> *</span>
|
<span className="text-red-500"> *</span>
|
||||||
|
|
@ -942,7 +942,7 @@ export default function EditBoardPage() {
|
||||||
className="min-h-[140px] font-mono text-xs"
|
className="min-h-[140px] font-mono text-xs"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Add key outcomes so the lead agent can measure progress.
|
Add key outcomes so the lead agent can measure progress.
|
||||||
</p>
|
</p>
|
||||||
{metricsError ? (
|
{metricsError ? (
|
||||||
|
|
@ -952,16 +952,16 @@ export default function EditBoardPage() {
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<section className="space-y-3 border-t border-slate-200 pt-4">
|
<section className="space-y-3 border-t border-border pt-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-base font-semibold text-slate-900">
|
<h2 className="text-base font-semibold text-foreground">
|
||||||
Rules
|
Rules
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xs text-slate-600">
|
<p className="text-xs text-muted-foreground">
|
||||||
Configure board-level workflow enforcement.
|
Configure board-level workflow enforcement.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-3 rounded-lg border border-slate-200 px-3 py-3">
|
<div className="flex items-start gap-3 rounded-lg border border-border px-3 py-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|
@ -974,11 +974,11 @@ export default function EditBoardPage() {
|
||||||
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
||||||
resolvedRequireApprovalForDone
|
resolvedRequireApprovalForDone
|
||||||
? "border-emerald-600 bg-emerald-600"
|
? "border-emerald-600 bg-emerald-600"
|
||||||
: "border-slate-300 bg-slate-200"
|
: "border-input bg-border"
|
||||||
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`inline-block h-5 w-5 rounded-full bg-white shadow-sm transition ${
|
className={`inline-block h-5 w-5 rounded-full bg-card shadow-sm transition ${
|
||||||
resolvedRequireApprovalForDone
|
resolvedRequireApprovalForDone
|
||||||
? "translate-x-5"
|
? "translate-x-5"
|
||||||
: "translate-x-0.5"
|
: "translate-x-0.5"
|
||||||
|
|
@ -986,17 +986,17 @@ export default function EditBoardPage() {
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<span className="space-y-1">
|
<span className="space-y-1">
|
||||||
<span className="block text-sm font-medium text-slate-900">
|
<span className="block text-sm font-medium text-foreground">
|
||||||
Require approval
|
Require approval
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-xs text-slate-600">
|
<span className="block text-xs text-muted-foreground">
|
||||||
Require at least one linked approval in{" "}
|
Require at least one linked approval in{" "}
|
||||||
<code>approved</code> state before a task can be marked{" "}
|
<code>approved</code> state before a task can be marked{" "}
|
||||||
<code>done</code>.
|
<code>done</code>.
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-3 rounded-lg border border-slate-200 px-3 py-3">
|
<div className="flex items-start gap-3 rounded-lg border border-border px-3 py-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|
@ -1009,11 +1009,11 @@ export default function EditBoardPage() {
|
||||||
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
||||||
resolvedRequireReviewBeforeDone
|
resolvedRequireReviewBeforeDone
|
||||||
? "border-emerald-600 bg-emerald-600"
|
? "border-emerald-600 bg-emerald-600"
|
||||||
: "border-slate-300 bg-slate-200"
|
: "border-input bg-border"
|
||||||
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`inline-block h-5 w-5 rounded-full bg-white shadow-sm transition ${
|
className={`inline-block h-5 w-5 rounded-full bg-card shadow-sm transition ${
|
||||||
resolvedRequireReviewBeforeDone
|
resolvedRequireReviewBeforeDone
|
||||||
? "translate-x-5"
|
? "translate-x-5"
|
||||||
: "translate-x-0.5"
|
: "translate-x-0.5"
|
||||||
|
|
@ -1021,16 +1021,16 @@ export default function EditBoardPage() {
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<span className="space-y-1">
|
<span className="space-y-1">
|
||||||
<span className="block text-sm font-medium text-slate-900">
|
<span className="block text-sm font-medium text-foreground">
|
||||||
Require review before done
|
Require review before done
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-xs text-slate-600">
|
<span className="block text-xs text-muted-foreground">
|
||||||
Tasks must move to <code>review</code> before they can be
|
Tasks must move to <code>review</code> before they can be
|
||||||
marked <code>done</code>.
|
marked <code>done</code>.
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-3 rounded-lg border border-slate-200 px-3 py-3">
|
<div className="flex items-start gap-3 rounded-lg border border-border px-3 py-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|
@ -1045,11 +1045,11 @@ export default function EditBoardPage() {
|
||||||
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
||||||
resolvedCommentRequiredForReview
|
resolvedCommentRequiredForReview
|
||||||
? "border-emerald-600 bg-emerald-600"
|
? "border-emerald-600 bg-emerald-600"
|
||||||
: "border-slate-300 bg-slate-200"
|
: "border-input bg-border"
|
||||||
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`inline-block h-5 w-5 rounded-full bg-white shadow-sm transition ${
|
className={`inline-block h-5 w-5 rounded-full bg-card shadow-sm transition ${
|
||||||
resolvedCommentRequiredForReview
|
resolvedCommentRequiredForReview
|
||||||
? "translate-x-5"
|
? "translate-x-5"
|
||||||
: "translate-x-0.5"
|
: "translate-x-0.5"
|
||||||
|
|
@ -1057,16 +1057,16 @@ export default function EditBoardPage() {
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<span className="space-y-1">
|
<span className="space-y-1">
|
||||||
<span className="block text-sm font-medium text-slate-900">
|
<span className="block text-sm font-medium text-foreground">
|
||||||
Require comment for review
|
Require comment for review
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-xs text-slate-600">
|
<span className="block text-xs text-muted-foreground">
|
||||||
Require a task comment when moving status to{" "}
|
Require a task comment when moving status to{" "}
|
||||||
<code>review</code>.
|
<code>review</code>.
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-3 rounded-lg border border-slate-200 px-3 py-3">
|
<div className="flex items-start gap-3 rounded-lg border border-border px-3 py-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|
@ -1081,11 +1081,11 @@ export default function EditBoardPage() {
|
||||||
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
||||||
resolvedBlockStatusChangesWithPendingApproval
|
resolvedBlockStatusChangesWithPendingApproval
|
||||||
? "border-emerald-600 bg-emerald-600"
|
? "border-emerald-600 bg-emerald-600"
|
||||||
: "border-slate-300 bg-slate-200"
|
: "border-input bg-border"
|
||||||
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`inline-block h-5 w-5 rounded-full bg-white shadow-sm transition ${
|
className={`inline-block h-5 w-5 rounded-full bg-card shadow-sm transition ${
|
||||||
resolvedBlockStatusChangesWithPendingApproval
|
resolvedBlockStatusChangesWithPendingApproval
|
||||||
? "translate-x-5"
|
? "translate-x-5"
|
||||||
: "translate-x-0.5"
|
: "translate-x-0.5"
|
||||||
|
|
@ -1093,16 +1093,16 @@ export default function EditBoardPage() {
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<span className="space-y-1">
|
<span className="space-y-1">
|
||||||
<span className="block text-sm font-medium text-slate-900">
|
<span className="block text-sm font-medium text-foreground">
|
||||||
Block status changes with pending approval
|
Block status changes with pending approval
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-xs text-slate-600">
|
<span className="block text-xs text-muted-foreground">
|
||||||
Prevent status transitions while any linked approval is in{" "}
|
Prevent status transitions while any linked approval is in{" "}
|
||||||
<code>pending</code> state.
|
<code>pending</code> state.
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-3 rounded-lg border border-slate-200 px-3 py-3">
|
<div className="flex items-start gap-3 rounded-lg border border-border px-3 py-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|
@ -1115,11 +1115,11 @@ export default function EditBoardPage() {
|
||||||
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
className={`mt-0.5 inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
||||||
resolvedOnlyLeadCanChangeStatus
|
resolvedOnlyLeadCanChangeStatus
|
||||||
? "border-emerald-600 bg-emerald-600"
|
? "border-emerald-600 bg-emerald-600"
|
||||||
: "border-slate-300 bg-slate-200"
|
: "border-input bg-border"
|
||||||
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`inline-block h-5 w-5 rounded-full bg-white shadow-sm transition ${
|
className={`inline-block h-5 w-5 rounded-full bg-card shadow-sm transition ${
|
||||||
resolvedOnlyLeadCanChangeStatus
|
resolvedOnlyLeadCanChangeStatus
|
||||||
? "translate-x-5"
|
? "translate-x-5"
|
||||||
: "translate-x-0.5"
|
: "translate-x-0.5"
|
||||||
|
|
@ -1127,10 +1127,10 @@ export default function EditBoardPage() {
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<span className="space-y-1">
|
<span className="space-y-1">
|
||||||
<span className="block text-sm font-medium text-slate-900">
|
<span className="block text-sm font-medium text-foreground">
|
||||||
Only lead can change status
|
Only lead can change status
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-xs text-slate-600">
|
<span className="block text-xs text-muted-foreground">
|
||||||
Restrict status changes to the board lead.
|
Restrict status changes to the board lead.
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -1138,7 +1138,7 @@ export default function EditBoardPage() {
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{gateways.length === 0 ? (
|
{gateways.length === 0 ? (
|
||||||
<div className="rounded-lg border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
|
<div className="rounded-lg border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
<p>
|
<p>
|
||||||
No gateways available. Create one in Gateways to continue.
|
No gateways available. Create one in Gateways to continue.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -1166,18 +1166,18 @@ export default function EditBoardPage() {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section className="space-y-4 border-t border-slate-200 pt-4">
|
<section className="space-y-4 border-t border-border pt-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-base font-semibold text-slate-900">
|
<h2 className="text-base font-semibold text-foreground">
|
||||||
Webhooks
|
Webhooks
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xs text-slate-600">
|
<p className="text-xs text-muted-foreground">
|
||||||
Add inbound webhook endpoints so the lead agent can react to
|
Add inbound webhook endpoints so the lead agent can react to
|
||||||
external events.
|
external events.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-3 rounded-lg border border-slate-200 px-4 py-4">
|
<div className="space-y-3 rounded-lg border border-border px-4 py-4">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Lead agent instruction
|
Lead agent instruction
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -1190,7 +1190,7 @@ export default function EditBoardPage() {
|
||||||
disabled={isLoading || isWebhookBusy}
|
disabled={isLoading || isWebhookBusy}
|
||||||
/>
|
/>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Agent
|
Agent
|
||||||
</label>
|
</label>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -1237,11 +1237,11 @@ export default function EditBoardPage() {
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{webhooksQuery.isLoading ? (
|
{webhooksQuery.isLoading ? (
|
||||||
<p className="text-sm text-slate-500">Loading webhooks…</p>
|
<p className="text-sm text-muted-foreground">Loading webhooks…</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{!webhooksQuery.isLoading && webhooks.length === 0 ? (
|
{!webhooksQuery.isLoading && webhooks.length === 0 ? (
|
||||||
<p className="rounded-lg border border-dashed border-slate-300 px-4 py-3 text-sm text-slate-600">
|
<p className="rounded-lg border border-dashed border-input px-4 py-3 text-sm text-muted-foreground">
|
||||||
No webhooks configured yet.
|
No webhooks configured yet.
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
@ -1282,7 +1282,7 @@ export default function EditBoardPage() {
|
||||||
<DialogClose asChild>
|
<DialogClose asChild>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="sticky top-4 z-10 ml-auto rounded-lg border border-slate-200 bg-[color:var(--surface)] p-2 text-slate-500 transition hover:bg-slate-50"
|
className="sticky top-4 z-10 ml-auto rounded-lg border border-border bg-[color:var(--surface)] p-2 text-muted-foreground transition hover:bg-muted"
|
||||||
aria-label="Close onboarding"
|
aria-label="Close onboarding"
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
|
|
@ -1295,7 +1295,7 @@ export default function EditBoardPage() {
|
||||||
onConfirmed={handleOnboardingConfirmed}
|
onConfirmed={handleOnboardingConfirmed}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-600">
|
<div className="rounded-lg border border-border bg-muted p-3 text-sm text-muted-foreground">
|
||||||
Unable to start onboarding.
|
Unable to start onboarding.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -111,13 +111,13 @@ export default function WebhookPayloadsPage() {
|
||||||
isAdmin={isAdmin}
|
isAdmin={isAdmin}
|
||||||
adminOnlyMessage="Only organization owners and admins can view webhook payloads."
|
adminOnlyMessage="Only organization owners and admins can view webhook payloads."
|
||||||
>
|
>
|
||||||
<div className="space-y-4 rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
<div className="space-y-4 rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<h2 className="text-base font-semibold text-slate-900">
|
<h2 className="text-base font-semibold text-foreground">
|
||||||
{payloadTitle}
|
{payloadTitle}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-slate-600">
|
<p className="text-sm text-muted-foreground">
|
||||||
{webhook?.description ?? "Loading webhook details..."}
|
{webhook?.description ?? "Loading webhook details..."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -131,15 +131,15 @@ export default function WebhookPayloadsPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{webhook ? (
|
{webhook ? (
|
||||||
<div className="rounded-md bg-slate-50 px-3 py-2">
|
<div className="rounded-md bg-muted px-3 py-2">
|
||||||
<code className="break-all text-xs text-slate-700">
|
<code className="break-all text-xs text-muted-foreground">
|
||||||
{webhook.endpoint_url ?? webhook.endpoint_path}
|
{webhook.endpoint_url ?? webhook.endpoint_path}
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-slate-200 px-3 py-2">
|
<div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-border px-3 py-2">
|
||||||
<p className="text-sm text-slate-700">
|
<p className="text-sm text-muted-foreground">
|
||||||
{total} payload{total === 1 ? "" : "s"} total
|
{total} payload{total === 1 ? "" : "s"} total
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|
@ -153,7 +153,7 @@ export default function WebhookPayloadsPage() {
|
||||||
>
|
>
|
||||||
Previous
|
Previous
|
||||||
</Button>
|
</Button>
|
||||||
<span className="text-xs text-slate-600">
|
<span className="text-xs text-muted-foreground">
|
||||||
Page {currentPage} of {pageCount}
|
Page {currentPage} of {pageCount}
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -172,11 +172,11 @@ export default function WebhookPayloadsPage() {
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<p className="text-sm text-slate-500">Loading payloads...</p>
|
<p className="text-sm text-muted-foreground">Loading payloads...</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{!isLoading && payloads.length === 0 ? (
|
{!isLoading && payloads.length === 0 ? (
|
||||||
<p className="rounded-lg border border-dashed border-slate-300 px-4 py-3 text-sm text-slate-600">
|
<p className="rounded-lg border border-dashed border-input px-4 py-3 text-sm text-muted-foreground">
|
||||||
No payloads received for this webhook yet.
|
No payloads received for this webhook yet.
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
@ -185,17 +185,17 @@ export default function WebhookPayloadsPage() {
|
||||||
{payloads.map((payload: BoardWebhookPayloadRead) => (
|
{payloads.map((payload: BoardWebhookPayloadRead) => (
|
||||||
<div
|
<div
|
||||||
key={payload.id}
|
key={payload.id}
|
||||||
className="space-y-3 rounded-lg border border-slate-200 px-4 py-4"
|
className="space-y-3 rounded-lg border border-border px-4 py-4"
|
||||||
>
|
>
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
Payload {payload.id.slice(0, 8)}
|
Payload {payload.id.slice(0, 8)}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-slate-500">
|
<span className="text-xs text-muted-foreground">
|
||||||
{new Date(payload.received_at).toLocaleString()}
|
{new Date(payload.received_at).toLocaleString()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2 text-xs text-slate-600 md:grid-cols-2">
|
<div className="grid gap-2 text-xs text-muted-foreground md:grid-cols-2">
|
||||||
<p>
|
<p>
|
||||||
Content type:{" "}
|
Content type:{" "}
|
||||||
<code>{payload.content_type ?? "not provided"}</code>
|
<code>{payload.content_type ?? "not provided"}</code>
|
||||||
|
|
@ -204,7 +204,7 @@ export default function WebhookPayloadsPage() {
|
||||||
Source IP: <code>{payload.source_ip ?? "not provided"}</code>
|
Source IP: <code>{payload.source_ip ?? "not provided"}</code>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<pre className="max-h-96 overflow-auto rounded-md bg-slate-900/95 p-3 text-xs text-slate-100">
|
<pre className="max-h-96 overflow-auto rounded-md bg-foreground/95 p-3 text-xs text-background">
|
||||||
{stringifyPayload(payload.payload)}
|
{stringifyPayload(payload.payload)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -161,12 +161,12 @@ export default function NewBoardPage() {
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
|
className="space-y-6 rounded-xl border border-border bg-card p-6 shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Board name <span className="text-red-500">*</span>
|
Board name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -177,7 +177,7 @@ export default function NewBoardPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Gateway <span className="text-red-500">*</span>
|
Gateway <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<SearchableSelect
|
<SearchableSelect
|
||||||
|
|
@ -197,7 +197,7 @@ export default function NewBoardPage() {
|
||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Board group
|
Board group
|
||||||
</label>
|
</label>
|
||||||
<SearchableSelect
|
<SearchableSelect
|
||||||
|
|
@ -213,14 +213,14 @@ export default function NewBoardPage() {
|
||||||
itemClassName="px-4 py-3"
|
itemClassName="px-4 py-3"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Optional. Groups increase cross-board visibility.
|
Optional. Groups increase cross-board visibility.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Description <span className="text-red-500">*</span>
|
Description <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -234,12 +234,12 @@ export default function NewBoardPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{gateways.length === 0 ? (
|
{gateways.length === 0 ? (
|
||||||
<div className="rounded-lg border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
|
<div className="rounded-lg border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
<p>
|
<p>
|
||||||
No gateways available. Create one in{" "}
|
No gateways available. Create one in{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/gateways"
|
href="/gateways"
|
||||||
className="font-medium text-blue-600 hover:text-blue-700"
|
className="font-medium text-primary hover:text-primary"
|
||||||
>
|
>
|
||||||
Gateways
|
Gateways
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ export default function BoardsPage() {
|
||||||
}
|
}
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<BoardsTable
|
<BoardsTable
|
||||||
boards={boards}
|
boards={boards}
|
||||||
boardGroups={groups}
|
boardGroups={groups}
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ export default function EditCustomFieldPage() {
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
{customFieldsQuery.isLoading ? (
|
{customFieldsQuery.isLoading ? (
|
||||||
<div className="max-w-3xl rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-500 shadow-sm">
|
<div className="max-w-3xl rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
Loading custom field…
|
Loading custom field…
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ export default function CustomFieldsPage() {
|
||||||
adminOnlyMessage="Only organization owners and admins can manage custom fields."
|
adminOnlyMessage="Only organization owners and admins can manage custom fields."
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<CustomFieldsTable
|
<CustomFieldsTable
|
||||||
fields={customFields}
|
fields={customFields}
|
||||||
isLoading={customFieldsQuery.isLoading}
|
isLoading={customFieldsQuery.isLoading}
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ export default function GatewayDetailPage() {
|
||||||
adminOnlyMessage="Only organization owners and admins can access gateways."
|
adminOnlyMessage="Only organization owners and admins can access gateways."
|
||||||
>
|
>
|
||||||
{gatewayQuery.isLoading ? (
|
{gatewayQuery.isLoading ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-500 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
Loading gateway…
|
Loading gateway…
|
||||||
</div>
|
</div>
|
||||||
) : gatewayQuery.error ? (
|
) : gatewayQuery.error ? (
|
||||||
|
|
@ -195,16 +195,16 @@ export default function GatewayDetailPage() {
|
||||||
) : gateway ? (
|
) : gateway ? (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="grid gap-6 lg:grid-cols-2">
|
<div className="grid gap-6 lg:grid-cols-2">
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wide text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
||||||
Connection
|
Connection
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2 text-xs text-slate-500">
|
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
<span
|
<span
|
||||||
className={`h-2 w-2 rounded-full ${
|
className={`h-2 w-2 rounded-full ${
|
||||||
statusQuery.isLoading
|
statusQuery.isLoading
|
||||||
? "bg-slate-300"
|
? "bg-muted-foreground/40"
|
||||||
: isConnected
|
: isConnected
|
||||||
? "bg-emerald-500"
|
? "bg-emerald-500"
|
||||||
: "bg-rose-500"
|
: "bg-rose-500"
|
||||||
|
|
@ -219,59 +219,59 @@ export default function GatewayDetailPage() {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 space-y-3 text-sm text-slate-700">
|
<div className="mt-4 space-y-3 text-sm text-muted-foreground">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs uppercase text-slate-400">
|
<p className="text-xs uppercase text-muted-foreground/70">
|
||||||
Gateway URL
|
Gateway URL
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm font-medium text-slate-900">
|
<p className="mt-1 text-sm font-medium text-foreground">
|
||||||
{gateway.url}
|
{gateway.url}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs uppercase text-slate-400">Token</p>
|
<p className="text-xs uppercase text-muted-foreground/70">Token</p>
|
||||||
<p className="mt-1 text-sm font-medium text-slate-900">
|
<p className="mt-1 text-sm font-medium text-foreground">
|
||||||
{maskToken(gateway.token)}
|
{maskToken(gateway.token)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs uppercase text-slate-400">
|
<p className="text-xs uppercase text-muted-foreground/70">
|
||||||
Device pairing
|
Device pairing
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm font-medium text-slate-900">
|
<p className="mt-1 text-sm font-medium text-foreground">
|
||||||
{gateway.disable_device_pairing ? "Disabled" : "Required"}
|
{gateway.disable_device_pairing ? "Disabled" : "Required"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wide text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
||||||
Runtime
|
Runtime
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4 space-y-3 text-sm text-slate-700">
|
<div className="mt-4 space-y-3 text-sm text-muted-foreground">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs uppercase text-slate-400">
|
<p className="text-xs uppercase text-muted-foreground/70">
|
||||||
Workspace root
|
Workspace root
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm font-medium text-slate-900">
|
<p className="mt-1 text-sm font-medium text-foreground">
|
||||||
{gateway.workspace_root}
|
{gateway.workspace_root}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-3 sm:grid-cols-2">
|
<div className="grid gap-3 sm:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs uppercase text-slate-400">
|
<p className="text-xs uppercase text-muted-foreground/70">
|
||||||
Created
|
Created
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm font-medium text-slate-900">
|
<p className="mt-1 text-sm font-medium text-foreground">
|
||||||
{formatTimestamp(gateway.created_at)}
|
{formatTimestamp(gateway.created_at)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs uppercase text-slate-400">
|
<p className="text-xs uppercase text-muted-foreground/70">
|
||||||
Updated
|
Updated
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm font-medium text-slate-900">
|
<p className="mt-1 text-sm font-medium text-foreground">
|
||||||
{formatTimestamp(gateway.updated_at)}
|
{formatTimestamp(gateway.updated_at)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -280,15 +280,15 @@ export default function GatewayDetailPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wide text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
||||||
Agents
|
Agents
|
||||||
</p>
|
</p>
|
||||||
{agentsQuery.isLoading ? (
|
{agentsQuery.isLoading ? (
|
||||||
<span className="text-xs text-slate-500">Loading…</span>
|
<span className="text-xs text-muted-foreground">Loading…</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="text-xs text-slate-500">
|
<span className="text-xs text-muted-foreground">
|
||||||
{agents.length} total
|
{agents.length} total
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ export default function GatewaysPage() {
|
||||||
adminOnlyMessage="Only organization owners and admins can access gateways."
|
adminOnlyMessage="Only organization owners and admins can access gateways."
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<GatewaysTable
|
<GatewaysTable
|
||||||
gateways={gateways}
|
gateways={gateways}
|
||||||
isLoading={gatewaysQuery.isLoading}
|
isLoading={gatewaysQuery.isLoading}
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ export default function ForgejoConnectionsEditPage({
|
||||||
errorMessage={deleteError}
|
errorMessage={deleteError}
|
||||||
confirmLabel="Delete Connection"
|
confirmLabel="Delete Connection"
|
||||||
confirmingLabel="Deleting…"
|
confirmingLabel="Deleting…"
|
||||||
confirmClassName="bg-[color:var(--danger)] text-white hover:bg-[color:var(--danger)]/90"
|
confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
cancelLabel="Keep Connection"
|
cancelLabel="Keep Connection"
|
||||||
/>
|
/>
|
||||||
</DashboardPageLayout>
|
</DashboardPageLayout>
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ export default function ForgejoConnectionsPage() {
|
||||||
errorMessage={deleteError}
|
errorMessage={deleteError}
|
||||||
confirmLabel="Delete Connection"
|
confirmLabel="Delete Connection"
|
||||||
confirmingLabel="Deleting…"
|
confirmingLabel="Deleting…"
|
||||||
confirmClassName="bg-[color:var(--danger)] text-white hover:bg-[color:var(--danger)]/90"
|
confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
cancelLabel="Keep Connection"
|
cancelLabel="Keep Connection"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ export default function ForgejoRepositoriesEditPage({
|
||||||
errorMessage={deleteError}
|
errorMessage={deleteError}
|
||||||
confirmLabel="Delete Repository"
|
confirmLabel="Delete Repository"
|
||||||
confirmingLabel="Deleting…"
|
confirmingLabel="Deleting…"
|
||||||
confirmClassName="bg-[color:var(--danger)] text-white hover:bg-[color:var(--danger)]/90"
|
confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
cancelLabel="Keep Repository"
|
cancelLabel="Keep Repository"
|
||||||
/>
|
/>
|
||||||
</DashboardPageLayout>
|
</DashboardPageLayout>
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ export default function ForgejoRepositoriesPage() {
|
||||||
errorMessage={deleteError}
|
errorMessage={deleteError}
|
||||||
confirmLabel="Delete Repository"
|
confirmLabel="Delete Repository"
|
||||||
confirmingLabel="Deleting…"
|
confirmingLabel="Deleting…"
|
||||||
confirmClassName="bg-[color:var(--danger)] text-white hover:bg-[color:var(--danger)]/90"
|
confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
cancelLabel="Keep Repository"
|
cancelLabel="Keep Repository"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ export default function InvitePage() {
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
<div className="min-h-screen bg-app text-strong">
|
<div className="min-h-screen bg-app text-strong">
|
||||||
<header className="border-b border-[color:var(--border)] bg-white">
|
<header className="border-b border-[color:var(--border)] bg-card">
|
||||||
<div className="mx-auto flex max-w-5xl items-center justify-between px-6 py-4">
|
<div className="mx-auto flex max-w-5xl items-center justify-between px-6 py-4">
|
||||||
<BrandMark />
|
<BrandMark />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ export default function Loading() {
|
||||||
className="flex min-h-screen items-center justify-center bg-app px-6"
|
className="flex min-h-screen items-center justify-center bg-app px-6"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col items-center gap-3">
|
<div className="flex flex-col items-center gap-3">
|
||||||
<div className="h-10 w-10 animate-spin rounded-full border-2 border-slate-200 border-t-[var(--accent)]" />
|
<div className="h-10 w-10 animate-spin rounded-full border-2 border-border border-t-[var(--accent)]" />
|
||||||
<p className="text-sm text-slate-500">Loading pipeline...</p>
|
<p className="text-sm text-muted-foreground">Loading pipeline...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -115,12 +115,12 @@ export default function OnboardingPage() {
|
||||||
<DashboardShell>
|
<DashboardShell>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<div className="lg:col-span-2 flex min-h-[70vh] items-center justify-center">
|
<div className="lg:col-span-2 flex min-h-[70vh] items-center justify-center">
|
||||||
<div className="w-full max-w-2xl rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="w-full max-w-2xl rounded-xl border border-border bg-card shadow-sm">
|
||||||
<div className="border-b border-slate-100 px-6 py-5">
|
<div className="border-b border-border px-6 py-5">
|
||||||
<h1 className="text-2xl font-semibold tracking-tight text-slate-900">
|
<h1 className="text-2xl font-semibold tracking-tight text-foreground">
|
||||||
Pipeline profile
|
Pipeline profile
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-1 text-sm text-slate-600">
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
Sign in to configure your profile and timezone.
|
Sign in to configure your profile and timezone.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -138,12 +138,12 @@ export default function OnboardingPage() {
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<div className="lg:col-span-2 flex min-h-[70vh] items-center justify-center">
|
<div className="lg:col-span-2 flex min-h-[70vh] items-center justify-center">
|
||||||
<section className="w-full max-w-2xl rounded-xl border border-slate-200 bg-white shadow-sm">
|
<section className="w-full max-w-2xl rounded-xl border border-border bg-card shadow-sm">
|
||||||
<div className="border-b border-slate-100 px-6 py-5">
|
<div className="border-b border-border px-6 py-5">
|
||||||
<h1 className="text-2xl font-semibold tracking-tight text-slate-900">
|
<h1 className="text-2xl font-semibold tracking-tight text-foreground">
|
||||||
Pipeline profile
|
Pipeline profile
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-1 text-sm text-slate-600">
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
Configure your Pipeline settings and preferences.
|
Configure your Pipeline settings and preferences.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -151,8 +151,8 @@ export default function OnboardingPage() {
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-700 flex items-center gap-2">
|
<label className="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||||
<User className="h-4 w-4 text-slate-500" />
|
<User className="h-4 w-4 text-muted-foreground" />
|
||||||
Name
|
Name
|
||||||
<span className="text-red-500">*</span>
|
<span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -161,12 +161,12 @@ export default function OnboardingPage() {
|
||||||
onChange={(event) => setName(event.target.value)}
|
onChange={(event) => setName(event.target.value)}
|
||||||
placeholder="Enter your name"
|
placeholder="Enter your name"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="border-slate-300 text-slate-900 focus-visible:ring-blue-500"
|
className="border-input text-foreground focus-visible:ring-ring"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-700 flex items-center gap-2">
|
<label className="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||||
<Globe className="h-4 w-4 text-slate-500" />
|
<Globe className="h-4 w-4 text-muted-foreground" />
|
||||||
Timezone
|
Timezone
|
||||||
<span className="text-red-500">*</span>
|
<span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -185,8 +185,8 @@ export default function OnboardingPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-lg border border-blue-200 bg-blue-50 p-4 text-sm text-blue-800 flex items-start gap-3">
|
<div className="flex items-start gap-3 rounded-lg border border-border bg-muted p-4 text-sm text-muted-foreground">
|
||||||
<Info className="mt-0.5 h-4 w-4 text-blue-600" />
|
<Info className="mt-0.5 h-4 w-4 text-primary" />
|
||||||
<p>
|
<p>
|
||||||
<strong>Note:</strong> Your timezone is used to display all
|
<strong>Note:</strong> Your timezone is used to display all
|
||||||
timestamps and schedule mission-critical events accurately.
|
timestamps and schedule mission-critical events accurately.
|
||||||
|
|
@ -194,7 +194,7 @@ export default function OnboardingPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{errorMessage ? (
|
{errorMessage ? (
|
||||||
<div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-xs text-slate-600">
|
<div className="rounded-lg border border-border bg-muted p-3 text-xs text-muted-foreground">
|
||||||
{errorMessage}
|
{errorMessage}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
@ -202,26 +202,27 @@ export default function OnboardingPage() {
|
||||||
<div className="flex flex-wrap gap-3 pt-2">
|
<div className="flex flex-wrap gap-3 pt-2">
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex-1 bg-blue-600 text-white hover:bg-blue-700 py-2.5"
|
className="flex-1 py-2.5"
|
||||||
disabled={isLoading || requiredMissing}
|
disabled={isLoading || requiredMissing}
|
||||||
>
|
>
|
||||||
<Save className="h-4 w-4" />
|
<Save className="h-4 w-4" />
|
||||||
{isLoading ? "Saving…" : "Save Profile"}
|
{isLoading ? "Saving…" : "Save Profile"}
|
||||||
</Button>
|
</Button>
|
||||||
<button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
variant="outline"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setName("");
|
setName("");
|
||||||
setTimezone("");
|
setTimezone("");
|
||||||
setError(null);
|
setError(null);
|
||||||
}}
|
}}
|
||||||
className="flex-1 rounded-md border border-slate-300 px-4 py-2.5 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50"
|
className="flex-1 py-2.5"
|
||||||
>
|
>
|
||||||
<span className="inline-flex items-center gap-2">
|
<span className="inline-flex items-center gap-2">
|
||||||
<RotateCcw className="h-4 w-4" />
|
<RotateCcw className="h-4 w-4" />
|
||||||
Reset
|
Reset
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -157,17 +157,17 @@ function BoardAccessEditor({
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Board access
|
Board access
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-3 inline-flex rounded-xl border border-slate-200 bg-slate-100 p-1">
|
<div className="mt-3 inline-flex rounded-xl border border-border bg-accent p-1">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-md px-3 py-1.5 text-xs font-semibold transition",
|
"rounded-md px-3 py-1.5 text-xs font-semibold transition",
|
||||||
scope === "all"
|
scope === "all"
|
||||||
? "bg-white text-slate-900 shadow-sm"
|
? "bg-card text-foreground shadow-sm"
|
||||||
: "text-slate-500 hover:text-slate-700",
|
: "text-muted-foreground hover:text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
onClick={() => onScopeChange("all")}
|
onClick={() => onScopeChange("all")}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
@ -179,8 +179,8 @@ function BoardAccessEditor({
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-md px-3 py-1.5 text-xs font-semibold transition",
|
"rounded-md px-3 py-1.5 text-xs font-semibold transition",
|
||||||
scope === "custom"
|
scope === "custom"
|
||||||
? "bg-white text-slate-900 shadow-sm"
|
? "bg-card text-foreground shadow-sm"
|
||||||
: "text-slate-500 hover:text-slate-700",
|
: "text-muted-foreground hover:text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
onClick={() => onScopeChange("custom")}
|
onClick={() => onScopeChange("custom")}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
@ -191,8 +191,8 @@ function BoardAccessEditor({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{scope === "all" ? (
|
{scope === "all" ? (
|
||||||
<div className="flex flex-wrap items-center gap-6 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm">
|
<div className="flex flex-wrap items-center gap-6 rounded-xl border border-border bg-card px-4 py-2.5 text-sm">
|
||||||
<label className="flex items-center gap-2 text-slate-600">
|
<label className="flex items-center gap-2 text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="h-4 w-4"
|
className="h-4 w-4"
|
||||||
|
|
@ -202,7 +202,7 @@ function BoardAccessEditor({
|
||||||
/>
|
/>
|
||||||
Read
|
Read
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center gap-2 text-slate-600">
|
<label className="flex items-center gap-2 text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="h-4 w-4"
|
className="h-4 w-4"
|
||||||
|
|
@ -212,18 +212,18 @@ function BoardAccessEditor({
|
||||||
/>
|
/>
|
||||||
Write
|
Write
|
||||||
</label>
|
</label>
|
||||||
<span className="text-xs text-slate-500">
|
<span className="text-xs text-muted-foreground">
|
||||||
Write access implies read permissions.
|
Write access implies read permissions.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
{boards.length === 0 ? (
|
{boards.length === 0 ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
|
<div className="rounded-xl border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
{emptyMessage ?? "No boards available yet."}
|
{emptyMessage ?? "No boards available yet."}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200">
|
<div className="overflow-hidden rounded-xl border border-border">
|
||||||
<BoardAccessTable
|
<BoardAccessTable
|
||||||
boards={boards}
|
boards={boards}
|
||||||
access={access}
|
access={access}
|
||||||
|
|
@ -702,13 +702,13 @@ export default function OrganizationPage() {
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
<DashboardSidebar />
|
<DashboardSidebar />
|
||||||
<main className="flex-1 overflow-y-auto bg-slate-50">
|
<main className="flex-1 overflow-y-auto bg-muted">
|
||||||
<div className="sticky top-0 z-30 border-b border-slate-200 bg-white">
|
<div className="sticky top-0 z-30 border-b border-border bg-card">
|
||||||
<div className="px-4 py-4 md:px-8 md:py-6">
|
<div className="px-4 py-4 md:px-8 md:py-6">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-6">
|
<div className="flex flex-wrap items-center justify-between gap-6">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-wrap items-center gap-3">
|
<div className="flex flex-wrap items-center gap-3">
|
||||||
<h1 className="text-2xl font-semibold tracking-tight text-slate-900">
|
<h1 className="text-2xl font-semibold tracking-tight text-foreground">
|
||||||
Organization
|
Organization
|
||||||
</h1>
|
</h1>
|
||||||
<Badge
|
<Badge
|
||||||
|
|
@ -719,24 +719,24 @@ export default function OrganizationPage() {
|
||||||
{orgName}
|
{orgName}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-1 text-sm text-slate-500">
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
Manage members and board access across your workspace.
|
Manage members and board access across your workspace.
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-3 flex flex-wrap items-center gap-4 text-xs text-slate-500">
|
<div className="mt-3 flex flex-wrap items-center gap-4 text-xs text-muted-foreground">
|
||||||
<span>
|
<span>
|
||||||
<strong className="text-slate-900">
|
<strong className="text-foreground">
|
||||||
{members.length}
|
{members.length}
|
||||||
</strong>{" "}
|
</strong>{" "}
|
||||||
members
|
members
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<strong className="text-slate-900">
|
<strong className="text-foreground">
|
||||||
{boards.length}
|
{boards.length}
|
||||||
</strong>{" "}
|
</strong>{" "}
|
||||||
boards
|
boards
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<strong className="text-slate-900">
|
<strong className="text-foreground">
|
||||||
{invites.length}
|
{invites.length}
|
||||||
</strong>{" "}
|
</strong>{" "}
|
||||||
pending
|
pending
|
||||||
|
|
@ -776,17 +776,17 @@ export default function OrganizationPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="px-4 py-4 md:px-8 md:py-8">
|
<div className="px-4 py-4 md:px-8 md:py-8">
|
||||||
<div className="overflow-hidden rounded-2xl border border-slate-200 bg-white">
|
<div className="overflow-hidden rounded-2xl border border-border bg-card">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3 border-b border-slate-200 px-5 py-4">
|
<div className="flex flex-wrap items-center justify-between gap-3 border-b border-border px-5 py-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-sm font-semibold text-slate-900">
|
<h2 className="text-sm font-semibold text-foreground">
|
||||||
Members & invites
|
Members & invites
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Invite teammates and tune their board permissions.
|
Invite teammates and tune their board permissions.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-xs text-slate-500">
|
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
<Users className="h-4 w-4" />
|
<Users className="h-4 w-4" />
|
||||||
{members.length + invites.length} total
|
{members.length + invites.length} total
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -829,7 +829,7 @@ export default function OrganizationPage() {
|
||||||
<form className="space-y-5" onSubmit={handleInviteSubmit}>
|
<form className="space-y-5" onSubmit={handleInviteSubmit}>
|
||||||
<div className="grid gap-4 sm:grid-cols-[1fr_200px]">
|
<div className="grid gap-4 sm:grid-cols-[1fr_200px]">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Email address
|
Email address
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -841,7 +841,7 @@ export default function OrganizationPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Role
|
Role
|
||||||
</label>
|
</label>
|
||||||
<Select value={inviteRole} onValueChange={setInviteRole}>
|
<Select value={inviteRole} onValueChange={setInviteRole}>
|
||||||
|
|
@ -893,7 +893,7 @@ export default function OrganizationPage() {
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</form>
|
</form>
|
||||||
) : (
|
) : (
|
||||||
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
|
<div className="rounded-xl border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
Only organization admins can invite new members.
|
Only organization admins can invite new members.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -910,26 +910,26 @@ export default function OrganizationPage() {
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
{memberDetailsQuery.isLoading ? (
|
{memberDetailsQuery.isLoading ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
|
<div className="rounded-xl border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
Loading member access...
|
Loading member access...
|
||||||
</div>
|
</div>
|
||||||
) : memberDetailsQuery.data?.status === 200 ? (
|
) : memberDetailsQuery.data?.status === 200 ? (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-5 py-4">
|
<div className="rounded-xl border border-border bg-card px-5 py-4">
|
||||||
<p className="text-sm font-semibold text-slate-900">
|
<p className="text-sm font-semibold text-foreground">
|
||||||
{memberDetailsQuery.data.data.user?.name ||
|
{memberDetailsQuery.data.data.user?.name ||
|
||||||
memberDetailsQuery.data.data.user?.preferred_name ||
|
memberDetailsQuery.data.data.user?.preferred_name ||
|
||||||
memberDetailsQuery.data.data.user?.email ||
|
memberDetailsQuery.data.data.user?.email ||
|
||||||
memberDetailsQuery.data.data.user_id}
|
memberDetailsQuery.data.data.user_id}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
{memberDetailsQuery.data.data.user?.email ??
|
{memberDetailsQuery.data.data.user?.email ??
|
||||||
"No email on file"}
|
"No email on file"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Role
|
Role
|
||||||
</label>
|
</label>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -967,7 +967,7 @@ export default function OrganizationPage() {
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-500">
|
<div className="rounded-xl border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
Unable to load member access.
|
Unable to load member access.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -683,7 +683,7 @@ export default function GitProjectSettingsPage() {
|
||||||
errorMessage={deleteError}
|
errorMessage={deleteError}
|
||||||
confirmLabel="Delete"
|
confirmLabel="Delete"
|
||||||
confirmingLabel="Deleting…"
|
confirmingLabel="Deleting…"
|
||||||
confirmClassName="bg-[color:var(--danger)] text-white hover:bg-[color:var(--danger)]/90"
|
confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
cancelLabel="Keep"
|
cancelLabel="Keep"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -161,17 +161,17 @@ export default function SettingsPage() {
|
||||||
description="Update your profile and account preferences."
|
description="Update your profile and account preferences."
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<section className="rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
<section className="rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||||
<h2 className="text-base font-semibold text-slate-900">Profile</h2>
|
<h2 className="text-base font-semibold text-foreground">Profile</h2>
|
||||||
<p className="mt-1 text-sm text-slate-500">
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
Keep your identity and timezone up to date.
|
Keep your identity and timezone up to date.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form onSubmit={handleSave} className="mt-6 space-y-5">
|
<form onSubmit={handleSave} className="mt-6 space-y-5">
|
||||||
<div className="grid gap-5 md:grid-cols-2">
|
<div className="grid gap-5 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="flex items-center gap-2 text-sm font-medium text-slate-700">
|
<label className="flex items-center gap-2 text-sm font-medium text-muted-foreground">
|
||||||
<User className="h-4 w-4 text-slate-500" />
|
<User className="h-4 w-4 text-muted-foreground" />
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -182,12 +182,12 @@ export default function SettingsPage() {
|
||||||
}}
|
}}
|
||||||
placeholder="Your name"
|
placeholder="Your name"
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="border-slate-300 [--input-bg:#fff] [--input-text:#0f172a] placeholder:text-slate-500 focus-visible:ring-blue-500"
|
className="border-input [--input-bg:var(--card)] [--input-text:var(--card-foreground)] placeholder:text-muted-foreground focus-visible:ring-ring"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="flex items-center gap-2 text-sm font-medium text-slate-700">
|
<label className="flex items-center gap-2 text-sm font-medium text-muted-foreground">
|
||||||
<Globe className="h-4 w-4 text-slate-500" />
|
<Globe className="h-4 w-4 text-muted-foreground" />
|
||||||
Timezone
|
Timezone
|
||||||
</label>
|
</label>
|
||||||
<SearchableSelect
|
<SearchableSelect
|
||||||
|
|
@ -210,15 +210,15 @@ export default function SettingsPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="flex items-center gap-2 text-sm font-medium text-slate-700">
|
<label className="flex items-center gap-2 text-sm font-medium text-muted-foreground">
|
||||||
<Mail className="h-4 w-4 text-slate-500" />
|
<Mail className="h-4 w-4 text-muted-foreground" />
|
||||||
Email
|
Email
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
value={displayEmail}
|
value={displayEmail}
|
||||||
readOnly
|
readOnly
|
||||||
disabled
|
disabled
|
||||||
className="border-slate-200 [--input-bg:#f8fafc] [--input-text:#475569]"
|
className="border-border [--input-bg:var(--muted)] [--input-text:var(--muted-foreground)]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -251,14 +251,14 @@ export default function SettingsPage() {
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
<section className="rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h2 className="flex items-center gap-2 text-base font-semibold text-slate-900">
|
<h2 className="flex items-center gap-2 text-base font-semibold text-foreground">
|
||||||
<GitBranch className="h-4 w-4 text-slate-500" />
|
<GitBranch className="h-4 w-4 text-muted-foreground" />
|
||||||
Git Projects
|
Git Projects
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-1 text-sm text-slate-500">
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
Manage Forgejo connections, tracked repositories, and issue
|
Manage Forgejo connections, tracked repositories, and issue
|
||||||
sync.
|
sync.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -283,7 +283,7 @@ export default function SettingsPage() {
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="bg-rose-600 text-white hover:bg-rose-700"
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteError(null);
|
setDeleteError(null);
|
||||||
setDeleteDialogOpen(true);
|
setDeleteDialogOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ export default function SignInPage() {
|
||||||
// Dedicated sign-in route for Cypress E2E.
|
// Dedicated sign-in route for Cypress E2E.
|
||||||
// Avoids modal/iframe auth flows and gives Cypress a stable top-level page.
|
// Avoids modal/iframe auth flows and gives Cypress a stable top-level page.
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen items-center justify-center bg-slate-50 p-6">
|
<main className="flex min-h-screen items-center justify-center bg-muted p-6">
|
||||||
<SignIn
|
<SignIn
|
||||||
routing="path"
|
routing="path"
|
||||||
path="/sign-in"
|
path="/sign-in"
|
||||||
|
|
|
||||||
|
|
@ -788,8 +788,8 @@ export default function SkillsMarketplacePage() {
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{gateways.length === 0 ? (
|
{gateways.length === 0 ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-600 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
<p className="font-medium text-slate-900">
|
<p className="font-medium text-foreground">
|
||||||
No gateways available yet.
|
No gateways available yet.
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-2">
|
<p className="mt-2">
|
||||||
|
|
@ -804,12 +804,12 @@ export default function SkillsMarketplacePage() {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="mb-5 rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
|
<div className="mb-5 rounded-xl border border-border bg-card p-4 shadow-sm">
|
||||||
<div className="grid gap-4 md:grid-cols-[1fr_240px_240px]">
|
<div className="grid gap-4 md:grid-cols-[1fr_240px_240px]">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="marketplace-search"
|
htmlFor="marketplace-search"
|
||||||
className="mb-1 block text-sm font-medium text-slate-700"
|
className="mb-1 block text-sm font-medium text-muted-foreground"
|
||||||
>
|
>
|
||||||
Search
|
Search
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -824,7 +824,7 @@ export default function SkillsMarketplacePage() {
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="marketplace-category-filter"
|
htmlFor="marketplace-category-filter"
|
||||||
className="mb-1 block text-sm font-medium text-slate-700"
|
className="mb-1 block text-sm font-medium text-muted-foreground"
|
||||||
>
|
>
|
||||||
Category
|
Category
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -854,7 +854,7 @@ export default function SkillsMarketplacePage() {
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="marketplace-risk-filter"
|
htmlFor="marketplace-risk-filter"
|
||||||
className="mb-1 block text-sm font-medium text-slate-700"
|
className="mb-1 block text-sm font-medium text-muted-foreground"
|
||||||
>
|
>
|
||||||
Risk
|
Risk
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -880,7 +880,7 @@ export default function SkillsMarketplacePage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<MarketplaceSkillsTable
|
<MarketplaceSkillsTable
|
||||||
skills={filteredSkills}
|
skills={filteredSkills}
|
||||||
installedGatewayNamesBySkillId={
|
installedGatewayNamesBySkillId={
|
||||||
|
|
@ -901,13 +901,13 @@ export default function SkillsMarketplacePage() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-white px-4 py-3 text-sm text-slate-600 shadow-sm">
|
<div className="flex items-center justify-between rounded-xl border border-border bg-card px-4 py-3 text-sm text-muted-foreground shadow-sm">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<p>
|
<p>
|
||||||
Showing {rangeStart}-{rangeEnd} of {totalSkills}
|
Showing {rangeStart}-{rangeEnd} of {totalSkills}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-xs font-medium uppercase tracking-wide text-slate-500">
|
<span className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||||
Rows
|
Rows
|
||||||
</span>
|
</span>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -951,7 +951,7 @@ export default function SkillsMarketplacePage() {
|
||||||
>
|
>
|
||||||
Previous
|
Previous
|
||||||
</Button>
|
</Button>
|
||||||
<span className="text-xs font-medium uppercase tracking-wide text-slate-500">
|
<span className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||||
{totalCountInfo.hasKnownTotal
|
{totalCountInfo.hasKnownTotal
|
||||||
? `Page ${currentPage} of ${totalPages}`
|
? `Page ${currentPage} of ${totalPages}`
|
||||||
: `Page ${currentPage}`}
|
: `Page ${currentPage}`}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export default function EditSkillPackPage() {
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
{packQuery.isLoading ? (
|
{packQuery.isLoading ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-500 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
Loading pack...
|
Loading pack...
|
||||||
</div>
|
</div>
|
||||||
) : packQuery.error ? (
|
) : packQuery.error ? (
|
||||||
|
|
@ -62,7 +62,7 @@ export default function EditSkillPackPage() {
|
||||||
{packQuery.error.message}
|
{packQuery.error.message}
|
||||||
</div>
|
</div>
|
||||||
) : !pack ? (
|
) : !pack ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-500 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
Pack not found.
|
Pack not found.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ export default function SkillsPacksPage() {
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<SkillPacksTable
|
<SkillPacksTable
|
||||||
packs={packs}
|
packs={packs}
|
||||||
isLoading={packsQuery.isLoading}
|
isLoading={packsQuery.isLoading}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ export default function EditTagPage() {
|
||||||
adminOnlyMessage="Only organization owners and admins can manage tags."
|
adminOnlyMessage="Only organization owners and admins can manage tags."
|
||||||
>
|
>
|
||||||
{tagQuery.isLoading ? (
|
{tagQuery.isLoading ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-500 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
Loading tag…
|
Loading tag…
|
||||||
</div>
|
</div>
|
||||||
) : tagQuery.error ? (
|
) : tagQuery.error ? (
|
||||||
|
|
@ -68,7 +68,7 @@ export default function EditTagPage() {
|
||||||
{tagQuery.error.message}
|
{tagQuery.error.message}
|
||||||
</div>
|
</div>
|
||||||
) : !tag ? (
|
) : !tag ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-500 shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-6 text-sm text-muted-foreground shadow-sm">
|
||||||
Tag not found.
|
Tag not found.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ export default function TagsPage() {
|
||||||
adminOnlyMessage="Only organization owners and admins can manage tags."
|
adminOnlyMessage="Only organization owners and admins can manage tags."
|
||||||
stickyHeader
|
stickyHeader
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
|
||||||
<TagsTable
|
<TagsTable
|
||||||
tags={tags}
|
tags={tags}
|
||||||
isLoading={tagsQuery.isLoading}
|
isLoading={tagsQuery.isLoading}
|
||||||
|
|
|
||||||
|
|
@ -134,14 +134,14 @@ const formatRubricTooltipValue = (
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full items-center justify-between gap-3">
|
<div className="flex w-full items-center justify-between gap-3">
|
||||||
<span className="flex items-center gap-2 text-slate-600">
|
<span className="flex items-center gap-2 text-muted-foreground">
|
||||||
<span
|
<span
|
||||||
className="h-2.5 w-2.5 rounded-[2px]"
|
className="h-2.5 w-2.5 rounded-[2px]"
|
||||||
style={{ backgroundColor: indicatorColor }}
|
style={{ backgroundColor: indicatorColor }}
|
||||||
/>
|
/>
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
</span>
|
</span>
|
||||||
<span className="font-mono font-medium tabular-nums text-slate-900">
|
<span className="font-mono font-medium tabular-nums text-foreground">
|
||||||
{displayValue}
|
{displayValue}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -554,11 +554,11 @@ export function BoardApprovalsPanel({
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{loadingState ? (
|
{loadingState ? (
|
||||||
<p className="text-sm text-slate-500">Loading approvals…</p>
|
<p className="text-sm text-muted-foreground">Loading approvals…</p>
|
||||||
) : pendingCount === 0 && resolvedCount === 0 ? (
|
) : pendingCount === 0 && resolvedCount === 0 ? (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-xl border border-dashed border-slate-200 bg-white px-6 py-10 text-center",
|
"rounded-xl border border-dashed border-border bg-card px-6 py-10 text-center",
|
||||||
scrollable && "flex h-full items-center justify-center",
|
scrollable && "flex h-full items-center justify-center",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
@ -566,10 +566,10 @@ export function BoardApprovalsPanel({
|
||||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-emerald-50 text-emerald-600">
|
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-emerald-50 text-emerald-600">
|
||||||
<CheckCircle2 className="h-6 w-6" />
|
<CheckCircle2 className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-4 text-sm font-semibold text-slate-900">
|
<p className="mt-4 text-sm font-semibold text-foreground">
|
||||||
All clear
|
All clear
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-2 text-sm text-slate-500">
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
No approvals to review right now. New approvals will show up here
|
No approvals to review right now. New approvals will show up here
|
||||||
as soon as they arrive.
|
as soon as they arrive.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -584,15 +584,15 @@ export function BoardApprovalsPanel({
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"overflow-hidden rounded-xl border border-slate-200 bg-white",
|
"overflow-hidden rounded-xl border border-border bg-card",
|
||||||
scrollable && "flex min-h-0 flex-col",
|
scrollable && "flex min-h-0 flex-col",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="border-b border-slate-200 bg-slate-50 px-4 py-3">
|
<div className="border-b border-border bg-muted px-4 py-3">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Unapproved tasks
|
Unapproved tasks
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
{pendingCount} pending · {resolvedCount} resolved
|
{pendingCount} pending · {resolvedCount} resolved
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -632,13 +632,13 @@ export function BoardApprovalsPanel({
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setSelectedId(approval.id)}
|
onClick={() => setSelectedId(approval.id)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full px-4 py-4 text-left transition hover:bg-slate-50",
|
"w-full px-4 py-4 text-left transition hover:bg-muted",
|
||||||
isSelected && "bg-amber-50 border-l-2 border-amber-500",
|
isSelected && "bg-amber-50 border-l-2 border-amber-500",
|
||||||
!isPending && "opacity-60",
|
!isPending && "opacity-60",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<span className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">
|
<span className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||||
{humanizeAction(approval.action_type)}
|
{humanizeAction(approval.action_type)}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
|
|
@ -650,16 +650,16 @@ export function BoardApprovalsPanel({
|
||||||
{formatStatusLabel(approval.status)}
|
{formatStatusLabel(approval.status)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-2 text-sm font-semibold text-slate-900">
|
<p className="mt-2 text-sm font-semibold text-foreground">
|
||||||
{primaryLabel}
|
{primaryLabel}
|
||||||
</p>
|
</p>
|
||||||
{boardText ? (
|
{boardText ? (
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
Board · {boardText}
|
Board · {boardText}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="mt-2 flex items-center gap-2 text-xs text-slate-500">
|
<div className="mt-2 flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
<span className="rounded bg-slate-100 px-1.5 py-0.5 font-semibold text-slate-700">
|
<span className="rounded bg-accent px-1.5 py-0.5 font-semibold text-muted-foreground">
|
||||||
{approval.confidence}% score
|
{approval.confidence}% score
|
||||||
</span>
|
</span>
|
||||||
<Clock className="h-3.5 w-3.5 opacity-60" />
|
<Clock className="h-3.5 w-3.5 opacity-60" />
|
||||||
|
|
@ -673,19 +673,19 @@ export function BoardApprovalsPanel({
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"overflow-hidden rounded-xl border border-slate-200 bg-white",
|
"overflow-hidden rounded-xl border border-border bg-card",
|
||||||
scrollable && "flex min-h-0 flex-col",
|
scrollable && "flex min-h-0 flex-col",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="border-b border-slate-200 bg-slate-50 px-4 py-3">
|
<div className="border-b border-border bg-muted px-4 py-3">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
{selectedApproval?.status === "pending"
|
{selectedApproval?.status === "pending"
|
||||||
? "Latest unapproved task"
|
? "Latest unapproved task"
|
||||||
: "Approval detail"}
|
: "Approval detail"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{!selectedApproval ? (
|
{!selectedApproval ? (
|
||||||
<div className="flex h-full items-center justify-center px-6 py-10 text-sm text-slate-500">
|
<div className="flex h-full items-center justify-center px-6 py-10 text-sm text-muted-foreground">
|
||||||
Select an approval to review details.
|
Select an approval to review details.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -755,10 +755,10 @@ export function BoardApprovalsPanel({
|
||||||
<div className="flex h-full flex-col gap-6 px-6 py-6">
|
<div className="flex h-full flex-col gap-6 px-6 py-6">
|
||||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-lg font-semibold text-slate-900">
|
<p className="text-lg font-semibold text-foreground">
|
||||||
{humanizeAction(selectedApproval.action_type)}
|
{humanizeAction(selectedApproval.action_type)}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
Requested{" "}
|
Requested{" "}
|
||||||
{formatTimestamp(selectedApproval.created_at)}
|
{formatTimestamp(selectedApproval.created_at)}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -781,7 +781,7 @@ export function BoardApprovalsPanel({
|
||||||
handleDecision(selectedApproval.id, "approved")
|
handleDecision(selectedApproval.id, "approved")
|
||||||
}
|
}
|
||||||
disabled={updatingId === selectedApproval.id}
|
disabled={updatingId === selectedApproval.id}
|
||||||
className="bg-slate-900 text-white hover:bg-slate-800"
|
className="bg-foreground text-background hover:bg-foreground/90"
|
||||||
>
|
>
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -792,7 +792,7 @@ export function BoardApprovalsPanel({
|
||||||
handleDecision(selectedApproval.id, "rejected")
|
handleDecision(selectedApproval.id, "rejected")
|
||||||
}
|
}
|
||||||
disabled={updatingId === selectedApproval.id}
|
disabled={updatingId === selectedApproval.id}
|
||||||
className="border-slate-300 text-slate-700 hover:bg-slate-100"
|
className="border-input text-muted-foreground hover:bg-accent"
|
||||||
>
|
>
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -801,17 +801,17 @@ export function BoardApprovalsPanel({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-3 rounded-lg border border-slate-200 bg-slate-50 px-4 py-3">
|
<div className="flex items-center gap-3 rounded-lg border border-border bg-muted px-4 py-3">
|
||||||
<StatusDot
|
<StatusDot
|
||||||
status={selectedApproval.status}
|
status={selectedApproval.status}
|
||||||
variant="approval"
|
variant="approval"
|
||||||
className={cn("h-2 w-2 rounded-full")}
|
className={cn("h-2 w-2 rounded-full")}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Status
|
Status
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm font-medium text-slate-700">
|
<p className="text-sm font-medium text-muted-foreground">
|
||||||
{formatStatusLabel(selectedApproval.status)} ·{" "}
|
{formatStatusLabel(selectedApproval.status)} ·{" "}
|
||||||
{selectedApproval.status === "pending"
|
{selectedApproval.status === "pending"
|
||||||
? "Awaiting your decision"
|
? "Awaiting your decision"
|
||||||
|
|
@ -822,10 +822,10 @@ export function BoardApprovalsPanel({
|
||||||
|
|
||||||
{titleText ? (
|
{titleText ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Title
|
Title
|
||||||
</p>
|
</p>
|
||||||
<div className="text-sm font-medium text-slate-900">
|
<div className="text-sm font-medium text-foreground">
|
||||||
{titleText}
|
{titleText}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -833,10 +833,10 @@ export function BoardApprovalsPanel({
|
||||||
|
|
||||||
{descriptionText ? (
|
{descriptionText ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Description
|
Description
|
||||||
</p>
|
</p>
|
||||||
<div className="rounded-lg border border-slate-200 bg-white px-4 py-3 text-sm text-slate-700">
|
<div className="rounded-lg border border-border bg-card px-4 py-3 text-sm text-muted-foreground">
|
||||||
{descriptionText}
|
{descriptionText}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -844,10 +844,10 @@ export function BoardApprovalsPanel({
|
||||||
|
|
||||||
{reasoningText ? (
|
{reasoningText ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Lead reasoning
|
Lead reasoning
|
||||||
</p>
|
</p>
|
||||||
<div className="rounded-lg border border-slate-200 bg-white px-4 py-3 text-sm text-slate-600">
|
<div className="rounded-lg border border-border bg-card px-4 py-3 text-sm text-muted-foreground">
|
||||||
<p>{reasoningText}</p>
|
<p>{reasoningText}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -855,7 +855,7 @@ export function BoardApprovalsPanel({
|
||||||
|
|
||||||
{relatedTasks.length > 0 ? (
|
{relatedTasks.length > 0 ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Related tasks
|
Related tasks
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
|
|
@ -866,7 +866,7 @@ export function BoardApprovalsPanel({
|
||||||
selectedApproval.board_id,
|
selectedApproval.board_id,
|
||||||
task.id,
|
task.id,
|
||||||
)}
|
)}
|
||||||
className="rounded-md border border-slate-200 bg-white px-2 py-1 text-xs text-slate-700 underline-offset-2 transition hover:border-slate-300 hover:bg-slate-50 hover:text-slate-900 hover:underline"
|
className="rounded-md border border-border bg-card px-2 py-1 text-xs text-muted-foreground underline-offset-2 transition hover:border-input hover:bg-muted hover:text-foreground hover:underline"
|
||||||
>
|
>
|
||||||
{task.title}
|
{task.title}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -877,19 +877,19 @@ export function BoardApprovalsPanel({
|
||||||
|
|
||||||
{extraRows.length > 0 ? (
|
{extraRows.length > 0 ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Details
|
Details
|
||||||
</p>
|
</p>
|
||||||
<div className="grid gap-3 sm:grid-cols-2">
|
<div className="grid gap-3 sm:grid-cols-2">
|
||||||
{extraRows.map((row) => (
|
{extraRows.map((row) => (
|
||||||
<div
|
<div
|
||||||
key={`${selectedApproval.id}-${row.label}`}
|
key={`${selectedApproval.id}-${row.label}`}
|
||||||
className="rounded-lg border border-slate-200 bg-white px-3 py-2"
|
className="rounded-lg border border-border bg-card px-3 py-2"
|
||||||
>
|
>
|
||||||
<p className="text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500">
|
<p className="text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||||
{row.label}
|
{row.label}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm font-medium text-slate-900">
|
<p className="mt-1 text-sm font-medium text-foreground">
|
||||||
{row.value}
|
{row.value}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -900,7 +900,7 @@ export function BoardApprovalsPanel({
|
||||||
|
|
||||||
{hasRubric ? (
|
{hasRubric ? (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||||
Rubric scores
|
Rubric scores
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center">
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center">
|
||||||
|
|
@ -915,11 +915,11 @@ export function BoardApprovalsPanel({
|
||||||
className="h-2.5 w-2.5 rounded-full"
|
className="h-2.5 w-2.5 rounded-full"
|
||||||
style={{ backgroundColor: entry.fill }}
|
style={{ backgroundColor: entry.fill }}
|
||||||
/>
|
/>
|
||||||
<span className="text-slate-700">
|
<span className="text-muted-foreground">
|
||||||
{entry.name}
|
{entry.name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="font-medium tabular-nums text-slate-900">
|
<span className="font-medium tabular-nums text-foreground">
|
||||||
{entry.percentLabel}
|
{entry.percentLabel}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ function BoardChatComposerImpl({
|
||||||
disabled={isSending || disabled}
|
disabled={isSending || disabled}
|
||||||
/>
|
/>
|
||||||
{mentionTarget && filteredMentionOptions.length > 0 ? (
|
{mentionTarget && filteredMentionOptions.length > 0 ? (
|
||||||
<div className="absolute bottom-full left-0 z-20 mb-2 w-full overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg">
|
<div className="absolute bottom-full left-0 z-20 mb-2 w-full overflow-hidden rounded-xl border border-border bg-card shadow-lg">
|
||||||
<div className="max-h-52 overflow-y-auto py-1">
|
<div className="max-h-52 overflow-y-auto py-1">
|
||||||
{filteredMentionOptions.map((option, index) => (
|
{filteredMentionOptions.map((option, index) => (
|
||||||
<button
|
<button
|
||||||
|
|
@ -239,12 +239,12 @@ function BoardChatComposerImpl({
|
||||||
}}
|
}}
|
||||||
className={`flex w-full items-center justify-between px-3 py-2 text-left text-sm transition ${
|
className={`flex w-full items-center justify-between px-3 py-2 text-left text-sm transition ${
|
||||||
index === activeIndex
|
index === activeIndex
|
||||||
? "bg-slate-100 text-slate-900"
|
? "bg-accent text-foreground"
|
||||||
: "text-slate-700 hover:bg-slate-50"
|
: "text-muted-foreground hover:bg-muted"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span className="font-mono">@{option}</span>
|
<span className="font-mono">@{option}</span>
|
||||||
<span className="text-xs text-slate-400">mention</span>
|
<span className="text-xs text-muted-foreground/70">mention</span>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -392,13 +392,13 @@ export function BoardOnboardingChat({
|
||||||
|
|
||||||
{draft ? (
|
{draft ? (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<p className="text-sm text-slate-600">
|
<p className="text-sm text-muted-foreground">
|
||||||
Review the lead agent draft and confirm.
|
Review the lead agent draft and confirm.
|
||||||
</p>
|
</p>
|
||||||
{isAwaitingAgent ? (
|
{isAwaitingAgent ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-700">
|
<div className="rounded-xl border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
<div className="flex items-center gap-2 font-medium text-slate-900">
|
<div className="flex items-center gap-2 font-medium text-foreground">
|
||||||
<RefreshCcw className="h-4 w-4 animate-spin text-slate-500" />
|
<RefreshCcw className="h-4 w-4 animate-spin text-muted-foreground" />
|
||||||
<span>
|
<span>
|
||||||
{awaitingKind === "extra_context"
|
{awaitingKind === "extra_context"
|
||||||
? "Updating the draft…"
|
? "Updating the draft…"
|
||||||
|
|
@ -406,80 +406,80 @@ export function BoardOnboardingChat({
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{lastSubmittedAnswer ? (
|
{lastSubmittedAnswer ? (
|
||||||
<p className="mt-2 text-xs text-slate-600">
|
<p className="mt-2 text-xs text-muted-foreground">
|
||||||
Sent:{" "}
|
Sent:{" "}
|
||||||
<span className="font-medium text-slate-900">
|
<span className="font-medium text-foreground">
|
||||||
{lastSubmittedAnswer}
|
{lastSubmittedAnswer}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
This usually takes a few seconds.
|
This usually takes a few seconds.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm">
|
<div className="rounded-lg border border-border bg-muted p-3 text-sm">
|
||||||
<p className="font-semibold text-slate-900">Objective</p>
|
<p className="font-semibold text-foreground">Objective</p>
|
||||||
<p className="text-slate-700">{draft.objective || "—"}</p>
|
<p className="text-muted-foreground">{draft.objective || "—"}</p>
|
||||||
<p className="mt-3 font-semibold text-slate-900">Success metrics</p>
|
<p className="mt-3 font-semibold text-foreground">Success metrics</p>
|
||||||
<pre className="mt-1 whitespace-pre-wrap text-xs text-slate-600">
|
<pre className="mt-1 whitespace-pre-wrap text-xs text-muted-foreground">
|
||||||
{JSON.stringify(draft.success_metrics ?? {}, null, 2)}
|
{JSON.stringify(draft.success_metrics ?? {}, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
<p className="mt-3 font-semibold text-slate-900">Target date</p>
|
<p className="mt-3 font-semibold text-foreground">Target date</p>
|
||||||
<p className="text-slate-700">{draft.target_date || "—"}</p>
|
<p className="text-muted-foreground">{draft.target_date || "—"}</p>
|
||||||
<p className="mt-3 font-semibold text-slate-900">Board type</p>
|
<p className="mt-3 font-semibold text-foreground">Board type</p>
|
||||||
<p className="text-slate-700">{draft.board_type || "goal"}</p>
|
<p className="text-muted-foreground">{draft.board_type || "goal"}</p>
|
||||||
{draft.user_profile ? (
|
{draft.user_profile ? (
|
||||||
<>
|
<>
|
||||||
<p className="mt-4 font-semibold text-slate-900">
|
<p className="mt-4 font-semibold text-foreground">
|
||||||
User profile
|
User profile
|
||||||
</p>
|
</p>
|
||||||
<p className="text-slate-700">
|
<p className="text-muted-foreground">
|
||||||
<span className="font-medium text-slate-900">
|
<span className="font-medium text-foreground">
|
||||||
Preferred name:
|
Preferred name:
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
{draft.user_profile.preferred_name || "—"}
|
{draft.user_profile.preferred_name || "—"}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-slate-700">
|
<p className="text-muted-foreground">
|
||||||
<span className="font-medium text-slate-900">Pronouns:</span>{" "}
|
<span className="font-medium text-foreground">Pronouns:</span>{" "}
|
||||||
{draft.user_profile.pronouns || "—"}
|
{draft.user_profile.pronouns || "—"}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-slate-700">
|
<p className="text-muted-foreground">
|
||||||
<span className="font-medium text-slate-900">Timezone:</span>{" "}
|
<span className="font-medium text-foreground">Timezone:</span>{" "}
|
||||||
{draft.user_profile.timezone || "—"}
|
{draft.user_profile.timezone || "—"}
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
{draft.lead_agent ? (
|
{draft.lead_agent ? (
|
||||||
<>
|
<>
|
||||||
<p className="mt-4 font-semibold text-slate-900">
|
<p className="mt-4 font-semibold text-foreground">
|
||||||
Lead agent preferences
|
Lead agent preferences
|
||||||
</p>
|
</p>
|
||||||
<p className="text-slate-700">
|
<p className="text-muted-foreground">
|
||||||
<span className="font-medium text-slate-900">Name:</span>{" "}
|
<span className="font-medium text-foreground">Name:</span>{" "}
|
||||||
{draft.lead_agent.name || "—"}
|
{draft.lead_agent.name || "—"}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-slate-700">
|
<p className="text-muted-foreground">
|
||||||
<span className="font-medium text-slate-900">Role:</span>{" "}
|
<span className="font-medium text-foreground">Role:</span>{" "}
|
||||||
{draft.lead_agent.identity_profile?.role || "—"}
|
{draft.lead_agent.identity_profile?.role || "—"}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-slate-700">
|
<p className="text-muted-foreground">
|
||||||
<span className="font-medium text-slate-900">
|
<span className="font-medium text-foreground">
|
||||||
Communication:
|
Communication:
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
{draft.lead_agent.identity_profile?.communication_style ||
|
{draft.lead_agent.identity_profile?.communication_style ||
|
||||||
"—"}
|
"—"}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-slate-700">
|
<p className="text-muted-foreground">
|
||||||
<span className="font-medium text-slate-900">Emoji:</span>{" "}
|
<span className="font-medium text-foreground">Emoji:</span>{" "}
|
||||||
{draft.lead_agent.identity_profile?.emoji || "—"}
|
{draft.lead_agent.identity_profile?.emoji || "—"}
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-lg border border-slate-200 bg-white p-3">
|
<div className="rounded-lg border border-border bg-card p-3">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<p className="text-sm font-semibold text-slate-900">
|
<p className="text-sm font-semibold text-foreground">
|
||||||
Extra context (optional)
|
Extra context (optional)
|
||||||
</p>
|
</p>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -527,12 +527,12 @@ export function BoardOnboardingChat({
|
||||||
: "Send context"}
|
: "Send context"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Tip: press Enter to send. Shift+Enter for a newline.
|
Tip: press Enter to send. Shift+Enter for a newline.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-2 text-xs text-slate-600">
|
<p className="mt-2 text-xs text-muted-foreground">
|
||||||
Add anything that wasn't covered in the agent's
|
Add anything that wasn't covered in the agent's
|
||||||
questions.
|
questions.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -550,13 +550,13 @@ export function BoardOnboardingChat({
|
||||||
</div>
|
</div>
|
||||||
) : question ? (
|
) : question ? (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<p className="text-sm font-medium text-slate-900">
|
<p className="text-sm font-medium text-foreground">
|
||||||
{question.question}
|
{question.question}
|
||||||
</p>
|
</p>
|
||||||
{isAwaitingAgent ? (
|
{isAwaitingAgent ? (
|
||||||
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-700">
|
<div className="rounded-xl border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
||||||
<div className="flex items-center gap-2 font-medium text-slate-900">
|
<div className="flex items-center gap-2 font-medium text-foreground">
|
||||||
<RefreshCcw className="h-4 w-4 animate-spin text-slate-500" />
|
<RefreshCcw className="h-4 w-4 animate-spin text-muted-foreground" />
|
||||||
<span>
|
<span>
|
||||||
{awaitingKind === "extra_context"
|
{awaitingKind === "extra_context"
|
||||||
? "Updating the draft…"
|
? "Updating the draft…"
|
||||||
|
|
@ -564,14 +564,14 @@ export function BoardOnboardingChat({
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{lastSubmittedAnswer ? (
|
{lastSubmittedAnswer ? (
|
||||||
<p className="mt-2 text-xs text-slate-600">
|
<p className="mt-2 text-xs text-muted-foreground">
|
||||||
Sent:{" "}
|
Sent:{" "}
|
||||||
<span className="font-medium text-slate-900">
|
<span className="font-medium text-foreground">
|
||||||
{lastSubmittedAnswer}
|
{lastSubmittedAnswer}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
This usually takes a few seconds.
|
This usually takes a few seconds.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -611,7 +611,7 @@ export function BoardOnboardingChat({
|
||||||
}}
|
}}
|
||||||
disabled={loading || isAwaitingAgent}
|
disabled={loading || isAwaitingAgent}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Tip: press Enter to send. Shift+Enter for a newline.
|
Tip: press Enter to send. Shift+Enter for a newline.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -631,16 +631,16 @@ export function BoardOnboardingChat({
|
||||||
{loading ? "Sending..." : isAwaitingAgent ? "Waiting..." : "Next"}
|
{loading ? "Sending..." : isAwaitingAgent ? "Waiting..." : "Next"}
|
||||||
</Button>
|
</Button>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<p className="text-xs text-slate-500">Sending your answer…</p>
|
<p className="text-xs text-muted-foreground">Sending your answer…</p>
|
||||||
) : isAwaitingAgent ? (
|
) : isAwaitingAgent ? (
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Waiting for the agent to respond…
|
Waiting for the agent to respond…
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-600">
|
<div className="rounded-lg border border-border bg-muted p-3 text-sm text-muted-foreground">
|
||||||
{loading
|
{loading
|
||||||
? "Waiting for the lead agent..."
|
? "Waiting for the lead agent..."
|
||||||
: "Preparing onboarding..."}
|
: "Preparing onboarding..."}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ export function ActivityFeed<TItem extends FeedItem>({
|
||||||
renderItem,
|
renderItem,
|
||||||
}: ActivityFeedProps<TItem>) {
|
}: ActivityFeedProps<TItem>) {
|
||||||
if (isLoading && items.length === 0) {
|
if (isLoading && items.length === 0) {
|
||||||
return <p className="text-sm text-slate-500">Loading feed…</p>;
|
return <p className="text-sm text-muted-foreground">Loading feed…</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasError = errorMessage !== null && errorMessage !== undefined;
|
const hasError = errorMessage !== null && errorMessage !== undefined;
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-slate-200 bg-white p-4 text-sm text-slate-700 shadow-sm">
|
<div className="rounded-lg border border-border bg-card p-4 text-sm text-muted-foreground shadow-sm">
|
||||||
{errorMessage || "Unable to load feed."}
|
{errorMessage || "Unable to load feed."}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -32,11 +32,11 @@ export function ActivityFeed<TItem extends FeedItem>({
|
||||||
|
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white p-10 text-center shadow-sm">
|
<div className="rounded-xl border border-border bg-card p-10 text-center shadow-sm">
|
||||||
<p className="text-sm font-medium text-slate-900">
|
<p className="text-sm font-medium text-foreground">
|
||||||
Waiting for new activity…
|
Waiting for new activity…
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm text-slate-500">
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
When updates happen, they will show up here.
|
When updates happen, they will show up here.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ type AgentsTableProps = {
|
||||||
|
|
||||||
const DEFAULT_EMPTY_ICON = (
|
const DEFAULT_EMPTY_ICON = (
|
||||||
<svg
|
<svg
|
||||||
className="h-16 w-16 text-slate-300"
|
className="h-16 w-16 text-muted-foreground/50"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|
@ -120,7 +120,7 @@ export function AgentsTable({
|
||||||
accessorKey: "openclaw_session_id",
|
accessorKey: "openclaw_session_id",
|
||||||
header: "Session",
|
header: "Session",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-sm text-slate-700">
|
<span className="text-sm text-muted-foreground">
|
||||||
{truncate(row.original.openclaw_session_id)}
|
{truncate(row.original.openclaw_session_id)}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
|
@ -131,7 +131,7 @@ export function AgentsTable({
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const boardId = row.original.board_id;
|
const boardId = row.original.board_id;
|
||||||
if (!boardId) {
|
if (!boardId) {
|
||||||
return <span className="text-sm text-slate-700">—</span>;
|
return <span className="text-sm text-muted-foreground">—</span>;
|
||||||
}
|
}
|
||||||
const boardName = boardNameById.get(boardId) ?? boardId;
|
const boardName = boardNameById.get(boardId) ?? boardId;
|
||||||
return linkifyCell({
|
return linkifyCell({
|
||||||
|
|
@ -186,7 +186,7 @@ export function AgentsTable({
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
rowClassName="hover:bg-slate-50"
|
rowClassName="hover:bg-muted"
|
||||||
cellClassName="px-6 py-4"
|
cellClassName="px-6 py-4"
|
||||||
emptyState={
|
emptyState={
|
||||||
emptyState
|
emptyState
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ const MARKDOWN_CODE_COMPONENTS: Components = {
|
||||||
pre: ({ node: _node, className, ...props }) => (
|
pre: ({ node: _node, className, ...props }) => (
|
||||||
<pre
|
<pre
|
||||||
className={cn(
|
className={cn(
|
||||||
"my-3 overflow-x-auto rounded-lg bg-slate-950 p-3 text-xs leading-relaxed text-slate-100",
|
"my-3 overflow-x-auto rounded-lg bg-foreground p-3 text-xs leading-relaxed text-background",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -134,7 +134,7 @@ const MARKDOWN_CODE_COMPONENTS: Components = {
|
||||||
return (
|
return (
|
||||||
<code
|
<code
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded bg-slate-100 px-1 py-0.5 font-mono text-[0.85em] text-slate-900",
|
"rounded bg-accent px-1 py-0.5 font-mono text-[0.85em] text-foreground",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -160,7 +160,7 @@ const MARKDOWN_TABLE_COMPONENTS: Components = {
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
thead: ({ node: _node, className, ...props }) => (
|
thead: ({ node: _node, className, ...props }) => (
|
||||||
<thead className={cn("bg-slate-50", className)} {...props} />
|
<thead className={cn("bg-muted", className)} {...props} />
|
||||||
),
|
),
|
||||||
tbody: ({ node: _node, className, ...props }) => (
|
tbody: ({ node: _node, className, ...props }) => (
|
||||||
<tbody className={cn("divide-y divide-slate-100", className)} {...props} />
|
<tbody className={cn("divide-y divide-slate-100", className)} {...props} />
|
||||||
|
|
@ -171,7 +171,7 @@ const MARKDOWN_TABLE_COMPONENTS: Components = {
|
||||||
th: ({ node: _node, className, children, ...props }) => (
|
th: ({ node: _node, className, children, ...props }) => (
|
||||||
<th
|
<th
|
||||||
className={cn(
|
className={cn(
|
||||||
"border border-slate-200 px-3 py-2 text-left text-xs font-semibold",
|
"border border-border px-3 py-2 text-left text-xs font-semibold",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -181,7 +181,7 @@ const MARKDOWN_TABLE_COMPONENTS: Components = {
|
||||||
),
|
),
|
||||||
td: ({ node: _node, className, children, ...props }) => (
|
td: ({ node: _node, className, children, ...props }) => (
|
||||||
<td
|
<td
|
||||||
className={cn("border border-slate-200 px-3 py-2 align-top", className)}
|
className={cn("border border-border px-3 py-2 align-top", className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{renderMentions(children)}
|
{renderMentions(children)}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export function PipelineIcon({ className }: PipelineIconProps) {
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
className ??
|
className ??
|
||||||
"grid h-10 w-10 place-items-center rounded-lg bg-[color:var(--accent)] text-white shadow-sm"
|
"grid h-10 w-10 place-items-center rounded-lg bg-primary text-primary-foreground shadow-sm"
|
||||||
}
|
}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const AGENT_STATUS_DOT_CLASS_BY_STATUS: Record<string, string> = {
|
||||||
provisioning: "bg-amber-500",
|
provisioning: "bg-amber-500",
|
||||||
updating: "bg-sky-500",
|
updating: "bg-sky-500",
|
||||||
deleting: "bg-rose-500",
|
deleting: "bg-rose-500",
|
||||||
offline: "bg-slate-400",
|
offline: "bg-muted-foreground",
|
||||||
};
|
};
|
||||||
|
|
||||||
const APPROVAL_STATUS_DOT_CLASS_BY_STATUS: Record<string, string> = {
|
const APPROVAL_STATUS_DOT_CLASS_BY_STATUS: Record<string, string> = {
|
||||||
|
|
@ -18,7 +18,7 @@ const APPROVAL_STATUS_DOT_CLASS_BY_STATUS: Record<string, string> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const TASK_STATUS_DOT_CLASS_BY_STATUS: Record<string, string> = {
|
const TASK_STATUS_DOT_CLASS_BY_STATUS: Record<string, string> = {
|
||||||
inbox: "bg-slate-400",
|
inbox: "bg-muted-foreground",
|
||||||
in_progress: "bg-purple-500",
|
in_progress: "bg-purple-500",
|
||||||
review: "bg-indigo-500",
|
review: "bg-indigo-500",
|
||||||
done: "bg-emerald-500",
|
done: "bg-emerald-500",
|
||||||
|
|
@ -34,9 +34,9 @@ const STATUS_DOT_CLASS_BY_VARIANT: Record<
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_STATUS_DOT_CLASS: Record<StatusDotVariant, string> = {
|
const DEFAULT_STATUS_DOT_CLASS: Record<StatusDotVariant, string> = {
|
||||||
agent: "bg-slate-300",
|
agent: "bg-muted-foreground/40",
|
||||||
approval: "bg-amber-500",
|
approval: "bg-amber-500",
|
||||||
task: "bg-slate-300",
|
task: "bg-muted-foreground/40",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const statusDotClass = (
|
export const statusDotClass = (
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ type AdminOnlyNoticeProps = {
|
||||||
|
|
||||||
export function AdminOnlyNotice({ message }: AdminOnlyNoticeProps) {
|
export function AdminOnlyNotice({ message }: AdminOnlyNoticeProps) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-6 py-5 text-sm text-slate-600 shadow-sm">
|
<div className="rounded-xl border border-border bg-card px-6 py-5 text-sm text-muted-foreground shadow-sm">
|
||||||
{message}
|
{message}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ export function SignedOutPanel({
|
||||||
buttonTestId,
|
buttonTestId,
|
||||||
}: SignedOutPanelProps) {
|
}: SignedOutPanelProps) {
|
||||||
return (
|
return (
|
||||||
<div className="col-span-1 md:col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-slate-50 p-10 text-center">
|
<div className="col-span-1 md:col-span-2 flex min-h-[calc(100vh-64px)] items-center justify-center bg-muted p-10 text-center">
|
||||||
<div className="rounded-xl border border-slate-200 bg-white px-4 py-4 md:px-8 md:py-6 shadow-sm">
|
<div className="rounded-xl border border-border bg-card px-4 py-4 md:px-8 md:py-6 shadow-sm">
|
||||||
<p className="text-sm text-slate-600">{message}</p>
|
<p className="text-sm text-muted-foreground">{message}</p>
|
||||||
<SignInButton
|
<SignInButton
|
||||||
mode={mode}
|
mode={mode}
|
||||||
forceRedirectUrl={forceRedirectUrl}
|
forceRedirectUrl={forceRedirectUrl}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ type BoardGroupsTableProps = {
|
||||||
|
|
||||||
const DEFAULT_EMPTY_ICON = (
|
const DEFAULT_EMPTY_ICON = (
|
||||||
<svg
|
<svg
|
||||||
className="h-16 w-16 text-slate-300"
|
className="h-16 w-16 text-muted-foreground/50"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|
@ -94,8 +94,8 @@ export function BoardGroupsTable({
|
||||||
label: row.original.name,
|
label: row.original.name,
|
||||||
subtitle: row.original.description ?? "No description",
|
subtitle: row.original.description ?? "No description",
|
||||||
subtitleClassName: row.original.description
|
subtitleClassName: row.original.description
|
||||||
? "mt-1 line-clamp-2 text-xs text-slate-500"
|
? "mt-1 line-clamp-2 text-xs text-muted-foreground"
|
||||||
: "mt-1 text-xs text-slate-400",
|
: "mt-1 text-xs text-muted-foreground/70",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -129,7 +129,7 @@ export function BoardGroupsTable({
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
stickyHeader={stickyHeader}
|
stickyHeader={stickyHeader}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
rowClassName="transition hover:bg-slate-50"
|
rowClassName="transition hover:bg-muted"
|
||||||
cellClassName="px-3 py-3 md:px-6 md:py-4 align-top"
|
cellClassName="px-3 py-3 md:px-6 md:py-4 align-top"
|
||||||
rowActions={
|
rowActions={
|
||||||
showActions
|
showActions
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ type BoardsTableProps = {
|
||||||
|
|
||||||
const DEFAULT_EMPTY_ICON = (
|
const DEFAULT_EMPTY_ICON = (
|
||||||
<svg
|
<svg
|
||||||
className="h-16 w-16 text-slate-300"
|
className="h-16 w-16 text-muted-foreground/50"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|
@ -117,7 +117,7 @@ export function BoardsTable({
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const groupId = row.original.board_group_id;
|
const groupId = row.original.board_group_id;
|
||||||
if (!groupId) {
|
if (!groupId) {
|
||||||
return <span className="text-sm text-slate-400">—</span>;
|
return <span className="text-sm text-muted-foreground/70">—</span>;
|
||||||
}
|
}
|
||||||
const group = groupById.get(groupId);
|
const group = groupById.get(groupId);
|
||||||
const label = group?.name ?? compactId(groupId);
|
const label = group?.name ?? compactId(groupId);
|
||||||
|
|
@ -161,7 +161,7 @@ export function BoardsTable({
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
stickyHeader={stickyHeader}
|
stickyHeader={stickyHeader}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
rowClassName="transition hover:bg-slate-50"
|
rowClassName="transition hover:bg-muted"
|
||||||
cellClassName="px-3 py-3 md:px-6 md:py-4 align-top"
|
cellClassName="px-3 py-3 md:px-6 md:py-4 align-top"
|
||||||
rowActions={
|
rowActions={
|
||||||
showActions
|
showActions
|
||||||
|
|
|
||||||
|
|
@ -314,10 +314,10 @@ function ChartTooltipCard({
|
||||||
<ChartTooltipContent
|
<ChartTooltipContent
|
||||||
{...props}
|
{...props}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border border-gray-200 bg-white px-3 py-2 text-sm shadow-lg",
|
"border border-border bg-popover px-3 py-2 text-sm text-popover-foreground shadow-lg",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
labelClassName={cn("text-sm font-semibold text-gray-900", labelClassName)}
|
labelClassName={cn("text-sm font-semibold text-foreground", labelClassName)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -439,7 +439,7 @@ function ChartLegendItem({
|
||||||
aria-pressed={!isHidden}
|
aria-pressed={!isHidden}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-2 text-gray-600 transition-opacity [&>svg]:h-3 [&>svg]:w-3 cursor-pointer disabled:cursor-not-allowed disabled:opacity-60",
|
"flex items-center gap-2 text-muted-foreground transition-opacity [&>svg]:h-3 [&>svg]:w-3 cursor-pointer disabled:cursor-not-allowed disabled:opacity-60",
|
||||||
isHidden && "opacity-50",
|
isHidden && "opacity-50",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|
@ -453,7 +453,7 @@ function ChartLegendItem({
|
||||||
style={{ backgroundColor: resolvedColor }}
|
style={{ backgroundColor: resolvedColor }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span className={cn(isHidden && "line-through text-gray-400")}>
|
<span className={cn(isHidden && "line-through text-muted-foreground/70")}>
|
||||||
{resolvedLabel}
|
{resolvedLabel}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ const SparklineTooltip = ({
|
||||||
: "Day";
|
: "Day";
|
||||||
const prefix = resolvedLabel ?? (dayIndex ? `${label} ${dayIndex}` : "");
|
const prefix = resolvedLabel ?? (dayIndex ? `${label} ${dayIndex}` : "");
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md border border-gray-200 bg-white px-2 py-1 text-xs font-medium text-gray-700 shadow-sm">
|
<div className="rounded-md border border-border bg-popover px-2 py-1 text-xs font-medium text-popover-foreground shadow-sm">
|
||||||
{prefix ? `${prefix}: ` : ""}
|
{prefix ? `${prefix}: ` : ""}
|
||||||
{formatSparkValue(rawValue)}
|
{formatSparkValue(rawValue)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -85,8 +85,8 @@ export default function MetricSparkline({
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = buildSparkData(values);
|
const data = buildSparkData(values);
|
||||||
const strokeColor = "#60a5fa";
|
const strokeColor = "var(--accent)";
|
||||||
const fillColor = "#bfdbfe";
|
const fillColor = "var(--accent-soft)";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("h-8 w-full", className)}>
|
<div className={cn("h-8 w-full", className)}>
|
||||||
|
|
|
||||||
|
|
@ -93,15 +93,15 @@ export function CustomFieldForm({
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="max-w-3xl rounded-xl border border-slate-200 bg-white p-6 shadow-sm space-y-6"
|
className="max-w-3xl rounded-xl border border-border bg-card p-6 shadow-sm space-y-6"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Basic configuration
|
Basic configuration
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4 grid gap-6 md:grid-cols-2">
|
<div className="mt-4 grid gap-6 md:grid-cols-2">
|
||||||
<label className="space-y-1">
|
<label className="space-y-1">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
Field key
|
Field key
|
||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -118,14 +118,14 @@ export function CustomFieldForm({
|
||||||
required={mode === "create"}
|
required={mode === "create"}
|
||||||
/>
|
/>
|
||||||
{mode === "edit" ? (
|
{mode === "edit" ? (
|
||||||
<span className="text-xs text-slate-500">
|
<span className="text-xs text-muted-foreground">
|
||||||
Field key cannot be changed after creation.
|
Field key cannot be changed after creation.
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="space-y-1">
|
<label className="space-y-1">
|
||||||
<span className="text-sm font-semibold text-slate-900">Label</span>
|
<span className="text-sm font-semibold text-foreground">Label</span>
|
||||||
<Input
|
<Input
|
||||||
value={formState.label}
|
value={formState.label}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
|
|
@ -138,7 +138,7 @@ export function CustomFieldForm({
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="space-y-1">
|
<label className="space-y-1">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
Field type
|
Field type
|
||||||
</span>
|
</span>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -165,7 +165,7 @@ export function CustomFieldForm({
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="space-y-1">
|
<label className="space-y-1">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
UI visible
|
UI visible
|
||||||
</span>
|
</span>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -192,7 +192,7 @@ export function CustomFieldForm({
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label className="mt-4 flex items-center gap-2 text-sm text-slate-700">
|
<label className="mt-4 flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={formState.required}
|
checked={formState.required}
|
||||||
|
|
@ -209,12 +209,12 @@ export function CustomFieldForm({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Validation and defaults
|
Validation and defaults
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4 space-y-4">
|
<div className="mt-4 space-y-4">
|
||||||
<label className="space-y-1">
|
<label className="space-y-1">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
Validation regex
|
Validation regex
|
||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -231,13 +231,13 @@ export function CustomFieldForm({
|
||||||
!STRING_VALIDATION_FIELD_TYPES.has(formState.fieldType)
|
!STRING_VALIDATION_FIELD_TYPES.has(formState.fieldType)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Supported for text/date/date-time/url fields.
|
Supported for text/date/date-time/url fields.
|
||||||
</p>
|
</p>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="space-y-1">
|
<label className="space-y-1">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
Default value
|
Default value
|
||||||
</span>
|
</span>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -255,7 +255,7 @@ export function CustomFieldForm({
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="space-y-1">
|
<label className="space-y-1">
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-foreground">
|
||||||
Description
|
Description
|
||||||
</span>
|
</span>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -276,10 +276,10 @@ export function CustomFieldForm({
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Board bindings
|
Board bindings
|
||||||
</p>
|
</p>
|
||||||
<span className="text-xs text-slate-500">
|
<span className="text-xs text-muted-foreground">
|
||||||
{selectedBoardIds.size} selected
|
{selectedBoardIds.size} selected
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -290,9 +290,9 @@ export function CustomFieldForm({
|
||||||
placeholder="Search boards..."
|
placeholder="Search boards..."
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
/>
|
/>
|
||||||
<div className="max-h-64 overflow-auto rounded-xl border border-slate-200 bg-slate-50/40">
|
<div className="max-h-64 overflow-auto rounded-xl border border-border bg-muted/40">
|
||||||
{boardsLoading ? (
|
{boardsLoading ? (
|
||||||
<div className="px-4 py-6 text-sm text-slate-500">
|
<div className="px-4 py-6 text-sm text-muted-foreground">
|
||||||
Loading boards…
|
Loading boards…
|
||||||
</div>
|
</div>
|
||||||
) : boardsError ? (
|
) : boardsError ? (
|
||||||
|
|
@ -300,7 +300,7 @@ export function CustomFieldForm({
|
||||||
{boardsError}
|
{boardsError}
|
||||||
</div>
|
</div>
|
||||||
) : filteredBoards.length === 0 ? (
|
) : filteredBoards.length === 0 ? (
|
||||||
<div className="px-4 py-6 text-sm text-slate-500">
|
<div className="px-4 py-6 text-sm text-muted-foreground">
|
||||||
No boards found.
|
No boards found.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -312,7 +312,7 @@ export function CustomFieldForm({
|
||||||
<label className="flex cursor-pointer items-start gap-3">
|
<label className="flex cursor-pointer items-start gap-3">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="mt-1 h-4 w-4 rounded border-slate-300 text-blue-600"
|
className="mt-1 h-4 w-4 rounded border-input text-primary"
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setSelectedBoardIds((prev) => {
|
setSelectedBoardIds((prev) => {
|
||||||
|
|
@ -328,10 +328,10 @@ export function CustomFieldForm({
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
/>
|
/>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="truncate text-sm font-medium text-slate-900">
|
<p className="truncate text-sm font-medium text-foreground">
|
||||||
{board.name}
|
{board.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
{board.slug}
|
{board.slug}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -342,7 +342,7 @@ export function CustomFieldForm({
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
Required. The custom field appears on tasks in selected boards.
|
Required. The custom field appears on tasks in selected boards.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ type CustomFieldsTableProps = {
|
||||||
|
|
||||||
const DEFAULT_EMPTY_ICON = (
|
const DEFAULT_EMPTY_ICON = (
|
||||||
<svg
|
<svg
|
||||||
className="h-16 w-16 text-slate-300"
|
className="h-16 w-16 text-muted-foreground/50"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|
@ -77,13 +77,13 @@ export function CustomFieldsTable({
|
||||||
header: "Field",
|
header: "Field",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-semibold text-slate-900">
|
<p className="text-sm font-semibold text-foreground">
|
||||||
{row.original.label || row.original.field_key}
|
{row.original.label || row.original.field_key}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 font-mono text-xs text-slate-500">
|
<p className="mt-1 font-mono text-xs text-muted-foreground">
|
||||||
key: {row.original.field_key}
|
key: {row.original.field_key}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs text-slate-500">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
{row.original.description || "No description"}
|
{row.original.description || "No description"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -93,7 +93,7 @@ export function CustomFieldsTable({
|
||||||
accessorKey: "required",
|
accessorKey: "required",
|
||||||
header: "Required",
|
header: "Required",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-sm text-slate-700">
|
<span className="text-sm text-muted-foreground">
|
||||||
{row.original.required === true ? "Required" : "Optional"}
|
{row.original.required === true ? "Required" : "Optional"}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
|
@ -102,7 +102,7 @@ export function CustomFieldsTable({
|
||||||
accessorKey: "field_type",
|
accessorKey: "field_type",
|
||||||
header: "Type",
|
header: "Type",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-sm text-slate-700">
|
<span className="text-sm text-muted-foreground">
|
||||||
{row.original.field_type}
|
{row.original.field_type}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
|
@ -111,7 +111,7 @@ export function CustomFieldsTable({
|
||||||
accessorKey: "ui_visibility",
|
accessorKey: "ui_visibility",
|
||||||
header: "UI visible",
|
header: "UI visible",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-sm text-slate-700">
|
<span className="text-sm text-muted-foreground">
|
||||||
{row.original.ui_visibility}
|
{row.original.ui_visibility}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
|
@ -121,7 +121,7 @@ export function CustomFieldsTable({
|
||||||
header: "Default value",
|
header: "Default value",
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<p className="font-mono text-xs break-all text-slate-700">
|
<p className="font-mono text-xs break-all text-muted-foreground">
|
||||||
{formatCustomFieldDefaultValue(row.original.default_value) || "—"}
|
{formatCustomFieldDefaultValue(row.original.default_value) || "—"}
|
||||||
</p>
|
</p>
|
||||||
),
|
),
|
||||||
|
|
@ -152,7 +152,7 @@ export function CustomFieldsTable({
|
||||||
table={table}
|
table={table}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
stickyHeader={stickyHeader}
|
stickyHeader={stickyHeader}
|
||||||
rowClassName="transition hover:bg-slate-50"
|
rowClassName="transition hover:bg-muted"
|
||||||
cellClassName="px-6 py-4 align-top"
|
cellClassName="px-6 py-4 align-top"
|
||||||
rowActions={
|
rowActions={
|
||||||
editHref || onDelete
|
editHref || onDelete
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@ export function GatewayForm({
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
|
className="space-y-6 rounded-xl border border-border bg-card p-6 shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Gateway name <span className="text-red-500">*</span>
|
Gateway name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -76,7 +76,7 @@ export function GatewayForm({
|
||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Gateway URL <span className="text-red-500">*</span>
|
Gateway URL <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
|
@ -95,7 +95,7 @@ export function GatewayForm({
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Gateway token
|
Gateway token
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -109,7 +109,7 @@ export function GatewayForm({
|
||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Workspace root <span className="text-red-500">*</span>
|
Workspace root <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -121,10 +121,10 @@ export function GatewayForm({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Disable device pairing
|
Disable device pairing
|
||||||
</label>
|
</label>
|
||||||
<label className="flex h-10 items-center gap-3 px-1 text-sm text-slate-900">
|
<label className="flex h-10 items-center gap-3 px-1 text-sm text-foreground">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|
@ -137,11 +137,11 @@ export function GatewayForm({
|
||||||
className={`inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
className={`inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
||||||
disableDevicePairing
|
disableDevicePairing
|
||||||
? "border-emerald-600 bg-emerald-600"
|
? "border-emerald-600 bg-emerald-600"
|
||||||
: "border-slate-300 bg-slate-200"
|
: "border-input bg-border"
|
||||||
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`inline-block h-5 w-5 rounded-full bg-white shadow-sm transition ${
|
className={`inline-block h-5 w-5 rounded-full bg-card shadow-sm transition ${
|
||||||
disableDevicePairing ? "translate-x-5" : "translate-x-0.5"
|
disableDevicePairing ? "translate-x-5" : "translate-x-0.5"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
@ -151,10 +151,10 @@ export function GatewayForm({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-slate-900">
|
<label className="text-sm font-medium text-foreground">
|
||||||
Allow self-signed TLS certificates
|
Allow self-signed TLS certificates
|
||||||
</label>
|
</label>
|
||||||
<label className="flex h-10 items-center gap-3 px-1 text-sm text-slate-900">
|
<label className="flex h-10 items-center gap-3 px-1 text-sm text-foreground">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|
@ -165,11 +165,11 @@ export function GatewayForm({
|
||||||
className={`inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
className={`inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition ${
|
||||||
allowInsecureTls
|
allowInsecureTls
|
||||||
? "border-emerald-600 bg-emerald-600"
|
? "border-emerald-600 bg-emerald-600"
|
||||||
: "border-slate-300 bg-slate-200"
|
: "border-input bg-border"
|
||||||
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
} ${isLoading ? "cursor-not-allowed opacity-60" : "cursor-pointer"}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`inline-block h-5 w-5 rounded-full bg-white shadow-sm transition ${
|
className={`inline-block h-5 w-5 rounded-full bg-card shadow-sm transition ${
|
||||||
allowInsecureTls ? "translate-x-5" : "translate-x-0.5"
|
allowInsecureTls ? "translate-x-5" : "translate-x-0.5"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ type GatewaysTableProps = {
|
||||||
|
|
||||||
const DEFAULT_EMPTY_ICON = (
|
const DEFAULT_EMPTY_ICON = (
|
||||||
<svg
|
<svg
|
||||||
className="h-16 w-16 text-slate-300"
|
className="h-16 w-16 text-muted-foreground/50"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|
@ -100,7 +100,7 @@ export function GatewaysTable({
|
||||||
accessorKey: "workspace_root",
|
accessorKey: "workspace_root",
|
||||||
header: "Workspace root",
|
header: "Workspace root",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-sm text-slate-700">
|
<span className="text-sm text-muted-foreground">
|
||||||
{truncate(row.original.workspace_root, 28)}
|
{truncate(row.original.workspace_root, 28)}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ export function BoardForgejoRepositoryLinks({
|
||||||
errorMessage={unlinkError}
|
errorMessage={unlinkError}
|
||||||
confirmLabel="Unlink Repository"
|
confirmLabel="Unlink Repository"
|
||||||
confirmingLabel="Unlinking..."
|
confirmingLabel="Unlinking..."
|
||||||
confirmClassName="bg-[color:var(--danger)] text-white hover:bg-[color:var(--danger)]/90"
|
confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
cancelLabel="Keep Linked"
|
cancelLabel="Keep Linked"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ type DependencyBannerVariant = "blocked" | "resolved";
|
||||||
|
|
||||||
const toneClassByVariant: Record<DependencyBannerVariant, string> = {
|
const toneClassByVariant: Record<DependencyBannerVariant, string> = {
|
||||||
blocked: "border-rose-200 bg-rose-50 text-rose-700",
|
blocked: "border-rose-200 bg-rose-50 text-rose-700",
|
||||||
resolved: "border-blue-200 bg-blue-50 text-blue-700",
|
resolved: "border-primary/30 bg-primary/10 text-primary",
|
||||||
};
|
};
|
||||||
|
|
||||||
export function DependencyBanner({
|
export function DependencyBanner({
|
||||||
|
|
@ -52,12 +52,12 @@ export function DependencyBanner({
|
||||||
? "border-rose-200 bg-rose-50 hover:bg-rose-100/40"
|
? "border-rose-200 bg-rose-50 hover:bg-rose-100/40"
|
||||||
: isDone
|
: isDone
|
||||||
? "border-emerald-200 bg-emerald-50 hover:bg-emerald-100/40"
|
? "border-emerald-200 bg-emerald-50 hover:bg-emerald-100/40"
|
||||||
: "border-slate-200 bg-white hover:bg-slate-50",
|
: "border-border bg-card hover:bg-muted",
|
||||||
dependency.disabled && "cursor-not-allowed opacity-60",
|
dependency.disabled && "cursor-not-allowed opacity-60",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<p className="truncate text-sm font-medium text-slate-900">
|
<p className="truncate text-sm font-medium text-foreground">
|
||||||
{dependency.title}
|
{dependency.title}
|
||||||
</p>
|
</p>
|
||||||
<span
|
<span
|
||||||
|
|
@ -67,7 +67,7 @@ export function DependencyBanner({
|
||||||
? "text-rose-700"
|
? "text-rose-700"
|
||||||
: isDone
|
: isDone
|
||||||
? "text-emerald-700"
|
? "text-emerald-700"
|
||||||
: "text-slate-500",
|
: "text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{dependency.statusLabel}
|
{dependency.statusLabel}
|
||||||
|
|
@ -77,7 +77,7 @@ export function DependencyBanner({
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-slate-500">{emptyMessage}</p>
|
<p className="text-sm text-muted-foreground">{emptyMessage}</p>
|
||||||
)}
|
)}
|
||||||
{children ? (
|
{children ? (
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export function TaskCard({
|
||||||
if (normalized === "low") {
|
if (normalized === "low") {
|
||||||
return "bg-emerald-100 text-emerald-700";
|
return "bg-emerald-100 text-emerald-700";
|
||||||
}
|
}
|
||||||
return "bg-slate-100 text-slate-600";
|
return "bg-accent text-muted-foreground";
|
||||||
};
|
};
|
||||||
|
|
||||||
const priorityLabel = priority ? priority.toUpperCase() : "MEDIUM";
|
const priorityLabel = priority ? priority.toUpperCase() : "MEDIUM";
|
||||||
|
|
@ -70,7 +70,7 @@ export function TaskCard({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"group relative cursor-pointer rounded-lg border border-slate-200 bg-white p-4 shadow-sm transition-all hover:-translate-y-0.5 hover:border-slate-300 hover:shadow-md",
|
"group relative cursor-pointer rounded-lg border border-border bg-card p-4 shadow-sm transition-all hover:-translate-y-0.5 hover:border-input hover:shadow-md",
|
||||||
isDragging && "opacity-60 shadow-none",
|
isDragging && "opacity-60 shadow-none",
|
||||||
hasPendingApproval && "border-amber-200 bg-amber-50/40",
|
hasPendingApproval && "border-amber-200 bg-amber-50/40",
|
||||||
isBlocked && "border-rose-200 bg-rose-50/50",
|
isBlocked && "border-rose-200 bg-rose-50/50",
|
||||||
|
|
@ -99,7 +99,7 @@ export function TaskCard({
|
||||||
) : null}
|
) : null}
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div className="min-w-0 space-y-2">
|
<div className="min-w-0 space-y-2">
|
||||||
<p className="text-sm font-medium text-slate-900 line-clamp-2 break-words">
|
<p className="text-sm font-medium text-foreground line-clamp-2 break-words">
|
||||||
{title}
|
{title}
|
||||||
</p>
|
</p>
|
||||||
{isBlocked ? (
|
{isBlocked ? (
|
||||||
|
|
@ -125,7 +125,7 @@ export function TaskCard({
|
||||||
{visibleTags.map((tag) => (
|
{visibleTags.map((tag) => (
|
||||||
<span
|
<span
|
||||||
key={tag.id}
|
key={tag.id}
|
||||||
className="inline-flex items-center gap-1 rounded-full border border-slate-200 bg-white px-2 py-0.5 text-[10px] font-semibold text-slate-700"
|
className="inline-flex items-center gap-1 rounded-full border border-border bg-card px-2 py-0.5 text-[10px] font-semibold text-muted-foreground"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="h-1.5 w-1.5 rounded-full"
|
className="h-1.5 w-1.5 rounded-full"
|
||||||
|
|
@ -135,7 +135,7 @@ export function TaskCard({
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
{tags.length > visibleTags.length ? (
|
{tags.length > visibleTags.length ? (
|
||||||
<span className="text-[10px] font-semibold text-slate-500">
|
<span className="text-[10px] font-semibold text-muted-foreground">
|
||||||
+{tags.length - visibleTags.length}
|
+{tags.length - visibleTags.length}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
@ -146,16 +146,16 @@ export function TaskCard({
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center rounded-full px-2 py-1 text-[10px] font-semibold uppercase tracking-wide",
|
"inline-flex items-center rounded-full px-2 py-1 text-[10px] font-semibold uppercase tracking-wide",
|
||||||
priorityBadge(priority) ?? "bg-slate-100 text-slate-600",
|
priorityBadge(priority) ?? "bg-accent text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{priorityLabel}
|
{priorityLabel}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 flex items-center justify-between text-xs text-slate-500">
|
<div className="mt-3 flex items-center justify-between text-xs text-muted-foreground">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<UserCircle className="h-4 w-4 text-slate-400" />
|
<UserCircle className="h-4 w-4 text-muted-foreground/70" />
|
||||||
<span>{assignee ?? "Unassigned"}</span>
|
<span>{assignee ?? "Unassigned"}</span>
|
||||||
</div>
|
</div>
|
||||||
{due ? (
|
{due ? (
|
||||||
|
|
@ -168,7 +168,7 @@ export function TaskCard({
|
||||||
<CalendarClock
|
<CalendarClock
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-4 w-4",
|
"h-4 w-4",
|
||||||
isOverdue ? "text-rose-500" : "text-slate-400",
|
isOverdue ? "text-rose-500" : "text-muted-foreground/70",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<span>{due}</span>
|
<span>{due}</span>
|
||||||
|
|
|
||||||
|
|
@ -51,17 +51,17 @@ const columns: Array<{
|
||||||
{
|
{
|
||||||
title: "Inbox",
|
title: "Inbox",
|
||||||
status: "inbox",
|
status: "inbox",
|
||||||
dot: "bg-slate-400",
|
dot: "bg-muted-foreground",
|
||||||
accent: "hover:border-slate-400 hover:bg-slate-50",
|
accent: "hover:border-muted-foreground hover:bg-muted",
|
||||||
text: "group-hover:text-slate-700 text-slate-500",
|
text: "group-hover:text-muted-foreground text-muted-foreground",
|
||||||
badge: "bg-slate-100 text-slate-600",
|
badge: "bg-accent text-muted-foreground",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "In Progress",
|
title: "In Progress",
|
||||||
status: "in_progress",
|
status: "in_progress",
|
||||||
dot: "bg-purple-500",
|
dot: "bg-purple-500",
|
||||||
accent: "hover:border-purple-400 hover:bg-purple-50",
|
accent: "hover:border-purple-400 hover:bg-purple-50",
|
||||||
text: "group-hover:text-purple-600 text-slate-500",
|
text: "group-hover:text-purple-600 text-muted-foreground",
|
||||||
badge: "bg-purple-100 text-purple-700",
|
badge: "bg-purple-100 text-purple-700",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -69,7 +69,7 @@ const columns: Array<{
|
||||||
status: "review",
|
status: "review",
|
||||||
dot: "bg-indigo-500",
|
dot: "bg-indigo-500",
|
||||||
accent: "hover:border-indigo-400 hover:bg-indigo-50",
|
accent: "hover:border-indigo-400 hover:bg-indigo-50",
|
||||||
text: "group-hover:text-indigo-600 text-slate-500",
|
text: "group-hover:text-indigo-600 text-muted-foreground",
|
||||||
badge: "bg-indigo-100 text-indigo-700",
|
badge: "bg-indigo-100 text-indigo-700",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -77,7 +77,7 @@ const columns: Array<{
|
||||||
status: "done",
|
status: "done",
|
||||||
dot: "bg-green-500",
|
dot: "bg-green-500",
|
||||||
accent: "hover:border-green-400 hover:bg-green-50",
|
accent: "hover:border-green-400 hover:bg-green-50",
|
||||||
text: "group-hover:text-green-600 text-slate-500",
|
text: "group-hover:text-green-600 text-muted-foreground",
|
||||||
badge: "bg-emerald-100 text-emerald-700",
|
badge: "bg-emerald-100 text-emerald-700",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -424,17 +424,17 @@ export const TaskBoard = memo(function TaskBoard({
|
||||||
"sm:min-h-[calc(100vh-260px)]",
|
"sm:min-h-[calc(100vh-260px)]",
|
||||||
activeColumn === column.status &&
|
activeColumn === column.status &&
|
||||||
!readOnly &&
|
!readOnly &&
|
||||||
"ring-2 ring-slate-200",
|
"ring-2 ring-border",
|
||||||
)}
|
)}
|
||||||
onDrop={readOnly ? undefined : handleDrop(column.status)}
|
onDrop={readOnly ? undefined : handleDrop(column.status)}
|
||||||
onDragOver={readOnly ? undefined : handleDragOver(column.status)}
|
onDragOver={readOnly ? undefined : handleDragOver(column.status)}
|
||||||
onDragLeave={readOnly ? undefined : handleDragLeave(column.status)}
|
onDragLeave={readOnly ? undefined : handleDragLeave(column.status)}
|
||||||
>
|
>
|
||||||
<div className="column-header z-10 rounded-t-xl border border-b-0 border-slate-200 bg-white px-4 py-3 sm:sticky sm:top-0 sm:bg-white/80 sm:backdrop-blur">
|
<div className="column-header z-10 rounded-t-xl border border-b-0 border-border bg-card px-4 py-3 sm:sticky sm:top-0 sm:bg-card/80 sm:backdrop-blur">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className={cn("h-2 w-2 rounded-full", column.dot)} />
|
<span className={cn("h-2 w-2 rounded-full", column.dot)} />
|
||||||
<h3 className="text-sm font-semibold text-slate-900">
|
<h3 className="text-sm font-semibold text-foreground">
|
||||||
{column.title}
|
{column.title}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -448,7 +448,7 @@ export const TaskBoard = memo(function TaskBoard({
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{column.status === "review" && reviewCounts ? (
|
{column.status === "review" && reviewCounts ? (
|
||||||
<div className="mt-2 flex flex-wrap items-center gap-2 text-[10px] font-semibold uppercase tracking-wide text-slate-500">
|
<div className="mt-2 flex flex-wrap items-center gap-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">
|
||||||
{(
|
{(
|
||||||
[
|
[
|
||||||
{ key: "all", label: "All", count: reviewCounts.all },
|
{ key: "all", label: "All", count: reviewCounts.all },
|
||||||
|
|
@ -476,8 +476,8 @@ export const TaskBoard = memo(function TaskBoard({
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-full border px-2.5 py-1 transition",
|
"rounded-full border px-2.5 py-1 transition",
|
||||||
reviewBucket === option.key
|
reviewBucket === option.key
|
||||||
? "border-slate-900 bg-slate-900 text-white"
|
? "border-foreground bg-foreground text-background"
|
||||||
: "border-slate-200 bg-white text-slate-600 hover:border-slate-300 hover:bg-slate-50",
|
: "border-border bg-card text-muted-foreground hover:border-input hover:bg-muted",
|
||||||
)}
|
)}
|
||||||
aria-pressed={reviewBucket === option.key}
|
aria-pressed={reviewBucket === option.key}
|
||||||
>
|
>
|
||||||
|
|
@ -487,7 +487,7 @@ export const TaskBoard = memo(function TaskBoard({
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-b-xl border border-t-0 border-slate-200 bg-white p-3">
|
<div className="rounded-b-xl border border-t-0 border-border bg-card p-3">
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{filteredTasks.map((task) => {
|
{filteredTasks.map((task) => {
|
||||||
const dueState = resolveDueState(task);
|
const dueState = resolveDueState(task);
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export function UserMenu({
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex h-9 w-9 items-center justify-center overflow-hidden rounded-[10px] text-xs font-semibold text-white shadow-sm",
|
"relative flex h-9 w-9 items-center justify-center overflow-hidden rounded-[10px] text-xs font-semibold text-primary-foreground shadow-sm",
|
||||||
avatarUrl
|
avatarUrl
|
||||||
? "bg-[color:var(--neutral-200,var(--surface-muted))]"
|
? "bg-[color:var(--neutral-200,var(--surface-muted))]"
|
||||||
: "bg-gradient-to-br from-[color:var(--primary-navy,var(--accent))] to-[color:var(--secondary-navy,var(--accent-strong))]",
|
: "bg-gradient-to-br from-[color:var(--primary-navy,var(--accent))] to-[color:var(--secondary-navy,var(--accent-strong))]",
|
||||||
|
|
@ -99,7 +99,7 @@ export function UserMenu({
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-10 items-center justify-center overflow-hidden rounded-xl text-sm font-semibold text-white",
|
"flex h-10 w-10 items-center justify-center overflow-hidden rounded-xl text-sm font-semibold text-primary-foreground",
|
||||||
avatarUrl
|
avatarUrl
|
||||||
? "bg-[color:var(--neutral-200,var(--surface-muted))]"
|
? "bg-[color:var(--neutral-200,var(--surface-muted))]"
|
||||||
: "bg-gradient-to-br from-[color:var(--primary-navy,var(--accent))] to-[color:var(--secondary-navy,var(--accent-strong))]",
|
: "bg-gradient-to-br from-[color:var(--primary-navy,var(--accent))] to-[color:var(--secondary-navy,var(--accent-strong))]",
|
||||||
|
|
@ -141,7 +141,7 @@ export function UserMenu({
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/boards/new"
|
href="/boards/new"
|
||||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-[color:var(--primary-navy,var(--accent))] px-3 py-2 text-sm font-semibold text-white shadow-[0_2px_8px_rgba(10,22,40,0.15)] transition hover:bg-[color:var(--secondary-navy,var(--accent-strong))] hover:translate-y-[-1px] hover:shadow-[0_4px_12px_rgba(10,22,40,0.20)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent-teal,var(--accent))] focus-visible:ring-offset-2"
|
className="flex w-full items-center justify-center gap-2 rounded-xl bg-primary px-3 py-2 text-sm font-semibold text-primary-foreground shadow-[0_2px_8px_rgba(10,22,40,0.15)] transition hover:bg-[color:var(--accent-strong)] hover:translate-y-[-1px] hover:shadow-[0_4px_12px_rgba(10,22,40,0.20)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||||
onClick={() => setOpen(false)}
|
onClick={() => setOpen(false)}
|
||||||
>
|
>
|
||||||
<Plus className="h-4 w-4 opacity-90" />
|
<Plus className="h-4 w-4 opacity-90" />
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export function BoardAccessTable({
|
||||||
href: `/boards/${row.original.id}`,
|
href: `/boards/${row.original.id}`,
|
||||||
label: row.original.name,
|
label: row.original.name,
|
||||||
subtitle: row.original.slug,
|
subtitle: row.original.slug,
|
||||||
subtitleClassName: "mt-1 text-xs text-slate-500",
|
subtitleClassName: "mt-1 text-xs text-muted-foreground",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -97,8 +97,8 @@ export function BoardAccessTable({
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
table={table}
|
table={table}
|
||||||
rowClassName="border-t border-slate-200 hover:bg-slate-50"
|
rowClassName="border-t border-border hover:bg-muted"
|
||||||
headerClassName="bg-slate-50 text-[11px] uppercase tracking-wide text-slate-500"
|
headerClassName="bg-muted text-[11px] uppercase tracking-wide text-muted-foreground"
|
||||||
headerCellClassName="px-4 py-2 font-medium"
|
headerCellClassName="px-4 py-2 font-medium"
|
||||||
cellClassName="px-4 py-3"
|
cellClassName="px-4 py-3"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -97,14 +97,14 @@ export function MembersInvitesTable({
|
||||||
const display = memberDisplay(row.original.member);
|
const display = memberDisplay(row.original.member);
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-indigo-500 text-xs font-semibold text-white">
|
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-primary text-xs font-semibold text-primary-foreground">
|
||||||
{display.initials}
|
{display.initials}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-semibold text-slate-900">
|
<div className="text-sm font-semibold text-foreground">
|
||||||
{display.primary}
|
{display.primary}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-slate-500">
|
<div className="text-xs text-muted-foreground">
|
||||||
{display.secondary}
|
{display.secondary}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -114,14 +114,14 @@ export function MembersInvitesTable({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-slate-200 text-xs font-semibold text-slate-600">
|
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-border text-xs font-semibold text-muted-foreground">
|
||||||
{initialsFrom(row.original.invite.invited_email)}
|
{initialsFrom(row.original.invite.invited_email)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-semibold text-slate-900">
|
<div className="text-sm font-semibold text-foreground">
|
||||||
{row.original.invite.invited_email}
|
{row.original.invite.invited_email}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-slate-500">
|
<div className="text-xs text-muted-foreground">
|
||||||
Invited {formatTimestamp(row.original.invite.created_at)}
|
Invited {formatTimestamp(row.original.invite.created_at)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -155,7 +155,7 @@ export function MembersInvitesTable({
|
||||||
id: "access",
|
id: "access",
|
||||||
header: "Access",
|
header: "Access",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-slate-600">
|
<span className="text-muted-foreground">
|
||||||
{row.original.kind === "member"
|
{row.original.kind === "member"
|
||||||
? summarizeAccess(
|
? summarizeAccess(
|
||||||
row.original.member.all_boards_read,
|
row.original.member.all_boards_read,
|
||||||
|
|
@ -175,7 +175,7 @@ export function MembersInvitesTable({
|
||||||
if (row.original.kind === "member") {
|
if (row.original.kind === "member") {
|
||||||
const member = row.original.member;
|
const member = row.original.member;
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
return <span className="text-xs text-slate-400">Admin only</span>;
|
return <span className="text-xs text-muted-foreground/70">Admin only</span>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
|
|
@ -241,13 +241,13 @@ export function MembersInvitesTable({
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
loadingLabel="Loading members..."
|
loadingLabel="Loading members..."
|
||||||
emptyMessage="No members or invites yet."
|
emptyMessage="No members or invites yet."
|
||||||
headerClassName="bg-slate-50 text-[11px] uppercase tracking-wide text-slate-500"
|
headerClassName="bg-muted text-[11px] uppercase tracking-wide text-muted-foreground"
|
||||||
headerCellClassName="px-5 py-3 text-left font-medium"
|
headerCellClassName="px-5 py-3 text-left font-medium"
|
||||||
cellClassName="px-5 py-4"
|
cellClassName="px-5 py-4"
|
||||||
rowClassName={(row) =>
|
rowClassName={(row) =>
|
||||||
row.original.kind === "invite"
|
row.original.kind === "invite"
|
||||||
? "border-t border-slate-200 bg-slate-50/60"
|
? "border-t border-border bg-muted/60"
|
||||||
: "border-t border-slate-200 hover:bg-slate-50"
|
: "border-t border-border hover:bg-muted"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -138,13 +138,13 @@ export function MarketplaceSkillForm({
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
|
className="space-y-6 rounded-xl border border-border bg-card p-6 shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label
|
<label
|
||||||
htmlFor="source-url"
|
htmlFor="source-url"
|
||||||
className="text-xs font-semibold uppercase tracking-wider text-slate-500"
|
className="text-xs font-semibold uppercase tracking-wider text-muted-foreground"
|
||||||
>
|
>
|
||||||
{sourceLabel}
|
{sourceLabel}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -158,7 +158,7 @@ export function MarketplaceSkillForm({
|
||||||
disabled={isSubmitting || sourceUrlReadOnly}
|
disabled={isSubmitting || sourceUrlReadOnly}
|
||||||
/>
|
/>
|
||||||
{sourceUrlHelpText ? (
|
{sourceUrlHelpText ? (
|
||||||
<p className="text-xs text-slate-500">{sourceUrlHelpText}</p>
|
<p className="text-xs text-muted-foreground">{sourceUrlHelpText}</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -166,7 +166,7 @@ export function MarketplaceSkillForm({
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label
|
<label
|
||||||
htmlFor="skill-branch"
|
htmlFor="skill-branch"
|
||||||
className="text-xs font-semibold uppercase tracking-wider text-slate-500"
|
className="text-xs font-semibold uppercase tracking-wider text-muted-foreground"
|
||||||
>
|
>
|
||||||
{branchLabel}
|
{branchLabel}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -183,7 +183,7 @@ export function MarketplaceSkillForm({
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label
|
<label
|
||||||
htmlFor="skill-name"
|
htmlFor="skill-name"
|
||||||
className="text-xs font-semibold uppercase tracking-wider text-slate-500"
|
className="text-xs font-semibold uppercase tracking-wider text-muted-foreground"
|
||||||
>
|
>
|
||||||
{nameLabel}
|
{nameLabel}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -199,7 +199,7 @@ export function MarketplaceSkillForm({
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label
|
<label
|
||||||
htmlFor="skill-description"
|
htmlFor="skill-description"
|
||||||
className="text-xs font-semibold uppercase tracking-wider text-slate-500"
|
className="text-xs font-semibold uppercase tracking-wider text-muted-foreground"
|
||||||
>
|
>
|
||||||
{descriptionLabel}
|
{descriptionLabel}
|
||||||
</label>
|
</label>
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ function riskPillClassName(risk: string | null | undefined) {
|
||||||
case "critical":
|
case "critical":
|
||||||
return "bg-[color:rgba(244,63,94,0.16)] text-rose-800 border border-rose-200/70";
|
return "bg-[color:rgba(244,63,94,0.16)] text-rose-800 border border-rose-200/70";
|
||||||
case "unknown":
|
case "unknown":
|
||||||
return "bg-[color:rgba(148,163,184,0.16)] text-slate-700 border border-slate-200/80";
|
return "bg-[color:rgba(148,163,184,0.16)] text-muted-foreground border border-border/80";
|
||||||
default:
|
default:
|
||||||
return "bg-[color:rgba(99,102,241,0.16)] text-indigo-800 border border-indigo-200/70";
|
return "bg-[color:rgba(99,102,241,0.16)] text-indigo-800 border border-indigo-200/70";
|
||||||
}
|
}
|
||||||
|
|
@ -129,17 +129,17 @@ export function MarketplaceSkillsTable({
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onSkillClick(row.original)}
|
onClick={() => onSkillClick(row.original)}
|
||||||
className="text-sm font-medium text-blue-700 hover:text-blue-600 hover:underline"
|
className="text-sm font-medium text-primary hover:text-primary hover:underline"
|
||||||
>
|
>
|
||||||
{row.original.name}
|
{row.original.name}
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm font-medium text-slate-900">
|
<p className="text-sm font-medium text-foreground">
|
||||||
{row.original.name}
|
{row.original.name}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<p
|
<p
|
||||||
className="mt-1 line-clamp-2 text-xs text-slate-500"
|
className="mt-1 line-clamp-2 text-xs text-muted-foreground"
|
||||||
title={row.original.description || "No description provided."}
|
title={row.original.description || "No description provided."}
|
||||||
>
|
>
|
||||||
{row.original.description || "No description provided."}
|
{row.original.description || "No description provided."}
|
||||||
|
|
@ -155,7 +155,7 @@ export function MarketplaceSkillsTable({
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={packsHrefFromPackUrl(packUrl)}
|
href={packsHrefFromPackUrl(packUrl)}
|
||||||
className="inline-flex items-center gap-1 text-sm font-medium text-slate-700 hover:text-blue-600"
|
className="inline-flex items-center gap-1 text-sm font-medium text-muted-foreground hover:text-primary"
|
||||||
>
|
>
|
||||||
{truncate(packLabelFromUrl(packUrl), 40)}
|
{truncate(packLabelFromUrl(packUrl), 40)}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -166,7 +166,7 @@ export function MarketplaceSkillsTable({
|
||||||
accessorKey: "category",
|
accessorKey: "category",
|
||||||
header: "Category",
|
header: "Category",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-sm text-slate-700">
|
<span className="text-sm text-muted-foreground">
|
||||||
{row.original.category || "uncategorized"}
|
{row.original.category || "uncategorized"}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
|
@ -190,7 +190,7 @@ export function MarketplaceSkillsTable({
|
||||||
const sourceHref = row.original.source || row.original.source_url;
|
const sourceHref = row.original.source || row.original.source_url;
|
||||||
|
|
||||||
if (!sourceHref) {
|
if (!sourceHref) {
|
||||||
return <span className="text-sm text-slate-400">No source</span>;
|
return <span className="text-sm text-muted-foreground/70">No source</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -198,7 +198,7 @@ export function MarketplaceSkillsTable({
|
||||||
href={sourceHref}
|
href={sourceHref}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="text-sm font-medium text-slate-700 hover:text-blue-600 hover:underline"
|
className="text-sm font-medium text-muted-foreground hover:text-primary hover:underline"
|
||||||
title={sourceHref}
|
title={sourceHref}
|
||||||
>
|
>
|
||||||
{truncate(sourceHref, 36)}
|
{truncate(sourceHref, 36)}
|
||||||
|
|
@ -214,7 +214,7 @@ export function MarketplaceSkillsTable({
|
||||||
const installedOn =
|
const installedOn =
|
||||||
installedGatewayNamesBySkillId?.[row.original.id] ?? [];
|
installedGatewayNamesBySkillId?.[row.original.id] ?? [];
|
||||||
if (installedOn.length === 0) {
|
if (installedOn.length === 0) {
|
||||||
return <span className="text-sm text-slate-500">-</span>;
|
return <span className="text-sm text-muted-foreground">-</span>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
|
|
@ -223,12 +223,12 @@ export function MarketplaceSkillsTable({
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
key={`${gateway.id}-${index}`}
|
key={`${gateway.id}-${index}`}
|
||||||
className="inline-flex items-center gap-1 text-sm text-slate-700"
|
className="inline-flex items-center gap-1 text-sm text-muted-foreground"
|
||||||
title={gateway.name}
|
title={gateway.name}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/gateways/${gateway.id}`}
|
href={`/gateways/${gateway.id}`}
|
||||||
className="text-blue-700 hover:text-blue-600 hover:underline"
|
className="text-primary hover:text-primary hover:underline"
|
||||||
>
|
>
|
||||||
{gateway.name}
|
{gateway.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -302,7 +302,7 @@ export function MarketplaceSkillsTable({
|
||||||
table={table}
|
table={table}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
stickyHeader={stickyHeader}
|
stickyHeader={stickyHeader}
|
||||||
rowClassName="transition hover:bg-slate-50"
|
rowClassName="transition hover:bg-muted"
|
||||||
cellClassName="px-6 py-4 align-top"
|
cellClassName="px-6 py-4 align-top"
|
||||||
emptyState={
|
emptyState={
|
||||||
emptyState
|
emptyState
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ export function SkillInstallDialog({
|
||||||
|
|
||||||
<div className="mt-2 space-y-3.5">
|
<div className="mt-2 space-y-3.5">
|
||||||
{isGatewayStatusLoading ? (
|
{isGatewayStatusLoading ? (
|
||||||
<p className="text-sm text-slate-500">Loading gateways...</p>
|
<p className="text-sm text-muted-foreground">Loading gateways...</p>
|
||||||
) : (
|
) : (
|
||||||
gateways.map((gateway) => {
|
gateways.map((gateway) => {
|
||||||
const isInstalled = gatewayInstalledById[gateway.id] === true;
|
const isInstalled = gatewayInstalledById[gateway.id] === true;
|
||||||
|
|
@ -67,10 +67,10 @@ export function SkillInstallDialog({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={gateway.id}
|
key={gateway.id}
|
||||||
className="flex items-center justify-between rounded-xl border border-slate-200 bg-white p-4"
|
className="flex items-center justify-between rounded-xl border border-border bg-card p-4"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-900">
|
<p className="text-sm font-medium text-foreground">
|
||||||
{gateway.name}
|
{gateway.name}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -101,7 +101,7 @@ export function SkillInstallDialog({
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter className="mt-6 border-t border-slate-200 pt-4">
|
<DialogFooter className="mt-6 border-t border-border pt-4">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => onOpenChange(false)}
|
onClick={() => onOpenChange(false)}
|
||||||
|
|
|
||||||
|
|
@ -65,10 +65,10 @@ export function SkillPacksTable({
|
||||||
header: "Pack",
|
header: "Pack",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-900">
|
<p className="text-sm font-medium text-foreground">
|
||||||
{row.original.name}
|
{row.original.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 line-clamp-2 text-xs text-slate-500">
|
<p className="mt-1 line-clamp-2 text-xs text-muted-foreground">
|
||||||
{row.original.description || "No description provided."}
|
{row.original.description || "No description provided."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -82,7 +82,7 @@ export function SkillPacksTable({
|
||||||
href={row.original.source_url}
|
href={row.original.source_url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="inline-flex items-center gap-1 text-sm font-medium text-slate-700 hover:text-blue-600"
|
className="inline-flex items-center gap-1 text-sm font-medium text-muted-foreground hover:text-primary"
|
||||||
>
|
>
|
||||||
{truncate(row.original.source_url, 48)}
|
{truncate(row.original.source_url, 48)}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -92,7 +92,7 @@ export function SkillPacksTable({
|
||||||
accessorKey: "branch",
|
accessorKey: "branch",
|
||||||
header: "Branch",
|
header: "Branch",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<p className="text-sm text-slate-900">
|
<p className="text-sm text-foreground">
|
||||||
{row.original.branch || "main"}
|
{row.original.branch || "main"}
|
||||||
</p>
|
</p>
|
||||||
),
|
),
|
||||||
|
|
@ -103,7 +103,7 @@ export function SkillPacksTable({
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<Link
|
<Link
|
||||||
href={`/skills/marketplace?packId=${encodeURIComponent(row.original.id)}`}
|
href={`/skills/marketplace?packId=${encodeURIComponent(row.original.id)}`}
|
||||||
className="text-sm font-medium text-blue-700 hover:text-blue-600 hover:underline"
|
className="text-sm font-medium text-primary hover:text-primary hover:underline"
|
||||||
>
|
>
|
||||||
{row.original.skill_count ?? 0}
|
{row.original.skill_count ?? 0}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -159,7 +159,7 @@ export function SkillPacksTable({
|
||||||
table={table}
|
table={table}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
stickyHeader={stickyHeader}
|
stickyHeader={stickyHeader}
|
||||||
rowClassName="transition hover:bg-slate-50"
|
rowClassName="transition hover:bg-muted"
|
||||||
cellClassName="px-6 py-4 align-top"
|
cellClassName="px-6 py-4 align-top"
|
||||||
rowActions={
|
rowActions={
|
||||||
getEditHref || onDelete
|
getEditHref || onDelete
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
|
|
||||||
export const SKILLS_TABLE_EMPTY_ICON = (
|
export const SKILLS_TABLE_EMPTY_ICON = (
|
||||||
<svg
|
<svg
|
||||||
className="h-16 w-16 text-slate-300"
|
className="h-16 w-16 text-muted-foreground/50"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|
|
||||||
|
|
@ -101,13 +101,13 @@ export function TagForm({
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="space-y-6 rounded-xl border border-slate-200 bg-white p-6 shadow-sm"
|
className="space-y-6 rounded-xl border border-border bg-card p-6 shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<div className="rounded-xl border border-slate-200 bg-slate-50/40 p-4">
|
<div className="rounded-xl border border-border bg-muted/40 p-4">
|
||||||
<div className="grid gap-4 md:grid-cols-2">
|
<div className="grid gap-4 md:grid-cols-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -119,13 +119,13 @@ export function TagForm({
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Slug
|
Slug
|
||||||
</label>
|
</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setSlug(suggestedSlug)}
|
onClick={() => setSlug(suggestedSlug)}
|
||||||
className="text-xs font-medium text-slate-500 underline underline-offset-2 transition hover:text-slate-700 disabled:cursor-not-allowed disabled:opacity-50"
|
className="text-xs font-medium text-muted-foreground underline underline-offset-2 transition hover:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
disabled={!suggestedSlug || isSubmitting}
|
disabled={!suggestedSlug || isSubmitting}
|
||||||
>
|
>
|
||||||
Use from name
|
Use from name
|
||||||
|
|
@ -139,18 +139,18 @@ export function TagForm({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-2 text-xs text-slate-500">
|
<p className="mt-2 text-xs text-muted-foreground">
|
||||||
Leave slug blank to auto-generate from the tag name.
|
Leave slug blank to auto-generate from the tag name.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-4 md:grid-cols-[1fr_auto]">
|
<div className="grid gap-4 md:grid-cols-[1fr_auto]">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Color
|
Color
|
||||||
</label>
|
</label>
|
||||||
<div className="flex items-center rounded-lg border border-slate-200 bg-white px-3">
|
<div className="flex items-center rounded-lg border border-border bg-card px-3">
|
||||||
<span className="text-sm font-medium text-slate-400">#</span>
|
<span className="text-sm font-medium text-muted-foreground/70">#</span>
|
||||||
<Input
|
<Input
|
||||||
value={color}
|
value={color}
|
||||||
onChange={(event) => setColor(event.target.value)}
|
onChange={(event) => setColor(event.target.value)}
|
||||||
|
|
@ -161,15 +161,15 @@ export function TagForm({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Preview
|
Preview
|
||||||
</label>
|
</label>
|
||||||
<div className="inline-flex h-[42px] items-center gap-2 rounded-lg border border-slate-200 bg-white px-3">
|
<div className="inline-flex h-[42px] items-center gap-2 rounded-lg border border-border bg-card px-3">
|
||||||
<span
|
<span
|
||||||
className="h-4 w-4 rounded border border-slate-300"
|
className="h-4 w-4 rounded border border-input"
|
||||||
style={{ backgroundColor: `#${previewColor}` }}
|
style={{ backgroundColor: `#${previewColor}` }}
|
||||||
/>
|
/>
|
||||||
<span className="text-xs font-semibold text-slate-700">
|
<span className="text-xs font-semibold text-muted-foreground">
|
||||||
#{previewColor.toUpperCase()}
|
#{previewColor.toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -177,7 +177,7 @@ export function TagForm({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-xs font-semibold uppercase tracking-wider text-slate-500">
|
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ type TagsTableProps = {
|
||||||
|
|
||||||
const DEFAULT_EMPTY_ICON = (
|
const DEFAULT_EMPTY_ICON = (
|
||||||
<svg
|
<svg
|
||||||
className="h-16 w-16 text-slate-300"
|
className="h-16 w-16 text-muted-foreground/50"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|
@ -81,14 +81,14 @@ export function TagsTable({
|
||||||
const color = normalizeColor(row.original.color);
|
const color = normalizeColor(row.original.color);
|
||||||
return (
|
return (
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<div className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-2.5 py-1 text-xs font-semibold text-slate-800">
|
<div className="inline-flex items-center gap-2 rounded-full border border-border bg-card px-2.5 py-1 text-xs font-semibold text-foreground">
|
||||||
<span
|
<span
|
||||||
className="h-2 w-2 rounded-full"
|
className="h-2 w-2 rounded-full"
|
||||||
style={{ backgroundColor: `#${color}` }}
|
style={{ backgroundColor: `#${color}` }}
|
||||||
/>
|
/>
|
||||||
{row.original.name}
|
{row.original.name}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-500">
|
<p className="text-xs text-muted-foreground">
|
||||||
{row.original.slug}
|
{row.original.slug}
|
||||||
{row.original.description
|
{row.original.description
|
||||||
? ` · ${row.original.description}`
|
? ` · ${row.original.description}`
|
||||||
|
|
@ -104,9 +104,9 @@ export function TagsTable({
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const color = normalizeColor(row.original.color);
|
const color = normalizeColor(row.original.color);
|
||||||
return (
|
return (
|
||||||
<div className="inline-flex items-center gap-2 text-xs text-slate-700">
|
<div className="inline-flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
<span
|
<span
|
||||||
className="h-4 w-4 rounded border border-slate-300"
|
className="h-4 w-4 rounded border border-input"
|
||||||
style={{ backgroundColor: `#${color}` }}
|
style={{ backgroundColor: `#${color}` }}
|
||||||
/>
|
/>
|
||||||
#{color.toUpperCase()}
|
#{color.toUpperCase()}
|
||||||
|
|
@ -118,7 +118,7 @@ export function TagsTable({
|
||||||
accessorKey: "task_count",
|
accessorKey: "task_count",
|
||||||
header: "Tasks",
|
header: "Tasks",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="text-sm font-medium text-slate-700">
|
<span className="text-sm font-medium text-muted-foreground">
|
||||||
{row.original.task_count ?? 0}
|
{row.original.task_count ?? 0}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
|
@ -149,7 +149,7 @@ export function TagsTable({
|
||||||
table={table}
|
table={table}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
stickyHeader={stickyHeader}
|
stickyHeader={stickyHeader}
|
||||||
rowClassName="transition hover:bg-slate-50"
|
rowClassName="transition hover:bg-muted"
|
||||||
cellClassName="px-6 py-4 align-top"
|
cellClassName="px-6 py-4 align-top"
|
||||||
rowActions={
|
rowActions={
|
||||||
onEdit || onDelete
|
onEdit || onDelete
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const buttonVariants = cva(
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
primary:
|
primary:
|
||||||
"bg-[color:var(--accent)] text-white shadow-sm hover:bg-[color:var(--accent-strong)]",
|
"bg-primary text-primary-foreground shadow-sm hover:bg-[color:var(--accent-strong)]",
|
||||||
secondary:
|
secondary:
|
||||||
"border border-[color:var(--border)] bg-[color:var(--surface)] text-strong hover:border-[color:var(--accent)] hover:text-[color:var(--accent)]",
|
"border border-[color:var(--border)] bg-[color:var(--surface)] text-strong hover:border-[color:var(--accent)] hover:text-[color:var(--accent)]",
|
||||||
outline:
|
outline:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const DialogOverlay = React.forwardRef<
|
||||||
<DialogPrimitive.Overlay
|
<DialogPrimitive.Overlay
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-0 z-50 bg-slate-950/40 backdrop-blur-[2px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
"fixed inset-0 z-50 bg-foreground/40 backdrop-blur-[2px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const TabsTrigger = React.forwardRef<
|
||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-full px-4 py-2 text-xs font-semibold text-muted transition data-[state=active]:bg-[color:var(--accent)] data-[state=active]:text-white",
|
"rounded-full px-4 py-2 text-xs font-semibold text-muted transition data-[state=active]:bg-primary data-[state=active]:text-primary-foreground",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const TooltipContent = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-lg bg-slate-900 px-3 py-2 text-xs font-semibold text-white shadow-lg",
|
"rounded-lg bg-foreground px-3 py-2 text-xs font-semibold text-background shadow-lg",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue