mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Fix: replace drag drop & clipboard dependencies with Angular CDK (#4362)
* Swap ngx-drag-drop dependency for Angular CDK * Swap ngx-clipboard dependency for Angular CDK
This commit is contained in:
		| @@ -464,11 +464,11 @@ | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.html</context> | ||||
|           <context context-type="linenumber">15</context> | ||||
|           <context context-type="linenumber">14</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html</context> | ||||
|           <context context-type="linenumber">21</context> | ||||
|           <context context-type="linenumber">14</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> | ||||
| @@ -1482,7 +1482,7 @@ | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">17</context> | ||||
|           <context context-type="linenumber">13</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> | ||||
| @@ -1706,7 +1706,7 @@ | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">27</context> | ||||
|           <context context-type="linenumber">23</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context> | ||||
| @@ -2078,7 +2078,7 @@ | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">19</context> | ||||
|           <context context-type="linenumber">15</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html</context> | ||||
| @@ -3612,35 +3612,35 @@ | ||||
|         <source>Hello <x id="PH" equiv-text="this.settingsService.displayName"/>, welcome to Paperless-ngx</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||
|           <context context-type="linenumber">48</context> | ||||
|           <context context-type="linenumber">53</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="5334686081082652461" datatype="html"> | ||||
|         <source>Welcome to Paperless-ngx</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||
|           <context context-type="linenumber">50</context> | ||||
|           <context context-type="linenumber">55</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="1325877348738783391" datatype="html"> | ||||
|         <source>Dashboard updated</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||
|           <context context-type="linenumber">73</context> | ||||
|           <context context-type="linenumber">86</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="3214475953924351473" datatype="html"> | ||||
|         <source>Error updating dashboard</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/dashboard.component.ts</context> | ||||
|           <context context-type="linenumber">76</context> | ||||
|           <context context-type="linenumber">89</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="2946624699882754313" datatype="html"> | ||||
|         <source>Show all</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">12</context> | ||||
|           <context context-type="linenumber">8</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html</context> | ||||
| @@ -3651,7 +3651,7 @@ | ||||
|         <source>Title</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">18</context> | ||||
|           <context context-type="linenumber">14</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> | ||||
| @@ -3674,7 +3674,7 @@ | ||||
|         <source>Correspondent</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">20</context> | ||||
|           <context context-type="linenumber">16</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> | ||||
| @@ -3701,14 +3701,14 @@ | ||||
|         <source>View Preview</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">35</context> | ||||
|           <context context-type="linenumber">31</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="3099741642167775297" datatype="html"> | ||||
|         <source>Download</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">45</context> | ||||
|           <context context-type="linenumber">41</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> | ||||
| @@ -3731,7 +3731,7 @@ | ||||
|         <source>No documents</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context> | ||||
|           <context context-type="linenumber">57</context> | ||||
|           <context context-type="linenumber">53</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="1069523139277190436" datatype="html"> | ||||
|   | ||||
							
								
								
									
										63
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										63
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -9,6 +9,7 @@ | ||||
|       "version": "0.0.0", | ||||
|       "hasInstallScript": true, | ||||
|       "dependencies": { | ||||
|         "@angular/cdk": "^16.2.7", | ||||
|         "@angular/common": "~16.2.7", | ||||
|         "@angular/compiler": "~16.2.7", | ||||
|         "@angular/core": "~16.2.7", | ||||
| @@ -25,10 +26,8 @@ | ||||
|         "file-saver": "^2.0.5", | ||||
|         "mime-names": "^1.0.0", | ||||
|         "ng2-pdf-viewer": "^10.0.0", | ||||
|         "ngx-clipboard": "^16.0.0", | ||||
|         "ngx-color": "^9.0.0", | ||||
|         "ngx-cookie-service": "^16.0.1", | ||||
|         "ngx-drag-drop": "^16.1.0", | ||||
|         "ngx-file-drop": "^16.0.0", | ||||
|         "ngx-ui-tour-ng-bootstrap": "^13.0.4", | ||||
|         "rxjs": "^7.8.1", | ||||
| @@ -1160,6 +1159,22 @@ | ||||
|         "typescript": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@angular/cdk": { | ||||
|       "version": "16.2.7", | ||||
|       "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.7.tgz", | ||||
|       "integrity": "sha512-LLbCu0pHHsZWGjSpQW0qRoKYRCm09TuFH2vzsViyaQF7umDKlk52QcDFB/nMioyiWPgqXkyHyGMFG1vFBNSIeg==", | ||||
|       "dependencies": { | ||||
|         "tslib": "^2.3.0" | ||||
|       }, | ||||
|       "optionalDependencies": { | ||||
|         "parse5": "^7.1.2" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@angular/common": "^16.0.0 || ^17.0.0", | ||||
|         "@angular/core": "^16.0.0 || ^17.0.0", | ||||
|         "rxjs": "^6.5.3 || ^7.4.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@angular/cli": { | ||||
|       "version": "16.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.4.tgz", | ||||
| @@ -8918,7 +8933,7 @@ | ||||
|       "version": "4.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", | ||||
|       "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=0.12" | ||||
|       }, | ||||
| @@ -14073,19 +14088,6 @@ | ||||
|         "pdfjs-dist": "~2.16.105" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ngx-clipboard": { | ||||
|       "version": "16.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-16.0.0.tgz", | ||||
|       "integrity": "sha512-rZ/Eo1PqiKMiyF8tdjhmUkoUu68f7OzBJ7YH1YFeh2RAaNrerTaW8XfFOzppSckjFQqA1fwGSYuTTJlDhDag5w==", | ||||
|       "dependencies": { | ||||
|         "ngx-window-token": ">=7.0.0", | ||||
|         "tslib": "^2.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@angular/common": ">=13.0.0", | ||||
|         "@angular/core": ">=13.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ngx-color": { | ||||
|       "version": "9.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/ngx-color/-/ngx-color-9.0.0.tgz", | ||||
| @@ -14112,18 +14114,6 @@ | ||||
|         "@angular/core": "^16.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ngx-drag-drop": { | ||||
|       "version": "16.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/ngx-drag-drop/-/ngx-drag-drop-16.1.0.tgz", | ||||
|       "integrity": "sha512-y2l9pJGD7OupsIRkCElN/JqTgzjg2V9ZxymKGQR7ZjjcdjaP1wKkiFWIgVEvLNtb8wgm10U+9tkGwLClGaHkQA==", | ||||
|       "dependencies": { | ||||
|         "tslib": "^2.3.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@angular/common": "^16.0.0", | ||||
|         "@angular/core": "^16.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ngx-file-drop": { | ||||
|       "version": "16.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/ngx-file-drop/-/ngx-file-drop-16.0.0.tgz", | ||||
| @@ -14168,21 +14158,6 @@ | ||||
|         "@ng-bootstrap/ng-bootstrap": "^15.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ngx-window-token": { | ||||
|       "version": "7.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/ngx-window-token/-/ngx-window-token-7.0.0.tgz", | ||||
|       "integrity": "sha512-5+XfRVSY7Dciu8xyCNMkOlH2UfwR9W2P1Pirz7caaZgOZDjFbL8aEO2stjfJJm2FFf1D6dlVHNzhLWGk9HGkqA==", | ||||
|       "dependencies": { | ||||
|         "tslib": "^2.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^14.20.0 || ^16.13.0 || >=18.10.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@angular/common": ">=13.0.0", | ||||
|         "@angular/core": ">=13.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/nice-napi": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", | ||||
| @@ -15048,7 +15023,7 @@ | ||||
|       "version": "7.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", | ||||
|       "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "entities": "^4.4.0" | ||||
|       }, | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
|   }, | ||||
|   "private": true, | ||||
|   "dependencies": { | ||||
|     "@angular/cdk": "^16.2.7", | ||||
|     "@angular/common": "~16.2.7", | ||||
|     "@angular/compiler": "~16.2.7", | ||||
|     "@angular/core": "~16.2.7", | ||||
| @@ -27,10 +28,8 @@ | ||||
|     "file-saver": "^2.0.5", | ||||
|     "mime-names": "^1.0.0", | ||||
|     "ng2-pdf-viewer": "^10.0.0", | ||||
|     "ngx-clipboard": "^16.0.0", | ||||
|     "ngx-color": "^9.0.0", | ||||
|     "ngx-cookie-service": "^16.0.1", | ||||
|     "ngx-drag-drop": "^16.1.0", | ||||
|     "ngx-file-drop": "^16.0.0", | ||||
|     "ngx-ui-tour-ng-bootstrap": "^13.0.4", | ||||
|     "rxjs": "^7.8.1", | ||||
|   | ||||
| @@ -99,7 +99,7 @@ import { ConsumptionTemplatesComponent } from './components/manage/consumption-t | ||||
| import { ConsumptionTemplateEditDialogComponent } from './components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component' | ||||
| import { MailComponent } from './components/manage/mail/mail.component' | ||||
| import { UsersAndGroupsComponent } from './components/admin/users-groups/users-groups.component' | ||||
| import { DndModule } from 'ngx-drag-drop' | ||||
| import { DragDropModule } from '@angular/cdk/drag-drop' | ||||
| import { FileDropComponent } from './components/file-drop/file-drop.component' | ||||
|  | ||||
| import localeAf from '@angular/common/locales/af' | ||||
| @@ -257,7 +257,7 @@ function initializeApp(settings: SettingsService) { | ||||
|     NgSelectModule, | ||||
|     ColorSliderModule, | ||||
|     TourNgBootstrapModule, | ||||
|     DndModule, | ||||
|     DragDropModule, | ||||
|   ], | ||||
|   providers: [ | ||||
|     { | ||||
|   | ||||
| @@ -18,7 +18,7 @@ import { ShareLinkService } from 'src/app/services/rest/share-link.service' | ||||
| import { ToastService } from 'src/app/services/toast.service' | ||||
| import { environment } from 'src/environments/environment' | ||||
| import { ShareLinksDropdownComponent } from './share-links-dropdown.component' | ||||
| import { ClipboardService } from 'ngx-clipboard' | ||||
| import { Clipboard } from '@angular/cdk/clipboard' | ||||
|  | ||||
| describe('ShareLinksDropdownComponent', () => { | ||||
|   let component: ShareLinksDropdownComponent | ||||
| @@ -26,7 +26,7 @@ describe('ShareLinksDropdownComponent', () => { | ||||
|   let shareLinkService: ShareLinkService | ||||
|   let toastService: ToastService | ||||
|   let httpController: HttpTestingController | ||||
|   let clipboardService: ClipboardService | ||||
|   let clipboard: Clipboard | ||||
|  | ||||
|   beforeEach(() => { | ||||
|     TestBed.configureTestingModule({ | ||||
| @@ -38,7 +38,7 @@ describe('ShareLinksDropdownComponent', () => { | ||||
|     shareLinkService = TestBed.inject(ShareLinkService) | ||||
|     toastService = TestBed.inject(ToastService) | ||||
|     httpController = TestBed.inject(HttpTestingController) | ||||
|     clipboardService = TestBed.inject(ClipboardService) | ||||
|     clipboard = TestBed.inject(Clipboard) | ||||
|  | ||||
|     component = fixture.componentInstance | ||||
|     fixture.detectChanges() | ||||
| @@ -102,7 +102,7 @@ describe('ShareLinksDropdownComponent', () => { | ||||
|     const expiration = new Date() | ||||
|     expiration.setDate(expiration.getDate() + 7) | ||||
|  | ||||
|     const copySpy = jest.spyOn(clipboardService, 'copy') | ||||
|     const copySpy = jest.spyOn(clipboard, 'copy') | ||||
|     const refreshSpy = jest.spyOn(component, 'refresh') | ||||
|  | ||||
|     component.createLink() | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import { | ||||
| import { ShareLinkService } from 'src/app/services/rest/share-link.service' | ||||
| import { ToastService } from 'src/app/services/toast.service' | ||||
| import { environment } from 'src/environments/environment' | ||||
| import { ClipboardService } from 'ngx-clipboard' | ||||
| import { Clipboard } from '@angular/cdk/clipboard' | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'pngx-share-links-dropdown', | ||||
| @@ -51,7 +51,7 @@ export class ShareLinksDropdownComponent implements OnInit { | ||||
|   constructor( | ||||
|     private shareLinkService: ShareLinkService, | ||||
|     private toastService: ToastService, | ||||
|     private clipboardService: ClipboardService | ||||
|     private clipboard: Clipboard | ||||
|   ) {} | ||||
|  | ||||
|   ngOnInit(): void { | ||||
| @@ -91,7 +91,7 @@ export class ShareLinksDropdownComponent implements OnInit { | ||||
|   } | ||||
|  | ||||
|   copy(link: PaperlessShareLink) { | ||||
|     this.clipboardService.copy(this.getShareUrl(link)) | ||||
|     this.clipboard.copy(this.getShareUrl(link)) | ||||
|     this.copied = link.id | ||||
|     setTimeout(() => { | ||||
|       this.copied = null | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import { ComponentFixture } from '@angular/core/testing' | ||||
| import { HttpClientTestingModule } from '@angular/common/http/testing' | ||||
| import { of } from 'rxjs' | ||||
| import { NgbModule } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { ClipboardService } from 'ngx-clipboard' | ||||
| import { Clipboard } from '@angular/cdk/clipboard' | ||||
|  | ||||
| const toasts = [ | ||||
|   { | ||||
| @@ -42,7 +42,7 @@ describe('ToastsComponent', () => { | ||||
|   let component: ToastsComponent | ||||
|   let fixture: ComponentFixture<ToastsComponent> | ||||
|   let toastService: ToastService | ||||
|   let clipboardService: ClipboardService | ||||
|   let clipboard: Clipboard | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     TestBed.configureTestingModule({ | ||||
| @@ -60,7 +60,7 @@ describe('ToastsComponent', () => { | ||||
|  | ||||
|     fixture = TestBed.createComponent(ToastsComponent) | ||||
|     toastService = TestBed.inject(ToastService) | ||||
|     clipboardService = TestBed.inject(ClipboardService) | ||||
|     clipboard = TestBed.inject(Clipboard) | ||||
|  | ||||
|     component = fixture.componentInstance | ||||
|  | ||||
| @@ -117,7 +117,7 @@ describe('ToastsComponent', () => { | ||||
|       'Error 2 message details' | ||||
|     ) | ||||
|  | ||||
|     const copySpy = jest.spyOn(clipboardService, 'copy') | ||||
|     const copySpy = jest.spyOn(clipboard, 'copy') | ||||
|     component.copyError(toasts[2].error) | ||||
|     expect(copySpy).toHaveBeenCalled() | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { Component, OnDestroy, OnInit } from '@angular/core' | ||||
| import { Subscription } from 'rxjs' | ||||
| import { Toast, ToastService } from 'src/app/services/toast.service' | ||||
| import { ClipboardService } from 'ngx-clipboard' | ||||
| import { Clipboard } from '@angular/cdk/clipboard' | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'pngx-toasts', | ||||
| @@ -11,7 +11,7 @@ import { ClipboardService } from 'ngx-clipboard' | ||||
| export class ToastsComponent implements OnInit, OnDestroy { | ||||
|   constructor( | ||||
|     private toastService: ToastService, | ||||
|     private clipboardService: ClipboardService | ||||
|     private clipboard: Clipboard | ||||
|   ) {} | ||||
|  | ||||
|   private subscription: Subscription | ||||
| @@ -49,7 +49,7 @@ export class ToastsComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   public copyError(error: any) { | ||||
|     this.clipboardService.copy(JSON.stringify(error)) | ||||
|     this.clipboard.copy(JSON.stringify(error)) | ||||
|     this.copied = true | ||||
|     setTimeout(() => { | ||||
|       this.copied = false | ||||
|   | ||||
| @@ -5,10 +5,9 @@ | ||||
| <div class="row"> | ||||
|   <div class="col-auto col-lg-8 col-xl-9 mb-4"> | ||||
|     <div class="row row-cols-1 g-4" tourAnchor="tour.dashboard" | ||||
|       dndDropzone | ||||
|       [dndDisableIf]="settingsService.globalDropzoneActive" | ||||
|       dndEffectAllowed="move" | ||||
|       (dndDrop)="onDrop($event)" | ||||
|       cdkDropList | ||||
|       [cdkDropListDisabled]="settingsService.globalDropzoneActive" | ||||
|       (cdkDropListDropped)="onDrop($event)" | ||||
|     > | ||||
|       <div *ngIf="savedViewService.loading" class="col"> | ||||
|         <div class="spinner-border spinner-border-sm me-2" role="status"></div> | ||||
| @@ -23,14 +22,12 @@ | ||||
|         <div *ngFor="let v of dashboardViews" class="col"> | ||||
|           <pngx-saved-view-widget | ||||
|             [savedView]="v" | ||||
|             (dndStart)="onDragStart($event)" | ||||
|             (dndMoved)="onDragged(v)" | ||||
|             (dndEnd)="onDragEnd($event)" | ||||
|             > | ||||
|             (cdkDragStarted)="onDragStart($event)" | ||||
|             (cdkDragEnded)="onDragEnd($event)" | ||||
|           > | ||||
|           </pngx-saved-view-widget> | ||||
|         </div> | ||||
|       </ng-container> | ||||
|       <div class="p-1" dndPlaceholderRef></div> | ||||
|     </div> | ||||
|   </div> | ||||
|   <div class="col-auto col-lg-4 col-xl-3 col-sidebar"> | ||||
|   | ||||
| @@ -1,3 +1,19 @@ | ||||
| .col-sidebar .row { | ||||
|     top: 3.5rem; | ||||
| } | ||||
|  | ||||
| :host ::ng-deep { | ||||
|     .cdk-drag-placeholder { | ||||
|       opacity: .5; | ||||
|     } | ||||
|  | ||||
|     /* Animate items as they're being sorted. */ | ||||
|     .cdk-drop-list-dragging .cdk-drag { | ||||
|       transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); | ||||
|     } | ||||
|  | ||||
|     /* Animate an item that has been dropped. */ | ||||
|     .cdk-drag-animating { | ||||
|       transition: transform 300ms cubic-bezier(0, 0, 0.2, 1); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing' | ||||
| import { NgbAlertModule, NgbAlert } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { PermissionsGuard } from 'src/app/guards/permissions.guard' | ||||
| import { DashboardComponent } from './dashboard.component' | ||||
| import { HttpClientTestingModule } from '@angular/common/http/testing' | ||||
| @@ -17,9 +17,10 @@ import { RouterTestingModule } from '@angular/router/testing' | ||||
| import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap' | ||||
| import { LogoComponent } from '../common/logo/logo.component' | ||||
| import { of, throwError } from 'rxjs' | ||||
| import { DndDropEvent, DndModule } from 'ngx-drag-drop' | ||||
| import { ToastService } from 'src/app/services/toast.service' | ||||
| import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings' | ||||
| import { CdkDragDrop, DragDropModule } from '@angular/cdk/drag-drop' | ||||
| import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' | ||||
|  | ||||
| const saved_views = [ | ||||
|   { | ||||
| @@ -105,7 +106,7 @@ describe('DashboardComponent', () => { | ||||
|         HttpClientTestingModule, | ||||
|         RouterTestingModule, | ||||
|         TourNgBootstrapModule, | ||||
|         DndModule, | ||||
|         DragDropModule, | ||||
|       ], | ||||
|     }).compileComponents() | ||||
|  | ||||
| @@ -165,18 +166,18 @@ describe('DashboardComponent', () => { | ||||
|     const settingsSpy = jest.spyOn(settingsService, 'updateDashboardViewsSort') | ||||
|     const toastSpy = jest.spyOn(toastService, 'showInfo') | ||||
|     jest.spyOn(settingsService, 'storeSettings').mockReturnValue(of(true)) | ||||
|     component.onDrop({ index: 2, data: saved_views[0] } as DndDropEvent) | ||||
|     component.onDragged(saved_views[0]) | ||||
|     component.onDrop({ previousIndex: 0, currentIndex: 1 } as CdkDragDrop< | ||||
|       PaperlessSavedView[] | ||||
|     >) | ||||
|     expect(settingsSpy).toHaveBeenCalledWith([ | ||||
|       saved_views[2], | ||||
|       saved_views[0], | ||||
|       saved_views[3], | ||||
|     ]) | ||||
|     expect(toastSpy).toHaveBeenCalled() | ||||
|     component.onDrop({ data: saved_views[3] } as DndDropEvent) | ||||
|   }) | ||||
|  | ||||
|   it('should update saved view sorting on drag + drop, show info2', () => { | ||||
|   it('should update saved view sorting on drag + drop, show error', () => { | ||||
|     jest.spyOn(settingsService, 'get').mockImplementation((key) => { | ||||
|       if (key === SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER) return [] | ||||
|     }) | ||||
| @@ -188,8 +189,9 @@ describe('DashboardComponent', () => { | ||||
|     jest | ||||
|       .spyOn(settingsService, 'storeSettings') | ||||
|       .mockReturnValue(throwError(() => new Error('unable to save'))) | ||||
|     component.onDrop({ index: 2, data: saved_views[0] } as DndDropEvent) | ||||
|     component.onDragged(saved_views[0]) | ||||
|     component.onDrop({ previousIndex: 0, currentIndex: 2 } as CdkDragDrop< | ||||
|       PaperlessSavedView[] | ||||
|     >) | ||||
|     expect(toastSpy).toHaveBeenCalled() | ||||
|   }) | ||||
| }) | ||||
|   | ||||
| @@ -4,9 +4,14 @@ import { SettingsService } from 'src/app/services/settings.service' | ||||
| import { ComponentWithPermissions } from '../with-permissions/with-permissions.component' | ||||
| import { TourService } from 'ngx-ui-tour-ng-bootstrap' | ||||
| import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' | ||||
| import { DndDropEvent } from 'ngx-drag-drop' | ||||
| import { ToastService } from 'src/app/services/toast.service' | ||||
| import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings' | ||||
| import { | ||||
|   CdkDragDrop, | ||||
|   CdkDragEnd, | ||||
|   CdkDragStart, | ||||
|   moveItemInArray, | ||||
| } from '@angular/cdk/drag-drop' | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'pngx-dashboard', | ||||
| @@ -59,13 +64,21 @@ export class DashboardComponent extends ComponentWithPermissions { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   onDragStart(event: DragEvent) { | ||||
|   onDragStart(event: CdkDragStart) { | ||||
|     this.settingsService.globalDropzoneEnabled = false | ||||
|   } | ||||
|  | ||||
|   onDragged(v: PaperlessSavedView) { | ||||
|     const index = this.dashboardViews.indexOf(v) | ||||
|     this.dashboardViews.splice(index, 1) | ||||
|   onDragEnd(event: CdkDragEnd) { | ||||
|     this.settingsService.globalDropzoneEnabled = true | ||||
|   } | ||||
|  | ||||
|   onDrop(event: CdkDragDrop<PaperlessSavedView[]>) { | ||||
|     moveItemInArray( | ||||
|       this.dashboardViews, | ||||
|       event.previousIndex, | ||||
|       event.currentIndex | ||||
|     ) | ||||
|  | ||||
|     this.settingsService | ||||
|       .updateDashboardViewsSort(this.dashboardViews) | ||||
|       .subscribe({ | ||||
| @@ -77,16 +90,4 @@ export class DashboardComponent extends ComponentWithPermissions { | ||||
|         }, | ||||
|       }) | ||||
|   } | ||||
|  | ||||
|   onDragEnd(event: DragEvent) { | ||||
|     this.settingsService.globalDropzoneEnabled = true | ||||
|   } | ||||
|  | ||||
|   onDrop(event: DndDropEvent) { | ||||
|     if (typeof event.index === 'undefined') { | ||||
|       event.index = this.dashboardViews.length | ||||
|     } | ||||
|  | ||||
|     this.dashboardViews.splice(event.index, 0, event.data) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -3,10 +3,6 @@ | ||||
|   [title]="savedView.name" | ||||
|   [loading]="loading" | ||||
|   [draggable]="savedView" | ||||
|   (dndStart)="dndStart.emit($event)" | ||||
|   (dndMoved)="dndMoved.emit($event)" | ||||
|   (dndCanceled)="dndCanceled.emit($event)" | ||||
|   (dndEnd)="dndEnd.emit($event)" | ||||
| > | ||||
|  | ||||
|   <a *ngIf="documents.length" class="btn-link text-decoration-none" header-buttons [routerLink]="[]" (click)="showAll()" i18n>Show all</a> | ||||
|   | ||||
| @@ -28,7 +28,7 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component' | ||||
| import { SavedViewWidgetComponent } from './saved-view-widget.component' | ||||
| import { By } from '@angular/platform-browser' | ||||
| import { SafeUrlPipe } from 'src/app/pipes/safeurl.pipe' | ||||
| import { DndModule } from 'ngx-drag-drop' | ||||
| import { DragDropModule } from '@angular/cdk/drag-drop' | ||||
|  | ||||
| const savedView: PaperlessSavedView = { | ||||
|   id: 1, | ||||
| @@ -91,7 +91,7 @@ describe('SavedViewWidgetComponent', () => { | ||||
|         HttpClientTestingModule, | ||||
|         NgbModule, | ||||
|         RouterTestingModule.withRoutes(routes), | ||||
|         DndModule, | ||||
|         DragDropModule, | ||||
|       ], | ||||
|     }).compileComponents() | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,8 @@ | ||||
| import { | ||||
|   Component, | ||||
|   EventEmitter, | ||||
|   Input, | ||||
|   OnDestroy, | ||||
|   OnInit, | ||||
|   Output, | ||||
|   QueryList, | ||||
|   ViewChildren, | ||||
| } from '@angular/core' | ||||
| @@ -53,18 +51,6 @@ export class SavedViewWidgetComponent | ||||
|   @Input() | ||||
|   savedView: PaperlessSavedView | ||||
|  | ||||
|   @Output() | ||||
|   dndStart: EventEmitter<DragEvent> = new EventEmitter() | ||||
|  | ||||
|   @Output() | ||||
|   dndMoved: EventEmitter<DragEvent> = new EventEmitter() | ||||
|  | ||||
|   @Output() | ||||
|   dndCanceled: EventEmitter<DragEvent> = new EventEmitter() | ||||
|  | ||||
|   @Output() | ||||
|   dndEnd: EventEmitter<DragEvent> = new EventEmitter() | ||||
|  | ||||
|   documents: PaperlessDocument[] = [] | ||||
|  | ||||
|   unsubscribeNotifier: Subject<any> = new Subject() | ||||
|   | ||||
| @@ -12,12 +12,12 @@ import { RouterTestingModule } from '@angular/router/testing' | ||||
| import { routes } from 'src/app/app-routing.module' | ||||
| import { PermissionsGuard } from 'src/app/guards/permissions.guard' | ||||
| import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' | ||||
| import { DndModule } from 'ngx-drag-drop' | ||||
| import { | ||||
|   ConsumerStatusService, | ||||
|   FileStatus, | ||||
| } from 'src/app/services/consumer-status.service' | ||||
| import { Subject } from 'rxjs' | ||||
| import { DragDropModule } from '@angular/cdk/drag-drop' | ||||
|  | ||||
| describe('StatisticsWidgetComponent', () => { | ||||
|   let component: StatisticsWidgetComponent | ||||
| @@ -38,7 +38,7 @@ describe('StatisticsWidgetComponent', () => { | ||||
|         HttpClientTestingModule, | ||||
|         NgbModule, | ||||
|         RouterTestingModule.withRoutes(routes), | ||||
|         DndModule, | ||||
|         DragDropModule, | ||||
|       ], | ||||
|     }).compileComponents() | ||||
|  | ||||
|   | ||||
| @@ -25,7 +25,7 @@ import { PermissionsService } from 'src/app/services/permissions.service' | ||||
| import { UploadDocumentsService } from 'src/app/services/upload-documents.service' | ||||
| import { WidgetFrameComponent } from '../widget-frame/widget-frame.component' | ||||
| import { UploadFileWidgetComponent } from './upload-file-widget.component' | ||||
| import { DndModule } from 'ngx-drag-drop' | ||||
| import { DragDropModule } from '@angular/cdk/drag-drop' | ||||
|  | ||||
| describe('UploadFileWidgetComponent', () => { | ||||
|   let component: UploadFileWidgetComponent | ||||
| @@ -54,7 +54,7 @@ describe('UploadFileWidgetComponent', () => { | ||||
|         NgbModule, | ||||
|         RouterTestingModule.withRoutes(routes), | ||||
|         NgbAlertModule, | ||||
|         DndModule, | ||||
|         DragDropModule, | ||||
|       ], | ||||
|     }).compileComponents() | ||||
|  | ||||
|   | ||||
| @@ -1,15 +1,8 @@ | ||||
| <div class="card shadow-sm bg-light" | ||||
|   [dndDraggable]="draggable" | ||||
|   dndEffectAllowed="move" | ||||
|   [dndDisableIf]="!draggable" | ||||
|   (dndStart)="dndStart.emit($event)" | ||||
|   (dndMoved)="dndMoved.emit($event)" | ||||
|   (dndCanceled)="dndCanceled.emit($event)" | ||||
|   (dndEnd)="dndEnd.emit($event)"> | ||||
| <div class="card shadow-sm bg-light" cdkDrag [cdkDragDisabled]="!draggable" cdkDragPreviewContainer="parent"> | ||||
|   <div class="card-header"> | ||||
|     <div class="d-flex justify-content-between align-items-center"> | ||||
|       <div class="d-flex"> | ||||
|         <div *ngIf="draggable" class="ms-n2 me-1" dndHandle> | ||||
|         <div *ngIf="draggable" class="ms-n2 me-1" cdkDragHandle> | ||||
|           <svg class="sidebaricon text-muted" fill="currentColor"> | ||||
|             <use xlink:href="assets/bootstrap-icons.svg#grip-vertical"/> | ||||
|           </svg> | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import { Component } from '@angular/core' | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing' | ||||
| import { By } from '@angular/platform-browser' | ||||
| import { NgbAlertModule, NgbAlert } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { PermissionsGuard } from 'src/app/guards/permissions.guard' | ||||
| import { WidgetFrameComponent } from './widget-frame.component' | ||||
| import { DndModule } from 'ngx-drag-drop' | ||||
| import { DragDropModule } from '@angular/cdk/drag-drop' | ||||
|  | ||||
| @Component({ | ||||
|   template: ` | ||||
| @@ -30,7 +30,7 @@ describe('WidgetFrameComponent', () => { | ||||
|     TestBed.configureTestingModule({ | ||||
|       declarations: [WidgetFrameComponent, WidgetFrameComponent], | ||||
|       providers: [PermissionsGuard], | ||||
|       imports: [NgbAlertModule, DndModule], | ||||
|       imports: [NgbAlertModule, DragDropModule], | ||||
|     }).compileComponents() | ||||
|  | ||||
|     fixture = TestBed.createComponent(WidgetFrameComponent) | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { Component, EventEmitter, Input, Output } from '@angular/core' | ||||
| import { Component, Input } from '@angular/core' | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'pngx-widget-frame', | ||||
| @@ -16,16 +16,4 @@ export class WidgetFrameComponent { | ||||
|  | ||||
|   @Input() | ||||
|   draggable: any | ||||
|  | ||||
|   @Output() | ||||
|   dndStart: EventEmitter<DragEvent> = new EventEmitter() | ||||
|  | ||||
|   @Output() | ||||
|   dndMoved: EventEmitter<DragEvent> = new EventEmitter() | ||||
|  | ||||
|   @Output() | ||||
|   dndCanceled: EventEmitter<DragEvent> = new EventEmitter() | ||||
|  | ||||
|   @Output() | ||||
|   dndEnd: EventEmitter<DragEvent> = new EventEmitter() | ||||
| } | ||||
|   | ||||
| @@ -333,6 +333,97 @@ describe('DocumentListViewService', () => { | ||||
|     }) | ||||
|   }) | ||||
|  | ||||
|   it('should not return next doc when documents is null', () => { | ||||
|     jest | ||||
|       .spyOn(documentListViewService, 'documents', 'get') | ||||
|       .mockReturnValue(null) | ||||
|     const complete = jest.fn() | ||||
|     documentListViewService.getNext(1).subscribe({ | ||||
|       next: () => fail('Observable should not emit any value'), | ||||
|       complete: complete(), | ||||
|     }) | ||||
|     expect(complete).toHaveBeenCalled() | ||||
|   }) | ||||
|  | ||||
|   it('should return next doc when exists', () => { | ||||
|     jest | ||||
|       .spyOn(documentListViewService, 'documents', 'get') | ||||
|       .mockReturnValue(documents) | ||||
|     const next = jest.fn() | ||||
|     documentListViewService.getNext(3).subscribe({ | ||||
|       next: (id) => next(id), | ||||
|       complete: () => {}, | ||||
|     }) | ||||
|     expect(next).toHaveBeenCalledWith(4) | ||||
|   }) | ||||
|  | ||||
|   it('should increase page on get next doc if needed', () => { | ||||
|     jest | ||||
|       .spyOn(documentListViewService, 'documents', 'get') | ||||
|       .mockReturnValue(documents) | ||||
|     expect(documentListViewService.currentPage).toEqual(1) | ||||
|     documentListViewService.currentPageSize = 3 | ||||
|     jest | ||||
|       .spyOn(documentListViewService, 'getLastPage') | ||||
|       .mockReturnValue(Math.ceil(documents.length / 3)) | ||||
|     const reloadSpy = jest.spyOn(documentListViewService, 'reload') | ||||
|     documentListViewService | ||||
|       .getNext(documents[documents.length - 1].id) | ||||
|       .subscribe({ | ||||
|         next: () => {}, | ||||
|         complete: () => {}, | ||||
|       }) | ||||
|     expect(reloadSpy).toHaveBeenCalled() | ||||
|     expect(documentListViewService.currentPage).toEqual(2) | ||||
|     const reqs = httpTestingController.match( | ||||
|       `${environment.apiBaseUrl}documents/?page=2&page_size=3&ordering=-created&truncate_content=true` | ||||
|     ) | ||||
|     expect(reqs.length).toBeGreaterThan(0) | ||||
|   }) | ||||
|  | ||||
|   it('should not return previous doc when documents is null', () => { | ||||
|     jest | ||||
|       .spyOn(documentListViewService, 'documents', 'get') | ||||
|       .mockReturnValue(null) | ||||
|     const complete = jest.fn() | ||||
|     documentListViewService.getPrevious(1).subscribe({ | ||||
|       next: () => fail('Observable should not emit any value'), | ||||
|       complete: complete(), | ||||
|     }) | ||||
|     expect(complete).toHaveBeenCalled() | ||||
|   }) | ||||
|  | ||||
|   it('should return previous doc when exists', () => { | ||||
|     jest | ||||
|       .spyOn(documentListViewService, 'documents', 'get') | ||||
|       .mockReturnValue(documents) | ||||
|     const next = jest.fn() | ||||
|     documentListViewService.getPrevious(3).subscribe({ | ||||
|       next: (id) => next(id), | ||||
|       complete: () => {}, | ||||
|     }) | ||||
|     expect(next).toHaveBeenCalledWith(2) | ||||
|   }) | ||||
|  | ||||
|   it('should decrease page on get previous doc if needed', () => { | ||||
|     jest | ||||
|       .spyOn(documentListViewService, 'documents', 'get') | ||||
|       .mockReturnValue(documents) | ||||
|     documentListViewService.currentPage = 2 | ||||
|     documentListViewService.currentPageSize = 3 | ||||
|     const reloadSpy = jest.spyOn(documentListViewService, 'reload') | ||||
|     documentListViewService.getPrevious(1).subscribe({ | ||||
|       next: () => {}, | ||||
|       complete: () => {}, | ||||
|     }) | ||||
|     expect(reloadSpy).toHaveBeenCalled() | ||||
|     expect(documentListViewService.currentPage).toEqual(1) | ||||
|     const reqs = httpTestingController.match( | ||||
|       `${environment.apiBaseUrl}documents/?page=1&page_size=3&ordering=-created&truncate_content=true` | ||||
|     ) | ||||
|     expect(reqs.length).toBeGreaterThan(0) | ||||
|   }) | ||||
|  | ||||
|   it('should update page size from settings', () => { | ||||
|     settingsService.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, 10) | ||||
|     documentListViewService.updatePageSize() | ||||
| @@ -435,4 +526,22 @@ describe('DocumentListViewService', () => { | ||||
|     ) | ||||
|     expect(cancelSpy).toHaveBeenCalled() | ||||
|   }) | ||||
|  | ||||
|   it('should reset sort field if changing from search result', () => { | ||||
|     const view2 = { | ||||
|       id: 22, | ||||
|       name: 'Saved View 2', | ||||
|       sort_field: 'score', | ||||
|       sort_reverse: true, | ||||
|       filter_rules: filterRules, | ||||
|     } | ||||
|  | ||||
|     documentListViewService.loadSavedView(view2) | ||||
|     expect(documentListViewService.sortField).toEqual('score') | ||||
|     documentListViewService.filterRules = [] | ||||
|     expect(documentListViewService.sortField).toEqual('created') | ||||
|     httpTestingController.expectOne( | ||||
|       `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true` | ||||
|     ) | ||||
|   }) | ||||
| }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon