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 420cd00  admin: components editor — toggle which per-layer views exist
420cd00 is described below

commit 420cd00a97dfc87310e4f6da3136bc016d27f8e7
Author: Wu Sheng <[email protected]>
AuthorDate: Tue May 12 22:24:58 2026 +0800

    admin: components editor — toggle which per-layer views exist
    
    Replace the read-only component chip row with an editable toggle
    grid. Each tile binds to a key on the template's components block;
    flipping it shows / hides the matching sidebar entry + per-layer
    route. Save writes the JSON template; the BFF reloads its cache so
    the layer page reflects the new components on next refresh.
    
    Toggles (with hint tooltips on hover):
      Service              dashboards.service widget grid
      Instances            dashboards.instance widget grid
      Endpoints            dashboards.endpoint widget grid
      API dependency       Phase 4
      Topology             Phase 4
      Traces               Phase 5
      Logs                 Phase 5
      Profiling            Phase 8
---
 apps/ui/src/views/admin/LayerDashboardsAdmin.vue | 120 ++++++++++++++++++++---
 1 file changed, 107 insertions(+), 13 deletions(-)

diff --git a/apps/ui/src/views/admin/LayerDashboardsAdmin.vue 
b/apps/ui/src/views/admin/LayerDashboardsAdmin.vue
index fb30e9d..f789761 100644
--- a/apps/ui/src/views/admin/LayerDashboardsAdmin.vue
+++ b/apps/ui/src/views/admin/LayerDashboardsAdmin.vue
@@ -209,18 +209,33 @@ function deleteMetricColumn(i: number): void {
   draft.template.metrics.columns.splice(i, 1);
 }
 
-function componentFlags(t: AdminLayerTemplate): string[] {
-  const c = t.components;
-  const out: string[] = [];
-  if (c.service) out.push('service');
-  if (c.instances) out.push('instances');
-  if (c.endpoints) out.push('endpoints');
-  if (c.endpointDependency) out.push('api dependency');
-  if (c.topology) out.push('topology');
-  if (c.traces) out.push('traces');
-  if (c.logs) out.push('logs');
-  if (c.profiling) out.push('profiling');
-  return out;
+/**
+ * Component toggles surfaced in the admin editor. Each entry binds to
+ * a key on the template's `components` block; flipping the toggle
+ * shows / hides the matching sidebar entry + per-layer route.
+ */
+type ComponentKey = keyof AdminLayerTemplate['components'];
+const COMPONENT_TOGGLES: Array<{ key: ComponentKey; label: string; hint: 
string }> = [
+  { key: 'service', label: 'Service', hint: "The layer's primary landing — 
widget grid driven by dashboards.service." },
+  { key: 'instances', label: 'Instances', hint: 'Per-instance dashboard 
(dashboards.instance widget set).' },
+  { key: 'endpoints', label: 'Endpoints', hint: 'Per-endpoint dashboard 
(dashboards.endpoint widget set).' },
+  { key: 'endpointDependency', label: 'API dependency', hint: 
'Endpoint-to-endpoint dependency view (Phase 4).' },
+  { key: 'topology', label: 'Topology', hint: 'Service topology graph for this 
layer (Phase 4).' },
+  { key: 'traces', label: 'Traces', hint: 'Trace explorer scoped to this layer 
(Phase 5).' },
+  { key: 'logs', label: 'Logs', hint: 'Log explorer scoped to this layer 
(Phase 5).' },
+  { key: 'profiling', label: 'Profiling', hint: 'Flame graphs / sampled stacks 
(Phase 8).' },
+];
+
+function ensureComponents(): AdminLayerTemplate['components'] {
+  if (!draft.template) throw new Error('no template selected');
+  if (!draft.template.components) {
+    (draft.template as AdminLayerTemplate).components = {};
+  }
+  return draft.template.components;
+}
+function toggleComponent(key: ComponentKey): void {
+  const c = ensureComponents();
+  c[key] = !c[key];
 }
 </script>
 
@@ -269,7 +284,6 @@ function componentFlags(t: AdminLayerTemplate): string[] {
               <h2>{{ selectedTpl.alias || selectedTpl.key }}</h2>
               <div class="meta">
                 <code>{{ selectedTpl.key }}</code>
-                <span v-for="c in componentFlags(selectedTpl)" :key="c" 
class="chip on">{{ c }}</span>
               </div>
             </div>
             <div class="actions">
@@ -294,6 +308,33 @@ function componentFlags(t: AdminLayerTemplate): string[] {
           </div>
         </section>
 
+        <!-- Components editor: which per-layer views exist. Each
+             toggle controls a sidebar entry + a route + (where the
+             component is service / instance / endpoint) the matching
+             dashboards.<scope> widget set. -->
+        <section class="sw-card components-card">
+          <div class="card-head">
+            <h4>Components</h4>
+            <span class="sub">which sub-views this layer exposes</span>
+          </div>
+          <div class="comp-grid">
+            <label
+              v-for="t in COMPONENT_TOGGLES"
+              :key="t.key"
+              class="comp-toggle"
+              :class="{ on: !!selectedTpl.components?.[t.key] }"
+              :title="t.hint"
+            >
+              <input
+                type="checkbox"
+                :checked="!!selectedTpl.components?.[t.key]"
+                @change="toggleComponent(t.key)"
+              />
+              <span class="comp-label">{{ t.label }}</span>
+            </label>
+          </div>
+        </section>
+
         <!-- Metrics editor (the layer's summary KPI columns + the
              orderBy / throughput / spark selectors). These drive the
              Overview KPI tile and the per-layer header summary. -->
@@ -679,6 +720,59 @@ function componentFlags(t: AdminLayerTemplate): string[] {
 }
 .scope-tab.on .count { color: var(--sw-accent-2); }
 
+.components-card { padding: 0; }
+.components-card .card-head {
+  display: flex;
+  align-items: baseline;
+  gap: 10px;
+  padding: 10px 14px;
+  border-bottom: 1px solid var(--sw-line);
+}
+.components-card .card-head h4 {
+  margin: 0;
+  font-size: 12px;
+  font-weight: 600;
+  color: var(--sw-fg-0);
+}
+.components-card .card-head .sub {
+  font-size: 10.5px;
+  color: var(--sw-fg-3);
+}
+.comp-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
+  gap: 6px;
+  padding: 12px 14px;
+}
+.comp-toggle {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  font-size: 11.5px;
+  color: var(--sw-fg-2);
+  padding: 6px 10px;
+  background: var(--sw-bg-2);
+  border: 1px solid var(--sw-line-2);
+  border-radius: 4px;
+  cursor: pointer;
+  user-select: none;
+}
+.comp-toggle:hover {
+  background: var(--sw-bg-3);
+}
+.comp-toggle.on {
+  background: var(--sw-accent-soft);
+  border-color: var(--sw-accent-line);
+  color: var(--sw-accent-2);
+}
+.comp-toggle input {
+  accent-color: var(--sw-accent);
+  margin: 0;
+}
+.comp-label {
+  font-weight: 500;
+}
+
 .metrics-card { padding: 0; }
 .metrics-card .card-head .add {
   margin-left: auto;

Reply via email to