fix(desktop): disclose requested channel lifetime

Co-authored-by: Wrench <0eabe6ea5758c1e4c5b68cea4ac42b32c479072883cb28da8110b4a47c32b9a1@buzz.block.builderlab.xyz>
Signed-off-by: Wrench <0eabe6ea5758c1e4c5b68cea4ac42b32c479072883cb28da8110b4a47c32b9a1@buzz.block.builderlab.xyz>
This commit is contained in:
Wrench
2026-08-26 11:26:13 -04:00
parent 8428b3238c
commit d2c5f7eb59
2 changed files with 91 additions and 36 deletions

View File

@@ -0,0 +1,41 @@
import assert from "node:assert/strict";
import test from "node:test";
import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { ProjectChannelRequestDetails } from "./ProjectChannelRequestDialog.tsx";
function request(overrides = {}) {
return {
homeChannelId: "11111111-1111-4111-8111-111111111111",
name: "release-planning",
visibility: "private",
...overrides,
};
}
test("owner review shows an agent-requested temporary channel lifetime and cleanup consequence", () => {
const html = renderToStaticMarkup(
React.createElement(ProjectChannelRequestDetails, {
request: request({ ttlSeconds: 90_000 }),
}),
);
assert.match(html, />Lifetime</);
assert.match(html, /Temporary · 1d1h/);
assert.match(
html,
/Cleans up automatically after that period of inactivity\./,
);
});
test("owner review omits temporary-channel lifetime when none was requested", () => {
const html = renderToStaticMarkup(
React.createElement(ProjectChannelRequestDetails, { request: request() }),
);
assert.doesNotMatch(html, />Lifetime</);
assert.doesNotMatch(html, /Temporary/);
assert.doesNotMatch(html, /Cleans up automatically/);
});

View File

@@ -8,8 +8,57 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from "@/shared/ui/alert-dialog";
import { formatTtlDuration } from "@/features/channels/lib/ephemeralChannel";
import type { ProjectChannelRequest } from "@/features/projects/projectChannelRequest";
import { useProjectChannelRequests } from "@/features/projects/useProjectChannelRequests";
type RequestedChannel = ProjectChannelRequest["request"];
/** Details an owner reviews before approving an agent-requested project channel. */
export function ProjectChannelRequestDetails({
request,
}: {
request: RequestedChannel;
}) {
return (
<dl className="space-y-2 rounded-xl border border-border/60 bg-muted/25 p-3 text-sm">
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">Name</dt>
<dd className="min-w-0 break-words text-foreground">#{request.name}</dd>
</div>
{request.description ? (
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">Description</dt>
<dd className="min-w-0 break-words text-foreground">
{request.description}
</dd>
</div>
) : null}
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">Visibility</dt>
<dd className="text-foreground">{request.visibility}</dd>
</div>
{request.ttlSeconds ? (
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">Lifetime</dt>
<dd className="min-w-0 break-words text-foreground">
Temporary · {formatTtlDuration(request.ttlSeconds)}. Cleans up
automatically after that period of inactivity.
</dd>
</div>
) : null}
{request.templateName ? (
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">Template</dt>
<dd className="min-w-0 break-words text-foreground">
{request.templateName}
</dd>
</div>
) : null}
</dl>
);
}
/** Global owner-review surface for project-channel requests from managed agents. */
export function ProjectChannelRequestDialog() {
const management = useProjectChannelRequests();
@@ -31,42 +80,7 @@ export function ProjectChannelRequestDialog() {
before creating it.
</AlertDialogDescription>
</AlertDialogHeader>
{request ? (
<dl className="space-y-2 rounded-xl border border-border/60 bg-muted/25 p-3 text-sm">
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">Name</dt>
<dd className="min-w-0 break-words text-foreground">
#{request.name}
</dd>
</div>
{request.description ? (
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">
Description
</dt>
<dd className="min-w-0 break-words text-foreground">
{request.description}
</dd>
</div>
) : null}
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">
Visibility
</dt>
<dd className="text-foreground">{request.visibility}</dd>
</div>
{request.templateName ? (
<div className="flex gap-3">
<dt className="w-24 shrink-0 text-muted-foreground">
Template
</dt>
<dd className="min-w-0 break-words text-foreground">
{request.templateName}
</dd>
</div>
) : null}
</dl>
) : null}
{request ? <ProjectChannelRequestDetails request={request} /> : null}
{management.error ? (
<p className="text-sm text-destructive">{management.error}</p>
) : null}