<legend i18n>Daemons</legend>
<cd-table [data]="daemons"
+ (fetchData)="refresh()"
[columns]="daemonsColumns">
</cd-table>
-import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
import { CephShortVersionPipe } from '../../../shared/pipes/ceph-short-version.pipe';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
templateUrl: './iscsi.component.html',
styleUrls: ['./iscsi.component.scss']
})
-export class IscsiComponent implements OnInit, OnDestroy {
+export class IscsiComponent {
daemons = [];
daemonsColumns: any;
images = [];
imagesColumns: any;
- interval: any;
constructor(private tcmuIscsiService: TcmuIscsiService,
cephShortVersionPipe: CephShortVersionPipe,
}
- ngOnInit() {
- this.refresh();
-
- this.interval = setInterval(() => {
- this.refresh();
- }, 5000);
- }
-
- ngOnDestroy() {
- clearInterval(this.interval);
- }
-
refresh() {
this.tcmuIscsiService.tcmuiscsi().then((resp) => {
this.daemons = resp.daemons;
<cd-table [data]="daemons.data"
columnMode="flex"
[columns]="daemons.columns"
+ [autoReload]="30000"
(fetchData)="refresh()">
</cd-table>
</fieldset>
<cd-table [data]="pools.data"
columnMode="flex"
- [columns]="pools.columns"
- (fetchData)="refresh()">
+ [autoReload]="0"
+ (fetchData)="refresh()"
+ [columns]="pools.columns">
</cd-table>
</fieldset>
</div>
<tab heading="Issues" i18n-heading>
<cd-table [data]="image_error.data"
columnMode="flex"
- [columns]="image_error.columns"
- (fetchData)="refresh()">
+ [autoReload]="0"
+ (fetchData)="refresh()"
+ [columns]="image_error.columns">
</cd-table>
</tab>
<tab heading="Syncing" i18n-heading>
<cd-table [data]="image_syncing.data"
columnMode="flex"
- [columns]="image_syncing.columns"
- (fetchData)="refresh()">
+ [autoReload]="0"
+ (fetchData)="refresh()"
+ [columns]="image_syncing.columns">
</cd-table>
</tab>
<tab heading="Ready" i18n-heading>
<cd-table [data]="image_ready.data"
columnMode="flex"
- [columns]="image_ready.columns"
- (fetchData)="refresh()">
+ [autoReload]="0"
+ (fetchData)="refresh()"
+ [columns]="image_ready.columns">
</cd-table>
</tab>
</tabset>
import { HttpClient } from '@angular/common/http';
-import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import * as _ from 'lodash';
templateUrl: './mirroring.component.html',
styleUrls: ['./mirroring.component.scss']
})
-export class MirroringComponent implements OnInit, OnDestroy {
+export class MirroringComponent implements OnInit {
@ViewChild('healthTmpl') healthTmpl: TemplateRef<any>;
@ViewChild('stateTmpl') stateTmpl: TemplateRef<any>;
@ViewChild('syncTmpl') syncTmpl: TemplateRef<any>;
@ViewChild('progressTmpl') progressTmpl: TemplateRef<any>;
contentData: any;
- interval: any;
status: ViewCacheStatus;
daemons = {
flexGrow: 1
}
];
-
- setTimeout(() => {
- this.interval = this.refresh();
- }, 30000);
- }
-
- ngOnDestroy() {
- clearInterval(this.interval);
}
refresh() {
import { CdTableColumn } from '../../../shared/models/cd-table-column';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
import { DimlessPipe } from '../../../shared/pipes/dimless.pipe';
-import { FormatterService } from '../../../shared/services/formatter.service';
import { PoolService } from '../../../shared/services/pool.service';
@Component({
images: any;
columns: CdTableColumn[];
retries: number;
- maxRetries = 5;
routeParamsSubscribe: any;
viewCacheStatus: ViewCacheStatus;
- interval: any;
constructor(
private route: ActivatedRoute,
this.images = [];
this.retries = 0;
});
-
- this.interval = setInterval(() => {
- this.loadImages();
- }, 5000);
}
ngOnDestroy() {
this.routeParamsSubscribe.unsubscribe();
- clearInterval(this.interval);
}
loadImages() {
<cd-table [data]="ranks.data"
[columns]="ranks.columns"
+ (fetchData)="refresh()"
toolHeader="false">
</cd-table>
</fieldset>
import * as _ from 'lodash';
-import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
import { DimlessPipe } from '../../../shared/pipes/dimless.pipe';
import { CephfsService } from '../cephfs.service';
this.pools.data = [];
this.standbys = [];
this.mdsCounters = {};
-
- this.refresh();
- this.draw_chart();
});
-
- this.interval = setInterval(() => {
- this.refresh();
- this.draw_chart();
- }, 5000);
}
ngOnDestroy() {
- clearInterval(this.interval);
this.routeParamsSubscribe.unsubscribe();
}
];
this.name = data.cephfs.name;
this.clientCount = data.cephfs.client_count;
+ this.draw_chart();
});
}
this.cephfsService.getMdsCounters(this.id).subscribe(data => {
const topChart = true;
- const oldKeys = Object.keys(this.mdsCounters);
- const newKeys = Object.keys(data);
-
_.each(this.mdsCounters, (value, key) => {
if (data[key] === undefined) {
delete this.mdsCounters[key];
const rhsData = this.delta_timeseries(mdsData[this.rhsCounter]);
if (this.mdsCounters[mdsName] === undefined) {
- const elem = {
+ this.mdsCounters[mdsName] = {
datasets: [
{
label: this.lhsCounter,
},
chartType: 'line'
};
-
- this.mdsCounters[mdsName] = elem;
} else {
this.mdsCounters[mdsName].datasets[0].data = lhsData;
this.mdsCounters[mdsName].datasets[1].data = rhsData;
<cd-table [data]="clients.data"
[columns]="clients.columns"
+ (fetchData)="refresh()"
[header]="false">
</cd-table>
</fieldset>
clients: any;
viewCacheStatus: ViewCacheStatus;
- interval: any;
-
constructor(private route: ActivatedRoute, private cephfsService: CephfsService) {}
ngOnInit() {
this.cephfsService.getCephfs(this.id).subscribe((data: any) => {
this.name = data.cephfs.name;
});
-
- this.refresh();
});
-
- this.interval = setInterval(() => {
- this.refresh();
- }, 5000);
}
ngOnDestroy() {
- clearInterval(this.interval);
this.routeParamsSubscribe.unsubscribe();
}
-import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { CdTableColumn } from '../../../shared/models/cd-table-column';
import { CephShortVersionPipe } from '../../../shared/pipes/ceph-short-version.pipe';
templateUrl: './hosts.component.html',
styleUrls: ['./hosts.component.scss']
})
-export class HostsComponent implements OnInit, OnDestroy {
+export class HostsComponent implements OnInit {
columns: Array<CdTableColumn> = [];
hosts: Array<object> = [];
- interval: any;
isLoadingHosts = false;
@ViewChild('servicesTpl') public servicesTpl: TemplateRef<any>;
pipe: this.cephShortVersionPipe
}
];
- this.interval = setInterval(() => {
- this.getHosts();
- }, 5000);
- }
-
- ngOnDestroy() {
- clearInterval(this.interval);
}
getHosts() {
<legend i18n
class="in-quorum">Not In Quorum</legend>
<cd-table [data]="notInQuorum.data"
+ (fetchData)="refresh()"
[columns]="notInQuorum.columns">
</cd-table>
</fieldset>
-import { Component, OnDestroy, OnInit } from '@angular/core';
-
-import * as _ from 'lodash';
+import { Component } from '@angular/core';
import { CellTemplate } from '../../../shared/enum/cell-template.enum';
import { MonitorService } from '../monitor.service';
templateUrl: './monitor.component.html',
styleUrls: ['./monitor.component.scss']
})
-export class MonitorComponent implements OnInit, OnDestroy {
+export class MonitorComponent {
mon_status: any;
inQuorum: any;
width: '50%'
};
- constructor(private monitorService: MonitorService) {}
-
- ngOnInit() {
+ constructor(private monitorService: MonitorService) {
this.inQuorum = {
columns: [
{ prop: 'name', name: 'Name', cellTransformation: CellTemplate.routerLink },
],
data: []
};
-
- this.refresh();
-
- this.interval = setInterval(() => {
- this.refresh();
- }, 5000);
- }
-
- ngOnDestroy() {
- clearInterval(this.interval);
}
refresh() {
-import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Component, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
templateUrl: './performance-counter.component.html',
styleUrls: ['./performance-counter.component.scss']
})
-export class PerformanceCounterComponent implements OnInit, OnDestroy {
+export class PerformanceCounterComponent implements OnDestroy {
serviceId: string;
serviceType: string;
routeParamsSubscribe: any;
- constructor(private route: ActivatedRoute) { }
-
- ngOnInit() {
+ constructor(private route: ActivatedRoute) {
this.routeParamsSubscribe = this.route.params.subscribe(
(params: { type: string; id: string }) => {
this.serviceId = params.id;
<!-- refresh button -->
<div class="widget-toolbar tc_refreshBtn">
- <a (click)="reloadData()">
+ <a (click)="refreshBtn()">
<i class="fa fa-lg fa-refresh"></i>
</a>
</div>
[footerHeight]="footer ? 'auto' : 0"
[limit]="limit > 0 ? limit : undefined"
[loadingIndicator]="loadingIndicator"
+ [rowIdentity]="rowIdentity()"
[rowHeight]="'auto'">
<!-- Row Detail Template -->
<ngx-datatable-row-detail (toggle)="updateDetailView()">
EventEmitter,
Input,
OnChanges,
+ OnDestroy,
OnInit,
Output,
TemplateRef,
} from '@angular/core';
import { DatatableComponent, SortDirection, SortPropDir } from '@swimlane/ngx-datatable';
+
import * as _ from 'lodash';
+import 'rxjs/add/observable/timer';
+import { Observable } from 'rxjs/Observable';
import { CdTableColumn } from '../../models/cd-table-column';
import { TableDetailsDirective } from '../table-details.directive';
templateUrl: './table.component.html',
styleUrls: ['./table.component.scss']
})
-export class TableComponent implements AfterContentChecked, OnInit, OnChanges {
+export class TableComponent implements AfterContentChecked, OnInit, OnChanges, OnDestroy {
@ViewChild(DatatableComponent) table: DatatableComponent;
@ViewChild(TableDetailsDirective) detailTemplate: TableDetailsDirective;
@ViewChild('tableCellBoldTpl') tableCellBoldTpl: TemplateRef<any>;
@ViewChild('perSecondTpl') perSecondTpl: TemplateRef<any>;
// This is the array with the items to be shown.
- @Input() data: any[] = [];
+ @Input() data: any[];
// Each item -> { prop: 'attribute name', name: 'display name' }
@Input() columns: CdTableColumn[];
// Each item -> { prop: 'attribute name', dir: 'asc'||'desc'}
// the details page, return false.
@Input() beforeShowDetails: Function;
- // Should be the function that will update the input data.
+ /**
+ * Auto reload time in ms - per default every 5s
+ * You can set it to 0, undefined or false to disable the auto reload feature in order to
+ * trigger 'fetchData' if the reload button is clicked.
+ */
+ @Input() autoReload: any = 5000;
+
+ // Which row property is unique for a row
+ @Input() identifier = 'id';
+
+ /**
+ * Should be a function to update the input data if undefined nothing will be triggered
+ *
+ * Sometimes it's useful to only define fetchData once.
+ * Example:
+ * Usage of multiple tables with data which is updated by the same function
+ * What happens:
+ * The function is triggered through one table and all tables will update
+ */
@Output() fetchData = new EventEmitter();
cellTemplates: {
search = '';
rows = [];
selected = [];
- loadingIndicator = false;
+ loadingIndicator = true;
paginationClasses = {
pagerLeftArrow: 'i fa fa-angle-double-left',
pagerRightArrow: 'i fa fa-angle-double-right',
pagerPrevious: 'i fa fa-angle-left',
pagerNext: 'i fa fa-angle-right'
};
+ private subscriber;
+ private updating = false;
// Internal variable to check if it is necessary to recalculate the
// table columns after the browser window has been resized.
}
return column;
});
- this.reloadData();
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: this.columns[0].prop,
+ prop: sortProp,
dir: SortDirection.asc
}
];
}
+ if (this.autoReload) { // Also if nothing is bound to fetchData nothing will be triggered
+ this.subscriber = Observable.timer(0, this.autoReload).subscribe(x => {
+ return this.reloadData();
+ });
+ }
+ }
+
+ ngOnDestroy() {
+ if (this.subscriber) {
+ this.subscriber.unsubscribe();
+ }
}
ngAfterContentChecked() {
}
reloadData() {
- if (this.loadingIndicator) {
- return;
+ if (!this.updating) {
+ this.fetchData.emit();
+ this.updating = true;
}
+ }
+
+ refreshBtn () {
this.loadingIndicator = true;
- this.fetchData.emit();
+ this.reloadData();
+ }
+
+ rowIdentity() {
+ return (row) => {
+ const id = row[this.identifier];
+ if (_.isUndefined(id)) {
+ throw new Error(`Wrong identifier "${this.identifier}" -> "${id}"`);
+ }
+ return id;
+ };
}
useData() {
return; // Wait for data
}
this.rows = [...this.data];
+ if (this.search.length > 0) {
+ this.updateFilter(true);
+ }
this.loadingIndicator = false;
+ this.updating = false;
}
toggleExpandRow() {