RED-1817: fixed access permissions to settings screens

This commit is contained in:
Adina Țeudan 2021-07-15 12:24:16 +03:00
parent d30e74e14c
commit 1c81469e6b
18 changed files with 149 additions and 308 deletions

View File

@ -111,14 +111,19 @@ const routes = [
{ path: '', redirectTo: 'dictionaries', pathMatch: 'full' } { path: '', redirectTo: 'dictionaries', pathMatch: 'full' }
] ]
} }
] ],
data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
requiredRoles: ['RED_MANAGER', 'RED_ADMIN']
}
}, },
{ {
path: 'users', path: 'users',
component: UserListingScreenComponent, component: UserListingScreenComponent,
canActivate: [CompositeRouteGuard], canActivate: [CompositeRouteGuard],
data: { data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard] routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
requiredRoles: ['RED_USER_ADMIN']
} }
}, },
{ {
@ -126,7 +131,8 @@ const routes = [
component: LicenseInformationScreenComponent, component: LicenseInformationScreenComponent,
canActivate: [CompositeRouteGuard], canActivate: [CompositeRouteGuard],
data: { data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard] routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
requiredRoles: ['RED_ADMIN']
} }
}, },
{ {
@ -134,7 +140,8 @@ const routes = [
component: DigitalSignatureScreenComponent, component: DigitalSignatureScreenComponent,
canActivate: [CompositeRouteGuard], canActivate: [CompositeRouteGuard],
data: { data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard] routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
requiredRoles: ['RED_ADMIN']
} }
}, },
{ {
@ -142,7 +149,8 @@ const routes = [
component: AuditScreenComponent, component: AuditScreenComponent,
canActivate: [CompositeRouteGuard], canActivate: [CompositeRouteGuard],
data: { data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard] routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
requiredRoles: ['RED_ADMIN']
} }
}, },
{ {
@ -150,7 +158,8 @@ const routes = [
component: SmtpConfigScreenComponent, component: SmtpConfigScreenComponent,
canActivate: [CompositeRouteGuard], canActivate: [CompositeRouteGuard],
data: { data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard] routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
requiredRoles: ['RED_ADMIN']
} }
}, },
{ {

View File

@ -4,7 +4,8 @@
*ngIf=" *ngIf="
(!item.onlyAdmin || permissionsService.isAdmin()) && (!item.onlyAdmin || permissionsService.isAdmin()) &&
(!item.onlyDevMode || userPreferenceService.areDevFeaturesEnabled) && (!item.onlyDevMode || userPreferenceService.areDevFeaturesEnabled) &&
(!item.userManagerOnly || permissionsService.canManageUsers()) (!item.userManagerOnly || permissionsService.canManageUsers()) &&
(!item.onlyManager || permissionsService.isManager())
" "
[routerLinkActiveOptions]="{ exact: false }" [routerLinkActiveOptions]="{ exact: false }"
[routerLink]="prefix + item.screen" [routerLink]="prefix + item.screen"

View File

@ -16,12 +16,13 @@ export class AdminSideNavComponent {
screen: string; screen: string;
onlyDevMode?: boolean; onlyDevMode?: boolean;
onlyAdmin?: boolean; onlyAdmin?: boolean;
onlyManager?: boolean;
userManagerOnly?: boolean; userManagerOnly?: boolean;
label?: string; label?: string;
}[]; }[];
} = { } = {
settings: [ settings: [
{ screen: 'dossier-templates', onlyAdmin: true }, { screen: 'dossier-templates', onlyManager: true },
{ screen: 'digital-signature', onlyAdmin: true }, { screen: 'digital-signature', onlyAdmin: true },
{ screen: 'license-info', label: 'license-information', onlyAdmin: true }, { screen: 'license-info', label: 'license-information', onlyAdmin: true },
{ screen: 'audit', onlyAdmin: true }, { screen: 'audit', onlyAdmin: true },
@ -33,9 +34,9 @@ export class AdminSideNavComponent {
{ screen: 'rules', onlyDevMode: true, label: 'rule-editor' }, { screen: 'rules', onlyDevMode: true, label: 'rule-editor' },
{ screen: 'default-colors' }, { screen: 'default-colors' },
{ screen: 'watermark' }, { screen: 'watermark' },
{ screen: 'file-attributes', onlyAdmin: true }, { screen: 'file-attributes' },
{ screen: 'dossier-attributes', onlyAdmin: true }, { screen: 'dossier-attributes' },
{ screen: 'reports', onlyAdmin: true, onlyDevMode: true } { screen: 'reports', onlyDevMode: true }
] ]
}; };

View File

