show time to restore

This commit is contained in:
Dan Percic 2021-07-07 20:07:47 +03:00
parent 53d8406c23
commit 7990636066
6 changed files with 160 additions and 60 deletions

View File

@ -1,7 +1,10 @@
<section>
<div class="overlay-shadow"></div>
<redaction-page-header pageLabel="trash.label" [showCloseButton]="true"></redaction-page-header>
<redaction-page-header
[pageLabel]="'trash.label' | translate"
[showCloseButton]="true"
></redaction-page-header>
<div class="red-content-inner">
<div class="content-container">
@ -20,22 +23,20 @@
}}
</span>
<ng-container *ngIf="areSomeEntitiesSelected">
<redaction-circle-button
*ngIf="permissionsService.isAdmin()"
icon="red:trash"
tooltip="trash.bulk.delete"
type="dark-bg"
></redaction-circle-button>
</ng-container>
<redaction-circle-button
*ngIf="areSomeEntitiesSelected"
icon="red:trash"
[tooltip]="'trash.bulk.delete' | translate"
type="dark-bg"
></redaction-circle-button>
<div class="actions flex-1">
<redaction-input-with-action
[form]="searchForm"
[placeholder]="'trash.search'"
type="search"
></redaction-input-with-action>
</div>
<!-- <div class="actions flex-1">-->
<!-- <redaction-input-with-action-->
<!-- [form]="searchForm"-->
<!-- [placeholder]="'trash.search' | translate"-->
<!-- type="search"-->
<!-- ></redaction-input-with-action>-->
<!-- </div>-->
</div>
<div
@ -50,25 +51,25 @@
[activeSortingOption]="sortingOption"
[withSort]="true"
column="name"
label="trash.table-col-names.name"
[label]="'trash.table-col-names.name' | translate"
></redaction-table-col-name>
<redaction-table-col-name
class="user-column"
label="trash.table-col-names.owner"
[label]="'trash.table-col-names.owner' | translate"
></redaction-table-col-name>
<redaction-table-col-name
(toggleSort)="toggleSort($event)"
[activeSortingOption]="sortingOption"
[withSort]="true"
column="dateDeleted"
label="trash.table-col-names.deleted-on"
[label]="'trash.table-col-names.deleted-on' | translate"
></redaction-table-col-name>
<redaction-table-col-name
(toggleSort)="toggleSort($event)"
[activeSortingOption]="sortingOption"
[withSort]="true"
column="timeToRestore"
label="trash.table-col-names.time-to-restore"
[label]="'trash.table-col-names.time-to-restore' | translate"
></redaction-table-col-name>
<div class="scrollbar-placeholder"></div>
</div>
@ -88,82 +89,75 @@
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
<div
*cdkVirtualFor="
let dw of displayedEntities
| sortBy: sortingOption.order:sortingOption.column
let entity of displayedEntities
| sortBy: sortingOption.order:sortingOption.column;
trackBy: trackById
"
class="table-item"
>
<div (click)="toggleEntitySelected($event, dw)" class="selection-column">
<div (click)="toggleEntitySelected($event, entity)" class="selection-column">
<redaction-round-checkbox
[active]="isSelected(dw)"
[active]="isSelected(entity)"
></redaction-round-checkbox>
</div>
<div class="filename">
<div
class="table-item-title heading"
[matTooltip]="dw.dossierName"
[matTooltip]="entity.dossierName"
matTooltipPosition="above"
>
{{ dw.dossierName }}
{{ entity.dossierName }}
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:template"></mat-icon>
{{ getDossierTemplate(dw).name }}
{{ getDossierTemplate(entity.dossierTemplateId).name }}
</div>
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:document"></mat-icon>
{{ dw.files.length }}
</div>
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
{{ dw.totalNumberOfPages }}
</div>
<div>
<mat-icon svgIcon="red:user"></mat-icon>
{{ dw.numberOfMembers }}
{{ entity.memberIds.length }}
</div>
<div>
<mat-icon svgIcon="red:calendar"></mat-icon>
{{ dw.dossier.date | date: 'mediumDate' }}
{{ entity.date | date: 'mediumDate' }}
</div>
<div *ngIf="dw.dossier.dueDate">
<div *ngIf="entity.dueDate">
<mat-icon svgIcon="red:lightning"></mat-icon>
{{ dw.dossier.dueDate | date: 'mediumDate' }}
{{ entity.dueDate | date: 'mediumDate' }}
</div>
</div>
</div>
<div class="user-column">
<redaction-initials-avatar
[userId]="dw.dossier.ownerId"
[userId]="entity.ownerId"
[withName]="true"
></redaction-initials-avatar>
</div>
<div class="small-label">
{{ dw.dossierDate | date: 'd MMM. yyyy' }}
{{ entity.softDeletedTime | date: 'd MMM. yyyy' }}
</div>
<div>
<div class="small-label">
{{ dw.dossier.date | date: 'd MMM. yyyy' }}
{{ getRestoreDate(entity.softDeletedTime) | date: 'timeFromNow' }}
</div>
<div class="action-buttons">
<redaction-circle-button
*ngIf="permissionsService.isManager()"
(action)="restore(entity)"
icon="red:undo"
tooltip="trash.action.restore"
[tooltip]="'trash.action.restore' | translate"
type="dark-bg"
></redaction-circle-button>
<redaction-circle-button
*ngIf="permissionsService.isManager()"
(action)="hardDelete(entity)"
icon="red:trash"
tooltip="trash.action.delete"
[tooltip]="'trash.action.delete' | translate"
type="dark-bg"
></redaction-circle-button>
</div>

