desktop/src/app/components/pool/details/pool-details.component.ts (168 lines of code) (raw):
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { EntityView, autobind } from "@batch-flask/core";
import { PoolDecorator } from "app/decorators";
import { ImageInformation, Pool } from "app/models";
import { BatchExplorerService, PoolOsService, PoolParams, PoolService, PricingService } from "app/services";
import { NumberUtils, PoolUtils } from "app/utils";
import { List } from "immutable";
import { Subscription, from } from "rxjs";
import { flatMap } from "rxjs/operators";
import { PoolCommands } from "../action";
import { ElectronShell } from "@batch-flask/electron";
import "./pool-details.scss";
export enum ImageEOLState {
PassedEndOfLife,
NearingEndOfLife,
FarAwayFromEndOfLife,
}
@Component({
selector: "bl-pool-details",
templateUrl: "pool-details.html",
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [PoolCommands],
})
export class PoolDetailsComponent implements OnInit, OnDestroy {
public static breadcrumb({ id }, { tab }) {
const label = tab ? `Pool - ${tab}` : "Pool";
return {
name: id,
label,
icon: "database",
};
}
public poolId: string;
public poolDecorator: PoolDecorator;
public set pool(pool: Pool) {
this._pool = pool;
this.poolDecorator = pool && new PoolDecorator(pool);
}
public get pool() { return this._pool; }
public get isImageDeprecated() {
return this._isImageDeprecated;
}
public get isCloudServicePool() {
return this._isCloudServicePool;
}
public get hasDeprecationLink() {
return this.isImageDeprecated && PoolUtils.getEndOfLifeHyperlinkforPoolDetails(this.poolDecorator.poolOs);
}
public get selectedImageEndOfLifeDate() {
return this._selectedImageEndOfLifeDate.toDateString();
}
public data: EntityView<Pool, PoolParams>;
public estimatedCost = "-";
public imageEOLState = ImageEOLState;
public endOfLifeProximity: ImageEOLState;
private _paramsSubscriber: Subscription;
private _pool: Pool;
private _isImageDeprecated: boolean;
private _isCloudServicePool: boolean;
private _supportedImages: ImageInformation[];
private _selectedImageEndOfLifeDate: Date;
constructor(
public commands: PoolCommands,
private changeDetector: ChangeDetectorRef,
private router: Router,
private activatedRoute: ActivatedRoute,
private poolOsService: PoolOsService,
private batchExplorer: BatchExplorerService,
private pricingService: PricingService,
private poolService: PoolService,
private electronShell: ElectronShell) {
this.data = this.poolService.view();
this.data.item.subscribe((pool) => {
this.pool = pool;
this.changeDetector.markForCheck();
this._updatePrice();
this._updatePoolDeprecationWarning();
this._cloudServiceDeprecationWarning();
});
this.data.deleted.subscribe((key) => {
if (key === this.poolId) {
this.router.navigate(["/pools"]);
}
});
}
public ngOnInit() {
this._paramsSubscriber = this.activatedRoute.params.subscribe((params) => {
this.poolId = params["id"];
this.data.params = { id: this.poolId };
this.data.fetch();
});
this.poolOsService.supportedImages.subscribe(val => {
this._supportedImages = val.toArray();
this._updatePoolDeprecationWarning();
this._cloudServiceDeprecationWarning();
});
}
public ngOnDestroy() {
this._paramsSubscriber.unsubscribe();
this.data.dispose();
}
public get filterPlaceholderText() {
return "Filter by node id";
}
@autobind()
public refreshPool() {
return this.commands.get(this.poolId);
}
@autobind()
public updateTags(newTags: List<string>) {
return this.poolService.updateTags(this.pool, newTags).pipe(
flatMap(() => this.data.refresh()),
);
}
@autobind()
public openInNewWindow() {
const link = `ms-batch-explorer://route/standalone/pools/${this.pool.id}/graphs?fullscreen=true`;
const window = this.batchExplorer.openNewWindow(link);
return from(window.appReady);
}
public openDeprecationLink() {
const link = PoolUtils.getEndOfLifeHyperlinkforPoolDetails(this.poolDecorator.poolOs);
this.electronShell.openExternal(link, {activate: true});
}
public openLink(link: string) {
this.electronShell.openExternal(link, {activate: true});
}
private _updatePrice() {
if (!this.pool) {
this.estimatedCost = "-";
this.changeDetector.markForCheck();
return;
}
this.pricingService.computePoolPrice(this.pool).subscribe((cost) => {
if (!cost) {
this.estimatedCost = "-";
} else {
this.estimatedCost = `${cost.unit} ${NumberUtils.pretty(cost.total)}`;
}
this.changeDetector.markForCheck();
});
}
private _updatePoolDeprecationWarning() {
this._isImageDeprecated = false;
if (!this._supportedImages) {
return;
}
for (let i = 0; i < this._supportedImages.length; i++) {
const selectedImage = this._supportedImages[i];
if (this.poolDecorator
&& this.poolDecorator.poolOs.includes(selectedImage.imageReference.sku)
&& selectedImage.batchSupportEndOfLife) {
this._isImageDeprecated = true;
this._selectedImageEndOfLifeDate = selectedImage.batchSupportEndOfLife;
this._updateImageEOLState();
}
}
}
private _cloudServiceDeprecationWarning() {
this._isCloudServicePool = false;
if (this.pool && this.pool.cloudServiceConfiguration) {
this._isCloudServicePool = true;
}
}
private _updateImageEOLState() {
const diff = this._selectedImageEndOfLifeDate.getTime() - Date.now();
const days = diff / (1000 * 3600 * 24);
if (days < 0) {
this.endOfLifeProximity = ImageEOLState.PassedEndOfLife;
} else if (days >= 0 && days <= 365) {
this.endOfLifeProximity = ImageEOLState.NearingEndOfLife;
} else {
this.endOfLifeProximity = ImageEOLState.FarAwayFromEndOfLife;
}
}
}