Skip to content
Permalink
Browse files
feat(ontology): ontology editor read mode (DEV-1183) (#799)
* feat(ontology): ontology editor can now be viewed by project members in read mode

* feat(ontology): allow project members to access ontology editor via the old dashboard
  • Loading branch information
mdelez committed Aug 18, 2022
1 parent 5f4d52f commit 02b5a489b539c555d557d8f78d03a88b30470fc6
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 55 deletions.
@@ -16,11 +16,8 @@ export class SettingsComponent implements OnInit {
constructor() { }

ngOnInit(): void {
// we need only two items from the old project navigation
// collaboration
this.navigation.push(AppGlobal.projectNav[1]);
// permissions
this.navigation.push(AppGlobal.projectNav[2]);
}

}
@@ -1,4 +1,4 @@
<div *ngIf="projectAdmin && !disableContent">
<div *ngIf="(projectMember || projectAdmin) && !disableContent">

<app-progress-indicator *ngIf="loading"></app-progress-indicator>

@@ -41,7 +41,8 @@ <h2 class="mat-title">

<span class="fill-remaining-space"></span>

<span class="app-toolbar-action" [class.select-form]="ontologies.length" *ngIf="project.status">
<span class="app-toolbar-action" [class.select-form]="ontologies.length"
*ngIf="project.status && projectAdmin">
<button mat-raised-button color="primary" class="create-data-model-btn"
(click)="openOntologyForm('createOntology')">
{{ontologies.length ? 'New data model' : 'Create your first data model'}}
@@ -101,16 +102,17 @@ <h2 class="mat-title">
<span class="ontology-actions project-actions" *ngIf="project.status">
<p class="mat-caption space-reducer">Data model configuration</p>
<span
[matTooltip]="(ontology.lastModificationDate ? 'Edit data model info' : 'This data model can\'t be edited because of missing lastModificationDate!')">
<button mat-button [disabled]="!ontology.lastModificationDate"
[matTooltip]="(projectAdmin ? (ontology.lastModificationDate ? 'Edit data model info' : 'This data model can\'t be edited because of missing lastModificationDate!') : null)">
<button mat-button [disabled]="!ontology.lastModificationDate || !projectAdmin"
(click)="$event.stopPropagation(); openOntologyForm('editOntology', ontology.id)">
<mat-icon>edit</mat-icon>
Edit
</button>
</span>
<span
[matTooltip]="(ontology.lastModificationDate ? (ontologyCanBeDeleted ? 'Delete data model' : 'This data model can\'t be deleted because it is in use!') : 'This data model can\'t be deleted because of missing lastModificationDate!')">
<button mat-button [disabled]="!ontology.lastModificationDate || !ontologyCanBeDeleted"
[matTooltip]="(projectAdmin ? (ontology.lastModificationDate ? (ontologyCanBeDeleted ? 'Delete data model' : 'This data model can\'t be deleted because it is in use!') : 'This data model can\'t be deleted because of missing lastModificationDate!') : null)">
<button mat-button
[disabled]="(!ontology.lastModificationDate || !ontologyCanBeDeleted) || (!projectAdmin || !sysAdmin)"
(click)="$event.stopPropagation(); delete('Ontology', {iri: ontologyIri, label: ontology.label})">
<mat-icon>delete</mat-icon>
Delete
@@ -182,6 +184,7 @@ <h2 class="mat-title">
<app-resource-class-info *ngFor="let resClass of ontoClasses" [resourceClass]="resClass"
[projectCode]="projectCode" [projectStatus]="project.status" [ontologies]="ontologies"
[expanded]="expandClasses" [(lastModificationDate)]="lastModificationDate"
[userCanEdit]="(projectAdmin || sysAdmin)"
(editResourceClass)="openResourceClassForm('editResourceClass', $event)"
(deleteResourceClass)="delete('ResourceClass', $event)"
(updateCardinality)="initOntology($event)">
@@ -196,6 +199,7 @@ <h2 class="mat-title">
if objectType is a linkValue hide it (otherwise we have the property twice) -->
<app-property-info [propDef]="ontology?.properties[prop.id]" [projectCode]="projectCode"
[projectStatus]="project.status" [(lastModificationDate)]="lastModificationDate"
[userCanEdit]="(projectAdmin || sysAdmin)"
(editResourceProperty)="openPropertyForm('editProperty', $event)"
(deleteResourceProperty)="delete('Property', $event)">
</app-property-info>
@@ -210,8 +214,8 @@ <h2 class="mat-title">

</div>

<div *ngIf="!projectAdmin && !disableContent" class="content large middle">
<div *ngIf="!projectMember && !disableContent && !loading" class="content large middle">
<app-status [status]="403"></app-status>
</div>

<app-status *ngIf="disableContent" [status]="204"></app-status>
<app-status *ngIf="disableContent" [status]="204"></app-status>
@@ -19,7 +19,8 @@ import {
PropertyDefinition,
ReadOntology,
ReadProject,
UpdateOntology
UpdateOntology,
UserResponse
} from '@dasch-swiss/dsp-js';
import { CacheService } from 'src/app/main/cache/cache.service';
import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens';
@@ -58,9 +59,10 @@ export class OntologyComponent implements OnInit {

// permissions of logged-in user
session: Session;
// system admin or project admin is by default false
// system admin, project admin, and project member are by default false
sysAdmin = false;
projectAdmin = false;
projectMember = false;

// project shortcode; as identifier in project cache service
projectCode: string;
@@ -194,8 +196,13 @@ export class OntologyComponent implements OnInit {
// is logged-in user projectAdmin?
this.projectAdmin = this.sysAdmin ? this.sysAdmin : this.session.user.projectAdmin.some(e => e === this.project.id);

// get the ontologies for this project
this.initOntologiesList();
this._dspApiConnection.admin.usersEndpoint.getUserByUsername(this.session.user.name).subscribe(
(userResponse: ApiResponseData<UserResponse>) => {
this.projectMember = userResponse.body.user.projects.some(p => p.shortcode === this.project.shortcode);

// get the ontologies for this project
this.initOntologiesList();
});

this.ontologyForm = this._fb.group({
ontology: new FormControl({
@@ -102,6 +102,8 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {

@Input() lastModificationDate?: string;

@Input() userCanEdit: boolean; // is user a project admin or sys admin?

// event emitter when the lastModificationDate changed; bidirectional binding with lastModificationDate parameter
@Output() lastModificationDateChange: EventEmitter<string> = new EventEmitter<string>();

@@ -315,8 +317,10 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
* show action bubble with various CRUD buttons when hovered over.
*/
mouseEnter() {
this.canBeDeleted();
this.showActionBubble = true;
if (this.userCanEdit) {
this.canBeDeleted();
this.showActionBubble = true;
}
}

/**
@@ -18,7 +18,8 @@
<span class="resource-class-header-action">
<span class="resource-class-more" *ngIf="projectStatus"
[matTooltip]="(ontology.lastModificationDate ? 'more' : 'This data model can\'t be edited because of missing lastModificationDate!')">
<button mat-icon-button [matMenuTriggerFor]="resClassMenu" class="res-class-menu" [disabled]="!ontology.lastModificationDate" (click)="canBeDeleted()">
<button mat-icon-button [matMenuTriggerFor]="resClassMenu" class="res-class-menu"
[disabled]="!ontology.lastModificationDate" (click)="canBeDeleted()">
<mat-icon>more_horiz</mat-icon>
</button>
</span>
@@ -29,22 +30,28 @@
</span>
</span>
<mat-menu #resClassMenu="matMenu" xPosition="before">
<button mat-menu-item class="res-class-edit"
(click)="editResourceClass.emit({iri: resourceClass.id, label: resourceClass.label})">
Edit resource class info
</button>
<span *ngIf="userCanEdit">
<button mat-menu-item class="res-class-edit"
(click)="editResourceClass.emit({iri: resourceClass.id, label: resourceClass.label})">
Edit resource class info
</button>
</span>
<span [matTooltip]="'This opens the resource instance form'" matTooltipPosition="before">
<button mat-menu-item (click)="createResourceInstance(resourceClass.id, resourceClass.label + ' (' + subClassOfLabel + ')')">
<button mat-menu-item
(click)="createResourceInstance(resourceClass.id, resourceClass.label + ' (' + subClassOfLabel + ')')">
Create new resource instance
</button>
</span>
<span [matTooltip]="(classCanBeDeleted ? 'This class doesn\'t have any instances yet' : null)" matTooltipPosition="before">
<span [matTooltip]="(classCanBeDeleted ? 'This class doesn\'t have any instances yet' : null)"
matTooltipPosition="before">
<button mat-menu-item (click)="openResourceInstances(resourceClass.id)" [disabled]="classCanBeDeleted">
Open resource instances
</button>
</span>
<span [matTooltip]="(classCanBeDeleted ? null : 'This class can\'t be deleted because it is in use')" matTooltipPosition="before">
<button mat-menu-item [disabled]="!classCanBeDeleted" class="res-class-delete"
<span *ngIf="userCanEdit"
[matTooltip]="classCanBeDeleted ? null : 'This class can\'t be deleted because it is in use'"
matTooltipPosition="before">
<button mat-menu-item [disabled]="!classCanBeDeleted || !userCanEdit" class="res-class-delete"
(click)="deleteResourceClass.emit({iri: resourceClass.id, label: resourceClass.label})">
Delete resource class
</button>
@@ -56,40 +63,40 @@
<mat-card-content *ngIf="expanded">
<mat-list cdkDropList class="resource-class-properties" (cdkDropListDropped)="drop($event)"
*ngIf="propsToDisplay.length; else noProperties">
<div cdkDrag [cdkDragDisabled]="!ontology.lastModificationDate || !cardinalityUpdateEnabled"
<div cdkDrag
[cdkDragDisabled]="(!ontology.lastModificationDate || !cardinalityUpdateEnabled) || !userCanEdit"
*ngFor="let prop of propsToDisplay; let i = index;">
<div class="drag-n-drop-placeholder" *cdkDragPlaceholder></div>
<mat-list-item class="property" [disabled]="loadProperty">
<span cdkDragHandle mat-list-icon class="list-icon gui-order">
<span [class.hide-on-hover]="cardinalityUpdateEnabled && lastModificationDate">{{i + 1}})</span>
<span *ngIf="lastModificationDate && cardinalityUpdateEnabled"
<span [class.hide-on-hover]="cardinalityUpdateEnabled && lastModificationDate && userCanEdit">
{{i + 1}})
</span>
<span *ngIf="cardinalityUpdateEnabled && lastModificationDate && userCanEdit"
class="display-on-hover drag-n-drop-handle">
<mat-icon>drag_indicator</mat-icon>
</span>
</span>
<!-- display only properties if they exist in list of properties;
objectType is not a linkValue (otherwise we have the property twice) -->
<app-property-info class="property-info"
[propDef]="propsToDisplay[i].propDef"
[propCard]="propsToDisplay[i]"
[projectCode]="projectCode"
[projectStatus]="projectStatus"
[resourceIri]="resourceClass.id"
[(lastModificationDate)]="lastModificationDate"
(removePropertyFromClass)="removeProperty($event)">
<app-property-info class="property-info" [propDef]="propsToDisplay[i].propDef"
[propCard]="propsToDisplay[i]" [projectCode]="projectCode" [projectStatus]="projectStatus"
[resourceIri]="resourceClass.id" [(lastModificationDate)]="lastModificationDate"
[userCanEdit]="userCanEdit" (removePropertyFromClass)="removeProperty($event)">
</app-property-info>
</mat-list-item>
</div>
</mat-list>
<!-- message if the class doesn't have any property -->
<!-- message if the class doesn't have any properties -->
<ng-template #noProperties>
<p>There is no property assigned to this class yet.</p>
<p>There are no properties assigned to this class yet.</p>
</ng-template>
<!-- button to assign new property to class -->
<mat-list>
<!-- here we have to know if the class has values or not;
this information is important to handle the cardinality (1 resp. 1-n); we get this information from the canReplaceCardinality method -->
<mat-list-item *ngIf="lastModificationDate && projectStatus" class="property link" [matMenuTriggerFor]="addPropertyMenu" (click)="canReplaceCardinality()">
<mat-list-item *ngIf="lastModificationDate && projectStatus && userCanEdit" class="property link"
[matMenuTriggerFor]="addPropertyMenu" (click)="canReplaceCardinality()">
<span mat-list-icon class="list-icon">
<mat-icon>add</mat-icon>
</span>
@@ -105,25 +112,25 @@
<ng-container *ngFor="let type of defaultProperties">
<button mat-menu-item [matMenuTriggerFor]="sub_menu">{{type.group}}</button>
<mat-menu #sub_menu="matMenu" class="default-nested-sub-menu">
<button mat-menu-item *ngFor="let ele of type.elements" [value]="ele"
[matTooltip]="ele.description" matTooltipPosition="after"
(click)="addNewProperty(ele)">
<button mat-menu-item *ngFor="let ele of type.elements" [value]="ele" [matTooltip]="ele.description"
matTooltipPosition="after" (click)="addNewProperty(ele)">
<mat-icon>{{ele.icon}}</mat-icon> {{ele.label}}
</button>
</mat-menu>
</ng-container>
</mat-menu>
<mat-menu #addExistingProp="matMenu" class="default-nested-sub-menu">
<ng-container *ngFor="let onto of existingProperties">
<button mat-menu-item [disabled]="!onto.properties.length" [matMenuTriggerFor]="sub_menu">{{ onto.ontologyLabel }}</button>
<button mat-menu-item [disabled]="!onto.properties.length" [matMenuTriggerFor]="sub_menu">{{
onto.ontologyLabel }}</button>
<mat-menu #sub_menu="matMenu" class="default-nested-sub-menu">
<button mat-menu-item *ngFor="let prop of onto.properties" [matTooltip]="prop.propDef.comment" matTooltipPosition="after"
(click)="addExistingProperty(prop)">
<button mat-menu-item *ngFor="let prop of onto.properties" [matTooltip]="prop.propDef.comment"
matTooltipPosition="after" (click)="addExistingProperty(prop)">
<mat-icon>{{prop.propType?.icon}}</mat-icon> {{prop.propDef.label}}
</button>
</mat-menu>
</ng-container>

</mat-menu>
</mat-card-content>
</mat-card>
</mat-card>
@@ -30,7 +30,7 @@ import { ResourceClassInfoComponent } from './resource-class-info.component';
* Property is of type simple text
*/
@Component({
template: '<app-resource-class-info #resClassInfo [resourceClass]="resourceClass" [projectStatus]="true"></app-resource-class-info>'
template: '<app-resource-class-info #resClassInfo [resourceClass]="resourceClass" [projectStatus]="true" [userCanEdit]="userCanEdit"></app-resource-class-info>'
})
class HostComponent implements OnInit {

@@ -41,6 +41,8 @@ class HostComponent implements OnInit {

resourceClass: ClassDefinition;

userCanEdit: boolean;

constructor(
private _cache: CacheService,
private _sortingService: SortingService
@@ -72,6 +74,8 @@ class HostComponent implements OnInit {
}
);

this.userCanEdit = true;

}

}
@@ -57,6 +57,8 @@ export class ResourceClassInfoComponent implements OnInit {

@Input() lastModificationDate?: string;

@Input() userCanEdit: boolean; // is user a project admin or sys admin?

// event emitter when the lastModificationDate changed; bidirectional binding with lastModificationDate parameter
@Output() lastModificationDateChange: EventEmitter<string> = new EventEmitter<string>();

0 comments on commit 02b5a48

Please sign in to comment.