This is an automated email from the ASF dual-hosted git repository. wu-sheng pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
commit 4fbc2e8e72407e03f23f22c20c822800d2fcdc53 Author: Wu Sheng <[email protected]> AuthorDate: Tue May 12 10:36:43 2026 +0800 ui: add overview link plus marketplace; alarms top-level user-facing --- apps/ui/src/components/shell/AppSidebar.vue | 122 +++++++++++++++++++--------- apps/ui/src/router/index.ts | 24 ++++-- 2 files changed, 100 insertions(+), 46 deletions(-) diff --git a/apps/ui/src/components/shell/AppSidebar.vue b/apps/ui/src/components/shell/AppSidebar.vue index 982db3e..7d09b33 100644 --- a/apps/ui/src/components/shell/AppSidebar.vue +++ b/apps/ui/src/components/shell/AppSidebar.vue @@ -43,20 +43,64 @@ interface NavRow { badge?: { text: string; kind?: 'ok' | 'warn' | 'err' | 'info' }; } -// Operate = OAP runtime operations (vantage-parity) + alarms. -// Trace search is per-layer (lives under /layer/:key/traces) so it's NOT here. -const operate: NavRow[] = [ - { icon: 'alert', label: 'Alarms', to: '/operate/alarms', badge: { text: '7', kind: 'err' } }, - { icon: 'svc', label: 'Cluster status', to: '/operate/cluster' }, - { icon: 'set', label: 'DSL catalog', to: '/operate/dsl' }, - { icon: 'metric', label: 'Inspect', to: '/operate/inspect' }, - { icon: 'flame', label: 'Live debug', to: '/operate/live-debug' }, - { icon: 'trace', label: 'OAL viewer', to: '/operate/oal' }, - { icon: 'download', label: 'Dump', to: '/operate/dump' }, -]; -const admin: NavRow[] = [ - { icon: 'user', label: 'Users', to: '/admin/users' }, - { icon: 'set', label: 'Roles', to: '/admin/roles' }, +interface NavSection { + kicker: string; + links: NavRow[]; +} + +// One leading row before the Layers block — the cross-layer landing. +const overview: NavRow = { icon: 'dash', label: 'Overview', to: '/' }; + +// Vantage-style flat kickers for the Operate / Admin half of the sidebar. +// Alarms is user-facing so it sits before the Operate block (between user +// observability concerns and OAP operator concerns). +const sections: NavSection[] = [ + { + kicker: 'Alerts', + links: [{ icon: 'alert', label: 'Alarms', to: '/alarms', badge: { text: '7', kind: 'err' } }], + }, + { + kicker: 'Marketplace', + links: [{ icon: 'metric', label: 'All dashboards', to: '/operate/marketplace' }], + }, + { + kicker: 'Cluster', + links: [{ icon: 'svc', label: 'Cluster status', to: '/operate/cluster' }], + }, + { + kicker: 'DSL Management', + links: [ + { icon: 'set', label: 'MAL · OTEL', to: '/operate/dsl/otel-rules' }, + { icon: 'set', label: 'MAL · Telegraf', to: '/operate/dsl/telegraf-rules' }, + { icon: 'set', label: 'LAL', to: '/operate/dsl/lal' }, + // log-mal-rules = MAL applied to LAL-derived logs; the data flow reads + // LAL → MAL so the label says so. + { icon: 'set', label: 'LAL → MAL', to: '/operate/dsl/log-mal-rules' }, + { icon: 'trace', label: 'OAL · read-only', to: '/operate/oal' }, + ], + }, + { + kicker: 'Inspect', + links: [{ icon: 'metric', label: 'Inspect', to: '/operate/inspect' }], + }, + { + kicker: 'Live debugger', + links: [ + { icon: 'flame', label: 'Live debugger', to: '/operate/live-debug' }, + { icon: 'event', label: 'Capture history', to: '/operate/live-debug/history' }, + ], + }, + { + kicker: 'Dump', + links: [{ icon: 'download', label: 'Dump & restore', to: '/operate/dump' }], + }, + { + kicker: 'Admin', + links: [ + { icon: 'user', label: 'Users', to: '/admin/users' }, + { icon: 'set', label: 'Roles', to: '/admin/roles' }, + ], + }, ]; </script> @@ -68,6 +112,14 @@ const admin: NavRow[] = [ </RouterLink> <nav class="sw-nav"> + <RouterLink + :to="overview.to" + class="sw-nav-item lead" + :class="{ 'is-active': route.path === overview.to }" + > + <Icon :name="overview.icon" /><span>{{ overview.label }}</span> + </RouterLink> + <div class="sw-nav-section sw-row" style="justify-content: space-between"> <span>Layers</span> <span style="color: var(--sw-fg-3); font-weight: 400">{{ LAYERS.length }} layers</span> @@ -172,30 +224,21 @@ const admin: NavRow[] = [ </div> </template> - <div class="sw-nav-section">Operate</div> - <RouterLink - v-for="row in operate" - :key="row.to" - :to="row.to" - class="sw-nav-item" - :class="{ 'is-active': isActive(row.to) }" - > - <Icon :name="row.icon" /><span>{{ row.label }}</span> - <span v-if="row.badge" class="sw-badge" :class="row.badge.kind" style="margin-left: auto"> - {{ row.badge.text }} - </span> - </RouterLink> - - <div class="sw-nav-section">Admin</div> - <RouterLink - v-for="row in admin" - :key="row.to" - :to="row.to" - class="sw-nav-item" - :class="{ 'is-active': isActive(row.to) }" - > - <Icon :name="row.icon" /><span>{{ row.label }}</span> - </RouterLink> + <template v-for="sec in sections" :key="sec.kicker"> + <div class="sw-nav-section">{{ sec.kicker }}</div> + <RouterLink + v-for="row in sec.links" + :key="row.to" + :to="row.to" + class="sw-nav-item" + :class="{ 'is-active': isActive(row.to) }" + > + <Icon :name="row.icon" /><span>{{ row.label }}</span> + <span v-if="row.badge" class="sw-badge" :class="row.badge.kind" style="margin-left: auto"> + {{ row.badge.text }} + </span> + </RouterLink> + </template> </nav> <div class="sw-side-foot"> @@ -274,4 +317,7 @@ const admin: NavRow[] = [ .sw-nav-item { text-decoration: none; } +.sw-nav-item.lead { + margin-top: 4px; +} </style> diff --git a/apps/ui/src/router/index.ts b/apps/ui/src/router/index.ts index d297819..cfdde91 100644 --- a/apps/ui/src/router/index.ts +++ b/apps/ui/src/router/index.ts @@ -85,16 +85,24 @@ function layerSubRoutes(): RouteRecordRaw[] { const shellRoutes: RouteRecordRaw[] = [ { path: '', name: 'home', component: () => import('@/views/landing/LandingView.vue') }, ...layerSubRoutes(), - // Operate (vantage-parity) — OAP runtime operations - { path: 'operate/alarms', component: placeholder, props: { title: 'Alarms', phase: 'Phase 5', note: 'Read-only; recovery is backend-auto. Live debug card via admin REST.' } }, + // Alerts (user-facing — alarms are observability data, not operator-only) + { path: 'alarms', component: placeholder, props: { title: 'Alarms', phase: 'Phase 5', note: 'Read-only; recovery is backend-auto. Live debug card via admin REST.' } }, + // Marketplace — all dashboards / templates across layers + { path: 'operate/marketplace', component: placeholder, props: { title: 'Marketplace', phase: 'Phase 2', note: 'All dashboard templates browse + clone + customize.' } }, + // Cluster { path: 'operate/cluster', component: placeholder, props: { title: 'Cluster status', phase: 'Phase 6 / 7', note: 'Module activity matrix · storage health · receiver activity · effective config tree · TTL grid.' } }, - { path: 'operate/dsl', component: placeholder, props: { title: 'DSL catalog', phase: 'Phase 6', note: 'MAL / LAL rule catalog + Monaco editor with diff and revert-to-bundled.' } }, - { path: 'operate/dsl/:catalog/:name', component: placeholder, props: (r) => ({ title: `Edit · ${r.params.name}`, phase: 'Phase 6' }) }, + // DSL Management + { path: 'operate/dsl/:catalog(otel-rules|telegraf-rules|lal|log-mal-rules)', component: placeholder, props: (r) => ({ title: `DSL · ${r.params.catalog}`, phase: 'Phase 6', note: 'Rule catalog grid + filter + new-rule form. Click a rule to open the editor.' }) }, + { path: 'operate/dsl/:catalog(otel-rules|telegraf-rules|lal|log-mal-rules)/:name', component: placeholder, props: (r) => ({ title: `Edit · ${r.params.name}`, phase: 'Phase 6', note: 'Monaco YAML + diff vs server + diff vs bundled + destructive-confirm.' }) }, + { path: 'operate/oal', component: placeholder, props: { title: 'OAL · read-only', phase: 'Phase 6', note: 'Line-numbered OAL files with jump-to-debugger on each rule.' } }, + // Inspect { path: 'operate/inspect', component: placeholder, props: { title: 'Inspect', phase: 'Phase 6', note: 'OAP metric catalog browse + MQE ad-hoc charts with rule attribution.' } }, - { path: 'operate/live-debug/:tab(mal|lal|oal)?', component: placeholder, props: (r) => ({ title: `Live debug · ${r.params.tab ?? 'mal'}`, phase: 'Phase 6' }) }, - { path: 'operate/oal', component: placeholder, props: { title: 'OAL viewer', phase: 'Phase 6', note: 'Read-only OAL files with line-numbered syntax highlighting.' } }, - { path: 'operate/dump', component: placeholder, props: { title: 'Dump', phase: 'Phase 6', note: 'Stream OAP runtime-rule dump as tar.gz.' } }, - // Admin (users + roles only; no audit log UI — BFF JSONL is server-side forensic only) + // Live debugger + { path: 'operate/live-debug/:tab(mal|lal|oal)?', component: placeholder, props: (r) => ({ title: `Live debugger · ${r.params.tab ?? 'mal'}`, phase: 'Phase 6' }) }, + { path: 'operate/live-debug/history', component: placeholder, props: { title: 'Capture history', phase: 'Phase 6', note: 'Local-only history of finished capture sessions.' } }, + // Dump + { path: 'operate/dump', component: placeholder, props: { title: 'Dump & restore', phase: 'Phase 6', note: 'Stream OAP runtime-rule dump as tar.gz. Restore is deferred (no OAP endpoint yet).' } }, + // Admin { path: 'admin/users', component: placeholder, props: { title: 'Users', phase: 'Phase 7' } }, { path: 'admin/roles', component: placeholder, props: { title: 'Roles & permissions', phase: 'Phase 7' } }, ];
