]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: add reusable carbon popover 64388/head
authorNaman Munet <naman.munet@ibm.com>
Tue, 8 Jul 2025 15:26:34 +0000 (20:56 +0530)
committerNaman Munet <naman.munet@ibm.com>
Thu, 31 Jul 2025 12:33:23 +0000 (18:03 +0530)
https://tracker.ceph.com/issues/72002

Signed-off-by: Naman Munet <naman.munet@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-sync-data-info/rgw-sync-data-info.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-sync-metadata-info/rgw-sync-metadata-info.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/enum/cd-helper.enum.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/styles/_carbon-defaults.scss

index 85a7333437e0a8eb49e76f9c5b567569531bffc1..440986c535aadccaf937ecfa451a0ee4c277fd2f 100644 (file)
@@ -58,7 +58,9 @@
             </i>
             </div>
             <div cdsToggletipContent>
-              <cd-health-checks [healthData]="healthData.health.checks"></cd-health-checks>
+              <div class="cds--popover-scroll-container">
+                <cd-health-checks [healthData]="healthData.health.checks"></cd-health-checks>
+              </div>
             </div>
           </cds-toggletip>
         </ng-template>
index baa80cb41eb4bd7c6ab05e28babc38bcc183d812..c4b8ec5e7cb26bab84fb3514bf303e01997040f7 100644 (file)
               </div>
               <div cdsToggletipContent
                    #healthCheck>
-                <cd-health-checks *ngIf="healthData?.health?.checks"
-                                  [healthData]="healthData.health.checks">
-                </cd-health-checks>
+                <div class="cds--popover-scroll-container">
+                  <cd-health-checks *ngIf="healthData?.health?.checks"
+                                    [healthData]="healthData.health.checks">
+                  </cd-health-checks>
+                </div>
               </div>
             </cds-toggletip>
           </div>
index 18ceaf85672f2ebb6e7c2a5fd979ee98aae736ed..b015c7323361e6a8f02dfa592f5ff0882ea33863 100644 (file)
@@ -28,7 +28,9 @@
             </span>
           </div>
           <div cdsToggletipContent>
-            <cd-health-checks [healthData]="healthData"></cd-health-checks>
+            <div class="cds--popover-scroll-container">
+              <cd-health-checks [healthData]="healthData"></cd-health-checks>
+            </div>
           </div>
         </cds-toggletip>
       </ng-container>
         </cd-health-pie>
         </div>
         <cds-popover-content>
-        <ng-container *ngTemplateOutlet="logsLink"></ng-container>
-          <ul>
-            <li *ngFor="let pgStatesText of healthData.pg_info.statuses | keyvalue">
-             {{ pgStatesText.key }}: {{ pgStatesText.value }}
-            </li>
-          </ul>
+          <div class="cds--popover-scroll-container">
+            <ng-container *ngTemplateOutlet="logsLink"></ng-container>
+            <ul>
+              <li *ngFor="let pgStatesText of healthData.pg_info.statuses | keyvalue">
+              {{ pgStatesText.key }}: {{ pgStatesText.value }}
+              </li>
+            </ul>
+          </div>
         </cds-popover-content>
       </div>
     </cd-info-card>
index cbf9b033792a3749d3340fd5f98f14ce23f58fa1..920a548f50b0428363f8a7b4ca52884f3a51a11f 100644 (file)
     </li>
   </div>
   <div cdsToggletipContent>
-    <ul class="text-center">
-      <li><h5><b i18n>Sync Status:</b></h5></li>
-      <li *ngFor="let status of zone.fullSyncStatus">
-        <span *ngIf="!status?.includes(zone.name) && !status?.includes(zone.syncstatus) && !status?.includes('failed') && !status?.includes('error')">
-          <span *ngIf="status?.includes(':')">
-            <b>{{ status.split(': ')[0] | titlecase }}</b>:{{ status.split(': ')[1] | titlecase}}
+    <div class="cds--popover-scroll-container">
+      <ul class="text-center">
+        <li><h5><b i18n>Sync Status:</b></h5></li>
+        <li *ngFor="let status of zone.fullSyncStatus">
+          <span *ngIf="!status?.includes(zone.name) && !status?.includes(zone.syncstatus) && !status?.includes('failed') && !status?.includes('error')">
+            <span *ngIf="status?.includes(':')">
+              <b>{{ status.split(': ')[0] | titlecase }}</b>:{{ status.split(': ')[1] | titlecase}}
+            </span>
+            <span *ngIf="!status?.includes(':')">
+              <b>{{ status | titlecase }}</b>
+            </span>
           </span>
