add route reuse for projects listing and project overview
This commit is contained in:
parent
81e0498e48
commit
8767c051b4
@ -30,7 +30,7 @@ import { AppRoutingModule } from './app-routing.module';
|
||||
import { SharedModule } from './modules/shared/shared.module';
|
||||
import { FileUploadDownloadModule } from './modules/upload-download/file-upload-download.module';
|
||||
import { UserProfileScreenComponent } from './components/user-profile/user-profile-screen.component';
|
||||
import { CustomRouteReuseStrategy } from './modules/projects/services/custom-route-reuse.strategy';
|
||||
import { CustomRouteReuseStrategy } from './utils/custom-route-reuse.strategy';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
|
||||
|
||||
@ -418,7 +418,7 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
public _loadDocument() {
|
||||
private _loadDocument() {
|
||||
if (this.fileData) {
|
||||
this.instance.loadDocument(this.fileData, {
|
||||
filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf'
|
||||
|
||||
@ -14,7 +14,8 @@ const routes = [
|
||||
component: ProjectListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
|
||||
reuse: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -22,7 +23,8 @@ const routes = [
|
||||
component: ProjectOverviewScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
|
||||
reuse: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -30,8 +32,8 @@ const routes = [
|
||||
component: FilePreviewScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
|
||||
reuse: true
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
// reuse: true
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<section *ngIf="activeFile" [class.fullscreen]="fullScreen">
|
||||
<section *ngIf="appStateService.activeFile" [class.fullscreen]="fullScreen">
|
||||
<div class="page-header">
|
||||
<div class="flex flex-1">
|
||||
<div
|
||||
|
||||
@ -89,10 +89,6 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
get activeFile() {
|
||||
return this.appStateService.activeFile;
|
||||
}
|
||||
|
||||
get annotations(): AnnotationWrapper[] {
|
||||
return this.annotationData ? this.annotationData.visibleAnnotations : [];
|
||||
}
|
||||
@ -191,15 +187,6 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this._router.events.subscribe((event: Event) => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
console.log(event);
|
||||
if (!event.url.includes('?page=') && event.url.includes('/ui/projects/') && event.url.includes('/file/')) {
|
||||
this._viewerComponent._loadDocument();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
||||
@ -16,13 +16,14 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { PermissionsService } from '../../../../services/permissions.service';
|
||||
import { ProjectWrapper } from '../../../../state/model/project.wrapper';
|
||||
import { Subscription, timer } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { filter, tap } from 'rxjs/operators';
|
||||
import { TranslateChartService } from '../../../../services/translate-chart.service';
|
||||
import { RedactionFilterSorter } from '../../../../utils/sorters/redaction-filter-sorter';
|
||||
import { StatusSorter } from '../../../../utils/sorters/status-sorter';
|
||||
import { Router } from '@angular/router';
|
||||
import { NavigationEnd, NavigationStart, Router } from '@angular/router';
|
||||
import { FilterComponent } from '../../../shared/components/filter/filter.component';
|
||||
import { ProjectsDialogService } from '../../services/projects-dialog.service';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
@ -51,6 +52,9 @@ export class ProjectListingScreenComponent extends BaseListingComponent<ProjectW
|
||||
};
|
||||
|
||||
private projectAutoUpdateTimer: Subscription;
|
||||
private _lastScrollPosition: number;
|
||||
|
||||
@ViewChild(CdkVirtualScrollViewport) private _scrollBar: CdkVirtualScrollViewport;
|
||||
|
||||
@ViewChild('statusFilter') private _statusFilterComponent: FilterComponent;
|
||||
@ViewChild('peopleFilter') private _peopleFilterComponent: FilterComponent;
|
||||
@ -60,12 +64,13 @@ export class ProjectListingScreenComponent extends BaseListingComponent<ProjectW
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
public readonly userService: UserService,
|
||||
public readonly sortingService: SortingService,
|
||||
public readonly translateChartService: TranslateChartService,
|
||||
public readonly permissionsService: PermissionsService,
|
||||
private readonly _dialogService: ProjectsDialogService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _router: Router,
|
||||
public readonly translateChartService: TranslateChartService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
@ -86,6 +91,15 @@ export class ProjectListingScreenComponent extends BaseListingComponent<ProjectW
|
||||
this._appStateService.fileChanged.subscribe(() => {
|
||||
this._calculateData();
|
||||
});
|
||||
|
||||
this._router.events.pipe(filter((events) => events instanceof NavigationStart || events instanceof NavigationEnd)).subscribe((event) => {
|
||||
if (event instanceof NavigationStart && event.url !== '/ui/projects') {
|
||||
this._lastScrollPosition = this._scrollBar.getOffsetToRenderedContentStart() + this._scrollBar.getRenderedRange().end;
|
||||
}
|
||||
if (event instanceof NavigationEnd && event.url === '/ui/projects') {
|
||||
this._scrollBar.scrollTo({ top: this._lastScrollPosition });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component, HostListener, Injector, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRoute, NavigationEnd, NavigationStart, Router } from '@angular/router';
|
||||
import { NotificationService, NotificationType } from '../../../../services/notification.service';
|
||||
import { AppStateService } from '../../../../state/app-state.service';
|
||||
import { FileDropOverlayService } from '../../../upload-download/services/file-drop-overlay.service';
|
||||
@ -15,15 +15,16 @@ import { FileStatusWrapper } from '../../../../models/file/file-status.wrapper';
|
||||
import { annotationFilterChecker, keyChecker, processFilters } from '../../../shared/components/filter/utils/filter-utils';
|
||||
import { PermissionsService } from '../../../../services/permissions.service';
|
||||
import { UserService } from '../../../../services/user.service';
|
||||
import { FileManagementControllerService, FileStatus } from '@redaction/red-ui-http';
|
||||
import { FileStatus } from '@redaction/red-ui-http';
|
||||
import { Subscription, timer } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { filter, tap } from 'rxjs/operators';
|
||||
import { RedactionFilterSorter } from '../../../../utils/sorters/redaction-filter-sorter';
|
||||
import { StatusSorter } from '../../../../utils/sorters/status-sorter';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { convertFiles, handleFileDrop } from '../../../../utils/file-drop-utils';
|
||||
import { FilterComponent } from '../../../shared/components/filter/filter.component';
|
||||
import { ProjectsDialogService } from '../../services/projects-dialog.service';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
import { ProjectWrapper } from '../../../../state/model/project.wrapper';
|
||||
|
||||
@ -50,7 +51,10 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent<FileSta
|
||||
|
||||
@ViewChild('projectDetailsComponent', { static: false })
|
||||
private _projectDetailsComponent: ProjectDetailsComponent;
|
||||
private filesAutoUpdateTimer: Subscription;
|
||||
private _filesAutoUpdateTimer: Subscription;
|
||||
private _lastScrollPosition: number;
|
||||
|
||||
@ViewChild(CdkVirtualScrollViewport) private _scrollBar: CdkVirtualScrollViewport;
|
||||
|
||||
@ViewChild('statusFilter') private _statusFilterComponent: FilterComponent;
|
||||
@ViewChild('peopleFilter') private _peopleFilterComponent: FilterComponent;
|
||||
@ -60,6 +64,7 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent<FileSta
|
||||
private readonly _appStateService: AppStateService,
|
||||
public readonly userService: UserService,
|
||||
public readonly permissionsService: PermissionsService,
|
||||
private readonly _sortingService: SortingService,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _dialogService: ProjectsDialogService,
|
||||
@ -69,7 +74,6 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent<FileSta
|
||||
private readonly _router: Router,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _fileDropOverlayService: FileDropOverlayService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
@ -85,7 +89,7 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent<FileSta
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.filesAutoUpdateTimer = timer(0, 7500)
|
||||
this._filesAutoUpdateTimer = timer(0, 7500)
|
||||
.pipe(
|
||||
tap(async () => {
|
||||
await this._appStateService.reloadActiveProjectFilesIfNecessary();
|
||||
@ -95,11 +99,21 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent<FileSta
|
||||
.subscribe();
|
||||
this._fileDropOverlayService.initFileDropHandling();
|
||||
this.calculateData();
|
||||
|
||||
this._router.events.pipe(filter((events) => events instanceof NavigationStart || events instanceof NavigationEnd)).subscribe((event) => {
|
||||
if (event instanceof NavigationStart && !event.url.endsWith(this.appStateService.activeProjectId)) {
|
||||
this._lastScrollPosition = this._scrollBar.getOffsetToRenderedContentStart() + this._scrollBar.getRenderedRange().end;
|
||||
}
|
||||
|
||||
if (event instanceof NavigationEnd && event.url.endsWith(this.appStateService.activeProjectId)) {
|
||||
this._scrollBar.scrollTo({ top: this._lastScrollPosition });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._fileDropOverlayService.cleanupFileDropHandling();
|
||||
this.filesAutoUpdateTimer.unsubscribe();
|
||||
this._filesAutoUpdateTimer.unsubscribe();
|
||||
}
|
||||
|
||||
public get activeProject(): ProjectWrapper {
|
||||
|
||||
@ -38,12 +38,16 @@ export class SyncWidthDirective implements AfterViewInit, OnDestroy {
|
||||
const hasExtraColumns = headerItems.length !== length ? 1 : 0;
|
||||
|
||||
for (let idx = 0; idx < length - hasExtraColumns - 1; ++idx) {
|
||||
headerItems[idx].style.width = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
headerItems[idx].style.minWidth = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
if (headerItems[idx]) {
|
||||
headerItems[idx].style.width = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
headerItems[idx].style.minWidth = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
}
|
||||
}
|
||||
|
||||
for (let idx = length - hasExtraColumns - 1; idx < headerItems.length; ++idx) {
|
||||
headerItems[idx].style.minWidth = `0`;
|
||||
if (headerItems[idx]) {
|
||||
headerItems[idx].style.minWidth = `0`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ import {
|
||||
} from '@redaction/red-ui-http';
|
||||
import { NotificationService, NotificationType } from '../services/notification.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ActivatedRoute, Event, ResolveStart, Router } from '@angular/router';
|
||||
import { Event, NavigationEnd, ResolveStart, Router } from '@angular/router';
|
||||
import { UserService } from '../services/user.service';
|
||||
import { forkJoin, Observable } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
@ -71,18 +71,33 @@ export class AppStateService {
|
||||
};
|
||||
|
||||
this._router.events.subscribe((event: Event) => {
|
||||
if (event instanceof ResolveStart) {
|
||||
console.log(event);
|
||||
if (event.url.includes('/ui/projects/') && event.url.includes('/file/')) {
|
||||
const url = event.url.replace('/ui/projects/', '').split('/');
|
||||
const projectId = url[0];
|
||||
const fileId = url[2];
|
||||
this.activateFile(projectId, fileId);
|
||||
}
|
||||
if (AppStateService._isFileOverviewRoute(event)) {
|
||||
const url = (event as ResolveStart).url.replace('/ui/projects/', '');
|
||||
const [projectId, , fileId] = url.split('/');
|
||||
this.activateFile(projectId, fileId);
|
||||
}
|
||||
if (AppStateService._isProjectOverviewRoute(event)) {
|
||||
const projectId = (event as ResolveStart).url.replace('/ui/projects/', '');
|
||||
this.activateProject(projectId);
|
||||
}
|
||||
if (AppStateService._isRandomRoute(event)) {
|
||||
this._appState.activeProjectId = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static _isFileOverviewRoute(event: Event) {
|
||||
return event instanceof ResolveStart && event.url.includes('/ui/projects/') && event.url.includes('/file/');
|
||||
}
|
||||
|
||||
private static _isProjectOverviewRoute(event: Event) {
|
||||
return event instanceof ResolveStart && event.url.includes('/ui/projects/') && !event.url.includes('/file/');
|
||||
}
|
||||
|
||||
private static _isRandomRoute(event: Event) {
|
||||
return event instanceof NavigationEnd && !event.url.includes('/ui/projects/') && !event.url.includes('/file/');
|
||||
}
|
||||
|
||||
async reloadActiveProjectFilesIfNecessary() {
|
||||
if (this.activeProject?.hasPendingOrProcessing) {
|
||||
await this.reloadActiveProjectFiles();
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
|
||||
|
||||
export class CustomRouteReuseStrategy implements RouteReuseStrategy {
|
||||
handlers: { [key: string]: DetachedRouteHandle } = {};
|
||||
private _handlers: { [key: string]: DetachedRouteHandle } = {};
|
||||
|
||||
shouldDetach(route: ActivatedRouteSnapshot): boolean {
|
||||
return route.routeConfig.path === ':projectId/file/:fileId';
|
||||
return !!route.routeConfig.data?.reuse;
|
||||
}
|
||||
|
||||
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
|
||||
if (handle === null) return;
|
||||
this.handlers[route.url.join('/')] = handle;
|
||||
this._handlers[route.toString()] = handle;
|
||||
}
|
||||
|
||||
shouldAttach(route: ActivatedRouteSnapshot): boolean {
|
||||
return !!this.handlers[route.url.join('/')];
|
||||
return !!this._handlers[route.toString()];
|
||||
}
|
||||
|
||||
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
|
||||
console.log(this.handlers[route.url.join('/')]);
|
||||
return this.handlers[route.url.join('/')] as DetachedRouteHandle;
|
||||
return this._handlers[route.toString()] as DetachedRouteHandle;
|
||||
}
|
||||
|
||||
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
|
||||
Loading…
x
Reference in New Issue
Block a user