-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
import { GridModule, TilesModule } from 'carbon-components-angular';
import { OverviewStorageCardComponent } from './storage-card/overview-storage-card.component';
+import { HealthService } from '~/app/shared/api/health.service';
+import { HealthSnapshotMap } from '~/app/shared/models/health.interface';
+import { RefreshIntervalService } from '~/app/shared/services/refresh-interval.service';
+import { catchError, exhaustMap, takeUntil } from 'rxjs/operators';
+import { EMPTY, Subject } from 'rxjs';
@Component({
selector: 'cd-overview',
templateUrl: './overview.component.html',
styleUrl: './overview.component.scss'
})
-export class OverviewComponent {}
+export class OverviewComponent implements OnInit {
+ totalCapacity: number;
+ usedCapacity: number;
+ private destroy$ = new Subject<void>();
+
+
+ constructor(private healthService: HealthService, private refreshIntervalService: RefreshIntervalService) {}
+
+ ngOnInit(): void {
+ this.refreshIntervalObs(() => this.healthService.getHealthSnapshot()).subscribe({
+ next: (healthData: HealthSnapshotMap) => {
+ this.totalCapacity = healthData?.pgmap?.bytes_total;
+ this.usedCapacity = healthData?.pgmap?.bytes_used;
+ }});
+ }
+
+ refreshIntervalObs(fn: Function) {
+ return this.refreshIntervalService.intervalData$.pipe(
+ exhaustMap(() => fn().pipe(catchError(() => EMPTY))),
+ takeUntil(this.destroy$)
+ );
+ }
+
+ ngOnDestroy() {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
+}
-import { Component, ViewEncapsulation } from '@angular/core';
+import { Component, Input, OnChanges, ViewEncapsulation } from '@angular/core';
import {
CheckboxModule,
DropdownModule,
} from 'carbon-components-angular';
import { ProductiveCardComponent } from '~/app/shared/components/productive-card/productive-card.component';
import { MeterChartComponent, MeterChartOptions } from '@carbon/charts-angular';
+import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
const StorageType = {
ALL: $localize`All`,
OBJECT: $localize`Object`
};
+// const Query = {
+// RAW: {
+// [StorageType.ALL]: `sum by (application) (ceph_pool_bytes_used * on(pool_id) group_left(instance, name, application) ceph_pool_metadata{application=~"(.*Block.*)|(.*Filesystem.*)|(.*Object.*)|(..*)"})`,
+// [StorageType.BLOCK]: "",
+// [StorageType.FILE]: "",
+// [StorageType.OBJECT]: ""
+// },
+// USED: {
+// [StorageType.ALL]: `sum by (application) (ceph_pool_stored * on(pool_id) group_left(instance, name, application) ceph_pool_metadata{application=~"(.*Block.*)|(.*Filesystem.*)|(.*Object.*)|(..*)"})`,
+// [StorageType.BLOCK]: "",
+// [StorageType.FILE]: "",
+// [StorageType.OBJECT]: ""
+// }
+// }
+
+/**
+ * 1. Fetch snapshot query -> [pass total and used raw]
+ * 2. Show the usage title -> always fixed
+ * 3. The chart total -> raw total always fixed
+ * 4. Set data for block, file , object, all -> raw, sep queries
+ * 5. Set data for block, file object + replicated -> usable
+ * 6. Dont show what is 0
+ */
+
@Component({
selector: 'cd-overview-storage-card',
imports: [
styleUrl: './overview-storage-card.component.scss',
encapsulation: ViewEncapsulation.None
})
-export class OverviewStorageCardComponent {
+export class OverviewStorageCardComponent implements OnChanges {
+ @Input() total!: number;
+ @Input() used!: number;
+ totalRaw: string;
+ usedRaw: string;
+ totalRawUnit: string;
+ usedRawUnit: string;
options: MeterChartOptions = {
height: '45px',
meter: {
proportional: {
- total: 2000,
+ total: null,
unit: 'GB',
breakdownFormatter: (_e) => null,
totalFormatter: (_e) => null
allData = [
{
group: StorageType.BLOCK,
- value: 202
+ value: 100,
},
{
group: StorageType.FILE,
- value: 654
+ value: 105
},
{
group: StorageType.OBJECT,
- value: 120
- }
+ value: 60 }
];
dropdownItems = [
{ content: StorageType.ALL },
selectedStorageType: string = StorageType.ALL;
displayData = this.allData;
+ constructor(private dimlessBinaryPipe: DimlessBinaryPipe) {}
+
+ngOnChanges(): void {
+ if (this.total == null || this.used == null) return;
+
+ const totalRaw = this.dimlessBinaryPipe.transform(this.total);
+ const usedRaw = this.dimlessBinaryPipe.transform(this.used);
+
+ const [totalValue, totalUnit] = totalRaw.split(/\s+/);
+ const [usedValue, usedUnit] = usedRaw.split(/\s+/);
+
+ const cleanedTotal = Number(totalValue.replace(/,/g, '').trim());
+
+ if (Number.isNaN(cleanedTotal)) return;
+
+ this.totalRaw = totalValue;
+ this.totalRawUnit = totalUnit;
+ this.usedRaw = usedValue;
+ this.usedRawUnit = usedUnit;
+
+ // chart reacts to 'options' and 'data' changes only, hence mandatory to replace whole object
+ this.options = {
+ ...this.options,
+ meter: {
+ ...this.options.meter,
+ proportional: {
+ ...this.options.meter.proportional,
+ total: cleanedTotal,
+ unit: totalUnit
+ }
+ }
+ };
+}
+
toggleRawCapacity(isChecked: boolean) {
this.isRawCapacity = isChecked;
}