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
The following commit(s) were added to refs/heads/main by this push:
new 74b657d layer: drop overview cap; services is the default entry per
layer
74b657d is described below
commit 74b657d7d056fd288662fe2dd69b2a55e5bd1c61
Author: Wu Sheng <[email protected]>
AuthorDate: Tue May 12 15:09:48 2026 +0800
layer: drop overview cap; services is the default entry per layer
There's no per-layer Overview page. The global Overview at / already
composes all layers; visiting a layer means going straight to its
Services (or its renamed equivalent โ Workloads / Functions / Pages /
Clusters / Databases / Brokers).
- LayerCaps.overview removed from packages/api-client/menu.ts; BFF
LAYER_DEFAULTS scrubbed to match.
- BFF setup zod schema no longer accepts an 'overview' cap field.
- AppSidebar drops the per-layer Overview row; Services becomes the
first child under each expanded layer.
- Router: /layer/:layerKey now redirects to /layer/:layerKey/services
(the bare layer route was an orphan).
- Overview LayerLandingCard's 'View all' link points at the services
slot route.
---
apps/bff/src/oap/menu-routes.ts | 46 ++++++++++++-------------
apps/bff/src/setup/routes.ts | 1 -
apps/ui/src/components/shell/AppSidebar.vue | 11 +-----
apps/ui/src/router/index.ts | 10 +++---
apps/ui/src/views/overview/LayerLandingCard.vue | 2 +-
apps/ui/src/views/setup/LayerSetupCard.vue | 4 ++-
packages/api-client/src/menu.ts | 1 -
7 files changed, 32 insertions(+), 43 deletions(-)
diff --git a/apps/bff/src/oap/menu-routes.ts b/apps/bff/src/oap/menu-routes.ts
index 4d19cee..6f157fe 100644
--- a/apps/bff/src/oap/menu-routes.ts
+++ b/apps/bff/src/oap/menu-routes.ts
@@ -95,7 +95,7 @@ const LAYER_DEFAULTS: Record<string, { color: string; slots:
LayerSlots; caps: L
color: 'var(--sw-accent)',
slots: { services: 'Services', instances: 'Instances', endpoints: 'API',
endpointDependency: 'API dependency' },
caps: {
- overview: true, serviceMap: true, endpointDependency: true,
instanceTopology: true, processTopology: true,
+ serviceMap: true, endpointDependency: true, instanceTopology: true,
processTopology: true,
dashboards: true, traces: true, logs: true, profiling: true, events:
true,
},
},
@@ -103,36 +103,36 @@ const LAYER_DEFAULTS: Record<string, { color: string;
slots: LayerSlots; caps: L
color: 'var(--sw-info)',
slots: { services: 'Services', instances: 'Sidecars', endpoints:
'Endpoints' },
caps: {
- overview: true, serviceMap: true, endpointDependency: true,
instanceTopology: true,
+ serviceMap: true, endpointDependency: true, instanceTopology: true,
dashboards: true, traces: true, logs: true, events: true,
},
},
- MESH_CP: { color: 'var(--sw-info)', slots: { services: 'Control-plane
services' }, caps: { overview: true, dashboards: true } },
- MESH_DP: { color: 'var(--sw-info)', slots: { services: 'Data-plane
services', instances: 'Sidecars' }, caps: { overview: true, dashboards: true,
instanceTopology: true } },
- K8S: { color: 'var(--sw-purple)', slots: { services: 'Workloads', instances:
'Pods' }, caps: { overview: true, serviceMap: true, instanceTopology: true,
dashboards: true, events: true } },
- K8S_SERVICE: { color: 'var(--sw-purple)', slots: { services: 'K8s services',
instances: 'Pods' }, caps: { overview: true, serviceMap: true,
instanceTopology: true, dashboards: true } },
- BROWSER: { color: 'var(--sw-cyan)', slots: { services: 'Applications',
instances: 'Versions', endpoints: 'Pages' }, caps: { overview: true,
dashboards: true, traces: true, logs: true } },
- MYSQL: { color: 'var(--sw-warn)', slots: { services: 'Instances' }, caps: {
overview: true, dashboards: true } },
- POSTGRESQL: { color: 'var(--sw-warn)', slots: { services: 'Instances' },
caps: { overview: true, dashboards: true } },
- ELASTICSEARCH: { color: 'var(--sw-warn)', slots: { services: 'Clusters',
instances: 'Nodes' }, caps: { overview: true, dashboards: true } },
- REDIS: { color: 'var(--sw-warn)', slots: { services: 'Instances' }, caps: {
overview: true, dashboards: true } },
- MONGODB: { color: 'var(--sw-warn)', slots: { services: 'Clusters',
instances: 'Nodes' }, caps: { overview: true, dashboards: true } },
- CLICKHOUSE: { color: 'var(--sw-warn)', slots: { services: 'Services',
instances: 'Instances' }, caps: { overview: true, dashboards: true } },
- KAFKA: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers' }, caps: { overview: true, dashboards: true } },
- PULSAR: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers' }, caps: { overview: true, dashboards: true } },
- ROCKETMQ: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers', endpoints: 'Topics' }, caps: { overview: true, dashboards: true } },
- RABBITMQ: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Nodes' }, caps: { overview: true, dashboards: true } },
- ACTIVEMQ: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers', endpoints: 'Destinations' }, caps: { overview: true, dashboards:
true } },
- VIRTUAL_DATABASE: { color: 'var(--sw-warn)', slots: { services: 'Databases'
}, caps: { overview: true, dashboards: true } },
- VIRTUAL_CACHE: { color: 'var(--sw-warn)', slots: { services: 'Caches' },
caps: { overview: true, dashboards: true } },
- VIRTUAL_MQ: { color: 'var(--sw-ok)', slots: { services: 'Queues' }, caps: {
overview: true, dashboards: true } },
- VIRTUAL_GENAI: { color: 'var(--sw-purple)', slots: { services: 'Providers',
instances: 'Models' }, caps: { overview: true, dashboards: true } },
+ MESH_CP: { color: 'var(--sw-info)', slots: { services: 'Control-plane
services' }, caps: { dashboards: true } },
+ MESH_DP: { color: 'var(--sw-info)', slots: { services: 'Data-plane
services', instances: 'Sidecars' }, caps: { dashboards: true, instanceTopology:
true } },
+ K8S: { color: 'var(--sw-purple)', slots: { services: 'Workloads', instances:
'Pods' }, caps: { serviceMap: true, instanceTopology: true, dashboards: true,
events: true } },
+ K8S_SERVICE: { color: 'var(--sw-purple)', slots: { services: 'K8s services',
instances: 'Pods' }, caps: { serviceMap: true, instanceTopology: true,
dashboards: true } },
+ BROWSER: { color: 'var(--sw-cyan)', slots: { services: 'Applications',
instances: 'Versions', endpoints: 'Pages' }, caps: { dashboards: true, traces:
true, logs: true } },
+ MYSQL: { color: 'var(--sw-warn)', slots: { services: 'Instances' }, caps: {
dashboards: true } },
+ POSTGRESQL: { color: 'var(--sw-warn)', slots: { services: 'Instances' },
caps: { dashboards: true } },
+ ELASTICSEARCH: { color: 'var(--sw-warn)', slots: { services: 'Clusters',
instances: 'Nodes' }, caps: { dashboards: true } },
+ REDIS: { color: 'var(--sw-warn)', slots: { services: 'Instances' }, caps: {
dashboards: true } },
+ MONGODB: { color: 'var(--sw-warn)', slots: { services: 'Clusters',
instances: 'Nodes' }, caps: { dashboards: true } },
+ CLICKHOUSE: { color: 'var(--sw-warn)', slots: { services: 'Services',
instances: 'Instances' }, caps: { dashboards: true } },
+ KAFKA: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers' }, caps: { dashboards: true } },
+ PULSAR: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers' }, caps: { dashboards: true } },
+ ROCKETMQ: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers', endpoints: 'Topics' }, caps: { dashboards: true } },
+ RABBITMQ: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Nodes' }, caps: { dashboards: true } },
+ ACTIVEMQ: { color: 'var(--sw-ok)', slots: { services: 'Clusters', instances:
'Brokers', endpoints: 'Destinations' }, caps: { dashboards: true } },
+ VIRTUAL_DATABASE: { color: 'var(--sw-warn)', slots: { services: 'Databases'
}, caps: { dashboards: true } },
+ VIRTUAL_CACHE: { color: 'var(--sw-warn)', slots: { services: 'Caches' },
caps: { dashboards: true } },
+ VIRTUAL_MQ: { color: 'var(--sw-ok)', slots: { services: 'Queues' }, caps: {
dashboards: true } },
+ VIRTUAL_GENAI: { color: 'var(--sw-purple)', slots: { services: 'Providers',
instances: 'Models' }, caps: { dashboards: true } },
};
const DEFAULT_FOR_UNKNOWN_LAYER = {
color: 'var(--sw-fg-2)',
slots: { services: 'Services' } as LayerSlots,
- caps: { overview: true, dashboards: true } as LayerCaps,
+ caps: {dashboards: true } as LayerCaps,
};
function deriveLayer(
diff --git a/apps/bff/src/setup/routes.ts b/apps/bff/src/setup/routes.ts
index 03efc4b..df0e5a5 100644
--- a/apps/bff/src/setup/routes.ts
+++ b/apps/bff/src/setup/routes.ts
@@ -70,7 +70,6 @@ const layerConfigSchema = z
.strict(),
caps: z
.object({
- overview: z.boolean().optional(),
serviceMap: z.boolean().optional(),
endpointDependency: z.boolean().optional(),
instanceTopology: z.boolean().optional(),
diff --git a/apps/ui/src/components/shell/AppSidebar.vue
b/apps/ui/src/components/shell/AppSidebar.vue
index 2c9b254..b207468 100644
--- a/apps/ui/src/components/shell/AppSidebar.vue
+++ b/apps/ui/src/components/shell/AppSidebar.vue
@@ -174,20 +174,11 @@ const sections: NavSection[] = [
</span>
</div>
<div v-if="expandedLayer === L.key" class="layer-children">
- <RouterLink
- v-if="L.caps.overview"
- :to="`/layer/${L.key}`"
- class="sw-nav-item"
- :class="{ 'is-active': isActive(`/layer/${L.key}`) && route.path
=== `/layer/${L.key}` }"
- >
- <Icon name="dash" /><span>Overview</span>
- </RouterLink>
-
<RouterLink
v-if="L.slots.services"
:to="`/layer/${L.key}/services`"
class="sw-nav-item"
- :class="{ 'is-active': isActive(`/layer/${L.key}/services`) }"
+ :class="{ 'is-active': isActive(`/layer/${L.key}/services`) ||
route.path === `/layer/${L.key}` }"
>
<Icon name="svc" /><span>{{ L.slots.services }}</span>
<span class="sw-badge" style="margin-left: auto">{{ L.serviceCount
}}</span>
diff --git a/apps/ui/src/router/index.ts b/apps/ui/src/router/index.ts
index e81da7a..3fc988d 100644
--- a/apps/ui/src/router/index.ts
+++ b/apps/ui/src/router/index.ts
@@ -29,14 +29,12 @@ function humanKey(k: string): string {
// only needs the raw key + the feature label.
function layerSubRoutes(): RouteRecordRaw[] {
const sub: RouteRecordRaw[] = [];
+ // Bare /layer/:layerKey redirects to /layer/:layerKey/services โ the
+ // default entry point per layer. There is no per-layer 'overview'
+ // (the global Overview at / handles that).
sub.push({
path: 'layer/:layerKey',
- component: placeholder,
- props: (r) => ({
- title: `${humanKey(String(r.params.layerKey))} ยท Overview`,
- phase: 'Phase 2',
- note: 'Per-layer landing: KPIs, throughput, service constellation,
services table.',
- }),
+ redirect: (to) => ({ path: `/layer/${to.params.layerKey}/services` }),
});
const features: { path: string; label: string; phase: string }[] = [
diff --git a/apps/ui/src/views/overview/LayerLandingCard.vue
b/apps/ui/src/views/overview/LayerLandingCard.vue
index 43f08d9..308e08a 100644
--- a/apps/ui/src/views/overview/LayerLandingCard.vue
+++ b/apps/ui/src/views/overview/LayerLandingCard.vue
@@ -26,7 +26,7 @@ const props = defineProps<{ layer: LayerDef }>();
const store = useSetupStore();
const cfg = computed(() => store.ensure(props.layer.key, { slots:
props.layer.slots, caps: props.layer.caps }));
const slotName = computed(() => cfg.value.slots.services ?? 'Services');
-const detailHref = computed(() => `/layer/${props.layer.key}`);
+const detailHref = computed(() => `/layer/${props.layer.key}/services`);
</script>
<template>
diff --git a/apps/ui/src/views/setup/LayerSetupCard.vue
b/apps/ui/src/views/setup/LayerSetupCard.vue
index 1176b87..3f30c48 100644
--- a/apps/ui/src/views/setup/LayerSetupCard.vue
+++ b/apps/ui/src/views/setup/LayerSetupCard.vue
@@ -55,7 +55,9 @@ const summary = computed<string>(() => {
return base;
});
-// Default cap labels with the "Topology" trio collapsed for compact display.
+// Cap rows the operator can toggle. The per-layer page always opens on
+// Services โ there's no `overview` cap; the global Overview already
+// composes layers automatically.
const capRows: Array<{ key: keyof typeof cfg.value.caps; label: string }> = [
{ key: 'serviceMap', label: 'Service map' },
{ key: 'endpointDependency', label: 'API dependency' },
diff --git a/packages/api-client/src/menu.ts b/packages/api-client/src/menu.ts
index 640dbc4..a8cfec2 100644
--- a/packages/api-client/src/menu.ts
+++ b/packages/api-client/src/menu.ts
@@ -39,7 +39,6 @@ export interface LayerSlots {
}
export interface LayerCaps {
- overview?: boolean;
serviceMap?: boolean;
endpointDependency?: boolean;
instanceTopology?: boolean;