diff --git a/package-lock.json b/package-lock.json index 8676716836..4abdb2ae5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@angular/platform-browser-dynamic": "^9.1.13", "@angular/router": "^9.1.13", "@ckeditor/ckeditor5-angular": "^1.2.3", - "@dasch-swiss/dsp-js": "^2.1.1", + "@dasch-swiss/dsp-js": "^2.2.0", "@dasch-swiss/dsp-ui": "^1.2.2", "@ngx-translate/core": "^12.1.2", "@ngx-translate/http-loader": "5.0.0", @@ -1777,9 +1777,9 @@ } }, "node_modules/@dasch-swiss/dsp-js": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-2.1.1.tgz", - "integrity": "sha512-p4DF7UkKDadMEohpw2iGQilQ+jYsfiZkotIMsOg1eZZTfIXL3n3RhmWRwHjokwZ1gweGsxyZq8u4VcR2eROGjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-2.2.0.tgz", + "integrity": "sha512-C+usboHcWxuejIwdHNJpLNjNrfCegSTyNhxF2MhHmgFk4ocFnJ/nh04sTf5mv+HqtGqpVhHpnb+xFJ9XyBVtAA==", "dependencies": { "@types/jsonld": "^1.5.0", "json2typescript": "1.4.1", @@ -21109,9 +21109,9 @@ } }, "@dasch-swiss/dsp-js": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-2.1.1.tgz", - "integrity": "sha512-p4DF7UkKDadMEohpw2iGQilQ+jYsfiZkotIMsOg1eZZTfIXL3n3RhmWRwHjokwZ1gweGsxyZq8u4VcR2eROGjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-2.2.0.tgz", + "integrity": "sha512-C+usboHcWxuejIwdHNJpLNjNrfCegSTyNhxF2MhHmgFk4ocFnJ/nh04sTf5mv+HqtGqpVhHpnb+xFJ9XyBVtAA==", "requires": { "@types/jsonld": "^1.5.0", "json2typescript": "1.4.1", diff --git a/package.json b/package.json index a2bea8d4db..a338002834 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@angular/platform-browser-dynamic": "^9.1.13", "@angular/router": "^9.1.13", "@ckeditor/ckeditor5-angular": "^1.2.3", - "@dasch-swiss/dsp-js": "^2.1.1", + "@dasch-swiss/dsp-js": "^2.2.0", "@dasch-swiss/dsp-ui": "^1.2.2", "@ngx-translate/core": "^12.1.2", "@ngx-translate/http-loader": "5.0.0", diff --git a/src/app/main/dialog/dialog.component.html b/src/app/main/dialog/dialog.component.html index b179b65630..d90b9dfb81 100644 --- a/src/app/main/dialog/dialog.component.html +++ b/src/app/main/dialog/dialog.component.html @@ -213,15 +213,16 @@
- +
- + -

