Skip to content

Commit

Permalink
fix: #DEV-3111, #DEV-3108, #DEV-3118 project initialisation from url (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
irmastnt committed Dec 15, 2023
1 parent 814fb98 commit 4e5c19a
Show file tree
Hide file tree
Showing 26 changed files with 744 additions and 858 deletions.
Expand Up @@ -7,10 +7,10 @@ import {
} from '@dasch-swiss/dsp-js';
import { ProjectService } from '@dasch-swiss/vre/shared/app-helper-services';
import { AddUserComponent } from './add-user/add-user.component';
import { Actions, Select, Store, ofActionSuccessful } from '@ngxs/store';
import { CurrentProjectSelectors, LoadProjectMembersAction, ProjectsSelectors, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Actions, Select, Store } from '@ngxs/store';
import { LoadProjectMembersAction, ProjectsSelectors, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Observable, Subject } from 'rxjs';
import { map, take, takeUntil } from 'rxjs/operators';
import { map, takeUntil } from 'rxjs/operators';
import { ProjectBase } from '../project-base';

@Component({
Expand Down Expand Up @@ -56,7 +56,7 @@ export class CollaborationComponent extends ProjectBase implements OnInit, OnDes
@Select(ProjectsSelectors.isProjectsLoading) isProjectsLoading$: Observable<boolean>;
@Select(UserSelectors.isSysAdmin) isSysAdmin$: Observable<boolean>;
@Select(UserSelectors.user) user$: Observable<ReadUser>;
@Select(CurrentProjectSelectors.project) project$: Observable<ReadProject>;
@Select(ProjectsSelectors.currentProject) project$: Observable<ReadProject>;

constructor(
protected _route: ActivatedRoute,
Expand All @@ -78,7 +78,7 @@ export class CollaborationComponent extends ProjectBase implements OnInit, OnDes

ngOnInit() {
super.ngOnInit();
const project = this._store.selectSnapshot(CurrentProjectSelectors.project) as ReadProject;
const project = this._store.selectSnapshot(ProjectsSelectors.currentProject) as ReadProject;
this._titleService.setTitle(`Project ${project?.shortname} | Collaboration`);
}

Expand Down
Expand Up @@ -43,7 +43,7 @@ export class DescriptionComponent {
return false;
}

return this.projectService.isProjectAdminOrSysAdmin(user, userProjectGroups, readProject.id);
return ProjectService.IsProjectAdminOrSysAdmin(user, userProjectGroups, readProject.id);
})
);
}
Expand All @@ -56,7 +56,6 @@ export class DescriptionComponent {
private _route: ActivatedRoute,
private _router: Router,
private store: Store,
private projectService: ProjectService,
) {
// get the uuid of the current project
this._route.parent.paramMap.subscribe((params: Params) => {
Expand Down
4 changes: 2 additions & 2 deletions apps/dsp-app/src/app/project/list/list.component.ts
Expand Up @@ -15,7 +15,7 @@ import { ProjectBase } from '../project-base';
import { Actions, Select, Store, ofActionSuccessful } from '@ngxs/store';
import { Observable, Subject } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { CurrentProjectSelectors, DeleteListNodeAction, ListsSelectors, LoadListsInProjectAction } from '@dasch-swiss/vre/shared/app-state';
import { DeleteListNodeAction, ListsSelectors, LoadListsInProjectAction, ProjectsSelectors } from '@dasch-swiss/vre/shared/app-state';

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
Expand Down Expand Up @@ -149,7 +149,7 @@ export class ListComponent extends ProjectBase implements OnInit, OnDestroy {
}

private _setPageTitle() {
const project = this._store.selectSnapshot(CurrentProjectSelectors.project);
const project = this._store.selectSnapshot(ProjectsSelectors.currentProject);
this._titleService.setTitle(`Project ${project?.shortname} | List ${this.listIri ? '' : 's'}`);
}
}
Expand Up @@ -57,6 +57,10 @@ export class OntologyClassInstanceComponent extends ProjectBase implements OnIni
}

ngOnInit() {
// this._route.params.subscribe((params) => {
// this.initProject(params);
// });

this.project$.pipe(
filter(project => project !== undefined),
).subscribe((project) => {
Expand Down
Expand Up @@ -27,7 +27,7 @@ import {DspApiConnectionToken, RouteConstants} from '@dasch-swiss/vre/shared/app
import { existingNamesValidator } from '@dsp-app/src/app/main/directive/existing-name/existing-name.directive';
import { AppErrorHandler } from '@dasch-swiss/vre/shared/app-error-handler';
import { CustomRegex } from '@dsp-app/src/app/workspace/resource/values/custom-regex';
import { ClearProjectOntologiesAction, CurrentOntologyCanBeDeletedAction, CurrentProjectSelectors, LoadListsInProjectAction, LoadOntologyAction, LoadProjectOntologiesAction, OntologiesSelectors, SetCurrentOntologyAction, SetCurrentProjectOntologyPropertiesAction } from '@dasch-swiss/vre/shared/app-state';
import { ClearProjectOntologiesAction, CurrentOntologyCanBeDeletedAction, LoadListsInProjectAction, LoadProjectOntologiesAction, OntologiesSelectors, ProjectsSelectors, SetCurrentOntologyAction, SetCurrentProjectOntologyPropertiesAction } from '@dasch-swiss/vre/shared/app-state';
import { Actions, Select, Store, ofActionSuccessful } from '@ngxs/store';
import { Observable, Subject } from 'rxjs';
import { take, takeUntil } from 'rxjs/operators';
Expand Down Expand Up @@ -157,7 +157,7 @@ export class OntologyFormComponent implements OnInit, OnDestroy {
});
}

this.project = this._store.selectSnapshot(CurrentProjectSelectors.project);
this.project = this._store.selectSnapshot(ProjectsSelectors.currentProject);
this.buildForm();

if (this.iri) {
Expand Down
8 changes: 4 additions & 4 deletions apps/dsp-app/src/app/project/ontology/ontology.component.html
Expand Up @@ -29,7 +29,7 @@
<span class="fill-remaining-space"></span>

<!-- edit options -->
<span class="ontology-actions project-actions" *ngIf="(project$ | async).status">
<span class="ontology-actions project-actions" *ngIf="(project$ | async)?.status">
<p class="mat-caption space-reducer">Data model configuration</p>
<span
[matTooltip]="((isAdmin$ | async) ? ((lastModificationDate$ | async) ? 'Edit data model info' : 'This data model can\'t be edited because of missing lastModificationDate!') : null)">
Expand Down Expand Up @@ -114,7 +114,7 @@
<app-resource-class-info *ngFor="let resClass of ontoClasses; trackBy: trackByClassDefinitionFn"
[resourceClass]="resClass"
[projectUuid]="projectUuid"
[projectStatus]="(project$ | async).status"
[projectStatus]="(project$ | async)?.status"
[expanded]="expandClasses"
[userCanEdit]="isAdmin$ | async"
(editResourceClass)="openResourceClassForm('editResourceClass', $event)"
Expand All @@ -126,14 +126,14 @@
<div class="ontology-editor-list properties" *ngIf="view === 'properties'">
<!-- list of properties of current ontology -->
<mat-list class="without-padding">
<mat-list-item class="property" *ngFor="let prop of ontoProperties.properties; trackBy: trackByPropertyDefinitionFn; let odd = odd"
<mat-list-item class="property" *ngFor="let prop of ontoProperties?.properties; trackBy: trackByPropertyDefinitionFn; let odd = odd"
[class.odd]="odd">
<!-- display only properties with guiOrder and if they exist in list of properties;
if objectType is a linkValue hide it (otherwise we have the property twice) -->
<app-property-info
[propDef]="(currentOntology$ | async)?.properties[prop.id]"
[projectUuid]="projectUuid"
[projectStatus]="(project$ | async).status"
[projectStatus]="(project$ | async)?.status"
[lastModificationDate]="lastModificationDate$ | async"
(lastModificationDate)="onLastModificationDateChange($event)"
[userCanEdit]="isAdmin$ | async"
Expand Down
61 changes: 39 additions & 22 deletions apps/dsp-app/src/app/project/ontology/ontology.component.ts
Expand Up @@ -26,6 +26,7 @@ import {
KnoraApiConnection,
PropertyDefinition,
ReadOntology,
ReadProject,
ReadUser,
UpdateOntology,
} from '@dasch-swiss/dsp-js';
Expand All @@ -41,8 +42,8 @@ import {
} from '@dasch-swiss/vre/shared/app-helper-services';
import { OntologyService } from '@dasch-swiss/vre/shared/app-helper-services';
import { Actions, Select, Store, ofActionSuccessful } from '@ngxs/store';
import { ClearCurrentOntologyAction, ClearProjectOntologiesAction, CurrentOntologyCanBeDeletedAction, CurrentProjectSelectors, LoadListsInProjectAction, LoadOntologyAction, LoadProjectOntologiesAction, OntologiesSelectors, OntologyProperties, ProjectsSelectors, SetCurrentOntologyAction, SetCurrentProjectOntologyPropertiesAction, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Observable, Subject, combineLatest } from 'rxjs';
import { ClearCurrentOntologyAction, ClearProjectOntologiesAction, CurrentOntologyCanBeDeletedAction, LoadListsInProjectAction, LoadOntologyAction, LoadProjectOntologiesAction, OntologiesSelectors, OntologyProperties, ProjectsSelectors, SetCurrentOntologyAction, SetCurrentProjectOntologyPropertiesAction, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Observable, Subject, combineLatest, forkJoin } from 'rxjs';
import { map, take, takeUntil } from 'rxjs/operators';
import { ProjectBase } from '../project-base';

Expand Down Expand Up @@ -101,7 +102,13 @@ export class OntologyComponent extends ProjectBase implements OnInit, OnDestroy
get ontologyIri(): string {
const iriBase = this._ontologyService.getIriBaseUrl();
const ontologyName = this._route.snapshot.paramMap.get(RouteConstants.ontoParameter);
return `${iriBase}/${RouteConstants.ontology}/${this.project.shortcode}/${ontologyName}/v2`;
return `${iriBase}/${RouteConstants.ontology}/${this.project?.shortcode}/${ontologyName}/v2`;
}

getOntologyIri(projectShortcode: string): string {
const iriBase = this._ontologyService.getIriBaseUrl();
const ontologyName = this._route.snapshot.paramMap.get(RouteConstants.ontoParameter);
return `${iriBase}/${RouteConstants.ontology}/${projectShortcode}/${ontologyName}/v2`;
}

// the lastModificationDate is the most important key
Expand Down Expand Up @@ -172,22 +179,12 @@ export class OntologyComponent extends ProjectBase implements OnInit, OnDestroy
? this._route.snapshot.params.view
: RouteConstants.classes;
}

const currentProject = this._store.selectSnapshot(CurrentProjectSelectors.project);
if (this.projectUuid
&& (currentProject && currentProject.id === this.projectIri)) {
const projectOntologies = this._store.selectSnapshot(OntologiesSelectors.projectOntologies);
if (currentProject.ontologies.length > 0
&& (!projectOntologies[this.projectIri] || projectOntologies[this.projectIri].readOntologies.length === 0)) {
this._store.dispatch(new LoadProjectOntologiesAction(currentProject.id));
this._actions$.pipe(ofActionSuccessful(LoadListsInProjectAction))
.subscribe(() => {
this.initOntology();
});
} else {
this.initOntology();
}
}

this._store.select(ProjectsSelectors.currentProject)
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe((project) => {
this.initProjectOntologies(project);
});

//TODO temporary solution to replace eventemitter with subject because emitter loses subscriber after child component
//subscription responsible for emitting event is triggered
Expand All @@ -198,6 +195,24 @@ export class OntologyComponent extends ProjectBase implements OnInit, OnDestroy
this._cd.markForCheck();
}

private initProjectOntologies(currentProject: ReadProject) {
if (!currentProject || !this.projectUuid || currentProject.id !== this.projectIri) {
return;
}

const projectOntologies = this._store.selectSnapshot(OntologiesSelectors.projectOntologies);
if (currentProject.ontologies.length > 0
&& (!projectOntologies[this.projectIri] || projectOntologies[this.projectIri].readOntologies.length === 0)) {
this._store.dispatch(new LoadProjectOntologiesAction(currentProject.id));
this._actions$.pipe(ofActionSuccessful(LoadListsInProjectAction))
.subscribe(() => {
this.initOntology();
});
} else {
this.initOntology();
}
}

ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
Expand Down Expand Up @@ -250,13 +265,15 @@ export class OntologyComponent extends ProjectBase implements OnInit, OnDestroy
if (!currentOntology) {
const projectOntologies = this._store.selectSnapshot(OntologiesSelectors.projectOntologies);
const projectIri = this._projectService.uuidToIri(this.projectUuid);
currentOntology = projectOntologies[projectIri]?.readOntologies.find(o => o.id === this.ontologyIri);
const currentProject = this._store.selectSnapshot(ProjectsSelectors.currentProject);
const ontologyIri = this.getOntologyIri(currentProject.shortcode);
currentOntology = projectOntologies[projectIri]?.readOntologies.find(o => o.id === ontologyIri);
if (currentOntology) {
this.resetOntologyView(currentOntology);
} else {
const isLoading = this._store.selectSnapshot(OntologiesSelectors.isLoading);
if (isLoading === false) {
this._store.dispatch(new LoadOntologyAction(this.ontologyIri, this.projectUuid, true));
this._store.dispatch(new LoadOntologyAction(ontologyIri, this.projectUuid, true));
this._actions$.pipe(ofActionSuccessful(LoadOntologyAction))
.pipe(take(1))
.subscribe(() => {
Expand Down Expand Up @@ -609,7 +626,7 @@ export class OntologyComponent extends ProjectBase implements OnInit, OnDestroy
combineLatest([ProjectBase.navigationEndFilter(this._router.events), this.project$, this.currentOntology$])
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(([event, project, currentOntology]) => {
this._titleService.setTitle(`Project ${project.shortname} | Data model ${currentOntology.id ? '' : 's'}`);
this._titleService.setTitle(`Project ${project?.shortname} | Data model ${currentOntology.id ? '' : 's'}`);
});
}

Expand Down
50 changes: 38 additions & 12 deletions apps/dsp-app/src/app/project/project-base.ts
@@ -1,10 +1,10 @@
import { ChangeDetectorRef, Directive, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { ReadProject, ReadUser } from '@dasch-swiss/dsp-js';
import { CurrentProjectSelectors, LoadProjectAction, LoadProjectOntologiesAction, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { LoadProjectAction, LoadProjectOntologiesAction, OntologiesSelectors, ProjectsSelectors, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Actions, Select, Store, ofActionSuccessful } from '@ngxs/store';
import { Observable, Subject, combineLatest } from 'rxjs';
import { filter, map, take, takeUntil } from 'rxjs/operators';
import { filter, map, take, takeUntil, takeWhile } from 'rxjs/operators';
import { ProjectService } from '@dasch-swiss/vre/shared/app-helper-services';
import { Title } from '@angular/platform-browser';

Expand All @@ -13,15 +13,16 @@ export class ProjectBase implements OnInit, OnDestroy {
destroyed: Subject<void> = new Subject<void>();

projectUuid: string;
project: ReadProject;
project: ReadProject; //TODO use project$ instead

// permissions of logged-in user
get isAdmin$(): Observable<boolean> {
return combineLatest([this.user$, this.userProjectAdminGroups$, this._route.parent.params])
return combineLatest([this.user$, this.userProjectAdminGroups$, this._route.params, this._route.parent.params])
.pipe(
takeUntil(this.destroyed),
map(([user, userProjectGroups, params]) => {
return this._projectService.isProjectAdminOrSysAdmin(user, userProjectGroups, params.uuid);
map(([user, userProjectGroups, params, parentParams]) => {
const projectIri = this._projectService.uuidToIri(params.uuid ? params.uuid : parentParams.uuid);
return ProjectService.IsProjectAdminOrSysAdmin(user, userProjectGroups, projectIri);
})
)
}
Expand All @@ -32,10 +33,11 @@ export class ProjectBase implements OnInit, OnDestroy {

@Select(UserSelectors.user) user$: Observable<ReadUser>;
@Select(UserSelectors.userProjectAdminGroups) userProjectAdminGroups$: Observable<string[]>;
@Select(CurrentProjectSelectors.project) project$: Observable<ReadProject>;
@Select(CurrentProjectSelectors.isProjectAdmin) isProjectAdmin$: Observable<boolean>;
@Select(CurrentProjectSelectors.isProjectMember) isProjectMember$: Observable<boolean>;

@Select(ProjectsSelectors.isCurrentProjectAdmin) isProjectAdmin$: Observable<boolean>;
@Select(ProjectsSelectors.isCurrentProjectMember) isProjectMember$: Observable<boolean>;
@Select(ProjectsSelectors.currentProject) project$: Observable<ReadProject>;
@Select(ProjectsSelectors.isProjectsLoading) isProjectsLoading$: Observable<boolean>;

constructor(
protected _store: Store,
protected _route: ActivatedRoute,
Expand All @@ -52,11 +54,19 @@ export class ProjectBase implements OnInit, OnDestroy {
}

ngOnInit(): void {
this.project = this._store.selectSnapshot(CurrentProjectSelectors.project);
this.project = this._store.selectSnapshot(ProjectsSelectors.currentProject);
if (this.projectUuid && (!this.project || this.project.id !== this.projectIri)) {
// get current project data, project members and project groups
// and set the project state here
this.loadProject();
} else {
if (!this.isOntologiesAvailable()) {
this.isProjectsLoading$
.pipe(takeWhile((isLoading) => isLoading === false))
.subscribe((isLoading: boolean) => {
this._store.dispatch(new LoadProjectOntologiesAction(this.projectUuid));
});
}
}
}

Expand All @@ -82,7 +92,7 @@ export class ProjectBase implements OnInit, OnDestroy {
}

private setProjectData(): void {
this.project = this._store.selectSnapshot(CurrentProjectSelectors.project);
this.project = this._store.selectSnapshot(ProjectsSelectors.currentProject);
if (!this.project) {
return;
}
Expand All @@ -97,4 +107,20 @@ export class ProjectBase implements OnInit, OnDestroy {
filter((e) => !(e as NavigationEnd).url.startsWith('api'))
);
}

private isOntologiesAvailable(): boolean {
const currentProjectOntologies = this._store.selectSnapshot(OntologiesSelectors.currentProjectOntologies);
let result = true;

this.project.ontologies.forEach((ontoIri) => {
if (!currentProjectOntologies
|| currentProjectOntologies.length === 0
|| !currentProjectOntologies.find((o) => o.id === ontoIri)
) {
result = false;
}
});

return result;
}
}

0 comments on commit 4e5c19a

Please sign in to comment.