mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-19 04:00:38 +09:00
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:
commit
2a33acce3a
49 changed files with 1793 additions and 418 deletions
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue