research/publish: gate approve+reject on Owner role (#4)
ci / gates (push) Successful in 5s
ci / frontend (push) Successful in 24s
ci / rust (push) Successful in 4m5s
ci / e2e (push) Skipped
ci / publish (push) Successful in 4m32s

This commit was merged in pull request #4.
This commit is contained in:
2026-07-15 04:28:01 +00:00
parent dd791061ee
commit 1cb643142c
5 changed files with 149 additions and 5 deletions
@@ -88,11 +88,16 @@ export function ResearchCanvas({
agents,
refreshKey,
onChanged,
canApprovePublish = false,
}: {
selectedId: string | null;
agents: Agent[];
refreshKey: number;
onChanged: () => void;
/** True when the current user is a workspace Owner. Members can request
* publish but not decide it — matches the server's Role::Owner guard on
* POST /api/research/publish-approvals/:id/{approve,reject}. */
canApprovePublish?: boolean;
}) {
const [topic, setTopic] = useState<TopicDetail | null>(null);
const [pendingApproval, setPendingApproval] = useState<PublishApproval | null>(null);
@@ -742,7 +747,9 @@ export function ResearchCanvas({
</span>
</div>
<div style={{ fontFamily: mono, fontSize: 11, color: "#cfcfd5", lineHeight: 1.55 }}>
Any workspace member can decide.{" "}
{canApprovePublish
? "Workspace owners decide publish."
: "A workspace owner needs to approve or reject."}{" "}
{boundApproval ? (
<>
Requested{" "}
@@ -752,6 +759,7 @@ export function ResearchCanvas({
"Loading approval…"
)}
</div>
{canApprovePublish ? (
<div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
<button
type="button"
@@ -802,6 +810,7 @@ export function ResearchCanvas({
Reject
</button>
</div>
) : null}
{rejectFormOpen ? (
<div
style={{