mirror of
https://github.com/45Drives/cockpit-navigator.git
synced 2025-07-27 07:34:37 +02:00
Show file type icons with the option to disable
This commit is contained in:
parent
344c2d1468
commit
da920db018
@ -30,7 +30,7 @@ With no command line use needed, you can:
|
|||||||
### EL8
|
### EL8
|
||||||
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.5.8/cockpit-navigator-0.5.8-1.el8.noarch.rpm`
|
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.5.8/cockpit-navigator-0.5.8-1.el8.noarch.rpm`
|
||||||
## From Source
|
## From Source
|
||||||
1. Ensure dependencies are installed: `cockpit`, `python3`, `rsync`, `zip`.
|
1. Ensure dependencies are installed: `cockpit`, `python3`, `python3-magic`, `zip`.
|
||||||
1. `$ git clone https://github.com/45Drives/cockpit-navigator.git`
|
1. `$ git clone https://github.com/45Drives/cockpit-navigator.git`
|
||||||
1. `$ cd cockpit-navigator`
|
1. `$ cd cockpit-navigator`
|
||||||
1. `$ git checkout <version>` (v0.5.8 is latest)
|
1. `$ git checkout <version>` (v0.5.8 is latest)
|
||||||
|
@ -25,13 +25,13 @@
|
|||||||
"deb": [
|
"deb": [
|
||||||
"cockpit",
|
"cockpit",
|
||||||
"python3",
|
"python3",
|
||||||
"rsync",
|
"python3-magic",
|
||||||
"zip"
|
"zip"
|
||||||
],
|
],
|
||||||
"el": [
|
"el": [
|
||||||
"cockpit",
|
"cockpit",
|
||||||
"python3",
|
"python3",
|
||||||
"rsync",
|
"python3-magic",
|
||||||
"zip"
|
"zip"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -57,11 +57,12 @@
|
|||||||
"version": "0.5.9",
|
"version": "0.5.9",
|
||||||
"buildVersion": "1",
|
"buildVersion": "1",
|
||||||
"ignore": [],
|
"ignore": [],
|
||||||
"date": "2021-12-15T17:43:15.251513",
|
"date": "2021-12-16T14:46:53.434779",
|
||||||
"packager": "Joshua Boudreau <jboudreau@45drives.com>",
|
"packager": "Joshua Boudreau <jboudreau@45drives.com>",
|
||||||
"changes": [
|
"changes": [
|
||||||
"Disallow downloading files of size 0 to avoid Cockpit bug where fsread never returns.",
|
"Disallow downloading files of size 0 to avoid Cockpit bug where fsread never returns.",
|
||||||
"Overhaul copying/moving to use built in python functions instead of rsync, making moving large files within the same fs instant."
|
"Overhaul copying/moving to use built in python functions instead of rsync, making moving large files within the same fs instant.",
|
||||||
|
"Add descriptive icons using mimetype with the option to disable."
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -62,16 +62,21 @@ export class NavDir extends NavEntry {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {NavWindow} nav_window_ref
|
* @param {NavWindow} nav_window_ref
|
||||||
|
* @param {Boolean} show_mimetype_icons
|
||||||
* @returns {Promise<NavEntry[]>}
|
* @returns {Promise<NavEntry[]>}
|
||||||
*/
|
*/
|
||||||
get_children(nav_window_ref) {
|
get_children(nav_window_ref, show_mimetype_icons = false) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
var children = [];
|
var children = [];
|
||||||
|
var argv = ["/usr/share/cockpit/navigator/scripts/ls.py3", this.path_str()];
|
||||||
|
if (!show_mimetype_icons)
|
||||||
|
argv.push("--no-mimetype");
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["/usr/share/cockpit/navigator/scripts/ls.py3", this.path_str()],
|
argv,
|
||||||
{err:"out", superuser: "try"}
|
{err:"out", superuser: "try"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
|
console.log(argv);
|
||||||
reject(data);
|
reject(data);
|
||||||
});
|
});
|
||||||
var data;
|
var data;
|
||||||
@ -100,7 +105,7 @@ export class NavDir extends NavEntry {
|
|||||||
children.push(new NavFileLink(path, stat, nav_window_ref, entry["link-target"]));
|
children.push(new NavFileLink(path, stat, nav_window_ref, entry["link-target"]));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
children.push(new NavFile(path, stat, nav_window_ref));
|
children.push(new NavFile(path, stat, nav_window_ref, entry["mimetype"]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -29,10 +29,61 @@ export class NavFile extends NavEntry {
|
|||||||
* @param {object} stat
|
* @param {object} stat
|
||||||
* @param {NavWindow} nav_window_ref
|
* @param {NavWindow} nav_window_ref
|
||||||
*/
|
*/
|
||||||
constructor(path, stat, nav_window_ref) {
|
constructor(path, stat, nav_window_ref, mimetype) {
|
||||||
super(path, stat, nav_window_ref);
|
super(path, stat, nav_window_ref);
|
||||||
this.nav_type = "file";
|
this.nav_type = "file";
|
||||||
|
if (mimetype) {
|
||||||
|
if (/^image\//.test(mimetype)) {
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-image");
|
||||||
|
} else if (/^video\//.test(mimetype)) {
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-video");
|
||||||
|
} else if (/^audio\//.test(mimetype)) {
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-audio");
|
||||||
|
} else {
|
||||||
|
switch (mimetype) {
|
||||||
|
case "text/plain":
|
||||||
|
case "application/rtf":
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-alt");
|
||||||
|
break;
|
||||||
|
case "text/csv":
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-csv");
|
||||||
|
break;
|
||||||
|
case "application/msword":
|
||||||
|
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
||||||
|
case "application/vnd.oasis.opendocument.text":
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-word");
|
||||||
|
break;
|
||||||
|
case "application/vnd.ms-powerpoint":
|
||||||
|
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
|
||||||
|
case "application/vnd.oasis.opendocument.presentation":
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-powerpoint");
|
||||||
|
break;
|
||||||
|
case "application/vnd.ms-excel":
|
||||||
|
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
||||||
|
case "application/vnd.oasis.opendocument.spreadsheet":
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-excel");
|
||||||
|
break;
|
||||||
|
case "application/pdf":
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-pdf");
|
||||||
|
break;
|
||||||
|
case "application/x-freearc":
|
||||||
|
case "application/x-bzip":
|
||||||
|
case "application/x-bzip2":
|
||||||
|
case "application/gzip":
|
||||||
|
case "application/vnd.rar":
|
||||||
|
case "application/x-tar":
|
||||||
|
case "application/zip":
|
||||||
|
case "application/x-7z-compressed":
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file-archive");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
this.dom_element.nav_item_icon.classList.add("fas", "fa-file");
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file");
|
||||||
|
}
|
||||||
this.double_click = false;
|
this.double_click = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ import { format_bytes, format_permissions } from "../functions.js";
|
|||||||
export class NavWindow {
|
export class NavWindow {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.item_display = "grid";
|
this.item_display = "grid";
|
||||||
|
var show_mimetype_icons_str = localStorage.getItem('show-mimetype-icons') ?? 'true';
|
||||||
|
this.show_mimetype_icons = show_mimetype_icons_str === 'true';
|
||||||
|
document.getElementById("nav-show-mimetype-icons").checked = this.show_mimetype_icons;
|
||||||
this.path_stack = (localStorage.getItem('navigator-path') ?? '/').split('/');
|
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));
|
this.path_stack = this.path_stack.map((_, index) => new NavDir([...this.path_stack.slice(0, index + 1)].filter(part => part != ''), this));
|
||||||
|
|
||||||
@ -126,7 +129,7 @@ export class NavWindow {
|
|||||||
this.show_hidden = document.getElementById("nav-show-hidden").checked;
|
this.show_hidden = document.getElementById("nav-show-hidden").checked;
|
||||||
this.start_load();
|
this.start_load();
|
||||||
try {
|
try {
|
||||||
var files = await this.pwd().get_children(this);
|
var files = await this.pwd().get_children(this, this.show_mimetype_icons);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
await this.modal_prompt.alert(e);
|
await this.modal_prompt.alert(e);
|
||||||
this.up();
|
this.up();
|
||||||
@ -914,6 +917,13 @@ export class NavWindow {
|
|||||||
localStorage.setItem("item-display", this.item_display);
|
localStorage.setItem("item-display", this.item_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async set_show_mimetype_icons(e) {
|
||||||
|
console.log(e);
|
||||||
|
this.show_mimetype_icons = e.target.checked;
|
||||||
|
localStorage.setItem("show-mimetype-icons", e.target.checked.toString());
|
||||||
|
await this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
search_filter(event) {
|
search_filter(event) {
|
||||||
var search_name = event.target.value;
|
var search_name = event.target.value;
|
||||||
let search_func;
|
let search_func;
|
||||||
|
@ -181,6 +181,17 @@
|
|||||||
<i class="fas fa-list" id="nav-item-display-icon"></i>
|
<i class="fas fa-list" id="nav-item-display-icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="horizontal-spacer"></div>
|
<div class="horizontal-spacer"></div>
|
||||||
|
<div class="nav-toggle">
|
||||||
|
<div class="nav-btn-group">
|
||||||
|
<i class="fas fa-icons" id="nav-show-mimetype-icons-icon"></i>
|
||||||
|
<div class="horizontal-spacer-sm"></div>
|
||||||
|
<label class="switch" title="Show File Type Icons (Disable for faster load)">
|
||||||
|
<input type="checkbox" id="nav-show-mimetype-icons">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="horizontal-spacer"></div>
|
||||||
<div class="nav-toggle">
|
<div class="nav-toggle">
|
||||||
<div class="nav-btn-group">
|
<div class="nav-btn-group">
|
||||||
<i class="fas fa-low-vision" id="nav-show-hidden-icon"></i>
|
<i class="fas fa-low-vision" id="nav-show-hidden-icon"></i>
|
||||||
|
@ -117,6 +117,7 @@ function set_up_buttons() {
|
|||||||
document.getElementById("pwd").addEventListener("focus", nav_window.nav_bar_update_choices.bind(nav_window), false);
|
document.getElementById("pwd").addEventListener("focus", nav_window.nav_bar_update_choices.bind(nav_window), false);
|
||||||
document.getElementById("pwd").addEventListener("keydown", nav_window.nav_bar_event_handler.bind(nav_window));
|
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("toggle-theme").addEventListener("change", switch_theme, false);
|
||||||
|
document.getElementById("nav-show-mimetype-icons").addEventListener("change", nav_window.set_show_mimetype_icons.bind(nav_window));
|
||||||
document.getElementById("nav-show-hidden").addEventListener("change", nav_window.toggle_show_hidden.bind(nav_window));
|
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));
|
document.getElementById("nav-item-display-btn").addEventListener("click", nav_window.switch_item_display.bind(nav_window));
|
||||||
for (let option of ["name", "owner", "group", "size", "modified", "created"]) {
|
for (let option of ["name", "owner", "group", "size", "modified", "created"]) {
|
||||||
|
@ -21,10 +21,12 @@ import os
|
|||||||
from stat import S_ISDIR, S_ISLNK, filemode
|
from stat import S_ISDIR, S_ISLNK, filemode
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
import magic
|
||||||
|
from optparse import OptionParser
|
||||||
from pwd import getpwuid
|
from pwd import getpwuid
|
||||||
from grp import getgrgid
|
from grp import getgrgid
|
||||||
|
|
||||||
def get_stat(full_path, filename = '/'):
|
def get_stat(full_path, filename = '/', no_mimetype=False):
|
||||||
try:
|
try:
|
||||||
stats = os.lstat(full_path)
|
stats = os.lstat(full_path)
|
||||||
except OSError:
|
except OSError:
|
||||||
@ -64,6 +66,13 @@ def get_stat(full_path, filename = '/'):
|
|||||||
group = getgrgid(stats.st_gid).gr_name
|
group = getgrgid(stats.st_gid).gr_name
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
mimetype = None
|
||||||
|
if not no_mimetype:
|
||||||
|
try:
|
||||||
|
if not isdir:
|
||||||
|
mimetype = magic.detect_from_filename(full_path)[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
response = {
|
response = {
|
||||||
"inaccessible": False,
|
"inaccessible": False,
|
||||||
"filename": filename,
|
"filename": filename,
|
||||||
@ -80,25 +89,30 @@ def get_stat(full_path, filename = '/'):
|
|||||||
"atime": stats.st_atime,
|
"atime": stats.st_atime,
|
||||||
"mtime": stats.st_mtime,
|
"mtime": stats.st_mtime,
|
||||||
"ctime": stats.st_ctime
|
"ctime": stats.st_ctime
|
||||||
}
|
},
|
||||||
|
"mimetype": mimetype
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if(len(sys.argv) < 2):
|
parser = OptionParser()
|
||||||
|
parser.add_option("-m", "--no-mimetype", dest="no_mimetype", default=False, action="store_true")
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
if(len(args) != 1):
|
||||||
|
print("Not enough args: ", args)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
try:
|
try:
|
||||||
nodes = os.listdir(sys.argv[1])
|
nodes = os.listdir(args[0])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
response = {
|
response = {
|
||||||
".": get_stat(sys.argv[1]),
|
".": get_stat(args[0], no_mimetype=options.no_mimetype),
|
||||||
"children": []
|
"children": []
|
||||||
}
|
}
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
full_path = sys.argv[1] + "/" + node
|
full_path = args[0] + "/" + node
|
||||||
response["children"].append(get_stat(full_path, node))
|
response["children"].append(get_stat(full_path, node, no_mimetype=options.no_mimetype))
|
||||||
print(json.dumps(response))
|
print(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user