diff --git a/apps/dsp-app/src/app/main/services/component-communication-event.service.ts b/apps/dsp-app/src/app/main/services/component-communication-event.service.ts index 30e461bc08..b34274597c 100644 --- a/apps/dsp-app/src/app/main/services/component-communication-event.service.ts +++ b/apps/dsp-app/src/app/main/services/component-communication-event.service.ts @@ -42,6 +42,7 @@ export enum Events { gravSearchExecuted, projectCreated, resourceDeleted, + resourceChanged, resourceCreated, unselectedListItem, } diff --git a/apps/dsp-app/src/app/project/description/description.component.html b/apps/dsp-app/src/app/project/description/description.component.html index ae7120b534..b0d2cb3df4 100644 --- a/apps/dsp-app/src/app/project/description/description.component.html +++ b/apps/dsp-app/src/app/project/description/description.component.html @@ -1,4 +1,4 @@ - +

Project Description

diff --git a/apps/dsp-app/src/app/project/description/description.component.ts b/apps/dsp-app/src/app/project/description/description.component.ts index 2dc956b203..25f5efa39e 100644 --- a/apps/dsp-app/src/app/project/description/description.component.ts +++ b/apps/dsp-app/src/app/project/description/description.component.ts @@ -1,35 +1,38 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { Component, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ReadUser } from '@dasch-swiss/dsp-js'; import { StringLiteral } from '@dasch-swiss/dsp-js/src/models/admin/string-literal'; import { RouteConstants } from '@dasch-swiss/vre/shared/app-config'; import { ProjectService } from '@dasch-swiss/vre/shared/app-helper-services'; import { ProjectsSelectors, UserSelectors } from '@dasch-swiss/vre/shared/app-state'; -import { Store } from '@ngxs/store'; -import { combineLatest } from 'rxjs'; -import { map, switchMap, tap } from 'rxjs/operators'; +import { Select, Store } from '@ngxs/store'; +import { Observable, Subject, combineLatest } from 'rxjs'; +import { map, takeUntil, takeWhile } from 'rxjs/operators'; import { AppGlobal } from '../../app-global'; @Component({ - changeDetection: ChangeDetectionStrategy.OnPush, + // changeDetection: ChangeDetectionStrategy.OnPush, selector: 'app-description', templateUrl: './description.component.html', styleUrls: ['./description.component.scss'], }) -export class DescriptionComponent { - loading = false; - readProject$ = this._route.paramMap.pipe( - switchMap(params => { - this.loading = true; - return this._store - .select(ProjectsSelectors.allProjects) - .pipe(map(projects => projects.find(x => x.id.split('/').pop() === params.get(RouteConstants.uuidParameter)))); - }), - tap(() => { - this.loading = false; +export class DescriptionComponent implements OnDestroy { + destroyed$: Subject = new Subject(); + + readProject$ = combineLatest([this._route.paramMap, this._store.select(ProjectsSelectors.allProjects)]).pipe( + takeUntil(this.destroyed$), + map(([params, allProjects]) => { + const projects = allProjects.find(x => x.id.split('/').pop() === params.get(RouteConstants.uuidParameter)); + return projects; }) ); - sortedDescriptions$ = this.readProject$.pipe(map(({ description }) => this._sortDescriptionsByLanguage(description))); + + sortedDescriptions$ = this.readProject$.pipe( + takeUntil(this.destroyed$), + takeWhile(readProject => readProject !== undefined), + map(({ description }) => this._sortDescriptionsByLanguage(description)) + ); + userHasPermission$ = combineLatest([ this._store.select(UserSelectors.user), this.readProject$, @@ -46,11 +49,19 @@ export class DescriptionComponent { RouteConstants = RouteConstants; + @Select(ProjectsSelectors.isProjectsLoading) isLoading$: Observable; + constructor( private _route: ActivatedRoute, - private _store: Store + private _store: Store, + private _projectService: ProjectService ) {} + ngOnDestroy(): void { + this.destroyed$.next(); + this.destroyed$.complete(); + } + private _sortDescriptionsByLanguage(descriptions: StringLiteral[]): StringLiteral[] { const languageOrder = AppGlobal.languagesList.map(l => l.language); diff --git a/apps/dsp-app/src/app/workspace/resource/properties/properties.component.ts b/apps/dsp-app/src/app/workspace/resource/properties/properties.component.ts index 0f83b58964..4c012b14c7 100644 --- a/apps/dsp-app/src/app/workspace/resource/properties/properties.component.ts +++ b/apps/dsp-app/src/app/workspace/resource/properties/properties.component.ts @@ -391,6 +391,7 @@ export class PropertiesComponent implements OnInit, OnChanges, OnDestroy { this.resource.res.label = payload.label; this.lastModificationDate = response.lastModificationDate; // if annotations tab is active; a label of a region has been changed --> update regions + this._componentCommsService.emit(new EmitEvent(CommsEvents.resourceChanged)); if (this.isAnnotation) { this.regionChanged.emit(); } diff --git a/apps/dsp-app/src/app/workspace/results/list-view/list-view.component.ts b/apps/dsp-app/src/app/workspace/results/list-view/list-view.component.ts index 412444e4ee..7432ce6c9d 100644 --- a/apps/dsp-app/src/app/workspace/results/list-view/list-view.component.ts +++ b/apps/dsp-app/src/app/workspace/results/list-view/list-view.component.ts @@ -21,7 +21,7 @@ import { import { DspApiConnectionToken, RouteConstants } from '@dasch-swiss/vre/shared/app-config'; import { AppErrorHandler } from '@dasch-swiss/vre/shared/app-error-handler'; import { NotificationService } from '@dasch-swiss/vre/shared/app-notification'; -import { of, Subject, Subscription } from 'rxjs'; +import { Subject, Subscription, of } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import { ComponentCommunicationEventService, @@ -141,9 +141,8 @@ export class ListViewComponent implements OnChanges, OnInit, OnDestroy { ngOnInit(): void { this.componentCommsSubscriptions.push( - this._componentCommsService.on(Events.resourceDeleted, () => { - this._doSearch(); - }) + this._componentCommsService.on(Events.resourceChanged, () => this._doSearch()), + this._componentCommsService.on(Events.resourceDeleted, () => this._doSearch()) ); } diff --git a/libs/vre/shared/app-state/src/lib/projects/projects.state-model.ts b/libs/vre/shared/app-state/src/lib/projects/projects.state-model.ts index 670c78d7ef..95d74090d8 100644 --- a/libs/vre/shared/app-state/src/lib/projects/projects.state-model.ts +++ b/libs/vre/shared/app-state/src/lib/projects/projects.state-model.ts @@ -3,6 +3,7 @@ import { IKeyValuePairs } from '../model-interfaces'; export class ProjectsStateModel { isLoading = false; + isMembershipLoading = false; hasLoadingErrors = false; allProjects: ReadProject[] = []; projectMembers: IKeyValuePairs = {}; diff --git a/libs/vre/shared/app-state/src/lib/projects/projects.state.ts b/libs/vre/shared/app-state/src/lib/projects/projects.state.ts index 84ed684c52..79b322c596 100644 --- a/libs/vre/shared/app-state/src/lib/projects/projects.state.ts +++ b/libs/vre/shared/app-state/src/lib/projects/projects.state.ts @@ -38,6 +38,7 @@ import { ProjectsStateModel } from './projects.state-model'; const defaults: ProjectsStateModel = { isLoading: false, + isMembershipLoading: false, hasLoadingErrors: false, allProjects: [], projectMembers: {}, @@ -139,10 +140,10 @@ export class ProjectsState { const userProjectAdminGroups = this.store.selectSnapshot(UserSelectors.userProjectAdminGroups); const isProjectAdmin = ProjectService.IsProjectAdminOrSysAdmin(user, userProjectAdminGroups, projectIri); if (isProjectAdmin) { - ctx.patchState({ isLoading: true }); + ctx.patchState({ isMembershipLoading: true }); ctx.dispatch([new LoadProjectMembersAction(projectUuid), new LoadProjectGroupsAction(projectUuid)]); this.actions.pipe(take(1), ofActionSuccessful(LoadProjectGroupsAction)).subscribe(() => { - ctx.patchState({ isLoading: false }); + ctx.patchState({ isMembershipLoading: false }); }); } } @@ -166,14 +167,14 @@ export class ProjectsState { @Action(RemoveUserFromProjectAction) removeUserFromProject(ctx: StateContext, { userId, projectIri }: RemoveUserFromProjectAction) { - ctx.patchState({ isLoading: true }); + ctx.patchState({ isMembershipLoading: true }); return this._dspApiConnection.admin.usersEndpoint.removeUserFromProjectMembership(userId, projectIri).pipe( take(1), map((response: ApiResponseData | ApiResponseError) => response as ApiResponseData), tap({ next: (response: ApiResponseData) => { ctx.dispatch([new SetUserAction(response.body.user), new LoadProjectMembersAction(projectIri)]); - ctx.patchState({ isLoading: false }); + ctx.patchState({ isMembershipLoading: false }); }, error: error => { this.errorHandler.showMessage(error); @@ -187,14 +188,14 @@ export class ProjectsState { ctx: StateContext, { userId, projectIri }: AddUserToProjectMembershipAction ) { - ctx.patchState({ isLoading: true, hasLoadingErrors: false }); + ctx.patchState({ isMembershipLoading: true, hasLoadingErrors: false }); return this._dspApiConnection.admin.usersEndpoint.addUserToProjectMembership(userId, projectIri).pipe( take(1), map((response: ApiResponseData | ApiResponseError) => response as ApiResponseData), tap({ next: (response: ApiResponseData) => { ctx.dispatch([new SetUserAction(response.body.user), new LoadProjectMembersAction(projectIri)]); - ctx.patchState({ isLoading: false }); + ctx.patchState({ isMembershipLoading: false }); }, error: error => { ctx.patchState({ hasLoadingErrors: true }); @@ -210,7 +211,7 @@ export class ProjectsState { return; } - ctx.patchState({ isLoading: true }); + ctx.patchState({ isMembershipLoading: true }); const projectIri = this.projectService.uuidToIri(projectUuid); return this._dspApiConnection.admin.projectsEndpoint.getProjectMembersByIri(projectIri).pipe( take(1), @@ -222,7 +223,7 @@ export class ProjectsState { next: (response: ApiResponseData) => { ctx.setState({ ...ctx.getState(), - isLoading: false, + isMembershipLoading: false, projectMembers: { [projectIri]: { value: response.body.members }, }, @@ -238,7 +239,7 @@ export class ProjectsState { @Action(LoadProjectGroupsAction) loadProjectGroupsAction(ctx: StateContext) { - ctx.patchState({ isLoading: true }); + ctx.patchState({ isMembershipLoading: true }); return this._dspApiConnection.admin.groupsEndpoint.getGroups().pipe( take(1), map( @@ -259,7 +260,7 @@ export class ProjectsState { ctx.setState({ ...ctx.getState(), - isLoading: false, + isMembershipLoading: false, projectGroups: groups, }); },