-          <span *ngIf="!status?.includes(':')">
-            <b>{{ status | titlecase }}</b>
+          <span *ngIf="status?.includes('failed') || status?.includes('error')">
+            {{ status | titlecase }}
           </span>
-        </span>
-        <span *ngIf="status?.includes('failed') || status?.includes('error')">
-          {{ status | titlecase }}
-        </span>
-      </li>
-    </ul>
+        </li>
+      </ul>
+    </div>
   </div>
   </cds-toggletip>
   <li class="mt-4 fw-bold"
index 211def32cabfb21b9ad2766caff6c4ad6624604b..b32ca8a0ba0b51f378a96ee0c673e1255e0f1881 100644 (file)
         </li>
       </div>
       <div cdsToggletipContent>
-        <ul class="text-center">
-          <li><h5><b i18n>Metadata Sync Status:</b></h5></li>
-          <li *ngFor="let status of metadataSyncInfo.fullSyncStatus">
-            <span *ngIf="!status?.includes(metadataSyncInfo.syncstatus) && !status?.includes('failed') && !status?.includes('error')">
-              <span *ngIf="status?.includes(':')">
-                <b>{{ status.split(':')[0] | titlecase }}</b>:{{ status.split(':')[1] | titlecase}}
+        <div class="cds--popover-scroll-container">
+          <ul class="text-center">
+            <li><h5><b i18n>Metadata Sync Status:</b></h5></li>
+            <li *ngFor="let status of metadataSyncInfo.fullSyncStatus">
+              <span *ngIf="!status?.includes(metadataSyncInfo.syncstatus) && !status?.includes('failed') && !status?.includes('error')">
+                <span *ngIf="status?.includes(':')">
+                  <b>{{ status.split(':')[0] | titlecase }}</b>:{{ status.split(':')[1] | titlecase}}
+                </span>
+                <span *ngIf="!status?.includes(':')">
+                  <b>{{ status | titlecase }}</b>
+                </span>
               </span>
-              <span *ngIf="!status?.includes(':')">
-                <b>{{ status | titlecase }}</b>
+              <span *ngIf="status?.includes('failed') || status?.includes('error')">
+                  {{ status | titlecase }}
               </span>
-            </span>
-            <span *ngIf="status?.includes('failed') || status?.includes('error')">
-                {{ status | titlecase }}
-            </span>
-          </li>
-        </ul>
+            </li>
+          </ul>
+        </div>
       </div>
     </cds-toggletip>
     <li class="mt-4 fw-bold"
index 74e9b8f02129a923c2d1177510299d25b94386b4..c52612e01c27095dd39f813133c7d527472b07eb 100644 (file)
@@ -38,7 +38,8 @@ import {
   ProgressIndicatorModule,
   PanelModule,
   LayoutModule,
-  TilesModule
+  TilesModule,
+  PopoverModule
 } from 'carbon-components-angular';
 import EditIcon from '@carbon/icons/es/edit/20';
 import CodeIcon from '@carbon/icons/es/code/16';
@@ -138,7 +139,8 @@ import CloseIcon from '@carbon/icons/es/close/16';
     PanelModule,
     ChartsModule,
     LayoutModule,
