From 46e016d55e8fa179b3dca9832502c7273e525efd Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Thu, 28 Mar 2024 12:27:36 +0200 Subject: [PATCH 01/21] RED-8748 - extracted file preview header logic in another component --- .../annotation-card.component.ts | 2 - .../file-header/file-header.component.html | 86 +++++++ .../file-header/file-header.component.scss | 9 + .../file-header/file-header.component.ts | 217 ++++++++++++++++++ ...component-management-dialog.component.html | 0 ...component-management-dialog.component.scss | 0 ...d-component-management-dialog.component.ts | 43 ++-- .../file-preview-screen.component.html | 91 +------- .../file-preview-screen.component.scss | 10 - .../file-preview-screen.component.ts | 178 +------------- .../file-preview/file-preview.module.ts | 2 + .../services/file-preview-dialog.service.ts | 14 +- .../services/pdf-proxy.service.ts | 8 +- apps/red-ui/src/assets/config/config.json | 10 +- 14 files changed, 359 insertions(+), 311 deletions(-) create mode 100644 apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html create mode 100644 apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.scss create mode 100644 apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.ts rename apps/red-ui/src/app/modules/file-preview/dialogs/{ => docu-mine}/structured-component-management-dialog/structured-component-management-dialog.component.html (100%) rename apps/red-ui/src/app/modules/file-preview/dialogs/{ => docu-mine}/structured-component-management-dialog/structured-component-management-dialog.component.scss (100%) rename apps/red-ui/src/app/modules/file-preview/dialogs/{ => docu-mine}/structured-component-management-dialog/structured-component-management-dialog.component.ts (89%) diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts index 322593075..8fb71348f 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts @@ -3,8 +3,6 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { MultiSelectService } from '../../services/multi-select.service'; import { annotationTypesTranslations } from '@translations/annotation-types-translations'; import { Roles } from '@users/roles'; -import { ImageCategory } from '../../utils/constants'; -import { ManualRedactionTypes } from '@red/domain'; @Component({ selector: 'redaction-annotation-card', diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html new file mode 100644 index 000000000..c351dfd24 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html @@ -0,0 +1,86 @@ + diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.scss b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.scss new file mode 100644 index 000000000..cc61e02a9 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.scss @@ -0,0 +1,9 @@ +.page-header { + max-width: 100vw; +} + +.actions-container { + display: flex; + justify-content: flex-end; + align-items: center; +} diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.ts b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.ts new file mode 100644 index 000000000..c023dfa27 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.ts @@ -0,0 +1,217 @@ +import { + AfterViewInit, + ChangeDetectorRef, + Component, + computed, + ElementRef, + HostListener, + Input, + NgZone, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; +import { Roles } from '@users/roles'; +import { CircleButtonTypes, HelpModeService, IqserDialog, IqserPermissionsService, isIqserDevMode, LoadingService } from '@iqser/common-ui'; +import { Bind, Debounce, OnDetach } from '@iqser/common-ui/lib/utils'; +import { File } from '@red/domain'; +import { PermissionsService } from '@services/permissions.service'; +import { FilePreviewStateService } from '../../services/file-preview-state.service'; +import { UserPreferenceService } from '@users/user-preference.service'; +import JSZip from 'jszip'; +import { saveAs } from 'file-saver'; +import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service'; +import { AnnotationDrawService } from '../../../pdf-viewer/services/annotation-draw.service'; +import { TablesService } from '../../services/tables.service'; +import { ALL_HOTKEYS } from '../../utils/constants'; +import { Router } from '@angular/router'; +import { AnnotationActionsService } from '../../services/annotation-actions.service'; +import { FileDataService } from '../../services/file-data.service'; +import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service'; +import { MatDialog } from '@angular/material/dialog'; +import { download } from '@utils/file-download-utils'; +import { firstValueFrom } from 'rxjs'; +import { FileManagementService } from '@services/files/file-management.service'; +import { StructuredComponentManagementDialogComponent } from '../../dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component'; + +@Component({ + selector: 'redaction-file-header', + templateUrl: './file-header.component.html', + styleUrls: ['/file-header.component.scss'], +}) +export class FileHeaderComponent implements OnInit, AfterViewInit, OnDetach, OnDestroy { + @ViewChild('actionsWrapper', { static: false }) private readonly _actionsWrapper: ElementRef; + @Input() file: File; + + protected readonly roles = Roles; + protected readonly circleButtonTypes = CircleButtonTypes; + + readonly lastAssignee = computed(() => this.getLastAssignee()); + readonly isIqserDevMode = isIqserDevMode(); + width: number; + fullScreen = false; + + constructor( + private readonly _changeRef: ChangeDetectorRef, + private readonly _iqserPermissionsService: IqserPermissionsService, + private readonly _userPreferenceService: UserPreferenceService, + private readonly _iqserDialog: IqserDialog, + private readonly _loadingService: LoadingService, + private readonly _pdf: PdfViewer, + private readonly _annotationDrawService: AnnotationDrawService, + private readonly _tablesService: TablesService, + private readonly _router: Router, + private readonly _ngZone: NgZone, + private readonly _helpModeService: HelpModeService, + private readonly _annotationActionsService: AnnotationActionsService, + private readonly _fileDataService: FileDataService, + private readonly _annotationManager: REDAnnotationManager, + private readonly _dialog: MatDialog, + private readonly _fileManagementService: FileManagementService, + readonly state: FilePreviewStateService, + readonly permissionsService: PermissionsService, + ) {} + + ngOnInit() { + this.#openComponentLogDialogIfDefault(); + document.documentElement.addEventListener('fullscreenchange', this.fullscreenListener); + } + + ngAfterViewInit() { + const _observer = new ResizeObserver((entries: ResizeObserverEntry[]) => { + this._updateItemWidth(entries[0]); + }); + _observer.observe(this._actionsWrapper.nativeElement); + } + + ngOnDetach() { + document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener); + } + + ngOnDestroy() { + document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener); + } + + async downloadOriginalFile({ cacheIdentifier, dossierId, fileId, filename }: File) { + const originalFile = this._fileManagementService.downloadOriginal(dossierId, fileId, 'response', cacheIdentifier); + download(await firstValueFrom(originalFile), filename); + } + + getLastAssignee() { + const { isApproved, lastReviewer, lastApprover } = this.state.file(); + const isRss = this._iqserPermissionsService.has(this.roles.getRss); + return isApproved ? (isRss ? lastReviewer : lastApprover) : lastReviewer; + } + + openComponentLogView() { + const data = { file: this.state.file(), dictionaries: this.state.dictionaries }; + this._iqserDialog.openDefault(StructuredComponentManagementDialogComponent, { data }); + } + + async getTables() { + this._loadingService.start(); + + const currentPage = this._pdf.currentPage(); + const tables = await this._tablesService.get(this.state.dossierId, this.state.fileId, this._pdf.currentPage()); + await this._annotationDrawService.drawTables(tables, currentPage, this.state.dossierTemplateId); + + const filename = this.state.file().filename; + const zip = new JSZip(); + + tables.forEach((t, index) => { + const blob = new Blob([atob(t.csvAsBytes)], { + type: 'text/csv;charset=utf-8', + }); + zip.file(filename + '_page' + currentPage + '_table' + (index + 1) + '.csv', blob); + }); + + saveAs(await zip.generateAsync({ type: 'blob' }), filename + '_tables.zip'); + + this._loadingService.stop(); + } + + toggleFullScreen() { + this.fullScreen = !this.fullScreen; + if (this.fullScreen) { + this.#openFullScreen(); + } else { + this.closeFullScreen(); + } + } + + closeFullScreen() { + if (!!document.fullscreenElement && document.exitFullscreen) { + document.exitFullscreen().then(); + } + } + + @Bind() + fullscreenListener() { + if (!document.fullscreenElement) { + this.fullScreen = false; + } + } + + @HostListener('document:keyup', ['$event']) + handleKeyEvent($event: KeyboardEvent) { + if (this._router.url.indexOf('/file/') < 0) { + return; + } + + if (!ALL_HOTKEYS.includes($event.key) || this._dialog.openDialogs.length) { + return; + } + + if (['Escape'].includes($event.key)) { + $event.preventDefault(); + if (this._annotationManager.resizingAnnotationId) { + const resizedAnnotation = this._fileDataService + .annotations() + .find(annotation => annotation.id === this._annotationManager.resizingAnnotationId); + this._annotationActionsService.cancelResize(resizedAnnotation).then(); + } + this.fullScreen = false; + this.closeFullScreen(); + this._changeRef.markForCheck(); + } + + if (!$event.ctrlKey && !$event.metaKey && ['f', 'F'].includes($event.key)) { + // if you type in an input, don't toggle full-screen + if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) { + return; + } + this.toggleFullScreen(); + return; + } + + if (['h', 'H'].includes($event.key)) { + if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) { + return; + } + this._ngZone.run(() => { + window.focus(); + this._helpModeService.activateHelpMode(false); + }); + return; + } + } + + #openFullScreen() { + const documentElement = document.documentElement; + if (documentElement.requestFullscreen) { + documentElement.requestFullscreen().then(); + } + } + + #openComponentLogDialogIfDefault() { + if (this.permissionsService.canViewRssDialog() && this._userPreferenceService.getOpenScmDialogByDefault()) { + this.openComponentLogView(); + } + } + + @Debounce(30) + private _updateItemWidth(entry: ResizeObserverEntry): void { + this.width = entry.contentRect.width; + this._changeRef.detectChanges(); + } +} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/structured-component-management-dialog/structured-component-management-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.html similarity index 100% rename from apps/red-ui/src/app/modules/file-preview/dialogs/structured-component-management-dialog/structured-component-management-dialog.component.html rename to apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.html diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/structured-component-management-dialog/structured-component-management-dialog.component.scss b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/file-preview/dialogs/structured-component-management-dialog/structured-component-management-dialog.component.scss rename to apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.scss diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/structured-component-management-dialog/structured-component-management-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.ts similarity index 89% rename from apps/red-ui/src/app/modules/file-preview/dialogs/structured-component-management-dialog/structured-component-management-dialog.component.ts rename to apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.ts index f8193d7c2..a656a8cf1 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/structured-component-management-dialog/structured-component-management-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.ts @@ -1,21 +1,30 @@ -import { KeyValuePipe, NgForOf, NgIf } from '@angular/common'; -import { ChangeDetectionStrategy, Component, Inject, OnInit, signal } from '@angular/core'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { ReplaceNbspPipe } from '@common-ui/pipes/replace-nbsp.pipe'; -import { BaseDialogComponent, CircleButtonComponent, EditableInputComponent, IconButtonComponent } from '@iqser/common-ui'; -import { TranslateModule } from '@ngx-translate/core'; import { ComponentLogEntry, Dictionary, IFile, WorkflowFileStatuses } from '@red/domain'; -import { FilesMapService } from '@services/files/files-map.service'; -import { UserPreferenceService } from '@users/user-preference.service'; -import { firstValueFrom } from 'rxjs'; +import { ChangeDetectionStrategy, Component, Inject, OnInit, signal } from '@angular/core'; +import { KeyValuePipe, NgForOf, NgIf } from '@angular/common'; +import { + CircleButtonComponent, + EditableInputComponent, + IconButtonComponent, + IconButtonTypes, + IqserDialogComponent, + LoadingService, +} from '@iqser/common-ui'; +import { TranslateModule } from '@ngx-translate/core'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { ReplaceNbspPipe } from '@common-ui/pipes/replace-nbsp.pipe'; import { ComponentLogService } from '@services/files/component-log.service'; +import { UserPreferenceService } from '@users/user-preference.service'; +import { FilesMapService } from '@services/files/files-map.service'; +import { firstValueFrom } from 'rxjs'; interface ScmData { file: IFile; dictionaries: Dictionary[]; } +interface ScmResult {} + @Component({ templateUrl: './structured-component-management-dialog.component.html', styleUrls: ['./structured-component-management-dialog.component.scss'], @@ -34,18 +43,22 @@ interface ScmData { ReplaceNbspPipe, ], }) -export class StructuredComponentManagementDialogComponent extends BaseDialogComponent implements OnInit { +export class StructuredComponentManagementDialogComponent + extends IqserDialogComponent + implements OnInit +{ readonly componentLogData = signal(undefined); readonly openScmDialogByDefault = signal(this.userPreferences.getOpenScmDialogByDefault()); + readonly iconButtonTypes = IconButtonTypes; constructor( - protected readonly _dialogRef: MatDialogRef, private readonly _componentLogService: ComponentLogService, - readonly userPreferences: UserPreferenceService, private readonly _filesMapService: FilesMapService, + private readonly _loadingService: LoadingService, + readonly userPreferences: UserPreferenceService, @Inject(MAT_DIALOG_DATA) readonly data: ScmData, ) { - super(_dialogRef); + super(); } get canEdit() { @@ -60,8 +73,6 @@ export class StructuredComponentManagementDialogComponent extends BaseDialogComp return `value-cell-${index}`; } - originalOrder = (): number => 0; - exportJSON() { return firstValueFrom( this._componentLogService.exportJSON(this.data.file.dossierTemplateId, this.data.file.dossierId, this.data.file), diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html index 1e4eea900..2e3214931 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html @@ -1,90 +1,5 @@
- +
@@ -94,7 +9,9 @@
- +
diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss index bdae60f2f..55ac580d8 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss @@ -5,16 +5,6 @@ margin: 0 16px; } -.page-header { - max-width: 100vw; -} - -.actions-container { - display: flex; - justify-content: flex-end; - align-items: center; -} - .content-inner { position: absolute; } diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index f52cb6fa0..805a9f0e9 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -1,18 +1,4 @@ -import { - AfterViewInit, - ChangeDetectorRef, - Component, - computed, - effect, - ElementRef, - HostListener, - NgZone, - OnDestroy, - OnInit, - TemplateRef, - ViewChild, -} from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; +import { ChangeDetectorRef, Component, effect, NgZone, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { ActivatedRouteSnapshot, NavigationExtras, Router } from '@angular/router'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ComponentCanDeactivate } from '@guards/can-deactivate.guard'; @@ -23,16 +9,13 @@ import { CustomError, ErrorService, getConfig, - HelpModeService, IConfirmationDialogData, IqserDialog, - IqserPermissionsService, - isIqserDevMode, LoadingService, Toaster, } from '@iqser/common-ui'; import { copyLocalStorageFiltersValues, FilterService, NestedFilter, processFilters } from '@iqser/common-ui/lib/filtering'; -import { AutoUnsubscribe, Bind, bool, Debounce, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils'; +import { AutoUnsubscribe, Bind, bool, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { ManualRedactionEntryTypes, ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper'; import { Dictionary, File, ViewModes } from '@red/domain'; @@ -46,8 +29,6 @@ import { PermissionsService } from '@services/permissions.service'; import { ReanalysisService } from '@services/reanalysis.service'; import { Roles } from '@users/roles'; import { PreferencesKeys, UserPreferenceService } from '@users/user-preference.service'; -import { saveAs } from 'file-saver'; -import JSZip from 'jszip'; import { NGXLogger } from 'ngx-logger'; import { combineLatest, first, firstValueFrom, Observable, of, pairwise } from 'rxjs'; import { catchError, filter, map, startWith, switchMap, tap } from 'rxjs/operators'; @@ -73,36 +54,25 @@ import { ManualRedactionService } from './services/manual-redaction.service'; import { PdfProxyService } from './services/pdf-proxy.service'; import { SkippedService } from './services/skipped.service'; import { StampService } from './services/stamp.service'; -import { TablesService } from './services/tables.service'; import { ViewModeService } from './services/view-mode.service'; -import { ALL_HOTKEYS } from './utils/constants'; import { RedactTextData } from './utils/dialog-types'; -import { AnnotationActionsService } from './services/annotation-actions.service'; @Component({ templateUrl: './file-preview-screen.component.html', styleUrls: ['./file-preview-screen.component.scss'], providers: filePreviewScreenProviders, }) -export class FilePreviewScreenComponent - extends AutoUnsubscribe - implements AfterViewInit, OnInit, OnDestroy, OnAttach, OnDetach, ComponentCanDeactivate -{ +export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnInit, OnDestroy, OnAttach, OnDetach, ComponentCanDeactivate { readonly circleButtonTypes = CircleButtonTypes; readonly roles = Roles; - fullScreen = false; readonly fileId = this.state.fileId; readonly dossierId = this.state.dossierId; - readonly lastAssignee = computed(() => this.getLastAssignee()); - width: number; - readonly isIqserDevMode = isIqserDevMode(); @ViewChild('annotationFilterTemplate', { read: TemplateRef, static: false, }) private readonly _filterTemplate: TemplateRef; #loadAllAnnotationsEnabled = false; - @ViewChild('actionsWrapper', { static: false }) private readonly _actionsWrapper: ElementRef; readonly #isDocumine = getConfig().IS_DOCUMINE; constructor( @@ -112,7 +82,6 @@ export class FilePreviewScreenComponent readonly userPreferenceService: UserPreferenceService, readonly pdfProxyService: PdfProxyService, readonly configService: ConfigService, - private readonly _iqserPermissionsService: IqserPermissionsService, private readonly _listingService: AnnotationsListingService, private readonly _router: Router, private readonly _ngZone: NgZone, @@ -141,11 +110,7 @@ export class FilePreviewScreenComponent private readonly _filesService: FilesService, private readonly _fileManagementService: FileManagementService, private readonly _readableRedactionsService: ReadableRedactionsService, - private readonly _helpModeService: HelpModeService, private readonly _dossierTemplatesService: DossierTemplatesService, - private readonly _dialog: MatDialog, - private readonly _tablesService: TablesService, - private readonly _annotationActionsService: AnnotationActionsService, ) { super(); effect(() => { @@ -211,12 +176,6 @@ export class FilePreviewScreenComponent ); } - getLastAssignee() { - const { isApproved, lastReviewer, lastApprover } = this.state.file(); - const isRss = this._iqserPermissionsService.has(this.roles.getRss); - return isApproved ? (isRss ? lastReviewer : lastApprover) : lastReviewer; - } - deleteEarmarksOnViewChange$() { const isChangingFromEarmarksViewMode$ = this._viewModeService.viewMode$.pipe( pairwise(), @@ -293,24 +252,15 @@ export class FilePreviewScreenComponent this._viewerHeaderService.resetCompareButtons(); this._viewerHeaderService.enableLoadAllAnnotations(); // Reset the button state (since the viewer is reused between files) super.ngOnDetach(); - document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener); this.pdf.instance.UI.hotkeys.off('esc'); this._changeRef.markForCheck(); } ngOnDestroy() { - document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener); this.pdf.instance.UI.hotkeys.off('esc'); super.ngOnDestroy(); } - @Bind() - fullscreenListener() { - if (!document.fullscreenElement) { - this.fullScreen = false; - } - } - @Bind() handleDeleteRectangleOnEsc($event: KeyboardEvent) { $event.preventDefault(); @@ -355,19 +305,10 @@ export class FilePreviewScreenComponent this.pdfProxyService.configureElements(); this.#restoreOldFilters(); - document.documentElement.addEventListener('fullscreenchange', this.fullscreenListener); this.pdf.instance.UI.hotkeys.on('esc', this.handleDeleteRectangleOnEsc); - this.#openComponentLogDialogIfDefault(); this._viewerHeaderService.resetLayers(); } - ngAfterViewInit() { - const _observer = new ResizeObserver((entries: ResizeObserverEntry[]) => { - this._updateItemWidth(entries[0]); - }); - _observer.observe(this._actionsWrapper.nativeElement); - } - openManualAnnotationDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { const file = this.state.file(); @@ -393,59 +334,6 @@ export class FilePreviewScreenComponent ); } - toggleFullScreen() { - this.fullScreen = !this.fullScreen; - if (this.fullScreen) { - this.#openFullScreen(); - } else { - this.closeFullScreen(); - } - } - - @HostListener('document:keyup', ['$event']) - handleKeyEvent($event: KeyboardEvent) { - if (this._router.url.indexOf('/file/') < 0) { - return; - } - - if (!ALL_HOTKEYS.includes($event.key) || this._dialog.openDialogs.length) { - return; - } - - if (['Escape'].includes($event.key)) { - $event.preventDefault(); - if (this._annotationManager.resizingAnnotationId) { - const resizedAnnotation = this._fileDataService - .annotations() - .find(annotation => annotation.id === this._annotationManager.resizingAnnotationId); - this._annotationActionsService.cancelResize(resizedAnnotation).then(); - } - this.fullScreen = false; - this.closeFullScreen(); - this._changeRef.markForCheck(); - } - - if (!$event.ctrlKey && !$event.metaKey && ['f', 'F'].includes($event.key)) { - // if you type in an input, don't toggle full-screen - if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) { - return; - } - this.toggleFullScreen(); - return; - } - - if (['h', 'H'].includes($event.key)) { - if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) { - return; - } - this._ngZone.run(() => { - window.focus(); - this._helpModeService.activateHelpMode(false); - }); - return; - } - } - async viewerReady(pageNumber?: string) { if (pageNumber) { const file = this.state.file(); @@ -467,21 +355,6 @@ export class FilePreviewScreenComponent this._changeRef.markForCheck(); } - closeFullScreen() { - if (!!document.fullscreenElement && document.exitFullscreen) { - document.exitFullscreen().then(); - } - } - - async downloadOriginalFile({ cacheIdentifier, dossierId, fileId, filename }: File) { - const originalFile = this._fileManagementService.downloadOriginal(dossierId, fileId, 'response', cacheIdentifier); - download(await firstValueFrom(originalFile), filename); - } - - openComponentLogView() { - this._dialogService.openDialog('componentLog', { file: this.state.file(), dictionaries: this.state.dictionaries }); - } - loadAnnotations$() { const annotations$ = this._fileDataService.annotations$.pipe( startWith([] as AnnotationWrapper[]), @@ -527,28 +400,6 @@ export class FilePreviewScreenComponent return this.#cleanupAndRedrawAnnotations(annotationsToDraw); } - async getTables() { - this._loadingService.start(); - - const currentPage = this.pdf.currentPage(); - const tables = await this._tablesService.get(this.state.dossierId, this.state.fileId, this.pdf.currentPage()); - await this._annotationDrawService.drawTables(tables, currentPage, this.state.dossierTemplateId); - - const filename = this.state.file().filename; - const zip = new JSZip(); - - tables.forEach((t, index) => { - const blob = new Blob([atob(t.csvAsBytes)], { - type: 'text/csv;charset=utf-8', - }); - zip.file(filename + '_page' + currentPage + '_table' + (index + 1) + '.csv', blob); - }); - - saveAs(await zip.generateAsync({ type: 'blob' }), filename + '_tables.zip'); - - this._loadingService.stop(); - } - async #openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { const file = this.state.file(); @@ -572,12 +423,6 @@ export class FilePreviewScreenComponent return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined)))); } - @Debounce(30) - private _updateItemWidth(entry: ResizeObserverEntry): void { - this.width = entry.contentRect.width; - this._changeRef.detectChanges(); - } - #getAnnotationsToDraw(oldAnnotations: AnnotationWrapper[], newAnnotations: AnnotationWrapper[]) { const currentPage = this.pdf.currentPage(); const currentPageAnnotations = this._annotationManager.get(a => a.getPageNumber() === currentPage); @@ -711,10 +556,6 @@ export class FilePreviewScreenComponent .pipe(tap(() => this.#handleDeletedFile())) .subscribe(); - this.addActiveScreenSubscription = this._documentViewer.keyUp$.subscribe($event => { - this.handleKeyEvent($event); - }); - this.addActiveScreenSubscription = this.#earmarks$.subscribe(); this.addActiveScreenSubscription = this.deleteEarmarksOnViewChange$().subscribe(); @@ -845,13 +686,6 @@ export class FilePreviewScreenComponent }); } - #openFullScreen() { - const documentElement = document.documentElement; - if (documentElement.requestFullscreen) { - documentElement.requestFullscreen().then(); - } - } - #navigateToDossier() { this._logger.info('Navigating to ', this.state.dossier().dossierName); return this._router.navigate([this.state.dossier().routerLink]); @@ -878,12 +712,6 @@ export class FilePreviewScreenComponent }); } - #openComponentLogDialogIfDefault() { - if (this.permissionsService.canViewRssDialog() && this.userPreferenceService.getOpenScmDialogByDefault()) { - this.openComponentLogView(); - } - } - #getRedactTextDialog(data: RedactTextData) { if (this.#isDocumine) { return this._iqserDialog.openDefault(AddAnnotationDialogComponent, { data }); diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts index 8bad2b0f3..05a4c955a 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts @@ -70,6 +70,7 @@ import { DocumentUnloadedGuard } from './services/document-unloaded.guard'; import { FilePreviewDialogService } from './services/file-preview-dialog.service'; import { ManualRedactionService } from './services/manual-redaction.service'; import { TablesService } from './services/tables.service'; +import { FileHeaderComponent } from './components/file-header/file-header.component'; const routes: IqserRoutes = [ { @@ -119,6 +120,7 @@ const components = [ FilePreviewScreenComponent, FilePreviewRightContainerComponent, ReadonlyBannerComponent, + FileHeaderComponent, ]; @NgModule({ diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts index 283eed614..59af5fef2 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts @@ -6,16 +6,8 @@ import { DocumentInfoDialogComponent } from '../dialogs/document-info-dialog/doc import { ForceAnnotationDialogComponent } from '../dialogs/force-redaction-dialog/force-annotation-dialog.component'; import { HighlightActionDialogComponent } from '../dialogs/highlight-action-dialog/highlight-action-dialog.component'; import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component'; -import { StructuredComponentManagementDialogComponent } from '../dialogs/structured-component-management-dialog/structured-component-management-dialog.component'; -type DialogType = - | 'confirm' - | 'documentInfo' - | 'componentLog' - | 'changeLegalBasis' - | 'forceAnnotation' - | 'manualAnnotation' - | 'highlightAction'; +type DialogType = 'confirm' | 'documentInfo' | 'changeLegalBasis' | 'forceAnnotation' | 'manualAnnotation' | 'highlightAction'; @Injectable() export class FilePreviewDialogService extends DialogService { @@ -41,10 +33,6 @@ export class FilePreviewDialogService extends DialogService { highlightAction: { component: HighlightActionDialogComponent, }, - componentLog: { - component: StructuredComponentManagementDialogComponent, - dialogConfig: { width: '90vw' }, - }, }; constructor(protected readonly _dialog: MatDialog) { diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts index 68797a6e7..0f6ab7b36 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts @@ -133,9 +133,11 @@ export class PdfProxyService { } configureElements() { - const hexColor = this._dictionariesMapService.get(this._state.dossierTemplateId, 'manual').hexColor; - const color = this._annotationDrawService.convertColor(hexColor); - this._documentViewer.setRectangleToolStyles(color); + const hexColor = this._dictionariesMapService.get(this._state.dossierTemplateId, 'manual')?.hexColor; + if (hexColor) { + const color = this._annotationDrawService.convertColor(hexColor); + this._documentViewer.setRectangleToolStyles(color); + } } #configureRectangleAnnotationPopup(annotation: Annotation) { diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index deb14e6da..2ccc6f6d1 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -1,9 +1,9 @@ { "ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_URL": null, - "API_URL": "https://dan1.iqser.cloud", + "API_URL": "https://frontend2.iqser.cloud", "APP_NAME": "RedactManager", - "IS_DOCUMINE": false, + "IS_DOCUMINE": true, "RULE_EDITOR_DEV_ONLY": false, "AUTO_READ_TIME": 3, "BACKEND_APP_VERSION": "4.4.40", @@ -13,13 +13,13 @@ "MAX_RETRIES_ON_SERVER_ERROR": 3, "OAUTH_CLIENT_ID": "redaction", "OAUTH_IDP_HINT": null, - "OAUTH_URL": "https://dan1.iqser.cloud/auth", + "OAUTH_URL": "https://frontend2.iqser.cloud/auth", "RECENT_PERIOD_IN_HOURS": 24, "SELECTION_MODE": "structural", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview", "ANNOTATIONS_THRESHOLD": 1000, - "THEME": "redact", - "BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/redact/", + "THEME": "scm", + "BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/scm/", "AVAILABLE_NOTIFICATIONS_DAYS": 30, "AVAILABLE_OLD_NOTIFICATIONS_MINUTES": 60, "NOTIFICATIONS_THRESHOLD": 1000, From 48bc514f5b80d4e6e4afc95a686674c62bb52cf3 Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Tue, 2 Apr 2024 21:57:50 +0300 Subject: [PATCH 02/21] RED-8748 - added DocuMine component view --- .../documine-export.component.html | 7 + .../documine-export.component.ts | 7 + .../file-header/file-header.component.html | 39 ++-- .../file-header/file-header.component.scss | 18 +- .../file-header/file-header.component.ts | 24 +-- .../file-workload.component.html | 80 ++++---- .../file-workload.component.scss | 9 +- .../file-workload/file-workload.component.ts | 6 +- .../components/pages/pages.component.ts | 1 - ...ctured-component-management.component.html | 92 +++++++++ ...tured-component-management.component.scss} | 8 +- ...uctured-component-management.component.ts} | 87 +++------ ...component-management-dialog.component.html | 97 ---------- .../file-preview-screen.component.html | 8 +- .../file-preview-screen.component.scss | 15 +- .../file-preview-screen.component.ts | 5 +- .../file-preview/file-preview.module.ts | 4 + apps/red-ui/src/assets/i18n/redact/de.json | 174 +++++++++--------- apps/red-ui/src/assets/i18n/redact/en.json | 28 +-- apps/red-ui/src/assets/i18n/scm/de.json | 174 +++++++++--------- apps/red-ui/src/assets/i18n/scm/en.json | 28 +-- apps/red-ui/src/styles.scss | 16 +- 22 files changed, 442 insertions(+), 485 deletions(-) create mode 100644 apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.html create mode 100644 apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.ts create mode 100644 apps/red-ui/src/app/modules/file-preview/components/structured-component-management/structured-component-management.component.html rename apps/red-ui/src/app/modules/file-preview/{dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.scss => components/structured-component-management/structured-component-management.component.scss} (83%) rename apps/red-ui/src/app/modules/file-preview/{dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.ts => components/structured-component-management/structured-component-management.component.ts} (55%) delete mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/structured-component-management-dialog/structured-component-management-dialog.component.html diff --git a/apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.html b/apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.html new file mode 100644 index 000000000..9baaaabdf --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.html @@ -0,0 +1,7 @@ + + + diff --git a/apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.ts b/apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.ts new file mode 100644 index 000000000..01b3ef135 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/components/documine-export/documine-export.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'redaction-documine-export', + templateUrl: './documine-export.component.html', +}) +export class DocumineExportComponent {} diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html index c351dfd24..8ef995925 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/file-header/file-header.component.html @@ -1,37 +1,32 @@