@ -7,10 +7,7 @@
></redaction-round-checkbox> ></redaction-round-checkbox>
</div> </div>
<span class="all-caps-label"> <span class="all-caps-label">
{{ {{ 'file-attributes-csv-import.table-header.title' | translate: { length: allEntities.length } }}
'file-attributes-csv-import.table-header.title'
| translate: { length: allEntities.length }
}}
</span> </span>
<ng-container *ngIf="areSomeEntitiesSelected$ | async"> <ng-container *ngIf="areSomeEntitiesSelected$ | async">
@ -49,11 +46,7 @@
</mat-menu> </mat-menu>
<mat-menu #typeMenu="matMenu" class="padding-bottom-8"> <mat-menu #typeMenu="matMenu" class="padding-bottom-8">
<button <button (click)="setAttributeForSelection('type', type)" *ngFor="let type of typeOptions" mat-menu-item>
(click)="setAttributeForSelection('type', type)"
*ngFor="let type of typeOptions"
mat-menu-item
>
{{ 'file-attribute-types.' + type | translate }} {{ 'file-attribute-types.' + type | translate }}
</button> </button>
</mat-menu> </mat-menu>
@ -63,14 +56,9 @@
<div class="table-header" redactionSyncWidth="table-item"> <div class="table-header" redactionSyncWidth="table-item">
<div class="select-oval-placeholder"></div> <div class="select-oval-placeholder"></div>
<redaction-table-col-name <redaction-table-col-name class="name" label="file-attributes-csv-import.table-col-names.name"></redaction-table-col-name>
class="name"
label="file-attributes-csv-import.table-col-names.name"
></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name label="file-attributes-csv-import.table-col-names.type"></redaction-table-col-name>
label="file-attributes-csv-import.table-col-names.type"
></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name
class="flex-center" class="flex-center"
@ -89,11 +77,7 @@
<div class="scrollbar-placeholder"></div> <div class="scrollbar-placeholder"></div>
</div> </div>
<redaction-empty-state <redaction-empty-state *ngIf="noData" icon="red:attribute" screen="file-attributes-csv-import"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length === 0"
icon="red:attribute"
screen="file-attributes-csv-import"
></redaction-empty-state>
<cdk-virtual-scroll-viewport [itemSize]="50" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="50" redactionHasScrollbar>
<!-- Table lines --> <!-- Table lines -->
@ -110,10 +94,7 @@
<div *ngIf="!field.editingName"> <div *ngIf="!field.editingName">
{{ field.name }} {{ field.name }}
</div> </div>
<form <form (submit)="field.editingName = false; field.name = field.temporaryName" *ngIf="field.editingName">
(submit)="field.editingName = false; field.name = field.temporaryName"
*ngIf="field.editingName"
>
<div class="red-input-group w-200"> <div class="red-input-group w-200">
<input [(ngModel)]="field.temporaryName" name="name" /> <input [(ngModel)]="field.temporaryName" name="name" />
</div> </div>
@ -156,10 +137,7 @@
<mat-slide-toggle [(ngModel)]="field.readonly" color="primary"></mat-slide-toggle> <mat-slide-toggle [(ngModel)]="field.readonly" color="primary"></mat-slide-toggle>
</div> </div>
<div class="center"> <div class="center">
<redaction-round-checkbox <redaction-round-checkbox (click)="togglePrimary(field)" [active]="field.primaryAttribute"></redaction-round-checkbox>
(click)="togglePrimary(field)"
[active]="field.primaryAttribute"
></redaction-round-checkbox>
</div> </div>
<div class="actions-container"> <div class="actions-container">
<div class="action-buttons"> <div class="action-buttons">

View File

@ -35,7 +35,7 @@
<redaction-circle-button <redaction-circle-button
(action)="openConfirmDeleteAttributeDialog($event)" (action)="openConfirmDeleteAttributeDialog($event)"
*ngIf="areSomeEntitiesSelected$ | async" *ngIf="permissionsService.isAdmin() && areSomeEntitiesSelected$ | async"
icon="red:trash" icon="red:trash"
tooltip="dossier-attributes-listing.bulk.delete" tooltip="dossier-attributes-listing.bulk.delete"
type="dark-bg" type="dark-bg"
@ -50,6 +50,7 @@
<redaction-icon-button <redaction-icon-button
(action)="openAddEditAttributeDialog($event)" (action)="openAddEditAttributeDialog($event)"
*ngIf="permissionsService.isAdmin()"
icon="red:plus" icon="red:plus"
text="dossier-attributes-listing.add-new" text="dossier-attributes-listing.add-new"
type="primary" type="primary"
@ -81,17 +82,13 @@
<redaction-empty-state <redaction-empty-state
(action)="openAddEditAttributeDialog($event)" (action)="openAddEditAttributeDialog($event)"
*ngIf="(allEntities$ | async)?.length === 0" *ngIf="noData"
[showButton]="true" [showButton]="permissionsService.isAdmin()"
icon="red:attribute" icon="red:attribute"
screen="dossier-attributes-listing" screen="dossier-attributes-listing"
></redaction-empty-state> ></redaction-empty-state>
<redaction-empty-state <redaction-empty-state *ngIf="noMatch" screen="dossier-attributes-listing" type="no-match"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length && (displayedEntities$ | async)?.length === 0"
screen="dossier-attributes-listing"
type="no-match"
></redaction-empty-state>
<cdk-virtual-scroll-viewport [itemSize]="50" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="50" redactionHasScrollbar>
<div <div
@ -114,7 +111,7 @@
{{ 'dossier-attribute-types.' + attribute.type | translate }} {{ 'dossier-attribute-types.' + attribute.type | translate }}
</div> </div>
<div class="actions-container"> <div class="actions-container">
<div class="action-buttons"> <div *ngIf="permissionsService.isAdmin()" class="action-buttons">
<redaction-circle-button <redaction-circle-button
(action)="openAddEditAttributeDialog($event, attribute)" (action)="openAddEditAttributeDialog($event, attribute)"
icon="red:edit" icon="red:edit"

View File