+
diff --git a/src/app/project/ontology/ontology-form/ontology-form.component.html b/src/app/project/ontology/ontology-form/ontology-form.component.html index 470c9148dc..305f09c1c1 100644 --- a/src/app/project/ontology/ontology-form/ontology-form.component.html +++ b/src/app/project/ontology/ontology-form/ontology-form.component.html @@ -1,23 +1,31 @@ -
+
- - + {{ formErrors.name }} + {{ontologyForm.controls['name'].value.length}} / {{nameMaxLength}} - - {{project.shortname}}:  - - {{ formErrors.label }} - + {{project.shortname}}:  + + {{ formErrors.label }} + + + + +
@@ -28,8 +36,11 @@ -
diff --git a/src/app/project/ontology/ontology-form/ontology-form.component.spec.ts b/src/app/project/ontology/ontology-form/ontology-form.component.spec.ts index 37ea33a733..fa9c8ff635 100644 --- a/src/app/project/ontology/ontology-form/ontology-form.component.spec.ts +++ b/src/app/project/ontology/ontology-form/ontology-form.component.spec.ts @@ -3,9 +3,10 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; +import { By } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterTestingModule } from '@angular/router/testing'; -import { KnoraApiConnection } from '@dasch-swiss/dsp-js'; +import { KnoraApiConnection, MockProjects } from '@dasch-swiss/dsp-js'; import { AppInitService, DspActionModule, @@ -14,23 +15,23 @@ import { DspCoreModule } from '@dasch-swiss/dsp-ui'; import { TranslateModule } from '@ngx-translate/core'; -import { DialogComponent } from 'src/app/main/dialog/dialog.component'; -import { ErrorComponent } from 'src/app/main/error/error.component'; +import { of } from 'rxjs'; +import { CacheService } from 'src/app/main/cache/cache.service'; import { TestConfig } from 'test.config'; import { OntologyFormComponent } from './ontology-form.component'; describe('OntologyFormComponent', () => { - let component: OntologyFormComponent; - let fixture: ComponentFixture; + let ontologyFormComponent: OntologyFormComponent; + let ontologyFormFixture: ComponentFixture; const formBuilder: FormBuilder = new FormBuilder(); + const cacheServiceSpy = jasmine.createSpyObj('CacheService', ['get']); + beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ - OntologyFormComponent, - DialogComponent, - ErrorComponent + OntologyFormComponent ], imports: [ BrowserAnimationsModule, @@ -54,6 +55,10 @@ describe('OntologyFormComponent', () => { { provide: DspApiConnectionToken, useValue: new KnoraApiConnection(TestConfig.ApiConfig) + }, + { + provide: CacheService, + useValue: cacheServiceSpy } ] }) @@ -61,19 +66,84 @@ describe('OntologyFormComponent', () => { })); beforeEach(() => { - fixture = TestBed.createComponent(OntologyFormComponent); - component = fixture.componentInstance; + // mock cache service for currentOntology + const cacheSpy = TestBed.inject(CacheService); + + (cacheSpy as jasmine.SpyObj).get.and.callFake( + () => { + const response = MockProjects.mockProject(); + return of(response); + } + ); - // pass in the form dynamically - component.ontologyForm = formBuilder.group({ - name: null, - label: null - }); + ontologyFormFixture = TestBed.createComponent(OntologyFormComponent); + ontologyFormComponent = ontologyFormFixture.componentInstance; + ontologyFormComponent.projectcode = '00FF'; + // ontologyFormComponent.iri = 'http://0.0.0.0:3333/ontology/0001/anything/v2'; + ontologyFormComponent.existingOntologyNames = ['images']; - fixture.detectChanges(); + ontologyFormComponent.ngOnInit(); + ontologyFormFixture.detectChanges(); }); + it('should create', () => { - expect(component).toBeTruthy(); + expect(ontologyFormComponent).toBeTruthy(); + }); + + it('should render input elements', () => { + const compiled = ontologyFormFixture.debugElement; + const nameInput = compiled.query(By.css('.ontology-name input')); + const labelInput = compiled.query(By.css('.ontology-label input')); + const commentInput = compiled.query(By.css('.ontology-comment textarea')); + + expect(nameInput).toBeTruthy(); + expect(labelInput).toBeTruthy(); + expect(commentInput).toBeTruthy(); }); + + it('should test form validity with allowed name', () => { + const form = ontologyFormComponent.ontologyForm; + expect(form.valid).toBeFalsy(); + + const nameInput = form.controls.name; + nameInput.setValue('biblio'); + + expect(form.valid).toBeTruthy(); + }); + + it('should test form validity with forbidden names', () => { + const form = ontologyFormComponent.ontologyForm; + expect(form.valid).toBeFalsy(); + + const nameInput = form.controls.name; + + nameInput.setValue('ontology'); + expect(form.valid).toBeFalsy(); + + nameInput.setValue('images'); + expect(form.valid).toBeFalsy(); + + }); + + it('should test form validity without label', () => { + const form = ontologyFormComponent.ontologyForm; + expect(form.valid).toBeFalsy(); + + const nameInput = form.controls.name; + const labelInput = form.controls.label; + + nameInput.setValue('biblio'); + + const compiled = ontologyFormFixture.debugElement; + expect(ontologyFormComponent.ontologyLabel).toEqual('Biblio'); + expect(form.valid).toBeTruthy(); + + + labelInput.setValue('Biblio Ontology'); + expect(ontologyFormComponent.ontologyForm.controls.label.value).toEqual('Biblio Ontology'); + expect(form.valid).toBeTruthy(); + + }); + }); diff --git a/src/app/project/ontology/ontology-form/ontology-form.component.ts b/src/app/project/ontology/ontology-form/ontology-form.component.ts index 2fc4a0e45c..49cbda9bb5 100644 --- a/src/app/project/ontology/ontology-form/ontology-form.component.ts +++ b/src/app/project/ontology/ontology-form/ontology-form.component.ts @@ -7,11 +7,14 @@ import { KnoraApiConnection, OntologyMetadata, ProjectResponse, - ReadProject + ReadOntology, + ReadProject, + UpdateOntologyMetadata } from '@dasch-swiss/dsp-js'; import { DspApiConnectionToken, existingNamesValidator } from '@dasch-swiss/dsp-ui'; import { CacheService } from 'src/app/main/cache/cache.service'; import { ErrorHandlerService } from 'src/app/main/error/error-handler.service'; +import { ResourceClassFormService } from '../resource-class-form/resource-class-form.service'; export interface NewOntology { projectIri: string; @@ -26,10 +29,12 @@ export interface NewOntology { }) export class OntologyFormComponent implements OnInit { - // project short code @Input() projectcode: string; + // ontology iri in case of edit + @Input() iri: string; + // existing ontology names; name has to be unique @Input() existingOntologyNames: string[]; @@ -43,7 +48,10 @@ export class OntologyFormComponent implements OnInit { ontologyForm: FormGroup; - ontologyLabel = ''; + ontologyLabel: string; + ontologyComment: string; + + lastModificationDate: string; nameRegex = /^(?![vV][0-9]|[0-9]|[\u00C0-\u017F]).[a-zA-Z0-9]+\S*$/; @@ -80,11 +88,15 @@ export class OntologyFormComponent implements OnInit { } }; + error = false; + constructor( @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, private _cache: CacheService, private _errorHandler: ErrorHandlerService, - private _fb: FormBuilder) { } + private _fb: FormBuilder, + private _resourceClassFormService: ResourceClassFormService + ) { } ngOnInit() { @@ -108,6 +120,29 @@ export class OntologyFormComponent implements OnInit { } ); + if (this.iri) { + // edit mode: get current ontology + this._cache.get('currentOntology').subscribe( + (response: ReadOntology) => { + // add values to the ontology form + this.ontologyForm.controls['name'].disable(); + const name = this._resourceClassFormService.getOntologyName(this.iri); + this.ontologyForm.controls['name'].setValue(name); + this.ontologyForm.controls['label'].setValue(response.label); + this.ontologyForm.controls['label'].setValidators( + [Validators.required] + ); + this.ontologyForm.controls['comment'].setValue(response.comment); + // disable name input + + this.lastModificationDate = response.lastModificationDate; + }, + (error: ApiResponseError) => { + this._errorHandler.showMessage(error); + } + ); + } + } buildForm() { @@ -148,7 +183,10 @@ export class OntologyFormComponent implements OnInit { value: this.ontologyLabel, disabled: false }, [ Validators.minLength(this.nameMinLength) - ]) + ]), + comment: new FormControl({ + value: this.ontologyComment, disabled: false + }) }); this.ontologyForm.valueChanges.subscribe(data => this.onValueChanged(data)); @@ -160,7 +198,9 @@ export class OntologyFormComponent implements OnInit { return; } - this.ontologyLabel = data.name; + if (!this.iri) { + this.ontologyLabel = this.capitalizeFirstLetter(data.name); + } Object.keys(this.formErrors).map(field => { this.formErrors[field] = ''; @@ -176,40 +216,59 @@ export class OntologyFormComponent implements OnInit { } - createOntology() { + submitData() { this.loading = true; - // const something: number = Math.floor(Math.random() * Math.floor(9999)); - - const ontologyData = new CreateOntology(); - ontologyData.label = this.project.shortname + ': ' + (this.ontologyLabel ? this.ontologyLabel : this.ontologyForm.controls['name'].value); - ontologyData.name = this.ontologyForm.controls['name'].value; - ontologyData.attachedToProject = this.project.id; - - this._dspApiConnection.v2.onto.createOntology(ontologyData).subscribe( - (response: OntologyMetadata) => { - this.updateParent.emit(response.id); - this.closeDialog.emit(response.id); - }, - (error: ApiResponseError) => { - // in case of an error... e.g. because the ontolog iri is not unique, rebuild the form including the error message - this.formErrors['name'] += this.validationMessages['name']['existingName'] + ' '; - this.loading = false; + if (this.iri) { + // edit mode + const ontologyData = new UpdateOntologyMetadata(); + ontologyData.id = this.iri; + ontologyData.lastModificationDate = this.lastModificationDate; + ontologyData.label = this.ontologyForm.controls['label'].value; + ontologyData.comment = this.ontologyForm.controls['comment'].value; + + this._dspApiConnection.v2.onto.updateOntology(ontologyData).subscribe( + (response: OntologyMetadata) => { + this.updateParent.emit(response.id); + this.closeDialog.emit(response.id); + }, + (error: ApiResponseError) => { + // in case of an error + this.loading = false; + this.error = true; + + this._errorHandler.showMessage(error); + } + ); - this._errorHandler.showMessage(error); - } - ); + } else { + // create mode + + const ontologyData = new CreateOntology(); + ontologyData.label = this.project.shortname + ': ' + (this.ontologyLabel ? this.ontologyLabel : this.ontologyForm.controls['name'].value); + ontologyData.name = this.ontologyForm.controls['name'].value; + ontologyData.comment = this.ontologyForm.controls['comment'].value; + ontologyData.attachedToProject = this.project.id; + + this._dspApiConnection.v2.onto.createOntology(ontologyData).subscribe( + (response: OntologyMetadata) => { + this.updateParent.emit(response.id); + this.closeDialog.emit(response.id); + }, + (error: ApiResponseError) => { + // in case of an error... e.g. because the ontolog iri is not unique, rebuild the form including the error message + this.formErrors['name'] += this.validationMessages['name']['existingName'] + ' '; + this.loading = false; + + this._errorHandler.showMessage(error); + } + ); + } } - /** - * reset the form - */ - resetForm(ev: Event, resourceClass?: any) { - - this.ontologyLabel = this.project.shortname + ' ontology (data model): '; - - this.buildForm(); - + capitalizeFirstLetter(text: string) { + return text.charAt(0).toUpperCase() + text.slice(1); } + } diff --git a/src/app/project/ontology/ontology.component.html b/src/app/project/ontology/ontology.component.html index b1aa9a2b16..ff2c4cb377 100644 --- a/src/app/project/ontology/ontology.component.html +++ b/src/app/project/ontology/ontology.component.html @@ -57,7 +57,11 @@

-

{{ontology?.label}}

+

+ {{ontology?.label}} +

@@ -94,8 +98,8 @@

{{ontology?.label

Data model configuration

-