Skip to content

Commit 39d0b65

Browse files
author
Lasim
committed
feat(frontend): add tools metrics panel and update token distribution
1 parent 4dace87 commit 39d0b65

File tree

4 files changed

+105
-88
lines changed

4 files changed

+105
-88
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<script setup lang="ts">
2+
interface Props {
3+
toolCount: number
4+
totalTokens: number
5+
enabledCount: number
6+
disabledCount: number
7+
}
8+
9+
defineProps<Props>()
10+
11+
// Format token count with commas
12+
const formatTokenCount = (count: number) => {
13+
return count.toLocaleString()
14+
}
15+
</script>
16+
17+
<template>
18+
<div class="border rounded-lg p-6">
19+
<div class="grid grid-cols-2 md:grid-cols-4 gap-8">
20+
<!-- Total Tools Metric -->
21+
<div class="flex flex-col gap-1">
22+
<span class="text-sm text-muted-foreground font-medium">
23+
Total Tools
24+
</span>
25+
<div class="flex items-baseline gap-1">
26+
<span class="text-xl font-normal">
27+
{{ toolCount }}
28+
</span>
29+
</div>
30+
</div>
31+
32+
<!-- Enabled Tools Metric -->
33+
<div class="flex flex-col gap-1 border-l pl-8">
34+
<span class="text-sm text-muted-foreground font-medium">
35+
Enabled Tools
36+
</span>
37+
<div class="flex items-baseline gap-1">
38+
<span class="text-xl font-normal">
39+
{{ enabledCount }} / {{ toolCount }}
40+
</span>
41+
</div>
42+
</div>
43+
44+
<!-- Disabled Tools Metric -->
45+
<div class="flex flex-col gap-1 border-l pl-8">
46+
<span class="text-sm text-muted-foreground font-medium">
47+
Disabled Tools
48+
</span>
49+
<div class="flex items-baseline gap-1">
50+
<span class="text-xl font-normal">
51+
{{ disabledCount }} / {{ toolCount }}
52+
</span>
53+
</div>
54+
</div>
55+
56+
<!-- Total Tokens Metric -->
57+
<div class="flex flex-col gap-1 border-l pl-8">
58+
<span class="text-sm text-muted-foreground font-medium">
59+
Total Tokens
60+
</span>
61+
<div class="flex items-baseline gap-1">
62+
<span class="text-xl font-normal">
63+
{{ formatTokenCount(totalTokens) }}
64+
</span>
65+
</div>
66+
</div>
67+
</div>
68+
</div>
69+
</template>

services/frontend/src/components/mcp-server/installation/ToolsTab.vue

