Skip to content
Snippets Groups Projects
Commit 6ef51ed5 authored by Nathan Hertz's avatar Nathan Hertz
Browse files

WS-348: Real-time updates for request status page

parent a6806706
No related branches found
No related tags found
1 merge request!433WS-348: Real-time updates for request status page
Pipeline #2589 passed
import { Component, OnInit } from "@angular/core";
import { Component, OnDestroy, OnInit } from "@angular/core";
import { CapabilityRequest } from "../../model/capability-request";
import { ActivatedRoute } from "@angular/router";
import { DataRetrieverService } from "../../services/data-retriever.service";
import { CapabilityExecution } from "../../model/capability-execution";
import { Capability } from "../../model/capability";
import { CapabilityRequestService } from "../../services/capability-request.service";
import { CapabilityVersion } from "../../model/capability-version";
import { AlertService } from "src/app/shared/alert/alert.service";
import { PollingDataUpdaterService } from "../../services/polling-data-updater.service";
import { AlertService } from "../../../shared/alert/alert.service";
import { JsonObject } from "@angular/compiler-cli/ngcc/src/packages/entry_point";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { Capability } from "../../model/capability";
@Component({
selector: "app-capability-request",
templateUrl: "./capability-request.component.html",
styleUrls: ["./capability-request.component.scss"],
})
export class CapabilityRequestComponent implements OnInit {
export class CapabilityRequestComponent implements OnInit, OnDestroy {
public capabilityRequest: CapabilityRequest;
public capability: Capability;
public capabilityExecution: CapabilityExecution;
public currentVersion: CapabilityVersion;
private ngUnsubscribe = new Subject(); // to signal when all subscribers should unsubscribe (triggered in tear down)
// Observer for capability request objects
private capabilityRequestObserver = {
next: (request) => {
......@@ -26,6 +32,7 @@ export class CapabilityRequestComponent implements OnInit {
this.capabilityExecution = request.current_execution;
this.dataRetriever
.getCapability(this.capabilityRequest.capability_name)
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(this.capabilityObserver);
},
error: (error) => console.error("Error when retrieving capability request:" + error),
......@@ -53,27 +60,31 @@ export class CapabilityRequestComponent implements OnInit {
private route: ActivatedRoute,
private dataRetriever: DataRetrieverService,
private capabilityRequestService: CapabilityRequestService,
public alertService: AlertService,
private pollingDataUpdaterService: PollingDataUpdaterService,
private alertService: AlertService,
) {
const requestID = parseInt(this.route.snapshot.paramMap.get("id"));
this.capabilityRequestService
.getCapabilityRequest(requestID)
this.pollingDataUpdaterService
.getDataPoller$(this.capabilityRequestService.getCapabilityRequestURL(requestID))
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(this.capabilityRequestObserver);
this.capabilityRequestService
.getLatestVersion(requestID)
this.pollingDataUpdaterService
.getDataPoller$(this.capabilityRequestService.getLatestVersionURL(requestID))
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(this.capabilityVersionObserver);
}
ngOnInit(): void {}
alertMessage(eventDetails) {
let message = ""
let title = ""
alertMessage(eventDetails: JsonObject): void {
let message = "";
let title = "";
switch(eventDetails.type) {
switch (eventDetails.type) {
case "carta": {
title = "Launching CARTA";
message = "An email has been sent to <strong>" + eventDetails.email + "</strong> with a link to your CARTA instance.";
message =
"An email has been sent to <strong>" +
eventDetails.email +
"</strong> with a link to your CARTA instance.";
this.alertService.info(message, title);
break;
}
......@@ -85,4 +96,12 @@ export class CapabilityRequestComponent implements OnInit {
}
}
}
ngOnInit(): void {}
ngOnDestroy(): void {
// Prevent memory leakage by unsubscribing all observers
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
......@@ -17,14 +17,22 @@ export class CapabilityRequestService {
private route: ActivatedRoute,
) {}
/**
* Returns URL for GETting capability request definition
* @param id Capability request ID
* @return string The "GET capability request" HTTP url
*/
public getCapabilityRequestURL(id: number): string {
return `capability/request/${id}`;
}
/**
* Gets JSON representation of a capability request given an ID
* @param id The ID of the request
* @return Observable<CapabilityRequest> Result of REST caall to get the request
*/
public getCapabilityRequest(id: number): Observable<CapabilityRequest> {
const url = `capability/request/${id}`;
return this.httpClient.get<CapabilityRequest>(url);
return this.httpClient.get<CapabilityRequest>(this.getCapabilityRequestURL(id));
}
/**
......@@ -45,14 +53,22 @@ export class CapabilityRequestService {
return this.httpClient.get<JsonObject>(url);
}
/**
* Returns URL for GETting the latest version of a capability request
* @param id Capability request ID
* @return string The "GET latest version" HTTP url
*/
public getLatestVersionURL(id: number): string {
return `capability/request/${id}/version/latest`;
}
/**
* Get latest version for capability request with given ID
* @param id ID of request to get version for
* @return Observable<CapabilityVersion> Result of REST call to get the version
*/
public getLatestVersion(id: number): Observable<CapabilityVersion> {
const url = `capability/request/${id}/version/latest`;
return this.httpClient.get<CapabilityVersion>(url);
return this.httpClient.get<CapabilityVersion>(this.getLatestVersionURL(id));
}
/**
......
import { TestBed } from '@angular/core/testing';
import { PollingDataUpdaterService } from './polling-data-updater.service';
describe('PollingDataUpdaterService', () => {
let service: PollingDataUpdaterService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(PollingDataUpdaterService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
import { Injectable, OnDestroy } from "@angular/core";
import { Observable, Subject, timer } from "rxjs";
import { JsonObject } from "@angular/compiler-cli/ngcc/src/packages/entry_point";
import { HttpClient } from "@angular/common/http";
import { retry, switchMap, takeUntil } from "rxjs/operators";
/**
* Service that implements a polling mechanism for data that is retrieved using HTTP GET requests
*/
@Injectable({
providedIn: "root",
})
export class PollingDataUpdaterService implements OnDestroy {
private stopPolling = new Subject();
constructor(private httpClient: HttpClient) {}
/**
* Get data poller observer that makes periodic GET requests; allows for periodic real-time updates to UI components
* that get results from REST
* @param url URL to make periodic GET requests to
* @return Observable<JsonObject> Data poller observable
*/
public getDataPoller$(url: string): Observable<JsonObject> {
return timer(1, 3000).pipe(
switchMap(() => this.httpClient.get<JsonObject>(url)),
retry(),
takeUntil(this.stopPolling),
);
}
ngOnDestroy(): void {
this.stopPolling.next();
this.stopPolling.complete();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment