- Added `nuqs` package for enhanced query handling. - Introduced new routes for tools, including catalog, connections, policies, and editor. - Updated navigation links to direct to specific tool routes instead of generic paths. - Refactored tool-related components to accommodate new routing and state management. - Adjusted type definitions to reflect changes in tool policy management, replacing role-based terminology with policy-centric terms.
Unified · Split
| @@ -106,6 +106,7 @@ · 105 unmodified lines | ||
| 106 | 106 | "lucide-react": "^0.563.0", |
| 107 | 107 | "monaco-editor": "^0.55.1", |
| 108 | 108 | "next-themes": "^0.4.6", |
| 109 | + "nuqs": "^2.8.8", | |
| 109 | 110 | "radix-ui": "^1.4.3", |
| 110 | 111 | "react": "19.2.3", |
| 111 | 112 | "react-dom": "19.2.3", |
| @@ -2049,6 +2050,8 @@ · 1937 unmodified lines | ||
| 2049 | 2050 | |
| 2050 | 2051 | "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], |
| 2051 | 2052 | |
| 2053 | + "nuqs": ["nuqs@2.8.8", "", { "dependencies": { "@standard-schema/spec": "1.0.0" }, "peerDependencies": { "@remix-run/react": ">=2", "@tanstack/react-router": "^1", "next": ">=14.2.0", "react": ">=18.2.0 || ^19.0.0-0", "react-router": "^5 || ^6 || ^7", "react-router-dom": "^5 || ^6 || ^7" }, "optionalPeers": ["@remix-run/react", "@tanstack/react-router", "next", "react-router", "react-router-dom"] }, "sha512-LF5sw9nWpHyPWzMMu9oho3r9C5DvkpmBIg4LQN78sexIzGaeRx8DWr0uy3YiFx5i2QGZN1Qqcb+OAtEVRa2bnA=="], | |
| 2054 | + | |
| 2052 | 2055 | "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], |
| 2053 | 2056 | |
| 2054 | 2057 | "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], |
| @@ -2687,6 +2690,8 @@ · 632 unmodified lines | ||
| 2687 | 2690 | |
| 2688 | 2691 | "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], |
| 2689 | 2692 | |
| 2693 | + "nuqs/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], | |
| 2694 | + | |
| 2690 | 2695 | "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], |
| 2691 | 2696 | |
| 2692 | 2697 | "parse-json/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], |
| @@ -17,11 +17,11 @@ · 16 unmodified lines | ||
| 17 | 17 | "@executor/ui": "workspace:*", |
| 18 | 18 | "@monaco-editor/react": "^4.7.0", |
| 19 | 19 | "@streamdown/code": "^1.0.1", |
| 20 | + "@tanstack/react-query": "^5.80.7", | |
| 20 | 21 | "@tanstack/react-router": "^1.132.0", |
| 21 | 22 | "@tanstack/react-start": "^1.132.0", |
| 22 | − "@tanstack/router-plugin": "^1.132.0", | |
| 23 | − "@tanstack/react-query": "^5.80.7", | |
| 24 | 23 | "@tanstack/react-virtual": "^3.13.18", |
| 24 | + "@tanstack/router-plugin": "^1.132.0", | |
| 25 | 25 | "@workos/authkit-tanstack-react-start": "^0.5.0", |
| 26 | 26 | "better-result": "^2.7.0", |
| 27 | 27 | "class-variance-authority": "^0.7.1", |
| @@ -32,6 +32,7 @@ · 4 unmodified lines | ||
| 32 | 32 | "lucide-react": "^0.563.0", |
| 33 | 33 | "monaco-editor": "^0.55.1", |
| 34 | 34 | "next-themes": "^0.4.6", |
| 35 | + "nuqs": "^2.8.8", | |
| 35 | 36 | "radix-ui": "^1.4.3", |
| 36 | 37 | "react": "19.2.3", |
| 37 | 38 | "react-dom": "19.2.3", |
| @@ -97,7 +97,7 @@ function ApprovalCard({ · 96 unmodified lines | ||
| 97 | 97 | variant="ghost" |
| 98 | 98 | size="sm" |
| 99 | 99 | className="h-7 text-[11px]" |
| 100 | − onClick={() => navigate("/tools?tab=editor")} | |
| 100 | + onClick={() => navigate("/tools/editor")} | |
| 101 | 101 | > |
| 102 | 102 | Open editor |
| 103 | 103 | </Button> |
| @@ -60,7 +60,7 @@ export function MenubarMvpView() { · 59 unmodified lines | ||
| 60 | 60 | </p> |
| 61 | 61 | </div> |
| 62 | 62 | <div className="flex items-center gap-2"> |
| 63 | − <Button size="sm" variant="outline" className="h-8 text-xs" onClick={() => navigate("/tools?tab=editor")}> | |
| 63 | + <Button size="sm" variant="outline" className="h-8 text-xs" onClick={() => navigate("/tools/editor")}> | |
| 64 | 64 | Open Editor |
| 65 | 65 | </Button> |
| 66 | 66 | <Button size="sm" variant="outline" className="h-8 text-xs" onClick={() => navigate("/approvals")}> |
| @@ -112,7 +112,7 @@ export function MenubarMvpView() { · 45 unmodified lines | ||
| 112 | 112 | <Sparkles className="h-4 w-4 text-primary" /> |
| 113 | 113 | Recent AI tasks |
| 114 | 114 | </p> |
| 115 | − <Button size="sm" variant="outline" className="h-8 text-xs" onClick={() => navigate("/tools?tab=editor")}>Open Editor</Button> | |
| 115 | + <Button size="sm" variant="outline" className="h-8 text-xs" onClick={() => navigate("/tools/editor")}>Open Editor</Button> | |
| 116 | 116 | </div> |
| 117 | 117 | |
| 118 | 118 | {tasksLoading ? ( |
| @@ -130,7 +130,7 @@ export function MenubarMvpView() { · 11 unmodified lines | ||
| 130 | 130 | key={task.id} |
| 131 | 131 | type="button" |
| 132 | 132 | className="flex w-full items-center justify-between rounded border border-border bg-background px-2.5 py-2 text-left hover:bg-accent" |
| 133 | − onClick={() => navigate("/tools?tab=editor")} | |
| 133 | + onClick={() => navigate("/tools/editor")} | |
| 134 | 134 | > |
| 135 | 135 | <span className="min-w-0"> |
| 136 | 136 | <span className="block truncate text-[11px] font-mono text-foreground">{task.id}</span> |
| @@ -51,9 +51,17 @@ interface ToolExplorerProps { · 50 unmodified lines | ||
| 51 | 51 | loadingSources?: string[]; |
| 52 | 52 | onLoadToolDetails?: (toolPaths: string[]) => Promise<Record<string, Pick<ToolDescriptor, "path" | "description" | "display" | "typing">>>; |
| 53 | 53 | warnings?: string[]; |
| 54 | − initialSource?: string | null; | |
| 55 | − activeSource?: string | null; | |
| 56 | − onActiveSourceChange?: (source: string | null) => void; | |
| 54 | + activeSource: string | null; | |
| 55 | + searchValue: string; | |
| 56 | + filterApprovalValue: FilterApproval; | |
| 57 | + focusedToolPathValue: string | null; | |
| 58 | + selectedToolPathsValue: string[]; | |
| 59 | + focusedSourceNameValue: string | null; | |
| 60 | + onSearchValueChange: (value: string) => void; | |
| 61 | + onFilterApprovalValueChange: (filter: FilterApproval) => void; | |
| 62 | + onFocusedToolPathChange: (toolPath: string | null) => void; | |
| 63 | + onSelectedToolPathsChange: (toolPaths: string[]) => void; | |
| 64 | + onFocusedSourceNameChange: (sourceName: string | null) => void; | |
| 57 | 65 | /** @deprecated No longer used — source sidebar is merged into the tool list panel. */ |
| 58 | 66 | showSourceSidebar?: boolean; |
| 59 | 67 | onSourceAdded?: (source: ToolSourceRecord) => void; |
| @@ -79,9 +87,17 @@ export function ToolExplorer({ · 19 unmodified lines | ||
| 79 | 87 | loadingSources = [], |
| 80 | 88 | onLoadToolDetails, |
| 81 | 89 | warnings = [], |
| 82 | − initialSource = null, | |
| 83 | 90 | activeSource, |
| 84 | − onActiveSourceChange, | |
| 91 | + searchValue, | |
| 92 | + filterApprovalValue, | |
| 93 | + focusedToolPathValue, | |
| 94 | + selectedToolPathsValue, | |
| 95 | + focusedSourceNameValue, | |
| 96 | + onSearchValueChange, | |
| 97 | + onFilterApprovalValueChange, | |
| 98 | + onFocusedToolPathChange, | |
| 99 | + onSelectedToolPathsChange, | |
| 100 | + onFocusedSourceNameChange, | |
| 85 | 101 | onSourceAdded, |
| 86 | 102 | sourceDialogMeta, |
| 87 | 103 | sourceAuthProfiles, |
| @@ -106,21 +122,45 @@ export function ToolExplorer({ · 18 unmodified lines | ||
| 106 | 122 | return description.length > 0 || hasInputHint || hasOutputHint || hasSchemas; |
| 107 | 123 | }, []); |
| 108 | 124 | |
| 109 | − const [searchInput, setSearchInput] = useState(""); | |
| 110 | − const search = useDeferredValue(searchInput); | |
| 111 | − const [internalActiveSource] = useState<string | null>(initialSource); | |
| 112 | − const [selectedKeys, setSelectedKeys] = useState<Set<string>>(new Set()); | |
| 113 | − const [filterApproval, setFilterApproval] = useState<FilterApproval>("all"); | |
| 114 | 125 | const [toolDetailsByPath, setToolDetailsByPath] = useState<Record<string, Pick<ToolDescriptor, "path" | "description" | "display" | "typing">>>({}); |
| 115 | 126 | const [loadingDetailPaths, setLoadingDetailPaths] = useState<Set<string>>(new Set()); |
| 116 | − const [focusedToolPath, setFocusedToolPath] = useState<string | null>(null); | |
| 117 | − const [focusedSourceName, setFocusedSourceName] = useState<string | null>(null); | |
| 118 | 127 | // "new" = add source form, ToolSourceRecord = edit/view existing source, null = no source panel |
| 119 | 128 | const [formSource, setFormSource] = useState<"new" | ToolSourceRecord | null>(null); |
| 120 | 129 | const toolListRef = useRef<HTMLDivElement>(null); |
| 121 | 130 | const toolListScrollContainerId = "tool-explorer-toollist-scroll"; |
| 122 | − const resolvedActiveSource = | |
| 123 | − activeSource === undefined ? internalActiveSource : activeSource; | |
| 131 | + const resolvedActiveSource = activeSource; | |
| 132 | + const searchInput = searchValue; | |
| 133 | + const filterApproval = filterApprovalValue; | |
| 134 | + const focusedToolPath = focusedToolPathValue; | |
| 135 | + const selectedKeys = useMemo(() => new Set(selectedToolPathsValue), [selectedToolPathsValue]); | |
| 136 | + const focusedSourceName = focusedSourceNameValue; | |
| 137 | + const search = useDeferredValue(searchInput); | |
| 138 | + | |
| 139 | + const setSearchInput = useCallback((value: string) => { | |
| 140 | + onSearchValueChange(value); | |
| 141 | + }, [onSearchValueChange]); | |
| 142 | + | |
| 143 | + const setFilterApproval = useCallback((nextFilter: FilterApproval) => { | |
| 144 | + onFilterApprovalValueChange(nextFilter); | |
| 145 | + }, [onFilterApprovalValueChange]); | |
| 146 | + | |
| 147 | + const setFocusedToolPath = useCallback((toolPath: string | null) => { | |
| 148 | + onFocusedToolPathChange(toolPath); | |
| 149 | + }, [onFocusedToolPathChange]); | |
| 150 | + | |
| 151 | + const setSelectedKeys = useCallback((next: Set<string>) => { | |
| 152 | + onSelectedToolPathsChange(Array.from(next)); | |
| 153 | + }, [onSelectedToolPathsChange]); | |
| 154 | + | |
| 155 | + const setFocusedSourceName = useCallback((sourceName: string | null) => { | |
| 156 | + onFocusedSourceNameChange(sourceName); | |
| 157 | + }, [onFocusedSourceNameChange]); | |
| 158 | + | |
| 159 | + const setSourceFocusState = useCallback((sourceName: string | null, sourceRecord: ToolSourceRecord | null) => { | |
| 160 | + setFocusedSourceName(sourceName); | |
| 161 | + setFormSource(sourceRecord); | |
| 162 | + setFocusedToolPath(null); | |
| 163 | + }, [setFocusedSourceName, setFocusedToolPath]); | |
| 124 | 164 | |
| 125 | 165 | const hydratedTools = useMemo(() => { |
| 126 | 166 | if (Object.keys(toolDetailsByPath).length === 0) { |
| @@ -212,21 +252,30 @@ export function ToolExplorer({ · 85 unmodified lines | ||
| 212 | 252 | return map; |
| 213 | 253 | }, [visibleSources]); |
| 214 | 254 | |
| 255 | + useEffect(() => { | |
| 256 | + const resolvedSource = focusedSourceNameValue | |
| 257 | + ? sourceByName.get(focusedSourceNameValue) ?? null | |
| 258 | + : null; | |
| 259 | + | |
| 260 | + setFormSource(resolvedSource); | |
| 261 | + if (focusedSourceNameValue) { | |
| 262 | + setFocusedToolPath(null); | |
| 263 | + } | |
| 264 | + }, [focusedSourceNameValue, sourceByName, setFocusedToolPath]); | |
| 265 | + | |
| 215 | 266 | const toggleSelectTool = useCallback( |
| 216 | 267 | (path: string, e: React.MouseEvent) => { |
| 217 | 268 | e.stopPropagation(); |
| 218 | 269 | e.preventDefault(); |
| 219 | − setSelectedKeys((prev) => { | |
| 220 | − const next = new Set(prev); | |
| 221 | − if (next.has(path)) { | |
| 222 | − next.delete(path); | |
| 223 | − } else { | |
| 224 | − next.add(path); | |
| 225 | − } | |
| 226 | − return next; | |
| 227 | − }); | |
| 270 | + const next = new Set(selectedKeys); | |
| 271 | + if (next.has(path)) { | |
| 272 | + next.delete(path); | |
| 273 | + } else { | |
| 274 | + next.add(path); | |
| 275 | + } | |
| 276 | + setSelectedKeys(next); | |
| 228 | 277 | }, |
| 229 | − [], | |
| 278 | + [selectedKeys, setSelectedKeys], | |
| 230 | 279 | ); |
| 231 | 280 | |
| 232 | 281 | const clearSelection = useCallback(() => { |
| @@ -280,14 +329,11 @@ export function ToolExplorer({ · 47 unmodified lines | ||
| 280 | 329 | setFocusedSourceName(null); |
| 281 | 330 | setFormSource(null); |
| 282 | 331 | void maybeLoadToolDetails(tool, true); |
| 283 | − }, [maybeLoadToolDetails]); | |
| 332 | + }, [maybeLoadToolDetails, setFocusedSourceName]); | |
| 284 | 333 | |
| 285 | 334 | const handleSourceClick = useCallback((sourceName: string) => { |
| 286 | 335 | const source = sourceByName.get(sourceName); |
| 287 | − setFocusedSourceName(sourceName); | |
| 288 | − setFocusedToolPath(null); | |
| 289 | − // Open the source form panel directly — no separate "view" mode | |
| 290 | − setFormSource(source ?? null); | |
| 336 | + setSourceFocusState(sourceName, source ?? null); | |
| 291 | 337 | // Ensure the source group is expanded |
| 292 | 338 | setExpandedKeys((prev) => { |
| 293 | 339 | const key = `source:${sourceName}`; |
| @@ -299,10 +345,9 @@ export function ToolExplorer({ · 5 unmodified lines | ||
| 299 | 345 | }, [sourceByName]); |
| 300 | 346 | |
| 301 | 347 | const handleAddSource = useCallback(() => { |
| 348 | + setSourceFocusState(null, null); | |
| 302 | 349 | setFormSource("new"); |
| 303 | − setFocusedToolPath(null); | |
| 304 | − setFocusedSourceName(null); | |
| 305 | − }, []); | |
| 350 | + }, [setFocusedSourceName, setSourceFocusState]); | |
| 306 | 351 | |
| 307 | 352 | const handleSourceFormClose = useCallback(() => { |
| 308 | 353 | setFormSource(null); |
| @@ -311,10 +356,8 @@ export function ToolExplorer({ · 2 unmodified lines | ||
| 311 | 356 | const handleSourceFormAdded = useCallback((source: ToolSourceRecord) => { |
| 312 | 357 | onSourceAdded?.(source); |
| 313 | 358 | // After adding, show the new source in the form |
| 314 | − setFormSource(null); | |
| 315 | − setFocusedSourceName(source.name); | |
| 316 | − setFocusedToolPath(null); | |
| 317 | − }, [onSourceAdded]); | |
| 359 | + setSourceFocusState(source.name, source); | |
| 360 | + }, [onSourceAdded, setSourceFocusState]); | |
| 318 | 361 | |
| 319 | 362 | const focusedTool = useMemo(() => { |
| 320 | 363 | if (!focusedToolPath) return null; |
| @@ -328,7 +371,7 @@ export function ToolExplorer({ · 7 unmodified lines | ||
| 328 | 371 | |
| 329 | 372 | // Auto-focus first tool when tools arrive |
| 330 | 373 | useEffect(() => { |
| 331 | − if (!focusedToolPath && searchedTools.length > 0) { | |
| 374 | + if (!focusedToolPath && !focusedSourceName && searchedTools.length > 0) { | |
| 332 | 375 | const first = searchedTools[0]; |
| 333 | 376 | setFocusedToolPath(first.path); |
| 334 | 377 | void maybeLoadToolDetails(first, true); |
| @@ -336,6 +379,16 @@ export function ToolExplorer({ · 1 unmodified line | ||
| 336 | 379 | // eslint-disable-next-line react-hooks/exhaustive-deps |
| 337 | 380 | }, [searchedTools.length > 0]); |
| 338 | 381 | |
| 382 | + useEffect(() => { | |
| 383 | + if (!focusedToolPath || searchedTools.length === 0) { | |
| 384 | + return; | |
| 385 | + } | |
| 386 | + | |
| 387 | + if (!searchedTools.some((tool) => tool.path === focusedToolPath)) { | |
| 388 | + setFocusedToolPath(null); | |
| 389 | + } | |
| 390 | + }, [focusedToolPath, searchedTools]); | |
| 391 | + | |
| 339 | 392 | const loadingRows = useMemo(() => { |
| 340 | 393 | if (search.length > 0) return []; |
| 341 | 394 | const visibleLoadingSources = loadingSourceSet.size === 0 |
| @@ -53,9 +53,9 @@ import type { · 52 unmodified lines | ||
| 53 | 53 | ArgumentCondition, |
| 54 | 54 | ArgumentConditionOperator, |
| 55 | 55 | ToolDescriptor, |
| 56 | − ToolRoleBindingRecord, | |
| 57 | − ToolRoleRuleRecord, | |
| 58 | − ToolRoleRecord, | |
| 56 | + ToolPolicyAssignmentRecord, | |
| 57 | + ToolPolicyRuleRecord, | |
| 58 | + ToolPolicySetRecord, | |
| 59 | 59 | } from "@/lib/types"; |
| 60 | 60 | import type { Id } from "@executor/database/convex/_generated/dataModel"; |
| 61 | 61 | import { workspaceQueryArgs } from "@/lib/workspace/query-args"; |
| @@ -94,20 +94,20 @@ interface RoleFormState { · 32 unmodified lines | ||
| 94 | 94 | } |
| 95 | 95 | |
| 96 | 96 | interface RoleRuleFormState { |
| 97 | − selectorType: ToolRoleRuleRecord["selectorType"]; | |
| 97 | + selectorType: ToolPolicyRuleRecord["selectorType"]; | |
| 98 | 98 | sourceKey: string; |
| 99 | 99 | resourcePattern: string; |
| 100 | − matchType: ToolRoleRuleRecord["matchType"]; | |
| 101 | − effect: ToolRoleRuleRecord["effect"]; | |
| 102 | − approvalMode: ToolRoleRuleRecord["approvalMode"]; | |
| 100 | + matchType: ToolPolicyRuleRecord["matchType"]; | |
| 101 | + effect: ToolPolicyRuleRecord["effect"]; | |
| 102 | + approvalMode: ToolPolicyRuleRecord["approvalMode"]; | |
| 103 | 103 | priority: string; |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | interface RoleBindingFormState { |
| 107 | − scopeType: ToolRoleBindingRecord["scopeType"]; | |
| 107 | + scopeType: ToolPolicyAssignmentRecord["scopeType"]; | |
| 108 | 108 | targetAccountId: string; |
| 109 | 109 | clientId: string; |
| 110 | − status: ToolRoleBindingRecord["status"]; | |
| 110 | + status: ToolPolicyAssignmentRecord["status"]; | |
| 111 | 111 | } |
| 112 | 112 | |
| 113 | 113 | interface OrganizationMemberListItem { |
| @@ -343,7 +343,7 @@ function isDirectToolPolicy(policy: ToolPolicyRecord): boolean { · 229 unmodified lines | ||
| 343 | 343 | ); |
| 344 | 344 | } |
| 345 | 345 | |
| 346 | −function roleRulePattern(rule: ToolRoleRuleRecord): string { | |
| 346 | +function roleRulePattern(rule: ToolPolicyRuleRecord): string { | |
| 347 | 347 | if (rule.selectorType === "all") return "*"; |
| 348 | 348 | if (rule.selectorType === "source") return rule.sourceKey ?? ""; |
| 349 | 349 | if (rule.selectorType === "namespace") return rule.namespacePattern ?? ""; |
| @@ -837,7 +837,7 @@ function PolicyCard({ · 487 unmodified lines | ||
| 837 | 837 | </button> |
| 838 | 838 | </TooltipTrigger> |
| 839 | 839 | <TooltipContent side="left" className="text-xs"> |
| 840 | − {canDelete ? "Delete policy" : "Role-managed policy (delete from roles)"} | |
| 840 | + {canDelete ? "Delete policy" : "Policy-set-managed policy (delete from policy sets)"} | |
| 841 | 841 | </TooltipContent> |
| 842 | 842 | </Tooltip> |
| 843 | 843 | </TooltipProvider> |
| @@ -869,12 +869,12 @@ export function PoliciesPanel({ · 25 unmodified lines | ||
| 869 | 869 | |
| 870 | 870 | const listArgs = workspaceQueryArgs(context); |
| 871 | 871 | const policiesQuery = useQuery(convexApi.workspace.listToolPolicies, listArgs); |
| 872 | − const upsertToolRole = useMutation(convexApi.workspace.upsertToolRole); | |
| 873 | − const upsertToolRoleRule = useMutation(convexApi.workspace.upsertToolRoleRule); | |
| 874 | − const upsertToolRoleBinding = useMutation(convexApi.workspace.upsertToolRoleBinding); | |
| 875 | − const deleteToolRole = useMutation(convexApi.workspace.deleteToolRole); | |
| 876 | − const deleteToolRoleRule = useMutation(convexApi.workspace.deleteToolRoleRule); | |
| 877 | − const deleteToolRoleBinding = useMutation(convexApi.workspace.deleteToolRoleBinding); | |
| 872 | + const upsertToolPolicySet = useMutation(convexApi.workspace.upsertToolPolicySet); | |
| 873 | + const upsertToolPolicyRule = useMutation(convexApi.workspace.upsertToolPolicyRule); | |
| 874 | + const upsertToolPolicyAssignment = useMutation(convexApi.workspace.upsertToolPolicyAssignment); | |
| 875 | + const deleteToolPolicySet = useMutation(convexApi.workspace.deleteToolPolicySet); | |
| 876 | + const deleteToolPolicyRule = useMutation(convexApi.workspace.deleteToolPolicyRule); | |
| 877 | + const deleteToolPolicyAssignment = useMutation(convexApi.workspace.deleteToolPolicyAssignment); | |
| 878 | 878 | |
| 879 | 879 | const loading = Boolean(context) && policiesQuery === undefined; |
| 880 | 880 | const policies = useMemo(() => (policiesQuery ?? []) as ToolPolicyRecord[], [policiesQuery]); |
| @@ -902,10 +902,10 @@ export function PoliciesPanel({ · 21 unmodified lines | ||
| 902 | 902 | const canManageRoles = selfMembership?.role === "owner" || selfMembership?.role === "admin"; |
| 903 | 903 | |
| 904 | 904 | const rolesQuery = useQuery( |
| 905 | − convexApi.workspace.listToolRoles, | |
| 905 | + convexApi.workspace.listToolPolicySets, | |
| 906 | 906 | context && canManageRoles ? listArgs : "skip", |
| 907 | 907 | ); |
| 908 | − const roleItems = useMemo(() => ((rolesQuery ?? []) as ToolRoleRecord[]), [rolesQuery]); | |
| 908 | + const roleItems = useMemo(() => ((rolesQuery ?? []) as ToolPolicySetRecord[]), [rolesQuery]); | |
| 909 | 909 | const activeRoleId = useMemo(() => { |
| 910 | 910 | if (!canManageRoles) { |
| 911 | 911 | return null; |
| @@ -919,13 +919,13 @@ export function PoliciesPanel({ · 7 unmodified lines | ||
| 919 | 919 | }, [canManageRoles, roleItems, selectedRoleId]); |
| 920 | 920 | |
| 921 | 921 | const bindingsQuery = useQuery( |
| 922 | − convexApi.workspace.listToolRoleBindings, | |
| 922 | + convexApi.workspace.listToolPolicyAssignments, | |
| 923 | 923 | context && canManageRoles ? listArgs : "skip", |
| 924 | 924 | ); |
| 925 | − const bindingItems = useMemo(() => ((bindingsQuery ?? []) as ToolRoleBindingRecord[]), [bindingsQuery]); | |
| 925 | + const bindingItems = useMemo(() => ((bindingsQuery ?? []) as ToolPolicyAssignmentRecord[]), [bindingsQuery]); | |
| 926 | 926 | |
| 927 | 927 | const roleRulesQuery = useQuery( |
| 928 | − convexApi.workspace.listToolRoleRules, | |
| 928 | + convexApi.workspace.listToolPolicyRules, | |
| 929 | 929 | context && canManageRoles && activeRoleId |
| 930 | 930 | ? { |
| 931 | 931 | workspaceId: context.workspaceId, |
| @@ -935,7 +935,7 @@ export function PoliciesPanel({ · 3 unmodified lines | ||
| 935 | 935 | : "skip", |
| 936 | 936 | ); |
| 937 | 937 | const selectedRoleRules = useMemo( |
| 938 | − () => ((roleRulesQuery ?? []) as ToolRoleRuleRecord[]), | |
| 938 | + () => ((roleRulesQuery ?? []) as ToolPolicyRuleRecord[]), | |
| 939 | 939 | [roleRulesQuery], |
| 940 | 940 | ); |
| 941 | 941 | |
| @@ -1024,7 +1024,7 @@ export function PoliciesPanel({ · 82 unmodified lines | ||
| 1024 | 1024 | : "organization" as const; |
| 1025 | 1025 | const targetAccountId = form.scope === "personal" ? context.accountId : undefined; |
| 1026 | 1026 | |
| 1027 | − await upsertToolRole({ | |
| 1027 | + await upsertToolPolicySet({ | |
| 1028 | 1028 | workspaceId: context.workspaceId, |
| 1029 | 1029 | sessionId: context.sessionId, |
| 1030 | 1030 | id: roleId, |
| @@ -1033,7 +1033,7 @@ export function PoliciesPanel({ · 2 unmodified lines | ||
| 1033 | 1033 | }); |
| 1034 | 1034 | |
| 1035 | 1035 | try { |
| 1036 | − await upsertToolRoleRule({ | |
| 1036 | + await upsertToolPolicyRule({ | |
| 1037 | 1037 | workspaceId: context.workspaceId, |
| 1038 | 1038 | sessionId: context.sessionId, |
| 1039 | 1039 | id: ruleId, |
| @@ -1048,7 +1048,7 @@ export function PoliciesPanel({ · 8 unmodified lines | ||
| 1048 | 1048 | priority, |
| 1049 | 1049 | }); |
| 1050 | 1050 | |
| 1051 | − await upsertToolRoleBinding({ | |
| 1051 | + await upsertToolPolicyAssignment({ | |
| 1052 | 1052 | workspaceId: context.workspaceId, |
| 1053 | 1053 | sessionId: context.sessionId, |
| 1054 | 1054 | id: bindingId, |
| @@ -1060,7 +1060,7 @@ export function PoliciesPanel({ · 5 unmodified lines | ||
| 1060 | 1060 | }); |
| 1061 | 1061 | } catch (error) { |
| 1062 | 1062 | try { |
| 1063 | − await deleteToolRole({ | |
| 1063 | + await deleteToolPolicySet({ | |
| 1064 | 1064 | workspaceId: context.workspaceId, |
| 1065 | 1065 | sessionId: context.sessionId, |
| 1066 | 1066 | roleId, |
| @@ -1084,7 +1084,7 @@ export function PoliciesPanel({ · 17 unmodified lines | ||
| 1084 | 1084 | const handleDelete = useCallback(async (policy: ToolPolicyRecord) => { |
| 1085 | 1085 | if (!context) return; |
| 1086 | 1086 | if (!isDirectToolPolicy(policy)) { |
| 1087 | − toast.error("This policy is managed by role bindings. Use role management to remove it."); | |
| 1087 | + toast.error("This policy is managed by a policy set assignment. Use the Policy Set Manager to remove it."); | |
| 1088 | 1088 | return; |
| 1089 | 1089 | } |
| 1090 | 1090 | |
| @@ -1095,7 +1095,7 @@ export function PoliciesPanel({ · 4 unmodified lines | ||
| 1095 | 1095 | |
| 1096 | 1096 | setDeletingId(policy.id); |
| 1097 | 1097 | try { |
| 1098 | − await deleteToolRole({ | |
| 1098 | + await deleteToolPolicySet({ | |
| 1099 | 1099 | workspaceId: context.workspaceId, |
| 1100 | 1100 | sessionId: context.sessionId, |
| 1101 | 1101 | roleId: policy.roleId, |
| @@ -1106,7 +1106,7 @@ export function PoliciesPanel({ · 4 unmodified lines | ||
| 1106 | 1106 | } finally { |
| 1107 | 1107 | setDeletingId(null); |
| 1108 | 1108 | } |
| 1109 | − }, [context, deleteToolRole]); | |
| 1109 | + }, [context, deleteToolPolicySet]); | |
| 1110 | 1110 | |
| 1111 | 1111 | const handleCreateRole = useCallback(async () => { |
| 1112 | 1112 | if (!context) return; |
| @@ -1118,7 +1118,7 @@ export function PoliciesPanel({ · 5 unmodified lines | ||
| 1118 | 1118 | |
| 1119 | 1119 | setBusyRoleAction("create-role"); |
| 1120 | 1120 | try { |
| 1121 | − const role = await upsertToolRole({ | |
| 1121 | + const role = await upsertToolPolicySet({ | |
| 1122 | 1122 | workspaceId: context.workspaceId, |
| 1123 | 1123 | sessionId: context.sessionId, |
| 1124 | 1124 | name, |
| @@ -1132,7 +1132,7 @@ export function PoliciesPanel({ · 7 unmodified lines | ||
| 1132 | 1132 | } finally { |
| 1133 | 1133 | setBusyRoleAction(null); |
| 1134 | 1134 | } |
| 1135 | − }, [context, roleForm, upsertToolRole]); | |
| 1135 | + }, [context, roleForm, upsertToolPolicySet]); | |
| 1136 | 1136 | |
| 1137 | 1137 | const handleCreateRoleRule = useCallback(async () => { |
| 1138 | 1138 | if (!context || !activeRoleId) return; |
| @@ -1157,7 +1157,7 @@ export function PoliciesPanel({ · 18 unmodified lines | ||
| 1157 | 1157 | |
| 1158 | 1158 | setBusyRoleAction("create-rule"); |
| 1159 | 1159 | try { |
| 1160 | − await upsertToolRoleRule({ | |
| 1160 | + await upsertToolPolicyRule({ | |
| 1161 | 1161 | workspaceId: context.workspaceId, |
| 1162 | 1162 | sessionId: context.sessionId, |
| 1163 | 1163 | roleId: activeRoleId, |
| @@ -1176,7 +1176,7 @@ export function PoliciesPanel({ · 12 unmodified lines | ||
| 1176 | 1176 | } finally { |
| 1177 | 1177 | setBusyRoleAction(null); |
| 1178 | 1178 | } |
| 1179 | − }, [activeRoleId, context, roleRuleForm, upsertToolRoleRule]); | |
| 1179 | + }, [activeRoleId, context, roleRuleForm, upsertToolPolicyRule]); | |
| 1180 | 1180 | |
| 1181 | 1181 | const handleCreateRoleBinding = useCallback(async () => { |
| 1182 | 1182 | if (!context || !activeRoleId) return; |
| @@ -1190,7 +1190,7 @@ export function PoliciesPanel({ · 7 unmodified lines | ||
| 1190 | 1190 | |
| 1191 | 1191 | setBusyRoleAction("create-binding"); |
| 1192 | 1192 | try { |
| 1193 | − await upsertToolRoleBinding({ | |
| 1193 | + await upsertToolPolicyAssignment({ | |
| 1194 | 1194 | workspaceId: context.workspaceId, |
| 1195 | 1195 | sessionId: context.sessionId, |
| 1196 | 1196 | roleId: activeRoleId, |
| @@ -1208,14 +1208,14 @@ export function PoliciesPanel({ · 11 unmodified lines | ||
| 1208 | 1208 | } finally { |
| 1209 | 1209 | setBusyRoleAction(null); |
| 1210 | 1210 | } |
| 1211 | − }, [activeRoleId, context, roleBindingForm, upsertToolRoleBinding]); | |
| 1211 | + }, [activeRoleId, context, roleBindingForm, upsertToolPolicyAssignment]); | |
| 1212 | 1212 | |
| 1213 | 1213 | const handleDeleteRole = useCallback(async (roleId: string) => { |
| 1214 | 1214 | if (!context) return; |
| 1215 | 1215 | |
| 1216 | 1216 | setBusyRoleAction(`delete-role:${roleId}`); |
| 1217 | 1217 | try { |
| 1218 | − await deleteToolRole({ | |
| 1218 | + await deleteToolPolicySet({ | |
| 1219 | 1219 | workspaceId: context.workspaceId, |
| 1220 | 1220 | sessionId: context.sessionId, |
| 1221 | 1221 | roleId, |
| @@ -1229,14 +1229,14 @@ export function PoliciesPanel({ · 7 unmodified lines | ||
| 1229 | 1229 | } finally { |
| 1230 | 1230 | setBusyRoleAction(null); |
| 1231 | 1231 | } |
| 1232 | − }, [activeRoleId, context, deleteToolRole]); | |
| 1232 | + }, [activeRoleId, context, deleteToolPolicySet]); | |
| 1233 | 1233 | |
| 1234 | 1234 | const handleDeleteRule = useCallback(async (ruleId: string) => { |
| 1235 | 1235 | if (!context || !activeRoleId) return; |
| 1236 | 1236 | |
| 1237 | 1237 | setBusyRoleAction(`delete-rule:${ruleId}`); |
| 1238 | 1238 | try { |
| 1239 | − await deleteToolRoleRule({ | |
| 1239 | + await deleteToolPolicyRule({ | |
| 1240 | 1240 | workspaceId: context.workspaceId, |
| 1241 | 1241 | sessionId: context.sessionId, |
| 1242 | 1242 | roleId: activeRoleId, |
| @@ -1248,14 +1248,14 @@ export function PoliciesPanel({ · 5 unmodified lines | ||
| 1248 | 1248 | } finally { |
| 1249 | 1249 | setBusyRoleAction(null); |
| 1250 | 1250 | } |
| 1251 | − }, [activeRoleId, context, deleteToolRoleRule]); | |
| 1251 | + }, [activeRoleId, context, deleteToolPolicyRule]); | |
| 1252 | 1252 | |
| 1253 | 1253 | const handleDeleteBinding = useCallback(async (bindingId: string) => { |
| 1254 | 1254 | if (!context) return; |
| 1255 | 1255 | |
| 1256 | 1256 | setBusyRoleAction(`delete-binding:${bindingId}`); |
| 1257 | 1257 | try { |
| 1258 | − await deleteToolRoleBinding({ | |
| 1258 | + await deleteToolPolicyAssignment({ | |
| 1259 | 1259 | workspaceId: context.workspaceId, |
| 1260 | 1260 | sessionId: context.sessionId, |
| 1261 | 1261 | bindingId, |
| @@ -1266,7 +1266,7 @@ export function PoliciesPanel({ · 4 unmodified lines | ||
| 1266 | 1266 | } finally { |
| 1267 | 1267 | setBusyRoleAction(null); |
| 1268 | 1268 | } |
| 1269 | − }, [context, deleteToolRoleBinding]); | |
| 1269 | + }, [context, deleteToolPolicyAssignment]); | |
| 1270 | 1270 | |
| 1271 | 1271 | // ── Group policies by decision for display ── |
| 1272 | 1272 | |
| @@ -1305,7 +1305,7 @@ export function PoliciesPanel({ · 32 unmodified lines | ||
| 1305 | 1305 | disabled={!context} |
| 1306 | 1306 | > |
| 1307 | 1307 | <Plus className="h-3.5 w-3.5" /> |
| 1308 | − New Policy | |
| 1308 | + Quick Policy | |
| 1309 | 1309 | </Button> |
| 1310 | 1310 | </div> |
| 1311 | 1311 | |
| @@ -1375,28 +1375,31 @@ export function PoliciesPanel({ · 63 unmodified lines | ||
| 1375 | 1375 | |
| 1376 | 1376 | <Separator className="bg-border/40" /> |
| 1377 | 1377 | |
| 1378 | − <div className="space-y-3"> | |
| 1379 | − <div className="flex items-center justify-between"> | |
| 1378 | + <details className="group rounded-lg border border-border/60 bg-card/40"> | |
| 1379 | + <summary className="flex cursor-pointer list-none items-center justify-between gap-3 px-3 py-2.5"> | |
| 1380 | 1380 | <div> |
| 1381 | − <h4 className="text-sm font-medium">Role Manager</h4> | |
| 1382 | − <p className="text-[11px] text-muted-foreground mt-1"> | |
| 1383 | − Manage reusable tool roles, rule selectors, and scoped bindings. | |
| 1381 | + <h4 className="text-sm font-medium">Policy Set Manager</h4> | |
| 1382 | + <p className="text-[11px] text-muted-foreground mt-0.5"> | |
| 1383 | + Advanced: reusable policy sets with rules and assignments. | |
| 1384 | 1384 | </p> |
| 1385 | 1385 | </div> |
| 1386 | − </div> | |
| 1387 | − | |
| 1388 | − {!canManageRoles ? ( | |
| 1389 | − <div className="rounded-lg border border-dashed border-border/50 p-4 text-xs text-muted-foreground"> | |
| 1390 | − Organization owner/admin role required to manage tool roles. | |
| 1391 | − </div> | |
| 1392 | − ) : ( | |
| 1393 | − <div className="grid grid-cols-1 gap-4 lg:grid-cols-[280px_1fr]"> | |
| 1386 | + <span className="text-[10px] text-muted-foreground group-open:hidden">Expand</span> | |
| 1387 | + <span className="text-[10px] text-muted-foreground hidden group-open:inline">Collapse</span> | |
| 1388 | + </summary> | |
| 1389 | + | |
| 1390 | + <div className="px-3 pb-3"> | |
| 1391 | + {!canManageRoles ? ( | |
| 1392 | + <div className="rounded-lg border border-dashed border-border/50 p-4 text-xs text-muted-foreground"> | |
| 1393 | + Organization owner/admin role required to manage tool policy sets. | |
| 1394 | + </div> | |
| 1395 | + ) : ( | |
| 1396 | + <div className="grid grid-cols-1 gap-4 lg:grid-cols-[280px_1fr]"> | |
| 1394 | 1397 | <div className="space-y-3 rounded-lg border border-border/60 bg-card p-3"> |
| 1395 | − <Label className="text-xs text-muted-foreground">Create role</Label> | |
| 1398 | + <Label className="text-xs text-muted-foreground">Create policy set</Label> | |
| 1396 | 1399 | <Input |
| 1397 | 1400 | value={roleForm.name} |
| 1398 | 1401 | onChange={(event) => setRoleForm((state) => ({ ...state, name: event.target.value }))} |
| 1399 | − placeholder="Role name" | |
| 1402 | + placeholder="Policy set name" | |
| 1400 | 1403 | className="h-8 text-xs" |
| 1401 | 1404 | /> |
| 1402 | 1405 | <Input |
| @@ -1411,14 +1414,14 @@ export function PoliciesPanel({ · 8 unmodified lines | ||
| 1411 | 1414 | onClick={handleCreateRole} |
| 1412 | 1415 | disabled={busyRoleAction === "create-role"} |
| 1413 | 1416 | > |
| 1414 | − {busyRoleAction === "create-role" ? "Creating..." : "Create role"} | |
| 1417 | + {busyRoleAction === "create-role" ? "Creating..." : "Create policy set"} | |
| 1415 | 1418 | </Button> |
| 1416 | 1419 | |
| 1417 | 1420 | <Separator className="bg-border/40" /> |
| 1418 | 1421 | |
| 1419 | 1422 | <div className="space-y-1.5 max-h-[320px] overflow-y-auto"> |
| 1420 | 1423 | {roleItems.length === 0 ? ( |
| 1421 | − <p className="text-[11px] text-muted-foreground">No roles yet.</p> | |
| 1424 | + <p className="text-[11px] text-muted-foreground">No policy sets yet.</p> | |
| 1422 | 1425 | ) : ( |
| 1423 | 1426 | roleItems.map((role) => { |
| 1424 | 1427 | const bindingCount = bindingItems.filter((binding) => binding.roleId === role.id).length; |
| @@ -1429,7 +1432,7 @@ export function PoliciesPanel({ · 4 unmodified lines | ||
| 1429 | 1432 | onClick={() => setSelectedRoleId(role.id)} |
| 1430 | 1433 | className={cn( |
| 1431 | 1434 | "w-full rounded-md border px-2 py-1.5 text-left", |
| 1432 | − selectedRoleId === role.id | |
| 1435 | + activeRoleId === role.id | |
| 1433 | 1436 | ? "border-primary/40 bg-primary/5" |
| 1434 | 1437 | : "border-border/40 hover:bg-muted/30", |
| 1435 | 1438 | )} |
| @@ -1437,7 +1440,7 @@ export function PoliciesPanel({ · 1 unmodified line | ||
| 1437 | 1440 | <div className="flex items-center justify-between gap-2"> |
| 1438 | 1441 | <span className="truncate text-xs font-medium">{role.name}</span> |
| 1439 | 1442 | <Badge variant="outline" className="text-[9px] px-1.5 py-0"> |
| 1440 | − {bindingCount} bind | |
| 1443 | + {bindingCount} assign | |
| 1441 | 1444 | </Badge> |
| 1442 | 1445 | </div> |
| 1443 | 1446 | {role.description ? ( |
| @@ -1452,7 +1455,7 @@ export function PoliciesPanel({ · 8 unmodified lines | ||
| 1452 | 1455 | |
| 1453 | 1456 | <div className="space-y-4 rounded-lg border border-border/60 bg-card p-4"> |
| 1454 | 1457 | {!selectedRole ? ( |
| 1455 | − <p className="text-xs text-muted-foreground">Select a role to manage its rules and bindings.</p> | |
| 1458 | + <p className="text-xs text-muted-foreground">Select a policy set to manage its rules and assignments.</p> | |
| 1456 | 1459 | ) : ( |
| 1457 | 1460 | <> |
| 1458 | 1461 | <div className="flex items-start justify-between gap-3"> |
| @@ -1470,7 +1473,7 @@ export function PoliciesPanel({ · 11 unmodified lines | ||
| 1470 | 1473 | onClick={() => handleDeleteRole(selectedRole.id)} |
| 1471 | 1474 | disabled={busyRoleAction === `delete-role:${selectedRole.id}`} |
| 1472 | 1475 | > |
| 1473 | − {busyRoleAction === `delete-role:${selectedRole.id}` ? "Deleting..." : "Delete role"} | |
| 1476 | + {busyRoleAction === `delete-role:${selectedRole.id}` ? "Deleting..." : "Delete set"} | |
| 1474 | 1477 | </Button> |
| 1475 | 1478 | </div> |
| 1476 | 1479 | |
| @@ -1520,7 +1523,7 @@ export function PoliciesPanel({ · 43 unmodified lines | ||
| 1520 | 1523 | value={roleRuleForm.selectorType} |
| 1521 | 1524 | onValueChange={(value) => setRoleRuleForm((state) => ({ |
| 1522 | 1525 | ...state, |
| 1523 | − selectorType: value as ToolRoleRuleRecord["selectorType"], | |
| 1526 | + selectorType: value as ToolPolicyRuleRecord["selectorType"], | |
| 1524 | 1527 | }))} |
| 1525 | 1528 | > |
| 1526 | 1529 | <SelectTrigger className="h-8 text-xs"> |
| @@ -1564,7 +1567,7 @@ export function PoliciesPanel({ · 37 unmodified lines | ||
| 1564 | 1567 | value={roleRuleForm.effect} |
| 1565 | 1568 | onValueChange={(value) => setRoleRuleForm((state) => ({ |
| 1566 | 1569 | ...state, |
| 1567 | − effect: value as ToolRoleRuleRecord["effect"], | |
| 1570 | + effect: value as ToolPolicyRuleRecord["effect"], | |
| 1568 | 1571 | }))} |
| 1569 | 1572 | > |
| 1570 | 1573 | <SelectTrigger className="h-8 text-xs"> |
| @@ -1580,7 +1583,7 @@ export function PoliciesPanel({ · 9 unmodified lines | ||
| 1580 | 1583 | value={roleRuleForm.approvalMode} |
| 1581 | 1584 | onValueChange={(value) => setRoleRuleForm((state) => ({ |
| 1582 | 1585 | ...state, |
| 1583 | − approvalMode: value as ToolRoleRuleRecord["approvalMode"], | |
| 1586 | + approvalMode: value as ToolPolicyRuleRecord["approvalMode"], | |
| 1584 | 1587 | }))} |
| 1585 | 1588 | > |
| 1586 | 1589 | <SelectTrigger className="h-8 text-xs"> |
| @@ -1615,7 +1618,7 @@ export function PoliciesPanel({ · 28 unmodified lines | ||
| 1615 | 1618 | |
| 1616 | 1619 | <div className="space-y-2"> |
| 1617 | 1620 | <div className="flex items-center justify-between"> |
| 1618 | − <Label className="text-xs text-muted-foreground">Bindings</Label> | |
| 1621 | + <Label className="text-xs text-muted-foreground">Assignments</Label> | |
| 1619 | 1622 | <span className="text-[10px] text-muted-foreground">{selectedRoleBindings.length}</span> |
| 1620 | 1623 | </div> |
| 1621 | 1624 | <div className="space-y-1.5 max-h-[200px] overflow-y-auto"> |
| @@ -1657,7 +1660,7 @@ export function PoliciesPanel({ · 35 unmodified lines | ||
| 1657 | 1660 | value={roleBindingForm.scopeType} |
| 1658 | 1661 | onValueChange={(value) => setRoleBindingForm((state) => ({ |
| 1659 | 1662 | ...state, |
| 1660 | − scopeType: value as ToolRoleBindingRecord["scopeType"], | |
| 1663 | + scopeType: value as ToolPolicyAssignmentRecord["scopeType"], | |
| 1661 | 1664 | }))} |
| 1662 | 1665 | > |
| 1663 | 1666 | <SelectTrigger className="h-8 text-xs"> |
| @@ -1699,7 +1702,7 @@ export function PoliciesPanel({ · 35 unmodified lines | ||
| 1699 | 1702 | value={roleBindingForm.status} |
| 1700 | 1703 | onValueChange={(value) => setRoleBindingForm((state) => ({ |
| 1701 | 1704 | ...state, |
| 1702 | − status: value as ToolRoleBindingRecord["status"], | |
| 1705 | + status: value as ToolPolicyAssignmentRecord["status"], | |
| 1703 | 1706 | }))} |
| 1704 | 1707 | > |
| 1705 | 1708 | <SelectTrigger className="h-8 text-xs"> |
| @@ -1717,7 +1720,7 @@ export function PoliciesPanel({ · 11 unmodified lines | ||
| 1717 | 1720 | onClick={handleCreateRoleBinding} |
| 1718 | 1721 | disabled={busyRoleAction === "create-binding"} |
| 1719 | 1722 | > |
| 1720 | − {busyRoleAction === "create-binding" ? "Adding binding..." : "Add binding"} | |
| 1723 | + {busyRoleAction === "create-binding" ? "Adding assignment..." : "Add assignment"} | |
| 1721 | 1724 | </Button> |
| 1722 | 1725 | </div> |
| 1723 | 1726 | </div> |
| @@ -1725,8 +1728,9 @@ export function PoliciesPanel({ · 1 unmodified line | ||
| 1725 | 1728 | )} |
| 1726 | 1729 | </div> |
| 1727 | 1730 | </div> |
| 1728 | − )} | |
| 1729 | − </div> | |
| 1731 | + )} | |
| 1732 | + </div> | |
| 1733 | + </details> | |
| 1730 | 1734 | |
| 1731 | 1735 | {/* Create Policy Dialog */} |
| 1732 | 1736 | <Dialog open={dialogOpen} onOpenChange={setDialogOpen}> |
| @@ -1924,26 +1928,28 @@ export function PoliciesPanel({ · 191 unmodified lines | ||
| 1924 | 1928 | /> |
| 1925 | 1929 | </div> |
| 1926 | 1930 | |
| 1927 | − {/* Advanced filters */} | |
| 1928 | − <div className="space-y-3 rounded-md border border-border/40 bg-muted/10 p-3"> | |
| 1929 | − <div className="space-y-1"> | |
| 1930 | − <Label className="text-xs text-muted-foreground">Client ID</Label> | |
| 1931 | − <Input | |
| 1932 | − value={form.clientId} | |
| 1933 | − onChange={(event) => setForm((state) => ({ ...state, clientId: event.target.value }))} | |
| 1934 | − placeholder="optional client identifier" | |
| 1935 | − className="h-8 text-xs font-mono bg-background" | |
| 1931 | + <details className="rounded-md border border-border/40 bg-muted/10 p-3"> | |
| 1932 | + <summary className="cursor-pointer text-xs text-muted-foreground">Optional filters</summary> | |
| 1933 | + <div className="mt-3 space-y-3"> | |
| 1934 | + <div className="space-y-1"> | |
| 1935 | + <Label className="text-xs text-muted-foreground">Client ID</Label> | |
| 1936 | + <Input | |
| 1937 | + value={form.clientId} | |
| 1938 | + onChange={(event) => setForm((state) => ({ ...state, clientId: event.target.value }))} | |
| 1939 | + placeholder="optional client identifier" | |
| 1940 | + className="h-8 text-xs font-mono bg-background" | |
| 1941 | + /> | |
| 1942 | + <p className="text-[10px] text-muted-foreground/60 leading-tight"> | |
| 1943 | + When set, this policy only applies to tool calls from this client ID. | |
| 1944 | + </p> | |
| 1945 | + </div> | |
| 1946 | + | |
| 1947 | + <ArgumentConditionsEditor | |
| 1948 | + conditions={form.argumentConditions} | |
| 1949 | + onChange={(argumentConditions) => setForm((state) => ({ ...state, argumentConditions }))} | |
| 1936 | 1950 | /> |
| 1937 | − <p className="text-[10px] text-muted-foreground/60 leading-tight"> | |
| 1938 | − When set, this policy only applies to tool calls from this client ID. | |
| 1939 | − </p> | |
| 1940 | 1951 | </div> |
| 1941 | − | |
| 1942 | − <ArgumentConditionsEditor | |
| 1943 | − conditions={form.argumentConditions} | |
| 1944 | − onChange={(argumentConditions) => setForm((state) => ({ ...state, argumentConditions }))} | |
| 1945 | − /> | |
| 1946 | − </div> | |
| 1952 | + </details> | |
| 1947 | 1953 | </div> |
| 1948 | 1954 | |
| 1949 | 1955 | <DialogFooter> |
| @@ -1,6 +1,8 @@ | ||
| 1 | 1 | "use client"; |
| 2 | 2 | |
| 3 | −import { useCallback, useMemo, useRef, useState } from "react"; | |
| 3 | +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; | |
| 4 | +import { parseAsNativeArrayOf, parseAsString, parseAsStringLiteral, useQueryStates } from "nuqs"; | |
| 5 | +import { useLocation, useNavigate } from "@/lib/router"; | |
| 4 | 6 | import { Card, CardContent } from "@/components/ui/card"; |
| 5 | 7 | import { Skeleton } from "@/components/ui/skeleton"; |
| 6 | 8 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; |
| @@ -27,6 +29,7 @@ import { · 20 unmodified lines | ||
| 27 | 29 | import { sourceLabel } from "@/lib/tool/source-utils"; |
| 28 | 30 | import { workspaceQueryArgs } from "@/lib/workspace/query-args"; |
| 29 | 31 | import type { SourceDialogMeta } from "@/components/tools/add/source-dialog"; |
| 32 | +import type { FilterApproval } from "@/components/tools/explorer-derived"; | |
| 30 | 33 | |
| 31 | 34 | // ── Optimistic source helpers ── |
| 32 | 35 | |
| @@ -80,34 +83,87 @@ function pruneStaleOps( · 47 unmodified lines | ||
| 80 | 83 | }); |
| 81 | 84 | } |
| 82 | 85 | |
| 83 | −type ToolsTab = "catalog" | "credentials" | "policies" | "editor"; | |
| 86 | +type ToolsTab = "catalog" | "connections" | "policies" | "editor"; | |
| 84 | 87 | const INVENTORY_REGENERATION_TOAST_ID = "tool-inventory-regeneration"; |
| 85 | 88 | |
| 86 | −function parseInitialTab(tab?: string | null): ToolsTab { | |
| 87 | − if (tab === "runner" || tab === "editor") { | |
| 88 | − return "editor"; | |
| 89 | +function parseToolsTab(pathname: string): ToolsTab { | |
| 90 | + const segments = pathname.split("/").filter(Boolean); | |
| 91 | + const last = segments.at(-1); | |
| 92 | + | |
| 93 | + if (last === "catalog") { | |
| 94 | + return "catalog"; | |
| 89 | 95 | } |
| 90 | − if (tab === "catalog" || tab === "credentials") { | |
| 91 | − return tab; | |
| 96 | + if (last === "connections" || last === "credentials") { | |
| 97 | + return "connections"; | |
| 92 | 98 | } |
| 93 | − if (tab === "policies") { | |
| 99 | + if (last === "policies") { | |
| 94 | 100 | return "policies"; |
| 95 | 101 | } |
| 102 | + if (last === "editor" || last === "runner") { | |
| 103 | + return "editor"; | |
| 104 | + } | |
| 105 | + | |
| 96 | 106 | return "catalog"; |
| 97 | 107 | } |
| 98 | 108 | |
| 109 | +function normalizeCatalogApprovalFilter(value: string | null): FilterApproval { | |
| 110 | + if (value === "required" || value === "auto") { | |
| 111 | + return value; | |
| 112 | + } | |
| 113 | + | |
| 114 | + return "all"; | |
| 115 | +} | |
| 116 | + | |
| 117 | +function toolsPathFromTab(tab: ToolsTab): string { | |
| 118 | + if (tab === "catalog") { | |
| 119 | + return "/tools/catalog"; | |
| 120 | + } | |
| 121 | + if (tab === "connections") { | |
| 122 | + return "/tools/connections"; | |
| 123 | + } | |
| 124 | + if (tab === "policies") { | |
| 125 | + return "/tools/policies"; | |
| 126 | + } | |
| 127 | + return "/tools/editor"; | |
| 128 | +} | |
| 129 | + | |
| 130 | +function mapEmptyQueryValueToNull(value: string): string | null { | |
| 131 | + return value.length > 0 ? value : null; | |
| 132 | +} | |
| 133 | + | |
| 99 | 134 | // ── Tools View ── |
| 100 | 135 | |
| 101 | −export function ToolsView({ | |
| 102 | − initialSource, | |
| 103 | − initialTab, | |
| 104 | −}: { | |
| 105 | − initialSource?: string | null; | |
| 106 | − initialTab?: string | null; | |
| 107 | −}) { | |
| 136 | +export function ToolsView() { | |
| 137 | + const navigate = useNavigate(); | |
| 138 | + const location = useLocation(); | |
| 108 | 139 | const { context, loading: sessionLoading } = useSession(); |
| 109 | − const [selectedSource, setSelectedSource] = useState<string | null>(initialSource ?? null); | |
| 110 | − const [activeTab, setActiveTab] = useState<ToolsTab>(parseInitialTab(initialTab)); | |
| 140 | + const activeTab = useMemo(() => parseToolsTab(location.pathname), [location.pathname]); | |
| 141 | + const [catalogQueryState, setCatalogQueryState] = useQueryStates({ | |
| 142 | + q: parseAsString.withDefault(""), | |
| 143 | + approval: parseAsStringLiteral(["all", "required", "auto"]).withDefault("all"), | |
| 144 | + tool: parseAsString.withDefault(""), | |
| 145 | + selected: parseAsNativeArrayOf(parseAsString), | |
| 146 | + source: parseAsString.withDefault(""), | |
| 147 | + sourcePanel: parseAsString.withDefault(""), | |
| 148 | + }, { | |
| 149 | + history: "replace", | |
| 150 | + }); | |
| 151 | + | |
| 152 | + const catalogSearchValue = catalogQueryState.q; | |
| 153 | + const catalogFilterValue = useMemo( | |
| 154 | + () => normalizeCatalogApprovalFilter(catalogQueryState.approval), | |
| 155 | + [catalogQueryState.approval], | |
| 156 | + ); | |
| 157 | + const catalogSourceValue = useMemo(() => mapEmptyQueryValueToNull(catalogQueryState.source), [catalogQueryState.source]); | |
| 158 | + const catalogActiveToolPath = mapEmptyQueryValueToNull(catalogQueryState.tool); | |
| 159 | + const catalogSelectedToolPaths = useMemo( | |
| 160 | + () => catalogQueryState.selected ?? [], | |
| 161 | + [catalogQueryState.selected], | |
| 162 | + ); | |
| 163 | + const catalogFocusedSourceName = useMemo( | |
| 164 | + () => mapEmptyQueryValueToNull(catalogQueryState.sourcePanel), | |
| 165 | + [catalogQueryState.sourcePanel], | |
| 166 | + ); | |
| 111 | 167 | const [connectionDialogOpen, setConnectionDialogOpen] = useState(false); |
| 112 | 168 | const [connectionDialogEditing, setConnectionDialogEditing] = useState<CredentialRecord | null>(null); |
| 113 | 169 | const [connectionDialogSourceKey, setConnectionDialogSourceKey] = useState<string | null>(null); |
| @@ -316,6 +372,7 @@ export function ToolsView({ · 202 unmodified lines | ||
| 316 | 372 | |
| 317 | 373 | const existingSourceNames = useMemo(() => new Set(sourceItems.map((source) => source.name)), [sourceItems]); |
| 318 | 374 | const warningsBySource = useMemo(() => warningsBySourceName(warnings), [warnings]); |
| 375 | + | |
| 319 | 376 | const sourceDialogMeta = useMemo(() => { |
| 320 | 377 | const bySource: Record<string, SourceDialogMeta> = {}; |
| 321 | 378 | for (const source of sourceItems) { |
| @@ -328,10 +385,10 @@ export function ToolsView({ · 6 unmodified lines | ||
| 328 | 385 | } |
| 329 | 386 | return bySource; |
| 330 | 387 | }, [sourceItems, sourceQuality, refreshingTools, warningsBySource]); |
| 331 | − const activeSource = selectedSource | |
| 332 | − && (sourceItems.some((source) => source.name === selectedSource) || toolSourceNames.has(selectedSource)) | |
| 333 | − ? selectedSource | |
| 334 | − : null; | |
| 388 | + const activeSource = catalogSourceValue | |
| 389 | + && (sourceItems.some((source) => source.name === catalogSourceValue) || toolSourceNames.has(catalogSourceValue)) | |
| 390 | + ? catalogSourceValue | |
| 391 | + : null; | |
| 335 | 392 | |
| 336 | 393 | const handleSourceAdded = useCallback((source: ToolSourceRecord) => { |
| 337 | 394 | setOptimisticOps((ops) => [ |
| @@ -340,13 +397,67 @@ export function ToolsView({ · 2 unmodified lines | ||
| 340 | 397 | ]); |
| 341 | 398 | }, []); |
| 342 | 399 | |
| 400 | + const syncSourceToUrl = useCallback((sourceName: string) => { | |
| 401 | + void setCatalogQueryState({ | |
| 402 | + source: sourceName, | |
| 403 | + }, { | |
| 404 | + history: "replace", | |
| 405 | + }); | |
| 406 | + }, [setCatalogQueryState]); | |
| 407 | + | |
| 343 | 408 | const handleSourceDeleted = useCallback((sourceName: string) => { |
| 344 | 409 | setOptimisticOps((ops) => [ |
| 345 | 410 | ...ops, |
| 346 | 411 | { kind: "remove", sourceName, removedAt: Date.now() }, |
| 347 | 412 | ]); |
| 348 | − setSelectedSource((current) => (current === sourceName ? null : current)); | |
| 349 | − }, []); | |
| 413 | + syncSourceToUrl(activeSource === sourceName ? "" : (activeSource ?? "")); | |
| 414 | + }, [activeSource, syncSourceToUrl]); | |
| 415 | + | |
| 416 | + const setCatalogSearch = useCallback((search: string) => { | |
| 417 | + void setCatalogQueryState({ | |
| 418 | + q: search, | |
| 419 | + }, { | |
| 420 | + history: "replace", | |
| 421 | + }); | |
| 422 | + }, [setCatalogQueryState]); | |
| 423 | + | |
| 424 | + const setCatalogApprovalFilter = useCallback((filterApproval: FilterApproval) => { | |
| 425 | + void setCatalogQueryState({ | |
| 426 | + approval: filterApproval, | |
| 427 | + }, { | |
| 428 | + history: "replace", | |
| 429 | + }); | |
| 430 | + }, [setCatalogQueryState]); | |
| 431 | + | |
| 432 | + const setCatalogActiveToolPath = useCallback((toolPath: string | null) => { | |
| 433 | + void setCatalogQueryState({ | |
| 434 | + tool: toolPath ?? "", | |
| 435 | + }, { | |
| 436 | + history: "replace", | |
| 437 | + }); | |
| 438 | + }, [setCatalogQueryState]); | |
| 439 | + | |
| 440 | + const setCatalogSelectedToolPaths = useCallback((toolPaths: string[]) => { | |
| 441 | + void setCatalogQueryState({ | |
| 442 | + selected: toolPaths, | |
| 443 | + }, { | |
| 444 | + history: "replace", | |
| 445 | + }); | |
| 446 | + }, [setCatalogQueryState]); | |
| 447 | + | |
| 448 | + const setCatalogFocusedSourceName = useCallback((sourceName: string | null) => { | |
| 449 | + void setCatalogQueryState({ | |
| 450 | + sourcePanel: sourceName ?? "", | |
| 451 | + }, { | |
| 452 | + history: "replace", | |
| 453 | + }); | |
| 454 | + }, [setCatalogQueryState]); | |
| 455 | + | |
| 456 | + const setActiveTab = useCallback((nextTab: ToolsTab) => { | |
| 457 | + const nextPath = toolsPathFromTab(nextTab); | |
| 458 | + const qs = location.searchStr; | |
| 459 | + navigate(qs ? `${nextPath}?${qs}` : nextPath); | |
| 460 | + }, [location.searchStr, navigate]); | |
| 350 | 461 | |
| 351 | 462 | const handleRegenerateInventory = useCallback(async () => { |
| 352 | 463 | if (!context || regenerationInFlight) { |
| @@ -442,7 +553,7 @@ export function ToolsView({ · 89 unmodified lines | ||
| 442 | 553 | {loadingTools ? "..." : totalTools} |
| 443 | 554 | </span> |
| 444 | 555 | </TabsTrigger> |
| 445 | − <TabsTrigger value="credentials" className="text-xs data-[state=active]:bg-background"> | |
| 556 | + <TabsTrigger value="connections" className="text-xs data-[state=active]:bg-background"> | |
| 446 | 557 | Connections |
| 447 | 558 | {credentials && ( |
| 448 | 559 | <span className="ml-1.5 text-[10px] font-mono text-muted-foreground"> |
| @@ -478,16 +589,24 @@ export function ToolsView({ · 29 unmodified lines | ||
| 478 | 589 | sourceHasMoreTools={sourceHasMoreTools} |
| 479 | 590 | sourceLoadingMoreTools={sourceLoadingMoreTools} |
| 480 | 591 | onLoadMoreToolsForSource={loadMoreToolsForSource} |
| 481 | − loading={loadingTools} | |
| 482 | − sourceDialogMeta={sourceDialogMeta} | |
| 483 | − sourceAuthProfiles={sourceAuthProfiles} | |
| 484 | − existingSourceNames={existingSourceNames} | |
| 485 | − onSourceDeleted={handleSourceDeleted} | |
| 486 | − onLoadToolDetails={loadToolDetails} | |
| 487 | − warnings={warnings} | |
| 488 | − initialSource={initialSource} | |
| 489 | − activeSource={activeSource} | |
| 490 | − onActiveSourceChange={setSelectedSource} | |
| 592 | + loading={loadingTools} | |
| 593 | + sourceDialogMeta={sourceDialogMeta} | |
| 594 | + sourceAuthProfiles={sourceAuthProfiles} | |
| 595 | + existingSourceNames={existingSourceNames} | |
| 596 | + onSourceDeleted={handleSourceDeleted} | |
| 597 | + onLoadToolDetails={loadToolDetails} | |
| 598 | + warnings={warnings} | |
| 599 | + activeSource={activeSource} | |
| 600 | + searchValue={catalogSearchValue} | |
| 601 | + filterApprovalValue={catalogFilterValue} | |
| 602 | + focusedToolPathValue={catalogActiveToolPath} | |
| 603 | + selectedToolPathsValue={catalogSelectedToolPaths} | |
| 604 | + focusedSourceNameValue={catalogFocusedSourceName} | |
| 605 | + onSearchValueChange={setCatalogSearch} | |
| 606 | + onFilterApprovalValueChange={setCatalogApprovalFilter} | |
| 607 | + onFocusedToolPathChange={setCatalogActiveToolPath} | |
| 608 | + onSelectedToolPathsChange={setCatalogSelectedToolPaths} | |
| 609 | + onFocusedSourceNameChange={setCatalogFocusedSourceName} | |
| 491 | 610 | onRegenerate={handleRegenerateInventory} |
| 492 | 611 | inventoryState={inventoryStatus?.state} |
| 493 | 612 | inventoryError={inventoryStatus?.error} |
| @@ -503,7 +622,7 @@ export function ToolsView({ · 9 unmodified lines | ||
| 503 | 622 | </Card> |
| 504 | 623 | </TabsContent> |
| 505 | 624 | |
| 506 | − <TabsContent value="credentials" className="mt-4"> | |
| 625 | + <TabsContent value="connections" className="mt-4"> | |
| 507 | 626 | <CredentialsPanel |
| 508 | 627 | sources={sourceItems} |
| 509 | 628 | credentials={credentialItems} |
| @@ -1,9 +1,9 @@ | ||
| 1 | 1 | import type { Id } from "@executor/database/convex/_generated/dataModel"; |
| 2 | 2 | import type { |
| 3 | 3 | ToolPolicyRecord as CoreToolPolicyRecord, |
| 4 | − ToolRoleBindingRecord as CoreToolRoleBindingRecord, | |
| 5 | − ToolRoleRecord as CoreToolRoleRecord, | |
| 6 | − ToolRoleRuleRecord as CoreToolRoleRuleRecord, | |
| 4 | + ToolPolicyAssignmentRecord as CoreToolPolicyAssignmentRecord, | |
| 5 | + ToolPolicySetRecord as CoreToolPolicySetRecord, | |
| 6 | + ToolPolicyRuleRecord as CoreToolPolicyRuleRecord, | |
| 7 | 7 | } from "@executor/core/types"; |
| 8 | 8 | |
| 9 | 9 | // ── Shared types (inlined from @executor/contracts) ────────────────────────── |
| @@ -85,9 +85,9 @@ export interface TaskEventRecord { · 75 unmodified lines | ||
| 85 | 85 | } |
| 86 | 86 | |
| 87 | 87 | export type ToolPolicyRecord = CoreToolPolicyRecord; |
| 88 | −export type ToolRoleRecord = CoreToolRoleRecord; | |
| 89 | −export type ToolRoleRuleRecord = CoreToolRoleRuleRecord; | |
| 90 | −export type ToolRoleBindingRecord = CoreToolRoleBindingRecord; | |
| 88 | +export type ToolPolicySetRecord = CoreToolPolicySetRecord; | |
| 89 | +export type ToolPolicyRuleRecord = CoreToolPolicyRuleRecord; | |
| 90 | +export type ToolPolicyAssignmentRecord = CoreToolPolicyAssignmentRecord; | |
| 91 | 91 | |
| 92 | 92 | export interface CredentialRecord { |
| 93 | 93 | id: string; |
| @@ -9,7 +9,6 @@ · 8 unmodified lines | ||
| 9 | 9 | // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. |
| 10 | 10 | |
| 11 | 11 | import { Route as rootRouteImport } from './routes/__root' |
| 12 | −import { Route as ToolsRouteImport } from './routes/tools' | |
| 13 | 12 | import { Route as TasksRouteImport } from './routes/tasks' |
| 14 | 13 | import { Route as StaticAppShellRouteImport } from './routes/static-app-shell' |
| 15 | 14 | import { Route as SignUpRouteImport } from './routes/sign-up' |
| @@ -25,6 +24,11 @@ import { Route as CallbackRouteImport } from './routes/callback' · 9 unmodified lines | ||
| 25 | 24 | import { Route as BillingRouteImport } from './routes/billing' |
| 26 | 25 | import { Route as ApprovalsRouteImport } from './routes/approvals' |
| 27 | 26 | import { Route as IndexRouteImport } from './routes/index' |
| 27 | +import { Route as ToolsIndexRouteImport } from './routes/tools/index' | |
| 28 | +import { Route as ToolsPoliciesRouteImport } from './routes/tools/policies' | |
| 29 | +import { Route as ToolsEditorRouteImport } from './routes/tools/editor' | |
| 30 | +import { Route as ToolsConnectionsRouteImport } from './routes/tools/connections' | |
| 31 | +import { Route as ToolsCatalogRouteImport } from './routes/tools/catalog' | |
| 28 | 32 | import { Route as McpOauthStartRouteImport } from './routes/mcp/oauth/start' |
| 29 | 33 | import { Route as McpOauthResultRouteImport } from './routes/mcp/oauth/result' |
| 30 | 34 | import { Route as McpOauthDetectRouteImport } from './routes/mcp/oauth/detect' |
| @@ -34,11 +38,6 @@ import { Route as ApiOpenapiInspectRouteImport } from './routes/api/openapi/insp · 3 unmodified lines | ||
| 34 | 38 | import { Route as ApiAuthCallbackRouteImport } from './routes/api/auth/callback' |
| 35 | 39 | import { Route as ApiAuthAnonymousTokenRouteImport } from './routes/api/auth/anonymous-token' |
| 36 | 40 | |
| 37 | −const ToolsRoute = ToolsRouteImport.update({ | |
| 38 | − id: '/tools', | |
| 39 | − path: '/tools', | |
| 40 | − getParentRoute: () => rootRouteImport, | |
| 41 | −} as any) | |
| 42 | 41 | const TasksRoute = TasksRouteImport.update({ |
| 43 | 42 | id: '/tasks', |
| 44 | 43 | path: '/tasks', |
| @@ -114,6 +113,31 @@ const IndexRoute = IndexRouteImport.update({ · 69 unmodified lines | ||
| 114 | 113 | path: '/', |
| 115 | 114 | getParentRoute: () => rootRouteImport, |
| 116 | 115 | } as any) |
| 116 | +const ToolsIndexRoute = ToolsIndexRouteImport.update({ | |
| 117 | + id: '/tools/', | |
| 118 | + path: '/tools/', | |
| 119 | + getParentRoute: () => rootRouteImport, | |
| 120 | +} as any) | |
| 121 | +const ToolsPoliciesRoute = ToolsPoliciesRouteImport.update({ | |
| 122 | + id: '/tools/policies', | |
| 123 | + path: '/tools/policies', | |
| 124 | + getParentRoute: () => rootRouteImport, | |
| 125 | +} as any) | |
| 126 | +const ToolsEditorRoute = ToolsEditorRouteImport.update({ | |
| 127 | + id: '/tools/editor', | |
| 128 | + path: '/tools/editor', | |
| 129 | + getParentRoute: () => rootRouteImport, | |
| 130 | +} as any) | |
| 131 | +const ToolsConnectionsRoute = ToolsConnectionsRouteImport.update({ | |
| 132 | + id: '/tools/connections', | |
| 133 | + path: '/tools/connections', | |
| 134 | + getParentRoute: () => rootRouteImport, | |
| 135 | +} as any) | |
| 136 | +const ToolsCatalogRoute = ToolsCatalogRouteImport.update({ | |
| 137 | + id: '/tools/catalog', | |
| 138 | + path: '/tools/catalog', | |
| 139 | + getParentRoute: () => rootRouteImport, | |
| 140 | +} as any) | |
| 117 | 141 | const McpOauthStartRoute = McpOauthStartRouteImport.update({ |
| 118 | 142 | id: '/mcp/oauth/start', |
| 119 | 143 | path: '/mcp/oauth/start', |
| @@ -171,7 +195,11 @@ export interface FileRoutesByFullPath { · 51 unmodified lines | ||
| 171 | 195 | '/sign-up': typeof SignUpRoute |
| 172 | 196 | '/static-app-shell': typeof StaticAppShellRoute |
| 173 | 197 | '/tasks': typeof TasksRoute |
| 174 | − '/tools': typeof ToolsRoute | |
| 198 | + '/tools/catalog': typeof ToolsCatalogRoute | |
| 199 | + '/tools/connections': typeof ToolsConnectionsRoute | |
| 200 | + '/tools/editor': typeof ToolsEditorRoute | |
| 201 | + '/tools/policies': typeof ToolsPoliciesRoute | |
| 202 | + '/tools/': typeof ToolsIndexRoute | |
| 175 | 203 | '/api/auth/anonymous-token': typeof ApiAuthAnonymousTokenRoute |
| 176 | 204 | '/api/auth/callback': typeof ApiAuthCallbackRoute |
| 177 | 205 | '/api/openapi/inspect': typeof ApiOpenapiInspectRoute |
| @@ -197,7 +225,11 @@ export interface FileRoutesByTo { · 19 unmodified lines | ||
| 197 | 225 | '/sign-up': typeof SignUpRoute |
| 198 | 226 | '/static-app-shell': typeof StaticAppShellRoute |
| 199 | 227 | '/tasks': typeof TasksRoute |
| 200 | − '/tools': typeof ToolsRoute | |
| 228 | + '/tools/catalog': typeof ToolsCatalogRoute | |
| 229 | + '/tools/connections': typeof ToolsConnectionsRoute | |
| 230 | + '/tools/editor': typeof ToolsEditorRoute | |
| 231 | + '/tools/policies': typeof ToolsPoliciesRoute | |
| 232 | + '/tools': typeof ToolsIndexRoute | |
| 201 | 233 | '/api/auth/anonymous-token': typeof ApiAuthAnonymousTokenRoute |
| 202 | 234 | '/api/auth/callback': typeof ApiAuthCallbackRoute |
| 203 | 235 | '/api/openapi/inspect': typeof ApiOpenapiInspectRoute |
| @@ -224,7 +256,11 @@ export interface FileRoutesById { · 20 unmodified lines | ||
| 224 | 256 | '/sign-up': typeof SignUpRoute |
| 225 | 257 | '/static-app-shell': typeof StaticAppShellRoute |
| 226 | 258 | '/tasks': typeof TasksRoute |
| 227 | − '/tools': typeof ToolsRoute | |
| 259 | + '/tools/catalog': typeof ToolsCatalogRoute | |
| 260 | + '/tools/connections': typeof ToolsConnectionsRoute | |
| 261 | + '/tools/editor': typeof ToolsEditorRoute | |
| 262 | + '/tools/policies': typeof ToolsPoliciesRoute | |
| 263 | + '/tools/': typeof ToolsIndexRoute | |
| 228 | 264 | '/api/auth/anonymous-token': typeof ApiAuthAnonymousTokenRoute |
| 229 | 265 | '/api/auth/callback': typeof ApiAuthCallbackRoute |
| 230 | 266 | '/api/openapi/inspect': typeof ApiOpenapiInspectRoute |
| @@ -252,7 +288,11 @@ export interface FileRouteTypes { · 21 unmodified lines | ||
| 252 | 288 | | '/sign-up' |
| 253 | 289 | | '/static-app-shell' |
| 254 | 290 | | '/tasks' |
| 255 | − | '/tools' | |
| 291 | + | '/tools/catalog' | |
| 292 | + | '/tools/connections' | |
| 293 | + | '/tools/editor' | |
| 294 | + | '/tools/policies' | |
| 295 | + | '/tools/' | |
| 256 | 296 | | '/api/auth/anonymous-token' |
| 257 | 297 | | '/api/auth/callback' |
| 258 | 298 | | '/api/openapi/inspect' |
| @@ -278,6 +318,10 @@ export interface FileRouteTypes { · 19 unmodified lines | ||
| 278 | 318 | | '/sign-up' |
| 279 | 319 | | '/static-app-shell' |
| 280 | 320 | | '/tasks' |
| 321 | + | '/tools/catalog' | |
| 322 | + | '/tools/connections' | |
| 323 | + | '/tools/editor' | |
| 324 | + | '/tools/policies' | |
| 281 | 325 | | '/tools' |
| 282 | 326 | | '/api/auth/anonymous-token' |
| 283 | 327 | | '/api/auth/callback' |
| @@ -304,7 +348,11 @@ export interface FileRouteTypes { · 20 unmodified lines | ||
| 304 | 348 | | '/sign-up' |
| 305 | 349 | | '/static-app-shell' |
| 306 | 350 | | '/tasks' |
| 307 | − | '/tools' | |
| 351 | + | '/tools/catalog' | |
| 352 | + | '/tools/connections' | |
| 353 | + | '/tools/editor' | |
| 354 | + | '/tools/policies' | |
| 355 | + | '/tools/' | |
| 308 | 356 | | '/api/auth/anonymous-token' |
| 309 | 357 | | '/api/auth/callback' |
| 310 | 358 | | '/api/openapi/inspect' |
| @@ -331,7 +379,11 @@ export interface RootRouteChildren { · 20 unmodified lines | ||
| 331 | 379 | SignUpRoute: typeof SignUpRoute |
| 332 | 380 | StaticAppShellRoute: typeof StaticAppShellRoute |
| 333 | 381 | TasksRoute: typeof TasksRoute |
| 334 | − ToolsRoute: typeof ToolsRoute | |
| 382 | + ToolsCatalogRoute: typeof ToolsCatalogRoute | |
| 383 | + ToolsConnectionsRoute: typeof ToolsConnectionsRoute | |
| 384 | + ToolsEditorRoute: typeof ToolsEditorRoute | |
| 385 | + ToolsPoliciesRoute: typeof ToolsPoliciesRoute | |
| 386 | + ToolsIndexRoute: typeof ToolsIndexRoute | |
| 335 | 387 | ApiAuthAnonymousTokenRoute: typeof ApiAuthAnonymousTokenRoute |
| 336 | 388 | ApiAuthCallbackRoute: typeof ApiAuthCallbackRoute |
| 337 | 389 | ApiOpenapiInspectRoute: typeof ApiOpenapiInspectRoute |
| @@ -344,13 +396,6 @@ export interface RootRouteChildren { · 6 unmodified lines | ||
| 344 | 396 | |
| 345 | 397 | declare module '@tanstack/react-router' { |
| 346 | 398 | interface FileRoutesByPath { |
| 347 | − '/tools': { | |
| 348 | − id: '/tools' | |
| 349 | − path: '/tools' | |
| 350 | − fullPath: '/tools' | |
| 351 | − preLoaderRoute: typeof ToolsRouteImport | |
| 352 | − parentRoute: typeof rootRouteImport | |
| 353 | − } | |
| 354 | 399 | '/tasks': { |
| 355 | 400 | id: '/tasks' |
| 356 | 401 | path: '/tasks' |
| @@ -456,6 +501,41 @@ declare module '@tanstack/react-router' { · 99 unmodified lines | ||
| 456 | 501 | preLoaderRoute: typeof IndexRouteImport |
| 457 | 502 | parentRoute: typeof rootRouteImport |
| 458 | 503 | } |
| 504 | + '/tools/': { | |
| 505 | + id: '/tools/' | |
| 506 | + path: '/tools' | |
| 507 | + fullPath: '/tools/' | |
| 508 | + preLoaderRoute: typeof ToolsIndexRouteImport | |
| 509 | + parentRoute: typeof rootRouteImport | |
| 510 | + } | |
| 511 | + '/tools/policies': { | |
| 512 | + id: '/tools/policies' | |
| 513 | + path: '/tools/policies' | |
| 514 | + fullPath: '/tools/policies' | |
| 515 | + preLoaderRoute: typeof ToolsPoliciesRouteImport | |
| 516 | + parentRoute: typeof rootRouteImport | |
| 517 | + } | |
| 518 | + '/tools/editor': { | |
| 519 | + id: '/tools/editor' | |
| 520 | + path: '/tools/editor' | |
| 521 | + fullPath: '/tools/editor' | |
| 522 | + preLoaderRoute: typeof ToolsEditorRouteImport | |
| 523 | + parentRoute: typeof rootRouteImport | |
| 524 | + } | |
| 525 | + '/tools/connections': { | |
| 526 | + id: '/tools/connections' | |
| 527 | + path: '/tools/connections' | |
| 528 | + fullPath: '/tools/connections' | |
| 529 | + preLoaderRoute: typeof ToolsConnectionsRouteImport | |
| 530 | + parentRoute: typeof rootRouteImport | |
| 531 | + } | |
| 532 | + '/tools/catalog': { | |
| 533 | + id: '/tools/catalog' | |
| 534 | + path: '/tools/catalog' | |
| 535 | + fullPath: '/tools/catalog' | |
| 536 | + preLoaderRoute: typeof ToolsCatalogRouteImport | |
| 537 | + parentRoute: typeof rootRouteImport | |
| 538 | + } | |
| 459 | 539 | '/mcp/oauth/start': { |
| 460 | 540 | id: '/mcp/oauth/start' |
| 461 | 541 | path: '/mcp/oauth/start' |
| @@ -531,7 +611,11 @@ const rootRouteChildren: RootRouteChildren = { · 69 unmodified lines | ||
| 531 | 611 | SignUpRoute: SignUpRoute, |
| 532 | 612 | StaticAppShellRoute: StaticAppShellRoute, |
| 533 | 613 | TasksRoute: TasksRoute, |
| 534 | − ToolsRoute: ToolsRoute, | |
| 614 | + ToolsCatalogRoute: ToolsCatalogRoute, | |
| 615 | + ToolsConnectionsRoute: ToolsConnectionsRoute, | |
| 616 | + ToolsEditorRoute: ToolsEditorRoute, | |
| 617 | + ToolsPoliciesRoute: ToolsPoliciesRoute, | |
| 618 | + ToolsIndexRoute: ToolsIndexRoute, | |
| 535 | 619 | ApiAuthAnonymousTokenRoute: ApiAuthAnonymousTokenRoute, |
| 536 | 620 | ApiAuthCallbackRoute: ApiAuthCallbackRoute, |
| 537 | 621 | ApiOpenapiInspectRoute: ApiOpenapiInspectRoute, |
| @@ -5,6 +5,7 @@ import { AppConvexProvider } from "@/lib/convex-provider"; · 4 unmodified lines | ||
| 5 | 5 | import { QueryProvider } from "@/lib/query-provider"; |
| 6 | 6 | import { SessionProvider } from "@/lib/session-context"; |
| 7 | 7 | import { AppErrorBoundary } from "@/components/app-error-boundary"; |
| 8 | +import { NuqsAdapter } from "nuqs/adapters/tanstack-router"; | |
| 8 | 9 | import { runtimeConfigFromEnv } from "@/lib/runtime-config"; |
| 9 | 10 | import appCss from "../app/globals.css?url"; |
| 10 | 11 | |
| @@ -55,23 +56,25 @@ function RootDocument({ children }: { children: React.ReactNode }) { · 44 unmodified lines | ||
| 55 | 56 | __html: `window.__EXECUTOR_RUNTIME_CONFIG__ = ${runtimeConfig};`, |
| 56 | 57 | }} |
| 57 | 58 | /> |
| 58 | − <ThemeProvider | |
| 59 | − attribute="class" | |
| 60 | − defaultTheme="dark" | |
| 61 | − enableSystem | |
| 62 | − enableColorScheme | |
| 63 | − > | |
| 64 | − <AppErrorBoundary> | |
| 65 | − <QueryProvider> | |
| 66 | − <AppConvexProvider> | |
| 67 | − <SessionProvider> | |
| 68 | − {children} | |
| 69 | − </SessionProvider> | |
| 70 | − </AppConvexProvider> | |
| 71 | − </QueryProvider> | |
| 72 | − </AppErrorBoundary> | |
| 73 | − <Toaster position="bottom-right" /> | |
| 74 | − </ThemeProvider> | |
| 59 | + <NuqsAdapter> | |
| 60 | + <ThemeProvider | |
| 61 | + attribute="class" | |
| 62 | + defaultTheme="dark" | |
| 63 | + enableSystem | |
| 64 | + enableColorScheme | |
| 65 | + > | |
| 66 | + <AppErrorBoundary> | |
| 67 | + <QueryProvider> | |
| 68 | + <AppConvexProvider> | |
| 69 | + <SessionProvider> | |
| 70 | + {children} | |
| 71 | + </SessionProvider> | |
| 72 | + </AppConvexProvider> | |
| 73 | + </QueryProvider> | |
| 74 | + </AppErrorBoundary> | |
| 75 | + <Toaster position="bottom-right" /> | |
| 76 | + </ThemeProvider> | |
| 77 | + </NuqsAdapter> | |
| 75 | 78 | <Scripts /> |
| 76 | 79 | </body> |
| 77 | 80 | </html> |
| @@ -1,22 +0,0 @@ | ||
| 1 | −import { createFileRoute } from "@tanstack/react-router"; | |
| 2 | −import { AppShell } from "@/components/app-shell"; | |
| 3 | −import { ToolsView } from "@/components/tools/view"; | |
| 4 | −import { useSearchParams } from "@/lib/router"; | |
| 5 | − | |
| 6 | −export const Route = createFileRoute("/tools")({ | |
| 7 | − component: ToolsPage, | |
| 8 | −}); | |
| 9 | − | |
| 10 | −function ToolsPage() { | |
| 11 | − const [searchParams] = useSearchParams(); | |
| 12 | − const source = searchParams.get("source"); | |
| 13 | − const tab = searchParams.get("tab"); | |
| 14 | − | |
| 15 | − return ( | |
| 16 | − <AppShell> | |
| 17 | − <div className="h-full min-h-0"> | |
| 18 | − <ToolsView key={`${tab ?? "catalog"}:${source ?? "all"}`} initialSource={source} initialTab={tab} /> | |
| 19 | − </div> | |
| 20 | − </AppShell> | |
| 21 | − ); | |
| 22 | −} | |
| @@ -0,0 +1,15 @@ | ||
| 1 | +import { createFileRoute } from "@tanstack/react-router"; | |
| 2 | +import { AppShell } from "@/components/app-shell"; | |
| 3 | +import { ToolsView } from "@/components/tools/view"; | |
| 4 | + | |
| 5 | +export const Route = createFileRoute("/tools/catalog")({ | |
| 6 | + component: ToolsCatalogPage, | |
| 7 | +}); | |
| 8 | + | |
| 9 | +function ToolsCatalogPage() { | |
| 10 | + return ( | |
| 11 | + <AppShell> | |
| 12 | + <ToolsView /> | |
| 13 | + </AppShell> | |
| 14 | + ); | |
| 15 | +} | |
| @@ -0,0 +1,15 @@ | ||
| 1 | +import { createFileRoute } from "@tanstack/react-router"; | |
| 2 | +import { AppShell } from "@/components/app-shell"; | |
| 3 | +import { ToolsView } from "@/components/tools/view"; | |
| 4 | + | |
| 5 | +export const Route = createFileRoute("/tools/connections")({ | |
| 6 | + component: ToolsConnectionsPage, | |
| 7 | +}); | |
| 8 | + | |
| 9 | +function ToolsConnectionsPage() { | |
| 10 | + return ( | |
| 11 | + <AppShell> | |
| 12 | + <ToolsView /> | |
| 13 | + </AppShell> | |
| 14 | + ); | |
| 15 | +} | |
| @@ -0,0 +1,15 @@ | ||
| 1 | +import { createFileRoute } from "@tanstack/react-router"; | |
| 2 | +import { AppShell } from "@/components/app-shell"; | |
| 3 | +import { ToolsView } from "@/components/tools/view"; | |
| 4 | + | |
| 5 | +export const Route = createFileRoute("/tools/editor")({ | |
| 6 | + component: ToolsEditorPage, | |
| 7 | +}); | |
| 8 | + | |
| 9 | +function ToolsEditorPage() { | |
| 10 | + return ( | |
| 11 | + <AppShell> | |
| 12 | + <ToolsView /> | |
| 13 | + </AppShell> | |
| 14 | + ); | |
| 15 | +} | |
| @@ -0,0 +1,18 @@ | ||
| 1 | +import { createFileRoute } from "@tanstack/react-router"; | |
| 2 | +import { AppShell } from "@/components/app-shell"; | |
| 3 | +import { Navigate, useLocation } from "@/lib/router"; | |
| 4 | + | |
| 5 | +export const Route = createFileRoute("/tools/")({ | |
| 6 | + component: ToolsLayout, | |
| 7 | +}); | |
| 8 | + | |
| 9 | +function ToolsLayout() { | |
| 10 | + const location = useLocation(); | |
| 11 | + const search = location.searchStr ? `?${location.searchStr}` : ""; | |
| 12 | + | |
| 13 | + return ( | |
| 14 | + <AppShell> | |
| 15 | + <Navigate to={`/tools/catalog${search}`} replace /> | |
| 16 | + </AppShell> | |
| 17 | + ); | |
| 18 | +} | |
| @@ -0,0 +1,15 @@ | ||
| 1 | +import { createFileRoute } from "@tanstack/react-router"; | |
| 2 | +import { AppShell } from "@/components/app-shell"; | |
| 3 | +import { ToolsView } from "@/components/tools/view"; | |
| 4 | + | |
| 5 | +export const Route = createFileRoute("/tools/policies")({ | |
| 6 | + component: ToolsPoliciesPage, | |
| 7 | +}); | |
| 8 | + | |
| 9 | +function ToolsPoliciesPage() { | |
| 10 | + return ( | |
| 11 | + <AppShell> | |
| 12 | + <ToolsView /> | |
| 13 | + </AppShell> | |
| 14 | + ); | |
| 15 | +} | |
| @@ -123,7 +123,7 @@ export interface ToolPolicyRecord { · 122 unmodified lines | ||
| 123 | 123 | |
| 124 | 124 | export type ToolRoleSelectorType = "all" | "source" | "namespace" | "tool_path"; |
| 125 | 125 | |
| 126 | −export interface ToolRoleRecord { | |
| 126 | +export interface ToolPolicySetRecord { | |
| 127 | 127 | id: string; |
| 128 | 128 | organizationId: Id<"organizations">; |
| 129 | 129 | name: string; |
| @@ -133,7 +133,7 @@ export interface ToolRoleRecord { · 3 unmodified lines | ||
| 133 | 133 | updatedAt: number; |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | −export interface ToolRoleRuleRecord { | |
| 136 | +export interface ToolPolicyRuleRecord { | |
| 137 | 137 | id: string; |
| 138 | 138 | roleId: string; |
| 139 | 139 | organizationId: Id<"organizations">; |
| @@ -150,7 +150,7 @@ export interface ToolRoleRuleRecord { · 10 unmodified lines | ||
| 150 | 150 | updatedAt: number; |
| 151 | 151 | } |
| 152 | 152 | |
| 153 | −export interface ToolRoleBindingRecord { | |
| 153 | +export interface ToolPolicyAssignmentRecord { | |
| 154 | 154 | id: string; |
| 155 | 155 | roleId: string; |
| 156 | 156 | organizationId: Id<"organizations">; |
| @@ -306,19 +306,13 @@ export declare const api: { · 305 unmodified lines | ||
| 306 | 306 | { accountId?: string; sessionId?: string }, |
| 307 | 307 | any |
| 308 | 308 | >; |
| 309 | − deleteToolRole: FunctionReference< | |
| 310 | − "mutation", | |
| 311 | − "public", | |
| 312 | − { roleId: string; sessionId?: string; workspaceId: Id<"workspaces"> }, | |
| 313 | − any | |
| 314 | − >; | |
| 315 | − deleteToolRoleBinding: FunctionReference< | |
| 309 | + deleteToolPolicyAssignment: FunctionReference< | |
| 316 | 310 | "mutation", |
| 317 | 311 | "public", |
| 318 | 312 | { bindingId: string; sessionId?: string; workspaceId: Id<"workspaces"> }, |
| 319 | 313 | any |
| 320 | 314 | >; |
| 321 | − deleteToolRoleRule: FunctionReference< | |
| 315 | + deleteToolPolicyRule: FunctionReference< | |
| 322 | 316 | "mutation", |
| 323 | 317 | "public", |
| 324 | 318 | { |
| @@ -329,6 +323,12 @@ export declare const api: { · 4 unmodified lines | ||
| 329 | 323 | }, |
| 330 | 324 | any |
| 331 | 325 | >; |
| 326 | + deleteToolPolicySet: FunctionReference< | |
| 327 | + "mutation", | |
| 328 | + "public", | |
| 329 | + { roleId: string; sessionId?: string; workspaceId: Id<"workspaces"> }, | |
| 330 | + any | |
| 331 | + >; | |
| 332 | 332 | deleteToolSource: FunctionReference< |
| 333 | 333 | "mutation", |
| 334 | 334 | "public", |
| @@ -381,19 +381,19 @@ export declare const api: { · 46 unmodified lines | ||
| 381 | 381 | { sessionId?: string; workspaceId: Id<"workspaces"> }, |
| 382 | 382 | any |
| 383 | 383 | >; |
| 384 | − listToolRoleBindings: FunctionReference< | |
| 384 | + listToolPolicyAssignments: FunctionReference< | |
| 385 | 385 | "query", |
| 386 | 386 | "public", |
| 387 | 387 | { roleId?: string; sessionId?: string; workspaceId: Id<"workspaces"> }, |
| 388 | 388 | any |
| 389 | 389 | >; |
| 390 | − listToolRoleRules: FunctionReference< | |
| 390 | + listToolPolicyRules: FunctionReference< | |
| 391 | 391 | "query", |
| 392 | 392 | "public", |
| 393 | 393 | { roleId: string; sessionId?: string; workspaceId: Id<"workspaces"> }, |
| 394 | 394 | any |
| 395 | 395 | >; |
| 396 | − listToolRoles: FunctionReference< | |
| 396 | + listToolPolicySets: FunctionReference< | |
| 397 | 397 | "query", |
| 398 | 398 | "public", |
| 399 | 399 | { sessionId?: string; workspaceId: Id<"workspaces"> }, |
| @@ -439,19 +439,7 @@ export declare const api: { · 39 unmodified lines | ||
| 439 | 439 | }, |
| 440 | 440 | any |
| 441 | 441 | >; |
| 442 | − upsertToolRole: FunctionReference< | |
| 443 | − "mutation", | |
| 444 | − "public", | |
| 445 | − { | |
| 446 | − description?: string; | |
| 447 | − id?: string; | |
| 448 | − name: string; | |
| 449 | − sessionId?: string; | |
| 450 | − workspaceId: Id<"workspaces">; | |
| 451 | − }, | |
| 452 | − any | |
| 453 | − >; | |
| 454 | − upsertToolRoleBinding: FunctionReference< | |
| 442 | + upsertToolPolicyAssignment: FunctionReference< | |
| 455 | 443 | "mutation", |
| 456 | 444 | "public", |
| 457 | 445 | { |
| @@ -467,7 +455,7 @@ export declare const api: { · 9 unmodified lines | ||
| 467 | 455 | }, |
| 468 | 456 | any |
| 469 | 457 | >; |
| 470 | − upsertToolRoleRule: FunctionReference< | |
| 458 | + upsertToolPolicyRule: FunctionReference< | |
| 471 | 459 | "mutation", |
| 472 | 460 | "public", |
| 473 | 461 | { |
| @@ -490,6 +478,18 @@ export declare const api: { · 16 unmodified lines | ||
| 490 | 478 | }, |
| 491 | 479 | any |
| 492 | 480 | >; |
| 481 | + upsertToolPolicySet: FunctionReference< | |
| 482 | + "mutation", | |
| 483 | + "public", | |
| 484 | + { | |
| 485 | + description?: string; | |
| 486 | + id?: string; | |
| 487 | + name: string; | |
| 488 | + sessionId?: string; | |
| 489 | + workspaceId: Id<"workspaces">; | |
| 490 | + }, | |
| 491 | + any | |
| 492 | + >; | |
| 493 | 493 | upsertToolSource: FunctionReference< |
| 494 | 494 | "mutation", |
| 495 | 495 | "public", |
| @@ -742,22 +742,22 @@ export declare const internal: { · 246 unmodified lines | ||
| 742 | 742 | any |
| 743 | 743 | >; |
| 744 | 744 | }; |
| 745 | − deleteToolRole: FunctionReference< | |
| 745 | + deleteToolPolicyAssignment: FunctionReference< | |
| 746 | 746 | "mutation", |
| 747 | 747 | "internal", |
| 748 | − { roleId: string; workspaceId: Id<"workspaces"> }, | |
| 748 | + { bindingId: string; workspaceId: Id<"workspaces"> }, | |
| 749 | 749 | any |
| 750 | 750 | >; |
| 751 | − deleteToolRoleBinding: FunctionReference< | |
| 751 | + deleteToolPolicyRule: FunctionReference< | |
| 752 | 752 | "mutation", |
| 753 | 753 | "internal", |
| 754 | − { bindingId: string; workspaceId: Id<"workspaces"> }, | |
| 754 | + { roleId: string; ruleId: string; workspaceId: Id<"workspaces"> }, | |
| 755 | 755 | any |
| 756 | 756 | >; |
| 757 | − deleteToolRoleRule: FunctionReference< | |
| 757 | + deleteToolPolicySet: FunctionReference< | |
| 758 | 758 | "mutation", |
| 759 | 759 | "internal", |
| 760 | − { roleId: string; ruleId: string; workspaceId: Id<"workspaces"> }, | |
| 760 | + { roleId: string; workspaceId: Id<"workspaces"> }, | |
| 761 | 761 | any |
| 762 | 762 | >; |
| 763 | 763 | deleteToolSource: FunctionReference< |
| @@ -855,19 +855,19 @@ export declare const internal: { · 91 unmodified lines | ||
| 855 | 855 | { accountId?: Id<"accounts">; workspaceId: Id<"workspaces"> }, |
| 856 | 856 | any |
| 857 | 857 | >; |
| 858 | − listToolRoleBindings: FunctionReference< | |
| 858 | + listToolPolicyAssignments: FunctionReference< | |
| 859 | 859 | "query", |
| 860 | 860 | "internal", |
| 861 | 861 | { roleId?: string; workspaceId: Id<"workspaces"> }, |
| 862 | 862 | any |
| 863 | 863 | >; |
| 864 | − listToolRoleRules: FunctionReference< | |
| 864 | + listToolPolicyRules: FunctionReference< | |
| 865 | 865 | "query", |
| 866 | 866 | "internal", |
| 867 | 867 | { roleId: string; workspaceId: Id<"workspaces"> }, |
| 868 | 868 | any |
| 869 | 869 | >; |
| 870 | − listToolRoles: FunctionReference< | |
| 870 | + listToolPolicySets: FunctionReference< | |
| 871 | 871 | "query", |
| 872 | 872 | "internal", |
| 873 | 873 | { workspaceId: Id<"workspaces"> }, |
| @@ -897,22 +897,22 @@ export declare const internal: { · 23 unmodified lines | ||
| 897 | 897 | any |
| 898 | 898 | >; |
| 899 | 899 | policies: { |
| 900 | − deleteToolRole: FunctionReference< | |
| 900 | + deleteToolPolicyAssignment: FunctionReference< | |
| 901 | 901 | "mutation", |
| 902 | 902 | "internal", |
| 903 | − { roleId: string; workspaceId: Id<"workspaces"> }, | |
| 903 | + { bindingId: string; workspaceId: Id<"workspaces"> }, | |
| 904 | 904 | any |
| 905 | 905 | >; |
| 906 | − deleteToolRoleBinding: FunctionReference< | |
| 906 | + deleteToolPolicyRule: FunctionReference< | |
| 907 | 907 | "mutation", |
| 908 | 908 | "internal", |
| 909 | − { bindingId: string; workspaceId: Id<"workspaces"> }, | |
| 909 | + { roleId: string; ruleId: string; workspaceId: Id<"workspaces"> }, | |
| 910 | 910 | any |
| 911 | 911 | >; |
| 912 | − deleteToolRoleRule: FunctionReference< | |
| 912 | + deleteToolPolicySet: FunctionReference< | |
| 913 | 913 | "mutation", |
| 914 | 914 | "internal", |
| 915 | − { roleId: string; ruleId: string; workspaceId: Id<"workspaces"> }, | |
| 915 | + { roleId: string; workspaceId: Id<"workspaces"> }, | |
| 916 | 916 | any |
| 917 | 917 | >; |
| 918 | 918 | listRuntimeTargets: FunctionReference<"query", "internal", {}, any>; |
| @@ -922,37 +922,25 @@ export declare const internal: { · 3 unmodified lines | ||
| 922 | 922 | { accountId?: Id<"accounts">; workspaceId: Id<"workspaces"> }, |
| 923 | 923 | any |
| 924 | 924 | >; |
| 925 | − listToolRoleBindings: FunctionReference< | |
| 925 | + listToolPolicyAssignments: FunctionReference< | |
| 926 | 926 | "query", |
| 927 | 927 | "internal", |
| 928 | 928 | { roleId?: string; workspaceId: Id<"workspaces"> }, |
| 929 | 929 | any |
| 930 | 930 | >; |
| 931 | − listToolRoleRules: FunctionReference< | |
| 931 | + listToolPolicyRules: FunctionReference< | |
| 932 | 932 | "query", |
| 933 | 933 | "internal", |
| 934 | 934 | { roleId: string; workspaceId: Id<"workspaces"> }, |
| 935 | 935 | any |
| 936 | 936 | >; |
| 937 | − listToolRoles: FunctionReference< | |
| 937 | + listToolPolicySets: FunctionReference< | |
| 938 | 938 | "query", |
| 939 | 939 | "internal", |
| 940 | 940 | { workspaceId: Id<"workspaces"> }, |
| 941 | 941 | any |
| 942 | 942 | >; |
| 943 | − upsertToolRole: FunctionReference< | |
| 944 | − "mutation", | |
| 945 | − "internal", | |
| 946 | − { | |
| 947 | − createdByAccountId?: Id<"accounts">; | |
| 948 | − description?: string; | |
| 949 | − id?: string; | |
| 950 | − name: string; | |
| 951 | − workspaceId: Id<"workspaces">; | |
| 952 | − }, | |
| 953 | − any | |
| 954 | − >; | |
| 955 | − upsertToolRoleBinding: FunctionReference< | |
| 943 | + upsertToolPolicyAssignment: FunctionReference< | |
| 956 | 944 | "mutation", |
| 957 | 945 | "internal", |
| 958 | 946 | { |
| @@ -967,7 +955,7 @@ export declare const internal: { · 8 unmodified lines | ||
| 967 | 955 | }, |
| 968 | 956 | any |
| 969 | 957 | >; |
| 970 | − upsertToolRoleRule: FunctionReference< | |
| 958 | + upsertToolPolicyRule: FunctionReference< | |
| 971 | 959 | "mutation", |
| 972 | 960 | "internal", |
| 973 | 961 | { |
| @@ -989,6 +977,18 @@ export declare const internal: { · 15 unmodified lines | ||
| 989 | 977 | }, |
| 990 | 978 | any |
| 991 | 979 | >; |
| 980 | + upsertToolPolicySet: FunctionReference< | |
| 981 | + "mutation", | |
| 982 | + "internal", | |
| 983 | + { | |
| 984 | + createdByAccountId?: Id<"accounts">; | |
| 985 | + description?: string; | |
| 986 | + id?: string; | |
| 987 | + name: string; | |
| 988 | + workspaceId: Id<"workspaces">; | |
| 989 | + }, | |
| 990 | + any | |
| 991 | + >; | |
| 992 | 992 | }; |
| 993 | 993 | resolveApproval: FunctionReference< |
| 994 | 994 | "mutation", |
| @@ -1186,19 +1186,7 @@ export declare const internal: { · 191 unmodified lines | ||
| 1186 | 1186 | }, |
| 1187 | 1187 | any |
| 1188 | 1188 | >; |
| 1189 | − upsertToolRole: FunctionReference< | |
| 1190 | − "mutation", | |
| 1191 | − "internal", | |
| 1192 | − { | |
| 1193 | − createdByAccountId?: Id<"accounts">; | |
| 1194 | − description?: string; | |
| 1195 | − id?: string; | |
| 1196 | − name: string; | |
| 1197 | − workspaceId: Id<"workspaces">; | |
| 1198 | − }, | |
| 1199 | − any | |
| 1200 | − >; | |
| 1201 | − upsertToolRoleBinding: FunctionReference< | |
| 1189 | + upsertToolPolicyAssignment: FunctionReference< | |
| 1202 | 1190 | "mutation", |
| 1203 | 1191 | "internal", |
| 1204 | 1192 | { |
| @@ -1213,7 +1201,7 @@ export declare const internal: { · 8 unmodified lines | ||
| 1213 | 1201 | }, |
| 1214 | 1202 | any |
| 1215 | 1203 | >; |
| 1216 | − upsertToolRoleRule: FunctionReference< | |
| 1204 | + upsertToolPolicyRule: FunctionReference< | |
| 1217 | 1205 | "mutation", |
| 1218 | 1206 | "internal", |
| 1219 | 1207 | { |
| @@ -1235,6 +1223,18 @@ export declare const internal: { · 15 unmodified lines | ||
| 1235 | 1223 | }, |
| 1236 | 1224 | any |
| 1237 | 1225 | >; |
| 1226 | + upsertToolPolicySet: FunctionReference< | |
| 1227 | + "mutation", | |
| 1228 | + "internal", | |
| 1229 | + { | |
| 1230 | + createdByAccountId?: Id<"accounts">; | |
| 1231 | + description?: string; | |
| 1232 | + id?: string; | |
| 1233 | + name: string; | |
| 1234 | + workspaceId: Id<"workspaces">; | |
| 1235 | + }, | |
| 1236 | + any | |
| 1237 | + >; | |
| 1238 | 1238 | upsertToolSource: FunctionReference< |
| 1239 | 1239 | "mutation", |
| 1240 | 1240 | "internal", |
| @@ -217,7 +217,7 @@ describe("authentication", () => { · 216 unmodified lines | ||
| 217 | 217 | const owner = await seedUser(t, { subject: "owner-2" }); |
| 218 | 218 | |
| 219 | 219 | await expect( |
| 220 | − t.mutation(api.workspace.upsertToolRole, { | |
| 220 | + t.mutation(api.workspace.upsertToolPolicySet, { | |
| 221 | 221 | workspaceId: owner.workspaceId, |
| 222 | 222 | name: "anonymous-role", |
| 223 | 223 | }), |
| @@ -439,7 +439,7 @@ describe("workspace access controls", () => { · 215 unmodified lines | ||
| 439 | 439 | const authedMember = t.withIdentity({ subject: "ws-plain-member" }); |
| 440 | 440 | |
| 441 | 441 | await expect( |
| 442 | − authedMember.mutation(api.workspace.upsertToolRole, { | |
| 442 | + authedMember.mutation(api.workspace.upsertToolPolicySet, { | |
| 443 | 443 | workspaceId: owner.workspaceId, |
| 444 | 444 | name: "member-managed-role", |
| 445 | 445 | }), |
| @@ -464,13 +464,13 @@ describe("workspace access controls", () => { · 18 unmodified lines | ||
| 464 | 464 | |
| 465 | 465 | const authedAdmin = t.withIdentity({ subject: "ws-policy-admin" }); |
| 466 | 466 | |
| 467 | − const role = await authedAdmin.mutation(api.workspace.upsertToolRole, { | |
| 467 | + const role = await authedAdmin.mutation(api.workspace.upsertToolPolicySet, { | |
| 468 | 468 | workspaceId: owner.workspaceId, |
| 469 | 469 | name: "policy-admin-role", |
| 470 | 470 | description: "workspace admin policy role", |
| 471 | 471 | }); |
| 472 | 472 | |
| 473 | − await authedAdmin.mutation(api.workspace.upsertToolRoleRule, { | |
| 473 | + await authedAdmin.mutation(api.workspace.upsertToolPolicyRule, { | |
| 474 | 474 | workspaceId: owner.workspaceId, |
| 475 | 475 | roleId: role.id, |
| 476 | 476 | selectorType: "tool_path", |
| @@ -479,7 +479,7 @@ describe("workspace access controls", () => { · 2 unmodified lines | ||
| 479 | 479 | approvalMode: "required", |
| 480 | 480 | }); |
| 481 | 481 | |
| 482 | − await authedAdmin.mutation(api.workspace.upsertToolRoleBinding, { | |
| 482 | + await authedAdmin.mutation(api.workspace.upsertToolPolicyAssignment, { | |
| 483 | 483 | workspaceId: owner.workspaceId, |
| 484 | 484 | roleId: role.id, |
| 485 | 485 | scopeType: "workspace", |
| @@ -503,13 +503,13 @@ describe("workspace access controls", () => { · 17 unmodified lines | ||
| 503 | 503 | const outsider = await seedUser(t, { subject: "policy-target-outsider" }); |
| 504 | 504 | const authedOwner = t.withIdentity({ subject: "policy-target-owner" }); |
| 505 | 505 | |
| 506 | − const role = await authedOwner.mutation(api.workspace.upsertToolRole, { | |
| 506 | + const role = await authedOwner.mutation(api.workspace.upsertToolPolicySet, { | |
| 507 | 507 | workspaceId: owner.workspaceId, |
| 508 | 508 | name: "policy-target-role", |
| 509 | 509 | }); |
| 510 | 510 | |
| 511 | 511 | await expect( |
| 512 | − authedOwner.mutation(api.workspace.upsertToolRoleBinding, { | |
| 512 | + authedOwner.mutation(api.workspace.upsertToolPolicyAssignment, { | |
| 513 | 513 | workspaceId: owner.workspaceId, |
| 514 | 514 | roleId: role.id, |
| 515 | 515 | scopeType: "account", |
| @@ -524,12 +524,12 @@ describe("workspace access controls", () => { · 8 unmodified lines | ||
| 524 | 524 | const owner = await seedUser(t, { subject: "ws-owner-policy" }); |
| 525 | 525 | const authedOwner = t.withIdentity({ subject: "ws-owner-policy" }); |
| 526 | 526 | |
| 527 | − const role = await authedOwner.mutation(api.workspace.upsertToolRole, { | |
| 527 | + const role = await authedOwner.mutation(api.workspace.upsertToolPolicySet, { | |
| 528 | 528 | workspaceId: owner.workspaceId, |
| 529 | 529 | name: "owner-policy-role", |
| 530 | 530 | }); |
| 531 | 531 | |
| 532 | − await authedOwner.mutation(api.workspace.upsertToolRoleRule, { | |
| 532 | + await authedOwner.mutation(api.workspace.upsertToolPolicyRule, { | |
| 533 | 533 | workspaceId: owner.workspaceId, |
| 534 | 534 | roleId: role.id, |
| 535 | 535 | selectorType: "all", |
| @@ -537,7 +537,7 @@ describe("workspace access controls", () => { · 1 unmodified line | ||
| 537 | 537 | approvalMode: "required", |
| 538 | 538 | }); |
| 539 | 539 | |
| 540 | − await authedOwner.mutation(api.workspace.upsertToolRoleBinding, { | |
| 540 | + await authedOwner.mutation(api.workspace.upsertToolPolicyAssignment, { | |
| 541 | 541 | workspaceId: owner.workspaceId, |
| 542 | 542 | roleId: role.id, |
| 543 | 543 | scopeType: "workspace", |
| @@ -555,12 +555,12 @@ describe("workspace access controls", () => { · 11 unmodified lines | ||
| 555 | 555 | const owner = await seedUser(t, { subject: "ws-owner-policy-delete" }); |
| 556 | 556 | const authedOwner = t.withIdentity({ subject: "ws-owner-policy-delete" }); |
| 557 | 557 | |
| 558 | − const role = await authedOwner.mutation(api.workspace.upsertToolRole, { | |
| 558 | + const role = await authedOwner.mutation(api.workspace.upsertToolPolicySet, { | |
| 559 | 559 | workspaceId: owner.workspaceId, |
| 560 | 560 | name: "owner-policy-delete-role", |
| 561 | 561 | }); |
| 562 | 562 | |
| 563 | − await authedOwner.mutation(api.workspace.upsertToolRoleRule, { | |
| 563 | + await authedOwner.mutation(api.workspace.upsertToolPolicyRule, { | |
| 564 | 564 | workspaceId: owner.workspaceId, |
| 565 | 565 | roleId: role.id, |
| 566 | 566 | selectorType: "tool_path", |
| @@ -569,14 +569,14 @@ describe("workspace access controls", () => { · 2 unmodified lines | ||
| 569 | 569 | matchType: "exact", |
| 570 | 570 | }); |
| 571 | 571 | |
| 572 | − await authedOwner.mutation(api.workspace.upsertToolRoleBinding, { | |
| 572 | + await authedOwner.mutation(api.workspace.upsertToolPolicyAssignment, { | |
| 573 | 573 | workspaceId: owner.workspaceId, |
| 574 | 574 | roleId: role.id, |
| 575 | 575 | scopeType: "workspace", |
| 576 | 576 | status: "active", |
| 577 | 577 | }); |
| 578 | 578 | |
| 579 | − await authedOwner.mutation(api.workspace.deleteToolRole, { | |
| 579 | + await authedOwner.mutation(api.workspace.deleteToolPolicySet, { | |
| 580 | 580 | workspaceId: owner.workspaceId, |
| 581 | 581 | roleId: role.id, |
| 582 | 582 | }); |
| @@ -754,7 +754,7 @@ describe("workspace access controls", () => { · 171 unmodified lines | ||
| 754 | 754 | const authedMember = t.withIdentity({ subject: "role-tool-member" }); |
| 755 | 755 | |
| 756 | 756 | await expect( |
| 757 | − authedMember.mutation(api.workspace.upsertToolRole, { | |
| 757 | + authedMember.mutation(api.workspace.upsertToolPolicySet, { | |
| 758 | 758 | workspaceId: owner.workspaceId, |
| 759 | 759 | name: "limited", |
| 760 | 760 | }), |
| @@ -766,13 +766,13 @@ describe("workspace access controls", () => { · 5 unmodified lines | ||
| 766 | 766 | const owner = await seedUser(t, { subject: "role-source-owner" }); |
| 767 | 767 | const authedOwner = t.withIdentity({ subject: "role-source-owner" }); |
| 768 | 768 | |
| 769 | − const role = await authedOwner.mutation(api.workspace.upsertToolRole, { | |
| 769 | + const role = await authedOwner.mutation(api.workspace.upsertToolPolicySet, { | |
| 770 | 770 | workspaceId: owner.workspaceId, |
| 771 | 771 | name: "github-access", |
| 772 | 772 | description: "Allows github source tools", |
| 773 | 773 | }); |
| 774 | 774 | |
| 775 | − await authedOwner.mutation(api.workspace.upsertToolRoleRule, { | |
| 775 | + await authedOwner.mutation(api.workspace.upsertToolPolicyRule, { | |
| 776 | 776 | workspaceId: owner.workspaceId, |
| 777 | 777 | roleId: role.id, |
| 778 | 778 | selectorType: "source", |
| @@ -781,7 +781,7 @@ describe("workspace access controls", () => { · 2 unmodified lines | ||
| 781 | 781 | approvalMode: "auto", |
| 782 | 782 | }); |
| 783 | 783 | |
| 784 | − await authedOwner.mutation(api.workspace.upsertToolRoleBinding, { | |
| 784 | + await authedOwner.mutation(api.workspace.upsertToolPolicyAssignment, { | |
| 785 | 785 | workspaceId: owner.workspaceId, |
| 786 | 786 | roleId: role.id, |
| 787 | 787 | scopeType: "organization", |
| @@ -1120,7 +1120,7 @@ describe("cross-workspace isolation", () => { · 332 unmodified lines | ||
| 1120 | 1120 | const authedA = t.withIdentity({ subject: "policy-user-a" }); |
| 1121 | 1121 | |
| 1122 | 1122 | await expect( |
| 1123 | − authedA.mutation(api.workspace.upsertToolRole, { | |
| 1123 | + authedA.mutation(api.workspace.upsertToolPolicySet, { | |
| 1124 | 1124 | workspaceId: userB.workspaceId, |
| 1125 | 1125 | name: "cross-workspace-role", |
| 1126 | 1126 | }), |
| @@ -1628,18 +1628,18 @@ describe("role hierarchy validation", () => { · 501 unmodified lines | ||
| 1628 | 1628 | const authed = t.withIdentity({ subject: "admin-hier-admin" }); |
| 1629 | 1629 | |
| 1630 | 1630 | // Admin can manage tool-policy roles/rules/bindings |
| 1631 | − const role = await authed.mutation(api.workspace.upsertToolRole, { | |
| 1631 | + const role = await authed.mutation(api.workspace.upsertToolPolicySet, { | |
| 1632 | 1632 | workspaceId: org.workspaceId, |
| 1633 | 1633 | name: "admin-hierarchy-role", |
| 1634 | 1634 | }); |
| 1635 | − await authed.mutation(api.workspace.upsertToolRoleRule, { | |
| 1635 | + await authed.mutation(api.workspace.upsertToolPolicyRule, { | |
| 1636 | 1636 | workspaceId: org.workspaceId, |
| 1637 | 1637 | roleId: role.id, |
| 1638 | 1638 | selectorType: "tool_path", |
| 1639 | 1639 | resourcePattern: "admin.*", |
| 1640 | 1640 | effect: "deny", |
| 1641 | 1641 | }); |
| 1642 | − await authed.mutation(api.workspace.upsertToolRoleBinding, { | |
| 1642 | + await authed.mutation(api.workspace.upsertToolPolicyAssignment, { | |
| 1643 | 1643 | workspaceId: org.workspaceId, |
| 1644 | 1644 | roleId: role.id, |
| 1645 | 1645 | scopeType: "workspace", |
| @@ -25,15 +25,15 @@ export { · 24 unmodified lines | ||
| 25 | 25 | export { bootstrapAnonymousSession } from "./database/anonymous_session"; |
| 26 | 26 | export { |
| 27 | 27 | listRuntimeTargets, |
| 28 | − upsertToolRole, | |
| 29 | − listToolRoles, | |
| 30 | − deleteToolRole, | |
| 31 | − upsertToolRoleRule, | |
| 32 | − listToolRoleRules, | |
| 33 | − deleteToolRoleRule, | |
| 34 | − upsertToolRoleBinding, | |
| 35 | − listToolRoleBindings, | |
| 36 | − deleteToolRoleBinding, | |
| 28 | + upsertToolPolicySet, | |
| 29 | + listToolPolicySets, | |
| 30 | + deleteToolPolicySet, | |
| 31 | + upsertToolPolicyRule, | |
| 32 | + listToolPolicyRules, | |
| 33 | + deleteToolPolicyRule, | |
| 34 | + upsertToolPolicyAssignment, | |
| 35 | + listToolPolicyAssignments, | |
| 36 | + deleteToolPolicyAssignment, | |
| 37 | 37 | listToolPolicies, |
| 38 | 38 | } from "./database/policies"; |
| 39 | 39 | export { |
| @@ -5,9 +5,9 @@ import type { MutationCtx, QueryCtx } from "../_generated/server"; · 4 unmodified lines | ||
| 5 | 5 | import { listRuntimeTargets as listAvailableRuntimeTargets } from "../../../core/src/runtimes/runtime-catalog"; |
| 6 | 6 | import type { |
| 7 | 7 | ToolPolicyRecord, |
| 8 | − ToolRoleBindingRecord, | |
| 9 | − ToolRoleRecord, | |
| 10 | − ToolRoleRuleRecord, | |
| 8 | + ToolPolicyAssignmentRecord, | |
| 9 | + ToolPolicySetRecord, | |
| 10 | + ToolPolicyRuleRecord, | |
| 11 | 11 | ToolRoleSelectorType, |
| 12 | 12 | } from "../../../core/src/types"; |
| 13 | 13 | import { |
| @@ -83,7 +83,7 @@ function mapToolRole(doc: { · 69 unmodified lines | ||
| 83 | 83 | createdByAccountId?: Id<"accounts">; |
| 84 | 84 | createdAt: number; |
| 85 | 85 | updatedAt: number; |
| 86 | −}): ToolRoleRecord { | |
| 86 | +}): ToolPolicySetRecord { | |
| 87 | 87 | return { |
| 88 | 88 | id: doc.roleId, |
| 89 | 89 | organizationId: doc.organizationId, |
| @@ -110,7 +110,7 @@ function mapToolRoleRule(doc: { · 20 unmodified lines | ||
| 110 | 110 | priority: number; |
| 111 | 111 | createdAt: number; |
| 112 | 112 | updatedAt: number; |
| 113 | −}): ToolRoleRuleRecord { | |
| 113 | +}): ToolPolicyRuleRecord { | |
| 114 | 114 | return { |
| 115 | 115 | id: doc.ruleId, |
| 116 | 116 | roleId: doc.roleId, |
| @@ -141,7 +141,7 @@ function mapToolRoleBinding(doc: { · 24 unmodified lines | ||
| 141 | 141 | expiresAt?: number; |
| 142 | 142 | createdAt: number; |
| 143 | 143 | updatedAt: number; |
| 144 | −}): ToolRoleBindingRecord { | |
| 144 | +}): ToolPolicyAssignmentRecord { | |
| 145 | 145 | return { |
| 146 | 146 | id: doc.bindingId, |
| 147 | 147 | roleId: doc.roleId, |
| @@ -328,7 +328,7 @@ async function listEffectiveBindings( · 180 unmodified lines | ||
| 328 | 328 | } |
| 329 | 329 | |
| 330 | 330 | function selectorInputToResource( |
| 331 | − rule: Pick<ToolRoleRuleRecord, "selectorType" | "sourceKey" | "namespacePattern" | "toolPathPattern">, | |
| 331 | + rule: Pick<ToolPolicyRuleRecord, "selectorType" | "sourceKey" | "namespacePattern" | "toolPathPattern">, | |
| 332 | 332 | ): { resourceType: PolicyResourceType; resourcePattern: string } { |
| 333 | 333 | const resourceType = resourceTypeFromSelectorType(rule.selectorType); |
| 334 | 334 | const resourcePattern = resourcePatternFromRule(rule); |
| @@ -346,7 +346,7 @@ export const listRuntimeTargets = internalQuery({ · 11 unmodified lines | ||
| 346 | 346 | }, |
| 347 | 347 | }); |
| 348 | 348 | |
| 349 | −export const upsertToolRole = internalMutation({ | |
| 349 | +export const upsertToolPolicySet = internalMutation({ | |
| 350 | 350 | args: { |
| 351 | 351 | workspaceId: v.id("workspaces"), |
| 352 | 352 | id: v.optional(v.string()), |
| @@ -410,7 +410,7 @@ export const upsertToolRole = internalMutation({ · 57 unmodified lines | ||
| 410 | 410 | }, |
| 411 | 411 | }); |
| 412 | 412 | |
| 413 | −export const listToolRoles = internalQuery({ | |
| 413 | +export const listToolPolicySets = internalQuery({ | |
| 414 | 414 | args: { |
| 415 | 415 | workspaceId: v.id("workspaces"), |
| 416 | 416 | }, |
| @@ -426,7 +426,7 @@ export const listToolRoles = internalQuery({ · 9 unmodified lines | ||
| 426 | 426 | }, |
| 427 | 427 | }); |
| 428 | 428 | |
| 429 | −export const deleteToolRole = internalMutation({ | |
| 429 | +export const deleteToolPolicySet = internalMutation({ | |
| 430 | 430 | args: { |
| 431 | 431 | workspaceId: v.id("workspaces"), |
| 432 | 432 | roleId: v.string(), |
| @@ -459,7 +459,7 @@ export const deleteToolRole = internalMutation({ · 26 unmodified lines | ||
| 459 | 459 | }, |
| 460 | 460 | }); |
| 461 | 461 | |
| 462 | −export const upsertToolRoleRule = internalMutation({ | |
| 462 | +export const upsertToolPolicyRule = internalMutation({ | |
| 463 | 463 | args: { |
| 464 | 464 | workspaceId: v.id("workspaces"), |
| 465 | 465 | roleId: v.string(), |
| @@ -541,7 +541,7 @@ export const upsertToolRoleRule = internalMutation({ · 75 unmodified lines | ||
| 541 | 541 | }, |
| 542 | 542 | }); |
| 543 | 543 | |
| 544 | −export const listToolRoleRules = internalQuery({ | |
| 544 | +export const listToolPolicyRules = internalQuery({ | |
| 545 | 545 | args: { |
| 546 | 546 | workspaceId: v.id("workspaces"), |
| 547 | 547 | roleId: v.string(), |
| @@ -572,7 +572,7 @@ export const listToolRoleRules = internalQuery({ · 24 unmodified lines | ||
| 572 | 572 | }, |
| 573 | 573 | }); |
| 574 | 574 | |
| 575 | −export const deleteToolRoleRule = internalMutation({ | |
| 575 | +export const deleteToolPolicyRule = internalMutation({ | |
| 576 | 576 | args: { |
| 577 | 577 | workspaceId: v.id("workspaces"), |
| 578 | 578 | roleId: v.string(), |
| @@ -601,7 +601,7 @@ export const deleteToolRoleRule = internalMutation({ · 22 unmodified lines | ||
| 601 | 601 | }, |
| 602 | 602 | }); |
| 603 | 603 | |
| 604 | −export const upsertToolRoleBinding = internalMutation({ | |
| 604 | +export const upsertToolPolicyAssignment = internalMutation({ | |
| 605 | 605 | args: { |
| 606 | 606 | workspaceId: v.id("workspaces"), |
| 607 | 607 | roleId: v.string(), |
| @@ -680,7 +680,7 @@ export const upsertToolRoleBinding = internalMutation({ · 72 unmodified lines | ||
| 680 | 680 | }, |
| 681 | 681 | }); |
| 682 | 682 | |
| 683 | −export const listToolRoleBindings = internalQuery({ | |
| 683 | +export const listToolPolicyAssignments = internalQuery({ | |
| 684 | 684 | args: { |
| 685 | 685 | workspaceId: v.id("workspaces"), |
| 686 | 686 | roleId: v.optional(v.string()), |
| @@ -705,7 +705,7 @@ export const listToolRoleBindings = internalQuery({ · 18 unmodified lines | ||
| 705 | 705 | }, |
| 706 | 706 | }); |
| 707 | 707 | |
| 708 | −export const deleteToolRoleBinding = internalMutation({ | |
| 708 | +export const deleteToolPolicyAssignment = internalMutation({ | |
| 709 | 709 | args: { |
| 710 | 710 | workspaceId: v.id("workspaces"), |
| 711 | 711 | bindingId: v.string(), |
| @@ -136,7 +136,7 @@ export const listToolPolicies = workspaceQuery({ · 135 unmodified lines | ||
| 136 | 136 | }, |
| 137 | 137 | }); |
| 138 | 138 | |
| 139 | −export const upsertToolRole = workspaceMutation({ | |
| 139 | +export const upsertToolPolicySet = workspaceMutation({ | |
| 140 | 140 | method: "POST", |
| 141 | 141 | requireAdmin: true, |
| 142 | 142 | args: { |
| @@ -145,7 +145,7 @@ export const upsertToolRole = workspaceMutation({ · 2 unmodified lines | ||
| 145 | 145 | description: v.optional(v.string()), |
| 146 | 146 | }, |
| 147 | 147 | handler: async (ctx, args) => { |
| 148 | − return await ctx.runMutation(internal.database.upsertToolRole, { | |
| 148 | + return await ctx.runMutation(internal.database.upsertToolPolicySet, { | |
| 149 | 149 | ...args, |
| 150 | 150 | workspaceId: ctx.workspaceId, |
| 151 | 151 | createdByAccountId: ctx.account._id, |
| @@ -153,32 +153,32 @@ export const upsertToolRole = workspaceMutation({ · 1 unmodified line | ||
| 153 | 153 | }, |
| 154 | 154 | }); |
| 155 | 155 | |
| 156 | −export const listToolRoles = workspaceQuery({ | |
| 156 | +export const listToolPolicySets = workspaceQuery({ | |
| 157 | 157 | method: "GET", |
| 158 | 158 | requireAdmin: true, |
| 159 | 159 | args: {}, |
| 160 | 160 | handler: async (ctx) => { |
| 161 | − return await ctx.runQuery(internal.database.listToolRoles, { | |
| 161 | + return await ctx.runQuery(internal.database.listToolPolicySets, { | |
| 162 | 162 | workspaceId: ctx.workspaceId, |
| 163 | 163 | }); |
| 164 | 164 | }, |
| 165 | 165 | }); |
| 166 | 166 | |
| 167 | −export const deleteToolRole = workspaceMutation({ | |
| 167 | +export const deleteToolPolicySet = workspaceMutation({ | |
| 168 | 168 | method: "POST", |
| 169 | 169 | requireAdmin: true, |
| 170 | 170 | args: { |
| 171 | 171 | roleId: v.string(), |
| 172 | 172 | }, |
| 173 | 173 | handler: async (ctx, args) => { |
| 174 | − return await ctx.runMutation(internal.database.deleteToolRole, { | |
| 174 | + return await ctx.runMutation(internal.database.deleteToolPolicySet, { | |
| 175 | 175 | workspaceId: ctx.workspaceId, |
| 176 | 176 | roleId: args.roleId, |
| 177 | 177 | }); |
| 178 | 178 | }, |
| 179 | 179 | }); |
| 180 | 180 | |
| 181 | −export const upsertToolRoleRule = workspaceMutation({ | |
| 181 | +export const upsertToolPolicyRule = workspaceMutation({ | |
| 182 | 182 | method: "POST", |
| 183 | 183 | requireAdmin: true, |
| 184 | 184 | args: { |
| @@ -198,28 +198,28 @@ export const upsertToolRoleRule = workspaceMutation({ · 13 unmodified lines | ||
| 198 | 198 | priority: v.optional(v.number()), |
| 199 | 199 | }, |
| 200 | 200 | handler: async (ctx, args) => { |
| 201 | − return await ctx.runMutation(internal.database.upsertToolRoleRule, { | |
| 201 | + return await ctx.runMutation(internal.database.upsertToolPolicyRule, { | |
| 202 | 202 | ...args, |
| 203 | 203 | workspaceId: ctx.workspaceId, |
| 204 | 204 | }); |
| 205 | 205 | }, |
| 206 | 206 | }); |
| 207 | 207 | |
| 208 | −export const listToolRoleRules = workspaceQuery({ | |
| 208 | +export const listToolPolicyRules = workspaceQuery({ | |
| 209 | 209 | method: "GET", |
| 210 | 210 | requireAdmin: true, |
| 211 | 211 | args: { |
| 212 | 212 | roleId: v.string(), |
| 213 | 213 | }, |
| 214 | 214 | handler: async (ctx, args) => { |
| 215 | − return await ctx.runQuery(internal.database.listToolRoleRules, { | |
| 215 | + return await ctx.runQuery(internal.database.listToolPolicyRules, { | |
| 216 | 216 | workspaceId: ctx.workspaceId, |
| 217 | 217 | roleId: args.roleId, |
| 218 | 218 | }); |
| 219 | 219 | }, |
| 220 | 220 | }); |
| 221 | 221 | |
| 222 | −export const deleteToolRoleRule = workspaceMutation({ | |
| 222 | +export const deleteToolPolicyRule = workspaceMutation({ | |
| 223 | 223 | method: "POST", |
| 224 | 224 | requireAdmin: true, |
| 225 | 225 | args: { |
| @@ -227,7 +227,7 @@ export const deleteToolRoleRule = workspaceMutation({ · 1 unmodified line | ||
| 227 | 227 | ruleId: v.string(), |
| 228 | 228 | }, |
| 229 | 229 | handler: async (ctx, args) => { |
| 230 | − return await ctx.runMutation(internal.database.deleteToolRoleRule, { | |
| 230 | + return await ctx.runMutation(internal.database.deleteToolPolicyRule, { | |
| 231 | 231 | workspaceId: ctx.workspaceId, |
| 232 | 232 | roleId: args.roleId, |
| 233 | 233 | ruleId: args.ruleId, |
| @@ -235,7 +235,7 @@ export const deleteToolRoleRule = workspaceMutation({ · 1 unmodified line | ||
| 235 | 235 | }, |
| 236 | 236 | }); |
| 237 | 237 | |
| 238 | −export const upsertToolRoleBinding = workspaceMutation({ | |
| 238 | +export const upsertToolPolicyAssignment = workspaceMutation({ | |
| 239 | 239 | method: "POST", |
| 240 | 240 | requireAdmin: true, |
| 241 | 241 | args: { |
| @@ -248,35 +248,35 @@ export const upsertToolRoleBinding = workspaceMutation({ · 6 unmodified lines | ||
| 248 | 248 | expiresAt: v.optional(v.number()), |
| 249 | 249 | }, |
| 250 | 250 | handler: async (ctx, args) => { |
| 251 | − return await ctx.runMutation(internal.database.upsertToolRoleBinding, { | |
| 251 | + return await ctx.runMutation(internal.database.upsertToolPolicyAssignment, { | |
| 252 | 252 | ...args, |
| 253 | 253 | workspaceId: ctx.workspaceId, |
| 254 | 254 | }); |
| 255 | 255 | }, |
| 256 | 256 | }); |
| 257 | 257 | |
| 258 | −export const listToolRoleBindings = workspaceQuery({ | |
| 258 | +export const listToolPolicyAssignments = workspaceQuery({ | |
| 259 | 259 | method: "GET", |
| 260 | 260 | requireAdmin: true, |
| 261 | 261 | args: { |
| 262 | 262 | roleId: v.optional(v.string()), |
| 263 | 263 | }, |
| 264 | 264 | handler: async (ctx, args) => { |
| 265 | − return await ctx.runQuery(internal.database.listToolRoleBindings, { | |
| 265 | + return await ctx.runQuery(internal.database.listToolPolicyAssignments, { | |
| 266 | 266 | workspaceId: ctx.workspaceId, |
| 267 | 267 | roleId: args.roleId, |
| 268 | 268 | }); |
| 269 | 269 | }, |
| 270 | 270 | }); |
| 271 | 271 | |
| 272 | −export const deleteToolRoleBinding = workspaceMutation({ | |
| 272 | +export const deleteToolPolicyAssignment = workspaceMutation({ | |
| 273 | 273 | method: "POST", |
| 274 | 274 | requireAdmin: true, |
| 275 | 275 | args: { |
| 276 | 276 | bindingId: v.string(), |
| 277 | 277 | }, |
| 278 | 278 | handler: async (ctx, args) => { |
| 279 | − return await ctx.runMutation(internal.database.deleteToolRoleBinding, { | |
| 279 | + return await ctx.runMutation(internal.database.deleteToolPolicyAssignment, { | |
| 280 | 280 | workspaceId: ctx.workspaceId, |
| 281 | 281 | bindingId: args.bindingId, |
| 282 | 282 | }); |