Merge changes for cephfs-dir-stats and light mode

This commit is contained in:
joshuaboud 2021-05-27 11:52:04 -03:00
commit b59acf84d5
No known key found for this signature in database
GPG Key ID: 17EFB59E2A8BF50E
3 changed files with 289 additions and 92 deletions

View File

@ -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%;
}

View File

@ -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>

View File

@ -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);