History

Make toolkits a first-class route

Rhys Sullivan committed 4 months ago

Commit be7fa251 parent d1fb12515 files · +602 −178Browse files

Unified · Split

15 files
  1. apps/cloud/src/routeTree.gen.ts +65 −0
  2. apps/host-cloudflare/web/routeTree.gen.ts +61 −0
  3. apps/host-selfhost/web/routeTree.gen.ts +61 −0
  4. e2e/selfhost/toolkits-ui.test.ts +37 −16
  5. packages/app/src/routeTree.gen.ts +58 −0
  6. packages/app/src/web/shell.tsx +7 −0
  7. packages/plugins/toolkits/src/client.tsx +0 −1
  8. packages/plugins/toolkits/src/page.tsx +190 −158
  9. packages/react/src/console-routes.ts +4 −0
  10. packages/react/src/multiplayer/shell.tsx +1 −0
  11. packages/react/src/routes/plugins.$pluginId.$.tsx +18 −3
  12. packages/react/src/routes/routeTree.gen.ts +53 −0
  13. packages/react/src/routes/toolkits-route.tsx +23 −0
  14. packages/react/src/routes/toolkits.$toolkitSlug.tsx +12 −0
  15. packages/react/src/routes/toolkits.tsx +12 −0
apps/cloud/src/routeTree.gen.ts+65−0
@@ -14,11 +14,13 @@ import { Route as LoginRouteImport } from './routes/bare/login' · 13 unmodified lines
1414 import { Route as CreateOrgRouteImport } from './routes/bare/create-org'
1515 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRouteImport } from './../../../packages/react/src/routes/index'
1616 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRouteImport } from './../../../packages/react/src/routes/tools'
17+import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport } from './../../../packages/react/src/routes/toolkits'
1718 import { Route as SecretsRouteImport } from './routes/app/secrets'
1819 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRouteImport } from './../../../packages/react/src/routes/policies'
1920 import { Route as OrgRouteImport } from './routes/app/org'
2021 import { Route as BillingRouteImport } from './routes/app/billing'
2122 import { Route as ApiKeysRouteImport } from './routes/app/api-keys'
23+import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport } from './../../../packages/react/src/routes/toolkits.$toolkitSlug'
2224 import { Route as ResumeDotexecutionIdRouteImport } from './routes/app/resume.$executionId'
2325 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport } from './../../../packages/react/src/routes/integrations.$namespace'
2426 import { Route as Billing_DotplansRouteImport } from './routes/app/billing_.plans'
@@ -51,6 +53,12 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute = · 26 unmodified lines
5153 path: '/{-$orgSlug}/tools',
5254 getParentRoute: () => rootRouteImport,
5355 } as any)
56+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute =
57+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport.update({
58+ id: '/{-$orgSlug}/toolkits',
59+ path: '/{-$orgSlug}/toolkits',
60+ getParentRoute: () => rootRouteImport,
61+ } as any)
5462 const SecretsRoute = SecretsRouteImport.update({
5563 id: '/{-$orgSlug}/secrets',
5664 path: '/{-$orgSlug}/secrets',
@@ -77,6 +85,15 @@ const ApiKeysRoute = ApiKeysRouteImport.update({ · 20 unmodified lines
7785 path: '/{-$orgSlug}/api-keys',
7886 getParentRoute: () => rootRouteImport,
7987 } as any)
88+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute =
89+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport.update(
90+ {
91+ id: '/$toolkitSlug',
92+ path: '/$toolkitSlug',
93+ getParentRoute: () =>
94+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute,
95+ } as any,
96+ )
8097 const ResumeDotexecutionIdRoute = ResumeDotexecutionIdRouteImport.update({
8198 id: '/{-$orgSlug}/resume/$executionId',
8299 path: '/{-$orgSlug}/resume/$executionId',
@@ -113,11 +130,13 @@ export interface FileRoutesByFullPath { · 30 unmodified lines
113130 '/{-$orgSlug}/org': typeof OrgRoute
114131 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
115132 '/{-$orgSlug}/secrets': typeof SecretsRoute
133+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
116134 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
117135 '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
118136 '/{-$orgSlug}/billing/plans': typeof Billing_DotplansRoute
119137 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
120138 '/{-$orgSlug}/resume/$executionId': typeof ResumeDotexecutionIdRoute
139+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
121140 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
122141 }
123142 export interface FileRoutesByTo {
@@ -129,11 +148,13 @@ export interface FileRoutesByTo { · 5 unmodified lines
129148 '/{-$orgSlug}/org': typeof OrgRoute
130149 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
131150 '/{-$orgSlug}/secrets': typeof SecretsRoute
151+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
132152 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
133153 '/{-$orgSlug}': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
134154 '/{-$orgSlug}/billing/plans': typeof Billing_DotplansRoute
135155 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
136156 '/{-$orgSlug}/resume/$executionId': typeof ResumeDotexecutionIdRoute
157+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
137158 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
138159 }
139160 export interface FileRoutesById {
@@ -146,11 +167,13 @@ export interface FileRoutesById { · 6 unmodified lines
146167 '/{-$orgSlug}/org': typeof OrgRoute
147168 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
148169 '/{-$orgSlug}/secrets': typeof SecretsRoute
170+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
149171 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
150172 '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
151173 '/{-$orgSlug}/billing_/plans': typeof Billing_DotplansRoute
152174 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
153175 '/{-$orgSlug}/resume/$executionId': typeof ResumeDotexecutionIdRoute
176+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
154177 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
155178 }
156179 export interface FileRouteTypes {
@@ -164,11 +187,13 @@ export interface FileRouteTypes { · 7 unmodified lines
164187 | '/{-$orgSlug}/org'
165188 | '/{-$orgSlug}/policies'
166189 | '/{-$orgSlug}/secrets'
190+ | '/{-$orgSlug}/toolkits'
167191 | '/{-$orgSlug}/tools'
168192 | '/{-$orgSlug}/'
169193 | '/{-$orgSlug}/billing/plans'
170194 | '/{-$orgSlug}/integrations/$namespace'
171195 | '/{-$orgSlug}/resume/$executionId'
196+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
172197 | '/{-$orgSlug}/integrations/add/$pluginKey'
173198 fileRoutesByTo: FileRoutesByTo
174199 to:
@@ -180,11 +205,13 @@ export interface FileRouteTypes { · 5 unmodified lines
180205 | '/{-$orgSlug}/org'
181206 | '/{-$orgSlug}/policies'
182207 | '/{-$orgSlug}/secrets'
208+ | '/{-$orgSlug}/toolkits'
183209 | '/{-$orgSlug}/tools'
184210 | '/{-$orgSlug}'
185211 | '/{-$orgSlug}/billing/plans'
186212 | '/{-$orgSlug}/integrations/$namespace'
187213 | '/{-$orgSlug}/resume/$executionId'
214+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
188215 | '/{-$orgSlug}/integrations/add/$pluginKey'
189216 id:
190217 | '__root__'
@@ -196,11 +223,13 @@ export interface FileRouteTypes { · 5 unmodified lines
196223 | '/{-$orgSlug}/org'
197224 | '/{-$orgSlug}/policies'
198225 | '/{-$orgSlug}/secrets'
226+ | '/{-$orgSlug}/toolkits'
199227 | '/{-$orgSlug}/tools'
200228 | '/{-$orgSlug}/'
201229 | '/{-$orgSlug}/billing_/plans'
202230 | '/{-$orgSlug}/integrations/$namespace'
203231 | '/{-$orgSlug}/resume/$executionId'
232+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
204233 | '/{-$orgSlug}/integrations/add/$pluginKey'
205234 fileRoutesById: FileRoutesById
206235 }
@@ -213,6 +242,7 @@ export interface RootRouteChildren { · 6 unmodified lines
213242 OrgRoute: typeof OrgRoute
214243 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
215244 SecretsRoute: typeof SecretsRoute
245+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
216246 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
217247 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
218248 Billing_DotplansRoute: typeof Billing_DotplansRoute
@@ -258,6 +288,13 @@ declare module '@tanstack/react-router' { · 39 unmodified lines
258288 preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRouteImport
259289 parentRoute: typeof rootRouteImport
260290 }
291+ '/{-$orgSlug}/toolkits': {
292+ id: '/{-$orgSlug}/toolkits'
293+ path: '/{-$orgSlug}/toolkits'
294+ fullPath: '/{-$orgSlug}/toolkits'
295+ preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport
296+ parentRoute: typeof rootRouteImport
297+ }
261298 '/{-$orgSlug}/secrets': {
262299 id: '/{-$orgSlug}/secrets'
263300 path: '/{-$orgSlug}/secrets'
@@ -293,6 +330,13 @@ declare module '@tanstack/react-router' { · 29 unmodified lines
293330 preLoaderRoute: typeof ApiKeysRouteImport
294331 parentRoute: typeof rootRouteImport
295332 }
333+ '/{-$orgSlug}/toolkits/$toolkitSlug': {
334+ id: '/{-$orgSlug}/toolkits/$toolkitSlug'
335+ path: '/$toolkitSlug'
336+ fullPath: '/{-$orgSlug}/toolkits/$toolkitSlug'
337+ preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport
338+ parentRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute
339+ }
296340 '/{-$orgSlug}/resume/$executionId': {
297341 id: '/{-$orgSlug}/resume/$executionId'
298342 path: '/{-$orgSlug}/resume/$executionId'
@@ -324,6 +368,21 @@ declare module '@tanstack/react-router' { · 25 unmodified lines
324368 }
325369 }
326370
371+interface DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren {
372+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
373+}
374+
375+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren: DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren =
376+ {
377+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute:
378+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute,
379+ }
380+
381+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren =
382+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute._addFileChildren(
383+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren,
384+ )
385+
327386 const rootRouteChildren: RootRouteChildren = {
328387 CreateOrgRoute: CreateOrgRoute,
329388 LoginRoute: LoginRoute,
@@ -334,6 +393,8 @@ const rootRouteChildren: RootRouteChildren = { · 4 unmodified lines
334393 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute:
335394 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute,
336395 SecretsRoute: SecretsRoute,
396+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute:
397+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren,
337398 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute:
338399 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute,
339400 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute:
@@ -350,11 +411,15 @@ export const routeTree = rootRouteImport · 10 unmodified lines
350411 ._addFileTypes<FileRouteTypes>()
351412
352413 import type { getRouter } from './router.tsx'
414+
353415 import type { startInstance } from './start.ts'
416+
354417 declare module '@tanstack/react-start' {
355418 interface Register {
356419 ssr: true
420+
357421 router: Awaited<ReturnType<typeof getRouter>>
422+
358423 config: Awaited<ReturnType<typeof startInstance.getOptions>>
359424 }
360425 }
apps/host-cloudflare/web/routeTree.gen.ts+61−0
@@ -11,8 +11,10 @@ · 10 unmodified lines
1111 import { Route as rootRouteImport } from './routes/__root'
1212 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRouteImport } from './../../../packages/react/src/routes/index'
1313 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRouteImport } from './../../../packages/react/src/routes/tools'
14+import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport } from './../../../packages/react/src/routes/toolkits'
1415 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRouteImport } from './../../../packages/react/src/routes/secrets'
1516 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRouteImport } from './../../../packages/react/src/routes/policies'
17+import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport } from './../../../packages/react/src/routes/toolkits.$toolkitSlug'
1618 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRouteImport } from './../../../packages/react/src/routes/resume.$executionId'
1719 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport } from './../../../packages/react/src/routes/integrations.$namespace'
1820 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRouteImport } from './../../../packages/react/src/routes/plugins.$pluginId.$'
@@ -30,6 +32,12 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute = · 11 unmodified lines
3032 path: '/{-$orgSlug}/tools',
3133 getParentRoute: () => rootRouteImport,
3234 } as any)
35+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute =
36+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport.update({
37+ id: '/{-$orgSlug}/toolkits',
38+ path: '/{-$orgSlug}/toolkits',
39+ getParentRoute: () => rootRouteImport,
40+ } as any)
3341 const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute =
3442 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRouteImport.update({
3543 id: '/{-$orgSlug}/secrets',
@@ -42,6 +50,15 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute = · 6 unmodified lines
4250 path: '/{-$orgSlug}/policies',
4351 getParentRoute: () => rootRouteImport,
4452 } as any)
53+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute =
54+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport.update(
55+ {
56+ id: '/$toolkitSlug',
57+ path: '/$toolkitSlug',
58+ getParentRoute: () =>
59+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute,
60+ } as any,
61+ )
4562 const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute =
4663 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRouteImport.update(
4764 {
@@ -78,20 +95,24 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginK · 30 unmodified lines
7895 export interface FileRoutesByFullPath {
7996 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
8097 '/{-$orgSlug}/secrets': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
98+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
8199 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
82100 '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
83101 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
84102 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute
103+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
85104 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
86105 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute
87106 }
88107 export interface FileRoutesByTo {
89108 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
90109 '/{-$orgSlug}/secrets': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
110+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
91111 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
92112 '/{-$orgSlug}': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
93113 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
94114 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute
115+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
95116 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
96117 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute
97118 }
@@ -99,10 +120,12 @@ export interface FileRoutesById { · 1 unmodified line
99120 __root__: typeof rootRouteImport
100121 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
101122 '/{-$orgSlug}/secrets': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
123+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
102124 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
103125 '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
104126 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
105127 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute
128+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
106129 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
107130 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute
108131 }
@@ -111,30 +134,36 @@ export interface FileRouteTypes { · 2 unmodified lines
111134 fullPaths:
112135 | '/{-$orgSlug}/policies'
113136 | '/{-$orgSlug}/secrets'
137+ | '/{-$orgSlug}/toolkits'
114138 | '/{-$orgSlug}/tools'
115139 | '/{-$orgSlug}/'
116140 | '/{-$orgSlug}/integrations/$namespace'
117141 | '/{-$orgSlug}/resume/$executionId'
142+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
118143 | '/{-$orgSlug}/integrations/add/$pluginKey'
119144 | '/{-$orgSlug}/plugins/$pluginId/$'
120145 fileRoutesByTo: FileRoutesByTo
121146 to:
122147 | '/{-$orgSlug}/policies'
123148 | '/{-$orgSlug}/secrets'
149+ | '/{-$orgSlug}/toolkits'
124150 | '/{-$orgSlug}/tools'
125151 | '/{-$orgSlug}'
126152 | '/{-$orgSlug}/integrations/$namespace'
127153 | '/{-$orgSlug}/resume/$executionId'
154+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
128155 | '/{-$orgSlug}/integrations/add/$pluginKey'
129156 | '/{-$orgSlug}/plugins/$pluginId/$'
130157 id:
131158 | '__root__'
132159 | '/{-$orgSlug}/policies'
133160 | '/{-$orgSlug}/secrets'
161+ | '/{-$orgSlug}/toolkits'
134162 | '/{-$orgSlug}/tools'
135163 | '/{-$orgSlug}/'
136164 | '/{-$orgSlug}/integrations/$namespace'
137165 | '/{-$orgSlug}/resume/$executionId'
166+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
138167 | '/{-$orgSlug}/integrations/add/$pluginKey'
139168 | '/{-$orgSlug}/plugins/$pluginId/$'
140169 fileRoutesById: FileRoutesById
@@ -142,6 +171,7 @@ export interface FileRouteTypes { · 1 unmodified line
142171 export interface RootRouteChildren {
143172 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
144173 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
174+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
145175 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
146176 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
147177 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
@@ -166,6 +196,13 @@ declare module '@tanstack/react-router' { · 18 unmodified lines
166196 preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRouteImport
167197 parentRoute: typeof rootRouteImport
168198 }
199+ '/{-$orgSlug}/toolkits': {
200+ id: '/{-$orgSlug}/toolkits'
201+ path: '/{-$orgSlug}/toolkits'
202+ fullPath: '/{-$orgSlug}/toolkits'
203+ preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport
204+ parentRoute: typeof rootRouteImport
205+ }
169206 '/{-$orgSlug}/secrets': {
170207 id: '/{-$orgSlug}/secrets'
171208 path: '/{-$orgSlug}/secrets'
@@ -180,6 +217,13 @@ declare module '@tanstack/react-router' { · 8 unmodified lines
180217 preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRouteImport
181218 parentRoute: typeof rootRouteImport
182219 }
220+ '/{-$orgSlug}/toolkits/$toolkitSlug': {
221+ id: '/{-$orgSlug}/toolkits/$toolkitSlug'
222+ path: '/$toolkitSlug'
223+ fullPath: '/{-$orgSlug}/toolkits/$toolkitSlug'
224+ preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport
225+ parentRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute
226+ }
183227 '/{-$orgSlug}/resume/$executionId': {
184228 id: '/{-$orgSlug}/resume/$executionId'
185229 path: '/{-$orgSlug}/resume/$executionId'
@@ -211,11 +255,28 @@ declare module '@tanstack/react-router' { · 25 unmodified lines
211255 }
212256 }
213257
258+interface DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren {
259+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
260+}
261+
262+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren: DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren =
263+ {
264+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute:
265+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute,
266+ }
267+
268+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren =
269+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute._addFileChildren(
270+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren,
271+ )
272+
214273 const rootRouteChildren: RootRouteChildren = {
215274 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute:
216275 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute,
217276 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute:
218277 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute,
278+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute:
279+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren,
219280 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute:
220281 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute,
221282 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute:
apps/host-selfhost/web/routeTree.gen.ts+61−0
@@ -11,11 +11,13 @@ · 10 unmodified lines
1111 import { Route as rootRouteImport } from './routes/__root'
1212 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRouteImport } from './../../../packages/react/src/routes/index'
1313 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRouteImport } from './../../../packages/react/src/routes/tools'
14+import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport } from './../../../packages/react/src/routes/toolkits'
1415 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRouteImport } from './../../../packages/react/src/routes/secrets'
1516 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRouteImport } from './../../../packages/react/src/routes/policies'
1617 import { Route as ApiKeysRouteImport } from './routes/app/api-keys'
1718 import { Route as AdminRouteImport } from './routes/app/admin'
1819 import { Route as JoinDotcodeRouteImport } from './routes/public/join.$code'
20+import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport } from './../../../packages/react/src/routes/toolkits.$toolkitSlug'
1921 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRouteImport } from './../../../packages/react/src/routes/resume.$executionId'
2022 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRouteImport } from './../../../packages/react/src/routes/integrations.$namespace'
2123 import { Route as DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRouteImport } from './../../../packages/react/src/routes/plugins.$pluginId.$'
@@ -33,6 +35,12 @@ const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute = · 11 unmodified lines
3335 path: '/{-$orgSlug}/tools',
3436 getParentRoute: () => rootRouteImport,
3537 } as any)
38+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute =
39+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport.update({
40+ id: '/{-$orgSlug}/toolkits',
41+ path: '/{-$orgSlug}/toolkits',
42+ getParentRoute: () => rootRouteImport,
43+ } as any)
3644 const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute =
3745 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRouteImport.update({
3846 id: '/{-$orgSlug}/secrets',
@@ -60,6 +68,15 @@ const JoinDotcodeRoute = JoinDotcodeRouteImport.update({ · 21 unmodified lines
6068 path: '/join/$code',
6169 getParentRoute: () => rootRouteImport,
6270 } as any)
71+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute =
72+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport.update(
73+ {
74+ id: '/$toolkitSlug',
75+ path: '/$toolkitSlug',
76+ getParentRoute: () =>
77+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute,
78+ } as any,
79+ )
6380 const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute =
6481 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRouteImport.update(
6582 {
@@ -99,10 +116,12 @@ export interface FileRoutesByFullPath { · 33 unmodified lines
99116 '/{-$orgSlug}/api-keys': typeof ApiKeysRoute
100117 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
101118 '/{-$orgSlug}/secrets': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
119+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
102120 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
103121 '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
104122 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
105123 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute
124+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
106125 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
107126 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute
108127 }
@@ -112,10 +131,12 @@ export interface FileRoutesByTo { · 3 unmodified lines
112131 '/{-$orgSlug}/api-keys': typeof ApiKeysRoute
113132 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
114133 '/{-$orgSlug}/secrets': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
134+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
115135 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
116136 '/{-$orgSlug}': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
117137 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
118138 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute
139+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
119140 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
120141 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute
121142 }
@@ -126,10 +147,12 @@ export interface FileRoutesById { · 4 unmodified lines
126147 '/{-$orgSlug}/api-keys': typeof ApiKeysRoute
127148 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
128149 '/{-$orgSlug}/secrets': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
150+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
129151 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
130152 '/{-$orgSlug}/': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
131153 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
132154 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesResumeDotexecutionIdRoute
155+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
133156 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
134157 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPluginsDotpluginIdDotsplatRoute
135158 }
@@ -141,10 +164,12 @@ export interface FileRouteTypes { · 5 unmodified lines
141164 | '/{-$orgSlug}/api-keys'
142165 | '/{-$orgSlug}/policies'
143166 | '/{-$orgSlug}/secrets'
167+ | '/{-$orgSlug}/toolkits'
144168 | '/{-$orgSlug}/tools'
145169 | '/{-$orgSlug}/'
146170 | '/{-$orgSlug}/integrations/$namespace'
147171 | '/{-$orgSlug}/resume/$executionId'
172+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
148173 | '/{-$orgSlug}/integrations/add/$pluginKey'
149174 | '/{-$orgSlug}/plugins/$pluginId/$'
150175 fileRoutesByTo: FileRoutesByTo
@@ -154,10 +179,12 @@ export interface FileRouteTypes { · 3 unmodified lines
154179 | '/{-$orgSlug}/api-keys'
155180 | '/{-$orgSlug}/policies'
156181 | '/{-$orgSlug}/secrets'
182+ | '/{-$orgSlug}/toolkits'
157183 | '/{-$orgSlug}/tools'
158184 | '/{-$orgSlug}'
159185 | '/{-$orgSlug}/integrations/$namespace'
160186 | '/{-$orgSlug}/resume/$executionId'
187+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
161188 | '/{-$orgSlug}/integrations/add/$pluginKey'
162189 | '/{-$orgSlug}/plugins/$pluginId/$'
163190 id:
@@ -167,10 +194,12 @@ export interface FileRouteTypes { · 3 unmodified lines
167194 | '/{-$orgSlug}/api-keys'
168195 | '/{-$orgSlug}/policies'
169196 | '/{-$orgSlug}/secrets'
197+ | '/{-$orgSlug}/toolkits'
170198 | '/{-$orgSlug}/tools'
171199 | '/{-$orgSlug}/'
172200 | '/{-$orgSlug}/integrations/$namespace'
173201 | '/{-$orgSlug}/resume/$executionId'
202+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
174203 | '/{-$orgSlug}/integrations/add/$pluginKey'
175204 | '/{-$orgSlug}/plugins/$pluginId/$'
176205 fileRoutesById: FileRoutesById
@@ -181,6 +210,7 @@ export interface RootRouteChildren { · 4 unmodified lines
181210 ApiKeysRoute: typeof ApiKeysRoute
182211 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute
183212 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute
213+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren
184214 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute
185215 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute
186216 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIntegrationsDotnamespaceRoute
@@ -205,6 +235,13 @@ declare module '@tanstack/react-router' { · 18 unmodified lines
205235 preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRouteImport
206236 parentRoute: typeof rootRouteImport
207237 }
238+ '/{-$orgSlug}/toolkits': {
239+ id: '/{-$orgSlug}/toolkits'
240+ path: '/{-$orgSlug}/toolkits'
241+ fullPath: '/{-$orgSlug}/toolkits'
242+ preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteImport
243+ parentRoute: typeof rootRouteImport
244+ }
208245 '/{-$orgSlug}/secrets': {
209246 id: '/{-$orgSlug}/secrets'
210247 path: '/{-$orgSlug}/secrets'
@@ -240,6 +277,13 @@ declare module '@tanstack/react-router' { · 29 unmodified lines
240277 preLoaderRoute: typeof JoinDotcodeRouteImport
241278 parentRoute: typeof rootRouteImport
242279 }
280+ '/{-$orgSlug}/toolkits/$toolkitSlug': {
281+ id: '/{-$orgSlug}/toolkits/$toolkitSlug'
282+ path: '/$toolkitSlug'
283+ fullPath: '/{-$orgSlug}/toolkits/$toolkitSlug'
284+ preLoaderRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRouteImport
285+ parentRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute
286+ }
243287 '/{-$orgSlug}/resume/$executionId': {
244288 id: '/{-$orgSlug}/resume/$executionId'
245289 path: '/{-$orgSlug}/resume/$executionId'
@@ -271,6 +315,21 @@ declare module '@tanstack/react-router' { · 25 unmodified lines
271315 }
272316 }
273317
318+interface DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren {
319+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute: typeof DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute
320+}
321+
322+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren: DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren =
323+ {
324+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute:
325+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsDottoolkitSlugRoute,
326+ }
327+
328+const DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren =
329+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute._addFileChildren(
330+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteChildren,
331+ )
332+
274333 const rootRouteChildren: RootRouteChildren = {
275334 JoinDotcodeRoute: JoinDotcodeRoute,
276335 AdminRoute: AdminRoute,
@@ -279,6 +338,8 @@ const rootRouteChildren: RootRouteChildren = { · 2 unmodified lines
279338 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesPoliciesRoute,
280339 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute:
281340 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesSecretsRoute,
341+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRoute:
342+ DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolkitsRouteWithChildren,
282343 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute:
283344 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesToolsRoute,
284345 DotDotDotDotDotDotDotDotPackagesReactSrcRoutesIndexRoute:
e2e/selfhost/toolkits-ui.test.ts+37−16
@@ -52,12 +52,13 @@ scenario( · 51 unmodified lines
5252
5353 yield* browser.session(identity, async ({ page, step }) => {
5454 await step("Open the Toolkits plugin page", async () => {
55− await page.goto("/plugins/toolkits/", { waitUntil: "networkidle" });
55+ await page.goto("/default/toolkits/", { waitUntil: "domcontentloaded" });
5656 await page.getByRole("heading", { name: "Toolkits" }).waitFor();
5757 await page.getByRole("heading", { name: "Workspace" }).waitFor();
5858 await page.getByRole("heading", { name: "Personal" }).waitFor();
5959 await page.getByRole("button", { name: "Add workspace toolkit" }).waitFor();
6060 await page.getByRole("button", { name: "Add personal toolkit" }).waitFor();
61+ await page.locator('main [data-slot="skeleton"]').first().waitFor({ state: "detached" });
6162 expect(await page.locator('main [data-slot="skeleton"]').count()).toBe(0);
6263 const seededCard = page.getByRole("link", {
6364 name: `Open toolkit ${prefix}-workspace-a`,
@@ -104,8 +105,8 @@ scenario( · 40 unmodified lines
104105
105106 await step("Open the created toolkit from the grid", async () => {
106107 await page.getByRole("link", { name: `Open toolkit ${name}` }).click();
107− await page.waitForURL(new RegExp(`/plugins/toolkits/${slug}$`));
108− expect(page.url()).toMatch(new RegExp(`/plugins/toolkits/${slug}$`));
108+ await page.waitForURL(new RegExp(`/toolkits/${slug}$`));
109+ expect(page.url()).toMatch(new RegExp(`/toolkits/${slug}$`));
109110 await page
110111 .locator("code")
111112 .filter({ hasText: `/mcp/toolkits/${slug}` })
@@ -116,15 +117,15 @@ scenario( · 4 unmodified lines
116117
117118 await step("Return to the toolkit grid with browser-visible routing", async () => {
118119 await page.getByRole("button", { name: "Toolkits" }).click();
119− await page.waitForURL(/\/plugins\/toolkits\/?$/);
120− expect(page.url()).toMatch(/\/plugins\/toolkits\/?$/);
120+ await page.waitForURL(/\/toolkits\/?$/);
121+ expect(page.url()).toMatch(/\/toolkits\/?$/);
121122 await page.getByRole("heading", { name: "Workspace" }).waitFor();
122123 await page.getByRole("link", { name: `Open toolkit ${name}` }).waitFor();
123124 });
124125
125126 await step("Open the created toolkit from a direct URL", async () => {
126− await page.goto(`/plugins/toolkits/${slug}`, { waitUntil: "networkidle" });
127− expect(page.url()).toMatch(new RegExp(`/plugins/toolkits/${slug}$`));
127+ await page.goto(`/default/toolkits/${slug}`, { waitUntil: "domcontentloaded" });
128+ expect(page.url()).toMatch(new RegExp(`/toolkits/${slug}$`));
128129 await page
129130 .locator("code")
130131 .filter({ hasText: `/mcp/toolkits/${slug}` })
@@ -133,9 +134,18 @@ scenario( · 2 unmodified lines
133134 expect(await page.getByLabel("New toolkit").count()).toBe(0);
134135 });
135136
137+ await step("Cancel toolkit deletion from the confirmation modal", async () => {
138+ await page.getByRole("button", { name: "Delete toolkit" }).click();
139+ const dialog = page.getByRole("alertdialog", { name: `Delete ${name}?` });
140+ await dialog.waitFor();
141+ await dialog.getByRole("button", { name: "Cancel" }).click();
142+ await dialog.waitFor({ state: "detached" });
143+ await page.getByRole("heading", { name }).waitFor();
144+ });
145+
136146 await step("Add a connection to the toolkit", async () => {
137− await page.getByRole("button", { name: "Add connection to toolkit" }).click();
138− const dialog = page.getByRole("dialog", { name: "Add connection" });
147+ await page.getByRole("button", { name: "Manage toolkit connections" }).click();
148+ const dialog = page.getByRole("dialog", { name: "Manage connections" });
139149 await dialog.waitFor();
140150 await dialog.getByLabel("Search connections and tools").fill("policies.list");
141151 expect(await dialog.getByRole("button", { name: /^Add tool/ }).count()).toBe(0);
@@ -145,6 +155,8 @@ scenario( · 3 unmodified lines
145155 .getByRole("button", { name: /^Add connection / })
146156 .first()
147157 .click();
158+ await dialog.getByRole("button", { name: /^Remove connection / }).waitFor();
159+ await page.keyboard.press("Escape");
148160 await dialog.waitFor({ state: "hidden" });
149161 const toolkitTools = page.getByRole("region", { name: "Toolkit tools" });
150162 await toolkitTools.waitFor();
@@ -154,30 +166,39 @@ scenario( · 3 unmodified lines
154166 });
155167
156168 await step("The add connection list reflects the saved toolkit connection", async () => {
157− await page.getByRole("button", { name: "Add connection to toolkit" }).click();
158− const dialog = page.getByRole("dialog", { name: "Add connection" });
169+ await page.getByRole("button", { name: "Manage toolkit connections" }).click();
170+ const dialog = page.getByRole("dialog", { name: "Manage connections" });
159171 await dialog.waitFor();
160172 await dialog.getByLabel("Search connections and tools").fill("policies.list");
161− await dialog.getByRole("button", { name: /^Connection added / }).waitFor();
173+ await dialog.getByRole("button", { name: /^Remove connection / }).waitFor();
162174 expect(await dialog.getByRole("button", { name: /^Add connection / }).count()).toBe(0);
163175 await page.keyboard.press("Escape");
164176 await dialog.waitFor({ state: "hidden" });
165177 });
166178
167− await step("Remove the connection from the toolkit tools list", async () => {
168− await page
179+ await step("Remove the connection from the manage modal", async () => {
180+ await page.getByRole("button", { name: "Manage toolkit connections" }).click();
181+ const removeDialog = page.getByRole("dialog", { name: "Manage connections" });
182+ await removeDialog.waitFor();
183+ await removeDialog.getByLabel("Search connections and tools").fill("policies.list");
184+ await removeDialog
169185 .getByRole("button", { name: /^Remove connection / })
170186 .first()
171187 .click();
188+ await removeDialog.getByRole("button", { name: /^Add connection / }).waitFor();
189+ await page.keyboard.press("Escape");
190+ await removeDialog.waitFor({ state: "hidden" });
172191 await page.getByText("No connections added").waitFor();
173− await page.getByRole("button", { name: "Add connection to toolkit" }).click();
174− const dialog = page.getByRole("dialog", { name: "Add connection" });
192+ await page.getByRole("button", { name: "Manage toolkit connections" }).click();
193+ const dialog = page.getByRole("dialog", { name: "Manage connections" });
175194 await dialog.waitFor();
176195 await dialog.getByLabel("Search connections and tools").fill("policies.list");
177196 await dialog
178197 .getByRole("button", { name: /^Add connection / })
179198 .first()
180199 .click();
200+ await dialog.getByRole("button", { name: /^Remove connection / }).waitFor();
201+ await page.keyboard.press("Escape");
181202 await dialog.waitFor({ state: "hidden" });
182203 const toolkitTools = page.getByRole("region", { name: "Toolkit tools" });
183204 await toolkitTools.getByLabel("Filter tools").fill("policies.list");
packages/app/src/routeTree.gen.ts+58−0
@@ -11,8 +11,10 @@ · 10 unmodified lines
1111 import { Route as rootRouteImport } from './routes/__root'
1212 import { Route as DotDotDotDotDotDotReactSrcRoutesIndexRouteImport } from './../../react/src/routes/index'
1313 import { Route as DotDotDotDotDotDotReactSrcRoutesToolsRouteImport } from './../../react/src/routes/tools'
14+import { Route as DotDotDotDotDotDotReactSrcRoutesToolkitsRouteImport } from './../../react/src/routes/toolkits'
1415 import { Route as SecretsRouteImport } from './routes/app/secrets'
1516 import { Route as DotDotDotDotDotDotReactSrcRoutesPoliciesRouteImport } from './../../react/src/routes/policies'
17+import { Route as DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRouteImport } from './../../react/src/routes/toolkits.$toolkitSlug'
1618 import { Route as DotDotDotDotDotDotReactSrcRoutesResumeDotexecutionIdRouteImport } from './../../react/src/routes/resume.$executionId'
1719 import { Route as DotDotDotDotDotDotReactSrcRoutesIntegrationsDotnamespaceRouteImport } from './../../react/src/routes/integrations.$namespace'
1820 import { Route as DotDotDotDotDotDotReactSrcRoutesPluginsDotpluginIdDotsplatRouteImport } from './../../react/src/routes/plugins.$pluginId.$'
@@ -30,6 +32,12 @@ const DotDotDotDotDotDotReactSrcRoutesToolsRoute = · 11 unmodified lines
3032 path: '/{-$orgSlug}/tools',
3133 getParentRoute: () => rootRouteImport,
3234 } as any)
35+const DotDotDotDotDotDotReactSrcRoutesToolkitsRoute =
36+ DotDotDotDotDotDotReactSrcRoutesToolkitsRouteImport.update({
37+ id: '/{-$orgSlug}/toolkits',
38+ path: '/{-$orgSlug}/toolkits',
39+ getParentRoute: () => rootRouteImport,
40+ } as any)
3341 const SecretsRoute = SecretsRouteImport.update({
3442 id: '/{-$orgSlug}/secrets',
3543 path: '/{-$orgSlug}/secrets',
@@ -41,6 +49,12 @@ const DotDotDotDotDotDotReactSrcRoutesPoliciesRoute = · 5 unmodified lines
4149 path: '/{-$orgSlug}/policies',
4250 getParentRoute: () => rootRouteImport,
4351 } as any)
52+const DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute =
53+ DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRouteImport.update({
54+ id: '/$toolkitSlug',
55+ path: '/$toolkitSlug',
56+ getParentRoute: () => DotDotDotDotDotDotReactSrcRoutesToolkitsRoute,
57+ } as any)
4458 const DotDotDotDotDotDotReactSrcRoutesResumeDotexecutionIdRoute =
4559 DotDotDotDotDotDotReactSrcRoutesResumeDotexecutionIdRouteImport.update({
4660 id: '/{-$orgSlug}/resume/$executionId',
@@ -71,20 +85,24 @@ const DotDotDotDotDotDotReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute = · 24 unmodified lines
7185 export interface FileRoutesByFullPath {
7286 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotReactSrcRoutesPoliciesRoute
7387 '/{-$orgSlug}/secrets': typeof SecretsRoute
88+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotReactSrcRoutesToolkitsRouteWithChildren
7489 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotReactSrcRoutesToolsRoute
7590 '/{-$orgSlug}/': typeof DotDotDotDotDotDotReactSrcRoutesIndexRoute
7691 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotReactSrcRoutesIntegrationsDotnamespaceRoute
7792 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotReactSrcRoutesResumeDotexecutionIdRoute
93+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute
7894 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
7995 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotReactSrcRoutesPluginsDotpluginIdDotsplatRoute
8096 }
8197 export interface FileRoutesByTo {
8298 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotReactSrcRoutesPoliciesRoute
8399 '/{-$orgSlug}/secrets': typeof SecretsRoute
100+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotReactSrcRoutesToolkitsRouteWithChildren
84101 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotReactSrcRoutesToolsRoute
85102 '/{-$orgSlug}': typeof DotDotDotDotDotDotReactSrcRoutesIndexRoute
86103 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotReactSrcRoutesIntegrationsDotnamespaceRoute
87104 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotReactSrcRoutesResumeDotexecutionIdRoute
105+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute
88106 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
89107 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotReactSrcRoutesPluginsDotpluginIdDotsplatRoute
90108 }
@@ -92,10 +110,12 @@ export interface FileRoutesById { · 1 unmodified line
92110 __root__: typeof rootRouteImport
93111 '/{-$orgSlug}/policies': typeof DotDotDotDotDotDotReactSrcRoutesPoliciesRoute
94112 '/{-$orgSlug}/secrets': typeof SecretsRoute
113+ '/{-$orgSlug}/toolkits': typeof DotDotDotDotDotDotReactSrcRoutesToolkitsRouteWithChildren
95114 '/{-$orgSlug}/tools': typeof DotDotDotDotDotDotReactSrcRoutesToolsRoute
96115 '/{-$orgSlug}/': typeof DotDotDotDotDotDotReactSrcRoutesIndexRoute
97116 '/{-$orgSlug}/integrations/$namespace': typeof DotDotDotDotDotDotReactSrcRoutesIntegrationsDotnamespaceRoute
98117 '/{-$orgSlug}/resume/$executionId': typeof DotDotDotDotDotDotReactSrcRoutesResumeDotexecutionIdRoute
118+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute
99119 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotDotDotDotDotDotReactSrcRoutesIntegrationsDotaddDotpluginKeyRoute
100120 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotDotDotDotDotDotReactSrcRoutesPluginsDotpluginIdDotsplatRoute
101121 }
@@ -104,30 +124,36 @@ export interface FileRouteTypes { · 2 unmodified lines
104124 fullPaths:
105125 | '/{-$orgSlug}/policies'
106126 | '/{-$orgSlug}/secrets'
127+ | '/{-$orgSlug}/toolkits'
107128 | '/{-$orgSlug}/tools'
108129 | '/{-$orgSlug}/'
109130 | '/{-$orgSlug}/integrations/$namespace'
110131 | '/{-$orgSlug}/resume/$executionId'
132+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
111133 | '/{-$orgSlug}/integrations/add/$pluginKey'
112134 | '/{-$orgSlug}/plugins/$pluginId/$'
113135 fileRoutesByTo: FileRoutesByTo
114136 to:
115137 | '/{-$orgSlug}/policies'
116138 | '/{-$orgSlug}/secrets'
139+ | '/{-$orgSlug}/toolkits'
117140 | '/{-$orgSlug}/tools'
118141 | '/{-$orgSlug}'
119142 | '/{-$orgSlug}/integrations/$namespace'
120143 | '/{-$orgSlug}/resume/$executionId'
144+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
121145 | '/{-$orgSlug}/integrations/add/$pluginKey'
122146 | '/{-$orgSlug}/plugins/$pluginId/$'
123147 id:
124148 | '__root__'
125149 | '/{-$orgSlug}/policies'
126150 | '/{-$orgSlug}/secrets'
151+ | '/{-$orgSlug}/toolkits'
127152 | '/{-$orgSlug}/tools'
128153 | '/{-$orgSlug}/'
129154 | '/{-$orgSlug}/integrations/$namespace'
130155 | '/{-$orgSlug}/resume/$executionId'
156+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
131157 | '/{-$orgSlug}/integrations/add/$pluginKey'
132158 | '/{-$orgSlug}/plugins/$pluginId/$'
133159 fileRoutesById: FileRoutesById
@@ -135,6 +161,7 @@ export interface FileRouteTypes { · 1 unmodified line
135161 export interface RootRouteChildren {
136162 DotDotDotDotDotDotReactSrcRoutesPoliciesRoute: typeof DotDotDotDotDotDotReactSrcRoutesPoliciesRoute
137163 SecretsRoute: typeof SecretsRoute
164+ DotDotDotDotDotDotReactSrcRoutesToolkitsRoute: typeof DotDotDotDotDotDotReactSrcRoutesToolkitsRouteWithChildren
138165 DotDotDotDotDotDotReactSrcRoutesToolsRoute: typeof DotDotDotDotDotDotReactSrcRoutesToolsRoute
139166 DotDotDotDotDotDotReactSrcRoutesIndexRoute: typeof DotDotDotDotDotDotReactSrcRoutesIndexRoute
140167 DotDotDotDotDotDotReactSrcRoutesIntegrationsDotnamespaceRoute: typeof DotDotDotDotDotDotReactSrcRoutesIntegrationsDotnamespaceRoute
@@ -159,6 +186,13 @@ declare module '@tanstack/react-router' { · 18 unmodified lines
159186 preLoaderRoute: typeof DotDotDotDotDotDotReactSrcRoutesToolsRouteImport
160187 parentRoute: typeof rootRouteImport
161188 }
189+ '/{-$orgSlug}/toolkits': {
190+ id: '/{-$orgSlug}/toolkits'
191+ path: '/{-$orgSlug}/toolkits'
192+ fullPath: '/{-$orgSlug}/toolkits'
193+ preLoaderRoute: typeof DotDotDotDotDotDotReactSrcRoutesToolkitsRouteImport
194+ parentRoute: typeof rootRouteImport
195+ }
162196 '/{-$orgSlug}/secrets': {
163197 id: '/{-$orgSlug}/secrets'
164198 path: '/{-$orgSlug}/secrets'
@@ -173,6 +207,13 @@ declare module '@tanstack/react-router' { · 8 unmodified lines
173207 preLoaderRoute: typeof DotDotDotDotDotDotReactSrcRoutesPoliciesRouteImport
174208 parentRoute: typeof rootRouteImport
175209 }
210+ '/{-$orgSlug}/toolkits/$toolkitSlug': {
211+ id: '/{-$orgSlug}/toolkits/$toolkitSlug'
212+ path: '/$toolkitSlug'
213+ fullPath: '/{-$orgSlug}/toolkits/$toolkitSlug'
214+ preLoaderRoute: typeof DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRouteImport
215+ parentRoute: typeof DotDotDotDotDotDotReactSrcRoutesToolkitsRoute
216+ }
176217 '/{-$orgSlug}/resume/$executionId': {
177218 id: '/{-$orgSlug}/resume/$executionId'
178219 path: '/{-$orgSlug}/resume/$executionId'
@@ -204,10 +245,27 @@ declare module '@tanstack/react-router' { · 25 unmodified lines
204245 }
205246 }
206247
248+interface DotDotDotDotDotDotReactSrcRoutesToolkitsRouteChildren {
249+ DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute: typeof DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute
250+}
251+
252+const DotDotDotDotDotDotReactSrcRoutesToolkitsRouteChildren: DotDotDotDotDotDotReactSrcRoutesToolkitsRouteChildren =
253+ {
254+ DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute:
255+ DotDotDotDotDotDotReactSrcRoutesToolkitsDottoolkitSlugRoute,
256+ }
257+
258+const DotDotDotDotDotDotReactSrcRoutesToolkitsRouteWithChildren =
259+ DotDotDotDotDotDotReactSrcRoutesToolkitsRoute._addFileChildren(
260+ DotDotDotDotDotDotReactSrcRoutesToolkitsRouteChildren,
261+ )
262+
207263 const rootRouteChildren: RootRouteChildren = {
208264 DotDotDotDotDotDotReactSrcRoutesPoliciesRoute:
209265 DotDotDotDotDotDotReactSrcRoutesPoliciesRoute,
210266 SecretsRoute: SecretsRoute,
267+ DotDotDotDotDotDotReactSrcRoutesToolkitsRoute:
268+ DotDotDotDotDotDotReactSrcRoutesToolkitsRouteWithChildren,
211269 DotDotDotDotDotDotReactSrcRoutesToolsRoute:
212270 DotDotDotDotDotDotReactSrcRoutesToolsRoute,
213271 DotDotDotDotDotDotReactSrcRoutesIndexRoute:
packages/app/src/web/shell.tsx+7−0
@@ -342,6 +342,7 @@ function SidebarContent(props: { · 341 unmodified lines
342342 const isHome = props.pathname === "/";
343343 const isSecrets = props.pathname === "/secrets";
344344 const isPolicies = props.pathname === "/policies";
345+ const isToolkits = props.pathname === "/toolkits" || props.pathname.startsWith("/toolkits/");
345346
346347 return (
347348 <>
@@ -381,6 +382,12 @@ function SidebarContent(props: { · 33 unmodified lines
381382 active={isPolicies}
382383 onNavigate={props.onNavigate}
383384 />
385+ <NavItem
386+ to="/{-$orgSlug}/toolkits"
387+ label="Toolkits"
388+ active={isToolkits}
389+ onNavigate={props.onNavigate}
390+ />
384391
385392 <PluginNav pathname={props.pathname} onNavigate={props.onNavigate} />
386393
packages/plugins/toolkits/src/client.tsx+0−1
@@ -8,7 +8,6 @@ export default defineClientPlugin({ · 7 unmodified lines
88 {
99 path: "/",
1010 component: ToolkitsPage,
11− nav: { label: "Toolkits" },
1211 },
1312 {
1413 path: "/$toolkitSlug",
packages/plugins/toolkits/src/page.tsx+190−158
@@ -1,17 +1,9 @@
11 import { useId, useMemo, useState } from "react";
2−import { Link, useNavigate, useParams } from "@tanstack/react-router";
2+import { Link, useNavigate } from "@tanstack/react-router";
33 import { useAtomSet, useAtomValue } from "@effect/atom-react";
44 import * as Atom from "effect/unstable/reactivity/Atom";
55 import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
6−import {
7− ArrowLeftIcon,
8− BoxIcon,
9− CheckIcon,
10− PlugIcon,
11− PlusIcon,
12− SearchIcon,
13− Trash2Icon,
14−} from "lucide-react";
6+import { ArrowLeftIcon, BoxIcon, PlugIcon, PlusIcon, SearchIcon, Trash2Icon } from "lucide-react";
157 import {
168 createPluginAtomClient,
179 useIntegrationPlugins,
@@ -28,15 +20,27 @@ import { · 10 unmodified lines
2820 } from "@executor-js/sdk/shared";
2921 import { integrationsOptimisticAtom, toolsAllAtom } from "@executor-js/react/api/atoms";
3022 import { ReactivityKey } from "@executor-js/react/api/reactivity-keys";
23+import { useOrganizationSlug } from "@executor-js/react/api/organization-context";
3124 import {
3225 getExecutorApiBaseUrl,
3326 getExecutorOrganizationHeaders,
3427 getExecutorServerAuthorizationHeader,
3528 } from "@executor-js/react/api/server-connection";
36−import { ownerLabel } from "@executor-js/react/api/owner-display";
29+import { ownerLabel, useOwnerDisplay } from "@executor-js/react/api/owner-display";
3730 import { Badge } from "@executor-js/react/components/badge";
3831 import { Button } from "@executor-js/react/components/button";
3932 import { CopyButton } from "@executor-js/react/components/copy-button";
33+import {
34+ AlertDialog,
35+ AlertDialogAction,
36+ AlertDialogCancel,
37+ AlertDialogContent,
38+ AlertDialogDescription,
39+ AlertDialogFooter,
40+ AlertDialogHeader,
41+ AlertDialogTitle,
42+ AlertDialogTrigger,
43+} from "@executor-js/react/components/alert-dialog";
4044 import {
4145 IntegrationFavicon,
4246 integrationPresetIconUrl,
@@ -294,6 +298,9 @@ const compareTools = (a: ToolRow, b: ToolRow): number => · 251 unmodified lines
294298 const connectionTitle = (group: ToolkitConnectionGroup): string =>
295299 `${ownerLabel(group.owner)} ${group.integration} / ${group.connection}`;
296300
301+const connectionTitleForHost = (group: ToolkitConnectionGroup, showOwnerLabels: boolean): string =>
302+ showOwnerLabels ? connectionTitle(group) : `${group.integration} / ${group.connection}`;
303+
297304 const connectionDisplayTitle = (group: ToolkitConnectionGroup, meta: IntegrationMeta): string =>
298305 group.connection === "built-in" || group.connection === "default" ? meta.name : group.connection;
299306
@@ -302,6 +309,15 @@ const connectionDisplaySubtitle = (group: ToolkitConnectionGroup, meta: Integrat · 2 unmodified lines
302309 ? `${group.tools.length} ${group.tools.length === 1 ? "tool" : "tools"}`
303310 : `${meta.name} · ${group.tools.length} ${group.tools.length === 1 ? "tool" : "tools"}`;
304311
312+const connectionDisplaySubtitleForHost = (
313+ group: ToolkitConnectionGroup,
314+ meta: IntegrationMeta,
315+ showOwnerLabels: boolean,
316+): string => {
317+ const subtitle = connectionDisplaySubtitle(group, meta);
318+ return showOwnerLabels ? `${ownerLabel(group.owner)} · ${subtitle}` : subtitle;
319+};
320+
305321 const integrationMetaFor = (
306322 group: ToolkitConnectionGroup,
307323 integrations: readonly Integration[],
@@ -340,6 +356,7 @@ const configuredConnectionViews = ( · 32 unmodified lines
340356 connectionGroups: readonly ToolkitConnectionGroup[],
341357 integrations: readonly Integration[],
342358 integrationPlugins: readonly IntegrationPlugin[],
359+ showOwnerLabels: boolean,
343360 ): readonly ConfiguredConnectionView[] =>
344361 connections.map((connection) => {
345362 const group = connectionGroups.find((candidate) =>
@@ -358,7 +375,7 @@ const configuredConnectionViews = ( · 12 unmodified lines
358375 return {
359376 id: connection.id,
360377 title: connectionDisplayTitle(group, meta),
361− subtitle: `${ownerLabel(group.owner)} · ${connectionDisplaySubtitle(group, meta)}`,
378+ subtitle: connectionDisplaySubtitleForHost(group, meta, showOwnerLabels),
362379 pattern: connection.pattern,
363380 sourceId: meta.sourceId,
364381 icon: meta.icon,
@@ -434,7 +451,7 @@ function ToolkitConnectionIconStack(props: { connections: readonly ConfiguredCon · 69 unmodified lines
434451 const connectionCountLabel = (count: number): string =>
435452 count === 0 ? "No connections" : `${count} ${count === 1 ? "connection" : "connections"}`;
436453
437−function ToolkitTile(props: { pluginId: string; toolkit: ToolkitResponse }) {
454+function ToolkitTile(props: { showOwnerLabels: boolean; toolkit: ToolkitResponse }) {
438455 const toolkit = props.toolkit;
439456 const tools = useAtomValue(toolsAllAtom);
440457 const integrations = useAtomValue(integrationsOptimisticAtom);
@@ -464,12 +481,13 @@ function ToolkitTile(props: { pluginId: string; toolkit: ToolkitResponse }) { · 23 unmodified lines
464481 connectionGroups,
465482 integrationRows,
466483 integrationPlugins,
484+ props.showOwnerLabels,
467485 )
468486 : [];
469487 return (
470488 <Link
471− to="/{-$orgSlug}/plugins/$pluginId/$"
472− params={{ pluginId: props.pluginId, _splat: toolkit.slug }}
489+ to="/{-$orgSlug}/toolkits/$toolkitSlug"
490+ params={{ toolkitSlug: toolkit.slug }}
473491 aria-label={`Open toolkit ${toolkit.name}`}
474492 className="group flex min-h-36 min-w-0 self-start flex-col justify-between rounded-md border border-border/70 bg-card p-3.5 text-left text-card-foreground shadow-xs transition-[border-color,background-color,box-shadow] hover:border-foreground/25 hover:bg-muted/20 hover:shadow-sm focus-visible:ring-[3px] focus-visible:ring-ring/30 focus-visible:outline-none"
475493 style={toolkitCardStyle}
@@ -491,12 +509,18 @@ function ToolkitTile(props: { pluginId: string; toolkit: ToolkitResponse }) { · 15 unmodified lines
491509 );
492510 }
493511
494−const addToolkitScopeLabel = (owner: Owner): string => (owner === "org" ? "workspace" : "personal");
495−const addToolkitTitle = (owner: Owner): string =>
496− owner === "org" ? "New workspace toolkit" : "New personal toolkit";
512+const addToolkitScopeLabel = (owner: Owner, showOwnerLabels: boolean): string =>
513+ showOwnerLabels ? (owner === "org" ? "workspace" : "personal") : "";
514+const addToolkitTitle = (owner: Owner, showOwnerLabels: boolean): string =>
515+ showOwnerLabels
516+ ? owner === "org"
517+ ? "New workspace toolkit"
518+ : "New personal toolkit"
519+ : "New toolkit";
497520
498521 function CreateToolkitDialog(props: {
499522 owner: Owner;
523+ showOwnerLabels: boolean;
500524 open: boolean;
501525 onOpenChange: (open: boolean) => void;
502526 onCreate: (input: { owner: Owner; name: string }) => Promise<void>;
@@ -504,7 +528,7 @@ function CreateToolkitDialog(props: { · 1 unmodified line
504528 const inputId = useId();
505529 const [name, setName] = useState("");
506530 const trimmed = name.trim();
507− const title = addToolkitTitle(props.owner);
531+ const title = addToolkitTitle(props.owner, props.showOwnerLabels);
508532
509533 const submit = async () => {
510534 if (!trimmed) return;
@@ -568,14 +592,14 @@ function CreateToolkitDialog(props: { · 57 unmodified lines
568592 );
569593 }
570594
571−function AddToolkitCard(props: { owner: Owner; onClick: () => void }) {
572− const scopeLabel = addToolkitScopeLabel(props.owner);
595+function AddToolkitCard(props: { owner: Owner; showOwnerLabels: boolean; onClick: () => void }) {
596+ const scopeLabel = addToolkitScopeLabel(props.owner, props.showOwnerLabels);
573597 return (
574598 <Button
575599 type="button"
576600 variant="ghost"
577601 onClick={props.onClick}
578− aria-label={`Add ${scopeLabel} toolkit`}
602+ aria-label={scopeLabel ? `Add ${scopeLabel} toolkit` : "Add toolkit"}
579603 className="group flex h-auto min-h-36 min-w-0 self-start items-center justify-center rounded-md border border-dashed border-border/75 bg-card/40 p-0 text-muted-foreground transition-[border-color,background-color,box-shadow,color] hover:border-foreground/25 hover:bg-muted/20 hover:text-foreground hover:shadow-sm focus-visible:ring-[3px] focus-visible:ring-ring/30 focus-visible:outline-none"
580604 style={toolkitCardStyle}
581605 >
@@ -593,9 +617,9 @@ function AddToolkitCard(props: { owner: Owner; onClick: () => void }) { · 11 unmodified lines
593617 }
594618
595619 function ToolkitSection(props: {
596− pluginId: string;
597620 owner: Owner;
598− title: string;
621+ title?: string;
622+ showOwnerLabels: boolean;
599623 toolkits: readonly ToolkitResponse[];
600624 onCreate: (input: { owner: Owner; name: string }) => Promise<void>;
601625 }) {
@@ -604,24 +628,31 @@ function ToolkitSection(props: { · 2 unmodified lines
604628 const openCreate = () => setCreateOpen(true);
605629 return (
606630 <section className="space-y-3">
607− <div className="border-b border-border/60 pb-2">
608− <h2 className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
609− {props.title}
610− </h2>
611− </div>
631+ {props.title ? (
632+ <div className="border-b border-border/60 pb-2">
633+ <h2 className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
634+ {props.title}
635+ </h2>
636+ </div>
637+ ) : null}
612638
613639 <div
614640 className="grid content-start grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3"
615641 style={toolkitShelfStyle}
616642 >
617643 {rows.map((toolkit) => (
618− <ToolkitTile key={toolkit.id} pluginId={props.pluginId} toolkit={toolkit} />
644+ <ToolkitTile key={toolkit.id} showOwnerLabels={props.showOwnerLabels} toolkit={toolkit} />
619645 ))}
620− <AddToolkitCard owner={props.owner} onClick={openCreate} />
646+ <AddToolkitCard
647+ owner={props.owner}
648+ showOwnerLabels={props.showOwnerLabels}
649+ onClick={openCreate}
650+ />
621651 </div>
622652
623653 <CreateToolkitDialog
624654 owner={props.owner}
655+ showOwnerLabels={props.showOwnerLabels}
625656 open={createOpen}
626657 onOpenChange={setCreateOpen}
627658 onCreate={props.onCreate}
@@ -631,27 +662,41 @@ function ToolkitSection(props: { · 3 unmodified lines
631662 }
632663
633664 function ToolkitGrid(props: {
634− pluginId: string;
635665 toolkits: readonly ToolkitResponse[];
636666 onCreate: (input: { owner: Owner; name: string }) => Promise<void>;
637667 }) {
668+ const ownerDisplay = useOwnerDisplay();
638669 // Toolkit shelves are grouped by owner; the selected toolkit owns the page.
639670 const workspaceToolkits = props.toolkits.filter((toolkit) => toolkit.owner === "org");
640671 const personalToolkits = props.toolkits.filter((toolkit) => toolkit.owner === "user");
672+ if (!ownerDisplay.showOwnerLabels) {
673+ return (
674+ <div className="min-h-0 flex-1 overflow-y-auto">
675+ <div className="w-full space-y-7 px-4 py-4" style={toolkitGridContainerStyle}>
676+ <ToolkitSection
677+ owner="org"
678+ showOwnerLabels={false}
679+ toolkits={props.toolkits}
680+ onCreate={props.onCreate}
681+ />
682+ </div>
683+ </div>
684+ );
685+ }
641686
642687 return (
643688 <div className="min-h-0 flex-1 overflow-y-auto">
644689 <div className="w-full space-y-7 px-4 py-4" style={toolkitGridContainerStyle}>
645690 <ToolkitSection
646− pluginId={props.pluginId}
647691 owner="org"
692+ showOwnerLabels
648693 title="Workspace"
649694 toolkits={workspaceToolkits}
650695 onCreate={props.onCreate}
651696 />
652697 <ToolkitSection
653− pluginId={props.pluginId}
654698 owner="user"
699+ showOwnerLabels
655700 title="Personal"
656701 toolkits={personalToolkits}
657702 onCreate={props.onCreate}
@@ -661,7 +706,7 @@ function ToolkitGrid(props: { · 3 unmodified lines
661706 );
662707 }
663708
664−function ToolkitContentsEmpty(props: { onAddConnection: () => void }) {
709+function ToolkitContentsEmpty(props: { onManageConnections: () => void }) {
665710 return (
666711 <div className="flex h-full items-center justify-center px-6 py-10">
667712 <div className="max-w-sm text-center">
@@ -672,75 +717,19 @@ function ToolkitContentsEmpty(props: { onAddConnection: () => void }) { · 4 unmodified lines
672717 <p className="mt-1.5 text-sm leading-6 text-muted-foreground">
673718 Add a connection to decide what this toolkit exposes.
674719 </p>
675− <Button type="button" size="sm" onClick={props.onAddConnection} className="mt-4">
676− <PlusIcon className="size-3.5" />
677− Add connection
720+ <Button type="button" size="sm" onClick={props.onManageConnections} className="mt-4">
721+ Manage connections
678722 </Button>
679723 </div>
680724 </div>
681725 );
682726 }
683727
684−function ToolkitConfiguredConnections(props: {
685− connections: readonly ConfiguredConnectionView[];
686− onRemoveConnection: (connectionId: string) => void;
687−}) {
688− if (props.connections.length === 0) return null;
689− return (
690− <div className="border-b border-border/60 bg-background/60 px-3 py-2">
691− <div className="mb-1.5 flex items-center justify-between gap-2">
692− <span className="text-[10px] font-semibold uppercase tracking-widest text-muted-foreground">
693− Connections
694− </span>
695− <span className="text-xs tabular-nums text-muted-foreground">
696− {props.connections.length}
697− </span>
698− </div>
699− <div className="space-y-1">
700− {props.connections.map((connection) => (
701− <div
702− key={connection.id}
703− className="group flex min-w-0 items-center gap-2 rounded-md border border-border/60 bg-card px-2 py-1.5"
704− >
705− <span className="flex size-7 shrink-0 items-center justify-center rounded-md border border-border/70 bg-muted/30">
706− <IntegrationFavicon
707− icon={connection.icon}
708− sourceId={connection.sourceId}
709− url={connection.url}
710− size={16}
711− />
712− </span>
713− <div className="min-w-0 flex-1">
714− <div className="truncate text-xs font-medium text-foreground">{connection.title}</div>
715− <div className="truncate text-[11px] text-muted-foreground">
716− {connection.subtitle}
717− </div>
718− </div>
719− <Button
720− type="button"
721− variant="ghost"
722− size="icon-xs"
723− aria-label={`Remove connection ${connection.title} from toolkit`}
724− title="Remove connection"
725− onClick={() => props.onRemoveConnection(connection.id)}
726− className="size-6 shrink-0 text-muted-foreground hover:text-destructive"
727− >
728− <Trash2Icon className="size-3.5" />
729− </Button>
730− </div>
731− ))}
732− </div>
733− </div>
734− );
735−}
736−
737728 function ToolkitToolsPanel(props: {
738729 tools: readonly ToolSummary[];
739− configuredConnections: readonly ConfiguredConnectionView[];
740730 selectedToolId: string | null;
741731 policies: readonly ToolkitPolicyResponse[];
742− onAddConnection: () => void;
743− onRemoveConnection: (connectionId: string) => void;
732+ onManageConnections: () => void;
744733 onSelectTool: (toolId: string) => void;
745734 onSetPolicy: (pattern: string, action: ToolPolicyAction) => void;
746735 onClearPolicy: (pattern: string) => void;
@@ -765,21 +754,16 @@ function ToolkitToolsPanel(props: { · 18 unmodified lines
765754 <Button
766755 type="button"
767756 size="sm"
768− aria-label="Add connection to toolkit"
769− onClick={props.onAddConnection}
757+ aria-label="Manage toolkit connections"
758+ onClick={props.onManageConnections}
770759 className="h-8"
771760 >
772− <PlusIcon className="size-3.5" />
773− Add
761+ Manage
774762 </Button>
775763 </div>
776764 </div>
777− <ToolkitConfiguredConnections
778− connections={props.configuredConnections}
779− onRemoveConnection={props.onRemoveConnection}
780− />
781765 {props.tools.length === 0 ? (
782− <ToolkitContentsEmpty onAddConnection={props.onAddConnection} />
766+ <ToolkitContentsEmpty onManageConnections={props.onManageConnections} />
783767 ) : (
784768 <ToolTree
785769 tools={props.tools}
@@ -799,11 +783,13 @@ function ToolkitToolsPanel(props: { · 13 unmodified lines
799783 function AddConnectionDialog(props: {
800784 open: boolean;
801785 groups: readonly ToolkitConnectionGroup[];
802− configuredToolIds: ReadonlySet<string>;
786+ configuredConnections: readonly ConfiguredConnectionView[];
803787 integrations: readonly Integration[];
804788 integrationPlugins: readonly IntegrationPlugin[];
789+ showOwnerLabels: boolean;
805790 onOpenChange: (open: boolean) => void;
806791 onAddPatterns: (patterns: readonly string[]) => Promise<void> | void;
792+ onRemoveConnection: (connectionId: string) => Promise<void> | void;
807793 }) {
808794 const searchId = useId();
809795 const [query, setQuery] = useState("");
@@ -823,9 +809,12 @@ function AddConnectionDialog(props: { · 13 unmodified lines
823809 });
824810 }, [props.groups, trimmedQuery]);
825811
826− const addAndClose = async (patterns: readonly string[]) => {
812+ const addConnection = async (patterns: readonly string[]) => {
827813 await props.onAddPatterns(patterns);
828− props.onOpenChange(false);
814+ };
815+
816+ const removeConnection = async (connectionId: string) => {
817+ await props.onRemoveConnection(connectionId);
829818 };
830819
831820 return (
@@ -852,9 +841,9 @@ function AddConnectionDialog(props: { · 20 unmodified lines
852841 <PlugIcon className="size-4" />
853842 </span>
854843 <div className="min-w-0">
855− <DialogTitle className="text-sm">Add connection</DialogTitle>
844+ <DialogTitle className="text-sm">Manage connections</DialogTitle>
856845 <DialogDescription className="mt-1 text-xs">
857− Choose which connected account this toolkit can use.
846+ Choose which connected accounts this toolkit can use.
858847 </DialogDescription>
859848 </div>
860849 </div>
@@ -892,10 +881,11 @@ function AddConnectionDialog(props: { · 31 unmodified lines
892881 ) : (
893882 <div className="overflow-hidden rounded-md border border-border/70 bg-background/30">
894883 {filteredGroups.map((group) => {
895− const title = connectionTitle(group);
896− const added = group.tools.every((tool) =>
897− props.configuredToolIds.has(toolMatchId(tool)),
884+ const title = connectionTitleForHost(group, props.showOwnerLabels);
885+ const configuredConnection = props.configuredConnections.find((connection) =>
886+ group.patterns.includes(connection.pattern),
898887 );
888+ const added = configuredConnection !== undefined;
899889 const meta = integrationMetaFor(
900890 group,
901891 props.integrations,
@@ -919,9 +909,11 @@ function AddConnectionDialog(props: { · 17 unmodified lines
919909 <span className="truncate text-xs font-medium text-foreground">
920910 {connectionDisplayTitle(group, meta)}
921911 </span>
922− <Badge variant="outline" className="shrink-0 text-[10px]">
923− {ownerLabel(group.owner)}
924− </Badge>
912+ {props.showOwnerLabels ? (
913+ <Badge variant="outline" className="shrink-0 text-[10px]">
914+ {ownerLabel(group.owner)}
915+ </Badge>
916+ ) : null}
925917 </div>
926918 <div className="flex min-w-0 items-center gap-2">
927919 <span className="truncate text-[11px] text-muted-foreground">
@@ -933,22 +925,25 @@ function AddConnectionDialog(props: { · 5 unmodified lines
933925 type="button"
934926 variant={added ? "outline" : "default"}
935927 size="sm"
936− disabled={added}
937− aria-label={`${added ? "Connection added" : "Add connection"} ${title}`}
938− onClick={() => void addAndClose(group.patterns)}
928+ aria-label={`${added ? "Remove connection" : "Add connection"} ${title}`}
929+ onClick={() =>
930+ void (added && configuredConnection
931+ ? removeConnection(configuredConnection.id)
932+ : addConnection(group.patterns))
933+ }
939934 className={cn(
940935 "h-7 shrink-0 px-2.5 text-xs",
941936 added
942− ? "border-border/70 bg-transparent text-muted-foreground"
937+ ? "border-border/70 bg-transparent text-muted-foreground hover:text-destructive"
943938 : "bg-primary/10 text-primary hover:bg-primary/15",
944939 )}
945940 >
946941 {added ? (
947− <CheckIcon className="size-3.5" />
942+ <Trash2Icon className="size-3.5" />
948943 ) : (
949944 <PlusIcon className="size-3.5" />
950945 )}
951− {added ? "Added" : "Add"}
946+ {added ? "Remove" : "Add"}
952947 </Button>
953948 </div>
954949 );
@@ -964,6 +959,7 @@ function AddConnectionDialog(props: { · 9 unmodified lines
964959
965960 function ToolkitHeader(props: {
966961 toolkit: ToolkitResponse;
962+ showOwnerLabels: boolean;
967963 toolCount: number;
968964 mcpUrl: string;
969965 onBack: () => void;
@@ -985,9 +981,11 @@ function ToolkitHeader(props: { · 15 unmodified lines
985981 <div className="min-w-0">
986982 <div className="flex min-w-0 items-center gap-2">
987983 <h2 className="truncate text-sm font-semibold text-foreground">{props.toolkit.name}</h2>
988− <Badge variant="outline" className="text-[10px]">
989− {ownerLabel(props.toolkit.owner)}
990− </Badge>
984+ {props.showOwnerLabels ? (
985+ <Badge variant="outline" className="text-[10px]">
986+ {ownerLabel(props.toolkit.owner)}
987+ </Badge>
988+ ) : null}
991989 <span className="text-xs tabular-nums text-muted-foreground">
992990 {props.toolCount} {props.toolCount === 1 ? "tool" : "tools"}
993991 </span>
@@ -999,16 +997,34 @@ function ToolkitHeader(props: { · 5 unmodified lines
999997 <CopyButton value={props.mcpUrl} label="Copy toolkit MCP URL" />
1000998 </div>
1001999 </div>
1002− <Button
1003− type="button"
1004− variant="ghost"
1005− size="icon-sm"
1006− aria-label="Delete toolkit"
1007− onClick={props.onRemove}
1008− className="text-muted-foreground hover:text-destructive"
1009− >
1010− <Trash2Icon className="size-3.5" />
1011− </Button>
1000+ <AlertDialog>
1001+ <AlertDialogTrigger asChild>
1002+ <Button
1003+ type="button"
1004+ variant="ghost"
1005+ size="icon-sm"
1006+ aria-label="Delete toolkit"
1007+ className="text-muted-foreground hover:text-destructive"
1008+ >
1009+ <Trash2Icon className="size-3.5" />
1010+ </Button>
1011+ </AlertDialogTrigger>
1012+ <AlertDialogContent size="sm">
1013+ <AlertDialogHeader>
1014+ <AlertDialogTitle>Delete {props.toolkit.name}?</AlertDialogTitle>
1015+ <AlertDialogDescription>
1016+ This removes the toolkit and its dedicated MCP endpoint. Connections are not
1017+ deleted.
1018+ </AlertDialogDescription>
1019+ </AlertDialogHeader>
1020+ <AlertDialogFooter>
1021+ <AlertDialogCancel>Cancel</AlertDialogCancel>
1022+ <AlertDialogAction variant="destructive" onClick={props.onRemove}>
1023+ Delete
1024+ </AlertDialogAction>
1025+ </AlertDialogFooter>
1026+ </AlertDialogContent>
1027+ </AlertDialog>
10121028 </div>
10131029 </div>
10141030 );
@@ -1016,6 +1032,7 @@ function ToolkitHeader(props: { · 1 unmodified line
10161032
10171033 function ToolkitWorkspace(props: {
10181034 toolkit: ToolkitResponse;
1035+ showOwnerLabels: boolean;
10191036 policies: readonly ToolkitPolicyResponse[];
10201037 connections: readonly ToolkitConnectionResponse[];
10211038 tools: readonly ToolRow[];
@@ -1043,8 +1060,15 @@ function ToolkitWorkspace(props: { · 21 unmodified lines
10431060 connectionGroups,
10441061 props.integrations,
10451062 props.integrationPlugins,
1063+ props.showOwnerLabels,
10461064 ),
1047− [connectionGroups, props.connections, props.integrationPlugins, props.integrations],
1065+ [
1066+ connectionGroups,
1067+ props.connections,
1068+ props.integrationPlugins,
1069+ props.integrations,
1070+ props.showOwnerLabels,
1071+ ],
10481072 );
10491073 const legacyPolicyIds = useMemo(
10501074 () => legacyConnectionPolicyIds(props.policies, connectionGroups, props.connections),
@@ -1103,6 +1127,7 @@ function ToolkitWorkspace(props: { · 52 unmodified lines
11031127 <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
11041128 <ToolkitHeader
11051129 toolkit={props.toolkit}
1130+ showOwnerLabels={props.showOwnerLabels}
11061131 toolCount={exposedToolIds.size}
11071132 mcpUrl={props.mcpUrl}
11081133 onBack={props.onBack}
@@ -1112,11 +1137,9 @@ function ToolkitWorkspace(props: { · 3 unmodified lines
11121137 <div className="flex min-h-0 flex-1 overflow-hidden">
11131138 <ToolkitToolsPanel
11141139 tools={toolkitTools}
1115− configuredConnections={configuredConnections}
11161140 selectedToolId={selectedToolId}
11171141 policies={accessPolicies}
1118− onAddConnection={() => setAddOpen(true)}
1119− onRemoveConnection={(connectionId) => void props.onRemoveConnection(connectionId)}
1142+ onManageConnections={() => setAddOpen(true)}
11201143 onSelectTool={setSelectedToolId}
11211144 onSetPolicy={(pattern, action) => void props.onSetPolicy(pattern, action)}
11221145 onClearPolicy={(pattern) => void props.onClearPolicy(pattern)}
@@ -1142,14 +1165,16 @@ function ToolkitWorkspace(props: { · 19 unmodified lines
11421165 open={addOpen}
11431166 onOpenChange={setAddOpen}
11441167 groups={connectionGroups}
1145− configuredToolIds={configuredToolIds}
1168+ configuredConnections={configuredConnections}
11461169 integrations={props.integrations}
11471170 integrationPlugins={props.integrationPlugins}
1171+ showOwnerLabels={props.showOwnerLabels}
11481172 onAddPatterns={async (patterns) => {
11491173 for (const pattern of patterns) {
11501174 await props.onAddConnection(pattern);
11511175 }
11521176 }}
1177+ onRemoveConnection={props.onRemoveConnection}
11531178 />
11541179 </div>
11551180 );
@@ -1171,14 +1196,16 @@ function ToolkitTileSkeleton(props: { index: number }) { · 15 unmodified lines
11711196 );
11721197 }
11731198
1174−function ToolkitSectionSkeleton(props: { title: string; offset: number }) {
1199+function ToolkitSectionSkeleton(props: { title?: string; offset: number }) {
11751200 return (
1176− <section className="space-y-3" aria-label={`Loading ${props.title.toLowerCase()} toolkits`}>
1177− <div className="border-b border-border/60 pb-2">
1178− <h2 className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
1179− {props.title}
1180− </h2>
1181− </div>
1201+ <section className="space-y-3" aria-label="Loading toolkits">
1202+ {props.title ? (
1203+ <div className="border-b border-border/60 pb-2">
1204+ <h2 className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
1205+ {props.title}
1206+ </h2>
1207+ </div>
1208+ ) : null}
11821209
11831210 <div className="grid content-start grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3">
11841211 {Array.from({ length: 3 }).map((_, index) => (
@@ -1189,12 +1216,18 @@ function ToolkitSectionSkeleton(props: { title: string; offset: number }) { · 4 unmodified lines
11891216 );
11901217 }
11911218
1192−function ToolkitGridSkeleton() {
1219+function ToolkitGridSkeleton(props: { showOwnerLabels: boolean }) {
11931220 return (
11941221 <div className="min-h-0 flex-1 overflow-y-auto">
11951222 <div className="w-full space-y-7 px-4 py-4" style={toolkitGridContainerStyle}>
1196− <ToolkitSectionSkeleton title="Workspace" offset={0} />
1197− <ToolkitSectionSkeleton title="Personal" offset={3} />
1223+ {props.showOwnerLabels ? (
1224+ <>
1225+ <ToolkitSectionSkeleton title="Workspace" offset={0} />
1226+ <ToolkitSectionSkeleton title="Personal" offset={3} />
1227+ </>
1228+ ) : (
1229+ <ToolkitSectionSkeleton offset={0} />
1230+ )}
11981231 </div>
11991232 </div>
12001233 );
@@ -1258,6 +1291,7 @@ function ToolkitDetailSkeleton() { · 57 unmodified lines
12581291
12591292 function ToolkitDetailView(props: {
12601293 toolkit: ToolkitResponse;
1294+ showOwnerLabels: boolean;
12611295 tools: readonly ToolRow[];
12621296 integrations: readonly Integration[];
12631297 integrationPlugins: readonly IntegrationPlugin[];
@@ -1326,6 +1360,7 @@ function ToolkitDetailView(props: { · 62 unmodified lines
13261360 return (
13271361 <ToolkitWorkspace
13281362 toolkit={props.toolkit}
1363+ showOwnerLabels={props.showOwnerLabels}
13291364 policies={policyRows}
13301365 connections={connectionRows}
13311366 tools={props.tools}
@@ -1343,8 +1378,9 @@ function ToolkitDetailView(props: { · 11 unmodified lines
13431378 }
13441379
13451380 export function ToolkitsPage(props: PluginPageProps) {
1346− const params = useParams({ strict: false }) as { orgSlug?: string };
13471381 const navigate = useNavigate();
1382+ const organizationSlug = useOrganizationSlug();
1383+ const ownerDisplay = useOwnerDisplay();
13481384 const integrationPlugins = useIntegrationPlugins();
13491385 const toolkits = useAtomValue(toolkitsAtom);
13501386 const tools = useAtomValue(toolsAllAtom);
@@ -1367,8 +1403,7 @@ export function ToolkitsPage(props: PluginPageProps) { · 16 unmodified lines
13671403 const toolsFailed = AsyncResult.isFailure(tools);
13681404 const navigateToIndex = () =>
13691405 navigate({
1370− to: "/{-$orgSlug}/plugins/$pluginId/$",
1371− params: { pluginId: props.pluginId, _splat: "" },
1406+ to: "/{-$orgSlug}/toolkits",
13721407 });
13731408
13741409 const createToolkitHandler = async (input: { owner: Owner; name: string }) => {
@@ -1411,7 +1446,7 @@ export function ToolkitsPage(props: PluginPageProps) { · 36 unmodified lines
14111446 toolkitsFailed ? (
14121447 <div className="p-6 text-sm text-destructive">Failed to load toolkits</div>
14131448 ) : (
1414− <ToolkitGridSkeleton />
1449+ <ToolkitGridSkeleton showOwnerLabels={ownerDisplay.showOwnerLabels} />
14151450 )
14161451 ) : selectedToolkit ? (
14171452 toolsFailed ? (
@@ -1421,10 +1456,11 @@ export function ToolkitsPage(props: PluginPageProps) { · 3 unmodified lines
14211456 ) : (
14221457 <ToolkitDetailView
14231458 toolkit={selectedToolkit}
1459+ showOwnerLabels={ownerDisplay.showOwnerLabels}
14241460 tools={toolRows}
14251461 integrations={integrationRows}
14261462 integrationPlugins={integrationPlugins}
1427− orgSlug={params.orgSlug}
1463+ orgSlug={organizationSlug ?? undefined}
14281464 onBack={() => void navigateToIndex()}
14291465 onRemoveToolkit={removeToolkitHandler}
14301466 />
@@ -1444,11 +1480,7 @@ export function ToolkitsPage(props: PluginPageProps) { · 13 unmodified lines
14441480 <div className="text-sm text-muted-foreground">Toolkit not found</div>
14451481 </div>
14461482 ) : (
1447− <ToolkitGrid
1448− pluginId={props.pluginId}
1449− toolkits={toolkitRows}
1450− onCreate={createToolkitHandler}
1451− />
1483+ <ToolkitGrid toolkits={toolkitRows} onCreate={createToolkitHandler} />
14521484 )}
14531485 </div>
14541486 );
packages/react/src/console-routes.ts+4−0
@@ -39,6 +39,8 @@ export const CONSOLE_ROUTE_PATHS = [ · 38 unmodified lines
3939 "/policies",
4040 "/secrets",
4141 "/tools",
42+ "/toolkits",
43+ "/toolkits/$toolkitSlug",
4244 "/resume/$executionId",
4345 "/plugins/$pluginId/$",
4446 ] as const;
@@ -71,6 +73,8 @@ export const consoleRoutes = (options: ConsoleRoutesOptions): Array<VirtualRoute · 26 unmodified lines
7173 ["/policies", route("/policies", file("policies.tsx"))],
7274 ["/secrets", route("/secrets", file("secrets.tsx"))],
7375 ["/tools", route("/tools", file("tools.tsx"))],
76+ ["/toolkits", route("/toolkits", file("toolkits.tsx"))],
77+ ["/toolkits/$toolkitSlug", route("/toolkits/$toolkitSlug", file("toolkits.$toolkitSlug.tsx"))],
7478 ["/resume/$executionId", route("/resume/$executionId", file("resume.$executionId.tsx"))],
7579 ["/plugins/$pluginId/$", route("/plugins/$pluginId/$", file("plugins.$pluginId.$.tsx"))],
7680 ];
packages/react/src/multiplayer/shell.tsx+1−0
@@ -49,6 +49,7 @@ export const defaultShellNavItems: ReadonlyArray<ShellNavItem> = [ · 48 unmodified lines
4949 { to: "/", label: "Integrations" },
5050 { to: "/secrets", label: "Providers" },
5151 { to: "/policies", label: "Policies" },
52+ { to: "/toolkits", label: "Toolkits" },
5253 ];
5354
5455 /** Canonical public docs (Mintlify). Same-origin on cloud (executor.sh proxies
packages/react/src/routes/plugins.$pluginId.$.tsx+18−3
@@ -1,4 +1,4 @@
1−import { createFileRoute, notFound } from "@tanstack/react-router";
1+import { createFileRoute, Navigate, notFound } from "@tanstack/react-router";
22 import { useClientPlugins } from "@executor-js/sdk/client";
33
44 // ---------------------------------------------------------------------------
@@ -84,13 +84,28 @@ export const matchPluginPage = <TPage extends { readonly path: string }>( · 79 unmodified lines
8484 };
8585
8686 function PluginRouteComponent() {
87− const { pluginId, _splat: rest } = Route.useParams();
87+ const { orgSlug, pluginId, _splat: rest } = Route.useParams();
8888 const plugins = useClientPlugins();
89+ const target = normalizePath(rest ?? "/");
90+ if (pluginId === "toolkits") {
91+ const segments = pathSegments(target);
92+ const toolkitSlug = segments[0];
93+ if (toolkitSlug) {
94+ return (
95+ <Navigate
96+ to="/{-$orgSlug}/toolkits/$toolkitSlug"
97+ params={{ orgSlug, toolkitSlug }}
98+ replace
99+ />
100+ );
101+ }
102+ return <Navigate to="/{-$orgSlug}/toolkits" params={{ orgSlug }} replace />;
103+ }
104+
89105 const plugin = plugins.find((p) => p.id === pluginId);
90106 // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: TanStack Router represents not-found from components by throwing notFound()
91107 if (!plugin) throw notFound();
92108
93− const target = normalizePath(rest ?? "/");
94109 const match = matchPluginPage(plugin.pages, target);
95110 // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: TanStack Router represents not-found from components by throwing notFound()
96111 if (!match) throw notFound();
packages/react/src/routes/routeTree.gen.ts+53−0
@@ -11,8 +11,10 @@ · 10 unmodified lines
1111 import { Route as rootRouteImport } from './__root'
1212 import { Route as DotIndexRouteImport } from './index'
1313 import { Route as DotToolsRouteImport } from './tools'
14+import { Route as DotToolkitsRouteImport } from './toolkits'
1415 import { Route as DotSecretsRouteImport } from './secrets'
1516 import { Route as DotPoliciesRouteImport } from './policies'
17+import { Route as DotToolkitsDottoolkitSlugRouteImport } from './toolkits.$toolkitSlug'
1618 import { Route as DotResumeDotexecutionIdRouteImport } from './resume.$executionId'
1719 import { Route as DotIntegrationsDotnamespaceRouteImport } from './integrations.$namespace'
1820 import { Route as DotPluginsDotpluginIdDotsplatRouteImport } from './plugins.$pluginId.$'
@@ -28,6 +30,11 @@ const DotToolsRoute = DotToolsRouteImport.update({ · 9 unmodified lines
2830 path: '/{-$orgSlug}/tools',
2931 getParentRoute: () => rootRouteImport,
3032 } as any)
33+const DotToolkitsRoute = DotToolkitsRouteImport.update({
34+ id: '/{-$orgSlug}/toolkits',
35+ path: '/{-$orgSlug}/toolkits',
36+ getParentRoute: () => rootRouteImport,
37+} as any)
3138 const DotSecretsRoute = DotSecretsRouteImport.update({
3239 id: '/{-$orgSlug}/secrets',
3340 path: '/{-$orgSlug}/secrets',
@@ -38,6 +45,12 @@ const DotPoliciesRoute = DotPoliciesRouteImport.update({ · 4 unmodified lines
3845 path: '/{-$orgSlug}/policies',
3946 getParentRoute: () => rootRouteImport,
4047 } as any)
48+const DotToolkitsDottoolkitSlugRoute =
49+ DotToolkitsDottoolkitSlugRouteImport.update({
50+ id: '/$toolkitSlug',
51+ path: '/$toolkitSlug',
52+ getParentRoute: () => DotToolkitsRoute,
53+ } as any)
4154 const DotResumeDotexecutionIdRoute = DotResumeDotexecutionIdRouteImport.update({
4255 id: '/{-$orgSlug}/resume/$executionId',
4356 path: '/{-$orgSlug}/resume/$executionId',
@@ -65,20 +78,24 @@ const DotIntegrationsDotaddDotpluginKeyRoute = · 21 unmodified lines
6578 export interface FileRoutesByFullPath {
6679 '/{-$orgSlug}/policies': typeof DotPoliciesRoute
6780 '/{-$orgSlug}/secrets': typeof DotSecretsRoute
81+ '/{-$orgSlug}/toolkits': typeof DotToolkitsRouteWithChildren
6882 '/{-$orgSlug}/tools': typeof DotToolsRoute
6983 '/{-$orgSlug}/': typeof DotIndexRoute
7084 '/{-$orgSlug}/integrations/$namespace': typeof DotIntegrationsDotnamespaceRoute
7185 '/{-$orgSlug}/resume/$executionId': typeof DotResumeDotexecutionIdRoute
86+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotToolkitsDottoolkitSlugRoute
7287 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotIntegrationsDotaddDotpluginKeyRoute
7388 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotPluginsDotpluginIdDotsplatRoute
7489 }
7590 export interface FileRoutesByTo {
7691 '/{-$orgSlug}/policies': typeof DotPoliciesRoute
7792 '/{-$orgSlug}/secrets': typeof DotSecretsRoute
93+ '/{-$orgSlug}/toolkits': typeof DotToolkitsRouteWithChildren
7894 '/{-$orgSlug}/tools': typeof DotToolsRoute
7995 '/{-$orgSlug}': typeof DotIndexRoute
8096 '/{-$orgSlug}/integrations/$namespace': typeof DotIntegrationsDotnamespaceRoute
8197 '/{-$orgSlug}/resume/$executionId': typeof DotResumeDotexecutionIdRoute
98+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotToolkitsDottoolkitSlugRoute
8299 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotIntegrationsDotaddDotpluginKeyRoute
83100 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotPluginsDotpluginIdDotsplatRoute
84101 }
@@ -86,10 +103,12 @@ export interface FileRoutesById { · 1 unmodified line
86103 __root__: typeof rootRouteImport
87104 '/{-$orgSlug}/policies': typeof DotPoliciesRoute
88105 '/{-$orgSlug}/secrets': typeof DotSecretsRoute
106+ '/{-$orgSlug}/toolkits': typeof DotToolkitsRouteWithChildren
89107 '/{-$orgSlug}/tools': typeof DotToolsRoute
90108 '/{-$orgSlug}/': typeof DotIndexRoute
91109 '/{-$orgSlug}/integrations/$namespace': typeof DotIntegrationsDotnamespaceRoute
92110 '/{-$orgSlug}/resume/$executionId': typeof DotResumeDotexecutionIdRoute
111+ '/{-$orgSlug}/toolkits/$toolkitSlug': typeof DotToolkitsDottoolkitSlugRoute
93112 '/{-$orgSlug}/integrations/add/$pluginKey': typeof DotIntegrationsDotaddDotpluginKeyRoute
94113 '/{-$orgSlug}/plugins/$pluginId/$': typeof DotPluginsDotpluginIdDotsplatRoute
95114 }
@@ -98,30 +117,36 @@ export interface FileRouteTypes { · 2 unmodified lines
98117 fullPaths:
99118 | '/{-$orgSlug}/policies'
100119 | '/{-$orgSlug}/secrets'
120+ | '/{-$orgSlug}/toolkits'
101121 | '/{-$orgSlug}/tools'
102122 | '/{-$orgSlug}/'
103123 | '/{-$orgSlug}/integrations/$namespace'
104124 | '/{-$orgSlug}/resume/$executionId'
125+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
105126 | '/{-$orgSlug}/integrations/add/$pluginKey'
106127 | '/{-$orgSlug}/plugins/$pluginId/$'
107128 fileRoutesByTo: FileRoutesByTo
108129 to:
109130 | '/{-$orgSlug}/policies'
110131 | '/{-$orgSlug}/secrets'
132+ | '/{-$orgSlug}/toolkits'
111133 | '/{-$orgSlug}/tools'
112134 | '/{-$orgSlug}'
113135 | '/{-$orgSlug}/integrations/$namespace'
114136 | '/{-$orgSlug}/resume/$executionId'
137+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
115138 | '/{-$orgSlug}/integrations/add/$pluginKey'
116139 | '/{-$orgSlug}/plugins/$pluginId/$'
117140 id:
118141 | '__root__'
119142 | '/{-$orgSlug}/policies'
120143 | '/{-$orgSlug}/secrets'
144+ | '/{-$orgSlug}/toolkits'
121145 | '/{-$orgSlug}/tools'
122146 | '/{-$orgSlug}/'
123147 | '/{-$orgSlug}/integrations/$namespace'
124148 | '/{-$orgSlug}/resume/$executionId'
149+ | '/{-$orgSlug}/toolkits/$toolkitSlug'
125150 | '/{-$orgSlug}/integrations/add/$pluginKey'
126151 | '/{-$orgSlug}/plugins/$pluginId/$'
127152 fileRoutesById: FileRoutesById
@@ -129,6 +154,7 @@ export interface FileRouteTypes { · 1 unmodified line
129154 export interface RootRouteChildren {
130155 DotPoliciesRoute: typeof DotPoliciesRoute
131156 DotSecretsRoute: typeof DotSecretsRoute
157+ DotToolkitsRoute: typeof DotToolkitsRouteWithChildren
132158 DotToolsRoute: typeof DotToolsRoute
133159 DotIndexRoute: typeof DotIndexRoute
134160 DotIntegrationsDotnamespaceRoute: typeof DotIntegrationsDotnamespaceRoute
@@ -153,6 +179,13 @@ declare module '@tanstack/react-router' { · 18 unmodified lines
153179 preLoaderRoute: typeof DotToolsRouteImport
154180 parentRoute: typeof rootRouteImport
155181 }
182+ '/{-$orgSlug}/toolkits': {
183+ id: '/{-$orgSlug}/toolkits'
184+ path: '/{-$orgSlug}/toolkits'
185+ fullPath: '/{-$orgSlug}/toolkits'
186+ preLoaderRoute: typeof DotToolkitsRouteImport
187+ parentRoute: typeof rootRouteImport
188+ }
156189 '/{-$orgSlug}/secrets': {
157190 id: '/{-$orgSlug}/secrets'
158191 path: '/{-$orgSlug}/secrets'
@@ -167,6 +200,13 @@ declare module '@tanstack/react-router' { · 8 unmodified lines
167200 preLoaderRoute: typeof DotPoliciesRouteImport
168201 parentRoute: typeof rootRouteImport
169202 }
203+ '/{-$orgSlug}/toolkits/$toolkitSlug': {
204+ id: '/{-$orgSlug}/toolkits/$toolkitSlug'
205+ path: '/$toolkitSlug'
206+ fullPath: '/{-$orgSlug}/toolkits/$toolkitSlug'
207+ preLoaderRoute: typeof DotToolkitsDottoolkitSlugRouteImport
208+ parentRoute: typeof DotToolkitsRoute
209+ }
170210 '/{-$orgSlug}/resume/$executionId': {
171211 id: '/{-$orgSlug}/resume/$executionId'
172212 path: '/{-$orgSlug}/resume/$executionId'
@@ -198,9 +238,22 @@ declare module '@tanstack/react-router' { · 25 unmodified lines
198238 }
199239 }
200240
241+interface DotToolkitsRouteChildren {
242+ DotToolkitsDottoolkitSlugRoute: typeof DotToolkitsDottoolkitSlugRoute
243+}
244+
245+const DotToolkitsRouteChildren: DotToolkitsRouteChildren = {
246+ DotToolkitsDottoolkitSlugRoute: DotToolkitsDottoolkitSlugRoute,
247+}
248+
249+const DotToolkitsRouteWithChildren = DotToolkitsRoute._addFileChildren(
250+ DotToolkitsRouteChildren,
251+)
252+
201253 const rootRouteChildren: RootRouteChildren = {
202254 DotPoliciesRoute: DotPoliciesRoute,
203255 DotSecretsRoute: DotSecretsRoute,
256+ DotToolkitsRoute: DotToolkitsRouteWithChildren,
204257 DotToolsRoute: DotToolsRoute,
205258 DotIndexRoute: DotIndexRoute,
206259 DotIntegrationsDotnamespaceRoute: DotIntegrationsDotnamespaceRoute,
packages/react/src/routes/toolkits-route.tsx+23−0
@@ -0,0 +1,23 @@
1+import { notFound } from "@tanstack/react-router";
2+import { useClientPlugins } from "@executor-js/sdk/client";
3+
4+export function ToolkitsPluginRoute(props: { toolkitSlug?: string }) {
5+ const plugins = useClientPlugins();
6+ const plugin = plugins.find((candidate) => candidate.id === "toolkits");
7+ const path = props.toolkitSlug ? `/${props.toolkitSlug}` : "/";
8+ const page = plugin?.pages?.find((candidate) =>
9+ props.toolkitSlug ? candidate.path === "/$toolkitSlug" : candidate.path === "/",
10+ );
11+
12+ // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: TanStack Router represents not-found from components by throwing notFound()
13+ if (!plugin || !page) throw notFound();
14+
15+ const Component = page.component;
16+ return (
17+ <Component
18+ params={props.toolkitSlug ? { toolkitSlug: props.toolkitSlug } : {}}
19+ path={path}
20+ pluginId={plugin.id}
21+ />
22+ );
23+}
packages/react/src/routes/toolkits.$toolkitSlug.tsx+12−0
@@ -0,0 +1,12 @@
1+import { createFileRoute } from "@tanstack/react-router";
2+
3+import { ToolkitsPluginRoute } from "./toolkits-route";
4+
5+export const Route = createFileRoute("/{-$orgSlug}/toolkits/$toolkitSlug")({
6+ component: ToolkitsRouteComponent,
7+});
8+
9+function ToolkitsRouteComponent() {
10+ const { toolkitSlug } = Route.useParams();
11+ return <ToolkitsPluginRoute toolkitSlug={toolkitSlug} />;
12+}
packages/react/src/routes/toolkits.tsx+12−0
@@ -0,0 +1,12 @@
1+import { createFileRoute, useParams } from "@tanstack/react-router";
2+
3+import { ToolkitsPluginRoute } from "./toolkits-route";
4+
5+export const Route = createFileRoute("/{-$orgSlug}/toolkits")({
6+ component: ToolkitsRouteComponent,
7+});
8+
9+function ToolkitsRouteComponent() {
10+ const { toolkitSlug } = useParams({ strict: false }) as { toolkitSlug?: string };
11+ return <ToolkitsPluginRoute toolkitSlug={toolkitSlug} />;
12+}