@swiss-ai-hub/web 0.290.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +479 -0
  3. package/app.config.ts +1 -0
  4. package/app.vue +52 -0
  5. package/assets/css/main.css +4 -0
  6. package/assets/images/logo.png +0 -0
  7. package/components/Agent/Avatar.vue +40 -0
  8. package/components/Agent/Card.vue +139 -0
  9. package/components/Agent/Configuration.vue +20 -0
  10. package/components/Agent/CreateModal.vue +287 -0
  11. package/components/Agent/EmptyCard.vue +35 -0
  12. package/components/Agent/List.vue +85 -0
  13. package/components/Agent/TemplateCard.vue +58 -0
  14. package/components/AppLoader.vue +55 -0
  15. package/components/Chat/Message.vue +90 -0
  16. package/components/Chat/SourceNodes.vue +120 -0
  17. package/components/Chat/Thread.vue +134 -0
  18. package/components/Costs/Table.vue +56 -0
  19. package/components/Dashboard/Component/BarChart.vue +46 -0
  20. package/components/Dashboard/Component/LineChart.vue +138 -0
  21. package/components/Dashboard/Component/Number.vue +31 -0
  22. package/components/Dashboard/Grid.vue +214 -0
  23. package/components/Dashboard/Item.vue +75 -0
  24. package/components/Dashboard/Trend.vue +34 -0
  25. package/components/Display/List/DisplayList.vue +93 -0
  26. package/components/Evaluation/Dataset/Card.vue +70 -0
  27. package/components/Evaluation/Dataset/Create.vue +81 -0
  28. package/components/Evaluation/Dataset/Edit.vue +132 -0
  29. package/components/Event/Display/AddMemoryToChatHistoryEvent.vue +60 -0
  30. package/components/Event/Display/AgentInTheLoopRequestEvent.vue +56 -0
  31. package/components/Event/Display/AgentInTheLoopResponseEvent.vue +17 -0
  32. package/components/Event/Display/Base.vue +125 -0
  33. package/components/Event/Display/BaseRetrieveMemoryEvent.vue +101 -0
  34. package/components/Event/Display/BaseStoreMemoryEvent.vue +182 -0
  35. package/components/Event/Display/ChunkEvent.vue +40 -0
  36. package/components/Event/Display/EmbeddingEvent.vue +25 -0
  37. package/components/Event/Display/ExceptionEvent.vue +21 -0
  38. package/components/Event/Display/GuardAcceptEvent.vue +25 -0
  39. package/components/Event/Display/GuardEvent.vue +17 -0
  40. package/components/Event/Display/GuardRejectionEvent.vue +25 -0
  41. package/components/Event/Display/HumanInTheLoopRequestEvent.vue +53 -0
  42. package/components/Event/Display/HumanInTheLoopResponseEvent.vue +40 -0
  43. package/components/Event/Display/LLMCostEvent.vue +25 -0
  44. package/components/Event/Display/LLMEvent.vue +92 -0
  45. package/components/Event/Display/LimitChatHistoryEvent.vue +60 -0
  46. package/components/Event/Display/RAGFailureStopEvent.vue +28 -0
  47. package/components/Event/Display/RAGStartEvent.vue +77 -0
  48. package/components/Event/Display/RAGSuccessStopEvent.vue +16 -0
  49. package/components/Event/Display/RawDataContent.vue +69 -0
  50. package/components/Event/Display/RerankerEvent.vue +39 -0
  51. package/components/Event/Display/RetrieverEvent.vue +22 -0
  52. package/components/Event/Display/RouterEvent.vue +54 -0
  53. package/components/Event/Display/StandaloneQuestionCondenserEvent.vue +38 -0
  54. package/components/Event/Display/StopEvent.vue +16 -0
  55. package/components/Event/Display/ThoughtEvent.vue +20 -0
  56. package/components/Event/Display/ToolEvent.vue +38 -0
  57. package/components/Event/Display/UnknownEvent.vue +17 -0
  58. package/components/Event/Display/UserMessageEvent.vue +35 -0
  59. package/components/Event/List/EventList.vue +249 -0
  60. package/components/Event/Statistics.vue +49 -0
  61. package/components/Event/Timeseries.vue +224 -0
  62. package/components/FormKit/AgentSelector.vue +307 -0
  63. package/components/FormKit/ChipsInput.vue +62 -0
  64. package/components/FormKit/DynamicConfiguration.vue +155 -0
  65. package/components/FormKit/IconSelector.vue +72 -0
  66. package/components/FormKit/KnowledgeDatabaseSelector.vue +92 -0
  67. package/components/FormKit/LocaleInput.vue +150 -0
  68. package/components/FormKit/ModelSelect.vue +110 -0
  69. package/components/FormKit/Repeater.vue +93 -0
  70. package/components/FormKit/VectorStoreInput.vue +247 -0
  71. package/components/Knowledge/Document/List.vue +140 -0
  72. package/components/Knowledge/Document/Overview.vue +28 -0
  73. package/components/Knowledge/Document/UploadModal.vue +298 -0
  74. package/components/Knowledge/Document/WithNodes.vue +105 -0
  75. package/components/Knowledge/Namespace/Card.vue +108 -0
  76. package/components/Knowledge/Namespace/CreateModal.vue +203 -0
  77. package/components/Knowledge/Namespace/EditModal.vue +134 -0
  78. package/components/Knowledge/Namespace/EmptyCard.vue +35 -0
  79. package/components/Knowledge/Node/Content.vue +71 -0
  80. package/components/Markdown/Renderer.vue +87 -0
  81. package/components/Memory/DetailPage.vue +48 -0
  82. package/components/Memory/Edit.vue +241 -0
  83. package/components/Memory/Graph.vue +318 -0
  84. package/components/Memory/List.vue +155 -0
  85. package/components/Memory/MemoryManagementPage.vue +178 -0
  86. package/components/Memory/OpenWebUIContent.vue +96 -0
  87. package/components/Memory/PageLayout.vue +72 -0
  88. package/components/Models/ModelDetailsPanel.vue +250 -0
  89. package/components/Models/NamespaceCard.vue +79 -0
  90. package/components/Navigation/Left.vue +85 -0
  91. package/components/Navigation/Top.vue +31 -0
  92. package/components/Notification/Item.vue +88 -0
  93. package/components/Notification/NotificationsOverlay.vue +164 -0
  94. package/components/Process/Card.vue +119 -0
  95. package/components/Process/Configuration.vue +20 -0
  96. package/components/Process/CreateModal.vue +276 -0
  97. package/components/Process/EmptyCard.vue +35 -0
  98. package/components/Process/Form.vue +153 -0
  99. package/components/Process/Starts.vue +44 -0
  100. package/components/Process/Walkthrough/List.vue +162 -0
  101. package/components/Role/AccessRulesEditor.vue +132 -0
  102. package/components/Role/Card.vue +68 -0
  103. package/components/Role/Create.vue +55 -0
  104. package/components/Role/Edit.vue +82 -0
  105. package/components/Role/UsageLimitsEditor.vue +225 -0
  106. package/components/Service/Selection.vue +148 -0
  107. package/components/Structural/Column.vue +74 -0
  108. package/components/Structural/Screen.vue +10 -0
  109. package/components/Structural/Substructure.vue +5 -0
  110. package/components/Tenant/Switcher.vue +102 -0
  111. package/components/Thread/Details.vue +135 -0
  112. package/components/Thread/Hierarchy.vue +136 -0
  113. package/components/Thread/Info.vue +41 -0
  114. package/components/Thread/List.vue +136 -0
  115. package/components/User/Bar.vue +74 -0
  116. package/components/User/List.vue +86 -0
  117. package/components/User/RoleChips.vue +83 -0
  118. package/components/User/Settings.vue +79 -0
  119. package/components/Workflow/Modal.vue +39 -0
  120. package/components/Workflow/NodeCard.vue +41 -0
  121. package/components/Workflow/StartNode.vue +24 -0
  122. package/components/Workflow/StepNode.vue +27 -0
  123. package/components/Workflow/StopNode.vue +24 -0
  124. package/components/Workflow/Visualization.vue +265 -0
  125. package/components/mdc/MarkdownFigure.vue +9 -0
  126. package/components/mdc/MarkdownTable.vue +9 -0
  127. package/components/mdc/ResolveImageComponent.vue +58 -0
  128. package/composables/agent/useAgentClass.ts +27 -0
  129. package/composables/agent/useAgentClassInstances.ts +27 -0
  130. package/composables/agent/useAgentClasses.ts +27 -0
  131. package/composables/agent/useAgentIconFromThread.ts +8 -0
  132. package/composables/agent/useAgentInstance.ts +28 -0
  133. package/composables/agent/useAgentInstanceThreads.ts +76 -0
  134. package/composables/agent/useAgentInstances.ts +25 -0
  135. package/composables/agent/useAgentNavigation.ts +35 -0
  136. package/composables/agent/useCreateAgentInstance.ts +33 -0
  137. package/composables/agent/useDeleteAgentInstance.ts +31 -0
  138. package/composables/agent/useUpdateAgentInstance.ts +40 -0
  139. package/composables/auth/useAuth.ts +54 -0
  140. package/composables/auth/useAuthProviders.ts +14 -0
  141. package/composables/chat/useChatCompletions.ts +30 -0
  142. package/composables/dashboard/useAgentNameFromDashboardWidget.ts +27 -0
  143. package/composables/dashboard/useDashboardComponent.ts +27 -0
  144. package/composables/dashboard/useSaveDashboard.ts +21 -0
  145. package/composables/document/useCreateNamespace.ts +26 -0
  146. package/composables/document/useDatabases.ts +23 -0
  147. package/composables/document/useDocument.ts +29 -0
  148. package/composables/document/useDocumentUrl.ts +20 -0
  149. package/composables/document/useDocuments.ts +107 -0
  150. package/composables/document/useNodes.ts +29 -0
  151. package/composables/document/useSummaryNodes.ts +32 -0
  152. package/composables/document/useUpdateNamespace.ts +22 -0
  153. package/composables/evaluation/useCreateDataset.ts +19 -0
  154. package/composables/evaluation/useDataset.ts +26 -0
  155. package/composables/evaluation/useDatasets.ts +25 -0
  156. package/composables/evaluation/useUpdateDataset.ts +23 -0
  157. package/composables/event/useBasicEventStatistics.ts +83 -0
  158. package/composables/event/useEventColor.ts +25 -0
  159. package/composables/event/useEventComponent.ts +87 -0
  160. package/composables/event/useEventTimeseries.ts +39 -0
  161. package/composables/event/useEventTimeseriesStats.ts +26 -0
  162. package/composables/file/useFileUpload.ts +91 -0
  163. package/composables/file/useSupportedFileTypes.ts +22 -0
  164. package/composables/form/useCreateInstanceForm.ts +251 -0
  165. package/composables/form/useFormKitTransform.ts +753 -0
  166. package/composables/memory/useMemoryCRUD.ts +88 -0
  167. package/composables/memory/useMemoryFactory.ts +319 -0
  168. package/composables/memory/useMemorySearchFilter.ts +74 -0
  169. package/composables/models/useModelsList.ts +24 -0
  170. package/composables/models/useSingleModel.ts +30 -0
  171. package/composables/notification/useNotificationPoller.ts +58 -0
  172. package/composables/notification/useNotifications.ts +57 -0
  173. package/composables/notification/useUpdateMultipleNotifications.ts +17 -0
  174. package/composables/notification/useUpdateNotification.ts +17 -0
  175. package/composables/process/useCreateProcessInstance.ts +32 -0
  176. package/composables/process/useDeleteProcessInstance.ts +31 -0
  177. package/composables/process/useProcessClasses.ts +27 -0
  178. package/composables/process/useProcessInstance.ts +28 -0
  179. package/composables/process/useProcessInstances.ts +27 -0
  180. package/composables/process/useProcessWalkthroughs.ts +73 -0
  181. package/composables/process/useSendProcessStartForm.ts +43 -0
  182. package/composables/process/useUpdateProcessInstance.ts +40 -0
  183. package/composables/role/useCreateRole.ts +19 -0
  184. package/composables/role/useDeleteRole.ts +21 -0
  185. package/composables/role/useRole.ts +30 -0
  186. package/composables/role/useRoles.ts +25 -0
  187. package/composables/role/useUpdateRole.ts +22 -0
  188. package/composables/suite/useApps.ts +31 -0
  189. package/composables/suite/useSuite.ts +26 -0
  190. package/composables/tenant/useActiveTenant.ts +27 -0
  191. package/composables/tenant/useSysadminNavigation.ts +19 -0
  192. package/composables/tenant/useTenant.ts +38 -0
  193. package/composables/tenant/useTenantMemberships.ts +15 -0
  194. package/composables/tenant/useTenantPath.ts +20 -0
  195. package/composables/tenant/useTenantPolling.ts +30 -0
  196. package/composables/tenant/useTenantReady.ts +12 -0
  197. package/composables/theme/useDarkMode.ts +5 -0
  198. package/composables/thread/useThread.ts +27 -0
  199. package/composables/thread/useThreadEvents.ts +91 -0
  200. package/composables/thread/useThreadUtils.ts +49 -0
  201. package/composables/thread/useThreads.ts +64 -0
  202. package/composables/thread/useThreadsInfinite.ts +56 -0
  203. package/composables/translation/useTranslate.ts +20 -0
  204. package/composables/useRouteReady.ts +21 -0
  205. package/composables/useTimeAgo.ts +40 -0
  206. package/composables/user/useAssignRoleToUser.ts +22 -0
  207. package/composables/user/useMyUser.ts +25 -0
  208. package/composables/user/useRevokeRoleFromUser.ts +21 -0
  209. package/composables/user/useUser.ts +30 -0
  210. package/composables/user/useUsers.ts +63 -0
  211. package/composables/utils/useJsonTree.ts +138 -0
  212. package/formkit.config.ts +44 -0
  213. package/i18n/locales/de.yaml +815 -0
  214. package/i18n/locales/en.yaml +804 -0
  215. package/i18n/locales/fr.yaml +812 -0
  216. package/i18n/locales/it.yaml +808 -0
  217. package/layouts/anonymous.vue +8 -0
  218. package/layouts/default.vue +116 -0
  219. package/middleware/auth.global.ts +62 -0
  220. package/nuxt.config.ts +145 -0
  221. package/package.json +114 -0
  222. package/pages/[tenant]/index.vue +31 -0
  223. package/pages/[tenant]/notifications/index.vue +235 -0
  224. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/chat.vue +67 -0
  225. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/configuration.vue +122 -0
  226. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/memories/[memory_id].vue +3 -0
  227. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/memories.vue +20 -0
  228. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/overview.vue +72 -0
  229. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/threads.vue +52 -0
  230. package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/workflow.vue +19 -0
  231. package/pages/[tenant]/service/agents/[agent_class]-[agent_id].vue +63 -0
  232. package/pages/[tenant]/service/agents/templates.vue +102 -0
  233. package/pages/[tenant]/service/agents.vue +185 -0
  234. package/pages/[tenant]/service/datasets/[dataset_id].vue +81 -0
  235. package/pages/[tenant]/service/datasets.vue +53 -0
  236. package/pages/[tenant]/service/health/index.vue +3 -0
  237. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/nodes.vue +20 -0
  238. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/overview.vue +40 -0
  239. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/summary.vue +88 -0
  240. package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id].vue +48 -0
  241. package/pages/[tenant]/service/knowledge/[db]/[namespace].vue +144 -0
  242. package/pages/[tenant]/service/knowledge.vue +126 -0
  243. package/pages/[tenant]/service/models/[model_name].vue +84 -0
  244. package/pages/[tenant]/service/models.vue +61 -0
  245. package/pages/[tenant]/service/my-account.vue +117 -0
  246. package/pages/[tenant]/service/openai/[thread_id]/[display_id]/memories.vue +66 -0
  247. package/pages/[tenant]/service/openai/[thread_id]/[display_id]/sources.vue +100 -0
  248. package/pages/[tenant]/service/openai/[thread_id]/[display_id]/tracing.vue +49 -0
  249. package/pages/[tenant]/service/openai.vue +101 -0
  250. package/pages/[tenant]/service/organization-memories/graph.vue +97 -0
  251. package/pages/[tenant]/service/organization-memories/list/[memory_id].vue +3 -0
  252. package/pages/[tenant]/service/organization-memories/list.vue +150 -0
  253. package/pages/[tenant]/service/organization-memories.vue +3 -0
  254. package/pages/[tenant]/service/processes/[process_class]-[process_id]/[process_walkthrough_id].vue +7 -0
  255. package/pages/[tenant]/service/processes/[process_class]-[process_id]/configuration.vue +106 -0
  256. package/pages/[tenant]/service/processes/[process_class]-[process_id]/overview.vue +67 -0
  257. package/pages/[tenant]/service/processes/[process_class]-[process_id]/start.vue +26 -0
  258. package/pages/[tenant]/service/processes/[process_class]-[process_id]/walkthroughs/[process_walkthrough_id]/overview.vue +14 -0
  259. package/pages/[tenant]/service/processes/[process_class]-[process_id]/walkthroughs.vue +54 -0
  260. package/pages/[tenant]/service/processes/[process_class]-[process_id].vue +60 -0
  261. package/pages/[tenant]/service/processes.vue +129 -0
  262. package/pages/[tenant]/service/roles/[role_id].vue +54 -0
  263. package/pages/[tenant]/service/roles.vue +84 -0
  264. package/pages/[tenant]/service/threads/[thread_id]/chat.vue +51 -0
  265. package/pages/[tenant]/service/threads/[thread_id]/display/[display_id].vue +21 -0
  266. package/pages/[tenant]/service/threads/[thread_id]/display.vue +29 -0
  267. package/pages/[tenant]/service/threads/[thread_id]/hierarchy.vue +14 -0
  268. package/pages/[tenant]/service/threads/[thread_id]/memories/[memory_id].vue +3 -0
  269. package/pages/[tenant]/service/threads/[thread_id]/memories.vue +19 -0
  270. package/pages/[tenant]/service/threads/[thread_id]/overview.vue +100 -0
  271. package/pages/[tenant]/service/threads/[thread_id].vue +54 -0
  272. package/pages/[tenant]/service/threads.vue +52 -0
  273. package/pages/[tenant]/service/user-memories/graph.vue +97 -0
  274. package/pages/[tenant]/service/user-memories/list/[memory_id].vue +3 -0
  275. package/pages/[tenant]/service/user-memories/list.vue +150 -0
  276. package/pages/[tenant]/service/user-memories.vue +3 -0
  277. package/pages/[tenant]/service/users/[user_id].vue +117 -0
  278. package/pages/[tenant]/service/users.vue +88 -0
  279. package/pages/auth/callback.vue +52 -0
  280. package/pages/auth/login.vue +80 -0
  281. package/pages/auth/renew.vue +24 -0
  282. package/pages/index.vue +59 -0
  283. package/pages/select-tenant.vue +76 -0
  284. package/plugins/0.runtime-config.client.ts +55 -0
  285. package/plugins/apexcharts.client.ts +5 -0
  286. package/plugins/api-client.client.ts +38 -0
  287. package/plugins/dark-mode.client.ts +12 -0
  288. package/plugins/keycloak-client.ts +41 -0
  289. package/plugins/oidc-client.ts +78 -0
  290. package/sdk/client/client/client.gen.ts +237 -0
  291. package/sdk/client/client/index.ts +24 -0
  292. package/sdk/client/client/types.gen.ts +213 -0
  293. package/sdk/client/client/utils.gen.ts +407 -0
  294. package/sdk/client/client.gen.ts +25 -0
  295. package/sdk/client/core/auth.gen.ts +42 -0
  296. package/sdk/client/core/bodySerializer.gen.ts +96 -0
  297. package/sdk/client/core/params.gen.ts +181 -0
  298. package/sdk/client/core/pathSerializer.gen.ts +180 -0
  299. package/sdk/client/core/queryKeySerializer.gen.ts +136 -0
  300. package/sdk/client/core/serverSentEvents.gen.ts +265 -0
  301. package/sdk/client/core/types.gen.ts +118 -0
  302. package/sdk/client/core/utils.gen.ts +143 -0
  303. package/sdk/client/index.ts +1013 -0
  304. package/sdk/client/schemas.gen.ts +35395 -0
  305. package/sdk/client/sdk.gen.ts +3438 -0
  306. package/sdk/client/transformers.gen.ts +143 -0
  307. package/sdk/client/types.gen.ts +27567 -0
  308. package/tailwind.config.mjs +27 -0
  309. package/themes/aihub-theme.ts +125 -0
  310. package/types/DashboardWidget.ts +13 -0
  311. package/types/EventChartInput.ts +7 -0
  312. package/types/NavItem.ts +6 -0
  313. package/types/TimeseriesInput.ts +7 -0
