Skip to content

Commit ace6ab2

Browse files
authored
1 parent afd62f1 commit ace6ab2

File tree

4 files changed

+108
-16
lines changed

4 files changed

+108
-16
lines changed

ddp-workspace/projects/ddp-dsm-ui/src/app/oncHistoryUpload/oncHistoryUpload.component.html

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
<h1> Onc History Upload </h1>
2+
13
<div class="message">
2-
<p class="message-fail" *ngIf="uploadStatus === 1">{{errorMessage}}</p>
3-
<p class="message-success" *ngIf="uploadStatus === 0">Upload successful</p>
4+
<p class="message-fail" *ngIf="requestStatus === 1">{{errorMessage}}</p>
5+
<p class="message-success" *ngIf="requestStatus === 0">Upload successful</p>
6+
</div>
47

8+
<div class="download-button">
9+
<button (click)="downloadTemplateAndDirectory()" mat-raised-button color="primary">Download</button>
10+
<p>Click here to download the Onc History upload template and data dictionary</p>
511
</div>
12+
613
<div class="upload">
714
<app-filepicker [id]="'kitUploadFile'" [fileFormat]="'.txt'" (fileSelected)="fileSelected($event)"></app-filepicker>
815
<button type="button" mat-raised-button color="primary"

ddp-workspace/projects/ddp-dsm-ui/src/app/oncHistoryUpload/oncHistoryUpload.component.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@use 'commonStyles' as common;
2+
13
.message {
24
height: 2em;
35
width: 100%;
@@ -21,3 +23,12 @@
2123
margin-top: .5em;
2224
}
2325
}
26+
27+
.download-button {
28+
@include common.flexContainer(center, space-between);
29+
width: 42em;
30+
p {
31+
margin: 0;
32+
padding: 0;
33+
}
34+
}
Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import { Component } from '@angular/core';
1+
import {Component, OnDestroy} from '@angular/core';
22
import { DSMService } from '../services/dsm.service';
33
import {finalize} from 'rxjs/operators';
44
import {SessionService} from '../services/session.service';
55
import {MatDialog} from '@angular/material/dialog';
66
import {LoadingModalComponent} from '../modals/loading-modal.component';
7-
import {HttpErrorResponse} from '@angular/common/http';
7+
import {HttpErrorResponse, HttpResponse} from '@angular/common/http';
8+
import {Subject, takeUntil} from 'rxjs';
89

9-
enum UploadStatus {
10+
enum RequestStatus {
1011
SUCCESS,
1112
FAIL,
1213
DEFAULT
@@ -17,18 +18,24 @@ enum UploadStatus {
1718
templateUrl: 'oncHistoryUpload.component.html',
1819
styleUrls: ['oncHistoryUpload.component.scss']
1920
})
20-
export class OncHistoryUploadComponent {
21-
public uploadStatus: UploadStatus = UploadStatus.DEFAULT;
21+
export class OncHistoryUploadComponent implements OnDestroy {
22+
public requestStatus: RequestStatus = RequestStatus.DEFAULT;
2223
public errorMessage: string;
2324
public selectedTextFile: File;
2425

26+
private subscriptionSubject = new Subject<void>();
27+
2528
constructor(private readonly dsmService: DSMService,
2629
private readonly session: SessionService,
2730
private readonly dialog: MatDialog) {}
2831

32+
ngOnDestroy(): void {
33+
this.subscriptionSubject.next();
34+
this.subscriptionSubject.complete();
35+
}
2936

3037
upload(): void {
31-
this.uploadStatus = UploadStatus.DEFAULT;
38+
this.requestStatus = RequestStatus.DEFAULT;
3239

3340
const tempDialog = this.dialog
3441
.open(LoadingModalComponent, {data: {message: 'Uploading, this may take a while'}, disableClose: true});
@@ -37,17 +44,12 @@ export class OncHistoryUploadComponent {
3744
this.session.selectedRealm,
3845
this.selectedTextFile
3946
).pipe(
47+
takeUntil(this.subscriptionSubject),
4048
finalize(() => tempDialog.close())
4149
)
4250
.subscribe({
43-
next: () => this.uploadStatus = UploadStatus.SUCCESS,
44-
error: (error: any) => {
45-
if (error instanceof HttpErrorResponse) {
46-
console.log(error);
47-
this.uploadStatus = UploadStatus.FAIL;
48-
this.errorMessage = error.error;
49-
}
50-
},
51+
next: () => this.requestStatus = RequestStatus.SUCCESS,
52+
error: (error: any) => this.handleError(error)
5153
});
5254
}
5355

@@ -57,4 +59,44 @@ export class OncHistoryUploadComponent {
5759
}
5860
this.selectedTextFile = file;
5961
}
62+
63+
public downloadTemplateAndDirectory(): void {
64+
const tempDialog = this.dialog
65+
.open(LoadingModalComponent, {data: {message: 'Downloading... this may take a while'}, disableClose: true});
66+
67+
this.dsmService.downloadOncHistoryTemplateAndDirectory(this.session.selectedRealm)
68+
.pipe(takeUntil(this.subscriptionSubject), finalize(() => tempDialog.close()))
69+
.subscribe({
70+
next: (response: HttpResponse<ArrayBuffer>) => {
71+
const arrayBuffer = response.body;
72+
const contentDisposition = response.headers.get('Content-Disposition');
73+
const blob = new Blob([arrayBuffer], {
74+
type: 'application/zip'
75+
});
76+
77+
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
78+
const matches = filenameRegex.exec(contentDisposition);
79+
let filename = 'Onc_history.zip'; // Default filename in case extraction fails
80+
if (matches != null && matches[1]) {
81+
filename = matches[1].replace(/['"]/g, '');
82+
}
83+
84+
const url = window.URL.createObjectURL(blob);
85+
const link = document.createElement('a');
86+
link.href = url;
87+
link.download = filename;
88+
89+
link.click();
90+
window.URL.revokeObjectURL(url);
91+
},
92+
error: (error: any) => this.handleError(error)
93+
});
94+
}
95+
96+
private handleError(error: any): void {
97+
if (error instanceof HttpErrorResponse) {
98+
this.requestStatus = RequestStatus.FAIL;
99+
this.errorMessage = error.error;
100+
}
101+
}
60102
}

ddp-workspace/projects/ddp-dsm-ui/src/app/services/dsm.service.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,16 @@ export class DSMService {
595595
);
596596
}
597597

598+
public downloadOncHistoryTemplateAndDirectory(realm: string): Observable<any> {
599+
const url = this.baseUrl + DSMService.UI + 'oncHistory/template';
600+
const map: { name: string; value: any }[] = [];
601+
map.push({name: DSMService.REALM, value: realm});
602+
603+
return this.http.get(url, this.buildZipDownloadHeader(map)).pipe(
604+
catchError(this.handleError)
605+
);
606+
}
607+
598608
public getKitTypes(realm: string): Observable<any> {
599609
const url = this.baseUrl + DSMService.UI + 'kitTypes/' + realm;
600610
const map: { name: string; value: any }[] = [];
@@ -1197,6 +1207,19 @@ export class DSMService {
11971207
return {headers: this.uploadHeader(), withCredentials: true, params};
11981208
}
11991209

1210+
private buildZipDownloadHeader(map: any[]): any {
1211+
let params: HttpParams = new HttpParams();
1212+
for (const param of map) {
1213+
params = params.append(param.name, param.value);
1214+
}
1215+
return {headers: this.zipDownloadHeaders(),
1216+
withCredentials: true,
1217+
params,
1218+
responseType: 'arraybuffer',
1219+
observe: 'response'
1220+
};
1221+
}
1222+
12001223
private buildJsonAuthHeader(): HttpHeaders {
12011224
if (this.checkCookieBeforeCall()) {
12021225
return new HttpHeaders({
@@ -1216,6 +1239,15 @@ export class DSMService {
12161239
}
12171240
}
12181241

1242+
private zipDownloadHeaders(): HttpHeaders {
1243+
if (this.checkCookieBeforeCall()) {
1244+
return new HttpHeaders({
1245+
'Content-Type': 'application/zip',
1246+
Authorization: this.sessionService.getAuthBearerHeaderValue()
1247+
} );
1248+
}
1249+
}
1250+
12191251
private uploadHeader(): HttpHeaders {
12201252
if (this.checkCookieBeforeCall()) {
12211253
return new HttpHeaders({

0 commit comments

Comments
 (0)