From: Devika Babrekar Date: Thu, 21 May 2026 06:33:04 +0000 (+0530) Subject: mgr/dashboard: Combining Quorum tables data on Monitors page X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c87ea33407132a29bd6dfabdb0f4097569d25da1;p=ceph.git mgr/dashboard: Combining Quorum tables data on Monitors page Fixes: https://tracker.ceph.com/issues/76746 Signed-off-by: Devika Babrekar --- diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.e2e-spec.ts index 4d4e53aee50..8e830fa3af0 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.e2e-spec.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.e2e-spec.ts @@ -16,13 +16,10 @@ describe('Monitors page', () => { describe('fields check', () => { it('should check status table is present', () => { - // check for table header 'Status' - monitors.getLegends().its(0).should('have.text', 'Status'); - - // check for fields in table monitors - .getStatusTables() - .should('contain.text', 'Cluster ID') + .getStatusTable() + .should('be.visible') + .and('contain.text', 'Cluster ID') .and('contain.text', 'monmap modified') .and('contain.text', 'monmap epoch') .and('contain.text', 'quorum con') @@ -31,30 +28,21 @@ describe('Monitors page', () => { .and('contain.text', 'required mon'); }); - it('should check In Quorum and Not In Quorum tables are present', () => { - // check for there to be two tables - monitors.getDataTables().should('have.length', 2); - - // check for table header 'In Quorum' - monitors.getLegends().its(1).should('have.text', 'In Quorum'); - - // check for table header 'Not In Quorum' - monitors.getLegends().its(2).should('have.text', 'Not In Quorum'); - - // verify correct columns on In Quorum table - monitors.getDataTableHeaders().contains('Name'); - - monitors.getDataTableHeaders().contains('Rank'); + it('should check monitors table is present', () => { + monitors.getMonitorTable().should('be.visible'); + monitors.getDataTables().should('have.length', 1); - monitors.getDataTableHeaders().contains('Public Address'); - - monitors.getDataTableHeaders().contains('Open Sessions'); - // verify correct columns on Not In Quorum table - monitors.getDataTableHeaders().contains('Name'); - - monitors.getDataTableHeaders().contains('Rank'); - - monitors.getDataTableHeaders().contains('Public Address'); + monitors.getMonitorTable().find('h4').should('contain.text', 'Monitors'); + monitors + .getMonitorTable() + .find('p') + .should('contain.text', 'Maintains the master copy of the cluster state'); + + monitors.getMonitorTableHeaders().should('contain.text', 'Name'); + monitors.getMonitorTableHeaders().should('contain.text', 'Rank'); + monitors.getMonitorTableHeaders().should('contain.text', 'Public address'); + monitors.getMonitorTableHeaders().should('contain.text', 'In Quorum'); + monitors.getMonitorTableHeaders().should('contain.text', 'Open sessions'); }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.po.ts index 4113b99288d..fdcfa93e77c 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.po.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/monitors.po.ts @@ -4,4 +4,18 @@ export class MonitorsPageHelper extends PageHelper { pages = { index: { url: '#/monitor', id: 'cd-monitor' } }; + + getStatusTable() { + cy.get('cd-monitor cd-table table[cdstable] tbody').should('exist'); + cy.contains('Loading').should('not.exist'); + return cy.get('cd-monitor fieldset table'); + } + + getMonitorTable() { + return cy.get('cd-monitor cd-table'); + } + + getMonitorTableHeaders() { + return this.getMonitorTable().find('th'); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.html index 9a92cfe04ee..72438079fb6 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.html @@ -1,65 +1,45 @@ -
-
-
- Status - +
+ @if(mon_status) { +
- + - + - + - + - + - + - + -
Cluster IDCluster ID {{ mon_status.monmap.fsid }}
monmap modifiedmonmap modified {{ mon_status.monmap.modified | relativeDate }}
monmap epochmonmap epoch {{ mon_status.monmap.epoch }}
quorum conquorum con {{ mon_status.features.quorum_con }}
quorum monquorum mon {{ mon_status.features.quorum_mon }}
required conrequired con {{ mon_status.features.required_con }}
required monrequired mon {{ mon_status.features.required_mon }}
-
-
+ + } + -
- In Quorum -
- -
- - Not In Quorum -
- -
-
+
+ +
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts index 53673c7f4c0..44c7acaf532 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.spec.ts @@ -74,31 +74,31 @@ describe('MonitorComponent', () => { expect(getMonitorSpy).toHaveBeenCalled(); - expect(component.inQuorum.columns[3].comparator(undefined, undefined)).toBe(0); - expect(component.inQuorum.columns[3].comparator(null, null)).toBe(0); - expect(component.inQuorum.columns[3].comparator([], [])).toBe(0); + expect(component.quorum.columns[4].comparator(undefined, undefined)).toBe(0); + expect(component.quorum.columns[4].comparator(null, null)).toBe(0); + expect(component.quorum.columns[4].comparator([], [])).toBe(0); expect( - component.inQuorum.columns[3].comparator( - component.inQuorum.data[0].cdOpenSessions, - component.inQuorum.data[3].cdOpenSessions + component.quorum.columns[4].comparator( + component.quorum.data[0].cdOpenSessions, + component.quorum.data[3].cdOpenSessions ) ).toBe(0); expect( - component.inQuorum.columns[3].comparator( - component.inQuorum.data[0].cdOpenSessions, - component.inQuorum.data[1].cdOpenSessions + component.quorum.columns[4].comparator( + component.quorum.data[0].cdOpenSessions, + component.quorum.data[1].cdOpenSessions ) ).toBe(1); expect( - component.inQuorum.columns[3].comparator( - component.inQuorum.data[1].cdOpenSessions, - component.inQuorum.data[0].cdOpenSessions + component.quorum.columns[4].comparator( + component.quorum.data[1].cdOpenSessions, + component.quorum.data[0].cdOpenSessions ) ).toBe(-1); expect( - component.inQuorum.columns[3].comparator( - component.inQuorum.data[2].cdOpenSessions, - component.inQuorum.data[1].cdOpenSessions + component.quorum.columns[4].comparator( + component.quorum.data[2].cdOpenSessions, + component.quorum.data[1].cdOpenSessions ) ).toBe(1); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts index fb0d13d2df1..6293cb0dac8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/monitor/monitor.component.ts @@ -5,6 +5,11 @@ import _ from 'lodash'; import { MonitorService } from '~/app/shared/api/monitor.service'; import { CellTemplate } from '~/app/shared/enum/cell-template.enum'; +const enum QuorumPresent { + Yes = 'Yes', + No = 'No' +} + @Component({ selector: 'cd-monitor', templateUrl: './monitor.component.html', @@ -13,20 +18,31 @@ import { CellTemplate } from '~/app/shared/enum/cell-template.enum'; }) export class MonitorComponent { mon_status: any; - inQuorum: any; - notInQuorum: any; - + quorum: any; interval: any; + title: string = $localize`Monitors`; + description: string = $localize`Maintains the master copy of the cluster state, including the monitor map, OSD map, and CRUSH map`; constructor(private monitorService: MonitorService) { - this.inQuorum = { + this.quorum = { columns: [ { prop: 'name', name: $localize`Name`, cellTransformation: CellTemplate.routerLink }, { prop: 'rank', name: $localize`Rank` }, - { prop: 'public_addr', name: $localize`Public Address` }, + { prop: 'public_addr', name: $localize`Public address` }, + { + prop: 'status', + name: $localize`In Quorum`, + cellTransformation: CellTemplate.tag, + customTemplateConfig: { + map: { + Yes: { value: $localize`Yes`, class: 'tag-success' }, + No: { value: $localize`No`, class: 'tag-danger' } + } + } + }, { prop: 'cdOpenSessions', - name: $localize`Open Sessions`, + name: $localize`Open sessions`, cellTransformation: CellTemplate.sparkline, comparator: (dataA: any, dataB: any) => { // We get the last value of time series to compare: @@ -42,14 +58,6 @@ export class MonitorComponent { } ] }; - - this.notInQuorum = { - columns: [ - { prop: 'name', name: $localize`Name`, cellTransformation: CellTemplate.routerLink }, - { prop: 'rank', name: $localize`Rank` }, - { prop: 'public_addr', name: $localize`Public Address` } - ] - }; } refresh() { @@ -58,17 +66,19 @@ export class MonitorComponent { row.cdOpenSessions = row.stats.num_sessions.map((i: string) => i[1]); row.cdLink = '/perf_counters/mon/' + row.name; row.cdParams = { fromLink: '/monitor' }; + row.status = QuorumPresent.Yes; return row; }); data.out_quorum.map((row: any) => { row.cdLink = '/perf_counters/mon/' + row.name; row.cdParams = { fromLink: '/monitor' }; + row.status = QuorumPresent.No; + row.cdOpenSessions = []; return row; }); - this.inQuorum.data = [...data.in_quorum]; - this.notInQuorum.data = [...data.out_quorum]; + this.quorum.data = [...data.in_quorum, ...data.out_quorum]; this.mon_status = data.mon_status; }); }