show time to restore
This commit is contained in:
parent
53d8406c23
commit
7990636066
@ -1,7 +1,10 @@
|
|||||||
<section>
|
<section>
|
||||||
<div class="overlay-shadow"></div>
|
<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="red-content-inner">
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
@ -20,22 +23,20 @@
|
|||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ng-container *ngIf="areSomeEntitiesSelected">
|
<redaction-circle-button
|
||||||
<redaction-circle-button
|
*ngIf="areSomeEntitiesSelected"
|
||||||
*ngIf="permissionsService.isAdmin()"
|
icon="red:trash"
|
||||||
icon="red:trash"
|
[tooltip]="'trash.bulk.delete' | translate"
|
||||||
tooltip="trash.bulk.delete"
|
type="dark-bg"
|
||||||
type="dark-bg"
|
></redaction-circle-button>
|
||||||
></redaction-circle-button>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<div class="actions flex-1">
|
<!-- <div class="actions flex-1">-->
|
||||||
<redaction-input-with-action
|
<!-- <redaction-input-with-action-->
|
||||||
[form]="searchForm"
|
<!-- [form]="searchForm"-->
|
||||||
[placeholder]="'trash.search'"
|
<!-- [placeholder]="'trash.search' | translate"-->
|
||||||
type="search"
|
<!-- type="search"-->
|
||||||
></redaction-input-with-action>
|
<!-- ></redaction-input-with-action>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -50,25 +51,25 @@
|
|||||||
[activeSortingOption]="sortingOption"
|
[activeSortingOption]="sortingOption"
|
||||||
[withSort]="true"
|
[withSort]="true"
|
||||||
column="name"
|
column="name"
|
||||||
label="trash.table-col-names.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"
|
class="user-column"
|
||||||
label="trash.table-col-names.owner"
|
[label]="'trash.table-col-names.owner' | 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"
|
||||||
[withSort]="true"
|
[withSort]="true"
|
||||||
column="dateDeleted"
|
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>
|
||||||
<redaction-table-col-name
|
<redaction-table-col-name
|
||||||
(toggleSort)="toggleSort($event)"
|
(toggleSort)="toggleSort($event)"
|
||||||
[activeSortingOption]="sortingOption"
|
[activeSortingOption]="sortingOption"
|
||||||
[withSort]="true"
|
[withSort]="true"
|
||||||
column="timeToRestore"
|
column="timeToRestore"
|
||||||
label="trash.table-col-names.time-to-restore"
|
[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>
|
||||||
@ -88,82 +89,75 @@
|
|||||||
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
|
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
|
||||||
<div
|
<div
|
||||||
*cdkVirtualFor="
|
*cdkVirtualFor="
|
||||||
let dw of displayedEntities
|
let entity of displayedEntities
|
||||||
| sortBy: sortingOption.order:sortingOption.column
|
| sortBy: sortingOption.order:sortingOption.column;
|
||||||
|
trackBy: trackById
|
||||||
"
|
"
|
||||||
class="table-item"
|
class="table-item"
|
||||||
>
|
>
|
||||||
<div (click)="toggleEntitySelected($event, dw)" class="selection-column">
|
<div (click)="toggleEntitySelected($event, entity)" class="selection-column">
|
||||||
<redaction-round-checkbox
|
<redaction-round-checkbox
|
||||||
[active]="isSelected(dw)"
|
[active]="isSelected(entity)"
|
||||||
></redaction-round-checkbox>
|
></redaction-round-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filename">
|
<div class="filename">
|
||||||
<div
|
<div
|
||||||
class="table-item-title heading"
|
class="table-item-title heading"
|
||||||
[matTooltip]="dw.dossierName"
|
[matTooltip]="entity.dossierName"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
>
|
>
|
||||||
{{ dw.dossierName }}
|
{{ entity.dossierName }}
|
||||||
</div>
|
</div>
|
||||||
<div class="small-label stats-subtitle">
|
<div class="small-label stats-subtitle">
|
||||||
<div>
|
<div>
|
||||||
<mat-icon svgIcon="red:template"></mat-icon>
|
<mat-icon svgIcon="red:template"></mat-icon>
|
||||||
{{ getDossierTemplate(dw).name }}
|
{{ getDossierTemplate(entity.dossierTemplateId).name }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="small-label stats-subtitle">
|
<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>
|
<div>
|
||||||
<mat-icon svgIcon="red:user"></mat-icon>
|
<mat-icon svgIcon="red:user"></mat-icon>
|
||||||
{{ dw.numberOfMembers }}
|
{{ entity.memberIds.length }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||||
{{ dw.dossier.date | date: 'mediumDate' }}
|
{{ entity.date | date: 'mediumDate' }}
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="dw.dossier.dueDate">
|
<div *ngIf="entity.dueDate">
|
||||||
<mat-icon svgIcon="red:lightning"></mat-icon>
|
<mat-icon svgIcon="red:lightning"></mat-icon>
|
||||||
{{ dw.dossier.dueDate | date: 'mediumDate' }}
|
{{ entity.dueDate | date: 'mediumDate' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="user-column">
|
<div class="user-column">
|
||||||
<redaction-initials-avatar
|
<redaction-initials-avatar
|
||||||
[userId]="dw.dossier.ownerId"
|
[userId]="entity.ownerId"
|
||||||
[withName]="true"
|
[withName]="true"
|
||||||
></redaction-initials-avatar>
|
></redaction-initials-avatar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="small-label">
|
<div class="small-label">
|
||||||
{{ dw.dossierDate | date: 'd MMM. yyyy' }}
|
{{ entity.softDeletedTime | date: 'd MMM. yyyy' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="small-label">
|
<div class="small-label">
|
||||||
{{ dw.dossier.date | date: 'd MMM. yyyy' }}
|
{{ getRestoreDate(entity.softDeletedTime) | date: 'timeFromNow' }}
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<redaction-circle-button
|
<redaction-circle-button
|
||||||
*ngIf="permissionsService.isManager()"
|
(action)="restore(entity)"
|
||||||
icon="red:undo"
|
icon="red:undo"
|
||||||
tooltip="trash.action.restore"
|
[tooltip]="'trash.action.restore' | translate"
|
||||||
type="dark-bg"
|
type="dark-bg"
|
||||||
></redaction-circle-button>
|
></redaction-circle-button>
|
||||||
|
|
||||||
<redaction-circle-button
|
<redaction-circle-button
|
||||||
*ngIf="permissionsService.isManager()"
|
(action)="hardDelete(entity)"
|
||||||
icon="red:trash"
|
icon="red:trash"
|
||||||
tooltip="trash.action.delete"
|
[tooltip]="'trash.action.delete' | translate"
|
||||||
type="dark-bg"
|
type="dark-bg"
|
||||||
></redaction-circle-button>
|
></redaction-circle-button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,42 +1,74 @@
|
|||||||
import { Component, Injector, OnInit } from '@angular/core';
|
import { Component, Injector, OnInit } from '@angular/core';
|
||||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
|
||||||
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 { UserPreferenceService } from '@services/user-preference.service';
|
import { Dossier, DossierControllerService, DossierTemplateModel } from '@redaction/red-ui-http';
|
||||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
import { LoadingService } from '../../../../services/loading.service';
|
||||||
import { DossierTemplateModel } from '@redaction/red-ui-http';
|
import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './trash-screen.component.html',
|
templateUrl: './trash-screen.component.html',
|
||||||
styleUrls: ['./trash-screen.component.scss']
|
styleUrls: ['./trash-screen.component.scss']
|
||||||
})
|
})
|
||||||
export class TrashScreenComponent extends BaseListingComponent<DossierWrapper> implements OnInit {
|
export class TrashScreenComponent extends BaseListingComponent<Dossier> implements OnInit {
|
||||||
readonly itemSize = 85;
|
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 _selectionKey = 'dossierId';
|
||||||
protected readonly _sortKey = 'dossier-listing';
|
protected readonly _sortKey = 'dossier-listing';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _dialogService: AdminDialogService,
|
|
||||||
private readonly _appStateService: AppStateService,
|
private readonly _appStateService: AppStateService,
|
||||||
readonly permissionsService: PermissionsService,
|
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);
|
super(_injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
async ngOnInit(): Promise<void> {
|
||||||
this.loadDossierTemplatesData();
|
this._loadingService.start();
|
||||||
|
await this.loadDossierTemplatesData();
|
||||||
|
this._loadingService.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDossierTemplatesData() {
|
async loadDossierTemplatesData(): Promise<void> {
|
||||||
this.allEntities = this._appStateService.allDossiers;
|
this.allEntities = await this._dossierControllerService.getDeletedDossiers().toPromise();
|
||||||
|
console.log(this.allEntities);
|
||||||
this._executeSearchImmediately();
|
this._executeSearchImmediately();
|
||||||
}
|
}
|
||||||
|
|
||||||
getDossierTemplate(dw: DossierWrapper): DossierTemplateModel {
|
getDossierTemplate(dossierTemplateId: string): DossierTemplateModel {
|
||||||
return this._appStateService.getDossierTemplateById(dw.dossier.dossierTemplateId);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
apps/red-ui/src/app/modules/shared/pipes/date.pipe.ts
Normal file
62
apps/red-ui/src/app/modules/shared/pipes/date.pipe.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 { AssignUserDropdownComponent } from './components/assign-user-dropdown/assign-user-dropdown.component';
|
||||||
import { InputWithActionComponent } from '@shared/components/input-with-action/input-with-action.component';
|
import { InputWithActionComponent } from '@shared/components/input-with-action/input-with-action.component';
|
||||||
import { PageHeaderComponent } from './components/page-header/page-header.component';
|
import { PageHeaderComponent } from './components/page-header/page-header.component';
|
||||||
|
import { DatePipe } from '@shared/pipes/date.pipe';
|
||||||
|
|
||||||
const buttons = [
|
const buttons = [
|
||||||
ChevronButtonComponent,
|
ChevronButtonComponent,
|
||||||
@ -75,6 +76,7 @@ const components = [
|
|||||||
|
|
||||||
const utils = [
|
const utils = [
|
||||||
HumanizePipe,
|
HumanizePipe,
|
||||||
|
DatePipe,
|
||||||
SyncWidthDirective,
|
SyncWidthDirective,
|
||||||
HasScrollbarDirective,
|
HasScrollbarDirective,
|
||||||
NavigateLastDossiersScreenDirective
|
NavigateLastDossiersScreenDirective
|
||||||
|
|||||||
@ -1404,5 +1404,13 @@
|
|||||||
"text-placeholder": "Enter text"
|
"text-placeholder": "Enter text"
|
||||||
},
|
},
|
||||||
"title": "Watermark"
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,10 +19,12 @@ export interface Dossier {
|
|||||||
dossierTemplateId?: string;
|
dossierTemplateId?: string;
|
||||||
downloadFileTypes?: Array<Dossier.DownloadFileTypesEnum>;
|
downloadFileTypes?: Array<Dossier.DownloadFileTypesEnum>;
|
||||||
dueDate?: string;
|
dueDate?: string;
|
||||||
|
hardDeletedTime?: string;
|
||||||
memberIds?: Array<string>;
|
memberIds?: Array<string>;
|
||||||
ownerId?: string;
|
ownerId?: string;
|
||||||
reportTemplateIds?: Array<string>;
|
reportTemplateIds?: Array<string>;
|
||||||
reportTypes?: Array<Dossier.ReportTypesEnum>;
|
reportTypes?: Array<Dossier.ReportTypesEnum>;
|
||||||
|
softDeletedTime?: string;
|
||||||
status?: Dossier.StatusEnum;
|
status?: Dossier.StatusEnum;
|
||||||
watermarkEnabled?: boolean;
|
watermarkEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user