trash screen fixes + update other listing screens

This commit is contained in:
Dan Percic 2021-07-14 13:53:16 +03:00
parent e1bfef2562
commit 421d9d734a
11 changed files with 97 additions and 76 deletions

View File

@ -23,18 +23,20 @@
<redaction-round-checkbox
(click)="toggleSelectAll()"
[active]="areAllEntitiesSelected"
[indeterminate]="areSomeEntitiesSelected && !areAllEntitiesSelected"
[indeterminate]="
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox>
</div>
<span class="all-caps-label">
{{
'dossier-templates-listing.table-header.title'
| translate: { length: displayedEntities.length }
| translate: { length: (displayedEntities$ | async).length }
}}
</span>
<ng-container *ngIf="areSomeEntitiesSelected">
<ng-container *ngIf="areSomeEntitiesSelected$ | async">
<redaction-circle-button
(action)="openDeleteTemplatesDialog($event)"
*ngIf="permissionsService.isAdmin()"
@ -65,7 +67,7 @@
</div>
<div
[class.no-data]="!allEntities.length"
[class.no-data]="(allEntities$ | async)?.length === 0"
class="table-header"
redactionSyncWidth="table-item"
>
@ -100,13 +102,15 @@
</div>
<redaction-empty-state
*ngIf="!allEntities.length"
*ngIf="(allEntities$ | async)?.length === 0"
icon="red:template"
screen="dossier-templates-listing"
></redaction-empty-state>
<redaction-empty-state
*ngIf="allEntities.length && !displayedEntities.length"
*ngIf="
(allEntities$ | async)?.length && (displayedEntities$ | async).length === 0
"
screen="dossier-templates-listing"
type="no-match"
></redaction-empty-state>
@ -114,7 +118,8 @@
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
<div
*cdkVirtualFor="
let dossierTemplate of displayedEntities
let dossierTemplate of displayedEntities$
| async
| sortBy: sortingOption.order:sortingOption.column
"
[routerLink]="[dossierTemplate.dossierTemplateId, 'dictionaries']"

View File