-    TilesModule
+    TilesModule,
+    PopoverModule
   ],
   declarations: [
     SparklineComponent,
index 81ad90914b6aaf1a42df53d2d3ab20e9d24e2fec..82a6cc7fd758b28f2aeec9941867bf6edbf5ce54 100644 (file)
@@ -1,13 +1,42 @@
-<ng-template #popoverTpl>
-  <div [class]="class"
-       [innerHtml]="html">
+<ng-template #tooltipTemplate>
+  <div class="cds--popover-scroll-container">
+    <div [class]="class"
+         [innerHtml]="html">
+    </div>
+    <ng-container *ngTemplateOutlet="content"></ng-container>
   </div>
-  <ng-content></ng-content>
 </ng-template>
+@if (type === helperType.tooltip) {
+  <cds-tooltip [description]="tooltipTemplate"
+               [autoAlign]="true">
+    <svg [cdsIcon]="iconType"
+         [size]="iconSize"></svg>
+  </cds-tooltip>
+} @else {
+  <div class="inline-block"
+       [ngClass]="class">
+    <div
+      cdsPopover
+      [isOpen]="isPopoverOpen"
+      [autoAlign]="true"
+      (click)="togglePopover()"
+      (keydown.enter)="togglePopover()"
+      tabindex="0">
+      <div class="popover-trigger">
+        <svg
+          [cdsIcon]="iconType"
+          [size]="iconSize"></svg>
+      </div>
+      <cds-popover-content>
+        <div class="cds--popover-scroll-container"
+             (click)="$event.stopPropagation()">
+          <ng-container *ngTemplateOutlet="content"></ng-container>
+        </div>
+      </cds-popover-content>
+    </div>
+  </div>
+}
 
-<cds-tooltip [description]="popoverTpl"
-             [autoAlign]="true">
-  <svg cdsIcon="information"
-       size="16"
-       title="info"></svg>
-</cds-tooltip>
+<ng-template #content>
+  <ng-content></ng-content>
+</ng-template>
index 073fb37a07185cde6cdbbf3b20ea2f69d604a2f3..c55d1abfc9de163bf78dcc0335a447ee96442009 100644 (file)
@@ -1,4 +1,6 @@
 import { Component, Input } from '@angular/core';
+import { Icons } from '../../enum/icons.enum';
+import { HelperType } from '../../enum/cd-helper.enum';
 
 @Component({
   selector: 'cd-helper',
@@ -6,12 +8,25 @@ import { Component, Input } from '@angular/core';
   styleUrls: ['./helper.component.scss']
 })
 export class HelperComponent {
-  @Input()
-  class: string;
+  icons = Icons;
+  isPopoverOpen = false;
+  helperType = HelperType;
 
-  @Input()
-  iconClass = '';
+  // Tooltip: Displayed on hover or focus and contains contextual, helpful, and nonessential information.
+  // Popover: Displayed on click and can contain varying text and interactive elements
+  @Input() type: HelperType.tooltip | HelperType.popover = HelperType.tooltip; // Default to tooltip for backward compatibility
+  @Input() class: string;
+  @Input() html: any;
+  @Input() iconSize = this.icons.size16;
+  @Input() iconType = this.icons.info;
 
-  @Input()
-  html: any;
+  togglePopover() {
+    this.isPopoverOpen = !this.isPopoverOpen;
+  }
+
+  closePopover() {
+    if (this.type === HelperType.popover && this.isPopoverOpen) {
+      this.isPopoverOpen = false;
+    }
+  }
 }
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/enum/cd-helper.enum.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/enum/cd-helper.enum.ts
new file mode 100644 (file)
index 0000000..8c64ce9
--- /dev/null
@@ -0,0 +1,4 @@
+export enum HelperType {
+  popover = 'popover',
+  tooltip = 'tooltip'
+}
index b1ba3d9ec47889384de1e208a67d4c2b1affb13c..289e2f0fa20f8ab119fb4cd0be4c5ebdbc77fb7f 100644 (file)
@@ -168,10 +168,22 @@ Tooltip
 /******************************************
 Carbon Popover
 ******************************************/
+.cds--popover {
+  .cds--popover-caret {
+    background-color: theme.$background;
+  }
+}
+
 .cds--popover-content {
-  background-color: theme.$layer-02;
+  background-color: theme.$background;
+}
+
+// inner container class for overflow
+.cds--popover-scroll-container {
   max-height: layout.$spacing-13;
-  overflow: auto;
+  overflow-y: auto;
+  margin-right: -1rem;
+  padding-right: 1rem;
 }
 
 /******************************************