From: Tiago Melo Date: Thu, 8 Mar 2018 15:37:47 +0000 (+0000) Subject: mgr/dashboard_v2: fix and improve table details X-Git-Tag: v13.1.0~579^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F20811%2Fhead;p=ceph.git mgr/dashboard_v2: fix and improve table details There was a problem with the current implementation of the table details, when compiled in production mode, where the method that created the details element would throw an exception. Besides fixing that, this commit also improves the way we define the details. Now instead of sending the component name, through the 'detailsComponent' attr, we need to get the current selection via 'updateSelection' attr and declare the detail component inside the cdTable and add the cdTableDetail attr to that element. Signed-off-by: Tiago Melo --- diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts index 9b683f0a8d40..d661f51baed4 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts @@ -3,7 +3,8 @@ import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; -import { TabsModule } from 'ngx-bootstrap'; +import { TabsModule } from 'ngx-bootstrap/tabs'; + import { ComponentsModule } from '../../shared/components/components.module'; import { SharedModule } from '../../shared/shared.module'; import { PerformanceCounterModule } from '../performance-counter/performance-counter.module'; @@ -26,7 +27,7 @@ import { OsdService } from './osd/osd.service'; CommonModule, PerformanceCounterModule, ComponentsModule, - TabsModule, + TabsModule.forRoot(), SharedModule, RouterModule, FormsModule diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.html index 831e5620dc30..c511d54e78c1 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.html +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.spec.ts index 67eaaa9c41b0..c24618286de1 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.spec.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.spec.ts @@ -4,6 +4,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TabsModule } from 'ngx-bootstrap'; import { DataTableModule } from '../../../../shared/datatable/datatable.module'; +import { CdTableSelection } from '../../../../shared/models/cd-table-selection'; import { PerformanceCounterModule } from '../../../performance-counter/performance-counter.module'; import { OsdPerformanceHistogramComponent @@ -35,6 +36,9 @@ describe('OsdDetailsComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(OsdDetailsComponent); component = fixture.componentInstance; + + component.selection = new CdTableSelection(); + fixture.detectChanges(); }); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.ts index 572e0d65b549..7f2af3724976 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.ts @@ -1,7 +1,8 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnChanges } from '@angular/core'; import * as _ from 'lodash'; +import { CdTableSelection } from '../../../../shared/models/cd-table-selection'; import { OsdService } from '../osd.service'; @Component({ @@ -9,19 +10,19 @@ import { OsdService } from '../osd.service'; templateUrl: './osd-details.component.html', styleUrls: ['./osd-details.component.scss'] }) -export class OsdDetailsComponent implements OnInit { - osd: any; +export class OsdDetailsComponent implements OnChanges { + @Input() selection: CdTableSelection; - @Input() selected?: any[] = []; + osd: any; constructor(private osdService: OsdService) {} - ngOnInit() { + ngOnChanges() { this.osd = { loaded: false }; - if (this.selected.length > 0) { - this.osd = this.selected[0]; + if (this.selection.hasSelection) { + this.osd = this.selection.first(); this.osd.autoRefresh = () => { this.refresh(); }; diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.html index d67eefb55bf8..2683102f0188 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.html +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.html @@ -7,15 +7,18 @@ + selectionType="single" + (updateSelection)="updateSelection($event)"> + + + + [class.text-warning]="'down' === state || 'out' === state"> {{ state }}, diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts index 06faf69da28c..506b536a6364 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts @@ -1,7 +1,7 @@ import { HttpClientModule } from '@angular/common/http'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TabsModule } from 'ngx-bootstrap'; +import { TabsModule } from 'ngx-bootstrap/tabs'; import { DataTableModule } from '../../../../shared/datatable/datatable.module'; import { DimlessPipe } from '../../../../shared/pipes/dimless.pipe'; @@ -23,7 +23,7 @@ describe('OsdListComponent', () => { imports: [ HttpClientModule, PerformanceCounterModule, - TabsModule, + TabsModule.forRoot(), DataTableModule ], declarations: [ diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts index 5573550e9825..29f0f22ede28 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.ts @@ -14,9 +14,10 @@ import { OsdService } from '../osd.service'; export class OsdListComponent implements OnInit { @ViewChild('statusColor') statusColor: TemplateRef; + osds = []; - detailsComponent = 'OsdDetailsComponent'; columns: CdTableColumn[]; + selection = new CdTableSelection(); constructor( private osdService: OsdService, @@ -45,6 +46,10 @@ export class OsdListComponent implements OnInit { ]; } + updateSelection(selection: CdTableSelection) { + this.selection = selection; + } + getOsdList() { this.osdService.getList().subscribe((data: any[]) => { this.osds = data; diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.html index 73ffbb7ebb8f..81c5919db697 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.html +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.html @@ -1,4 +1,4 @@ - + { let component: RgwDaemonDetailsComponent; let fixture: ComponentFixture; + const fakeService = { + get: (id: string) => { + return new Promise(function(resolve, reject) { + return []; + }); + } + }; + beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ RgwDaemonDetailsComponent ], imports: [ SharedModule, PerformanceCounterModule, - HttpClientTestingModule, - HttpClientModule, - BsDropdownModule.forRoot(), TabsModule.forRoot() ], - providers: [ RgwDaemonService ] - }) - .compileComponents(); + providers: [{ provide: RgwDaemonService, useValue: fakeService }] + }); })); beforeEach(() => { fixture = TestBed.createComponent(RgwDaemonDetailsComponent); component = fixture.componentInstance; + + component.selection = new CdTableSelection(); + fixture.detectChanges(); }); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.ts index e6be4f277a63..8ac62fac84c8 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.ts @@ -1,7 +1,8 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnChanges } from '@angular/core'; import * as _ from 'lodash'; +import { CdTableSelection } from '../../../shared/models/cd-table-selection'; import { RgwDaemonService } from '../services/rgw-daemon.service'; @Component({ @@ -9,19 +10,18 @@ import { RgwDaemonService } from '../services/rgw-daemon.service'; templateUrl: './rgw-daemon-details.component.html', styleUrls: ['./rgw-daemon-details.component.scss'] }) -export class RgwDaemonDetailsComponent implements OnInit { - +export class RgwDaemonDetailsComponent implements OnChanges { metadata: any; serviceId = ''; - @Input() selected?: Array = []; + @Input() selection: CdTableSelection; - constructor(private rgwDaemonService: RgwDaemonService) { } + constructor(private rgwDaemonService: RgwDaemonService) {} - ngOnInit() { + ngOnChanges() { // Get the service id of the first selected row. - if (this.selected.length > 0) { - this.serviceId = this.selected[0].id; + if (this.selection.hasSelection) { + this.serviceId = this.selection.first().id; } } @@ -29,9 +29,8 @@ export class RgwDaemonDetailsComponent implements OnInit { if (_.isEmpty(this.serviceId)) { return; } - this.rgwDaemonService.get(this.serviceId) - .then((resp) => { - this.metadata = resp['rgw_metadata']; - }); + this.rgwDaemonService.get(this.serviceId).then(resp => { + this.metadata = resp['rgw_metadata']; + }); } } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.html index d22ed89b1020..64b703fd98e4 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.html +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.html @@ -5,10 +5,14 @@ aria-current="page">Object Gateway + + selectionType="single" + (updateSelection)="updateSelection($event)" + (fetchData)="getDaemonList()"> + + diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts index d3c5a11a6844..c0d331e3599f 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.spec.ts @@ -2,9 +2,11 @@ import { HttpClientModule } from '@angular/common/http'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { BsDropdownModule } from 'ngx-bootstrap'; +import { TabsModule } from 'ngx-bootstrap/tabs'; import { DataTableModule } from '../../../shared/datatable/datatable.module'; +import { PerformanceCounterModule } from '../../performance-counter/performance-counter.module'; +import { RgwDaemonDetailsComponent } from '../rgw-daemon-details/rgw-daemon-details.component'; import { RgwDaemonService } from '../services/rgw-daemon.service'; import { RgwDaemonListComponent } from './rgw-daemon-list.component'; @@ -14,12 +16,13 @@ describe('RgwDaemonListComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ RgwDaemonListComponent ], + declarations: [ RgwDaemonListComponent, RgwDaemonDetailsComponent ], imports: [ DataTableModule, HttpClientTestingModule, - BsDropdownModule.forRoot(), - HttpClientModule + HttpClientModule, + TabsModule.forRoot(), + PerformanceCounterModule ], providers: [ RgwDaemonService ] }) diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts index a9b41942bcdf..ce1c2456fdf0 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-list/rgw-daemon-list.component.ts @@ -14,8 +14,7 @@ export class RgwDaemonListComponent { columns: Array = []; daemons: Array = []; - - detailsComponent = 'RgwDaemonDetailsComponent'; + selection = new CdTableSelection(); constructor(private rgwDaemonService: RgwDaemonService, cephShortVersionPipe: CephShortVersionPipe) { @@ -46,7 +45,7 @@ export class RgwDaemonListComponent { }); } - beforeShowDetails(selection: CdTableSelection) { - return selection.hasSingleSelection; + updateSelection(selection: CdTableSelection) { + this.selection = selection; } } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation.module.ts index 6ec240de965e..823d4feea184 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation.module.ts @@ -13,7 +13,7 @@ import { NavigationComponent } from './navigation/navigation.component'; imports: [ CommonModule, AuthModule, - BsDropdownModule, + BsDropdownModule.forRoot(), AppRoutingModule, SharedModule, RouterModule diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/datatable.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/datatable.module.ts index 19d1a45605a6..b09a31ebaa7c 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/datatable.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/datatable.module.ts @@ -4,11 +4,10 @@ import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { NgxDatatableModule } from '@swimlane/ngx-datatable'; +import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; -import { BsDropdownModule } from 'ngx-bootstrap'; import { ComponentsModule } from '../components/components.module'; import { PipesModule } from '../pipes/pipes.module'; -import { TableDetailsDirective } from './table-details.directive'; import { TableKeyValueComponent } from './table-key-value/table-key-value.component'; import { TableComponent } from './table/table.component'; @@ -17,14 +16,13 @@ import { TableComponent } from './table/table.component'; CommonModule, NgxDatatableModule, FormsModule, - BsDropdownModule, + BsDropdownModule.forRoot(), PipesModule, ComponentsModule, RouterModule ], declarations: [ TableComponent, - TableDetailsDirective, TableKeyValueComponent ], exports: [ diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-details.directive.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-details.directive.spec.ts deleted file mode 100644 index b3e26843cbac..000000000000 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-details.directive.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { TableDetailsDirective } from './table-details.directive'; - -describe('TableDetailsDirective', () => { - it('should create an instance', () => { - const directive = new TableDetailsDirective(null); - expect(directive).toBeTruthy(); - }); -}); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-details.directive.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-details.directive.ts deleted file mode 100644 index 5c529dc72b74..000000000000 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-details.directive.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Directive, Input, ViewContainerRef } from '@angular/core'; - -@Directive({ - selector: '[cdTableDetails]' -}) -export class TableDetailsDirective { - @Input() selected?: any[]; - - constructor(public viewContainerRef: ViewContainerRef) { } - -} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table/table.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table/table.component.html index 2c68b32e9790..ba6adf5ae7e7 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table/table.component.html +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table/table.component.html @@ -90,12 +90,11 @@ [loadingIndicator]="loadingIndicator" [rowIdentity]="rowIdentity()" [rowHeight]="'auto'"> - - - - + + + ; @ViewChild('sparklineTpl') sparklineTpl: TemplateRef; @ViewChild('routerLinkTpl') routerLinkTpl: TemplateRef; @@ -48,8 +45,6 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O @Input() sorts?: SortPropDir[]; // Method used for setting column widths. @Input() columnMode ?= 'flex'; - // Name of the component e.g. 'TableDetailsComponent' - @Input() detailsComponent?: string; // Display the tool header, including reload button, pagination and search fields? @Input() toolHeader ?= true; // Display the table header? @@ -58,10 +53,6 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O @Input() footer ?= true; // Page size to show. Set to 0 to show unlimited number of rows. @Input() limit ?= 10; - // An optional function that is called before the details page is show. - // The current selection is passed as function argument. To do not display - // the details page, return false. - @Input() beforeShowDetails: Function; /** * Auto reload time in ms - per default every 5s @@ -72,6 +63,9 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O // Which row property is unique for a row @Input() identifier = 'id'; + // Allows other components to specify which type of selection they want, + // e.g. 'single' or 'multi'. + @Input() selectionType: string = undefined; /** * Should be a function to update the input data if undefined nothing will be triggered @@ -84,6 +78,16 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O */ @Output() fetchData = new EventEmitter(); + /** + * This should be defined if you need access to the selection object. + * + * Each time the table selection changes, this will be triggered and + * the new selection object will be sent. + * + * @memberof TableComponent + */ + @Output() updateSelection = new EventEmitter(); + /** * Use this variable to access the selected row(s). */ @@ -93,7 +97,6 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O cellTemplates: { [key: string]: TemplateRef } = {}; - selectionType: string = undefined; search = ''; rows = []; loadingIndicator = true; @@ -110,7 +113,7 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O // table columns after the browser window has been resized. private currentWidth: number; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor() {} ngOnInit() { this._addTemplates(); @@ -132,9 +135,6 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O } return c; }); - if (this.detailsComponent) { - this.selectionType = 'multi'; - } this.tableColumns = this.columns.filter(c => !c.isHidden); if (this.autoReload) { // Also if nothing is bound to fetchData nothing will be triggered // Force showing the loading indicator because it has been set to False in @@ -164,7 +164,7 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O } } - _addTemplates () { + _addTemplates() { this.cellTemplates.bold = this.tableCellBoldTpl; this.cellTemplates.sparkline = this.sparklineTpl; this.cellTemplates.routerLink = this.routerLinkTpl; @@ -218,15 +218,7 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O onSelect() { this.selection.update(); - this.toggleExpandRow(); - } - - toggleExpandRow() { - if (this.selection.hasSelection) { - this.table.rowDetail.toggleExpandRow(this.selection.first()); - } else { - this.detailTemplate.viewContainerRef.clear(); - } + this.updateSelection.emit(_.clone(this.selection)); } toggleColumn($event: any) { @@ -258,25 +250,6 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O ]; } - updateDetailView() { - if (!this.detailsComponent) { - return; - } - if (_.isFunction(this.beforeShowDetails)) { - if (!this.beforeShowDetails(this.selection)) { - this.detailTemplate.viewContainerRef.clear(); - return; - } - } - const factories = Array.from(this.componentFactoryResolver['_factories'].keys()); - const factoryClass = >factories.find((x: any) => x.name === this.detailsComponent); - this.detailTemplate.viewContainerRef.clear(); - const cmpRef = this.detailTemplate.viewContainerRef.createComponent( - this.componentFactoryResolver.resolveComponentFactory(factoryClass) - ); - cmpRef.instance.selected = this.selection.selected; - } - updateFilter(event?) { if (!event) { this.search = ''; @@ -284,11 +257,15 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O const val = this.search.toLowerCase(); const columns = this.columns; // update the rows - this.rows = this.data.filter(function (d) { - return columns.filter((c) => { - return (typeof d[c.prop] === 'string' || typeof d[c.prop] === 'number') - && (d[c.prop] + '').toLowerCase().indexOf(val) !== -1; - }).length > 0; + this.rows = this.data.filter((d) => { + return ( + columns.filter(c => { + return ( + (_.isString(d[c.prop]) || _.isNumber(d[c.prop])) && + (d[c.prop] + '').toLowerCase().indexOf(val) !== -1 + ); + }).length > 0 + ); }); // Whenever the filter changes, always go back to the first page this.table.offset = 0; @@ -298,7 +275,7 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O // Return the function used to populate a row's CSS classes. return () => { return { - 'clickable': !_.isUndefined(this.detailsComponent) + clickable: !_.isUndefined(this.selectionType) }; }; } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/models/cd-table-selection.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/models/cd-table-selection.ts index f6ec8b4deb52..9732abc5a032 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/models/cd-table-selection.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/models/cd-table-selection.ts @@ -18,6 +18,10 @@ export class CdTableSelection { this.hasMultiSelection = this.selected.length > 1; } + /** + * Get the first selected row. + * @return {any | null} + */ first() { return this.hasSelection ? this.selected[0] : null; }