mirror of
https://github.com/Ysurac/openmptcprouter-feeds.git
synced 2025-03-09 15:40:03 +00:00
fix
This commit is contained in:
parent
6b7f0b4dba
commit
fd8b7384d5
104 changed files with 13356 additions and 31 deletions
147
luci-app-dockerman/luasrc/view/dockerman/apply_widget.htm
Normal file
147
luci-app-dockerman/luasrc/view/dockerman/apply_widget.htm
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<style type="text/css">
|
||||
#docker_apply_overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: none;
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
#docker_apply_overlay .alert-message {
|
||||
position: relative;
|
||||
top: 10%;
|
||||
width: 60%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-height: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#docker_apply_overlay .alert-message > h4,
|
||||
#docker_apply_overlay .alert-message > p,
|
||||
#docker_apply_overlay .alert-message > div {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
#docker_apply_overlay .alert-message > img {
|
||||
margin-right: 1em;
|
||||
flex-basis: 32px;
|
||||
}
|
||||
|
||||
body.apply-overlay-active {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body.apply-overlay-active #docker_apply_overlay {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var xhr = new XHR(),
|
||||
uci_apply_rollback = <%=math.max(luci.config and luci.config.apply and luci.config.apply.rollback or 90, 90)%>,
|
||||
uci_apply_holdoff = <%=math.max(luci.config and luci.config.apply and luci.config.apply.holdoff or 4, 1)%>,
|
||||
uci_apply_timeout = <%=math.max(luci.config and luci.config.apply and luci.config.apply.timeout or 5, 1)%>,
|
||||
uci_apply_display = <%=math.max(luci.config and luci.config.apply and luci.config.apply.display or 1.5, 1)%>,
|
||||
was_xhr_poll_running = false;
|
||||
|
||||
function docker_status_message(type, content) {
|
||||
document.getElementById('docker_apply_overlay') || document.body.insertAdjacentHTML("beforeend",'<div id="docker_apply_overlay"><div class="alert-message"></div></div>')
|
||||
var overlay = document.getElementById('docker_apply_overlay')
|
||||
message = overlay.querySelector('.alert-message');
|
||||
|
||||
if (message && type) {
|
||||
if (!message.classList.contains(type)) {
|
||||
message.classList.remove('notice');
|
||||
message.classList.remove('warning');
|
||||
message.classList.add(type);
|
||||
}
|
||||
|
||||
if (content)
|
||||
message.innerHTML = content;
|
||||
|
||||
document.body.classList.add('apply-overlay-active');
|
||||
document.body.scrollTop = document.documentElement.scrollTop = 0;
|
||||
if (!was_xhr_poll_running) {
|
||||
was_xhr_poll_running = XHR.running();
|
||||
XHR.halt();
|
||||
}
|
||||
}
|
||||
else {
|
||||
document.body.classList.remove('apply-overlay-active');
|
||||
|
||||
if (was_xhr_poll_running)
|
||||
XHR.run();
|
||||
}
|
||||
}
|
||||
|
||||
var loading_msg="Loading.."
|
||||
function uci_confirm_docker() {
|
||||
var tt;
|
||||
docker_status_message('notice');
|
||||
var call = function(r, resjson, duration) {
|
||||
if (r && r.status === 200 ) {
|
||||
var indicator = document.querySelector('.uci_change_indicator');
|
||||
if (indicator) indicator.style.display = 'none';
|
||||
docker_status_message('notice', '<%:Docker actions done.%>');
|
||||
document.body.classList.remove('apply-overlay-active');
|
||||
window.clearTimeout(tt);
|
||||
return;
|
||||
}
|
||||
loading_msg = resjson?resjson.info:loading_msg
|
||||
// var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
|
||||
var delay =1000
|
||||
window.setTimeout(function() {
|
||||
xhr.get('<%=url("admin/docker/confirm")%>', null, call, uci_apply_timeout * 1000);
|
||||
}, delay);
|
||||
};
|
||||
|
||||
var tick = function() {
|
||||
var now = Date.now();
|
||||
|
||||
docker_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> <span style="white-space:pre-line; word-break:break-all; font-family: \'Courier New\', Courier, monospace;">' +
|
||||
loading_msg + '</span>');
|
||||
|
||||
tt = window.setTimeout(tick, 200);
|
||||
ts = now;
|
||||
};
|
||||
|
||||
tick();
|
||||
/* wait a few seconds for the settings to become effective */
|
||||
window.setTimeout(call, Math.max(uci_apply_holdoff * 1000 , 1));
|
||||
}
|
||||
// document.getElementsByTagName("form")[0].addEventListener("submit", (e)=>{
|
||||
// uci_confirm_docker()
|
||||
// })
|
||||
|
||||
function fnSubmitForm(el){
|
||||
if (el.id != "cbid.table.1._new") {
|
||||
uci_confirm_docker()
|
||||
}
|
||||
}
|
||||
|
||||
<% if self.err then -%>
|
||||
docker_status_message('warning', '<span style="white-space:pre-line; word-break:break-all; font-family: \'Courier New\', Courier, monospace;">'+`<%=self.err%>`+'</span>');
|
||||
document.getElementById('docker_apply_overlay').addEventListener("click", (e)=>{
|
||||
docker_status_message()
|
||||
})
|
||||
<%- end %>
|
||||
|
||||
window.onload= function (){
|
||||
var buttons = document.querySelectorAll('input[type="submit"]');
|
||||
[].slice.call(buttons).forEach(function (el) {
|
||||
el.onclick = fnSubmitForm.bind(this, el);
|
||||
});
|
||||
|
||||
if(typeof(fnWindowLoad) == "function"){
|
||||
fnWindowLoad()
|
||||
}
|
||||
}
|
||||
|
||||
//]]></script>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<div style="display: inline-block;">
|
||||
<% if self:cfgvalue(section) ~= false then %>
|
||||
<input class="btn cbi-button cbi-button-<%=self.inputstyle or "button" %>" type="submit"" <% if self.disable then %>disabled <% end %><%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> />
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
</div>
|
||||
33
luci-app-dockerman/luasrc/view/dockerman/cbi/inlinevalue.htm
Normal file
33
luci-app-dockerman/luasrc/view/dockerman/cbi/inlinevalue.htm
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<div style="display: inline-block;">
|
||||
<!-- <%- if self.title then -%>
|
||||
<label class="cbi-value-title"<%= attr("for", cbid) %>>
|
||||
<%- if self.titleref then -%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=self.titleref%>"><%- end -%>
|
||||
<%-=self.title-%>
|
||||
<%- if self.titleref then -%></a><%- end -%>
|
||||
</label>
|
||||
<%- end -%> -->
|
||||
<%- if self.password then -%>
|
||||
<input type="password" style="position:absolute; left:-100000px" aria-hidden="true"<%=
|
||||
attr("name", "password." .. cbid)
|
||||
%> />
|
||||
<%- end -%>
|
||||
<input data-update="change"<%=
|
||||
attr("id", cbid) ..
|
||||
attr("name", cbid) ..
|
||||
attr("type", self.password and "password" or "text") ..
|
||||
attr("class", self.password and "cbi-input-password" or "cbi-input-text") ..
|
||||
attr("value", self:cfgvalue(section) or self.default) ..
|
||||
ifattr(self.password, "autocomplete", "new-password") ..
|
||||
ifattr(self.size, "size") ..
|
||||
ifattr(self.placeholder, "placeholder") ..
|
||||
ifattr(self.readonly, "readonly") ..
|
||||
ifattr(self.maxlength, "maxlength") ..
|
||||
ifattr(self.datatype, "data-type", self.datatype) ..
|
||||
ifattr(self.datatype, "data-optional", self.optional or self.rmempty) ..
|
||||
ifattr(self.combobox_manual, "data-manual", self.combobox_manual) ..
|
||||
ifattr(#self.keylist > 0, "data-choices", { self.keylist, self.vallist })
|
||||
%> />
|
||||
<%- if self.password then -%>
|
||||
<div class="btn cbi-button cbi-button-neutral" title="<%:Reveal/hide password%>" onclick="var e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'">∗</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<% if self:cfgvalue(self.section) then section = self.section %>
|
||||
<div class="cbi-section" id="cbi-<%=self.config%>-<%=section%>">
|
||||
<%+cbi/tabmenu%>
|
||||
<div class="cbi-section-node<% if self.tabs then %> cbi-section-node-tabbed<% end %>" id="cbi-<%=self.config%>-<%=section%>">
|
||||
<%+cbi/ucisection%>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<!-- /nsection -->
|
||||
10
luci-app-dockerman/luasrc/view/dockerman/cbi/xfvalue.htm
Normal file
10
luci-app-dockerman/luasrc/view/dockerman/cbi/xfvalue.htm
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<%+cbi/valueheader%>
|
||||
<input type="hidden" value="1"<%=
|
||||
attr("name", "cbi.cbe." .. self.config .. "." .. section .. "." .. self.option)
|
||||
%> />
|
||||
<input class="cbi-input-checkbox" data-update="click change" type="checkbox" <% if self.disable == 1 then %>disabled <% end %><%=
|
||||
attr("id", cbid) .. attr("name", cbid) .. attr("value", self.enabled or 1) ..
|
||||
ifattr((self:cfgvalue(section) or self.default) == self.enabled, "checked", "checked")
|
||||
%> />
|
||||
<label<%= attr("for", cbid)%>></label>
|
||||
<%+cbi/valuefooter%>
|
||||
28
luci-app-dockerman/luasrc/view/dockerman/container.htm
Normal file
28
luci-app-dockerman/luasrc/view/dockerman/container.htm
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<br>
|
||||
<ul class="cbi-tabmenu">
|
||||
<li id="cbi-tab-container_info"><a id="a-cbi-tab-container_info" href=""><%:Info%></a></li>
|
||||
<li id="cbi-tab-container_resources"><a id="a-cbi-tab-container_resources" href=""><%:Resources%></a></li>
|
||||
<li id="cbi-tab-container_stats"><a id="a-cbi-tab-container_stats" href=""><%:Stats%></a></li>
|
||||
<li id="cbi-tab-container_file"><a id="a-cbi-tab-container_file" href=""><%:File%></a></li>
|
||||
<li id="cbi-tab-container_console"><a id="a-cbi-tab-container_console" href=""><%:Console%></a></li>
|
||||
<li id="cbi-tab-container_inspect"><a id="a-cbi-tab-container_inspect" href=""><%:Inspect%></a></li>
|
||||
<li id="cbi-tab-container_logs"><a id="a-cbi-tab-container_logs" href=""><%:Logs%></a></li>
|
||||
</ul>
|
||||
|
||||
<script type="text/javascript">
|
||||
let re = /\/admin\/docker\/container\//
|
||||
let p = window.location.href
|
||||
let path = p.split(re)
|
||||
let container_id = path[1].split('/')[0] || path[1]
|
||||
let action = path[1].split('/')[1] || "info"
|
||||
let actions=["info","resources","stats","file","console","logs","inspect"]
|
||||
actions.forEach(function(item) {
|
||||
document.getElementById("a-cbi-tab-container_" + item).href= path[0]+"/admin/docker/container/"+container_id+'/'+item
|
||||
if (action === item) {
|
||||
document.getElementById("cbi-tab-container_" + item).className="cbi-tab"
|
||||
}
|
||||
else {
|
||||
document.getElementById("cbi-tab-container_" + item).className="cbi-tab-disabled"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<div class="cbi-map">
|
||||
<iframe id="terminal" style="width: 100%; min-height: 500px; border: none; border-radius: 3px;"></iframe>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
document.getElementById("terminal").src = window.location.protocol + "//" + window.location.hostname + ":7682";
|
||||
</script>
|
||||
|
|
@ -0,0 +1,332 @@
|
|||
<link rel="stylesheet" href="/luci-static/resources/dockerman/file-manager.css?v=@ver">
|
||||
<fieldset class="cbi-section fb-container">
|
||||
<input id="current-path" type="text" class="current-path cbi-input-text" value="/" />
|
||||
<div class="panel-container">
|
||||
<input type="file" name="upload_archive" accept="*/*"
|
||||
style="visibility:hidden; position: absolute;top: 0px; left: 0px;" multiple="multiple" id="upload_archive" />
|
||||
<button id="upload-file" class="upload-toggle cbi-button cbi-button-edit"><%:Upload%></button>
|
||||
</div>
|
||||
<div id="list-content"></div>
|
||||
</fieldset>
|
||||
<script type="text/javascript" src="<%=resource%>/dockerman/tar.min.js"></script>
|
||||
<script>
|
||||
String.prototype.replaceAll = function (search, replacement) {
|
||||
var target = this;
|
||||
return target.replace(new RegExp(search, 'g'), replacement);
|
||||
};
|
||||
(function () {
|
||||
var iwxhr = new XHR();
|
||||
var listElem = document.getElementById("list-content");
|
||||
listElem.onclick = handleClick;
|
||||
var currentPath;
|
||||
var pathElem = document.getElementById("current-path");
|
||||
pathElem.onblur = function () {
|
||||
update_list(this.value.trim());
|
||||
};
|
||||
pathElem.onkeydown = function (evt) {
|
||||
if (evt.keyCode == 13) {
|
||||
this.blur()
|
||||
evt.preventDefault()
|
||||
}
|
||||
};
|
||||
function removePath(filename, isdir) {
|
||||
var c = confirm('!!!<%:DELETING%> ' + filename + ' ... <%:PLEASE CONFIRM%>!!!');
|
||||
if (c) {
|
||||
iwxhr.get('<%=luci.dispatcher.build_url("admin/docker/container_remove_file")%>/<%=self.container%>',
|
||||
{
|
||||
path: concatPath(currentPath, filename),
|
||||
isdir: isdir
|
||||
},
|
||||
function (x, res) {
|
||||
if (res.ec === 0) {
|
||||
refresh_list(res.data, currentPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renamePath(filename) {
|
||||
var newname = prompt('%:Please input new filename%>: ', filename);
|
||||
if (newname) {
|
||||
newname = newname.trim();
|
||||
if (newname != filename) {
|
||||
var newpath = concatPath(currentPath, newname);
|
||||
iwxhr.get('<%=luci.dispatcher.build_url("admin/docker/container_rename_file")%>/<%=self.container%>',
|
||||
{
|
||||
filepath: concatPath(currentPath, filename),
|
||||
newpath: newpath
|
||||
},
|
||||
function (x, res) {
|
||||
if (res.ec === 0) {
|
||||
refresh_list(res.data, currentPath);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openpath(filename, dirname) {
|
||||
dirname = dirname || currentPath;
|
||||
window.open('<%=luci.dispatcher.build_url("admin/docker/container_get_archive")%>?id=<%=self.container%>&path='
|
||||
+ encodeURIComponent(dirname + '/' + filename) + '&filename='
|
||||
+ encodeURIComponent(filename))
|
||||
}
|
||||
|
||||
function getFileElem(elem) {
|
||||
if (elem.className.indexOf('-icon') > -1) {
|
||||
return elem;
|
||||
}
|
||||
else if (elem.parentNode.className.indexOf('-icon') > -1) {
|
||||
return elem.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
function concatPath(path, filename) {
|
||||
if (path === '/') {
|
||||
return path + filename;
|
||||
}
|
||||
else {
|
||||
return path.replace(/\/$/, '') + '/' + filename;
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(evt) {
|
||||
// evt.preventDefault();
|
||||
var targetElem = evt.target;
|
||||
var infoElem;
|
||||
if (targetElem.className.indexOf('cbi-button-remove') > -1) {
|
||||
infoElem = targetElem.parentNode.parentNode;
|
||||
removePath(infoElem.dataset['filename'], infoElem.dataset['isdir'])
|
||||
evt.preventDefault();
|
||||
location.reload()
|
||||
}
|
||||
else if (targetElem.className.indexOf('cbi-button-download') > -1) {
|
||||
infoElem = targetElem.parentNode.parentNode;
|
||||
openpath(targetElem.parentNode.parentNode.dataset['filename']);
|
||||
evt.preventDefault();
|
||||
}
|
||||
else if (targetElem.className.indexOf('cbi-button-rename') > -1) {
|
||||
renamePath(targetElem.parentNode.parentNode.dataset['filename']);
|
||||
evt.preventDefault();
|
||||
location.reload()
|
||||
}
|
||||
else if (targetElem = getFileElem(targetElem)) {
|
||||
if (targetElem.className.indexOf('parent-icon') > -1) {
|
||||
update_list(currentPath.replace(/\/[^/]+($|\/$)/, ''));
|
||||
}
|
||||
else if (targetElem.className.indexOf('file-icon') > -1) {
|
||||
openpath(targetElem.parentNode.dataset['filename']);
|
||||
}
|
||||
else if (targetElem.className.indexOf('link-icon') > -1) {
|
||||
infoElem = targetElem.parentNode;
|
||||
var filepath = infoElem.dataset['linktarget'];
|
||||
if (filepath) {
|
||||
if (infoElem.dataset['isdir'] === "1") {
|
||||
update_list(filepath);
|
||||
}
|
||||
else {
|
||||
var lastSlash = filepath.lastIndexOf('/')
|
||||
openpath(filepath.substring(lastSlash + 1), filepath.substring(0, lastSlash));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targetElem.className.indexOf('folder-icon') > -1) {
|
||||
update_list(concatPath(currentPath, targetElem.parentNode.dataset['filename']))
|
||||
}
|
||||
}
|
||||
}
|
||||
function refresh_list(filenames, path) {
|
||||
var listHtml = '<table class="cbi-section-table"><tbody>';
|
||||
if (path !== '/') {
|
||||
listHtml += '<tr class="cbi-section-table-row cbi-rowstyle-2"><td class="parent-icon" colspan="6"><strong>..</strong></td></tr>';
|
||||
}
|
||||
if (filenames) {
|
||||
for (var i = 0; i < filenames.length; i++) {
|
||||
var line = filenames[i]
|
||||
if (line) {
|
||||
var f = line.match(/(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+([\S\s]+)/);
|
||||
var isLink = f[1][0] === 'z' || f[1][0] === 'l' || f[1][0] === 'x';
|
||||
var o = {
|
||||
displayname: f[9],
|
||||
filename: isLink ? f[9].split(' -> ')[0] : f[9],
|
||||
perms: f[1],
|
||||
date: f[7] + ' ' + f[6] + ' ' + f[8],
|
||||
size: f[5],
|
||||
owner: f[3],
|
||||
icon: (f[1][0] === 'd') ? "folder-icon" : (isLink ? "link-icon" : "file-icon")
|
||||
};
|
||||
listHtml += '<tr class="cbi-section-table-row cbi-rowstyle-' + (1 + i % 2)
|
||||
+ '" data-filename="' + o.filename + '" data-isdir="' + Number(f[1][0] === 'd' || f[1][0] === 'z') + '"'
|
||||
+ ((f[1][0] === 'z' || f[1][0] === 'l') ? (' data-linktarget="' + f[9].split(' -> ')[1]) : '')
|
||||
+ '">'
|
||||
+ '<td class="cbi-value-field ' + o.icon + '">'
|
||||
+ '<strong>' + o.displayname + '</strong>'
|
||||
+ '</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-owner">' + o.owner + '</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-date">' + o.date + '</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-size">' + o.size + '</td>'
|
||||
+ '<td class="cbi-value-field cbi-value-perm">' + o.perms + '</td>'
|
||||
+ '<td class="cbi-section-table-cell">\
|
||||
<button class="btn cbi-button cbi-button-rename cbi-button-edit">'+ "<%:Rename%>" + '</button>\
|
||||
<button class="btn cbi-button cbi-button-download cbi-button-add">'+ "<%:Download%>" + '</button>\
|
||||
<button class="btn cbi-button cbi-button-remove">'+ "<%:Remove%>" + '</button>\
|
||||
</td>'
|
||||
+ '</tr>';
|
||||
}
|
||||
}
|
||||
}
|
||||
listHtml += "</table>";
|
||||
listElem.innerHTML = listHtml;
|
||||
}
|
||||
function update_list(path, opt) {
|
||||
opt = opt || {};
|
||||
path = concatPath(path, '');
|
||||
if (currentPath != path) {
|
||||
iwxhr.get('<%=luci.dispatcher.build_url("admin/docker/container_list_file")%>/<%=self.container%>',
|
||||
{ path: path },
|
||||
function (x, res) {
|
||||
if (res.ec === 0) {
|
||||
refresh_list(res.data, path);
|
||||
}
|
||||
else {
|
||||
refresh_list([], path);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (!opt.popState) {
|
||||
history.pushState({ path: path }, null, '?path=' + path);
|
||||
}
|
||||
currentPath = path;
|
||||
pathElem.value = currentPath;
|
||||
}
|
||||
};
|
||||
|
||||
async function file2Tar(tarFile, fileToLoad) {
|
||||
if (! fileToLoad) return
|
||||
function file2Byte(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onerror = () => {
|
||||
fileReader.abort();
|
||||
reject(new DOMException("Problem parsing input file."));
|
||||
};
|
||||
fileReader.onload = (fileLoadedEvent) => {
|
||||
resolve(ByteHelper.stringUTF8ToBytes(fileLoadedEvent.target.result));
|
||||
}
|
||||
fileReader.readAsBinaryString(file);
|
||||
})
|
||||
}
|
||||
const x = await file2Byte(fileToLoad)
|
||||
return fileByte2Tar(tarFile, fileToLoad.name, x).downloadAs(fileToLoad.name + ".tar")
|
||||
}
|
||||
|
||||
function fileByte2Tar(tarFile, fileName, fileBytes) {
|
||||
if (!tarFile) tarFile = TarFile.create(fileName)
|
||||
var tarHeader = TarFileEntryHeader.default();
|
||||
var tarFileEntryHeader = new TarFileEntryHeader
|
||||
(
|
||||
// ByteHelper.bytesToStringUTF8(fileName),
|
||||
fileName,
|
||||
tarHeader.fileMode,
|
||||
tarHeader.userIDOfOwner,
|
||||
tarHeader.userIDOfGroup,
|
||||
fileBytes.length, // fileSizeInBytes,
|
||||
tarHeader.timeModifiedInUnixFormat, // todo
|
||||
0, // checksum,
|
||||
TarFileTypeFlag.Instances().Normal,
|
||||
tarHeader.nameOfLinkedFile,
|
||||
tarHeader.uStarIndicator,
|
||||
tarHeader.uStarVersion,
|
||||
tarHeader.userNameOfOwner,
|
||||
tarHeader.groupNameOfOwner,
|
||||
tarHeader.deviceNumberMajor,
|
||||
tarHeader.deviceNumberMinor,
|
||||
tarHeader.filenamePrefix
|
||||
);
|
||||
|
||||
tarFileEntryHeader.checksumCalculate();
|
||||
var entryForFileToAdd = new TarFileEntry
|
||||
(
|
||||
tarFileEntryHeader,
|
||||
fileBytes
|
||||
);
|
||||
|
||||
tarFile.entries.push(entryForFileToAdd);
|
||||
return tarFile
|
||||
}
|
||||
|
||||
var btnUpload = document.getElementById('upload-file');
|
||||
|
||||
btnUpload.onclick = function (e) {
|
||||
document.getElementById("upload_archive").click()
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
let fileLoad = document.getElementById('upload_archive')
|
||||
fileLoad.onchange = async function (e) {
|
||||
let uploadArchive = document.getElementById('upload_archive')
|
||||
// let uploadPath = document.getElementById('path').value
|
||||
if (!uploadArchive.value) {
|
||||
docker_status_message('warning', "<%:Please input the PATH and select the file !%>")
|
||||
document.getElementById('docker_apply_overlay').addEventListener("click", (e) => {
|
||||
docker_status_message()
|
||||
})
|
||||
return
|
||||
}
|
||||
docker_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" style="vertical-align:middle" /> <span style="white-space:pre-line; word-break:break-all; font-family: \'Courier New\', Courier, monospace;">' +
|
||||
'Uploading...' + '</span>');
|
||||
Globals.Instance.tarFile = TarFile.create("Archive.tar")
|
||||
let bytesToWriteAsBlob
|
||||
for (let i = 0; i < uploadArchive.files.length; i++) {
|
||||
let fileName = uploadArchive.files[i].name
|
||||
bytesToWriteAsBlob = await file2Tar(Globals.Instance.tarFile, uploadArchive.files[i])
|
||||
}
|
||||
let formData = new FormData()
|
||||
formData.append('upload-filename', "Archive.tar")
|
||||
formData.append('upload-path', concatPath(currentPath, ''))
|
||||
formData.append('upload-archive', bytesToWriteAsBlob)
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.open("POST", '<%=luci.dispatcher.build_url("admin/docker/container_put_archive")%>/<%=self.container%>', true)
|
||||
xhr.onload = function () {
|
||||
if (xhr.status == 200) {
|
||||
uploadArchive.value = ''
|
||||
docker_status_message('notice', "<%:Upload Success%>")
|
||||
function sleep(time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time))
|
||||
}
|
||||
sleep(800).then(() => {
|
||||
location.reload()
|
||||
})
|
||||
}
|
||||
else {
|
||||
// docker_status_message('warning', "<%:Upload Error%>:" + xhr.statusText)
|
||||
docker_status_message('warning', "<%:Upload Error%>:" + '<span style="white-space:pre-line; word-break:break-all; font-family: \'Courier New\', Courier, monospace;">' +
|
||||
JSON.parse(xhr.response).message + '</span>')
|
||||
}
|
||||
document.getElementById('docker_apply_overlay').addEventListener("click", (e) => {
|
||||
docker_status_message()
|
||||
})
|
||||
}
|
||||
xhr.send(formData)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (evt) {
|
||||
var initPath = '/';
|
||||
if (/path=([/\w\.\-\_]+)/.test(location.search)) {
|
||||
initPath = RegExp.$1;
|
||||
}
|
||||
update_list(initPath, { popState: true });
|
||||
});
|
||||
window.addEventListener('popstate', function (evt) {
|
||||
var path = '/';
|
||||
if (evt.state && evt.state.path) {
|
||||
path = evt.state.path;
|
||||
}
|
||||
update_list(path, { popState: true });
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
81
luci-app-dockerman/luasrc/view/dockerman/container_stats.htm
Normal file
81
luci-app-dockerman/luasrc/view/dockerman/container_stats.htm
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<script type="text/javascript">//<![CDATA[
|
||||
let last_bw_tx
|
||||
let last_bw_rx
|
||||
let interval = 3
|
||||
|
||||
function progressbar(v, m, pc, np, f) {
|
||||
m = m || 100
|
||||
|
||||
return String.format(
|
||||
'<div style="width:100%%; max-width:500px; position:relative; border:1px solid #999999">' +
|
||||
'<div style="background-color:#CCCCCC; width:%d%%; height:15px">' +
|
||||
'<div style="position:absolute; left:0; top:0; text-align:center; width:100%%; color:#000000">' +
|
||||
'<small>%s '+(f?f:'/')+' %s ' + (np ? "" : '(%d%%)') + '</small>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>', pc, v, m, pc, f
|
||||
);
|
||||
}
|
||||
|
||||
function niceBytes(bytes, decimals) {
|
||||
if (bytes == 0) return '0 Bytes';
|
||||
var k = 1000,
|
||||
dm = decimals + 1 || 3,
|
||||
sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
|
||||
i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
XHR.poll(interval, '<%=luci.dispatcher.build_url("admin/docker/container_stats")%>/<%=self.container_id%>', { status: 1 },
|
||||
function (x, info) {
|
||||
var e;
|
||||
|
||||
if (e = document.getElementById('cbi-table-cpu-value'))
|
||||
e.innerHTML = progressbar(
|
||||
(info.cpu_percent), 100, (info.cpu_percent ? info.cpu_percent : 0));
|
||||
if (e = document.getElementById('cbi-table-memory-value'))
|
||||
e.innerHTML = progressbar(
|
||||
niceBytes(info.memory.mem_useage),
|
||||
niceBytes(info.memory.mem_limit),
|
||||
((100 / (info.memory.mem_limit ? info.memory.mem_limit : 100)) * (info.memory.mem_useage ? info.memory.mem_useage : 0))
|
||||
);
|
||||
|
||||
for (var eth in info.bw_rxtx) {
|
||||
if (!document.getElementById("cbi-table-speed_" + eth + "-value")) {
|
||||
let tab = document.getElementById("cbi-table-cpu").parentNode
|
||||
let div = document.getElementById('cbi-table-cpu').cloneNode(true);
|
||||
div.id = "cbi-table-speed_" + eth;
|
||||
div.children[0].innerHTML = "<%:Upload/Download%>: " + eth
|
||||
div.children[1].id = "cbi-table-speed_" + eth + "-value"
|
||||
tab.appendChild(div)
|
||||
}
|
||||
if (!document.getElementById("cbi-table-network_" + eth + "-value")) {
|
||||
let tab = document.getElementById("cbi-table-cpu").parentNode
|
||||
let div = document.getElementById('cbi-table-cpu').cloneNode(true);
|
||||
div.id = "cbi-table-network_" + eth;
|
||||
div.children[0].innerHTML = "<%:TX/RX%>: " + eth
|
||||
div.children[1].id = "cbi-table-network_" + eth + "-value"
|
||||
tab.appendChild(div)
|
||||
}
|
||||
e = document.getElementById("cbi-table-network_" + eth + "-value")
|
||||
e.innerHTML = progressbar(
|
||||
'↑'+niceBytes(info.bw_rxtx[eth].bw_tx),
|
||||
'↓'+niceBytes(info.bw_rxtx[eth].bw_rx),
|
||||
null,
|
||||
true, " "
|
||||
);
|
||||
e = document.getElementById("cbi-table-speed_" + eth + "-value")
|
||||
if (! last_bw_tx) last_bw_tx = info.bw_rxtx[eth].bw_tx
|
||||
if (! last_bw_rx) last_bw_rx = info.bw_rxtx[eth].bw_rx
|
||||
e.innerHTML = progressbar(
|
||||
'↑'+niceBytes((info.bw_rxtx[eth].bw_tx - last_bw_tx)/interval)+'/s',
|
||||
'↓'+niceBytes((info.bw_rxtx[eth].bw_rx - last_bw_rx)/interval)+'/s',
|
||||
null,
|
||||
true, " "
|
||||
);
|
||||
last_bw_tx = info.bw_rxtx[eth].bw_tx
|
||||
last_bw_rx = info.bw_rxtx[eth].bw_rx
|
||||
}
|
||||
|
||||
});
|
||||
//]]></script>
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
<script type="text/javascript">
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
function niceBytes(x) {
|
||||
let l = 0, n = parseInt(x, 10) || 0;
|
||||
while (n >= 1024 && ++l) {
|
||||
n = n / 1024;
|
||||
}
|
||||
return (n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]);
|
||||
}
|
||||
|
||||
fnWindowLoad = function () {
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin/docker/get_system_df")%>/', null, (x, info)=>{
|
||||
if(!info || !info.Containers || !info.Containers.forEach) return
|
||||
info.Containers.forEach(item=>{
|
||||
const size_c = document.getElementsByClassName("container_size_" + item.Id)
|
||||
size_c[0].title = "RW Size: " + niceBytes(item.SizeRw) + " / RootFS Size(Include Image): " + niceBytes(item.SizeRootFs)
|
||||
size_c[0].innerText = "Size: " + niceBytes(item.SizeRw) + "/" + niceBytes(item.SizeRootFs)
|
||||
})
|
||||
})
|
||||
let lines = document.querySelectorAll('[id^=cbi-containers-]')
|
||||
let last_bw_tx = {}
|
||||
let last_bw_rx = {}
|
||||
let interval = 30
|
||||
let containers = []
|
||||
lines.forEach((item) => {
|
||||
let containerId = item.id.match(/cbi-containers-.+_id_(.*)/)
|
||||
if (!containerId) { return }
|
||||
containerId = containerId[1]
|
||||
if (item.getElementsByClassName("container_not_running").length > 0) { return }
|
||||
XHR.poll(interval, '<%=luci.dispatcher.build_url("admin/docker/container_stats")%>/' + containerId, null, (x, info) => {
|
||||
// handle stats info
|
||||
if (!info) { return }
|
||||
item.childNodes.forEach((cell) => {
|
||||
if (cell && cell.attributes) {
|
||||
if (cell.getAttribute("data-name") == "_status" || cell.childNodes[1] && cell.childNodes[1].id.match(/_status/)) {
|
||||
let runningStats = cell.getElementsByClassName("container_cpu_status")
|
||||
runningStats[0].innerText = "CPU: " + info.cpu_percent + "%"
|
||||
runningStats = cell.getElementsByClassName("container_mem_status")
|
||||
runningStats[0].innerText = "MEM: " + niceBytes(info.memory.mem_useage)
|
||||
runningStats = cell.getElementsByClassName("container_network_status")
|
||||
for (var eth in info.bw_rxtx) {
|
||||
if (last_bw_tx[containerId] != undefined && last_bw_rx[containerId] != undefined) {
|
||||
runningStats[0].innerText = '↑' + niceBytes((info.bw_rxtx[eth].bw_tx - last_bw_tx[containerId]) / interval) + '/s ↓' + niceBytes((info.bw_rxtx[eth].bw_rx - last_bw_rx[containerId]) / interval) + '/s'
|
||||
}
|
||||
last_bw_rx[containerId] = info.bw_rxtx[eth].bw_rx
|
||||
last_bw_tx[containerId] = info.bw_rxtx[eth].bw_tx
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
// containers.push(containerId)
|
||||
})
|
||||
// XHR.post('<%=luci.dispatcher.build_url("admin/docker/containers_stats")%>', {
|
||||
// containers: JSON.stringify(containers)
|
||||
// }, (x, info) => {
|
||||
// lines.forEach((item) => {
|
||||
// if (!info) { return }
|
||||
|
||||
// let containerId = item.id.match(/cbi-containers-.+_id_(.*)/)
|
||||
// if (!containerId) { return }
|
||||
// containerId = containerId[1]
|
||||
// if (!info[containerId]) { return }
|
||||
// infoC = info[containerId]
|
||||
// if (item.getElementsByClassName("container_not_running").length > 0) { return }
|
||||
// item.childNodes.forEach((cell) => {
|
||||
// if (cell && cell.attributes) {
|
||||
// if (cell.getAttribute("data-name") == "_status" || cell.childNodes[1] && cell.childNodes[1].id.match(/_status/)) {
|
||||
// let runningStats = cell.getElementsByClassName("container_cpu_status")
|
||||
// runningStats[0].innerText = "CPU: " + infoC.cpu_percent + "%"
|
||||
// runningStats = cell.getElementsByClassName("container_mem_status")
|
||||
// runningStats[0].innerText = "MEM: " + niceBytes(infoC.memory.mem_useage)
|
||||
// runningStats = cell.getElementsByClassName("container_network_status")
|
||||
// for (var eth in infoC.bw_rxtx) {
|
||||
// if (last_bw_tx[containerId] != undefined && last_bw_rx[containerId] != undefined) {
|
||||
// runningStats[0].innerText = '↑' + niceBytes((infoC.bw_rxtx[eth].bw_tx - last_bw_tx[containerId]) / interval) + '/s ↓' + niceBytes((infoC.bw_rxtx[eth].bw_rx - last_bw_rx[containerId]) / interval) + '/s'
|
||||
// }
|
||||
// last_bw_rx[containerId] = infoC.bw_rxtx[eth].bw_rx
|
||||
// last_bw_tx[containerId] = infoC.bw_rxtx[eth].bw_tx
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
|
||||
|
||||
XHR.run()
|
||||
XHR.halt()
|
||||
}
|
||||
</script>
|
||||
104
luci-app-dockerman/luasrc/view/dockerman/images_import.htm
Normal file
104
luci-app-dockerman/luasrc/view/dockerman/images_import.htm
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<input type="text" class="cbi-input-text" name="isrc" placeholder="http://host/image.tar" id="isrc" />
|
||||
<input type="text" class="cbi-input-text" name="itag" placeholder="repository:tag" id="itag" />
|
||||
<div style="display: inline-block;">
|
||||
<input type="button"" class="btn cbi-button cbi-button-add" id="btnimport" name="import" value="<%:Import%>" <% if self.disable then %>disabled <% end %>/>
|
||||
<input type="file" id="file_import" style="visibility:hidden; position: absolute;top: 0px; left: 0px;" />
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
let btnImport = document.getElementById('btnimport')
|
||||
let valISrc = document.getElementById('isrc')
|
||||
let valITag = document.getElementById('itag')
|
||||
btnImport.onclick = function (e) {
|
||||
if (valISrc.value == "") {
|
||||
document.getElementById("file_import").click()
|
||||
return
|
||||
}
|
||||
else {
|
||||
let formData = new FormData()
|
||||
formData.append('src', valISrc.value)
|
||||
formData.append('tag', valITag.value)
|
||||
let xhr = new XMLHttpRequest()
|
||||
uci_confirm_docker()
|
||||
xhr.open("POST", "<%=luci.dispatcher.build_url('admin/docker/images_import')%>", true)
|
||||
xhr.onload = function () {
|
||||
location.reload()
|
||||
}
|
||||
xhr.send(formData)
|
||||
}
|
||||
}
|
||||
|
||||
let fileimport = document.getElementById('file_import')
|
||||
fileimport.onchange = function (e) {
|
||||
let fileimport = document.getElementById('file_import')
|
||||
if (!fileimport.value) {
|
||||
return
|
||||
}
|
||||
let valITag = document.getElementById('itag')
|
||||
let fileName = fileimport.files[0].name
|
||||
let formData = new FormData()
|
||||
formData.append('upload-filename', fileName)
|
||||
formData.append('tag', valITag.value)
|
||||
formData.append('upload-archive', fileimport.files[0])
|
||||
let xhr = new XMLHttpRequest()
|
||||
uci_confirm_docker()
|
||||
xhr.open("POST", "<%=luci.dispatcher.build_url('admin/docker/images_import')%>", true)
|
||||
xhr.onload = function () {
|
||||
fileimport.value = ''
|
||||
location.reload()
|
||||
}
|
||||
xhr.send(formData)
|
||||
}
|
||||
|
||||
let new_tag = function (image_id) {
|
||||
let new_tag = prompt("<%:New tag%>\n<%:Image%>" + "ID: " + image_id + "\n<%:Please input new tag%>:", "")
|
||||
if (new_tag) {
|
||||
(new XHR()).post("<%=luci.dispatcher.build_url('admin/docker/images_tag')%>",
|
||||
{
|
||||
id: image_id,
|
||||
tag: new_tag
|
||||
},
|
||||
function (r) {
|
||||
if (r.status == 201) {
|
||||
location.reload()
|
||||
}
|
||||
else {
|
||||
docker_status_message('warning', 'Image: untagging ' + tag + '...fail code:' + r.status + r.statusText);
|
||||
document.getElementById('docker_apply_overlay').addEventListener(
|
||||
"click",
|
||||
(e)=>{
|
||||
docker_status_message()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let un_tag = function (tag) {
|
||||
if (tag.match("<none>"))
|
||||
return
|
||||
if (confirm("<%:Remove tag%>: " + tag + " ?")) {
|
||||
(new XHR()).post("<%=luci.dispatcher.build_url('admin/docker/images_untag')%>",
|
||||
{
|
||||
tag: tag
|
||||
},
|
||||
function (r) {
|
||||
if (r.status == 200) {
|
||||
location.reload()
|
||||
}
|
||||
else {
|
||||
docker_status_message('warning', 'Image: untagging ' + tag + '...fail code:' + r.status + r.statusText);
|
||||
document.getElementById('docker_apply_overlay').addEventListener(
|
||||
"click",
|
||||
(e)=>{
|
||||
docker_status_message()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
40
luci-app-dockerman/luasrc/view/dockerman/images_load.htm
Normal file
40
luci-app-dockerman/luasrc/view/dockerman/images_load.htm
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<div style="display: inline-block;">
|
||||
<input type="button"" class="btn cbi-button cbi-button-add" id="btnload" name="load" value="<%:Load%>" <% if self.disable then %>disabled <% end %>/>
|
||||
<input type="file" id="file_load" style="visibility:hidden; position: absolute;top: 0px; left: 0px;" accept="application/x-tar" />
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
let btnLoad = document.getElementById('btnload')
|
||||
btnLoad.onclick = function (e) {
|
||||
document.getElementById("file_load").click()
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
let fileLoad = document.getElementById('file_load')
|
||||
fileLoad.onchange = function(e){
|
||||
let fileLoad = document.getElementById('file_load')
|
||||
if (!fileLoad.value) {
|
||||
return
|
||||
}
|
||||
let fileName = fileLoad.files[0].name
|
||||
let formData = new FormData()
|
||||
formData.append('upload-filename', fileName)
|
||||
formData.append('upload-archive', fileLoad.files[0])
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.open("POST", '<%=luci.dispatcher.build_url("admin/docker/images_load")%>', true)
|
||||
xhr.onload = function() {
|
||||
if (xhr.status == 200) {
|
||||
docker_status_message('notice', xhr.statusText)
|
||||
function sleep(time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time))
|
||||
}
|
||||
sleep(1500).then(() => {
|
||||
location.reload()
|
||||
})
|
||||
} else {
|
||||
location.reload()
|
||||
}
|
||||
}
|
||||
uci_confirm_docker()
|
||||
xhr.send(formData)
|
||||
}
|
||||
</script>
|
||||
13
luci-app-dockerman/luasrc/view/dockerman/logs.htm
Normal file
13
luci-app-dockerman/luasrc/view/dockerman/logs.htm
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<% if self.title == "Events" then %>
|
||||
<%+header%>
|
||||
<h2 name="content"><%:Docker - Events%></h2>
|
||||
<div class="cbi-section">
|
||||
<h3><%:Events%></h3>
|
||||
<% end %>
|
||||
<div id="content_syslog">
|
||||
<textarea readonly="readonly" wrap="off" rows="<%=self.syslog:cmatch('\n')+2%>" id="syslog"><%=self.syslog:pcdata()%></textarea>
|
||||
</div>
|
||||
<% if self.title == "Events" then %>
|
||||
</div>
|
||||
<%+footer%>
|
||||
<% end %>
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<style type="text/css">
|
||||
#dialog_reslov {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: none;
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
#dialog_reslov .dialog_box {
|
||||
position: relative;
|
||||
background: rgba(255, 255, 255);
|
||||
top: 10%;
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height:auto;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#dialog_reslov .dialog_line {
|
||||
margin-top: .5em;
|
||||
margin-bottom: .5em;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
#dialog_reslov .dialog_box>h4,
|
||||
#dialog_reslov .dialog_box>p,
|
||||
#dialog_reslov .dialog_box>div {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
#dialog_reslov .dialog_box>img {
|
||||
margin-right: 1em;
|
||||
flex-basis: 32px;
|
||||
}
|
||||
|
||||
body.dialog-reslov-active {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body.dialog-reslov-active #dialog_reslov {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
function close_reslov_dialog() {
|
||||
document.body.classList.remove('dialog-reslov-active')
|
||||
document.documentElement.style.overflowY = 'scroll'
|
||||
}
|
||||
|
||||
function reslov_container() {
|
||||
let s = document.getElementById('cmd-line-status')
|
||||
|
||||
if (!s)
|
||||
return
|
||||
|
||||
let cmd_line = document.getElementById("dialog_reslov_text").value;
|
||||
if (cmd_line == null || cmd_line == "") {
|
||||
return
|
||||
}
|
||||
|
||||
cmd_line = cmd_line.replace(/(^\s*)/g,"")
|
||||
if (!cmd_line.match(/^docker\s+(run|create)/)) {
|
||||
s.innerHTML = "<font color='red'><%:Command line Error%></font>"
|
||||
return
|
||||
}
|
||||
|
||||
let reg_space = /\s+/g
|
||||
let reg_muti_line= /\\\s*\n/g
|
||||
// reg_rem =/(?<!\\)`#.+(?<!\\)`/g // the command has `# `
|
||||
let reg_rem =/`#.+`/g// the command has `# `
|
||||
cmd_line = cmd_line.replace(/^docker\s+(run|create)/,"DOCKERCLI").replace(reg_rem, " ").replace(reg_muti_line, " ").replace(reg_space, " ")
|
||||
console.log(cmd_line)
|
||||
window.location.href = '<%=luci.dispatcher.build_url("admin/docker/newcontainer")%>/' + encodeURI(cmd_line)
|
||||
}
|
||||
|
||||
function clear_text(){
|
||||
let s = document.getElementById('cmd-line-status')
|
||||
s.innerHTML = ""
|
||||
}
|
||||
|
||||
function show_reslov_dialog() {
|
||||
document.getElementById('dialog_reslov') || document.body.insertAdjacentHTML("beforeend", '<div id="dialog_reslov"><div class="dialog_box"><div class="dialog_line"></div><div class="dialog_line"><span><%:Plese input <docker create/run> command line:%></span><br><span id="cmd-line-status"></span></div><div class="dialog_line"><textarea class="cbi-input-textarea" id="dialog_reslov_text" style="width: 100%; height:100%;" rows="15" onkeyup="clear_text()" placeholder="docker run -d alpine sh"></textarea></div><div class="dialog_line" style="text-align: right;"><input type="button" class="btn cbi-button cbi-button-apply" type="submit" value="<%:Submit%>" onclick="reslov_container()"/> <input type="button" class="btn cbi-button cbi-button-reset" type="reset" value="<%:Cancel%>" onclick="close_reslov_dialog()" /></div><div class="dialog_line"></div></div></div>')
|
||||
document.body.classList.add('dialog-reslov-active')
|
||||
let s = document.getElementById('cmd-line-status')
|
||||
s.innerHTML = ""
|
||||
document.documentElement.style.overflowY = 'hidden'
|
||||
}
|
||||
</script>
|
||||
<%+cbi/valueheader%>
|
||||
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" value="<%:Command line%>" onclick="show_reslov_dialog()" />
|
||||
|
||||
<%+cbi/valuefooter%>
|
||||
197
luci-app-dockerman/luasrc/view/dockerman/overview.htm
Normal file
197
luci-app-dockerman/luasrc/view/dockerman/overview.htm
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<style>
|
||||
/*!
|
||||
Pure v1.0.1
|
||||
Copyright 2013 Yahoo!
|
||||
Licensed under the BSD License.
|
||||
https://github.com/pure-css/pure/blob/master/LICENSE.md
|
||||
*/
|
||||
.pure-g {
|
||||
letter-spacing: -.31em;
|
||||
text-rendering: optimizespeed;
|
||||
font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-flow: row wrap;
|
||||
-ms-flex-flow: row wrap;
|
||||
flex-flow: row wrap;
|
||||
-webkit-align-content: flex-start;
|
||||
-ms-flex-line-pack: start;
|
||||
align-content: flex-start
|
||||
}
|
||||
|
||||
.pure-u {
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
letter-spacing: normal;
|
||||
word-spacing: normal;
|
||||
vertical-align: top;
|
||||
text-rendering: auto
|
||||
}
|
||||
|
||||
.pure-g [class*=pure-u] {
|
||||
font-family: sans-serif
|
||||
}
|
||||
|
||||
.pure-u-1-4,
|
||||
.pure-u-2-5,
|
||||
.pure-u-3-5 {
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
letter-spacing: normal;
|
||||
word-spacing: normal;
|
||||
vertical-align: top;
|
||||
text-rendering: auto
|
||||
}
|
||||
|
||||
.pure-u-1-4 {
|
||||
width: 25%
|
||||
}
|
||||
|
||||
.pure-u-2-5 {
|
||||
width: 40%
|
||||
}
|
||||
|
||||
.pure-u-3-5 {
|
||||
width: 60%
|
||||
}
|
||||
|
||||
.status {
|
||||
margin: 1rem -0.5rem 1rem -0.5rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
margin: 0.5rem 0.5rem;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
font-family: inherit;
|
||||
min-width: inherit;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
border: 1px solid rgba(0, 0, 0, .05);
|
||||
border-radius: .375rem;
|
||||
box-shadow: 0 0 2rem 0 rgba(136, 152, 170, .15);
|
||||
}
|
||||
|
||||
.img-con {
|
||||
margin: 1rem;
|
||||
min-width: 4rem;
|
||||
max-width: 4rem;
|
||||
min-height: 4rem;
|
||||
max-height: 4rem;
|
||||
}
|
||||
|
||||
.block h4 {
|
||||
font-size: .8125rem;
|
||||
font-weight: 600;
|
||||
margin: 1rem;
|
||||
color: #8898aa !important;
|
||||
line-height: 1.8em;
|
||||
}
|
||||
|
||||
.cbi-section-table-cell {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 700px) {
|
||||
.pure-u-1-4 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.cbi-button-add {
|
||||
position: fixed;
|
||||
padding: 0.3rem 0.5rem;
|
||||
z-index: 1000;
|
||||
width: 50px !important;
|
||||
height: 50px;
|
||||
bottom: 90px;
|
||||
right: 5px;
|
||||
font-size: 16px;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
background-color: #fb6340 !important;
|
||||
border-color: #fb6340 !important;
|
||||
box-shadow: 0 0 1rem 0 rgba(136, 152, 170, .75);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="pure-g status">
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="<%=resource%>/dockerman/containers.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-3-5">
|
||||
<h4 style="text-align: right; font-size: 1rem"><%:Containers%></h4>
|
||||
<h4 style="text-align: right;">
|
||||
<%- if self.containers_total ~= "-" then -%><a href='<%=luci.dispatcher.build_url("admin/docker/containers")%>'><%- end -%>
|
||||
<span style="font-size: 2rem; color: #2dce89;"><%=self.containers_running%></span>
|
||||
<span style="font-size: 1rem; color: #8898aa !important;">/<%=self.containers_total%></span>
|
||||
<%- if self.containers_total ~= "-" then -%></a><%- end -%>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="<%=resource%>/dockerman/images.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-3-5">
|
||||
<h4 style="text-align: right; font-size: 1rem"><%:Images%></h4>
|
||||
<h4 style="text-align: right;">
|
||||
<%- if self.images_total ~= "-" then -%><a href='<%=luci.dispatcher.build_url("admin/docker/images")%>'><%- end -%>
|
||||
<span style="font-size: 2rem; color: #2dce89;"><%=self.images_used%></span>
|
||||
<span style="font-size: 1rem; color: #8898aa !important;">/<%=self.images_total%></span>
|
||||
<%- if self.images_total ~= "-" then -%></a><%- end -%>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="<%=resource%>/dockerman/networks.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-3-5">
|
||||
<h4 style="text-align: right; font-size: 1rem"><%:Networks%></h4>
|
||||
<h4 style="text-align: right;">
|
||||
<%- if self.networks_total ~= "-" then -%><a href='<%=luci.dispatcher.build_url("admin/docker/networks")%>'><%- end -%>
|
||||
<span style="font-size: 2rem; color: #2dce89;"><%=self.networks_total%></span>
|
||||
<!-- <span style="font-size: 1rem; color: #8898aa !important;">/20</span> -->
|
||||
<%- if self.networks_total ~= "-" then -%></a><%- end -%>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="<%=resource%>/dockerman/volumes.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-3-5">
|
||||
<h4 style="text-align: right; font-size: 1rem"><%:Volumes%></h4>
|
||||
<h4 style="text-align: right;">
|
||||
<%- if self.volumes_total ~= "-" then -%><a href='<%=luci.dispatcher.build_url("admin/docker/volumes")%>'><%- end -%>
|
||||
<span style="font-size: 2rem; color: #2dce89;"><%=self.volumes_total%></span>
|
||||
<!-- <span style="font-size: 1rem; color: #8898aa !important;">/20</span> -->
|
||||
<%- if self.volumes_total ~= "-" then -%></a><%- end -%>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
21
luci-app-dockerman/luasrc/view/dockerman/volume_size.htm
Normal file
21
luci-app-dockerman/luasrc/view/dockerman/volume_size.htm
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script type="text/javascript">
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
function niceBytes(x) {
|
||||
let l = 0, n = parseInt(x, 10) || 0;
|
||||
while (n >= 1024 && ++l) {
|
||||
n = n / 1024;
|
||||
}
|
||||
return (n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]);
|
||||
}
|
||||
|
||||
fnWindowLoad = function () {
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin/docker/get_system_df")%>/', null, (x, info)=>{
|
||||
if(!info || !info.Volumes || !info.Volumes.forEach) return
|
||||
info.Volumes.forEach(item=>{
|
||||
console.log(info)
|
||||
const size_c = document.getElementsByClassName("volume_size_" + item.Name)
|
||||
size_c[0].innerText = item.UsageData ? niceBytes(item.UsageData.Size) : '-'
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue