update file download service
This commit is contained in:
parent
0ca1c3b536
commit
5365c6c7e6
@ -14,5 +14,9 @@ max_line_length = 140
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.ts]
|
||||
ij_typescript_use_double_quotes = false
|
||||
ij_typescript_enforce_trailing_comma = keep
|
||||
|
||||
[{*.json, .prettierrc, .eslintrc}]
|
||||
indent_size = 2
|
||||
|
||||
@ -184,6 +184,7 @@
|
||||
"prefer-const": "error",
|
||||
"radix": "error",
|
||||
"curly": "error",
|
||||
"quotes": ["error", "single"],
|
||||
"comma-dangle": [
|
||||
"error",
|
||||
{
|
||||
|
||||
@ -1,22 +1,34 @@
|
||||
import { Component, forwardRef, Injector, OnInit } from '@angular/core';
|
||||
import { Component, forwardRef, Injector } from '@angular/core';
|
||||
import { FileDownloadService } from '@upload-download/services/file-download.service';
|
||||
import { DownloadStatusWrapper } from '@upload-download/model/download-status.wrapper';
|
||||
import { DownloadControllerService } from '@redaction/red-ui-http';
|
||||
import { CircleButtonTypes, DefaultListingServices, ListingComponent, LoadingService, TableColumnConfig } from '@iqser/common-ui';
|
||||
import { DownloadStatus } from '@upload-download/model/download-status';
|
||||
import {
|
||||
CircleButtonTypes,
|
||||
DefaultListingServicesTmp,
|
||||
EntitiesService,
|
||||
ListingComponent,
|
||||
LoadingService,
|
||||
TableColumnConfig,
|
||||
} from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { timer } from 'rxjs';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-downloads-list-screen',
|
||||
templateUrl: './downloads-list-screen.component.html',
|
||||
styleUrls: ['./downloads-list-screen.component.scss'],
|
||||
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DownloadsListScreenComponent) }],
|
||||
providers: [
|
||||
...DefaultListingServicesTmp,
|
||||
{ provide: EntitiesService, useExisting: FileDownloadService },
|
||||
{
|
||||
provide: ListingComponent,
|
||||
useExisting: forwardRef(() => DownloadsListScreenComponent),
|
||||
},
|
||||
],
|
||||
})
|
||||
export class DownloadsListScreenComponent extends ListingComponent<DownloadStatusWrapper> implements OnInit {
|
||||
export class DownloadsListScreenComponent extends ListingComponent<DownloadStatus> {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly tableHeaderLabel = _('downloads-list.table-header.title');
|
||||
readonly tableColumnConfigs: TableColumnConfig<DownloadStatusWrapper>[] = [
|
||||
readonly tableColumnConfigs: TableColumnConfig<DownloadStatus>[] = [
|
||||
{ label: _('downloads-list.table-col-names.name'), width: '2fr' },
|
||||
{ label: _('downloads-list.table-col-names.size') },
|
||||
{ label: _('downloads-list.table-col-names.date') },
|
||||
@ -28,37 +40,27 @@ export class DownloadsListScreenComponent extends ListingComponent<DownloadStatu
|
||||
private readonly _loadingService: LoadingService,
|
||||
readonly fileDownloadService: FileDownloadService,
|
||||
readonly routerHistoryService: RouterHistoryService,
|
||||
private readonly _downloadControllerService: DownloadControllerService,
|
||||
) {
|
||||
super(_injector);
|
||||
this._loadingService.loadWhile(this._loadData());
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this._loadingService.start();
|
||||
await this._loadData();
|
||||
this.addSubscription = timer(0, 5000).subscribe(async () => {
|
||||
await this._loadData();
|
||||
});
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
downloadItem(download: DownloadStatusWrapper) {
|
||||
downloadItem(download: DownloadStatus) {
|
||||
this._loadingService.loadWhile(this.fileDownloadService.performDownload(download));
|
||||
}
|
||||
|
||||
deleteItems(downloads?: DownloadStatusWrapper[]) {
|
||||
deleteItems(downloads?: DownloadStatus[]) {
|
||||
this._loadingService.loadWhile(this._deleteItems(downloads));
|
||||
}
|
||||
|
||||
private async _deleteItems(downloads?: DownloadStatusWrapper[]) {
|
||||
private async _deleteItems(downloads?: DownloadStatus[]) {
|
||||
const storageIds = (downloads || this.listingService.selected).map(d => d.storageId);
|
||||
await this._downloadControllerService.deleteDownload({ storageIds }).toPromise();
|
||||
await this.fileDownloadService.delete({ storageIds }).toPromise();
|
||||
this.listingService.setSelected([]);
|
||||
await this._loadData();
|
||||
}
|
||||
|
||||
private async _loadData() {
|
||||
await this.fileDownloadService.getDownloadStatus().toPromise();
|
||||
this.entitiesService.setEntities(this.fileDownloadService.downloads);
|
||||
await this.fileDownloadService.loadAll().toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,10 @@ export class FileDownloadBtnComponent extends AutoUnsubscribe implements OnDestr
|
||||
downloadFiles($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this.addSubscription = this._fileDownloadService
|
||||
.downloadFiles(this.files, this.dossier)
|
||||
.downloadFiles(
|
||||
this.files.map(f => f.fileId),
|
||||
this.dossier.dossierId,
|
||||
)
|
||||
.subscribe(() => this._toaster.info(_('download-status.queued')));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
import { DownloadFileType, DownloadStatusType, IDownloadStatus, List } from '@redaction/red-ui-http';
|
||||
import { IListable } from '@iqser/common-ui';
|
||||
|
||||
export class DownloadStatus implements IDownloadStatus, IListable {
|
||||
readonly creationDate?: string;
|
||||
readonly dossierId?: string;
|
||||
readonly downloadFileTypes?: List<DownloadFileType>;
|
||||
readonly fileIds?: List;
|
||||
readonly fileSize?: number;
|
||||
readonly filename?: string;
|
||||
readonly lastDownload?: string;
|
||||
readonly mimeType?: string;
|
||||
readonly status?: DownloadStatusType;
|
||||
readonly storageId?: string;
|
||||
readonly userId?: string;
|
||||
readonly size?: string;
|
||||
inProgress: boolean;
|
||||
|
||||
constructor(downloadStatus: IDownloadStatus) {
|
||||
this.creationDate = downloadStatus.creationDate;
|
||||
this.dossierId = downloadStatus.dossierId;
|
||||
this.downloadFileTypes = downloadStatus.downloadFileTypes;
|
||||
this.fileIds = downloadStatus.fileIds;
|
||||
this.fileSize = downloadStatus.fileSize;
|
||||
this.filename = downloadStatus.filename;
|
||||
this.lastDownload = downloadStatus.lastDownload;
|
||||
this.mimeType = downloadStatus.mimeType;
|
||||
this.status = downloadStatus.status;
|
||||
this.storageId = downloadStatus.storageId;
|
||||
this.userId = downloadStatus.userId;
|
||||
this.size = this._size;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.storageId;
|
||||
}
|
||||
|
||||
get searchKey(): string {
|
||||
return this.storageId;
|
||||
}
|
||||
|
||||
get isReady() {
|
||||
return this.status === 'READY';
|
||||
}
|
||||
|
||||
private get _size() {
|
||||
const i = this.fileSize === 0 ? 0 : Math.floor(Math.log(this.fileSize) / Math.log(1024));
|
||||
return (this.fileSize / Math.pow(1024, i)).toFixed(2) + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
|
||||
}
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
import { DownloadStatus } from '@redaction/red-ui-http';
|
||||
import { IListable } from '@iqser/common-ui';
|
||||
|
||||
export class DownloadStatusWrapper implements IListable {
|
||||
inProgress: boolean;
|
||||
|
||||
constructor(private _downloadStatus: DownloadStatus) {}
|
||||
|
||||
get id() {
|
||||
return this.storageId;
|
||||
}
|
||||
|
||||
get searchKey(): string {
|
||||
return this.storageId;
|
||||
}
|
||||
|
||||
get size() {
|
||||
const i = this._downloadStatus.fileSize === 0 ? 0 : Math.floor(Math.log(this._downloadStatus.fileSize) / Math.log(1024));
|
||||
return (this._downloadStatus.fileSize / Math.pow(1024, i)).toFixed(2) + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
|
||||
}
|
||||
|
||||
get creationDate() {
|
||||
return this._downloadStatus.creationDate;
|
||||
}
|
||||
|
||||
get filename() {
|
||||
return this._downloadStatus.filename;
|
||||
}
|
||||
|
||||
get lastDownload() {
|
||||
return this._downloadStatus.lastDownload;
|
||||
}
|
||||
|
||||
get mimeType() {
|
||||
return this._downloadStatus.mimeType;
|
||||
}
|
||||
|
||||
get dossierId() {
|
||||
return this._downloadStatus.dossierId;
|
||||
}
|
||||
|
||||
get isReady() {
|
||||
return this._downloadStatus.status === 'READY';
|
||||
}
|
||||
|
||||
get status() {
|
||||
return this._downloadStatus.status;
|
||||
}
|
||||
|
||||
get storageId() {
|
||||
return this._downloadStatus.storageId;
|
||||
}
|
||||
}
|
||||
@ -1,59 +1,57 @@
|
||||
import { ApplicationRef, Injectable } from '@angular/core';
|
||||
import { DownloadControllerService, FileManagementControllerService } from '@redaction/red-ui-http';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import {
|
||||
DownloadResponse,
|
||||
DownloadStatusResponse,
|
||||
IDownloadStatus,
|
||||
PrepareDownloadRequest,
|
||||
RemoveDownloadRequest,
|
||||
} from '@redaction/red-ui-http';
|
||||
import { interval, Observable } from 'rxjs';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Dossier } from '@state/model/dossier';
|
||||
import { File } from '@models/file/file';
|
||||
import { mergeMap, tap } from 'rxjs/operators';
|
||||
import { DownloadStatusWrapper } from '../model/download-status.wrapper';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { map, mergeMap, tap } from 'rxjs/operators';
|
||||
import { DownloadStatus } from '../model/download-status';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { List } from '@iqser/common-ui';
|
||||
import { EntitiesService, List, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
|
||||
@Injectable()
|
||||
export class FileDownloadService {
|
||||
downloads: DownloadStatusWrapper[] = [];
|
||||
|
||||
hasPendingDownloads;
|
||||
export class FileDownloadService extends EntitiesService<DownloadStatus, IDownloadStatus> {
|
||||
hasPendingDownloads = false;
|
||||
|
||||
constructor(
|
||||
private readonly _userService: UserService,
|
||||
private readonly _applicationRef: ApplicationRef,
|
||||
private readonly _keycloakService: KeycloakService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _configService: ConfigService,
|
||||
private readonly _downloadControllerService: DownloadControllerService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
protected readonly _injector: Injector,
|
||||
) {
|
||||
super(_injector, DownloadStatus, 'async/download');
|
||||
interval(5000).subscribe(() => {
|
||||
if (_userService.currentUser.isUser) {
|
||||
this.getDownloadStatus().subscribe(() => {});
|
||||
this.loadAll().subscribe(() => {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
downloadFiles(files: List<File>, dossier: Dossier): Observable<any> {
|
||||
return this._downloadControllerService
|
||||
.prepareDownload({
|
||||
fileIds: files.map(f => f.fileId),
|
||||
dossierId: dossier.id,
|
||||
})
|
||||
.pipe(mergeMap(() => this.getDownloadStatus()));
|
||||
downloadFiles(fileIds: List, dossierId: string): Observable<any> {
|
||||
return this.prepareDownload({
|
||||
fileIds,
|
||||
dossierId,
|
||||
}).pipe(mergeMap(() => this.loadAll()));
|
||||
}
|
||||
|
||||
getDownloadStatus() {
|
||||
return this._downloadControllerService.getDownloadStatus().pipe(
|
||||
tap(statusResponse => {
|
||||
this.downloads = statusResponse.downloadStatus.map(d => new DownloadStatusWrapper(d));
|
||||
this.hasPendingDownloads = !!this.downloads.find(f => !f.lastDownload && f.isReady);
|
||||
}),
|
||||
loadAll(): Observable<DownloadStatus[]> {
|
||||
return this.getStatuses().pipe(
|
||||
map(entities => entities.map(entity => new DownloadStatus(entity))),
|
||||
tap(entities => this.setEntities(entities)),
|
||||
tap(() => (this.hasPendingDownloads = !!this.all.find(f => !f.lastDownload && f.isReady))),
|
||||
);
|
||||
}
|
||||
|
||||
async performDownload(status: DownloadStatusWrapper) {
|
||||
getStatuses(): Observable<IDownloadStatus[]> {
|
||||
return super._getOne<DownloadStatusResponse>(['status']).pipe(map(res => res.downloadStatus));
|
||||
}
|
||||
|
||||
async performDownload(status: DownloadStatus) {
|
||||
const token = await this._keycloakService.getToken();
|
||||
const anchor = document.createElement('a');
|
||||
anchor.href = `${this._configService.values.API_URL}/async/download?access_token=${encodeURIComponent(
|
||||
@ -66,4 +64,14 @@ export class FileDownloadService {
|
||||
anchor.click();
|
||||
document.body.removeChild(anchor);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
prepareDownload(@RequiredParam() body: PrepareDownloadRequest): Observable<DownloadResponse> {
|
||||
return this._post(body, `${this._defaultModelPath}/prepare`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
delete(@RequiredParam() body: RemoveDownloadRequest): Observable<unknown> {
|
||||
return super._post(body, `${this._defaultModelPath}/delete`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
|
||||
import { Configuration } from './configuration';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DownloadControllerService } from './api/downloadController.service';
|
||||
import { FileManagementControllerService } from './api/fileManagementController.service';
|
||||
import { GeneralSettingsControllerService } from './api/generalSettingsController.service';
|
||||
import { InfoControllerService } from './api/infoController.service';
|
||||
@ -26,7 +25,6 @@ import { StatusReportControllerService } from './api/statusReportController.serv
|
||||
declarations: [],
|
||||
exports: [],
|
||||
providers: [
|
||||
DownloadControllerService,
|
||||
FileManagementControllerService,
|
||||
GeneralSettingsControllerService,
|
||||
InfoControllerService,
|
||||
|
||||
@ -11,5 +11,5 @@
|
||||
*/
|
||||
|
||||
export interface DownloadResponse {
|
||||
storageId?: string;
|
||||
readonly storageId?: string;
|
||||
}
|
||||
|
||||
@ -9,35 +9,27 @@
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
import { DownloadFileType } from './dossier';
|
||||
import { List } from '../red-types';
|
||||
|
||||
export interface DownloadStatus {
|
||||
creationDate?: string;
|
||||
dossierId?: string;
|
||||
downloadFileTypes?: Array<DownloadStatus.DownloadFileTypesEnum>;
|
||||
fileIds?: Array<string>;
|
||||
fileSize?: number;
|
||||
filename?: string;
|
||||
lastDownload?: string;
|
||||
mimeType?: string;
|
||||
status?: DownloadStatus.StatusEnum;
|
||||
storageId?: string;
|
||||
userId?: string;
|
||||
export interface IDownloadStatus {
|
||||
readonly creationDate?: string;
|
||||
readonly dossierId?: string;
|
||||
readonly downloadFileTypes?: List<DownloadFileType>;
|
||||
readonly fileIds?: List;
|
||||
readonly fileSize?: number;
|
||||
readonly filename?: string;
|
||||
readonly lastDownload?: string;
|
||||
readonly mimeType?: string;
|
||||
readonly status?: DownloadStatusType;
|
||||
readonly storageId?: string;
|
||||
readonly userId?: string;
|
||||
}
|
||||
|
||||
export namespace DownloadStatus {
|
||||
export type DownloadFileTypesEnum = 'ANNOTATED' | 'FLATTEN' | 'ORIGINAL' | 'PREVIEW' | 'REDACTED';
|
||||
export const DownloadFileTypesEnum = {
|
||||
ANNOTATED: 'ANNOTATED' as DownloadFileTypesEnum,
|
||||
FLATTEN: 'FLATTEN' as DownloadFileTypesEnum,
|
||||
ORIGINAL: 'ORIGINAL' as DownloadFileTypesEnum,
|
||||
PREVIEW: 'PREVIEW' as DownloadFileTypesEnum,
|
||||
REDACTED: 'REDACTED' as DownloadFileTypesEnum,
|
||||
};
|
||||
export type StatusEnum = 'FAILED' | 'GENERATING' | 'QUEUED' | 'READY';
|
||||
export const StatusEnum = {
|
||||
FAILED: 'FAILED' as StatusEnum,
|
||||
GENERATING: 'GENERATING' as StatusEnum,
|
||||
QUEUED: 'QUEUED' as StatusEnum,
|
||||
READY: 'READY' as StatusEnum,
|
||||
};
|
||||
}
|
||||
export const DownloadStatuses = {
|
||||
FAILED: 'FAILED',
|
||||
GENERATING: 'GENERATING',
|
||||
QUEUED: 'QUEUED',
|
||||
READY: 'READY',
|
||||
} as const;
|
||||
export type DownloadStatusType = keyof typeof DownloadStatuses;
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
import { DownloadStatus } from './downloadStatus';
|
||||
import { IDownloadStatus } from './downloadStatus';
|
||||
|
||||
export interface DownloadStatusResponse {
|
||||
downloadStatus?: Array<DownloadStatus>;
|
||||
downloadStatus?: IDownloadStatus[];
|
||||
}
|
||||
|
||||
@ -10,10 +10,12 @@
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { List } from '../red-types';
|
||||
|
||||
/**
|
||||
* Object containing information on which file and report types should be included in the download.
|
||||
*/
|
||||
export interface PrepareDownloadRequest {
|
||||
dossierId?: string;
|
||||
fileIds?: Array<string>;
|
||||
readonly dossierId?: string;
|
||||
readonly fileIds?: List;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user