Skip to content

Commit d6adf7d

Browse files
committed
refactor(ui): design pass 2 — Built-in shelf, bounded activity, journeys
Follow-up design critique fixes + a pass over remaining pages, responsive from narrow windows to ultrawide. Built-in page (was "Context" for one commit — name collided with the Spaces-as-"isolated contexts" copy; now "Built-in", Sparkles icon): - Redesigned as three stages instead of one giant centered card: 1. The shelf — every capability as a uniform card in one responsive grid (1/2/3/5 columns by width): Tool Optimization live + Memory, Skills, Hooks, Plugins as "Soon" — the page now reads as the home for built-in tools and additional features, per the product direction. 2. Detail panel — the selected capability's tools with per-tool switches (cards select; switches stopPropagation so toggling doesn't reselect). 3. Approvals & activity — grants + audit moved OUT of the server card into their own section, side-by-side on xl, stacked on narrow; grants list now max-h bounded like the audit log (which was already a 50-row ring buffer with internal scroll). Journeys: - Home gets a three-step "Get started" strip (Discover → enable in Tools → connect an app) shown only while the Space has zero installed servers; disappears after the first install. Page polish: - Tools page: the big tinted "Gateway Status" banner shrunk to a compact accent-strip status row (full surface lives on Home); wraps on narrow. - FeatureSets: heading "Feature Sets" → "FeatureSets" (matches nav), copy explains grant-to-apps / map-to-folders; Settings: consistent header. - Full-bleed headers use p-6 lg:p-8 so non-maximized windows aren't eaten by padding. e2e label assertions updated (Context→Built-in, Feature Sets→FeatureSets). Verified: vitest 174 passed, tsc clean, eslint 0 errors, web build green. Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
1 parent e1c5d0a commit d6adf7d

10 files changed

Lines changed: 922 additions & 789 deletions

File tree

apps/desktop/src/features/builtinServers/BuiltinServersPage.tsx

Lines changed: 177 additions & 133 deletions
Large diffs are not rendered by default.

apps/desktop/src/features/featuresets/FeatureSetsPage.tsx

Lines changed: 262 additions & 258 deletions
Large diffs are not rendered by default.

apps/desktop/src/features/home/HomePage.tsx

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* the page that manages what it counts.
1111
*/
1212
import { useEffect, useState } from 'react';
13-
import { Server, Wrench, Monitor, Globe, ArrowUpRight } from 'lucide-react';
13+
import { Server, Wrench, Monitor, Globe, ArrowUpRight, Compass, ArrowRight } from 'lucide-react';
1414
import type { LucideIcon } from 'lucide-react';
1515
import { PageHeader } from '@mcpmux/ui';
1616
import { ConnectionCard } from '@/components/ConnectionCard';
@@ -83,13 +83,83 @@ function StatTile({
8383
);
8484
}
8585

86+
/**
87+
* Three-step journey shown only while the Space has zero installed servers —
88+
* it walks a newcomer from empty to "my AI app has tools" and disappears
89+
* forever after the first install.
90+
*/
91+
function GetStartedStrip() {
92+
const navigateTo = useNavigateTo();
93+
const steps = [
94+
{
95+
n: 1,
96+
icon: Compass,
97+
title: 'Pick your first tools',
98+
desc: 'Browse the registry and install a server in one click.',
99+
cta: 'Open Discover',
100+
nav: 'registry' as NavItem,
101+
},
102+
{
103+
n: 2,
104+
icon: Server,
105+
title: 'Enable it',
106+
desc: 'Turn the server on so the gateway can serve its tools.',
107+
cta: 'Open Tools',
108+
nav: 'servers' as NavItem,
109+
},
110+
{
111+
n: 3,
112+
icon: Monitor,
113+
title: 'Connect an AI app',
114+
desc: 'Point Cursor, Claude, or VS Code at your gateway below.',
115+
cta: 'See Apps',
116+
nav: 'clients' as NavItem,
117+
},
118+
];
119+
return (
120+
<div
121+
className="overflow-hidden rounded-xl border border-[rgb(var(--primary))]/25 bg-[rgb(var(--primary))]/5"
122+
data-testid="home-get-started"
123+
>
124+
<div className="grid grid-cols-1 divide-y divide-[rgb(var(--primary))]/15 md:grid-cols-3 md:divide-x md:divide-y-0">
125+
{steps.map((s) => (
126+
<button
127+
key={s.n}
128+
type="button"
129+
onClick={() => navigateTo(s.nav)}
130+
className="group flex items-start gap-3 p-4 text-left transition-colors hover:bg-[rgb(var(--primary))]/10"
131+
>
132+
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-[rgb(var(--primary))]/15 text-sm font-bold text-[rgb(var(--primary))]">
133+
{s.n}
134+
</span>
135+
<span className="min-w-0">
136+
<span className="flex items-center gap-1.5 text-sm font-semibold">
137+
<s.icon className="h-3.5 w-3.5 text-[rgb(var(--primary))]" />
138+
{s.title}
139+
</span>
140+
<span className="mt-0.5 block text-xs leading-relaxed text-[rgb(var(--muted))]">
141+
{s.desc}
142+
</span>
143+
<span className="mt-1.5 inline-flex items-center gap-1 text-xs font-medium text-[rgb(var(--primary))]">
144+
{s.cta}
145+
<ArrowRight className="h-3 w-3 transition-transform group-hover:translate-x-0.5" />
146+
</span>
147+
</span>
148+
</button>
149+
))}
150+
</div>
151+
</div>
152+
);
153+
}
154+
86155
export function HomePage() {
87156
const [stats, setStats] = useState({
88157
installedServers: 0,
89158
connectedServers: 0,
90159
clients: 0,
91160
featureSets: 0,
92161
});
162+
const [statsLoaded, setStatsLoaded] = useState(false);
93163
const viewSpace = useViewSpace();
94164

95165
const loadStats = async () => {
@@ -108,6 +178,7 @@ export function HomePage() {
108178
clients: clients.length,
109179
featureSets: featureSets.length,
110180
});
181+
setStatsLoaded(true);
111182
} catch (e) {
112183
console.error('Failed to load home stats:', e);
113184
}
@@ -142,6 +213,9 @@ export function HomePage() {
142213
subtitle="Your AI control plane at a glance — one gateway, every app, your rules."
143214
/>
144215

216+
{/* First-steps journey — only until the first server is installed. */}
217+
{statsLoaded && stats.installedServers === 0 && <GetStartedStrip />}
218+
145219
{/* Canonical connection surface — owns URL, Start/Stop, IDE grid,
146220
pending-approval nudge. */}
147221
<ConnectionCard />

apps/desktop/src/features/metaTools/MetaToolGrantsPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export function MetaToolGrantsPanel() {
122122
No auto-approvals yet. Each dialog defaults to &quot;Allow once&quot;.
123123
</p>
124124
) : (
125-
<ul className="divide-y divide-[rgb(var(--border-subtle))]">
125+
<ul className="max-h-64 divide-y divide-[rgb(var(--border-subtle))] overflow-y-auto">
126126
{grants.map((g) => {
127127
const key = `${g.client_id}:${g.tool_name}`;
128128
return (

apps/desktop/src/features/servers/ServersPage.tsx

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -915,37 +915,43 @@ export function ServersPage() {
915915
}
916916
/>
917917

918-
{/* Gateway Status */}
918+
{/* Gateway status — compact strip; the full surface lives on Home. */}
919919
<div
920-
className={`rounded-xl border p-4 ${
920+
className={`relative flex flex-wrap items-center justify-between gap-2 overflow-hidden rounded-lg border px-3 py-2 ${
921921
gatewayRunning
922-
? 'border-[rgb(var(--success))]/30 bg-[rgb(var(--success))]/10'
922+
? 'border-[rgb(var(--border-subtle))] bg-[rgb(var(--surface))]'
923923
: 'border-[rgb(var(--warning))]/30 bg-[rgb(var(--warning))]/10'
924924
}`}
925925
>
926-
<div className="flex items-center justify-between">
927-
<div className="flex items-center gap-3">
928-
<span
929-
className={`h-3 w-3 rounded-full ${gatewayRunning ? 'animate-pulse bg-[rgb(var(--success))]' : 'bg-[rgb(var(--warning))]'}`}
930-
/>
931-
<span className="font-medium">
932-
{gatewayRunning ? 'Gateway Running' : 'Gateway Stopped'}
933-
</span>
934-
{gatewayRunning && (
935-
<code className="rounded bg-[rgb(var(--surface-elevated))] px-2 py-1 text-xs text-[rgb(var(--primary))]">
936-
{gatewayUrl}
937-
</code>
938-
)}
939-
</div>
940-
{!gatewayRunning && (
941-
<button
942-
onClick={handleStartGateway}
943-
className="rounded-lg bg-[rgb(var(--primary))] px-4 py-2 text-sm text-[rgb(var(--primary-foreground))] transition-colors hover:bg-[rgb(var(--primary-hover))]"
944-
>
945-
Start Gateway
946-
</button>
926+
<span
927+
aria-hidden
928+
className={`absolute inset-y-0 left-0 w-1 ${
929+
gatewayRunning ? 'bg-emerald-500' : 'bg-amber-500'
930+
}`}
931+
/>
932+
<div className="flex min-w-0 flex-wrap items-center gap-2.5 pl-2 text-sm">
933+
<span
934+
className={`h-2 w-2 flex-shrink-0 rounded-full ${
935+
gatewayRunning ? 'animate-pulse bg-[rgb(var(--success))]' : 'bg-[rgb(var(--warning))]'
936+
}`}
937+
/>
938+
<span className="font-medium">
939+
{gatewayRunning ? 'Gateway running' : 'Gateway stopped'}
940+
</span>
941+
{gatewayRunning && (
942+
<code className="truncate rounded bg-[rgb(var(--surface-dim))] px-2 py-0.5 text-xs text-[rgb(var(--primary))]">
943+
{gatewayUrl}
944+
</code>
947945
)}
948946
</div>
947+
{!gatewayRunning && (
948+
<button
949+
onClick={handleStartGateway}
950+
className="rounded-lg bg-[rgb(var(--primary))] px-3 py-1.5 text-sm text-[rgb(var(--primary-foreground))] transition-colors hover:bg-[rgb(var(--primary-hover))]"
951+
>
952+
Start Gateway
953+
</button>
954+
)}
949955
</div>
950956

951957
{/* Server List */}

0 commit comments

Comments
 (0)