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 5f16170  ui sidebar: group header click cascades to first layer's 
first tab
5f16170 is described below

commit 5f161708d5ace2c42fcad578850689e8f5102554
Author: Wu Sheng <[email protected]>
AuthorDate: Sun May 17 11:19:01 2026 +0800

    ui sidebar: group header click cascades to first layer's first tab
    
    Group section headers ("Istio", "Self-Observability", "Platform
    monitoring") were inert labels — operators had to click the layer
    row first, then the tab, to reach a screen. Now clicking the
    header cascades two levels: pick the first layer in the group,
    expand it, navigate to its first tab. Matches the requested
    "group menu only has the first sub menu select (nested twice),
    then fire the real menu selection" behaviour.
    
    Visual affordance: clickable section headers get cursor: pointer
    + a fg-1 hover lift so they read as actionable, without breaking
    the L0 label voice (uppercase, fg-3).
---
 apps/ui/src/shell/AppSidebar.vue | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/apps/ui/src/shell/AppSidebar.vue b/apps/ui/src/shell/AppSidebar.vue
index 94194ce..8bd763b 100644
--- a/apps/ui/src/shell/AppSidebar.vue
+++ b/apps/ui/src/shell/AppSidebar.vue
@@ -147,6 +147,24 @@ function toggleLayer(key: string): void {
   }
 }
 
+/**
+ * Group-header click — cascade two levels: expand the first layer in
+ * the group AND navigate to its first tab. Mirrors the behaviour
+ * described as "for group menu, only the first sub menu select
+ * (nested twice), then fire the real menu selection". Without this
+ * the section labels were inert and the operator had to drill in via
+ * two clicks (layer → tab) instead of one (group).
+ */
+function pickGroupFirst(layers: SidebarLayer[]): void {
+  const first = layers[0];
+  if (!first) return;
+  const nav = layerNavByKey.value.get(first.key);
+  if (!nav) return;
+  expandedLayer.value = first.key;
+  if (route.path === nav.primaryTo) return;
+  void router.push(nav.primaryTo);
+}
+
 interface LayerGroup { kind: 'group'; label: string; layers: SidebarLayer[] }
 interface LayerSingle { kind: 'single'; layer: SidebarLayer }
 type SidebarEntry = LayerGroup | LayerSingle;
@@ -347,7 +365,10 @@ watch(
       </div>
       <template v-for="(E, ei) in sidebarEntries" :key="E.kind === 'group' ? 
`g:${E.label}` : `s:${E.layer.key}:${ei}`">
         <template v-if="E.kind === 'group'">
-          <div class="sw-nav-section sw-nav-section--icon">
+          <div
+            class="sw-nav-section sw-nav-section--icon 
sw-nav-section--clickable"
+            @click="pickGroupFirst(E.layers)"
+          >
             <Icon :name="sectionIcon(E.label)" />
             <span class="layer-group-name">{{ E.label }}</span>
           </div>
@@ -438,7 +459,10 @@ watch(
       </template>
 
       <template v-if="operateLayers.length > 0">
-        <div class="sw-nav-section sw-nav-section--icon">
+        <div
+          class="sw-nav-section sw-nav-section--icon sw-nav-section--clickable"
+          @click="pickGroupFirst(operateLayers)"
+        >
           <Icon :name="sectionIcon('Platform monitoring')" />
           <span>Platform monitoring</span>
         </div>
@@ -758,6 +782,16 @@ watch(
   color: var(--sw-fg-3);
   opacity: 1;
 }
+/* Clickable section header — cascades through the first child layer
+ * to its first tab. Hover lifts the text so the affordance reads. */
+.sw-nav-section--clickable {
+  cursor: pointer;
+  user-select: none;
+}
+.sw-nav-section--clickable:hover,
+.sw-nav-section--clickable:hover :deep(svg) {
+  color: var(--sw-fg-1);
+}
 .layer-group-name { flex: 1; min-width: 0; }
 /* Grouped and ungrouped layer rows sit at the same indent — the group
  * header already delineates the section, so no extra tree-style nest. */

Reply via email to