mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-24 17:31:52 +00:00
[ACS-8959] Introduce new takeUntilDestroyed
operator (#4237)
This commit is contained in:
committed by
GitHub
parent
dec6c41e5c
commit
adda597f15
@@ -32,20 +32,19 @@ import {
|
||||
} from '@alfresco/adf-content-services';
|
||||
import { ShowHeaderMode, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ContentActionRef, DocumentListPresetRef, SelectionState } from '@alfresco/adf-extensions';
|
||||
import { OnDestroy, OnInit, OnChanges, ViewChild, SimpleChanges, Directive, inject, HostListener } from '@angular/core';
|
||||
import { DestroyRef, Directive, HostListener, inject, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NodeEntry, Node, NodePaging } from '@alfresco/js-api';
|
||||
import { Observable, Subject, Subscription } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Node, NodeEntry, NodePaging } from '@alfresco/js-api';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { DocumentBasePageService } from './document-base-page.service';
|
||||
import {
|
||||
AppStore,
|
||||
getCurrentFolder,
|
||||
getAppSelection,
|
||||
getCurrentFolder,
|
||||
isInfoDrawerOpened,
|
||||
SetSelectedNodesAction,
|
||||
ViewNodeAction,
|
||||
ViewNodeExtras,
|
||||
SetSelectedNodesAction
|
||||
ViewNodeExtras
|
||||
} from '@alfresco/aca-shared/store';
|
||||
import { AppExtensionService } from '../../services/app.extension.service';
|
||||
import { isLibrary, isLocked } from '../../utils/node.utils';
|
||||
@@ -54,12 +53,11 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
||||
import { Router } from '@angular/router';
|
||||
import { AppSettingsService } from '../../services/app-settings.service';
|
||||
import { NavigationHistoryService } from '../../services/navigation-history.service';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
/* eslint-disable @angular-eslint/directive-class-suffix */
|
||||
@Directive()
|
||||
export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
||||
onDestroy$: Subject<void> = new Subject<void>();
|
||||
|
||||
@ViewChild(DocumentListComponent)
|
||||
documentList: DocumentListComponent;
|
||||
|
||||
@@ -90,6 +88,9 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
||||
protected router = inject(Router);
|
||||
protected userPreferencesService = inject(UserPreferencesService);
|
||||
protected searchAiService = inject(SearchAiService);
|
||||
|
||||
protected readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
private autoDownloadService = inject(AutoDownloadService, { optional: true });
|
||||
private navigationHistoryService = inject(NavigationHistoryService);
|
||||
|
||||
@@ -106,7 +107,7 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
||||
ngOnInit() {
|
||||
this.extensions
|
||||
.getCreateActions()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((actions) => {
|
||||
this.createActions = actions;
|
||||
});
|
||||
@@ -115,7 +116,7 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
||||
|
||||
this.store
|
||||
.select(getAppSelection)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((selection) => {
|
||||
this.selection = selection;
|
||||
this.canUpdateNode = this.selection.count === 1 && this.content.canUpdateNode(selection.first);
|
||||
@@ -123,41 +124,41 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
||||
|
||||
this.extensions
|
||||
.getAllowedToolbarActions()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((actions) => {
|
||||
this.actions = actions;
|
||||
});
|
||||
|
||||
this.extensions
|
||||
.getBulkActions()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((actions) => {
|
||||
this.bulkActions = actions;
|
||||
});
|
||||
|
||||
this.extensions
|
||||
.getViewerToolbarActions()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((actions) => {
|
||||
this.viewerToolbarActions = actions;
|
||||
});
|
||||
|
||||
this.store
|
||||
.select(getCurrentFolder)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((node) => {
|
||||
this.canUpload = node && this.content.canUploadContent(node);
|
||||
});
|
||||
|
||||
this.breakpointObserver
|
||||
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((result) => {
|
||||
this.isSmallScreen = result.matches;
|
||||
});
|
||||
|
||||
this.searchAiService.toggleSearchAiInput$
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((searchAiInputState) => (this._searchAiInputState = searchAiInputState));
|
||||
|
||||
this.setKnowledgeRetrievalState();
|
||||
@@ -173,8 +174,6 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
||||
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
|
||||
this.subscriptions = [];
|
||||
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
this.store.dispatch(new SetSelectedNodesAction([]));
|
||||
}
|
||||
|
||||
|
@@ -22,15 +22,13 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, HostListener, Input, OnChanges, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { NodeEntry, Node, SiteEntry } from '@alfresco/js-api';
|
||||
import { Component, DestroyRef, HostListener, inject, Input, OnChanges, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Node, NodeEntry, SiteEntry } from '@alfresco/js-api';
|
||||
import { ContentActionRef, DynamicTabComponent, SidebarTabRef } from '@alfresco/adf-extensions';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { SetInfoDrawerStateAction, ToggleInfoDrawerAction, infoDrawerPreview } from '@alfresco/aca-shared/store';
|
||||
import { infoDrawerPreview, SetInfoDrawerStateAction, ToggleInfoDrawerAction } from '@alfresco/aca-shared/store';
|
||||
import { AppExtensionService } from '../../services/app.extension.service';
|
||||
import { ContentApiService } from '../../services/content-api.service';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { InfoDrawerModule } from '@alfresco/adf-core';
|
||||
@@ -38,6 +36,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { A11yModule } from '@angular/cdk/a11y';
|
||||
import { ToolbarComponent } from '../toolbar/toolbar.component';
|
||||
import { ContentService, NodesApiService } from '@alfresco/adf-content-services';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
@@ -57,7 +56,7 @@ export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
displayNode: Node | SiteEntry;
|
||||
tabs: Array<SidebarTabRef> = [];
|
||||
actions: Array<ContentActionRef> = [];
|
||||
onDestroy$ = new Subject<boolean>();
|
||||
|
||||
preventFromClosing = false;
|
||||
icon: string = null;
|
||||
|
||||
@@ -66,6 +65,8 @@ export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.close();
|
||||
}
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private contentApi: ContentApiService,
|
||||
@@ -78,26 +79,24 @@ export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.tabs = this.extensions.getSidebarTabs();
|
||||
this.extensions
|
||||
.getAllowedSidebarActions()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((actions) => {
|
||||
this.actions = actions;
|
||||
});
|
||||
|
||||
this.store
|
||||
.select(infoDrawerPreview)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((isInfoDrawerPreviewOpened) => {
|
||||
this.preventFromClosing = isInfoDrawerPreviewOpened;
|
||||
});
|
||||
|
||||
this.nodesService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node: any) => {
|
||||
this.nodesService.nodeUpdated.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((node: any) => {
|
||||
this.node.entry = node;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
if (!this.preventFromClosing) {
|
||||
this.store.dispatch(new SetInfoDrawerStateAction(false));
|
||||
}
|
||||
|
@@ -22,14 +22,14 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation, Input, OnDestroy } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Component, Input, ViewEncapsulation } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AppService } from '../../services/app.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
@@ -40,23 +40,17 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'aca-page-layout' }
|
||||
})
|
||||
export class PageLayoutComponent implements OnDestroy {
|
||||
export class PageLayoutComponent {
|
||||
@Input()
|
||||
hasError = false;
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
appNavNarMode$: Observable<'collapsed' | 'expanded'>;
|
||||
|
||||
constructor(private appService: AppService) {
|
||||
this.appNavNarMode$ = appService.appNavNarMode$.pipe(takeUntil(this.onDestroy$));
|
||||
this.appNavNarMode$ = appService.appNavNarMode$.pipe(takeUntilDestroyed());
|
||||
}
|
||||
|
||||
toggleClick() {
|
||||
this.appService.toggleAppNavBar$.next();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,9 @@
|
||||
import { ContextActionsDirective } from './contextmenu.directive';
|
||||
import { ContextMenu, CustomContextMenu } from '@alfresco/aca-shared/store';
|
||||
import { ContentActionRef, ContentActionType } from '@alfresco/adf-extensions';
|
||||
import { fakeAsync, tick } from '@angular/core/testing';
|
||||
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Injector, runInInjectionContext } from '@angular/core';
|
||||
|
||||
const customActionsMock: ContentActionRef[] = [
|
||||
{
|
||||
@@ -46,7 +48,13 @@ describe('ContextActionsDirective', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
directive = new ContextActionsDirective(storeMock);
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ContextActionsDirective],
|
||||
providers: [{ provide: Store, useValue: storeMock }]
|
||||
});
|
||||
runInInjectionContext(TestBed.inject(Injector), () => {
|
||||
directive = new ContextActionsDirective(storeMock);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render context menu when `enabled` property is false', () => {
|
||||
|
@@ -22,22 +22,20 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, HostListener, Input, OnInit, OnDestroy } from '@angular/core';
|
||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
||||
import { DestroyRef, Directive, HostListener, inject, Input, OnInit } from '@angular/core';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore, ContextMenu, CustomContextMenu } from '@alfresco/aca-shared/store';
|
||||
import { ContentActionRef } from '@alfresco/adf-extensions';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Directive({
|
||||
standalone: true,
|
||||
selector: '[acaContextActions]',
|
||||
exportAs: 'acaContextActions'
|
||||
})
|
||||
export class ContextActionsDirective implements OnInit, OnDestroy {
|
||||
private execute$: Subject<any> = new Subject();
|
||||
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||
|
||||
export class ContextActionsDirective implements OnInit {
|
||||
// eslint-disable-next-line
|
||||
@Input('acaContextEnable')
|
||||
enabled = true;
|
||||
@@ -59,10 +57,14 @@ export class ContextActionsDirective implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
private execute$: Subject<any> = new Subject();
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(private store: Store<AppStore>) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.execute$.pipe(debounceTime(300), takeUntil(this.onDestroy$)).subscribe((event: MouseEvent) => {
|
||||
this.execute$.pipe(debounceTime(300), takeUntilDestroyed(this.destroyRef)).subscribe((event: MouseEvent) => {
|
||||
if (this.customActions?.length) {
|
||||
this.store.dispatch(new CustomContextMenu(event, this.customActions));
|
||||
} else {
|
||||
@@ -70,12 +72,6 @@ export class ContextActionsDirective implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
execute(event: MouseEvent, target: Element) {
|
||||
if (!this.isSelected(target)) {
|
||||
target.dispatchEvent(new MouseEvent('click'));
|
||||
|
@@ -23,10 +23,11 @@
|
||||
*/
|
||||
|
||||
import { PaginationDirective } from './pagination.directive';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { UserPreferencesService, AppConfigService, PaginationComponent, PaginationModel } from '@alfresco/adf-core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { AppConfigService, PaginationComponent, PaginationModel, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { initialState, LibTestingModule } from '../testing/lib-testing-module';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { Injector, runInInjectionContext } from '@angular/core';
|
||||
|
||||
describe('PaginationDirective', () => {
|
||||
let preferences: UserPreferencesService;
|
||||
@@ -45,12 +46,13 @@ describe('PaginationDirective', () => {
|
||||
config = TestBed.inject(AppConfigService);
|
||||
fixture = TestBed.createComponent(PaginationComponent);
|
||||
pagination = fixture.componentInstance;
|
||||
directive = new PaginationDirective(pagination, preferences, config);
|
||||
runInInjectionContext(TestBed.inject(Injector), () => {
|
||||
directive = new PaginationDirective(pagination, preferences, config);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
directive.ngOnDestroy();
|
||||
});
|
||||
|
||||
it('should setup supported page sizes from app config', () => {
|
||||
|
@@ -22,31 +22,23 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, OnInit, OnDestroy } from '@angular/core';
|
||||
import { PaginationComponent, UserPreferencesService, PaginationModel, AppConfigService } from '@alfresco/adf-core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { DestroyRef, Directive, inject, OnInit } from '@angular/core';
|
||||
import { AppConfigService, PaginationComponent, PaginationModel, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Directive({
|
||||
standalone: true,
|
||||
selector: '[acaPagination]'
|
||||
})
|
||||
export class PaginationDirective implements OnInit, OnDestroy {
|
||||
private subscriptions: Subscription[] = [];
|
||||
export class PaginationDirective implements OnInit {
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(private pagination: PaginationComponent, private preferences: UserPreferencesService, private config: AppConfigService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.pagination.supportedPageSizes = this.config.get('pagination.supportedPageSizes');
|
||||
|
||||
this.subscriptions.push(
|
||||
this.pagination.changePageSize.subscribe((event: PaginationModel) => {
|
||||
this.preferences.paginationSize = event.maxItems;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
|
||||
this.subscriptions = [];
|
||||
this.pagination.changePageSize.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event: PaginationModel) => {
|
||||
this.preferences.paginationSize = event.maxItems;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -22,20 +22,20 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { inject, Injectable, OnDestroy } from '@angular/core';
|
||||
import { AuthenticationService, AppConfigService, PageTitleService, UserPreferencesService, NotificationService } from '@alfresco/adf-core';
|
||||
import { Observable, BehaviorSubject, Subject } from 'rxjs';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { AppConfigService, AuthenticationService, NotificationService, PageTitleService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import {
|
||||
AlfrescoApiService,
|
||||
FileUploadErrorEvent,
|
||||
SearchQueryBuilderService,
|
||||
SharedLinksApiService,
|
||||
UploadService,
|
||||
FileUploadErrorEvent
|
||||
UploadService
|
||||
} from '@alfresco/adf-content-services';
|
||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
||||
import { ActivatedRoute, ActivationEnd, NavigationStart, Router } from '@angular/router';
|
||||
import { filter, map } from 'rxjs/operators';
|
||||
import { AppStore, SetCurrentUrlAction, SetRepositoryInfoAction, SetUserProfileAction, ResetSelectionAction } from '@alfresco/aca-shared/store';
|
||||
import { AppStore, ResetSelectionAction, SetCurrentUrlAction, SetRepositoryInfoAction, SetUserProfileAction } from '@alfresco/aca-shared/store';
|
||||
import { ContentApiService } from './content-api.service';
|
||||
import { RouterExtensionService } from './router.extension.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
@@ -50,7 +50,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
providedIn: 'root'
|
||||
})
|
||||
// After moving shell to ADF to core, AppService will implement ShellAppService
|
||||
export class AppService implements ShellAppService, OnDestroy {
|
||||
export class AppService implements ShellAppService {
|
||||
private notificationService = inject(NotificationService);
|
||||
private matDialog = inject(MatDialog);
|
||||
private ready: BehaviorSubject<boolean>;
|
||||
@@ -67,8 +67,6 @@ export class AppService implements ShellAppService, OnDestroy {
|
||||
hideSidenavConditions = ['/preview/'];
|
||||
minimizeSidenavConditions = ['/search'];
|
||||
|
||||
onDestroy$ = new Subject<boolean>();
|
||||
|
||||
/**
|
||||
* Whether `withCredentials` mode is enabled.
|
||||
* Usually means that `Kerberos` mode is used.
|
||||
@@ -121,11 +119,6 @@ export class AppService implements ShellAppService, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
init(): void {
|
||||
this.alfrescoApiService.getInstance().on('error', (error: { status: number; response: any }) => {
|
||||
if (error.status === 401 && !this.alfrescoApiService.isExcludedErrorListener(error?.response?.req?.url)) {
|
||||
|
Reference in New Issue
Block a user