mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Feature: allow create objects from bulk edit (#5667)
This commit is contained in:
@@ -45,10 +45,18 @@
|
||||
</div>
|
||||
}
|
||||
@if (editing) {
|
||||
<button class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!modelIsDirty || disabled">
|
||||
<small class="ms-2" [ngClass]="{'fw-bold': modelIsDirty}" i18n>Apply</small>
|
||||
<i-bs width="1.5em" height="1em" name="arrow-right"></i-bs>
|
||||
</button>
|
||||
@if ((selectionModel.itemsSorted | filter: filterText).length === 0 && createRef !== undefined) {
|
||||
<button class="list-group-item list-group-item-action bg-light" (click)="createClicked()" [disabled]="disabled">
|
||||
<small class="ms-2"><ng-container i18n>Create</ng-container> "{{filterText}}"</small>
|
||||
<i-bs width="1.5em" height="1em" name="plus"></i-bs>
|
||||
</button>
|
||||
}
|
||||
@if ((selectionModel.itemsSorted | filter: filterText).length > 0) {
|
||||
<button class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!modelIsDirty || disabled">
|
||||
<small class="ms-2" [ngClass]="{'fw-bold': modelIsDirty}" i18n>Apply</small>
|
||||
<i-bs width="1.5em" height="1em" name="arrow-right"></i-bs>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
@if (!editing && manyToOne) {
|
||||
<div class="list-group-item list-group-item-note pt-1 pb-2">
|
||||
|
@@ -500,4 +500,46 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
|
||||
selectionModel.apply()
|
||||
expect(selectionModel.itemsSorted).toEqual([nullItem, items[1], items[0]])
|
||||
})
|
||||
|
||||
it('should set support create, keep open model and call createRef method', fakeAsync(() => {
|
||||
component.items = items
|
||||
component.icon = 'tag-fill'
|
||||
component.selectionModel = selectionModel
|
||||
fixture.nativeElement
|
||||
.querySelector('button')
|
||||
.dispatchEvent(new MouseEvent('click')) // open
|
||||
fixture.detectChanges()
|
||||
tick(100)
|
||||
|
||||
component.filterText = 'Test Filter Text'
|
||||
component.createRef = jest.fn()
|
||||
component.createClicked()
|
||||
expect(component.creating).toBeTruthy()
|
||||
expect(component.createRef).toHaveBeenCalledWith('Test Filter Text')
|
||||
const openSpy = jest.spyOn(component.dropdown, 'open')
|
||||
component.dropdownOpenChange(false)
|
||||
expect(openSpy).toHaveBeenCalled() // should keep open
|
||||
}))
|
||||
|
||||
it('should call create on enter inside filter field if 0 items remain while editing', fakeAsync(() => {
|
||||
component.items = items
|
||||
component.icon = 'tag-fill'
|
||||
component.editing = true
|
||||
component.createRef = jest.fn()
|
||||
const createSpy = jest.spyOn(component, 'createClicked')
|
||||
expect(component.selectionModel.getSelectedItems()).toEqual([])
|
||||
fixture.nativeElement
|
||||
.querySelector('button')
|
||||
.dispatchEvent(new MouseEvent('click')) // open
|
||||
fixture.detectChanges()
|
||||
tick(100)
|
||||
component.filterText = 'FooBar'
|
||||
fixture.detectChanges()
|
||||
component.listFilterTextInput.nativeElement.dispatchEvent(
|
||||
new KeyboardEvent('keyup', { key: 'Enter' })
|
||||
)
|
||||
expect(component.selectionModel.getSelectedItems()).toEqual([])
|
||||
tick(300)
|
||||
expect(createSpy).toHaveBeenCalled()
|
||||
}))
|
||||
})
|
||||
|
@@ -398,6 +398,11 @@ export class FilterableDropdownComponent {
|
||||
@Input()
|
||||
disabled = false
|
||||
|
||||
@Input()
|
||||
createRef: (name) => void
|
||||
|
||||
creating: boolean = false
|
||||
|
||||
@Output()
|
||||
apply = new EventEmitter<ChangedItems>()
|
||||
|
||||
@@ -437,6 +442,11 @@ export class FilterableDropdownComponent {
|
||||
}
|
||||
}
|
||||
|
||||
createClicked() {
|
||||
this.creating = true
|
||||
this.createRef(this.filterText)
|
||||
}
|
||||
|
||||
dropdownOpenChange(open: boolean): void {
|
||||
if (open) {
|
||||
setTimeout(() => {
|
||||
@@ -448,9 +458,14 @@ export class FilterableDropdownComponent {
|
||||
}
|
||||
this.opened.next(this)
|
||||
} else {
|
||||
this.filterText = ''
|
||||
if (this.applyOnClose && this.selectionModel.isDirty()) {
|
||||
this.apply.emit(this.selectionModel.diff())
|
||||
if (this.creating) {
|
||||
this.dropdown.open()
|
||||
this.creating = false
|
||||
} else {
|
||||
this.filterText = ''
|
||||
if (this.applyOnClose && this.selectionModel.isDirty()) {
|
||||
this.apply.emit(this.selectionModel.diff())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,6 +481,8 @@ export class FilterableDropdownComponent {
|
||||
this.dropdown.close()
|
||||
}
|
||||
}, 200)
|
||||
} else if (filtered.length == 0 && this.createRef) {
|
||||
this.createClicked()
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user