Lines changed: 33 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,11 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@
88
import { Checkbox } from '@/components/ui/checkbox'
99
import { Button } from '@/components/ui/button'
1010
import { ButtonGroup } from '@/components/ui/button-group'
11-
import { Badge } from '@/components/ui/badge'
1211
import { Spinner } from '@/components/ui/spinner'
1312
import { Alert, AlertDescription } from '@/components/ui/alert'
14-
import { Chart } from '@/components/ui/chart'
15-
import { AlertCircle, Package, Wrench, Coins, CircleCheck, CircleMinus } from 'lucide-vue-next'
16-
import { use } from 'echarts/core'
17-
import { PieChart } from 'echarts/charts'
18-
import { TooltipComponent, LegendComponent } from 'echarts/components'
19-
import { CanvasRenderer } from 'echarts/renderers'
20-
import type { EChartsOption } from 'echarts'
13+
import { AlertCircle, Package, CircleCheck, CircleMinus } from 'lucide-vue-next'
2114
import type { McpInstallation } from '@/types/mcp-installations'
22-
23-
// Register ECharts components for pie chart
24-
use([TooltipComponent, LegendComponent, PieChart, CanvasRenderer])
15+
import ToolsMetricsPanel from './ToolsMetricsPanel.vue'
2516
2617
interface Props {
2718
installation: McpInstallation
@@ -49,6 +40,15 @@ const formatTokenCount = (count: number) => {
4940
return count.toLocaleString()
5041
}
5142
43+
// Calculate percentage of total tokens
44+
const calculateTokenPercentage = (tokenCount: number) => {
45+
if (!tools.value || !tools.value.total_tokens || tools.value.total_tokens === 0) {
46+
return '0.0%'
47+
}
48+
const percentage = (tokenCount / tools.value.total_tokens) * 100
49+
return `${percentage.toFixed(1)}%`
50+
}
51+
5252
// Load tools on component mount
5353
onMounted(async () => {
5454
await loadTools()
@@ -72,6 +72,17 @@ const hasTools = computed(() => {
7272
return tools.value && tools.value.tools && tools.value.tools.length > 0
7373
})
7474
75+
// Count enabled and disabled tools
76+
const enabledToolsCount = computed(() => {
77+
if (!hasTools.value) return 0
78+
return tools.value.tools.filter((t: { is_disabled: boolean }) => !t.is_disabled).length
79+
})
80+
81+
const disabledToolsCount = computed(() => {
82+
if (!hasTools.value) return 0
83+
return tools.value.tools.filter((t: { is_disabled: boolean }) => t.is_disabled).length
84+
})
85+
7586
// Check if all tools are selected
7687
const allToolsSelected = computed(() => {
7788
return hasTools.value && selectedToolIds.value.length === tools.value.tools.length
@@ -183,48 +194,6 @@ async function handleBulkToggle(isDisabled: boolean) {
183194
isBulkToggling.value = false
184195
}
185196
}
186-
187-
// Pie chart configuration for token distribution
188-
const pieChartOption = computed<EChartsOption>(() => {
189-
if (!hasTools.value) return {}
190-
191-
const pieData = tools.value.tools.map((tool: { tool_name: string; token_count: number }) => ({
192-
name: tool.tool_name,
193-
value: tool.token_count
194-
}))
195-
196-
return {
197-
tooltip: {
198-
trigger: 'item',
199-
formatter: '{b}: {c} tokens ({d}%)'
200-
},
201-
legend: {
202-
show: false
203-
},
204-
series: [
205-
{
206-
name: 'Token Distribution',
207-
type: 'pie',
208-
radius: ['40%', '70%'],
209-
avoidLabelOverlap: true,
210-
itemStyle: {
211-
borderRadius: 4,
212-
borderColor: '#fff',
213-
borderWidth: 2
214-
},
215-
label: {
216-
show: true,
217-
formatter: '{b}',
218-
fontSize: 11
219-
},
220-
labelLine: {
221-
show: true
222-
},
223-
data: pieData
224-
}
225-
]
226-
}
227-
})
228197
</script>
229198

230199
<template>
@@ -248,40 +217,13 @@ const pieChartOption = computed<EChartsOption>(() => {
248217

249218
<!-- Tools Display -->
250219
<div v-else class="space-y-6">
251-
<!-- Summary Cards with Pie Chart -->
252-
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
253-
<!-- Left: Stats with Icons -->
254-
<div class="bg-white dark:bg-card border rounded-lg p-6 space-y-6">
255-
<div class="flex items-center gap-4">
256-
<div class="flex h-12 w-12 items-center justify-center rounded-lg bg-teal-100 dark:bg-teal-900/30">
257-
<Wrench class="h-6 w-6 text-teal-700 dark:text-teal-400" />
258-
</div>
259-
<div>
260-
<div class="text-sm text-muted-foreground">{{ t('mcpInstallations.details.tools.summary.totalTools') }}</div>
261-
<div class="text-2xl font-bold">{{ tools.tool_count }}</div>
262-
</div>
263-
</div>
264-
<div class="flex items-center gap-4">
265-
<div class="flex h-12 w-12 items-center justify-center rounded-lg bg-amber-100 dark:bg-amber-900/30">
266-
<Coins class="h-6 w-6 text-amber-700 dark:text-amber-400" />
267-
</div>
268-
<div>
269-
<div class="text-sm text-muted-foreground">{{ t('mcpInstallations.details.tools.summary.totalTokens') }}</div>
270-
<div class="text-2xl font-bold">{{ formatTokenCount(tools.total_tokens) }}</div>
271-
</div>
272-
</div>
273-
</div>
274-
275-
<!-- Right: Pie Chart for Token Distribution -->
276-
<div class="bg-white dark:bg-card border rounded-lg p-4">
277-
<div class="text-sm font-medium mb-2">Token Distribution</div>
278-
<Chart
279-
:option="pieChartOption"
280-
variant="pie"
281-
size="sm"
282-
/>
283-
</div>
284-
</div>
220+
<!-- Metrics Panel -->
221+
<ToolsMetricsPanel
222+
:tool-count="tools.tool_count"
223+
:total-tokens="tools.total_tokens"
224+
:enabled-count="enabledToolsCount"
225+
:disabled-count="disabledToolsCount"
226+
/>
285227

286228
<!-- Bulk Actions -->
287229
<div class="flex items-center justify-end gap-2 mb-4">
@@ -324,6 +266,7 @@ const pieChartOption = computed<EChartsOption>(() => {
324266
<TableHead>{{ t('mcpInstallations.details.tools.table.columns.toolName') }}</TableHead>
325267
<TableHead>{{ t('mcpInstallations.details.tools.table.columns.description') }}</TableHead>
326268
<TableHead class="text-right">{{ t('mcpInstallations.details.tools.table.columns.tokenCount') }}</TableHead>
269+
<TableHead class="text-right">{{ t('mcpInstallations.details.tools.table.columns.distribution') }}</TableHead>
327270
</TableRow>
328271
</TableHeader>
329272
<TableBody>
@@ -364,6 +307,9 @@ const pieChartOption = computed<EChartsOption>(() => {
364307
<TableCell class="text-right whitespace-nowrap text-sm font-medium">
365308
{{ formatTokenCount(tool.token_count) }}
366309
</TableCell>
310+
<TableCell class="text-right whitespace-nowrap text-sm text-muted-foreground">
311+
{{ calculateTokenPercentage(tool.token_count) }}
312+
</TableCell>
367313
</TableRow>
368314
</TableBody>
369315
</Table>

services/frontend/src/components/mcp-server/installation/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { default as DangerZone } from './DangerZone.vue'
66
export { default as InstallationTabs } from './InstallationTabs.vue'
77
export { default as RequestsTab } from './RequestsTab.vue'
88
export { default as RequestDetailSheet } from './RequestDetailSheet.vue'
9+
export { default as ToolsMetricsPanel } from './ToolsMetricsPanel.vue'

services/frontend/src/i18n/locales/en/mcp-installations.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,8 @@ export default {
632632
toolName: 'Tool Name',
633633
description: 'Description',
634634
status: 'Status',
635-
tokenCount: 'Token Count'
635+
tokenCount: 'Token Count',
636+
distribution: '% of Total'
636637
},
637638
values: {
638639
noDescription: 'No description provided',

0 commit comments

Comments
 (0)