@@ -3,17 +3,15 @@ import { TranslatePipe, TranslateService } from '@ngx-translate/core';
33import { Button } from 'primeng/button' ;
44import { DynamicDialogConfig , DynamicDialogRef } from 'primeng/dynamicdialog' ;
55
6- import { finalize , forkJoin , of } from 'rxjs' ;
7- import { catchError } from 'rxjs/operators' ;
6+ import { finalize , tap } from 'rxjs' ;
87
9- import { ChangeDetectionStrategy , Component , DestroyRef , inject } from '@angular/core' ;
8+ import { ChangeDetectionStrategy , Component , DestroyRef , inject , signal } from '@angular/core' ;
109import { takeUntilDestroyed } from '@angular/core/rxjs-interop' ;
1110
12- import { CustomConfirmationService } from '@osf/shared/services/custom-confirmation.service' ;
13- import { FilesService } from '@osf/shared/services/files.service' ;
14- import { ToastService } from '@osf/shared/services/toast.service' ;
15- import { FileMenuType } from '@shared/enums/file-menu-type.enum' ;
16- import { FileModel } from '@shared/models/files/file.model' ;
11+ import { FileModel } from '@osf/shared/models/files/file.model' ;
12+
13+ import { MoveCopyAction } from '../../enums/move-copy-action.enum' ;
14+ import { FilesMoveCopyService } from '../../services/files-move-copy.service' ;
1715
1816@Component ( {
1917 selector : 'osf-confirm-move-file-dialog' ,
@@ -26,124 +24,54 @@ export class ConfirmMoveFileDialogComponent {
2624 readonly config = inject ( DynamicDialogConfig ) ;
2725 readonly dialogRef = inject ( DynamicDialogRef ) ;
2826
29- private readonly filesService = inject ( FilesService ) ;
3027 private readonly destroyRef = inject ( DestroyRef ) ;
3128 private readonly translateService = inject ( TranslateService ) ;
32- private readonly toastService = inject ( ToastService ) ;
33- private readonly customConfirmationService = inject ( CustomConfirmationService ) ;
29+ private readonly filesMoveCopyService = inject ( FilesMoveCopyService ) ;
3430
35- readonly provider = this . config . data . storageProvider ;
31+ readonly currentFolder = this . config . data . destination as FileModel ;
3632
37- private fileProjectId = this . config . data . resourceId ;
38- protected currentFolder = this . config . data . destination ;
33+ readonly dragNodeName =
34+ this . config . data . files . length > 1
35+ ? this . translateService . instant ( 'files.dialogs.moveFile.multipleFiles' , { count : this . config . data . files . length } )
36+ : ( this . config . data . files [ 0 ] ?. name ?? '' ) ;
3937
40- get dragNodeName ( ) {
41- const filesCount = this . config . data . files . length ;
42- if ( filesCount > 1 ) {
43- return this . translateService . instant ( 'files.dialogs.moveFile.multipleFiles' , { count : filesCount } ) ;
44- } else {
45- return this . config . data . files [ 0 ] ?. name ;
46- }
47- }
38+ readonly isLoading = signal ( false ) ;
4839
4940 copyFiles ( ) : void {
50- return this . copyOrMoveFiles ( FileMenuType . Copy ) ;
41+ this . copyOrMoveFiles ( MoveCopyAction . Copy ) ;
5142 }
5243
5344 moveFiles ( ) : void {
54- return this . copyOrMoveFiles ( FileMenuType . Move ) ;
45+ this . copyOrMoveFiles ( MoveCopyAction . Move ) ;
5546 }
5647
57- private copyOrMoveFiles ( action : FileMenuType ) : void {
58- const path = this . currentFolder . path ;
59- if ( ! path ) {
60- throw new Error ( this . translateService . instant ( 'files.dialogs.moveFile.pathError' ) ) ;
48+ private copyOrMoveFiles ( action : MoveCopyAction ) : void {
49+ if ( this . isLoading ( ) ) {
50+ return ;
6151 }
62- const isMoveAction = action === FileMenuType . Move ;
6352
64- const headerKey = isMoveAction ? 'files.dialogs.moveFile.movingHeader' : 'files.dialogs.moveFile.copingHeader' ;
65- this . config . header = this . translateService . instant ( headerKey ) ;
66- const files : FileModel [ ] = this . config . data . files ;
67- const totalFiles = files . length ;
68- let completed = 0 ;
69- const conflictFiles : { file : FileModel ; link : string } [ ] = [ ] ;
70-
71- files . forEach ( ( file ) => {
72- const link = file . links . move ;
73- this . filesService
74- . moveFile ( link , path , this . fileProjectId , this . provider , action )
75- . pipe (
76- takeUntilDestroyed ( this . destroyRef ) ,
77- catchError ( ( error ) => {
78- if ( error . status === 409 ) {
79- conflictFiles . push ( { file, link } ) ;
80- } else {
81- this . showErrorToast ( action , error . error ?. message ) ;
82- }
83- return of ( null ) ;
84- } ) ,
85- finalize ( ( ) => {
86- completed ++ ;
87- if ( completed === totalFiles ) {
88- if ( conflictFiles . length > 0 ) {
89- this . openReplaceMoveDialog ( conflictFiles , path , action ) ;
90- } else {
91- this . showSuccessToast ( action ) ;
92- this . config . header = this . translateService . instant ( 'files.dialogs.moveFile.title' ) ;
93- this . completeMove ( ) ;
94- }
95- }
96- } )
97- )
98- . subscribe ( ) ;
99- } ) ;
100- }
53+ this . isLoading . set ( true ) ;
10154
102- private openReplaceMoveDialog (
103- conflictFiles : { file : FileModel ; link : string } [ ] ,
104- path : string ,
105- action : string
106- ) : void {
107- this . customConfirmationService . confirmDelete ( {
108- headerKey : conflictFiles . length > 1 ? 'files.dialogs.replaceFile.multiple' : 'files.dialogs.replaceFile.single' ,
109- messageKey : 'files.dialogs.replaceFile.message' ,
110- messageParams : { name : conflictFiles . map ( ( c ) => c . file . name ) . join ( ', ' ) } ,
111- acceptLabelKey : 'common.buttons.replace' ,
112- onConfirm : ( ) => {
113- const replaceRequests$ = conflictFiles . map ( ( { link } ) =>
114- this . filesService . moveFile ( link , path , this . fileProjectId , this . provider , action , true ) . pipe (
115- takeUntilDestroyed ( this . destroyRef ) ,
116- catchError ( ( ) => of ( null ) )
117- )
118- ) ;
119- forkJoin ( replaceRequests$ ) . subscribe ( {
120- next : ( ) => {
121- this . showSuccessToast ( action ) ;
122- this . completeMove ( ) ;
123- } ,
124- } ) ;
125- } ,
126- onReject : ( ) => {
127- const totalFiles = this . config . data . files . length ;
128- if ( totalFiles > conflictFiles . length ) {
129- this . showErrorToast ( action ) ;
130- }
131- this . completeMove ( ) ;
132- } ,
133- } ) ;
134- }
135-
136- private showSuccessToast ( action : string ) {
137- const messageType = action === 'move' ? 'moveFile' : 'copyFile' ;
138- this . toastService . showSuccess ( `files.dialogs.${ messageType } .success` ) ;
139- }
140-
141- private showErrorToast ( action : string , errorMessage ?: string ) {
142- const messageType = action === 'move' ? 'moveFile' : 'copyFile' ;
143- this . toastService . showError ( errorMessage ?? `files.dialogs.${ messageType } .error` ) ;
144- }
55+ const headerKey =
56+ action === MoveCopyAction . Move ? 'files.dialogs.moveFile.movingHeader' : 'files.dialogs.moveFile.copingHeader' ;
57+ this . config . header = this . translateService . instant ( headerKey ) ;
14558
146- private completeMove ( ) : void {
147- this . dialogRef . close ( true ) ;
59+ this . filesMoveCopyService
60+ . execute ( {
61+ files : this . config . data . files ,
62+ destination : this . currentFolder ,
63+ resourceId : this . config . data . resourceId ,
64+ storageProvider : this . config . data . storageProvider ,
65+ action,
66+ } )
67+ . pipe (
68+ tap ( ( ) => this . dialogRef . close ( true ) ) ,
69+ finalize ( ( ) => {
70+ this . isLoading . set ( false ) ;
71+ this . config . header = this . translateService . instant ( 'files.dialogs.moveFile.title' ) ;
72+ } ) ,
73+ takeUntilDestroyed ( this . destroyRef )
74+ )
75+ . subscribe ( ) ;
14876 }
14977}
0 commit comments