TSK-1675: fix import function to go through http interceptor (#1737)
This commit is contained in:
parent
d922d8a178
commit
6124db01ad
|
@ -1,5 +1,5 @@
|
|||
<div class="import-export">
|
||||
<button mat-stroked-button class="mr-1" matTooltip="Import {{parentComponent}}" [ngClass]="{disabled: uploadService?.isInUse}" (click)="selectedFile.click()" title="Import">
|
||||
<button mat-stroked-button class="mr-1" matTooltip="Import {{parentComponent}}" (click)="selectedFile.click()" title="Import">
|
||||
Import
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
</button>
|
||||
|
@ -8,7 +8,7 @@
|
|||
<input #selectedFile type="file" accept=".json" (change)="uploadFile()" class="hidden" />
|
||||
</form>
|
||||
|
||||
<button mat-stroked-button class="mr-1" matTooltip="Export {{parentComponent}}" [matMenuTriggerFor]="menu" [ngClass]="{disabled: uploadService?.isInUse}" title="Export">
|
||||
<button mat-stroked-button class="mr-1" matTooltip="Export {{parentComponent}}" [matMenuTriggerFor]="menu" title="Export">
|
||||
Export
|
||||
<mat-icon>cloud_download</mat-icon>
|
||||
</button>
|
||||
|
@ -16,7 +16,7 @@
|
|||
<button mat-menu-item href="javascript:void(0)" (click)="export()">
|
||||
All Domains
|
||||
</button>
|
||||
<button mat-menu-item *ngFor="let domain of domains" href="javascript:void(0)" (click)="export(domain)">
|
||||
<button mat-menu-item *ngFor="let domain of (domains$ | async)" href="javascript:void(0)" (click)="export(domain)">
|
||||
{{domain === '' ? 'Master' : domain}}
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
|
|
@ -7,7 +7,6 @@ import { WindowRefService } from '../../../shared/services/window/window.service
|
|||
import { DomainService } from '../../../shared/services/domain/domain.service';
|
||||
import { WorkbasketDefinitionService } from '../../services/workbasket-definition.service';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { UploadService } from '../../../shared/services/upload/upload.service';
|
||||
import { ImportExportService } from '../../services/import-export.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { of } from 'rxjs';
|
||||
|
@ -56,7 +55,6 @@ xdescribe('ImportExportComponent', () => {
|
|||
WindowRefService,
|
||||
WorkbasketDefinitionService,
|
||||
ClassificationDefinitionService,
|
||||
UploadService,
|
||||
ImportExportService,
|
||||
{ provide: DomainService, useClass: domainServiceSpy },
|
||||
{ provide: NotificationService, useClass: notificationServiceSpy },
|
||||
|
|
|
@ -1,40 +1,45 @@
|
|||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ClassificationDefinitionService } from 'app/administration/services/classification-definition.service';
|
||||
import { WorkbasketDefinitionService } from 'app/administration/services/workbasket-definition.service';
|
||||
import { DomainService } from 'app/shared/services/domain/domain.service';
|
||||
import { TaskanaType } from 'app/shared/models/taskana-type';
|
||||
import { environment } from 'environments/environment';
|
||||
import { UploadService } from 'app/shared/services/upload/upload.service';
|
||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { HotToastService } from '@ngneat/hot-toast';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Recommendation: Turn this component into presentational component - no logic, instead events are
|
||||
* fired back to parent components with @Output(). This way the logic of exporting/importing workbasket
|
||||
* or classification is stored in their respective container component.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'taskana-administration-import-export',
|
||||
templateUrl: './import-export.component.html',
|
||||
styleUrls: ['./import-export.component.scss']
|
||||
})
|
||||
export class ImportExportComponent implements OnInit {
|
||||
export class ImportExportComponent implements OnInit, OnDestroy {
|
||||
@Input() currentSelection: TaskanaType;
|
||||
@Input() parentComponent: string;
|
||||
|
||||
@ViewChild('selectedFile', { static: true })
|
||||
selectedFileInput;
|
||||
|
||||
domains: string[] = [];
|
||||
domains$: Observable<string[]>;
|
||||
destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private domainService: DomainService,
|
||||
private workbasketDefinitionService: WorkbasketDefinitionService,
|
||||
private classificationDefinitionService: ClassificationDefinitionService,
|
||||
public uploadService: UploadService,
|
||||
private notificationService: NotificationService,
|
||||
private importExportService: ImportExportService
|
||||
private importExportService: ImportExportService,
|
||||
private hotToastService: HotToastService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.domainService.getDomains().subscribe((data) => {
|
||||
this.domains = data;
|
||||
});
|
||||
this.domains$ = this.domainService.getDomains();
|
||||
}
|
||||
|
||||
export(domain = '') {
|
||||
|
@ -47,31 +52,42 @@ export class ImportExportComponent implements OnInit {
|
|||
|
||||
uploadFile() {
|
||||
const file = this.selectedFileInput.nativeElement.files[0];
|
||||
const formdata = new FormData();
|
||||
const ajax = new XMLHttpRequest();
|
||||
if (this.checkFormatFile(file)) {
|
||||
formdata.append('file', file);
|
||||
ajax.upload.addEventListener('progress', this.progressHandler.bind(this), false);
|
||||
ajax.addEventListener('load', this.resetProgress.bind(this), false);
|
||||
ajax.addEventListener('error', this.onFailedResponse.bind(this, ajax), false);
|
||||
ajax.onreadystatechange = this.onReadyStateChangeHandler.bind(this, ajax);
|
||||
if (this.currentSelection === TaskanaType.WORKBASKETS) {
|
||||
ajax.open('POST', `${environment.taskanaRestUrl}/v1/workbasket-definitions`);
|
||||
this.workbasketDefinitionService
|
||||
.importWorkbasket(file)
|
||||
.pipe(
|
||||
takeUntil(this.destroy$),
|
||||
this.hotToastService.observe({
|
||||
loading: 'Uploading...',
|
||||
success: 'File successfully uploaded',
|
||||
error: 'Upload failed'
|
||||
})
|
||||
)
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.importExportService.setImportingFinished(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ajax.open('POST', `${environment.taskanaRestUrl}/v1/classification-definitions`);
|
||||
this.classificationDefinitionService
|
||||
.importClassification(file)
|
||||
.pipe(
|
||||
takeUntil(this.destroy$),
|
||||
this.hotToastService.observe({
|
||||
loading: 'Uploading...',
|
||||
success: 'File successfully uploaded',
|
||||
error: 'Upload failed'
|
||||
})
|
||||
)
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.importExportService.setImportingFinished(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!environment.production) {
|
||||
ajax.setRequestHeader('Authorization', 'Basic YWRtaW46YWRtaW4=');
|
||||
}
|
||||
ajax.send(formdata);
|
||||
this.uploadService.isInUse = true;
|
||||
this.uploadService.setCurrentProgressValue(1);
|
||||
}
|
||||
}
|
||||
|
||||
progressHandler(event) {
|
||||
const percent = (event.loaded / event.total) * 100;
|
||||
this.uploadService.setCurrentProgressValue(Math.round(percent));
|
||||
this.resetProgress();
|
||||
}
|
||||
|
||||
private checkFormatFile(file): boolean {
|
||||
|
@ -87,40 +103,11 @@ export class ImportExportComponent implements OnInit {
|
|||
}
|
||||
|
||||
private resetProgress() {
|
||||
this.uploadService.setCurrentProgressValue(0);
|
||||
this.uploadService.isInUse = false;
|
||||
this.selectedFileInput.nativeElement.value = '';
|
||||
}
|
||||
|
||||
private onReadyStateChangeHandler(event) {
|
||||
if (event.readyState === 4 && event.status >= 400) {
|
||||
let key = 'FALLBACK';
|
||||
|
||||
if (event.status === 401) {
|
||||
key = 'IMPORT_EXPORT_UPLOAD_FAILED_AUTH';
|
||||
} else if (event.status === 404) {
|
||||
key = 'IMPORT_EXPORT_UPLOAD_FAILED_NOT_FOUND';
|
||||
} else if (event.status === 409) {
|
||||
key = 'IMPORT_EXPORT_UPLOAD_FAILED_CONFLICTS';
|
||||
} else if (event.status === 413) {
|
||||
key = 'IMPORT_EXPORT_UPLOAD_FAILED_SIZE';
|
||||
}
|
||||
this.errorHandler(key);
|
||||
} else if (event.readyState === 4 && event.status === 204) {
|
||||
const message = this.currentSelection === TaskanaType.WORKBASKETS ? 'WORKBASKET_IMPORT' : 'CLASSIFICATION_IMPORT';
|
||||
this.notificationService.showSuccess(message);
|
||||
this.importExportService.setImportingFinished(true);
|
||||
this.resetProgress();
|
||||
}
|
||||
}
|
||||
|
||||
private onFailedResponse() {
|
||||
this.errorHandler('IMPORT_EXPORT_UPLOAD_FAILED');
|
||||
}
|
||||
|
||||
private errorHandler(key: string) {
|
||||
this.notificationService.showError(key);
|
||||
delete this.selectedFileInput.files;
|
||||
this.resetProgress();
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
||||
import { BlobGenerator } from 'app/shared/util/blob-generator';
|
||||
import { Classification } from '../../shared/models/classification';
|
||||
|
@ -24,4 +24,11 @@ export class ClassificationDefinitionService {
|
|||
);
|
||||
return classificationDefObservable;
|
||||
}
|
||||
|
||||
importClassification(file: File) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const headers = new HttpHeaders().set('Content-Type', 'multipart/form-data');
|
||||
return this.httpClient.post(this.url, formData, { headers });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { environment } from 'environments/environment';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { WorkbasketDefinition } from 'app/shared/models/workbasket-definition';
|
||||
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
||||
import { BlobGenerator } from 'app/shared/util/blob-generator';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import { StartupService } from '../../shared/services/startup/startup.service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkbasketDefinitionService {
|
||||
url: string = `${environment.taskanaRestUrl}/v1/workbasket-definitions`;
|
||||
constructor(private httpClient: HttpClient, private startupService: StartupService) {}
|
||||
|
||||
constructor(private httpClient: HttpClient) {}
|
||||
get url(): string {
|
||||
return this.startupService.getTaskanaRestUrl() + '/v1/workbasket-definitions';
|
||||
}
|
||||
|
||||
// GET
|
||||
exportWorkbaskets(domain: string): Observable<WorkbasketDefinition[]> {
|
||||
|
@ -22,4 +24,11 @@ export class WorkbasketDefinitionService {
|
|||
);
|
||||
return workbasketDefObservable;
|
||||
}
|
||||
|
||||
importWorkbasket(file: File) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const headers = new HttpHeaders().set('Content-Type', 'multipart/form-data');
|
||||
return this.httpClient.post(this.url, formData, { headers });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
<mat-progress-bar *ngIf="requestInProgress" mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
<taskana-shared-progress-spinner
|
||||
[hidden]="currentProgressValue === 0" currentValue={{currentProgressValue}}>
|
||||
</taskana-shared-progress-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
|
|
|
@ -6,7 +6,6 @@ import { SidenavService } from './shared/services/sidenav/sidenav.service';
|
|||
import { RequestInProgressService } from './shared/services/request-in-progress/request-in-progress.service';
|
||||
import { OrientationService } from './shared/services/orientation/orientation.service';
|
||||
import { SelectedRouteService } from './shared/services/selected-route/selected-route';
|
||||
import { UploadService } from './shared/services/upload/upload.service';
|
||||
import { TaskanaEngineService } from './shared/services/taskana-engine/taskana-engine.service';
|
||||
import { WindowRefService } from 'app/shared/services/window/window.service';
|
||||
import { environment } from 'environments/environment';
|
||||
|
@ -23,7 +22,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
selectedRoute = '';
|
||||
|
||||
requestInProgress = false;
|
||||
currentProgressValue = 0;
|
||||
|
||||
version: string;
|
||||
toggle: boolean = false;
|
||||
|
@ -36,7 +34,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
private orientationService: OrientationService,
|
||||
private selectedRouteService: SelectedRouteService,
|
||||
private formsValidatorService: FormsValidatorService,
|
||||
public uploadService: UploadService,
|
||||
private sidenavService: SidenavService,
|
||||
private taskanaEngineService: TaskanaEngineService,
|
||||
private window: WindowRefService
|
||||
|
@ -76,13 +73,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
this.selectedRoute = value;
|
||||
});
|
||||
|
||||
this.uploadService
|
||||
.getCurrentProgressObservable()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((value) => {
|
||||
this.currentProgressValue = value;
|
||||
});
|
||||
|
||||
this.taskanaEngineService
|
||||
.getVersion()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
|
|
|
@ -39,7 +39,6 @@ import { NavBarComponent } from 'app/shared/components/nav-bar/nav-bar.component
|
|||
import { UserInformationComponent } from 'app/shared/components/user-information/user-information.component';
|
||||
import { NoAccessComponent } from 'app/shared/components/no-access/no-access.component';
|
||||
import { FormsValidatorService } from './shared/services/forms-validator/forms-validator.service';
|
||||
import { UploadService } from './shared/services/upload/upload.service';
|
||||
import { NotificationService } from './shared/services/notifications/notification.service';
|
||||
import { SidenavService } from './shared/services/sidenav/sidenav.service';
|
||||
import { SidenavListComponent } from 'app/shared/components/sidenav-list/sidenav-list.component';
|
||||
|
@ -105,7 +104,6 @@ const PROVIDERS = [
|
|||
MasterAndDetailService,
|
||||
TaskanaEngineService,
|
||||
FormsValidatorService,
|
||||
UploadService,
|
||||
NotificationService,
|
||||
ClassificationCategoriesService,
|
||||
SidenavService,
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UploadService {
|
||||
private currentProgressValue = new Subject<number>();
|
||||
public isInUse = false;
|
||||
|
||||
setCurrentProgressValue(value: number) {
|
||||
this.currentProgressValue.next(value);
|
||||
}
|
||||
|
||||
getCurrentProgressObservable(): Observable<number> {
|
||||
return this.currentProgressValue.asObservable();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue