@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.
- package/LICENSE +661 -0
- package/README.md +479 -0
- package/app.config.ts +1 -0
- package/app.vue +52 -0
- package/assets/css/main.css +4 -0
- package/assets/images/logo.png +0 -0
- package/components/Agent/Avatar.vue +40 -0
- package/components/Agent/Card.vue +139 -0
- package/components/Agent/Configuration.vue +20 -0
- package/components/Agent/CreateModal.vue +287 -0
- package/components/Agent/EmptyCard.vue +35 -0
- package/components/Agent/List.vue +85 -0
- package/components/Agent/TemplateCard.vue +58 -0
- package/components/AppLoader.vue +55 -0
- package/components/Chat/Message.vue +90 -0
- package/components/Chat/SourceNodes.vue +120 -0
- package/components/Chat/Thread.vue +134 -0
- package/components/Costs/Table.vue +56 -0
- package/components/Dashboard/Component/BarChart.vue +46 -0
- package/components/Dashboard/Component/LineChart.vue +138 -0
- package/components/Dashboard/Component/Number.vue +31 -0
- package/components/Dashboard/Grid.vue +214 -0
- package/components/Dashboard/Item.vue +75 -0
- package/components/Dashboard/Trend.vue +34 -0
- package/components/Display/List/DisplayList.vue +93 -0
- package/components/Evaluation/Dataset/Card.vue +70 -0
- package/components/Evaluation/Dataset/Create.vue +81 -0
- package/components/Evaluation/Dataset/Edit.vue +132 -0
- package/components/Event/Display/AddMemoryToChatHistoryEvent.vue +60 -0
- package/components/Event/Display/AgentInTheLoopRequestEvent.vue +56 -0
- package/components/Event/Display/AgentInTheLoopResponseEvent.vue +17 -0
- package/components/Event/Display/Base.vue +125 -0
- package/components/Event/Display/BaseRetrieveMemoryEvent.vue +101 -0
- package/components/Event/Display/BaseStoreMemoryEvent.vue +182 -0
- package/components/Event/Display/ChunkEvent.vue +40 -0
- package/components/Event/Display/EmbeddingEvent.vue +25 -0
- package/components/Event/Display/ExceptionEvent.vue +21 -0
- package/components/Event/Display/GuardAcceptEvent.vue +25 -0
- package/components/Event/Display/GuardEvent.vue +17 -0
- package/components/Event/Display/GuardRejectionEvent.vue +25 -0
- package/components/Event/Display/HumanInTheLoopRequestEvent.vue +53 -0
- package/components/Event/Display/HumanInTheLoopResponseEvent.vue +40 -0
- package/components/Event/Display/LLMCostEvent.vue +25 -0
- package/components/Event/Display/LLMEvent.vue +92 -0
- package/components/Event/Display/LimitChatHistoryEvent.vue +60 -0
- package/components/Event/Display/RAGFailureStopEvent.vue +28 -0
- package/components/Event/Display/RAGStartEvent.vue +77 -0
- package/components/Event/Display/RAGSuccessStopEvent.vue +16 -0
- package/components/Event/Display/RawDataContent.vue +69 -0
- package/components/Event/Display/RerankerEvent.vue +39 -0
- package/components/Event/Display/RetrieverEvent.vue +22 -0
- package/components/Event/Display/RouterEvent.vue +54 -0
- package/components/Event/Display/StandaloneQuestionCondenserEvent.vue +38 -0
- package/components/Event/Display/StopEvent.vue +16 -0
- package/components/Event/Display/ThoughtEvent.vue +20 -0
- package/components/Event/Display/ToolEvent.vue +38 -0
- package/components/Event/Display/UnknownEvent.vue +17 -0
- package/components/Event/Display/UserMessageEvent.vue +35 -0
- package/components/Event/List/EventList.vue +249 -0
- package/components/Event/Statistics.vue +49 -0
- package/components/Event/Timeseries.vue +224 -0
- package/components/FormKit/AgentSelector.vue +307 -0
- package/components/FormKit/ChipsInput.vue +62 -0
- package/components/FormKit/DynamicConfiguration.vue +155 -0
- package/components/FormKit/IconSelector.vue +72 -0
- package/components/FormKit/KnowledgeDatabaseSelector.vue +92 -0
- package/components/FormKit/LocaleInput.vue +150 -0
- package/components/FormKit/ModelSelect.vue +110 -0
- package/components/FormKit/Repeater.vue +93 -0
- package/components/FormKit/VectorStoreInput.vue +247 -0
- package/components/Knowledge/Document/List.vue +140 -0
- package/components/Knowledge/Document/Overview.vue +28 -0
- package/components/Knowledge/Document/UploadModal.vue +298 -0
- package/components/Knowledge/Document/WithNodes.vue +105 -0
- package/components/Knowledge/Namespace/Card.vue +108 -0
- package/components/Knowledge/Namespace/CreateModal.vue +203 -0
- package/components/Knowledge/Namespace/EditModal.vue +134 -0
- package/components/Knowledge/Namespace/EmptyCard.vue +35 -0
- package/components/Knowledge/Node/Content.vue +71 -0
- package/components/Markdown/Renderer.vue +87 -0
- package/components/Memory/DetailPage.vue +48 -0
- package/components/Memory/Edit.vue +241 -0
- package/components/Memory/Graph.vue +318 -0
- package/components/Memory/List.vue +155 -0
- package/components/Memory/MemoryManagementPage.vue +178 -0
- package/components/Memory/OpenWebUIContent.vue +96 -0
- package/components/Memory/PageLayout.vue +72 -0
- package/components/Models/ModelDetailsPanel.vue +250 -0
- package/components/Models/NamespaceCard.vue +79 -0
- package/components/Navigation/Left.vue +85 -0
- package/components/Navigation/Top.vue +31 -0
- package/components/Notification/Item.vue +88 -0
- package/components/Notification/NotificationsOverlay.vue +164 -0
- package/components/Process/Card.vue +119 -0
- package/components/Process/Configuration.vue +20 -0
- package/components/Process/CreateModal.vue +276 -0
- package/components/Process/EmptyCard.vue +35 -0
- package/components/Process/Form.vue +153 -0
- package/components/Process/Starts.vue +44 -0
- package/components/Process/Walkthrough/List.vue +162 -0
- package/components/Role/AccessRulesEditor.vue +132 -0
- package/components/Role/Card.vue +68 -0
- package/components/Role/Create.vue +55 -0
- package/components/Role/Edit.vue +82 -0
- package/components/Role/UsageLimitsEditor.vue +225 -0
- package/components/Service/Selection.vue +148 -0
- package/components/Structural/Column.vue +74 -0
- package/components/Structural/Screen.vue +10 -0
- package/components/Structural/Substructure.vue +5 -0
- package/components/Tenant/Switcher.vue +102 -0
- package/components/Thread/Details.vue +135 -0
- package/components/Thread/Hierarchy.vue +136 -0
- package/components/Thread/Info.vue +41 -0
- package/components/Thread/List.vue +136 -0
- package/components/User/Bar.vue +74 -0
- package/components/User/List.vue +86 -0
- package/components/User/RoleChips.vue +83 -0
- package/components/User/Settings.vue +79 -0
- package/components/Workflow/Modal.vue +39 -0
- package/components/Workflow/NodeCard.vue +41 -0
- package/components/Workflow/StartNode.vue +24 -0
- package/components/Workflow/StepNode.vue +27 -0
- package/components/Workflow/StopNode.vue +24 -0
- package/components/Workflow/Visualization.vue +265 -0
- package/components/mdc/MarkdownFigure.vue +9 -0
- package/components/mdc/MarkdownTable.vue +9 -0
- package/components/mdc/ResolveImageComponent.vue +58 -0
- package/composables/agent/useAgentClass.ts +27 -0
- package/composables/agent/useAgentClassInstances.ts +27 -0
- package/composables/agent/useAgentClasses.ts +27 -0
- package/composables/agent/useAgentIconFromThread.ts +8 -0
- package/composables/agent/useAgentInstance.ts +28 -0
- package/composables/agent/useAgentInstanceThreads.ts +76 -0
- package/composables/agent/useAgentInstances.ts +25 -0
- package/composables/agent/useAgentNavigation.ts +35 -0
- package/composables/agent/useCreateAgentInstance.ts +33 -0
- package/composables/agent/useDeleteAgentInstance.ts +31 -0
- package/composables/agent/useUpdateAgentInstance.ts +40 -0
- package/composables/auth/useAuth.ts +54 -0
- package/composables/auth/useAuthProviders.ts +14 -0
- package/composables/chat/useChatCompletions.ts +30 -0
- package/composables/dashboard/useAgentNameFromDashboardWidget.ts +27 -0
- package/composables/dashboard/useDashboardComponent.ts +27 -0
- package/composables/dashboard/useSaveDashboard.ts +21 -0
- package/composables/document/useCreateNamespace.ts +26 -0
- package/composables/document/useDatabases.ts +23 -0
- package/composables/document/useDocument.ts +29 -0
- package/composables/document/useDocumentUrl.ts +20 -0
- package/composables/document/useDocuments.ts +107 -0
- package/composables/document/useNodes.ts +29 -0
- package/composables/document/useSummaryNodes.ts +32 -0
- package/composables/document/useUpdateNamespace.ts +22 -0
- package/composables/evaluation/useCreateDataset.ts +19 -0
- package/composables/evaluation/useDataset.ts +26 -0
- package/composables/evaluation/useDatasets.ts +25 -0
- package/composables/evaluation/useUpdateDataset.ts +23 -0
- package/composables/event/useBasicEventStatistics.ts +83 -0
- package/composables/event/useEventColor.ts +25 -0
- package/composables/event/useEventComponent.ts +87 -0
- package/composables/event/useEventTimeseries.ts +39 -0
- package/composables/event/useEventTimeseriesStats.ts +26 -0
- package/composables/file/useFileUpload.ts +91 -0
- package/composables/file/useSupportedFileTypes.ts +22 -0
- package/composables/form/useCreateInstanceForm.ts +251 -0
- package/composables/form/useFormKitTransform.ts +753 -0
- package/composables/memory/useMemoryCRUD.ts +88 -0
- package/composables/memory/useMemoryFactory.ts +319 -0
- package/composables/memory/useMemorySearchFilter.ts +74 -0
- package/composables/models/useModelsList.ts +24 -0
- package/composables/models/useSingleModel.ts +30 -0
- package/composables/notification/useNotificationPoller.ts +58 -0
- package/composables/notification/useNotifications.ts +57 -0
- package/composables/notification/useUpdateMultipleNotifications.ts +17 -0
- package/composables/notification/useUpdateNotification.ts +17 -0
- package/composables/process/useCreateProcessInstance.ts +32 -0
- package/composables/process/useDeleteProcessInstance.ts +31 -0
- package/composables/process/useProcessClasses.ts +27 -0
- package/composables/process/useProcessInstance.ts +28 -0
- package/composables/process/useProcessInstances.ts +27 -0
- package/composables/process/useProcessWalkthroughs.ts +73 -0
- package/composables/process/useSendProcessStartForm.ts +43 -0
- package/composables/process/useUpdateProcessInstance.ts +40 -0
- package/composables/role/useCreateRole.ts +19 -0
- package/composables/role/useDeleteRole.ts +21 -0
- package/composables/role/useRole.ts +30 -0
- package/composables/role/useRoles.ts +25 -0
- package/composables/role/useUpdateRole.ts +22 -0
- package/composables/suite/useApps.ts +31 -0
- package/composables/suite/useSuite.ts +26 -0
- package/composables/tenant/useActiveTenant.ts +27 -0
- package/composables/tenant/useSysadminNavigation.ts +19 -0
- package/composables/tenant/useTenant.ts +38 -0
- package/composables/tenant/useTenantMemberships.ts +15 -0
- package/composables/tenant/useTenantPath.ts +20 -0
- package/composables/tenant/useTenantPolling.ts +30 -0
- package/composables/tenant/useTenantReady.ts +12 -0
- package/composables/theme/useDarkMode.ts +5 -0
- package/composables/thread/useThread.ts +27 -0
- package/composables/thread/useThreadEvents.ts +91 -0
- package/composables/thread/useThreadUtils.ts +49 -0
- package/composables/thread/useThreads.ts +64 -0
- package/composables/thread/useThreadsInfinite.ts +56 -0
- package/composables/translation/useTranslate.ts +20 -0
- package/composables/useRouteReady.ts +21 -0
- package/composables/useTimeAgo.ts +40 -0
- package/composables/user/useAssignRoleToUser.ts +22 -0
- package/composables/user/useMyUser.ts +25 -0
- package/composables/user/useRevokeRoleFromUser.ts +21 -0
- package/composables/user/useUser.ts +30 -0
- package/composables/user/useUsers.ts +63 -0
- package/composables/utils/useJsonTree.ts +138 -0
- package/formkit.config.ts +44 -0
- package/i18n/locales/de.yaml +815 -0
- package/i18n/locales/en.yaml +804 -0
- package/i18n/locales/fr.yaml +812 -0
- package/i18n/locales/it.yaml +808 -0
- package/layouts/anonymous.vue +8 -0
- package/layouts/default.vue +116 -0
- package/middleware/auth.global.ts +62 -0
- package/nuxt.config.ts +145 -0
- package/package.json +114 -0
- package/pages/[tenant]/index.vue +31 -0
- package/pages/[tenant]/notifications/index.vue +235 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/chat.vue +67 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/configuration.vue +122 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/memories/[memory_id].vue +3 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/memories.vue +20 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/overview.vue +72 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/threads.vue +52 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id]/workflow.vue +19 -0
- package/pages/[tenant]/service/agents/[agent_class]-[agent_id].vue +63 -0
- package/pages/[tenant]/service/agents/templates.vue +102 -0
- package/pages/[tenant]/service/agents.vue +185 -0
- package/pages/[tenant]/service/datasets/[dataset_id].vue +81 -0
- package/pages/[tenant]/service/datasets.vue +53 -0
- package/pages/[tenant]/service/health/index.vue +3 -0
- package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/nodes.vue +20 -0
- package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/overview.vue +40 -0
- package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id]/summary.vue +88 -0
- package/pages/[tenant]/service/knowledge/[db]/[namespace]/[document_id].vue +48 -0
- package/pages/[tenant]/service/knowledge/[db]/[namespace].vue +144 -0
- package/pages/[tenant]/service/knowledge.vue +126 -0
- package/pages/[tenant]/service/models/[model_name].vue +84 -0
- package/pages/[tenant]/service/models.vue +61 -0
- package/pages/[tenant]/service/my-account.vue +117 -0
- package/pages/[tenant]/service/openai/[thread_id]/[display_id]/memories.vue +66 -0
- package/pages/[tenant]/service/openai/[thread_id]/[display_id]/sources.vue +100 -0
- package/pages/[tenant]/service/openai/[thread_id]/[display_id]/tracing.vue +49 -0
- package/pages/[tenant]/service/openai.vue +101 -0
- package/pages/[tenant]/service/organization-memories/graph.vue +97 -0
- package/pages/[tenant]/service/organization-memories/list/[memory_id].vue +3 -0
- package/pages/[tenant]/service/organization-memories/list.vue +150 -0
- package/pages/[tenant]/service/organization-memories.vue +3 -0
- package/pages/[tenant]/service/processes/[process_class]-[process_id]/[process_walkthrough_id].vue +7 -0
- package/pages/[tenant]/service/processes/[process_class]-[process_id]/configuration.vue +106 -0
- package/pages/[tenant]/service/processes/[process_class]-[process_id]/overview.vue +67 -0
- package/pages/[tenant]/service/processes/[process_class]-[process_id]/start.vue +26 -0
- package/pages/[tenant]/service/processes/[process_class]-[process_id]/walkthroughs/[process_walkthrough_id]/overview.vue +14 -0
- package/pages/[tenant]/service/processes/[process_class]-[process_id]/walkthroughs.vue +54 -0
- package/pages/[tenant]/service/processes/[process_class]-[process_id].vue +60 -0
- package/pages/[tenant]/service/processes.vue +129 -0
- package/pages/[tenant]/service/roles/[role_id].vue +54 -0
- package/pages/[tenant]/service/roles.vue +84 -0
- package/pages/[tenant]/service/threads/[thread_id]/chat.vue +51 -0
- package/pages/[tenant]/service/threads/[thread_id]/display/[display_id].vue +21 -0
- package/pages/[tenant]/service/threads/[thread_id]/display.vue +29 -0
- package/pages/[tenant]/service/threads/[thread_id]/hierarchy.vue +14 -0
- package/pages/[tenant]/service/threads/[thread_id]/memories/[memory_id].vue +3 -0
- package/pages/[tenant]/service/threads/[thread_id]/memories.vue +19 -0
- package/pages/[tenant]/service/threads/[thread_id]/overview.vue +100 -0
- package/pages/[tenant]/service/threads/[thread_id].vue +54 -0
- package/pages/[tenant]/service/threads.vue +52 -0
- package/pages/[tenant]/service/user-memories/graph.vue +97 -0
- package/pages/[tenant]/service/user-memories/list/[memory_id].vue +3 -0
- package/pages/[tenant]/service/user-memories/list.vue +150 -0
- package/pages/[tenant]/service/user-memories.vue +3 -0
- package/pages/[tenant]/service/users/[user_id].vue +117 -0
- package/pages/[tenant]/service/users.vue +88 -0
- package/pages/auth/callback.vue +52 -0
- package/pages/auth/login.vue +80 -0
- package/pages/auth/renew.vue +24 -0
- package/pages/index.vue +59 -0
- package/pages/select-tenant.vue +76 -0
- package/plugins/0.runtime-config.client.ts +55 -0
- package/plugins/apexcharts.client.ts +5 -0
- package/plugins/api-client.client.ts +38 -0
- package/plugins/dark-mode.client.ts +12 -0
- package/plugins/keycloak-client.ts +41 -0
- package/plugins/oidc-client.ts +78 -0
- package/sdk/client/client/client.gen.ts +237 -0
- package/sdk/client/client/index.ts +24 -0
- package/sdk/client/client/types.gen.ts +213 -0
- package/sdk/client/client/utils.gen.ts +407 -0
- package/sdk/client/client.gen.ts +25 -0
- package/sdk/client/core/auth.gen.ts +42 -0
- package/sdk/client/core/bodySerializer.gen.ts +96 -0
- package/sdk/client/core/params.gen.ts +181 -0
- package/sdk/client/core/pathSerializer.gen.ts +180 -0
- package/sdk/client/core/queryKeySerializer.gen.ts +136 -0
- package/sdk/client/core/serverSentEvents.gen.ts +265 -0
- package/sdk/client/core/types.gen.ts +118 -0
- package/sdk/client/core/utils.gen.ts +143 -0
- package/sdk/client/index.ts +1013 -0
- package/sdk/client/schemas.gen.ts +35395 -0
- package/sdk/client/sdk.gen.ts +3438 -0
- package/sdk/client/transformers.gen.ts +143 -0
- package/sdk/client/types.gen.ts +27567 -0
- package/tailwind.config.mjs +27 -0
- package/themes/aihub-theme.ts +125 -0
- package/types/DashboardWidget.ts +13 -0
- package/types/EventChartInput.ts +7 -0
- package/types/NavItem.ts +6 -0
- 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
|
+
[](https://www.npmjs.com/package/@swiss-ai-hub/web)
|
|
9
|
+
[](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>
|
|
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>
|