Compare commits
2 Commits
master
...
VM/RED-978
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e560fb593b | ||
|
|
9535f6f06a |
@ -0,0 +1,6 @@
|
|||||||
|
import { Directive } from '@angular/core';
|
||||||
|
|
||||||
|
@Directive()
|
||||||
|
export class BaseWorkloadComponent {
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<div class="workload-container">
|
||||||
|
<div class="workload">
|
||||||
|
<div class="workload-header flex-align-items-center workload-separator">
|
||||||
|
<span [innerHTML]="'documine-workload.header-label' | translate"></span>
|
||||||
|
<!-- <iqser-popup-filter-->
|
||||||
|
<!-- [actionsTemplate]="annotationFilterActionTemplate"-->
|
||||||
|
<!-- [attr.help-mode-key]="'workload_filter'"-->
|
||||||
|
<!-- [fileId]="state.file()?.id"-->
|
||||||
|
<!-- [primaryFiltersSlug]="'primaryFilters'"-->
|
||||||
|
<!-- [secondaryFiltersSlug]="'secondaryFilters'"-->
|
||||||
|
<!-- ></iqser-popup-filter>-->
|
||||||
|
<iqser-popup-filter
|
||||||
|
[attr.help-mode-key]="'workload_filter'"
|
||||||
|
[primaryFiltersSlug]="'primaryFilters'"
|
||||||
|
[secondaryFiltersSlug]="'secondaryFilters'"
|
||||||
|
></iqser-popup-filter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (documentInfoService.shown()) {
|
||||||
|
<redaction-document-info id="document-info"></redaction-document-info>
|
||||||
|
} @else {
|
||||||
|
<redaction-pages [pages]="pages"></redaction-pages>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
:host {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workload-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.workload {
|
||||||
|
width: var(--documine-workload-content-width);
|
||||||
|
border-right: 1px solid var(--iqser-separator);
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.workload-header {
|
||||||
|
min-height: 37px;
|
||||||
|
background: var(--iqser-grey-8);
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
::ng-deep span {
|
||||||
|
color: var(--iqser-text);
|
||||||
|
font-size: var(--iqser-font-size);
|
||||||
|
line-height: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NgIf } from '@angular/common';
|
||||||
|
import { PopupFilterComponent } from '@common-ui/filtering';
|
||||||
|
import { PagesComponent } from '../../pages/pages.component';
|
||||||
|
import { DocumentInfoService } from '../../../services/document-info.service';
|
||||||
|
import { DocumentInfoComponent } from '../../document-info/document-info.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-documine-file-workload',
|
||||||
|
templateUrl: './documine-file-workload.component.html',
|
||||||
|
styleUrls: ['./documine-file-workload.component.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [TranslateModule, NgIf, PopupFilterComponent, PagesComponent, DocumentInfoComponent],
|
||||||
|
})
|
||||||
|
export class DocumineFileWorkloadComponent {
|
||||||
|
pages = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
constructor(readonly documentInfoService: DocumentInfoService) {}
|
||||||
|
}
|
||||||
@ -1,273 +0,0 @@
|
|||||||
<ng-container *ngIf="!isDocumine && !documentInfoService.shown()">
|
|
||||||
<div
|
|
||||||
*ngIf="excludedPagesService.shown(); else selectAndFilter"
|
|
||||||
class="right-title heading"
|
|
||||||
translate="file-preview.tabs.exclude-pages.label"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<iqser-circle-button
|
|
||||||
(action)="excludedPagesService.toggle()"
|
|
||||||
[tooltip]="'file-preview.tabs.exclude-pages.close' | translate"
|
|
||||||
icon="iqser:close"
|
|
||||||
tooltipPosition="before"
|
|
||||||
></iqser-circle-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-template #selectAndFilter>
|
|
||||||
<div class="right-title heading">
|
|
||||||
{{ title() | translate }}
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
(click)="multiSelectService.activate()"
|
|
||||||
*ngIf="multiSelectService.enabled() && multiSelectService.inactive()"
|
|
||||||
[attr.help-mode-key]="'workload_bulk_selection'"
|
|
||||||
class="all-caps-label primary pointer"
|
|
||||||
translate="file-preview.tabs.annotations.select"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<ng-container *ngTemplateOutlet="annotationsFilter"></ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
@if (displayedAnnotations$ | async; as annotations) {
|
|
||||||
<div class="right-content">
|
|
||||||
<ng-container *ngIf="!isDocumine">
|
|
||||||
<redaction-readonly-banner
|
|
||||||
*ngIf="showAnalysisDisabledBanner; else readOnlyBanner"
|
|
||||||
[customTranslation]="translations.analysisDisabled"
|
|
||||||
></redaction-readonly-banner>
|
|
||||||
<ng-template #readOnlyBanner>
|
|
||||||
<redaction-readonly-banner *ngIf="state.isReadonly()"></redaction-readonly-banner>
|
|
||||||
</ng-template>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<div *ngIf="multiSelectService.active()" class="multi-select">
|
|
||||||
<div class="selected-wrapper">
|
|
||||||
<iqser-round-checkbox
|
|
||||||
(click)="annotationManager.deselect()"
|
|
||||||
[indeterminate]="listingService.areSomeSelected$ | async"
|
|
||||||
type="with-bg"
|
|
||||||
></iqser-round-checkbox>
|
|
||||||
|
|
||||||
<span class="all-caps-label">{{ listingService.selectedLength$ | async }} selected </span>
|
|
||||||
|
|
||||||
<redaction-annotation-actions
|
|
||||||
*ngIf="listingService.areSomeSelected$ | async"
|
|
||||||
[alwaysVisible]="true"
|
|
||||||
[annotations]="listingService.selectedEntities$ | async"
|
|
||||||
[canPerformAnnotationActions]="state.isWritable()"
|
|
||||||
buttonType="primary"
|
|
||||||
tooltipPosition="above"
|
|
||||||
></redaction-annotation-actions>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<iqser-circle-button
|
|
||||||
(action)="multiSelectService.deactivate()"
|
|
||||||
[tooltip]="'file-preview.tabs.multi-select.close' | translate"
|
|
||||||
[type]="circleButtonTypes.primary"
|
|
||||||
icon="iqser:close"
|
|
||||||
tooltipPosition="before"
|
|
||||||
></iqser-circle-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="annotations-wrapper" [class.documine-direction]="isDocumine">
|
|
||||||
<div [class.border-left]="isDocumine">
|
|
||||||
<div
|
|
||||||
#quickNavigation
|
|
||||||
*ngIf="!(documentInfoService.shown() && isDocumine); else documentInfo"
|
|
||||||
(keydown)="preventKeyDefault($event)"
|
|
||||||
(keyup)="preventKeyDefault($event)"
|
|
||||||
[class.active-panel]="pagesPanelActive"
|
|
||||||
class="quick-navigation"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
(click)="scrollQuickNavFirst()"
|
|
||||||
[class.disabled]="pdf.currentPage() === 1"
|
|
||||||
[matTooltip]="'file-preview.quick-nav.jump-first' | translate"
|
|
||||||
[class.documine-height]="isDocumine"
|
|
||||||
class="jump"
|
|
||||||
matTooltipPosition="above"
|
|
||||||
>
|
|
||||||
<mat-icon svgIcon="iqser:nav-first"></mat-icon>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<redaction-pages (click)="pagesPanelActive = true" [pages]="displayedPages"></redaction-pages>
|
|
||||||
|
|
||||||
<div
|
|
||||||
(click)="scrollQuickNavLast()"
|
|
||||||
[class.disabled]="pdf.currentPage() === state.file()?.numberOfPages"
|
|
||||||
[matTooltip]="'file-preview.quick-nav.jump-last' | translate"
|
|
||||||
[class.documine-height]="isDocumine"
|
|
||||||
class="jump"
|
|
||||||
matTooltipPosition="above"
|
|
||||||
>
|
|
||||||
<mat-icon svgIcon="iqser:nav-last"></mat-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content" [class.documine-width]="isDocumine">
|
|
||||||
@if (state.file().excluded && documentInfoService.hidden()) {
|
|
||||||
<iqser-empty-state
|
|
||||||
[horizontalPadding]="40"
|
|
||||||
[text]="'file-preview.tabs.is-excluded' | translate"
|
|
||||||
icon="red:needs-work"
|
|
||||||
></iqser-empty-state>
|
|
||||||
} @else {
|
|
||||||
<div
|
|
||||||
*ngIf="!viewModeService.isEarmarks()"
|
|
||||||
[attr.anotation-page-header]="pdf.currentPage()"
|
|
||||||
[hidden]="excludedPagesService.shown()"
|
|
||||||
class="workload-separator"
|
|
||||||
>
|
|
||||||
<span *ngIf="!!pdf.currentPage()" class="flex-align-items-center">
|
|
||||||
<ng-container *ngIf="!isDocumine; else documineHeader">
|
|
||||||
<iqser-circle-button
|
|
||||||
(action)="excludedPagesService.toggle()"
|
|
||||||
*ngIf="currentPageIsExcluded()"
|
|
||||||
[size]="14"
|
|
||||||
[tooltip]="'file-preview.excluded-from-redaction' | translate | capitalize"
|
|
||||||
class="mr-10 primary"
|
|
||||||
icon="red:exclude-pages"
|
|
||||||
tooltipPosition="above"
|
|
||||||
></iqser-circle-button>
|
|
||||||
|
|
||||||
<span
|
|
||||||
[translateParams]="{ page: pdf.currentPage(), count: activeAnnotations.length }"
|
|
||||||
[translate]="'page'"
|
|
||||||
class="all-caps-label"
|
|
||||||
></span>
|
|
||||||
</ng-container>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div *ngIf="multiSelectService.active()">
|
|
||||||
<div
|
|
||||||
(click)="selectAllOnActivePage()"
|
|
||||||
class="all-caps-label primary pointer"
|
|
||||||
translate="file-preview.tabs.annotations.select-all"
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
(click)="deselectAllOnActivePage()"
|
|
||||||
class="all-caps-label primary pointer"
|
|
||||||
translate="file-preview.tabs.annotations.select-none"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
#annotationsElement
|
|
||||||
(keydown)="preventKeyDefault($event)"
|
|
||||||
(keyup)="preventKeyDefault($event)"
|
|
||||||
[class.active-panel]="!pagesPanelActive"
|
|
||||||
[hidden]="excludedPagesService.shown()"
|
|
||||||
class="annotations"
|
|
||||||
id="annotations-list"
|
|
||||||
tabindex="1"
|
|
||||||
>
|
|
||||||
<ng-container *ngIf="pdf.currentPage() && !displayedAnnotations.get(pdf.currentPage())?.length">
|
|
||||||
<iqser-empty-state
|
|
||||||
[horizontalPadding]="24"
|
|
||||||
[text]="'file-preview.no-data.title' | translate"
|
|
||||||
[verticalPadding]="40"
|
|
||||||
icon="iqser:document"
|
|
||||||
>
|
|
||||||
<ng-container *ngIf="currentPageIsExcluded() && displayedPages.length">
|
|
||||||
{{ 'file-preview.tabs.annotations.page-is' | translate }}
|
|
||||||
<a
|
|
||||||
(click)="excludedPagesService.toggle()"
|
|
||||||
class="with-underline"
|
|
||||||
translate="file-preview.excluded-from-redaction"
|
|
||||||
></a
|
|
||||||
>.
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container
|
|
||||||
*ngIf="(fileDataService.allLength$ | async) === 0 || filterService.noAnnotationsFilterChecked"
|
|
||||||
>
|
|
||||||
{{ 'file-preview.tabs.annotations.no-annotations' | translate }}
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container
|
|
||||||
*ngIf="
|
|
||||||
(fileDataService.allLength$ | async) > 0 &&
|
|
||||||
displayedPages.length === 0 &&
|
|
||||||
!filterService.noAnnotationsFilterChecked
|
|
||||||
"
|
|
||||||
>{{ 'file-preview.tabs.annotations.wrong-filters' | translate }}
|
|
||||||
<a
|
|
||||||
(click)="filterService.reset()"
|
|
||||||
class="with-underline"
|
|
||||||
translate="file-preview.tabs.annotations.reset"
|
|
||||||
></a>
|
|
||||||
{{ 'file-preview.tabs.annotations.the-filters' | translate }}
|
|
||||||
</ng-container>
|
|
||||||
</iqser-empty-state>
|
|
||||||
|
|
||||||
<div *ngIf="displayedPages.length" class="no-annotations-buttons-container mt-32">
|
|
||||||
<iqser-icon-button
|
|
||||||
(action)="jumpToPreviousWithAnnotations()"
|
|
||||||
[disabled]="pdf.currentPage() <= displayedPages[0]"
|
|
||||||
[label]="'file-preview.tabs.annotations.jump-to-previous' | translate"
|
|
||||||
[type]="iconButtonTypes.dark"
|
|
||||||
icon="iqser:nav-prev"
|
|
||||||
></iqser-icon-button>
|
|
||||||
|
|
||||||
<iqser-icon-button
|
|
||||||
(action)="jumpToNextWithAnnotations()"
|
|
||||||
[disabled]="pdf.currentPage() >= displayedPages[displayedPages.length - 1]"
|
|
||||||
[label]="'file-preview.tabs.annotations.jump-to-next' | translate"
|
|
||||||
[type]="iconButtonTypes.dark"
|
|
||||||
class="mt-8"
|
|
||||||
icon="iqser:nav-next"
|
|
||||||
></iqser-icon-button>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<redaction-annotations-list
|
|
||||||
(pagesPanelActive)="pagesPanelActive = $event"
|
|
||||||
[annotations]="annotations.get(pdf.currentPage())"
|
|
||||||
></redaction-annotations-list>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<redaction-page-exclusion *ngIf="excludedPagesService.shown()"></redaction-page-exclusion>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<ng-template #annotationFilterActionTemplate let-filter="filter">
|
|
||||||
<iqser-circle-button
|
|
||||||
(action)="skippedService.toggleSkipped()"
|
|
||||||
*ngIf="filter.id === 'skipped'"
|
|
||||||
[icon]="skippedService.hideSkipped() ? 'iqser:visibility-off' : 'iqser:visibility'"
|
|
||||||
[tooltip]="
|
|
||||||
(skippedService.hideSkipped() ? 'file-preview.tabs.annotations.show-skipped' : 'file-preview.tabs.annotations.hide-skipped')
|
|
||||||
| translate
|
|
||||||
"
|
|
||||||
iqserPreventDefault
|
|
||||||
></iqser-circle-button>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #documineHeader>
|
|
||||||
<span [translate]="'annotations'"></span>
|
|
||||||
<ng-container *ngTemplateOutlet="annotationsFilter"></ng-container>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #annotationsFilter>
|
|
||||||
<iqser-popup-filter
|
|
||||||
*ngIf="documentInfoService.hidden() || isDocumine"
|
|
||||||
[actionsTemplate]="annotationFilterActionTemplate"
|
|
||||||
[attr.help-mode-key]="'workload_filter'"
|
|
||||||
[fileId]="state.file()?.id"
|
|
||||||
[primaryFiltersSlug]="'primaryFilters'"
|
|
||||||
[secondaryFiltersSlug]="'secondaryFilters'"
|
|
||||||
></iqser-popup-filter>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #documentInfo>
|
|
||||||
<redaction-document-info id="document-info"></redaction-document-info>
|
|
||||||
</ng-template>
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
@use 'common-mixins';
|
|
||||||
|
|
||||||
:host {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disabled-auto-analysis {
|
|
||||||
background-color: var(--iqser-yellow-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-content {
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.no-annotations-buttons-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
iqser-icon-button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotations-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&.documine-direction {
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-left {
|
|
||||||
border-left: 1px solid var(--iqser-separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
overflow: hidden;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&.documine-width {
|
|
||||||
width: calc(var(--documine-workload-content-width));
|
|
||||||
border-right: 1px solid var(--iqser-separator);
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
.workload-separator {
|
|
||||||
min-height: 37px;
|
|
||||||
background: var(--iqser-grey-8);
|
|
||||||
|
|
||||||
.flex-align-items-center {
|
|
||||||
width: 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
::ng-deep span {
|
|
||||||
color: var(--iqser-text);
|
|
||||||
font-size: var(--iqser-font-size);
|
|
||||||
line-height: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-navigation,
|
|
||||||
.annotations {
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&.active-panel {
|
|
||||||
background-color: var(--iqser-workload-pages-bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-navigation {
|
|
||||||
height: 100%;
|
|
||||||
border-right: 1px solid var(--iqser-separator);
|
|
||||||
min-width: var(--qiuck-navigation-width);
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.jump {
|
|
||||||
min-height: 32px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.25s;
|
|
||||||
|
|
||||||
&.documine-height {
|
|
||||||
min-height: 37px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.disabled):hover {
|
|
||||||
background-color: var(--iqser-tab-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-icon {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
cursor: default;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
mat-icon {
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotations {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
redaction-document-info {
|
|
||||||
width: var(--workload-width);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,205 @@
|
|||||||
|
<div
|
||||||
|
*ngIf="excludedPagesService.shown(); else selectAndFilter"
|
||||||
|
class="right-title heading"
|
||||||
|
translate="file-preview.tabs.exclude-pages.label"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<iqser-circle-button
|
||||||
|
(action)="excludedPagesService.toggle()"
|
||||||
|
[tooltip]="'file-preview.tabs.exclude-pages.close' | translate"
|
||||||
|
icon="iqser:close"
|
||||||
|
tooltipPosition="before"
|
||||||
|
></iqser-circle-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #selectAndFilter>
|
||||||
|
<div class="right-title heading">
|
||||||
|
{{ title() | translate }}
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
(click)="multiSelectService.activate()"
|
||||||
|
*ngIf="multiSelectService.enabled() && multiSelectService.inactive()"
|
||||||
|
[attr.help-mode-key]="'workload_bulk_selection'"
|
||||||
|
class="all-caps-label primary pointer"
|
||||||
|
translate="file-preview.tabs.annotations.select"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<iqser-popup-filter
|
||||||
|
*ngIf="documentInfoService.hidden()"
|
||||||
|
[actionsTemplate]="annotationFilterActionTemplate"
|
||||||
|
[attr.help-mode-key]="'workload_filter'"
|
||||||
|
[fileId]="state.file()?.id"
|
||||||
|
[primaryFiltersSlug]="'primaryFilters'"
|
||||||
|
[secondaryFiltersSlug]="'secondaryFilters'"
|
||||||
|
></iqser-popup-filter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<div class="right-content">
|
||||||
|
<redaction-readonly-banner
|
||||||
|
*ngIf="showAnalysisDisabledBanner; else readOnlyBanner"
|
||||||
|
[customTranslation]="translations.analysisDisabled"
|
||||||
|
></redaction-readonly-banner>
|
||||||
|
<ng-template #readOnlyBanner>
|
||||||
|
<redaction-readonly-banner *ngIf="state.isReadonly()"></redaction-readonly-banner>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<div *ngIf="multiSelectService.active()" class="multi-select">
|
||||||
|
<div class="selected-wrapper">
|
||||||
|
<iqser-round-checkbox
|
||||||
|
(click)="annotationManager.deselect()"
|
||||||
|
[indeterminate]="listingService.areSomeSelected$ | async"
|
||||||
|
type="with-bg"
|
||||||
|
></iqser-round-checkbox>
|
||||||
|
|
||||||
|
<span class="all-caps-label">{{ listingService.selectedLength$ | async }} selected </span>
|
||||||
|
|
||||||
|
<redaction-annotation-actions
|
||||||
|
*ngIf="listingService.areSomeSelected$ | async"
|
||||||
|
[alwaysVisible]="true"
|
||||||
|
[annotations]="listingService.selectedEntities$ | async"
|
||||||
|
[canPerformAnnotationActions]="state.isWritable()"
|
||||||
|
buttonType="primary"
|
||||||
|
tooltipPosition="above"
|
||||||
|
></redaction-annotation-actions>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<iqser-circle-button
|
||||||
|
(action)="multiSelectService.deactivate()"
|
||||||
|
[tooltip]="'file-preview.tabs.multi-select.close' | translate"
|
||||||
|
[type]="circleButtonTypes.primary"
|
||||||
|
icon="iqser:close"
|
||||||
|
tooltipPosition="before"
|
||||||
|
></iqser-circle-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="annotations-wrapper">
|
||||||
|
<redaction-quick-navigation
|
||||||
|
[pagesPanelActive]="pagesPanelActive"
|
||||||
|
[displayedPages]="displayedPages"
|
||||||
|
(pagesPanelActiveChange)="pagesPanelActive = $event"
|
||||||
|
(preventKeyDefault)="preventKeyDefault($event)"
|
||||||
|
></redaction-quick-navigation>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div
|
||||||
|
*ngIf="!viewModeService.isEarmarks()"
|
||||||
|
[attr.anotation-page-header]="pdf.currentPage()"
|
||||||
|
[hidden]="excludedPagesService.shown()"
|
||||||
|
class="workload-separator"
|
||||||
|
>
|
||||||
|
<span *ngIf="!!pdf.currentPage()" class="flex-align-items-center">
|
||||||
|
<iqser-circle-button
|
||||||
|
(action)="excludedPagesService.toggle()"
|
||||||
|
*ngIf="currentPageIsExcluded()"
|
||||||
|
[size]="14"
|
||||||
|
[tooltip]="'file-preview.excluded-from-redaction' | translate | capitalize"
|
||||||
|
class="mr-10 primary"
|
||||||
|
icon="red:exclude-pages"
|
||||||
|
tooltipPosition="above"
|
||||||
|
></iqser-circle-button>
|
||||||
|
|
||||||
|
<span
|
||||||
|
[translateParams]="{ page: pdf.currentPage(), count: activeAnnotations.length }"
|
||||||
|
[translate]="'page'"
|
||||||
|
class="all-caps-label"
|
||||||
|
></span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div *ngIf="multiSelectService.active()">
|
||||||
|
<div
|
||||||
|
(click)="selectAllOnActivePage()"
|
||||||
|
class="all-caps-label primary pointer"
|
||||||
|
translate="file-preview.tabs.annotations.select-all"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
(click)="deselectAllOnActivePage()"
|
||||||
|
class="all-caps-label primary pointer"
|
||||||
|
translate="file-preview.tabs.annotations.select-none"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
#annotationsElement
|
||||||
|
(keydown)="preventKeyDefault($event)"
|
||||||
|
(keyup)="preventKeyDefault($event)"
|
||||||
|
[class.active-panel]="!pagesPanelActive"
|
||||||
|
[hidden]="excludedPagesService.shown()"
|
||||||
|
class="annotations"
|
||||||
|
id="annotations-list"
|
||||||
|
tabindex="1"
|
||||||
|
>
|
||||||
|
<ng-container *ngIf="pdf.currentPage() && !displayedAnnotations.get(pdf.currentPage())?.length">
|
||||||
|
<iqser-empty-state
|
||||||
|
[horizontalPadding]="24"
|
||||||
|
[text]="'file-preview.no-data.title' | translate"
|
||||||
|
[verticalPadding]="40"
|
||||||
|
icon="iqser:document"
|
||||||
|
>
|
||||||
|
<ng-container *ngIf="currentPageIsExcluded() && displayedPages.length">
|
||||||
|
{{ 'file-preview.tabs.annotations.page-is' | translate }}
|
||||||
|
<a
|
||||||
|
(click)="excludedPagesService.toggle()"
|
||||||
|
class="with-underline"
|
||||||
|
translate="file-preview.excluded-from-redaction"
|
||||||
|
></a
|
||||||
|
>.
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="(fileDataService.allLength$ | async) === 0">
|
||||||
|
{{ 'file-preview.tabs.annotations.no-annotations' | translate }}
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="(fileDataService.allLength$ | async) > 0 && displayedPages.length === 0"
|
||||||
|
>{{ 'file-preview.tabs.annotations.wrong-filters' | translate }}
|
||||||
|
<a (click)="filterService.reset()" class="with-underline" translate="file-preview.tabs.annotations.reset"></a>
|
||||||
|
{{ 'file-preview.tabs.annotations.the-filters' | translate }}
|
||||||
|
</ng-container>
|
||||||
|
</iqser-empty-state>
|
||||||
|
|
||||||
|
<div *ngIf="displayedPages.length" class="no-annotations-buttons-container mt-32">
|
||||||
|
<iqser-icon-button
|
||||||
|
(action)="jumpToPreviousWithAnnotations()"
|
||||||
|
[disabled]="pdf.currentPage() <= displayedPages[0]"
|
||||||
|
[label]="'file-preview.tabs.annotations.jump-to-previous' | translate"
|
||||||
|
[type]="iconButtonTypes.dark"
|
||||||
|
icon="iqser:nav-prev"
|
||||||
|
></iqser-icon-button>
|
||||||
|
|
||||||
|
<iqser-icon-button
|
||||||
|
(action)="jumpToNextWithAnnotations()"
|
||||||
|
[disabled]="pdf.currentPage() >= displayedPages[displayedPages.length - 1]"
|
||||||
|
[label]="'file-preview.tabs.annotations.jump-to-next' | translate"
|
||||||
|
[type]="iconButtonTypes.dark"
|
||||||
|
class="mt-8"
|
||||||
|
icon="iqser:nav-next"
|
||||||
|
></iqser-icon-button>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<redaction-annotations-list
|
||||||
|
(pagesPanelActive)="pagesPanelActive = $event"
|
||||||
|
[annotations]="(displayedAnnotations$ | async)?.get(pdf.currentPage())"
|
||||||
|
></redaction-annotations-list>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<redaction-page-exclusion *ngIf="excludedPagesService.shown()"></redaction-page-exclusion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #annotationFilterActionTemplate let-filter="filter">
|
||||||
|
<iqser-circle-button
|
||||||
|
(action)="skippedService.toggleSkipped()"
|
||||||
|
*ngIf="filter.id === 'skipped'"
|
||||||
|
[icon]="skippedService.hideSkipped() ? 'iqser:visibility-off' : 'iqser:visibility'"
|
||||||
|
[tooltip]="
|
||||||
|
(skippedService.hideSkipped() ? 'file-preview.tabs.annotations.show-skipped' : 'file-preview.tabs.annotations.hide-skipped')
|
||||||
|
| translate
|
||||||
|
"
|
||||||
|
iqserPreventDefault
|
||||||
|
></iqser-circle-button>
|
||||||
|
</ng-template>
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
@use '../../../../../../../../../libs/common-ui/src/assets/styles/common-mixins';
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled-auto-analysis {
|
||||||
|
background-color: var(--iqser-yellow-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-content {
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.no-annotations-buttons-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
iqser-icon-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotations-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotations {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotations {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { AsyncPipe, NgIf, NgTemplateOutlet } from '@angular/common';
|
import { AsyncPipe, NgIf, NgTemplateOutlet } from '@angular/common';
|
||||||
import { ChangeDetectorRef, Component, computed, effect, ElementRef, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { ChangeDetectorRef, Component, computed, effect, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatIcon } from '@angular/material/icon';
|
import { MatIcon } from '@angular/material/icon';
|
||||||
import { MatTooltip } from '@angular/material/tooltip';
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
@ -15,8 +15,8 @@ import {
|
|||||||
IconButtonTypes,
|
IconButtonTypes,
|
||||||
PreventDefaultDirective,
|
PreventDefaultDirective,
|
||||||
} from '@iqser/common-ui';
|
} from '@iqser/common-ui';
|
||||||
import { FilterService, INestedFilter, PopupFilterComponent } from '@iqser/common-ui/lib/filtering';
|
import { FilterService, INestedFilter, PopupFilterComponent } from '@common-ui/filtering';
|
||||||
import { AutoUnsubscribe, Debounce, IqserEventTarget } from '@iqser/common-ui/lib/utils';
|
import { Debounce, IqserEventTarget } from '@common-ui/utils';
|
||||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||||
import { ListItem } from '@models/file/list-item';
|
import { ListItem } from '@models/file/list-item';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
@ -25,35 +25,38 @@ import { workloadTranslations } from '@translations/workload-translations';
|
|||||||
import { UserPreferenceService } from '@users/user-preference.service';
|
import { UserPreferenceService } from '@users/user-preference.service';
|
||||||
import { getLocalStorageDataByFileId } from '@utils/local-storage';
|
import { getLocalStorageDataByFileId } from '@utils/local-storage';
|
||||||
import { combineLatest, delay, Observable } from 'rxjs';
|
import { combineLatest, delay, Observable } from 'rxjs';
|
||||||
import { map, tap } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
import { REDAnnotationManager } from '../../../../pdf-viewer/services/annotation-manager.service';
|
||||||
|
import { REDDocumentViewer } from '../../../../pdf-viewer/services/document-viewer.service';
|
||||||
|
import { PageRotationService } from '../../../../pdf-viewer/services/page-rotation.service';
|
||||||
|
import { PdfViewer } from '../../../../pdf-viewer/services/pdf-viewer.service';
|
||||||
|
import { AnnotationProcessingService } from '../../../services/annotation-processing.service';
|
||||||
|
import { AnnotationsListingService } from '../../../services/annotations-listing.service';
|
||||||
|
import { DocumentInfoService } from '../../../services/document-info.service';
|
||||||
|
import { ExcludedPagesService } from '../../../services/excluded-pages.service';
|
||||||
|
import { FileDataService } from '../../../services/file-data.service';
|
||||||
|
import { FilePreviewStateService } from '../../../services/file-preview-state.service';
|
||||||
|
import { MultiSelectService } from '../../../services/multi-select.service';
|
||||||
|
import { SkippedService } from '../../../services/skipped.service';
|
||||||
|
import { ViewModeService } from '../../../services/view-mode.service';
|
||||||
|
import { AnnotationActionsComponent } from '../../annotation-actions/annotation-actions.component';
|
||||||
|
import { AnnotationsListComponent } from '../../annotations-list/annotations-list.component';
|
||||||
|
import { PageExclusionComponent } from '../../page-exclusion/page-exclusion.component';
|
||||||
|
import { PagesComponent } from '../../pages/pages.component';
|
||||||
|
import { ReadonlyBannerComponent } from '../../readonly-banner/readonly-banner.component';
|
||||||
|
import { DocumentInfoComponent } from '../../document-info/document-info.component';
|
||||||
|
import { QuickNavigationComponent } from '../../quick-navigation/quick-navigation.component';
|
||||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||||
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
|
import { BaseWorkloadComponent } from '../base-workload.component';
|
||||||
import { REDDocumentViewer } from '../../../pdf-viewer/services/document-viewer.service';
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
import { PageRotationService } from '../../../pdf-viewer/services/page-rotation.service';
|
|
||||||
import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
|
|
||||||
import { AnnotationProcessingService } from '../../services/annotation-processing.service';
|
|
||||||
import { AnnotationsListingService } from '../../services/annotations-listing.service';
|
|
||||||
import { DocumentInfoService } from '../../services/document-info.service';
|
|
||||||
import { ExcludedPagesService } from '../../services/excluded-pages.service';
|
|
||||||
import { FileDataService } from '../../services/file-data.service';
|
|
||||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
|
||||||
import { MultiSelectService } from '../../services/multi-select.service';
|
|
||||||
import { SkippedService } from '../../services/skipped.service';
|
|
||||||
import { ViewModeService } from '../../services/view-mode.service';
|
|
||||||
import { AnnotationActionsComponent } from '../annotation-actions/annotation-actions.component';
|
|
||||||
import { AnnotationsListComponent } from '../annotations-list/annotations-list.component';
|
|
||||||
import { PageExclusionComponent } from '../page-exclusion/page-exclusion.component';
|
|
||||||
import { PagesComponent } from '../pages/pages.component';
|
|
||||||
import { ReadonlyBannerComponent } from '../readonly-banner/readonly-banner.component';
|
|
||||||
import { DocumentInfoComponent } from '../document-info/document-info.component';
|
|
||||||
|
|
||||||
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
|
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
|
||||||
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-file-workload',
|
selector: 'redaction-redact-file-workload',
|
||||||
templateUrl: './file-workload.component.html',
|
templateUrl: './redact-file-workload.component.html',
|
||||||
styleUrls: ['./file-workload.component.scss'],
|
styleUrls: ['./redact-file-workload.component.scss'],
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
@ -75,9 +78,10 @@ const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
|||||||
CapitalizePipe,
|
CapitalizePipe,
|
||||||
NgTemplateOutlet,
|
NgTemplateOutlet,
|
||||||
DocumentInfoComponent,
|
DocumentInfoComponent,
|
||||||
|
QuickNavigationComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, OnDestroy {
|
export class RedactFileWorkloadComponent extends BaseWorkloadComponent implements OnInit {
|
||||||
@ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef;
|
@ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef;
|
||||||
@ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef;
|
@ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef;
|
||||||
readonly #isIqserDevMode = this._userPreferenceService.isIqserDevMode;
|
readonly #isIqserDevMode = this._userPreferenceService.isIqserDevMode;
|
||||||
@ -94,6 +98,10 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
displayedPages: number[] = [];
|
displayedPages: number[] = [];
|
||||||
pagesPanelActive = true;
|
pagesPanelActive = true;
|
||||||
|
|
||||||
|
protected readonly currentPage = toSignal(this.pdf.currentPage$);
|
||||||
|
protected readonly selectedAnnotationIds = toSignal(this.listingService.selected$);
|
||||||
|
protected readonly keyUp = toSignal(this._documentViewer.keyUp$);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly filterService: FilterService,
|
readonly filterService: FilterService,
|
||||||
readonly skippedService: SkippedService,
|
readonly skippedService: SkippedService,
|
||||||
@ -115,24 +123,23 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
// TODO: ngOnDetach is not called here, so we need to unsubscribe manually
|
effect(() => {
|
||||||
this.addActiveScreenSubscription = this.pdf.currentPage$.subscribe(pageNumber => {
|
this.#scrollViews();
|
||||||
this._scrollViews();
|
this.scrollAnnotationsToPage(this.currentPage(), 'always');
|
||||||
this.scrollAnnotationsToPage(pageNumber, 'always');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addActiveScreenSubscription = this.listingService.selected$.subscribe(annotationIds => {
|
effect(() => {
|
||||||
if (annotationIds.length > 0) {
|
if (this.selectedAnnotationIds().length > 0) {
|
||||||
this.pagesPanelActive = false;
|
this.pagesPanelActive = false;
|
||||||
}
|
}
|
||||||
this.scrollToSelectedAnnotation();
|
this.scrollToSelectedAnnotation();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addActiveScreenSubscription = this._documentViewer.keyUp$.subscribe($event => {
|
effect(() => {
|
||||||
this.handleKeyEvent($event);
|
this.handleKeyEvent(this.keyUp());
|
||||||
});
|
});
|
||||||
|
|
||||||
this.displayedAnnotations$ = this._displayedAnnotations$;
|
this.displayedAnnotations$ = this.#displayedAnnotations$;
|
||||||
|
|
||||||
effect(() => {
|
effect(() => {
|
||||||
if (this.multiSelectService.inactive()) {
|
if (this.multiSelectService.inactive()) {
|
||||||
@ -142,7 +149,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
|
|
||||||
effect(() => {
|
effect(() => {
|
||||||
this.viewModeService.viewMode();
|
this.viewModeService.viewMode();
|
||||||
this._scrollViews();
|
this.#scrollViews();
|
||||||
});
|
});
|
||||||
|
|
||||||
effect(
|
effect(
|
||||||
@ -168,7 +175,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
return this.listingService.selected.length ? this.listingService.selected[0] : null;
|
return this.listingService.selected.length ? this.listingService.selected[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _displayedAnnotations$(): Observable<Map<number, ListItem<AnnotationWrapper>[]>> {
|
get #displayedAnnotations$(): Observable<Map<number, ListItem<AnnotationWrapper>[]>> {
|
||||||
const primary$ = this.filterService.getFilterModels$('primaryFilters');
|
const primary$ = this.filterService.getFilterModels$('primaryFilters');
|
||||||
const secondary$ = this.filterService.getFilterModels$('secondaryFilters');
|
const secondary$ = this.filterService.getFilterModels$('secondaryFilters');
|
||||||
|
|
||||||
@ -182,7 +189,6 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
delay(0),
|
delay(0),
|
||||||
map(([annotations, primary, secondary]) => this.#filterAnnotations(annotations, primary, secondary)),
|
map(([annotations, primary, secondary]) => this.#filterAnnotations(annotations, primary, secondary)),
|
||||||
map(annotations => this.#mapListItemsFromAnnotationWrapperArray(annotations)),
|
map(annotations => this.#mapListItemsFromAnnotationWrapperArray(annotations)),
|
||||||
tap(annotations => this.#scrollToFirstAnnotationPage(annotations)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +233,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
@HostListener('window:keyup', ['$event'])
|
@HostListener('window:keyup', ['$event'])
|
||||||
handleKeyEvent($event: KeyboardEvent): void {
|
handleKeyEvent($event: KeyboardEvent): void {
|
||||||
if (
|
if (
|
||||||
!ALL_HOTKEY_ARRAY.includes($event.key) ||
|
!ALL_HOTKEY_ARRAY.includes($event?.key) ||
|
||||||
this._dialog.openDialogs.length ||
|
this._dialog.openDialogs.length ||
|
||||||
($event.target as IqserEventTarget).localName === 'input'
|
($event.target as IqserEventTarget).localName === 'input'
|
||||||
) {
|
) {
|
||||||
@ -277,7 +283,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
scrollAnnotationsToPage(page: number, mode: 'always' | 'if-needed' = 'if-needed'): void {
|
scrollAnnotationsToPage(page: number, mode: 'always' | 'if-needed' = 'if-needed'): void {
|
||||||
if (this._annotationsElement) {
|
if (this._annotationsElement) {
|
||||||
const elements: HTMLElement[] = this._annotationsElement.nativeElement.querySelectorAll(`div[anotation-page-header="${page}"]`);
|
const elements: HTMLElement[] = this._annotationsElement.nativeElement.querySelectorAll(`div[anotation-page-header="${page}"]`);
|
||||||
FileWorkloadComponent._scrollToFirstElement(elements, mode);
|
RedactFileWorkloadComponent._scrollToFirstElement(elements, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +295,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
const elements: HTMLElement[] = this._annotationsElement.nativeElement.querySelectorAll(
|
const elements: HTMLElement[] = this._annotationsElement.nativeElement.querySelectorAll(
|
||||||
`[annotation-id="${this._firstSelectedAnnotation?.id}"]`,
|
`[annotation-id="${this._firstSelectedAnnotation?.id}"]`,
|
||||||
);
|
);
|
||||||
FileWorkloadComponent._scrollToFirstElement(elements);
|
RedactFileWorkloadComponent._scrollToFirstElement(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollQuickNavigation(): void {
|
scrollQuickNavigation(): void {
|
||||||
@ -301,14 +307,6 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
this.#scrollQuickNavigationToPage(this.displayedPages[quickNavPageIndex]);
|
this.#scrollQuickNavigationToPage(this.displayedPages[quickNavPageIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollQuickNavFirst(): void {
|
|
||||||
this.pdf.navigateTo(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollQuickNavLast() {
|
|
||||||
this.pdf.navigateTo(this.state.file().numberOfPages);
|
|
||||||
}
|
|
||||||
|
|
||||||
preventKeyDefault($event: KeyboardEvent): void {
|
preventKeyDefault($event: KeyboardEvent): void {
|
||||||
if (COMMAND_KEY_ARRAY.includes($event.key) && !(($event.target as any).localName === 'input')) {
|
if (COMMAND_KEY_ARRAY.includes($event.key) && !(($event.target as any).localName === 'input')) {
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
@ -384,8 +382,9 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
@Debounce(0)
|
@Debounce(0)
|
||||||
private _scrollViews() {
|
#scrollViews() {
|
||||||
this.scrollQuickNavigation();
|
this.scrollQuickNavigation();
|
||||||
this.scrollAnnotations();
|
this.scrollAnnotations();
|
||||||
}
|
}
|
||||||
@ -501,9 +500,10 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
}
|
}
|
||||||
|
|
||||||
#scrollQuickNavigationToPage(page: number) {
|
#scrollQuickNavigationToPage(page: number) {
|
||||||
|
console.log('scrollQuickNavigationToPage');
|
||||||
if (this._quickNavigationElement) {
|
if (this._quickNavigationElement) {
|
||||||
const elements: HTMLElement[] = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${page}`);
|
const elements: HTMLElement[] = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${page}`);
|
||||||
FileWorkloadComponent._scrollToFirstElement(elements);
|
RedactFileWorkloadComponent._scrollToFirstElement(elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,11 +521,4 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
|
|||||||
});
|
});
|
||||||
return listItemsMap;
|
return listItemsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#scrollToFirstAnnotationPage(annotations: Map<number, ListItem<AnnotationWrapper>[]>) {
|
|
||||||
if (this.isDocumine && annotations.size && !this.displayedPages.includes(this.pdf.currentPage())) {
|
|
||||||
const page = annotations.keys().next().value;
|
|
||||||
this.pdf.navigateTo(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
<div
|
||||||
|
#quickNavigation
|
||||||
|
(keydown)="preventKeyDefault.emit($event)"
|
||||||
|
(keyup)="preventKeyDefault.emit($event)"
|
||||||
|
[class.active-panel]="pagesPanelActive()"
|
||||||
|
class="quick-navigation"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
(click)="scrollQuickNavFirst()"
|
||||||
|
[class.disabled]="pdf.currentPage() === 1"
|
||||||
|
[matTooltip]="'file-preview.quick-nav.jump-first' | translate"
|
||||||
|
class="jump"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
>
|
||||||
|
<mat-icon svgIcon="iqser:nav-first"></mat-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<redaction-pages (click)="pagesPanelActiveChange.emit(true)" [pages]="displayedPages()"></redaction-pages>
|
||||||
|
|
||||||
|
<div
|
||||||
|
(click)="scrollQuickNavLast()"
|
||||||
|
[class.disabled]="pdf.currentPage() === state.file()?.numberOfPages"
|
||||||
|
[matTooltip]="'file-preview.quick-nav.jump-last' | translate"
|
||||||
|
class="jump"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
>
|
||||||
|
<mat-icon svgIcon="iqser:nav-last"></mat-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
.quick-navigation {
|
||||||
|
height: 100%;
|
||||||
|
border-right: 1px solid var(--iqser-separator);
|
||||||
|
min-width: 61px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.jump {
|
||||||
|
min-height: 32px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.25s;
|
||||||
|
|
||||||
|
&:not(.disabled):hover {
|
||||||
|
background-color: var(--iqser-tab-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
cursor: default;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active-panel {
|
||||||
|
background-color: var(--iqser-workload-pages-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
import { Component, EventEmitter, input, Output } from '@angular/core';
|
||||||
|
import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
|
||||||
|
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||||
|
import { MatIcon } from '@angular/material/icon';
|
||||||
|
import { PagesComponent } from '../pages/pages.component';
|
||||||
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-quick-navigation',
|
||||||
|
templateUrl: './quick-navigation.component.html',
|
||||||
|
styleUrls: ['./quick-navigation.component.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [MatIcon, PagesComponent, MatTooltip, TranslateModule],
|
||||||
|
})
|
||||||
|
export class QuickNavigationComponent {
|
||||||
|
readonly pagesPanelActive = input<boolean>(false);
|
||||||
|
readonly displayedPages = input<number[]>([]);
|
||||||
|
@Output() readonly pagesPanelActiveChange = new EventEmitter<boolean>();
|
||||||
|
@Output() readonly preventKeyDefault = new EventEmitter<KeyboardEvent>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly pdf: PdfViewer,
|
||||||
|
readonly state: FilePreviewStateService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
scrollQuickNavFirst() {
|
||||||
|
this.pdf.navigateTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollQuickNavLast() {
|
||||||
|
this.pdf.navigateTo(this.state.file().numberOfPages);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,16 @@
|
|||||||
<ng-container *ngIf="state.file() as file">
|
@if (state.file(); as file) {
|
||||||
<iqser-empty-state
|
@if (isDocumine) {
|
||||||
*ngIf="file.excluded && documentInfoService.hidden() && !this.isDocumine"
|
<redaction-documine-file-workload></redaction-documine-file-workload>
|
||||||
[horizontalPadding]="40"
|
} @else {
|
||||||
[text]="'file-preview.tabs.is-excluded' | translate"
|
<iqser-empty-state
|
||||||
icon="red:needs-work"
|
*ngIf="file.excluded && documentInfoService.hidden()"
|
||||||
></iqser-empty-state>
|
[horizontalPadding]="40"
|
||||||
|
[text]="'file-preview.tabs.is-excluded' | translate"
|
||||||
|
icon="red:needs-work"
|
||||||
|
></iqser-empty-state>
|
||||||
|
|
||||||
<redaction-document-info *ngIf="documentInfoService.shown() && !isDocumine" id="document-info"></redaction-document-info>
|
<redaction-document-info *ngIf="documentInfoService.shown()" id="document-info"></redaction-document-info>
|
||||||
|
|
||||||
<redaction-file-workload *ngIf="!file.excluded || isDocumine"></redaction-file-workload>
|
<redaction-redact-file-workload *ngIf="!file.excluded"></redaction-redact-file-workload>
|
||||||
</ng-container>
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -6,15 +6,23 @@ import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
|
|||||||
import { DocumentInfoService } from '../../services/document-info.service';
|
import { DocumentInfoService } from '../../services/document-info.service';
|
||||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||||
import { DocumentInfoComponent } from '../document-info/document-info.component';
|
import { DocumentInfoComponent } from '../document-info/document-info.component';
|
||||||
import { FileWorkloadComponent } from '../file-workload/file-workload.component';
|
|
||||||
import { getConfig } from '@iqser/common-ui';
|
import { getConfig } from '@iqser/common-ui';
|
||||||
|
import { RedactFileWorkloadComponent } from '../file-workload/redact-file-workload/redact-file-workload.component';
|
||||||
|
import { DocumineFileWorkloadComponent } from '../file-workload/documine-file-workload/documine-file-workload.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-file-preview-right-container',
|
selector: 'redaction-file-preview-right-container',
|
||||||
templateUrl: './file-preview-right-container.component.html',
|
templateUrl: './file-preview-right-container.component.html',
|
||||||
styleUrls: ['./file-preview-right-container.component.scss'],
|
styleUrls: ['./file-preview-right-container.component.scss'],
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [EmptyStateComponent, NgIf, TranslateModule, DocumentInfoComponent, FileWorkloadComponent],
|
imports: [
|
||||||
|
EmptyStateComponent,
|
||||||
|
NgIf,
|
||||||
|
TranslateModule,
|
||||||
|
DocumentInfoComponent,
|
||||||
|
RedactFileWorkloadComponent,
|
||||||
|
DocumineFileWorkloadComponent,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class FilePreviewRightContainerComponent {
|
export class FilePreviewRightContainerComponent {
|
||||||
readonly isDocumine = getConfig().IS_DOCUMINE;
|
readonly isDocumine = getConfig().IS_DOCUMINE;
|
||||||
|
|||||||
@ -392,7 +392,6 @@
|
|||||||
"annotation": {
|
"annotation": {
|
||||||
"pending": "(Analyse steht aus)"
|
"pending": "(Analyse steht aus)"
|
||||||
},
|
},
|
||||||
"annotations": "Annotationen",
|
|
||||||
"archived-dossiers-listing": {
|
"archived-dossiers-listing": {
|
||||||
"no-data": {
|
"no-data": {
|
||||||
"title": "Keine archivierten Dossiers."
|
"title": "Keine archivierten Dossiers."
|
||||||
@ -855,6 +854,9 @@
|
|||||||
"export": "Export",
|
"export": "Export",
|
||||||
"export-tooltip": "Export"
|
"export-tooltip": "Export"
|
||||||
},
|
},
|
||||||
|
"documine-workload": {
|
||||||
|
"header-label": ""
|
||||||
|
},
|
||||||
"dossier-attribute-types": {
|
"dossier-attribute-types": {
|
||||||
"date": "Datum",
|
"date": "Datum",
|
||||||
"image": "Bild",
|
"image": "Bild",
|
||||||
|
|||||||
@ -392,7 +392,6 @@
|
|||||||
"annotation": {
|
"annotation": {
|
||||||
"pending": "(Pending analysis)"
|
"pending": "(Pending analysis)"
|
||||||
},
|
},
|
||||||
"annotations": "Annotations",
|
|
||||||
"archived-dossiers-listing": {
|
"archived-dossiers-listing": {
|
||||||
"no-data": {
|
"no-data": {
|
||||||
"title": "No archived dossiers."
|
"title": "No archived dossiers."
|
||||||
@ -855,6 +854,9 @@
|
|||||||
"export": "Export",
|
"export": "Export",
|
||||||
"export-tooltip": "Export"
|
"export-tooltip": "Export"
|
||||||
},
|
},
|
||||||
|
"documine-workload": {
|
||||||
|
"header-label": ""
|
||||||
|
},
|
||||||
"dossier-attribute-types": {
|
"dossier-attribute-types": {
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
|
|||||||
@ -392,7 +392,6 @@
|
|||||||
"annotation": {
|
"annotation": {
|
||||||
"pending": "(Pending analysis)"
|
"pending": "(Pending analysis)"
|
||||||
},
|
},
|
||||||
"annotations": "Annotations",
|
|
||||||
"archived-dossiers-listing": {
|
"archived-dossiers-listing": {
|
||||||
"no-data": {
|
"no-data": {
|
||||||
"title": "No archived dossiers."
|
"title": "No archived dossiers."
|
||||||
@ -855,6 +854,9 @@
|
|||||||
"export": "Component download",
|
"export": "Component download",
|
||||||
"export-tooltip": "Component download"
|
"export-tooltip": "Component download"
|
||||||
},
|
},
|
||||||
|
"documine-workload": {
|
||||||
|
"header-label": ""
|
||||||
|
},
|
||||||
"dossier-attribute-types": {
|
"dossier-attribute-types": {
|
||||||
"date": "Datum",
|
"date": "Datum",
|
||||||
"image": "Bild",
|
"image": "Bild",
|
||||||
|
|||||||
@ -392,7 +392,6 @@
|
|||||||
"annotation": {
|
"annotation": {
|
||||||
"pending": "(Pending analysis)"
|
"pending": "(Pending analysis)"
|
||||||
},
|
},
|
||||||
"annotations": "Annotations",
|
|
||||||
"archived-dossiers-listing": {
|
"archived-dossiers-listing": {
|
||||||
"no-data": {
|
"no-data": {
|
||||||
"title": "No archived dossiers."
|
"title": "No archived dossiers."
|
||||||
@ -855,6 +854,9 @@
|
|||||||
"export": "Component download",
|
"export": "Component download",
|
||||||
"export-tooltip": "Component download"
|
"export-tooltip": "Component download"
|
||||||
},
|
},
|
||||||
|
"documine-workload": {
|
||||||
|
"header-label": "Annotations"
|
||||||
|
},
|
||||||
"dossier-attribute-types": {
|
"dossier-attribute-types": {
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
|
|||||||
@ -187,7 +187,8 @@ body {
|
|||||||
);
|
);
|
||||||
height: calc(100% - calc(var(--iqser-top-bar-height) + 50px));
|
height: calc(100% - calc(var(--iqser-top-bar-height) + 50px));
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: calc(var(--qiuck-navigation-width) + 3px);
|
//right: calc(var(--qiuck-navigation-width) + 3px);
|
||||||
|
right: calc(var(--qiuck-navigation-width));
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
&.document-info {
|
&.document-info {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user