mirror of
https://github.com/45Drives/cockpit-navigator.git
synced 2025-07-29 16:45:13 +02:00
Merge changes for cephfs-dir-stats and light mode
This commit is contained in:
commit
b59acf84d5
@ -1,3 +1,23 @@
|
|||||||
|
:root {
|
||||||
|
/* white style */
|
||||||
|
--container: #fff;
|
||||||
|
--border: #bebebe;
|
||||||
|
--navigation: #f0f0f0;
|
||||||
|
--font: #1c1c1c;
|
||||||
|
--selected: #fff;
|
||||||
|
--toggle-light: #151515;
|
||||||
|
--toggle-dark: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] {
|
||||||
|
/* Dark style */
|
||||||
|
--container: #212427;
|
||||||
|
--border: #3c3f42;
|
||||||
|
--navigation: #151515;
|
||||||
|
--font: #fff;
|
||||||
|
--selected: #191a1b;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-row {
|
.flex-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -26,17 +46,17 @@
|
|||||||
|
|
||||||
.outer-container {
|
.outer-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #212427;
|
background-color: var(--container);
|
||||||
color: #fff;
|
color: var(--font);
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-bar {
|
.navigation-bar {
|
||||||
background-color: #212427;
|
background-color: var(--container);
|
||||||
color: inherit;
|
color: inherit;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding: 0.25em 1em 0.25em 1em;
|
padding: 0.25em 1em 0.25em 1em;
|
||||||
border: 1px solid #3c3f42;
|
border: 1px solid var(--border);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,8 +70,8 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
flex-grow: 8;
|
flex-grow: 8;
|
||||||
background-color: #151515;
|
background-color: var(--navigation);
|
||||||
border: 1px solid #3c3f42;
|
border: 1px solid var(--border);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -74,8 +94,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-item-selected {
|
.nav-item-selected {
|
||||||
background-color: #191a1b;
|
background-color: var(--selected);
|
||||||
border: 1px solid #3c3f42;
|
border: 1px solid var(--border);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
@ -90,15 +110,15 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
font-size: 80px;
|
font-size: 80px;
|
||||||
color: #3c3f42;
|
color: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-info-column {
|
.nav-info-column {
|
||||||
background-color: #212427;
|
background-color: var(--container);
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
flex-grow: 3;
|
flex-grow: 3;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
border: 1px solid #3c3f42;
|
border: 1px solid var(--border);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +143,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-property-pair-value {
|
.nav-property-pair-value {
|
||||||
font-family:'Courier New', Courier, monospace;
|
font-family: "Courier New", Courier, monospace;
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
flex: 3;
|
flex: 3;
|
||||||
@ -164,4 +184,70 @@
|
|||||||
white-space: pre;
|
white-space: pre;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
resize: none;
|
resize: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-toggle {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0.5em;
|
||||||
|
margin-right: 1.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 60px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: var(--toggle-light);
|
||||||
|
-webkit-transition: 0.4s;
|
||||||
|
transition: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
left: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
background-color: white;
|
||||||
|
-webkit-transition: 0.4s;
|
||||||
|
transition: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider {
|
||||||
|
background-color: var(--toggle-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus + .slider {
|
||||||
|
box-shadow: 0 0 1px var(--toggle-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider:before {
|
||||||
|
-webkit-transform: translateX(26px);
|
||||||
|
-ms-transform: translateX(26px);
|
||||||
|
transform: translateX(26px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round {
|
||||||
|
border-radius: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round:before {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
@ -78,6 +78,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-info-column-properties" id="nav-info-column-properties"></div>
|
<div class="nav-info-column-properties" id="nav-info-column-properties"></div>
|
||||||
|
<div class="nav-toggle">
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="toggle-theme">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
<div class="vertical-spacer"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-hidden" id="nav-edit-properties">
|
<div class="nav-hidden" id="nav-edit-properties">
|
||||||
<div class="nav-info-column-filename"></div>
|
<div class="nav-info-column-filename"></div>
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
function property_entry_html(key, value) {
|
function property_entry_html(key, value) {
|
||||||
var html = '<div class="nav-property-pair">';
|
var html = '<div class="nav-property-pair">';
|
||||||
html += '<span class="nav-property-pair-key">' + key + '</span>'
|
html += '<span class="nav-property-pair-key">' + key + '</span>';
|
||||||
html += '<span class="nav-property-pair-value">' + value + '</span>'
|
html += '<span class="nav-property-pair-value">' + value + '</span>';
|
||||||
html += '</div>'
|
html += '</div>';
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
function format_bytes(bytes) {
|
function format_bytes(bytes) {
|
||||||
if(bytes === 0)
|
if (bytes === 0)
|
||||||
return "0 B";
|
return "0 B";
|
||||||
var units = [" B", " KiB", " MiB", " GiB", " TiB", " PiB"];
|
var units = [" B", " KiB", " MiB", " GiB", " TiB", " PiB"];
|
||||||
var index = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1)
|
var index = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
|
||||||
var pow = Math.pow(1024, index);
|
var pow = Math.pow(1024, index);
|
||||||
var formatted = bytes / pow;
|
var formatted = bytes / pow;
|
||||||
return formatted.toFixed(2).toString() + units[index];
|
return formatted.toFixed(2).toString() + units[index];
|
||||||
@ -26,23 +24,72 @@ function format_time(timestamp) {
|
|||||||
function format_permissions(/*int*/ mode) {
|
function format_permissions(/*int*/ mode) {
|
||||||
var bit_list = ["x", "w", "r"];
|
var bit_list = ["x", "w", "r"];
|
||||||
var result = "";
|
var result = "";
|
||||||
for(let bit = 8; bit >= 0; bit--){
|
for (let bit = 8; bit >= 0; bit--) {
|
||||||
var test_bit = 1 << bit;
|
var test_bit = 1 << bit;
|
||||||
var test_result = mode & test_bit;
|
var test_result = mode & test_bit;
|
||||||
if(test_result != 0){
|
if (test_result != 0) {
|
||||||
result += bit_list[bit % bit_list.length];
|
result += bit_list[bit % bit_list.length];
|
||||||
}else{
|
} else {
|
||||||
result += "-";
|
result += "-";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Code to change theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
const toggleSwitch = document.getElementById("toggle-theme");
|
||||||
|
|
||||||
|
function switchTheme(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
document.documentElement.setAttribute("data-theme", "dark");
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute("data-theme", "light");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSwitch.addEventListener("change", switchTheme, false);
|
||||||
|
|
||||||
|
/* cephfs_dir_stats
|
||||||
|
* Receives: path to folder
|
||||||
|
* Does: Tries command with --json flag at path to folder. If
|
||||||
|
* command fails and gives an error then catch that error
|
||||||
|
* Returns: JSON object or nothing
|
||||||
|
*/
|
||||||
|
async function cephfs_dir_stats(path) {
|
||||||
|
try {
|
||||||
|
var proc = await cockpit.spawn(
|
||||||
|
["cephfs-dir-stats", "-j", path],
|
||||||
|
{err: "ignore",}
|
||||||
|
);
|
||||||
|
return JSON.parse(proc.replace(/\[|\]/g, ""));
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in_json
|
||||||
|
* Receives: A boolean to see if key is in JSON object
|
||||||
|
* and the JSON objects value if it exists
|
||||||
|
* Does: Checks if JSON key exists; if so, return the
|
||||||
|
* value of the key, if not, return the string "N/A"
|
||||||
|
* Returns: The value of key or "N/A"
|
||||||
|
*/
|
||||||
|
function in_json(is_key, value) {
|
||||||
|
if (is_key) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class NavEntry {
|
class NavEntry {
|
||||||
constructor(/*string or array*/ path, /*dict*/ stat, /*NavWindow*/ nav_window_ref) {
|
constructor(/*string or array*/ path, /*dict*/ stat, /*NavWindow*/ nav_window_ref) {
|
||||||
this.nav_window_ref = nav_window_ref;
|
this.nav_window_ref = nav_window_ref;
|
||||||
if(typeof path == 'string')
|
if (typeof path == "string")
|
||||||
this.path = path.split('/').splice(1);
|
this.path = path.split("/").splice(1);
|
||||||
else
|
else
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.dom_element = document.createElement("div");
|
this.dom_element = document.createElement("div");
|
||||||
@ -55,10 +102,10 @@ class NavEntry {
|
|||||||
this.dom_element.appendChild(icon);
|
this.dom_element.appendChild(icon);
|
||||||
this.dom_element.appendChild(title);
|
this.dom_element.appendChild(title);
|
||||||
this.stat = stat;
|
this.stat = stat;
|
||||||
this.dom_element.addEventListener("click", this)
|
this.dom_element.addEventListener("click", this);
|
||||||
}
|
}
|
||||||
handleEvent(e) {
|
handleEvent(e) {
|
||||||
switch(e.type){
|
switch (e.type) {
|
||||||
case "click":
|
case "click":
|
||||||
this.show_properties();
|
this.show_properties();
|
||||||
this.nav_window_ref.set_selected(this);
|
this.nav_window_ref.set_selected(this);
|
||||||
@ -67,20 +114,20 @@ class NavEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
while(this.dom_element.firstChild){
|
while (this.dom_element.firstChild) {
|
||||||
this.dom_element.removeChild(this.dom_element.firstChild);
|
this.dom_element.removeChild(this.dom_element.firstChild);
|
||||||
}
|
}
|
||||||
if(this.dom_element.parentElement)
|
if (this.dom_element.parentElement)
|
||||||
this.dom_element.parentElement.removeChild(this.dom_element);
|
this.dom_element.parentElement.removeChild(this.dom_element);
|
||||||
}
|
}
|
||||||
filename() {
|
filename() {
|
||||||
var name = this.path[this.path.length -1];
|
var name = this.path[this.path.length - 1];
|
||||||
if(name === "")
|
if (name === "")
|
||||||
name = "/";
|
name = "/";
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
path_str() {
|
path_str() {
|
||||||
return "/" + this.path.join('/');
|
return "/" + this.path.join("/");
|
||||||
}
|
}
|
||||||
parent_dir() {
|
parent_dir() {
|
||||||
return this.path.slice(0, this.path.length - 1);
|
return this.path.slice(0, this.path.length - 1);
|
||||||
@ -97,7 +144,7 @@ class NavEntry {
|
|||||||
async chmod(/*int*/ new_perms) {
|
async chmod(/*int*/ new_perms) {
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["chmod", (new_perms & 0o777).toString(8), this.path_str()],
|
["chmod", (new_perms & 0o777).toString(8), this.path_str()],
|
||||||
{superuser: "try", err:"out"}
|
{superuser: "try", err: "out"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
@ -107,7 +154,7 @@ class NavEntry {
|
|||||||
async chown(/*string*/ new_owner, /*string*/ new_group) {
|
async chown(/*string*/ new_owner, /*string*/ new_group) {
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["chown", [new_owner, new_group].join(":"), this.path_str()],
|
["chown", [new_owner, new_group].join(":"), this.path_str()],
|
||||||
{superuser: "try", err:"out"}
|
{superuser: "try", err: "out"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
@ -116,8 +163,8 @@ class NavEntry {
|
|||||||
}
|
}
|
||||||
async mv(/*string*/ new_path) {
|
async mv(/*string*/ new_path) {
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["mv", "-n", this.path_str(), [this.nav_window_ref.pwd().path_str(), new_path].join('/')],
|
["mv", "-n", this.path_str(), [this.nav_window_ref.pwd().path_str(), new_path].join("/")],
|
||||||
{superuser: "try", err:"out"}
|
{superuser: "try", err: "out"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
@ -126,7 +173,7 @@ class NavEntry {
|
|||||||
}
|
}
|
||||||
show_properties(/*string*/ extra_properties = "") {
|
show_properties(/*string*/ extra_properties = "") {
|
||||||
var selected_name_fields = document.getElementsByClassName("nav-info-column-filename");
|
var selected_name_fields = document.getElementsByClassName("nav-info-column-filename");
|
||||||
for(let elem of selected_name_fields){
|
for (let elem of selected_name_fields) {
|
||||||
elem.innerText = this.filename();
|
elem.innerText = this.filename();
|
||||||
}
|
}
|
||||||
var html = "";
|
var html = "";
|
||||||
@ -142,11 +189,13 @@ class NavEntry {
|
|||||||
}
|
}
|
||||||
populate_edit_fields() {
|
populate_edit_fields() {
|
||||||
document.getElementById("nav-edit-filename").value = this.filename();
|
document.getElementById("nav-edit-filename").value = this.filename();
|
||||||
var mode_bits = ["other-exec", "other-write", "other-read",
|
var mode_bits = [
|
||||||
"group-exec", "group-write", "group-read",
|
"other-exec", "other-write", "other-read",
|
||||||
"owner-exec", "owner-write", "owner-read"];
|
"group-exec", "group-write", "group-read",
|
||||||
for(let i = 0; i < mode_bits.length; i++){
|
"owner-exec", "owner-write", "owner-read"
|
||||||
var bit_check = (1 << i);
|
];
|
||||||
|
for (let i = 0; i < mode_bits.length; i++) {
|
||||||
|
var bit_check = 1 << i;
|
||||||
var result = this.stat["mode"] & bit_check;
|
var result = this.stat["mode"] & bit_check;
|
||||||
document.getElementById(mode_bits[i]).checked = (result != 0);
|
document.getElementById(mode_bits[i]).checked = (result != 0);
|
||||||
}
|
}
|
||||||
@ -182,7 +231,7 @@ class NavFile extends NavEntry {
|
|||||||
async rm() {
|
async rm() {
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["rm", "-f", this.path_str()],
|
["rm", "-f", this.path_str()],
|
||||||
{superuser: "try", err:"out"}
|
{superuser: "try", err: "out"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
@ -223,22 +272,19 @@ class NavDir extends NavEntry {
|
|||||||
this.nav_type = "dir";
|
this.nav_type = "dir";
|
||||||
this.dom_element.nav_item_icon.classList.add("fas", "fa-folder");
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-folder");
|
||||||
this.double_click = false;
|
this.double_click = false;
|
||||||
/*
|
this.ceph_stats = [];
|
||||||
Sam:
|
cephfs_dir_stats(this.path_str()).then((data) => (this.ceph_stats = data));
|
||||||
add a method to NavDir that calls cephfs-dir-stats and call it here.
|
|
||||||
The function should save the results as a dictionary like the following:
|
|
||||||
this.cephfs_dir_stats = {key : "value", etc};
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
handleEvent(e) {
|
handleEvent(e) {
|
||||||
switch(e.type){
|
switch (e.type) {
|
||||||
case "click":
|
case "click":
|
||||||
if(this.double_click)
|
if (this.double_click)
|
||||||
this.nav_window_ref.cd(this);
|
this.nav_window_ref.cd(this);
|
||||||
else{ // single click
|
else {
|
||||||
|
// single click
|
||||||
this.double_click = true;
|
this.double_click = true;
|
||||||
if(this.timeout)
|
if (this.timeout)
|
||||||
clearTimeout(this.timeout)
|
clearTimeout(this.timeout);
|
||||||
this.timeout = setTimeout(() => {
|
this.timeout = setTimeout(() => {
|
||||||
this.double_click = false;
|
this.double_click = false;
|
||||||
}, 500);
|
}, 500);
|
||||||
@ -249,38 +295,41 @@ class NavDir extends NavEntry {
|
|||||||
}
|
}
|
||||||
async get_children(nav_window_ref, no_alert = false) {
|
async get_children(nav_window_ref, no_alert = false) {
|
||||||
var children = [];
|
var children = [];
|
||||||
var proc = cockpit.spawn(["/usr/share/cockpit/navigator/scripts/ls.py", this.path_str()], {err:"out", superuser: "try"});
|
var proc = cockpit.spawn(
|
||||||
|
["/usr/share/cockpit/navigator/scripts/ls.py", this.path_str()],
|
||||||
|
{err:"out", superuser: "try"}
|
||||||
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
if(!no_alert)
|
if(!no_alert)
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
})
|
});
|
||||||
var data = await proc;
|
var data = await proc;
|
||||||
var response = JSON.parse(data);
|
var response = JSON.parse(data);
|
||||||
this.stat = response["."]["stat"];
|
this.stat = response["."]["stat"];
|
||||||
var entries = response["children"];
|
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"];
|
var stat = entry["stat"];
|
||||||
if(entry["isdir"])
|
if (entry["isdir"])
|
||||||
children.push(new NavDir(path, stat, nav_window_ref));
|
children.push(new NavDir(path, stat, nav_window_ref));
|
||||||
else
|
else
|
||||||
children.push(new NavFile(path, stat, nav_window_ref));
|
children.push(new NavFile(path, stat, nav_window_ref));
|
||||||
});
|
});
|
||||||
children.sort((first, second) => {
|
children.sort((first, second) => {
|
||||||
if(first.nav_type === second.nav_type){
|
if (first.nav_type === second.nav_type) {
|
||||||
return first.filename().localeCompare(second.filename());
|
return first.filename().localeCompare(second.filename());
|
||||||
}
|
}
|
||||||
if(first.nav_type === "dir")
|
if (first.nav_type === "dir")
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
})
|
});
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
async rm() {
|
async rm() {
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["rmdir", this.path_str()],
|
["rmdir", this.path_str()],
|
||||||
{superuser: "try", err:"out"}
|
{superuser: "try", err: "out"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
@ -289,12 +338,43 @@ class NavDir extends NavEntry {
|
|||||||
}
|
}
|
||||||
show_properties() {
|
show_properties() {
|
||||||
var extra_properties = "";
|
var extra_properties = "";
|
||||||
/*
|
// See if a JSON object exists for folder we are currently looking at
|
||||||
Sam:
|
if (this.ceph_stats.length !== 0) {
|
||||||
Follow NavEntry.show_properties() as an example to put the cephfs-dir-stats results
|
extra_properties +=
|
||||||
into extra_properties as html elements. If cephfs-dir-stats failed, i.e. it's not in a
|
'<div class="vertical-spacer"></div><h2 class="nav-info-column-filename">Ceph Status</h2>';
|
||||||
ceph filesystem, make sure extra_properties is an empty string.
|
extra_properties += property_entry_html(
|
||||||
*/
|
"Files",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("files"), this.ceph_stats.files)
|
||||||
|
);
|
||||||
|
extra_properties += property_entry_html(
|
||||||
|
"Directories",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("subdirs"), this.ceph_stats.subdirs)
|
||||||
|
);
|
||||||
|
extra_properties += property_entry_html(
|
||||||
|
"Recursive files",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("rfiles"), this.ceph_stats.rfiles)
|
||||||
|
);
|
||||||
|
extra_properties += property_entry_html(
|
||||||
|
"Recursive directories",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("rsubdirs"), this.ceph_stats.rsubdirs)
|
||||||
|
);
|
||||||
|
extra_properties += property_entry_html(
|
||||||
|
"Total size",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("rbytes"), this.ceph_stats.rbytes)
|
||||||
|
);
|
||||||
|
extra_properties += property_entry_html(
|
||||||
|
"Layout pool",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("layout.pool"), this.ceph_stats["layout.pool"])
|
||||||
|
);
|
||||||
|
extra_properties += property_entry_html(
|
||||||
|
"Max files",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("max_files"), this.ceph_stats.max_files)
|
||||||
|
);
|
||||||
|
extra_properties += property_entry_html(
|
||||||
|
"Max bytes",
|
||||||
|
in_json(this.ceph_stats.hasOwnProperty("max_bytes"), this.ceph_stats.max_bytes)
|
||||||
|
);
|
||||||
|
}
|
||||||
super.show_properties(extra_properties);
|
super.show_properties(extra_properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,7 +389,7 @@ class NavWindow {
|
|||||||
this.window.addEventListener("click", this);
|
this.window.addEventListener("click", this);
|
||||||
}
|
}
|
||||||
handleEvent(e) {
|
handleEvent(e) {
|
||||||
switch(e.type){
|
switch (e.type) {
|
||||||
case "click":
|
case "click":
|
||||||
this.set_selected(this.pwd());
|
this.set_selected(this.pwd());
|
||||||
this.show_selected_properties();
|
this.show_selected_properties();
|
||||||
@ -318,11 +398,11 @@ class NavWindow {
|
|||||||
}
|
}
|
||||||
async refresh() {
|
async refresh() {
|
||||||
var files = await this.pwd().get_children(this);
|
var files = await this.pwd().get_children(this);
|
||||||
while(this.entries.length){
|
while (this.entries.length) {
|
||||||
var entry = this.entries.pop();
|
var entry = this.entries.pop();
|
||||||
entry.destroy();
|
entry.destroy();
|
||||||
}
|
}
|
||||||
files.forEach(file => {
|
files.forEach((file) => {
|
||||||
file.show();
|
file.show();
|
||||||
this.entries.push(file);
|
this.entries.push(file);
|
||||||
});
|
});
|
||||||
@ -359,24 +439,41 @@ class NavWindow {
|
|||||||
set_selected(/*NavEntry*/ entry) {
|
set_selected(/*NavEntry*/ entry) {
|
||||||
this.hide_edit_selected();
|
this.hide_edit_selected();
|
||||||
this.selected_entry.dom_element.classList.remove("nav-item-selected");
|
this.selected_entry.dom_element.classList.remove("nav-item-selected");
|
||||||
if(this.selected_entry.nav_type === "dir"){
|
if (this.selected_entry.nav_type === "dir") {
|
||||||
this.selected_entry.dom_element.nav_item_icon.classList.remove("fa-folder-open");
|
this.selected_entry.dom_element.nav_item_icon.classList.remove("fa-folder-open");
|
||||||
this.selected_entry.dom_element.nav_item_icon.classList.add("fa-folder");
|
this.selected_entry.dom_element.nav_item_icon.classList.add("fa-folder");
|
||||||
}
|
}
|
||||||
this.selected_entry = entry;
|
this.selected_entry = entry;
|
||||||
this.selected_entry.dom_element.classList.add("nav-item-selected");
|
this.selected_entry.dom_element.classList.add("nav-item-selected");
|
||||||
if(this.selected_entry.nav_type === "dir"){
|
if (this.selected_entry.nav_type === "dir") {
|
||||||
this.selected_entry.dom_element.nav_item_icon.classList.remove("fa-folder");
|
this.selected_entry.dom_element.nav_item_icon.classList.remove("fa-folder");
|
||||||
this.selected_entry.dom_element.nav_item_icon.classList.add("fa-folder-open");
|
this.selected_entry.dom_element.nav_item_icon.classList.add("fa-folder-open");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
show_edit_selected() {
|
show_edit_selected() {
|
||||||
var dangerous_dirs = [
|
var dangerous_dirs = [
|
||||||
"/", "/usr", "/bin", "/sbin", "/lib", "/lib32", "/lib64", "/usr/bin",
|
"/",
|
||||||
"/usr/include", "/usr/lib", "/usr/lib32", "/usr/lib64", "/usr/sbin"
|
"/usr",
|
||||||
|
"/bin",
|
||||||
|
"/sbin",
|
||||||
|
"/lib",
|
||||||
|
"/lib32",
|
||||||
|
"/lib64",
|
||||||
|
"/usr/bin",
|
||||||
|
"/usr/include",
|
||||||
|
"/usr/lib",
|
||||||
|
"/usr/lib32",
|
||||||
|
"/usr/lib64",
|
||||||
|
"/usr/sbin",
|
||||||
];
|
];
|
||||||
if(dangerous_dirs.includes(this.selected_entry.path_str())){
|
if (dangerous_dirs.includes(this.selected_entry.path_str())) {
|
||||||
if(!window.confirm("Warning: editing `" + this.selected_entry.path_str() + "` can be dangerous. Are you sure?")){
|
if (
|
||||||
|
!window.confirm(
|
||||||
|
"Warning: editing `" +
|
||||||
|
this.selected_entry.path_str() +
|
||||||
|
"` can be dangerous. Are you sure?"
|
||||||
|
)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,9 +491,9 @@ class NavWindow {
|
|||||||
var action_list = ["exec", "write", "read"];
|
var action_list = ["exec", "write", "read"];
|
||||||
var result = 0;
|
var result = 0;
|
||||||
var bit = 0;
|
var bit = 0;
|
||||||
for(let category of category_list){
|
for (let category of category_list) {
|
||||||
for(let action of action_list){
|
for (let action of action_list) {
|
||||||
if(document.getElementById(category + "-" + action).checked)
|
if (document.getElementById(category + "-" + action).checked)
|
||||||
result |= 1 << bit;
|
result |= 1 << bit;
|
||||||
bit++;
|
bit++;
|
||||||
}
|
}
|
||||||
@ -413,22 +510,29 @@ class NavWindow {
|
|||||||
// do mv last so the rest don't fail from not finding path
|
// do mv last so the rest don't fail from not finding path
|
||||||
var new_owner = document.getElementById("nav-edit-owner").value;
|
var new_owner = document.getElementById("nav-edit-owner").value;
|
||||||
var new_group = document.getElementById("nav-edit-group").value;
|
var new_group = document.getElementById("nav-edit-group").value;
|
||||||
if(new_owner !== this.selected_entry.stat["owner"] || new_group !== this.selected_entry.stat["group"]){
|
if (
|
||||||
|
new_owner !== this.selected_entry.stat["owner"] ||
|
||||||
|
new_group !== this.selected_entry.stat["group"]
|
||||||
|
) {
|
||||||
await this.selected_entry.chown(new_owner, new_group).catch(/*ignore, caught in chown*/);
|
await this.selected_entry.chown(new_owner, new_group).catch(/*ignore, caught in chown*/);
|
||||||
}
|
}
|
||||||
var new_perms = this.get_new_permissions();
|
var new_perms = this.get_new_permissions();
|
||||||
if((new_perms & 0o777) !== (this.selected_entry.stat["mode"] & 0o777)){
|
if ((new_perms & 0o777) !== (this.selected_entry.stat["mode"] & 0o777)) {
|
||||||
await this.selected_entry.chmod(new_perms).catch(/*ignore, caught in chmod*/);
|
await this.selected_entry.chmod(new_perms).catch(/*ignore, caught in chmod*/);
|
||||||
}
|
}
|
||||||
var new_name = document.getElementById("nav-edit-filename").value;
|
var new_name = document.getElementById("nav-edit-filename").value;
|
||||||
if(new_name !== this.selected_entry.filename()){
|
if (new_name !== this.selected_entry.filename()) {
|
||||||
await this.selected_entry.mv(new_name).catch(/*ignore, caught in mv*/);
|
await this.selected_entry.mv(new_name).catch(/*ignore, caught in mv*/);
|
||||||
}
|
}
|
||||||
this.refresh();
|
this.refresh();
|
||||||
this.hide_edit_selected();
|
this.hide_edit_selected();
|
||||||
}
|
}
|
||||||
async delete_selected() {
|
async delete_selected() {
|
||||||
if(!window.confirm("Deleting `" + this.selected_entry.path_str() + "` cannot be undone. Are you sure?")){
|
if (
|
||||||
|
!window.confirm(
|
||||||
|
"Deleting `" + this.selected_entry.path_str() + "` cannot be undone. Are you sure?"
|
||||||
|
)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.selected_entry.rm().catch(/*ignore, caught in rm*/);
|
await this.selected_entry.rm().catch(/*ignore, caught in rm*/);
|
||||||
@ -436,15 +540,15 @@ class NavWindow {
|
|||||||
}
|
}
|
||||||
async mkdir() {
|
async mkdir() {
|
||||||
var new_dir_name = window.prompt("Directory Name: ");
|
var new_dir_name = window.prompt("Directory Name: ");
|
||||||
if(new_dir_name === null)
|
if (new_dir_name === null)
|
||||||
return;
|
return;
|
||||||
if(new_dir_name.includes("/")){
|
if (new_dir_name.includes("/")) {
|
||||||
window.alert("Directory name can't contain `/`.");
|
window.alert("Directory name can't contain `/`.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["mkdir", this.pwd().path_str() + "/" + new_dir_name],
|
["mkdir", this.pwd().path_str() + "/" + new_dir_name],
|
||||||
{superuser: "try", err:"out"}
|
{superuser: "try", err: "out"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
@ -454,15 +558,15 @@ class NavWindow {
|
|||||||
}
|
}
|
||||||
async touch() {
|
async touch() {
|
||||||
var new_file_name = window.prompt("File Name: ");
|
var new_file_name = window.prompt("File Name: ");
|
||||||
if(new_file_name === null)
|
if (new_file_name === null)
|
||||||
return;
|
return;
|
||||||
if(new_file_name.includes("/")){
|
if (new_file_name.includes("/")) {
|
||||||
window.alert("File name can't contain `/`.");
|
window.alert("File name can't contain `/`.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var proc = cockpit.spawn(
|
var proc = cockpit.spawn(
|
||||||
["touch", this.pwd().path_str() + "/" + new_file_name],
|
["touch", this.pwd().path_str() + "/" + new_file_name],
|
||||||
{superuser: "try", err:"out"}
|
{superuser: "try", err: "out"}
|
||||||
);
|
);
|
||||||
proc.fail((e, data) => {
|
proc.fail((e, data) => {
|
||||||
window.alert(data);
|
window.alert(data);
|
||||||
@ -524,7 +628,7 @@ function set_up_buttons() {
|
|||||||
document.getElementById("nav-cancel-edit-btn").addEventListener("click", nav_window.hide_edit_selected.bind(nav_window));
|
document.getElementById("nav-cancel-edit-btn").addEventListener("click", nav_window.hide_edit_selected.bind(nav_window));
|
||||||
document.getElementById("nav-apply-edit-btn").addEventListener("click", nav_window.apply_edit_selected.bind(nav_window));
|
document.getElementById("nav-apply-edit-btn").addEventListener("click", nav_window.apply_edit_selected.bind(nav_window));
|
||||||
var mode_checkboxes = document.getElementsByClassName("mode-checkbox");
|
var mode_checkboxes = document.getElementsByClassName("mode-checkbox");
|
||||||
for(let checkbox of mode_checkboxes){
|
for (let checkbox of mode_checkboxes) {
|
||||||
checkbox.addEventListener("change", nav_window.update_permissions_preview.bind(nav_window));
|
checkbox.addEventListener("change", nav_window.update_permissions_preview.bind(nav_window));
|
||||||
}
|
}
|
||||||
document.getElementById("pwd").addEventListener("input", nav_window.nav_bar_update_choices.bind(nav_window), false);
|
document.getElementById("pwd").addEventListener("input", nav_window.nav_bar_update_choices.bind(nav_window), false);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user