diff --git a/src-ui/src/app/components/common/input/tags/tags.component.html b/src-ui/src/app/components/common/input/tags/tags.component.html index eba8ef218..497a62335 100644 --- a/src-ui/src/app/components/common/input/tags/tags.component.html +++ b/src-ui/src/app/components/common/input/tags/tags.component.html @@ -2,7 +2,7 @@
- + (change)="onChange(value)"> diff --git a/src-ui/src/app/components/common/input/tags/tags.component.spec.ts b/src-ui/src/app/components/common/input/tags/tags.component.spec.ts index f3ea05d5d..85c492aba 100644 --- a/src-ui/src/app/components/common/input/tags/tags.component.spec.ts +++ b/src-ui/src/app/components/common/input/tags/tags.component.spec.ts @@ -15,16 +15,28 @@ import { DEFAULT_MATCHING_ALGORITHM, MATCH_ALL, } from 'src/app/data/matching-model' -import { NgSelectModule } from '@ng-select/ng-select' +import { NgSelectComponent, NgSelectModule } from '@ng-select/ng-select' import { RouterTestingModule } from '@angular/router/testing' import { HttpClientTestingModule } from '@angular/common/http/testing' import { of } from 'rxjs' import { TagService } from 'src/app/services/rest/tag.service' import { + NgbAccordionModule, NgbModal, NgbModalModule, NgbModalRef, + NgbPopoverModule, } from '@ng-bootstrap/ng-bootstrap' +import { TagEditDialogComponent } from '../../edit-dialog/tag-edit-dialog/tag-edit-dialog.component' +import { CheckComponent } from '../check/check.component' +import { IfOwnerDirective } from 'src/app/directives/if-owner.directive' +import { TextComponent } from '../text/text.component' +import { ColorComponent } from '../color/color.component' +import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' +import { PermissionsFormComponent } from '../permissions/permissions-form/permissions-form.component' +import { SelectComponent } from '../select/select.component' +import { ColorSliderModule } from 'ngx-color/slider' +import { By } from '@angular/platform-browser' const tags: PaperlessTag[] = [ { @@ -56,12 +68,32 @@ describe('TagsComponent', () => { beforeEach(async () => { TestBed.configureTestingModule({ - declarations: [TagsComponent], + declarations: [ + TagsComponent, + TagEditDialogComponent, + TextComponent, + ColorComponent, + IfOwnerDirective, + SelectComponent, + TextComponent, + PermissionsFormComponent, + ColorComponent, + CheckComponent, + ], providers: [ { provide: TagService, useValue: { - listAll: () => of(tags), + listAll: () => + of({ + results: tags, + }), + create: () => + of({ + name: 'bar', + id: 99, + color: '#fff000', + }), }, }, ], @@ -72,6 +104,8 @@ describe('TagsComponent', () => { RouterTestingModule, HttpClientTestingModule, NgbModalModule, + NgbAccordionModule, + NgbPopoverModule, ], }).compileComponents() @@ -85,7 +119,7 @@ describe('TagsComponent', () => { }) it('should support suggestions', () => { - expect(component.value).toBeUndefined() + expect(component.value).toHaveLength(0) component.value = [] component.tags = tags component.suggestions = [1, 2] @@ -107,19 +141,19 @@ describe('TagsComponent', () => { it('should support create new using last search term and open a modal', () => { let activeInstances: NgbModalRef[] modalService.activeInstances.subscribe((v) => (activeInstances = v)) - component.onSearch({ term: 'bar' }) + component.select.searchTerm = 'foobar' component.createTag() expect(modalService.hasOpenModals()).toBeTruthy() - expect(activeInstances[0].componentInstance.object.name).toEqual('bar') + expect(activeInstances[0].componentInstance.object.name).toEqual('foobar') + const editDialog = activeInstances[0] + .componentInstance as TagEditDialogComponent + editDialog.save() // create is mocked + fixture.detectChanges() + fixture.whenStable().then(() => { + expect(fixture.debugElement.nativeElement.textContent).toContain('foobar') + }) }) - it('should clear search term on blur after delay', fakeAsync(() => { - const clearSpy = jest.spyOn(component, 'clearLastSearchTerm') - component.onBlur() - tick(3000) - expect(clearSpy).toHaveBeenCalled() - })) - it('support remove tags', () => { component.tags = tags component.value = [1, 2] @@ -132,6 +166,7 @@ describe('TagsComponent', () => { }) it('should get tags', () => { + component.tags = null expect(component.getTag(2)).toBeNull() component.tags = tags expect(component.getTag(2)).toEqual(tags[1]) diff --git a/src-ui/src/app/components/common/input/tags/tags.component.ts b/src-ui/src/app/components/common/input/tags/tags.component.ts index 4fb0151b6..b6bfddb3c 100644 --- a/src-ui/src/app/components/common/input/tags/tags.component.ts +++ b/src-ui/src/app/components/common/input/tags/tags.component.ts @@ -5,6 +5,7 @@ import { Input, OnInit, Output, + ViewChild, } from '@angular/core' import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' @@ -12,6 +13,8 @@ import { PaperlessTag } from 'src/app/data/paperless-tag' import { TagEditDialogComponent } from '../../edit-dialog/tag-edit-dialog/tag-edit-dialog.component' import { TagService } from 'src/app/services/rest/tag.service' import { EditDialogMode } from '../../edit-dialog/edit-dialog.component' +import { first, firstValueFrom, tap } from 'rxjs' +import { NgSelectComponent } from '@ng-select/ng-select' @Component({ providers: [ @@ -74,14 +77,14 @@ export class TagsComponent implements OnInit, ControlValueAccessor { @Output() filterDocuments = new EventEmitter() - value: number[] + @ViewChild('tagSelect') select: NgSelectComponent - tags: PaperlessTag[] + value: number[] = [] + + tags: PaperlessTag[] = [] public createTagRef: (name) => void - private _lastSearchTerm: string - getTag(id: number) { if (this.tags) { return this.tags.find((tag) => tag.id == id) @@ -111,15 +114,20 @@ export class TagsComponent implements OnInit, ControlValueAccessor { }) modal.componentInstance.dialogMode = EditDialogMode.CREATE if (name) modal.componentInstance.object = { name: name } - else if (this._lastSearchTerm) - modal.componentInstance.object = { name: this._lastSearchTerm } - modal.componentInstance.succeeded.subscribe((newTag) => { - this.tagService.listAll().subscribe((tags) => { - this.tags = tags.results - this.value = [...this.value, newTag.id] - this.onChange(this.value) - }) - }) + else if (this.select.searchTerm) + modal.componentInstance.object = { name: this.select.searchTerm } + this.select.searchTerm = null + this.select.detectChanges() + return firstValueFrom( + (modal.componentInstance as TagEditDialogComponent).succeeded.pipe( + first(), + tap(() => { + this.tagService.listAll().subscribe((tags) => { + this.tags = tags.results + }) + }) + ) + ) } getSuggestions() { @@ -137,20 +145,6 @@ export class TagsComponent implements OnInit, ControlValueAccessor { this.onChange(this.value) } - clearLastSearchTerm() { - this._lastSearchTerm = null - } - - onSearch($event) { - this._lastSearchTerm = $event.term - } - - onBlur() { - setTimeout(() => { - this.clearLastSearchTerm() - }, 3000) - } - get hasPrivate(): boolean { return this.value.some( (t) => this.tags?.find((t2) => t2.id === t) === undefined