Feature: allow create objects from bulk edit (#5667)

This commit is contained in:
shamoon
2024-02-06 07:31:07 -08:00
committed by GitHub
parent c4e67d59b4
commit 7a760d7679
6 changed files with 364 additions and 8 deletions

View File

@@ -25,6 +25,7 @@
[editing]="true"
[manyToOne]="true"
[applyOnClose]="applyOnClose"
[createRef]="createTag.bind(this)"
(opened)="openTagsDropdown()"
[(selectionModel)]="tagSelectionModel"
[documentCounts]="tagDocumentCounts"
@@ -38,6 +39,7 @@
[disabled]="!userCanEditAll"
[editing]="true"
[applyOnClose]="applyOnClose"
[createRef]="createCorrespondent.bind(this)"
(opened)="openCorrespondentDropdown()"
[(selectionModel)]="correspondentSelectionModel"
[documentCounts]="correspondentDocumentCounts"
@@ -51,6 +53,7 @@
[disabled]="!userCanEditAll"
[editing]="true"
[applyOnClose]="applyOnClose"
[createRef]="createDocumentType.bind(this)"
(opened)="openDocumentTypeDropdown()"
[(selectionModel)]="documentTypeSelectionModel"
[documentCounts]="documentTypeDocumentCounts"
@@ -64,6 +67,7 @@
[disabled]="!userCanEditAll"
[editing]="true"
[applyOnClose]="applyOnClose"
[createRef]="createStoragePath.bind(this)"
(opened)="openStoragePathDropdown()"
[(selectionModel)]="storagePathsSelectionModel"
[documentCounts]="storagePathDocumentCounts"

View File

@@ -42,6 +42,16 @@ import { NgSelectModule } from '@ng-select/ng-select'
import { GroupService } from 'src/app/services/rest/group.service'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
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 = {
selected_tags: [
@@ -65,6 +75,10 @@ describe('BulkEditorComponent', () => {
let documentService: DocumentService
let toastService: ToastService
let modalService: NgbModal
let tagService: TagService
let correspondentsService: CorrespondentService
let documentTypeService: DocumentTypeService
let storagePathService: StoragePathService
let httpTestingController: HttpTestingController
beforeEach(async () => {
@@ -165,6 +179,10 @@ describe('BulkEditorComponent', () => {
documentService = TestBed.inject(DocumentService)
toastService = TestBed.inject(ToastService)
modalService = TestBed.inject(NgbModal)
tagService = TestBed.inject(TagService)
correspondentsService = TestBed.inject(CorrespondentService)
documentTypeService = TestBed.inject(DocumentTypeService)
storagePathService = TestBed.inject(StoragePathService)
httpTestingController = TestBed.inject(HttpTestingController)
fixture = TestBed.createComponent(BulkEditorComponent)
@@ -902,4 +920,180 @@ describe('BulkEditorComponent', () => {
`${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)
})
})

View File

@@ -33,7 +33,12 @@ import {
PermissionType,
} from 'src/app/services/permissions.service'
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({
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() {
let modal = this.modalService.open(ConfirmDialogComponent, {
backdrop: 'static',