From ee6fc26ffcd5f26cfb9f4bbbfd83332aa91219d5 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 13:34:52 -0300 Subject: [PATCH 01/12] implement drag and drop file upload --- navigator/navigator.css | 28 +++++ navigator/navigator.html | 5 +- navigator/navigator.js | 197 +++++++++++++++++++++++++++++++ navigator/scripts/write-chunk.py | 61 ++++++++++ 4 files changed, 290 insertions(+), 1 deletion(-) create mode 100755 navigator/scripts/write-chunk.py diff --git a/navigator/navigator.css b/navigator/navigator.css index 9c4465c..b6caaf2 100644 --- a/navigator/navigator.css +++ b/navigator/navigator.css @@ -207,6 +207,7 @@ input[type="text"] { align-items: flex-start; align-content: flex-start; overflow: auto; + position: relative; } .nav-item { @@ -486,3 +487,30 @@ input:checked + .slider:before { .nav-context-menu-item:hover { background-color: var(--border); } + +.drag-enter { + border: 1px dashed var(--border); +} + +.nav-notifications { + position: absolute; + bottom: 0; + right: 0; + padding: 5px; + display: flex; + flex-flow: column-reverse nowrap; +} + +.nav-notification { + z-index: 10; + flex-grow: 0; + padding: 5px; + background-color: var(--container); + border: 1px solid var(--border); + color: var(--font); +} + +.nav-notification-header { + font-size: 120%; + font-weight: bold; +} diff --git a/navigator/navigator.html b/navigator/navigator.html index 621db41..b5cd205 100644 --- a/navigator/navigator.html +++ b/navigator/navigator.html @@ -64,7 +64,10 @@
- +
- + 45Drives
From 815032456a1927ddc1ac39969c4219361cf4a810 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 13:53:19 -0300 Subject: [PATCH 03/12] style notification and rename write-chunk.py --- navigator/navigator.css | 18 +++++++++++++++++- navigator/navigator.js | 2 +- .../{write-chunk.py => write-chunks.py} | 0 3 files changed, 18 insertions(+), 2 deletions(-) rename navigator/scripts/{write-chunk.py => write-chunks.py} (100%) diff --git a/navigator/navigator.css b/navigator/navigator.css index b6caaf2..769a562 100644 --- a/navigator/navigator.css +++ b/navigator/navigator.css @@ -499,18 +499,34 @@ input:checked + .slider:before { padding: 5px; display: flex; flex-flow: column-reverse nowrap; + align-items: stretch; + max-height: 50%; + overflow-y: auto; } .nav-notification { + margin: 5px; + position: relative; + display: flex; + flex-flow: column nowrap; + align-items: stretch; z-index: 10; flex-grow: 0; padding: 5px; background-color: var(--container); - border: 1px solid var(--border); + border-radius: var(--nav-border-radius); color: var(--font); } .nav-notification-header { + position: relative; + z-index: 10; font-size: 120%; font-weight: bold; } + +.nav-notification-header > progress { + position: relative; + z-index: 10; +} + diff --git a/navigator/navigator.js b/navigator/navigator.js index 294da56..2ffd21a 100644 --- a/navigator/navigator.js +++ b/navigator/navigator.js @@ -894,7 +894,7 @@ class FileUpload { upload() { this.make_html_element(); - this.proc = cockpit.spawn(["/usr/share/cockpit/navigator/scripts/write-chunk.py", this.path], {err: "out", superuser: "try"}); + this.proc = cockpit.spawn(["/usr/share/cockpit/navigator/scripts/write-chunks.py", this.path], {err: "out", superuser: "try"}); this.proc.fail((e, data) => { window.alert(data); }) diff --git a/navigator/scripts/write-chunk.py b/navigator/scripts/write-chunks.py similarity index 100% rename from navigator/scripts/write-chunk.py rename to navigator/scripts/write-chunks.py From efd09793e88bb227c63a50638fb6e45b115e0bf4 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 14:00:13 -0300 Subject: [PATCH 04/12] skip upload of directories --- navigator/navigator.js | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/navigator/navigator.js b/navigator/navigator.js index 2ffd21a..55ac8fe 100644 --- a/navigator/navigator.js +++ b/navigator/navigator.js @@ -979,26 +979,20 @@ class NavDragDrop { for (let item of e.dataTransfer.items) { if (item.kind === 'file') { var file = item.getAsFile(); + if (file.type === "") { + window.alert(file.name + ": Cannot upload folders."); + continue; + } var uploader = new FileUpload(file, 4096, this.nav_window_ref); uploader.upload(); - // reader.onloadend = (function(file_, nav_window_ref) { - // return function(evt) { - // nav_window_ref.upload(evt, file_); - // }; - // })(file, this.nav_window_ref); - // reader.readAsArrayBuffer(file); } } } else { for (let file of ev.dataTransfer.files) { + if (file.type === "") + continue; var uploader = new FileUpload(file, 4096, this.nav_window_ref); uploader.upload(); - // reader.onloadend = (function(file_, nav_window_ref) { - // return function(evt) { - // nav_window_ref.upload(evt, file_); - // }; - // })(file, this.nav_window_ref); - // reader.readAsArrayBuffer(file); } } this.drop_area.classList.remove("drag-enter"); @@ -1562,27 +1556,6 @@ class NavWindow { } document.getElementById("pwd").disabled = false; } - - // /** - // * - // * @param {Event} event - // * @param {*} file - // */ - // async upload(event, file) { - // var bytes = new Uint8Array(event.target.result); - // console.log(bytes, file); - // var out_path = this.pwd().path_str() + "/" + file.name; - // var proc = cockpit.spawn(["dd", "of=" + out_path], {superuser: "try", err: "out"}); - // // for (let i = 0; i < bytes.byteLength; i++) { - // // proc.input(bytes[i], true); - // // } - // proc.input(bytes); - // proc.fail((e, data) => { - // window.alert(data); - // }); - // await proc; - // this.refresh(); - // } } let nav_window = new NavWindow(); From 73e4a09751de9c82ccc62eaa45ea8c61d1719b13 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 14:41:07 -0300 Subject: [PATCH 05/12] don't upload file if it already exists --- navigator/navigator.css | 1 - navigator/navigator.js | 18 ++++++++++++++++-- navigator/scripts/fail-if-exists.py | 26 ++++++++++++++++++++++++++ navigator/scripts/write-chunks.py | 2 +- 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100755 navigator/scripts/fail-if-exists.py diff --git a/navigator/navigator.css b/navigator/navigator.css index 769a562..5a8821c 100644 --- a/navigator/navigator.css +++ b/navigator/navigator.css @@ -521,7 +521,6 @@ input:checked + .slider:before { .nav-notification-header { position: relative; z-index: 10; - font-size: 120%; font-weight: bold; } diff --git a/navigator/navigator.js b/navigator/navigator.js index 55ac8fe..0201cfe 100644 --- a/navigator/navigator.js +++ b/navigator/navigator.js @@ -854,6 +854,14 @@ class FileUpload { this.chunk_index = 0; } + check_if_exists() { + return new Promise((resolve, reject) => { + var proc = cockpit.spawn(["/usr/share/cockpit/navigator/scripts/fail-if-exists.py", this.path], {superuser: "try"}); + proc.done((data) => {resolve(false)}); + proc.fail((e, data) => {resolve(true)}); + }); + } + make_html_element() { var notification = document.createElement("div"); notification.classList.add("nav-notification"); @@ -892,14 +900,20 @@ class FileUpload { return chunks; } - upload() { + async upload() { + if (await this.check_if_exists()) { + window.alert(this.filename + ": File exists."); + return; + } this.make_html_element(); this.proc = cockpit.spawn(["/usr/share/cockpit/navigator/scripts/write-chunks.py", this.path], {err: "out", superuser: "try"}); this.proc.fail((e, data) => { + this.reader.onload = () => {} + this.done(); window.alert(data); }) this.proc.done((data) => { - this.nav_window_ref.stop_load(); + }) this.reader.onload = (function(uploader_ref) { return async function(evt) { diff --git a/navigator/scripts/fail-if-exists.py b/navigator/scripts/fail-if-exists.py new file mode 100755 index 0000000..39cdcf6 --- /dev/null +++ b/navigator/scripts/fail-if-exists.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +""" + Cockpit Navigator - A File System Browser for Cockpit. + Copyright (C) 2021 Josh Boudreau + + This file is part of Cockpit Navigator. + Cockpit Navigator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Cockpit Navigator 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 General Public License for more details. + You should have received a copy of the GNU General Public License + along with Cockpit Navigator. If not, see . +""" + +import os +import sys + +if os.path.exists(sys.argv[1]): + sys.exit(1) + +sys.exit(0) diff --git a/navigator/scripts/write-chunks.py b/navigator/scripts/write-chunks.py index 6cde13d..79b7647 100755 --- a/navigator/scripts/write-chunks.py +++ b/navigator/scripts/write-chunks.py @@ -34,7 +34,7 @@ def main(): sys.exit(1) path = sys.argv[1] try: - file = open(path, "a+b") + file = open(path, "xb") except Exception as e: print(e) sys.exit(1) From 4bbd81105b898aebed4f3adc7ca166b9dc7d0aad Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 14:43:03 -0300 Subject: [PATCH 06/12] add synopsis to write-chunks --- navigator/scripts/write-chunks.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/navigator/scripts/write-chunks.py b/navigator/scripts/write-chunks.py index 79b7647..acec7e0 100755 --- a/navigator/scripts/write-chunks.py +++ b/navigator/scripts/write-chunks.py @@ -17,6 +17,15 @@ along with Cockpit Navigator. If not, see . """ +""" +Synopsis: `write-chunks.py ` +JSON objects are of form: +obj = { + seek: + chunk: +} +""" + import base64 import os import sys From 828748c9640c718edad4f6eb52ee6cea50400954 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 15:24:23 -0300 Subject: [PATCH 07/12] fix hiding divs and make hidden files transparent --- navigator/navigator.js | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/navigator/navigator.js b/navigator/navigator.js index 0201cfe..84e025c 100644 --- a/navigator/navigator.js +++ b/navigator/navigator.js @@ -164,6 +164,8 @@ class NavEntry { this.dom_element.addEventListener("click", this); this.dom_element.addEventListener("contextmenu", this); this.is_hidden_file = this.filename().startsWith('.'); + if (this.is_hidden_file) + icon.style.opacity = 0.5; this.dom_element.title = this.filename(); } @@ -760,14 +762,14 @@ class NavContextMenu { this.nav_window_ref.clip_board = [...this.nav_window_ref.selected_entries]; this.nav_window_ref.copy_or_move = "move"; this.nav_window_ref.paste_cwd = this.nav_window_ref.pwd().path_str(); - this.menu_options["paste"].hidden = false; + this.menu_options["paste"].style.display = "block"; } copy() { this.nav_window_ref.clip_board = [...this.nav_window_ref.selected_entries]; this.nav_window_ref.copy_or_move = "copy"; this.nav_window_ref.paste_cwd = this.nav_window_ref.pwd().path_str(); - this.menu_options["paste"].hidden = false; + this.menu_options["paste"].style.display = "block"; } paste() { @@ -809,18 +811,18 @@ class NavContextMenu { this.nav_window_ref.set_selected(target, false, false); } if (target === this.nav_window_ref.pwd()) { - this.menu_options["copy"].hidden = true; - this.menu_options["cut"].hidden = true; - this.menu_options["delete"].hidden = true; + this.menu_options["copy"].style.display = "none"; + this.menu_options["cut"].style.display = "none"; + this.menu_options["delete"].style.display = "none"; } else { - this.menu_options["copy"].hidden = false; - this.menu_options["cut"].hidden = false; - this.menu_options["delete"].hidden = false; + this.menu_options["copy"].style.display = "block"; + this.menu_options["cut"].style.display = "block"; + this.menu_options["delete"].style.display = "block"; } if (this.nav_window_ref.selected_entries.size > 1) { - this.menu_options["rename"].hidden = true; + this.menu_options["rename"].style.display = "none"; } else { - this.menu_options["rename"].hidden = false; + this.menu_options["rename"].style.display = "block"; } this.target = target; this.dom_element.style.display = "inline"; @@ -833,7 +835,7 @@ class NavContextMenu { } hide_paste() { - this.menu_options["paste"].hidden = true; + this.menu_options["paste"].style.display = "none"; } } @@ -1437,9 +1439,10 @@ class NavWindow { proc.fail((e, data) => { window.alert("Paste failed."); }); - await proc; - this.stop_load(); - this.refresh(); + proc.always(() => { + this.stop_load(); + this.refresh(); + }); } /** @@ -1489,7 +1492,7 @@ class NavWindow { } start_load() { - document.getElementById("nav-loader-container").hidden = false; + document.getElementById("nav-loader-container").style.display = "block"; var buttons = document.getElementsByTagName("button"); for (let button of buttons) { button.disabled = true; @@ -1497,7 +1500,7 @@ class NavWindow { } stop_load() { - document.getElementById("nav-loader-container").hidden = true; + document.getElementById("nav-loader-container").style.display = "none"; var buttons = document.getElementsByTagName("button"); for (let button of buttons) { button.disabled = false; From 68efafcd67cfa60a00d2022bc85fe550d7da6381 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 15:50:38 -0300 Subject: [PATCH 08/12] ctrl-A selects all --- navigator/navigator.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/navigator/navigator.js b/navigator/navigator.js index 84e025c..568e63f 100644 --- a/navigator/navigator.js +++ b/navigator/navigator.js @@ -1032,6 +1032,7 @@ class NavWindow { this.window = document.getElementById("nav-contents-view"); this.window.addEventListener("click", this); this.window.addEventListener("contextmenu", this); + window.addEventListener("keydown", this); this.last_selected_index = -1; this.context_menu = new NavContextMenu("nav-context-menu", this); @@ -1055,6 +1056,16 @@ class NavWindow { this.context_menu.show(e, this.pwd()); e.preventDefault(); break; + case "keydown": + if (e.keyCode === 46) { + this.delete_selected(); + } else if (e.keyCode === 65 && e.ctrlKey) { + this.select_all(); + e.preventDefault(); + } + break; + default: + break; } } @@ -1064,7 +1075,7 @@ class NavWindow { var num_dirs = 0; var num_files = 0; var bytes_sum = 0; - var show_hidden = document.getElementById("nav-show-hidden").checked; + this.show_hidden = document.getElementById("nav-show-hidden").checked; this.start_load(); var files = await this.pwd().get_children(this); while (this.entries.length) { @@ -1086,7 +1097,7 @@ class NavWindow { num_files++; bytes_sum += file.stat["size"]; } - if(!file.is_hidden_file || show_hidden) + if(!file.is_hidden_file || this.show_hidden) file.show(); this.entries.push(file); file.context_menu_ref = this.context_menu; @@ -1573,6 +1584,14 @@ class NavWindow { } document.getElementById("pwd").disabled = false; } + + select_all() { + for (let entry of this.entries) { + if (!entry.is_hidden_file || this.show_hidden) { + this.set_selected(entry, false, true); + } + } + } } let nav_window = new NavWindow(); From c3252e88d1b6f7f86634546d4ca8d8282c0ff708 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 16:00:05 -0300 Subject: [PATCH 09/12] ctrl-x, ctrl-c, ctrl-v for cut, copy, paste --- navigator/navigator.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/navigator/navigator.js b/navigator/navigator.js index 568e63f..0e5868d 100644 --- a/navigator/navigator.js +++ b/navigator/navigator.js @@ -1062,6 +1062,12 @@ class NavWindow { } else if (e.keyCode === 65 && e.ctrlKey) { this.select_all(); e.preventDefault(); + } else if (e.keyCode === 67 && e.ctrlKey) { + this.context_menu.copy(); + } else if (e.keyCode === 86 && e.ctrlKey) { + this.context_menu.paste(); + } else if (e.keyCode === 88 && e.ctrlKey) { + this.context_menu.cut(); } break; default: From 1615bcd922b47796563623a64414192ca7d2f83f Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 16:16:30 -0300 Subject: [PATCH 10/12] move cut copy and paste functions to NavWindow --- navigator/navigator.js | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/navigator/navigator.js b/navigator/navigator.js index 0e5868d..9f24f92 100644 --- a/navigator/navigator.js +++ b/navigator/navigator.js @@ -759,22 +759,15 @@ class NavContextMenu { } cut() { - this.nav_window_ref.clip_board = [...this.nav_window_ref.selected_entries]; - this.nav_window_ref.copy_or_move = "move"; - this.nav_window_ref.paste_cwd = this.nav_window_ref.pwd().path_str(); - this.menu_options["paste"].style.display = "block"; + this.nav_window_ref.cut(); } copy() { - this.nav_window_ref.clip_board = [...this.nav_window_ref.selected_entries]; - this.nav_window_ref.copy_or_move = "copy"; - this.nav_window_ref.paste_cwd = this.nav_window_ref.pwd().path_str(); - this.menu_options["paste"].style.display = "block"; + this.nav_window_ref.copy(); } paste() { - this.nav_window_ref.paste_clipboard(); - this.hide_paste(); + this.nav_window_ref.paste(); } rename() { @@ -1063,11 +1056,11 @@ class NavWindow { this.select_all(); e.preventDefault(); } else if (e.keyCode === 67 && e.ctrlKey) { - this.context_menu.copy(); + this.copy(); } else if (e.keyCode === 86 && e.ctrlKey) { - this.context_menu.paste(); + this.paste(); } else if (e.keyCode === 88 && e.ctrlKey) { - this.context_menu.cut(); + this.cut(); } break; default: @@ -1427,6 +1420,25 @@ class NavWindow { this.refresh(); } + cut() { + this.clip_board = [...this.selected_entries]; + this.copy_or_move = "move"; + this.paste_cwd = this.pwd().path_str(); + this.context_menu.menu_options["paste"].style.display = "block"; + } + + copy() { + this.clip_board = [...this.selected_entries]; + this.copy_or_move = "copy"; + this.paste_cwd = this.pwd().path_str(); + this.context_menu.menu_options["paste"].style.display = "block"; + } + + paste() { + this.paste_clipboard(); + this.context_menu.hide_paste(); + } + async paste_clipboard() { this.start_load(); this.context_menu.hide_paste(); From ed308477567c0214652f6f1aeff7293aa5e02b8c Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 16:33:26 -0300 Subject: [PATCH 11/12] update changelog --- debian/changelog | 8 ++++++++ el/cockpit-navigator.spec | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 30442a2..a91c7c9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +cockpit-navigator (0.3.0-1focal) focal; urgency=medium + + * Add drag and drop uploading of files. + * Add event listeners for ctrl+a to select all, ctrl+x to cut, + ctrl+c to copy, ctrl+v to paste, and delete to remove a file. + + -- Josh Boudreau Thu, 03 Jun 2021 16:33:00 -0300 + cockpit-navigator (0.2.3-1focal) focal; urgency=medium * Fix closing contextmenu in el7. diff --git a/el/cockpit-navigator.spec b/el/cockpit-navigator.spec index 6a67c1f..45496f4 100644 --- a/el/cockpit-navigator.spec +++ b/el/cockpit-navigator.spec @@ -1,5 +1,5 @@ Name: cockpit-navigator -Version: 0.2.3 +Version: 0.3.0 Release: 1%{?dist} Summary: A File System Browser for Cockpit. License: GPL-3.0+ @@ -32,6 +32,10 @@ rm -rf %{buildroot} /usr/share/cockpit/navigator/* %changelog +* Thu Jun 03 2021 Josh Boudreau 0.3.0-1 +- Add drag and drop uploading of files. +- Add event listeners for ctrl+a to select all, ctrl+x to cut, + ctrl+c to copy, ctrl+v to paste, and delete to remove a file. * Wed Jun 02 2021 Josh Boudreau 0.2.3-1 - Fix closing contextmenu in el7. - Hide rename in right click menu with multiple selected entries. From b6332baa359b19d45d36194715edeb24aad4cd85 Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Thu, 3 Jun 2021 16:34:25 -0300 Subject: [PATCH 12/12] update install URLs --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2ba392d..8bbe15a 100644 --- a/README.md +++ b/README.md @@ -19,17 +19,17 @@ With no command line use needed, you can: # Installation ## From Github Release ### Ubuntu -1. `$ wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.2.3/cockpit-navigator_0.2.3-1focal_all.deb` -1. `# apt install ./cockpit-navigator_0.2.3-1focal_all.deb` +1. `$ wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.3.0/cockpit-navigator_0.3.0-1focal_all.deb` +1. `# apt install ./cockpit-navigator_0.3.0-1focal_all.deb` ### EL7 -1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.2.3/cockpit-navigator-0.2.3-1.el7.noarch.rpm` +1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.3.0/cockpit-navigator-0.3.0-1.el7.noarch.rpm` ### EL8 -1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.2.3/cockpit-navigator-0.2.3-1.el8.noarch.rpm` +1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.3.0/cockpit-navigator-0.3.0-1.el8.noarch.rpm` ## From Source 1. Ensure dependencies are installed: `cockpit`, `python3`, `rsync`. 1. `$ git clone https://github.com/45Drives/cockpit-navigator.git` 1. `$ cd cockpit-navigator` -1. `$ git checkout ` (v0.2.3 is latest) +1. `$ git checkout ` (v0.3.0 is latest) 1. `# make install` ## From 45Drives Repositories ### Ubuntu