From a4b412dc46c8d7162033237ea6d237e8fafc00b5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 17 Jun 2025 20:26:15 -0400 Subject: [PATCH] refactor: IPC/showSaveFilePicker --- src/gui/src/IPC.js | 295 +++++++++++++++++++++++---------------------- 1 file changed, 153 insertions(+), 142 deletions(-) diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 3b83927d6..a38d96c1e 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -1216,6 +1216,152 @@ const ipc_listener = async (event, handled) => { $el_parent_disable_mask.show(); $el_parent_disable_mask.css('z-index', parseInt($el_parent_window.css('z-index')) + 1); $(target_iframe).blur(); + + const handle_same_name_exists = async ({ + action, parent_uuid, + }) => { + try { + await action({ overwrite: false }); + } catch ( err ) { + if ( err.code !== 'item_with_same_name_exists' ) { + await UIAlert({ + message: err.message ?? "Upload failed.", + parent_uuid, + }); + return false; + } + const alert_resp = await UIAlert({ + message: `${html_encode(err.entry_name)} already exists.`, + buttons:[ + { + label: i18n('replace'), + value: 'replace', + type: 'primary', + }, + { + label: i18n('cancel'), + value: 'cancel', + }, + ], + parent_uuid, + }); + if ( alert_resp === 'replace' ) { + await action({ overwrite: true }); + return true; + } + return false; + } + } + + const handle_url_save = async ({ target_path }) => { + // download progress tracker + let dl_op_id = window.operation_id++; + + // upload progress tracker defaults + window.progress_tracker[dl_op_id] = []; + window.progress_tracker[dl_op_id][0] = {}; + window.progress_tracker[dl_op_id][0].total = 0; + window.progress_tracker[dl_op_id][0].ajax_uploaded = 0; + window.progress_tracker[dl_op_id][0].cloud_uploaded = 0; + + let item_with_same_name_already_exists = true; + while(item_with_same_name_already_exists){ + await download({ + url: event.data.url, + name: path.basename(target_path), + dest_path: path.dirname(target_path), + auth_token: window.auth_token, + api_origin: window.api_origin, + dedupe_name: false, + overwrite: false, + operation_id: dl_op_id, + item_upload_id: 0, + success: function(res){ + }, + error: function(err){ + UIAlert(err && err.message ? err.message : "Download failed."); + } + }); + item_with_same_name_already_exists = false; + } + }; + + const write_file_tell_caller_and_update_views = async ({ + target_path, el_filedialog_window, + file_to_upload, overwrite, + }) => { + const res = await puter.fs.write( + target_path, + file_to_upload, + { + dedupeName: false, + overwrite: overwrite + } + ); + + let file_signature = await puter.fs.sign(app_uuid, {uid: res.uid, action: 'write'}); + file_signature = file_signature.items; + + target_iframe.contentWindow.postMessage({ + msg: "fileSaved", + original_msg_id: msg_id, + filename: res.name, + saved_file: { + name: file_signature.fsentry_name, + readURL: file_signature.read_url, + writeURL: file_signature.write_url, + metadataURL: file_signature.metadata_url, + type: file_signature.type, + uid: file_signature.uid, + path: privacy_aware_path(res.path) + }, + }, '*'); + + $(target_iframe).get(0).focus({preventScroll:true}); + // Update matching items on open windows + // todo don't blanket-update, mostly files with thumbnails really need to be updated + // first remove overwritten items + $(`.item[data-uid="${res.uid}"]`).removeItems(); + // now add new items + UIItem({ + appendTo: $(`.item-container[data-path="${html_encode(path.dirname(target_path))}" i]`), + immutable: res.immutable || res.writable === false, + associated_app_name: res.associated_app?.name, + path: target_path, + icon: await item_icon(res), + name: path.basename(target_path), + uid: res.uid, + size: res.size, + modified: res.modified, + type: res.type, + is_dir: false, + is_shared: res.is_shared, + suggested_apps: res.suggested_apps, + }); + // sort each window + $(`.item-container[data-path="${html_encode(path.dirname(target_path))}" i]`).each(function(){ + window.sort_items(this, $(this).attr('data-sort_by'), $(this).attr('data-sort_order')) + }); + $(el_filedialog_window).close(); + window.show_save_account_notice_if_needed(); + } + + const handle_data_save = async ({ target_path, el_filedialog_window }) => { + let file_to_upload = new File([event.data.content], path.basename(target_path)); + const written = await handle_same_name_exists({ + action: async ({ overwrite }) => { + console.log('action with overwrite flag:', overwrite); + await write_file_tell_caller_and_update_views({ + target_path, el_filedialog_window, + file_to_upload, overwrite, + }); + }, + parent_uuid: $(el_filedialog_window).attr('data-element_uuid'), + }); + + if ( written ) return true; + $(el_filedialog_window).find('.window-disable-mask, .busy-indicator').hide(); + }; await UIWindow({ path: '/' + window.user.username + '/Desktop', @@ -1234,150 +1380,15 @@ const ipc_listener = async (event, handled) => { onSaveFileDialogSave: async function(target_path, el_filedialog_window){ $(el_filedialog_window).find('.window-disable-mask, .busy-indicator').show(); let busy_init_ts = Date.now(); + let done; - // ------------------------------------- - // URL - // ------------------------------------- - if(event.data.url){ - // download progress tracker - let dl_op_id = window.operation_id++; - - // upload progress tracker defaults - window.progress_tracker[dl_op_id] = []; - window.progress_tracker[dl_op_id][0] = {}; - window.progress_tracker[dl_op_id][0].total = 0; - window.progress_tracker[dl_op_id][0].ajax_uploaded = 0; - window.progress_tracker[dl_op_id][0].cloud_uploaded = 0; - - let item_with_same_name_already_exists = true; - while(item_with_same_name_already_exists){ - await download({ - url: event.data.url, - name: path.basename(target_path), - dest_path: path.dirname(target_path), - auth_token: window.auth_token, - api_origin: window.api_origin, - dedupe_name: false, - overwrite: false, - operation_id: dl_op_id, - item_upload_id: 0, - success: function(res){ - }, - error: function(err){ - UIAlert(err && err.message ? err.message : "Download failed."); - } - }); - item_with_same_name_already_exists = false; - } - } - // ------------------------------------- - // File - // ------------------------------------- - else{ - let overwrite = false; - let file_to_upload = new File([event.data.content], path.basename(target_path)); - let item_with_same_name_already_exists = true; - while(item_with_same_name_already_exists){ - // overwrite? - if(overwrite) - item_with_same_name_already_exists = false; - // upload - try{ - const res = await puter.fs.write( - target_path, - file_to_upload, - { - dedupeName: false, - overwrite: overwrite - } - ); - - let file_signature = await puter.fs.sign(app_uuid, {uid: res.uid, action: 'write'}); - file_signature = file_signature.items; - - item_with_same_name_already_exists = false; - target_iframe.contentWindow.postMessage({ - msg: "fileSaved", - original_msg_id: msg_id, - filename: res.name, - saved_file: { - name: file_signature.fsentry_name, - readURL: file_signature.read_url, - writeURL: file_signature.write_url, - metadataURL: file_signature.metadata_url, - type: file_signature.type, - uid: file_signature.uid, - path: privacy_aware_path(res.path) - }, - }, '*'); - - $(target_iframe).get(0).focus({preventScroll:true}); - // Update matching items on open windows - // todo don't blanket-update, mostly files with thumbnails really need to be updated - // first remove overwritten items - $(`.item[data-uid="${res.uid}"]`).removeItems(); - // now add new items - UIItem({ - appendTo: $(`.item-container[data-path="${html_encode(path.dirname(target_path))}" i]`), - immutable: res.immutable || res.writable === false, - associated_app_name: res.associated_app?.name, - path: target_path, - icon: await item_icon(res), - name: path.basename(target_path), - uid: res.uid, - size: res.size, - modified: res.modified, - type: res.type, - is_dir: false, - is_shared: res.is_shared, - suggested_apps: res.suggested_apps, - }); - // sort each window - $(`.item-container[data-path="${html_encode(path.dirname(target_path))}" i]`).each(function(){ - window.sort_items(this, $(this).attr('data-sort_by'), $(this).attr('data-sort_order')) - }); - $(el_filedialog_window).close(); - window.show_save_account_notice_if_needed(); - } - catch(err){ - // item with same name exists - if(err.code === 'item_with_same_name_exists'){ - const alert_resp = await UIAlert({ - message: `${html_encode(err.entry_name)} already exists.`, - buttons:[ - { - label: i18n('replace'), - value: 'replace', - type: 'primary', - }, - { - label: i18n('cancel'), - value: 'cancel', - }, - ], - parent_uuid: $(el_filedialog_window).attr('data-element_uuid'), - }) - if(alert_resp === 'replace'){ - overwrite = true; - }else if(alert_resp === 'cancel'){ - // enable parent window - $(el_filedialog_window).find('.window-disable-mask, .busy-indicator').hide(); - return; - } - } - else{ - // show error - await UIAlert({ - message: err.message ?? "Upload failed.", - parent_uuid: $(el_filedialog_window).attr('data-element_uuid'), - }); - // enable parent window - $(el_filedialog_window).find('.window-disable-mask, .busy-indicator').hide(); - return; - } - } - } + if (event.data.url){ + done = await handle_url_save({ target_path }); + } else { + done = await handle_data_save({ target_path, el_filedialog_window }); } + + if ( ! done ) return; // done let busy_duration = (Date.now() - busy_init_ts);