refactor: clean up code formatting and improve readability in various files

This commit is contained in:
Abhimanyu Saharan
2026-02-09 00:29:26 +05:30
parent bb5a8482f3
commit 8c4bcca603
20 changed files with 1188 additions and 1146 deletions

View File

@@ -318,9 +318,13 @@ async def delete_board(
await session.execute( await session.execute(
delete(BoardOnboardingSession).where(col(BoardOnboardingSession.board_id) == board.id) delete(BoardOnboardingSession).where(col(BoardOnboardingSession.board_id) == board.id)
) )
await session.execute(delete(OrganizationBoardAccess).where(col(OrganizationBoardAccess.board_id) == board.id))
await session.execute( await session.execute(
delete(OrganizationInviteBoardAccess).where(col(OrganizationInviteBoardAccess.board_id) == board.id) delete(OrganizationBoardAccess).where(col(OrganizationBoardAccess.board_id) == board.id)
)
await session.execute(
delete(OrganizationInviteBoardAccess).where(
col(OrganizationInviteBoardAccess.board_id) == board.id
)
) )
# Tasks reference agents (assigned_agent_id) and have dependents (fingerprints/dependencies), so # Tasks reference agents (assigned_agent_id) and have dependents (fingerprints/dependencies), so

View File

@@ -99,15 +99,21 @@ def test_role_rank_unknown_role_falls_back_to_member_rank() -> None:
def test_is_org_admin_owner_admin_member() -> None: def test_is_org_admin_owner_admin_member() -> None:
assert organizations.is_org_admin(OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="owner")) assert organizations.is_org_admin(
assert organizations.is_org_admin(OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="admin")) OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="owner")
)
assert organizations.is_org_admin(
OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="admin")
)
assert not organizations.is_org_admin( assert not organizations.is_org_admin(
OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="member") OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="member")
) )
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_ensure_member_for_user_returns_existing_membership(monkeypatch: pytest.MonkeyPatch) -> None: async def test_ensure_member_for_user_returns_existing_membership(
monkeypatch: pytest.MonkeyPatch,
) -> None:
user = User(clerk_user_id="u1") user = User(clerk_user_id="u1")
existing = OrganizationMember(organization_id=uuid4(), user_id=user.id, role="member") existing = OrganizationMember(organization_id=uuid4(), user_id=user.id, role="member")
@@ -122,7 +128,9 @@ async def test_ensure_member_for_user_returns_existing_membership(monkeypatch: p
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_ensure_member_for_user_accepts_pending_invite(monkeypatch: pytest.MonkeyPatch) -> None: async def test_ensure_member_for_user_accepts_pending_invite(
monkeypatch: pytest.MonkeyPatch,
) -> None:
org_id = uuid4() org_id = uuid4()
invite = OrganizationInvite( invite = OrganizationInvite(
organization_id=org_id, organization_id=org_id,
@@ -140,7 +148,9 @@ async def test_ensure_member_for_user_accepts_pending_invite(monkeypatch: pytest
accepted = OrganizationMember(organization_id=org_id, user_id=user.id, role="member") accepted = OrganizationMember(organization_id=org_id, user_id=user.id, role="member")
async def _fake_accept(_session: Any, _invite: OrganizationInvite, _user: User) -> OrganizationMember: async def _fake_accept(
_session: Any, _invite: OrganizationInvite, _user: User
) -> OrganizationMember:
assert _invite is invite assert _invite is invite
assert _user is user assert _user is user
return accepted return accepted
@@ -155,7 +165,9 @@ async def test_ensure_member_for_user_accepts_pending_invite(monkeypatch: pytest
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_ensure_member_for_user_creates_default_org_and_first_owner(monkeypatch: pytest.MonkeyPatch) -> None: async def test_ensure_member_for_user_creates_default_org_and_first_owner(
monkeypatch: pytest.MonkeyPatch,
) -> None:
user = User(clerk_user_id="u1", email=None) user = User(clerk_user_id="u1", email=None)
org = Organization(id=uuid4(), name=organizations.DEFAULT_ORG_NAME) org = Organization(id=uuid4(), name=organizations.DEFAULT_ORG_NAME)
@@ -186,7 +198,10 @@ async def test_has_board_access_denies_cross_org() -> None:
session = _FakeSession(exec_results=[]) session = _FakeSession(exec_results=[])
member = OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="member") member = OrganizationMember(organization_id=uuid4(), user_id=uuid4(), role="member")
board = Board(id=uuid4(), organization_id=uuid4(), name="b", slug="b") board = Board(id=uuid4(), organization_id=uuid4(), name="b", slug="b")
assert await organizations.has_board_access(session, member=member, board=board, write=False) is False assert (
await organizations.has_board_access(session, member=member, board=board, write=False)
is False
)
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -202,7 +217,10 @@ async def test_has_board_access_uses_org_board_access_row_read_and_write() -> No
can_write=False, can_write=False,
) )
session = _FakeSession(exec_results=[_FakeExecResult(first_value=access)]) session = _FakeSession(exec_results=[_FakeExecResult(first_value=access)])
assert await organizations.has_board_access(session, member=member, board=board, write=False) is True assert (
await organizations.has_board_access(session, member=member, board=board, write=False)
is True
)
access2 = OrganizationBoardAccess( access2 = OrganizationBoardAccess(
organization_member_id=member.id, organization_member_id=member.id,
@@ -211,7 +229,10 @@ async def test_has_board_access_uses_org_board_access_row_read_and_write() -> No
can_write=True, can_write=True,
) )
session2 = _FakeSession(exec_results=[_FakeExecResult(first_value=access2)]) session2 = _FakeSession(exec_results=[_FakeExecResult(first_value=access2)])
assert await organizations.has_board_access(session2, member=member, board=board, write=False) is True assert (
await organizations.has_board_access(session2, member=member, board=board, write=False)
is True
)
access3 = OrganizationBoardAccess( access3 = OrganizationBoardAccess(
organization_member_id=member.id, organization_member_id=member.id,
@@ -220,7 +241,10 @@ async def test_has_board_access_uses_org_board_access_row_read_and_write() -> No
can_write=False, can_write=False,
) )
session3 = _FakeSession(exec_results=[_FakeExecResult(first_value=access3)]) session3 = _FakeSession(exec_results=[_FakeExecResult(first_value=access3)])
assert await organizations.has_board_access(session3, member=member, board=board, write=True) is False assert (
await organizations.has_board_access(session3, member=member, board=board, write=True)
is False
)
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -240,7 +264,9 @@ async def test_require_board_access_raises_when_no_member(monkeypatch: pytest.Mo
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_apply_member_access_update_deletes_existing_and_adds_rows_when_not_all_boards() -> None: async def test_apply_member_access_update_deletes_existing_and_adds_rows_when_not_all_boards() -> (
None
):
member = OrganizationMember(id=uuid4(), organization_id=uuid4(), user_id=uuid4(), role="member") member = OrganizationMember(id=uuid4(), organization_id=uuid4(), user_id=uuid4(), role="member")
update = OrganizationMemberAccessUpdate( update = OrganizationMemberAccessUpdate(
all_boards_read=False, all_boards_read=False,
@@ -263,7 +289,9 @@ async def test_apply_member_access_update_deletes_existing_and_adds_rows_when_no
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_apply_invite_to_member_upgrades_role_and_merges_access_rows(monkeypatch: pytest.MonkeyPatch) -> None: async def test_apply_invite_to_member_upgrades_role_and_merges_access_rows(
monkeypatch: pytest.MonkeyPatch,
) -> None:
org_id = uuid4() org_id = uuid4()
member = OrganizationMember( member = OrganizationMember(
id=uuid4(), id=uuid4(),
@@ -294,10 +322,12 @@ async def test_apply_invite_to_member_upgrades_role_and_merges_access_rows(monke
# 1st exec: invite access rows list # 1st exec: invite access rows list
# 2nd exec: existing access (none) # 2nd exec: existing access (none)
session = _FakeSession(exec_results=[ session = _FakeSession(
exec_results=[
[invite_access], [invite_access],
_FakeExecResult(first_value=None), _FakeExecResult(first_value=None),
]) ]
)
await organizations.apply_invite_to_member(session, member=member, invite=invite) await organizations.apply_invite_to_member(session, member=member, invite=invite)

View File

@@ -130,7 +130,9 @@ async def test_dependency_queries_and_replace_and_dependents() -> None:
# cover empty input short-circuit # cover empty input short-circuit
assert await td.dependency_status_by_id(session, board_id=board_id, dependency_ids=[]) == {} assert await td.dependency_status_by_id(session, board_id=board_id, dependency_ids=[]) == {}
status_map = await td.dependency_status_by_id(session, board_id=board_id, dependency_ids=[t2, t3]) status_map = await td.dependency_status_by_id(
session, board_id=board_id, dependency_ids=[t2, t3]
)
assert status_map[t2] == td.DONE_STATUS assert status_map[t2] == td.DONE_STATUS
assert status_map[t3] != td.DONE_STATUS assert status_map[t3] != td.DONE_STATUS

View File

@@ -408,9 +408,7 @@ export default function EditAgentPage() {
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-slate-300 text-blue-600 focus:ring-blue-200"
checked={resolvedIsGatewayMain} checked={resolvedIsGatewayMain}
onChange={(event) => onChange={(event) => setIsGatewayMain(event.target.checked)}
setIsGatewayMain(event.target.checked)
}
disabled={isLoading} disabled={isLoading}
/> />
<span> <span>
@@ -418,8 +416,8 @@ export default function EditAgentPage() {
Gateway main agent Gateway main agent
</span> </span>
<span className="block text-xs text-slate-500"> <span className="block text-xs text-slate-500">
Uses the gateway main session key and is not tied to a Uses the gateway main session key and is not tied to a single
single board. board.
</span> </span>
</span> </span>
</label> </label>
@@ -471,9 +469,7 @@ export default function EditAgentPage() {
</label> </label>
<Input <Input
value={resolvedHeartbeatEvery} value={resolvedHeartbeatEvery}
onChange={(event) => onChange={(event) => setHeartbeatEvery(event.target.value)}
setHeartbeatEvery(event.target.value)
}
placeholder="e.g. 10m" placeholder="e.g. 10m"
disabled={isLoading} disabled={isLoading}
/> />

View File

@@ -244,10 +244,7 @@ export default function NewAgentPage() {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{EMOJI_OPTIONS.map((option) => ( {EMOJI_OPTIONS.map((option) => (
<SelectItem <SelectItem key={option.value} value={option.value}>
key={option.value}
value={option.value}
>
{option.glyph} {option.label} {option.glyph} {option.label}
</SelectItem> </SelectItem>
))} ))}
@@ -284,9 +281,7 @@ export default function NewAgentPage() {
</label> </label>
<Textarea <Textarea
value={soulTemplate} value={soulTemplate}
onChange={(event) => onChange={(event) => setSoulTemplate(event.target.value)}
setSoulTemplate(event.target.value)
}
rows={10} rows={10}
disabled={isLoading} disabled={isLoading}
/> />
@@ -305,9 +300,7 @@ export default function NewAgentPage() {
</label> </label>
<Input <Input
value={heartbeatEvery} value={heartbeatEvery}
onChange={(event) => onChange={(event) => setHeartbeatEvery(event.target.value)}
setHeartbeatEvery(event.target.value)
}
placeholder="e.g. 10m" placeholder="e.g. 10m"
disabled={isLoading} disabled={isLoading}
/> />

View File

@@ -21,7 +21,10 @@ import { StatusPill } from "@/components/atoms/StatusPill";
import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout";
import { Button, buttonVariants } from "@/components/ui/button"; import { Button, buttonVariants } from "@/components/ui/button";
import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog";
import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; import {
TableEmptyStateRow,
TableLoadingRow,
} from "@/components/ui/table-state";
import { ApiError } from "@/api/mutator"; import { ApiError } from "@/api/mutator";
import { import {
@@ -257,7 +260,9 @@ export default function AgentsPage() {
description={`${agents.length} agent${agents.length === 1 ? "" : "s"} total.`} description={`${agents.length} agent${agents.length === 1 ? "" : "s"} total.`}
headerActions={ headerActions={
agents.length > 0 ? ( agents.length > 0 ? (
<Button onClick={() => router.push("/agents/new")}>New agent</Button> <Button onClick={() => router.push("/agents/new")}>
New agent
</Button>
) : null ) : null
} }
isAdmin={isAdmin} isAdmin={isAdmin}
@@ -330,7 +335,9 @@ export default function AgentsPage() {
</div> </div>
{agentsQuery.error ? ( {agentsQuery.error ? (
<p className="mt-4 text-sm text-red-500">{agentsQuery.error.message}</p> <p className="mt-4 text-sm text-red-500">
{agentsQuery.error.message}
</p>
) : null} ) : null}
</DashboardPageLayout> </DashboardPageLayout>
@@ -345,8 +352,7 @@ export default function AgentsPage() {
title="Delete agent" title="Delete agent"
description={ description={
<> <>
This will remove {deleteTarget?.name}. This action cannot be This will remove {deleteTarget?.name}. This action cannot be undone.
undone.
</> </>
} }
errorMessage={deleteMutation.error?.message} errorMessage={deleteMutation.error?.message}

View File

@@ -293,8 +293,7 @@ export default function EditBoardGroupPage() {
{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">
Group was created, but {assignFailedCount} board assignment Group was created, but {assignFailedCount} board assignment
{assignFailedCount === 1 ? "" : "s"} failed. You can retry {assignFailedCount === 1 ? "" : "s"} failed. You can retry below.
below.
</div> </div>
) : null} ) : null}
<div className="grid gap-6 md:grid-cols-2"> <div className="grid gap-6 md:grid-cols-2">
@@ -329,8 +328,8 @@ export default function EditBoardGroupPage() {
<div> <div>
<p className="text-sm font-medium text-slate-900">Boards</p> <p className="text-sm font-medium text-slate-900">Boards</p>
<p className="mt-1 text-xs text-slate-500"> <p className="mt-1 text-xs text-slate-500">
Assign boards to this group to share context across Assign boards to this group to share context across related
related work. work.
</p> </p>
</div> </div>
<span className="text-xs text-slate-500"> <span className="text-xs text-slate-500">
@@ -371,8 +370,7 @@ export default function EditBoardGroupPage() {
}) })
.map((board) => { .map((board) => {
const checked = selectedBoardIds.has(board.id); const checked = selectedBoardIds.has(board.id);
const isInThisGroup = const isInThisGroup = board.board_group_id === groupId;
board.board_group_id === groupId;
const isAlreadyGrouped = const isAlreadyGrouped =
Boolean(board.board_group_id) && !isInThisGroup; Boolean(board.board_group_id) && !isInThisGroup;
return ( return (

View File

@@ -164,9 +164,7 @@ 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"> <label className="text-sm font-medium text-slate-900">Boards</label>
Boards
</label>
<span className="text-xs text-slate-500"> <span className="text-xs text-slate-500">
{selectedBoardIds.size} selected {selectedBoardIds.size} selected
</span> </span>
@@ -203,9 +201,7 @@ export default function NewBoardGroupPage() {
}) })
.map((board) => { .map((board) => {
const checked = selectedBoardIds.has(board.id); const checked = selectedBoardIds.has(board.id);
const isAlreadyGrouped = Boolean( const isAlreadyGrouped = Boolean(board.board_group_id);
board.board_group_id,
);
return ( return (
<li key={board.id} className="px-4 py-3"> <li key={board.id} className="px-4 py-3">
<label className="flex cursor-pointer items-start gap-3"> <label className="flex cursor-pointer items-start gap-3">
@@ -250,8 +246,8 @@ export default function NewBoardGroupPage() {
</div> </div>
<p className="text-xs text-slate-500"> <p className="text-xs text-slate-500">
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 creation. You can change membership later in group edit or board
board settings. settings.
</p> </p>
</div> </div>

View File

@@ -26,7 +26,10 @@ import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"
import { Button, buttonVariants } from "@/components/ui/button"; import { Button, buttonVariants } from "@/components/ui/button";
import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog";
import { formatTimestamp } from "@/lib/formatters"; import { formatTimestamp } from "@/lib/formatters";
import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; import {
TableEmptyStateRow,
TableLoadingRow,
} from "@/components/ui/table-state";
export default function BoardGroupsPage() { export default function BoardGroupsPage() {
const { isSignedIn } = useAuth(); const { isSignedIn } = useAuth();
@@ -258,7 +261,9 @@ export default function BoardGroupsPage() {
</div> </div>
{groupsQuery.error ? ( {groupsQuery.error ? (
<p className="mt-4 text-sm text-red-500">{groupsQuery.error.message}</p> <p className="mt-4 text-sm text-red-500">
{groupsQuery.error.message}
</p>
) : null} ) : null}
</DashboardPageLayout> </DashboardPageLayout>
<ConfirmActionDialog <ConfirmActionDialog

View File

@@ -316,8 +316,7 @@ export default function EditBoardPage() {
Goal needs confirmation Goal needs confirmation
</p> </p>
<p className="mt-1 text-xs text-amber-800/80"> <p className="mt-1 text-xs text-amber-800/80">
Start onboarding to draft an objective and success Start onboarding to draft an objective and success metrics.
metrics.
</p> </p>
</div> </div>
<Button <Button
@@ -366,10 +365,7 @@ export default function EditBoardPage() {
<label className="text-sm font-medium text-slate-900"> <label className="text-sm font-medium text-slate-900">
Board type Board type
</label> </label>
<Select <Select value={resolvedBoardType} onValueChange={setBoardType}>
value={resolvedBoardType}
onValueChange={setBoardType}
>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Select board type" /> <SelectValue placeholder="Select board type" />
</SelectTrigger> </SelectTrigger>
@@ -397,8 +393,8 @@ export default function EditBoardPage() {
disabled={isLoading} disabled={isLoading}
/> />
<p className="text-xs text-slate-500"> <p className="text-xs text-slate-500">
Boards in the same group can share cross-board context Boards in the same group can share cross-board context for
for agents. agents.
</p> </p>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
@@ -408,9 +404,7 @@ export default function EditBoardPage() {
<Input <Input
type="date" type="date"
value={resolvedTargetDate} value={resolvedTargetDate}
onChange={(event) => onChange={(event) => setTargetDate(event.target.value)}
setTargetDate(event.target.value)
}
disabled={isLoading} disabled={isLoading}
/> />
</div> </div>
@@ -435,9 +429,7 @@ export default function EditBoardPage() {
</label> </label>
<Textarea <Textarea
value={resolvedSuccessMetrics} value={resolvedSuccessMetrics}
onChange={(event) => onChange={(event) => setSuccessMetrics(event.target.value)}
setSuccessMetrics(event.target.value)
}
placeholder='e.g. { "target": "Launch by week 2" }' placeholder='e.g. { "target": "Launch by week 2" }'
className="min-h-[140px] font-mono text-xs" className="min-h-[140px] font-mono text-xs"
disabled={isLoading} disabled={isLoading}
@@ -453,8 +445,7 @@ export default function EditBoardPage() {
{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-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
<p> <p>
No gateways available. Create one in Gateways to No gateways available. Create one in Gateways to continue.
continue.
</p> </p>
</div> </div>
) : null} ) : null}

View File

@@ -225,7 +225,9 @@ export default function NewBoardPage() {
</div> </div>
) : null} ) : null}
{errorMessage ? <p className="text-sm text-red-500">{errorMessage}</p> : null} {errorMessage ? (
<p className="text-sm text-red-500">{errorMessage}</p>
) : null}
<div className="flex justify-end gap-3"> <div className="flex justify-end gap-3">
<Button <Button

View File

@@ -31,7 +31,10 @@ import type { BoardGroupRead, BoardRead } from "@/api/generated/model";
import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout";
import { Button, buttonVariants } from "@/components/ui/button"; import { Button, buttonVariants } from "@/components/ui/button";
import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog";
import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; import {
TableEmptyStateRow,
TableLoadingRow,
} from "@/components/ui/table-state";
const compactId = (value: string) => const compactId = (value: string) =>
value.length > 8 ? `${value.slice(0, 8)}` : value; value.length > 8 ? `${value.slice(0, 8)}` : value;
@@ -312,7 +315,9 @@ export default function BoardsPage() {
</div> </div>
{boardsQuery.error ? ( {boardsQuery.error ? (
<p className="mt-4 text-sm text-red-500">{boardsQuery.error.message}</p> <p className="mt-4 text-sm text-red-500">
{boardsQuery.error.message}
</p>
) : null} ) : null}
</DashboardPageLayout> </DashboardPageLayout>
<ConfirmActionDialog <ConfirmActionDialog
@@ -326,8 +331,7 @@ export default function BoardsPage() {
title="Delete board" title="Delete board"
description={ description={
<> <>
This will remove {deleteTarget?.name}. This action cannot be This will remove {deleteTarget?.name}. This action cannot be undone.
undone.
</> </>
} }
errorMessage={deleteMutation.error?.message} errorMessage={deleteMutation.error?.message}

View File

@@ -166,9 +166,7 @@ export default function GatewayDetailPage() {
</p> </p>
</div> </div>
<div> <div>
<p className="text-xs uppercase text-slate-400"> <p className="text-xs uppercase text-slate-400">Token</p>
Token
</p>
<p className="mt-1 text-sm font-medium text-slate-900"> <p className="mt-1 text-sm font-medium text-slate-900">
{maskToken(gateway.token)} {maskToken(gateway.token)}
</p> </p>
@@ -199,17 +197,13 @@ export default function GatewayDetailPage() {
</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-slate-400">Created</p>
Created
</p>
<p className="mt-1 text-sm font-medium text-slate-900"> <p className="mt-1 text-sm font-medium text-slate-900">
{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-slate-400">Updated</p>
Updated
</p>
<p className="mt-1 text-sm font-medium text-slate-900"> <p className="mt-1 text-sm font-medium text-slate-900">
{formatTimestamp(gateway.updated_at)} {formatTimestamp(gateway.updated_at)}
</p> </p>
@@ -259,9 +253,7 @@ export default function GatewayDetailPage() {
<p className="text-sm font-medium text-slate-900"> <p className="text-sm font-medium text-slate-900">
{agent.name} {agent.name}
</p> </p>
<p className="text-xs text-slate-500"> <p className="text-xs text-slate-500">{agent.id}</p>
{agent.id}
</p>
</td> </td>
<td className="px-4 py-3 text-sm text-slate-700"> <td className="px-4 py-3 text-sm text-slate-700">
{agent.status} {agent.status}

View File

@@ -19,7 +19,10 @@ import { useQueryClient } from "@tanstack/react-query";
import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout";
import { Button, buttonVariants } from "@/components/ui/button"; import { Button, buttonVariants } from "@/components/ui/button";
import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog";
import { TableEmptyStateRow, TableLoadingRow } from "@/components/ui/table-state"; import {
TableEmptyStateRow,
TableLoadingRow,
} from "@/components/ui/table-state";
import { ApiError } from "@/api/mutator"; import { ApiError } from "@/api/mutator";
import { import {
@@ -267,7 +270,14 @@ export default function GatewaysPage() {
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
> >
<rect x="2" y="7" width="20" height="14" rx="2" ry="2" /> <rect
x="2"
y="7"
width="20"
height="14"
rx="2"
ry="2"
/>
<path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16" /> <path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16" />
</svg> </svg>
} }
@@ -283,7 +293,9 @@ export default function GatewaysPage() {
</div> </div>
{gatewaysQuery.error ? ( {gatewaysQuery.error ? (
<p className="mt-4 text-sm text-red-500">{gatewaysQuery.error.message}</p> <p className="mt-4 text-sm text-red-500">
{gatewaysQuery.error.message}
</p>
) : null} ) : null}
</DashboardPageLayout> </DashboardPageLayout>

View File

@@ -378,7 +378,9 @@ export default function OrganizationPage() {
}); });
const membershipRole = const membershipRole =
membershipQuery.data?.status === 200 ? membershipQuery.data.data.role : null; membershipQuery.data?.status === 200
? membershipQuery.data.data.role
: null;
const isOwner = membershipRole === "owner"; const isOwner = membershipRole === "owner";
const isAdmin = membershipRole === "admin" || membershipRole === "owner"; const isAdmin = membershipRole === "admin" || membershipRole === "owner";
@@ -842,7 +844,9 @@ export default function OrganizationPage() {
onClick={() => setInviteDialogOpen(true)} onClick={() => setInviteDialogOpen(true)}
disabled={!isAdmin} disabled={!isAdmin}
title={ title={
isAdmin ? undefined : "Only organization admins can invite" isAdmin
? undefined
: "Only organization admins can invite"
} }
> >
<UserPlus className="h-4 w-4" /> <UserPlus className="h-4 w-4" />

View File

@@ -1,7 +1,6 @@
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { ActivityFeed } from "./ActivityFeed"; import { ActivityFeed } from "./ActivityFeed";
type Item = { id: string; label: string }; type Item = { id: string; label: string };
@@ -56,9 +55,7 @@ describe("ActivityFeed", () => {
/>, />,
); );
expect( expect(screen.getByText("Waiting for new comments…")).toBeInTheDocument();
screen.getByText("Waiting for new comments…"),
).toBeInTheDocument();
expect( expect(
screen.getByText("When agents post updates, they will show up here."), screen.getByText("When agents post updates, they will show up here."),
).toBeInTheDocument(); ).toBeInTheDocument();

View File

@@ -159,10 +159,17 @@ export function GatewayForm({
</div> </div>
</div> </div>
{errorMessage ? <p className="text-sm text-red-500">{errorMessage}</p> : null} {errorMessage ? (
<p className="text-sm text-red-500">{errorMessage}</p>
) : null}
<div className="flex justify-end gap-3"> <div className="flex justify-end gap-3">
<Button type="button" variant="ghost" onClick={onCancel} disabled={isLoading}> <Button
type="button"
variant="ghost"
onClick={onCancel}
disabled={isLoading}
>
{cancelLabel} {cancelLabel}
</Button> </Button>
<Button type="submit" disabled={isLoading || !canSubmit}> <Button type="submit" disabled={isLoading || !canSubmit}>

View File

@@ -1,7 +1,6 @@
import { createExponentialBackoff } from "./backoff"; import { createExponentialBackoff } from "./backoff";
import { describe, expect, it, vi } from "vitest"; import { describe, expect, it, vi } from "vitest";
describe("createExponentialBackoff", () => { describe("createExponentialBackoff", () => {
it("uses default options", () => { it("uses default options", () => {
const backoff = createExponentialBackoff(); const backoff = createExponentialBackoff();

View File

@@ -50,7 +50,8 @@ export async function checkGatewayConnection(params: {
} catch (error) { } catch (error) {
return { return {
ok: false, ok: false,
message: error instanceof Error ? error.message : "Unable to reach gateway.", message:
error instanceof Error ? error.message : "Unable to reach gateway.",
}; };
} }
} }

View File

@@ -18,7 +18,10 @@ export default defineConfig({
reportsDirectory: "./coverage", reportsDirectory: "./coverage",
// Policy (scoped gate): require 100% coverage on *explicitly listed* unit-testable modules first. // Policy (scoped gate): require 100% coverage on *explicitly listed* unit-testable modules first.
// We'll expand this include list as we add more unit/component tests. // We'll expand this include list as we add more unit/component tests.
include: ["src/lib/backoff.ts", "src/components/activity/ActivityFeed.tsx"], include: [
"src/lib/backoff.ts",
"src/components/activity/ActivityFeed.tsx",
],
exclude: ["**/*.d.ts", "src/**/__generated__/**", "src/**/generated/**"], exclude: ["**/*.d.ts", "src/**/__generated__/**", "src/**/generated/**"],
thresholds: { thresholds: {
lines: 100, lines: 100,