diff --git a/packages/frontend/src/app/admin/roles/page.tsx b/packages/frontend/src/app/admin/roles/page.tsx
index 4373b4c..c19aa6b 100644
--- a/packages/frontend/src/app/admin/roles/page.tsx
+++ b/packages/frontend/src/app/admin/roles/page.tsx
@@ -5,6 +5,7 @@ import Link from 'next/link';
import { useAuth } from '@/lib/auth-context';
import { roles, connectors, tools as toolsApi, users } from '@/lib/api';
import { NavBar } from '@/components/nav-bar';
+import { AppSelect } from '@/components/ui/select';
import { Footer } from '@/components/footer';
interface RoleItem {
@@ -429,16 +430,15 @@ export default function AdminRolesPage() {
{u.role === 'ADMIN' ? (
Full access (admin)
) : (
-
+ options={[
+ { value: '', label: 'No restriction (full access)' },
+ ...roleList.map((r) => ({ value: r.id, label: r.name })),
+ ]}
+ />
)}
diff --git a/packages/frontend/src/app/admin/users/page.tsx b/packages/frontend/src/app/admin/users/page.tsx
index bdabd78..9c64646 100644
--- a/packages/frontend/src/app/admin/users/page.tsx
+++ b/packages/frontend/src/app/admin/users/page.tsx
@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
import { useAuth } from '@/lib/auth-context';
import { users, auth, roles } from '@/lib/api';
import { NavBar } from '@/components/nav-bar';
+import { AppSelect } from '@/components/ui/select';
import { Footer } from '@/components/footer';
const ROLES = ['ADMIN', 'EDITOR', 'VIEWER'] as const;
@@ -152,28 +153,24 @@ export default function AdminUsersPage() {
-
+ options={ROLES.map((r) => ({ value: r, label: r }))}
+ />
-
+ options={[
+ { value: '', label: 'No restriction (full access)' },
+ ...roleList.map((r) => ({ value: r.id, label: r.name })),
+ ]}
+ />
@@ -227,15 +224,12 @@ export default function AdminUsersPage() {
{u.id === currentUser?.id ? (
{u.role}
) : (
-
+ options={ROLES.map((r) => ({ value: r, label: r }))}
+ />
)}
diff --git a/packages/frontend/src/app/connectors/[id]/page.tsx b/packages/frontend/src/app/connectors/[id]/page.tsx
index 221eb61..a3d543e 100644
--- a/packages/frontend/src/app/connectors/[id]/page.tsx
+++ b/packages/frontend/src/app/connectors/[id]/page.tsx
@@ -8,6 +8,7 @@ import { NavBar } from '@/components/nav-bar';
import { Footer } from '@/components/footer';
import { ToolEditor } from '@/components/tool-editor';
import { McpAssignModal } from '@/components/mcp-assign-modal';
+import { AppSelect } from '@/components/ui/select';
const IMPORT_SOURCES = [
{ id: 'openapi', label: 'OpenAPI / Swagger', placeholder: 'Paste OpenAPI JSON/YAML or enter URL...' },
@@ -564,17 +565,18 @@ export default function ConnectorDetailPage() {
)}
-
+ options={[
+ { value: 'NONE', label: 'None' },
+ { value: 'API_KEY', label: 'API Key' },
+ { value: 'BEARER_TOKEN', label: 'Bearer Token' },
+ { value: 'BASIC_AUTH', label: 'Basic Auth' },
+ { value: 'OAUTH2', label: 'OAuth 2.0' },
+ ]}
+ />
{editAuthType === 'API_KEY' && (
diff --git a/packages/frontend/src/app/connectors/new/page.tsx b/packages/frontend/src/app/connectors/new/page.tsx
index 371bae1..48b3cd8 100644
--- a/packages/frontend/src/app/connectors/new/page.tsx
+++ b/packages/frontend/src/app/connectors/new/page.tsx
@@ -7,6 +7,7 @@ import { connectors } from '@/lib/api';
import { NavBar } from '@/components/nav-bar';
import { Footer } from '@/components/footer';
import { McpAssignModal } from '@/components/mcp-assign-modal';
+import { AppSelect } from '@/components/ui/select';
const CONNECTOR_TYPES = [
{ id: 'REST', name: 'REST API', description: 'Connect to any REST API. Import from OpenAPI/Swagger spec or configure manually.', color: 'bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-500/10 dark:text-blue-400 dark:border-blue-500/30', iconBg: 'bg-blue-50 dark:bg-blue-500/10 text-blue-600 dark:text-blue-400' },
@@ -277,17 +278,18 @@ export default function NewConnectorPage() {
-
+ options={[
+ { value: 'NONE', label: 'None' },
+ { value: 'API_KEY', label: 'API Key' },
+ { value: 'BEARER_TOKEN', label: 'Bearer Token' },
+ { value: 'BASIC_AUTH', label: 'Basic Auth' },
+ { value: 'OAUTH2', label: 'OAuth 2.0' },
+ ]}
+ />
{selectedType === 'MCP' && authType === 'OAUTH2' && (
diff --git a/packages/frontend/src/app/connectors/page.tsx b/packages/frontend/src/app/connectors/page.tsx
index d730cc0..ad3dfb0 100644
--- a/packages/frontend/src/app/connectors/page.tsx
+++ b/packages/frontend/src/app/connectors/page.tsx
@@ -7,6 +7,7 @@ import { connectors } from '@/lib/api';
import { NavBar } from '@/components/nav-bar';
import { Footer } from '@/components/footer';
import * as Dialog from '@radix-ui/react-dialog';
+import { AppSelect } from '@/components/ui/select';
type HealthStatus = { total: number; healthy: number; unhealthy: number; connectors: any[] } | null;
@@ -378,19 +379,19 @@ export default function ConnectorsPage() {
className="w-full border border-[var(--input)] rounded-md pl-9 pr-3 py-2 text-sm bg-[var(--background)]"
/>
-
+ options={[
+ { value: '', label: 'All types' },
+ { value: 'REST', label: 'REST' },
+ { value: 'SOAP', label: 'SOAP' },
+ { value: 'GRAPHQL', label: 'GraphQL' },
+ { value: 'MCP', label: 'MCP' },
+ { value: 'DATABASE', label: 'Database' },
+ ]}
+ />
{filtered.length} connector{filtered.length !== 1 ? 's' : ''}
diff --git a/packages/frontend/src/app/globals.css b/packages/frontend/src/app/globals.css
index 7aaebd4..5d973c6 100644
--- a/packages/frontend/src/app/globals.css
+++ b/packages/frontend/src/app/globals.css
@@ -99,21 +99,6 @@ button:not(:disabled), select, summary, [role="button"] {
cursor: pointer;
}
-/* Custom chevron arrow for native select elements.
- appearance-none removes the browser's built-in arrow so we can control spacing.
- padding-right !important overrides Tailwind px-* utilities to make room for the arrow. */
-main select {
- appearance: none;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='2' stroke='%236b7280'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m19 9-7 7-7-7'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right 0.5rem center;
- background-size: 1.25em 1.25em;
- padding-right: 2rem !important;
-}
-
-.dark main select {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='2' stroke='%239ca3af'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m19 9-7 7-7-7'/%3E%3C/svg%3E");
-}
button:disabled {
cursor: not-allowed;
}
diff --git a/packages/frontend/src/app/logs/page.tsx b/packages/frontend/src/app/logs/page.tsx
index 17e5eb1..346dc43 100644
--- a/packages/frontend/src/app/logs/page.tsx
+++ b/packages/frontend/src/app/logs/page.tsx
@@ -5,6 +5,7 @@ import { useAuth } from '@/lib/auth-context';
import { audit, connectors as connectorsApi, mcpServers } from '@/lib/api';
import { NavBar } from '@/components/nav-bar';
import { Footer } from '@/components/footer';
+import { AppSelect } from '@/components/ui/select';
const PAGE_SIZE = 50;
@@ -142,36 +143,35 @@ export default function LogsPage() {
className="w-full border border-[var(--input)] rounded-md pl-10 pr-3 py-2 text-sm bg-[var(--background)]"
/>
-
-
+ setConnectorFilter(e.target.value)}
+ onValueChange={setConnectorFilter}
className="border border-[var(--input)] rounded-md px-3 py-2 text-sm bg-[var(--background)]"
- >
-
- {connectors.map((c) => (
-
- ))}
-
-
+ options={[
+ { value: '', label: 'All MCP servers' },
+ ...servers.map((s) => ({ value: s.id, label: s.name })),
+ ]}
+ />
-
+ options={[
+ { value: '', label: 'All statuses' },
+ { value: 'active', label: 'Active' },
+ { value: 'inactive', label: 'Inactive' },
+ ]}
+ />
)}
diff --git a/packages/frontend/src/app/settings/roles/page.tsx b/packages/frontend/src/app/settings/roles/page.tsx
index b8f28c7..e128001 100644
--- a/packages/frontend/src/app/settings/roles/page.tsx
+++ b/packages/frontend/src/app/settings/roles/page.tsx
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
import Link from 'next/link';
import { useAuth } from '@/lib/auth-context';
import { roles, connectors, tools as toolsApi, users } from '@/lib/api';
+import { AppSelect } from '@/components/ui/select';
interface RoleItem {
id: string;
@@ -531,16 +532,15 @@ export default function SettingsRolesPage() {
{u.role === 'ADMIN' ? (
Full access (admin)
) : (
-
+ options={[
+ { value: '', label: 'No restriction (full access)' },
+ ...roleList.map((r) => ({ value: r.id, label: r.name })),
+ ]}
+ />
)}
|
diff --git a/packages/frontend/src/app/settings/users/page.tsx b/packages/frontend/src/app/settings/users/page.tsx
index 421a6cb..54d5068 100644
--- a/packages/frontend/src/app/settings/users/page.tsx
+++ b/packages/frontend/src/app/settings/users/page.tsx
@@ -4,6 +4,7 @@ import Link from 'next/link';
import { useEffect, useState } from 'react';
import { useAuth } from '@/lib/auth-context';
import { users, auth, roles } from '@/lib/api';
+import { AppSelect } from '@/components/ui/select';
const ROLES = ['ADMIN', 'EDITOR', 'VIEWER'] as const;
@@ -169,28 +170,24 @@ export default function SettingsUsersPage() {
-
+ options={ROLES.map((r) => ({ value: r, label: r }))}
+ />
-
+ options={[
+ { value: '', label: 'No restriction (full access)' },
+ ...roleList.map((r) => ({ value: r.id, label: r.name })),
+ ]}
+ />
@@ -260,15 +257,12 @@ export default function SettingsUsersPage() {
{u.id === currentUser?.id ? (
{u.role}
) : (
-
+ options={ROLES.map((r) => ({ value: r, label: r }))}
+ />
)}
diff --git a/packages/frontend/src/components/tool-editor/index.tsx b/packages/frontend/src/components/tool-editor/index.tsx
index 4a67a22..6ef6835 100644
--- a/packages/frontend/src/components/tool-editor/index.tsx
+++ b/packages/frontend/src/components/tool-editor/index.tsx
@@ -1,6 +1,7 @@
'use client';
import { useState, useEffect, useCallback } from 'react';
+import { AppSelect } from '@/components/ui/select';
/* ------------------------------------------------------------------ */
/* Types */
@@ -575,22 +576,22 @@ export function ToolEditor({
{/* Tool Type selector — available for all connector types */}
-
+ options={[
+ { value: 'native', label: getNativeLabel(type) },
+ { value: 'static', label: 'Static Text' },
+ ]}
+ />
{method === 'static' ? (
@@ -612,15 +613,12 @@ export function ToolEditor({
-
+ options={methods.filter(m => m !== 'static').map(m => ({ value: m, label: m }))}
+ />
@@ -681,15 +679,12 @@ export function ToolEditor({
-
+ options={methods.filter(m => m !== 'static').map(m => ({ value: m, label: m }))}
+ />
@@ -738,15 +733,16 @@ export function ToolEditor({
{!useBodyTemplate && (
-
+ options={[
+ { value: 'json', label: 'application/json' },
+ { value: 'form-urlencoded', label: 'application/x-www-form-urlencoded' },
+ { value: 'form-data', label: 'multipart/form-data' },
+ ]}
+ />
)}
@@ -844,18 +840,19 @@ export function ToolEditor({
)}
-
+ options={[
+ { value: 'string', label: 'string' },
+ { value: 'number', label: 'number' },
+ { value: 'integer', label: 'integer' },
+ { value: 'boolean', label: 'boolean' },
+ { value: 'array', label: 'array' },
+ { value: 'object', label: 'object' },
+ ]}
+ />
-
+ options={targets.map(t => ({ value: t.value, label: t.label }))}
+ />
|