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 d5e617a overview: drop landing.enabled toggle — every reporting layer
auto-renders
d5e617a is described below
commit d5e617ad3320187ca867e6e9b6e4fc2305c26931
Author: Wu Sheng <[email protected]>
AuthorDate: Tue May 12 14:35:25 2026 +0800
overview: drop landing.enabled toggle — every reporting layer auto-renders
The Overview is a pure composition of all available layers' configs,
ordered by priority. No on/off switch. Setup moves under Admin as
'Overview setup' since it is a global admin/customization feature.
- Removed LandingConfig.enabled and useLandingLayers; Overview now
iterates useLandingOrder(availableLayers) directly.
- LayerSetupCard drops the 'Show on landing' toggle; replaced with a
priority chip in the header.
- Sidebar removes the lead 'Setup' link; Admin section adds
'Overview setup' → /setup.
- SetupView KPI 'On landing' removed; filter tabs drop the 'On landing'
facet. Footer lists layers in priority order with the priority value.
---
apps/ui/src/components/shell/AppSidebar.vue | 12 +-------
apps/ui/src/composables/useLandingOrder.ts | 14 ++-------
apps/ui/src/stores/setup.ts | 10 ++++--
apps/ui/src/views/overview/OverviewView.vue | 36 ++++++++++------------
apps/ui/src/views/setup/LayerSetupCard.vue | 28 ++++++++---------
apps/ui/src/views/setup/SetupView.vue | 48 ++++++++++++-----------------
6 files changed, 59 insertions(+), 89 deletions(-)
diff --git a/apps/ui/src/components/shell/AppSidebar.vue
b/apps/ui/src/components/shell/AppSidebar.vue
index bd054ee..2c9b254 100644
--- a/apps/ui/src/components/shell/AppSidebar.vue
+++ b/apps/ui/src/components/shell/AppSidebar.vue
@@ -71,10 +71,6 @@ interface NavSection {
// One leading row before the Layers block — the cross-layer landing.
const overview: NavRow = { icon: 'dash', label: 'Overview', to: '/' };
-// Setup sits next to Overview as a leading link too — operators bounce
-// between these two during initial configuration.
-const setup: NavRow = { icon: 'set', label: 'Setup', to: '/setup' };
-
// 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).
@@ -121,6 +117,7 @@ const sections: NavSection[] = [
{
kicker: 'Admin',
links: [
+ { icon: 'set', label: 'Overview setup', to: '/setup' },
{ icon: 'user', label: 'Users', to: '/admin/users' },
{ icon: 'set', label: 'Roles', to: '/admin/roles' },
],
@@ -143,13 +140,6 @@ const sections: NavSection[] = [
>
<Icon :name="overview.icon" /><span>{{ overview.label }}</span>
</RouterLink>
- <RouterLink
- :to="setup.to"
- class="sw-nav-item lead"
- :class="{ 'is-active': isActive(setup.to) }"
- >
- <Icon :name="setup.icon" /><span>{{ setup.label }}</span>
- </RouterLink>
<div class="sw-nav-section sw-row" style="justify-content:
space-between">
<span>Layers</span>
diff --git a/apps/ui/src/composables/useLandingOrder.ts
b/apps/ui/src/composables/useLandingOrder.ts
index 2f5f78f..d111c57 100644
--- a/apps/ui/src/composables/useLandingOrder.ts
+++ b/apps/ui/src/composables/useLandingOrder.ts
@@ -40,14 +40,6 @@ export function useLandingOrder(layers: ComputedRef<readonly
LayerDef[]>) {
});
}
-/** Layers that opted in to the landing (`landing.enabled === true`),
- * sorted by priority. Drives the Overview's card list. */
-export function useLandingLayers(layers: ComputedRef<readonly LayerDef[]>) {
- const store = useSetupStore();
- const ordered = useLandingOrder(layers);
- return computed<LayerDef[]>(() =>
- ordered.value.filter(
- (L) => store.ensure(L.key, { slots: L.slots, caps: L.caps
}).landing.enabled,
- ),
- );
-}
+// (Removed `useLandingLayers` — every available layer is automatically on
+// the landing. The Overview just consumes `useLandingOrder(availableLayers)`
+// directly.)
diff --git a/apps/ui/src/stores/setup.ts b/apps/ui/src/stores/setup.ts
index 1fa4d34..752db37 100644
--- a/apps/ui/src/stores/setup.ts
+++ b/apps/ui/src/stores/setup.ts
@@ -19,9 +19,14 @@ import { defineStore } from 'pinia';
import { reactive } from 'vue';
import type { LayerCaps, LayerSlots } from '@skywalking-horizon-ui/api-client';
-/** Per-layer landing-card configuration. See
docs/design/landing-composition.md. */
+/** Per-layer landing-card configuration. See
docs/design/landing-composition.md.
+ *
+ * Every available layer (one with services reporting) appears on the
+ * landing automatically. There is intentionally NO `enabled` toggle — the
+ * landing is the auto-composition of all layers' configs. Operators
+ * adjust HOW each layer renders (priority, topN, columns, style); the
+ * only way to suppress a layer is to disable its features in `caps`. */
export interface LandingConfig {
- enabled: boolean;
/** Lower number → higher on the page. Defaults seeded from priority table.
*/
priority: number;
/** 5..8. */
@@ -70,7 +75,6 @@ function defaultColumns(_layerKey: string):
LandingConfig['columns'] {
export function defaultLandingFor(layerKey: string): LandingConfig {
return {
- enabled: false, // operator opts-in per layer in the setup page
priority: defaultPriority(layerKey),
topN: 5,
orderBy: 'cpm',
diff --git a/apps/ui/src/views/overview/OverviewView.vue
b/apps/ui/src/views/overview/OverviewView.vue
index e8df152..4155725 100644
--- a/apps/ui/src/views/overview/OverviewView.vue
+++ b/apps/ui/src/views/overview/OverviewView.vue
@@ -18,15 +18,15 @@
import { computed } from 'vue';
import { RouterLink } from 'vue-router';
import { useLayers } from '@/composables/useLayers';
-import { useLandingLayers } from '@/composables/useLandingOrder';
+import { useLandingOrder } from '@/composables/useLandingOrder';
import LayerLandingCard from './LayerLandingCard.vue';
const { availableLayers, oapReachable, oapError, isLoading } = useLayers();
-const enabledLayers = useLandingLayers(availableLayers);
+const orderedLayers = useLandingOrder(availableLayers);
-// "No one opted in yet" → guide the operator to Setup before anything
-// useful can render.
-const empty = computed(() => !isLoading.value && enabledLayers.value.length
=== 0);
+// Empty only when no layer is reporting services. Otherwise every
+// available layer auto-renders a card per its setup config.
+const empty = computed(() => !isLoading.value && orderedLayers.value.length
=== 0);
</script>
<template>
@@ -36,9 +36,10 @@ const empty = computed(() => !isLoading.value &&
enabledLayers.value.length ===
<div class="kicker">Overview</div>
<h1>Cross-layer landing</h1>
<p class="lede">
- Auto-built from the layers you've enabled in
- <RouterLink to="/setup">Setup</RouterLink>, in the order each
layer's priority defines.
- Each card shows the top services for that layer with its configured
metrics.
+ Every layer reporting services renders a card here, in the order
each layer's priority
+ defines. Each card shows the top services for that layer with its
configured metrics —
+ adjust per-layer priority, top-N, and columns in
+ <RouterLink to="/setup">Overview setup</RouterLink>.
</p>
</div>
</header>
@@ -50,25 +51,20 @@ const empty = computed(() => !isLoading.value &&
enabledLayers.value.length ===
<div v-if="empty" class="empty">
<div class="empty-card">
- <h2>Nothing on the landing yet</h2>
- <p v-if="availableLayers.length === 0">
- No layer is reporting services right now. Once data starts flowing
through OAP, the
- layers appear in <RouterLink to="/setup">Setup</RouterLink> for you
to enable here.
- </p>
- <p v-else>
- {{ availableLayers.length }} layer{{ availableLayers.length === 1 ?
'' : 's' }} reporting,
- none enabled on the landing yet. Open <RouterLink
to="/setup">Setup</RouterLink>, toggle
- "Show this layer on the landing" for the ones you care about, and
they'll appear here in
- priority order.
+ <h2>No layer is reporting services yet</h2>
+ <p>
+ Once data starts flowing through OAP, every reporting layer appears
here automatically,
+ ordered by the priority you assign in
+ <RouterLink to="/setup">Overview setup</RouterLink>.
</p>
<RouterLink class="sw-btn is-primary" to="/setup">
- Open Setup
+ Open Overview setup
</RouterLink>
</div>
</div>
<div v-else class="cards">
- <LayerLandingCard v-for="L in enabledLayers" :key="L.key" :layer="L" />
+ <LayerLandingCard v-for="L in orderedLayers" :key="L.key" :layer="L" />
</div>
</div>
</template>
diff --git a/apps/ui/src/views/setup/LayerSetupCard.vue
b/apps/ui/src/views/setup/LayerSetupCard.vue
index 127f881..e83a782 100644
--- a/apps/ui/src/views/setup/LayerSetupCard.vue
+++ b/apps/ui/src/views/setup/LayerSetupCard.vue
@@ -38,15 +38,14 @@ function resetThisLayer(): void {
const summary = computed<string>(() => {
const c = cfg.value;
- if (!c.landing.enabled) {
- return props.layer.active
- ? 'Hidden from landing — toggle to show'
- : `${props.layer.name} has no data yet — set up a receiver to start
ingesting`;
- }
const cols = c.landing.columns.map((x) => x.metric).join(', ');
- return `Top ${c.landing.topN} by ${c.landing.orderBy} · ${cols}${
+ const base = `Top ${c.landing.topN} by ${c.landing.orderBy} · ${cols}${
c.landing.spark ? ` · sparkline ${c.landing.spark.metric}` : ''
} · priority ${c.landing.priority}`;
+ if (!props.layer.active) {
+ return `${base} · no service reporting yet`;
+ }
+ return base;
});
// Default cap labels with the "Topology" trio collapsed for compact display.
@@ -94,9 +93,10 @@ const headerColor = computed(() => props.layer.color);
const isDefaultLanding = computed(() => {
const d = defaultLandingFor(props.layer.key);
return (
- !cfg.value.landing.enabled &&
cfg.value.landing.priority === d.priority &&
- cfg.value.landing.topN === d.topN
+ cfg.value.landing.topN === d.topN &&
+ cfg.value.landing.orderBy === d.orderBy &&
+ cfg.value.landing.columns.length === d.columns.length
);
});
</script>
@@ -108,8 +108,10 @@ const isDefaultLanding = computed(() => {
<span class="name">{{ cfg.displayName || layer.name }}</span>
<span v-if="layer.active" class="sw-badge ok dot-mark">{{
layer.serviceCount >= 0 ? `${layer.serviceCount} services` : 'active' }}</span>
<span v-else class="sw-badge">no data</span>
- <span v-if="cfg.landing.enabled" class="sw-badge info"
style="margin-left: auto">on landing</span>
- <span v-else-if="!isDefaultLanding" class="sw-badge" style="margin-left:
auto">customized</span>
+ <span class="sw-badge info" style="margin-left: auto" title="Priority on
the Overview">
+ ↑ {{ cfg.landing.priority }}
+ </span>
+ <span v-if="!isDefaultLanding" class="sw-badge">customized</span>
<span class="caret" :class="{ open }"><Icon name="caret" :size="12"
/></span>
</div>
<div class="summary">{{ summary }}</div>
@@ -154,12 +156,8 @@ const isDefaultLanding = computed(() => {
<section>
<h4>Landing card</h4>
<div class="field-grid landing">
- <label class="wide">
- <input type="checkbox" v-model="cfg.landing.enabled" />
- <span>Show this layer on the landing</span>
- </label>
<label>
- <span>Priority</span>
+ <span>Priority (lower = higher on page)</span>
<input type="number" v-model.number="cfg.landing.priority" min="0"
max="99" />
</label>
<label>
diff --git a/apps/ui/src/views/setup/SetupView.vue
b/apps/ui/src/views/setup/SetupView.vue
index eff3230..361278b 100644
--- a/apps/ui/src/views/setup/SetupView.vue
+++ b/apps/ui/src/views/setup/SetupView.vue
@@ -29,17 +29,9 @@ const store = useSetupStore();
// configure layers ahead of receivers coming online.
const orderedLayers = useLandingOrder(layers);
-const enabledOnLanding = computed(() =>
- orderedLayers.value.filter((L) => store.ensure(L.key, { slots: L.slots,
caps: L.caps }).landing.enabled),
-);
-
-const filter = ref<'all' | 'active' | 'enabled'>('all');
+const filter = ref<'all' | 'active'>('all');
const visibleLayers = computed(() => {
if (filter.value === 'active') return orderedLayers.value.filter((L) =>
L.active);
- if (filter.value === 'enabled')
- return orderedLayers.value.filter((L) =>
- store.ensure(L.key, { slots: L.slots, caps: L.caps }).landing.enabled,
- );
return orderedLayers.value;
});
</script>
@@ -48,13 +40,13 @@ const visibleLayers = computed(() => {
<div class="setup">
<header class="page-head">
<div>
- <div class="kicker">Setup</div>
- <h1>Configure layers and the landing page</h1>
+ <div class="kicker">Admin · Overview setup</div>
+ <h1>Configure how each layer renders on the Overview</h1>
<p class="lede">
- Each detected layer can appear on the landing as its own card with
the top services and a
- set of metrics. Pick which layers show up, set their priority,
choose the columns, and
- rename slots if the default terms don't fit. Inactive layers (no
data) can still be
- configured — they appear once their receiver starts reporting.
+ Every layer reporting services appears on the Overview automatically
— no enable toggle.
+ Use this page to set per-layer <strong>priority</strong>, choose the
metric columns,
+ rename the entity slots, and toggle features. Inactive layers (no
data yet) can still be
+ configured; their card appears as soon as a service starts reporting.
</p>
</div>
<div class="kpi-strip">
@@ -63,13 +55,9 @@ const visibleLayers = computed(() => {
<span class="kpi-value">{{ layers.length }}</span>
</div>
<div class="kpi">
- <span class="kpi-label">Active</span>
+ <span class="kpi-label">Reporting</span>
<span class="kpi-value">{{ layers.filter((L) => L.active).length
}}</span>
</div>
- <div class="kpi">
- <span class="kpi-label">On landing</span>
- <span class="kpi-value">{{ enabledOnLanding.length }}</span>
- </div>
</div>
</header>
@@ -98,10 +86,7 @@ const visibleLayers = computed(() => {
All <span class="count">{{ orderedLayers.length }}</span>
</button>
<button class="seg-btn" :class="{ on: filter === 'active' }"
@click="filter = 'active'">
- Active <span class="count">{{ layers.filter((L) =>
L.active).length }}</span>
- </button>
- <button class="seg-btn" :class="{ on: filter === 'enabled' }"
@click="filter = 'enabled'">
- On landing <span class="count">{{ enabledOnLanding.length }}</span>
+ Reporting <span class="count">{{ layers.filter((L) =>
L.active).length }}</span>
</button>
</div>
</div>
@@ -112,14 +97,19 @@ const visibleLayers = computed(() => {
<footer class="page-foot">
<div class="foot-left">
- <strong>{{ enabledOnLanding.length }}</strong> layer(s) enabled on
the landing,
- in priority order:
- <span v-for="(L, i) in enabledOnLanding" :key="L.key"
class="chip-name">
- {{ L.name }}<span v-if="i < enabledOnLanding.length - 1">,</span>
+ <strong>{{ orderedLayers.length }}</strong> layer(s) in this
deployment,
+ rendered on the Overview in priority order:
+ <span v-for="(L, i) in orderedLayers.slice(0, 8)" :key="L.key"
class="chip-name">
+ {{ L.name }} ({{ store.ensure(L.key, { slots: L.slots, caps:
L.caps }).landing.priority }})<span
+ v-if="i < Math.min(orderedLayers.length, 8) - 1"
+ >,</span>
</span>
+ <span v-if="orderedLayers.length > 8">…</span>
</div>
<div class="foot-right">
- <span class="hint">Persistence wires in at Stage 2.4. For now,
changes live in this tab only.</span>
+ <span class="hint">
+ Persistence wires in at Stage 2.4. For now, changes live in this
tab only.
+ </span>
</div>
</footer>
</template>