Pull request #264: Common lib
Merge in RED/ui from common-lib to master * commit 'd8e758ff147eb9331808ab51dc9cd0fee924974d': refactor file status update restore last scrolled position dossier wrapper refactor move status bar to common lib move table header to common lib move quick filters remove withSort, rename column to sortByKey
This commit is contained in:
commit
3f3ddb019c
@ -12,7 +12,7 @@
|
||||
[routerLink]="'/main/dossiers/' + appStateService.activeDossierId"
|
||||
mat-menu-item
|
||||
>
|
||||
{{ appStateService.activeDossier.dossier.dossierName }}
|
||||
{{ appStateService.activeDossier.dossierName }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="appStateService.activeFile"
|
||||
@ -44,7 +44,7 @@
|
||||
class="breadcrumb"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ appStateService.activeDossier.dossier.dossierName }}
|
||||
{{ appStateService.activeDossier.dossierName }}
|
||||
</a>
|
||||
<mat-icon *ngIf="appStateService.activeFile" svgIcon="red:arrow-right"></mat-icon>
|
||||
<a
|
||||
|
||||
@ -3,13 +3,13 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[hasEmptyColumn]="true"
|
||||
[selectionEnabled]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="entitiesService.noData$ | async"
|
||||
|
||||
@ -1,23 +1,55 @@
|
||||
import { FileAttributesConfig, FileStatus } from '@redaction/red-ui-http';
|
||||
import { StatusSorter } from '@utils/sorters/status-sorter';
|
||||
|
||||
export class FileStatusWrapper {
|
||||
const processingStatuses = [
|
||||
FileStatus.StatusEnum.REPROCESS,
|
||||
FileStatus.StatusEnum.FULLREPROCESS,
|
||||
FileStatus.StatusEnum.OCRPROCESSING,
|
||||
FileStatus.StatusEnum.INDEXING,
|
||||
FileStatus.StatusEnum.PROCESSING
|
||||
] as const;
|
||||
|
||||
export class FileStatusWrapper implements FileStatus {
|
||||
readonly added = this.fileStatus.added;
|
||||
readonly allManualRedactionsApplied = this.fileStatus.allManualRedactionsApplied;
|
||||
readonly analysisDuration = this.fileStatus.analysisDuration;
|
||||
readonly analysisRequired = this.fileStatus.analysisRequired && !this.fileStatus.excluded;
|
||||
readonly approvalDate = this.fileStatus.approvalDate;
|
||||
currentReviewer = this.fileStatus.currentReviewer;
|
||||
readonly dictionaryVersion = this.fileStatus.dictionaryVersion;
|
||||
readonly dossierDictionaryVersion = this.fileStatus.dossierDictionaryVersion;
|
||||
readonly dossierId = this.fileStatus.dossierId;
|
||||
readonly excluded = this.fileStatus.excluded;
|
||||
readonly fileAttributes = this.fileStatus.fileAttributes;
|
||||
readonly fileId = this.fileStatus.fileId;
|
||||
readonly filename = this.fileStatus.filename;
|
||||
readonly hasAnnotationComments = this.fileStatus.hasAnnotationComments;
|
||||
readonly hasHints = this.fileStatus.hasHints;
|
||||
readonly hasImages = this.fileStatus.hasImages;
|
||||
readonly hasRedactions = this.fileStatus.hasRedactions;
|
||||
readonly hasRequests = this.fileStatus.hasRequests;
|
||||
readonly hasUpdates = this.fileStatus.hasUpdates;
|
||||
readonly lastOCRTime = this.fileStatus.lastOCRTime;
|
||||
readonly lastProcessed = this.fileStatus.lastProcessed;
|
||||
readonly lastReviewer = this.fileStatus.lastReviewer;
|
||||
readonly lastUpdated = this.fileStatus.lastUpdated;
|
||||
readonly lastUploaded = this.fileStatus.lastUploaded;
|
||||
readonly legalBasisVersion = this.fileStatus.legalBasisVersion;
|
||||
readonly numberOfAnalyses = this.fileStatus.numberOfAnalyses;
|
||||
readonly numberOfPages = this.fileStatus.numberOfPages;
|
||||
readonly rulesVersion = this.fileStatus.rulesVersion;
|
||||
readonly status = this._status;
|
||||
readonly uploader = this.fileStatus.uploader;
|
||||
readonly excludedPages = this.fileStatus.excludedPages;
|
||||
|
||||
primaryAttribute: string;
|
||||
searchField: string;
|
||||
|
||||
constructor(
|
||||
public fileStatus: FileStatus,
|
||||
public reviewerName: string,
|
||||
public dossierTemplateId: string,
|
||||
fileAttributesConfig?: FileAttributesConfig
|
||||
) {
|
||||
this.searchField = fileStatus.filename;
|
||||
|
||||
constructor(readonly fileStatus: FileStatus, public reviewerName: string, fileAttributesConfig?: FileAttributesConfig) {
|
||||
if (fileAttributesConfig) {
|
||||
const primary = fileAttributesConfig.fileAttributeConfigs?.find(c => c.primaryAttribute);
|
||||
if (primary && fileStatus.fileAttributes?.attributeIdToValue) {
|
||||
this.primaryAttribute = fileStatus.fileAttributes?.attributeIdToValue[primary.id];
|
||||
this.searchField += ' ' + this.primaryAttribute;
|
||||
this.filename += ' ' + this.primaryAttribute;
|
||||
}
|
||||
|
||||
if (!this.primaryAttribute) {
|
||||
@ -27,178 +59,40 @@ export class FileStatusWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
get analysisDuration() {
|
||||
return this.fileStatus.analysisDuration;
|
||||
readonly excludedPagesCount = this.excludedPages?.length ?? 0;
|
||||
readonly statusSort = StatusSorter[this.status];
|
||||
readonly pages = this._pages;
|
||||
readonly cacheIdentifier = btoa(this.lastUploaded + this.lastOCRTime);
|
||||
|
||||
readonly hasUnappliedSuggestions = !this.allManualRedactionsApplied;
|
||||
readonly hintsOnly = this.hasHints && !this.hasRedactions;
|
||||
readonly hasNone = !this.hasRedactions && !this.hasHints && !this.hasRequests;
|
||||
|
||||
readonly isError = this.status === FileStatus.StatusEnum.ERROR;
|
||||
readonly isProcessing = processingStatuses.includes(this.status);
|
||||
readonly isApproved = this.status === FileStatus.StatusEnum.APPROVED;
|
||||
readonly isPending = this.status === FileStatus.StatusEnum.UNPROCESSED;
|
||||
readonly isUnderReview = this.status === FileStatus.StatusEnum.UNDERREVIEW;
|
||||
readonly isUnderApproval = this.status === FileStatus.StatusEnum.UNDERAPPROVAL;
|
||||
readonly canBeApproved = !this.analysisRequired && !this.hasRequests;
|
||||
readonly canBeOpened = !this.isError && !this.isPending;
|
||||
readonly isWorkable = !this.isProcessing && this.canBeOpened;
|
||||
readonly canBeOCRed = !this.excluded && !this.lastOCRTime && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(this.status);
|
||||
|
||||
get isUnassigned() {
|
||||
return !this.currentReviewer;
|
||||
}
|
||||
|
||||
get lastProcessed() {
|
||||
return this.fileStatus.lastProcessed;
|
||||
}
|
||||
|
||||
get added() {
|
||||
return this.fileStatus.added;
|
||||
}
|
||||
|
||||
get lastUploaded() {
|
||||
return this.fileStatus.lastUploaded;
|
||||
}
|
||||
|
||||
get hasImages() {
|
||||
return this.fileStatus.hasImages;
|
||||
}
|
||||
|
||||
get hasUpdates() {
|
||||
return this.fileStatus.hasUpdates && !this.hasRequests;
|
||||
}
|
||||
|
||||
get hasUnappliedSuggestions() {
|
||||
return !this.fileStatus.allManualRedactionsApplied;
|
||||
}
|
||||
|
||||
get currentReviewer() {
|
||||
return this.fileStatus.currentReviewer;
|
||||
}
|
||||
|
||||
set currentReviewer(value: string) {
|
||||
this.fileStatus.currentReviewer = value;
|
||||
}
|
||||
|
||||
get fileId() {
|
||||
return this.fileStatus.fileId;
|
||||
}
|
||||
|
||||
get filename() {
|
||||
return this.fileStatus.filename;
|
||||
}
|
||||
|
||||
get hasAnnotationComments() {
|
||||
// return this.fileStatus.hasAnnotationComments;
|
||||
// TODO remove this once backend works properly
|
||||
return false;
|
||||
}
|
||||
|
||||
get ocrTime() {
|
||||
return this.fileStatus.lastOCRTime;
|
||||
}
|
||||
|
||||
get hasHints() {
|
||||
return this.fileStatus.hasHints;
|
||||
}
|
||||
|
||||
get hintsOnly() {
|
||||
return this.fileStatus.hasHints && !this.fileStatus.hasRedactions;
|
||||
}
|
||||
|
||||
get hasRedactions() {
|
||||
return this.fileStatus.hasRedactions;
|
||||
}
|
||||
|
||||
get hasRequests() {
|
||||
return this.fileStatus.hasRequests || this.hasUnappliedSuggestions;
|
||||
}
|
||||
|
||||
get hasNone() {
|
||||
return !this.hasRedactions && !this.hasHints && !this.hasRequests;
|
||||
}
|
||||
|
||||
get lastUpdated() {
|
||||
return this.fileStatus.lastUpdated;
|
||||
}
|
||||
|
||||
get numberOfAnalyses() {
|
||||
return this.fileStatus.numberOfAnalyses;
|
||||
}
|
||||
|
||||
get dossierId() {
|
||||
return this.fileStatus.dossierId;
|
||||
}
|
||||
|
||||
get isExcluded() {
|
||||
return this.fileStatus.excluded;
|
||||
}
|
||||
|
||||
get status() {
|
||||
return this.fileStatus.status === 'REPROCESS' || this.fileStatus.status === 'FULLREPROCESS' ? 'PROCESSING' : this.fileStatus.status;
|
||||
}
|
||||
|
||||
get numberOfPages() {
|
||||
return this.fileStatus.numberOfPages;
|
||||
}
|
||||
|
||||
get numberOfExcludedPages() {
|
||||
return this.fileStatus.excludedPages?.length || 0;
|
||||
}
|
||||
|
||||
get uploader() {
|
||||
return this.fileStatus.uploader;
|
||||
}
|
||||
|
||||
get isPending() {
|
||||
return this.status === FileStatus.StatusEnum.UNPROCESSED;
|
||||
}
|
||||
|
||||
get isProcessing() {
|
||||
return [
|
||||
FileStatus.StatusEnum.REPROCESS,
|
||||
FileStatus.StatusEnum.FULLREPROCESS,
|
||||
FileStatus.StatusEnum.OCRPROCESSING,
|
||||
FileStatus.StatusEnum.INDEXING,
|
||||
FileStatus.StatusEnum.PROCESSING
|
||||
].includes(this.status);
|
||||
}
|
||||
|
||||
get analysisRequired() {
|
||||
return this.fileStatus.analysisRequired && !this.fileStatus.excluded;
|
||||
}
|
||||
|
||||
get statusSort() {
|
||||
return StatusSorter[this.status];
|
||||
}
|
||||
|
||||
get isWorkable() {
|
||||
return !this.isProcessing && !this.isPending && !this.isError;
|
||||
}
|
||||
|
||||
get isApproved() {
|
||||
return this.fileStatus.status === 'APPROVED';
|
||||
}
|
||||
|
||||
get isError() {
|
||||
return this.fileStatus.status === 'ERROR';
|
||||
}
|
||||
|
||||
get pages() {
|
||||
private get _pages() {
|
||||
if (this.fileStatus.status === 'ERROR') {
|
||||
return -1;
|
||||
}
|
||||
return this.fileStatus.numberOfPages ? this.fileStatus.numberOfPages : 0;
|
||||
}
|
||||
|
||||
get isApprovedOrUnderApproval() {
|
||||
return this.status === 'APPROVED' || this.status === 'UNDER_APPROVAL';
|
||||
}
|
||||
|
||||
get isUnassigned() {
|
||||
return !this.currentReviewer;
|
||||
}
|
||||
|
||||
get isUnderReview() {
|
||||
return this.fileStatus.status === 'UNDER_REVIEW';
|
||||
}
|
||||
|
||||
get isUnderApproval() {
|
||||
return this.fileStatus.status === 'UNDER_APPROVAL';
|
||||
}
|
||||
|
||||
get canApprove() {
|
||||
return this.status === 'UNDER_REVIEW' || this.status === 'UNDER_APPROVAL';
|
||||
}
|
||||
|
||||
get cacheIdentifier() {
|
||||
return btoa(this.fileStatus.lastUploaded + this.fileStatus.lastOCRTime);
|
||||
}
|
||||
|
||||
get excludedPages(): number[] {
|
||||
return this.fileStatus.excludedPages;
|
||||
private get _status(): FileStatus.StatusEnum {
|
||||
return this.fileStatus.status === FileStatus.StatusEnum.REPROCESS || this.fileStatus.status === FileStatus.StatusEnum.FULLREPROCESS
|
||||
? FileStatus.StatusEnum.PROCESSING
|
||||
: this.fileStatus.status;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<div class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDossierTemplateDialog($event)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
*ngIf="currentUser.isAdmin"
|
||||
[tooltip]="'dossier-templates-listing.action.delete' | translate"
|
||||
icon="red:trash"
|
||||
[type]="circleButtonTypes.dark"
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="openEditDossierTemplateDialog($event)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
*ngIf="currentUser.isAdmin"
|
||||
[tooltip]="'dossier-templates-listing.action.edit' | translate"
|
||||
icon="red:edit"
|
||||
[type]="circleButtonTypes.dark"
|
||||
|
||||
@ -1,34 +1,35 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { DossierTemplateControllerService } from '@redaction/red-ui-http';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { CircleButtonTypes } from '@iqser/common-ui';
|
||||
import { UserService } from '@services/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-template-actions',
|
||||
templateUrl: './dossier-template-actions.component.html',
|
||||
styleUrls: ['./dossier-template-actions.component.scss']
|
||||
})
|
||||
export class DossierTemplateActionsComponent {
|
||||
export class DossierTemplateActionsComponent implements OnInit {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
|
||||
@Input() dossierTemplateId: string;
|
||||
@Output() loadDossierTemplatesData = new EventEmitter<any>();
|
||||
|
||||
constructor(
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _dossierTemplateControllerService: DossierTemplateControllerService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _router: Router,
|
||||
readonly permissionsService: PermissionsService
|
||||
) {
|
||||
if (!this.dossierTemplateId) {
|
||||
this.dossierTemplateId = this._appStateService.activeDossierTemplateId;
|
||||
}
|
||||
private readonly _userService: UserService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _dossierTemplateControllerService: DossierTemplateControllerService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.dossierTemplateId ??= this._appStateService.activeDossierTemplateId;
|
||||
}
|
||||
|
||||
get dossierTemplate() {
|
||||
@ -48,9 +49,7 @@ export class DossierTemplateActionsComponent {
|
||||
await this._appStateService.loadAllDossierTemplates();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
await this._router.navigate(['main', 'admin']);
|
||||
if (this.loadDossierTemplatesData) {
|
||||
this.loadDossierTemplatesData.emit();
|
||||
}
|
||||
this.loadDossierTemplatesData?.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[hasEmptyColumn]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="entitiesService.noData$ | async"
|
||||
|
||||
@ -8,7 +8,7 @@ iqser-table-column-name::ng-deep > div {
|
||||
}
|
||||
}
|
||||
|
||||
redaction-table-header::ng-deep .header-item {
|
||||
iqser-table-header::ng-deep .header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
box-shadow: none;
|
||||
border-top: 1px solid $separator;
|
||||
|
||||
@ -86,7 +86,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<div class="table-header" iqserSyncWidth="table-item">
|
||||
<iqser-table-column-name
|
||||
[label]="'audit-screen.table-col-names.message' | translate"
|
||||
column="message"
|
||||
|
||||
@ -20,11 +20,11 @@
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[hasEmptyColumn]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
|
||||
<div *cdkVirtualFor="let color of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey" class="table-item">
|
||||
|
||||
@ -30,8 +30,7 @@ export class DefaultColorsScreenComponent extends ListingComponent<ListItem> imp
|
||||
readonly tableColumnConfigs: TableColumnConfig<ListItem>[] = [
|
||||
{
|
||||
label: _('default-colors-screen.table-col-names.key'),
|
||||
withSort: true,
|
||||
column: 'key'
|
||||
sortByKey: 'key'
|
||||
},
|
||||
{ label: _('default-colors-screen.table-col-names.color'), class: 'flex-center' }
|
||||
];
|
||||
|
||||
@ -20,13 +20,13 @@
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[hasEmptyColumn]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
(action)="openAddEditDictionaryDialog()"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import '../../../../../assets/styles/red-mixins';
|
||||
|
||||
redaction-table-header::ng-deep .header-item {
|
||||
iqser-table-header::ng-deep .header-item {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
|
||||
@ -34,13 +34,11 @@ export class DictionaryListingScreenComponent extends ListingComponent<TypeValue
|
||||
readonly tableColumnConfigs: TableColumnConfig<TypeValueWrapper>[] = [
|
||||
{
|
||||
label: _('dictionary-listing.table-col-names.type'),
|
||||
withSort: true,
|
||||
column: 'label'
|
||||
sortByKey: 'label'
|
||||
},
|
||||
{
|
||||
label: _('dictionary-listing.table-col-names.order-of-importance'),
|
||||
withSort: true,
|
||||
column: 'rank',
|
||||
sortByKey: 'rank',
|
||||
class: 'flex-center'
|
||||
},
|
||||
{
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<div class="actions">
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDictionaryDialog($event)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
*ngIf="currentUser.isAdmin"
|
||||
[tooltip]="'dictionary-overview.action.delete' | translate"
|
||||
icon="red:trash"
|
||||
tooltipPosition="below"
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="openEditDictionaryDialog($event)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
*ngIf="currentUser.isAdmin"
|
||||
[tooltip]="'dictionary-overview.action.edit' | translate"
|
||||
icon="red:edit"
|
||||
tooltipPosition="below"
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="fileInput.click()"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
*ngIf="currentUser.isAdmin"
|
||||
[tooltip]="'dictionary-overview.action.upload' | translate"
|
||||
icon="red:upload"
|
||||
tooltipPosition="below"
|
||||
@ -56,7 +56,7 @@
|
||||
<redaction-dictionary-manager
|
||||
#dictionaryManager
|
||||
(saveDictionary)="saveEntries($event)"
|
||||
[canEdit]="permissionsService.isAdmin()"
|
||||
[canEdit]="currentUser.isAdmin"
|
||||
[initialEntries]="entries"
|
||||
></redaction-dictionary-manager>
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { DictionaryControllerService } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { saveAs } from 'file-saver';
|
||||
@ -12,6 +11,7 @@ import { DictionarySaveService } from '@shared/services/dictionary-save.service'
|
||||
import { TypeValueWrapper } from '@models/file/type-value.wrapper';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { CircleButtonTypes } from '@iqser/common-ui';
|
||||
import { UserService } from '@services/user.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dictionary-overview-screen.component.html',
|
||||
@ -19,33 +19,32 @@ import { CircleButtonTypes } from '@iqser/common-ui';
|
||||
})
|
||||
export class DictionaryOverviewScreenComponent extends ComponentHasChanges implements OnInit {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
|
||||
entries: string[] = [];
|
||||
dictionary: TypeValueWrapper;
|
||||
|
||||
@ViewChild('dictionaryManager', { static: false })
|
||||
private readonly _dictionaryManager: DictionaryManagerComponent;
|
||||
@ViewChild('fileInput') private readonly _fileInput: ElementRef;
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
private readonly _router: Router,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
protected readonly _translateService: TranslateService,
|
||||
private readonly _dictionarySaveService: DictionarySaveService,
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _router: Router,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _loadingService: LoadingService
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService
|
||||
) {
|
||||
super(_translateService);
|
||||
this._appStateService.activateDictionary(
|
||||
this._activatedRoute.snapshot.params.type,
|
||||
this._activatedRoute.snapshot.params.dossierTemplateId
|
||||
);
|
||||
}
|
||||
|
||||
get dictionary(): TypeValueWrapper {
|
||||
return this._appStateService.activeDictionary;
|
||||
this.dictionary = this._appStateService.activeDictionary;
|
||||
}
|
||||
|
||||
get hasChanges() {
|
||||
@ -67,6 +66,7 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple
|
||||
async () => {
|
||||
this._loadingService.start();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this.dictionary = this._appStateService.activeDictionary;
|
||||
this._loadingService.stop();
|
||||
}
|
||||
);
|
||||
|
||||
@ -20,13 +20,13 @@
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[hasEmptyColumn]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
(action)="openAddEditAttributeDialog($event)"
|
||||
|
||||
@ -25,14 +25,12 @@ export class DossierAttributesListingScreenComponent extends ListingComponent<Do
|
||||
readonly tableColumnConfigs: TableColumnConfig<DossierAttributeConfig>[] = [
|
||||
{
|
||||
label: _('dossier-attributes-listing.table-col-names.label'),
|
||||
withSort: true,
|
||||
column: 'label'
|
||||
sortByKey: 'label'
|
||||
},
|
||||
{ label: _('dossier-attributes-listing.table-col-names.placeholder') },
|
||||
{
|
||||
label: _('dossier-attributes-listing.table-col-names.type'),
|
||||
withSort: true,
|
||||
column: 'type'
|
||||
sortByKey: 'type'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
@ -29,7 +29,7 @@
|
||||
icon="red:plus"
|
||||
></iqser-icon-button>
|
||||
</div>
|
||||
</redaction-table-header>
|
||||
</iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="entitiesService.noData$ | async"
|
||||
|
||||
@ -24,19 +24,16 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent<Dos
|
||||
tableColumnConfigs: TableColumnConfig<DossierTemplateModelWrapper>[] = [
|
||||
{
|
||||
label: _('dossier-templates-listing.table-col-names.name'),
|
||||
withSort: true,
|
||||
column: 'name'
|
||||
sortByKey: 'name'
|
||||
},
|
||||
{ label: _('dossier-templates-listing.table-col-names.created-by'), class: 'user-column' },
|
||||
{
|
||||
label: _('dossier-templates-listing.table-col-names.created-on'),
|
||||
withSort: true,
|
||||
column: 'dateAdded'
|
||||
sortByKey: 'dateAdded'
|
||||
},
|
||||
{
|
||||
label: _('dossier-templates-listing.table-col-names.modified-on'),
|
||||
withSort: true,
|
||||
column: 'dateModified'
|
||||
sortByKey: 'dateModified'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@ -20,13 +20,13 @@
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[hasEmptyColumn]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="entitiesService.noData$ | async"
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
redaction-table-header::ng-deep .header-item {
|
||||
iqser-table-header::ng-deep .header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
}
|
||||
|
||||
|
||||
@ -25,18 +25,15 @@ export class FileAttributesListingScreenComponent extends ListingComponent<FileA
|
||||
readonly tableColumnConfigs: TableColumnConfig<FileAttributeConfig>[] = [
|
||||
{
|
||||
label: _('file-attributes-listing.table-col-names.name'),
|
||||
withSort: true,
|
||||
column: 'label'
|
||||
sortByKey: 'label'
|
||||
},
|
||||
{
|
||||
label: _('file-attributes-listing.table-col-names.type'),
|
||||
withSort: true,
|
||||
column: 'type'
|
||||
sortByKey: 'type'
|
||||
},
|
||||
{
|
||||
label: _('file-attributes-listing.table-col-names.read-only'),
|
||||
withSort: true,
|
||||
column: 'editable',
|
||||
sortByKey: 'editable',
|
||||
class: 'flex-center'
|
||||
},
|
||||
{ label: _('file-attributes-listing.table-col-names.csv-column') },
|
||||
|
||||
@ -7,10 +7,9 @@ import { saveAs } from 'file-saver';
|
||||
import { ComponentHasChanges } from '@guards/can-deactivate.guard';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { Debounce } from '../../../../utils/debounce';
|
||||
import { Debounce, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { IconButtonTypes } from '@iqser/common-ui';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import ICodeEditor = monaco.editor.ICodeEditor;
|
||||
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
||||
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
|
||||
|
||||
@ -5,12 +5,12 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="entitiesService.noData$ | async"
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { Dossier } from '@redaction/red-ui-http';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
|
||||
@ -29,11 +28,10 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly tableHeaderLabel = _('trash.table-header.title');
|
||||
readonly canRestoreSelected$ = this._canRestoreSelected$;
|
||||
readonly tableColumnConfigs: TableColumnConfig<DossierListItem>[] = [
|
||||
readonly tableColumnConfigs: readonly TableColumnConfig<DossierListItem>[] = [
|
||||
{
|
||||
label: _('trash.table-col-names.name'),
|
||||
withSort: true,
|
||||
column: 'dossierName'
|
||||
sortByKey: 'dossierName'
|
||||
},
|
||||
{
|
||||
label: _('trash.table-col-names.owner'),
|
||||
@ -41,25 +39,22 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
|
||||
},
|
||||
{
|
||||
label: _('trash.table-col-names.deleted-on'),
|
||||
withSort: true,
|
||||
column: 'softDeletedTime'
|
||||
sortByKey: 'softDeletedTime'
|
||||
},
|
||||
{
|
||||
label: _('trash.table-col-names.time-to-restore'),
|
||||
withSort: true,
|
||||
column: 'softDeletedTime'
|
||||
sortByKey: 'softDeletedTime'
|
||||
}
|
||||
];
|
||||
protected readonly _primaryKey = 'dossierName';
|
||||
private readonly _deleteRetentionHours = this._appConfigService.getConfig(AppConfigKey.DELETE_RETENTION_HOURS);
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _adminDialogService: AdminDialogService,
|
||||
private readonly _appConfigService: AppConfigService
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _appConfigService: AppConfigService,
|
||||
private readonly _adminDialogService: AdminDialogService
|
||||
) {
|
||||
super(_injector);
|
||||
}
|
||||
|
||||
@ -33,13 +33,13 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div [class.extended]="collapsedDetails" class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[hasEmptyColumn]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state *ngIf="noMatch$ | async" [text]="'user-listing.no-match.title' | translate"></redaction-empty-state>
|
||||
|
||||
|
||||
@ -5,15 +5,14 @@ import { AppStateService } from '@state/app-state.service';
|
||||
import { environment } from '@environments/environment';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Debounce } from '@utils/debounce';
|
||||
import { Debounce, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { WatermarkControllerService, WatermarkModelRes } from '@redaction/red-ui-http';
|
||||
import { Toaster } from '@services/toaster.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { BASE_HREF } from '../../../../tokens';
|
||||
import { stampPDFPage } from '../../../../utils/page-stamper';
|
||||
import { stampPDFPage } from '@utils/page-stamper';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { IconButtonTypes } from '@iqser/common-ui';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
|
||||
export const DEFAULT_WATERMARK: WatermarkModelRes = {
|
||||
text: null,
|
||||
|
||||
@ -89,7 +89,7 @@ export class DossierOverviewBulkActionsComponent {
|
||||
}
|
||||
|
||||
get canOcr() {
|
||||
return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canOcrFile(file), true);
|
||||
return this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true);
|
||||
}
|
||||
|
||||
get fileStatuses() {
|
||||
@ -112,7 +112,7 @@ export class DossierOverviewBulkActionsComponent {
|
||||
}
|
||||
|
||||
get canApprove() {
|
||||
return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canApprove(file), true);
|
||||
return this.selectedFiles.reduce((acc, file) => acc && file.canBeApproved, true);
|
||||
}
|
||||
|
||||
// Undo approval
|
||||
@ -163,7 +163,7 @@ export class DossierOverviewBulkActionsComponent {
|
||||
}
|
||||
|
||||
async reanalyse() {
|
||||
const fileIds = this.selectedFiles.filter(file => this._permissionsService.fileRequiresReanalysis(file)).map(file => file.fileId);
|
||||
const fileIds = this.selectedFiles.filter(file => file.analysisRequired).map(file => file.fileId);
|
||||
this._performBulkAction(
|
||||
this._reanalysisControllerService.reanalyzeFilesForDossier(fileIds, this._appStateService.activeDossier.dossierId)
|
||||
);
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
<div class="section small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:folder"></mat-icon>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.dossier' | translate: { dossierName: dossier.name } }}</span>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.dossier' | translate: { dossierName: dossier.dossierName } }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:document"></mat-icon>
|
||||
@ -36,11 +36,9 @@
|
||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.created-on' | translate: { date: file.added | date: 'mediumDate' } }}</span>
|
||||
</div>
|
||||
<div *ngIf="dossier.dossier.dueDate">
|
||||
<div *ngIf="dossier.dueDate">
|
||||
<mat-icon svgIcon="red:lightning"></mat-icon>
|
||||
<span>{{
|
||||
'file-preview.tabs.document-info.details.due' | translate: { date: dossier.dossier.dueDate | date: 'mediumDate' }
|
||||
}}</span>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.due' | translate: { date: dossier.dueDate | date: 'mediumDate' } }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:template"></mat-icon>
|
||||
|
||||
@ -19,18 +19,18 @@
|
||||
'dossier-overview.dossier-details.stats.created-on'
|
||||
| translate
|
||||
: {
|
||||
date: activeDossier.dossier.date | date: 'd MMM. yyyy'
|
||||
date: activeDossier.date | date: 'd MMM. yyyy'
|
||||
}
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="activeDossier.dossier.dueDate">
|
||||
<div *ngIf="activeDossier.dueDate">
|
||||
<mat-icon svgIcon="red:lightning"></mat-icon>
|
||||
<span>{{
|
||||
'dossier-overview.dossier-details.stats.due-date'
|
||||
| translate
|
||||
: {
|
||||
date: activeDossier.dossier.dueDate | date: 'd MMM. yyyy'
|
||||
date: activeDossier.dueDate | date: 'd MMM. yyyy'
|
||||
}
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
</div>
|
||||
|
||||
<div class="header-wrapper mt-8">
|
||||
<div class="heading-xl flex-1">{{ appStateService.activeDossier.dossier.dossierName }}</div>
|
||||
<div class="heading-xl flex-1">{{ appStateService.activeDossier.dossierName }}</div>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="collapsible; context: { action: 'collapse', tooltip: (collapseTooltip | translate) }"
|
||||
></ng-container>
|
||||
@ -65,7 +65,7 @@
|
||||
></redaction-dossier-details-stats>
|
||||
</div>
|
||||
|
||||
<div *ngIf="appStateService.activeDossier.dossier.description as description" class="pb-32">
|
||||
<div *ngIf="appStateService.activeDossier.description as description" class="pb-32">
|
||||
<div class="heading" translate="dossier-overview.dossier-details.description"></div>
|
||||
<div class="mt-8">{{ description }}</div>
|
||||
</div>
|
||||
|
||||
@ -40,7 +40,7 @@ export class DossierDetailsComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
get memberIds(): string[] {
|
||||
return this.appStateService.activeDossier.dossier.memberIds;
|
||||
return this.appStateService.activeDossier.memberIds;
|
||||
}
|
||||
|
||||
get hasFiles(): boolean {
|
||||
@ -54,7 +54,7 @@ export class DossierDetailsComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
this.owner = this._userService.getRedUserById(this.appStateService.activeDossier.ownerId);
|
||||
this.calculateChartConfig();
|
||||
this.appStateService.fileChanged.subscribe(() => {
|
||||
this.appStateService.fileChanged$.subscribe(() => {
|
||||
this.calculateChartConfig();
|
||||
});
|
||||
}
|
||||
@ -81,12 +81,11 @@ export class DossierDetailsComponent implements OnInit {
|
||||
|
||||
async assignOwner(user: UserWrapper | string) {
|
||||
this.owner = typeof user === 'string' ? this._userService.getRedUserById(user) : user;
|
||||
const dw = Object.assign({}, this.appStateService.activeDossier);
|
||||
dw.dossier.ownerId = this.owner.id;
|
||||
await this.appStateService.createOrUpdateDossier(dw.dossier);
|
||||
const dw = { ...this.appStateService.activeDossier, ownerId: this.owner.id };
|
||||
await this.appStateService.createOrUpdateDossier(dw);
|
||||
|
||||
const ownerName = this._userService.getNameForId(this.owner.id);
|
||||
const dossierName = this.appStateService.activeDossier.name;
|
||||
const dossierName = this.appStateService.activeDossier.dossierName;
|
||||
this._toaster.info(_('assignment.owner'), { params: { ownerName, dossierName } });
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<redaction-status-bar [config]="getDossierStatusConfig(dossier)"></redaction-status-bar>
|
||||
<iqser-status-bar [configs]="statusBarConfig"></iqser-status-bar>
|
||||
<div class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openEditDossierDialog($event, dossier)"
|
||||
|
||||
@ -1,24 +1,28 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { StatusSorter } from '@utils/sorters/status-sorter';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
import { CircleButtonTypes } from '@iqser/common-ui';
|
||||
import { CircleButtonTypes, StatusBarConfig } from '@iqser/common-ui';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-listing-actions',
|
||||
templateUrl: './dossier-listing-actions.component.html',
|
||||
styleUrls: ['./dossier-listing-actions.component.scss']
|
||||
styleUrls: ['./dossier-listing-actions.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DossierListingActionsComponent {
|
||||
export class DossierListingActionsComponent implements OnInit {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
|
||||
@Input() dossier: DossierWrapper;
|
||||
@Output() actionPerformed = new EventEmitter<DossierWrapper | undefined>();
|
||||
|
||||
statusBarConfig: readonly StatusBarConfig<string>[];
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
readonly appStateService: AppStateService,
|
||||
@ -26,6 +30,10 @@ export class DossierListingActionsComponent {
|
||||
private readonly _userService: UserService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.statusBarConfig = this._getStatusConfig(this.dossier.files);
|
||||
}
|
||||
|
||||
openEditDossierDialog($event: MouseEvent, dossierWrapper: DossierWrapper) {
|
||||
this._dialogService.openDialog('editDossier', $event, {
|
||||
dossierWrapper,
|
||||
@ -40,8 +48,8 @@ export class DossierListingActionsComponent {
|
||||
});
|
||||
}
|
||||
|
||||
getDossierStatusConfig(dw: DossierWrapper) {
|
||||
const obj = dw.files.reduce((acc, file) => {
|
||||
private _getStatusConfig(files: readonly FileStatusWrapper[]) {
|
||||
const obj = files.reduce((acc, file) => {
|
||||
const status = file.status;
|
||||
if (!acc[status]) {
|
||||
acc[status] = 1;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div *ngIf="screen === 'dossier-overview'" class="action-buttons">
|
||||
<ng-container *ngTemplateOutlet="actions"></ng-container>
|
||||
<redaction-status-bar *ngIf="fileStatus?.isWorkable" [config]="statusBarConfig"></redaction-status-bar>
|
||||
<iqser-status-bar *ngIf="isWorkable" [configs]="statusBarConfig"></iqser-status-bar>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="screen === 'file-preview'">
|
||||
@ -9,10 +9,9 @@
|
||||
|
||||
<ng-template #actions>
|
||||
<div class="file-actions" *ngIf="fileStatus">
|
||||
<!-- delete-->
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteFileDialog($event)"
|
||||
*ngIf="permissionsService.canDeleteFile(fileStatus)"
|
||||
*ngIf="canDelete"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.delete.action' | translate"
|
||||
[type]="buttonType"
|
||||
@ -23,7 +22,7 @@
|
||||
(action)="assign($event)"
|
||||
*ngIf="canAssign && screen === 'dossier-overview'"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="assignTooltip"
|
||||
[tooltip]="assignTooltip | translate"
|
||||
[type]="buttonType"
|
||||
icon="red:assign"
|
||||
></iqser-circle-button>
|
||||
@ -88,13 +87,11 @@
|
||||
<!-- Approved-->
|
||||
<iqser-circle-button
|
||||
(action)="setFileApproved($event)"
|
||||
*ngIf="permissionsService.isReadyForApproval(fileStatus)"
|
||||
[disabled]="!permissionsService.canApprove(fileStatus)"
|
||||
*ngIf="readyForApproval"
|
||||
[disabled]="!fileStatus.canBeApproved"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="
|
||||
permissionsService.canApprove(fileStatus)
|
||||
? ('dossier-overview.approve' | translate)
|
||||
: ('dossier-overview.approve-disabled' | translate)
|
||||
fileStatus.canBeApproved ? ('dossier-overview.approve' | translate) : ('dossier-overview.approve-disabled' | translate)
|
||||
"
|
||||
[type]="buttonType"
|
||||
icon="red:approved"
|
||||
@ -112,7 +109,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="ocrFile($event)"
|
||||
*ngIf="canOcr"
|
||||
*ngIf="fileStatus.canBeOCRed"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.ocr-file' | translate"
|
||||
[type]="buttonType"
|
||||
@ -145,9 +142,9 @@
|
||||
<mat-slide-toggle
|
||||
(change)="toggleAnalysis()"
|
||||
(click)="$event.stopPropagation()"
|
||||
[checked]="!fileStatus?.isExcluded"
|
||||
[checked]="!fileStatus?.excluded"
|
||||
[class.mr-24]="screen === 'dossier-overview'"
|
||||
[disabled]="!permissionsService.canToggleAnalysis(fileStatus)"
|
||||
[disabled]="!canToggleAnalysis"
|
||||
[matTooltipPosition]="tooltipPosition"
|
||||
[matTooltip]="toggleTooltip | translate"
|
||||
color="primary"
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
redaction-status-bar {
|
||||
iqser-status-bar {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
@ -6,18 +6,18 @@ import { FileActionService } from '../../services/file-action.service';
|
||||
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { FileManagementControllerService } from '@redaction/red-ui-http';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { FileManagementControllerService, FileStatus } from '@redaction/red-ui-http';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { CircleButtonTypes } from '@iqser/common-ui';
|
||||
import { AutoUnsubscribe, CircleButtonType, CircleButtonTypes, StatusBarConfig } from '@iqser/common-ui';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-file-actions',
|
||||
templateUrl: './file-actions.component.html',
|
||||
styleUrls: ['./file-actions.component.scss']
|
||||
})
|
||||
export class FileActionsComponent implements OnInit {
|
||||
export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnDestroy {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
|
||||
@ -27,6 +27,22 @@ export class FileActionsComponent implements OnInit {
|
||||
@Output() actionPerformed = new EventEmitter<string>();
|
||||
|
||||
screen: 'file-preview' | 'dossier-overview';
|
||||
statusBarConfig?: readonly StatusBarConfig<FileStatus.StatusEnum>[];
|
||||
tooltipPosition?: 'below' | 'above';
|
||||
toggleTooltip?: string;
|
||||
assignTooltip?: string;
|
||||
buttonType?: CircleButtonType;
|
||||
isWorkable: boolean;
|
||||
|
||||
canUndoApproval: boolean;
|
||||
canAssignToSelf: boolean;
|
||||
canAssign: boolean;
|
||||
canDelete: boolean;
|
||||
canReanalyse: boolean;
|
||||
canSetToUnderReview: boolean;
|
||||
canSetToUnderApproval: boolean;
|
||||
readyForApproval: boolean;
|
||||
canToggleAnalysis: boolean;
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
@ -35,81 +51,57 @@ export class FileActionsComponent implements OnInit {
|
||||
private readonly _fileActionService: FileActionService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _userService: UserService
|
||||
) {}
|
||||
|
||||
get statusBarConfig() {
|
||||
return [{ color: this.fileStatus.status, length: 1 }];
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
get tooltipPosition() {
|
||||
return this.screen === 'file-preview' ? 'below' : 'above';
|
||||
}
|
||||
|
||||
get buttonType() {
|
||||
return this.screen === 'file-preview' ? CircleButtonTypes.default : CircleButtonTypes.dark;
|
||||
}
|
||||
|
||||
get toggleTooltip(): string {
|
||||
private get _toggleTooltip(): string {
|
||||
if (!this.currentUser.isManager) {
|
||||
return _('file-preview.toggle-analysis.only-managers');
|
||||
}
|
||||
|
||||
return this.fileStatus?.isExcluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable');
|
||||
return this.fileStatus?.excluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable');
|
||||
}
|
||||
|
||||
get canAssignToSelf() {
|
||||
return this.permissionsService.canAssignToSelf(this.fileStatus);
|
||||
}
|
||||
private _setup() {
|
||||
this.statusBarConfig = [{ color: this.fileStatus.status, length: 1 }];
|
||||
this.tooltipPosition = this.screen === 'file-preview' ? 'below' : 'above';
|
||||
this.assignTooltip = this.fileStatus.isUnderApproval
|
||||
? _('dossier-overview.assign-approver')
|
||||
: _('dossier-overview.assign-reviewer');
|
||||
this.buttonType = this.screen === 'file-preview' ? CircleButtonTypes.default : CircleButtonTypes.dark;
|
||||
this.isWorkable = this.fileStatus.isWorkable;
|
||||
this.toggleTooltip = this._toggleTooltip;
|
||||
|
||||
get canAssign() {
|
||||
return this.permissionsService.canAssignUser(this.fileStatus);
|
||||
}
|
||||
|
||||
get canDelete() {
|
||||
return this.permissionsService.canDeleteFile(this.fileStatus);
|
||||
}
|
||||
|
||||
get canReanalyse() {
|
||||
return this.permissionsService.canReanalyseFile(this.fileStatus);
|
||||
}
|
||||
|
||||
get canOcr() {
|
||||
return this.permissionsService.canOcrFile(this.fileStatus);
|
||||
}
|
||||
|
||||
get canSetToUnderReview() {
|
||||
return this.permissionsService.canSetUnderReview(this.fileStatus);
|
||||
}
|
||||
|
||||
get canSetToUnderApproval() {
|
||||
return this.permissionsService.canSetUnderApproval(this.fileStatus);
|
||||
}
|
||||
|
||||
get canUndoApproval() {
|
||||
return this.permissionsService.canUndoApproval(this.fileStatus);
|
||||
}
|
||||
|
||||
get assignTooltip() {
|
||||
return this.fileStatus.isUnderApproval
|
||||
? this._translateService.instant('dossier-overview.assign-approver')
|
||||
: this._translateService.instant('dossier-overview.assign-reviewer');
|
||||
this.canUndoApproval = this.permissionsService.canUndoApproval(this.fileStatus);
|
||||
this.canAssignToSelf = this.permissionsService.canAssignToSelf(this.fileStatus);
|
||||
this.canAssign = this.permissionsService.canAssignUser(this.fileStatus);
|
||||
this.canDelete = this.permissionsService.canDeleteFile(this.fileStatus);
|
||||
this.canReanalyse = this.permissionsService.canReanalyseFile(this.fileStatus);
|
||||
this.canSetToUnderReview = this.permissionsService.canSetUnderReview(this.fileStatus);
|
||||
this.canSetToUnderApproval = this.permissionsService.canSetUnderApproval(this.fileStatus);
|
||||
this.readyForApproval = this.permissionsService.isReadyForApproval(this.fileStatus);
|
||||
this.canToggleAnalysis = this.permissionsService.canToggleAnalysis(this.fileStatus);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.fileStatus) {
|
||||
this.screen = 'dossier-overview';
|
||||
this._setup();
|
||||
return;
|
||||
}
|
||||
|
||||
this.fileStatus = this.appStateService.activeFile;
|
||||
this.screen = 'file-preview';
|
||||
this.appStateService.fileChanged.subscribe(fileStatus => {
|
||||
if (fileStatus.fileId === this.fileStatus?.fileId) {
|
||||
this.fileStatus = this.appStateService.activeFile;
|
||||
}
|
||||
});
|
||||
this._setup();
|
||||
|
||||
this.addSubscription = this.appStateService.fileChanged$
|
||||
.pipe(filter(file => file.fileId === this.fileStatus?.fileId))
|
||||
.subscribe(fileStatus => {
|
||||
this.fileStatus = fileStatus;
|
||||
this._setup();
|
||||
});
|
||||
}
|
||||
|
||||
toggleViewDocumentInfo() {
|
||||
@ -156,7 +148,7 @@ export class FileActionsComponent implements OnInit {
|
||||
|
||||
reanalyseFile($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this._fileActionService.reanalyseFile(this.fileStatus).subscribe(() => {
|
||||
this.addSubscription = this._fileActionService.reanalyseFile(this.fileStatus).subscribe(() => {
|
||||
this.reloadDossiers('reanalyse');
|
||||
});
|
||||
}
|
||||
@ -171,7 +163,7 @@ export class FileActionsComponent implements OnInit {
|
||||
true
|
||||
);
|
||||
} else {
|
||||
this._fileActionService.setFileUnderApproval(this.fileStatus).subscribe(() => {
|
||||
this.addSubscription = this._fileActionService.setFileUnderApproval(this.fileStatus).subscribe(() => {
|
||||
this.reloadDossiers('set-under-approval');
|
||||
});
|
||||
}
|
||||
@ -179,14 +171,14 @@ export class FileActionsComponent implements OnInit {
|
||||
|
||||
setFileApproved($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this._fileActionService.setFileApproved(this.fileStatus).subscribe(() => {
|
||||
this.addSubscription = this._fileActionService.setFileApproved(this.fileStatus).subscribe(() => {
|
||||
this.reloadDossiers('set-approved');
|
||||
});
|
||||
}
|
||||
|
||||
ocrFile($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this._fileActionService.ocrFile(this.fileStatus).subscribe(() => {
|
||||
this.addSubscription = this._fileActionService.ocrFile(this.fileStatus).subscribe(() => {
|
||||
this.reloadDossiers('ocr-file');
|
||||
});
|
||||
}
|
||||
@ -210,6 +202,6 @@ export class FileActionsComponent implements OnInit {
|
||||
async toggleAnalysis() {
|
||||
await this._fileActionService.toggleAnalysis(this.fileStatus).toPromise();
|
||||
await this.appStateService.getFiles();
|
||||
this.actionPerformed.emit(this.fileStatus?.isExcluded ? 'enable-analysis' : 'disable-analysis');
|
||||
this.actionPerformed.emit(this.fileStatus?.excluded ? 'enable-analysis' : 'disable-analysis');
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,12 +15,11 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { AnnotationProcessingService } from '../../services/annotation-processing.service';
|
||||
import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
import { Debounce } from '@utils/debounce';
|
||||
import { CircleButtonTypes, Debounce, IconButtonTypes, NestedFilter } from '@iqser/common-ui';
|
||||
import { FileDataModel } from '@models/file/file-data.model';
|
||||
import { CommentsComponent } from '../comments/comments.component';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { WebViewerInstance } from '@pdftron/webviewer';
|
||||
import { CircleButtonTypes, IconButtonTypes, NestedFilter } from '@iqser/common-ui';
|
||||
|
||||
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
|
||||
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
|
||||
@ -12,7 +11,7 @@ import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
export class NeedsWorkBadgeComponent {
|
||||
@Input() needsWorkInput: FileStatusWrapper | DossierWrapper;
|
||||
|
||||
constructor(private readonly _appStateService: AppStateService, private readonly _permissionsService: PermissionsService) {}
|
||||
constructor(private readonly _appStateService: AppStateService) {}
|
||||
|
||||
get suggestionColor() {
|
||||
return this._getDictionaryColor('suggestion');
|
||||
@ -52,9 +51,9 @@ export class NeedsWorkBadgeComponent {
|
||||
|
||||
reanalysisRequired() {
|
||||
if (this.needsWorkInput instanceof DossierWrapper) {
|
||||
return this._permissionsService.dossierReanalysisRequired(this.needsWorkInput);
|
||||
return this.needsWorkInput.reanalysisRequired;
|
||||
} else {
|
||||
return this._permissionsService.fileRequiresReanalysis(this.needsWorkInput);
|
||||
return this.needsWorkInput.analysisRequired;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._subscription = this._appStateService.fileChanged.subscribe(() => {
|
||||
this._subscription = this._appStateService.fileChanged$.subscribe(() => {
|
||||
this.canMarkPagesAsViewed = this._permissionService.canMarkPagesAsViewed();
|
||||
});
|
||||
}
|
||||
|
||||
@ -82,11 +82,13 @@ export class TeamMembersManagerComponent implements OnInit {
|
||||
const ownerId = this.selectedOwnerId;
|
||||
const memberIds = this.selectedMembersList;
|
||||
const approverIds = this.selectedApproversList;
|
||||
const dw = Object.assign({}, this.dossierWrapper);
|
||||
dw.dossier.memberIds = memberIds;
|
||||
dw.dossier.approverIds = approverIds;
|
||||
dw.dossier.ownerId = ownerId;
|
||||
result = await this._appStateService.createOrUpdateDossier(dw.dossier);
|
||||
const dw = {
|
||||
...this.dossierWrapper,
|
||||
memberIds,
|
||||
approverIds,
|
||||
ownerId
|
||||
};
|
||||
result = await this._appStateService.createOrUpdateDossier(dw);
|
||||
this.save.emit(result);
|
||||
} catch (error) {
|
||||
this._toaster.error('Failed: ' + error.error ? error.error.message : error);
|
||||
|
||||
@ -8,7 +8,6 @@ import { downloadTypesTranslations } from '../../../../translations/download-typ
|
||||
import { IconButtonTypes } from '@iqser/common-ui';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-dossier-dialog',
|
||||
templateUrl: './add-dossier-dialog.component.html',
|
||||
styleUrls: ['./add-dossier-dialog.component.scss']
|
||||
})
|
||||
@ -71,7 +70,7 @@ export class AddDossierDialogComponent {
|
||||
async saveDossier() {
|
||||
const dossier: Dossier = this._formToObject();
|
||||
|
||||
const foundDossier = this._appStateService.allDossiers.find(p => p.dossier.dossierId === dossier.dossierId);
|
||||
const foundDossier = this._appStateService.allDossiers.find(p => p.dossierId === dossier.dossierId);
|
||||
if (foundDossier) {
|
||||
dossier.memberIds = foundDossier.memberIds;
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-document-info-dialog',
|
||||
templateUrl: './document-info-dialog.component.html',
|
||||
styleUrls: ['./document-info-dialog.component.scss']
|
||||
})
|
||||
|
||||
@ -43,11 +43,11 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
|
||||
get changed() {
|
||||
if (this.dossierForm) {
|
||||
for (const key of Object.keys(this.dossierForm.getRawValue())) {
|
||||
if (this.dossierWrapper.dossier[key].length !== this.dossierForm.get(key).value.length) {
|
||||
if (this.dossierWrapper[key].length !== this.dossierForm.get(key).value.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const originalItems = [...this.dossierWrapper.dossier[key]].sort();
|
||||
const originalItems = [...this.dossierWrapper[key]].sort();
|
||||
const newItems = [...this.dossierForm.get(key).value].sort();
|
||||
|
||||
for (let idx = 0; idx < originalItems.length; ++idx) {
|
||||
@ -71,8 +71,8 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
|
||||
|
||||
this.dossierForm = this._formBuilder.group(
|
||||
{
|
||||
reportTemplateIds: [this.dossierWrapper.dossier.reportTemplateIds],
|
||||
downloadFileTypes: [this.dossierWrapper.dossier.downloadFileTypes]
|
||||
reportTemplateIds: [this.dossierWrapper.reportTemplateIds],
|
||||
downloadFileTypes: [this.dossierWrapper.downloadFileTypes]
|
||||
},
|
||||
{
|
||||
validators: control =>
|
||||
@ -85,7 +85,7 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
|
||||
|
||||
async save() {
|
||||
const dossier = {
|
||||
...this.dossierWrapper.dossier,
|
||||
...this.dossierWrapper,
|
||||
downloadFileTypes: this.dossierForm.get('downloadFileTypes').value,
|
||||
reportTemplateIds: this.dossierForm.get('reportTemplateIds').value
|
||||
};
|
||||
@ -95,8 +95,8 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
|
||||
|
||||
revert() {
|
||||
this.dossierForm.reset({
|
||||
downloadFileTypes: this.dossierWrapper.dossier.downloadFileTypes,
|
||||
reportTemplateIds: this.dossierWrapper.dossier.reportTemplateIds
|
||||
downloadFileTypes: this.dossierWrapper.downloadFileTypes,
|
||||
reportTemplateIds: this.dossierWrapper.reportTemplateIds
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
{{ 'edit-dossier-dialog.header' | translate: { dossierName: dossierWrapper.name } }}
|
||||
{{ 'edit-dossier-dialog.header' | translate: { dossierName: dossierWrapper.dossierName } }}
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
|
||||
@ -94,7 +94,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
|
||||
async save() {
|
||||
const dossier = {
|
||||
...this.dossierWrapper.dossier,
|
||||
...this.dossierWrapper,
|
||||
dossierName: this.dossierForm.get('dossierName').value,
|
||||
description: this.dossierForm.get('description').value,
|
||||
watermarkEnabled: this.dossierForm.get('watermarkEnabled').value,
|
||||
|
||||
@ -8,10 +8,7 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
<iqser-table-header [tableColumnConfigs]="tableColumnConfigs" [tableHeaderLabel]="tableHeaderLabel"></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
(action)="openAddDossierDialog()"
|
||||
@ -26,54 +23,54 @@
|
||||
|
||||
<cdk-virtual-scroll-viewport #scrollViewport [itemSize]="itemSize" redactionHasScrollbar>
|
||||
<div
|
||||
*cdkVirtualFor="let dw of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
[class.pointer]="!!dw"
|
||||
[routerLink]="[!!dw ? '/main/dossiers/' + dw.dossier.dossierId : []]"
|
||||
*cdkVirtualFor="let item of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
[class.pointer]="!!item"
|
||||
[routerLink]="[item.routerLink]"
|
||||
class="table-item"
|
||||
>
|
||||
<div class="filename">
|
||||
<div [matTooltip]="dw.dossierName" class="table-item-title heading" matTooltipPosition="above">
|
||||
{{ dw.dossierName }}
|
||||
<div [matTooltip]="item.dossierName" class="table-item-title heading" matTooltipPosition="above">
|
||||
{{ item.dossierName }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:template"></mat-icon>
|
||||
{{ getDossierTemplate(dw).name }}
|
||||
{{ item.dossierTemplateName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:document"></mat-icon>
|
||||
{{ dw.files.length }}
|
||||
{{ item.dossier.filesLength }}
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:pages"></mat-icon>
|
||||
{{ dw.totalNumberOfPages }}
|
||||
{{ item.dossier.totalNumberOfPages }}
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:user"></mat-icon>
|
||||
{{ dw.numberOfMembers }}
|
||||
{{ item.dossier.memberCount }}
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||
{{ dw.dossier.date | date: 'mediumDate' }}
|
||||
{{ item.dossier.date | date: 'mediumDate' }}
|
||||
</div>
|
||||
<div *ngIf="dw.dossier.dueDate">
|
||||
<div *ngIf="item.dossier.dueDate">
|
||||
<mat-icon svgIcon="red:lightning"></mat-icon>
|
||||
{{ dw.dossier.dueDate | date: 'mediumDate' }}
|
||||
{{ item.dossier.dueDate | date: 'mediumDate' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<redaction-needs-work-badge [needsWorkInput]="dw"></redaction-needs-work-badge>
|
||||
<redaction-needs-work-badge [needsWorkInput]="item.dossier"></redaction-needs-work-badge>
|
||||
</div>
|
||||
<div class="user-column">
|
||||
<redaction-initials-avatar [userId]="dw.dossier.ownerId" [withName]="true"></redaction-initials-avatar>
|
||||
<redaction-initials-avatar [userId]="item.dossier.ownerId" [withName]="true"></redaction-initials-avatar>
|
||||
</div>
|
||||
<div class="status-container">
|
||||
<redaction-dossier-listing-actions
|
||||
(actionPerformed)="calculateData()"
|
||||
[dossier]="dw"
|
||||
[dossier]="item.dossier"
|
||||
></redaction-dossier-listing-actions>
|
||||
</div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, ChangeDetectorRef, Component, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { Dossier, DossierTemplateModel } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
@ -7,11 +7,11 @@ import { groupBy } from '@utils/functions';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { timer } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { TranslateChartService } from '@services/translate-chart.service';
|
||||
import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter';
|
||||
import { StatusSorter } from '@utils/sorters/status-sorter';
|
||||
import { NavigationStart, Router } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
@ -29,7 +29,12 @@ import {
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
|
||||
const isLeavingScreen = event => event instanceof NavigationStart && event.url !== '/main/dossiers';
|
||||
interface ListItem {
|
||||
readonly dossierName: string;
|
||||
readonly routerLink: string;
|
||||
readonly dossierTemplateName: string;
|
||||
readonly dossier: DossierWrapper;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-listing-screen.component.html',
|
||||
@ -37,13 +42,14 @@ const isLeavingScreen = event => event instanceof NavigationStart && event.url !
|
||||
providers: [...DefaultListingServices]
|
||||
})
|
||||
export class DossierListingScreenComponent
|
||||
extends ListingComponent<DossierWrapper>
|
||||
extends ListingComponent<ListItem>
|
||||
implements OnInit, AfterViewInit, OnDestroy, OnAttach, OnDetach
|
||||
{
|
||||
readonly itemSize = 85;
|
||||
protected readonly _primaryKey = 'dossierName';
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly tableHeaderLabel = _('dossier-listing.table-header.title');
|
||||
readonly buttonConfigs: ButtonConfig[] = [
|
||||
readonly buttonConfigs: readonly ButtonConfig[] = [
|
||||
{
|
||||
label: _('dossier-listing.add-new'),
|
||||
action: () => this.openAddDossierDialog(),
|
||||
@ -52,11 +58,10 @@ export class DossierListingScreenComponent
|
||||
type: 'primary'
|
||||
}
|
||||
];
|
||||
readonly tableColumnConfigs: TableColumnConfig<DossierWrapper>[] = [
|
||||
readonly tableColumnConfigs: readonly TableColumnConfig<ListItem>[] = [
|
||||
{
|
||||
label: _('dossier-listing.table-col-names.name'),
|
||||
withSort: true,
|
||||
column: 'dossierName'
|
||||
sortByKey: 'dossierName'
|
||||
},
|
||||
{
|
||||
label: _('dossier-listing.table-col-names.needs-work')
|
||||
@ -70,10 +75,11 @@ export class DossierListingScreenComponent
|
||||
class: 'flex-end'
|
||||
}
|
||||
];
|
||||
|
||||
dossiersChartData: DoughnutChartConfig[] = [];
|
||||
documentsChartData: DoughnutChartConfig[] = [];
|
||||
protected readonly _primaryKey = 'dossierName';
|
||||
private _lastScrollPosition: number;
|
||||
private _lastScrolledIndex: number;
|
||||
|
||||
@ViewChild('needsWorkTemplate', { read: TemplateRef, static: true })
|
||||
private readonly _needsWorkTemplate: TemplateRef<any>;
|
||||
@ViewChild(CdkVirtualScrollViewport)
|
||||
@ -83,7 +89,6 @@ export class DossierListingScreenComponent
|
||||
private readonly _router: Router,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _userService: UserService,
|
||||
readonly changeDetectorRef: ChangeDetectorRef,
|
||||
readonly permissionsService: PermissionsService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _translateService: TranslateService,
|
||||
@ -96,10 +101,6 @@ export class DossierListingScreenComponent
|
||||
this._loadEntitiesFromState();
|
||||
}
|
||||
|
||||
private get _userId() {
|
||||
return this._userService.currentUser.id;
|
||||
}
|
||||
|
||||
private get _activeDossiersCount(): number {
|
||||
return this.entitiesService.all.filter(p => p.dossier.status === Dossier.StatusEnum.ACTIVE).length;
|
||||
}
|
||||
@ -117,32 +118,29 @@ export class DossierListingScreenComponent
|
||||
this.calculateData();
|
||||
});
|
||||
|
||||
this.addSubscription = this._appStateService.fileChanged.subscribe(() => {
|
||||
this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
|
||||
this.calculateData();
|
||||
});
|
||||
|
||||
this.addSubscription = this._router.events.pipe(filter(isLeavingScreen)).subscribe(() => {
|
||||
this._lastScrollPosition = this._scrollViewport.measureScrollOffset('top');
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.changeDetectorRef.detectChanges();
|
||||
this.addSubscription = this._scrollViewport.scrolledIndexChange.pipe(tap(index => (this._lastScrolledIndex = index))).subscribe();
|
||||
}
|
||||
|
||||
ngOnAttach() {
|
||||
this._scrollViewport.scrollTo({ top: this._lastScrollPosition });
|
||||
this._appStateService.reset();
|
||||
this._loadEntitiesFromState();
|
||||
this.ngOnInit();
|
||||
this.ngAfterViewInit();
|
||||
this._scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
|
||||
}
|
||||
|
||||
ngOnDetach(): void {
|
||||
this.ngOnDestroy();
|
||||
}
|
||||
|
||||
getDossierTemplate(dw: DossierWrapper): DossierTemplateModel {
|
||||
return this._appStateService.getDossierTemplateById(dw.dossier.dossierTemplateId);
|
||||
private _getDossierTemplate(dossierTemplateId: string): DossierTemplateModel {
|
||||
return this._appStateService.getDossierTemplateById(dossierTemplateId);
|
||||
}
|
||||
|
||||
openAddDossierDialog(): void {
|
||||
@ -180,7 +178,17 @@ export class DossierListingScreenComponent
|
||||
}
|
||||
|
||||
private _loadEntitiesFromState() {
|
||||
this.entitiesService.setEntities(this._appStateService.allDossiers);
|
||||
const entities = this._appStateService.allDossiers.map(dossier => this._toListItem(dossier));
|
||||
this.entitiesService.setEntities(entities);
|
||||
}
|
||||
|
||||
private _toListItem(dossier: DossierWrapper): ListItem {
|
||||
return {
|
||||
dossierName: dossier.dossierName,
|
||||
routerLink: '/main/dossiers/' + dossier.dossierId.toString(),
|
||||
dossierTemplateName: this._getDossierTemplate(dossier.dossierTemplateId).name,
|
||||
dossier
|
||||
};
|
||||
}
|
||||
|
||||
private _computeAllFilters() {
|
||||
@ -189,20 +197,20 @@ export class DossierListingScreenComponent
|
||||
const allDistinctNeedsWork = new Set<string>();
|
||||
const allDistinctDossierTemplates = new Set<string>();
|
||||
|
||||
this.entitiesService?.all?.forEach(entry => {
|
||||
this.entitiesService.all?.forEach(entry => {
|
||||
// all people
|
||||
entry.dossier.memberIds.forEach(f => allDistinctPeople.add(f));
|
||||
// Needs work
|
||||
entry.files.forEach(file => {
|
||||
entry.dossier.files.forEach(file => {
|
||||
allDistinctFileStatus.add(file.status);
|
||||
if (this.permissionsService.fileRequiresReanalysis(file)) allDistinctNeedsWork.add('analysis');
|
||||
if (entry.hintsOnly) allDistinctNeedsWork.add('hint');
|
||||
if (entry.hasRedactions) allDistinctNeedsWork.add('redaction');
|
||||
if (entry.hasRequests) allDistinctNeedsWork.add('suggestion');
|
||||
if (entry.hasNone) allDistinctNeedsWork.add('none');
|
||||
if (file.analysisRequired) allDistinctNeedsWork.add('analysis');
|
||||
if (entry.dossier.hintsOnly) allDistinctNeedsWork.add('hint');
|
||||
if (entry.dossier.hasRedactions) allDistinctNeedsWork.add('redaction');
|
||||
if (entry.dossier.hasRequests) allDistinctNeedsWork.add('suggestion');
|
||||
if (entry.dossier.hasNone) allDistinctNeedsWork.add('none');
|
||||
});
|
||||
|
||||
allDistinctDossierTemplates.add(entry.dossierTemplateId);
|
||||
allDistinctDossierTemplates.add(entry.dossier.dossierTemplateId);
|
||||
});
|
||||
|
||||
const statusFilters = [...allDistinctFileStatus].map<NestedFilter>(status => ({
|
||||
@ -243,8 +251,7 @@ export class DossierListingScreenComponent
|
||||
filterTemplate: this._needsWorkTemplate,
|
||||
filters: needsWorkFilters.sort(RedactionFilterSorter.byKey),
|
||||
checker: annotationFilterChecker,
|
||||
matchAll: true,
|
||||
checkerArgs: [this.permissionsService]
|
||||
matchAll: true
|
||||
});
|
||||
|
||||
const dossierTemplateFilters = [...allDistinctDossierTemplates].map<NestedFilter>(id => ({
|
||||
@ -275,22 +282,22 @@ export class DossierListingScreenComponent
|
||||
{
|
||||
key: 'my-dossiers',
|
||||
label: myDossiersLabel,
|
||||
checker: (dw: DossierWrapper) => dw.ownerId === this._userId
|
||||
checker: (dw: DossierWrapper) => dw.ownerId === this.currentUser.id
|
||||
},
|
||||
{
|
||||
key: 'to-approve',
|
||||
label: this._translateService.instant('dossier-listing.quick-filters.to-approve'),
|
||||
checker: (dw: DossierWrapper) => dw.approverIds.includes(this._userId)
|
||||
checker: (dw: DossierWrapper) => dw.approverIds.includes(this.currentUser.id)
|
||||
},
|
||||
{
|
||||
key: 'to-review',
|
||||
label: this._translateService.instant('dossier-listing.quick-filters.to-review'),
|
||||
checker: (dw: DossierWrapper) => dw.memberIds.includes(this._userId)
|
||||
checker: (dw: DossierWrapper) => dw.memberIds.includes(this.currentUser.id)
|
||||
},
|
||||
{
|
||||
key: 'other',
|
||||
label: this._translateService.instant('dossier-listing.quick-filters.other'),
|
||||
checker: (dw: DossierWrapper) => !dw.memberIds.includes(this._userId)
|
||||
checker: (dw: DossierWrapper) => !dw.memberIds.includes(this.currentUser.id)
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<section *ngIf="!!activeDossier">
|
||||
<section *ngIf="!!currentDossier">
|
||||
<redaction-page-header
|
||||
[actionConfigs]="actionConfigs"
|
||||
[searchPlaceholder]="'dossier-overview.search' | translate"
|
||||
@ -6,7 +6,7 @@
|
||||
>
|
||||
<redaction-file-download-btn
|
||||
[disabled]="entitiesService.areSomeSelected$ | async"
|
||||
[dossier]="activeDossier"
|
||||
[dossier]="currentDossier"
|
||||
[file]="entitiesService.all$ | async"
|
||||
tooltipPosition="below"
|
||||
></redaction-file-download-btn>
|
||||
@ -36,12 +36,12 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div [class.extended]="collapsedDetails" class="content-container">
|
||||
<redaction-table-header
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[selectionEnabled]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
(action)="fileInput.click()"
|
||||
@ -57,9 +57,9 @@
|
||||
<cdk-virtual-scroll-viewport #scrollViewport [itemSize]="itemSize" redactionHasScrollbar>
|
||||
<div
|
||||
*cdkVirtualFor="let fileStatus of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
[class.disabled]="fileStatus.isExcluded"
|
||||
[class.disabled]="fileStatus.excluded"
|
||||
[class.last-opened]="isLastOpenedFile(fileStatus.fileId)"
|
||||
[class.pointer]="permissionsService.canOpenFile(fileStatus)"
|
||||
[class.pointer]="fileStatus.canBeOpened"
|
||||
[routerLink]="fileLink(fileStatus)"
|
||||
class="table-item"
|
||||
>
|
||||
@ -93,15 +93,15 @@
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:exclude-pages"></mat-icon>
|
||||
{{ fileStatus.numberOfExcludedPages }}
|
||||
{{ fileStatus.excludedPagesCount }}
|
||||
</div>
|
||||
<div
|
||||
*ngIf="fileStatus.ocrTime"
|
||||
*ngIf="fileStatus.lastOCRTime"
|
||||
[matTooltipPosition]="'above'"
|
||||
[matTooltip]="'dossier-overview.ocr-performed' | translate"
|
||||
>
|
||||
<mat-icon svgIcon="red:ocr"></mat-icon>
|
||||
{{ fileStatus.ocrTime | date: 'mediumDate' }}
|
||||
{{ fileStatus.lastOCRTime | date: 'mediumDate' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -147,15 +147,15 @@
|
||||
class="small-label loading"
|
||||
translate="dossier-overview.file-listing.file-entry.file-processing"
|
||||
></div>
|
||||
<redaction-status-bar
|
||||
<iqser-status-bar
|
||||
*ngIf="fileStatus.isWorkable"
|
||||
[config]="[
|
||||
[configs]="[
|
||||
{
|
||||
color: fileStatus.status,
|
||||
length: 1
|
||||
}
|
||||
]"
|
||||
></redaction-status-bar>
|
||||
></iqser-status-bar>
|
||||
|
||||
<redaction-file-actions
|
||||
(actionPerformed)="calculateData()"
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { ChangeDetectorRef, Component, ElementRef, HostListener, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { NavigationStart, Router } from '@angular/router';
|
||||
import { Toaster } from '@services/toaster.service';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { FileDropOverlayService } from '@upload-download/services/file-drop-overlay.service';
|
||||
@ -12,12 +11,11 @@ import { DossierDetailsComponent } from '../../components/dossier-details/dossie
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { timer } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter';
|
||||
import { StatusSorter } from '@utils/sorters/status-sorter';
|
||||
import { convertFiles, handleFileDrop } from '@utils/file-drop-utils';
|
||||
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
|
||||
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
|
||||
import { ActionConfig } from '@shared/components/page-header/models/action-config.model';
|
||||
@ -42,8 +40,9 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
readonly itemSize = 80;
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
currentDossier = this._appStateService.activeDossier;
|
||||
readonly tableHeaderLabel = _('dossier-overview.table-header.title');
|
||||
readonly actionConfigs: ActionConfig[] = [
|
||||
readonly actionConfigs: readonly ActionConfig[] = [
|
||||
{
|
||||
label: this._translateService.instant('dossier-overview.header-actions.edit'),
|
||||
action: $event => this.openEditDossierDialog($event),
|
||||
@ -51,45 +50,40 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
hide: !this.currentUser.isManager
|
||||
}
|
||||
];
|
||||
readonly tableColumnConfigs: TableColumnConfig<FileStatusWrapper>[] = [
|
||||
readonly tableColumnConfigs: readonly TableColumnConfig<FileStatusWrapper>[] = [
|
||||
{
|
||||
label: _('dossier-overview.table-col-names.name'),
|
||||
withSort: true,
|
||||
column: 'filename'
|
||||
sortByKey: 'filename'
|
||||
},
|
||||
{
|
||||
label: _('dossier-overview.table-col-names.added-on'),
|
||||
withSort: true,
|
||||
column: 'added'
|
||||
sortByKey: 'added'
|
||||
},
|
||||
{
|
||||
label: _('dossier-overview.table-col-names.needs-work')
|
||||
},
|
||||
{
|
||||
label: _('dossier-overview.table-col-names.assigned-to'),
|
||||
withSort: true,
|
||||
class: 'user-column',
|
||||
column: 'reviewerName'
|
||||
sortByKey: 'reviewerName'
|
||||
},
|
||||
{
|
||||
label: _('dossier-overview.table-col-names.pages'),
|
||||
withSort: true,
|
||||
column: 'pages'
|
||||
sortByKey: 'pages'
|
||||
},
|
||||
{
|
||||
label: _('dossier-overview.table-col-names.status'),
|
||||
withSort: true,
|
||||
class: 'flex-end',
|
||||
column: 'statusSort'
|
||||
sortByKey: 'statusSort'
|
||||
}
|
||||
];
|
||||
collapsedDetails = false;
|
||||
dossierAttributes: DossierAttributeWithValue[] = [];
|
||||
protected readonly _primaryKey = 'filename';
|
||||
private readonly _lastOpenedFileKey = 'Dossier-Recent-' + this.activeDossier.dossierId;
|
||||
private readonly _lastOpenedFileKey = 'Dossier-Recent-' + this.currentDossier.dossierId;
|
||||
@ViewChild(DossierDetailsComponent, { static: false })
|
||||
private readonly _dossierDetailsComponent: DossierDetailsComponent;
|
||||
private _lastScrollPosition: number;
|
||||
private _lastScrolledIndex: number;
|
||||
@ViewChild('needsWorkTemplate', { read: TemplateRef, static: true })
|
||||
private readonly _needsWorkTemplate: TemplateRef<any>;
|
||||
@ViewChild('fileInput') private readonly _fileInput: ElementRef;
|
||||
@ -97,7 +91,6 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
private readonly _scrollViewport: CdkVirtualScrollViewport;
|
||||
|
||||
constructor(
|
||||
private readonly _router: Router,
|
||||
private readonly _toaster: Toaster,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _userService: UserService,
|
||||
@ -118,10 +111,6 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
this._loadEntitiesFromState();
|
||||
}
|
||||
|
||||
get activeDossier(): DossierWrapper {
|
||||
return this._appStateService.activeDossier;
|
||||
}
|
||||
|
||||
get checkedRequiredFilters() {
|
||||
return this.filterService.getGroup('quickFilters')?.filters.filter(f => f.required && f.checked);
|
||||
}
|
||||
@ -146,20 +135,16 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
this._loadEntitiesFromState();
|
||||
});
|
||||
|
||||
this.addSubscription = this._appStateService.fileChanged.subscribe(() => {
|
||||
this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
|
||||
this.calculateData();
|
||||
});
|
||||
|
||||
this.addSubscription = this._router.events
|
||||
.pipe(filter(event => event instanceof NavigationStart))
|
||||
.subscribe((event: NavigationStart) => {
|
||||
if (!event.url.endsWith(this._appStateService.activeDossierId)) {
|
||||
this._lastScrollPosition = this._scrollViewport.measureScrollOffset('top');
|
||||
}
|
||||
});
|
||||
this.addSubscription = this._scrollViewport.scrolledIndexChange
|
||||
.pipe(tap(index => (this._lastScrolledIndex = index)))
|
||||
.subscribe();
|
||||
|
||||
this.dossierAttributes = await this._dossierAttributesService.getValues(this.activeDossier);
|
||||
this.searchService.setSearchKey('searchField');
|
||||
this.dossierAttributes = await this._dossierAttributesService.getValues(this.currentDossier);
|
||||
this.searchService.setSearchKey('filename');
|
||||
} catch (e) {
|
||||
} finally {
|
||||
this._loadingService.stop();
|
||||
@ -175,7 +160,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
await this._appStateService.reloadActiveDossierFiles();
|
||||
this._loadEntitiesFromState();
|
||||
await this.ngOnInit();
|
||||
this._scrollViewport.scrollTo({ top: this._lastScrollPosition });
|
||||
this._scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
|
||||
}
|
||||
|
||||
ngOnDetach() {
|
||||
@ -193,7 +178,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
}
|
||||
|
||||
reloadDossiers() {
|
||||
this._appStateService.getFiles(this.activeDossier, false).then(() => {
|
||||
this._appStateService.getFiles(this.currentDossier, false).then(() => {
|
||||
this.calculateData();
|
||||
});
|
||||
}
|
||||
@ -210,7 +195,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
|
||||
@HostListener('drop', ['$event'])
|
||||
onDrop(event: DragEvent) {
|
||||
handleFileDrop(event, this.activeDossier, this._uploadFiles.bind(this));
|
||||
handleFileDrop(event, this.currentDossier, this._uploadFiles.bind(this));
|
||||
}
|
||||
|
||||
@HostListener('dragover', ['$event'])
|
||||
@ -220,14 +205,12 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
}
|
||||
|
||||
async uploadFiles(files: File[] | FileList) {
|
||||
await this._uploadFiles(convertFiles(files, this.activeDossier));
|
||||
await this._uploadFiles(convertFiles(files, this.currentDossier));
|
||||
this._fileInput.nativeElement.value = null;
|
||||
}
|
||||
|
||||
fileLink(fileStatus: FileStatusWrapper) {
|
||||
return this.permissionsService.canOpenFile(fileStatus)
|
||||
? [`/main/dossiers/${this.activeDossier.dossierId}/file/${fileStatus.fileId}`]
|
||||
: [];
|
||||
return fileStatus.canBeOpened ? [`/main/dossiers/${this.currentDossier.dossierId}/file/${fileStatus.fileId}`] : [];
|
||||
}
|
||||
|
||||
bulkActionPerformed() {
|
||||
@ -237,7 +220,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
|
||||
openEditDossierDialog($event: MouseEvent) {
|
||||
this._dialogService.openDialog('editDossier', $event, {
|
||||
dossierWrapper: this.activeDossier
|
||||
dossierWrapper: this.currentDossier
|
||||
});
|
||||
}
|
||||
|
||||
@ -246,7 +229,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
'editDossier',
|
||||
null,
|
||||
{
|
||||
dossierWrapper: this.activeDossier,
|
||||
dossierWrapper: this.currentDossier,
|
||||
section: 'members'
|
||||
},
|
||||
() => this.reloadDossiers()
|
||||
@ -254,7 +237,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
}
|
||||
|
||||
openDossierDictionaryDialog() {
|
||||
this._dialogService.openDialog('dossierDictionary', null, this.activeDossier, () => {
|
||||
this._dialogService.openDialog('dossierDictionary', null, this.currentDossier, () => {
|
||||
this.reloadDossiers();
|
||||
});
|
||||
}
|
||||
@ -267,7 +250,8 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
moment(file.lastUpdated).add(this._appConfigService.getConfig(AppConfigKey.RECENT_PERIOD_IN_HOURS), 'hours').isAfter(moment());
|
||||
|
||||
private _loadEntitiesFromState() {
|
||||
if (this.activeDossier) this.entitiesService.setEntities(this.activeDossier.files);
|
||||
this.currentDossier = this._appStateService.activeDossier;
|
||||
if (this.currentDossier) this.entitiesService.setEntities(this.currentDossier.files);
|
||||
}
|
||||
|
||||
private async _uploadFiles(files: FileUploadModel[]) {
|
||||
@ -276,7 +260,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
}
|
||||
|
||||
private _computeAllFilters() {
|
||||
if (!this.activeDossier) return;
|
||||
if (!this.currentDossier) return;
|
||||
|
||||
const allDistinctFileStatusWrapper = new Set<string>();
|
||||
const allDistinctPeople = new Set<string>();
|
||||
@ -288,7 +272,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
allDistinctFileStatusWrapper.add(file.status);
|
||||
allDistinctAddedDates.add(moment(file.added).format('DD/MM/YYYY'));
|
||||
|
||||
if (this.permissionsService.fileRequiresReanalysis(file)) allDistinctNeedsWork.add('analysis');
|
||||
if (file.analysisRequired) allDistinctNeedsWork.add('analysis');
|
||||
if (file.hintsOnly) allDistinctNeedsWork.add('hint');
|
||||
if (file.hasRedactions) allDistinctNeedsWork.add('redaction');
|
||||
if (file.hasRequests) allDistinctNeedsWork.add('suggestion');
|
||||
@ -345,8 +329,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
filterTemplate: this._needsWorkTemplate,
|
||||
filters: needsWorkFilters.sort(RedactionFilterSorter.byKey),
|
||||
checker: annotationFilterChecker,
|
||||
matchAll: true,
|
||||
checkerArgs: [this.permissionsService]
|
||||
matchAll: true
|
||||
});
|
||||
|
||||
this.filterService.addFilterGroup({
|
||||
|
||||
@ -30,9 +30,9 @@
|
||||
</div>
|
||||
|
||||
<div class="flex-1 actions-container">
|
||||
<ng-container *ngIf="!appStateService.activeFile.isExcluded">
|
||||
<ng-container *ngIf="!appStateService.activeFile.excluded">
|
||||
<ng-container *ngIf="!appStateService.activeFile.isProcessing">
|
||||
<redaction-status-bar [config]="statusBarConfig" [small]="true"></redaction-status-bar>
|
||||
<iqser-status-bar [configs]="statusBarConfig" [small]="true"></iqser-status-bar>
|
||||
|
||||
<div class="all-caps-label mr-16 ml-8">
|
||||
{{ translations[status] | translate }}
|
||||
@ -148,7 +148,7 @@
|
||||
|
||||
<div class="right-container">
|
||||
<redaction-empty-state
|
||||
*ngIf="appStateService.activeFile.isExcluded && !viewDocumentInfo && !excludePages"
|
||||
*ngIf="appStateService.activeFile.excluded && !viewDocumentInfo && !excludePages"
|
||||
[horizontalPadding]="40"
|
||||
[text]="'file-preview.tabs.is-excluded' | translate"
|
||||
icon="red:needs-work"
|
||||
@ -168,7 +168,7 @@
|
||||
(selectAnnotations)="selectAnnotations($event)"
|
||||
(selectPage)="selectPage($event)"
|
||||
(toggleSkipped)="toggleSkipped($event)"
|
||||
*ngIf="!appStateService.activeFile.isExcluded"
|
||||
*ngIf="!appStateService.activeFile.excluded"
|
||||
[(shouldDeselectAnnotationsOnPageChange)]="shouldDeselectAnnotationsOnPageChange"
|
||||
[activeViewerPage]="activeViewerPage"
|
||||
[annotationActionsTemplate]="annotationActionsTemplate"
|
||||
|
||||
@ -3,7 +3,7 @@ import { ActivatedRoute, ActivatedRouteSnapshot, NavigationExtras, Router } from
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { Annotations, WebViewerInstance } from '@pdftron/webviewer';
|
||||
import { PdfViewerComponent } from '../../components/pdf-viewer/pdf-viewer.component';
|
||||
import { Debounce } from '@utils/debounce';
|
||||
import { AutoUnsubscribe, CircleButtonTypes, Debounce, NestedFilter, processFilters } from '@iqser/common-ui';
|
||||
import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
|
||||
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
@ -33,7 +33,6 @@ import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { stampPDFPage } from '@utils/page-stamper';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AutoUnsubscribe, CircleButtonTypes, NestedFilter, processFilters } from '@iqser/common-ui';
|
||||
import { fileStatusTranslations } from '../../translations/file-status-translations';
|
||||
import { handleFilterDelta } from '@shared/components/filters/popup-filter/utils/filter-utils';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
@ -41,7 +40,6 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f'];
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-file-preview-screen',
|
||||
templateUrl: './file-preview-screen.component.html',
|
||||
styleUrls: ['./file-preview-screen.component.scss']
|
||||
})
|
||||
@ -133,11 +131,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
}
|
||||
|
||||
get canSwitchToRedactedView() {
|
||||
return this.fileData && !this.permissionsService.fileRequiresReanalysis() && !this.fileData.fileStatus.isExcluded;
|
||||
return this.fileData && !this.fileData.fileStatus.analysisRequired && !this.fileData.fileStatus.excluded;
|
||||
}
|
||||
|
||||
get canSwitchToDeltaView() {
|
||||
return this.fileData?.redactionChangeLog?.redactionLogEntry?.length > 0 && !this.fileData.fileStatus.isExcluded;
|
||||
return this.fileData?.redactionChangeLog?.redactionLogEntry?.length > 0 && !this.fileData.fileStatus.excluded;
|
||||
}
|
||||
|
||||
get canAssign(): boolean {
|
||||
@ -233,7 +231,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
}
|
||||
|
||||
async ngOnAttach(previousRoute: ActivatedRouteSnapshot) {
|
||||
if (!this.permissionsService.canOpenFile(this.appStateService.activeFile)) {
|
||||
if (!this.appStateService.activeFile.canBeOpened) {
|
||||
await this._router.navigate(['/main/dossiers/' + this.dossierId]);
|
||||
return;
|
||||
}
|
||||
@ -549,7 +547,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
|
||||
private _subscribeToFileUpdates(): void {
|
||||
this.addSubscription = timer(0, 5000).subscribe(async () => await this.appStateService.reloadActiveFile());
|
||||
this.addSubscription = this.appStateService.fileReanalysed.subscribe(async (fileStatus: FileStatusWrapper) => {
|
||||
this.addSubscription = this.appStateService.fileReanalysed$.subscribe(async (fileStatus: FileStatusWrapper) => {
|
||||
if (fileStatus.fileId === this.fileId) {
|
||||
await this._loadFileData(!this._reloadFileOnReanalysis);
|
||||
this._reloadFileOnReanalysis = false;
|
||||
|
||||
@ -10,10 +10,7 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
<redaction-table-header
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
></redaction-table-header>
|
||||
<iqser-table-header [tableColumnConfigs]="tableColumnConfigs" [tableHeaderLabel]="tableHeaderLabel"></iqser-table-header>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="searchResult.length === 0"
|
||||
@ -62,8 +59,8 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<redaction-status-bar
|
||||
[config]="[
|
||||
<iqser-status-bar
|
||||
[configs]="[
|
||||
{
|
||||
color: item.status,
|
||||
label: fileStatusTranslations[item.status] | translate,
|
||||
@ -72,7 +69,7 @@
|
||||
}
|
||||
]"
|
||||
[small]="true"
|
||||
></redaction-status-bar>
|
||||
></iqser-status-bar>
|
||||
</div>
|
||||
|
||||
<div class="small-label">
|
||||
|
||||
@ -25,7 +25,7 @@ export class FileActionService {
|
||||
fileStatusWrapper = this._appStateService.activeFile;
|
||||
}
|
||||
return this._reanalysisControllerService.reanalyzeFile(
|
||||
this._appStateService.activeDossier.dossier.dossierId,
|
||||
this._appStateService.activeDossier.dossierId,
|
||||
fileStatusWrapper.fileId,
|
||||
true
|
||||
);
|
||||
@ -38,7 +38,7 @@ export class FileActionService {
|
||||
return this._reanalysisControllerService.toggleAnalysis(
|
||||
fileStatusWrapper.dossierId,
|
||||
fileStatusWrapper.fileId,
|
||||
!fileStatusWrapper.isExcluded
|
||||
!fileStatusWrapper.excluded
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -31,9 +31,9 @@
|
||||
</div>
|
||||
<div class="red-input-group w-200 mr-8">
|
||||
<mat-select [(ngModel)]="dossier" [disabled]="!compare">
|
||||
<mat-option [value]="selectDossier">{{ selectDossier.name | translate }}</mat-option>
|
||||
<mat-option [value]="selectDossier">{{ selectDossier.dossierName | translate }}</mat-option>
|
||||
<mat-option *ngFor="let dossier of dossiers" [value]="dossier">
|
||||
{{ dossier.name }}
|
||||
{{ dossier.dossierName }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</div>
|
||||
@ -55,7 +55,7 @@
|
||||
[original]="diffEditorText"
|
||||
></ngx-monaco-diff-editor>
|
||||
|
||||
<div *ngIf="compare && dossier === selectDossier" class="no-dictionary-selected">
|
||||
<div *ngIf="compare && dossier.dossierName === selectDossier.dossierName" class="no-dictionary-selected">
|
||||
<mat-icon svgIcon="red:dictionary"></mat-icon>
|
||||
<span class="heading-l" translate="dictionary-overview.select-dictionary"></span>
|
||||
</div>
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
|
||||
import { DictionaryControllerService } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { Debounce } from '@utils/debounce';
|
||||
import { Debounce, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { IconButtonTypes } from '@iqser/common-ui';
|
||||
import ICodeEditor = monaco.editor.ICodeEditor;
|
||||
import IDiffEditor = monaco.editor.IDiffEditor;
|
||||
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
||||
@ -41,7 +40,7 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
|
||||
showDiffEditor = false;
|
||||
searchText = '';
|
||||
|
||||
selectDossier = { name: _('dictionary-overview.compare.select-dossier') };
|
||||
selectDossier = { dossierName: _('dictionary-overview.compare.select-dossier') };
|
||||
compare: false;
|
||||
|
||||
private _codeEditor: ICodeEditor;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { handleCheckedValue, NestedFilter } from '@iqser/common-ui';
|
||||
|
||||
export function handleFilterDelta(oldFilters: NestedFilter[], newFilters: NestedFilter[], allFilters: NestedFilter[]) {
|
||||
@ -46,17 +45,13 @@ export function handleFilterDelta(oldFilters: NestedFilter[], newFilters: Nested
|
||||
});
|
||||
}
|
||||
|
||||
export const annotationFilterChecker = (
|
||||
input: FileStatusWrapper | DossierWrapper,
|
||||
filter: NestedFilter,
|
||||
permissionsService: PermissionsService
|
||||
) => {
|
||||
export const annotationFilterChecker = (input: FileStatusWrapper | DossierWrapper, filter: NestedFilter) => {
|
||||
switch (filter.key) {
|
||||
case 'analysis': {
|
||||
if (input instanceof DossierWrapper) {
|
||||
return permissionsService.dossierReanalysisRequired(input);
|
||||
return input.reanalysisRequired;
|
||||
} else {
|
||||
return permissionsService.fileRequiresReanalysis(input);
|
||||
return input.analysisRequired;
|
||||
}
|
||||
}
|
||||
case 'suggestion': {
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
<div
|
||||
(click)="filterService.toggleFilter('quickFilters', filter.key)"
|
||||
*ngFor="let filter of quickFilters$ | async"
|
||||
[class.active]="filter.checked"
|
||||
class="quick-filter"
|
||||
>
|
||||
{{ filter.label }}
|
||||
</div>
|
||||
@ -1,34 +0,0 @@
|
||||
@import '../../../../../../assets/styles/variables';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.quick-filter {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid $grey-5;
|
||||
border-radius: 17px;
|
||||
background-color: $grey-6;
|
||||
padding: 0 14px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $white;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { FilterService } from '@iqser/common-ui';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-quick-filters',
|
||||
templateUrl: './quick-filters.component.html',
|
||||
styleUrls: ['./quick-filters.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class QuickFiltersComponent {
|
||||
readonly quickFilters$ = this.filterService.getFilterModels$('quickFilters');
|
||||
|
||||
constructor(readonly filterService: FilterService) {}
|
||||
}
|
||||
@ -16,11 +16,11 @@ export class PageHeaderComponent<T extends object> {
|
||||
|
||||
@Input() pageLabel: string;
|
||||
@Input() showCloseButton: boolean;
|
||||
@Input() actionConfigs: ActionConfig[];
|
||||
@Input() buttonConfigs: ButtonConfig[];
|
||||
@Input() actionConfigs: readonly ActionConfig[];
|
||||
@Input() buttonConfigs: readonly ButtonConfig[];
|
||||
@Input() searchPlaceholder: string;
|
||||
@Input() searchWidth: number | 'full';
|
||||
@Input() searchPosition: SearchPosition = this.searchPositions.afterFilters;
|
||||
@Input() searchPosition: SearchPosition = SearchPositions.afterFilters;
|
||||
|
||||
readonly filters$ = this.filterService?.filterGroups$.pipe(map(all => all.filter(f => f.icon)));
|
||||
readonly showResetFilters$ = this._showResetFilters$;
|
||||
|
||||
@ -30,8 +30,8 @@
|
||||
[class.active]="filterChecked$(val.key) | async"
|
||||
[class.filter-disabled]="(statusFilters$ | async)?.length === 0"
|
||||
>
|
||||
<redaction-status-bar
|
||||
[config]="[
|
||||
<iqser-status-bar
|
||||
[configs]="[
|
||||
{
|
||||
length: val.value,
|
||||
color: val.color,
|
||||
@ -41,7 +41,7 @@
|
||||
]"
|
||||
[small]="true"
|
||||
>
|
||||
</redaction-status-bar>
|
||||
</iqser-status-bar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
<div [ngClass]="{ small: small }" class="rectangle-container">
|
||||
<div *ngFor="let rect of config" [style]="'flex: ' + (rect.length || 1) + ';'" class="section-wrapper">
|
||||
<div
|
||||
[className]="'rectangle ' + rect.color"
|
||||
[ngStyle]="{
|
||||
'background-color': rect.color.includes('#') ? rect.color : ''
|
||||
}"
|
||||
></div>
|
||||
<div *ngIf="rect.label" [class]="rect.cssClass">{{ rect.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,46 +0,0 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
|
||||
.rectangle-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-width: 12px;
|
||||
|
||||
&.small {
|
||||
.rectangle {
|
||||
width: 12px;
|
||||
min-width: 12px;
|
||||
}
|
||||
|
||||
.section-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section-wrapper:first-child {
|
||||
.rectangle {
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.section-wrapper:last-child {
|
||||
.rectangle {
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.rectangle {
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rectangle {
|
||||
height: 6px;
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
|
||||
import { Color } from '@utils/types';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-status-bar',
|
||||
templateUrl: './status-bar.component.html',
|
||||
styleUrls: ['./status-bar.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class StatusBarComponent {
|
||||
@Input()
|
||||
config: {
|
||||
length: number;
|
||||
color: Color;
|
||||
label?: string;
|
||||
cssClass?: string;
|
||||
}[] = [];
|
||||
|
||||
@Input()
|
||||
small = false;
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
<div [class.selection-enabled]="selectionEnabled" class="header-item">
|
||||
<iqser-round-checkbox
|
||||
(click)="entitiesService.selectAll()"
|
||||
*ngIf="selectionEnabled"
|
||||
[active]="entitiesService.areAllSelected$ | async"
|
||||
[indeterminate]="entitiesService.notAllSelected$ | async"
|
||||
></iqser-round-checkbox>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ tableHeaderLabel | translate: { length: (entitiesService.displayedLength$ | async) } }}
|
||||
</span>
|
||||
|
||||
<ng-container [ngTemplateOutlet]="bulkActions"></ng-container>
|
||||
|
||||
<redaction-quick-filters *ngIf="hasQuickFilters$ | async"></redaction-quick-filters>
|
||||
|
||||
<!-- Custom content-->
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
|
||||
<div
|
||||
[class.no-data]="entitiesService.noData$ | async"
|
||||
[class.selection-enabled]="selectionEnabled"
|
||||
class="table-header"
|
||||
redactionSyncWidth="table-item"
|
||||
>
|
||||
<div *ngIf="selectionEnabled" class="select-oval-placeholder"></div>
|
||||
|
||||
<iqser-table-column-name
|
||||
*ngFor="let config of tableColumnConfigs"
|
||||
[class]="config.class"
|
||||
[column]="config.column"
|
||||
[label]="config.label | translate"
|
||||
[leftIcon]="config.leftIcon"
|
||||
[rightIconTooltip]="config.rightIconTooltip"
|
||||
[rightIcon]="config.rightIcon"
|
||||
[withSort]="config.withSort"
|
||||
></iqser-table-column-name>
|
||||
|
||||
<div *ngIf="hasEmptyColumn"></div>
|
||||
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
@ -1,21 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, TemplateRef } from '@angular/core';
|
||||
import { EntitiesService, FilterService, Required, TableColumnConfig } from '@iqser/common-ui';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-table-header',
|
||||
templateUrl: './table-header.component.html',
|
||||
styleUrls: ['./table-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class TableHeaderComponent<T extends object> {
|
||||
@Input() @Required() tableHeaderLabel: string;
|
||||
@Input() @Required() tableColumnConfigs: TableColumnConfig<T>[];
|
||||
@Input() hasEmptyColumn = false;
|
||||
@Input() selectionEnabled = false;
|
||||
@Input() bulkActions: TemplateRef<any>;
|
||||
|
||||
readonly hasQuickFilters$ = this.filterService.getGroup$('quickFilters').pipe(map(filters => !!filters));
|
||||
|
||||
constructor(readonly entitiesService: EntitiesService<T>, readonly filterService: FilterService) {}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnDestroy } from '@angular/core';
|
||||
import { Debounce } from '@utils/debounce';
|
||||
|
||||
@Directive({
|
||||
selector: '[redactionSyncWidth]',
|
||||
exportAs: 'redactionSyncWidth'
|
||||
})
|
||||
export class SyncWidthDirective implements AfterViewInit, OnDestroy {
|
||||
@Input()
|
||||
redactionSyncWidth: string;
|
||||
private _interval: number;
|
||||
|
||||
constructor(private readonly _elementRef: ElementRef) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this._interval = setInterval(() => {
|
||||
this.matchWidth();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
clearInterval(this._interval);
|
||||
}
|
||||
|
||||
@Debounce(10)
|
||||
matchWidth() {
|
||||
const headerItems = this._elementRef.nativeElement.children;
|
||||
const tableRows = this._elementRef.nativeElement.parentElement.parentElement.getElementsByClassName(this.redactionSyncWidth);
|
||||
|
||||
if (!tableRows || !tableRows.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._elementRef.nativeElement.setAttribute('synced', true);
|
||||
|
||||
const { tableRow, length } = this._sampleRow(tableRows);
|
||||
|
||||
const hasExtraColumns = headerItems.length !== length ? 1 : 0;
|
||||
|
||||
for (let idx = 0; idx < length - hasExtraColumns - 1; ++idx) {
|
||||
if (headerItems[idx]) {
|
||||
headerItems[idx].style.width = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
headerItems[idx].style.minWidth = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
}
|
||||
}
|
||||
|
||||
for (let idx = length - hasExtraColumns - 1; idx < headerItems.length; ++idx) {
|
||||
if (headerItems[idx]) {
|
||||
headerItems[idx].style.minWidth = `0`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:resize')
|
||||
onResize() {
|
||||
this.matchWidth();
|
||||
}
|
||||
|
||||
private _sampleRow(tableRows: HTMLCollectionOf<Element>): {
|
||||
tableRow: Element;
|
||||
length: number;
|
||||
} {
|
||||
let length = 0;
|
||||
let tableRow: Element;
|
||||
|
||||
for (let idx = 0; idx < tableRows.length; ++idx) {
|
||||
const row = tableRows.item(idx);
|
||||
if (row.children.length > length) {
|
||||
length = row.children.length;
|
||||
tableRow = row;
|
||||
}
|
||||
}
|
||||
|
||||
return { tableRow, length };
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FullPageLoadingIndicatorComponent } from './components/full-page-loading-indicator/full-page-loading-indicator.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InitialsAvatarComponent } from './components/initials-avatar/initials-avatar.component';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { PaginationComponent } from './components/pagination/pagination.component';
|
||||
@ -12,8 +11,6 @@ import { IconsModule } from '../icons/icons.module';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { AnnotationIconComponent } from './components/annotation-icon/annotation-icon.component';
|
||||
import { SimpleDoughnutChartComponent } from './components/simple-doughnut-chart/simple-doughnut-chart.component';
|
||||
import { StatusBarComponent } from './components/status-bar/status-bar.component';
|
||||
import { SyncWidthDirective } from './directives/sync-width.directive';
|
||||
import { HasScrollbarDirective } from './directives/has-scrollbar.directive';
|
||||
import { DictionaryAnnotationIconComponent } from './components/dictionary-annotation-icon/dictionary-annotation-icon.component';
|
||||
import { HiddenActionComponent } from './components/hidden-action/hidden-action.component';
|
||||
@ -27,25 +24,21 @@ import { NavigateLastDossiersScreenDirective } from './directives/navigate-last-
|
||||
import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component';
|
||||
import { SideNavComponent } from '@shared/components/side-nav/side-nav.component';
|
||||
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
|
||||
import { QuickFiltersComponent } from './components/filters/quick-filters/quick-filters.component';
|
||||
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
|
||||
import { AssignUserDropdownComponent } from './components/assign-user-dropdown/assign-user-dropdown.component';
|
||||
import { InputWithActionComponent } from '@shared/components/input-with-action/input-with-action.component';
|
||||
import { PageHeaderComponent } from './components/page-header/page-header.component';
|
||||
import { DatePipe } from '@shared/pipes/date.pipe';
|
||||
import { TableHeaderComponent } from './components/table-header/table-header.component';
|
||||
|
||||
const buttons = [FileDownloadBtnComponent, UserButtonComponent];
|
||||
|
||||
const components = [
|
||||
FullPageLoadingIndicatorComponent,
|
||||
InitialsAvatarComponent,
|
||||
TableHeaderComponent,
|
||||
PaginationComponent,
|
||||
InputWithActionComponent,
|
||||
AnnotationIconComponent,
|
||||
SimpleDoughnutChartComponent,
|
||||
StatusBarComponent,
|
||||
DictionaryAnnotationIconComponent,
|
||||
HiddenActionComponent,
|
||||
PopupFilterComponent,
|
||||
@ -54,21 +47,20 @@ const components = [
|
||||
SelectComponent,
|
||||
SideNavComponent,
|
||||
DictionaryManagerComponent,
|
||||
QuickFiltersComponent,
|
||||
AssignUserDropdownComponent,
|
||||
PageHeaderComponent,
|
||||
|
||||
...buttons
|
||||
];
|
||||
|
||||
const utils = [DatePipe, SyncWidthDirective, HasScrollbarDirective, NavigateLastDossiersScreenDirective];
|
||||
const utils = [DatePipe, HasScrollbarDirective, NavigateLastDossiersScreenDirective];
|
||||
|
||||
const modules = [MatConfigModule, TranslateModule, ScrollingModule, IconsModule, FormsModule, ReactiveFormsModule, CommonUiModule];
|
||||
const modules = [MatConfigModule, ScrollingModule, IconsModule, FormsModule, ReactiveFormsModule, CommonUiModule];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components, ...utils, TableHeaderComponent],
|
||||
declarations: [...components, ...utils],
|
||||
imports: [CommonModule, ...modules, MonacoEditorModule],
|
||||
exports: [...modules, ...components, ...utils, TableHeaderComponent],
|
||||
exports: [...modules, ...components, ...utils],
|
||||
providers: [
|
||||
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] },
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserService, UserWrapper } from './user.service';
|
||||
import { UserService } from './user.service';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { Comment } from '@redaction/red-ui-http';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
@ -23,16 +23,8 @@ export class PermissionsService {
|
||||
return this.isFileReviewer(fileStatus) || this.isApprover();
|
||||
}
|
||||
|
||||
dossierReanalysisRequired(dossier: DossierWrapper): boolean {
|
||||
for (const file of dossier.files) if (this.fileRequiresReanalysis(file)) return true;
|
||||
}
|
||||
|
||||
fileRequiresReanalysis(fileStatus = this._activeFile): boolean {
|
||||
return fileStatus.analysisRequired;
|
||||
}
|
||||
|
||||
displayReanalyseBtn(dossier = this._activeDossier): boolean {
|
||||
return this.isApprover(dossier) && dossier.files.filter(file => this.fileRequiresReanalysis(file)).length > 0;
|
||||
return this.isApprover(dossier) && dossier.files.filter(file => file.analysisRequired).length > 0;
|
||||
}
|
||||
|
||||
canToggleAnalysis(fileStatus: FileStatusWrapper): boolean {
|
||||
@ -41,7 +33,7 @@ export class PermissionsService {
|
||||
|
||||
canReanalyseFile(fileStatus = this._activeFile): boolean {
|
||||
return (
|
||||
(this.fileRequiresReanalysis(fileStatus) && (this.isReviewerOrApprover(fileStatus) || fileStatus.isUnassigned)) ||
|
||||
(fileStatus.analysisRequired && (this.isReviewerOrApprover(fileStatus) || fileStatus.isUnassigned)) ||
|
||||
(fileStatus.isError && fileStatus.isUnassigned)
|
||||
);
|
||||
}
|
||||
@ -54,14 +46,10 @@ export class PermissionsService {
|
||||
return this.isOwner(dossier) || fileStatus.isUnassigned;
|
||||
}
|
||||
|
||||
isApprovedOrUnderApproval(fileStatus = this._activeFile): boolean {
|
||||
return fileStatus.isApprovedOrUnderApproval;
|
||||
}
|
||||
|
||||
canAssignToSelf(fileStatus = this._activeFile): boolean {
|
||||
const precondition = this.isDossierMember() && !fileStatus.isProcessing && !fileStatus.isError && !fileStatus.isApproved;
|
||||
|
||||
const isTheOnlyReviewer = !this._appStateService.activeDossier.hasMoreThanOneReviewer;
|
||||
const isTheOnlyReviewer = !this._appStateService.activeDossier?.hasMoreThanOneReviewer;
|
||||
|
||||
if (precondition) {
|
||||
if (
|
||||
@ -96,10 +84,6 @@ export class PermissionsService {
|
||||
return this.canSetUnderReview(fileStatus);
|
||||
}
|
||||
|
||||
canApprove(fileStatus = this._activeFile): boolean {
|
||||
return !fileStatus?.analysisRequired && !fileStatus.hasRequests;
|
||||
}
|
||||
|
||||
canSetUnderApproval(fileStatus = this._activeFile): boolean {
|
||||
return fileStatus?.isUnderReview && this.isReviewerOrApprover(fileStatus);
|
||||
}
|
||||
@ -124,18 +108,10 @@ export class PermissionsService {
|
||||
return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus?.status) && this.isFileReviewer(fileStatus);
|
||||
}
|
||||
|
||||
canOpenFile(fileStatus = this._activeFile): boolean {
|
||||
return !fileStatus?.isError && !fileStatus?.isPending;
|
||||
}
|
||||
|
||||
canUndoApproval(fileStatus = this._activeFile): boolean {
|
||||
return fileStatus?.isApproved && this.isApprover();
|
||||
}
|
||||
|
||||
canUndoUnderApproval(fileStatus = this._activeFile): boolean {
|
||||
return fileStatus?.isUnderApproval && this.isDossierMember();
|
||||
}
|
||||
|
||||
canMarkPagesAsViewed(fileStatus = this._activeFile): boolean {
|
||||
return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus?.status) && this.isFileReviewer(fileStatus);
|
||||
}
|
||||
@ -155,16 +131,6 @@ export class PermissionsService {
|
||||
return user.isAdmin;
|
||||
}
|
||||
|
||||
canOcrFile(fileStatus = this._activeFile): boolean {
|
||||
return (
|
||||
!fileStatus.isExcluded && !fileStatus.ocrTime && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus.status)
|
||||
);
|
||||
}
|
||||
|
||||
canManageUsers(user: UserWrapper = this._userService.currentUser): boolean {
|
||||
return user.isUserAdmin;
|
||||
}
|
||||
|
||||
canAddComment(fileStatus = this._activeFile): boolean {
|
||||
return (this.isFileReviewer(fileStatus) || this.isApprover()) && !fileStatus.isApproved;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
DictionaryControllerService,
|
||||
Dossier,
|
||||
@ -13,7 +13,7 @@ import { Toaster } from '@services/toaster.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Event, NavigationEnd, ResolveStart, Router } from '@angular/router';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { forkJoin, Observable, of, Subject } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
import { FALLBACK_COLOR, hexToRgb } from '@utils/functions';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
@ -41,8 +41,8 @@ export interface AppState {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AppStateService {
|
||||
fileChanged = new EventEmitter<FileStatusWrapper>();
|
||||
fileReanalysed = new EventEmitter<FileStatusWrapper>();
|
||||
readonly fileChanged$ = new Subject<FileStatusWrapper>();
|
||||
readonly fileReanalysed$ = new Subject<FileStatusWrapper>();
|
||||
private _appState: AppState;
|
||||
|
||||
constructor(
|
||||
@ -208,7 +208,7 @@ export class AppStateService {
|
||||
}
|
||||
|
||||
getDossierById(id: string) {
|
||||
return this.allDossiers.find(dossier => dossier.dossier.dossierId === id);
|
||||
return this.allDossiers.find(dossier => dossier.dossierId === id);
|
||||
}
|
||||
|
||||
getFileById(dossierId: string, fileId: string) {
|
||||
@ -243,7 +243,6 @@ export class AppStateService {
|
||||
const activeFileWrapper = new FileStatusWrapper(
|
||||
activeFile,
|
||||
this._userService.getNameForId(activeFile.currentReviewer),
|
||||
this.activeDossierTemplateId,
|
||||
this._appState.fileAttributesConfig[this.activeDossierTemplateId]
|
||||
);
|
||||
this.activeDossier.files = this.activeDossier?.files.map(file =>
|
||||
@ -252,9 +251,9 @@ export class AppStateService {
|
||||
|
||||
this._computeStats();
|
||||
if (activeFileWrapper.lastProcessed !== oldProcessedDate) {
|
||||
this.fileReanalysed.emit(activeFileWrapper);
|
||||
this.fileReanalysed$.next(activeFileWrapper);
|
||||
}
|
||||
this.fileChanged.emit(activeFileWrapper);
|
||||
this.fileChanged$.next(activeFileWrapper);
|
||||
return activeFileWrapper;
|
||||
}
|
||||
|
||||
@ -346,12 +345,13 @@ export class AppStateService {
|
||||
const updatedDossier = await this._dossiersService.createOrUpdate(dossier);
|
||||
let foundDossier = this.allDossiers.find(p => p.dossierId === updatedDossier.dossierId);
|
||||
if (foundDossier) {
|
||||
Object.assign((foundDossier.dossier = updatedDossier));
|
||||
this._appState.dossiers.splice(this._appState.dossiers.indexOf(foundDossier), 1);
|
||||
foundDossier = new DossierWrapper(updatedDossier, foundDossier.files);
|
||||
} else {
|
||||
foundDossier = new DossierWrapper(updatedDossier, []);
|
||||
this._appState.dossiers.push(foundDossier);
|
||||
}
|
||||
this._appState.dossiers = [...this._appState.dossiers];
|
||||
|
||||
this._appState.dossiers.push(foundDossier);
|
||||
return foundDossier;
|
||||
} catch (error) {
|
||||
this._toaster.error(
|
||||
@ -668,7 +668,6 @@ export class AppStateService {
|
||||
const fileStatusWrapper = new FileStatusWrapper(
|
||||
file,
|
||||
this._userService.getNameForId(file.currentReviewer),
|
||||
dossier.dossierTemplateId,
|
||||
this._appState.fileAttributesConfig[dossier.dossierTemplateId]
|
||||
);
|
||||
if (JSON.stringify(oldFile) !== JSON.stringify(fileStatusWrapper)) {
|
||||
@ -686,7 +685,6 @@ export class AppStateService {
|
||||
const fsw = new FileStatusWrapper(
|
||||
file,
|
||||
this._userService.getNameForId(file.currentReviewer),
|
||||
dossier.dossierTemplateId,
|
||||
this._appState.fileAttributesConfig[dossier.dossierTemplateId]
|
||||
);
|
||||
fileStatusChangedEvent.push(fsw);
|
||||
@ -698,15 +696,14 @@ export class AppStateService {
|
||||
new FileStatusWrapper(
|
||||
f,
|
||||
this._userService.getNameForId(f.currentReviewer),
|
||||
dossier.dossierTemplateId,
|
||||
this._appState.fileAttributesConfig[dossier.dossierTemplateId]
|
||||
)
|
||||
);
|
||||
this._computeStats();
|
||||
|
||||
if (emitEvents) {
|
||||
fileReanalysedEvent.forEach(file => this.fileReanalysed.emit(file));
|
||||
fileStatusChangedEvent.forEach(file => this.fileChanged.emit(file));
|
||||
fileReanalysedEvent.forEach(file => this.fileReanalysed$.next(file));
|
||||
fileStatusChangedEvent.forEach(file => this.fileChanged$.next(file));
|
||||
}
|
||||
|
||||
return files;
|
||||
@ -716,12 +713,10 @@ export class AppStateService {
|
||||
let totalAnalysedPages = 0;
|
||||
let totalDocuments = 0;
|
||||
const totalPeople = new Set<string>();
|
||||
|
||||
this.allDossiers.forEach(d => {
|
||||
totalDocuments += d.files.length;
|
||||
if (d.dossier.memberIds) {
|
||||
d.dossier.memberIds.forEach(m => totalPeople.add(m));
|
||||
}
|
||||
|
||||
d.memberIds?.forEach(m => totalPeople.add(m));
|
||||
d.totalNumberOfPages = d.files.reduce((acc, file) => acc + file.numberOfPages, 0);
|
||||
totalAnalysedPages += d.totalNumberOfPages;
|
||||
});
|
||||
|
||||
@ -2,9 +2,33 @@ import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import * as moment from 'moment';
|
||||
import { Dictionary, Dossier } from '@redaction/red-ui-http';
|
||||
|
||||
export class DossierWrapper {
|
||||
totalNumberOfPages?: number;
|
||||
export class DossierWrapper implements Dossier {
|
||||
readonly approverIds = this._dossier.approverIds;
|
||||
readonly date = this._dossier.date;
|
||||
readonly description = this._dossier.description;
|
||||
readonly dossierId = this._dossier.dossierId;
|
||||
readonly dossierName = this._dossier.dossierName;
|
||||
readonly dossierTemplateId = this._dossier.dossierTemplateId;
|
||||
readonly downloadFileTypes = this._dossier.downloadFileTypes;
|
||||
readonly dueDate = this._dossier.dueDate;
|
||||
readonly hardDeletedTime = this._dossier.hardDeletedTime;
|
||||
readonly memberIds = this._dossier.memberIds;
|
||||
readonly ownerId = this._dossier.ownerId;
|
||||
readonly reportTemplateIds = this._dossier.reportTemplateIds;
|
||||
readonly reportTypes = this._dossier.reportTypes;
|
||||
readonly softDeletedTime = this._dossier.softDeletedTime;
|
||||
readonly status = this._dossier.status;
|
||||
readonly watermarkEnabled = this._dossier.watermarkEnabled;
|
||||
|
||||
readonly hasMoreThanOneApprover = this.approverIds.length > 1;
|
||||
readonly hasMoreThanOneReviewer = this.memberIds.length > 1;
|
||||
readonly memberCount = this.memberIds.length;
|
||||
|
||||
reanalysisRequired = this._files.some(file => file.analysisRequired);
|
||||
hasFiles = this._files.length > 0;
|
||||
filesLength = this._files.length;
|
||||
|
||||
totalNumberOfPages?: number;
|
||||
hintsOnly?: boolean;
|
||||
hasRedactions?: boolean;
|
||||
hasRequests?: boolean;
|
||||
@ -12,15 +36,12 @@ export class DossierWrapper {
|
||||
hasPendingOrProcessing?: boolean;
|
||||
|
||||
allFilesApproved?: boolean;
|
||||
type: Dictionary;
|
||||
type?: Dictionary;
|
||||
|
||||
constructor(public dossier: Dossier, files: FileStatusWrapper[]) {
|
||||
this._files = files ? files : [];
|
||||
constructor(private readonly _dossier: Dossier, private _files: FileStatusWrapper[] = []) {
|
||||
this._recomputeFileStatus();
|
||||
}
|
||||
|
||||
private _files: FileStatusWrapper[];
|
||||
|
||||
get files() {
|
||||
return this._files;
|
||||
}
|
||||
@ -30,84 +51,16 @@ export class DossierWrapper {
|
||||
this._recomputeFileStatus();
|
||||
}
|
||||
|
||||
get hasMoreThanOneApprover() {
|
||||
return this.approverIds.length > 1;
|
||||
}
|
||||
|
||||
get hasMoreThanOneReviewer() {
|
||||
return this.memberIds.length > 1;
|
||||
}
|
||||
|
||||
get dossierName() {
|
||||
return this.dossier.dossierName;
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this.dossier.description;
|
||||
}
|
||||
|
||||
get dossierTemplateId() {
|
||||
return this.dossier.dossierTemplateId;
|
||||
}
|
||||
|
||||
get ownerId() {
|
||||
return this.dossier.ownerId;
|
||||
}
|
||||
|
||||
get dossierId() {
|
||||
return this.dossier.dossierId;
|
||||
}
|
||||
|
||||
get memberIds() {
|
||||
return this.dossier.memberIds;
|
||||
}
|
||||
|
||||
get approverIds() {
|
||||
return this.dossier.approverIds;
|
||||
}
|
||||
|
||||
get dossierDate() {
|
||||
return this.dossier.date;
|
||||
}
|
||||
|
||||
get numberOfMembers() {
|
||||
return this.dossier.memberIds.length;
|
||||
}
|
||||
|
||||
get dueDate() {
|
||||
return this.dossier.dueDate;
|
||||
}
|
||||
|
||||
get hasFiles() {
|
||||
return this._files.length > 0;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.dossier.dossierName;
|
||||
}
|
||||
|
||||
get memberCount() {
|
||||
return this.dossier.memberIds.length;
|
||||
}
|
||||
|
||||
get watermarkEnabled(): boolean {
|
||||
return this.dossier.watermarkEnabled;
|
||||
}
|
||||
|
||||
hasStatus(status: string): boolean {
|
||||
return !!this._files.find(f => f.status === status);
|
||||
}
|
||||
|
||||
hasMember(key: string) {
|
||||
return this.dossier.memberIds.indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
dueDateMatches(key: string) {
|
||||
return moment(this.dueDate).format('DD/MM/YYYY') === key;
|
||||
return this._dossier.memberIds.indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
addedDateMatches(key: string) {
|
||||
return moment(this.dossierDate).format('DD/MM/YYYY') === key;
|
||||
return moment(this.date).format('DD/MM/YYYY') === key;
|
||||
}
|
||||
|
||||
private _recomputeFileStatus() {
|
||||
@ -127,5 +80,8 @@ export class DossierWrapper {
|
||||
this.hasPendingOrProcessing = this.hasPendingOrProcessing || f.isPending || f.isProcessing;
|
||||
});
|
||||
this.hasNone = !this.hasRequests && !this.hasRedactions && !this.hintsOnly;
|
||||
this.hasFiles = this._files.length > 0;
|
||||
this.filesLength = this._files.length;
|
||||
this.reanalysisRequired = this._files.some(file => file.analysisRequired);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
|
||||
import { Debounce } from './debounce';
|
||||
import { Debounce } from '@iqser/common-ui';
|
||||
|
||||
export interface OnAttach {
|
||||
ngOnAttach(previousRoute: ActivatedRouteSnapshot);
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
export function Debounce(delay: number = 300): MethodDecorator {
|
||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||
let timeout = null;
|
||||
|
||||
const original = descriptor.value;
|
||||
|
||||
descriptor.value = function (...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => original.apply(this, args), delay);
|
||||
};
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
@ -35,5 +35,6 @@ $dark: $black;
|
||||
|
||||
$btn-bg-hover: $grey-4;
|
||||
$btn-bg: $grey-6;
|
||||
$quick-filter-border: $grey-5;
|
||||
|
||||
$separator: rgba(226, 228, 233, 0.9);
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
@import 'variables';
|
||||
@import 'red-mixins';
|
||||
|
||||
.header-item {
|
||||
background-color: $grey-6;
|
||||
height: 50px;
|
||||
padding: 0 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
border-bottom: 1px solid $separator;
|
||||
box-sizing: border-box;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.selection-enabled {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
@ -123,8 +123,3 @@ cdk-virtual-scroll-viewport {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scrollbar-placeholder {
|
||||
width: 11px;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
@import 'red-controls';
|
||||
@import 'red-toasts';
|
||||
@import 'red-tooltips';
|
||||
@import 'red-grid';
|
||||
@import 'red-breadcrumbs';
|
||||
@import 'red-editor';
|
||||
@import 'red-slider';
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit c552ed2e21d3df6fbcfe842ae85ac5a75006ab85
|
||||
Subproject commit 1d46b21c74c07d6811a99b9de6c940c740bc8ceb
|
||||
@ -169,5 +169,5 @@ export namespace FileStatus {
|
||||
UNDERREVIEW: 'UNDER_REVIEW' as StatusEnum,
|
||||
UNPROCESSED: 'UNPROCESSED' as StatusEnum,
|
||||
INDEXING: 'INDEXING' as StatusEnum
|
||||
};
|
||||
} as const;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user