New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(add-link-resource-button): Add Link Resource Button (DEV-404) #645
Merged
Merged
Changes from 12 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
d1aa9ed
feat(add-link-resource-button): adds new component to use in popup wh…
mdelez ebc50d3
Merge branch 'main' into wip/dev-404-add-link-value-button
mdelez 8514337
feat(add-link-resource-button): correctly generates form for the appr…
mdelez 490f5ee
feat(add-link-resource-button): adds submit button to submit the form…
mdelez 2b3af3a
feat(add-link-resource-button): adds support for uploading files in t…
mdelez 7845327
Merge branch 'main' into wip/dev-404-add-link-value-button
mdelez bf7a458
refactor(add-link-resource-button): refactors code to be more clear a…
mdelez 02d25e8
tests(add-link-resource-button): fixes tests
mdelez 1324fdf
tests(add-link-resource-button): adds tests and cleans up all the con…
mdelez bcc5118
feat(add-link-resource-button): moves the create new resource button …
mdelez a383fce
feat(add-link-resource-button): adds resource class label to input pl…
mdelez 6a32be9
Merge branch 'main' into wip/dev-404-add-link-value-button
mdelez 6e0ddb4
chore: removes a comment
mdelez 421a592
Merge branch 'main' into wip/dev-404-add-link-value-button
mdelez 5ef958c
Merge branch 'main' into wip/dev-404-add-link-value-button
mdelez 61e549e
Merge branch 'main' into wip/dev-404-add-link-value-button
mdelez File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
...pp/workspace/resource/operations/create-link-resource/create-link-resource.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<form [formGroup]="propertiesForm" (ngSubmit)="onSubmit()"> | ||
<!-- upload file --> | ||
<app-upload *ngIf="hasFileValue" | ||
[parentForm]="propertiesForm" | ||
[representation]="hasFileValue" | ||
(fileInfo)="setFileValue($event)"> | ||
</app-upload> | ||
|
||
<app-select-properties #selectProps | ||
[ontologyInfo]="ontologyInfo" | ||
[resourceClass]="resourceClass" | ||
[properties]="properties" | ||
[parentForm]="propertiesForm" | ||
class="select-properties"> | ||
</app-select-properties> | ||
<div class="form-panel form-action"> | ||
<span> | ||
<button mat-button type="button" (click)="closeDialog.emit()"> | ||
{{ 'appLabels.form.action.cancel' | translate }} | ||
</button> | ||
</span> | ||
<span class="fill-remaining-space"></span> | ||
<span> | ||
<button mat-raised-button type="submit" color="primary" class="form-submit" [disabled]="!propertiesForm.valid"> | ||
{{ 'appLabels.form.action.submit' | translate}} | ||
</button> | ||
</span> | ||
</div> | ||
</form> | ||
Empty file.
310 changes: 310 additions & 0 deletions
310
...workspace/resource/operations/create-link-resource/create-link-resource.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,310 @@ | ||
import { Component, DebugElement, Inject, Input, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'; | ||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; | ||
import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; | ||
import { MatButtonModule } from '@angular/material/button'; | ||
import { MatDialogModule } from '@angular/material/dialog'; | ||
import { MatFormFieldModule } from '@angular/material/form-field'; | ||
import { MatSnackBarModule } from '@angular/material/snack-bar'; | ||
import { By } from '@angular/platform-browser'; | ||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | ||
import { | ||
CreateIntValue, | ||
CreateResource, | ||
CreateTextValueAsString, | ||
CreateValue, | ||
MockOntology, | ||
MockResource, | ||
ReadResource, | ||
ResourceClassAndPropertyDefinitions, | ||
ResourceClassDefinition, | ||
ResourcePropertyDefinition, | ||
ResourcesEndpointV2 | ||
} from '@dasch-swiss/dsp-js'; | ||
import { OntologyCache } from '@dasch-swiss/dsp-js/src/cache/ontology-cache/OntologyCache'; | ||
import { TranslateModule } from '@ngx-translate/core'; | ||
import { of } from 'rxjs'; | ||
import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; | ||
import { BaseValueDirective } from 'src/app/main/directive/base-value.directive'; | ||
import { SwitchPropertiesComponent } from '../../resource-instance-form/select-properties/switch-properties/switch-properties.component'; | ||
import { ValueService } from '../../services/value.service'; | ||
import { IntValueComponent } from '../../values/int-value/int-value.component'; | ||
import { TextValueAsStringComponent } from '../../values/text-value/text-value-as-string/text-value-as-string.component'; | ||
|
||
import { CreateLinkResourceComponent } from './create-link-resource.component'; | ||
|
||
/** | ||
* test host component to simulate parent component. | ||
*/ | ||
@Component({ | ||
template: ` | ||
<app-create-link-resource [parentResource]="parentResource" [propDef]="propDef" [resourceClassDef]="resourceClassDef" #createLinkResourceComp></app-create-link-resource>` | ||
}) | ||
class TestHostComponent implements OnInit { | ||
|
||
@ViewChild('createLinkResourceComp') createLinkResourceComponent: CreateLinkResourceComponent; | ||
|
||
parentResource: ReadResource; | ||
propDef: string; | ||
resourceClassDef: string; | ||
|
||
ngOnInit() { | ||
MockResource.getTestThing().subscribe(res => { | ||
this.parentResource = res; | ||
this.propDef = 'http://0.0.0.0:3333/ontology/0001/anything/v2#hasOtherThingValue'; | ||
this.resourceClassDef = 'http://0.0.0.0:3333/ontology/0001/anything/v2#Thing'; | ||
}); | ||
} | ||
|
||
} | ||
|
||
/** | ||
* mock select-properties component to use in tests. | ||
*/ | ||
@Component({ | ||
selector: 'app-select-properties', | ||
template: ` | ||
<app-text-value-as-string #createVal | ||
[mode]="'create'" | ||
[commentDisabled]="true" | ||
[valueRequiredValidator]="true" | ||
[parentForm]="parentForm" | ||
[formName]="'label'"> | ||
</app-text-value-as-string> | ||
` | ||
}) | ||
class MockSelectPropertiesComponent { | ||
@ViewChildren('switchProp') switchPropertiesComponent: QueryList<SwitchPropertiesComponent>; | ||
|
||
// input for resource's label | ||
@ViewChild('createVal') createValueComponent: BaseValueDirective; | ||
|
||
@Input() properties: ResourcePropertyDefinition[]; | ||
|
||
@Input() ontologyInfo: ResourceClassAndPropertyDefinitions; | ||
|
||
@Input() resourceClass: ResourceClassDefinition; | ||
|
||
@Input() parentForm: FormGroup; | ||
|
||
parentResource = new ReadResource(); | ||
|
||
constructor(private _valueService: ValueService) { } | ||
} | ||
|
||
/** | ||
* mock switch-properties component to use in tests. | ||
*/ | ||
@Component({ | ||
selector: 'app-switch-properties' | ||
}) | ||
class MockSwitchPropertiesComponent { | ||
@ViewChild('createVal') createValueComponent: BaseValueDirective; | ||
|
||
@Input() property: ResourcePropertyDefinition; | ||
|
||
@Input() parentResource: ReadResource; | ||
|
||
@Input() parentForm: FormGroup; | ||
|
||
@Input() formName: string; | ||
} | ||
|
||
/** | ||
* mock value component to use in tests. | ||
*/ | ||
@Component({ | ||
selector: 'dsp-int-value' | ||
}) | ||
class MockCreateIntValueComponent implements OnInit { | ||
|
||
@ViewChild('createVal') createValueComponent: IntValueComponent; | ||
|
||
@Input() parentForm: FormGroup; | ||
|
||
@Input() formName: string; | ||
|
||
@Input() mode; | ||
|
||
@Input() displayValue; | ||
|
||
form: FormGroup; | ||
|
||
valueFormControl: FormControl; | ||
|
||
constructor(@Inject(FormBuilder) private _fb: FormBuilder) { } | ||
|
||
ngOnInit(): void { | ||
this.valueFormControl = new FormControl(null, [Validators.required]); | ||
|
||
this.form = this._fb.group({ | ||
test: this.valueFormControl | ||
}); | ||
} | ||
|
||
getNewValue(): CreateValue { | ||
const createIntVal = new CreateIntValue(); | ||
|
||
createIntVal.int = 123; | ||
|
||
return createIntVal; | ||
} | ||
|
||
updateCommentVisibility(): void { } | ||
} | ||
|
||
/** | ||
* mock value component to use in tests. | ||
*/ | ||
@Component({ | ||
selector: 'app-text-value-as-string' | ||
}) | ||
class MockCreateTextValueComponent implements OnInit { | ||
|
||
@ViewChild('createVal') createValueComponent: TextValueAsStringComponent; | ||
|
||
@Input() parentForm: FormGroup; | ||
|
||
@Input() formName: string; | ||
|
||
@Input() mode; | ||
|
||
@Input() displayValue; | ||
|
||
@Input() commentDisabled?: boolean; | ||
|
||
@Input() valueRequiredValidator: boolean; | ||
|
||
form: FormGroup; | ||
|
||
valueFormControl: FormControl; | ||
constructor(@Inject(FormBuilder) private _fb: FormBuilder) { } | ||
ngOnInit(): void { | ||
this.valueFormControl = new FormControl(null, [Validators.required]); | ||
this.form = this._fb.group({ | ||
label: this.valueFormControl | ||
}); | ||
} | ||
getNewValue(): CreateValue { | ||
const createTextVal = new CreateTextValueAsString(); | ||
createTextVal.text = 'My Label'; | ||
return createTextVal; | ||
} | ||
updateCommentVisibility(): void { } | ||
} | ||
|
||
describe('CreateLinkResourceComponent', () => { | ||
let testHostComponent: TestHostComponent; | ||
let testHostFixture: ComponentFixture<TestHostComponent>; | ||
let createLinkResourceComponentDe: DebugElement; | ||
|
||
beforeEach(waitForAsync(() => { | ||
|
||
const dspConnSpy = { | ||
v2: { | ||
ontologyCache: jasmine.createSpyObj('ontologyCache', ['getOntology', 'getResourceClassDefinition']), | ||
res: jasmine.createSpyObj('res', ['createResource']) | ||
} | ||
}; | ||
|
||
TestBed.configureTestingModule({ | ||
declarations: [ | ||
CreateLinkResourceComponent, | ||
TestHostComponent, | ||
MockSelectPropertiesComponent, | ||
MockCreateTextValueComponent, | ||
MockSwitchPropertiesComponent, | ||
MockCreateIntValueComponent | ||
], | ||
imports: [ | ||
BrowserAnimationsModule, | ||
MatButtonModule, | ||
MatDialogModule, | ||
MatFormFieldModule, | ||
MatSnackBarModule, | ||
ReactiveFormsModule, | ||
TranslateModule.forRoot() | ||
], | ||
providers: [ | ||
{ | ||
provide: DspApiConnectionToken, | ||
useValue: dspConnSpy | ||
}, | ||
ValueService | ||
] | ||
}) | ||
.compileComponents(); | ||
})); | ||
|
||
beforeEach(() => { | ||
const dspConnSpy = TestBed.inject(DspApiConnectionToken); | ||
|
||
(dspConnSpy.v2.ontologyCache as jasmine.SpyObj<OntologyCache>).getResourceClassDefinition.and.callFake( | ||
(resClassIri: string) => of(MockOntology.mockIResourceClassAndPropertyDefinitions('http://0.0.0.0:3333/ontology/0001/anything/v2#Thing')) | ||
); | ||
|
||
testHostFixture = TestBed.createComponent(TestHostComponent); | ||
testHostComponent = testHostFixture.componentInstance; | ||
testHostFixture.detectChanges(); | ||
expect(testHostComponent).toBeTruthy(); | ||
|
||
const hostCompDe = testHostFixture.debugElement; | ||
|
||
createLinkResourceComponentDe = hostCompDe.query(By.directive(CreateLinkResourceComponent)); | ||
|
||
}); | ||
|
||
it('should initialize the properties array', async () => { | ||
expect(testHostComponent.createLinkResourceComponent.properties.length).toEqual(18); | ||
}); | ||
|
||
it('should submit the form', () => { | ||
const dspConnSpy = TestBed.inject(DspApiConnectionToken); | ||
|
||
(dspConnSpy.v2.res as jasmine.SpyObj<ResourcesEndpointV2>).createResource.and.callFake( | ||
() => { | ||
let resource = new ReadResource(); | ||
|
||
MockResource.getTestThing().subscribe((res) => { | ||
resource = res; | ||
}); | ||
|
||
return of(resource); | ||
} | ||
); | ||
|
||
const anythingOnto = MockOntology.mockReadOntology('http://0.0.0.0:3333/ontology/0001/anything/v2'); | ||
|
||
// get resource class definitions | ||
const resourceClasses = anythingOnto.getClassDefinitionsByType(ResourceClassDefinition); | ||
|
||
testHostComponent.createLinkResourceComponent.properties = new Array<ResourcePropertyDefinition>(); | ||
|
||
MockResource.getTestThing().subscribe(res => { | ||
const resourcePropDef = (res.entityInfo as ResourceClassAndPropertyDefinitions).getAllPropertyDefinitions()[9]; | ||
testHostComponent.createLinkResourceComponent.properties.push(resourcePropDef as ResourcePropertyDefinition); | ||
}); | ||
|
||
testHostFixture.detectChanges(); | ||
|
||
const selectPropertiesComp = createLinkResourceComponentDe.query(By.directive(MockSelectPropertiesComponent)); | ||
|
||
expect(selectPropertiesComp).toBeTruthy(); | ||
|
||
const label = new CreateTextValueAsString(); | ||
label.text = 'My Label'; | ||
|
||
const props = {}; | ||
const createVal = new CreateIntValue(); | ||
createVal.int = 123; | ||
props['http://0.0.0.0:3333/ontology/0001/anything/v2#hasInteger'] = [createVal]; | ||
|
||
const expectedCreateResource = new CreateResource(); | ||
expectedCreateResource.label = 'My Label'; | ||
expectedCreateResource.type = 'http://0.0.0.0:3333/ontology/0001/anything/v2#Thing'; | ||
expectedCreateResource.properties = props; | ||
|
||
testHostComponent.createLinkResourceComponent.onSubmit(); | ||
|
||
expect(dspConnSpy.v2.res.createResource).toHaveBeenCalledTimes(1); | ||
}); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the
create-link-resource.component
the same as in the second step ofresource-instance-form
? Does it make sense to duplicate the code?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kilchenmann they're quite similar but the
resource-instance-form
has a back button to go back to the first step and it redirects the user to the created resource after it's been created.resource-instance-form
uses an array ofResourceClassDefinition
whereascreate-link-resource
does not use an array. We could try to condense it all into one component but we might have a lot of ugly if statements to hide/show relevant parts of the component depending on what the user is doing. What are your thoughts?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your response. That's true. Sooner or later the resource-instance-form will anyway have only one form (without the first step) and the back button will not be needed anymore. I would appreciate it if we do not have too many of the same forms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I refactor in this PR or another one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you prefer? I think it should be resolved in this PR... or what will be the simplest solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after speaking with André, we decided to do the refactor in another PR because the
create-resource-instance
form will change in the future