@ -9,6 +9,7 @@ import { ScreenNames, SortingService } from '../../../../services/sorting.servic
import { FilterService } from '../../../shared/services/filter.service'; import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service'; import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service'; import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { PermissionsService } from '@services/permissions.service';
@Component({ @Component({
templateUrl: './dossier-attributes-listing-screen.component.html', templateUrl: './dossier-attributes-listing-screen.component.html',
@ -22,7 +23,8 @@ export class DossierAttributesListingScreenComponent extends BaseListingComponen
private readonly _activatedRoute: ActivatedRoute, private readonly _activatedRoute: ActivatedRoute,
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _loadingService: LoadingService, private readonly _loadingService: LoadingService,
private readonly _dossierAttributesService: DossierAttributesControllerService private readonly _dossierAttributesService: DossierAttributesControllerService,
readonly permissionsService: PermissionsService
) { ) {
super(_injector); super(_injector);
this._searchService.setSearchKey('label'); this._searchService.setSearchKey('label');

View File

@ -23,17 +23,12 @@
<redaction-round-checkbox <redaction-round-checkbox
(click)="toggleSelectAll()" (click)="toggleSelectAll()"
[active]="areAllEntitiesSelected" [active]="areAllEntitiesSelected"
[indeterminate]=" [indeterminate]="(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected"
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox> ></redaction-round-checkbox>
</div> </div>
<span class="all-caps-label"> <span class="all-caps-label">
{{ {{ 'dossier-templates-listing.table-header.title' | translate: { length: (displayedEntities$ | async).length } }}
'dossier-templates-listing.table-header.title'
| translate: { length: (displayedEntities$ | async).length }
}}
</span> </span>
<ng-container *ngIf="areSomeEntitiesSelected$ | async"> <ng-container *ngIf="areSomeEntitiesSelected$ | async">
@ -55,10 +50,7 @@
<redaction-icon-button <redaction-icon-button
(action)="openAddDossierTemplateDialog()" (action)="openAddDossierTemplateDialog()"
*ngIf=" *ngIf="permissionsService.isAdmin() && userPreferenceService.areDevFeaturesEnabled"
permissionsService.isAdmin() &&
userPreferenceService.areDevFeaturesEnabled
"
icon="red:plus" icon="red:plus"
text="dossier-templates-listing.add-new" text="dossier-templates-listing.add-new"
type="primary" type="primary"
@ -66,11 +58,7 @@
</div> </div>
</div> </div>
<div <div [class.no-data]="noData" class="table-header" redactionSyncWidth="table-item">
[class.no-data]="(allEntities$ | async)?.length === 0"
class="table-header"
redactionSyncWidth="table-item"
>
<div class="select-oval-placeholder"></div> <div class="select-oval-placeholder"></div>
<redaction-table-col-name <redaction-table-col-name
@ -101,37 +89,20 @@
<div class="scrollbar-placeholder"></div> <div class="scrollbar-placeholder"></div>
</div> </div>
<redaction-empty-state <redaction-empty-state *ngIf="noData" icon="red:template" screen="dossier-templates-listing"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length === 0"
icon="red:template"
screen="dossier-templates-listing"
></redaction-empty-state>
<redaction-empty-state <redaction-empty-state *ngIf="noMatch" screen="dossier-templates-listing" type="no-match"></redaction-empty-state>
*ngIf="
(allEntities$ | async)?.length && (displayedEntities$ | async).length === 0
"
screen="dossier-templates-listing"
type="no-match"
></redaction-empty-state>
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
<div <div
*cdkVirtualFor=" *cdkVirtualFor="
let dossierTemplate of displayedEntities$ let dossierTemplate of displayedEntities$ | async | sortBy: sortingOption.order:sortingOption.column
| async
| sortBy: sortingOption.order:sortingOption.column
" "
[routerLink]="[dossierTemplate.dossierTemplateId, 'dictionaries']" [routerLink]="[dossierTemplate.dossierTemplateId, 'dictionaries']"
class="table-item pointer" class="table-item pointer"
> >
<div <div (click)="toggleEntitySelected($event, dossierTemplate)" class="selection-column">
(click)="toggleEntitySelected($event, dossierTemplate)" <redaction-round-checkbox [active]="isSelected(dossierTemplate)"></redaction-round-checkbox>
class="selection-column"
>
<redaction-round-checkbox
[active]="isSelected(dossierTemplate)"
></redaction-round-checkbox>
</div> </div>
<div> <div>
@ -142,19 +113,14 @@
<div> <div>
<mat-icon svgIcon="red:dictionary"></mat-icon> <mat-icon svgIcon="red:dictionary"></mat-icon>
{{ {{
'dossier-templates-listing.dictionaries' 'dossier-templates-listing.dictionaries' | translate: { length: dossierTemplate.dictionariesCount }
| translate
: { length: dossierTemplate.dictionariesCount }
}} }}
</div> </div>
</div> </div>
</div> </div>
<div class="user-column"> <div class="user-column">
<redaction-initials-avatar <redaction-initials-avatar [userId]="dossierTemplate.createdBy" [withName]="true"></redaction-initials-avatar>
[userId]="dossierTemplate.createdBy"
[withName]="true"
></redaction-initials-avatar>
</div> </div>
<div class="small-label"> <div class="small-label">
{{ dossierTemplate.dateAdded | date: 'd MMM. yyyy' }} {{ dossierTemplate.dateAdded | date: 'd MMM. yyyy' }}

View File

@ -25,22 +25,17 @@
<redaction-round-checkbox <redaction-round-checkbox
(click)="toggleSelectAll()" (click)="toggleSelectAll()"
[active]="areAllEntitiesSelected" [active]="areAllEntitiesSelected"
[indeterminate]=" [indeterminate]="(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected"
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox> ></redaction-round-checkbox>
</div> </div>
<span class="all-caps-label"> <span class="all-caps-label">
{{ {{ 'file-attributes-listing.table-header.title' | translate: { length: (displayedEntities$ | async)?.length } }}
'file-attributes-listing.table-header.title'
| translate: { length: (displayedEntities$ | async)?.length }
}}
</span> </span>
<redaction-circle-button <redaction-circle-button
(click)="openConfirmDeleteAttributeDialog($event)" (click)="openConfirmDeleteAttributeDialog($event)"
*ngIf="areSomeEntitiesSelected$ | async" *ngIf="permissionsService.isAdmin() && areSomeEntitiesSelected$ | async"
icon="red:trash" icon="red:trash"
tooltip="file-attributes-listing.bulk-actions.delete" tooltip="file-attributes-listing.bulk-actions.delete"
type="dark-bg" type="dark-bg"
@ -57,6 +52,7 @@
<redaction-circle-button <redaction-circle-button
(action)="fileInput.click()" (action)="fileInput.click()"
*ngIf="permissionsService.isAdmin()"
icon="red:upload" icon="red:upload"
tooltip="file-attributes-listing.upload-csv" tooltip="file-attributes-listing.upload-csv"
tooltipPosition="above" tooltipPosition="above"
@ -65,6 +61,7 @@
<redaction-icon-button <redaction-icon-button
(action)="openAddEditAttributeDialog($event)" (action)="openAddEditAttributeDialog($event)"
*ngIf="permissionsService.isAdmin()"
icon="red:plus" icon="red:plus"
text="file-attributes-listing.add-new" text="file-attributes-listing.add-new"
type="primary" type="primary"
@ -72,11 +69,7 @@
</div> </div>
</div> </div>
<div <div [class.no-data]="noData" class="table-header" redactionSyncWidth="table-item">
[class.no-data]="(allEntities$ | async)?.length === 0"
class="table-header"
redactionSyncWidth="table-item"
>
<div class="select-oval-placeholder"></div> <div class="select-oval-placeholder"></div>
<redaction-table-col-name <redaction-table-col-name
@ -118,26 +111,14 @@
<div class="scrollbar-placeholder"></div> <div class="scrollbar-placeholder"></div>
</div> </div>
<redaction-empty-state <redaction-empty-state *ngIf="noData" icon="red:attribute" screen="file-attributes-listing"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length === 0"
icon="red:attribute"
screen="file-attributes-listing"
></redaction-empty-state>
<redaction-empty-state <redaction-empty-state *ngIf="noMatch" screen="file-attributes-listing" type="no-match"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length && (displayedEntities$ | async)?.length === 0"
screen="file-attributes-listing"
type="no-match"
></redaction-empty-state>
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
<!-- Table lines --> <!-- Table lines -->
<div <div
*cdkVirtualFor=" *cdkVirtualFor="let attribute of displayedEntities$ | async | sortBy: sortingOption.order:sortingOption.column"
let attribute of displayedEntities$
| async
| sortBy: sortingOption.order:sortingOption.column
"
class="table-item" class="table-item"
> >
<div (click)="toggleEntitySelected($event, attribute)" class="selection-column"> <div (click)="toggleEntitySelected($event, attribute)" class="selection-column">
@ -165,7 +146,7 @@
<redaction-round-checkbox *ngIf="attribute.primaryAttribute" [active]="true" [size]="18"></redaction-round-checkbox> <redaction-round-checkbox *ngIf="attribute.primaryAttribute" [active]="true" [size]="18"></redaction-round-checkbox>
</div> </div>
<div class="actions-container"> <div class="actions-container">
<div class="action-buttons"> <div *ngIf="permissionsService.isAdmin()" class="action-buttons">
<redaction-circle-button <redaction-circle-button
(action)="openAddEditAttributeDialog($event, attribute)" (action)="openAddEditAttributeDialog($event, attribute)"
icon="red:edit" icon="red:edit"

View File

@ -46,6 +46,7 @@
<div class="heading" translate="reports-screen.report-documents"></div> <div class="heading" translate="reports-screen.report-documents"></div>
<redaction-circle-button <redaction-circle-button
(action)="fileInput.click()" (action)="fileInput.click()"
*ngIf="permissionsService.isAdmin()"
icon="red:upload" icon="red:upload"
tooltip="reports-screen.upload-document" tooltip="reports-screen.upload-document"
></redaction-circle-button> ></redaction-circle-button>
@ -53,7 +54,7 @@
<div <div
(click)="fileInput.click()" (click)="fileInput.click()"
*ngIf="!availableTemplates?.length" *ngIf="permissionsService.isAdmin() && !availableTemplates?.length"
class="template upload-button" class="template upload-button"
translate="reports-screen.upload-document" translate="reports-screen.upload-document"
></div> ></div>
@ -70,6 +71,7 @@
></redaction-circle-button> ></redaction-circle-button>
<redaction-circle-button <redaction-circle-button
(action)="deleteTemplate(template)" (action)="deleteTemplate(template)"
*ngIf="permissionsService.isAdmin()"
[iconSize]="12" [iconSize]="12"
[size]="18" [size]="18"
icon="red:trash" icon="red:trash"

View File

@ -21,6 +21,7 @@
align-items: center; align-items: center;
padding-left: 8px; padding-left: 8px;
margin-bottom: 8px; margin-bottom: 8px;
min-height: 34px;
} }
.template { .template {

View File

@ -5,6 +5,7 @@ import { ReportTemplate, ReportTemplateControllerService } from '@redaction/red-
import { download } from '../../../../utils/file-download-utils'; import { download } from '../../../../utils/file-download-utils';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { LoadingService } from '../../../../services/loading.service'; import { LoadingService } from '../../../../services/loading.service';
import { PermissionsService } from '../../../../services/permissions.service';
@Component({ @Component({
selector: 'redaction-reports-screen', selector: 'redaction-reports-screen',
@ -22,7 +23,8 @@ export class ReportsScreenComponent implements OnInit {
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
private readonly _reportTemplateService: ReportTemplateControllerService, private readonly _reportTemplateService: ReportTemplateControllerService,
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _loadingService: LoadingService private readonly _loadingService: LoadingService,
readonly permissionsService: PermissionsService
) { ) {
this._appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId); this._appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
} }

View File

@ -1,10 +1,7 @@
<section> <section>
<div class="overlay-shadow"></div> <div class="overlay-shadow"></div>
<redaction-page-header <redaction-page-header [pageLabel]="'trash.label' | translate" [showCloseButton]="true"></redaction-page-header>
[pageLabel]="'trash.label' | translate"
[showCloseButton]="true"
></redaction-page-header>
<div class="red-content-inner"> <div class="red-content-inner">
<div class="content-container"> <div class="content-container">
@ -13,105 +10,80 @@
<redaction-round-checkbox <redaction-round-checkbox
(click)="toggleSelectAll()" (click)="toggleSelectAll()"
[active]="areAllEntitiesSelected" [active]="areAllEntitiesSelected"
[indeterminate]=" [indeterminate]="(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected"
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox> ></redaction-round-checkbox>
</div> </div>
<span class="all-caps-label"> <span class="all-caps-label">
{{ {{ 'trash.table-header.title' | translate: { length: (displayedEntities$ | async)?.length } }}
'trash.table-header.title'
| translate: { length: (displayedEntities$ | async)?.length }
}}
</span> </span>
<redaction-circle-button <redaction-circle-button
(action)="bulkRestore()" (action)="bulkRestore()"
*ngIf="areSomeEntitiesSelected$ | async" *ngIf="areSomeEntitiesSelected$ | async"
icon="red:put-back"
[tooltip]="'trash.bulk.restore' | translate" [tooltip]="'trash.bulk.restore' | translate"
icon="red:put-back"
type="dark-bg" type="dark-bg"
></redaction-circle-button> ></redaction-circle-button>
<redaction-circle-button <redaction-circle-button
(action)="bulkDelete()" (action)="bulkDelete()"
*ngIf="areSomeEntitiesSelected$ | async" *ngIf="areSomeEntitiesSelected$ | async"
icon="red:trash"
[tooltip]="'trash.bulk.delete' | translate" [tooltip]="'trash.bulk.delete' | translate"
icon="red:trash"
type="dark-bg" type="dark-bg"
></redaction-circle-button> ></redaction-circle-button>
</div> </div>
<div <div [class.no-data]="noData" class="table-header" redactionSyncWidth="table-item">
[class.no-data]="(allEntities$ | async)?.length === 0"
class="table-header"
redactionSyncWidth="table-item"
>
<div class="select-oval-placeholder"></div> <div class="select-oval-placeholder"></div>
<redaction-table-col-name <redaction-table-col-name
(toggleSort)="toggleSort($event)" (toggleSort)="toggleSort($event)"
[activeSortingOption]="sortingOption" [activeSortingOption]="sortingOption"
[label]="'trash.table-col-names.name' | translate"
[withSort]="true" [withSort]="true"
column="name" column="name"
[label]="'trash.table-col-names.name' | translate"
></redaction-table-col-name> ></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name
class="user-column"
[label]="'trash.table-col-names.owner' | translate" [label]="'trash.table-col-names.owner' | translate"
class="user-column"
></redaction-table-col-name> ></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name
(toggleSort)="toggleSort($event)" (toggleSort)="toggleSort($event)"
[activeSortingOption]="sortingOption" [activeSortingOption]="sortingOption"
[label]="'trash.table-col-names.deleted-on' | translate"
[withSort]="true" [withSort]="true"
column="dateDeleted" column="dateDeleted"
[label]="'trash.table-col-names.deleted-on' | translate"
></redaction-table-col-name> ></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name
(toggleSort)="toggleSort($event)" (toggleSort)="toggleSort($event)"
[activeSortingOption]="sortingOption" [activeSortingOption]="sortingOption"
[label]="'trash.table-col-names.time-to-restore' | translate"
[withSort]="true" [withSort]="true"
column="timeToRestore" column="timeToRestore"
[label]="'trash.table-col-names.time-to-restore' | translate"
></redaction-table-col-name> ></redaction-table-col-name>
<div class="scrollbar-placeholder"></div> <div class="scrollbar-placeholder"></div>
</div> </div>
<redaction-empty-state <redaction-empty-state *ngIf="noData" icon="red:template" screen="trash"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length === 0"
icon="red:template"
screen="trash"
></redaction-empty-state>
<redaction-empty-state <redaction-empty-state *ngIf="noMatch" screen="trash" type="no-match"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length && (displayedEntities$ | async)?.length === 0"
screen="trash"
type="no-match"
></redaction-empty-state>
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
<div <div
*cdkVirtualFor=" *cdkVirtualFor="
let entity of displayedEntities$ let entity of displayedEntities$ | async | sortBy: sortingOption.order:sortingOption.column;
| async
| sortBy: sortingOption.order:sortingOption.column;
trackBy: trackById trackBy: trackById
" "
class="table-item" class="table-item"
> >
<div (click)="toggleEntitySelected($event, entity)" class="selection-column"> <div (click)="toggleEntitySelected($event, entity)" class="selection-column">
<redaction-round-checkbox <redaction-round-checkbox [active]="isSelected(entity)"></redaction-round-checkbox>
[active]="isSelected(entity)"
></redaction-round-checkbox>
</div> </div>
<div class="filename"> <div class="filename">
<div <div [matTooltip]="entity.dossierName" class="table-item-title heading" matTooltipPosition="above">
class="table-item-title heading"
[matTooltip]="entity.dossierName"
matTooltipPosition="above"
>
{{ entity.dossierName }} {{ entity.dossierName }}
</div> </div>
<div class="small-label stats-subtitle"> <div class="small-label stats-subtitle">
@ -131,10 +103,7 @@
</div> </div>
<div class="user-column"> <div class="user-column">
<redaction-initials-avatar <redaction-initials-avatar [userId]="entity.ownerId" [withName]="true"></redaction-initials-avatar>
[userId]="entity.ownerId"
[withName]="true"
></redaction-initials-avatar>
</div> </div>
<div class="small-label"> <div class="small-label">
@ -148,15 +117,15 @@
<div class="action-buttons"> <div class="action-buttons">
<redaction-circle-button <redaction-circle-button
(action)="bulkRestore([entity.dossierId])" (action)="bulkRestore([entity.dossierId])"
icon="red:put-back"
[tooltip]="'trash.action.restore' | translate" [tooltip]="'trash.action.restore' | translate"
icon="red:put-back"
type="dark-bg" type="dark-bg"
></redaction-circle-button> ></redaction-circle-button>
<redaction-circle-button <redaction-circle-button
(action)="bulkDelete([entity.dossierId])" (action)="bulkDelete([entity.dossierId])"
icon="red:trash"
[tooltip]="'trash.action.delete' | translate" [tooltip]="'trash.action.delete' | translate"
icon="red:trash"
type="dark-bg" type="dark-bg"
></redaction-circle-button> ></redaction-circle-button>
</div> </div>

View File

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core';
import { AppStateService } from '@state/app-state.service'; import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { Dossier, DossierTemplateModel, StatusControllerService } from '@redaction/red-ui-http'; import { Dossier, StatusControllerService } from '@redaction/red-ui-http';
import { LoadingService } from '../../../../services/loading.service'; import { LoadingService } from '../../../../services/loading.service';
import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service'; import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
import * as moment from 'moment'; import * as moment from 'moment';
@ -11,7 +11,6 @@ import { ScreenStateService } from '../../../shared/services/screen-state.servic
import { ScreenNames, SortingService } from '../../../../services/sorting.service'; import { ScreenNames, SortingService } from '../../../../services/sorting.service';
import { BaseListingComponent } from '../../../shared/base/base-listing.component'; import { BaseListingComponent } from '../../../shared/base/base-listing.component';
import { DossiersService } from '../../../dossier/services/dossiers.service'; import { DossiersService } from '../../../dossier/services/dossiers.service';
import { tap } from 'rxjs/operators';
@Component({ @Component({
templateUrl: './trash-screen.component.html', templateUrl: './trash-screen.component.html',
@ -21,9 +20,7 @@ import { tap } from 'rxjs/operators';
}) })
export class TrashScreenComponent extends BaseListingComponent<Dossier> implements OnInit { export class TrashScreenComponent extends BaseListingComponent<Dossier> implements OnInit {
readonly itemSize = 85; readonly itemSize = 85;
private readonly _deleteRetentionHours = this._appConfigService.getConfig( private readonly _deleteRetentionHours = this._appConfigService.getConfig(AppConfigKey.DELETE_RETENTION_HOURS);
AppConfigKey.DELETE_RETENTION_HOURS
);
constructor( constructor(
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,

View File

@ -10,10 +10,7 @@
<div class="content-container"> <div class="content-container">
<div class="header-item"> <div class="header-item">
<span class="all-caps-label"> <span class="all-caps-label">
{{ {{ 'dossier-listing.table-header.title' | translate: { length: (displayedEntities$ | async)?.length || 0 } }}
'dossier-listing.table-header.title'
| translate: { length: (displayedEntities$ | async)?.length || 0 }
}}
</span> </span>
<redaction-quick-filters></redaction-quick-filters> <redaction-quick-filters></redaction-quick-filters>
@ -28,53 +25,33 @@
label="dossier-listing.table-col-names.name" label="dossier-listing.table-col-names.name"
></redaction-table-col-name> ></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name label="dossier-listing.table-col-names.needs-work"></redaction-table-col-name>
label="dossier-listing.table-col-names.needs-work"
></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name class="user-column" label="dossier-listing.table-col-names.owner"></redaction-table-col-name>
class="user-column"
label="dossier-listing.table-col-names.owner"
></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name class="flex-end" label="dossier-listing.table-col-names.status"></redaction-table-col-name>
class="flex-end"
label="dossier-listing.table-col-names.status"
></redaction-table-col-name>
<div class="scrollbar-placeholder"></div> <div class="scrollbar-placeholder"></div>
</div> </div>
<redaction-empty-state <redaction-empty-state
(action)="openAddDossierDialog()" (action)="openAddDossierDialog()"
*ngIf="(allEntities$ | async)?.length === 0" *ngIf="noData"
[showButton]="permissionsService.isManager()" [showButton]="permissionsService.isManager()"
icon="red:folder" icon="red:folder"
screen="dossier-listing" screen="dossier-listing"
></redaction-empty-state> ></redaction-empty-state>
<redaction-empty-state <redaction-empty-state *ngIf="noMatch" screen="dossier-listing" type="no-match"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length && (displayedEntities$ | async)?.length === 0"
screen="dossier-listing"
type="no-match"
></redaction-empty-state>
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
<div <div
*cdkVirtualFor=" *cdkVirtualFor="let dw of displayedEntities$ | async | sortBy: sortingOption.order:sortingOption.column"
let dw of displayedEntities$
| async
| sortBy: sortingOption.order:sortingOption.column
"
[class.pointer]="!!dw" [class.pointer]="!!dw"
[routerLink]="[!!dw ? '/main/dossiers/' + dw.dossier.dossierId : []]" [routerLink]="[!!dw ? '/main/dossiers/' + dw.dossier.dossierId : []]"
class="table-item" class="table-item"
> >
<div class="filename"> <div class="filename">
<div <div [matTooltip]="dw.dossierName" class="table-item-title heading" matTooltipPosition="above">
[matTooltip]="dw.dossierName"
class="table-item-title heading"
matTooltipPosition="above"
>
{{ dw.dossierName }} {{ dw.dossierName }}
</div> </div>
<div class="small-label stats-subtitle"> <div class="small-label stats-subtitle">
@ -107,15 +84,10 @@
</div> </div>
</div> </div>
<div> <div>
<redaction-needs-work-badge <redaction-needs-work-badge [needsWorkInput]="dw"></redaction-needs-work-badge>
[needsWorkInput]="dw"
></redaction-needs-work-badge>
</div> </div>
<div class="user-column"> <div class="user-column">
<redaction-initials-avatar <redaction-initials-avatar [userId]="dw.dossier.ownerId" [withName]="true"></redaction-initials-avatar>
[userId]="dw.dossier.ownerId"
[withName]="true"
></redaction-initials-avatar>
</div> </div>
<div class="status-container"> <div class="status-container">
<redaction-dossier-listing-actions <redaction-dossier-listing-actions
@ -127,10 +99,7 @@
</div> </div>
</cdk-virtual-scroll-viewport> </cdk-virtual-scroll-viewport>
<redaction-scroll-button <redaction-scroll-button [itemSize]="itemSize" [scrollViewport]="scrollViewport"></redaction-scroll-button>
[itemSize]="itemSize"
[scrollViewport]="scrollViewport"
></redaction-scroll-button>
</div> </div>
<div class="right-container" redactionHasScrollbar> <div class="right-container" redactionHasScrollbar>

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { Component, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { Dossier, DossierTemplateModel } from '@redaction/red-ui-http'; import { Dossier, DossierTemplateModel } from '@redaction/red-ui-http';
import { AppStateService } from '@state/app-state.service'; import { AppStateService } from '@state/app-state.service';
import { UserService } from '@services/user.service'; import { UserService } from '@services/user.service';
@ -76,6 +76,18 @@ export class DossierListingScreenComponent extends BaseListingComponent<DossierW
this._loadEntitiesFromState(); this._loadEntitiesFromState();
} }
private get _user() {
return this._userService.user;
}
private get _activeDossiersCount(): number {
return this._screenStateService.entities.filter(p => p.dossier.status === Dossier.StatusEnum.ACTIVE).length;
}
private get _inactiveDossiersCount(): number {
return this._screenStateService.entities.length - this._activeDossiersCount;
}
ngOnInit(): void { ngOnInit(): void {
this.calculateData(); this.calculateData();
@ -135,22 +147,6 @@ export class DossierListingScreenComponent extends BaseListingComponent<DossierW
}); });
} }
private _loadEntitiesFromState() {
this._screenStateService.setEntities(this._appStateService.allDossiers);
}
private get _user() {
return this._userService.user;
}
private get _activeDossiersCount(): number {
return this._screenStateService.entities.filter(p => p.dossier.status === Dossier.StatusEnum.ACTIVE).length;
}
private get _inactiveDossiersCount(): number {
return this._screenStateService.entities.length - this._activeDossiersCount;
}
calculateData() { calculateData() {
this._computeAllFilters(); this._computeAllFilters();
@ -173,6 +169,10 @@ export class DossierListingScreenComponent extends BaseListingComponent<DossierW
this.documentsChartData = this._translateChartService.translateStatus(this.documentsChartData); this.documentsChartData = this._translateChartService.translateStatus(this.documentsChartData);
} }
private _loadEntitiesFromState() {
this._screenStateService.setEntities(this._appStateService.allDossiers);
}
private _computeAllFilters() { private _computeAllFilters() {
const allDistinctFileStatus = new Set<string>(); const allDistinctFileStatus = new Set<string>();
const allDistinctPeople = new Set<string>(); const allDistinctPeople = new Set<string>();

View File

@ -1,8 +1,8 @@
<section *ngIf="!!activeDossier"> <section *ngIf="!!activeDossier">
<redaction-page-header <redaction-page-header
[actionConfigs]="actionConfigs" [actionConfigs]="actionConfigs"
[showCloseButton]="true"
[searchPlaceholder]="'dossier-overview.search' | translate" [searchPlaceholder]="'dossier-overview.search' | translate"
[showCloseButton]="true"
> >
<redaction-file-download-btn <redaction-file-download-btn
[disabled]="areSomeEntitiesSelected$ | async" [disabled]="areSomeEntitiesSelected$ | async"
@ -24,9 +24,9 @@
<redaction-circle-button <redaction-circle-button
(action)="fileInput.click()" (action)="fileInput.click()"
[tooltip]="'dossier-overview.header-actions.upload-document' | translate"
class="ml-14" class="ml-14"
icon="red:upload" icon="red:upload"
[tooltip]="'dossier-overview.header-actions.upload-document' | translate"
tooltipPosition="below" tooltipPosition="below"
type="primary" type="primary"
></redaction-circle-button> ></redaction-circle-button>
@ -41,17 +41,12 @@
<redaction-round-checkbox <redaction-round-checkbox
(click)="toggleSelectAll()" (click)="toggleSelectAll()"
[active]="areAllEntitiesSelected" [active]="areAllEntitiesSelected"
[indeterminate]=" [indeterminate]="(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected"
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox> ></redaction-round-checkbox>
</div> </div>
<span class="all-caps-label"> <span class="all-caps-label">
{{ {{ 'dossier-overview.table-header.title' | translate: { length: (displayedEntities$ | async)?.length || 0 } }}
'dossier-overview.table-header.title'
| translate: { length: (displayedEntities$ | async)?.length || 0 }
}}
</span> </span>
<redaction-dossier-overview-bulk-actions <redaction-dossier-overview-bulk-actions
@ -62,11 +57,7 @@
<redaction-quick-filters></redaction-quick-filters> <redaction-quick-filters></redaction-quick-filters>
</div> </div>
<div <div [class.no-data]="noData" class="table-header" redactionSyncWidth="table-item">
[class.no-data]="(allEntities$ | async).length === 0"
class="table-header"
redactionSyncWidth="table-item"
>
<!-- Table column names--> <!-- Table column names-->
<div class="select-oval-placeholder"></div> <div class="select-oval-placeholder"></div>
@ -86,9 +77,7 @@
label="dossier-overview.table-col-names.added-on" label="dossier-overview.table-col-names.added-on"
></redaction-table-col-name> ></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name label="dossier-overview.table-col-names.needs-work"></redaction-table-col-name>
label="dossier-overview.table-col-names.needs-work"
></redaction-table-col-name>
<redaction-table-col-name <redaction-table-col-name
(toggleSort)="toggleSort($event)" (toggleSort)="toggleSort($event)"
@ -120,24 +109,18 @@
<redaction-empty-state <redaction-empty-state
(action)="fileInput.click()" (action)="fileInput.click()"
*ngIf="(allEntities$ | async)?.length === 0" *ngIf="noData"
buttonIcon="red:upload" buttonIcon="red:upload"
icon="red:document" icon="red:document"
screen="dossier-overview" screen="dossier-overview"
></redaction-empty-state> ></redaction-empty-state>
<redaction-empty-state <redaction-empty-state *ngIf="noMatch" screen="dossier-overview" type="no-match"></redaction-empty-state>
*ngIf="(allEntities$ | async)?.length && (displayedEntities$ | async).length === 0"
screen="dossier-overview"
type="no-match"
></redaction-empty-state>
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
<div <div
*cdkVirtualFor=" *cdkVirtualFor="
let fileStatus of displayedEntities$ let fileStatus of displayedEntities$ | async | sortBy: sortingOption.order:sortingOption.column;
| async
| sortBy: sortingOption.order:sortingOption.column;
trackBy: trackByFileId trackBy: trackByFileId
" "
[class.disabled]="fileStatus.isExcluded" [class.disabled]="fileStatus.isExcluded"
@ -146,13 +129,8 @@
[routerLink]="fileLink(fileStatus)" [routerLink]="fileLink(fileStatus)"
class="table-item" class="table-item"
> >
<div <div (click)="toggleEntitySelected($event, fileStatus)" class="selection-column">
(click)="toggleEntitySelected($event, fileStatus)" <redaction-round-checkbox [active]="isSelected(fileStatus)"></redaction-round-checkbox>
class="selection-column"
>
<redaction-round-checkbox
[active]="isSelected(fileStatus)"
></redaction-round-checkbox>
</div> </div>
<div> <div>
@ -169,19 +147,13 @@
</div> </div>
<div *ngIf="fileStatus.primaryAttribute" class="small-label stats-subtitle"> <div *ngIf="fileStatus.primaryAttribute" class="small-label stats-subtitle">
<div class="primary-attribute text-overflow"> <div class="primary-attribute text-overflow">
<span <span [matTooltip]="fileStatus.primaryAttribute" matTooltipPosition="above">
[matTooltip]="fileStatus.primaryAttribute"
matTooltipPosition="above"
>
{{ fileStatus.primaryAttribute }} {{ fileStatus.primaryAttribute }}
</span> </span>
</div> </div>
</div> </div>
<div *ngIf="fileStatus.ocrTime" class="small-label stats-subtitle"> <div *ngIf="fileStatus.ocrTime" class="small-label stats-subtitle">
<div <div [matTooltipPosition]="'above'" [matTooltip]="'dossier-overview.ocr-performed' | translate">
[matTooltipPosition]="'above'"
[matTooltip]="'dossier-overview.ocr-performed' | translate"
>
<mat-icon svgIcon="red:ocr"></mat-icon> <mat-icon svgIcon="red:ocr"></mat-icon>
{{ fileStatus.ocrTime | date: 'mediumDate' }} {{ fileStatus.ocrTime | date: 'mediumDate' }}
</div> </div>
@ -196,23 +168,14 @@
<!-- always show A for error--> <!-- always show A for error-->
<div *ngIf="fileStatus.isError"> <div *ngIf="fileStatus.isError">
<redaction-annotation-icon <redaction-annotation-icon color="#dd4d50" label="A" type="square"></redaction-annotation-icon>
color="#dd4d50"
label="A"
type="square"
></redaction-annotation-icon>
</div> </div>
<div *ngIf="!fileStatus.isError"> <div *ngIf="!fileStatus.isError">
<redaction-needs-work-badge <redaction-needs-work-badge [needsWorkInput]="fileStatus"></redaction-needs-work-badge>
[needsWorkInput]="fileStatus"
></redaction-needs-work-badge>
</div> </div>
<div *ngIf="!fileStatus.isError" class="user-column"> <div *ngIf="!fileStatus.isError" class="user-column">
<redaction-initials-avatar <redaction-initials-avatar [userId]="fileStatus.currentReviewer" [withName]="true"></redaction-initials-avatar>
[userId]="fileStatus.currentReviewer"
[withName]="true"
></redaction-initials-avatar>
</div> </div>
<div *ngIf="!fileStatus.isError"> <div *ngIf="!fileStatus.isError">
@ -259,10 +222,7 @@
</div> </div>
</cdk-virtual-scroll-viewport> </cdk-virtual-scroll-viewport>
<redaction-scroll-button <redaction-scroll-button [itemSize]="itemSize" [scrollViewport]="scrollViewport"></redaction-scroll-button>
[itemSize]="itemSize"
[scrollViewport]="scrollViewport"
></redaction-scroll-button>
</div> </div>
<div [class.collapsed]="collapsedDetails" class="right-container" redactionHasScrollbar> <div [class.collapsed]="collapsedDetails" class="right-container" redactionHasScrollbar>
@ -279,10 +239,4 @@
<redaction-type-filter [filter]="filter"></redaction-type-filter> <redaction-type-filter [filter]="filter"></redaction-type-filter>
</ng-template> </ng-template>
<input <input #fileInput (change)="uploadFiles($event.target['files'])" class="file-upload-input" multiple="true" type="file" />
#fileInput
(change)="uploadFiles($event.target['files'])"
class="file-upload-input"
multiple="true"
type="file"
/>

View File

@ -36,6 +36,10 @@ export abstract class BaseListingComponent<T> {
return this._screenStateService.entities$; return this._screenStateService.entities$;
} }
get displayedEntities(): T[] {
return this._screenStateService.displayedEntities;
}
get allEntities(): T[] { get allEntities(): T[] {
return this._screenStateService.entities; return this._screenStateService.entities;
} }
@ -52,14 +56,22 @@ export abstract class BaseListingComponent<T> {
return this._sortingService.getSortingOption(); return this._sortingService.getSortingOption();
} }
getFilter$(slug: string): Observable<FilterModel[]> {
return this.filterService.getFilter$(slug);
}
get searchForm() { get searchForm() {
return this._searchService.searchForm; return this._searchService.searchForm;
} }
get noMatch(): boolean {
return this.allEntities.length && this.displayedEntities?.length === 0;
}
get noData(): boolean {
return this.allEntities.length === 0;
}
getFilter$(slug: string): Observable<FilterModel[]> {
return this.filterService.getFilter$(slug);
}
resetFilters() { resetFilters() {
this.filterService.reset(); this.filterService.reset();
} }

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Output } from '@angular/core';
import { FilterModel } from '../popup-filter/model/filter.model'; import { FilterModel } from '../popup-filter/model/filter.model';
import { FilterService } from '@shared/services/filter.service'; import { FilterService } from '@shared/services/filter.service';