View File

@ -1,42 +1,74 @@
import { Component, Injector, OnInit } from '@angular/core';
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { AdminDialogService } from '../../services/admin-dialog.service';
import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { DossierWrapper } from '@state/model/dossier.wrapper';
import { DossierTemplateModel } from '@redaction/red-ui-http';
import { Dossier, DossierControllerService, DossierTemplateModel } from '@redaction/red-ui-http';
import { LoadingService } from '../../../../services/loading.service';
import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
import * as moment from 'moment';
import { TranslateService } from '@ngx-translate/core';
@Component({
templateUrl: './trash-screen.component.html',
styleUrls: ['./trash-screen.component.scss']
})
export class TrashScreenComponent extends BaseListingComponent<DossierWrapper> implements OnInit {
export class TrashScreenComponent extends BaseListingComponent<Dossier> implements OnInit {
readonly itemSize = 85;
private readonly _deleteRetentionHours = this._appConfigService.getConfig(
AppConfigKey.DELETE_RETENTION_HOURS
);
protected readonly _searchKey = 'name';
protected readonly _searchKey = 'dossierName';
protected readonly _selectionKey = 'dossierId';
protected readonly _sortKey = 'dossier-listing';
constructor(
private readonly _dialogService: AdminDialogService,
private readonly _appStateService: AppStateService,
readonly permissionsService: PermissionsService,
protected readonly _injector: Injector
protected readonly _injector: Injector,
private readonly _dossierControllerService: DossierControllerService,
private readonly _loadingService: LoadingService,
private readonly _appConfigService: AppConfigService,
private readonly _translateService: TranslateService
) {
super(_injector);
}
ngOnInit(): void {
this.loadDossierTemplatesData();
async ngOnInit(): Promise<void> {
this._loadingService.start();
await this.loadDossierTemplatesData();
this._loadingService.stop();
}
loadDossierTemplatesData() {
this.allEntities = this._appStateService.allDossiers;
async loadDossierTemplatesData(): Promise<void> {
this.allEntities = await this._dossierControllerService.getDeletedDossiers().toPromise();
console.log(this.allEntities);
this._executeSearchImmediately();
}
getDossierTemplate(dw: DossierWrapper): DossierTemplateModel {
return this._appStateService.getDossierTemplateById(dw.dossier.dossierTemplateId);
getDossierTemplate(dossierTemplateId: string): DossierTemplateModel {
return this._appStateService.getDossierTemplateById(dossierTemplateId);
}
getRestoreDate(softDeletedTime: string) {
return moment(softDeletedTime).add(5, 'hours').format();
}
async restore(dossier: Dossier) {
this._loadingService.start();
await this._dossierControllerService.restoreDossiers([dossier.dossierId]).toPromise();
this.allEntities = this.allEntities.filter(e => e !== dossier);
this._loadingService.stop();
}
async hardDelete(dossier: Dossier) {
this._loadingService.start();
await this._dossierControllerService.hardDeleteDossiers([dossier.dossierId]).toPromise();
this.allEntities = this.allEntities.filter(e => e !== dossier);
this._loadingService.stop();
}
trackById(index: number, dossier: Dossier) {
return dossier.dossierId;
}
}

View File

@ -0,0 +1,62 @@
import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe as BaseDatePipe } from '@angular/common';
const HOURS_IN_A_DAY = 24;
const MINUTES_IN_AN_HOUR = 60;
@Pipe({
name: 'date'
})
export class DatePipe extends BaseDatePipe implements PipeTransform {
constructor(
@Inject(LOCALE_ID) private readonly _locale: string,
private readonly _translateService: TranslateService
) {
super(_locale);
}
transform(value: null | undefined, format?: string, timezone?: string, locale?: string): null;
transform(
value: Date | string | number | null | undefined,
format?: string,
timezone?: string,
locale?: string
): string | null;
transform(value: any, format?: string, timezone?: string, locale?: string): string {
if (format === 'timeFromNow') return this._getTimeFromNow(value);
return super.transform(value, format, timezone, locale);
}
private _getTimeFromNow(item: string) {
const date = moment(item);
const now = new Date(Date.now());
const daysLeft = date.diff(now, 'days');
const hoursFromNow = date.diff(now, 'hours');
const hoursLeft = hoursFromNow - HOURS_IN_A_DAY * daysLeft;
const minutesFromNow = date.diff(now, 'minutes');
const minutesLeft = minutesFromNow - HOURS_IN_A_DAY * MINUTES_IN_AN_HOUR * daysLeft;
if (daysLeft === 0 && hoursLeft === 0 && minutesLeft > 0)
return this._translate('time.less-than-an-hour');
const hoursSuffix = this._translate(`time.hour${hoursLeft === 1 ? '' : 's'}`);
const hoursDisplay = `${hoursLeft} ${hoursSuffix}`;
if (daysLeft === 0 && hoursLeft > 0) return hoursDisplay;
const daysSuffix = this._translate(`time.day${daysLeft === 1 ? '' : 's'}`);
const daysDisplay = `${daysLeft} ${daysSuffix}`;
if (daysLeft > 0 && hoursLeft > 0) return `${daysDisplay} ${hoursDisplay}`;
if (daysLeft > 0) return daysDisplay;
return this._translate(`time.no-time-left`);
}
private _translate(value: string, params?: { [key: string]: string }) {
return this._translateService.instant(value, params);
}
}

View File

@ -38,6 +38,7 @@ import { PopupFilterComponent } from '@shared/components/filters/popup-filter/po
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';
const buttons = [
ChevronButtonComponent,
@ -75,6 +76,7 @@ const components = [
const utils = [
HumanizePipe,
DatePipe,
SyncWidthDirective,
HasScrollbarDirective,
NavigateLastDossiersScreenDirective

View File

@ -1404,5 +1404,13 @@
"text-placeholder": "Enter text"
},
"title": "Watermark"
},
"time": {
"no-time-left": "Time to restore already passed",
"less-than-an-hour": "< 1 hour",
"hour": "hour",
"hours": "hours",
"day": "day",
"days": "days"
}
}

View File

@ -19,10 +19,12 @@ export interface Dossier {
dossierTemplateId?: string;
downloadFileTypes?: Array<Dossier.DownloadFileTypesEnum>;
dueDate?: string;
hardDeletedTime?: string;
memberIds?: Array<string>;
ownerId?: string;
reportTemplateIds?: Array<string>;
reportTypes?: Array<Dossier.ReportTypesEnum>;
softDeletedTime?: string;
status?: Dossier.StatusEnum;
watermarkEnabled?: boolean;
}