mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-16 05:37:28 +00:00
feat(webui): MCP & Agents admin tab
New 'MCP & Agents' tab (after Charts) fed by GET /admin/api/targets: two Card panels, each a sortable DataTable (reusing DataTable/ SortHeaderButton — no hand-rolled table markup) listing configured MCP servers and agents with name, url (muted, truncated with a title tooltip), access (Badge per allowed group, muted 'All groups' when unrestricted — the same idiom UsageView's own group Access block already uses), and req/min, req/day, req/month. - types/api.ts: AdminTargetCountersView/AdminTargetView/ AdminTargetsResponse matching admin.go's JSON exactly. - stores/dashboard.ts: targets fetched in the SAME Promise.all/5s poll as overview and usage — one store, one timer, not a third. - lib/target-columns.ts: shared ColumnDef set both DataTables use. - components/TargetsView.vue: SearchInput + useSearchQuery name filter (inline matching, mirroring ProvidersView's own single-field aliasMatches — not every filter needs a lib/*-search.ts module).
This commit is contained in:
@@ -2,23 +2,26 @@ import { defineStore } from 'pinia'
|
||||
|
||||
import { AdminApiError, adminFetch } from '@/lib/api'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import type { AdminOverviewResponse, AdminUsageResponse } from '@/types/api'
|
||||
import type { AdminOverviewResponse, AdminTargetsResponse, AdminUsageResponse } from '@/types/api'
|
||||
|
||||
/** How often the Providers/Usage views poll (matches the replaced vanilla-JS page). */
|
||||
/** How often the Providers/Usage/Targets views poll (matches the replaced vanilla-JS page). */
|
||||
const POLL_MS = 5000
|
||||
|
||||
/**
|
||||
* useDashboardStore polls GET /admin/api/overview and GET /admin/api/usage
|
||||
* together every POLL_MS, feeding the Providers and Usage views (the store's
|
||||
* own `overview` field keeps the backend's name — see ProvidersView.vue's
|
||||
* doc comment for the UI-label/API-name split). A single
|
||||
* store (not two) because both routes are always fetched together — the
|
||||
* old vanilla-JS page's own Promise.all([overview, usage]) pattern.
|
||||
* useDashboardStore polls GET /admin/api/overview, GET /admin/api/usage,
|
||||
* and GET /admin/api/targets together every POLL_MS, feeding the
|
||||
* Providers, Usage, and MCP & Agents views (the store's own `overview`
|
||||
* field keeps the backend's name — see ProvidersView.vue's doc comment
|
||||
* for the UI-label/API-name split). A single store (not three) because
|
||||
* every route is always fetched together — the old vanilla-JS page's own
|
||||
* Promise.all([overview, usage]) pattern, extended to targets (Feature B,
|
||||
* v0.21) rather than given its own separate poll timer.
|
||||
*/
|
||||
export const useDashboardStore = defineStore('dashboard', {
|
||||
state: () => ({
|
||||
overview: null as AdminOverviewResponse | null,
|
||||
usage: null as AdminUsageResponse | null,
|
||||
targets: null as AdminTargetsResponse | null,
|
||||
lastUpdated: null as Date | null,
|
||||
error: '',
|
||||
timer: undefined as ReturnType<typeof setInterval> | undefined,
|
||||
@@ -28,12 +31,14 @@ export const useDashboardStore = defineStore('dashboard', {
|
||||
const auth = useAuthStore()
|
||||
if (!auth.isAuthenticated) return
|
||||
try {
|
||||
const [overview, usage] = await Promise.all([
|
||||
const [overview, usage, targets] = await Promise.all([
|
||||
adminFetch<AdminOverviewResponse>('/admin/api/overview'),
|
||||
adminFetch<AdminUsageResponse>('/admin/api/usage'),
|
||||
adminFetch<AdminTargetsResponse>('/admin/api/targets'),
|
||||
])
|
||||
this.overview = overview
|
||||
this.usage = usage
|
||||
this.targets = targets
|
||||
this.lastUpdated = new Date()
|
||||
this.error = ''
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user