Merge pull request #16 from 45Drives/dev-josh

changes for v0.4.3
This commit is contained in:
Josh Boudreau 2021-06-08 16:30:45 -03:00 committed by GitHub
commit 4e157887ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 199 additions and 26 deletions

View File

@ -12,22 +12,23 @@ With no command line use needed, you can:
* **Upload files by dragging and dropping**,
* **Download files and directories**.
### Browsing Filesystem
![User Interface](doc/ui_root.png)
### Editing Properties
![Edit Preferences](doc/ui_prefs.png)
### Editing Content
![Edit Contents](doc/ui_editor.png)
| Browsing Filesystem |
|---------------------|
| ![User Interface](doc/ui_root.png) |
| Editing Content | Editing Properties |
|-----------------|--------------------|
| ![Edit Contents](doc/ui_editor.png) | ![Edit Preferences](doc/ui_prefs.png) |
# Installation
## From Github Release
### Ubuntu
1. `$ wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator_0.4.2-1focal_all.deb`
1. `# apt install ./cockpit-navigator_0.4.2-1focal_all.deb`
1. `$ wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator_0.4.3-1focal_all.deb`
1. `# apt install ./cockpit-navigator_0.4.3-1focal_all.deb`
### EL7
1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.2-1.el7.noarch.rpm`
1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.3-1.el7.noarch.rpm`
### EL8
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.2-1.el8.noarch.rpm`
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.3-1.el8.noarch.rpm`
## From Source
1. Ensure dependencies are installed: `cockpit`, `python3`, `rsync`, `zip`.
1. `$ git clone https://github.com/45Drives/cockpit-navigator.git`

9
debian/changelog vendored
View File

@ -1,3 +1,12 @@
cockpit-navigator (0.4.3-1focal) focal; urgency=medium
* Add sort options for list view.
* Add search bar to filter items.
* Fix file size error after upload by refreshing after write process exits.
* Fix input of tab characters and copy and pasting in file editor.
-- Josh Boudreau <jboudreau@45drives.com> Tue, 08 Jun 2021 15:11:00 -0300
cockpit-navigator (0.4.2-1focal) focal; urgency=low
* Implement list view.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 148 KiB

View File

@ -1,5 +1,5 @@
Name: cockpit-navigator
Version: 0.4.2
Version: 0.4.3
Release: 1%{?dist}
Summary: A File System Browser for Cockpit.
License: GPL-3.0+
@ -32,6 +32,11 @@ rm -rf %{buildroot}
/usr/share/cockpit/navigator/*
%changelog
* Tue Jun 08 2021 Josh Boudreau <jboudreau@45drives.com> 0.4.3-1
- Add sort options for list view.
- Add search bar to filter items.
- Fix file size error after upload by refreshing after write process exits.
- Fix input of tab characters and copy and pasting in file editor.
* Mon Jun 07 2021 Josh Boudreau <jboudreau@45drives.com> 0.4.2-1
- Implement list view.
- Fix opening symlinks to files for editing.

View File

@ -180,13 +180,33 @@ body::-webkit-scrollbar-thumb {
padding-bottom: 0;
}
.nav-header {
align-items: baseline;
}
input[type="text"] {
background-color: var(--container);
color: inherit;
flex-grow: 1;
padding: 0.25em 1em 0.25em 1em;
border: 1px solid var(--border);
border-radius: 4px;
min-width: 30px;
}
.navigation-bar {
flex-basis: 0;
flex-grow: 5;
}
.search-bar {
flex-basis: 0;
flex-grow: 2;
}
.search-bar + i {
position: relative;
right: 30px;
width: 0;
}
.inner-container {
@ -275,6 +295,20 @@ input[type="text"] {
.contents-view-list-header {
background-color: var(--list-view-header);
cursor: default !important;
position: sticky;
top: 0;
z-index: 10;
}
.contents-view-list-header > div {
cursor: pointer;
position: relative;
}
.contents-view-list-header > div > i {
position: absolute;
right: 10px;
top: 0.25em;
}
.contents-view-list > .nav-item {

View File

@ -37,7 +37,7 @@
</div>
</div>
<div class="flex-col outer-container">
<div class="flex-row">
<div class="flex-row nav-header">
<div class="nav-btn-group">
<button class="pf-c-button pf-m-secondary" id="nav-back-btn" title="Back"><i class="fas fa-arrow-left"></i></button>
<div class="horizontal-spacer"></div>
@ -54,6 +54,9 @@
</select>
</datalist>
<div class="horizontal-spacer"></div>
<input type="text" autocomplete="off" class="search-bar" id="search-bar" title="Search in Directory" placeholder="Search in Directory"></input>
<i class="fas fa-search"></i>
<div class="horizontal-spacer"></div>
<div class="nav-btn-group">
<button class="pf-c-button pf-m-primary" id="nav-mkdir-btn" title="New Directory"><i class="fas fa-folder-plus"></i></button>
<div class="horizontal-spacer"></div>
@ -67,11 +70,11 @@
<div class="contents-view contents-view-grid" id="nav-contents-view">
<div class="contents-view-list-header nav-item">
<i class="nav-item-icon"></i>
<div class="nav-item-title">Name</div>
<div>Mode</div>
<div>Owner</div>
<div>Group</div>
<div>Size</div>
<div class="nav-item-title" id="sort-name-btn">Name<i class="sort-arrow fas fa-chevron-up" id="sort-name-icon"></i></div>
<div id="sort-mode-btn">Mode</div>
<div id="sort-owner-btn">Owner<i class="sort-arrow fas" id="sort-owner-icon"></i></div>
<div id="sort-group-btn">Group<i class="sort-arrow fas" id="sort-group-icon"></i></div>
<div id="sort-size-btn">Size<i class="sort-arrow fas" id="sort-size-icon"></i></div>
</div>
<div class="nav-notifications" id="nav-notifications">
</div>

View File

@ -309,7 +309,11 @@ class NavEntry {
}
show() {
document.getElementById("nav-contents-view").appendChild(this.dom_element);
this.dom_element.style.display = "flex";
}
hide() {
this.dom_element.style.display = "none";
}
/**
@ -522,6 +526,7 @@ class NavFile extends NavEntry {
}
async show_edit_file_contents() {
window.removeEventListener("keydown", this.nav_window_ref);
this.nav_window_ref.disable_buttons_for_editing();
var contents = "";
try {
@ -544,7 +549,10 @@ class NavFile extends NavEntry {
async write_to_file() {
var new_contents = document.getElementById("nav-edit-contents-textarea").value;
try {
await cockpit.file(this.path_str(), {superuser: "try"}).replace(new_contents); // cockpit.script("echo -n \"$1\" > $2", [new_contents, this.path_str()], {superuser: "try"});
if (new_contents.length)
await cockpit.file(this.path_str(), {superuser: "try"}).replace(new_contents);
else
await cockpit.script("echo -n > $1", [this.path_str()], {superuser: "try"});
} catch (e) {
window.alert(e.message);
}
@ -553,6 +561,7 @@ class NavFile extends NavEntry {
}
hide_edit_file_contents() {
window.addEventListener("keydown", this.nav_window_ref);
document.getElementById("nav-edit-contents-textarea").removeEventListener("keydown", this);
document.getElementById("nav-edit-contents-view").style.display = "none";
document.getElementById("nav-contents-view").style.display = "flex";
@ -615,6 +624,7 @@ class NavFileLink extends NavFile{
}
async show_edit_file_contents() {
window.removeEventListener("keydown", this.nav_window_ref);
this.nav_window_ref.disable_buttons_for_editing();
document.getElementById("pwd").disabled = true;
var target_path = this.get_link_target_path();
@ -1172,7 +1182,7 @@ class FileUpload {
window.alert(data);
})
this.proc.done((data) => {
this.nav_window_ref.refresh();
})
this.reader.onload = (function(uploader_ref) {
return async function(evt) {
@ -1216,7 +1226,6 @@ class FileUpload {
done() {
this.proc.input(); // close stdin
this.nav_window_ref.refresh();
this.remove_html_element();
}
@ -1292,6 +1301,81 @@ class NavDragDrop {
}
}
class SortFunctions {
constructor() {
this.orders = {
name: "asc",
owner: "asc",
group: "asc",
size: "asc",
}
this.icons = {};
for (let option of ["name", "owner", "group", "size"]) {
this.icons[option] = document.getElementById(`sort-${option}-icon`);
}
this.current_choice = "name";
}
get_func() {
return this[`${this.current_choice}_${this.orders[this.current_choice]}`];
}
set_func(option) {
if (this.current_choice === option) {
if (this.orders[this.current_choice] === "asc") {
this.orders[this.current_choice] = "desc";
this.icons[this.current_choice].classList.remove("fa-chevron-up");
this.icons[this.current_choice].classList.add("fa-chevron-down");
} else {
this.orders[this.current_choice] = "asc";
this.icons[this.current_choice].classList.remove("fa-chevron-down");
this.icons[this.current_choice].classList.add("fa-chevron-up");
}
} else {
this.icons[this.current_choice].classList.remove("fa-chevron-up", "fa-chevron-down");
this.current_choice = option;
if (this.orders[this.current_choice] === "asc") {
this.icons[this.current_choice].classList.add("fa-chevron-up");
} else {
this.icons[this.current_choice].classList.add("fa-chevron-down");
}
}
}
name_asc(first, second) {
return first.filename().localeCompare(second.filename());
}
name_desc(first, second) {
return second.filename().localeCompare(first.filename());
}
owner_asc(first, second) {
return first.stat["owner"].localeCompare(second.stat["owner"]);
}
owner_desc(first, second) {
return second.stat["owner"].localeCompare(first.stat["owner"]);
}
group_asc(first, second) {
return first.stat["group"].localeCompare(second.stat["group"]);
}
group_desc(first, second) {
return second.stat["group"].localeCompare(first.stat["group"]);
}
size_asc(first, second) {
return first.stat["size"] - second.stat["size"];
}
size_desc(first, second) {
return second.stat["size"] - first.stat["size"];
}
}
class NavWindow {
constructor() {
this.item_display = "grid";
@ -1312,6 +1396,8 @@ class NavWindow {
this.clip_board = [];
this.uploader = new NavDragDrop(this.window, this);
this.sort_function = new SortFunctions();
}
/**
@ -1368,7 +1454,9 @@ class NavWindow {
}
files.sort((first, second) => {
if (first.nav_type === second.nav_type) {
return first.filename().localeCompare(second.filename());
return this.item_display === "list"
? this.sort_function.get_func()(first, second)
: this.sort_function.name_asc(first, second); // default to sort by name in grid view
}
if (first.nav_type === "dir")
return -1;
@ -1381,9 +1469,10 @@ class NavWindow {
num_files++;
bytes_sum += file.stat["size"];
}
if(!file.is_hidden_file || this.show_hidden)
file.show();
this.entries.push(file);
if(!file.is_hidden_file || this.show_hidden) {
this.window.appendChild(file.dom_element);
this.entries.push(file);
}
file.context_menu_ref = this.context_menu;
});
document.getElementById("pwd").value = this.pwd().path_str();
@ -1999,6 +2088,16 @@ class NavWindow {
localStorage.setItem("item-display", this.item_display);
}
search_filter(event) {
var search_name = event.target.value;
this.entries.forEach((entry) => {
if (entry.filename().toLowerCase().startsWith(search_name.toLowerCase()))
entry.show();
else
entry.hide();
});
}
}
let nav_window = new NavWindow();
@ -2025,6 +2124,28 @@ function set_up_buttons() {
document.getElementById("toggle-theme").addEventListener("change", switch_theme, false);
document.getElementById("nav-show-hidden").addEventListener("change", nav_window.toggle_show_hidden.bind(nav_window));
document.getElementById("nav-item-display-btn").addEventListener("click", nav_window.switch_item_display.bind(nav_window));
for (let option of ["name", "owner", "group", "size"]) {
var elem = document.getElementById("sort-" + option + "-btn");
elem.addEventListener("click", (event) => {
nav_window.sort_function.set_func(option);
nav_window.refresh();
});
}
document.getElementById("search-bar").addEventListener("input", nav_window.search_filter.bind(nav_window));
document.getElementById("search-bar").addEventListener("keydown", (e) => {
if (e.keyCode === 13)
nav_window.search_filter(e);
});
// fix tab in editor input
document.getElementById('nav-edit-contents-textarea').addEventListener('keydown', (e) => {
if (e.key == 'Tab') {
e.preventDefault();
var start = e.target.selectionStart;
var end = e.target.selectionEnd;
e.target.value = `${e.target.value.substring(0, start)}\t${e.target.value.substring(end)}`;
e.target.selectionStart = e.target.selectionEnd = start + 1;
}
});
}
async function main() {