mirror of
https://github.com/45Drives/cockpit-navigator.git
synced 2025-07-29 16:45:13 +02:00
implement cd on double click and show stats on single click
This commit is contained in:
parent
da08328386
commit
0d12a2d4b9
@ -43,7 +43,7 @@
|
|||||||
<div class="flex-row inner-container">
|
<div class="flex-row inner-container">
|
||||||
<div class="contents-view" id="nav-contents-view"></div>
|
<div class="contents-view" id="nav-contents-view"></div>
|
||||||
<div class="horizontal-spacer"></div>
|
<div class="horizontal-spacer"></div>
|
||||||
<div class="info-column"></div>
|
<div class="info-column" id="nav-info-column"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class NavEntry {
|
class NavEntry {
|
||||||
constructor(/*string or array*/ path) {
|
constructor(/*string or array*/ path, /*dict*/ stat) {
|
||||||
if(typeof path == 'string')
|
if(typeof path == 'string')
|
||||||
this.path = path.split('/').splice(1);
|
this.path = path.split('/').splice(1);
|
||||||
else
|
else
|
||||||
@ -14,6 +14,8 @@ class NavEntry {
|
|||||||
title.innerText = this.filename();
|
title.innerText = this.filename();
|
||||||
this.dom_element.appendChild(icon);
|
this.dom_element.appendChild(icon);
|
||||||
this.dom_element.appendChild(title);
|
this.dom_element.appendChild(title);
|
||||||
|
this.stat = stat;
|
||||||
|
this.dom_element.nav_item_icon.addEventListener("click", this)
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
while(this.dom_element.firstChild){
|
while(this.dom_element.firstChild){
|
||||||
@ -23,7 +25,10 @@ class NavEntry {
|
|||||||
this.dom_element.parentElement.removeChild(this.dom_element);
|
this.dom_element.parentElement.removeChild(this.dom_element);
|
||||||
}
|
}
|
||||||
filename() {
|
filename() {
|
||||||
return this.path[this.path.length -1];
|
var name = this.path[this.path.length -1];
|
||||||
|
if(name === "")
|
||||||
|
name = "/";
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
path_str() {
|
path_str() {
|
||||||
return "/" + this.path.join('/');
|
return "/" + this.path.join('/');
|
||||||
@ -31,47 +36,81 @@ class NavEntry {
|
|||||||
show() {
|
show() {
|
||||||
document.getElementById("nav-contents-view").appendChild(this.dom_element);
|
document.getElementById("nav-contents-view").appendChild(this.dom_element);
|
||||||
}
|
}
|
||||||
}
|
get_properties() {
|
||||||
|
return this.stat;
|
||||||
class NavFile extends NavEntry {
|
}
|
||||||
constructor(/*string or array*/ path) {
|
show_properties(){
|
||||||
super(path);
|
var html = '<div class="nav-info-column-filename">' + this.filename() + '</div>\n';
|
||||||
this.nav_type = "file";
|
html += '<div class="nav-property-pair">';
|
||||||
this.dom_element.nav_item_icon.classList.add("nav-file-icon");
|
html += '<span class="nav-property-pair-key">Mode: </span>'
|
||||||
|
html += '<span class="nav-property-pair-value">' + this.stat["mode-str"] + '</span>'
|
||||||
|
html += '</div>'
|
||||||
|
document.getElementById("nav-info-column").innerHTML = html;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NavDir extends NavEntry {
|
class NavFile extends NavEntry {
|
||||||
constructor(/*string or array*/ path, nav_window_ref) {
|
constructor(/*string or array*/ path, /*dict*/ stat) {
|
||||||
super(path);
|
super(path, stat);
|
||||||
this.nav_type = "dir";
|
this.nav_type = "file";
|
||||||
this.dom_element.nav_item_icon.classList.add("nav-dir-icon");
|
this.dom_element.nav_item_icon.classList.add("nav-file-icon");
|
||||||
this.nav_window_ref = nav_window_ref;
|
|
||||||
this.dom_element.nav_item_icon.addEventListener("click", this)
|
|
||||||
}
|
}
|
||||||
handleEvent(e) {
|
handleEvent(e) {
|
||||||
switch(e.type){
|
switch(e.type){
|
||||||
case "click":
|
case "click":
|
||||||
this.nav_window_ref.cd(this);
|
this.show_properties();
|
||||||
|
e.stopPropagation();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NavDir extends NavEntry {
|
||||||
|
constructor(/*string or array*/ path, /*dict*/ stat, nav_window_ref) {
|
||||||
|
super(path, stat);
|
||||||
|
this.nav_type = "dir";
|
||||||
|
this.dom_element.nav_item_icon.classList.add("nav-dir-icon");
|
||||||
|
this.nav_window_ref = nav_window_ref;
|
||||||
|
this.double_click = false;
|
||||||
|
}
|
||||||
|
handleEvent(e) {
|
||||||
|
switch(e.type){
|
||||||
|
case "click":
|
||||||
|
if(this.double_click)
|
||||||
|
this.nav_window_ref.cd(this);
|
||||||
|
else{ // single click
|
||||||
|
this.show_properties();
|
||||||
|
this.double_click = true;
|
||||||
|
if(this.timeout)
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.double_click = false;
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
e.stopPropagation();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async get_children(nav_window_ref) {
|
async get_children(nav_window_ref) {
|
||||||
var children = [];
|
var children = [];
|
||||||
var data = await cockpit.spawn(["/usr/share/cockpit/navigator/scripts/ls.py", this.path_str()], {err:"ignore"});
|
var data = await cockpit.spawn(["/usr/share/cockpit/navigator/scripts/ls.py", this.path_str()], {err:"ignore"});
|
||||||
var entries = JSON.parse(data);
|
var response = JSON.parse(data);
|
||||||
|
this.stat = response["."]["stat"];
|
||||||
|
var entries = response["children"];
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
var filename = entry["filename"];
|
var filename = entry["filename"];
|
||||||
var path = (this.path.length >= 1 && this.path[0]) ? [... this.path, filename] : [filename];
|
var path = (this.path.length >= 1 && this.path[0]) ? [... this.path, filename] : [filename];
|
||||||
|
var stat = entry["stat"];
|
||||||
if(entry["isdir"])
|
if(entry["isdir"])
|
||||||
children.push(new NavDir(path, nav_window_ref));
|
children.push(new NavDir(path, stat, nav_window_ref));
|
||||||
else
|
else
|
||||||
children.push(new NavFile(path));
|
children.push(new NavFile(path, stat));
|
||||||
});
|
});
|
||||||
children.sort((first, second) => {
|
children.sort((first, second) => {
|
||||||
if(first.nav_type === second.nav_type)
|
if(first.nav_type === second.nav_type){
|
||||||
return 0;
|
return first.filename().localeCompare(second.filename());
|
||||||
if(first.nav_type == "dir")
|
}
|
||||||
|
if(first.nav_type === "dir")
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
})
|
})
|
||||||
@ -83,6 +122,15 @@ class NavWindow {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.path_stack = [new NavDir("/", this)];
|
this.path_stack = [new NavDir("/", this)];
|
||||||
this.entries = [];
|
this.entries = [];
|
||||||
|
this.window = document.getElementById("nav-contents-view");
|
||||||
|
this.window.addEventListener("click", this);
|
||||||
|
}
|
||||||
|
handleEvent(e) {
|
||||||
|
switch(e.type){
|
||||||
|
case "click":
|
||||||
|
this.show_pwd_properties();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async refresh() {
|
async refresh() {
|
||||||
var files = await this.pwd().get_children(this);
|
var files = await this.pwd().get_children(this);
|
||||||
@ -112,6 +160,9 @@ class NavWindow {
|
|||||||
this.path_stack.pop();
|
this.path_stack.pop();
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
show_pwd_properties() {
|
||||||
|
this.pwd().show_properties();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let nav_window = new NavWindow();
|
let nav_window = new NavWindow();
|
||||||
|
@ -1,8 +1,36 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from stat import S_ISDIR, filemode
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
from pwd import getpwuid
|
||||||
|
from grp import getgrgid
|
||||||
|
|
||||||
|
def get_stat(full_path, filename = '/'):
|
||||||
|
stats = os.lstat(full_path)
|
||||||
|
isdir = False
|
||||||
|
try:
|
||||||
|
isdir = S_ISDIR(os.stat(full_path).st_mode)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
response = {
|
||||||
|
"filename": filename,
|
||||||
|
"isdir": isdir,
|
||||||
|
"stat": {
|
||||||
|
"mode": stats.st_mode,
|
||||||
|
"mode-str": filemode(stats.st_mode),
|
||||||
|
"uid": stats.st_uid,
|
||||||
|
"owner": getpwuid(stats.st_uid).pw_name,
|
||||||
|
"gid": stats.st_gid,
|
||||||
|
"group": getgrgid(stats.st_gid).gr_name,
|
||||||
|
"size": stats.st_size,
|
||||||
|
"atime": stats.st_atime,
|
||||||
|
"mtime": stats.st_mtime,
|
||||||
|
"ctime": stats.st_ctime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if(len(sys.argv) < 2):
|
if(len(sys.argv) < 2):
|
||||||
@ -12,10 +40,14 @@ def main():
|
|||||||
except:
|
except:
|
||||||
print("No such file or directory")
|
print("No such file or directory")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
response = []
|
response = {
|
||||||
|
".": get_stat(sys.argv[1]),
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
response.append({"filename": node, "isdir": os.path.isdir(sys.argv[1] + "/" + node)})
|
full_path = sys.argv[1] + "/" + node
|
||||||
print(json.dumps(response, indent=4))
|
response["children"].append(get_stat(full_path, node))
|
||||||
|
print(json.dumps(response))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
x
Reference in New Issue
Block a user