From d2bd5e848429451af55da0d9b62a56b3168978c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Wed, 16 Jun 2021 14:55:20 +0300 Subject: [PATCH] Bulk delete templates & dictionaries & other fixes --- README.md | 8 +- .../dictionary-listing-screen.component.html | 14 +- .../dictionary-listing-screen.component.ts | 29 ++-- .../dictionary-overview-screen.component.ts | 12 +- ...er-templates-listing-screen.component.html | 12 ++ ...sier-templates-listing-screen.component.ts | 17 ++ .../admin/services/admin-dialog.service.ts | 26 ++- .../annotation-icon.component.ts | 6 +- apps/red-ui/src/assets/i18n/en.json | 6 + .../lib/api/dictionaryController.service.ts | 163 ++++++++++++++++-- .../api/dossierTemplateController.service.ts | 79 ++++++++- 11 files changed, 324 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 37fc10af1..49fa5d365 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ To re-generate http rune swagger YOu need swagger-codegen installed `brew install swagger-codegen` ``` -BASE=https://dev-08.iqser.cloud/ +BASE=https://dev-06.iqser.cloud/ URL="$BASE"redaction-gateway-v1/v2/api-docs?group=redaction-gateway-v1 rm -Rf /tmp/swagger mkdir -p /tmp/swagger @@ -17,10 +17,8 @@ cd /tmp/swagger ## To Create a new Stack in rancher -Goto rancher.iqser.com: Select Cluster `Development`, -go to apps, click launch and select `Redaction` from the `dev` section. -Add a new name and a new namespace. -Select `answers-development.yaml` and add it to answers `Edit as yaml`. +Goto rancher.iqser.com: Select Cluster `Development`, go to apps, click launch and select `Redaction` from the `dev` +section. Add a new name and a new namespace. Select `answers-development.yaml` and add it to answers `Edit as yaml`. For HTTPS / Cloudflare domain go to `workloads` -> `Loadbalancing` -> `select your stack` Add cloudflare certificate and specify a hostname to use `timo-redaction-dev.iqser.cloud` diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html index 309067414..e0f1fd189 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html @@ -36,6 +36,18 @@ }} + + + + + +
{ + this.selectedEntitiesIds = []; + this.loading = true; + await this._appStateService.loadDictionaryData(); + this._loadDictionaryData(); + this.loading = false; + } + ); + } + openAddEditDictionaryDialog($event?: MouseEvent, dict?: TypeValueWrapper) { $event?.stopPropagation(); this._dialogService.openAddEditDictionaryDialog( @@ -57,18 +74,6 @@ export class DictionaryListingScreenComponent ); } - openDeleteDictionaryDialog($event: any, dict: TypeValueWrapper) { - this._dialogService.openDeleteDictionaryDialog( - $event, - dict, - this._appStateService.activeDossierTemplateId, - async () => { - await this._appStateService.loadDictionaryData(); - this._loadDictionaryData(); - } - ); - } - private _loadDictionaryData() { const appStateDictionaryData = this._appStateService.dictionaryData[this._appStateService.activeDossierTemplateId]; diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts index 4c3031908..5f34c2bc7 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts @@ -65,13 +65,19 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple } openDeleteDictionaryDialog($event: any) { - this._dialogService.openDeleteDictionaryDialog( + this._dialogService.openDeleteDictionariesDialog( $event, - this.dictionary, + [this.dictionary.type], this.dictionary.dossierTemplateId, async () => { await this._appStateService.loadDictionaryData(); - this._router.navigate(['..']); + this._router.navigate([ + '/main', + 'admin', + 'dossier-templates', + this._appStateService.activeDossierTemplateId, + 'dictionaries' + ]); } ); } diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html index 607454d67..00b64cdb4 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html @@ -34,6 +34,18 @@ }} + + + + + +
implements OnInit { + loading = false; protected readonly _searchKey = 'name'; protected readonly _selectionKey = 'dossierTemplateId'; protected readonly _sortKey = 'dossier-templates-listing'; @@ -33,6 +34,22 @@ export class DossierTemplatesListingScreenComponent this.loadDossierTemplatesData(); } + openDeleteTemplatesDialog($event?: MouseEvent) { + $event?.stopPropagation(); + this._dialogService.openBulkDeleteDossierTemplatesDialog( + $event, + this.selectedEntitiesIds, + async () => { + this.selectedEntitiesIds = []; + this.loading = true; + await this._appStateService.loadAllDossierTemplates(); + await this._appStateService.loadDictionaryData(); + this.loadDossierTemplatesData(); + this.loading = false; + } + ); + } + loadDossierTemplatesData() { this._appStateService.reset(); this.allEntities = this._appStateService.dossierTemplates; diff --git a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts index bcb8823ef..3bf3ebd0c 100644 --- a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts +++ b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts @@ -53,9 +53,9 @@ export class AdminDialogService { private readonly _manualRedactionControllerService: ManualRedactionControllerService ) {} - openDeleteDictionaryDialog( + openDeleteDictionariesDialog( $event: MouseEvent, - dictionary: TypeValueWrapper, + dictionaryTypes: string[], dossierTemplateId: string, cb?: Function ): MatDialogRef { @@ -64,7 +64,7 @@ export class AdminDialogService { ref.afterClosed().subscribe(async result => { if (result) { await this._dictionaryControllerService - .deleteType(dictionary.type, dossierTemplateId) + .deleteTypes(dictionaryTypes, dossierTemplateId) .toPromise(); if (cb) cb(); } @@ -82,7 +82,25 @@ export class AdminDialogService { ref.afterClosed().subscribe(async result => { if (result) { await this._dossierTemplateControllerService - .getAllDossierTemplates(dossierTemplate.dossierTemplateId) + .deleteDossierTemplate(dossierTemplate.dossierTemplateId) + .toPromise(); + if (cb) await cb(); + } + }); + return ref; + } + + openBulkDeleteDossierTemplatesDialog( + $event: MouseEvent, + dossierTemplateIds: string[], + cb?: Function + ): MatDialogRef { + $event.stopPropagation(); + const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig); + ref.afterClosed().subscribe(async result => { + if (result) { + await this._dossierTemplateControllerService + .deleteDossierTemplates(dossierTemplateIds) .toPromise(); if (cb) await cb(); } diff --git a/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts b/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts index 6d0fcc49a..b66f0a1be 100644 --- a/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts @@ -1,4 +1,4 @@ -import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, ElementRef, Input, OnChanges, ViewChild } from '@angular/core'; import { TypeValueWrapper } from '@models/file/type-value.wrapper'; @Component({ @@ -6,7 +6,7 @@ import { TypeValueWrapper } from '@models/file/type-value.wrapper'; templateUrl: './annotation-icon.component.html', styleUrls: ['./annotation-icon.component.scss'] }) -export class AnnotationIconComponent implements OnInit { +export class AnnotationIconComponent implements OnChanges { @Input() color: string; @Input() type: 'square' | 'rhombus' | 'circle' | 'hexagon' | 'none'; @Input() label: string; @@ -32,7 +32,7 @@ export class AnnotationIconComponent implements OnInit { return this.color || this.dictType?.hexColor; } - ngOnInit() { + ngOnChanges() { this.icon.nativeElement.style.setProperty('--color', this.backgroundColor); } } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index eb40dc686..5df2d4ec2 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -774,6 +774,9 @@ "delete": "Delete Dictionary", "edit": "Edit Dictionary" }, + "bulk": { + "delete": "Delete Selected Dictionaries" + }, "case-sensitive": "Case Sensitive", "add-new": "New Dictionary", "stats": { @@ -806,6 +809,9 @@ "table-header": { "title": "{{length}} dossier templates" }, + "bulk": { + "delete": "Delete Selected Dossier Templates" + }, "entries": "{{length}} entries", "dictionaries": "{{length}} dictionaries", "action": { diff --git a/libs/red-ui-http/src/lib/api/dictionaryController.service.ts b/libs/red-ui-http/src/lib/api/dictionaryController.service.ts index b3faa1b25..883cdeb16 100644 --- a/libs/red-ui-http/src/lib/api/dictionaryController.service.ts +++ b/libs/red-ui-http/src/lib/api/dictionaryController.service.ts @@ -27,9 +27,9 @@ import { Configuration } from '../configuration'; @Injectable() export class DictionaryControllerService { - protected basePath = ''; public defaultHeaders = new HttpHeaders(); public configuration = new Configuration(); + protected basePath = ''; constructor( protected httpClient: HttpClient, @@ -45,20 +45,6 @@ export class DictionaryControllerService { } } - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - /** * Add dictionary entries with entry type. * None @@ -79,6 +65,7 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public addEntry( body: Array, dossierTemplateId: string, @@ -88,6 +75,7 @@ export class DictionaryControllerService { observe?: 'response', reportProgress?: boolean ): Observable>; + public addEntry( body: Array, dossierTemplateId: string, @@ -97,6 +85,7 @@ export class DictionaryControllerService { observe?: 'events', reportProgress?: boolean ): Observable>; + public addEntry( body: Array, dossierTemplateId: string, @@ -185,18 +174,21 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public addType( body: TypeValue, dossierId?: string, observe?: 'response', reportProgress?: boolean ): Observable>; + public addType( body: TypeValue, dossierId?: string, observe?: 'events', reportProgress?: boolean ): Observable>; + public addType( body: TypeValue, dossierId?: string, @@ -267,6 +259,7 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public deleteEntries( body: Array, dossierTemplateId: string, @@ -275,6 +268,7 @@ export class DictionaryControllerService { observe?: 'response', reportProgress?: boolean ): Observable>; + public deleteEntries( body: Array, dossierTemplateId: string, @@ -283,6 +277,7 @@ export class DictionaryControllerService { observe?: 'events', reportProgress?: boolean ): Observable>; + public deleteEntries( body: Array, dossierTemplateId: string, @@ -375,6 +370,7 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public deleteEntry( dossierTemplateId: string, entry: string, @@ -383,6 +379,7 @@ export class DictionaryControllerService { observe?: 'response', reportProgress?: boolean ): Observable>; + public deleteEntry( dossierTemplateId: string, entry: string, @@ -391,6 +388,7 @@ export class DictionaryControllerService { observe?: 'events', reportProgress?: boolean ): Observable>; + public deleteEntry( dossierTemplateId: string, entry: string, @@ -544,6 +542,106 @@ export class DictionaryControllerService { ); } + /** + * Deletes entry types + * None + * @param body types + * @param dossierTemplateId dossierTemplateId + * @param dossierId dossierId + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public deleteTypes( + body: Array, + dossierTemplateId: string, + dossierId?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + + public deleteTypes( + body: Array, + dossierTemplateId: string, + dossierId?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + + public deleteTypes( + body: Array, + dossierTemplateId: string, + dossierId?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + + public deleteTypes( + body: Array, + dossierTemplateId: string, + dossierId?: string, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + if (body === null || body === undefined) { + throw new Error( + 'Required parameter body was null or undefined when calling deleteTypes.' + ); + } + + if (dossierTemplateId === null || dossierTemplateId === undefined) { + throw new Error( + 'Required parameter dossierTemplateId was null or undefined when calling deleteTypes.' + ); + } + + let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (dossierId !== undefined && dossierId !== null) { + queryParameters = queryParameters.set('dossierId', dossierId); + } + + let headers = this.defaultHeaders; + + // authentication (RED-OAUTH) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = + this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected !== undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = + this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected !== undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'post', + `${this.basePath}/dictionary/type/${encodeURIComponent( + String(dossierTemplateId) + )}/delete`, + { + body: body, + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + /** * Returns file containing the the dictionary entries for given type.. * @@ -560,6 +658,7 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public downloadDictionaryFile( dossierTemplateId: string, type: string, @@ -567,6 +666,7 @@ export class DictionaryControllerService { observe?: 'response', reportProgress?: boolean ): Observable>; + public downloadDictionaryFile( dossierTemplateId: string, type: string, @@ -574,6 +674,7 @@ export class DictionaryControllerService { observe?: 'events', reportProgress?: boolean ): Observable>; + public downloadDictionaryFile( dossierTemplateId: string, type: string, @@ -646,18 +747,21 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public getAllTypes( dossierTemplateId: string, dossierId?: string, observe?: 'response', reportProgress?: boolean ): Observable>; + public getAllTypes( dossierTemplateId: string, dossierId?: string, observe?: 'events', reportProgress?: boolean ): Observable>; + public getAllTypes( dossierTemplateId: string, dossierId?: string, @@ -719,16 +823,19 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public getColors( dossierTemplateId: string, observe?: 'response', reportProgress?: boolean ): Observable>; + public getColors( dossierTemplateId: string, observe?: 'events', reportProgress?: boolean ): Observable>; + public getColors( dossierTemplateId: string, observe: any = 'body', @@ -787,6 +894,7 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public getDictionaryForType( dossierTemplateId: string, type: string, @@ -794,6 +902,7 @@ export class DictionaryControllerService { observe?: 'response', reportProgress?: boolean ): Observable>; + public getDictionaryForType( dossierTemplateId: string, type: string, @@ -801,6 +910,7 @@ export class DictionaryControllerService { observe?: 'events', reportProgress?: boolean ): Observable>; + public getDictionaryForType( dossierTemplateId: string, type: string, @@ -873,18 +983,21 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public setColors( body: Colors, dossierTemplateId: string, observe?: 'response', reportProgress?: boolean ): Observable>; + public setColors( body: Colors, dossierTemplateId: string, observe?: 'events', reportProgress?: boolean ): Observable>; + public setColors( body: Colors, dossierTemplateId: string, @@ -961,6 +1074,7 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public updateType( body: UpdateTypeValue, dossierTemplateId: string, @@ -969,6 +1083,7 @@ export class DictionaryControllerService { observe?: 'response', reportProgress?: boolean ): Observable>; + public updateType( body: UpdateTypeValue, dossierTemplateId: string, @@ -977,6 +1092,7 @@ export class DictionaryControllerService { observe?: 'events', reportProgress?: boolean ): Observable>; + public updateType( body: UpdateTypeValue, dossierTemplateId: string, @@ -1069,6 +1185,7 @@ export class DictionaryControllerService { observe?: 'body', reportProgress?: boolean ): Observable; + public uploadDictionaryFileForm( dossierTemplateId: string, type: string, @@ -1077,6 +1194,7 @@ export class DictionaryControllerService { observe?: 'response', reportProgress?: boolean ): Observable>; + public uploadDictionaryFileForm( dossierTemplateId: string, type: string, @@ -1085,6 +1203,7 @@ export class DictionaryControllerService { observe?: 'events', reportProgress?: boolean ): Observable>; + public uploadDictionaryFileForm( dossierTemplateId: string, type: string, @@ -1162,4 +1281,18 @@ export class DictionaryControllerService { } ); } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } } diff --git a/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts b/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts index d9014cffb..1c7b66194 100644 --- a/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts +++ b/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts @@ -117,31 +117,31 @@ export class DossierTemplateControllerService { } /** - * Get a specific DossierTemplate by its ID + * Delete a specific DossierTemplate by its ID * None * @param dossierTemplateId dossierTemplateId * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getAllDossierTemplates( + public deleteDossierTemplate( dossierTemplateId: string, observe?: 'body', reportProgress?: boolean ): Observable; - public getAllDossierTemplates( + public deleteDossierTemplate( dossierTemplateId: string, observe?: 'response', reportProgress?: boolean ): Observable>; - public getAllDossierTemplates( + public deleteDossierTemplate( dossierTemplateId: string, observe?: 'events', reportProgress?: boolean ): Observable>; - public getAllDossierTemplates( + public deleteDossierTemplate( dossierTemplateId: string, observe: any = 'body', reportProgress: boolean = false @@ -186,6 +186,75 @@ export class DossierTemplateControllerService { ); } + /** + * Delete multiple DossierTemplates by their IDs + * None + * @param body dossierTemplateIds + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public deleteDossierTemplates( + body: Array, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public deleteDossierTemplates( + body: Array, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public deleteDossierTemplates( + body: Array, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public deleteDossierTemplates( + body: Array, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + if (body === null || body === undefined) { + throw new Error( + 'Required parameter body was null or undefined when calling deleteDossierTemplates.' + ); + } + + let headers = this.defaultHeaders; + + // authentication (RED-OAUTH) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = + this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected !== undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = + this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected !== undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post', `${this.basePath}/dossier-template/delete`, { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + }); + } + /** * Lists all existing DossierTemplates. * None