(props: {
onSubmit: (input: { owner: Owner; pattern: string; action: ToolPolicyAction }) => void;
owner: Owner;
onOwnerChange: (owner: Owner) => void;
busy: boolean;
})
| 98 | // --------------------------------------------------------------------------- |
| 99 | |
| 100 | function AddPolicyForm(props: { |
| 101 | onSubmit: (input: { owner: Owner; pattern: string; action: ToolPolicyAction }) => void; |
| 102 | owner: Owner; |
| 103 | onOwnerChange: (owner: Owner) => void; |
| 104 | busy: boolean; |
| 105 | }) { |
| 106 | const [pattern, setPattern] = useState(""); |
| 107 | const [action, setAction] = useState<ToolPolicyAction>("require_approval"); |
| 108 | const valid = isValidPattern(pattern); |
| 109 | // Non-org hosts (local/desktop) have one local workspace. New local policies |
| 110 | // are org-owned internally to match the v1->v2 migration. |
| 111 | const ownerDisplay = useOwnerDisplay(); |
| 112 | const ownerChoices = ownerDisplay.isSinglePlayerHost |
| 113 | ? POLICY_OWNERS.filter((option) => option.owner === "org").map((option) => ({ |
| 114 | ...option, |
| 115 | label: "Local", |
| 116 | })) |
| 117 | : POLICY_OWNERS; |
| 118 | |
| 119 | return ( |
| 120 | <form |
| 121 | className="flex flex-col gap-3 rounded-xl border border-border bg-card px-5 py-4" |
| 122 | onSubmit={(e) => { |
| 123 | e.preventDefault(); |
| 124 | if (!valid) return; |
| 125 | props.onSubmit({ owner: props.owner, pattern, action }); |
| 126 | setPattern(""); |
| 127 | setAction("require_approval"); |
| 128 | }} |
| 129 | > |
| 130 | <div className="flex flex-col gap-1"> |
| 131 | <Label htmlFor="policy-pattern" className="text-xs font-medium text-foreground/80"> |
| 132 | Pattern |
| 133 | </Label> |
| 134 | <Input |
| 135 | id="policy-pattern" |
| 136 | placeholder="vercel.dns.* or *" |
| 137 | value={pattern} |
| 138 | onChange={(e) => setPattern(e.target.value)} |
| 139 | className="font-mono text-sm" |
| 140 | /> |
| 141 | <p className="text-xs text-muted-foreground"> |
| 142 | Exact tool id, trailing wildcard, or <code className="font-mono">*</code> for every tool. |
| 143 | Examples: <code className="font-mono">*</code>,{" "} |
| 144 | <code className="font-mono">vercel.*</code>,{" "} |
| 145 | <code className="font-mono">vercel.dns.*</code>,{" "} |
| 146 | <code className="font-mono">vercel.dns.create</code>. |
| 147 | </p> |
| 148 | </div> |
| 149 | <div className="flex flex-col gap-1"> |
| 150 | <Label className="text-xs font-medium text-foreground/80">Action</Label> |
| 151 | <Select value={action} onValueChange={(v) => setAction(v as ToolPolicyAction)}> |
| 152 | <SelectTrigger className="w-full"> |
| 153 | <SelectValue /> |
| 154 | </SelectTrigger> |
| 155 | <SelectContent> |
| 156 | {POLICY_ACTIONS_IN_ORDER.map((a) => ( |
| 157 | <SelectItem key={a} value={a}> |
nothing calls this directly
no test coverage detected