It's now possible to toggle columns on and off in the data table.
Signed-off-by: Stephan Müller <smueller@suse.com>
import { ToastModule, ToastOptions } from 'ng2-toastr/ng2-toastr';
-import { AccordionModule, TabsModule } from 'ngx-bootstrap';
+import { AccordionModule, BsDropdownModule, TabsModule } from 'ngx-bootstrap';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CephModule } from './ceph/ceph.module';
SharedModule,
CephModule,
AccordionModule.forRoot(),
+ BsDropdownModule.forRoot(),
TabsModule.forRoot(),
HttpClientModule,
BrowserAnimationsModule
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { BsDropdownModule, TabsModule } from 'ngx-bootstrap';
import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
-import { TabsModule } from 'ngx-bootstrap/tabs';
import { Observable } from 'rxjs/Observable';
import { RbdMirroringService } from '../../../shared/services/rbd-mirroring.service';
import { SharedModule } from '../../../shared/shared.module';
-import { BlockModule } from '../block.module';
import { MirrorHealthColorPipe } from '../mirror-health-color.pipe';
import { MirroringComponent } from './mirroring.component';
declarations: [MirroringComponent, MirrorHealthColorPipe],
imports: [
SharedModule,
+ BsDropdownModule.forRoot(),
TabsModule.forRoot(),
ProgressbarModule.forRoot(),
HttpClientTestingModule
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
-import { AlertModule, TabsModule } from 'ngx-bootstrap';
+import { AlertModule, BsDropdownModule, TabsModule } from 'ngx-bootstrap';
import { ComponentsModule } from '../../../shared/components/components.module';
import { SharedModule } from '../../../shared/shared.module';
TestBed.configureTestingModule({
imports: [
SharedModule,
+ BsDropdownModule.forRoot(),
TabsModule.forRoot(),
AlertModule.forRoot(),
ComponentsModule,
import { RouterTestingModule } from '@angular/router/testing';
import { ChartsModule } from 'ng2-charts/ng2-charts';
-import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
+import { BsDropdownModule, ProgressbarModule } from 'ngx-bootstrap';
import { Observable } from 'rxjs/Observable';
import { SharedModule } from '../../../shared/shared.module';
beforeEach(
async(() => {
TestBed.configureTestingModule({
- imports: [SharedModule, ChartsModule, RouterTestingModule, ProgressbarModule.forRoot()],
+ imports: [
+ SharedModule,
+ ChartsModule,
+ RouterTestingModule,
+ BsDropdownModule.forRoot(),
+ ProgressbarModule.forRoot()
+ ],
declarations: [CephfsComponent],
providers: [
{ provide: CephfsService, useValue: fakeFilesystemService }
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
+import { BsDropdownModule } from 'ngx-bootstrap';
import { Observable } from 'rxjs/Observable';
import { SharedModule } from '../../../shared/shared.module';
beforeEach(
async(() => {
TestBed.configureTestingModule({
- imports: [RouterTestingModule, SharedModule],
+ imports: [
+ RouterTestingModule,
+ BsDropdownModule.forRoot(),
+ SharedModule
+ ],
declarations: [ClientsComponent],
providers: [{ provide: CephfsService, useValue: fakeFilesystemService }]
}).compileComponents();
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
+import { BsDropdownModule } from 'ngx-bootstrap';
+
import { ComponentsModule } from '../../../shared/components/components.module';
import { SharedModule } from '../../../shared/shared.module';
import { HostsComponent } from './hosts.component';
SharedModule,
HttpClientTestingModule,
ComponentsModule,
+ BsDropdownModule.forRoot(),
RouterTestingModule
],
declarations: [
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
+import { BsDropdownModule } from 'ngx-bootstrap';
+
import { PerformanceCounterModule } from '../performance-counter.module';
import { TablePerformanceCounterService } from '../services/table-performance-counter.service';
import { PerformanceCounterComponent } from './performance-counter.component';
beforeEach(
async(() => {
TestBed.configureTestingModule({
- imports: [PerformanceCounterModule, RouterTestingModule],
+ imports: [
+ PerformanceCounterModule,
+ BsDropdownModule.forRoot(),
+ RouterTestingModule
+ ],
providers: [{ provide: TablePerformanceCounterService, useValue: fakeService }]
}).compileComponents();
})
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';
+import { BsDropdownModule } from 'ngx-bootstrap';
+
import { TablePerformanceCounterService } from './table-performance-counter.service';
describe('TablePerformanceCounterService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TablePerformanceCounterService],
- imports: [HttpClientTestingModule, HttpClientModule]
+ imports: [
+ HttpClientTestingModule,
+ BsDropdownModule.forRoot(),
+ HttpClientModule
+ ]
});
});
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { BsDropdownModule } from 'ngx-bootstrap';
+
import { SharedModule } from '../../../shared/shared.module';
import { TablePerformanceCounterService } from '../services/table-performance-counter.service';
import { TablePerformanceCounterComponent } from './table-performance-counter.component';
imports: [
HttpClientTestingModule,
HttpClientModule,
+ BsDropdownModule.forRoot(),
SharedModule
],
providers: [ TablePerformanceCounterService ]
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { TabsModule } from 'ngx-bootstrap/tabs';
+import { BsDropdownModule, TabsModule } from 'ngx-bootstrap';
import { SharedModule } from '../../../shared/shared.module';
import { PerformanceCounterModule } from '../../performance-counter/performance-counter.module';
PerformanceCounterModule,
HttpClientTestingModule,
HttpClientModule,
+ BsDropdownModule.forRoot(),
TabsModule.forRoot()
],
providers: [ RgwDaemonService ]
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { BsDropdownModule } from 'ngx-bootstrap';
+
import { DataTableModule } from '../../../shared/datatable/datatable.module';
import { RgwDaemonService } from '../services/rgw-daemon.service';
import { RgwDaemonListComponent } from './rgw-daemon-list.component';
imports: [
DataTableModule,
HttpClientTestingModule,
+ BsDropdownModule.forRoot(),
HttpClientModule
],
providers: [ RgwDaemonService ]
imports: [
CommonModule,
AuthModule,
- BsDropdownModule.forRoot(),
+ BsDropdownModule,
AppRoutingModule,
SharedModule,
RouterModule
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
+import { BsDropdownModule } from 'ngx-bootstrap';
import { ComponentsModule } from '../components/components.module';
import { PipesModule } from '../pipes/pipes.module';
import { TableDetailsDirective } from './table-details.directive';
CommonModule,
NgxDatatableModule,
FormsModule,
+ BsDropdownModule,
PipesModule,
ComponentsModule,
RouterModule
</div>
<!-- end pagination limit-->
+ <!-- show hide columns -->
+ <div class="widget-toolbar">
+ <div dropdown
+ class="dropdown tc_menuitem tc_menuitem_cluster">
+ <a dropdownToggle
+ class="btn btn-sm btn-default dropdown-toggle tc_columnBtn"
+ data-toggle="dropdown">
+ <i class="fa fa-lg fa-table"></i>
+ </a>
+ <ul *dropdownMenu
+ class="dropdown-menu">
+ <li *ngFor="let column of columns">
+ <label>
+ <input type="checkbox"
+ (change)="toggleColumn($event)"
+ [name]="column.prop"
+ [checked]="!column.isHidden">
+ <span>{{ column.name }}</span>
+ </label>
+ </li>
+ </ul>
+ </div>
+ </div>
+ <!-- end show hide columns -->
+
<!-- refresh button -->
<div class="widget-toolbar tc_refreshBtn">
<a (click)="refreshBtn()">
[selected]="selection.selected"
(select)="onSelect()"
[sorts]="sorts"
- [columns]="columns"
+ [columns]="tableColumns"
[columnMode]="columnMode"
[rows]="rows"
[rowClass]="getRowClass()"
component.updateFilter();
expect(component.rows.length).toBe(100);
});
+
+ describe('after ngInit', () => {
+ const toggleColumn = (prop, checked) => {
+ component.toggleColumn({
+ target: {
+ name: prop,
+ checked: checked
+ }
+ });
+ };
+
+ beforeEach(() => {
+ component.ngOnInit();
+ component.table.sorts = component.sorts;
+ });
+
+ it('should have updated the column definitions', () => {
+ expect(component.columns[0].flexGrow).toBe(1);
+ expect(component.columns[1].flexGrow).toBe(2);
+ expect(component.columns[2].flexGrow).toBe(2);
+ expect(component.columns[2].resizeable).toBe(false);
+ });
+
+ it('should have table columns', () => {
+ expect(component.tableColumns.length).toBe(3);
+ expect(component.tableColumns).toEqual(component.columns);
+ });
+
+ it('should have a unique identifier which is search for', () => {
+ expect(component.identifier).toBe('a');
+ expect(component.sorts[0].prop).toBe('a');
+ expect(component.sorts).toEqual(component.createSortingDefinition('a'));
+ });
+
+ it('should remove column "a"', () => {
+ toggleColumn('a', false);
+ expect(component.table.sorts[0].prop).toBe('b');
+ expect(component.tableColumns.length).toBe(2);
+ });
+
+ it('should not be able to remove all columns', () => {
+ toggleColumn('a', false);
+ toggleColumn('b', false);
+ toggleColumn('c', false);
+ expect(component.table.sorts[0].prop).toBe('c');
+ expect(component.tableColumns.length).toBe(1);
+ });
+
+ it('should enable column "a" again', () => {
+ toggleColumn('a', false);
+ toggleColumn('a', true);
+ expect(component.table.sorts[0].prop).toBe('b');
+ expect(component.tableColumns.length).toBe(3);
+ });
+ });
});
Type,
ViewChild
} from '@angular/core';
-
-import { DatatableComponent, SortDirection, SortPropDir } from '@swimlane/ngx-datatable';
+import {
+ DatatableComponent,
+ SortDirection,
+ SortPropDir,
+ TableColumnProp
+} from '@swimlane/ngx-datatable';
import * as _ from 'lodash';
import 'rxjs/add/observable/timer';
// Each item -> { prop: 'attribute name', dir: 'asc'||'desc'}
@Input() sorts?: SortPropDir[];
// Method used for setting column widths.
- @Input() columnMode ?= 'force';
+ @Input() columnMode ?= 'flex';
// Name of the component e.g. 'TableDetailsComponent'
@Input() detailsComponent?: string;
// Display the tool header, including reload button, pagination and search fields?
*/
selection = new CdTableSelection();
+ tableColumns: CdTableColumn[];
cellTemplates: {
[key: string]: TemplateRef<any>
} = {};
ngOnInit() {
this._addTemplates();
- this.columns.map((column) => {
- if (column.cellTransformation) {
- column.cellTemplate = this.cellTemplates[column.cellTransformation];
+ if (!this.sorts) {
+ this.identifier = this.columns.some(c => c.prop === this.identifier) ?
+ this.identifier :
+ this.columns[0].prop + '';
+ this.sorts = this.createSortingDefinition(this.identifier);
+ }
+ this.columns.map(c => {
+ if (c.cellTransformation) {
+ c.cellTemplate = this.cellTemplates[c.cellTransformation];
}
- return column;
+ if (!c.flexGrow) {
+ c.flexGrow = c.prop + '' === this.identifier ? 1 : 2;
+ }
+ if (!c.resizeable) {
+ c.resizeable = false;
+ }
+ return c;
});
if (this.detailsComponent) {
this.selectionType = 'multi';
}
- if (!this.sorts) {
- const sortProp = this.columns.some((c) => c.prop === this.identifier) ?
- this.identifier :
- this.columns[0].prop;
- this.sorts = [
- {
- prop: sortProp,
- dir: SortDirection.asc
- }
- ];
- }
+ 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
// useData() when this method was triggered by ngOnChanges().
}
}
+ toggleColumn($event: any) {
+ const prop: TableColumnProp = $event.target.name;
+ const hide = !$event.target.checked;
+ if (hide && this.tableColumns.length === 1) {
+ $event.target.checked = true;
+ return;
+ }
+ _.find(this.columns, (c: CdTableColumn) => c.prop === prop).isHidden = hide;
+ this.updateColumns();
+ }
+
+ updateColumns () {
+ this.tableColumns = this.columns.filter(c => !c.isHidden);
+ const sortProp = this.table.sorts[0].prop;
+ if (!_.find(this.tableColumns, (c: CdTableColumn) => c.prop === sortProp)) {
+ this.table.onColumnSort({sorts: this.createSortingDefinition(this.tableColumns[0].prop)});
+ }
+ this.table.recalculate();
+ }
+
+ createSortingDefinition (prop: TableColumnProp): SortPropDir[] {
+ return [
+ {
+ prop: prop,
+ dir: SortDirection.asc
+ }
+ ];
+ }
+
updateDetailView() {
if (!this.detailsComponent) {
return;
export interface CdTableColumn extends TableColumn {
cellTransformation?: CellTemplate;
+ isHidden?: boolean;
}