Merge pull request #15 from 45Drives/dev-josh
Implement list view and fix opening symlinks to files for editing
This commit is contained in:
commit
eb50adbad4
|
@ -22,12 +22,12 @@ With no command line use needed, you can:
|
|||
# Installation
|
||||
## From Github Release
|
||||
### Ubuntu
|
||||
1. `$ wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator_0.4.1-1focal_all.deb`
|
||||
1. `# apt install ./cockpit-navigator_0.4.1-1focal_all.deb`
|
||||
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`
|
||||
### EL7
|
||||
1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.1-1.el7.noarch.rpm`
|
||||
1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.2-1.el7.noarch.rpm`
|
||||
### EL8
|
||||
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.1-1.el8.noarch.rpm`
|
||||
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.4/cockpit-navigator-0.4.2-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`
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
cockpit-navigator (0.4.2-1focal) focal; urgency=low
|
||||
|
||||
* Implement list view.
|
||||
* Fix opening symlinks to files for editing.
|
||||
|
||||
-- Josh Boudreau <jboudreau@45drives.com> Mon, 07 Jun 2021 17:27:00 -0300
|
||||
|
||||
cockpit-navigator (0.4.1-1focal) focal; urgency=low
|
||||
|
||||
* Use smaller chunk size while uploading for older versions of Cockpit.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: cockpit-navigator
|
||||
Version: 0.4.1
|
||||
Version: 0.4.2
|
||||
Release: 1%{?dist}
|
||||
Summary: A File System Browser for Cockpit.
|
||||
License: GPL-3.0+
|
||||
|
@ -32,6 +32,9 @@ rm -rf %{buildroot}
|
|||
/usr/share/cockpit/navigator/*
|
||||
|
||||
%changelog
|
||||
* Mon Jun 07 2021 Josh Boudreau <jboudreau@45drives.com> 0.4.2-1
|
||||
- Implement list view.
|
||||
- Fix opening symlinks to files for editing.
|
||||
* Mon Jun 07 2021 Josh Boudreau <jboudreau@45drives.com> 0.4.1-1
|
||||
- Use smaller chunk size while uploading for older versions of Cockpit.
|
||||
* Mon Jun 07 2021 Josh Boudreau <jboudreau@45drives.com> 0.4.0-1
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
--border: #bebebe;
|
||||
--navigation: #fff;
|
||||
--font: #1c1c1c;
|
||||
--selected: #f8f8f8;
|
||||
--selected: #eeeeee;
|
||||
--toggle-light: #151515;
|
||||
--toggle-dark: #ccc;
|
||||
--scrollbar-thumb: var(--border);
|
||||
|
@ -34,6 +34,7 @@
|
|||
--nav-entry-color: #555F6E;
|
||||
--nav-border-radius: 4px;
|
||||
--symlink-symbol-color: var(--navigation);
|
||||
--list-view-header: var(--selected);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
|
@ -51,6 +52,7 @@
|
|||
--logo-45: #fff;
|
||||
--nav-entry-color: #555F6E;
|
||||
--symlink-symbol-color: var(--navigation);
|
||||
--list-view-header: var(--container);
|
||||
}
|
||||
|
||||
html {
|
||||
|
@ -200,17 +202,25 @@ input[type="text"] {
|
|||
background-color: var(--navigation);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--nav-border-radius);
|
||||
padding: 0.5em;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-content: flex-start;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
.contents-view-grid {
|
||||
flex-flow: row wrap;
|
||||
align-items: flex-start;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.contents-view-list {
|
||||
flex-flow: column nowrap;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.contents-view-grid > .nav-item {
|
||||
margin: 2px;
|
||||
padding: 3px;
|
||||
flex: 0;
|
||||
|
@ -221,20 +231,12 @@ input[type="text"] {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.nav-item-selected {
|
||||
background-color: var(--selected);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--nav-border-radius);
|
||||
box-sizing: border-box;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.nav-item .nav-item-title {
|
||||
.contents-view-grid > .nav-item > .nav-item-title {
|
||||
text-align: center;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.nav-item .nav-item-icon {
|
||||
.contents-view-grid > .nav-item > .nav-item-icon {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
|
@ -242,22 +244,103 @@ input[type="text"] {
|
|||
color: var(--nav-entry-color);
|
||||
}
|
||||
|
||||
.nav-item-symlink-symbol-dir {
|
||||
.contents-view-grid > .nav-item-selected {
|
||||
background-color: var(--selected);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--nav-border-radius);
|
||||
box-sizing: border-box;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.contents-view-grid > .nav-item > .nav-item-icon > .nav-item-symlink-symbol-dir {
|
||||
position: absolute;
|
||||
color: var(--symlink-symbol-color);
|
||||
font-size: 12pt;
|
||||
font-size: 20%;
|
||||
bottom: 19%;
|
||||
right: 15%;
|
||||
}
|
||||
|
||||
.nav-item-symlink-symbol-file {
|
||||
.contents-view-grid > .nav-item > .nav-item-icon > .nav-item-symlink-symbol-file {
|
||||
position: absolute;
|
||||
color: var(--symlink-symbol-color);
|
||||
font-size: 12pt;
|
||||
font-size: 20%;
|
||||
bottom: 6%;
|
||||
right: 25%;
|
||||
}
|
||||
|
||||
.contents-view-grid > .contents-view-list-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.contents-view-list-header {
|
||||
background-color: var(--list-view-header);
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item {
|
||||
padding: 3px;
|
||||
flex: 0;
|
||||
display: flex;
|
||||
flex: row nowrap;
|
||||
align-items: baseline;
|
||||
justify-content: flex-start;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item:nth-child(even) {
|
||||
background-color: var(--selected);
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item > .nav-item-title {
|
||||
margin-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item > .nav-item-icon {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
color: var(--nav-entry-color);
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item-selected {
|
||||
background-color: var(--selected);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--nav-border-radius);
|
||||
box-sizing: border-box;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item > .nav-item-icon > .nav-item-symlink-symbol-dir {
|
||||
position: absolute;
|
||||
color: var(--symlink-symbol-color);
|
||||
font-size: 40%;
|
||||
bottom: 19%;
|
||||
right: 15%;
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item > .nav-item-icon > .nav-item-symlink-symbol-file {
|
||||
position: absolute;
|
||||
color: var(--symlink-symbol-color);
|
||||
font-size: 40%;
|
||||
bottom: 6%;
|
||||
right: 25%;
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item > div {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.contents-view-list > .nav-item > div:first-of-type {
|
||||
flex-basis: 0;
|
||||
flex-grow: 2;
|
||||
}
|
||||
|
||||
.nav-info-column {
|
||||
background-color: var(--container);
|
||||
flex-basis: 0;
|
||||
|
@ -471,6 +554,10 @@ input:checked + .slider:before {
|
|||
left: -30%;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-context-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
|
|
|
@ -64,7 +64,15 @@
|
|||
</div>
|
||||
<div class="vertical-spacer"></div>
|
||||
<div class="flex-row inner-container">
|
||||
<div class="contents-view" id="nav-contents-view">
|
||||
<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>
|
||||
<div class="nav-notifications" id="nav-notifications">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -157,6 +165,10 @@
|
|||
<img src="branding/logo-light.svg" id="logo-45d"><span class="logo-45">45</span><span class="logo-drives">Drives</span>
|
||||
</a>
|
||||
<div class="flex-grow"></div>
|
||||
<div id="nav-item-display-btn" class="clickable">
|
||||
<i class="fas fa-list" id="nav-item-display-icon"></i>
|
||||
</div>
|
||||
<div class="horizontal-spacer"></div>
|
||||
<div class="nav-toggle">
|
||||
<div class="nav-btn-group">
|
||||
<i class="fas fa-low-vision" id="nav-show-hidden-icon"></i>
|
||||
|
|
|
@ -111,6 +111,18 @@ function load_hidden_file_state(nav_window) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {NavWindow} nav_window
|
||||
*/
|
||||
function load_item_display_state(nav_window) {
|
||||
const state = localStorage.getItem('item-display');
|
||||
|
||||
if (state === 'list') {
|
||||
nav_window.switch_item_display();
|
||||
}
|
||||
}
|
||||
|
||||
function set_last_theme_state() {
|
||||
var toggle_switch = document.getElementById("toggle-theme");
|
||||
var state = localStorage.getItem("houston-theme-state");
|
||||
|
@ -226,6 +238,20 @@ class NavEntry {
|
|||
if (this.is_hidden_file)
|
||||
icon.style.opacity = 0.5;
|
||||
this.dom_element.title = this.filename();
|
||||
if (nav_window_ref && nav_window_ref.item_display === "list") {
|
||||
let mode = document.createElement("div");
|
||||
let owner = document.createElement("div");
|
||||
let group = document.createElement("div");
|
||||
let size = document.createElement("div");
|
||||
mode.title = mode.innerText = this.stat["mode-str"];
|
||||
owner.title = owner.innerText = this.stat["owner"];
|
||||
group.title = group.innerText = this.stat["group"];
|
||||
size.title = size.innerText = format_bytes(this.stat["size"]);
|
||||
this.dom_element.appendChild(mode);
|
||||
this.dom_element.appendChild(owner);
|
||||
this.dom_element.appendChild(group);
|
||||
this.dom_element.appendChild(size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -550,6 +576,8 @@ class NavFileLink extends NavFile{
|
|||
this.double_click = false;
|
||||
this.link_target = link_target;
|
||||
this.dom_element.nav_item_title.style.fontStyle = "italic";
|
||||
if (nav_window_ref.item_display === "list")
|
||||
this.dom_element.nav_item_title.innerHTML += " → " + this.link_target;
|
||||
}
|
||||
|
||||
show_properties() {
|
||||
|
@ -572,22 +600,27 @@ class NavFileLink extends NavFile{
|
|||
return target;
|
||||
}
|
||||
|
||||
async open() {
|
||||
var target_path = this.get_link_target_path();
|
||||
var proc_output = await cockpit.spawn(["file", "--mime-type", target_path], {superuser: "try"});
|
||||
var fields = proc_output.split(/:(?=[^:]+$)/); // ensure it's the last : with lookahead
|
||||
var type = fields[1].trim();
|
||||
|
||||
if ((/^text/.test(type) || /^inode\/x-empty$/.test(type) || this.stat["size"] === 0)) {
|
||||
this.show_edit_file_contents();
|
||||
} else {
|
||||
console.log("Unknown mimetype: " + type);
|
||||
window.alert("Can't open " + this.filename() + " for editing.");
|
||||
}
|
||||
}
|
||||
|
||||
async show_edit_file_contents() {
|
||||
this.nav_window_ref.disable_buttons_for_editing();
|
||||
document.getElementById("pwd").disabled = true;
|
||||
var target_path = this.get_link_target_path();
|
||||
var proc_output = await cockpit.spawn(["file", "--mime-type", target_path], {superuser: "try"});
|
||||
var fields = proc_output.split(':');
|
||||
var type = fields[1].trim();
|
||||
if (!(/^text/.test(type) || /^inode\/x-empty$/.test(type) || this.stat["size"] === 0)) {
|
||||
if (!window.confirm("File is of type `" + type + "`. Are you sure you want to edit it?")) {
|
||||
this.nav_window_ref.enable_buttons();
|
||||
return;
|
||||
}
|
||||
}
|
||||
var contents = "";
|
||||
try {
|
||||
contents = await cockpit.file(this.path_str(), {superuser: "try"}).read();
|
||||
contents = await cockpit.file(target_path, {superuser: "try"}).read();
|
||||
} catch(e) {
|
||||
this.nav_window_ref.enable_buttons();
|
||||
window.alert(e.message);
|
||||
|
@ -825,6 +858,8 @@ class NavDirLink extends NavDir{
|
|||
this.double_click = false;
|
||||
this.link_target = link_target;
|
||||
this.dom_element.nav_item_title.style.fontStyle = "italic";
|
||||
if (nav_window_ref.item_display === "list")
|
||||
this.dom_element.nav_item_title.innerHTML += " → " + this.link_target;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1259,6 +1294,7 @@ class NavDragDrop {
|
|||
|
||||
class NavWindow {
|
||||
constructor() {
|
||||
this.item_display = "grid";
|
||||
this.path_stack = (localStorage.getItem('navigator-path') ?? '/').split('/');
|
||||
this.path_stack = this.path_stack.map((_, index) => new NavDir([...this.path_stack.slice(0, index + 1)].filter(part => part != ''), this));
|
||||
|
||||
|
@ -1942,6 +1978,27 @@ class NavWindow {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
async switch_item_display() {
|
||||
var button = document.getElementById("nav-item-display-icon");
|
||||
if (this.item_display === "grid") {
|
||||
this.item_display = "list";
|
||||
await this.refresh();
|
||||
this.window.classList.remove("contents-view-grid");
|
||||
this.window.classList.add("contents-view-list");
|
||||
button.classList.remove("fa-list");
|
||||
button.classList.add("fa-th");
|
||||
} else {
|
||||
this.item_display = "grid";
|
||||
await this.refresh();
|
||||
this.window.classList.remove("contents-view-list");
|
||||
this.window.classList.add("contents-view-grid");
|
||||
button.classList.remove("fa-th");
|
||||
button.classList.add("fa-list");
|
||||
}
|
||||
|
||||
localStorage.setItem("item-display", this.item_display);
|
||||
}
|
||||
}
|
||||
|
||||
let nav_window = new NavWindow();
|
||||
|
@ -1967,11 +2024,13 @@ function set_up_buttons() {
|
|||
document.getElementById("pwd").addEventListener("keydown", nav_window.nav_bar_event_handler.bind(nav_window));
|
||||
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));
|
||||
}
|
||||
|
||||
async function main() {
|
||||
set_last_theme_state();
|
||||
load_hidden_file_state(nav_window);
|
||||
load_item_display_state(nav_window);
|
||||
var get_users = nav_window.get_system_users();
|
||||
var get_groups = nav_window.get_system_groups();
|
||||
var refresh = nav_window.refresh();
|
||||
|
|
Loading…
Reference in New Issue