mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Feature: allow create objects from bulk edit (#5667)
This commit is contained in:
		| @@ -45,11 +45,19 @@ | |||||||
|         </div> |         </div> | ||||||
|       } |       } | ||||||
|       @if (editing) { |       @if (editing) { | ||||||
|  |         @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"> |           <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> |             <small class="ms-2" [ngClass]="{'fw-bold': modelIsDirty}" i18n>Apply</small> | ||||||
|             <i-bs width="1.5em" height="1em" name="arrow-right"></i-bs> |             <i-bs width="1.5em" height="1em" name="arrow-right"></i-bs> | ||||||
|           </button> |           </button> | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|       @if (!editing && manyToOne) { |       @if (!editing && manyToOne) { | ||||||
|         <div class="list-group-item list-group-item-note pt-1 pb-2"> |         <div class="list-group-item list-group-item-note pt-1 pb-2"> | ||||||
|           <small i18n>Click again to exclude items.</small> |           <small i18n>Click again to exclude items.</small> | ||||||
|   | |||||||
| @@ -500,4 +500,46 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () => | |||||||
|     selectionModel.apply() |     selectionModel.apply() | ||||||
|     expect(selectionModel.itemsSorted).toEqual([nullItem, items[1], items[0]]) |     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() |   @Input() | ||||||
|   disabled = false |   disabled = false | ||||||
|  |  | ||||||
|  |   @Input() | ||||||
|  |   createRef: (name) => void | ||||||
|  |  | ||||||
|  |   creating: boolean = false | ||||||
|  |  | ||||||
|   @Output() |   @Output() | ||||||
|   apply = new EventEmitter<ChangedItems>() |   apply = new EventEmitter<ChangedItems>() | ||||||
|  |  | ||||||
| @@ -437,6 +442,11 @@ export class FilterableDropdownComponent { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   createClicked() { | ||||||
|  |     this.creating = true | ||||||
|  |     this.createRef(this.filterText) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   dropdownOpenChange(open: boolean): void { |   dropdownOpenChange(open: boolean): void { | ||||||
|     if (open) { |     if (open) { | ||||||
|       setTimeout(() => { |       setTimeout(() => { | ||||||
| @@ -447,6 +457,10 @@ export class FilterableDropdownComponent { | |||||||
|         this.modelIsDirty = false |         this.modelIsDirty = false | ||||||
|       } |       } | ||||||
|       this.opened.next(this) |       this.opened.next(this) | ||||||
|  |     } else { | ||||||
|  |       if (this.creating) { | ||||||
|  |         this.dropdown.open() | ||||||
|  |         this.creating = false | ||||||
|       } else { |       } else { | ||||||
|         this.filterText = '' |         this.filterText = '' | ||||||
|         if (this.applyOnClose && this.selectionModel.isDirty()) { |         if (this.applyOnClose && this.selectionModel.isDirty()) { | ||||||
| @@ -454,6 +468,7 @@ export class FilterableDropdownComponent { | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   listFilterEnter(): void { |   listFilterEnter(): void { | ||||||
|     let filtered = this.filterPipe.transform(this.items, this.filterText) |     let filtered = this.filterPipe.transform(this.items, this.filterText) | ||||||
| @@ -466,6 +481,8 @@ export class FilterableDropdownComponent { | |||||||
|           this.dropdown.close() |           this.dropdown.close() | ||||||
|         } |         } | ||||||
|       }, 200) |       }, 200) | ||||||
|  |     } else if (filtered.length == 0 && this.createRef) { | ||||||
|  |       this.createClicked() | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ | |||||||
|               [editing]="true" |               [editing]="true" | ||||||
|               [manyToOne]="true" |               [manyToOne]="true" | ||||||
|               [applyOnClose]="applyOnClose" |               [applyOnClose]="applyOnClose" | ||||||
|  |               [createRef]="createTag.bind(this)" | ||||||
|               (opened)="openTagsDropdown()" |               (opened)="openTagsDropdown()" | ||||||
|               [(selectionModel)]="tagSelectionModel" |               [(selectionModel)]="tagSelectionModel" | ||||||
|               [documentCounts]="tagDocumentCounts" |               [documentCounts]="tagDocumentCounts" | ||||||
| @@ -38,6 +39,7 @@ | |||||||
|               [disabled]="!userCanEditAll" |               [disabled]="!userCanEditAll" | ||||||
|               [editing]="true" |               [editing]="true" | ||||||
|               [applyOnClose]="applyOnClose" |               [applyOnClose]="applyOnClose" | ||||||
|  |               [createRef]="createCorrespondent.bind(this)" | ||||||
|               (opened)="openCorrespondentDropdown()" |               (opened)="openCorrespondentDropdown()" | ||||||
|               [(selectionModel)]="correspondentSelectionModel" |               [(selectionModel)]="correspondentSelectionModel" | ||||||
|               [documentCounts]="correspondentDocumentCounts" |               [documentCounts]="correspondentDocumentCounts" | ||||||
| @@ -51,6 +53,7 @@ | |||||||
|               [disabled]="!userCanEditAll" |               [disabled]="!userCanEditAll" | ||||||
|               [editing]="true" |               [editing]="true" | ||||||
|               [applyOnClose]="applyOnClose" |               [applyOnClose]="applyOnClose" | ||||||
|  |               [createRef]="createDocumentType.bind(this)" | ||||||
|               (opened)="openDocumentTypeDropdown()" |               (opened)="openDocumentTypeDropdown()" | ||||||
|               [(selectionModel)]="documentTypeSelectionModel" |               [(selectionModel)]="documentTypeSelectionModel" | ||||||
|               [documentCounts]="documentTypeDocumentCounts" |               [documentCounts]="documentTypeDocumentCounts" | ||||||
| @@ -64,6 +67,7 @@ | |||||||
|               [disabled]="!userCanEditAll" |               [disabled]="!userCanEditAll" | ||||||
|               [editing]="true" |               [editing]="true" | ||||||
|               [applyOnClose]="applyOnClose" |               [applyOnClose]="applyOnClose" | ||||||
|  |               [createRef]="createStoragePath.bind(this)" | ||||||
|               (opened)="openStoragePathDropdown()" |               (opened)="openStoragePathDropdown()" | ||||||
|               [(selectionModel)]="storagePathsSelectionModel" |               [(selectionModel)]="storagePathsSelectionModel" | ||||||
|               [documentCounts]="storagePathDocumentCounts" |               [documentCounts]="storagePathDocumentCounts" | ||||||
|   | |||||||
| @@ -42,6 +42,16 @@ import { NgSelectModule } from '@ng-select/ng-select' | |||||||
| import { GroupService } from 'src/app/services/rest/group.service' | import { GroupService } from 'src/app/services/rest/group.service' | ||||||
| import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons' | import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons' | ||||||
| import { SwitchComponent } from '../../common/input/switch/switch.component' | import { SwitchComponent } from '../../common/input/switch/switch.component' | ||||||
|  | import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component' | ||||||
|  | import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component' | ||||||
|  | import { Results } from 'src/app/data/results' | ||||||
|  | import { Tag } from 'src/app/data/tag' | ||||||
|  | import { Correspondent } from 'src/app/data/correspondent' | ||||||
|  | import { DocumentType } from 'src/app/data/document-type' | ||||||
|  | import { StoragePath } from 'src/app/data/storage-path' | ||||||
|  | import { CorrespondentEditDialogComponent } from '../../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component' | ||||||
|  | import { DocumentTypeEditDialogComponent } from '../../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component' | ||||||
|  | import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component' | ||||||
|  |  | ||||||
| const selectionData: SelectionData = { | const selectionData: SelectionData = { | ||||||
|   selected_tags: [ |   selected_tags: [ | ||||||
| @@ -65,6 +75,10 @@ describe('BulkEditorComponent', () => { | |||||||
|   let documentService: DocumentService |   let documentService: DocumentService | ||||||
|   let toastService: ToastService |   let toastService: ToastService | ||||||
|   let modalService: NgbModal |   let modalService: NgbModal | ||||||
|  |   let tagService: TagService | ||||||
|  |   let correspondentsService: CorrespondentService | ||||||
|  |   let documentTypeService: DocumentTypeService | ||||||
|  |   let storagePathService: StoragePathService | ||||||
|   let httpTestingController: HttpTestingController |   let httpTestingController: HttpTestingController | ||||||
|  |  | ||||||
|   beforeEach(async () => { |   beforeEach(async () => { | ||||||
| @@ -165,6 +179,10 @@ describe('BulkEditorComponent', () => { | |||||||
|     documentService = TestBed.inject(DocumentService) |     documentService = TestBed.inject(DocumentService) | ||||||
|     toastService = TestBed.inject(ToastService) |     toastService = TestBed.inject(ToastService) | ||||||
|     modalService = TestBed.inject(NgbModal) |     modalService = TestBed.inject(NgbModal) | ||||||
|  |     tagService = TestBed.inject(TagService) | ||||||
|  |     correspondentsService = TestBed.inject(CorrespondentService) | ||||||
|  |     documentTypeService = TestBed.inject(DocumentTypeService) | ||||||
|  |     storagePathService = TestBed.inject(StoragePathService) | ||||||
|     httpTestingController = TestBed.inject(HttpTestingController) |     httpTestingController = TestBed.inject(HttpTestingController) | ||||||
|  |  | ||||||
|     fixture = TestBed.createComponent(BulkEditorComponent) |     fixture = TestBed.createComponent(BulkEditorComponent) | ||||||
| @@ -902,4 +920,180 @@ describe('BulkEditorComponent', () => { | |||||||
|       `${environment.apiBaseUrl}documents/storage_paths/` |       `${environment.apiBaseUrl}documents/storage_paths/` | ||||||
|     ) |     ) | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|  |   it('should support create new tag', () => { | ||||||
|  |     const name = 'New Tag' | ||||||
|  |     const newTag = { id: 101, name: 'New Tag' } | ||||||
|  |     const tags: Results<Tag> = { | ||||||
|  |       results: [ | ||||||
|  |         { id: 1, name: 'Tag 1' }, | ||||||
|  |         { id: 2, name: 'Tag 2' }, | ||||||
|  |       ], | ||||||
|  |       count: 2, | ||||||
|  |       all: [1, 2], | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const modalInstance = { | ||||||
|  |       componentInstance: { | ||||||
|  |         dialogMode: EditDialogMode.CREATE, | ||||||
|  |         object: { name }, | ||||||
|  |         succeeded: of(newTag), | ||||||
|  |       }, | ||||||
|  |     } | ||||||
|  |     const tagListAllSpy = jest.spyOn(tagService, 'listAll') | ||||||
|  |     tagListAllSpy.mockReturnValue(of(tags)) | ||||||
|  |  | ||||||
|  |     const tagSelectionModelToggleSpy = jest.spyOn( | ||||||
|  |       component.tagSelectionModel, | ||||||
|  |       'toggle' | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     const modalServiceOpenSpy = jest.spyOn(modalService, 'open') | ||||||
|  |     modalServiceOpenSpy.mockReturnValue(modalInstance as any) | ||||||
|  |  | ||||||
|  |     component.createTag(name) | ||||||
|  |  | ||||||
|  |     expect(modalServiceOpenSpy).toHaveBeenCalledWith(TagEditDialogComponent, { | ||||||
|  |       backdrop: 'static', | ||||||
|  |     }) | ||||||
|  |     expect(tagListAllSpy).toHaveBeenCalled() | ||||||
|  |  | ||||||
|  |     expect(tagSelectionModelToggleSpy).toHaveBeenCalledWith(newTag.id) | ||||||
|  |     expect(component.tags).toEqual(tags.results) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   it('should support create new correspondent', () => { | ||||||
|  |     const name = 'New Correspondent' | ||||||
|  |     const newCorrespondent = { id: 101, name: 'New Correspondent' } | ||||||
|  |     const correspondents: Results<Correspondent> = { | ||||||
|  |       results: [ | ||||||
|  |         { id: 1, name: 'Correspondent 1' }, | ||||||
|  |         { id: 2, name: 'Correspondent 2' }, | ||||||
|  |       ], | ||||||
|  |       count: 2, | ||||||
|  |       all: [1, 2], | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const modalInstance = { | ||||||
|  |       componentInstance: { | ||||||
|  |         dialogMode: EditDialogMode.CREATE, | ||||||
|  |         object: { name }, | ||||||
|  |         succeeded: of(newCorrespondent), | ||||||
|  |       }, | ||||||
|  |     } | ||||||
|  |     const correspondentsListAllSpy = jest.spyOn( | ||||||
|  |       correspondentsService, | ||||||
|  |       'listAll' | ||||||
|  |     ) | ||||||
|  |     correspondentsListAllSpy.mockReturnValue(of(correspondents)) | ||||||
|  |  | ||||||
|  |     const correspondentSelectionModelToggleSpy = jest.spyOn( | ||||||
|  |       component.correspondentSelectionModel, | ||||||
|  |       'toggle' | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     const modalServiceOpenSpy = jest.spyOn(modalService, 'open') | ||||||
|  |     modalServiceOpenSpy.mockReturnValue(modalInstance as any) | ||||||
|  |  | ||||||
|  |     component.createCorrespondent(name) | ||||||
|  |  | ||||||
|  |     expect(modalServiceOpenSpy).toHaveBeenCalledWith( | ||||||
|  |       CorrespondentEditDialogComponent, | ||||||
|  |       { backdrop: 'static' } | ||||||
|  |     ) | ||||||
|  |     expect(correspondentsListAllSpy).toHaveBeenCalled() | ||||||
|  |  | ||||||
|  |     expect(correspondentSelectionModelToggleSpy).toHaveBeenCalledWith( | ||||||
|  |       newCorrespondent.id | ||||||
|  |     ) | ||||||
|  |     expect(component.correspondents).toEqual(correspondents.results) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   it('should support create new document type', () => { | ||||||
|  |     const name = 'New Document Type' | ||||||
|  |     const newDocumentType = { id: 101, name: 'New Document Type' } | ||||||
|  |     const documentTypes: Results<DocumentType> = { | ||||||
|  |       results: [ | ||||||
|  |         { id: 1, name: 'Document Type 1' }, | ||||||
|  |         { id: 2, name: 'Document Type 2' }, | ||||||
|  |       ], | ||||||
|  |       count: 2, | ||||||
|  |       all: [1, 2], | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const modalInstance = { | ||||||
|  |       componentInstance: { | ||||||
|  |         dialogMode: EditDialogMode.CREATE, | ||||||
|  |         object: { name }, | ||||||
|  |         succeeded: of(newDocumentType), | ||||||
|  |       }, | ||||||
|  |     } | ||||||
|  |     const documentTypesListAllSpy = jest.spyOn(documentTypeService, 'listAll') | ||||||
|  |     documentTypesListAllSpy.mockReturnValue(of(documentTypes)) | ||||||
|  |  | ||||||
|  |     const documentTypeSelectionModelToggleSpy = jest.spyOn( | ||||||
|  |       component.documentTypeSelectionModel, | ||||||
|  |       'toggle' | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     const modalServiceOpenSpy = jest.spyOn(modalService, 'open') | ||||||
|  |     modalServiceOpenSpy.mockReturnValue(modalInstance as any) | ||||||
|  |  | ||||||
|  |     component.createDocumentType(name) | ||||||
|  |  | ||||||
|  |     expect(modalServiceOpenSpy).toHaveBeenCalledWith( | ||||||
|  |       DocumentTypeEditDialogComponent, | ||||||
|  |       { backdrop: 'static' } | ||||||
|  |     ) | ||||||
|  |     expect(documentTypesListAllSpy).toHaveBeenCalled() | ||||||
|  |  | ||||||
|  |     expect(documentTypeSelectionModelToggleSpy).toHaveBeenCalledWith( | ||||||
|  |       newDocumentType.id | ||||||
|  |     ) | ||||||
|  |     expect(component.documentTypes).toEqual(documentTypes.results) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   it('should support create new storage path', () => { | ||||||
|  |     const name = 'New Storage Path' | ||||||
|  |     const newStoragePath = { id: 101, name: 'New Storage Path' } | ||||||
|  |     const storagePaths: Results<StoragePath> = { | ||||||
|  |       results: [ | ||||||
|  |         { id: 1, name: 'Storage Path 1' }, | ||||||
|  |         { id: 2, name: 'Storage Path 2' }, | ||||||
|  |       ], | ||||||
|  |       count: 2, | ||||||
|  |       all: [1, 2], | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const modalInstance = { | ||||||
|  |       componentInstance: { | ||||||
|  |         dialogMode: EditDialogMode.CREATE, | ||||||
|  |         object: { name }, | ||||||
|  |         succeeded: of(newStoragePath), | ||||||
|  |       }, | ||||||
|  |     } | ||||||
|  |     const storagePathsListAllSpy = jest.spyOn(storagePathService, 'listAll') | ||||||
|  |     storagePathsListAllSpy.mockReturnValue(of(storagePaths)) | ||||||
|  |  | ||||||
|  |     const storagePathsSelectionModelToggleSpy = jest.spyOn( | ||||||
|  |       component.storagePathsSelectionModel, | ||||||
|  |       'toggle' | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     const modalServiceOpenSpy = jest.spyOn(modalService, 'open') | ||||||
|  |     modalServiceOpenSpy.mockReturnValue(modalInstance as any) | ||||||
|  |  | ||||||
|  |     component.createStoragePath(name) | ||||||
|  |  | ||||||
|  |     expect(modalServiceOpenSpy).toHaveBeenCalledWith( | ||||||
|  |       StoragePathEditDialogComponent, | ||||||
|  |       { backdrop: 'static' } | ||||||
|  |     ) | ||||||
|  |     expect(storagePathsListAllSpy).toHaveBeenCalled() | ||||||
|  |  | ||||||
|  |     expect(storagePathsSelectionModelToggleSpy).toHaveBeenCalledWith( | ||||||
|  |       newStoragePath.id | ||||||
|  |     ) | ||||||
|  |     expect(component.storagePaths).toEqual(storagePaths.results) | ||||||
|  |   }) | ||||||
| }) | }) | ||||||
|   | |||||||
| @@ -33,7 +33,12 @@ import { | |||||||
|   PermissionType, |   PermissionType, | ||||||
| } from 'src/app/services/permissions.service' | } from 'src/app/services/permissions.service' | ||||||
| import { FormControl, FormGroup } from '@angular/forms' | import { FormControl, FormGroup } from '@angular/forms' | ||||||
| import { first, Subject, takeUntil } from 'rxjs' | import { first, map, Subject, switchMap, takeUntil } from 'rxjs' | ||||||
|  | import { CorrespondentEditDialogComponent } from '../../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component' | ||||||
|  | import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component' | ||||||
|  | import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component' | ||||||
|  | import { DocumentTypeEditDialogComponent } from '../../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component' | ||||||
|  | import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'pngx-bulk-editor', |   selector: 'pngx-bulk-editor', | ||||||
| @@ -479,6 +484,92 @@ export class BulkEditorComponent | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   createTag(name: string) { | ||||||
|  |     let modal = this.modalService.open(TagEditDialogComponent, { | ||||||
|  |       backdrop: 'static', | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.dialogMode = EditDialogMode.CREATE | ||||||
|  |     modal.componentInstance.object = { name } | ||||||
|  |     modal.componentInstance.succeeded | ||||||
|  |       .pipe( | ||||||
|  |         switchMap((newTag) => { | ||||||
|  |           return this.tagService | ||||||
|  |             .listAll() | ||||||
|  |             .pipe(map((tags) => ({ newTag, tags }))) | ||||||
|  |         }) | ||||||
|  |       ) | ||||||
|  |       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||||
|  |       .subscribe(({ newTag, tags }) => { | ||||||
|  |         this.tags = tags.results | ||||||
|  |         this.tagSelectionModel.toggle(newTag.id) | ||||||
|  |       }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   createCorrespondent(name: string) { | ||||||
|  |     let modal = this.modalService.open(CorrespondentEditDialogComponent, { | ||||||
|  |       backdrop: 'static', | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.dialogMode = EditDialogMode.CREATE | ||||||
|  |     modal.componentInstance.object = { name } | ||||||
|  |     modal.componentInstance.succeeded | ||||||
|  |       .pipe( | ||||||
|  |         switchMap((newCorrespondent) => { | ||||||
|  |           return this.correspondentService | ||||||
|  |             .listAll() | ||||||
|  |             .pipe( | ||||||
|  |               map((correspondents) => ({ newCorrespondent, correspondents })) | ||||||
|  |             ) | ||||||
|  |         }) | ||||||
|  |       ) | ||||||
|  |       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||||
|  |       .subscribe(({ newCorrespondent, correspondents }) => { | ||||||
|  |         this.correspondents = correspondents.results | ||||||
|  |         this.correspondentSelectionModel.toggle(newCorrespondent.id) | ||||||
|  |       }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   createDocumentType(name: string) { | ||||||
|  |     let modal = this.modalService.open(DocumentTypeEditDialogComponent, { | ||||||
|  |       backdrop: 'static', | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.dialogMode = EditDialogMode.CREATE | ||||||
|  |     modal.componentInstance.object = { name } | ||||||
|  |     modal.componentInstance.succeeded | ||||||
|  |       .pipe( | ||||||
|  |         switchMap((newDocumentType) => { | ||||||
|  |           return this.documentTypeService | ||||||
|  |             .listAll() | ||||||
|  |             .pipe(map((documentTypes) => ({ newDocumentType, documentTypes }))) | ||||||
|  |         }) | ||||||
|  |       ) | ||||||
|  |       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||||
|  |       .subscribe(({ newDocumentType, documentTypes }) => { | ||||||
|  |         this.documentTypes = documentTypes.results | ||||||
|  |         this.documentTypeSelectionModel.toggle(newDocumentType.id) | ||||||
|  |       }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   createStoragePath(name: string) { | ||||||
|  |     let modal = this.modalService.open(StoragePathEditDialogComponent, { | ||||||
|  |       backdrop: 'static', | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.dialogMode = EditDialogMode.CREATE | ||||||
|  |     modal.componentInstance.object = { name } | ||||||
|  |     modal.componentInstance.succeeded | ||||||
|  |       .pipe( | ||||||
|  |         switchMap((newStoragePath) => { | ||||||
|  |           return this.storagePathService | ||||||
|  |             .listAll() | ||||||
|  |             .pipe(map((storagePaths) => ({ newStoragePath, storagePaths }))) | ||||||
|  |         }) | ||||||
|  |       ) | ||||||
|  |       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||||
|  |       .subscribe(({ newStoragePath, storagePaths }) => { | ||||||
|  |         this.storagePaths = storagePaths.results | ||||||
|  |         this.storagePathsSelectionModel.toggle(newStoragePath.id) | ||||||
|  |       }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   applyDelete() { |   applyDelete() { | ||||||
|     let modal = this.modalService.open(ConfirmDialogComponent, { |     let modal = this.modalService.open(ConfirmDialogComponent, { | ||||||
|       backdrop: 'static', |       backdrop: 'static', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon