Skip to content

Commit 388331a

Browse files
committed
refactor: remove dashboard navigation and enhance MCP server selection UI with category filter
1 parent 840733f commit 388331a

File tree

3 files changed

+97
-46
lines changed

3 files changed

+97
-46
lines changed

services/frontend/src/components/AppSidebar.vue

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { UserService, type User } from '@/services/userService'
3333
import { useEventBus } from '@/composables/useEventBus'
3434
import {
3535
Server,
36-
LayoutDashboard,
36+
// LayoutDashboard,
3737
Key,
3838
ChevronDown,
3939
User as UserIcon,
@@ -86,11 +86,11 @@ const teamItems = [
8686
]
8787
8888
const navigationItems = [
89-
{
90-
title: t('sidebar.navigation.dashboard'),
91-
icon: LayoutDashboard,
92-
url: '/dashboard',
93-
},
89+
// {
90+
// title: t('sidebar.navigation.dashboard'),
91+
// icon: LayoutDashboard,
92+
// url: '/dashboard',
93+
// },
9494
{
9595
title: t('sidebar.navigation.mcpServer'),
9696
icon: Server,
@@ -128,11 +128,11 @@ const fetchTeams = async (forceRefresh = false) => {
128128
try {
129129
teamsLoading.value = true; teamsError.value = '';
130130
const userTeams = await TeamService.getUserTeams(forceRefresh); teams.value = userTeams;
131-
131+
132132
// Initialize selected team from storage or fallback to default
133133
if (userTeams.length > 0) {
134134
const storedTeamId = eventBus.getState<string>('selected_team_id')
135-
135+
136136
if (storedTeamId) {
137137
// Try to find the stored team in available teams
138138
const storedTeam = userTeams.find(team => team.id === storedTeamId)

services/frontend/src/components/mcp-server/wizard/McpServerSelectionStep.vue

Lines changed: 84 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
import { ref, computed, onMounted } from 'vue'
33
import { useI18n } from 'vue-i18n'
44
import { useRouter } from 'vue-router'
5-
import { Loader2, Info, Download } from 'lucide-vue-next'
5+
import { Loader2, Info, Download, ChevronDown, PackagePlus } from 'lucide-vue-next'
66
import { Button } from '@/components/ui/button'
7-
import { Input } from '@/components/ui/input'
87
import { McpCatalogService } from '@/services/mcpCatalogService'
98
109
// Props and emits
@@ -27,18 +26,38 @@ const servers = ref<any[]>([])
2726
const searchTerm = ref('')
2827
const searchQuery = ref('')
2928
const selectedServerId = ref<string | null>(null)
29+
const selectedCategory = ref('all')
30+
31+
// Available categories (you can expand this based on your data)
32+
const categories = [
33+
{ value: 'all', label: 'All Categories' },
34+
{ value: 'productivity', label: 'Productivity' },
35+
{ value: 'development', label: 'Development' },
36+
{ value: 'ai', label: 'AI & Machine Learning' },
37+
{ value: 'database', label: 'Database' },
38+
{ value: 'api', label: 'API & Integration' }
39+
]
3040
3141
// Computed
3242
const filteredServers = computed(() => {
3343
if (!searchQuery.value.trim()) return []
3444
3545
const term = searchQuery.value.toLowerCase()
36-
return servers.value.filter(server =>
46+
let filtered = servers.value.filter(server =>
3747
server.name.toLowerCase().includes(term) ||
3848
server.description.toLowerCase().includes(term) ||
3949
server.author_name?.toLowerCase().includes(term) ||
4050
server.category_name?.toLowerCase().includes(term)
4151
)
52+
53+
// Filter by category if not 'all'
54+
if (selectedCategory.value !== 'all') {
55+
filtered = filtered.filter(server =>
56+
server.category_name?.toLowerCase() === selectedCategory.value.toLowerCase()
57+
)
58+
}
59+
60+
return filtered
4261
})
4362
4463
@@ -88,42 +107,69 @@ onMounted(() => {
88107
</script>
89108

90109
<template>
91-
<div class="space-y-6">
92-
<!-- Step Header -->
93-
<div>
94-
<h2 class="text-xl font-semibold text-gray-900 mb-2">
95-
{{ t('mcpInstallations.wizard.server.title') }}
96-
</h2>
97-
<p class="text-gray-600">
98-
{{ t('mcpInstallations.wizard.server.description') }}
99-
</p>
100-
</div>
101-
102-
<!-- Search Input -->
103-
<div class="space-y-2">
104-
<label for="server-search" class="text-sm font-medium text-gray-700">
105-
{{ t('mcpInstallations.wizard.server.searchLabel') }}
106-
</label>
107-
<div class="flex w-full items-center gap-1.5">
108-
<Input
109-
id="server-search"
110-
v-model="searchTerm"
111-
type="text"
112-
:placeholder="t('mcpInstallations.wizard.server.searchPlaceholder')"
113-
@keyup.enter="performSearch"
114-
class="flex-1"
115-
/>
116-
<Button type="button" @click="performSearch">
117-
Search
118-
</Button>
110+
<div class="pt-10">
111+
<div class="mx-auto max-w-2xl">
112+
<div class="text-center">
113+
<div class="mx-auto size-16 text-gray-400">
114+
<PackagePlus class="w-full h-full" stroke-width="1.25" aria-hidden="true" />
115+
</div>
116+
<h2 class="mt-2 text-base font-semibold text-gray-900">
117+
{{ t('mcpInstallations.wizard.server.title') }}
118+
</h2>
119+
<p class="mt-1 text-sm text-gray-500">
120+
{{ t('mcpInstallations.wizard.server.description') }}
121+
</p>
119122
</div>
123+
124+
<!-- Search Form -->
125+
<form class="mt-6 sm:flex sm:items-center" @submit.prevent="performSearch">
126+
<div class="flex grow items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 has-[input:focus-within]:outline-2 has-[input:focus-within]:-outline-offset-2 has-[input:focus-within]:outline-primary">
127+
<input
128+
v-model="searchTerm"
129+
type="text"
130+
name="search"
131+
:aria-label="t('mcpInstallations.wizard.server.searchLabel')"
132+
class="block min-w-0 grow py-1.5 pr-3 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6"
133+
:placeholder="t('mcpInstallations.wizard.server.searchPlaceholder')"
134+
@keyup.enter="performSearch"
135+
/>
136+
<div class="grid shrink-0 grid-cols-1 focus-within:relative">
137+
<select
138+
v-model="selectedCategory"
139+
name="category"
140+
:aria-label="t('mcpInstallations.wizard.server.categoryLabel')"
141+
class="col-start-1 row-start-1 w-full appearance-none rounded-md py-1.5 pr-7 pl-3 text-base text-gray-500 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-primary sm:text-sm/6"
142+
>
143+
<option
144+
v-for="category in categories"
145+
:key="category.value"
146+
:value="category.value"
147+
>
148+
{{ category.label }}
149+
</option>
150+
</select>
151+
<ChevronDown class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-gray-500 sm:size-4" aria-hidden="true" />
152+
</div>
153+
</div>
154+
<div class="mt-3 sm:mt-0 sm:ml-4 sm:shrink-0">
155+
<button
156+
type="submit"
157+
class="block w-full rounded-md bg-primary px-3 py-2 text-center text-sm font-semibold text-primary-foreground shadow-xs hover:bg-primary/90 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
158+
:disabled="isLoading"
159+
>
160+
{{ isLoading ? t('mcpInstallations.wizard.server.searching') : t('mcpInstallations.wizard.server.searchButton') }}
161+
</button>
162+
</div>
163+
</form>
120164
</div>
121165

122166
<!-- Error Alert -->
123-
<div v-if="error" class="rounded-md bg-red-50 p-4">
167+
<div v-if="error" class="mt-14 rounded-md bg-red-50 p-4">
124168
<div class="flex">
125169
<div class="ml-3">
126-
<h3 class="text-sm font-medium text-red-800">Error loading servers</h3>
170+
<h3 class="text-sm font-medium text-red-800">
171+
{{ t('mcpInstallations.wizard.server.errorTitle') }}
172+
</h3>
127173
<div class="mt-2 text-sm text-red-700">
128174
<p>{{ error }}</p>
129175
</div>
@@ -143,13 +189,13 @@ onMounted(() => {
143189
</div>
144190

145191
<!-- Loading State -->
146-
<div v-if="isLoading" class="flex items-center justify-center py-8">
192+
<div v-if="isLoading" class="mt-14 flex items-center justify-center py-8">
147193
<Loader2 class="h-6 w-6 animate-spin mr-2 text-gray-400" />
148194
<span class="text-gray-600">{{ t('messages.loading') }}</span>
149195
</div>
150196

151197
<!-- Server List (only show when there's a search query) -->
152-
<div v-else-if="searchQuery.trim() && filteredServers.length > 0" class="space-y-4">
198+
<div v-else-if="searchQuery.trim() && filteredServers.length > 0" class="mt-14 space-y-4">
153199
<div
154200
v-for="server in filteredServers"
155201
:key="server.id"
@@ -205,13 +251,13 @@ onMounted(() => {
205251
</div>
206252

207253
<!-- No Results -->
208-
<div v-else-if="searchQuery.trim() && filteredServers.length === 0" class="text-center py-8">
254+
<div v-else-if="searchQuery.trim() && filteredServers.length === 0" class="mt-14 text-center py-8">
209255
<p class="text-gray-500">{{ t('mcpInstallations.wizard.server.noServersFound') }}</p>
210256
</div>
211257

212258
<!-- Empty State (when no search performed) -->
213-
<div v-else-if="!searchQuery.trim() && !isLoading" class="text-center py-8">
214-
<p class="text-gray-500">Enter a search term and click Search to find MCP servers...</p>
259+
<div v-else-if="!searchQuery.trim() && !isLoading" class="mt-14 text-center py-8">
260+
<p class="text-gray-500">{{ t('mcpInstallations.wizard.server.emptyStateMessage') }}</p>
215261
</div>
216262
</div>
217263
</template>

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,15 @@ export default {
7373
description: 'Choose an MCP server from our catalog to install',
7474
selectLabel: 'MCP Server',
7575
searchLabel: 'Search MCP Servers',
76+
categoryLabel: 'Category Filter',
7677
selectServer: 'Select a server...',
7778
searchPlaceholder: 'Search servers by name, description, or author...',
79+
searchButton: 'Search',
80+
searching: 'Searching...',
7881
noServersFound: 'No servers found matching your search',
7982
noServersAvailable: 'No MCP servers are currently available',
83+
emptyStateMessage: 'Enter a search term and click Search to find MCP servers...',
84+
errorTitle: 'Error loading servers',
8085
requiredEnvVars: 'Required Environment Variables',
8186
details: 'Details',
8287
install: 'Install',

0 commit comments

Comments
 (0)