@ -1,9 +1,8 @@
import { Component, Injector, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { AdminDialogService } from '../../services/admin-dialog.service';
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { DossierTemplateModelWrapper } from '../../../../models/file/dossier-template-model.wrapper';
import { LoadingService } from '../../../../services/loading.service';
import { DossierTemplateControllerService } from '@redaction/red-ui-http';
@ -11,19 +10,18 @@ import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
import { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
@Component({
templateUrl: './dossier-templates-listing-screen.component.html',
styleUrls: ['./dossier-templates-listing-screen.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class DossierTemplatesListingScreenComponent
extends BaseListingComponent<DossierTemplateModelWrapper>
extends NewBaseListingComponent<DossierTemplateModelWrapper>
implements OnInit
{
protected readonly _searchKey = 'name';
protected readonly _selectionKey = 'dossierTemplateId';
constructor(
private readonly _dialogService: AdminDialogService,
private readonly _appStateService: AppStateService,
@ -35,6 +33,8 @@ export class DossierTemplatesListingScreenComponent
) {
super(_injector);
this._sortingService.setScreenName(ScreenNames.DOSSIER_TEMPLATES_LISTING);
this._searchService.setSearchKey('name');
this._screenStateService.setIdKey('dossierTemplateId');
}
ngOnInit(): void {
@ -45,9 +45,9 @@ export class DossierTemplatesListingScreenComponent
return this._dialogService.openDialog('confirm', $event, null, async () => {
this._loadingService.start();
await this._dossierTemplateControllerService
.deleteDossierTemplates(this.selectedEntitiesIds)
.deleteDossierTemplates(this._screenStateService.selectedEntitiesIds)
.toPromise();
this.selectedEntitiesIds = [];
this._screenStateService.setSelectedEntitiesIds([]);
await this._appStateService.loadAllDossierTemplates();
await this._appStateService.loadDictionaryData();
this.loadDossierTemplatesData();
@ -57,8 +57,8 @@ export class DossierTemplatesListingScreenComponent
loadDossierTemplatesData() {
this._loadingService.start();
this._appStateService.reset();
this.allEntities = this._appStateService.dossierTemplates;
this._executeSearchImmediately();
this._screenStateService.setEntities(this._appStateService.dossierTemplates);
this.filterService.filterEntities();
this._loadDossierTemplateStats();
this._loadingService.stop();
}
@ -77,7 +77,7 @@ export class DossierTemplatesListingScreenComponent
}
private _loadDossierTemplateStats() {
this.allEntities.forEach(rs => {
this._screenStateService.entities.forEach(rs => {
const dictionaries = this._appStateService.dictionaryData[rs.dossierTemplateId];
if (dictionaries) {
rs.dictionariesCount = Object.keys(dictionaries)

View File

@ -13,7 +13,9 @@
<redaction-round-checkbox
(click)="toggleSelectAll()"
[active]="areAllEntitiesSelected"
[indeterminate]="areSomeEntitiesSelected && !areAllEntitiesSelected"
[indeterminate]="
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox>
</div>
@ -24,9 +26,17 @@
}}
</span>
<redaction-circle-button
(action)="bulkRestore()"
*ngIf="areSomeEntitiesSelected$ | async"
icon="red:undo"
[tooltip]="'trash.bulk.restore' | translate"
type="dark-bg"
></redaction-circle-button>
<redaction-circle-button
(action)="bulkDelete()"
*ngIf="areSomeEntitiesSelected"
*ngIf="areSomeEntitiesSelected$ | async"
icon="red:trash"
[tooltip]="'trash.bulk.delete' | translate"
type="dark-bg"
@ -143,14 +153,14 @@
</div>
<div class="action-buttons">
<redaction-circle-button
(action)="restore(entity.dossierId)"
(action)="bulkRestore([entity.dossierId])"
icon="red:undo"
[tooltip]="'trash.action.restore' | translate"
type="dark-bg"
></redaction-circle-button>
<redaction-circle-button
(action)="hardDelete(entity.dossierId)"
(action)="bulkDelete([entity.dossierId])"
icon="red:trash"
[tooltip]="'trash.action.delete' | translate"
type="dark-bg"

View File

@ -58,40 +58,32 @@ export class TrashScreenComponent extends NewBaseListingComponent<Dossier> imple
return moment(softDeletedTime).add(this._deleteRetentionHours, 'hours').toISOString();
}
restore(dossierId: string): void {
this._loadingService.loadWhile(this._restore(dossierId));
}
hardDelete(dossierId: string): void {
this._loadingService.loadWhile(this._hardDelete(dossierId));
}
async bulkDelete() {
this._loadingService.start();
const dossierIds = this._screenStateService.selectedEntitiesIds;
for (const dossierId of dossierIds) await this._hardDelete(dossierId);
this._loadingService.stop();
}
trackById(index: number, dossier: Dossier): string {
return dossier.dossierId;
}
private async _restore(dossierId: string): Promise<void> {
await this._dossiersService.restore(dossierId);
this._removeFromList(dossierId);
bulkDelete(dossierIds = this._screenStateService.selectedEntitiesIds) {
this._loadingService.loadWhile(this._hardDelete(dossierIds));
}
private async _hardDelete(dossierId: string): Promise<void> {
await this._dossiersService.hardDelete(dossierId);
this._removeFromList(dossierId);
bulkRestore(dossierIds = this._screenStateService.selectedEntitiesIds) {
this._loadingService.loadWhile(this._restore(dossierIds));
}
private _removeFromList(dossierId: string): void {
const entities = this._screenStateService.entities.filter(e => e.dossierId !== dossierId);
private async _restore(dossierIds: string[]): Promise<void> {
await this._dossiersService.restore(dossierIds);
this._removeFromList(dossierIds);
}
private async _hardDelete(dossierIds: string[]): Promise<void> {
await this._dossiersService.hardDelete(dossierIds);
this._removeFromList(dossierIds);
}
private _removeFromList(ids: string[]): void {
const entities = this._screenStateService.entities.filter(e => !ids.includes(e.dossierId));
this._screenStateService.setEntities(entities);
this._screenStateService.setSelectedEntitiesIds([]);
this.filterService.filterEntities();
}
}

View File

@ -38,20 +38,22 @@
<redaction-round-checkbox
(click)="toggleSelectAll()"
[active]="areAllEntitiesSelected"
[indeterminate]="areSomeEntitiesSelected && !areAllEntitiesSelected"
[indeterminate]="
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox>
</div>
<span class="all-caps-label">
{{
'user-listing.table-header.title'
| translate: { length: displayedEntities.length }
| translate: { length: (displayedEntities$ | async)?.length }
}}
</span>
<redaction-circle-button
(action)="bulkDelete()"
*ngIf="areSomeEntitiesSelected"
*ngIf="areSomeEntitiesSelected$ | async"
[disabled]="!canDeleteSelected"
[tooltip]="
canDeleteSelected
@ -89,7 +91,7 @@
</div>
<redaction-empty-state
*ngIf="!displayedEntities.length"
*ngIf="(displayedEntities$ | async)?.length === 0"
screen="user-listing"
type="no-match"
></redaction-empty-state>
@ -97,7 +99,7 @@
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
<!-- Table lines -->
<div
*cdkVirtualFor="let user of displayedEntities; trackBy: trackById"
*cdkVirtualFor="let user of displayedEntities$ | async; trackBy: trackById"
class="table-item"
>
<div (click)="toggleEntitySelected($event, user)" class="selection-column">

View File

@ -6,23 +6,22 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
import { TranslateService } from '@ngx-translate/core';
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
import { TranslateChartService } from '@services/translate-chart.service';
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { LoadingService } from '../../../../services/loading.service';
import { InitialsAvatarComponent } from '../../../shared/components/initials-avatar/initials-avatar.component';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
import { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
@Component({
templateUrl: './user-listing-screen.component.html',
styleUrls: ['./user-listing-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class UserListingScreenComponent extends BaseListingComponent<User> implements OnInit {
export class UserListingScreenComponent extends NewBaseListingComponent<User> implements OnInit {
collapsedDetails = false;
chartData: DoughnutChartConfig[] = [];
protected readonly _selectionKey = 'userId';
@ViewChildren(InitialsAvatarComponent)
private readonly _avatars: QueryList<InitialsAvatarComponent>;
@ -37,10 +36,11 @@ export class UserListingScreenComponent extends BaseListingComponent<User> imple
protected readonly _injector: Injector
) {
super(_injector);
this._screenStateService.setIdKey('userId');
}
get canDeleteSelected(): boolean {
return this.selectedEntitiesIds.indexOf(this.userService.userId) === -1;
return this._screenStateService.selectedEntitiesIds.indexOf(this.userService.userId) === -1;
}
async ngOnInit() {
@ -79,7 +79,9 @@ export class UserListingScreenComponent extends BaseListingComponent<User> imple
}
async bulkDelete() {
this.openDeleteUsersDialog(this.allEntities.filter(u => this.isSelected(u)));
this.openDeleteUsersDialog(
this._screenStateService.entities.filter(u => this.isSelected(u))
);
}
trackById(index: number, user: User) {
@ -91,9 +93,11 @@ export class UserListingScreenComponent extends BaseListingComponent<User> imple
}
private async _loadData() {
this.allEntities = await this._userControllerService.getAllUsers().toPromise();
this._screenStateService.setEntities(
await this._userControllerService.getAllUsers().toPromise()
);
await this.userService.loadAllUsers();
this._executeSearchImmediately();
this.filterService.filterEntities();
this._computeStats();
this._loadingService.stop();
}

View File

@ -5,7 +5,7 @@
[searchPlaceholder]="'dossier-overview.search' | translate"
>
<redaction-file-download-btn
[disabled]="areSomeEntitiesSelected"
[disabled]="areSomeEntitiesSelected$ | async"
[dossier]="activeDossier"
[file]="allEntities$ | async"
tooltipPosition="below"
@ -14,8 +14,8 @@
<redaction-circle-button
(action)="reanalyseDossier()"
*ngIf="permissionsService.displayReanalyseBtn()"
[disabled]="areSomeEntitiesSelected"
[tooltipClass]="'small ' + (areSomeEntitiesSelected ? '' : 'warn')"
[disabled]="areSomeEntitiesSelected$ | async"
[tooltipClass]="'small ' + ((areSomeEntitiesSelected$ | async) ? '' : 'warn')"
[tooltip]="'dossier-overview.new-rule.toast.actions.reanalyse-all' | translate"
icon="red:refresh"
tooltipPosition="below"
@ -41,7 +41,9 @@
<redaction-round-checkbox
(click)="toggleSelectAll()"
[active]="areAllEntitiesSelected"
[indeterminate]="areSomeEntitiesSelected && !areAllEntitiesSelected"
[indeterminate]="
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
"
></redaction-round-checkbox>
</div>

View File

@ -9,13 +9,11 @@ export class DossiersService {
return this._dossierControllerService.getDeletedDossiers().toPromise();
}
restore(dossierIds: string | Array<string>): Promise<unknown> {
if (typeof dossierIds === 'string') dossierIds = [dossierIds];
restore(dossierIds: Array<string>): Promise<unknown> {
return this._dossierControllerService.restoreDossiers(dossierIds).toPromise();
}
hardDelete(dossierIds: string | Array<string>): Promise<unknown> {
if (typeof dossierIds === 'string') dossierIds = [dossierIds];
hardDelete(dossierIds: Array<string>): Promise<unknown> {
return this._dossierControllerService.hardDeleteDossiers(dossierIds).toPromise();
}
}

View File

@ -37,12 +37,16 @@ export abstract class NewBaseListingComponent<T> {
return this._screenStateService.entities$;
}
get allEntities(): T[] {
return this._screenStateService.entities;
}
get areAllEntitiesSelected() {
return this._screenStateService.areAllEntitiesSelected;
}
get areSomeEntitiesSelected() {
return this._screenStateService.areSomeEntitiesSelected;
get areSomeEntitiesSelected$() {
return this._screenStateService.areSomeEntitiesSelected$;
}
get sortingOption(): SortingOption {
@ -53,8 +57,8 @@ export abstract class NewBaseListingComponent<T> {
return this.filterService.getFilter$(slug);
}
protected get _filters(): FilterWrapper[] {
return [];
get searchForm() {
return this._searchService.searchForm;
}
resetFilters() {

View File

@ -68,11 +68,14 @@ export class FilterService<T> {
}
getFilter$(slug: string): Observable<FilterModel[]> {
return this.getFilterWrapper$(slug).pipe(map(f => f.values));
return this.getFilterWrapper$(slug).pipe(
filter(f => f !== null && f !== undefined),
map(f => f?.values)
);
}
getFilterWrapper$(slug: string): Observable<FilterWrapper> {
return this.allFilters$.pipe(map(all => all.find(f => f.slug === slug)));
return this.allFilters$.pipe(map(all => all.find(f => f?.slug === slug)));
}
get allFilters$(): Observable<FilterWrapper[]> {
@ -90,6 +93,7 @@ export class FilterService<T> {
});
});
});
this._allFilters$.next(this.filters);
this.filterEntities();
}

View File

@ -61,8 +61,8 @@ export class ScreenStateService<T> {
);
}
get areSomeEntitiesSelected(): boolean {
return this.selectedEntitiesIds.length > 0;
get areSomeEntitiesSelected$(): Observable<boolean> {
return this.selectedEntitiesIds$.pipe(map(all => all.length > 0));
}
isSelected(entity: T): boolean {
@ -81,7 +81,7 @@ export class ScreenStateService<T> {
}
toggleSelectAll(): void {
if (this.areSomeEntitiesSelected) return this.selectedEntitiesIds$.next([]);
if (this.areSomeEntitiesSelected$) return this.selectedEntitiesIds$.next([]);
this.setSelectedEntitiesIds(this._displayedEntitiesIds);
}