From 077232b891621c5b34aee357921d5477fb7423a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Fri, 3 Jun 2022 17:38:55 +0200 Subject: [PATCH 01/11] feat(workflow): new project concept --- src/app/app-routing.module.ts | 71 ++++++++++ src/app/app.module.ts | 8 +- src/app/main/action/hint/hint.component.scss | 5 + src/app/main/action/hint/hint.component.ts | 31 ++++- .../ontology-class-instance.component.html | 1 + .../ontology-class-instance.component.scss | 0 .../ontology-class-instance.component.spec.ts | 25 ++++ .../ontology-class-instance.component.ts | 65 +++++++++ .../ontology-class-item.component.html | 16 +++ .../ontology-class-item.component.scss | 26 ++++ .../ontology-class-item.component.spec.ts | 25 ++++ .../ontology-class-item.component.ts | 81 ++++++++++++ .../ontology-classes.component.html | 5 + .../ontology-classes.component.scss | 0 .../ontology-classes.component.spec.ts | 25 ++++ .../ontology-classes.component.ts | 35 +++++ src/app/project/list/list.component.html | 2 +- src/app/project/list/list.component.ts | 17 ++- .../project/ontology/ontology.component.html | 4 +- .../project/ontology/ontology.component.scss | 12 ++ .../project/ontology/ontology.component.ts | 17 +++ src/app/project/ontology/ontology.service.ts | 16 ++- src/app/project/project.component.html | 123 ++++++++++++++++-- src/app/project/project.component.scss | 12 ++ src/app/project/project.component.ts | 100 ++++++++++++-- .../list-view/list-view.component.html | 8 +- .../list-view/list-view.component.scss | 4 + .../results/list-view/list-view.component.ts | 16 ++- src/assets/style/_layout.scss | 119 ++++++++++++----- 29 files changed, 799 insertions(+), 70 deletions(-) create mode 100644 src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html create mode 100644 src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.scss create mode 100644 src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts create mode 100644 src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts create mode 100644 src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html create mode 100644 src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss create mode 100644 src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts create mode 100644 src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts create mode 100644 src/app/project/beta/ontology-classes/ontology-classes.component.html create mode 100644 src/app/project/beta/ontology-classes/ontology-classes.component.scss create mode 100644 src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts create mode 100644 src/app/project/beta/ontology-classes/ontology-classes.component.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 4e17aed31c..ac2d7454b9 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -28,6 +28,8 @@ import { ResultsComponent } from './workspace/results/results.component'; import { SystemComponent } from './system/system.component'; import { ProjectsComponent } from './system/projects/projects.component'; import { UsersComponent } from './system/users/users.component'; +import { OntologyClassInstanceComponent } from './project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component'; +import { HintComponent } from './main/action/hint/hint.component'; const routes: Routes = [ { @@ -102,6 +104,75 @@ const routes: Routes = [ } ] }, + { + path: 'beta/project/:shortcode', + component: ProjectComponent, + children: [ + { + path: '', + pathMatch: 'full', + redirectTo: 'info' + }, + { + path: 'info', + component: BoardComponent + }, + { + path: 'collaboration', + component: CollaborationComponent, + canActivate: [AuthGuard] + }, + { + path: 'permissions', + component: PermissionComponent, + canActivate: [AuthGuard] + }, + { + path: 'ontology', + component: HintComponent, + data: { topic: 'ontology' } + }, + { + path: 'ontology/:onto', + component: OntologyComponent, + }, + { + path: 'ontology/:onto/:name', + component: OntologyClassInstanceComponent, + canActivate: [AuthGuard] + }, + { + path: 'class/:id', + component: OntologyClassInstanceComponent, + canActivate: [AuthGuard] + }, + { + path: 'class/:id/add', + component: OntologyClassInstanceComponent, + canActivate: [AuthGuard] + }, + { + path: 'class/:id/conf', + component: OntologyClassInstanceComponent, + canActivate: [AuthGuard] + }, + { + path: 'list', + component: HintComponent, + data: { topic: 'list' } + }, + { + path: 'list/:list', + component: ListComponent, + canActivate: [AuthGuard] + }, + { + path: '**', + component: StatusComponent, + data: { status: 404 } + } + ] + }, /* { path: 'user/:name', diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 04a6369c08..6d14d74683 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -161,6 +161,9 @@ import { FulltextSearchComponent } from './workspace/search/fulltext-search/full import { SearchPanelComponent } from './workspace/search/search-panel/search-panel.component'; import { HintComponent } from './main/action/hint/hint.component'; import { TextComponent } from './workspace/resource/representation/text/text.component'; +import { OntologyClassesComponent } from './project/beta/ontology-classes/ontology-classes.component'; +import { OntologyClassItemComponent } from './project/beta/ontology-classes/ontology-class-item/ontology-class-item.component'; +import { OntologyClassInstanceComponent } from './project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component'; // translate: AoT requires an exported function for factories export function httpLoaderFactory(httpClient: HttpClient) { @@ -308,7 +311,10 @@ export function httpLoaderFactory(httpClient: HttpClient) { VideoComponent, VideoPreviewComponent, HintComponent, - TextComponent + TextComponent, + OntologyClassesComponent, + OntologyClassItemComponent, + OntologyClassInstanceComponent ], imports: [ AngularSplitModule.forRoot(), diff --git a/src/app/main/action/hint/hint.component.scss b/src/app/main/action/hint/hint.component.scss index 1ff304cfbb..3acd9f206b 100644 --- a/src/app/main/action/hint/hint.component.scss +++ b/src/app/main/action/hint/hint.component.scss @@ -1,3 +1,8 @@ +:host { + padding: 16px; + display: block; +} + a { margin: 16px auto; diff --git a/src/app/main/action/hint/hint.component.ts b/src/app/main/action/hint/hint.component.ts index fe382771ea..91c847e726 100644 --- a/src/app/main/action/hint/hint.component.ts +++ b/src/app/main/action/hint/hint.component.ts @@ -1,4 +1,5 @@ import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-hint', @@ -13,9 +14,18 @@ export class HintComponent implements OnInit { documentation: string; - constructor() { } + constructor( + private _route: ActivatedRoute + ) { } ngOnInit(): void { + if (!this.topic) { + // but status is defined in app.routing + this._route.data.subscribe(data => { + this.topic = data.topic; + }); + } + this.content = this._getHint(this.topic); } @@ -43,6 +53,25 @@ export class HintComponent implements OnInit { `; break; + case 'ontology': + this.documentation = 'https://docs.dasch.swiss/DSP-APP/user-guide/project/#data-model'; + return `

Data Model

+

+ The definition of the data model (ontology) is the most important step. + The data model is indispensable for structuring your data. Our platform + provides a tool for an easy creation of one or more project data models. + First, you have to know which data and sources you want to work with. + The data model can be flexible and customizable. +

`; + break; + case 'list': + this.documentation = ''; + return `

List Data

+

+ Lists are very useful if you want to use controlled vocabulary to describe something. + Typical examples are keywords. +

`; + break; default: return `There's no hint implemented for the topic ${topic}.`; diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html new file mode 100644 index 0000000000..a037e21d2f --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html @@ -0,0 +1 @@ + diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.scss b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts new file mode 100644 index 0000000000..5efefd1092 --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OntologyClassInstanceComponent } from './ontology-class-instance.component'; + +describe('OntologyClassInstanceComponent', () => { + let component: OntologyClassInstanceComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ OntologyClassInstanceComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(OntologyClassInstanceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts new file mode 100644 index 0000000000..3946b7d04e --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts @@ -0,0 +1,65 @@ +import { Component, OnChanges, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { OntologyService } from 'src/app/project/ontology/ontology.service'; +import { SearchParams } from 'src/app/workspace/results/list-view/list-view.component'; + +@Component({ + selector: 'app-ontology-class-instance', + templateUrl: './ontology-class-instance.component.html', + styleUrls: ['./ontology-class-instance.component.scss'] +}) +export class OntologyClassInstanceComponent implements OnInit { + + classId: string; + + searchParams: SearchParams; + + constructor( + private _route: ActivatedRoute, + private _ontologyService: OntologyService + ) { + + // parameters from the url + const projectCode = this._route.parent.snapshot.params.shortcode; + + + this._route.params.subscribe(params => { + const iriBase = this._ontologyService.getIriBaseUrl(); + + const ontologyName = params['onto']; + const className = params['name']; + + // get the resource class id from route + this.classId = `${iriBase}/ontology/${projectCode}/${ontologyName}/v2#${className}`; + + this.searchParams = { + query: this._setGravsearch(this.classId), + mode: 'gravsearch' + }; + }); + + } + + ngOnInit(): void { + + } + + private _setGravsearch(iri: string): string { + return ` + PREFIX knora-api: + CONSTRUCT { + + ?mainRes knora-api:isMainResource true . + + } WHERE { + + ?mainRes a knora-api:Resource . + + ?mainRes a <${iri}> . + + } + + OFFSET 0`; + } + +} diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html new file mode 100644 index 0000000000..7c15936d6e --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html @@ -0,0 +1,16 @@ + + {{resClass.label}} + + + + + + + + {{results | i18nPlural: itemPluralMapping['instance']}} + + diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss new file mode 100644 index 0000000000..77ef525360 --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss @@ -0,0 +1,26 @@ +:host { + width: 100%; + + &:hover { + .mat-line.label { + .hover-only { + display: block; + } + } + } +} + +.mat-line.label { + width: 100%; + display: flex; + flex-direction: row; + height: 40px; + + .mat-subheading-2 { + padding-top: 6px; + } + + .hover-only { + display: none; + } +} diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts new file mode 100644 index 0000000000..76ace5f566 --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OntologyClassItemComponent } from './ontology-class-item.component'; + +describe('OntologyClassItemComponent', () => { + let component: OntologyClassItemComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ OntologyClassItemComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(OntologyClassItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts new file mode 100644 index 0000000000..5833d54be4 --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts @@ -0,0 +1,81 @@ +import { Component, Inject, Input, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ClassDefinition, KnoraApiConnection, CountQueryResponse, ApiResponseError } from '@dasch-swiss/dsp-js'; +import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { ErrorHandlerService } from 'src/app/main/services/error-handler.service'; +import { OntologyService } from 'src/app/project/ontology/ontology.service'; + +@Component({ + selector: 'app-ontology-class-item', + templateUrl: './ontology-class-item.component.html', + styleUrls: ['./ontology-class-item.component.scss'] +}) +export class OntologyClassItemComponent implements OnInit { + + @Input() resClass: ClassDefinition; + + gravsearch: string; + + results: number; + + link: string; + + // i18n setup + itemPluralMapping = { + instance: { + '=1': '1 instance', + other: '# instances' + } + }; + + constructor( + @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, + private _errorHandler: ErrorHandlerService, + private _ontologyService: OntologyService, + private _route: ActivatedRoute + ) { + + // console.log(this.link) + + } + + ngOnInit(): void { + + const projectCode = this._route.snapshot.params.shortcode; + const splitIri = this.resClass.id.split('#'); + const ontologyName = this._ontologyService.getOntologyName(splitIri[0]); + this.link = `/beta/project/${projectCode}/ontology/${ontologyName}/${splitIri[1]}`; + + + this.gravsearch = this._setGravsearch(this.resClass.id); + + // get number of resource instances + this._dspApiConnection.v2.search.doExtendedSearchCountQuery(this.gravsearch).subscribe( + (res: CountQueryResponse) => { + this.results = res.numberOfResults; + }, + (error: ApiResponseError) => { + this._errorHandler.showMessage(error); + } + ); + } + + private _setGravsearch(iri: string): string { + return ` + PREFIX knora-api: + CONSTRUCT { + + ?mainRes knora-api:isMainResource true . + + } WHERE { + + ?mainRes a knora-api:Resource . + + ?mainRes a <${iri}> . + + } + + OFFSET 0`; + } + +} diff --git a/src/app/project/beta/ontology-classes/ontology-classes.component.html b/src/app/project/beta/ontology-classes/ontology-classes.component.html new file mode 100644 index 0000000000..6adc248a8e --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-classes.component.html @@ -0,0 +1,5 @@ + + + + + diff --git a/src/app/project/beta/ontology-classes/ontology-classes.component.scss b/src/app/project/beta/ontology-classes/ontology-classes.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts new file mode 100644 index 0000000000..1c7b465f6b --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OntologyClassesComponent } from './ontology-classes.component'; + +describe('OntologyClassesComponent', () => { + let component: OntologyClassesComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ OntologyClassesComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(OntologyClassesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/project/beta/ontology-classes/ontology-classes.component.ts b/src/app/project/beta/ontology-classes/ontology-classes.component.ts new file mode 100644 index 0000000000..5d2802d8c7 --- /dev/null +++ b/src/app/project/beta/ontology-classes/ontology-classes.component.ts @@ -0,0 +1,35 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { ClassDefinition, Constants } from '@dasch-swiss/dsp-js'; +import { SortingService } from 'src/app/main/services/sorting.service'; + +@Component({ + selector: 'app-ontology-classes', + templateUrl: './ontology-classes.component.html', + styleUrls: ['./ontology-classes.component.scss'] +}) +export class OntologyClassesComponent implements OnInit { + + @Input() resClasses: ClassDefinition[]; + + classesToDisplay: ClassDefinition[] = []; + + constructor( + private _sortingService: SortingService + + ) { } + + ngOnInit(): void { + + // display only the classes which are not a subClass of Standoff and sort them by label + this.resClasses.forEach(resClass => { + if (resClass.subClassOf.length) { + const splittedSubClass = resClass.subClassOf[0].split('#'); + if (!splittedSubClass[0].includes(Constants.StandoffOntology) && !splittedSubClass[1].includes('Standoff')) { + this.classesToDisplay.push(resClass); + } + } + }); + this.classesToDisplay = this._sortingService.keySortByAlphabetical(this.classesToDisplay, 'label'); + } + +} diff --git a/src/app/project/list/list.component.html b/src/app/project/list/list.component.html index 6f51786f2f..02a0d428f7 100644 --- a/src/app/project/list/list.component.html +++ b/src/app/project/list/list.component.html @@ -3,7 +3,7 @@ -
+

Lists are reusable data

diff --git a/src/app/project/list/list.component.ts b/src/app/project/list/list.component.ts index 5f1686a0f4..bcf4d06d0e 100644 --- a/src/app/project/list/list.component.ts +++ b/src/app/project/list/list.component.ts @@ -73,6 +73,9 @@ export class ListComponent implements OnInit { // disable content on small devices disableContent = false; + // feature toggle for new concept + beta = false; + constructor( @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, private _cache: CacheService, @@ -97,6 +100,14 @@ export class ListComponent implements OnInit { // set the page title this._setPageTitle(); + // get feature toggle information if url contains beta + this.beta = (this._route.parent.snapshot.url[0].path === 'beta'); + if (this.beta) { + this._route.params.subscribe(params => { + this.openList(params['list']); + }); + } + } @HostListener('window:resize', ['$event']) onWindwoResize(e: Event) { @@ -196,8 +207,10 @@ export class ListComponent implements OnInit { this.list = this.lists.find(i => i.id === id); - const goto = 'project/' + this.projectCode + '/lists/' + encodeURIComponent(id); - this._router.navigateByUrl(goto, { skipLocationChange: false }); + if (!this.beta) { + const goto = 'project/' + this.projectCode + '/lists/' + encodeURIComponent(id); + this._router.navigateByUrl(goto, { skipLocationChange: false }); + } setTimeout(() => { this.loadList = false; diff --git a/src/app/project/ontology/ontology.component.html b/src/app/project/ontology/ontology.component.html index 554ba0316f..e01ad2e108 100644 --- a/src/app/project/ontology/ontology.component.html +++ b/src/app/project/ontology/ontology.component.html @@ -3,7 +3,7 @@ -
+

Define your metadata

@@ -55,7 +55,7 @@

- +

{ + const iriBase = this._ontologyService.getIriBaseUrl(); + + const ontologyName = params['onto']; + this.ontologyIri = `${iriBase}/ontology/${projectCode}/${ontologyName}/v2`; + this.ngOnInit(); + }); + console.warn('This is a pre-released (beta) project\'s ontology view'); + } + } @HostListener('window:resize', ['$event']) onWindwoResize(e: Event) { diff --git a/src/app/project/ontology/ontology.service.ts b/src/app/project/ontology/ontology.service.ts index 00f4d91c91..e904175135 100644 --- a/src/app/project/ontology/ontology.service.ts +++ b/src/app/project/ontology/ontology.service.ts @@ -1,11 +1,12 @@ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; import { Cardinality, - Constants, ReadOntology, + Constants, KnoraApiConfig, ReadOntology, ResourcePropertyDefinitionWithAllLanguages } from '@dasch-swiss/dsp-js'; import { Observable, of } from 'rxjs'; import { CacheService } from 'src/app/main/cache/cache.service'; +import { DspApiConfigToken } from 'src/app/main/declarations/dsp-api-tokens'; import { DefaultProperties, DefaultProperty, @@ -24,7 +25,8 @@ export class OntologyService { defaultProperties: PropertyCategory[] = DefaultProperties.data; constructor( - private _cache: CacheService + @Inject(DspApiConfigToken) private _dspApiConfig: KnoraApiConfig, + private _cache: CacheService, ) { } /** @@ -185,4 +187,12 @@ export class OntologyService { return of (propType); } + + getIriBaseUrl(): string { + return ( + ('http://' + this._dspApiConfig.apiHost) + + (this._dspApiConfig.apiPort !== null ? ':' + this._dspApiConfig.apiPort : '') + + this._dspApiConfig.apiPath + ); + } } diff --git a/src/app/project/project.component.html b/src/app/project/project.component.html index d8abe7dd91..5cfb7072c9 100644 --- a/src/app/project/project.component.html +++ b/src/app/project/project.component.html @@ -1,18 +1,115 @@
- - - - - + + + +
+ + + + + + +

{{project.longname}}

+
+ +

+ {{project.shortname | uppercase}} +

+
+
+ + + + + + + + + + + + + + + +
+ + {{onto.label}} + + + + +
+
+ + + + + + +
+ +
+ + + + + + + + + + + + + {{list.labels | appStringifyStringLiteral}} + + + + + + + +

Members

+
+ + + +
+
+ + + + +
+
diff --git a/src/app/project/project.component.scss b/src/app/project/project.component.scss index 97cac260ea..343bdf1b21 100644 --- a/src/app/project/project.component.scss +++ b/src/app/project/project.component.scss @@ -5,6 +5,18 @@ color: $warn; } +.section-title { + .hover-only { + display: none; + } + + &:hover { + .hover-only { + display: block; + } + } +} + // mobile device: tablet and smaller than a tablet @media (max-width: map-get($grid-breakpoints, tablet)) { a[id="ontologies"] { diff --git a/src/app/project/project.component.ts b/src/app/project/project.component.ts index 62cdefdc50..608c3c4f86 100644 --- a/src/app/project/project.component.ts +++ b/src/app/project/project.component.ts @@ -1,12 +1,24 @@ import { Component, Inject, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; -import { ActivatedRoute } from '@angular/router'; -import { ApiResponseData, ApiResponseError, KnoraApiConnection, ProjectResponse, ReadProject } from '@dasch-swiss/dsp-js'; +import { ActivatedRoute, Router } from '@angular/router'; +import { + ApiResponseData, + ApiResponseError, + KnoraApiConnection, + ListNodeInfo, + ListsResponse, + OntologiesMetadata, + ProjectResponse, + ReadOntology, + ReadProject +} from '@dasch-swiss/dsp-js'; import { AppGlobal } from '../app-global'; import { CacheService } from '../main/cache/cache.service'; import { DspApiConnectionToken } from '../main/declarations/dsp-api-tokens'; import { MenuItem } from '../main/declarations/menu-item'; +import { ErrorHandlerService } from '../main/services/error-handler.service'; import { Session, SessionService } from '../main/services/session.service'; +import { OntologyService } from './ontology/ontology.service'; @Component({ selector: 'app-project', @@ -33,16 +45,23 @@ export class ProjectComponent implements OnInit { color = 'primary'; - // for the sidenav - open = true; - navigation: MenuItem[] = AppGlobal.projectNav; + // feature toggle for new concept + beta = false; + + // list of project ontologies + projectOntologies: ReadOntology[] = []; + projectLists: ListNodeInfo[] = []; + constructor( @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, - private _session: SessionService, + private _errorHandler: ErrorHandlerService, private _cache: CacheService, + private _ontologyService: OntologyService, private _route: ActivatedRoute, + private _router: Router, + private _session: SessionService, private _titleService: Title ) { // get the shortcode of the current project @@ -55,7 +74,13 @@ export class ProjectComponent implements OnInit { this._titleService.setTitle('Project ' + this.projectCode); // error handling in case of wrong project shortcode - this.error = this.validateShortcode(this.projectCode); + this.error = this._validateShortcode(this.projectCode); + + // get feature toggle information if url contains beta + this.beta = (this._route.snapshot.url[0].path === 'beta'); + if (this.beta) { + console.warn('This is a pre-released (beta) project view'); + } } ngOnInit() { @@ -94,9 +119,47 @@ export class ProjectComponent implements OnInit { this._cache.get('groups_of_' + this.projectCode, this._dspApiConnection.admin.groupsEndpoint.getGroups()); } - if (this._cache.has(this.projectCode)) { - this.loading = false; + // in the new concept of project view, we have to make many requests to get all project relevant information + if(this.beta) { + // get all project ontologies + this._dspApiConnection.v2.onto.getOntologiesByProjectIri(this.project.id).subscribe( + (ontoMeta: OntologiesMetadata) => { + ontoMeta.ontologies.forEach(onto => { + this._dspApiConnection.v2.onto.getOntology(onto.id).subscribe( + (ontology: ReadOntology) => { + this.projectOntologies.push(ontology); + this.loading = !this._cache.has(this.projectCode); + }, + (error: ApiResponseError) => { + this.loading = false; + console.error(error); + // todo: add error handler + } + ); + }); + }, + (error: ApiResponseError) => { + this._errorHandler.showMessage(error); + } + ); + + // get all project lists + this._dspApiConnection.admin.listsEndpoint.getListsInProject(this.project.id).subscribe( + (lists: ApiResponseData) => { + this.projectLists = lists.body.lists; + + }, + (error: ApiResponseError) => { + this._errorHandler.showMessage(error); + } + ); + + } else { + if (this._cache.has(this.projectCode)) { + this.loading = false; + } } + }, (error: ApiResponseError) => { this.error = true; @@ -106,12 +169,29 @@ export class ProjectComponent implements OnInit { } } + /** + * open form to create new ontology, class, property or list + * @param type + */ + create(type: 'ontology' | 'class' | 'property' | 'list' | 'user') { + console.log('this will create a new', type); + } + + open(route: string, id?: string) { + if (route === 'ontology' && id) { + id = this._ontologyService.getOntologyName(id); + } + const param = (id ? `/${encodeURIComponent(id)}` : ''); + this._router.navigateByUrl(`/beta/project/${this.projectCode}/${route}${param}`); + + } + /** * checks if the shortcode is valid: hexadecimal and length = 4 * * @param code project shortcode which is a parameter in the route */ - validateShortcode(code: string) { + private _validateShortcode(code: string) { const regexp: any = /^[0-9A-Fa-f]+$/; return !(regexp.test(code) && code.length === 4); diff --git a/src/app/workspace/results/list-view/list-view.component.html b/src/app/workspace/results/list-view/list-view.component.html index 90eed167c5..b7fe62544f 100644 --- a/src/app/workspace/results/list-view/list-view.component.html +++ b/src/app/workspace/results/list-view/list-view.component.html @@ -1,12 +1,12 @@ -
+
- Display as  + diff --git a/src/app/workspace/results/list-view/list-view.component.scss b/src/app/workspace/results/list-view/list-view.component.scss index f63e4879e5..0f58de7a29 100644 --- a/src/app/workspace/results/list-view/list-view.component.scss +++ b/src/app/workspace/results/list-view/list-view.component.scss @@ -39,3 +39,7 @@ button.active { ::ng-deep .selected-resource { background-color: $black-20-opacity; } + +.beta { + height: 80px; +} diff --git a/src/app/workspace/results/list-view/list-view.component.ts b/src/app/workspace/results/list-view/list-view.component.ts index fc1f4f88ea..dd3a3eb41c 100644 --- a/src/app/workspace/results/list-view/list-view.component.ts +++ b/src/app/workspace/results/list-view/list-view.component.ts @@ -5,6 +5,7 @@ import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens' import { ErrorHandlerService } from 'src/app/main/services/error-handler.service'; import { ComponentCommunicationEventService, EmitEvent, Events } from 'src/app/main/services/component-communication-event.service'; import { NotificationService } from 'src/app/main/services/notification.service'; +import { ActivatedRoute } from '@angular/router'; /** * query: search query. It can be gravserch query or fulltext string query. @@ -91,12 +92,23 @@ export class ListViewComponent implements OnChanges { // progress status loading = true; + // feature toggle for new concept + beta = false; + constructor( @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, private _componentCommsService: ComponentCommunicationEventService, private _errorHandler: ErrorHandlerService, - private _notification: NotificationService - ) { } + private _notification: NotificationService, + private _route: ActivatedRoute + ) { + + // get feature toggle information if url contains beta + this.beta = (this._route.parent.snapshot.url[0].path === 'beta'); + if (this.beta) { + console.warn('This is a pre-released (beta) search results view'); + } + } ngOnChanges(): void { // reset diff --git a/src/assets/style/_layout.scss b/src/assets/style/_layout.scss index 85b586978b..77a9b4c3a1 100644 --- a/src/assets/style/_layout.scss +++ b/src/assets/style/_layout.scss @@ -26,6 +26,7 @@ // // content wrapper .content { + &.small, &.medium, &.large { @@ -48,53 +49,109 @@ // -------------------------------------- // -// sidenav (not used anymore...? 2019-03-18) -.sidenav-container { - .sidenav { - background-color: lighten($primary, 50%); - letter-spacing: 0.3px; - width: 36px; - - &.wide { - width: 240px; - } +// sidenav in project view +.project-view { + height: calc(100vh - #{$header-height}); - &.narrow { - width: 36px; + .project-nav { + width: 220px; + + .mat-title, + .mat-subheading-2, + .mat-subheading-1 { + margin: 0; } - .mat-drawer-inner-container { - overflow-x: hidden; + .mat-list-item { + height: 64px; - .mat-list { - padding-top: 0; + &:hover { + background: rgba(0, 0, 0, .04); } } - .side-nav-footer { - border-top: 1px solid rgba(0, 0, 0, 0.12); - bottom: 0; - height: 36px; - position: absolute; - width: 100%; + .mat-expansion-panel { + box-shadow: none !important; - .mat-button { - min-width: 30px; - padding: 0; - width: 100%; + .mat-expansion-panel-header { + padding: 0 16px !important; + // display: block !important; + } - .mat-icon { - margin: 0 auto; + .sidenav-panel-header{ + width: 100%; + mat-panel-title { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + width: 100%; + display: block; } } + + // reset default value, if the panel is expanded + &.mat-expanded mat-panel-title { + overflow: unset; + white-space: inherit; + text-overflow: unset; + display: flex; + } + + .mat-expansion-panel-body { + padding: 0 !important + } } } - .mat-sidenav-content { - background: #fff; - } } + +// .sidenav-container { +// .sidenav { +// background-color: lighten($primary, 50%); +// letter-spacing: 0.3px; +// width: 36px; + +// &.wide { +// width: 240px; +// } + +// &.narrow { +// width: 36px; +// } + +// .mat-drawer-inner-container { +// overflow-x: hidden; + +// .mat-list { +// padding-top: 0; +// } +// } + +// .side-nav-footer { +// border-top: 1px solid rgba(0, 0, 0, 0.12); +// bottom: 0; +// height: 36px; +// position: absolute; +// width: 100%; + +// .mat-button { +// min-width: 30px; +// padding: 0; +// width: 100%; + +// .mat-icon { +// margin: 0 auto; +// } +// } +// } +// } + +// .mat-sidenav-content { +// background: #fff; +// } +// } + // -------------------------------------- // From 8ba866d933e2a84b2d1937c3852513c705cc4557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Tue, 7 Jun 2022 13:15:08 +0200 Subject: [PATCH 02/11] feat(workflow): new project concept --- src/app/app-routing.module.ts | 32 ++++++------ .../ontology-class-instance.component.html | 14 ++++- .../ontology-class-instance.component.scss | 5 ++ .../ontology-class-instance.component.spec.ts | 32 ++++++------ .../ontology-class-instance.component.ts | 36 +++++++++---- .../ontology-class-item.component.html | 2 +- .../ontology-class-item.component.spec.ts | 32 ++++++------ .../ontology-class-item.component.ts | 2 - .../ontology-classes.component.spec.ts | 32 ++++++------ .../resource-instance-form.component.html | 11 ++-- .../resource-instance-form.component.ts | 51 ++++++++++++------- 11 files changed, 147 insertions(+), 102 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index ac2d7454b9..17d088147e 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,13 +1,13 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; - -import { AuthGuard } from './main/guard/auth.guard'; +import { HintComponent } from './main/action/hint/hint.component'; +import { LoginFormComponent } from './main/action/login-form/login-form.component'; import { CookiePolicyComponent } from './main/cookie-policy/cookie-policy.component'; -import { StatusComponent } from './main/status/status.component'; +import { AuthGuard } from './main/guard/auth.guard'; import { HelpComponent } from './main/help/help.component'; -import { LoginFormComponent } from './main/action/login-form/login-form.component'; import { MainComponent } from './main/main.component'; - +import { StatusComponent } from './main/status/status.component'; +import { OntologyClassInstanceComponent } from './project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component'; // project import { BoardComponent } from './project/board/board.component'; import { CollaborationComponent } from './project/collaboration/collaboration.component'; @@ -15,21 +15,21 @@ import { ListComponent } from './project/list/list.component'; import { OntologyComponent } from './project/ontology/ontology.component'; import { PermissionComponent } from './project/permission/permission.component'; import { ProjectComponent } from './project/project.component'; - +import { ProjectsComponent } from './system/projects/projects.component'; +// system +import { SystemComponent } from './system/system.component'; +import { UsersComponent } from './system/users/users.component'; // user import { DashboardComponent } from './user/dashboard/dashboard.component'; import { UserComponent } from './user/user.component'; - // search results and resource viewer import { ResourceComponent } from './workspace/resource/resource.component'; import { ResultsComponent } from './workspace/results/results.component'; -// system -import { SystemComponent } from './system/system.component'; -import { ProjectsComponent } from './system/projects/projects.component'; -import { UsersComponent } from './system/users/users.component'; -import { OntologyClassInstanceComponent } from './project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component'; -import { HintComponent } from './main/action/hint/hint.component'; + + + + const routes: Routes = [ { @@ -137,17 +137,17 @@ const routes: Routes = [ component: OntologyComponent, }, { - path: 'ontology/:onto/:name', + path: 'ontology/:onto/:class', component: OntologyClassInstanceComponent, canActivate: [AuthGuard] }, { - path: 'class/:id', + path: 'ontology/:onto/:class/:instance', component: OntologyClassInstanceComponent, canActivate: [AuthGuard] }, { - path: 'class/:id/add', + path: 'ontology/:onto/:class/conf', component: OntologyClassInstanceComponent, canActivate: [AuthGuard] }, diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html index a037e21d2f..0701456c2e 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html @@ -1 +1,13 @@ - + + + + +
+

Create new {{classId}} instance

+ + +
+ + diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.scss b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.scss index e69de29bb2..eedc4016e0 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.scss +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.scss @@ -0,0 +1,5 @@ +.instance-form { + max-width: 720px; + display: block; + padding: 16px; +} diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts index 5efefd1092..ee697a9504 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts @@ -3,23 +3,23 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { OntologyClassInstanceComponent } from './ontology-class-instance.component'; describe('OntologyClassInstanceComponent', () => { - let component: OntologyClassInstanceComponent; - let fixture: ComponentFixture; + let component: OntologyClassInstanceComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ OntologyClassInstanceComponent ] - }) - .compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ OntologyClassInstanceComponent ] + }) + .compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(OntologyClassInstanceComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(OntologyClassInstanceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts index 3946b7d04e..da61adba58 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts @@ -1,4 +1,4 @@ -import { Component, OnChanges, OnInit } from '@angular/core'; +import { Component, OnChanges, SimpleChanges } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { OntologyService } from 'src/app/project/ontology/ontology.service'; import { SearchParams } from 'src/app/workspace/results/list-view/list-view.component'; @@ -8,10 +8,14 @@ import { SearchParams } from 'src/app/workspace/results/list-view/list-view.comp templateUrl: './ontology-class-instance.component.html', styleUrls: ['./ontology-class-instance.component.scss'] }) -export class OntologyClassInstanceComponent implements OnInit { +export class OntologyClassInstanceComponent implements OnChanges { + + projectId: string; classId: string; + instanceId: string; + searchParams: SearchParams; constructor( @@ -22,28 +26,42 @@ export class OntologyClassInstanceComponent implements OnInit { // parameters from the url const projectCode = this._route.parent.snapshot.params.shortcode; + this.projectId = `http://rdfh.ch/projects/${projectCode}`; this._route.params.subscribe(params => { const iriBase = this._ontologyService.getIriBaseUrl(); const ontologyName = params['onto']; - const className = params['name']; + const className = params['class']; // get the resource class id from route this.classId = `${iriBase}/ontology/${projectCode}/${ontologyName}/v2#${className}`; - this.searchParams = { - query: this._setGravsearch(this.classId), - mode: 'gravsearch' - }; + this.instanceId = params['instance']; + if (this.instanceId) { + // single instance + + if (this.instanceId === 'add') { + // create new res class instance: display res instance form + } + } else { + this.searchParams = { + query: this._setGravsearch(this.classId), + mode: 'gravsearch' + }; + } }); - } - ngOnInit(): void { + ngOnChanges(changes: SimpleChanges): void { + + // this.reset(); + console.log('something has changed',); } + + private _setGravsearch(iri: string): string { return ` PREFIX knora-api: diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html index 7c15936d6e..bdffce51f6 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html @@ -4,7 +4,7 @@ - diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts index 76ace5f566..bda9aa57c1 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts @@ -3,23 +3,23 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { OntologyClassItemComponent } from './ontology-class-item.component'; describe('OntologyClassItemComponent', () => { - let component: OntologyClassItemComponent; - let fixture: ComponentFixture; + let component: OntologyClassItemComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ OntologyClassItemComponent ] - }) - .compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ OntologyClassItemComponent ] + }) + .compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(OntologyClassItemComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(OntologyClassItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts index 5833d54be4..836ccad3cb 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts @@ -35,8 +35,6 @@ export class OntologyClassItemComponent implements OnInit { private _route: ActivatedRoute ) { - // console.log(this.link) - } ngOnInit(): void { diff --git a/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts index 1c7b465f6b..7a25327c66 100644 --- a/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts +++ b/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts @@ -3,23 +3,23 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { OntologyClassesComponent } from './ontology-classes.component'; describe('OntologyClassesComponent', () => { - let component: OntologyClassesComponent; - let fixture: ComponentFixture; + let component: OntologyClassesComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ OntologyClassesComponent ] - }) - .compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ OntologyClassesComponent ] + }) + .compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(OntologyClassesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(OntologyClassesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html index 6c1a9a8f39..bdcaf3724a 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html @@ -70,6 +70,7 @@
- - - - + diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts index 25d18f71a7..f69dfe91c4 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Inject, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { @@ -34,6 +34,12 @@ import { SelectResourceClassComponent } from './select-resource-class/select-res }) export class ResourceInstanceFormComponent implements OnInit, OnDestroy { + // ontology's resource class iri + @Input() selectedResourceClassIri?: string; + + // corresponding project (iri) + @Input() selectedProject?: string; + // output to close dialog @Output() closeDialog: EventEmitter = new EventEmitter(); @@ -59,7 +65,6 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy { userWentBack = false; usersProjects: StoredProject[]; - selectedProject: string; ontologiesMetadata: OntologiesMetadata; selectedOntology: string; resourceClasses: ResourceClassDefinition[]; @@ -99,25 +104,33 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy { ngOnInit(): void { - - // parent form is empty, it gets passed to the child components - this.selectResourceForm = this._fb.group({}); - this.propertiesParentForm = this._fb.group({}); - - // initialize projects to be used for the project selection in the creation form - this._project.initializeProjects().subscribe( - (proj: StoredProject[]) => { - this.usersProjects = proj; - - // notifies the user that he/she is not part of any project - if (proj.length === 0) { - this.errorMessage = 'You are not a part of any active projects or something went wrong'; + if (this.selectedResourceClassIri && this.selectedProject) { + // get ontology iri from res class iri + const splittedIri = this.selectedResourceClassIri.split('#'); + this.selectedOntology = splittedIri[0]; + this.selectProperties(this.selectedResourceClassIri); + this.showNextStepForm = false; + this.propertiesParentForm = this._fb.group({}); + } else { + // parent form is empty, it gets passed to the child components + this.selectResourceForm = this._fb.group({}); + this.propertiesParentForm = this._fb.group({}); + + // initialize projects to be used for the project selection in the creation form + this._project.initializeProjects().subscribe( + (proj: StoredProject[]) => { + this.usersProjects = proj; + + // notifies the user that he/she is not part of any project + if (proj.length === 0) { + this.errorMessage = 'You are not a part of any active projects or something went wrong'; + } } - } - ); + ); + // boolean to show only the first step of the form (= selectResourceForm) + this.showNextStepForm = true; + } - // boolean to show only the first step of the form (= selectResourceForm) - this.showNextStepForm = true; } From a3cefa0e82df27051affc88ae50f8f799bf751e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Tue, 7 Jun 2022 13:25:06 +0200 Subject: [PATCH 03/11] feat(workflow): new project concept --- .../resource-instance-form.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html index bdcaf3724a..eeb666d4af 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html @@ -70,7 +70,7 @@ Date: Tue, 7 Jun 2022 14:58:37 +0200 Subject: [PATCH 04/11] feat(workflow): new project concept --- .../resource-instance-form.component.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts index f69dfe91c4..d7d5014e9b 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChange, SimpleChanges, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { @@ -32,7 +32,7 @@ import { SelectResourceClassComponent } from './select-resource-class/select-res templateUrl: './resource-instance-form.component.html', styleUrls: ['./resource-instance-form.component.scss'] }) -export class ResourceInstanceFormComponent implements OnInit, OnDestroy { +export class ResourceInstanceFormComponent implements OnInit, OnChanges, OnDestroy { // ontology's resource class iri @Input() selectedResourceClassIri?: string; @@ -130,8 +130,12 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy { // boolean to show only the first step of the form (= selectResourceForm) this.showNextStepForm = true; } + } - + ngOnChanges(changes: SimpleChanges) { + if(changes.selectedResourceClassIri) { + this.ngOnInit(); + } } ngOnDestroy() { From ddc89e71e3aedaeb1240670628c2c6ab8b63ac75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Wed, 8 Jun 2022 06:36:13 +0200 Subject: [PATCH 05/11] feat(workflow): new project concept --- src/app/app-routing.module.ts | 33 +++++++------------ .../ontology-class-instance.component.html | 28 ++++++++++++++-- .../ontology-class-instance.component.scss | 9 ++++- .../ontology-class-instance.component.ts | 25 +++++++++++++- .../ontology-class-item.component.html | 21 ++++++------ .../ontology-class-item.component.scss | 31 ++++++++++------- .../ontology-class-item.component.ts | 10 ++++-- .../project/ontology/ontology.component.ts | 2 +- .../workspace/results/results.component.ts | 2 +- 9 files changed, 108 insertions(+), 53 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 17d088147e..f0efb70968 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -117,16 +117,6 @@ const routes: Routes = [ path: 'info', component: BoardComponent }, - { - path: 'collaboration', - component: CollaborationComponent, - canActivate: [AuthGuard] - }, - { - path: 'permissions', - component: PermissionComponent, - canActivate: [AuthGuard] - }, { path: 'ontology', component: HintComponent, @@ -135,26 +125,15 @@ const routes: Routes = [ { path: 'ontology/:onto', component: OntologyComponent, + canActivate: [AuthGuard] }, { path: 'ontology/:onto/:class', component: OntologyClassInstanceComponent, - canActivate: [AuthGuard] }, { path: 'ontology/:onto/:class/:instance', component: OntologyClassInstanceComponent, - canActivate: [AuthGuard] - }, - { - path: 'ontology/:onto/:class/conf', - component: OntologyClassInstanceComponent, - canActivate: [AuthGuard] - }, - { - path: 'class/:id/conf', - component: OntologyClassInstanceComponent, - canActivate: [AuthGuard] }, { path: 'list', @@ -166,6 +145,16 @@ const routes: Routes = [ component: ListComponent, canActivate: [AuthGuard] }, + { + path: 'settings/collaboration', + component: CollaborationComponent, + canActivate: [AuthGuard] + }, + { + path: 'settings/permissions', + component: PermissionComponent, + canActivate: [AuthGuard] + }, { path: '**', component: StatusComponent, diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html index 0701456c2e..84cc457db1 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html @@ -1,8 +1,32 @@ - + +
+ + + + + + +
+ + + + + + + + + +
+
+
+
+ -
+

Create new {{classId}} instance

0) ? 'intermediate' : 'single'); + } + } + + } + private _setGravsearch(iri: string): string { diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html index bdffce51f6..acb38ff276 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.html @@ -1,16 +1,15 @@ - - {{resClass.label}} - - - - - - - {{results | i18nPlural: itemPluralMapping['instance']}} - - diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss index 77ef525360..f9b039c6cd 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.scss @@ -1,26 +1,33 @@ +@import "../../../../../assets/style/config"; :host { width: 100%; &:hover { - .mat-line.label { - .hover-only { + .hover-only { display: block; - } } } } -.mat-line.label { +.mat-line { width: 100%; - display: flex; - flex-direction: row; - height: 40px; - .mat-subheading-2 { - padding-top: 6px; - } + &.label { + display: flex; + flex-direction: row; - .hover-only { - display: none; } + &.instances { + color: $primary_500; + } +} + +.overlay-buttons { + position: absolute; + right: 0; + bottom: 12px; +} + +.hover-only { + display: none; } diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts index 836ccad3cb..5bda3b68f9 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, Input, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { ClassDefinition, KnoraApiConnection, CountQueryResponse, ApiResponseError } from '@dasch-swiss/dsp-js'; import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; import { ErrorHandlerService } from 'src/app/main/services/error-handler.service'; @@ -32,7 +32,8 @@ export class OntologyClassItemComponent implements OnInit { @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, private _errorHandler: ErrorHandlerService, private _ontologyService: OntologyService, - private _route: ActivatedRoute + private _route: ActivatedRoute, + private _router: Router ) { } @@ -58,6 +59,11 @@ export class OntologyClassItemComponent implements OnInit { ); } + open(route: string) { + // event.preventDefault(); + this._router.navigateByUrl(route); + } + private _setGravsearch(iri: string): string { return ` PREFIX knora-api: diff --git a/src/app/project/ontology/ontology.component.ts b/src/app/project/ontology/ontology.component.ts index d7c585c771..01e0cb5552 100644 --- a/src/app/project/ontology/ontology.component.ts +++ b/src/app/project/ontology/ontology.component.ts @@ -236,7 +236,7 @@ export class OntologyComponent implements OnInit { } else { // in case project has only one ontology: open this ontology // because there will be no form to select an ontlogy - if (response.ontologies.length === 1) { + if (response.ontologies.length === 1 && !this.beta) { // open this ontology this.openOntologyRoute(response.ontologies[0].id, this.view); this.ontologyIri = response.ontologies[0].id; diff --git a/src/app/workspace/results/results.component.ts b/src/app/workspace/results/results.component.ts index fccfc0bbc6..c07b854a4e 100644 --- a/src/app/workspace/results/results.component.ts +++ b/src/app/workspace/results/results.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute, Params } from '@angular/router'; import { FilteredResources, SearchParams } from './list-view/list-view.component'; From 362bb9eedfbeafa5b02f70b25102d34155b339d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Wed, 8 Jun 2022 09:07:27 +0200 Subject: [PATCH 06/11] feat(workflow): new project concept --- src/app/app-routing.module.ts | 5 ----- src/app/project/project.component.html | 2 +- .../resource-instance-form.component.html | 15 ++++++++++---- .../resource-instance-form.component.scss | 15 ++++++++++++++ .../resource-instance-form.component.ts | 20 ++++++++++++++++--- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index f0efb70968..4f22205037 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -110,11 +110,6 @@ const routes: Routes = [ children: [ { path: '', - pathMatch: 'full', - redirectTo: 'info' - }, - { - path: 'info', component: BoardComponent }, { diff --git a/src/app/project/project.component.html b/src/app/project/project.component.html index 5cfb7072c9..f443fb3819 100644 --- a/src/app/project/project.component.html +++ b/src/app/project/project.component.html @@ -22,7 +22,7 @@ - +

{{project.longname}}

diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html index fbf538b4cf..157c0fc084 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.html @@ -59,7 +59,13 @@ -
+ + -
+
+ - diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.scss b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.scss index 7848a587d3..71547276e6 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.scss +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.scss @@ -1,3 +1,5 @@ +@import "../../../../assets/style/config"; + .stepTwo { margin: 24px 56px !important; width: calc(100% - 144px); @@ -8,6 +10,18 @@ } } +.standalone { + margin: 0; + width: 100%; + + .form-action { + &.fixed-at-bottom { + background-color: #fafafa; + bottom: 0; + } + } +} + .form-action { width: 100%; margin-top: 24px; @@ -24,3 +38,4 @@ .errorIfNoElement { margin-bottom: 36px; } + diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts index b6752a6ad8..50d7f479b5 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { ApiResponseError, Constants, @@ -86,6 +86,9 @@ export class ResourceInstanceFormComponent implements OnInit, OnChanges, OnDestr valueOperationEventSubscription: Subscription; + // prepare content + preparing = false; + // loading in case of submit loading = false; // in case of any error error = false; @@ -93,16 +96,24 @@ export class ResourceInstanceFormComponent implements OnInit, OnChanges, OnDestr propertiesObj = {}; + // feature toggle for new concept + beta = false; + constructor( @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, private _errorHandler: ErrorHandlerService, private _fb: FormBuilder, private _project: ProjectService, private _resourceService: ResourceService, + private _route: ActivatedRoute, private _router: Router, private _sortingService: SortingService - ) { } - + ) { + // get feature toggle information if url contains beta + if(this._route.parent) { + this.beta = (this._route.parent.snapshot.url[0].path === 'beta'); + } + } ngOnInit(): void { if (this.selectedResourceClassIri && this.selectedProject) { @@ -390,6 +401,7 @@ export class ResourceInstanceFormComponent implements OnInit, OnChanges, OnDestr if (resourceClassIri === null) { this.selectResourceClasses(this.selectedOntology); } else if (resourceClassIri) { + this.preparing = true; this.loading = true; this._dspApiConnection.v2.ontologyCache.reloadCachedItem(this.selectedOntology).subscribe( (res: ReadOntology) => { @@ -437,10 +449,12 @@ export class ResourceInstanceFormComponent implements OnInit, OnChanges, OnDestr if (!this.selectPropertiesComponent && this.properties.length === 0 && !this.hasFileValue) { this.errorMessage = 'No properties defined for the selected resource.'; } + this.preparing = false; this.loading = false; }, (error: ApiResponseError) => { + this.preparing = false; this.loading = false; this._errorHandler.showMessage(error); } From 8288e6210283dd79c3812eceb1b604735e5c8c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Thu, 9 Jun 2022 07:07:23 +0200 Subject: [PATCH 07/11] test: start to fix unit tests --- .../ontology-class-instance.component.html | 2 +- .../ontology-class-instance.component.spec.ts | 44 ++++++++++- .../ontology-class-item.component.spec.ts | 78 +++++++++++++++++-- .../ontology-class-item.component.ts | 1 + .../ontology-classes.component.spec.ts | 55 +++++++++++-- src/app/project/project.component.spec.ts | 14 ++++ 6 files changed, 176 insertions(+), 18 deletions(-) diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html index 84cc457db1..88643b5630 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.html @@ -3,7 +3,7 @@
- diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts index ee697a9504..0bbddf82ad 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts @@ -1,14 +1,54 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - +import { MatDialogModule } from '@angular/material/dialog'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { ActivatedRoute } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { KnoraApiConnection } from '@dasch-swiss/dsp-js'; +import { Observable, of } from 'rxjs'; +import { AppInitService } from 'src/app/app-init.service'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { TestConfig } from 'test.config'; import { OntologyClassInstanceComponent } from './ontology-class-instance.component'; + describe('OntologyClassInstanceComponent', () => { let component: OntologyClassInstanceComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ OntologyClassInstanceComponent ] + declarations: [OntologyClassInstanceComponent], + imports: [ + MatSnackBarModule, + MatDialogModule, + RouterTestingModule + ], + providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, + { + provide: DspApiConnectionToken, + useValue: new KnoraApiConnection(TestConfig.ApiConfig) + }, + { + provide: ActivatedRoute, + useValue: { + params: of({ + onto: 'anything', + class: 'BlueThing', + }), + parent: { + snapshot: { + params: { shortcode: '0001' } + } + } + } + } + + ] }) .compileComponents(); }); diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts index bda9aa57c1..63fda2e6ab 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.spec.ts @@ -1,25 +1,87 @@ +import { Component, ViewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; - +import { MatDialogModule } from '@angular/material/dialog'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { By } from '@angular/platform-browser'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ClassDefinition, KnoraApiConnection } from '@dasch-swiss/dsp-js'; +import { AppInitService } from 'src/app/app-init.service'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { TestConfig } from 'test.config'; import { OntologyClassItemComponent } from './ontology-class-item.component'; +/** + * test host component to simulate parent component. + */ +@Component({ + selector: 'test-host-component', + template: ` + + + ` +}) +class TestHostComponent { + + @ViewChild('ontoClassItem') ontoClassItem: OntologyClassItemComponent; + + resClass: ClassDefinition = { + 'id': 'http://0.0.0.0:3333/ontology/0001/something/v2#Something', + 'subClassOf': ['http://0.0.0.0:3333/ontology/0001/anything/v2#Thing'], + 'comment': 'A something is a thing.', + 'label': 'Something', + 'propertiesList': [{ + 'propertyIndex': 'http://api.knora.org/ontology/knora-api/v2#arkUrl', + 'cardinality': 0, + 'isInherited': true + }, { + 'propertyIndex': 'http://api.knora.org/ontology/knora-api/v2#attachedToProject', + 'cardinality': 0, + 'isInherited': true + }] + }; +} + describe('OntologyClassItemComponent', () => { - let component: OntologyClassItemComponent; - let fixture: ComponentFixture; + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture; + let ontoClassItemComponentDe; + let hostCompDe; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ OntologyClassItemComponent ] + declarations: [OntologyClassItemComponent], + imports: [ + MatSnackBarModule, + MatDialogModule, + RouterTestingModule + ], + providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, + { + provide: DspApiConnectionToken, + useValue: new KnoraApiConnection(TestConfig.ApiConfig) + } + ] }) .compileComponents(); }); beforeEach(() => { - fixture = TestBed.createComponent(OntologyClassItemComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + + hostCompDe = testHostFixture.debugElement; + ontoClassItemComponentDe = hostCompDe.query(By.directive(OntologyClassItemComponent)); }); it('should create', () => { - expect(component).toBeTruthy(); + expect(testHostComponent).toBeTruthy(); + expect(testHostComponent.ontoClassItem).toBeTruthy(); }); }); diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts index 5bda3b68f9..8c37b48705 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts @@ -39,6 +39,7 @@ export class OntologyClassItemComponent implements OnInit { } ngOnInit(): void { + console.log(JSON.stringify(this.resClass)); const projectCode = this._route.snapshot.params.shortcode; const splitIri = this.resClass.id.split('#'); diff --git a/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts index 7a25327c66..9d005e8266 100644 --- a/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts +++ b/src/app/project/beta/ontology-classes/ontology-classes.component.spec.ts @@ -1,10 +1,47 @@ +import { Component, ViewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; - +import { By } from '@angular/platform-browser'; +import { ClassDefinition } from '@dasch-swiss/dsp-js'; import { OntologyClassesComponent } from './ontology-classes.component'; +/** + * test host component to simulate parent component. + */ +@Component({ + selector: 'test-host-component', + template: ` + + + ` +}) +class TestHostComponent { + + @ViewChild('ontoClasses') ontoClasses: OntologyClassesComponent; + + resClasses: ClassDefinition[] = [{ + 'id': 'http://0.0.0.0:3333/ontology/0001/something/v2#Something', + 'subClassOf': ['http://0.0.0.0:3333/ontology/0001/anything/v2#Thing'], + 'comment': 'A something is a thing.', + 'label': 'Something', + 'propertiesList': [{ + 'propertyIndex': 'http://api.knora.org/ontology/knora-api/v2#arkUrl', + 'cardinality': 0, + 'isInherited': true + }, { + 'propertyIndex': 'http://api.knora.org/ontology/knora-api/v2#attachedToProject', + 'cardinality': 0, + 'isInherited': true + }] + }]; +} + describe('OntologyClassesComponent', () => { - let component: OntologyClassesComponent; - let fixture: ComponentFixture; + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture; + let ontoClassItemComponentDe; + let hostCompDe; beforeEach(async () => { await TestBed.configureTestingModule({ @@ -14,12 +51,16 @@ describe('OntologyClassesComponent', () => { }); beforeEach(() => { - fixture = TestBed.createComponent(OntologyClassesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + + hostCompDe = testHostFixture.debugElement; + ontoClassItemComponentDe = hostCompDe.query(By.directive(OntologyClassesComponent)); }); it('should create', () => { - expect(component).toBeTruthy(); + expect(testHostComponent).toBeTruthy(); + expect(testHostComponent.ontoClasses).toBeTruthy(); }); }); diff --git a/src/app/project/project.component.spec.ts b/src/app/project/project.component.spec.ts index d2a0723bfe..9b10b79c5d 100644 --- a/src/app/project/project.component.spec.ts +++ b/src/app/project/project.component.spec.ts @@ -4,6 +4,7 @@ import { MatIconModule } from '@angular/material/icon'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatTabsModule } from '@angular/material/tabs'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { KnoraApiConnection, MockProjects, ProjectResponse, ReadProject } from '@dasch-swiss/dsp-js'; import { of } from 'rxjs'; @@ -50,6 +51,19 @@ describe('ProjectComponent', () => { { provide: CacheService, useValue: cacheServiceSpy + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + url: [ + { path: 'beta' } + ], + params: [ + { shortcode: '0001' } + ] + } + } } ] }).compileComponents(); From 9b522bf1131410496a78afdafceb1de442a58aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Thu, 9 Jun 2022 08:55:53 +0200 Subject: [PATCH 08/11] test(list): refactor tests and list route --- src/app/app-routing.module.ts | 5 ----- src/app/project/list/list.component.spec.ts | 15 ++++++++++++++- src/app/project/list/list.component.ts | 4 +++- src/app/project/ontology/ontology.service.ts | 2 +- src/app/project/project.component.spec.ts | 2 +- src/app/project/project.component.ts | 7 +++++++ .../results/list-view/list-view.component.spec.ts | 13 +++++++++++++ 7 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 4f22205037..0aed0fcffe 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -26,11 +26,6 @@ import { UserComponent } from './user/user.component'; import { ResourceComponent } from './workspace/resource/resource.component'; import { ResultsComponent } from './workspace/results/results.component'; - - - - - const routes: Routes = [ { path: '', diff --git a/src/app/project/list/list.component.spec.ts b/src/app/project/list/list.component.spec.ts index e5daea0e1e..b66e453b49 100644 --- a/src/app/project/list/list.component.spec.ts +++ b/src/app/project/list/list.component.spec.ts @@ -111,7 +111,20 @@ describe('ListComponent', () => { return TestConfig.ProjectCode; } } - }) + }), + snapshot: { + url: [ + { path: 'project' } + ] + } + }, + params: of( + { list: 'mockList01' }, + ), + snapshot: { + params: [ + { id: 'http://rdfh.ch/lists/0001/mockList01' } + ] } } }, diff --git a/src/app/project/list/list.component.ts b/src/app/project/list/list.component.ts index bcf4d06d0e..0c287da87d 100644 --- a/src/app/project/list/list.component.ts +++ b/src/app/project/list/list.component.ts @@ -103,8 +103,10 @@ export class ListComponent implements OnInit { // get feature toggle information if url contains beta this.beta = (this._route.parent.snapshot.url[0].path === 'beta'); if (this.beta) { + // get list iri from list name this._route.params.subscribe(params => { - this.openList(params['list']); + const id = `http://rdfh.ch/lists/${this.projectCode}/${params['list']}`; + this.openList(id); }); } diff --git a/src/app/project/ontology/ontology.service.ts b/src/app/project/ontology/ontology.service.ts index e904175135..7bb2d9ee7a 100644 --- a/src/app/project/ontology/ontology.service.ts +++ b/src/app/project/ontology/ontology.service.ts @@ -61,7 +61,7 @@ export class OntologyService { const pos = array.length - 2; - return array[pos].toLowerCase(); + return array[pos]; } /** diff --git a/src/app/project/project.component.spec.ts b/src/app/project/project.component.spec.ts index 9b10b79c5d..f78f2b055f 100644 --- a/src/app/project/project.component.spec.ts +++ b/src/app/project/project.component.spec.ts @@ -57,7 +57,7 @@ describe('ProjectComponent', () => { useValue: { snapshot: { url: [ - { path: 'beta' } + { path: 'project' } ], params: [ { shortcode: '0001' } diff --git a/src/app/project/project.component.ts b/src/app/project/project.component.ts index 608c3c4f86..6058c55706 100644 --- a/src/app/project/project.component.ts +++ b/src/app/project/project.component.ts @@ -179,8 +179,15 @@ export class ProjectComponent implements OnInit { open(route: string, id?: string) { if (route === 'ontology' && id) { + // get name of ontology id = this._ontologyService.getOntologyName(id); } + if (route === 'list' && id) { + // get name of list + const array = id.split('/'); + const pos = array.length - 1; + id = array[pos]; + } const param = (id ? `/${encodeURIComponent(id)}` : ''); this._router.navigateByUrl(`/beta/project/${this.projectCode}/${route}${param}`); diff --git a/src/app/workspace/results/list-view/list-view.component.spec.ts b/src/app/workspace/results/list-view/list-view.component.spec.ts index 9f2c3c6259..05fb14fb87 100644 --- a/src/app/workspace/results/list-view/list-view.component.spec.ts +++ b/src/app/workspace/results/list-view/list-view.component.spec.ts @@ -6,6 +6,7 @@ import { MatIconModule } from '@angular/material/icon'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ActivatedRoute } from '@angular/router'; import { CountQueryResponse, IFulltextSearchParams, MockResource, ReadResourceSequence, SearchEndpointV2 } from '@dasch-swiss/dsp-js'; import { of } from 'rxjs'; import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; @@ -126,6 +127,18 @@ describe('ListViewComponent', () => { provide: DspApiConnectionToken, useValue: searchSpyObj }, + { + provide: ActivatedRoute, + useValue: { + parent: { + snapshot: { + url: [ + { path: 'project' } + ], + } + } + } + } ] }) .compileComponents(); From 33ad46e3be475093da8b1a763870b60d8b5c570a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Thu, 9 Jun 2022 16:03:28 +0200 Subject: [PATCH 09/11] test: refactor and resolve unit tests --- .../main/action/hint/hint.component.spec.ts | 4 ++- .../ontology-class-instance.component.spec.ts | 13 ++++++-- .../ontology-class-instance.component.ts | 4 ++- src/app/project/list/list.component.spec.ts | 11 +++++++ src/app/project/list/list.component.ts | 4 ++- .../ontology/ontology.component.spec.ts | 31 ++++++++++++++----- .../project/ontology/ontology.service.spec.ts | 16 ++++++++-- src/app/project/ontology/ontology.service.ts | 5 +++ .../property-form.component.spec.ts | 9 +++++- .../property-info.component.spec.ts | 9 +++++- .../resource-class-info.component.spec.ts | 11 +++++-- .../resource-class-info.component.ts | 1 - .../expert-search.component.spec.ts | 29 ++++++++++------- .../expert-search/expert-search.component.ts | 22 +++---------- 14 files changed, 120 insertions(+), 49 deletions(-) diff --git a/src/app/main/action/hint/hint.component.spec.ts b/src/app/main/action/hint/hint.component.spec.ts index 1f29135540..6cb1f0e58d 100644 --- a/src/app/main/action/hint/hint.component.spec.ts +++ b/src/app/main/action/hint/hint.component.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIconModule } from '@angular/material/icon'; +import { RouterTestingModule } from '@angular/router/testing'; import { HintComponent } from './hint.component'; @@ -13,7 +14,8 @@ describe('HintComponent', () => { HintComponent ], imports: [ - MatIconModule + MatIconModule, + RouterTestingModule ] }) .compileComponents(); diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts index 0bbddf82ad..209ac10513 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.spec.ts @@ -4,7 +4,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { KnoraApiConnection } from '@dasch-swiss/dsp-js'; -import { Observable, of } from 'rxjs'; +import { of } from 'rxjs'; import { AppInitService } from 'src/app/app-init.service'; import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; import { TestConfig } from 'test.config'; @@ -15,6 +15,12 @@ describe('OntologyClassInstanceComponent', () => { let component: OntologyClassInstanceComponent; let fixture: ComponentFixture; + const appInitSpy = { + dspAppConfig: { + iriBase: 'http://rdfh.ch' + } + }; + beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [OntologyClassInstanceComponent], @@ -24,7 +30,10 @@ describe('OntologyClassInstanceComponent', () => { RouterTestingModule ], providers: [ - AppInitService, + { + provide: AppInitService, + useValue: appInitSpy + }, { provide: DspApiConfigToken, useValue: TestConfig.ApiConfig diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts index ee0b327f19..2ad287f32f 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts @@ -1,5 +1,6 @@ import { Component, OnChanges, SimpleChanges } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { AppInitService } from 'src/app/app-init.service'; import { OntologyService } from 'src/app/project/ontology/ontology.service'; import { FilteredResources, SearchParams } from 'src/app/workspace/results/list-view/list-view.component'; import { SplitSize } from 'src/app/workspace/results/results.component'; @@ -28,6 +29,7 @@ export class OntologyClassInstanceComponent implements OnChanges { splitSizeChanged: SplitSize; constructor( + private _ais: AppInitService, private _route: ActivatedRoute, private _ontologyService: OntologyService ) { @@ -35,7 +37,7 @@ export class OntologyClassInstanceComponent implements OnChanges { // parameters from the url const projectCode = this._route.parent.snapshot.params.shortcode; - this.projectId = `http://rdfh.ch/projects/${projectCode}`; + this.projectId = `${this._ais.dspAppConfig.iriBase}/projects/${projectCode}`; this._route.params.subscribe(params => { const iriBase = this._ontologyService.getIriBaseUrl(); diff --git a/src/app/project/list/list.component.spec.ts b/src/app/project/list/list.component.spec.ts index b66e453b49..94f3c7da4b 100644 --- a/src/app/project/list/list.component.spec.ts +++ b/src/app/project/list/list.component.spec.ts @@ -20,6 +20,7 @@ import { ApiResponseData, DeleteListResponse, ListNodeInfo, ListsEndpointAdmin, import { TranslateModule } from '@ngx-translate/core'; import { of } from 'rxjs'; import { AjaxResponse } from 'rxjs/ajax'; +import { AppInitService } from 'src/app/app-init.service'; import { CacheService } from 'src/app/main/cache/cache.service'; import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; import { DialogHeaderComponent } from 'src/app/main/dialog/dialog-header/dialog-header.component'; @@ -62,6 +63,12 @@ describe('ListComponent', () => { let rootLoader: HarnessLoader; let overlayContainer: OverlayContainer; + const appInitSpy = { + dspAppConfig: { + iriBase: 'http://rdfh.ch' + } + }; + beforeEach(waitForAsync(() => { const dspConnSpyObj = { @@ -128,6 +135,10 @@ describe('ListComponent', () => { } } }, + { + provide: AppInitService, + useValue: appInitSpy + }, { provide: DspApiConnectionToken, useValue: dspConnSpyObj diff --git a/src/app/project/list/list.component.ts b/src/app/project/list/list.component.ts index 0c287da87d..6372791d9d 100644 --- a/src/app/project/list/list.component.ts +++ b/src/app/project/list/list.component.ts @@ -15,6 +15,7 @@ import { StringLiteral } from '@dasch-swiss/dsp-js'; import { AppGlobal } from 'src/app/app-global'; +import { AppInitService } from 'src/app/app-init.service'; import { CacheService } from 'src/app/main/cache/cache.service'; import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; import { DialogComponent } from 'src/app/main/dialog/dialog.component'; @@ -78,6 +79,7 @@ export class ListComponent implements OnInit { constructor( @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, + private _ais: AppInitService, private _cache: CacheService, private _dialog: MatDialog, private _errorHandler: ErrorHandlerService, @@ -105,7 +107,7 @@ export class ListComponent implements OnInit { if (this.beta) { // get list iri from list name this._route.params.subscribe(params => { - const id = `http://rdfh.ch/lists/${this.projectCode}/${params['list']}`; + const id = `${this._ais.dspAppConfig.iriBase}/lists/${this.projectCode}/${params['list']}`; this.openList(id); }); } diff --git a/src/app/project/ontology/ontology.component.spec.ts b/src/app/project/ontology/ontology.component.spec.ts index 92da0bb479..ab79f0673d 100644 --- a/src/app/project/ontology/ontology.component.spec.ts +++ b/src/app/project/ontology/ontology.component.spec.ts @@ -28,8 +28,9 @@ import { } from '@dasch-swiss/dsp-js'; import { of } from 'rxjs'; import { AjaxResponse } from 'rxjs/ajax'; +import { AppInitService } from 'src/app/app-init.service'; import { CacheService } from 'src/app/main/cache/cache.service'; -import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; import { DialogComponent } from 'src/app/main/dialog/dialog.component'; import { StatusComponent } from 'src/app/main/status/status.component'; import { TestConfig } from 'test.config'; @@ -42,7 +43,7 @@ describe('OntologyComponent', () => { let fixture: ComponentFixture; beforeEach(waitForAsync(() => { - const ontologyEndpointSpyObj = { + const apiSpyObj = { admin: { listsEndpoint: jasmine.createSpyObj('listsEndpoint', ['getListsInProject']) }, @@ -86,6 +87,15 @@ describe('OntologyComponent', () => { RouterTestingModule ], providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, + { + provide: DspApiConnectionToken, + useValue: apiSpyObj + }, { provide: ActivatedRoute, useValue: { @@ -96,14 +106,19 @@ describe('OntologyComponent', () => { return TestConfig.ProjectCode; } } - }) - } + }), + snapshot: { + params: { shortcode: '0001' }, + url: [ + { path: 'project' } + ] + } + }, + params: of({ + onto: 'anything' + }), } }, - { - provide: DspApiConnectionToken, - useValue: ontologyEndpointSpyObj - }, { provide: CacheService, useValue: cacheServiceSpy diff --git a/src/app/project/ontology/ontology.service.spec.ts b/src/app/project/ontology/ontology.service.spec.ts index 438d058d08..a724c7ffcc 100644 --- a/src/app/project/ontology/ontology.service.spec.ts +++ b/src/app/project/ontology/ontology.service.spec.ts @@ -1,8 +1,11 @@ import { TestBed } from '@angular/core/testing'; +import { KnoraApiConnection } from '@dasch-swiss/dsp-js'; +import { AppInitService } from 'src/app/app-init.service'; import { CacheService } from 'src/app/main/cache/cache.service'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { TestConfig } from 'test.config'; import { OntologyService } from './ontology.service'; - describe('OntologyService', () => { let service: OntologyService; @@ -11,10 +14,19 @@ describe('OntologyService', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, + { + provide: DspApiConnectionToken, + useValue: new KnoraApiConnection(TestConfig.ApiConfig) + }, { provide: CacheService, useValue: cacheServiceSpy - }, + } ] }); service = TestBed.inject(OntologyService); diff --git a/src/app/project/ontology/ontology.service.ts b/src/app/project/ontology/ontology.service.ts index 7bb2d9ee7a..cd09e069de 100644 --- a/src/app/project/ontology/ontology.service.ts +++ b/src/app/project/ontology/ontology.service.ts @@ -188,6 +188,11 @@ export class OntologyService { } + /** + * get the IRI base url without configured api protocol. + * The protocol in this case is always http + * TODO: move to DSP-JS-Lib similar to `get ApiUrl` + */ getIriBaseUrl(): string { return ( ('http://' + this._dspApiConfig.apiHost) + diff --git a/src/app/project/ontology/property-form/property-form.component.spec.ts b/src/app/project/ontology/property-form/property-form.component.spec.ts index 8f2a663b52..1c808a9619 100644 --- a/src/app/project/ontology/property-form/property-form.component.spec.ts +++ b/src/app/project/ontology/property-form/property-form.component.spec.ts @@ -17,8 +17,10 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ListNodeInfo, MockOntology, ReadOntology } from '@dasch-swiss/dsp-js'; import { TranslateModule } from '@ngx-translate/core'; import { of } from 'rxjs'; +import { AppInitService } from 'src/app/app-init.service'; import { CacheService } from 'src/app/main/cache/cache.service'; -import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { TestConfig } from 'test.config'; import { PropertyInfoObject } from '../default-data/default-properties'; import { PropertyFormComponent } from './property-form.component'; @@ -232,6 +234,11 @@ describe('PropertyFormComponent', () => { TranslateModule.forRoot() ], providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, { provide: DspApiConnectionToken, useValue: ontologyEndpointSpyObj diff --git a/src/app/project/ontology/property-info/property-info.component.spec.ts b/src/app/project/ontology/property-info/property-info.component.spec.ts index f8e149208c..a3fac2eedd 100644 --- a/src/app/project/ontology/property-info/property-info.component.spec.ts +++ b/src/app/project/ontology/property-info/property-info.component.spec.ts @@ -23,11 +23,13 @@ import { ResourcePropertyDefinitionWithAllLanguages } from '@dasch-swiss/dsp-js'; import { of } from 'rxjs'; +import { AppInitService } from 'src/app/app-init.service'; import { CacheService } from 'src/app/main/cache/cache.service'; -import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; import { DialogHeaderComponent } from 'src/app/main/dialog/dialog-header/dialog-header.component'; import { DialogComponent } from 'src/app/main/dialog/dialog.component'; import { SplitPipe } from 'src/app/main/pipes/split.pipe'; +import { TestConfig } from 'test.config'; import { PropertyFormComponent } from '../property-form/property-form.component'; import { PropertyInfoComponent } from './property-info.component'; @@ -207,6 +209,11 @@ describe('PropertyInfoComponent', () => { MatTooltipModule ], providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, { provide: DspApiConnectionToken, useValue: ontologyEndpointSpyObj diff --git a/src/app/project/ontology/resource-class-info/resource-class-info.component.spec.ts b/src/app/project/ontology/resource-class-info/resource-class-info.component.spec.ts index fca966a943..044332fdd0 100644 --- a/src/app/project/ontology/resource-class-info/resource-class-info.component.spec.ts +++ b/src/app/project/ontology/resource-class-info/resource-class-info.component.spec.ts @@ -14,13 +14,15 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatTooltipModule } from '@angular/material/tooltip'; import { By } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { CanDoResponse, ClassDefinition, Constants, MockOntology, OntologiesEndpointV2, OntologiesMetadata, OntologyMetadata, ReadOntology } from '@dasch-swiss/dsp-js'; +import { CanDoResponse, ClassDefinition, Constants, MockOntology, OntologiesEndpointV2, ReadOntology } from '@dasch-swiss/dsp-js'; import { of } from 'rxjs'; +import { AppInitService } from 'src/app/app-init.service'; import { CacheService } from 'src/app/main/cache/cache.service'; -import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; import { SplitPipe } from 'src/app/main/pipes/split.pipe'; import { TruncatePipe } from 'src/app/main/pipes/string-transformation/truncate.pipe'; import { SortingService } from 'src/app/main/services/sorting.service'; +import { TestConfig } from 'test.config'; import { ResourceClassInfoComponent } from './resource-class-info.component'; /** @@ -110,6 +112,11 @@ describe('ResourceClassInfoComponent', () => { MatTooltipModule ], providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, { provide: DspApiConnectionToken, useValue: ontologyEndpointSpyObj diff --git a/src/app/project/ontology/resource-class-info/resource-class-info.component.ts b/src/app/project/ontology/resource-class-info/resource-class-info.component.ts index ce380ece52..69c9bf6f85 100644 --- a/src/app/project/ontology/resource-class-info/resource-class-info.component.ts +++ b/src/app/project/ontology/resource-class-info/resource-class-info.component.ts @@ -524,7 +524,6 @@ OFFSET 0`; } ); - const dialogConfig: MatDialogConfig = { width: '840px', maxHeight: '80vh', diff --git a/src/app/workspace/search/expert-search/expert-search.component.spec.ts b/src/app/workspace/search/expert-search/expert-search.component.spec.ts index b55fd7e97f..eb84a5fb94 100644 --- a/src/app/workspace/search/expert-search/expert-search.component.spec.ts +++ b/src/app/workspace/search/expert-search/expert-search.component.spec.ts @@ -4,10 +4,13 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; import { By } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { KnoraApiConfig } from '@dasch-swiss/dsp-js'; -import { DspApiConfigToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { KnoraApiConnection } from '@dasch-swiss/dsp-js'; +import { AppInitService } from 'src/app/app-init.service'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { TestConfig } from 'test.config'; import { SearchParams } from '../../results/list-view/list-view.component'; import { AdvancedSearchParams, AdvancedSearchParamsService } from '../services/advanced-search-params.service'; import { ExpertSearchComponent } from './expert-search.component'; @@ -44,8 +47,6 @@ describe('ExpertSearchComponent', () => { beforeEach(waitForAsync(() => { - const dspConfSpy = new KnoraApiConfig('http', 'localhost', 3333, undefined, undefined, true); - const spy = jasmine.createSpyObj('SearchParamsService', ['changeSearchParamsMsg']); TestBed.configureTestingModule({ @@ -59,12 +60,18 @@ describe('ExpertSearchComponent', () => { MatDialogModule, MatFormFieldModule, MatInputModule, + MatSnackBarModule, ReactiveFormsModule ], providers: [ + AppInitService, { provide: DspApiConfigToken, - useValue: dspConfSpy + useValue: TestConfig.ApiConfig + }, + { + provide: DspApiConnectionToken, + useValue: new KnoraApiConnection(TestConfig.ApiConfig) }, { provide: AdvancedSearchParamsService, @@ -100,7 +107,7 @@ describe('ExpertSearchComponent', () => { expect(textareaEle.value).toBe( `PREFIX knora-api: -PREFIX incunabula: +PREFIX incunabula: CONSTRUCT { ?book knora-api:isMainResource true . @@ -133,7 +140,7 @@ CONSTRUCT { // reset the textarea content expect(textareaEle.value).toBe( `PREFIX knora-api: -PREFIX incunabula: +PREFIX incunabula: CONSTRUCT { ?book knora-api:isMainResource true . @@ -150,7 +157,7 @@ CONSTRUCT { it('should register the query in the params service', () => { const expectedGravsearch = `PREFIX knora-api: -PREFIX incunabula: +PREFIX incunabula: CONSTRUCT { ?book knora-api:isMainResource true . @@ -178,7 +185,7 @@ CONSTRUCT { it('should emit the Gravsearch query', () => { const expectedGravsearch = `PREFIX knora-api: -PREFIX incunabula: +PREFIX incunabula: CONSTRUCT { ?book knora-api:isMainResource true . @@ -214,7 +221,7 @@ CONSTRUCT { expect(textareaEle.value).toBe( `PREFIX knora-api: -PREFIX incunabula: +PREFIX incunabula: CONSTRUCT { ?book knora-api:isMainResource true . @@ -229,7 +236,7 @@ CONSTRUCT { textareaEle.value = `PREFIX knora-api: -PREFIX incunabula: +PREFIX incunabula: CONSTRUCT { ?book knora-api:isMainResource true . diff --git a/src/app/workspace/search/expert-search/expert-search.component.ts b/src/app/workspace/search/expert-search/expert-search.component.ts index 25d791c62f..e0803ca49e 100644 --- a/src/app/workspace/search/expert-search/expert-search.component.ts +++ b/src/app/workspace/search/expert-search/expert-search.component.ts @@ -1,7 +1,6 @@ -import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; import { AbstractControl, FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; -import { KnoraApiConfig } from '@dasch-swiss/dsp-js'; -import { DspApiConfigToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { OntologyService } from 'src/app/project/ontology/ontology.service'; import { SearchParams } from '../../results/list-view/list-view.component'; import { AdvancedSearchParams, AdvancedSearchParamsService } from '../services/advanced-search-params.service'; @@ -34,7 +33,7 @@ export class ExpertSearchComponent implements OnInit { expertSearchForm: FormGroup; queryFormControl: FormControl; - iriBaseUrl = this._getIriBaseUrl(); + iriBaseUrl = this._os.getIriBaseUrl(); defaultGravsearchQuery = `PREFIX knora-api: @@ -51,7 +50,7 @@ CONSTRUCT { `; constructor( - @Inject(DspApiConfigToken) private _dspApiConfig: KnoraApiConfig, + private _os: OntologyService, private _searchParamsService: AdvancedSearchParamsService, private _fb: FormBuilder ) { } @@ -121,17 +120,4 @@ CONSTRUCT { return query + offsetTemplate; } - /** - * get the IRI base url without configured api protocol. - * The protocol in this case is always http - * TODO: move to DSP-JS-Lib similar to `get ApiUrl` - */ - private _getIriBaseUrl(): string { - return ( - ('http://' + this._dspApiConfig.apiHost) + - (this._dspApiConfig.apiPort !== null ? ':' + this._dspApiConfig.apiPort : '') + - this._dspApiConfig.apiPath - ); - } - } From e6232bb52d5e08ef80ba2515781b00098675a79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Thu, 9 Jun 2022 16:07:31 +0200 Subject: [PATCH 10/11] chore(beta): avoid 404 when old route is active --- src/app/app-routing.module.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 0aed0fcffe..db09fc7c44 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -107,6 +107,10 @@ const routes: Routes = [ path: '', component: BoardComponent }, + { + path: 'info', // old path setup to avoid 404 when typing beta in front of project + redirectTo: '' + }, { path: 'ontology', component: HintComponent, From 190f1f283b6d2321b5818438dd821bd9def70573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kilchenmann?= Date: Fri, 10 Jun 2022 07:56:49 +0200 Subject: [PATCH 11/11] refactor: clean up code --- src/app/app-routing.module.ts | 12 +++++ src/app/main/status/status.component.ts | 2 + .../ontology-class-instance.component.ts | 13 +---- .../ontology-class-item.component.ts | 3 -- src/app/project/project.component.html | 7 +++ src/app/project/project.component.scss | 28 +++++++++++ src/app/project/project.component.ts | 3 +- .../workspace/results/results.component.ts | 2 +- src/assets/style/_layout.scss | 47 ------------------- 9 files changed, 53 insertions(+), 64 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index db09fc7c44..d0e5a3098c 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -125,6 +125,12 @@ const routes: Routes = [ path: 'ontology/:onto/:class', component: OntologyClassInstanceComponent, }, + { + path: 'ontology/:onto/:class/conf', + component: StatusComponent, + data: { status: 501, comment: 'Here you will be able to configure the resource class.' }, + canActivate: [AuthGuard] + }, { path: 'ontology/:onto/:class/:instance', component: OntologyClassInstanceComponent, @@ -139,6 +145,12 @@ const routes: Routes = [ component: ListComponent, canActivate: [AuthGuard] }, + { + path: 'settings', + component: StatusComponent, + data: { status: 501, comment: 'Here you will be able to configure the project: e.g. setup collaboration and permissions.' }, + canActivate: [AuthGuard] + }, { path: 'settings/collaboration', component: CollaborationComponent, diff --git a/src/app/main/status/status.component.ts b/src/app/main/status/status.component.ts index 0b6beeadbf..2a626d529d 100644 --- a/src/app/main/status/status.component.ts +++ b/src/app/main/status/status.component.ts @@ -98,6 +98,8 @@ export class StatusComponent implements OnInit { // but status is defined in app.routing this._route.data.subscribe(data => { this.status = data.status; + this.comment = data.comment; + this.url = data.url; }); } diff --git a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts index 2ad287f32f..fe72f6059c 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component.ts @@ -1,4 +1,4 @@ -import { Component, OnChanges, SimpleChanges } from '@angular/core'; +import { Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { AppInitService } from 'src/app/app-init.service'; import { OntologyService } from 'src/app/project/ontology/ontology.service'; @@ -10,7 +10,7 @@ import { SplitSize } from 'src/app/workspace/results/results.component'; templateUrl: './ontology-class-instance.component.html', styleUrls: ['./ontology-class-instance.component.scss'] }) -export class OntologyClassInstanceComponent implements OnChanges { +export class OntologyClassInstanceComponent { projectId: string; @@ -64,13 +64,6 @@ export class OntologyClassInstanceComponent implements OnChanges { }); } - ngOnChanges(changes: SimpleChanges): void { - - // this.reset(); - console.log('something has changed',); - - } - openSelectedResources(res: FilteredResources) { this.selectedResources = res; @@ -85,8 +78,6 @@ export class OntologyClassInstanceComponent implements OnChanges { } - - private _setGravsearch(iri: string): string { return ` PREFIX knora-api: diff --git a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts index 8c37b48705..ea1822c6fb 100644 --- a/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts +++ b/src/app/project/beta/ontology-classes/ontology-class-item/ontology-class-item.component.ts @@ -39,14 +39,12 @@ export class OntologyClassItemComponent implements OnInit { } ngOnInit(): void { - console.log(JSON.stringify(this.resClass)); const projectCode = this._route.snapshot.params.shortcode; const splitIri = this.resClass.id.split('#'); const ontologyName = this._ontologyService.getOntologyName(splitIri[0]); this.link = `/beta/project/${projectCode}/ontology/${ontologyName}/${splitIri[1]}`; - this.gravsearch = this._setGravsearch(this.resClass.id); // get number of resource instances @@ -61,7 +59,6 @@ export class OntologyClassItemComponent implements OnInit { } open(route: string) { - // event.preventDefault(); this._router.navigateByUrl(route); } diff --git a/src/app/project/project.component.html b/src/app/project/project.component.html index f443fb3819..a453be4f04 100644 --- a/src/app/project/project.component.html +++ b/src/app/project/project.component.html @@ -102,7 +102,14 @@

Members

+ + diff --git a/src/app/project/project.component.scss b/src/app/project/project.component.scss index 343bdf1b21..58c8c7ecda 100644 --- a/src/app/project/project.component.scss +++ b/src/app/project/project.component.scss @@ -33,3 +33,31 @@ display: none; } } + +.sidenav-footer { + border-top: 1px solid rgba(0, 0, 0, 0.12); + bottom: 0; + position: absolute; + width: 100%; + + .mat-icon { + margin-right: 16px; + } +} + +.sidenav-container { + .sidenav { + + &.wide { + width: 240px; + } + + &.narrow { + width: 36px; + } + } + + // .mat-sidenav-content { + // background: #fff; + // } +} diff --git a/src/app/project/project.component.ts b/src/app/project/project.component.ts index 6058c55706..b3001adb4a 100644 --- a/src/app/project/project.component.ts +++ b/src/app/project/project.component.ts @@ -132,8 +132,7 @@ export class ProjectComponent implements OnInit { }, (error: ApiResponseError) => { this.loading = false; - console.error(error); - // todo: add error handler + this._errorHandler.showMessage(error); } ); }); diff --git a/src/app/workspace/results/results.component.ts b/src/app/workspace/results/results.component.ts index c07b854a4e..fccfc0bbc6 100644 --- a/src/app/workspace/results/results.component.ts +++ b/src/app/workspace/results/results.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core'; +import { Component } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute, Params } from '@angular/router'; import { FilteredResources, SearchParams } from './list-view/list-view.component'; diff --git a/src/assets/style/_layout.scss b/src/assets/style/_layout.scss index 77a9b4c3a1..2776106b4c 100644 --- a/src/assets/style/_layout.scss +++ b/src/assets/style/_layout.scss @@ -105,53 +105,6 @@ } - -// .sidenav-container { -// .sidenav { -// background-color: lighten($primary, 50%); -// letter-spacing: 0.3px; -// width: 36px; - -// &.wide { -// width: 240px; -// } - -// &.narrow { -// width: 36px; -// } - -// .mat-drawer-inner-container { -// overflow-x: hidden; - -// .mat-list { -// padding-top: 0; -// } -// } - -// .side-nav-footer { -// border-top: 1px solid rgba(0, 0, 0, 0.12); -// bottom: 0; -// height: 36px; -// position: absolute; -// width: 100%; - -// .mat-button { -// min-width: 30px; -// padding: 0; -// width: 100%; - -// .mat-icon { -// margin: 0 auto; -// } -// } -// } -// } - -// .mat-sidenav-content { -// background: #fff; -// } -// } - // -------------------------------------- //