Remove api trigger kind and mark webhook as coming soon

Drop "api" from the trigger kind dropdown and disable the "webhook"
option with a "COMING SOON" label until it's ready.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-03-20 06:54:03 -05:00
commit 2a33acce3a
49 changed files with 1793 additions and 418 deletions

View file

@ -1,7 +1,13 @@
import { useCallback, useEffect, useMemo, useState, useRef } from "react";
import { useParams, useNavigate, Link, Navigate, useBeforeUnload } from "@/lib/router";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { agentsApi, type AgentKey, type ClaudeLoginResult } from "../api/agents";
import {
agentsApi,
type AgentKey,
type ClaudeLoginResult,
type AvailableSkill,
type AgentPermissionUpdate,
} from "../api/agents";
import { companySkillsApi } from "../api/companySkills";
import { budgetsApi } from "../api/budgets";
import { heartbeatsApi } from "../api/heartbeats";
@ -73,6 +79,7 @@ import {
type Agent,
type AgentSkillEntry,
type AgentSkillSnapshot,
type AgentDetail as AgentDetailRecord,
type BudgetPolicySummary,
type HeartbeatRun,
type HeartbeatRunEvent,
@ -516,7 +523,7 @@ export function AgentDetail() {
const setSaveConfigAction = useCallback((fn: (() => void) | null) => { saveConfigActionRef.current = fn; }, []);
const setCancelConfigAction = useCallback((fn: (() => void) | null) => { cancelConfigActionRef.current = fn; }, []);
const { data: agent, isLoading, error } = useQuery({
const { data: agent, isLoading, error } = useQuery<AgentDetailRecord>({
queryKey: [...queryKeys.agents.detail(routeAgentRef), lookupCompanyId ?? null],
queryFn: () => agentsApi.get(routeAgentRef, lookupCompanyId),
enabled: canFetchAgent,
@ -704,8 +711,8 @@ export function AgentDetail() {
});
const updatePermissions = useMutation({
mutationFn: (canCreateAgents: boolean) =>
agentsApi.updatePermissions(agentLookupRef, { canCreateAgents }, resolvedCompanyId ?? undefined),
mutationFn: (permissions: AgentPermissionUpdate) =>
agentsApi.updatePermissions(agentLookupRef, permissions, resolvedCompanyId ?? undefined),
onSuccess: () => {
setActionError(null);
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(routeAgentRef) });
@ -1109,7 +1116,7 @@ function AgentOverview({
agentId,
agentRouteId,
}: {
agent: Agent;
agent: AgentDetailRecord;
runs: HeartbeatRun[];
assignedIssues: { id: string; title: string; status: string; priority: string; identifier?: string | null; createdAt: Date }[];
runtimeState?: AgentRuntimeState;
@ -1266,14 +1273,14 @@ function AgentConfigurePage({
onSavingChange,
updatePermissions,
}: {
agent: Agent;
agent: AgentDetailRecord;
agentId: string;
companyId?: string;
onDirtyChange: (dirty: boolean) => void;
onSaveActionChange: (save: (() => void) | null) => void;
onCancelActionChange: (cancel: (() => void) | null) => void;
onSavingChange: (saving: boolean) => void;
updatePermissions: { mutate: (canCreate: boolean) => void; isPending: boolean };
updatePermissions: { mutate: (permissions: AgentPermissionUpdate) => void; isPending: boolean };
}) {
const queryClient = useQueryClient();
const [revisionsOpen, setRevisionsOpen] = useState(false);
@ -1377,13 +1384,13 @@ function ConfigurationTab({
hidePromptTemplate,
hideInstructionsFile,
}: {
agent: Agent;
agent: AgentDetailRecord;
companyId?: string;
onDirtyChange: (dirty: boolean) => void;
onSaveActionChange: (save: (() => void) | null) => void;
onCancelActionChange: (cancel: (() => void) | null) => void;
onSavingChange: (saving: boolean) => void;
updatePermissions: { mutate: (canCreate: boolean) => void; isPending: boolean };
updatePermissions: { mutate: (permissions: AgentPermissionUpdate) => void; isPending: boolean };
hidePromptTemplate?: boolean;
hideInstructionsFile?: boolean;
}) {
@ -1427,6 +1434,19 @@ function ConfigurationTab({
onSavingChange(isConfigSaving);
}, [onSavingChange, isConfigSaving]);
const canCreateAgents = Boolean(agent.permissions?.canCreateAgents);
const canAssignTasks = Boolean(agent.access?.canAssignTasks);
const taskAssignSource = agent.access?.taskAssignSource ?? "none";
const taskAssignLocked = agent.role === "ceo" || canCreateAgents;
const taskAssignHint =
taskAssignSource === "ceo_role"
? "Enabled automatically for CEO agents."
: taskAssignSource === "agent_creator"
? "Enabled automatically while this agent can create new agents."
: taskAssignSource === "explicit_grant"
? "Enabled via explicit company permission grant."
: "Disabled unless explicitly granted.";
return (
<div className="space-y-6">
<AgentConfigForm
@ -1446,21 +1466,62 @@ function ConfigurationTab({
<div>
<h3 className="text-sm font-medium mb-3">Permissions</h3>
<div className="border border-border rounded-lg p-4">
<div className="flex items-center justify-between text-sm">
<span>Can create new agents</span>
<div className="border border-border rounded-lg p-4 space-y-4">
<div className="flex items-center justify-between gap-4 text-sm">
<div className="space-y-1">
<div>Can create new agents</div>
<p className="text-xs text-muted-foreground">
Lets this agent create or hire agents and implicitly assign tasks.
</p>
</div>
<Button
variant={agent.permissions?.canCreateAgents ? "default" : "outline"}
variant={canCreateAgents ? "default" : "outline"}
size="sm"
className="h-7 px-2.5 text-xs"
onClick={() =>
updatePermissions.mutate(!Boolean(agent.permissions?.canCreateAgents))
updatePermissions.mutate({
canCreateAgents: !canCreateAgents,
canAssignTasks: !canCreateAgents ? true : canAssignTasks,
})
}
disabled={updatePermissions.isPending}
>
{agent.permissions?.canCreateAgents ? "Enabled" : "Disabled"}
{canCreateAgents ? "Enabled" : "Disabled"}
</Button>
</div>
<div className="flex items-center justify-between gap-4 text-sm">
<div className="space-y-1">
<div>Can assign tasks</div>
<p className="text-xs text-muted-foreground">
{taskAssignHint}
</p>
</div>
<button
type="button"
role="switch"
aria-checked={canAssignTasks}
className={cn(
"relative inline-flex h-6 w-11 shrink-0 rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
canAssignTasks
? "bg-green-500 focus-visible:ring-green-500/70"
: "bg-input/50 focus-visible:ring-ring",
)}
onClick={() =>
updatePermissions.mutate({
canCreateAgents,
canAssignTasks: !canAssignTasks,
})
}
disabled={updatePermissions.isPending || taskAssignLocked}
>
<span
className={cn(
"inline-block h-4 w-4 transform rounded-full bg-background transition-transform",
canAssignTasks ? "translate-x-6" : "translate-x-1",
)}
/>
</button>
</div>
</div>
</div>
</div>