package/README.md ADDED
@@ -0,0 +1,479 @@
1
+ <div align="center">
2
+
3
+ # @swiss-ai-hub/web
4
+
5
+ **The admin and management UI for [Swiss AI Hub](https://github.com/bbvch-ai/aihub-core), published as a
6
+ [Nuxt 3 layer](https://nuxt.com/docs/getting-started/layers).**
7
+
8
+ [![npm](https://img.shields.io/npm/v/@swiss-ai-hub/web?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@swiss-ai-hub/web)
9
+ [![License](https://img.shields.io/badge/license-AGPL%203.0--or--later-blue?style=flat-square)](https://github.com/bbvch-ai/aihub-core/blob/main/packages/web/LICENSE)
10
+
11
+ </div>
12
+
13
+ ______________________________________________________________________
14
+
15
+ ## What is Swiss AI Hub?
16
+
17
+ [Swiss AI Hub](https://github.com/bbvch-ai/aihub-core) is an open-source, self-hosted AI platform for enterprises. One
18
+ `docker compose up` starts ~30 integrated containers: an LLM gateway (LiteLLM), vector search (Milvus), data pipelines
19
+ (Dagster), document parsing (MinerU), SSO (Keycloak), observability (Langfuse + OpenTelemetry), a chat UI (Open-WebUI),
20
+ and more. You build custom agents, pipelines, and processes using the Python SDK; the platform provides the runtime.
21
+
22
+ ## What is this package?
23
+
24
+ This package is the **admin and management UI** -- one component of the larger platform. It is the interface where
25
+ administrators configure agents, manage knowledge bases, monitor processes, inspect threads, assign roles, track costs,
26
+ and build dashboards. It is **not** the chat UI (that's [Open-WebUI](https://github.com/open-webui/open-webui)) and not
27
+ the backend API.
28
+
29
+ The admin UI is built with [Nuxt 3](https://nuxt.com/), [Vue 3](https://vuejs.org/), [PrimeVue](https://primevue.org/),
30
+ and [Tailwind CSS](https://tailwindcss.com/). It is published as a
31
+ **[Nuxt layer](https://nuxt.com/docs/getting-started/layers)** -- a mechanism that lets you inherit an entire Nuxt
32
+ application (pages, components, composables, plugins, config) and extend or override any part of it in your own project.
33
+
34
+ ______________________________________________________________________
35
+
36
+ ## Should you use this package?
37
+
38
+ **Probably not.** Most deployments should use the pre-built Docker image, which ships the admin UI ready to go:
39
+
40
+ ```yaml
41
+ # docker-compose.yml
42
+ services:
43
+ admin-ui:
44
+ image: ghcr.io/bbvch-ai/aihub-core/web:latest
45
+ ports:
46
+ - "3333:80"
47
+ ```
48
+
49
+ The Docker image works out of the box with zero frontend code. Configuration (OIDC provider, API endpoint, WebSocket
50
+ URL) is handled through environment variables at runtime.
51
+
52
+ **Use this npm package only if you need to extend the UI with your own code** -- adding custom pages, overriding
53
+ components, modifying translations, or changing the theme. This is an SDK for building a custom frontend on top of Swiss
54
+ Swiss AI Hub, not a standalone app.
55
+
56
+ ## When this package makes sense
57
+
58
+ | Use case | Example |
59
+ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
60
+ | **Custom pages** | Add an organization-specific dashboard, a domain-specific tool, or internal admin views that don't belong in the open-source project |
61
+ | **Branding** | Override the PrimeVue theme, replace the logo, adjust colors to match corporate identity |
62
+ | **Translation overrides** | Fix or extend translations, add a fifth language, change terminology to match your domain |
63
+ | **Component overrides** | Replace a built-in component with your own implementation |
64
+ | **Custom plugins** | Add organization-specific Nuxt plugins (analytics, feature flags, custom error tracking) |
65
+ | **Custom auth flow** | Extend the OIDC middleware for provider-specific requirements |
66
+
67
+ ______________________________________________________________________
68
+
69
+ ## How Nuxt layers work
70
+
71
+ If you're not familiar with [Nuxt layers](https://nuxt.com/docs/getting-started/layers), here's the idea: a layer is a
72
+ full Nuxt application that another Nuxt project can inherit from using `extends` in `nuxt.config.ts`. When you extend
73
+ this layer, you get all of its pages, components, composables, plugins, middleware, layouts, and configuration -- merged
74
+ into your project automatically. Nuxt resolves conflicts by giving your project priority: if you define a component with
75
+ the same name and path as one in the layer, yours wins. Same for pages, composables, and config keys.
76
+
77
+ This means you don't fork the repo or copy files. You install the package, extend it, and only write the code for what
78
+ you want to change or add.
79
+
80
+ For a deeper understanding, see the [official Nuxt layers documentation](https://nuxt.com/docs/getting-started/layers)
81
+ and the [layer authoring guide](https://nuxt.com/docs/guide/going-further/layers).
82
+
83
+ ______________________________________________________________________
84
+
85
+ ## Installation
86
+
87
+ ```bash
88
+ npm install @swiss-ai-hub/web
89
+ # or
90
+ pnpm add @swiss-ai-hub/web
91
+ ```
92
+
93
+ Install the required peer dependencies:
94
+
95
+ ```bash
96
+ npm install primevue@4.5.5 vue@3.5.17
97
+ ```
98
+
99
+ ### Required dependency overrides
100
+
101
+ **Do not skip this step.** Without it your project ends up with two copies of Vue in `node_modules`, and the UI will
102
+ either fail to build or render with broken behavior.
103
+
104
+ Nuxt and several of its modules depend on their own (newer) copy of Vue, while this layer is built and tested against an
105
+ exact Vue version. With nothing forcing them to agree, your install resolves **two different Vue versions** -- and
106
+ therefore two copies of `@vue/runtime-core`, the package that owns Vue's runtime identity. Two Vue runtimes means two
107
+ separate reactivity systems: `provide`/`inject` stops working across the boundary, component instance checks fail, and
108
+ you get cryptic errors like _"Vue instance ... was created in a different application"_. The same single-instance
109
+ requirement applies to PrimeVue, whose theme system relies on a global singleton (two instances → unstyled components).
110
+
111
+ The fix is to force the whole dependency tree onto one Vue version using your package manager's override mechanism. Add
112
+ this to your project's `package.json`:
113
+
114
+ ```jsonc
115
+ // npm or yarn
116
+ {
117
+ "overrides": {
118
+ "vue": "3.5.17",
119
+ "@vueuse/router": { "vue-router": "4.6.4" }
120
+ }
121
+ }
122
+ ```
123
+
124
+ ```jsonc
125
+ // pnpm
126
+ {
127
+ "pnpm": {
128
+ "overrides": {
129
+ "vue": "3.5.17",
130
+ "@vueuse/router>vue-router": "4.6.4"
131
+ }
132
+ }
133
+ }
134
+ ```
135
+
136
+ Then reinstall from a clean state so the lockfile is regenerated, and confirm a single Vue instance:
137
+
138
+ ```bash
139
+ rm -rf node_modules package-lock.json # or pnpm-lock.yaml
140
+ npm install
141
+ npm ls @vue/runtime-core # must print exactly one version: 3.5.17
142
+ ```
143
+
144
+ > **Why these entries?** `vue` pins the framework runtime to a single instance shared by your app, the layer, and every
145
+ > Nuxt module -- this is the one that actually breaks if omitted. The scoped `@vueuse/router > vue-router` entry
146
+ > resolves a harmless peer-range mismatch (`@vueuse/router` expects vue-router 4, Nuxt's router is 5); it is scoped so
147
+ > it only affects that one nested dependency and never the router Nuxt itself uses. The versions match the
148
+ > [peer dependencies](#peer-dependencies) the layer is built and tested against.
149
+
150
+ ## Quick start
151
+
152
+ ### 1. Create a Nuxt project
153
+
154
+ ```bash
155
+ npx nuxi init my-aihub-frontend
156
+ cd my-aihub-frontend
157
+ npm install
158
+ ```
159
+
160
+ Then install this package, its peer dependencies, and -- importantly -- add the
161
+ [required dependency overrides](#required-dependency-overrides). Skipping the overrides leaves two copies of Vue in your
162
+ tree and the app will not work.
163
+
164
+ ### 2. Extend the layer
165
+
166
+ Replace the generated `nuxt.config.ts` with:
167
+
168
+ ```ts
169
+ // nuxt.config.ts
170
+ export default defineNuxtConfig({
171
+ extends: ['@swiss-ai-hub/web'],
172
+
173
+ // These defaults match infra/docker-compose.dev.yml + `make run-api`.
174
+ // In production, override via NUXT_PUBLIC_* environment variables.
175
+ runtimeConfig: {
176
+ public: {
177
+ env: 'dev',
178
+ oidc: {
179
+ clientId: 'aihub-frontend',
180
+ authorityUrl: 'http://localhost:8180/realms/aihub',
181
+ },
182
+ webui: {
183
+ url: 'http://localhost:8080',
184
+ },
185
+ ws: {
186
+ endpoint: 'ws://localhost:8000/api/v1/active/events/ws',
187
+ },
188
+ },
189
+ },
190
+
191
+ // Proxy API requests to the backend during development.
192
+ // In production, your reverse proxy (Traefik) handles this.
193
+ nitro: {
194
+ devProxy: {
195
+ '/api/v1': {
196
+ target: 'http://localhost:8000/api/v1',
197
+ changeOrigin: true,
198
+ ws: true,
199
+ },
200
+ },
201
+ },
202
+ })
203
+ ```
204
+
205
+ ### 3. Start the platform
206
+
207
+ Make sure the Swiss AI Hub backend is running (either via `docker compose up` or locally with `make run-api`).
208
+
209
+ ### 4. Run
210
+
211
+ ```bash
212
+ npx nuxi dev
213
+ ```
214
+
215
+ Open `http://localhost:3000`. You get the full admin UI -- agents, processes, threads, knowledge bases, models, roles,
216
+ dashboards, and chat -- running locally and pointing at your platform instance. Log in with your Keycloak credentials
217
+ (default: `admin` / `admin`).
218
+
219
+ ______________________________________________________________________
220
+
221
+ ## What the layer provides
222
+
223
+ Everything the admin UI needs ships inside this package:
224
+
225
+ | Category | What you get |
226
+ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
227
+ | **Pages** | Full file-based routing under `/service/` -- agents, processes, threads, knowledge, models, roles, dashboards, chat, costs, evaluations |
228
+ | **Components** | ~170 Vue components organized by domain (Agent, Chat, Dashboard, Event, Navigation, Process, Thread, Workflow, ...) |
229
+ | **Composables** | [Pinia-Colada](https://pinia-colada.esm.dev/) query/mutation wrappers for every API resource |
230
+ | **SDK client** | Auto-generated TypeScript API client ([HeyAPI](https://heyapi.dev/)) |
231
+ | **Layouts** | `default` (authenticated) and `anonymous` layouts |
232
+ | **Middleware** | OIDC auth guard on all routes |
233
+ | **Plugins** | OIDC client, config loader, ApexCharts |
234
+ | **i18n** | German, English, French, Italian (lazy-loaded YAML files) |
235
+ | **Theme** | PrimeVue [Aura](https://primevue.org/theming/styled/#aura)-based theme with dark mode support |
236
+ | **FormKit config** | Custom form inputs (agent selector, model select, knowledge database selector, icon selector, locale input, vector store input) |
237
+
238
+ ______________________________________________________________________
239
+
240
+ ## Extending the UI
241
+
242
+ ### Add a custom page
243
+
244
+ Create a Vue file in `pages/` and Nuxt merges it with the layer's routes. The layer's components and composables are
245
+ auto-imported and available in your pages without any explicit imports:
246
+
247
+ ```vue
248
+ <!-- pages/service/my-tool.vue -->
249
+ <template>
250
+ <StructuralScreen>
251
+ <StructuralColumn title="My Custom Tool">
252
+ <p>This page lives only in your deployment, not in the open-source project.</p>
253
+ <p>All layer components and composables are available here.</p>
254
+ </StructuralColumn>
255
+ </StructuralScreen>
256
+ </template>
257
+ ```
258
+
259
+ `StructuralScreen` is the full-height scrollable container used by every page. `StructuralColumn` provides a titled
260
+ panel with built-in loading states -- pass `:loading="true"` to show a progress bar and suppress content until data is
261
+ ready. These are the two layout primitives that all admin UI pages are built on.
262
+
263
+ To add navigation for your page, you can extend the sidebar by overriding the navigation component (see
264
+ [Override a component](#override-a-component) below).
265
+
266
+ ### Override translations
267
+
268
+ The layer ships i18n files for German, English, French, and Italian in `i18n/locales/`. To override specific keys or add
269
+ a new language, create matching locale files in your project:
270
+
271
+ ```
272
+ my-project/
273
+ i18n/
274
+ locales/
275
+ en.yaml # keys here override the layer's en.yaml
276
+ de.yaml
277
+ pt.yaml # add a new language
278
+ ```
279
+
280
+ ```yaml
281
+ # i18n/locales/en.yaml -- only the keys you want to change
282
+ agent:
283
+ title: "AI Assistants" # override "Agents" with your preferred term
284
+ my_tool:
285
+ title: "My Custom Tool" # add keys for your custom pages
286
+ ```
287
+
288
+ You also need to register new languages in your `nuxt.config.ts`:
289
+
290
+ ```ts
291
+ export default defineNuxtConfig({
292
+ extends: ['@swiss-ai-hub/web'],
293
+
294
+ i18n: {
295
+ locales: [
296
+ { code: 'pt', file: 'pt.yaml', name: 'Portugues' },
297
+ ],
298
+ },
299
+ })
300
+ ```
301
+
302
+ ### Override the theme
303
+
304
+ The admin UI uses [PrimeVue's styled mode](https://primevue.org/theming/styled/) with a customized
305
+ [Aura preset](https://primevue.org/theming/styled/#aura). Theming works through **design tokens** -- semantic color
306
+ values that PrimeVue components reference. You override tokens to change the look of every component at once.
307
+
308
+ To create your own theme, start from the Aura preset and customize the tokens you want to change:
309
+
310
+ ```ts
311
+ // themes/my-theme.ts
312
+ import { definePreset } from '@primeuix/themes'
313
+ import Aura from '@primeuix/themes/aura'
314
+
315
+ const MyPreset = definePreset(Aura, {
316
+ semantic: {
317
+ // Change the primary color palette (used for buttons, selections, highlights)
318
+ primary: {
319
+ 50: '#eff6ff',
320
+ 100: '#dbeafe',
321
+ 200: '#bfdbfe',
322
+ 300: '#93c5fd',
323
+ 400: '#60a5fa',
324
+ 500: '#3b82f6',
325
+ 600: '#2563eb',
326
+ 700: '#1d4ed8',
327
+ 800: '#1e40af',
328
+ 900: '#1e3a8a',
329
+ 950: '#172554',
330
+ },
331
+ // Override light/dark mode colors
332
+ colorScheme: {
333
+ light: {
334
+ primary: {
335
+ color: '#2563eb',
336
+ inverseColor: '#ffffff',
337
+ hoverColor: '#1d4ed8',
338
+ activeColor: '#1e40af',
339
+ },
340
+ },
341
+ dark: {
342
+ primary: {
343
+ color: '#60a5fa',
344
+ inverseColor: '#172554',
345
+ hoverColor: '#93c5fd',
346
+ activeColor: '#bfdbfe',
347
+ },
348
+ },
349
+ },
350
+ },
351
+ })
352
+
353
+ export default {
354
+ preset: MyPreset,
355
+ options: {
356
+ darkModeSelector: '.dark', // must stay '.dark' to match the Tailwind dark mode config
357
+ },
358
+ }
359
+ ```
360
+
361
+ Then point your `nuxt.config.ts` at it:
362
+
363
+ ```ts
364
+ // nuxt.config.ts
365
+ import { fileURLToPath } from 'url'
366
+
367
+ export default defineNuxtConfig({
368
+ extends: ['@swiss-ai-hub/web'],
369
+
370
+ primevue: {
371
+ importTheme: {
372
+ from: fileURLToPath(new URL('./themes/my-theme.ts', import.meta.url)),
373
+ },
374
+ },
375
+ })
376
+ ```
377
+
378
+ For the full list of design tokens you can customize, see the
379
+ [PrimeVue theming documentation](https://primevue.org/theming/styled/) and the
380
+ [Aura preset reference](https://primevue.org/theming/styled/#aura).
381
+
382
+ ### Override a component
383
+
384
+ Nuxt's layer system resolves components by name and directory path. If you place a component with the same name in the
385
+ same directory structure, your version takes priority over the layer's:
386
+
387
+ ```
388
+ my-project/
389
+ components/
390
+ Navigation/
391
+ Logo.vue # replaces the layer's Navigation/Logo.vue
392
+ Agent/
393
+ Card.vue # replaces the layer's Agent/Card.vue
394
+ ```
395
+
396
+ This works for any component in the layer. You can inspect the layer's component directory structure in the
397
+ [source repository](https://github.com/bbvch-ai/aihub-core/tree/main/packages/web/components) to find the exact names
398
+ and paths.
399
+
400
+ ______________________________________________________________________
401
+
402
+ ## Building for production
403
+
404
+ ```bash
405
+ npx nuxi generate
406
+ ```
407
+
408
+ This produces a fully static site in `.output/public/`. Runtime configuration values are baked in during build, but you
409
+ can override them at runtime using `NUXT_PUBLIC_*` environment variables (Nuxt rewrites them on the client at startup).
410
+
411
+ ### Dockerfile example
412
+
413
+ ```dockerfile
414
+ FROM node:22-alpine AS build
415
+ WORKDIR /app
416
+ COPY package.json package-lock.json ./
417
+ RUN npm ci
418
+ COPY . .
419
+ RUN npx nuxi generate
420
+
421
+ FROM nginx:alpine
422
+ COPY --from=build /app/.output/public /usr/share/nginx/html
423
+ ```
424
+
425
+ ______________________________________________________________________
426
+
427
+ ## Runtime configuration
428
+
429
+ All configuration is provided through `runtimeConfig.public` in `nuxt.config.ts`. In production, override them via
430
+ environment variables -- Nuxt automatically maps `NUXT_PUBLIC_*` variables to the corresponding config keys:
431
+
432
+ | Config key | Environment variable | Default (dev) | Description |
433
+ | ------------------- | -------------------------------- | --------------------------------------------- | ------------------------------------ |
434
+ | `env` | `NUXT_PUBLIC_ENV` | `dev` | Environment identifier |
435
+ | `oidc.clientId` | `NUXT_PUBLIC_OIDC_CLIENT_ID` | `aihub-frontend` | OIDC client ID for Keycloak |
436
+ | `oidc.authorityUrl` | `NUXT_PUBLIC_OIDC_AUTHORITY_URL` | `http://localhost:8180/realms/aihub` | Keycloak realm URL |
437
+ | `webui.url` | `NUXT_PUBLIC_WEBUI_URL` | `http://localhost:8080` | Open-WebUI URL (chat link) |
438
+ | `ws.endpoint` | `NUXT_PUBLIC_WS_ENDPOINT` | `ws://localhost:8000/api/v1/active/events/ws` | WebSocket for real-time agent events |
439
+
440
+ ## Peer dependencies
441
+
442
+ | Package | Version | Why |
443
+ | ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
444
+ | `primevue` | `4.5.5` | UI component library -- must be a single instance to avoid theme-singleton conflicts (see [overrides](#required-dependency-overrides)) |
445
+ | `vue` | `3.5.17` | Framework runtime -- must be a single instance; enforce with the [required overrides](#required-dependency-overrides) |
446
+
447
+ > These exact versions are what the layer is built and published against. They are declared as `peerDependencies`, so
448
+ > your project must provide them, and the [overrides](#required-dependency-overrides) above ensure every transitive
449
+ > dependency resolves to the same single copy.
450
+
451
+ ## Tech stack
452
+
453
+ | Category | Technologies |
454
+ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
455
+ | **Framework** | [Nuxt 3](https://nuxt.com/), [Vue 3](https://vuejs.org/) (Composition API), [TypeScript](https://www.typescriptlang.org/) |
456
+ | **UI** | [PrimeVue](https://primevue.org/), [Tailwind CSS](https://tailwindcss.com/), [FormKit](https://formkit.com/) |
457
+ | **State** | [Pinia-Colada](https://pinia-colada.esm.dev/) (query/mutation caching) |
458
+ | **Auth** | [oidc-client-ts](https://github.com/authts/oidc-client-ts) (OpenID Connect) |
459
+ | **API** | [HeyAPI](https://heyapi.dev/) (auto-generated TypeScript SDK) |
460
+ | **Visualization** | [VueFlow](https://vueflow.dev/) (workflow graphs), [ApexCharts](https://apexcharts.com/) (dashboards), [Sigma.js](https://www.sigmajs.org/) (knowledge graphs) |
461
+ | **Utilities** | [VueUse](https://vueuse.org/), [lodash-es](https://lodash.com/), [date-fns](https://date-fns.org/) |
462
+ | **i18n** | [@nuxtjs/i18n](https://i18n.nuxtjs.org/) (4 languages, lazy-loaded YAML) |
463
+
464
+ ## License
465
+
466
+ Copyright (C) 2024-2026 bbv Software Services AG.
467
+
468
+ AGPL-3.0-or-later — see [packages/web/LICENSE](https://github.com/bbvch-ai/aihub-core/blob/main/packages/web/LICENSE).
469
+ For the full per-package matrix (root, AGPL, and proprietary packages), see
470
+ [LICENSES.md](https://github.com/bbvch-ai/aihub-core/blob/main/LICENSES.md).
471
+
472
+ ______________________________________________________________________
473
+
474
+ <div align="center">
475
+
476
+ Part of [Swiss AI Hub](https://github.com/bbvch-ai/aihub-core). Built in Switzerland by
477
+ [bbv Software Services](https://www.bbv.ch).
478
+
479
+ </div>
package/app.config.ts ADDED
@@ -0,0 +1 @@
1
+ export default defineAppConfig({})
package/app.vue ADDED
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <NuxtLayout>
3
+ <NuxtPage />
4
+ <Toast />
5
+ <ConfirmDialog />
6
+ </NuxtLayout>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ import 'primeicons/primeicons.css'
11
+ import 'gridstack/dist/gridstack.min.css'
12
+ import { client } from './sdk/client/client.gen'
13
+
14
+ const { getToken } = useAuth()
15
+ const { t, locale } = useI18n()
16
+ const localePath = useLocalePath()
17
+ const route = useRoute()
18
+ const toast = useToast()
19
+ useNotificationPoller()
20
+ client.setConfig({
21
+ baseURL: '/api/v1',
22
+ auth: async () => {
23
+ return await getToken()
24
+ },
25
+ onRequest: ({ options }) => {
26
+ options.headers.set('lang', locale.value)
27
+ },
28
+ onResponseError: async ({ response }) => {
29
+ console.error('API error', response.status, response._data?.detail)
30
+
31
+ // Invalid or inaccessible tenant → redirect to tenant selection
32
+ if (response.status === 403 && response._data?.detail === 'Access denied') {
33
+ await navigateTo(localePath('/select-tenant'), { replace: true })
34
+ return
35
+ }
36
+
37
+ // Suppress error toasts on pages without tenant context (login, select-tenant, callback)
38
+ if (!route.params.tenant) return
39
+
40
+ const rawDetail = response._data?.detail
41
+ const message = typeof rawDetail === 'object' && rawDetail?.message
42
+ ? rawDetail.message
43
+ : rawDetail
44
+ toast.add({
45
+ severity: 'error',
46
+ summary: t(`http_error.code.${response.status}`),
47
+ detail: message,
48
+ life: 10_000,
49
+ })
50
+ },
51
+ })
52
+ </script>
@@ -0,0 +1,4 @@
1
+ html {
2
+ font-size: 14px;
3
+ font-family: -apple-system, BlinkMacSystemFont, Inter, ui-sans-serif, system-ui, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, Helvetica Neue, Arial, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
4
+ }
Binary file
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div class="flex gap-2">
3
+ <Avatar
4
+ :size="size"
5
+ icon="pi pi-verified"
6
+ >
7
+ <Icon
8
+ :name="agent.agent_config.icon"
9
+ />
10
+ </Avatar>
11
+ <div
12
+ class="mb-1 flex flex-col justify-center"
13
+ >
14
+ <p
15
+ class="font-bold"
16
+ :class="{ 'text-xs': size === 'normal', 'text-sm': size === 'large' }"
17
+ >
18
+ {{ agent.agent_config.name }}
19
+ </p>
20
+ <p
21
+ :class="{ 'text-xs': size === 'normal', 'text-sm': size === 'large' }"
22
+ >
23
+ {{ agent.agent_class }} / {{ agent.agent_id }}
24
+ </p>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import Avatar from 'primevue/avatar'
31
+
32
+ import type { FullAgentInstanceDto, MinimalAgentInstanceDto } from '@core/sdk/client'
33
+
34
+ withDefaults(defineProps<{
35
+ size?: 'normal' | 'large'
36
+ agent: FullAgentInstanceDto | MinimalAgentInstanceDto
37
+ }>(), {
38
+ size: 'large',
39
+ })
40
+ </script>