Forráskód Böngészése

Merge pull request #384 from AtkinsSJ/progress-dialogs

refactor: Replace several existing progress dialogs with one configurable one
Eric Dubé 1 éve
szülő
commit
3992fe1a45
43 módosított fájl, 293 hozzáadás és 653 törlés
  1. 1 1
      packages/backend/src/services/file-cache/FileCacheService.js
  2. 3 2
      src/UI/Components/Button.js
  3. 1 0
      src/UI/UIWindow.js
  4. 0 81
      src/UI/UIWindowCopyProgress.js
  5. 0 70
      src/UI/UIWindowDownloadDirProg.js
  6. 0 81
      src/UI/UIWindowDownloadProgress.js
  7. 0 81
      src/UI/UIWindowMoveProgress.js
  8. 0 74
      src/UI/UIWindowNewFolderProgress.js
  9. 155 0
      src/UI/UIWindowProgress.js
  10. 0 74
      src/UI/UIWindowProgressEmptyTrash.js
  11. 0 7
      src/UI/UIWindowQR.js
  12. 0 75
      src/UI/UIWindowUploadProgress.js
  13. 7 15
      src/css/style.css
  14. 93 61
      src/helpers.js
  15. 0 3
      src/helpers/download.js
  16. 1 1
      src/i18n/translations/ar.js
  17. 1 1
      src/i18n/translations/bn.js
  18. 1 1
      src/i18n/translations/br.js
  19. 1 1
      src/i18n/translations/da.js
  20. 1 1
      src/i18n/translations/de.js
  21. 1 1
      src/i18n/translations/emoji.js
  22. 6 1
      src/i18n/translations/en.js
  23. 1 1
      src/i18n/translations/es.js
  24. 1 1
      src/i18n/translations/fa.js
  25. 1 1
      src/i18n/translations/fi.js
  26. 1 1
      src/i18n/translations/fr.js
  27. 1 1
      src/i18n/translations/hy.js
  28. 1 1
      src/i18n/translations/ig.js
  29. 1 1
      src/i18n/translations/it.js
  30. 1 1
      src/i18n/translations/ko.js
  31. 1 1
      src/i18n/translations/nb.js
  32. 1 1
      src/i18n/translations/nl.js
  33. 1 1
      src/i18n/translations/nn.js
  34. 1 1
      src/i18n/translations/pl.js
  35. 1 1
      src/i18n/translations/pt.js
  36. 1 1
      src/i18n/translations/ro.js
  37. 1 1
      src/i18n/translations/ru.js
  38. 1 1
      src/i18n/translations/sv.js
  39. 1 1
      src/i18n/translations/th.js
  40. 1 1
      src/i18n/translations/tr.js
  41. 1 1
      src/i18n/translations/ur.js
  42. 1 1
      src/i18n/translations/zh.js
  43. 1 1
      src/i18n/translations/zhtw.js

+ 1 - 1
packages/backend/src/services/file-cache/FileCacheService.js

@@ -250,7 +250,7 @@ class FileCacheService extends AdvancedBase {
         const path = this._get_path(tracker.key);
         const path = this._get_path(tracker.key);
         console.log(`precache fetch key I guess?`, tracker.key);
         console.log(`precache fetch key I guess?`, tracker.key);
         const data = this.precache.get(tracker.key);
         const data = this.precache.get(tracker.key);
-        console.log(`path and data: ${path} ${data}`);
+        // console.log(`path and data: ${path} ${data}`);
         await fs.promises.writeFile(path, data);
         await fs.promises.writeFile(path, data);
         this.precache.delete(tracker.key);
         this.precache.delete(tracker.key);
         tracker.phase = FileTracker.PHASE_DISK;
         tracker.phase = FileTracker.PHASE_DISK;

+ 3 - 2
src/UI/Components/Button.js

@@ -33,14 +33,15 @@ export default class Button extends Component {
     create_template ({ template }) {
     create_template ({ template }) {
         if ( this.get('style') === 'link' ) {
         if ( this.get('style') === 'link' ) {
             $(template).html(/*html*/`
             $(template).html(/*html*/`
-                <button type="submit" class="link-button code-confirm-btn" style="margin-top:10px;" disabled>${
+                <button type="submit" class="link-button" style="margin-top:10px;" disabled>${
                     html_encode(this.get('label'))
                     html_encode(this.get('label'))
                 }</button>
                 }</button>
             `);
             `);
             return;
             return;
         }
         }
+        // TODO: Replace hack for 'small' with a better way to configure button classes.
         $(template).html(/*html*/`
         $(template).html(/*html*/`
-            <button type="submit" class="button button-block button-${this.get('style')} code-confirm-btn" style="margin-top:10px;" disabled>${
+            <button type="submit" class="button ${this.get('style') !== 'small' ? 'button-block' : ''} button-${this.get('style')}" style="margin-top:10px;" disabled>${
                 html_encode(this.get('label'))
                 html_encode(this.get('label'))
             }</button>
             }</button>
         `);
         `);

+ 1 - 0
src/UI/UIWindow.js

@@ -2086,6 +2086,7 @@ async function UIWindow(options) {
                             html: i18n('empty_trash'),
                             html: i18n('empty_trash'),
                             disabled: false,
                             disabled: false,
                             onClick: async function(){
                             onClick: async function(){
+                                // TODO: Merge this with window.empty_trash()
                                 const alert_resp = await UIAlert({
                                 const alert_resp = await UIAlert({
                                     message: i18n('empty_trash_confirmation'),
                                     message: i18n('empty_trash_confirmation'),
                                     buttons:[
                                     buttons:[

+ 0 - 81
src/UI/UIWindowCopyProgress.js

@@ -1,81 +0,0 @@
-/**
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-import UIWindow from './UIWindow.js'
-
-// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
-async function UIWindowCopyProgress(options){
-    let h = '';
-    h += `<div data-copy-operation-id="${options.operation_id}">`;
-        h += `<div>`;
-            // spinner
-            h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-            // Progress report
-            h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
-                // msg
-                h += `<span class="copy-progress-msg">${i18n('copying')} </span>`;
-                h += `<span class="copy-from" style="font-weight:strong;"></span>`;
-            h += `</div>`;
-            // progress
-            h += `<div class="copy-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
-                h += `<div class="copy-progress-bar"></div>`;
-            h += `</div>`;
-            // cancel
-            // h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small copy-cancel-btn">Cancel</button>`;
-        h +=`</div>`;
-    h += `</div>`;
-
-    const el_window = await UIWindow({
-        title: i18n('copying'),
-        icon: window.icons[`app-icon-copying.svg`],
-        uid: null,
-        is_dir: false,
-        body_content: h,
-        has_head: false,
-        selectable_body: false,
-        draggable_body: true,
-        allow_context_menu: false,
-        is_resizable: false,
-        is_droppable: false,
-        init_center: true,
-        allow_native_ctxmenu: false,
-        allow_user_select: false,
-        window_class: 'window-copy-progress',
-        width: 450,
-        dominant: true,
-        window_css:{
-            height: 'initial',
-        },
-        body_css: {
-            padding: '22px',
-            width: 'initial',
-            'background-color': 'rgba(231, 238, 245, .95)',
-            'backdrop-filter': 'blur(3px)',
-        }    
-    });
-
-    $(el_window).find('.copy-cancel-btn').on('click', function(e){
-        window.operation_cancelled[options.operation_id] = true;
-        $(el_window).close();
-    })
-
-    return el_window;
-}
-
-export default UIWindowCopyProgress

+ 0 - 70
src/UI/UIWindowDownloadDirProg.js

@@ -1,70 +0,0 @@
-/**
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-import UIWindow from './UIWindow.js'
-
-async function UIWindowDownloadDirProg(options){
-    options = options ?? {};
-
-    let h = '';
-    // Loading spinner
-    h +=`<svg style="height: 40px; width: 40px; padding: 10px; display: block; float: left;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-    h += `<p style="text-align:left; padding-left:20px; padding-right:20px; overflow:hidden; width: 310px; text-overflow: ellipsis; white-space: nowrap; float:left; font-size:14px;" class="dir-dl-status">${options.defaultText ?? i18n('preparing')}</p>`;
-
-    const el_window = await UIWindow({
-        title: 'Download Directory Progress',
-        app: 'instant-login',
-        single_instance: true,
-        icon: null,
-        uid: null,
-        is_dir: false,
-        body_content: h,
-        has_head: false,
-        selectable_body: false,
-        allow_context_menu: false,
-        is_resizable: false,
-        is_droppable: false,
-        init_center: true,
-        allow_native_ctxmenu: false,
-        allow_user_select: false,
-        backdrop: false,
-        width: 460,
-        height: 'auto',
-        dominant: true,
-        show_in_taskbar: false,
-        draggable_body: true,
-        onAppend: function(this_window){
-        },
-        window_class: 'window-qr',
-        body_css: {
-            width: 'initial',
-            height: '100px',
-            'background-color': 'rgb(245 247 249)',
-            'backdrop-filter': 'blur(3px)',
-            'display': 'flex',
-            "flex-direction": 'row',
-            'justify-content': 'center',
-            'align-items': 'center',
-        }    
-    })       
-
-    return el_window;
-}
-
-export default UIWindowDownloadDirProg

+ 0 - 81
src/UI/UIWindowDownloadProgress.js

@@ -1,81 +0,0 @@
-/**
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-import UIWindow from './UIWindow.js'
-
-// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
-async function UIWindowDownloadProgress(options){
-    let h = '';
-    h += `<div data-download-operation-id="${options.operation_id}">`;
-        h += `<div>`;
-            // Spinner
-            h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-            // Progress report
-            h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
-                // msg
-                h += `<span class="upload-progress-msg">${i18n('downloading')}...<strong>${options.item_name ?? ''}</strong></span>`;
-            h += `</div>`;
-            // Progress
-            h += `<div class="download-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
-                h += `<div class="download-progress-bar"></div>`;
-            h += `</div>`;
-            // Cancel
-            h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small download-cancel-btn">Cancel</button>`;
-        h +=`</div>`;
-    h += `</div>`;
-
-    const el_window = await UIWindow({
-        title: `Upload`,
-        icon: window.icons[`app-icon-uploader.svg`],
-        uid: null,
-        is_dir: false,
-        body_content: h,
-        has_head: false,
-        selectable_body: false,
-        draggable_body: true,
-        allow_context_menu: false,
-        is_resizable: false,
-        is_droppable: false,
-        init_center: true,
-        allow_native_ctxmenu: false,
-        allow_user_select: false,
-        window_class: 'window-upload-progress',
-        width: 450,
-        dominant: true,
-        window_css:{
-            height: 'initial',
-        },
-        body_css: {
-            padding: '22px',
-            width: 'initial',
-            'background-color': 'rgba(231, 238, 245, .95)',
-            'backdrop-filter': 'blur(3px)',
-        }    
-    });
-
-    // cancel download button clicked
-    $(el_window).find('.download-cancel-btn').on('click', function(){
-        window.operation_cancelled[options.operation_id] = true;
-        $(el_window).close();
-    })
-
-    return el_window;
-}
-
-export default UIWindowDownloadProgress

+ 0 - 81
src/UI/UIWindowMoveProgress.js

@@ -1,81 +0,0 @@
-/**
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-import UIWindow from './UIWindow.js'
-
-// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
-async function UIWindowMoveProgress(options){
-    let h = '';
-    h += `<div data-move-operation-id="${html_encode(options.operation_id)}">`;
-        h += `<div>`;
-            // spinner
-            h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-            // Progress report
-            h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
-                // msg
-                h += `<span class="move-progress-msg">${i18n('moving')} </span>`;
-                h += `<span class="move-from" style="font-weight:strong;"></span>`;
-            h += `</div>`;
-            // progress
-            h += `<div class="move-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
-                h += `<div class="move-progress-bar"></div>`;
-            h += `</div>`;
-            // cancel
-            // h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small move-cancel-btn">Cancel</button>`;
-        h +=`</div>`;
-    h += `</div>`;
-
-    const el_window = await UIWindow({
-        title: `moveing`,
-        icon: window.icons[`app-icon-moveing.svg`],
-        uid: null,
-        is_dir: false,
-        body_content: h,
-        has_head: false,
-        selectable_body: false,
-        draggable_body: true,
-        allow_context_menu: false,
-        is_resizable: false,
-        is_droppable: false,
-        init_center: true,
-        allow_native_ctxmenu: false,
-        allow_user_select: false,
-        window_class: 'window-move-progress',
-        width: 450,
-        dominant: true,
-        window_css:{
-            height: 'initial',
-        },
-        body_css: {
-            padding: '22px',
-            width: 'initial',
-            'background-color': 'rgba(231, 238, 245, .95)',
-            'backdrop-filter': 'blur(3px)',
-        }    
-    });
-
-    $(el_window).find('.move-cancel-btn').on('click', function(e){
-        window.operation_cancelled[options.operation_id] = true;
-        $(el_window).close();
-    })
-
-    return el_window;
-}
-
-export default UIWindowMoveProgress

+ 0 - 74
src/UI/UIWindowNewFolderProgress.js

@@ -1,74 +0,0 @@
-/**
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-import UIWindow from './UIWindow.js'
-
-// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
-async function UIWindowNewFolderProgress(options){
-    let h = '';
-    h += `<div data-newfolder-operation-id="${html_encode(options.operation_id)}">`;
-        h += `<div>`;
-            // spinner
-            h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-            // message
-            h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
-                // text
-                h += `<span class="newfolder-progress-msg">${i18n('taking_longer_than_usual')}</span>`;
-            h += `</div>`;
-        h +=`</div>`;
-    h += `</div>`;
-
-    const el_window = await UIWindow({
-        title: `Creating New Folder`,
-        icon: window.icons[`app-icon-newfolder.svg`],
-        uid: null,
-        is_dir: false,
-        body_content: h,
-        has_head: false,
-        selectable_body: false,
-        draggable_body: true,
-        allow_context_menu: false,
-        is_resizable: false,
-        is_droppable: false,
-        init_center: true,
-        allow_native_ctxmenu: false,
-        allow_user_select: false,
-        window_class: 'window-newfolder-progress',
-        width: 450,
-        dominant: true,
-        window_css:{
-            height: 'initial',
-        },
-        body_css: {
-            padding: '22px',
-            width: 'initial',
-            'background-color': 'rgba(231, 238, 245, .95)',
-            'backdrop-filter': 'blur(3px)',
-        }    
-    });
-
-    $(el_window).find('.newfolder-cancel-btn').on('click', function(e){
-        window.operation_cancelled[options.operation_id] = true;
-        $(el_window).close();
-    })
-
-    return el_window;
-}
-
-export default UIWindowNewFolderProgress

+ 155 - 0
src/UI/UIWindowProgress.js

@@ -0,0 +1,155 @@
+/**
+ * Copyright (C) 2024 Puter Technologies Inc.
+ *
+ * This file is part of Puter.
+ *
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import UIWindow from './UIWindow.js'
+import Placeholder from '../util/Placeholder.js';
+import Button from './Components/Button.js';
+
+/**
+ * General purpose progress dialog.
+ * @param operation_id If provided, is saved in the data-operation-id attribute, for later lookup.
+ * @param show_progress Enable a progress bar, and display `(foo%)` after the status message
+ * @param on_cancel A callback run when the Cancel button is clicked. Without it, no Cancel button will appear.
+ * @returns {Promise<{set_progress: *, set_status: *, close: *, show_error: *, element: Element}>} Object for managing the progress dialog
+ * @constructor
+ * TODO: Debouncing logic (show only after a delay, then hide only after a delay)
+ */
+async function UIWindowProgress({
+    operation_id = null,
+    show_progress = false,
+    on_cancel = null,
+} = {}){
+    const placeholder_cancel_btn = Placeholder();
+    const placeholder_ok_btn = Placeholder();
+
+    let h = '';
+    h += `<div ${operation_id ? `data-operation-id="${operation_id}"` : ''}>`;
+        h += `<div class="progress-running">`;
+            h += `<div style="display: flex; align-items: center; gap: 7px;">`;
+                // spinner
+                h += `<svg style="overflow: visible;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
+                // Progress report
+                h += `<div style="font-size:15px; overflow: hidden; flex-grow: 1; text-overflow: ellipsis; white-space: nowrap;">
+                    <span class="progress-msg">${i18n('preparing')}</span>`;
+                if (show_progress) {
+                    h += ` (<span class="progress-percent">0%</span>)`;
+                }
+                h += `</div>`;
+            h +=`</div>`;
+            if (show_progress) {
+                h += `<div class="progress-bar-container" style="margin-top:20px;">`;
+                    h += `<div class="progress-bar"></div>`;
+                h += `</div>`;
+            }
+            if (on_cancel) {
+                h += `<div style="display: flex; justify-content: flex-end;">`;
+                    h += placeholder_cancel_btn.html;
+                h += `</div>`;
+            }
+        h += `</div>`;
+        h += `<div class="progress-error" style="display: none">`;
+            h += `<div style="display: flex; align-items: center; gap: 7px;">`;
+                // Alert icon
+                h += `<img style="width:24px; height:24px;" src="${html_encode(window.icons['warning-sign.svg'])}" />`;
+                // Progress report
+                h += `<div style="font-size:15px; overflow: hidden; flex-grow: 1; text-overflow: ellipsis; white-space: nowrap;">
+                    <span class="progress-error-title"></span>`;
+                h += `</div>`;
+            h += `</div>`;
+            h += `<p class="progress-error-message"></p>`;
+            h += `<div style="display: flex; justify-content: flex-end;">`;
+                h += placeholder_ok_btn.html;
+            h += `</div>`;
+        h += `</div>`;
+    h += `</div>`;
+
+    const el_window = await UIWindow({
+        uid: null,
+        is_dir: false,
+        body_content: h,
+        has_head: false,
+        selectable_body: false,
+        draggable_body: true,
+        allow_context_menu: false,
+        is_resizable: false,
+        is_droppable: false,
+        init_center: true,
+        allow_native_ctxmenu: false,
+        allow_user_select: false,
+        window_class: 'window-progress',
+        width: 450,
+        dominant: true,
+        window_css:{
+            height: 'initial',
+        },
+        body_css: {
+            padding: '22px',
+            width: 'initial',
+            'background-color': `hsla(
+                var(--primary-hue),
+                var(--primary-saturation),
+                var(--primary-lightness),
+                var(--primary-alpha))`,
+            'backdrop-filter': 'blur(3px)',
+        }    
+    });
+
+    if (on_cancel) {
+        const cancel_btn = new Button({
+            label: i18n('cancel'),
+            style: 'small',
+            on_click: () => {
+                $(el_window).close();
+                on_cancel();
+            },
+        });
+        cancel_btn.attach(placeholder_cancel_btn);
+    }
+
+    const ok_btn = new Button({
+        label: i18n('ok'),
+        style: 'small',
+        on_click: () => {
+            $(el_window).close();
+        },
+    });
+    ok_btn.attach(placeholder_ok_btn);
+
+    return {
+        element: el_window,
+        set_status: (text) => {
+            el_window.querySelector('.progress-msg').innerHTML = text;
+        },
+        set_progress: (percent) => {
+            el_window.querySelector('.progress-bar').style.width = `${percent}%`;
+            el_window.querySelector('.progress-percent').innerText = `${percent}%`;
+        },
+        close: () => {
+            $(el_window).close();
+        },
+        show_error: (title, message) => {
+            el_window.querySelector('.progress-running').style.display = 'none';
+            el_window.querySelector('.progress-error').style.display = 'block';
+            el_window.querySelector('.progress-error-title').innerText = title;
+            el_window.querySelector('.progress-error-message').innerText = message;
+        },
+    };
+}
+
+export default UIWindowProgress;

+ 0 - 74
src/UI/UIWindowProgressEmptyTrash.js

@@ -1,74 +0,0 @@
-/**
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-import UIWindow from './UIWindow.js'
-
-// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
-async function UIWindowProgressEmptyTrash(options){
-    let h = '';
-    h += `<div data-newfolder-operation-id="${options.operation_id}">`;
-        h += `<div>`;
-            // spinner
-            h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-            // message
-            h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
-                // text
-                h += `<span class="newfolder-progress-msg">${i18n('emptying_trash')}</span>`;
-            h += `</div>`;
-        h +=`</div>`;
-    h += `</div>`;
-
-    const el_window = await UIWindow({
-        title: i18n('emptying_trash'),
-        icon: window.icons[`app-icon-newfolder.svg`],
-        uid: null,
-        is_dir: false,
-        body_content: h,
-        has_head: false,
-        selectable_body: false,
-        draggable_body: true,
-        allow_context_menu: false,
-        is_resizable: false,
-        is_droppable: false,
-        init_center: true,
-        allow_native_ctxmenu: false,
-        allow_user_select: false,
-        window_class: 'window-newfolder-progress',
-        width: 450,
-        dominant: true,
-        window_css:{
-            height: 'initial',
-        },
-        body_css: {
-            padding: '22px',
-            width: 'initial',
-            'background-color': 'rgba(231, 238, 245, .95)',
-            'backdrop-filter': 'blur(3px)',
-        }    
-    });
-
-    $(el_window).find('.newfolder-cancel-btn').on('click', function(e){
-        window.operation_cancelled[options.operation_id] = true;
-        $(el_window).close();
-    })
-
-    return el_window;
-}
-
-export default UIWindowProgressEmptyTrash

+ 0 - 7
src/UI/UIWindowQR.js

@@ -88,14 +88,7 @@ async function UIWindowQR(options){
         ]
         ]
     });
     });
 
 
-    // component_qr.attach(placeholder_qr);
     component_flexer.attach(placeholder_qr);
     component_flexer.attach(placeholder_qr);
-    // placeholder_qr.replaceWith($(`<h1>test</h1>`).get(0));
-
-    $(el_window).find('.qr-code-checkbox input').on('change', () => {
-        const all_checked = $(el_window).find('.qr-code-checkbox input').toArray().every(el => el.checked);
-        $(el_window).find('.code-confirm-btn').prop('disabled', !all_checked);
-    });
 }
 }
 
 
 export default UIWindowQR
 export default UIWindowQR

+ 0 - 75
src/UI/UIWindowUploadProgress.js

@@ -1,75 +0,0 @@
-/**
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-import UIWindow from './UIWindow.js'
-
-// todo do this using uid rather than item_path, since item_path is way mroe expensive on the DB
-async function UIWindowUploadProgress(options){
-    let h = '';
-    h += `<div data-upload-operation-id="${options.operation_id}">`;
-        h += `<div>`;
-            // spinner
-            h +=`<svg style="float:left; margin-right: 7px;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-            // Progress report
-            h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
-                // msg
-                h += `<span class="upload-progress-msg">${i18n('preparing_for_upload')}</span>`;
-            h += `</div>`;
-            // progress
-            h += `<div class="upload-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
-                h += `<div class="upload-progress-bar"></div>`;
-            h += `</div>`;
-            // cancel
-            h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small upload-cancel-btn">${i18n('cancel')}</button>`;
-        h +=`</div>`;
-    h += `</div>`;
-
-    const el_window = await UIWindow({
-        title: i18n('upload'),
-        icon: window.icons[`app-icon-uploader.svg`],
-        uid: null,
-        is_dir: false,
-        body_content: h,
-        has_head: false,
-        selectable_body: false,
-        draggable_body: true,
-        allow_context_menu: false,
-        is_resizable: false,
-        is_droppable: false,
-        init_center: true,
-        allow_native_ctxmenu: false,
-        allow_user_select: false,
-        window_class: 'window-upload-progress',
-        width: 450,
-        dominant: true,
-        window_css:{
-            height: 'initial',
-        },
-        body_css: {
-            padding: '22px',
-            width: 'initial',
-            'background-color': 'rgba(231, 238, 245, .95)',
-            'backdrop-filter': 'blur(3px)',
-        }    
-    });
-
-    return el_window;
-}
-
-export default UIWindowUploadProgress

+ 7 - 15
src/css/style.css

@@ -2625,16 +2625,6 @@ fieldset[name=number-code] {
     margin: 20px 0;
     margin: 20px 0;
 }
 }
 
 
-.qr-code-checkbox {
-    display: flex;
-    gap: 10px;
-    align-items: center;
-}
-
-.qr-code-checkbox input[type=checkbox] {
-    margin: 0;
-}
-
 .perm-title {
 .perm-title {
     text-align: center;
     text-align: center;
     margin-top: 0;
     margin-top: 0;
@@ -2718,17 +2708,19 @@ fieldset[name=number-code] {
     }
     }
 }
 }
 
 
-.upload-progress-bar-container, .download-progress-bar-container {
+.progress-bar-container {
+    box-sizing: border-box;
     width: 100%;
     width: 100%;
-    height: 15px;
+    height: 17px;
     border: 1px solid rgb(40 109 157);
     border: 1px solid rgb(40 109 157);
+    border-radius: 3px;
     background-color: white;
     background-color: white;
     box-shadow: inset -1px 3px 4px #dfdfdf;
     box-shadow: inset -1px 3px 4px #dfdfdf;
 }
 }
 
 
-.upload-progress-bar, .download-progress-bar {
+.progress-bar {
     width: 0;
     width: 0;
-    height: 15px;
+    height: 100%;
     background-color: rgb(0 137 255);
     background-color: rgb(0 137 255);
     transition: 0.4s width;
     transition: 0.4s width;
     background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.05));
     background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.05));
@@ -3947,4 +3939,4 @@ fieldset[name=number-code] {
 .taskmgr-task-title {
 .taskmgr-task-title {
     flex-grow: 1;
     flex-grow: 1;
     padding-left: calc(2.5 * var(--scale));
     padding-left: calc(2.5 * var(--scale));
-}
+}

+ 93 - 61
src/helpers.js

@@ -24,16 +24,11 @@ import UIItem from './UI/UIItem.js'
 import UIWindow from './UI/UIWindow.js'
 import UIWindow from './UI/UIWindow.js'
 import UIWindowLogin from './UI/UIWindowLogin.js';
 import UIWindowLogin from './UI/UIWindowLogin.js';
 import UIWindowSaveAccount from './UI/UIWindowSaveAccount.js';
 import UIWindowSaveAccount from './UI/UIWindowSaveAccount.js';
-import UIWindowCopyProgress from './UI/UIWindowCopyProgress.js';
-import UIWindowMoveProgress from './UI/UIWindowMoveProgress.js';
-import UIWindowNewFolderProgress from './UI/UIWindowNewFolderProgress.js';
-import UIWindowUploadProgress from './UI/UIWindowUploadProgress.js';
-import UIWindowProgressEmptyTrash from './UI/UIWindowProgressEmptyTrash.js';
 import update_username_in_gui from './helpers/update_username_in_gui.js';
 import update_username_in_gui from './helpers/update_username_in_gui.js';
 import update_title_based_on_uploads from './helpers/update_title_based_on_uploads.js';
 import update_title_based_on_uploads from './helpers/update_title_based_on_uploads.js';
 import content_type_to_icon from './helpers/content_type_to_icon.js';
 import content_type_to_icon from './helpers/content_type_to_icon.js';
-import UIWindowDownloadDirProg from './UI/UIWindowDownloadDirProg.js';
 import { PROCESS_RUNNING, PortalProcess, PseudoProcess } from "./definitions.js";
 import { PROCESS_RUNNING, PortalProcess, PseudoProcess } from "./definitions.js";
+import UIWindowProgress from './UI/UIWindowProgress.js';
 
 
 window.is_auth = ()=>{
 window.is_auth = ()=>{
     if(localStorage.getItem("auth_token") === null || window.auth_token === null)
     if(localStorage.getItem("auth_token") === null || window.auth_token === null)
@@ -1166,7 +1161,14 @@ window.create_folder = async(basedir, appendto_element)=>{
 
 
     // only show progress window if it takes longer than 500ms to create folder
     // only show progress window if it takes longer than 500ms to create folder
     let progwin_timeout = setTimeout(async () => {
     let progwin_timeout = setTimeout(async () => {
-        progwin = await UIWindowNewFolderProgress({operation_id: newfolder_op_id});
+        progwin = await UIWindowProgress({
+            operation_id: newfolder_op_id,
+            // TODO: Implement cancellation.
+            // on_cancel: () => {
+            //     window.operation_cancelled[newfolder_op_id] = true;
+            // },
+        });
+        progwin.set_status(i18n('taking_longer_than_usual'));
     }, 500);
     }, 500);
 
 
     // create folder
     // create folder
@@ -1190,14 +1192,16 @@ window.create_folder = async(basedir, appendto_element)=>{
 
 
                 // done
                 // done
                 let newfolder_duration = (Date.now() - newfolder_progress_window_init_ts);
                 let newfolder_duration = (Date.now() - newfolder_progress_window_init_ts);
-                if( progwin && newfolder_duration >= window.copy_progress_hide_delay){
-                    $(progwin).close();   
-                }else if(progwin){
-                    setTimeout(() => {
+                if (progwin) {
+                    if (newfolder_duration >= window.copy_progress_hide_delay) {
+                        progwin.close();
+                    } else {
                         setTimeout(() => {
                         setTimeout(() => {
-                            $(progwin).close();   
-                        }, Math.abs(window.copy_progress_hide_delay - newfolder_duration));
-                    })
+                            setTimeout(() => {
+                                progwin.close();
+                            }, Math.abs(window.copy_progress_hide_delay - newfolder_duration));
+                        });
+                    }
                 }
                 }
             }
             }
         });
         });
@@ -1267,8 +1271,13 @@ window.copy_clipboard_items = async function(dest_path, dest_container_element){
         // only show progress window if it takes longer than 2s to copy
         // only show progress window if it takes longer than 2s to copy
         let progwin;
         let progwin;
         let progwin_timeout = setTimeout(async () => {
         let progwin_timeout = setTimeout(async () => {
-            progwin = await UIWindowCopyProgress({operation_id: copy_op_id});
-        }, 2000);
+            progwin = await UIWindowProgress({
+                operation_id: copy_op_id,
+                on_cancel: () => {
+                    window.operation_cancelled[copy_op_id] = true;
+                },
+            });
+        }, 0);
 
 
         const copied_item_paths = []
         const copied_item_paths = []
 
 
@@ -1276,7 +1285,8 @@ window.copy_clipboard_items = async function(dest_path, dest_container_element){
             let copy_path = window.clipboard[i].path;
             let copy_path = window.clipboard[i].path;
             let item_with_same_name_already_exists = true;
             let item_with_same_name_already_exists = true;
             let overwrite = overwrite_all;
             let overwrite = overwrite_all;
-            $(progwin).find('.copy-from').html(html_encode(copy_path));
+            progwin?.set_status(i18n('copying_file', copy_path));
+
             do{
             do{
                 if(overwrite)
                 if(overwrite)
                     item_with_same_name_already_exists = false;
                     item_with_same_name_already_exists = false;
@@ -1344,14 +1354,16 @@ window.copy_clipboard_items = async function(dest_path, dest_container_element){
         clearTimeout(progwin_timeout);
         clearTimeout(progwin_timeout);
 
 
         let copy_duration = (Date.now() - copy_progress_window_init_ts);
         let copy_duration = (Date.now() - copy_progress_window_init_ts);
-        if(progwin && copy_duration >= window.copy_progress_hide_delay){
-            $(progwin).close();   
-        }else if(progwin){
-            setTimeout(() => {
+        if (progwin) {
+            if (copy_duration >= window.copy_progress_hide_delay) {
+                progwin.close();
+            } else {
                 setTimeout(() => {
                 setTimeout(() => {
-                    $(progwin).close();   
-                }, Math.abs(window.copy_progress_hide_delay - copy_duration));
-            })
+                    setTimeout(() => {
+                        progwin.close();
+                    }, Math.abs(window.copy_progress_hide_delay - copy_duration));
+                });
+            }
         }
         }
     })();
     })();
 }
 }
@@ -1371,7 +1383,12 @@ window.copy_items = function(el_items, dest_path){
         // only show progress window if it takes longer than 2s to copy
         // only show progress window if it takes longer than 2s to copy
         let progwin;
         let progwin;
         let progwin_timeout = setTimeout(async () => {
         let progwin_timeout = setTimeout(async () => {
-            progwin = await UIWindowCopyProgress({operation_id: copy_op_id});
+            progwin = await UIWindowProgress({
+                operation_id: copy_op_id,
+                on_cancel: () => {
+                    window.operation_cancelled[copy_op_id] = true;
+                },
+            });
         }, 2000);
         }, 2000);
 
 
         const copied_item_paths = []
         const copied_item_paths = []
@@ -1380,7 +1397,7 @@ window.copy_items = function(el_items, dest_path){
             let copy_path = $(el_items[i]).attr('data-path');
             let copy_path = $(el_items[i]).attr('data-path');
             let item_with_same_name_already_exists = true;
             let item_with_same_name_already_exists = true;
             let overwrite = overwrite_all;
             let overwrite = overwrite_all;
-            $(progwin).find('.copy-from').html(html_encode(copy_path));
+            progwin?.set_status(i18n('copying_file', copy_path));
 
 
             do{
             do{
                 if(overwrite)
                 if(overwrite)
@@ -1449,14 +1466,16 @@ window.copy_items = function(el_items, dest_path){
         clearTimeout(progwin_timeout);
         clearTimeout(progwin_timeout);
 
 
         let copy_duration = (Date.now() - copy_progress_window_init_ts);
         let copy_duration = (Date.now() - copy_progress_window_init_ts);
-        if(progwin && copy_duration >= window.copy_progress_hide_delay){
-            $(progwin).close();   
-        }else if(progwin){
-            setTimeout(() => {
+        if (progwin) {
+            if (copy_duration >= window.copy_progress_hide_delay) {
+                progwin.close();
+            } else {
                 setTimeout(() => {
                 setTimeout(() => {
-                    $(progwin).close();   
-                }, Math.abs(window.copy_progress_hide_delay - copy_duration));
-            })
+                    setTimeout(() => {
+                        progwin.close();
+                    }, Math.abs(window.copy_progress_hide_delay - copy_duration));
+                });
+            }
         }
         }
     })()
     })()
 }
 }
@@ -2125,7 +2144,12 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
     // only show progress window if it takes longer than 2s to move
     // only show progress window if it takes longer than 2s to move
     let progwin;
     let progwin;
     let progwin_timeout = setTimeout(async () => {
     let progwin_timeout = setTimeout(async () => {
-        progwin = await UIWindowMoveProgress({operation_id: move_op_id});
+        progwin = await UIWindowProgress({
+            operation_id: move_op_id,
+            on_cancel: () => {
+                window.operation_cancelled[move_op_id] = true;
+            },
+        });
     }, 2000);
     }, 2000);
 
 
     // storing moved items for undo ability
     // storing moved items for undo ability
@@ -2188,6 +2212,8 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
                 // indicates whether this is a recycling operation
                 // indicates whether this is a recycling operation
                 let recycling = false;
                 let recycling = false;
 
 
+                let status_i18n_string = 'moving_file';
+
                 // --------------------------------------------------------
                 // --------------------------------------------------------
                 // Trashing
                 // Trashing
                 // --------------------------------------------------------
                 // --------------------------------------------------------
@@ -2199,6 +2225,8 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
                         trashed_ts: Math.round(Date.now() / 1000),
                         trashed_ts: Math.round(Date.now() / 1000),
                     };
                     };
 
 
+                    status_i18n_string = 'deleting_file';
+
                     // update other clients
                     // update other clients
                     if(window.socket)
                     if(window.socket)
                         window.socket.emit('trash.is_empty', {is_empty: false});
                         window.socket.emit('trash.is_empty', {is_empty: false});
@@ -2211,7 +2239,7 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
 
 
                 // moving an item into a trashed directory? deny.
                 // moving an item into a trashed directory? deny.
                 else if(dest_path.startsWith(window.trash_path)){
                 else if(dest_path.startsWith(window.trash_path)){
-                    $(progwin).close();
+                    progwin?.close();
                     UIAlert('Cannot move items into a deleted folder.');
                     UIAlert('Cannot move items into a deleted folder.');
                     return;
                     return;
                 }
                 }
@@ -2230,7 +2258,7 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
                 // --------------------------------------------------------
                 // --------------------------------------------------------
                 // update progress window with current item being moved
                 // update progress window with current item being moved
                 // --------------------------------------------------------
                 // --------------------------------------------------------
-                $(progwin).find('.move-from').html(html_encode(path_to_show_on_progwin));
+                progwin?.set_status(i18n(status_i18n_string, path_to_show_on_progwin));
 
 
                 // execute move
                 // execute move
                 let resp = await puter.fs.move({
                 let resp = await puter.fs.move({
@@ -2437,7 +2465,7 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
 
 
     if(progwin){
     if(progwin){
         setTimeout(() => {
         setTimeout(() => {
-            $(progwin).close();   
+            progwin.close();
         }, window.copy_progress_hide_delay);
         }, window.copy_progress_hide_delay);
     }
     }
 }
 }
@@ -2685,25 +2713,28 @@ window.upload_items = async function(items, dest_path){
             init: async(operation_id, xhr)=>{
             init: async(operation_id, xhr)=>{
                 opid = operation_id;
                 opid = operation_id;
                 // create upload progress window
                 // create upload progress window
-                upload_progress_window = await UIWindowUploadProgress({operation_id: operation_id});
-                // cancel btn
-                $(upload_progress_window).find('.upload-cancel-btn').on('click', function(e){
-                    $(upload_progress_window).close();
-                    window.show_save_account_notice_if_needed();
-                    xhr.abort();
-                })
+                upload_progress_window = await UIWindowProgress({
+                    title: i18n('upload'),
+                    icon: window.icons[`app-icon-uploader.svg`],
+                    operation_id: operation_id,
+                    show_progress: true,
+                    on_cancel: () => {
+                        window.show_save_account_notice_if_needed();
+                        xhr.abort();
+                    },
+                });
                 // add to active_uploads
                 // add to active_uploads
                 window.active_uploads[opid] = 0;
                 window.active_uploads[opid] = 0;
             },
             },
             // start
             // start
             start: async function(){
             start: async function(){
                 // change upload progress window message to uploading
                 // change upload progress window message to uploading
-                $(upload_progress_window).find('.upload-progress-msg').html(`Uploading (<span class="upload-progress-percent">0%</span>)`);
+                upload_progress_window.set_status('Uploading');
+                upload_progress_window.set_progress(0);
             },
             },
             // progress
             // progress
             progress: async function(operation_id, op_progress){
             progress: async function(operation_id, op_progress){
-                $(`[data-upload-operation-id="${operation_id}"]`).find('.upload-progress-bar').css( 'width', op_progress+'%');
-                $(`[data-upload-operation-id="${operation_id}"]`).find('.upload-progress-percent').html(op_progress+'%');
+                upload_progress_window.set_progress(op_progress);
                 // update active_uploads
                 // update active_uploads
                 window.active_uploads[opid] = op_progress;
                 window.active_uploads[opid] = op_progress;
                 // update title if window is not visible
                 // update title if window is not visible
@@ -2731,7 +2762,7 @@ window.upload_items = async function(items, dest_path){
                 // close progress window after a bit of delay for a better UX
                 // close progress window after a bit of delay for a better UX
                 setTimeout(() => {
                 setTimeout(() => {
                     setTimeout(() => {
                     setTimeout(() => {
-                        $(upload_progress_window).close();
+                        upload_progress_window.close();
                         window.show_save_account_notice_if_needed();
                         window.show_save_account_notice_if_needed();
                     }, Math.abs(window.upload_progress_hide_delay));
                     }, Math.abs(window.upload_progress_hide_delay));
                 })
                 })
@@ -2740,8 +2771,7 @@ window.upload_items = async function(items, dest_path){
             },
             },
             // error
             // error
             error: async function(err){
             error: async function(err){
-                $(upload_progress_window).close();  
-                // UIAlert(err?.message ?? 'An error occurred while uploading.');
+                upload_progress_window.show_error(i18n('error_uploading_files'), err.message);
                 // remove from active_uploads
                 // remove from active_uploads
                 delete window.active_uploads[opid];
                 delete window.active_uploads[opid];
             },
             },
@@ -2778,7 +2808,8 @@ window.empty_trash = async function(){
     let progwin;
     let progwin;
     let op_id = window.uuidv4();
     let op_id = window.uuidv4();
     let progwin_timeout = setTimeout(async () => {
     let progwin_timeout = setTimeout(async () => {
-        progwin = await UIWindowProgressEmptyTrash({operation_id: op_id});
+        progwin = await UIWindowProgress({operation_id: op_id});
+        progwin.set_status(i18n('emptying_trash'));
     }, 500);
     }, 500);
 
 
     await puter.fs.delete({
     await puter.fs.delete({
@@ -2802,13 +2833,13 @@ window.empty_trash = async function(){
             // close progress window
             // close progress window
             clearTimeout(progwin_timeout);
             clearTimeout(progwin_timeout);
             setTimeout(() => {
             setTimeout(() => {
-                $(progwin).close();   
+                progwin?.close();
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - init_ts)));
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - init_ts)));
         },
         },
         error: async function (err){
         error: async function (err){
             clearTimeout(progwin_timeout);
             clearTimeout(progwin_timeout);
             setTimeout(() => {
             setTimeout(() => {
-                $(progwin).close();   
+                progwin?.close();
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - init_ts)));
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - init_ts)));
         }
         }
     });
     });
@@ -2931,14 +2962,14 @@ window.zipItems = async function(el_items, targetDirPath, download = true) {
     let progwin, progwin_timeout;
     let progwin, progwin_timeout;
     // only show progress window if it takes longer than 500ms to download
     // only show progress window if it takes longer than 500ms to download
     progwin_timeout = setTimeout(async () => {
     progwin_timeout = setTimeout(async () => {
-        progwin = await UIWindowDownloadDirProg();
+        progwin = await UIWindowProgress();
     }, 500);
     }, 500);
 
 
     for (const el_item of el_items) {
     for (const el_item of el_items) {
         let targetPath = $(el_item).attr('data-path');
         let targetPath = $(el_item).attr('data-path');
         // if directory, zip the directory
         // if directory, zip the directory
         if($(el_item).attr('data-is_dir') === '1'){
         if($(el_item).attr('data-is_dir') === '1'){
-            $(progwin).find('.dir-dl-status').html(`Reading <strong>${html_encode(targetPath)}</strong>`);
+            progwin?.set_status(i18n('reading_file', targetPath));
             // Recursively read the directory
             // Recursively read the directory
             let children = await readDirectoryRecursive(targetPath);
             let children = await readDirectoryRecursive(targetPath);
 
 
@@ -2951,7 +2982,7 @@ window.zipItems = async function(el_items, targetDirPath, download = true) {
                     relativePath = path.basename(targetPath) + '/' + child.relativePath;
                     relativePath = path.basename(targetPath) + '/' + child.relativePath;
 
 
                 // update progress window
                 // update progress window
-                $(progwin).find('.dir-dl-status').html(`Zipping <strong>${html_encode(relativePath)}</strong>`);
+                progwin?.set_status(i18n('zipping_file', relativePath));
                 
                 
                 // read file content
                 // read file content
                 let content = await puter.fs.read(child.path);
                 let content = await puter.fs.read(child.path);
@@ -3000,17 +3031,18 @@ window.zipItems = async function(el_items, targetDirPath, download = true) {
             // close progress window
             // close progress window
             clearTimeout(progwin_timeout);
             clearTimeout(progwin_timeout);
             setTimeout(() => {
             setTimeout(() => {
-                $(progwin).close();   
+                progwin?.close();
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
         })
         })
         .catch(function (err) {
         .catch(function (err) {
             // close progress window
             // close progress window
             clearTimeout(progwin_timeout);
             clearTimeout(progwin_timeout);
             setTimeout(() => {
             setTimeout(() => {
-                $(progwin).close();   
+                progwin?.close();
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
             }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
 
 
             // handle errors
             // handle errors
+            // TODO: Display in progress dialog
             console.error("Error in zipping files: ", err);
             console.error("Error in zipping files: ", err);
         });
         });
 }
 }
@@ -3053,7 +3085,7 @@ window.unzipItem = async function(itemPath) {
     let progwin, progwin_timeout;
     let progwin, progwin_timeout;
     // only show progress window if it takes longer than 500ms to download
     // only show progress window if it takes longer than 500ms to download
     progwin_timeout = setTimeout(async () => {
     progwin_timeout = setTimeout(async () => {
-        progwin = await UIWindowDownloadDirProg();
+        progwin = await UIWindowProgress();
     }, 500);
     }, 500);
 
 
     const zip = new JSZip();
     const zip = new JSZip();
@@ -3075,7 +3107,7 @@ window.unzipItem = async function(itemPath) {
         // close progress window
         // close progress window
         clearTimeout(progwin_timeout);
         clearTimeout(progwin_timeout);
         setTimeout(() => {
         setTimeout(() => {
-            $(progwin).close();   
+            progwin?.close();
         }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
         }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
 
 
     }).catch(function (e) {
     }).catch(function (e) {
@@ -3083,7 +3115,7 @@ window.unzipItem = async function(itemPath) {
         // close progress window
         // close progress window
         clearTimeout(progwin_timeout);
         clearTimeout(progwin_timeout);
         setTimeout(() => {
         setTimeout(() => {
-            $(progwin).close();   
+            progwin?.close();
         }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
         }, Math.max(0, window.copy_progress_hide_delay - (Date.now() - start_ts)));
     })
     })
 }
 }

+ 0 - 3
src/helpers/download.js

@@ -109,9 +109,6 @@ const download = function(options){
             let batch_progress = ((batch_download_progress[0].cloud_uploaded + batch_download_progress[0].downloaded)/batch_download_progress[0].total * 100).toFixed(0);
             let batch_progress = ((batch_download_progress[0].cloud_uploaded + batch_download_progress[0].downloaded)/batch_download_progress[0].total * 100).toFixed(0);
             batch_progress = batch_progress > 100 ? 100 : batch_progress;
             batch_progress = batch_progress > 100 ? 100 : batch_progress;
 
 
-            // Update the progress bar
-            $(`[data-download-operation-id="${options.operation_id}"]`).find('.download-progress-bar').css( 'width', batch_progress+'%');
-
             // If download is finished resolve promise
             // If download is finished resolve promise
             if((item_progress >= 1 || item_progress === 0) && item){
             if((item_progress >= 1 || item_progress === 0) && item){
                 // For a better UX, resolve 0.5 second after operation is finished.
                 // For a better UX, resolve 0.5 second after operation is finished.

+ 1 - 1
src/i18n/translations/ar.js

@@ -83,7 +83,7 @@ const ar = {
 		log_in: "تسجيل الدخول",
 		log_in: "تسجيل الدخول",
 		log_out: 'تسجيل خروج',
 		log_out: 'تسجيل خروج',
 		move: 'يتحرك',
 		move: 'يتحرك',
-		moving: "متحرك ",
+		moving_file: "متحرك %%",
 		my_websites: "مواقعي الإلكترونية ",
 		my_websites: "مواقعي الإلكترونية ",
 		name: 'اسم',
 		name: 'اسم',
 		name_cannot_be_empty: 'لا يمكن أن يكون الاسم فارغًا',
 		name_cannot_be_empty: 'لا يمكن أن يكون الاسم فارغًا',

+ 1 - 1
src/i18n/translations/bn.js

@@ -82,7 +82,7 @@ const bn = {
         log_in: "প্রবেশ করুন",
         log_in: "প্রবেশ করুন",
         log_out: 'প্রস্থান',
         log_out: 'প্রস্থান',
         move: 'সরান',
         move: 'সরান',
-        moving: "চলন্ত",
+        moving_file: "চলন্ত %%",
         my_websites: "আমার ওয়েবসাইট",
         my_websites: "আমার ওয়েবসাইট",
         name: 'নাম',
         name: 'নাম',
         name_cannot_be_empty: 'নাম খালি রাখা যাবে না।',
         name_cannot_be_empty: 'নাম খালি রাখা যাবে না।',

+ 1 - 1
src/i18n/translations/br.js

@@ -102,7 +102,7 @@ const br = {
         log_into_another_account_anyway: 'Entrar com outra conta de qualquer maneira',
         log_into_another_account_anyway: 'Entrar com outra conta de qualquer maneira',
         log_out: 'Sair',
         log_out: 'Sair',
         move: 'Mover',
         move: 'Mover',
-        moving: "Movendo",
+        moving_file: "Movendo %%",
         my_websites: "Meus Sites",
         my_websites: "Meus Sites",
         name: 'Nome',
         name: 'Nome',
         name_cannot_be_empty: 'Nome não pode ser vazio.',
         name_cannot_be_empty: 'Nome não pode ser vazio.',

+ 1 - 1
src/i18n/translations/da.js

@@ -83,7 +83,7 @@ const da = {
         log_in: "Log ind",
         log_in: "Log ind",
         log_out: "Log ud",
         log_out: "Log ud",
         move: "Flyt",
         move: "Flyt",
-        moving: "Flytter",
+        moving_file: "Flytter %%",
         my_websites: "Mine websteder",
         my_websites: "Mine websteder",
         name: "Navn",
         name: "Navn",
         name_cannot_be_empty: "Navn kan ikke være tomt.",
         name_cannot_be_empty: "Navn kan ikke være tomt.",

+ 1 - 1
src/i18n/translations/de.js

@@ -83,7 +83,7 @@ const de = {
         log_in: "Einloggen",
         log_in: "Einloggen",
         log_out: 'Ausloggen',
         log_out: 'Ausloggen',
         move: 'Verschieben',
         move: 'Verschieben',
-        moving: "Verschiebe",
+        moving_file: "Verschiebe %%",
         my_websites: "Meine Webseiten",
         my_websites: "Meine Webseiten",
         name: 'Name',
         name: 'Name',
         name_cannot_be_empty: 'Name kann nicht leer sein.',
         name_cannot_be_empty: 'Name kann nicht leer sein.',

+ 1 - 1
src/i18n/translations/emoji.js

@@ -92,7 +92,7 @@ const emoji = {
         log_into_another_account_anyway: '👤🔄',
         log_into_another_account_anyway: '👤🔄',
         log_out: '🔚',
         log_out: '🔚',
         move: '➡️',
         move: '➡️',
-        moving: "➡️...",
+        moving_file: "➡️ %%...",
         my_websites: "🌐👤",
         my_websites: "🌐👤",
         name: '📛',
         name: '📛',
         name_cannot_be_empty: '📛❌',
         name_cannot_be_empty: '📛❌',

+ 6 - 1
src/i18n/translations/en.js

@@ -71,6 +71,7 @@ const en = {
         copy: 'Copy',
         copy: 'Copy',
         copy_link: "Copy Link",
         copy_link: "Copy Link",
         copying: "Copying",
         copying: "Copying",
+        copying_file: "Copying %%",
         cover: 'Cover',
         cover: 'Cover',
         create_account: "Create Account",
         create_account: "Create Account",
         create_free_account: "Create Free Account",
         create_free_account: "Create Free Account",
@@ -87,6 +88,7 @@ const en = {
         delete: 'Delete',
         delete: 'Delete',
         delete_account: "Delete Account",
         delete_account: "Delete Account",
         delete_permanently: "Delete Permanently",
         delete_permanently: "Delete Permanently",
+        deleting_file: "Deleting %%",
         deploy_as_app: 'Deploy as app',
         deploy_as_app: 'Deploy as app',
         descending: 'Descending',
         descending: 'Descending',
         desktop_background_fit: "Fit",
         desktop_background_fit: "Fit",
@@ -113,6 +115,7 @@ const en = {
         enlarged_qr_code: "Enlarged QR Code",
         enlarged_qr_code: "Enlarged QR Code",
         enter_password_to_confirm_delete_user: "Enter your password to confirm account deletion",
         enter_password_to_confirm_delete_user: "Enter your password to confirm account deletion",
         error_unknown_cause: "An unknown error occurred.",
         error_unknown_cause: "An unknown error occurred.",
+        error_uploading_files: "Failed to upload files",
         feedback: "Feedback",
         feedback: "Feedback",
         feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.",
         feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.",
         feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.",
         feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.",
@@ -143,7 +146,7 @@ const en = {
         looks_good: "Looks good!",
         looks_good: "Looks good!",
         manage_sessions: "Manage Sessions",
         manage_sessions: "Manage Sessions",
         move: 'Move',
         move: 'Move',
-        moving: "Moving",
+        moving_file: "Moving %%",
         my_websites: "My Websites",
         my_websites: "My Websites",
         name: 'Name',
         name: 'Name',
         name_cannot_be_empty: 'Name cannot be empty.',
         name_cannot_be_empty: 'Name cannot be empty.',
@@ -197,6 +200,7 @@ const en = {
         publish_as_website: 'Publish as website',
         publish_as_website: 'Publish as website',
         puter_description: `Puter is a privacy-first personal cloud to keep all your files, apps, and games in one
         puter_description: `Puter is a privacy-first personal cloud to keep all your files, apps, and games in one
         secure place, accessible from anywhere at any time.`,
         secure place, accessible from anywhere at any time.`,
+        reading_file: "Reading %strong%",
         recent: "Recent",
         recent: "Recent",
         recommended: "Recommended",
         recommended: "Recommended",
         recover_password: "Recover Password",
         recover_password: "Recover Password",
@@ -280,6 +284,7 @@ const en = {
         yes_release_it: 'Yes, Release It',
         yes_release_it: 'Yes, Release It',
         you_have_been_referred_to_puter_by_a_friend: "You have been referred to Puter by a friend!",
         you_have_been_referred_to_puter_by_a_friend: "You have been referred to Puter by a friend!",
         zip: "Zip",
         zip: "Zip",
+        zipping_file: "Zipping %strong%",
 
 
         // === 2FA Setup ===
         // === 2FA Setup ===
         setup2fa_1_step_heading: 'Open your authenticator app',      
         setup2fa_1_step_heading: 'Open your authenticator app',      

+ 1 - 1
src/i18n/translations/es.js

@@ -83,7 +83,7 @@ const es = {
         log_in: "Iniciar sesión",
         log_in: "Iniciar sesión",
         log_out: 'Cerrar sesión',
         log_out: 'Cerrar sesión',
         move: 'Mover',
         move: 'Mover',
-        moving: "Moviendo",
+        moving_file: "Moviendo %%",
         my_websites: "Mis páginas web",
         my_websites: "Mis páginas web",
         name: 'Nombre',
         name: 'Nombre',
         name_cannot_be_empty: 'El nombre no puede estar vacío.',
         name_cannot_be_empty: 'El nombre no puede estar vacío.',

+ 1 - 1
src/i18n/translations/fa.js

@@ -84,7 +84,7 @@ const fa = {
         log_in: "ورود",
         log_in: "ورود",
         log_out: 'خروج',
         log_out: 'خروج',
         move: 'انتقال',
         move: 'انتقال',
-        moving: "انتقال",
+        moving_file: "انتقال %%",
         my_websites: "وبسایت های من",
         my_websites: "وبسایت های من",
         name: 'نام',
         name: 'نام',
         name_cannot_be_empty: 'نام نمی تواند خالی باشد.',
         name_cannot_be_empty: 'نام نمی تواند خالی باشد.',

+ 1 - 1
src/i18n/translations/fi.js

@@ -116,7 +116,7 @@ const fi = {
         log_in: "Kirjaudu Sisään",
         log_in: "Kirjaudu Sisään",
         log_out: 'Kirjaudu Ulos',
         log_out: 'Kirjaudu Ulos',
         move: 'Siirrä',
         move: 'Siirrä',
-        moving: "Siirretään",
+        moving_file: "Siirretään %%",
         my_websites: "Verkkosivustoni",
         my_websites: "Verkkosivustoni",
         name: 'Nimi',
         name: 'Nimi',
         name_cannot_be_empty: 'Nimi ei voi olla tyhjä.',
         name_cannot_be_empty: 'Nimi ei voi olla tyhjä.',

+ 1 - 1
src/i18n/translations/fr.js

@@ -82,7 +82,7 @@ const fr = {
         log_in: "Se connecter",
         log_in: "Se connecter",
         log_out: "Se déconnecter",
         log_out: "Se déconnecter",
         move: "Déplacer",
         move: "Déplacer",
-        moving: "Déplacement en cours",
+        moving_file: "Déplacement en cours %%",
         my_websites: "Mes sites web",
         my_websites: "Mes sites web",
         name: "Nom",
         name: "Nom",
         name_cannot_be_empty: "Le nom ne peut pas être vide.",
         name_cannot_be_empty: "Le nom ne peut pas être vide.",

+ 1 - 1
src/i18n/translations/hy.js

@@ -83,7 +83,7 @@ const hy = {
         log_in: "Մուտք գործել",
         log_in: "Մուտք գործել",
         log_out: "Դուրս գալ",
         log_out: "Դուրս գալ",
         move: "Տեղափոխել",
         move: "Տեղափոխել",
-        moving: "Տեղափոխվում է",
+        moving_file: "Տեղափոխվում է %%",
         my_websites: "Իմ կայքերը",
         my_websites: "Իմ կայքերը",
         name: "Անուն",
         name: "Անուն",
         name_cannot_be_empty: "Անվան դաշտը չի կառող լինել դատարկ։",
         name_cannot_be_empty: "Անվան դաշտը չի կառող լինել դատարկ։",

+ 1 - 1
src/i18n/translations/ig.js

@@ -126,7 +126,7 @@ const ig = {
         log_out: 'pụọ',
         log_out: 'pụọ',
         manage_sessions: "Jikwaa Oge",
         manage_sessions: "Jikwaa Oge",
         move: 'Bugharịa',
         move: 'Bugharịa',
-        moving: "Na Bugharịa",
+        moving_file: "Na Bugharịa %%",
         my_websites: "Weebụsaịtị m",
         my_websites: "Weebụsaịtị m",
         name: 'Aha',
         name: 'Aha',
         name_cannot_be_empty: 'Aha enweghị ike ịbụ ihe efu.',
         name_cannot_be_empty: 'Aha enweghị ike ịbụ ihe efu.',

+ 1 - 1
src/i18n/translations/it.js

@@ -83,7 +83,7 @@ const it = {
         log_in: "Accedi",
         log_in: "Accedi",
         log_out: 'Disconnettiti',
         log_out: 'Disconnettiti',
         move: 'Sposta',
         move: 'Sposta',
-        moving: "Spostamento in corso",
+        moving_file: "Spostamento in corso %%",
         my_websites: "I miei siti web",
         my_websites: "I miei siti web",
         name: 'Nome',
         name: 'Nome',
         name_cannot_be_empty: 'Il nome non può essere vuoto.',
         name_cannot_be_empty: 'Il nome non può essere vuoto.',

+ 1 - 1
src/i18n/translations/ko.js

@@ -91,7 +91,7 @@ const ko = {
         log_in: "로그인",
         log_in: "로그인",
         log_out: '로그아웃',
         log_out: '로그아웃',
         move: '이동',
         move: '이동',
-        moving: "이동 중",
+        moving_file: "이동 중 %%",
         my_websites: "내 웹사이트",
         my_websites: "내 웹사이트",
         name: '이름',
         name: '이름',
         name_cannot_be_empty: '이름은 비워둘 수 없습니다.',
         name_cannot_be_empty: '이름은 비워둘 수 없습니다.',

+ 1 - 1
src/i18n/translations/nb.js

@@ -92,7 +92,7 @@ const nb = {
         log_into_another_account_anyway: 'Logg inn på en annen bruker uansett',
         log_into_another_account_anyway: 'Logg inn på en annen bruker uansett',
         log_out: "Logg ut",
         log_out: "Logg ut",
         move: "Flytt",
         move: "Flytt",
-        moving: "Flytter",
+        moving_file: "Flytter %%",
         my_websites: "Mine nettsteder",
         my_websites: "Mine nettsteder",
         name: "Navn",
         name: "Navn",
         name_cannot_be_empty: "Navn kan ikke være tomt.",
         name_cannot_be_empty: "Navn kan ikke være tomt.",

+ 1 - 1
src/i18n/translations/nl.js

@@ -102,7 +102,7 @@ const nl = {
 		log_into_another_account_anyway: 'Alsnog met ander account inloggen',
 		log_into_another_account_anyway: 'Alsnog met ander account inloggen',
 		log_out: 'Uitloggen',
 		log_out: 'Uitloggen',
 		move: 'Verplaatsen',
 		move: 'Verplaatsen',
-		moving: "Aan het verplaatsen",
+		moving_file: "Aan het verplaatsen %%",
 		my_websites: "Mijn Websites",
 		my_websites: "Mijn Websites",
 		name: 'Naam',
 		name: 'Naam',
 		name_cannot_be_empty: 'Naam kan niet leeg zijn.',
 		name_cannot_be_empty: 'Naam kan niet leeg zijn.',

+ 1 - 1
src/i18n/translations/nn.js

@@ -83,7 +83,7 @@ const nn = {
         log_in: "Logg inn",
         log_in: "Logg inn",
         log_out: "Logg ut",
         log_out: "Logg ut",
         move: "Flytt",
         move: "Flytt",
-        moving: "Flyttar",
+        moving_file: "Flyttar %%",
         my_websites: "Mine nettstader",
         my_websites: "Mine nettstader",
         name: "Namn",
         name: "Namn",
         name_cannot_be_empty: "Namn kan ikkje vere tomt.",
         name_cannot_be_empty: "Namn kan ikkje vere tomt.",

+ 1 - 1
src/i18n/translations/pl.js

@@ -92,7 +92,7 @@ const pl = {
         log_into_another_account_anyway: 'Zaloguj się do innego konta mimo wszystko',
         log_into_another_account_anyway: 'Zaloguj się do innego konta mimo wszystko',
         log_out: 'Wyloguj się',
         log_out: 'Wyloguj się',
         move: 'Przenieś',
         move: 'Przenieś',
-        moving: "Przenoszenie",
+        moving_file: "Przenoszenie %%",
         my_websites: "Moje strony",
         my_websites: "Moje strony",
         name: 'Nazwa',
         name: 'Nazwa',
         name_cannot_be_empty: 'Nazwa nie może być pusta.',
         name_cannot_be_empty: 'Nazwa nie może być pusta.',

+ 1 - 1
src/i18n/translations/pt.js

@@ -106,7 +106,7 @@ const pt = {
         log_into_another_account_anyway: 'Entrar com outra conta na mesma',
         log_into_another_account_anyway: 'Entrar com outra conta na mesma',
         log_out: 'Sair',
         log_out: 'Sair',
         move: 'Mover',
         move: 'Mover',
-        moving: "Movendo",
+        moving_file: "Movendo %%",
         my_websites: "Meus Sites",
         my_websites: "Meus Sites",
         name: 'Nome',
         name: 'Nome',
         name_cannot_be_empty: 'Nome não pode ser vazio.',
         name_cannot_be_empty: 'Nome não pode ser vazio.',

+ 1 - 1
src/i18n/translations/ro.js

@@ -82,7 +82,7 @@ const ro = {
         log_in: "Loghează-te",
         log_in: "Loghează-te",
         log_out: 'Deconectează-te',
         log_out: 'Deconectează-te',
         move: 'Mută',
         move: 'Mută',
-        moving: "Se mută",
+        moving_file: "Se mută %%",
         my_websites: "Site-urile mele",
         my_websites: "Site-urile mele",
         name: 'Nume',
         name: 'Nume',
         name_cannot_be_empty: 'Numele nu poate fi necompletat.',
         name_cannot_be_empty: 'Numele nu poate fi necompletat.',

+ 1 - 1
src/i18n/translations/ru.js

@@ -126,7 +126,7 @@ const ru = {
         log_out: 'Выйти',
         log_out: 'Выйти',
         manage_sessions: "Управление Сеансами",
         manage_sessions: "Управление Сеансами",
         move: 'Переместить',
         move: 'Переместить',
-        moving: "Перемещается",
+        moving_file: "Перемещается %%",
         my_websites: "Мои Сайты",
         my_websites: "Мои Сайты",
         name: 'Имя',
         name: 'Имя',
         name_cannot_be_empty: 'Имя не может быть пустым.',
         name_cannot_be_empty: 'Имя не может быть пустым.',

+ 1 - 1
src/i18n/translations/sv.js

@@ -83,7 +83,7 @@ const sv = {
         log_in: "Logga in",
         log_in: "Logga in",
         log_out: "Logga ut",
         log_out: "Logga ut",
         move: "Flytta",
         move: "Flytta",
-        moving: "Flyttar",
+        moving_file: "Flyttar %%",
         my_websites: "Mina webbplatser",
         my_websites: "Mina webbplatser",
         name: "Namn",
         name: "Namn",
         name_cannot_be_empty: "Namn kan inte vara tomt.",
         name_cannot_be_empty: "Namn kan inte vara tomt.",

+ 1 - 1
src/i18n/translations/th.js

@@ -91,7 +91,7 @@ const th = {
         log_into_another_account_anyway: "ต้องการเข้าสู่บัญชีอื่น",
         log_into_another_account_anyway: "ต้องการเข้าสู่บัญชีอื่น",
         log_out: "ออกจากระบบ",
         log_out: "ออกจากระบบ",
         move: "ย้าย",
         move: "ย้าย",
-        moving: "กำลังย้าย",
+        moving_file: "กำลังย้าย %%",
         my_websites: "เว็บไซต์ของฉัน",
         my_websites: "เว็บไซต์ของฉัน",
         name: "ชื่อ",
         name: "ชื่อ",
         name_cannot_be_empty: "ไม่สามารถปล่อยช่องชื่อให้ว่างได้",
         name_cannot_be_empty: "ไม่สามารถปล่อยช่องชื่อให้ว่างได้",

+ 1 - 1
src/i18n/translations/tr.js

@@ -116,7 +116,7 @@ const tr = {
         log_out: "Çıkış Yap",
         log_out: "Çıkış Yap",
         manage_sessions: "Oturumları Yönet",
         manage_sessions: "Oturumları Yönet",
         move: "Taşı",
         move: "Taşı",
-        moving: "Taşınıyor",
+        moving_file: "Taşınıyor %%",
         my_websites: "Web Sitelerim",
         my_websites: "Web Sitelerim",
         name: "Ad",
         name: "Ad",
         name_cannot_be_empty: "Ad boş olamaz.",
         name_cannot_be_empty: "Ad boş olamaz.",

+ 1 - 1
src/i18n/translations/ur.js

@@ -83,7 +83,7 @@ const ur = {
         log_in: "لاگ ان",
         log_in: "لاگ ان",
         log_out: 'لاگ آؤٹ',
         log_out: 'لاگ آؤٹ',
         move: 'منتقل کریں',
         move: 'منتقل کریں',
-        moving: "منتقل ہو رہا ہے ",
+        moving_file: "منتقل ہو رہا ہے %%",
         my_websites: "میری ویب سائٹیں ",
         my_websites: "میری ویب سائٹیں ",
         name: 'نام',
         name: 'نام',
         name_cannot_be_empty: 'نام خالی نہیں ہو سکتا',
         name_cannot_be_empty: 'نام خالی نہیں ہو سکتا',

+ 1 - 1
src/i18n/translations/zh.js

@@ -87,7 +87,7 @@ const zh = {
         log_in: "登录",
         log_in: "登录",
         log_out: '登出',
         log_out: '登出',
         move: '移动',
         move: '移动',
-        moving: "移动",
+        moving_file: "移动 %%",
         my_websites: "我的网站",
         my_websites: "我的网站",
         name: '名称',
         name: '名称',
         name_cannot_be_empty: '名称不能为空。',
         name_cannot_be_empty: '名称不能为空。',

+ 1 - 1
src/i18n/translations/zhtw.js

@@ -113,7 +113,7 @@ const zhtw = {
         log_into_another_account_anyway: '無論如何都要登入另一個帳號',
         log_into_another_account_anyway: '無論如何都要登入另一個帳號',
         log_out: '登出',
         log_out: '登出',
         move: '移動',
         move: '移動',
-        moving: "正在移動",
+        moving_file: "正在移動 %%",
         my_websites: "我的網站",
         my_websites: "我的網站",
         name: '名稱',
         name: '名稱',
         name_cannot_be_empty: '名稱不能為空。',
         name_cannot_be_empty: '名稱不能為空。',