mirror of
https://github.com/unraid/webgui.git
synced 2026-05-06 20:30:50 -05:00
Merge remote-tracking branch 'upstream/master' into Intel-processor-core-types
This commit is contained in:
+2
-1
@@ -71,4 +71,5 @@ emhttp/plugins/node_modules/
|
||||
emhttp/plugins/.prettierignore
|
||||
emhttp/plugins/.prettierrc
|
||||
emhttp/plugins/package-lock.json
|
||||
emhttp/plugins/package.json
|
||||
emhttp/plugins/package.json
|
||||
emhttp/plugins/pnpm-lock.yaml
|
||||
Vendored
+3
-1
@@ -5,6 +5,8 @@
|
||||
"bmewburn.vscode-intelephense-client",
|
||||
"foxundermoon.shell-format",
|
||||
"timonwong.shellcheck",
|
||||
"esbenp.prettier-vscode"
|
||||
"esbenp.prettier-vscode",
|
||||
"phoenisx.cssvar",
|
||||
"usernamehw.errorlens",
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+5
-1
@@ -79,5 +79,9 @@
|
||||
"zip",
|
||||
"zlib",
|
||||
"libvirt-php"
|
||||
]
|
||||
],
|
||||
"search.exclude": {
|
||||
"emhttp/webGui/**/*": true
|
||||
},
|
||||
"php-cs-fixer.executablePath": "${extensionPath}/php-cs-fixer.phar"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
table.ups thead tr th{width:16.6%;padding-left:10px}
|
||||
table.ups tbody tr td{padding-left:10px;font-weight:bold}
|
||||
tr.ups{height:3rem;line-height:3rem}
|
||||
i.ups{margin-right:8px}
|
||||
table.ups thead tr th {
|
||||
width: 16.6%;
|
||||
padding-left: 10px;
|
||||
}
|
||||
table.ups tbody tr td {
|
||||
padding-left: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
tr.ups {
|
||||
height: 3rem;
|
||||
line-height: 3rem;
|
||||
}
|
||||
i.ups {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,7 @@ $top = in_array($theme,['white','black']) ? 40 : 20;
|
||||
$busy = "<i class='fa fa-spin fa-circle-o-notch'></i> "._('Please wait')."... "._('starting up containers');
|
||||
$cpus = cpu_list();
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.ui.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<table id="docker_containers" class="tablesorter shift">
|
||||
<thead><tr><th><a id="resetsort" class="nohand" onclick="resetSorting()" title="_(Reset sorting)_"><i class="fa fa-th-list"></i></a>_(Application)_</th><th>_(Version)_</th><th>_(Network)_</th><th>_(Container IP)_</th><th>_(Container Port)_</th><th>_(LAN IP:Port)_</th><th>_(Volume Mappings)_ <small>(_(App to Host)_)</small></th><th class="load advanced">_(CPU & Memory load)_</th><th class="nine">_(Autostart)_</th><th class="five">_(Uptime)_</th></tr></thead>
|
||||
@@ -192,10 +190,7 @@ $(function() {
|
||||
});
|
||||
$.removeCookie('lockbutton');
|
||||
loadlist(true);
|
||||
dockerload.start();
|
||||
dockerload.start().monitor();
|
||||
});
|
||||
|
||||
window.onunload = function(){
|
||||
dockerload.stop();
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -478,10 +478,8 @@ if (!empty($TS_no_peers) && !empty($TS_container)) {
|
||||
}
|
||||
}
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.switchbutton.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-{$display['theme']}.css")?>">
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
<script src="<?autov('/webGui/javascript/jquery.filetree.js')?>" charset="utf-8"></script>
|
||||
|
||||
@@ -1,5 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Useful to delete a docker runtime diretory. In case of btrfs storage driver, handles deletion of btrfs
|
||||
# subvolumes used to store image layers. Similarly, in caes of zfs storage driver, handles deletion of
|
||||
# zfs datasets used to store image layers. Assumes dockerd is not running.
|
||||
|
||||
# Note: If the $target diretory is spit across multiple volumes, this operation is a no-op.
|
||||
|
||||
# Caution: in case of 'native' zfs storage driver which uses datasets to store layers, $target is irrelevant
|
||||
# because datasets are not listed under directories. This script will destroy *all* legacy datasets in the
|
||||
# volume. For example, consider two directories on same volume:
|
||||
|
||||
# /mnt/cache/docker
|
||||
# /mnt/cache/docker-backup
|
||||
|
||||
# Each directory holds a valid docker tree structure, maybe 'docker' is current and 'docker-backup' is
|
||||
# a backup. User decides he no loner needs 'docker-backup' so he invokes this script. The result will be
|
||||
# that not only will /mnt/cache/docker-backup be deleted, but all datasets belonging to /mnt/cache/docker
|
||||
# will also be deleted. This is because we cannot tell which datasets belong with which docker instance.
|
||||
|
||||
# If /mnt/cache/docker and /mnt/cache/docker-backup were themselves datasets, then we would be able to, but
|
||||
# this is not implemented here.
|
||||
|
||||
dereference() {
|
||||
local DIR=$1
|
||||
# if directory is on user share, attempt to dereference
|
||||
if [[ "$DIR" == /mnt/user/* ]]; then
|
||||
# getfattr would return blank if /mnt/user/<share> is a bind-mount
|
||||
local DISK=$(getfattr -n system.LOCATIONS --absolute-names --only-values "$DIR" 2>/dev/null)
|
||||
if [[ -n "$DISK" ]]; then
|
||||
# whitespace in $DISK would exist if $target is split across multiple volumes
|
||||
[[ ! "$DISK" =~ [[:space:]] ]] && DIR="${DIR/user/$DISK}" || DIR=""
|
||||
fi
|
||||
fi
|
||||
echo "$DIR"
|
||||
}
|
||||
|
||||
rm_docker() {
|
||||
local target="${1%/}"
|
||||
|
||||
# sanity check that this is a docker folder
|
||||
if [[ ! -d "$target/containerd" ]]; then
|
||||
echo "docker_rm: $target is not a docker folder"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# dereference folder on user share
|
||||
target=$(dereference "$target")
|
||||
if [[ -z "$target" ]]; then
|
||||
echo "docker_rm: $target is split across multiple volumes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$target/btrfs/subvolumes" ]]; then
|
||||
# delete btrfs subvolumes
|
||||
for subvol in "$target/btrfs/subvolumes/"*; do
|
||||
btrfs subvolume delete -cR "$subvol"
|
||||
done
|
||||
elif [[ -d "$target/zfs" ]]; then
|
||||
# destroy zfs 'legacy' datasets
|
||||
zfs list -rHo name,mountpoint "$target" 2>/dev/null | awk '$2 == "legacy" {print $1}' | while read -r dataset; do
|
||||
echo "docker_rm: zfs destroy -R $dataset"
|
||||
zfs destroy -R "$dataset"
|
||||
done
|
||||
fi
|
||||
|
||||
# delete files and directories
|
||||
echo "docker_rm: rm -rf $target"
|
||||
rm -rf "$target"
|
||||
}
|
||||
|
||||
# delete the docker image file or folder
|
||||
if [[ -f /boot/config/docker.cfg ]]; then
|
||||
rm -f /var/local/emhttp/plugins/dynamix.docker.manager/docker.json
|
||||
@@ -9,6 +78,6 @@ if [[ -f /boot/config/docker.cfg ]]; then
|
||||
rm -f "$DOCKER_IMAGE_FILE"
|
||||
elif [[ -d $DOCKER_IMAGE_FILE ]]; then
|
||||
echo "Deleting $DOCKER_IMAGE_FILE ..."
|
||||
rm -rf "$DOCKER_IMAGE_FILE"
|
||||
rm_docker "$DOCKER_IMAGE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
||||
@@ -1,14 +1,72 @@
|
||||
.noshow,.advanced{display:none}
|
||||
.required:after{content:" *";color:#E80000}
|
||||
span.boxed{display:inline-block;line-height:normal;white-space:normal;width:60%}
|
||||
span.cpu,label.checkbox{display:inline-block;width:32px}
|
||||
span.ct{display:inline-block;width:230px}
|
||||
span.net{display:inline-block;width:120px}
|
||||
span.ip{display:inline-block;width:160px}
|
||||
dl,dt,dd{line-height:normal!important;height:auto!important}
|
||||
dl{padding:8px 0!important}
|
||||
dl>dt:nth-of-type(2),dl>dd:nth-of-type(2){padding:20px 0 0 0!important}
|
||||
input.setting_input{margin-right:4rem}
|
||||
input,select{margin-top:-0.8rem!important}
|
||||
div#configLocation,div#configLocation dl{padding:0!important}
|
||||
div#configLocation dt{margin-top:-0.18rem!important}
|
||||
.noshow,
|
||||
.advanced {
|
||||
display: none;
|
||||
}
|
||||
.required:after {
|
||||
content: " *";
|
||||
color: var(--red-800);
|
||||
}
|
||||
span.boxed {
|
||||
display: inline-block;
|
||||
line-height: normal;
|
||||
white-space: normal;
|
||||
width: 60%;
|
||||
}
|
||||
span.cpu,
|
||||
label.checkbox {
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
}
|
||||
span.ct {
|
||||
display: inline-block;
|
||||
width: 230px;
|
||||
}
|
||||
span.net {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
}
|
||||
span.ip {
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
}
|
||||
dl,
|
||||
dt,
|
||||
dd {
|
||||
line-height: normal !important;
|
||||
height: auto !important;
|
||||
}
|
||||
dl {
|
||||
padding: 8px 0 !important;
|
||||
}
|
||||
dl > dt:nth-of-type(2),
|
||||
dl > dd:nth-of-type(2) {
|
||||
padding: 20px 0 0 0 !important;
|
||||
}
|
||||
input.setting_input {
|
||||
margin-right: 4rem;
|
||||
}
|
||||
input,
|
||||
select {
|
||||
margin-top: -0.8rem !important;
|
||||
}
|
||||
div#configLocation,
|
||||
div#configLocation dl {
|
||||
padding: 0 !important;
|
||||
}
|
||||
div#configLocation dt {
|
||||
margin-top: -0.18rem !important;
|
||||
}
|
||||
|
||||
:root {
|
||||
--add-container-file-tree-background: var(--black);
|
||||
}
|
||||
|
||||
.Theme--azure:root,
|
||||
.Theme--white:root {
|
||||
--add-container-file-tree-background: var(--gray-100);
|
||||
}
|
||||
|
||||
/* .fileTree {
|
||||
width: 240px;
|
||||
max-height: 200px;
|
||||
} */
|
||||
|
||||
@@ -1,12 +1,45 @@
|
||||
.basic{display:block}
|
||||
.advanced{display:none;white-space:nowrap}
|
||||
.log{cursor:zoom-in}
|
||||
.exec{cursor:pointer}
|
||||
table#docker_containers{text-align:left}
|
||||
th.five{width:5%}
|
||||
th.nine{width:9%}
|
||||
th.load{width:140px}
|
||||
input.wait{width:24px;margin:0 4px;padding:0 5px;border:none;box-shadow:none;background-color:transparent}
|
||||
table tbody td{line-height:normal}
|
||||
i.mover{margin-right:8px;display:none}
|
||||
#resetsort{margin-left:12px;display:inline-block;width:32px}
|
||||
.basic {
|
||||
display: block;
|
||||
}
|
||||
.advanced {
|
||||
display: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.log {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
.exec {
|
||||
cursor: pointer;
|
||||
}
|
||||
table#docker_containers {
|
||||
text-align: left;
|
||||
}
|
||||
th.five {
|
||||
width: 5%;
|
||||
}
|
||||
th.nine {
|
||||
width: 9%;
|
||||
}
|
||||
th.load {
|
||||
width: 140px;
|
||||
}
|
||||
input.wait {
|
||||
width: 24px;
|
||||
margin: 0 4px;
|
||||
padding: 0 5px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
table tbody td {
|
||||
line-height: normal;
|
||||
}
|
||||
i.mover {
|
||||
margin-right: 8px;
|
||||
display: none;
|
||||
}
|
||||
#resetsort {
|
||||
margin-left: 12px;
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#B0B0B0}
|
||||
@@ -1,2 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#404040}
|
||||
@@ -1,2 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#404040}
|
||||
@@ -1,2 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#B0B0B0}
|
||||
@@ -1,17 +1,84 @@
|
||||
.errortext{color:#EF3D47;display:none;margin-left:20px}
|
||||
.basic{display:inline-block}
|
||||
.advanced{display:none}
|
||||
select.mask{min-width:0;margin:0 10px 0 4px}
|
||||
select.net{min-width:0;margin:0 4px 0 2px}
|
||||
select option.hide{display:none}
|
||||
input.ip4{width:100px;margin:0 4px 0 1px}
|
||||
input.ip6{width:140px;margin:0 4px}
|
||||
input.gw4{width:100px;margin:0 4px 0 1px}
|
||||
input.gw6{width:160px;margin:0 4px}
|
||||
input.pool6{width:40px;margin:0 4px 0 1px}
|
||||
span.net{margin-left:4px;margin-right:2px}
|
||||
span.ip4{display:inline-block;width:260px}
|
||||
span.ip6{display:inline-block;width:310px}
|
||||
span.gw4{display:inline-block;width:200px}
|
||||
span.gw6{display:inline-block;width:270px}
|
||||
span.nonexist{margin-left:20px}
|
||||
:root {
|
||||
--docker-settings-file-tree-background: var(--black);
|
||||
--docker-settings-span-disabled-color: var(--gray-600);
|
||||
}
|
||||
|
||||
.Theme--azure:root,
|
||||
.Theme--white:root {
|
||||
--docker-settings-file-tree-background: var(--gray-100);
|
||||
--docker-settings-span-disabled-color: var(--gray-300); /* Condensed from: #b0b0b0 */
|
||||
}
|
||||
|
||||
.errortext {
|
||||
color: var(--red-800); /* Condensed from: #ef3d47 */
|
||||
display: none;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.basic {
|
||||
display: inline-block;
|
||||
}
|
||||
.advanced {
|
||||
display: none;
|
||||
}
|
||||
select.mask {
|
||||
min-width: 0;
|
||||
margin: 0 10px 0 4px;
|
||||
}
|
||||
select.net {
|
||||
min-width: 0;
|
||||
margin: 0 4px 0 2px;
|
||||
}
|
||||
select option.hide {
|
||||
display: none;
|
||||
}
|
||||
input.ip4 {
|
||||
width: 100px;
|
||||
margin: 0 4px 0 1px;
|
||||
}
|
||||
input.ip6 {
|
||||
width: 140px;
|
||||
margin: 0 4px;
|
||||
}
|
||||
input.gw4 {
|
||||
width: 100px;
|
||||
margin: 0 4px 0 1px;
|
||||
}
|
||||
input.gw6 {
|
||||
width: 160px;
|
||||
margin: 0 4px;
|
||||
}
|
||||
input.pool6 {
|
||||
width: 40px;
|
||||
margin: 0 4px 0 1px;
|
||||
}
|
||||
span.net {
|
||||
margin-left: 4px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
span.ip4 {
|
||||
display: inline-block;
|
||||
width: 260px;
|
||||
}
|
||||
span.ip6 {
|
||||
display: inline-block;
|
||||
width: 310px;
|
||||
}
|
||||
span.gw4 {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
span.gw6 {
|
||||
display: inline-block;
|
||||
width: 270px;
|
||||
}
|
||||
span.nonexist {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
/* .fileTree {
|
||||
width: 300px;
|
||||
max-height: 150px;
|
||||
} */
|
||||
span.disabled {
|
||||
color: var(--docker-settings-span-disabled-color);
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
||||
@@ -1,14 +1,72 @@
|
||||
.noshow,.advanced{display:none}
|
||||
.required:after{content:" *";color:#E80000}
|
||||
span.boxed{display:inline-block;line-height:normal;white-space:normal;width:60%}
|
||||
span.cpu,label.checkbox{display:inline-block;width:32px}
|
||||
span.ct{display:inline-block;width:230px}
|
||||
span.net{display:inline-block;width:120px}
|
||||
span.ip{display:inline-block;width:160px}
|
||||
dl,dt,dd{line-height:normal!important;height:auto!important}
|
||||
dl{padding:8px 0!important}
|
||||
dl>dt:nth-of-type(2),dl>dd:nth-of-type(2){padding:20px 0 0 0!important}
|
||||
input.setting_input{margin-right:4rem}
|
||||
input,select{margin-top:-0.8rem!important}
|
||||
div#configLocation,div#configLocation dl{padding:0!important}
|
||||
div#configLocation dt{margin-top:-0.18rem!important}
|
||||
:root {
|
||||
--update-container-file-tree-background: var(--black);
|
||||
}
|
||||
|
||||
.Theme--azure:root,
|
||||
.Theme--white:root {
|
||||
--update-container-file-tree-background: var(--gray-100);
|
||||
}
|
||||
|
||||
.noshow,
|
||||
.advanced {
|
||||
display: none;
|
||||
}
|
||||
.required:after {
|
||||
content: " *";
|
||||
color: var(--red-800);
|
||||
}
|
||||
span.boxed {
|
||||
display: inline-block;
|
||||
line-height: normal;
|
||||
white-space: normal;
|
||||
width: 60%;
|
||||
}
|
||||
span.cpu,
|
||||
label.checkbox {
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
}
|
||||
span.ct {
|
||||
display: inline-block;
|
||||
width: 230px;
|
||||
}
|
||||
span.net {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
}
|
||||
span.ip {
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
}
|
||||
dl,
|
||||
dt,
|
||||
dd {
|
||||
line-height: normal !important;
|
||||
height: auto !important;
|
||||
}
|
||||
dl {
|
||||
padding: 8px 0 !important;
|
||||
}
|
||||
dl > dt:nth-of-type(2),
|
||||
dl > dd:nth-of-type(2) {
|
||||
padding: 20px 0 0 0 !important;
|
||||
}
|
||||
input.setting_input {
|
||||
margin-right: 4rem;
|
||||
}
|
||||
input,
|
||||
select {
|
||||
margin-top: -0.8rem !important;
|
||||
}
|
||||
div#configLocation,
|
||||
div#configLocation dl {
|
||||
padding: 0 !important;
|
||||
}
|
||||
div#configLocation dt {
|
||||
margin-top: -0.18rem !important;
|
||||
}
|
||||
|
||||
/* .fileTree {
|
||||
width: 240px;
|
||||
max-height: 200px;
|
||||
} */
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
|
||||
.ui-state-active{background:#e8e8e8}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
|
||||
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}
|
||||
.ui-tailscale-row {display: flex;justify-content: space-between;min-width: 300px;width: 100%;flex-wrap: nowrap;overflow-x: auto;}
|
||||
.ui-tailscale-label {flex: 1;}
|
||||
.ui-tailscale-value {flex: 3;}
|
||||
@@ -1,17 +0,0 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
|
||||
.ui-state-active{background:#262626}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
|
||||
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}
|
||||
.ui-tailscale-row {display: flex;justify-content: space-between;min-width: 300px;width: 100%;flex-wrap: nowrap;overflow-x: auto;}
|
||||
.ui-tailscale-label {flex: 1;}
|
||||
.ui-tailscale-value {flex: 3;}
|
||||
@@ -1,17 +0,0 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
|
||||
.ui-state-active{background:#262626}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
|
||||
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}
|
||||
.ui-tailscale-row {display: flex;justify-content: space-between;min-width: 300px;width: 100%;flex-wrap: nowrap;overflow-x: auto;}
|
||||
.ui-tailscale-label {flex: 1;}
|
||||
.ui-tailscale-value {flex: 3;}
|
||||
@@ -1,17 +0,0 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
|
||||
.ui-state-active{background:#e8e8e8}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
|
||||
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}
|
||||
.ui-tailscale-row {display: flex;justify-content: space-between;min-width: 300px;width: 100%;flex-wrap: nowrap;overflow-x: auto;}
|
||||
.ui-tailscale-label {flex: 1;}
|
||||
.ui-tailscale-value {flex: 3;}
|
||||
@@ -1,2 +0,0 @@
|
||||
#guiSearchBoxSpan{display:inline-block;margin:0 0 0 20px;padding:0;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBox{position:relative;top:0;left:0;width:50rem;border:none;border-radius:20px;margin:0;padding:5px 12px;color:#1c1b1b;background-color:#feefb3}
|
||||
@@ -1,3 +0,0 @@
|
||||
#guiSearchBoxSpan{display:inline-block;position:relative;margin:4px 2px 2px 2px;padding:0;text-align:left;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBoxSpan:after{font-family:unraid;content:'\e956';position:absolute;top:.8rem;left:1.5rem;font-size:1.3rem}
|
||||
#guiSearchBox{width:50rem;border:none;border-radius:20px;padding-left:4rem;opacity:0.5;invert(100%)}
|
||||
@@ -1,2 +0,0 @@
|
||||
#guiSearchBoxSpan{display:inline-block;margin:0 0 0 20px;padding:0;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBox{position:relative;top:0;left:0;width:50rem;border:none;border-radius:20px;margin:0;padding:5px 12px;color:#1c1b1b;background-color:#feefb3}
|
||||
@@ -1,3 +0,0 @@
|
||||
#guiSearchBoxSpan{display:inline-block;position:relative;margin:4px 2px 2px 2px;padding:0;text-align:left;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBoxSpan:after{font-family:unraid;content:'\e956';position:absolute;top:.8rem;left:1.5rem;font-size:1.3rem}
|
||||
#guiSearchBox{width:50rem;border:none;border-radius:20px;padding-left:4rem;opacity:0.5;invert(100%)}
|
||||
@@ -0,0 +1,56 @@
|
||||
:root {
|
||||
--gui-search-search-box-text-color: var(--white);
|
||||
--gui-search-search-box-background-color: var(--gray-500);
|
||||
}
|
||||
|
||||
#guiSearchBoxSpan {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
height: auto;
|
||||
line-height: normal;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
#guiSearchBox {
|
||||
width: 50rem;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
color: var(--gui-search-search-box-text-color);
|
||||
background-color: var(--gui-search-search-box-background-color);
|
||||
}
|
||||
|
||||
.Theme--black,
|
||||
.Theme--white {
|
||||
#guiSearchBoxSpan {
|
||||
position: relative;
|
||||
margin: 4px 2px 2px 2px;
|
||||
}
|
||||
#guiSearchBoxSpan:after {
|
||||
font-family: unraid;
|
||||
content: "\e956";
|
||||
position: absolute;
|
||||
top: 0.8rem;
|
||||
left: 1.5rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
#guiSearchBox {
|
||||
padding-left: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.Theme--sidebar {
|
||||
--gui-search-search-box-text-color: var(--black);
|
||||
--gui-search-search-box-background-color: var(--yellow-200);
|
||||
|
||||
#guiSearchBoxSpan {
|
||||
margin: 0 0 0 20px;
|
||||
}
|
||||
#guiSearchBox {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
}
|
||||
@@ -20,4 +20,4 @@ $replaceKey->check(true);
|
||||
?>
|
||||
<unraid-i18n-host>
|
||||
<unraid-registration></unraid-registration>
|
||||
</unraid-i18n-host>
|
||||
</unraid-i18n-host>
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
$var = (array)parse_ini_file('state/var.ini');
|
||||
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
$var = (array)parse_ini_file('state/var.ini'); // required for state.php - don't remove unless you've refactored the code to work without it
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/state.php";
|
||||
|
||||
$serverState = new ServerState();
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
class ActivationCodeExtractor {
|
||||
public const DIR = '/boot/config/activation';
|
||||
public const FILE_PATTERN = '/activation_code_([A-Za-z0-9]+)\.activationcode/';
|
||||
|
||||
public const DOCROOT = '/usr/local/emhttp';
|
||||
public const WEBGUI_IMAGES_BASE_DIR = '/webGui/images';
|
||||
public const PARTNER_LOGO_FILE_NAME = 'partner-logo.svg';
|
||||
public const DEFAULT_LOGO = self::DOCROOT . self::WEBGUI_IMAGES_BASE_DIR . '/UN-logotype-gradient.svg';
|
||||
|
||||
/** @var array{
|
||||
* code: string,
|
||||
* partnerName: string,
|
||||
* partnerUrl?: string,
|
||||
* sysModel?: string,
|
||||
* comment?: string,
|
||||
* caseIcon: string,
|
||||
* partnerLogo?: boolean,
|
||||
* header?: string,
|
||||
* headermetacolor?: string,
|
||||
* background?: string,
|
||||
* showBannerGradient?: string,
|
||||
* theme?: "azure" | "black" | "gray" | "white
|
||||
* }
|
||||
*/
|
||||
private array $data = [];
|
||||
private string $partnerName = '';
|
||||
private string $partnerUrl = 'https://unraid.net';
|
||||
private string $partnerLogoPath = '';
|
||||
|
||||
/**
|
||||
* Constructor to automatically fetch JSON data from all matching files.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->data = $this->fetchJsonData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch JSON data from all files matching the pattern.
|
||||
*
|
||||
* @return array Array of extracted JSON data.
|
||||
*/
|
||||
private function fetchJsonData(): array {
|
||||
$data = [];
|
||||
|
||||
if (!is_dir(self::DIR)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$files = scandir(self::DIR);
|
||||
|
||||
if ($files === false || count($files) === 0) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$filePath = self::DIR . DIRECTORY_SEPARATOR . $file;
|
||||
|
||||
if (preg_match(self::FILE_PATTERN, $file, $matches)) {
|
||||
// $activationCode = $matches[1];
|
||||
$fileContent = file_get_contents($filePath);
|
||||
$jsonData = json_decode($fileContent, true);
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
$data = $jsonData;
|
||||
} else {
|
||||
$data = ['error' => 'Invalid JSON format'];
|
||||
}
|
||||
|
||||
break; // Stop after the first match
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['partnerName'])) {
|
||||
$this->partnerName = $data['partnerName'];
|
||||
}
|
||||
|
||||
if (isset($data['partnerUrl'])) {
|
||||
$this->partnerUrl = $data['partnerUrl'];
|
||||
}
|
||||
|
||||
/**
|
||||
* During the plg install, the partner logo asset is copied to the webgui images dir.
|
||||
*/
|
||||
$logo = self::DOCROOT . self::WEBGUI_IMAGES_BASE_DIR . '/' . self::PARTNER_LOGO_FILE_NAME;
|
||||
if (file_exists($logo)) {
|
||||
$this->partnerLogoPath = $logo;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the partner logo path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPartnerLogoPath(): string {
|
||||
return $this->partnerLogoPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extracted data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getData(): array {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the activation code data as JSON string with converted special characters to HTML entities
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDataForHtmlAttr(): string {
|
||||
$json = json_encode($this->getData());
|
||||
return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the partner logo render string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPartnerLogoRenderString(): string {
|
||||
if (empty($this->partnerLogoPath)) { // default logo
|
||||
return file_get_contents(self::DEFAULT_LOGO);
|
||||
}
|
||||
|
||||
return file_get_contents($this->partnerLogoPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the partner name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPartnerName(): string {
|
||||
return $this->partnerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the partner URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPartnerUrl(): string {
|
||||
return $this->partnerUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output for debugging
|
||||
* @return void
|
||||
*/
|
||||
public function debug(): void {
|
||||
echo "data: "; var_dump($this->data);
|
||||
echo "partnerName: "; var_dump($this->partnerName);
|
||||
echo "partnerUrl: "; var_dump($this->partnerUrl);
|
||||
echo "partnerLogoPath: "; var_dump($this->partnerLogoPath);
|
||||
|
||||
echo $this->getPartnerLogoRenderString();
|
||||
}
|
||||
}
|
||||
@@ -36,27 +36,15 @@ a[href="/Tools/Downgrade"] .icon-update:before {
|
||||
display: inline-block; /* required otherwise the rotation won't work */
|
||||
rotate: 180deg;
|
||||
}
|
||||
/* overriding #header .logo svg */
|
||||
#header .logo .partner-logo svg {
|
||||
fill: var(--header-text-primary);
|
||||
width: auto;
|
||||
height: 28px;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
// Set the path for the local manifest file
|
||||
$localManifestFile = '/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components/manifest.json';
|
||||
require_once("$docroot/plugins/dynamix.my.servers/include/web-components-extractor.php");
|
||||
|
||||
// Load the local manifest
|
||||
$localManifest = json_decode(file_get_contents($localManifestFile), true);
|
||||
|
||||
$searchText = 'unraid-components.client.mjs';
|
||||
$fileValue = null;
|
||||
|
||||
foreach ($localManifest as $key => $value) {
|
||||
if (strpos($key, $searchText) !== false && isset($value["file"])) {
|
||||
$fileValue = $value["file"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fileValue !== null) {
|
||||
$prefixedPath = '/plugins/dynamix.my.servers/unraid-components/';
|
||||
echo '<script src="' . $prefixedPath . $fileValue . '"></script>';
|
||||
} else {
|
||||
echo '<script>console.error("%cNo matching key containing \'' . $searchText . '\' found.", "font-weight: bold; color: white; background-color: red");</script>';
|
||||
}
|
||||
$wcExtractor = new WebComponentsExtractor();
|
||||
echo $wcExtractor->getScriptTagHtml();
|
||||
|
||||
@@ -165,4 +165,4 @@ class RebootDetails
|
||||
$this->previousReleaseDate = $parseOutput['releaseDate'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @todo refactor globals – currently if you try to use $GLOBALS the class will break.
|
||||
*/
|
||||
$webguiGlobals = $GLOBALS;
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/activation-code-extractor.php";
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
/**
|
||||
@@ -52,6 +54,10 @@ class ServerState
|
||||
"nokeyserver" => 'NO_KEY_SERVER',
|
||||
"withdrawn" => 'WITHDRAWN',
|
||||
];
|
||||
/**
|
||||
* SSO Sub IDs from the my servers config file.
|
||||
*/
|
||||
public $ssoEnabled = false;
|
||||
private $osVersion;
|
||||
private $osVersionBranch;
|
||||
private $rebootDetails;
|
||||
@@ -66,12 +72,14 @@ class ServerState
|
||||
public $myServersMemoryCfg = [];
|
||||
public $host = 'unknown';
|
||||
public $combinedKnownOrigins = [];
|
||||
|
||||
|
||||
public $nginxCfg = [];
|
||||
public $flashbackupStatus = [];
|
||||
public $registered = false;
|
||||
public $myServersMiniGraphConnected = false;
|
||||
public $keyfileBase64 = '';
|
||||
public $activationCodeData = [];
|
||||
public $state = 'UNKNOWN';
|
||||
|
||||
/**
|
||||
* Constructor to initialize class properties and gather server information.
|
||||
@@ -83,12 +91,27 @@ class ServerState
|
||||
* @see - getWebguiGlobal() for usage
|
||||
* */
|
||||
global $webguiGlobals;
|
||||
$this->webguiGlobals =& $webguiGlobals;
|
||||
$this->webguiGlobals = &$webguiGlobals;
|
||||
// echo "<pre>" . json_encode($this->webguiGlobals, JSON_PRETTY_PRINT) . "</pre>";
|
||||
|
||||
$this->var = (array)parse_ini_file('state/var.ini');
|
||||
$this->var = $webguiGlobals['var'];
|
||||
|
||||
$patcherVersion = null;
|
||||
if (file_exists('/tmp/Patcher/patches.json')) {
|
||||
$patcherData = @json_decode(file_get_contents('/tmp/Patcher/patches.json'), true);
|
||||
$unraidVersionInfo = parse_ini_file('/etc/unraid-version');
|
||||
if ($patcherData['unraidVersion'] === $unraidVersionInfo['version']) {
|
||||
$patcherVersion = $patcherData['combinedVersion'] ?? null;
|
||||
}
|
||||
}
|
||||
// If we're on a patch, we need to use the combinedVersion to check for updates
|
||||
if ($patcherVersion) {
|
||||
$this->var['version'] = $patcherVersion;
|
||||
}
|
||||
|
||||
$this->nginxCfg = @parse_ini_file('/var/local/emhttp/nginx.ini') ?? [];
|
||||
|
||||
$this->state = strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']);
|
||||
$this->osVersion = $this->var['version'];
|
||||
$this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable');
|
||||
|
||||
@@ -109,12 +132,14 @@ class ServerState
|
||||
$this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult();
|
||||
|
||||
$this->setConnectValues();
|
||||
$this->detectActivationCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of a webgui global setting.
|
||||
*/
|
||||
public function getWebguiGlobal(string $key, ?string $subkey = null) {
|
||||
public function getWebguiGlobal(string $key, ?string $subkey = null)
|
||||
{
|
||||
if (!$subkey) {
|
||||
return _var($this->webguiGlobals, $key, '');
|
||||
}
|
||||
@@ -122,14 +147,15 @@ class ServerState
|
||||
return _var($keyArray, $subkey, '');
|
||||
}
|
||||
|
||||
private function setConnectValues() {
|
||||
private function setConnectValues()
|
||||
{
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) {
|
||||
$this->connectPluginInstalled = 'dynamix.unraid.net.plg';
|
||||
}
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) {
|
||||
$this->connectPluginInstalled = 'dynamix.unraid.net.staging.plg';
|
||||
}
|
||||
if ($this->connectPluginInstalled && !file_exists('/usr/local/sbin/unraid-api')) {
|
||||
if ($this->connectPluginInstalled && !file_exists('/usr/bin/unraid-api')) {
|
||||
$this->connectPluginInstalled .= '_installFailed';
|
||||
}
|
||||
|
||||
@@ -149,13 +175,15 @@ class ServerState
|
||||
$this->getFlashBackupStatus();
|
||||
}
|
||||
|
||||
private function getFlashBackupStatus() {
|
||||
private function getFlashBackupStatus()
|
||||
{
|
||||
$flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
|
||||
$this->flashbackupStatus = (file_exists($flashbackupCfg)) ? @parse_ini_file($flashbackupCfg) : [];
|
||||
$this->flashBackupActivated = empty($this->flashbackupStatus['activated']) ? '' : 'true';
|
||||
}
|
||||
|
||||
private function getMyServersCfgValues() {
|
||||
private function getMyServersCfgValues()
|
||||
{
|
||||
/**
|
||||
* @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg…
|
||||
* - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
|
||||
@@ -188,9 +216,11 @@ class ServerState
|
||||
$this->registered = !empty($this->myServersFlashCfg['remote']['apikey']) && $this->connectPluginInstalled;
|
||||
$this->registeredTime = $this->myServersFlashCfg['remote']['regWizTime'] ?? '';
|
||||
$this->username = $this->myServersFlashCfg['remote']['username'] ?? '';
|
||||
$this->ssoEnabled = !empty($this->myServersFlashCfg['remote']['ssoSubIds'] ?? '');
|
||||
}
|
||||
|
||||
private function getConnectKnownOrigins() {
|
||||
private function getConnectKnownOrigins()
|
||||
{
|
||||
/**
|
||||
* Allowed origins warning displayed when the current webGUI URL is NOT included in the known lists of allowed origins.
|
||||
* Include localhost in the test, but only display HTTP(S) URLs that do not include localhost.
|
||||
@@ -198,7 +228,7 @@ class ServerState
|
||||
$this->host = $_SERVER['HTTP_HOST'] ?? "unknown";
|
||||
$memoryCfgPath = '/var/local/emhttp/myservers.cfg';
|
||||
$this->myServersMemoryCfg = (file_exists($memoryCfgPath)) ? @parse_ini_file($memoryCfgPath) : [];
|
||||
$this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph']??'') === 'CONNECTED');
|
||||
$this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph'] ?? '') === 'CONNECTED');
|
||||
|
||||
$allowedOrigins = $this->myServersMemoryCfg['allowedOrigins'] ?? "";
|
||||
$extraOrigins = $this->myServersFlashCfg['api']['extraOrigins'] ?? "";
|
||||
@@ -214,8 +244,8 @@ class ServerState
|
||||
$this->combinedKnownOrigins = explode(",", $combinedOrigins);
|
||||
|
||||
if ($this->combinedKnownOrigins) {
|
||||
foreach($this->combinedKnownOrigins as $key => $origin) {
|
||||
if ( (strpos($origin, "http") === false) || (strpos($origin, "localhost") !== false) ) {
|
||||
foreach ($this->combinedKnownOrigins as $key => $origin) {
|
||||
if ((strpos($origin, "http") === false) || (strpos($origin, "localhost") !== false)) {
|
||||
// clean up $this->combinedKnownOrigins, only display warning if origins still remain to display
|
||||
unset($this->combinedKnownOrigins[$key]);
|
||||
}
|
||||
@@ -228,6 +258,23 @@ class ServerState
|
||||
}
|
||||
}
|
||||
|
||||
private function detectActivationCode()
|
||||
{
|
||||
// Fresh server and we're not loading with a callback param to install
|
||||
if ($this->state !== 'ENOKEYFILE' || !empty($_GET['c'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$activationCodeData = new ActivationCodeExtractor();
|
||||
$data = $activationCodeData->getData();
|
||||
|
||||
if (empty($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->activationCodeData = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as an associative array
|
||||
*
|
||||
@@ -286,7 +333,8 @@ class ServerState
|
||||
"registered" => $this->registered,
|
||||
"registeredTime" => $this->registeredTime,
|
||||
"site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'),
|
||||
"state" => strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']),
|
||||
"ssoEnabled" => $this->ssoEnabled,
|
||||
"state" => $this->state,
|
||||
"theme" => [
|
||||
"banner" => !empty($this->getWebguiGlobal('display', 'banner')),
|
||||
"bannerGradient" => $this->getWebguiGlobal('display', 'showBannerGradient') === 'yes' ?? false,
|
||||
@@ -318,6 +366,10 @@ class ServerState
|
||||
$serverState['updateOsResponse'] = $this->updateOsResponse;
|
||||
}
|
||||
|
||||
if ($this->activationCodeData) {
|
||||
$serverState['activationCodeData'] = $this->activationCodeData;
|
||||
}
|
||||
|
||||
return $serverState;
|
||||
}
|
||||
|
||||
@@ -326,7 +378,8 @@ class ServerState
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerStateJson() {
|
||||
public function getServerStateJson()
|
||||
{
|
||||
return json_encode($this->getServerState());
|
||||
}
|
||||
|
||||
@@ -335,8 +388,9 @@ class ServerState
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerStateJsonForHtmlAttr() {
|
||||
public function getServerStateJsonForHtmlAttr()
|
||||
{
|
||||
$json = json_encode($this->getServerState());
|
||||
return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,8 @@ class WebComponentTranslations
|
||||
'<p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
|
||||
'A Trial key provides all the functionality of an Unleashed Registration key' => _('A Trial key provides all the functionality of an Unleashed Registration key'),
|
||||
'Acklowledge that you have made a Flash Backup to enable this action' => _('Acklowledge that you have made a Flash Backup to enable this action'),
|
||||
'Activate License' => _('Activate License'),
|
||||
'Activate Now' => _('Activate Now'),
|
||||
'ago' => _('ago'),
|
||||
'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin.') . ' ' . _('Get started by installing the plugin.'),
|
||||
'Attached Storage Devices' => _('Attached Storage Devices'),
|
||||
@@ -117,11 +119,15 @@ class WebComponentTranslations
|
||||
'Copy Key URL' => _('Copy Key URL'),
|
||||
'Copy your Key URL: {0}' => sprintf(_('Copy your Key URL: %s'), '{0}'),
|
||||
'Create Flash Backup' => _('Create Flash Backup'),
|
||||
'Create a password' => _('Create a password'),
|
||||
'Create an Unraid.net account and activate your key' => _('Create an Unraid.net account and activate your key'),
|
||||
'Create Device Password' => _('Create Device Password'),
|
||||
'Current Version {0}' => sprintf(_('Current Version %s'), '{0}'),
|
||||
'Current Version: Unraid {0}' => sprintf(_('Current Version: Unraid %s'), '{0}'),
|
||||
'Customizable Dashboard Tiles' => _('Customizable Dashboard Tiles'),
|
||||
'day' => sprintf(_('%s day'), '{n}') . ' | ' . sprintf(_('%s days'), '{n}'),
|
||||
'Deep Linking' => _('Deep Linking'),
|
||||
'Device is ready to configure' => _('Device is ready to configure'),
|
||||
'DNS issue, unable to resolve wanip4.unraid.net' => _('DNS issue, unable to resolve wanip4.unraid.net'),
|
||||
'Downgrade Unraid OS to {0}' => sprintf(_('Downgrade Unraid OS to %s'), '{0}'),
|
||||
'Downgrade Unraid OS' => _('Downgrade Unraid OS'),
|
||||
@@ -204,6 +210,7 @@ class WebComponentTranslations
|
||||
'Learn more and link your key to your account' => _('Learn more and link your key to your account'),
|
||||
'Learn More' => _('Learn More'),
|
||||
'Learn more' => _('Learn more'),
|
||||
'Let\'s activate your Unraid OS License' => _('Let\'s activate your Unraid OS License'),
|
||||
'Let\'s Unleash your Hardware!' => _('Let\'s Unleash your Hardware!'),
|
||||
'License key actions' => _('License key actions'),
|
||||
'License key type' => _('License key type'),
|
||||
@@ -218,6 +225,8 @@ class WebComponentTranslations
|
||||
'minute' => sprintf(_('%s minute'), '{n}') . ' | ' . sprintf(_('%s minutes'), '{n}'),
|
||||
'Missing key file' => _('Missing key file'),
|
||||
'month' => sprintf(_('%s month'), '{n}') . ' | ' . sprintf(_('%s months'), '{n}'),
|
||||
'More about Unraid.net Accounts' => _('More about Unraid.net Accounts'),
|
||||
'More about Unraid.net' => _('More about Unraid.net'),
|
||||
'More options' => _('More options'),
|
||||
'Multiple License Keys Present' => _('Multiple License Keys Present'),
|
||||
'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.' => _('Never ever be left without a backup of your config.') . ' ' . _('If you need to change flash drives, generate a backup from Connect and be up and running in minutes.'),
|
||||
@@ -281,6 +290,7 @@ class WebComponentTranslations
|
||||
'Requires the local unraid-api to be running successfully' => _('Requires the local unraid-api to be running successfully'),
|
||||
'Restarting unraid-api…' => _('Restarting unraid-api…'),
|
||||
'second' => sprintf(_('%s second'), '{n}') . ' | ' . sprintf(_('%s seconds'), '{n}'),
|
||||
'Secure your device' => _('Secure your device'),
|
||||
'Server Up Since {0}' => sprintf(_('Server Up Since %s'), '{0}'),
|
||||
'Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI. Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.' => _('Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI.') . ' ' . _('Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.'),
|
||||
'Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.' => _('Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.'),
|
||||
@@ -302,6 +312,7 @@ class WebComponentTranslations
|
||||
'SSL certificates for unraid.net deprecated' => _('SSL certificates for unraid.net deprecated'),
|
||||
'Stale Server' => _('Stale Server'),
|
||||
'Stale' => _('Stale'),
|
||||
'On the following screen, your license will be activated. You\'ll then create an Unraid.net Account to manage your license going forward.' => _('On the following screen, your license will be activated.') . ' ' . _('You\'ll then create an Unraid.net Account to manage your license going forward.'),
|
||||
'Start Free 30 Day Trial' => _('Start Free 30 Day Trial'),
|
||||
'Starting your free 30 day trial' => _('Starting your free 30 day trial'),
|
||||
'Success!' => _('Success!'),
|
||||
@@ -372,6 +383,8 @@ class WebComponentTranslations
|
||||
'View on Docs' => _('View on Docs'),
|
||||
'View release notes' => _('View release notes'),
|
||||
'We recommend backing up your USB Flash Boot Device before starting the update.' => _('We recommend backing up your USB Flash Boot Device before starting the update.'),
|
||||
'Welcome to your new ${0} system, powered by Unraid!' => _('Welcome to your new ${0} system, powered by Unraid!'),
|
||||
'Welcome to Unraid!' => _('Welcome to Unraid!'),
|
||||
'year' => sprintf(_('%s year'), '{n}') . ' | ' . sprintf(_('%s years'), '{n}'),
|
||||
'You are still eligible to access OS updates that were published on or before {1}.' => sprintf(_('You are still eligible to access OS updates that were published on or before %s.'), '{1}'),
|
||||
'You can also manually create a new backup by clicking the Create Flash Backup button.' => _('You can also manually create a new backup by clicking the Create Flash Backup button.'),
|
||||
@@ -380,6 +393,7 @@ class WebComponentTranslations
|
||||
'You have exceeded the number of devices allowed for your license. Please remove a device before adding another.' => _('You have exceeded the number of devices allowed for your license. Please remove a device before adding another.'),
|
||||
'You have not activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have not activated the Flash Backup feature via the Unraid Connect plugin.'),
|
||||
'You may still update to releases dated prior to your update expiration date.' => _('You may still update to releases dated prior to your update expiration date.'),
|
||||
'You\'re about to create a password to secure access to your system. This password is essential for managing and configuring your server. You’ll use this password every time you access the Unraid web interface.' => _('You\'re about to create a password to secure access to your system.') . ' ' . _('This password is essential for managing and configuring your server.') . ' ' . _('You’ll use this password every time you access the Unraid web interface.'),
|
||||
'You\'re one step closer to enhancing your Unraid experience' => _('You\'re one step closer to enhancing your Unraid experience'),
|
||||
'Your {0} Key has been replaced!' => sprintf(_('Your %s Key has been replaced!'), '{0}'),
|
||||
'Your {0} license included one year of free updates at the time of purchase. You are now eligible to extend your license and access the latest OS updates. You are still eligible to access OS updates that were published on or before {1}.' => sprintf(_('Your %s license included one year of free updates at the time of purchase.'), '{0}') . ' ' . _('You are now eligible to extend your license and access the latest OS updates.') . ' ' . sprintf(_('You are still eligible to access OS updates that were published on or before %s.'), '{1}'),
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
class WebComponentsExtractor
|
||||
{
|
||||
private const PREFIXED_PATH = '/plugins/dynamix.my.servers/unraid-components/';
|
||||
private const RICH_COMPONENTS_ENTRY = 'unraid-components.client.mjs';
|
||||
private const UI_ENTRY = 'src/register.ts';
|
||||
private const UI_STYLES_ENTRY = 'style.css';
|
||||
|
||||
public function __construct() {}
|
||||
|
||||
private function findManifestFiles(string $manifestName): array
|
||||
{
|
||||
$basePath = '/usr/local/emhttp' . self::PREFIXED_PATH;
|
||||
$escapedBasePath = escapeshellarg($basePath);
|
||||
$escapedManifestName = escapeshellarg($manifestName);
|
||||
$command = "find {$escapedBasePath} -name {$escapedManifestName}";
|
||||
exec($command, $files);
|
||||
return $files;
|
||||
}
|
||||
|
||||
public function getAssetPath(string $asset, string $subfolder = ''): string
|
||||
{
|
||||
return self::PREFIXED_PATH . ($subfolder ? $subfolder . '/' : '') . $asset;
|
||||
}
|
||||
|
||||
private function getRelativePath(string $fullPath): string
|
||||
{
|
||||
$basePath = '/usr/local/emhttp' . self::PREFIXED_PATH;
|
||||
$relative = str_replace($basePath, '', $fullPath);
|
||||
return dirname($relative);
|
||||
}
|
||||
|
||||
public function getManifestContents(string $manifestPath): array
|
||||
{
|
||||
$contents = @file_get_contents($manifestPath);
|
||||
return $contents ? json_decode($contents, true) : [];
|
||||
}
|
||||
|
||||
private function getRichComponentsFile(): string
|
||||
{
|
||||
$manifestFiles = $this->findManifestFiles('manifest.json');
|
||||
|
||||
foreach ($manifestFiles as $manifestPath) {
|
||||
$manifest = $this->getManifestContents($manifestPath);
|
||||
$subfolder = $this->getRelativePath($manifestPath);
|
||||
|
||||
foreach ($manifest as $key => $value) {
|
||||
if (strpos($key, self::RICH_COMPONENTS_ENTRY) !== false && isset($value["file"])) {
|
||||
return ($subfolder ? $subfolder . '/' : '') . $value["file"];
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
private function getRichComponentsScript(): string
|
||||
{
|
||||
$jsFile = $this->getRichComponentsFile();
|
||||
if (empty($jsFile)) {
|
||||
return '<script>console.error("%cNo matching key containing \'' . self::RICH_COMPONENTS_ENTRY . '\' found.", "font-weight: bold; color: white; background-color: red");</script>';
|
||||
}
|
||||
return '<script src="' . $this->getAssetPath($jsFile) . '"></script>';
|
||||
}
|
||||
|
||||
private function getUnraidUiScriptHtml(): string
|
||||
{
|
||||
$manifestFiles = $this->findManifestFiles('ui.manifest.json');
|
||||
|
||||
if (empty($manifestFiles)) {
|
||||
error_log("No ui.manifest.json found");
|
||||
return '';
|
||||
}
|
||||
|
||||
$manifestPath = $manifestFiles[0]; // Use the first found manifest
|
||||
$manifest = $this->getManifestContents($manifestPath);
|
||||
$subfolder = $this->getRelativePath($manifestPath);
|
||||
|
||||
if (!isset($manifest[self::UI_ENTRY]) || !isset($manifest[self::UI_STYLES_ENTRY])) {
|
||||
error_log("Required entries not found in ui.manifest.json");
|
||||
return '';
|
||||
}
|
||||
|
||||
$jsFile = ($subfolder ? $subfolder . '/' : '') . $manifest[self::UI_ENTRY]['file'];
|
||||
$cssFile = ($subfolder ? $subfolder . '/' : '') . $manifest[self::UI_STYLES_ENTRY]['file'];
|
||||
|
||||
return '<script defer type="module">
|
||||
import { registerAllComponents } from "' . $this->getAssetPath($jsFile) . '";
|
||||
registerAllComponents({ pathToSharedCss: "' . $this->getAssetPath($cssFile) . '" });
|
||||
</script>';
|
||||
}
|
||||
|
||||
public function getScriptTagHtml(): string
|
||||
{
|
||||
try {
|
||||
return $this->getRichComponentsScript() . $this->getUnraidUiScriptHtml();
|
||||
} catch (\Exception $e) {
|
||||
error_log("Error in WebComponentsExtractor::getScriptTagHtml: " . $e->getMessage());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
File diff suppressed because one or more lines are too long
-28
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
||||
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
|
||||
Theme: GitHub Dark
|
||||
Description: Dark theme as seen on github.com
|
||||
Author: github.com
|
||||
Maintainer: @Hirse
|
||||
Updated: 2021-05-15
|
||||
|
||||
Outdated base version: https://github.com/primer/github-syntax-dark
|
||||
Current colors taken from GitHub's CSS
|
||||
*/.hljs{background:#0d1117;color:#c9d1d9}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{background-color:#033a16;color:#aff5b4}.hljs-deletion{background-color:#67060c;color:#ffdcd7}
|
||||
+92
File diff suppressed because one or more lines are too long
+3
-3
@@ -1,12 +1,12 @@
|
||||
{
|
||||
".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs": {
|
||||
"file": "_nuxt/unraid-components.client-DaXtPGYC.js",
|
||||
"file": "_nuxt/unraid-components.client-LDESjq-u.js",
|
||||
"name": "unraid-components.client",
|
||||
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs",
|
||||
"isEntry": true,
|
||||
"css": [
|
||||
"_nuxt/unraid-components-p_3YF86n.css"
|
||||
"_nuxt/unraid-components-BvEqdEb_.css"
|
||||
]
|
||||
},
|
||||
"ts": 1736299175
|
||||
"ts": 1744139284
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"src/register.ts": {
|
||||
"file": "register.D9MKs8Co.js",
|
||||
"name": "register",
|
||||
"src": "src/register.ts",
|
||||
"isEntry": true
|
||||
},
|
||||
"style.css": {
|
||||
"file": "ui.CaW9jS_X.css",
|
||||
"src": "style.css"
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,17 @@ class UnraidOsCheck
|
||||
|
||||
$params = [];
|
||||
$params['branch'] = plugin('category', self::PLG_PATH, 'stable');
|
||||
$params['current_version'] = plugin('version', self::PLG_PATH) ?: _var($var,'version');
|
||||
// Get current version from patches.json if it exists, otherwise fall back to plugin version or var.ini
|
||||
$patcherVersion = null;
|
||||
if (file_exists('/tmp/Patcher/patches.json')) {
|
||||
$patcherData = @json_decode(file_get_contents('/tmp/Patcher/patches.json'), true);
|
||||
$unraidVersionInfo = parse_ini_file('/etc/unraid-version');
|
||||
if ($patcherData['unraidVersion'] === $unraidVersionInfo['version']) {
|
||||
$patcherVersion = $patcherData['combinedVersion'] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
$params['current_version'] = $patcherVersion ?: plugin('version', self::PLG_PATH) ?: _var($var, 'version');
|
||||
if (_var($var,'regExp')) $params['update_exp'] = date('Y-m-d', _var($var,'regExp')*1);
|
||||
$defaultUrl = self::BASE_RELEASES_URL;
|
||||
// pass a param of altUrl to use the provided url instead of the default
|
||||
@@ -258,4 +268,4 @@ $isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVE
|
||||
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
|
||||
if ($isGetRequest && $getHasAction) {
|
||||
new UnraidOsCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,31 +12,57 @@
|
||||
class UnraidCheckExec
|
||||
{
|
||||
private const SCRIPT_PATH = '/usr/local/emhttp/plugins/dynamix.plugin.manager/scripts/unraidcheck';
|
||||
private const ALLOWED_DOMAIN = 'releases.unraid.net';
|
||||
|
||||
private function setupEnvironment(): void
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
header('X-Frame-Options: DENY');
|
||||
header('Content-Security-Policy: default-src \'none\'');
|
||||
|
||||
$params = [
|
||||
'json' => 'true',
|
||||
];
|
||||
// allows the web components to determine the OS_RELEASES url
|
||||
if (isset($_GET['altUrl']) && filter_var($_GET['altUrl'], FILTER_VALIDATE_URL)) {
|
||||
$params['altUrl'] = $_GET['altUrl'];
|
||||
|
||||
if (isset($_GET['altUrl'])) {
|
||||
$url = filter_var($_GET['altUrl'], FILTER_VALIDATE_URL);
|
||||
if ($url !== false) {
|
||||
$host = parse_url($url, PHP_URL_HOST);
|
||||
$scheme = parse_url($url, PHP_URL_SCHEME);
|
||||
|
||||
if ($host && $scheme === 'https' && (
|
||||
$host === self::ALLOWED_DOMAIN ||
|
||||
str_ends_with($host, '.' . self::ALLOWED_DOMAIN)
|
||||
)) {
|
||||
$params['altUrl'] = $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
// pass the params to the unraidcheck script for usage in UnraidCheck.php
|
||||
|
||||
putenv('QUERY_STRING=' . http_build_query($params));
|
||||
}
|
||||
|
||||
public function execute(): string
|
||||
{
|
||||
// Validate script with all necessary permissions
|
||||
if (!is_file(self::SCRIPT_PATH) ||
|
||||
!is_readable(self::SCRIPT_PATH) ||
|
||||
!is_executable(self::SCRIPT_PATH)) {
|
||||
throw new RuntimeException('Script not found or not executable');
|
||||
}
|
||||
|
||||
$this->setupEnvironment();
|
||||
$output = [];
|
||||
exec(self::SCRIPT_PATH, $output);
|
||||
$command = escapeshellcmd(self::SCRIPT_PATH);
|
||||
if (exec($command, $output) === false) {
|
||||
throw new RuntimeException('Script execution failed');
|
||||
}
|
||||
|
||||
return implode("\n", $output);
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
$checker = new UnraidCheckExec();
|
||||
echo $checker->execute();
|
||||
echo $checker->execute();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
?>
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
|
||||
require_once "$docroot/plugins/dynamix/include/ReplaceKey.php";
|
||||
$replaceKey = new ReplaceKey();
|
||||
$replaceKey->check();
|
||||
@@ -22,4 +23,4 @@ parse_str(getenv('QUERY_STRING') ?? '', $_GET);
|
||||
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
$unraidOsCheck = new UnraidOsCheck();
|
||||
$unraidOsCheck->checkForUpdate();
|
||||
$unraidOsCheck->checkForUpdate();
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
.ca_element_notice{padding-right:20px;width:100%;height:40px;line-height:40px;color:#e68a00;background:#feefb3;border-bottom:#e68a00 1px solid;text-align:center;font-size:1.4rem;z-index:900}
|
||||
a.ca_PluginUpdateInstall{cursor:pointer}
|
||||
span.ca_PluginUpdateDismiss{float:right;margin-right:20px;cursor:pointer}
|
||||
span.bannerInfo {cursor:pointer;text-decoration:none;margin:0 12px 0 6px}
|
||||
span.bannerInfo::before {content:"\f05a";font-family:fontAwesome;color:#e68a00}
|
||||
.ca_element_notice {
|
||||
padding-right: 20px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
color: var(--orange-300);
|
||||
background: var(--yellow-200);
|
||||
border-bottom: var(--orange-300) 1px solid;
|
||||
text-align: center;
|
||||
font-size: 1.4rem;
|
||||
z-index: 900;
|
||||
}
|
||||
a.ca_PluginUpdateInstall {
|
||||
cursor: pointer;
|
||||
}
|
||||
span.ca_PluginUpdateDismiss {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
span.bannerInfo {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
margin: 0 12px 0 6px;
|
||||
}
|
||||
span.bannerInfo::before {
|
||||
content: "\f05a";
|
||||
font-family: fontAwesome;
|
||||
color: var(--orange-300);
|
||||
}
|
||||
|
||||
@@ -1,2 +1,18 @@
|
||||
#plugin_tree{width:33%;height:200px;overflow-y:scroll}
|
||||
table tbody td{line-height:normal}
|
||||
#plugin_tree {
|
||||
width: 33%;
|
||||
height: 200px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
table tbody td {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.Theme--black,
|
||||
.Theme--white {
|
||||
span.status.vhshift {
|
||||
margin-top: 8px !important;
|
||||
}
|
||||
table#plugin_table {
|
||||
margin-top: -43px !important;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
span.vhshift{margin-top:13px!important}
|
||||
@@ -1 +0,0 @@
|
||||
span.vhshift{margin-top:13px!important}
|
||||
@@ -1,9 +1,52 @@
|
||||
ul,li{margin:0;padding-top:0;padding-bottom:0}
|
||||
pre.pre{margin:30px 0}
|
||||
pre>p{margin:0;padding:0}
|
||||
pre#swaltext{height:600px!important}
|
||||
@media (max-width:960px){pre#swaltext{height:400px!important}}
|
||||
@media (max-width:960px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
|
||||
@media (max-height:768px){pre#swaltext{height:400px!important}}
|
||||
@media (max-height:768px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
|
||||
input[value="_(Install)_"],input[value="_(Update)_"],input[value="_(Restore)_"]{margin:0}
|
||||
ul,
|
||||
li {
|
||||
margin: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
pre.pre {
|
||||
margin: 30px 0;
|
||||
}
|
||||
pre > p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
pre#swaltext {
|
||||
height: 600px !important;
|
||||
}
|
||||
@media (max-width: 960px) {
|
||||
pre#swaltext {
|
||||
height: 400px !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 960px) {
|
||||
.sweet-alert.nchan {
|
||||
height: 600px;
|
||||
width: 900px;
|
||||
margin-left: -470px;
|
||||
}
|
||||
}
|
||||
@media (max-height: 768px) {
|
||||
pre#swaltext {
|
||||
height: 400px !important;
|
||||
}
|
||||
}
|
||||
@media (max-height: 768px) {
|
||||
.sweet-alert.nchan {
|
||||
height: 600px;
|
||||
width: 900px;
|
||||
margin-left: -470px;
|
||||
}
|
||||
}
|
||||
input[value="_(Install)_"],
|
||||
input[value="_(Update)_"],
|
||||
input[value="_(Restore)_"] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Theme--black,
|
||||
.Theme--white {
|
||||
span.vhshift {
|
||||
margin-top: 13px !important;
|
||||
}
|
||||
}
|
||||
@@ -116,8 +116,6 @@ if (empty($vms)) {
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/dynamix.vm.manager.js')?>"></script>
|
||||
|
||||
@@ -16,6 +16,13 @@ Markdown="false"
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/dynamix.vm.manager.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/vmmanager.js')?>"></script>
|
||||
<script src="<?autov('/webGui/javascript/jquery.filetree.js')?>" charset="utf-8"></script>
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
@@ -37,17 +44,6 @@ Markdown="false"
|
||||
}
|
||||
if (strpos($strName,"User-") === false) $user = ""; else $user = ' class="user"';
|
||||
?>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/dynamix.vm.manager.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/vmmanager.js')?>"></script>
|
||||
<script src="<?autov('/webGui/javascript/jquery.filetree.js')?>" charset="utf-8"></script>
|
||||
|
||||
<div class="vmtemplate">
|
||||
<a href="/VMs/AddVM?template=<?=htmlspecialchars(urlencode($strName))?>">
|
||||
<span name="<?=htmlspecialchars($strName)?>" <?=$user?>><img src="/plugins/dynamix.vm.manager/templates/images/<?=htmlspecialchars($arrTemplate['icon'])?>" title="<?=htmlspecialchars($strName)?>"></span>
|
||||
|
||||
@@ -4,8 +4,8 @@ Nchan="vm_usage:stop"
|
||||
Cond="exec(\"grep -o '^USAGE=.Y' /boot/config/domain.cfg 2>/dev/null\") && is_file('/var/run/libvirt/libvirtd.pid')"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Simon Fairweather.
|
||||
/* Copyright 2005-2025, Lime Technology
|
||||
* Copyright 2012-2025, Simon Fairweather.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -32,10 +32,7 @@ vmusage.on('message', function(msg){
|
||||
});
|
||||
|
||||
$(function(){
|
||||
vmusage.start();
|
||||
vmusage.start().monitor();
|
||||
});
|
||||
|
||||
window.onunload = function(){
|
||||
vmusage.stop();
|
||||
}
|
||||
</script>
|
||||
@@ -100,9 +100,10 @@ if (strpos($strSelectedTemplate,"User-") !== false) {
|
||||
$usertemplate = 1;
|
||||
}
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/plugins/dynamix.vm.manager/styles/dynamix.vm.manager.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.filetree.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/plugins/dynamix.vm.manager/styles/dynamix.vm.manager.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/plugins/dynamix.vm.manager/styles/edit.css')?>">
|
||||
|
||||
<span class="status advancedview_panel" style="margin-top:<?=$top?>px;"><input type="checkbox" class="inlineview"><input type="checkbox" class="advancedview"></span>
|
||||
<div class="domain">
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#f2f2f2;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#f2f2f2;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#f2f2f2;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#1c1c1c;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#1c1c1c;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#1c1c1c;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#1c1c1c;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#1c1c1c;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#1c1c1c;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#f2f2f2;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#f2f2f2;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#f2f2f2;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,59 +0,0 @@
|
||||
body{-webkit-overflow-scrolling:touch}
|
||||
#vmform table{margin-top:0;table-layout:fixed}
|
||||
#vmform div.title + table{margin-top:0}
|
||||
#vmform table tr{vertical-align:top;line-height:4rem;height:4rem}
|
||||
#vmform table tr td:nth-child(1){width:25%;text-align:right;padding-right:4rem}}
|
||||
#vmform table tr td:nth-child(2){width:800px}
|
||||
#vmform textarea{max-width:500px;scrollbar-width:4px}
|
||||
#vmform textarea::-webkit-scrollbar{height:4px;width:4px}
|
||||
#vmform .multiple{position:relative}
|
||||
#vmform .sectionbutton{position:absolute;left:2px;cursor:pointer;opacity:0.4;font-size:1.4rem;line-height:17px;z-index:10;transition-property:opacity,left;transition-duration:0.1s;transition-timing-function:linear}
|
||||
#vmform .sectionbutton.remove{top:0;opacity:0.3}
|
||||
#vmform .sectionbutton.add{bottom:0}
|
||||
#vmform .sectionbutton:hover{opacity:1.0}
|
||||
#vmform .sectiontab{position:absolute;top:2px;bottom:2px;left:0;width:6px;border-radius:3px;background-color:#DDDDDD;transition-property:background,width;transition-duration:0.1s;transition-timing-function:linear}
|
||||
#vmform .multiple:hover .sectionbutton{opacity:0.7;left:4px}
|
||||
#vmform .multiple:hover .sectionbutton.remove{opacity:0.6}
|
||||
#vmform .multiple:hover .sectiontab{background-color:#CCCCCC;width:8px}
|
||||
#vmform table.multiple:hover{background-position:0 0;}
|
||||
#vmform table.multiple td{padding:5px 0}
|
||||
span.advancedview_panel{display:none;line-height:16px;margin-top:1px}
|
||||
.basic{display:none}
|
||||
.advanced{/*Empty placeholder*/}
|
||||
.switch-button-label.off{color:inherit}
|
||||
.template_img_parent{position:relative}
|
||||
#template_img{cursor:pointer}
|
||||
#template_img:hover{opacity:0.5}
|
||||
#template_img:hover i{opacity:1.0}
|
||||
.template_img_chooser_inner{display:inline-block;width:80px;margin-bottom:15px;margin-right:10px;text-align:center;}
|
||||
.template_img_chooser_inner img{width:48px;height:48px}
|
||||
.template_img_chooser_inner p{text-align:center;line-height:8px;}
|
||||
#template_img_chooser{width:560px;height:300px;overflow-y:scroll;position:relative;display:grid;grid-template-columns: repeat(6, minmax(0, 1fr));}
|
||||
#template_img_chooser div:hover{color:#ff8c2f;cursor:pointer;}
|
||||
#form_content{display:none}
|
||||
#vmform .four{overflow:hidden}
|
||||
#vmform .four label{float:left;display:table-cell;width:15%;}
|
||||
#vmform .four label:nth-child(4n+4){}
|
||||
#vmform .four label.cpu1{width:28%;height:16px;line-height:16px}
|
||||
#vmform .four label.cpu2{width:3%;height:16px;line-height:16px}
|
||||
#vmform .mac_generate{cursor:pointer;margin-left:-5px;color:#08C;font-size:1.3rem;transform:translate(0px, 2px)}
|
||||
#vmform .disk{display:none}
|
||||
#vmform .disk_preview{display:inline-block;color:#BBB;transform:translate(0px, 1px)}
|
||||
i.fa-plus-circle,i.fa-minus-circle{margin-left:8px}
|
||||
input[type=checkbox]{margin-left:0}
|
||||
span.width{display:inline-block;width:280px}
|
||||
span.column1{display:inline-block;width:140px}
|
||||
span.column2{display:inline-block;width:220px}
|
||||
input#btnvCPUSelect,input.wlan0_info{font-size:1rem;padding:5px 10px;margin:0 0 0 10px}
|
||||
span.space{display:inline-block;width:60px}
|
||||
span.label{display:inline-block;width:110px;text-align:right;overflow:hidden;text-overflow:ellipsis}
|
||||
span.ipvtap{margin-left:25px;font-family:bitstream}
|
||||
select.narrow{min-width:90px!important}
|
||||
select.second{margin-left:12px;max-width:90px;margin-right:0}
|
||||
div.wlan0{text-align:left}
|
||||
input.trim{width:98px;min-width:98px}
|
||||
input.second{margin-left:8px}
|
||||
.autostart~.switch-button-background{margin-top:8px!important;margin-left:0!important}
|
||||
.hidden{display:none!important}
|
||||
.CodeMirror{border:1px solid #eee;cursor:text;margin-top:15px;margin-bottom:10px}
|
||||
.CodeMirror pre.CodeMirror-placeholder{color:#999}
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#f2f2f2;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#f2f2f2;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#f2f2f2;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#1c1c1c;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#1c1c1c;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#1c1c1c;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#1c1c1c;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#1c1c1c;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#1c1c1c;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,4 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:relative;z-index:100;display:none}
|
||||
#vmform table.multiple{margin:10px 0;background:#f2f2f2;background-size:800px 100%;background-position:-800px;background-repeat:no-repeat;background-clip:content-box;transition:background 0.3s linear}
|
||||
#template_img_chooser_outer{position:absolute;display:none;border-radius:5px;border:1px solid <?=$border?>;background:#f2f2f2;z-index:10}
|
||||
span#dropbox{border:1px solid <?=$border?>;background:#f2f2f2;padding:28px 12px;line-height:72px;margin-right:16px;}
|
||||
@@ -1,59 +0,0 @@
|
||||
body{-webkit-overflow-scrolling:touch}
|
||||
#vmform table{margin-top:0;table-layout:fixed}
|
||||
#vmform div.title + table{margin-top:0}
|
||||
#vmform table tr{vertical-align:top;line-height:4rem;height:4rem}
|
||||
#vmform table tr td:nth-child(1){width:25%;text-align:right;padding-right:4rem}}
|
||||
#vmform table tr td:nth-child(2){width:800px}
|
||||
#vmform textarea{max-width:500px;scrollbar-width:4px}
|
||||
#vmform textarea::-webkit-scrollbar{height:4px;width:4px}
|
||||
#vmform .multiple{position:relative}
|
||||
#vmform .sectionbutton{position:absolute;left:2px;cursor:pointer;opacity:0.4;font-size:1.4rem;line-height:17px;z-index:10;transition-property:opacity,left;transition-duration:0.1s;transition-timing-function:linear}
|
||||
#vmform .sectionbutton.remove{top:0;opacity:0.3}
|
||||
#vmform .sectionbutton.add{bottom:0}
|
||||
#vmform .sectionbutton:hover{opacity:1.0}
|
||||
#vmform .sectiontab{position:absolute;top:2px;bottom:2px;left:0;width:6px;border-radius:3px;background-color:#DDDDDD;transition-property:background,width;transition-duration:0.1s;transition-timing-function:linear}
|
||||
#vmform .multiple:hover .sectionbutton{opacity:0.7;left:4px}
|
||||
#vmform .multiple:hover .sectionbutton.remove{opacity:0.6}
|
||||
#vmform .multiple:hover .sectiontab{background-color:#CCCCCC;width:8px}
|
||||
#vmform table.multiple:hover{background-position:0 0;}
|
||||
#vmform table.multiple td{padding:5px 0}
|
||||
span.advancedview_panel{display:none;line-height:16px;margin-top:1px}
|
||||
.basic{display:none}
|
||||
.advanced{/*Empty placeholder*/}
|
||||
.switch-button-label.off{color:inherit}
|
||||
.template_img_parent{position:relative}
|
||||
#template_img{cursor:pointer}
|
||||
#template_img:hover{opacity:0.5}
|
||||
#template_img:hover i{opacity:1.0}
|
||||
.template_img_chooser_inner{display:inline-block;width:80px;margin-bottom:15px;margin-right:10px;text-align:center;}
|
||||
.template_img_chooser_inner img{width:48px;height:48px}
|
||||
.template_img_chooser_inner p{text-align:center;line-height:8px;}
|
||||
#template_img_chooser{width:560px;height:300px;overflow-y:scroll;position:relative;display:grid;grid-template-columns: repeat(6, minmax(0, 1fr));}
|
||||
#template_img_chooser div:hover{color:#ff8c2f;cursor:pointer;}
|
||||
#form_content{display:none}
|
||||
#vmform .four{overflow:hidden}
|
||||
#vmform .four label{float:left;display:table-cell;width:15%;}
|
||||
#vmform .four label:nth-child(4n+4){}
|
||||
#vmform .four label.cpu1{width:28%;height:16px;line-height:16px}
|
||||
#vmform .four label.cpu2{width:3%;height:16px;line-height:16px}
|
||||
#vmform .mac_generate{cursor:pointer;margin-left:-5px;color:#08C;font-size:1.3rem;transform:translate(0px, 2px)}
|
||||
#vmform .disk{display:none}
|
||||
#vmform .disk_preview{display:inline-block;color:#BBB;transform:translate(0px, 1px)}
|
||||
i.fa-plus-circle,i.fa-minus-circle{margin-left:8px}
|
||||
input[type=checkbox]{margin-left:0}
|
||||
span.width{display:inline-block;width:280px}
|
||||
span.column1{display:inline-block;width:140px}
|
||||
span.column2{display:inline-block;width:220px}
|
||||
input#btnvCPUSelect,input.wlan0_info{font-size:1rem;padding:5px 10px;margin:0 0 0 10px}
|
||||
span.space{display:inline-block;width:60px}
|
||||
span.label{display:inline-block;width:110px;text-align:right;overflow:hidden;text-overflow:ellipsis}
|
||||
span.ipvtap{margin-left:25px;font-family:bitstream}
|
||||
select.narrow{min-width:90px!important}
|
||||
select.second{margin-left:12px;max-width:90px;margin-right:0}
|
||||
div.wlan0{text-align:left}
|
||||
input.trim{width:98px;min-width:98px}
|
||||
input.second{margin-left:8px}
|
||||
.autostart~.switch-button-background{margin-top:8px!important;margin-left:0!important}
|
||||
.hidden{display:none!important}
|
||||
.CodeMirror{border:1px solid #eee;cursor:text;margin-top:15px;margin-bottom:10px}
|
||||
.CodeMirror pre.CodeMirror-placeholder{color:#999}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:500px;max-height:320px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:500px;max-height:320px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:500px;max-height:320px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:500px;max-height:320px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1,23 +1,134 @@
|
||||
th.th1{width:25%}
|
||||
th.th2{width:15%}
|
||||
th.th3{width:80px}
|
||||
div.four{font-size:1.1rem;width:260px}
|
||||
div.four label{float:left;display:table-cell;width:25%}
|
||||
div.four label:nth-child(4n+4){float:none;clear:both}
|
||||
div.four label.cpu1{width:32%}
|
||||
div.four label.cpu2{width:26%}
|
||||
div.template,div#dialogWindow,input#upload{display:none}
|
||||
table.domdisk thead tr th:nth-child(1){width:56%!important}
|
||||
table.domdisk thead tr th:nth-child(n+2){width:8%!important}
|
||||
table.domdisk thead tr th:nth-child(1){padding-left:72px}
|
||||
table.domdisk tbody tr td:nth-child(1){padding-left:72px}
|
||||
table.domdisk tbody tr:nth-child(even){background-color:transparent!important}
|
||||
table.domdisk tbody tr:nth-child(4n-1){background-color:transparent!important}
|
||||
table.snapshot{margin-top:0}
|
||||
table tbody td{line-height:normal}
|
||||
i.mover{margin-right:8px;display:none}
|
||||
i.fa-dot-circle-o{padding-left:12px}
|
||||
#resetsort{margin-left:12px;display:inline-block;width:32px}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button[disabled]{cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.dropdown-menu{z-index:10001}
|
||||
span.vmgraphics{font-size:1.1rem;text-align:left}
|
||||
:root {
|
||||
--vm-machines-file-tree-background: var(--black);
|
||||
}
|
||||
|
||||
.Theme--azure:root,
|
||||
.Theme--white:root {
|
||||
--vm-machines-file-tree-background: var(--gray-100);
|
||||
}
|
||||
|
||||
th.th1 {
|
||||
width: 25%;
|
||||
}
|
||||
th.th2 {
|
||||
width: 15%;
|
||||
}
|
||||
th.th3 {
|
||||
width: 80px;
|
||||
}
|
||||
div.four {
|
||||
font-size: 1.1rem;
|
||||
width: 260px;
|
||||
}
|
||||
div.four label {
|
||||
float: left;
|
||||
display: table-cell;
|
||||
width: 25%;
|
||||
}
|
||||
div.four label:nth-child(4n + 4) {
|
||||
float: none;
|
||||
clear: both;
|
||||
}
|
||||
div.four label.cpu1 {
|
||||
width: 32%;
|
||||
}
|
||||
div.four label.cpu2 {
|
||||
width: 26%;
|
||||
}
|
||||
div.template,
|
||||
div#dialogWindow,
|
||||
input#upload {
|
||||
display: none;
|
||||
}
|
||||
table.domdisk thead tr th:nth-child(1) {
|
||||
width: 56% !important;
|
||||
}
|
||||
table.domdisk thead tr th:nth-child(n + 2) {
|
||||
width: 8% !important;
|
||||
}
|
||||
table.domdisk thead tr th:nth-child(1) {
|
||||
padding-left: 72px;
|
||||
}
|
||||
table.domdisk tbody tr td:nth-child(1) {
|
||||
padding-left: 72px;
|
||||
}
|
||||
table.domdisk tbody tr:nth-child(even) {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
table.domdisk tbody tr:nth-child(4n-1) {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
table.snapshot {
|
||||
margin-top: 0;
|
||||
}
|
||||
table tbody td {
|
||||
line-height: normal;
|
||||
}
|
||||
i.mover {
|
||||
margin-right: 8px;
|
||||
display: none;
|
||||
}
|
||||
i.fa-dot-circle-o {
|
||||
padding-left: 12px;
|
||||
}
|
||||
#resetsort {
|
||||
margin-left: 12px;
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button[disabled] {
|
||||
cursor: default;
|
||||
color: var(--gray-500);
|
||||
background:
|
||||
-webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
right top,
|
||||
from(var(--gray-600)),
|
||||
to(var(--gray-500))
|
||||
)
|
||||
0 0 no-repeat,
|
||||
-webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
right top,
|
||||
from(var(--gray-600)),
|
||||
to(var(--gray-500))
|
||||
) 0 100% no-repeat,
|
||||
-webkit-gradient(
|
||||
linear,
|
||||
left bottom,
|
||||
left top,
|
||||
from(var(--gray-600)),
|
||||
to(var(--gray-600))
|
||||
) 0 100% no-repeat,
|
||||
-webkit-gradient(
|
||||
linear,
|
||||
left bottom,
|
||||
left top,
|
||||
from(var(--gray-500)),
|
||||
to(var(--gray-500))
|
||||
) 100% 100% no-repeat;
|
||||
background:
|
||||
linear-gradient(90deg, var(--gray-600) 0, var(--gray-500)) 0 0 no-repeat,
|
||||
linear-gradient(90deg, var(--gray-600) 0, var(--gray-500)) 0 100% no-repeat,
|
||||
linear-gradient(0deg, var(--gray-600) 0, var(--gray-600)) 0 100% no-repeat,
|
||||
linear-gradient(0deg, var(--gray-500) 0, var(--gray-500)) 100% 100% no-repeat;
|
||||
background-size:
|
||||
100% 2px,
|
||||
100% 2px,
|
||||
2px 100%,
|
||||
2px 100%;
|
||||
}
|
||||
.dropdown-menu {
|
||||
z-index: 10001;
|
||||
}
|
||||
span.vmgraphics {
|
||||
font-size: 1.1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* .fileTree {
|
||||
width: 500px;
|
||||
max-height: 320px;
|
||||
} */
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1,12 +1,63 @@
|
||||
body{-webkit-overflow-scrolling:touch}
|
||||
.errortext{color:#EF3D47;display:none}
|
||||
.basic{display:block}
|
||||
.advanced{display:none}
|
||||
#winvirtio{display:none}
|
||||
#download_status{margin-left:5px;color:#777;display:none}
|
||||
#download_button{cursor:pointer;margin-left:-2px;color:#08C;display:none;transform:translate(0px,2px)}
|
||||
#download_button.fa-spin{cursor:default;color:#777}
|
||||
#download_button span{font-family:clear-sans}
|
||||
#download_button.fa-spin span{font-family:clear-sans;display:none}
|
||||
#remove_button{cursor:pointer;margin-left:-2px;color:#EF3D47;display:none;transform:translate(0px,2px)}
|
||||
#remove_button span{font-family:clear-sans}
|
||||
:root {
|
||||
--vm-machines-file-tree-background: var(--black);
|
||||
}
|
||||
|
||||
.Theme--azure:root,
|
||||
.Theme--white:root {
|
||||
--vm-machines-file-tree-background: var(--gray-100);
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.errortext {
|
||||
color: var(--red-800); /* Condensed from: #ef3d47 */
|
||||
display: none;
|
||||
}
|
||||
.basic {
|
||||
display: block;
|
||||
}
|
||||
.advanced {
|
||||
display: none;
|
||||
}
|
||||
#winvirtio {
|
||||
display: none;
|
||||
}
|
||||
#download_status {
|
||||
margin-left: 5px;
|
||||
color: var(--gray-500); /* Condensed from: #777 */
|
||||
display: none;
|
||||
}
|
||||
#download_button {
|
||||
cursor: pointer;
|
||||
margin-left: -2px;
|
||||
color: var(--blue-700); /* Condensed from: #08c */
|
||||
display: none;
|
||||
transform: translate(0px, 2px);
|
||||
}
|
||||
#download_button.fa-spin {
|
||||
cursor: default;
|
||||
color: var(--gray-500); /* Condensed from: #777 */
|
||||
}
|
||||
#download_button span {
|
||||
font-family: clear-sans;
|
||||
}
|
||||
#download_button.fa-spin span {
|
||||
font-family: clear-sans;
|
||||
display: none;
|
||||
}
|
||||
#remove_button {
|
||||
cursor: pointer;
|
||||
margin-left: -2px;
|
||||
color: var(--red-800); /* Condensed from: #ef3d47 */
|
||||
display: none;
|
||||
transform: translate(0px, 2px);
|
||||
}
|
||||
#remove_button span {
|
||||
font-family: clear-sans;
|
||||
}
|
||||
|
||||
/* .fileTree {
|
||||
width: 300px;
|
||||
max-height: 150px;
|
||||
} */
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -1,2 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
.vmheader{padding:10px;font-size:1.4rem;text-align:left;color:#888}
|
||||
.vmtemplate{display:inline-block;width:80px;height:90px;margin-bottom:15px;margin-left:10px;text-align:center;vertical-align:top}
|
||||
.vmtemplate img{width:48px;height:48px}
|
||||
.vmtemplate p{text-align:center;margin-top:8px;line-height:12px}
|
||||
div.template,div#dialogWindow,input#upload{display:none}
|
||||
.Theme--gray:root,
|
||||
.Theme--black:root {
|
||||
--filetree-background: #1c1c1c;
|
||||
}
|
||||
|
||||
.Theme--azure:root,
|
||||
.Theme--white:root {
|
||||
--filetree-background: #f2f2f2;
|
||||
}
|
||||
|
||||
.vmheader {
|
||||
padding: 10px;
|
||||
font-size: 1.4rem;
|
||||
text-align: left;
|
||||
color: var(--gray-500); /* Condensed from: #888 */
|
||||
}
|
||||
|
||||
.vmtemplate {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 90px;
|
||||
margin-bottom: 15px;
|
||||
margin-left: 10px;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.vmtemplate img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.vmtemplate p {
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
div.template,
|
||||
div#dialogWindow,
|
||||
input#upload {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* .fileTree {
|
||||
width: 300px;
|
||||
max-height: 150px;
|
||||
} */
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
:root {
|
||||
--add-vm-background: var(--black);
|
||||
--add-vm-border: var(--gray-150);
|
||||
}
|
||||
|
||||
.Theme--azure:root,
|
||||
.Theme--white:root {
|
||||
--add-vm-background: var(--gray-100);
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
#vmform table {
|
||||
margin-top: 0;
|
||||
table-layout: fixed;
|
||||
}
|
||||
#vmform div.title + table {
|
||||
margin-top: 0;
|
||||
}
|
||||
#vmform table tr {
|
||||
vertical-align: top;
|
||||
line-height: 4rem;
|
||||
height: 4rem;
|
||||
}
|
||||
#vmform table tr td:nth-child(1) {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
}
|
||||
#vmform table tr td:nth-child(2) {
|
||||
width: 800px;
|
||||
}
|
||||
@media (max-width: 1280px) {
|
||||
#vmform table tr td:first-child {
|
||||
width: 35%;
|
||||
padding-right: 4rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1281px) {
|
||||
#vmform table tr td:first-child {
|
||||
width: 30%;
|
||||
padding-right: 4rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1921px) {
|
||||
#vmform table tr td:first-child {
|
||||
width: 25%;
|
||||
padding-right: 4rem;
|
||||
}
|
||||
}
|
||||
#vmform table tr td:last-child {
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
#vmform textarea {
|
||||
max-width: 500px;
|
||||
scrollbar-width: 4px;
|
||||
}
|
||||
|
||||
#vmform textarea::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
#vmform .multiple {
|
||||
position: relative;
|
||||
}
|
||||
#vmform .sectionbutton {
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
cursor: pointer;
|
||||
opacity: 0.4;
|
||||
font-size: 1.4rem;
|
||||
line-height: 17px;
|
||||
z-index: 10;
|
||||
transition-property: opacity, left;
|
||||
transition-duration: 0.1s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
#vmform .sectionbutton.remove {
|
||||
top: 0;
|
||||
opacity: 0.3;
|
||||
}
|
||||
#vmform .sectionbutton.add {
|
||||
bottom: 0;
|
||||
}
|
||||
#vmform .sectionbutton:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
#vmform .sectiontab {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
bottom: 2px;
|
||||
left: 0;
|
||||
width: 6px;
|
||||
border-radius: 3px;
|
||||
background-color: var(--gray-200); /* Condensed from: #dddddd */
|
||||
transition-property: background, width;
|
||||
transition-duration: 0.1s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
#vmform .multiple:hover .sectionbutton {
|
||||
opacity: 0.7;
|
||||
left: 4px;
|
||||
}
|
||||
#vmform .multiple:hover .sectionbutton.remove {
|
||||
opacity: 0.6;
|
||||
}
|
||||
#vmform .multiple:hover .sectiontab {
|
||||
background-color: var(--gray-300);
|
||||
width: 8px;
|
||||
}
|
||||
#vmform table.multiple:hover {
|
||||
background-position: 0 0;
|
||||
}
|
||||
#vmform table.multiple td {
|
||||
padding: 5px 0;
|
||||
}
|
||||
span.advancedview_panel {
|
||||
display: none;
|
||||
line-height: 16px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
.basic {
|
||||
display: none;
|
||||
}
|
||||
.advanced {
|
||||
/*Empty placeholder*/
|
||||
}
|
||||
.switch-button-label.off {
|
||||
color: inherit;
|
||||
}
|
||||
#template_img {
|
||||
cursor: pointer;
|
||||
}
|
||||
#template_img:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
#template_img:hover i {
|
||||
opacity: 1;
|
||||
}
|
||||
.template_img_chooser_inner {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
.template_img_chooser_inner:hover {
|
||||
color: var(--orange-400);
|
||||
cursor: pointer;
|
||||
}
|
||||
.template_img_chooser_inner img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
.template_img_chooser_inner p {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
.template_img_parent {
|
||||
position: relative;
|
||||
}
|
||||
#template_img_chooser_outer {
|
||||
position: absolute;
|
||||
display: none;
|
||||
border-radius: 5px;
|
||||
border: 1px solid var(--add-vm-border);
|
||||
background: var(--add-vm-background);
|
||||
z-index: 10;
|
||||
}
|
||||
#template_img_chooser {
|
||||
width: 560px;
|
||||
height: 300px;
|
||||
overflow-y: scroll;
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
#form_content {
|
||||
display: none;
|
||||
}
|
||||
#vmform .four {
|
||||
overflow: hidden;
|
||||
}
|
||||
#vmform .four label {
|
||||
float: left;
|
||||
display: table-cell;
|
||||
width: 15%;
|
||||
}
|
||||
#vmform .four label:nth-child(4n + 4) {
|
||||
}
|
||||
#vmform .four label.cpu1 {
|
||||
width: 28%;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
}
|
||||
#vmform .four label.cpu2 {
|
||||
width: 3%;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
}
|
||||
#vmform .mac_generate {
|
||||
cursor: pointer;
|
||||
margin-left: -5px;
|
||||
color: var(--blue-700); /* Condensed from: #08c */
|
||||
font-size: 1.3rem;
|
||||
transform: translate(0px, 2px);
|
||||
}
|
||||
#vmform .disk {
|
||||
display: none;
|
||||
}
|
||||
#vmform .disk_preview {
|
||||
display: inline-block;
|
||||
color: var(--gray-300); /* Condensed from: #bbb */
|
||||
transform: translate(0px, 1px);
|
||||
}
|
||||
i.fa-plus-circle,
|
||||
i.fa-minus-circle {
|
||||
margin-left: 8px;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
span.width {
|
||||
display: inline-block;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
span.column1 {
|
||||
display: inline-block;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
span.column2 {
|
||||
display: inline-block;
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
input#btnvCPUSelect,
|
||||
input.wlan0_info {
|
||||
font-size: 1rem;
|
||||
padding: 5px 10px;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
|
||||
span.space {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
span.label {
|
||||
display: inline-block;
|
||||
width: 110px;
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
span.ipvtap {
|
||||
margin-left: 25px;
|
||||
font-family: bitstream;
|
||||
}
|
||||
|
||||
select.narrow {
|
||||
min-width: 90px !important;
|
||||
}
|
||||
|
||||
select.second {
|
||||
margin-left: 12px;
|
||||
max-width: 90px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
div.wlan0 {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input.trim {
|
||||
width: 98px;
|
||||
min-width: 98px;
|
||||
}
|
||||
|
||||
input.second {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.autostart ~ .switch-button-background {
|
||||
margin-top: 8px !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
border: 1px solid var(--gray-150);
|
||||
cursor: text;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.CodeMirror pre.CodeMirror-placeholder {
|
||||
color: var(--gray-400);
|
||||
}
|
||||
|
||||
.fileTree {
|
||||
position: relative;
|
||||
}
|
||||
@@ -1310,7 +1310,7 @@ foreach ($arrConfig['shares'] as $i => $arrShare) {
|
||||
<?
|
||||
echo mk_option($arrGPU['render'], 'auto', _('Auto'));
|
||||
foreach ($arrValidGPUDevices as $arrDev) {
|
||||
if (($arrDev['vendorid'] == "10de" && !is_file("/etc/libvirt/virglnv")) || $arrDev['driver'] == "vfio-pci") continue;
|
||||
if (($arrDev['vendorid'] == "10de" && ($arrDev['driver'] == "nvidia" && !is_file("/etc/libvirt/virglnv"))) || $arrDev['driver'] == "vfio-pci") continue;
|
||||
echo mk_option($arrGPU['render'], $arrDev['id'], $arrDev['name'].' ('.$arrDev['id'].')');
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -114,7 +114,7 @@ function toggle_state(device,name,action) {
|
||||
button = '[id^=button-]';
|
||||
}
|
||||
devices.stop();
|
||||
$.post('/webGui/include/ToggleState.php',{device:device,name:name,action:action},function(){setTimeout(function(){devices.start();},1000);if (button) $(button).prop('disabled',false);});
|
||||
$.post('/webGui/include/ToggleState.php',{device:device,name:name,action:action},function(){setTimeout(function(){devices.start().monitor();},1000);if (button) $(button).prop('disabled',false);});
|
||||
}
|
||||
|
||||
function display_diskio() {
|
||||
@@ -319,7 +319,7 @@ $('div[class=title]:not(":last, .disable_diskio")').each(function(){$(this).appe
|
||||
$('.tooltip_diskio').tooltipster({delay:100,trigger:'custom',triggerOpen:{mouseenter:true},triggerClose:{click:false,scroll:true,mouseleave:true}});
|
||||
|
||||
<?if (_var($var,'fsState')=='Started'):?>
|
||||
var mymonitor = new NchanSubscriber('/sub/mymonitor',{subscriber:'websocket'});
|
||||
var mymonitor = new NchanSubscriber('/sub/mymonitor',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
mymonitor.on('message', function(state) {
|
||||
switch (state) {
|
||||
case '0': // normal operation
|
||||
@@ -367,12 +367,12 @@ mymonitor.on('message', function(state) {
|
||||
mymonitor.start();
|
||||
<?endif;?>
|
||||
|
||||
var arraymonitor = new NchanSubscriber('/sub/arraymonitor',{subscriber:'websocket'});
|
||||
var arraymonitor = new NchanSubscriber('/sub/arraymonitor',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
arraymonitor.on('message', function(state) {
|
||||
if (state==1 && !timers.arraymonitor) timers.arraymonitor = setTimeout(refresh,1250);
|
||||
});
|
||||
|
||||
var devices = new NchanSubscriber('/sub/devices<?=$spot?",parity":""?>',{subscriber:'websocket'});
|
||||
var devices = new NchanSubscriber('/sub/devices<?=$spot?",parity":""?>',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
devices.on('message', function(msg,meta) {
|
||||
switch (<?if($spot):?>meta.id.channel()<?else:?>0<?endif;?>) {
|
||||
case 0:
|
||||
@@ -420,10 +420,10 @@ devices.on('message', function(msg,meta) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
devices.start();
|
||||
devices.start().monitor();
|
||||
|
||||
<?if (substr(_var($var,'fsState'),-3)=='ing'):?>
|
||||
var fsState = new NchanSubscriber('/sub/fsState',{subscriber:'websocket'});
|
||||
var fsState = new NchanSubscriber('/sub/fsState',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
fsState.on('message', function(msg) {
|
||||
switch (msg) {
|
||||
case 'stop':
|
||||
@@ -438,7 +438,7 @@ fsState.start();
|
||||
<?elseif ($spot):?>
|
||||
setTimeout(function(){$('#pauseButton').prop('disabled',false);$('#cancelButton').prop('disabled',false);},250);
|
||||
<?else:?>
|
||||
var paritymonitor = new NchanSubscriber('/sub/paritymonitor',{subscriber:'websocket'});
|
||||
var paritymonitor = new NchanSubscriber('/sub/paritymonitor',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
paritymonitor.on('message', function(busy){if (busy==1) refresh();});
|
||||
setTimeout(function(){paritymonitor.start();},5000);
|
||||
<?endif;?>
|
||||
|
||||
@@ -3,8 +3,8 @@ Tag="home"
|
||||
Nchan="file_manager"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* Copyright 2005-2025, Lime Technology
|
||||
* Copyright 2012-2025, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -18,21 +18,24 @@ Nchan="file_manager"
|
||||
function dfm_quote($text) {
|
||||
return "\"$text\"";
|
||||
}
|
||||
|
||||
function dfm_array($array) {
|
||||
return implode(',',array_map('dfm_quote',$array));
|
||||
return implode(',', array_map('dfm_quote', $array));
|
||||
}
|
||||
|
||||
function validdir($dir) {
|
||||
$path = realpath($dir);
|
||||
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path : '';
|
||||
return in_array(explode('/', $path)[1] ?? '', ['mnt','boot']) ? $path : '';
|
||||
}
|
||||
|
||||
$dir = validdir(htmlspecialchars_decode($dir));
|
||||
[$none,$root,$main,$next,$rest] = my_explode('/',$dir,5);
|
||||
$dir = htmlspecialchars(str_replace('\\','\\\\',$dir));
|
||||
$lock = $root=='mnt' ? ($main ?: '---') : ($root=='boot' ? _('flash') : '---');
|
||||
$isshare = $root=='mnt' && (!$main || !$next || ($main=='rootshare' && !$rest));
|
||||
[$none,$root,$main,$next,$rest] = my_explode('/', $dir,5);
|
||||
$dir = htmlspecialchars(str_replace('\\','\\\\', $dir));
|
||||
$lock = $root == 'mnt' ? ($main ?: '---') : ($root == 'boot' ? _('flash') : '---');
|
||||
$isshare = $root == 'mnt' && (!$main || !$next || ($main == 'rootshare' && !$rest));
|
||||
$editor = '/boot/config/editor.cfg';
|
||||
|
||||
if (!file_exists($editor)) file_put_contents($editor,implode("\n",['','txt','js','php','page','plg','xml','old','bak','log','css']));
|
||||
if (!file_exists($editor)) file_put_contents($editor, implode("\n",['','txt','js','php','page','plg','xml','old','bak','log','css']));
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.switchbutton.css")?>">
|
||||
@@ -41,19 +44,20 @@ if (!file_exists($editor)) file_put_contents($editor,implode("\n",['','txt','js'
|
||||
<script src="<?autov("/webGui/javascript/jquery.switchbutton.js")?>"></script>
|
||||
<script>
|
||||
// General variables
|
||||
var dir = "<?=$dir?>";
|
||||
var dir = "<?=$dir?>";
|
||||
var table = null;
|
||||
var thead = null;
|
||||
|
||||
function autoscale(value) {
|
||||
var unit = ['B','kB','MB','GB','TB','PB','EB'];
|
||||
var base = value>1?Math.floor(Math.log(value)/Math.log(1000)):0;
|
||||
var data = base<unit.length ? value/Math.pow(1000, base) : 0;
|
||||
var unit = ['B','kB','MB','GB','TB','PB','EB'];
|
||||
var base = value>1?Math.floor(Math.log(value)/Math.log(1000)):0;
|
||||
var data = base<unit.length ? value/Math.pow(1000, base) : 0;
|
||||
var scale = data<100?100:10;
|
||||
if (data==0) base=0;
|
||||
if (data == 0) base = 0;
|
||||
return ((Math.round(scale*data)/scale)+' '+unit[base]).replace('.','<?=$display['number'][0]?>')+'/s';
|
||||
}
|
||||
function folderContextMenu(id,button) {
|
||||
|
||||
function folderContextMenu(id, button) {
|
||||
var opts = [];
|
||||
context.settings({button:button});
|
||||
if (dfm.running) {
|
||||
@@ -81,7 +85,8 @@ function folderContextMenu(id,button) {
|
||||
}
|
||||
context.attach('#'+id, opts);
|
||||
}
|
||||
function fileContextMenu(id,button) {
|
||||
|
||||
function fileContextMenu(id, button) {
|
||||
var opts = [];
|
||||
context.settings({button:button});
|
||||
if (dfm.running) {
|
||||
@@ -106,7 +111,8 @@ function fileContextMenu(id,button) {
|
||||
}
|
||||
context.attach('#'+id, opts);
|
||||
}
|
||||
function deviceFolderContextMenu(dev,id) {
|
||||
|
||||
function deviceFolderContextMenu(dev, id) {
|
||||
var opts = [];
|
||||
context.settings({button:'both'});
|
||||
if (dfm.running) {
|
||||
@@ -121,7 +127,8 @@ function deviceFolderContextMenu(dev,id) {
|
||||
}
|
||||
context.attach('#device_'+id, opts);
|
||||
}
|
||||
function deviceFileContextMenu(dev,id) {
|
||||
|
||||
function deviceFileContextMenu(dev, id) {
|
||||
var opts = [];
|
||||
context.settings({button:'both'});
|
||||
if (dfm.running) {
|
||||
@@ -134,7 +141,8 @@ function deviceFileContextMenu(dev,id) {
|
||||
}
|
||||
context.attach('#device_'+id, opts);
|
||||
}
|
||||
function home(source,target) {
|
||||
|
||||
function home(source, target) {
|
||||
var equal = '?';
|
||||
$.ajax({
|
||||
async: false,
|
||||
@@ -146,9 +154,11 @@ function home(source,target) {
|
||||
});
|
||||
return equal;
|
||||
}
|
||||
|
||||
function resize() {
|
||||
$('div.autoheight').height(Math.max(window.innerHeight-320,330));
|
||||
}
|
||||
|
||||
function selectAll() {
|
||||
if (dfm.running) {
|
||||
context.attach('#check_0', [{text:"_(Job running)_", icon:"fa fa-ban"}]);
|
||||
@@ -169,7 +179,8 @@ function selectAll() {
|
||||
<?endif;?>
|
||||
}
|
||||
}
|
||||
function selectOne(id,check=true) {
|
||||
|
||||
function selectOne(id, check=true) {
|
||||
if (dfm.running && check) {
|
||||
context.attach('#'+id, [{text:"_(Job running)_", icon:"fa fa-ban"}]);
|
||||
return;
|
||||
@@ -183,36 +194,42 @@ function selectOne(id,check=true) {
|
||||
var checked = 0;
|
||||
if (check) {
|
||||
$('i[id^="check_"]').each(function(){if ($(this).prop('id')!='check_0' && $(this).hasClass('fa-check-square-o')) checked++;});
|
||||
$('input.extra').prop('disabled',checked==0);
|
||||
$('input.extra').prop('disabled',checked == 0);
|
||||
<?if (!$isshare):?>
|
||||
$('input.rename').prop('disabled',checked!=1);
|
||||
$('input.rename').prop('disabled',checked != 1);
|
||||
<?endif;?>
|
||||
} else {
|
||||
$('i[id^="queue_"]').each(function(){if ($(this).hasClass('fa-check-square-o')) checked++;});
|
||||
$('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',checked==0);
|
||||
$('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',checked == 0);
|
||||
}
|
||||
}
|
||||
|
||||
function errorSource() {
|
||||
swal({title:"_(Invalid source)_",text:"_(Not allowed to mix disk and user shares)_",html:true,type:'error',confirmButtonText:"_(Ok)_"});
|
||||
}
|
||||
|
||||
function errorTarget() {
|
||||
swal({title:"_(Invalid target)_",text:"_(Enter a valid target)_",html:true,type:'error',confirmButtonText:"_(Ok)_"},function(x){dfm.window.find('#dfm_target').prop('disabled',false);});
|
||||
}
|
||||
|
||||
function data(id) {
|
||||
var data = id.attr('data').dfm_quote();
|
||||
<?if ($isshare):?>
|
||||
return id.attr('type')=='d' ? data+'/' : data;
|
||||
return id.attr('type') == 'd' ? data+'/' : data;
|
||||
<?else:?>
|
||||
return data;
|
||||
<?endif;?>
|
||||
}
|
||||
|
||||
function fileName(file) {
|
||||
return file.indexOf('/')>=0 ? file.split('/').pop() : file;
|
||||
}
|
||||
|
||||
function fileExtension(file) {
|
||||
file = fileName(file);
|
||||
return file.indexOf('.')>=0 ? file.split('.').pop() : '';
|
||||
}
|
||||
|
||||
function fileEdit(id) {
|
||||
const known = ["","cfg","conf",<?=dfm_array(file($editor,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES))?>];
|
||||
var source = $('#'+id.dfm_proxy()).attr('data').dfm_quote();
|
||||
@@ -231,16 +248,16 @@ function fileEdit(id) {
|
||||
// file editor dialog
|
||||
dfm.window.html($("#dfm_templateEditFile").html().replace('{$0}',source).dfm_build());
|
||||
dfm.window.dialog({
|
||||
dialogClass: 'ui-dfm',
|
||||
classes: {'ui-dialog': 'ui-dfm'},
|
||||
autoOpen: true,
|
||||
title: fileName(source),
|
||||
height: Math.min(window.innerHeight-80,800),
|
||||
width: Math.min(window.innerWidth,1200),
|
||||
height: Math.min(window.innerHeight-80, 800),
|
||||
width: Math.min(window.innerWidth, 1200),
|
||||
resizable: false,
|
||||
modal: true,
|
||||
buttons: {
|
||||
"_(Save)_": function(){
|
||||
$.post('/webGui/include/Control.php',{mode:'save',file:encodeURIComponent(source), data:encodeURIComponent(editor.session.getValue())});
|
||||
$.post('/webGui/include/Control.php',{mode:'save', file:encodeURIComponent(source), data:encodeURIComponent(editor.session.getValue())});
|
||||
dfm.window.dialog('destroy');
|
||||
setTimeout(loadList,100);
|
||||
},
|
||||
@@ -251,6 +268,7 @@ function fileEdit(id) {
|
||||
});
|
||||
$('.ui-dfm .ui-dialog-titlebar-close').html('<i class="fa fa-expand"></i>').prop('title',"_(Expand)_").prop('onclick',null).off('click').click(function(){fullWindow();}).show();
|
||||
}
|
||||
|
||||
function fullWindow() {
|
||||
if ($('.ui-dfm .ui-dialog-titlebar-close').html().indexOf('expand')>=0) {
|
||||
dfm.window.dialog('option','height',window.innerHeight-40);
|
||||
@@ -265,11 +283,12 @@ function fullWindow() {
|
||||
}
|
||||
editor.resize();
|
||||
}
|
||||
|
||||
function doJobs(title) {
|
||||
dfm.window = $("#dfm_dialogWindow");
|
||||
dfm.window.html($('#dfm_templateJobs').html().dfm_build());
|
||||
dfm.window.dialog({
|
||||
dialogClass: 'ui-dfm',
|
||||
classes: {'ui-dialog': 'ui-dfm'},
|
||||
autoOpen: true,
|
||||
title: title,
|
||||
height: 630,
|
||||
@@ -278,7 +297,7 @@ function doJobs(title) {
|
||||
modal: true,
|
||||
buttons: {
|
||||
"_(Start)_": function(){
|
||||
$.post('/webGui/include/Control.php',{mode:'start'},function(queue){
|
||||
$.post('/webGui/include/Control.php', {mode:'start'}, function(queue){
|
||||
if (parseInt(queue) > 0) {
|
||||
if (dfm.window.find('i[id^="queue_"]').length < 2) $.removeCookie('dfm_control.jobs');
|
||||
dfm.window.dialog('close');
|
||||
@@ -295,7 +314,7 @@ function doJobs(title) {
|
||||
$('#dfm_jobs').html(jobs);
|
||||
if (dfm.window.find('i[id^="queue_"]').length==0) $.removeCookie('dfm_control.jobs');
|
||||
});
|
||||
if (parseInt(queue)==1) {
|
||||
if (parseInt(queue) == 1) {
|
||||
setTimeout(function(){$('#dfm_jobs').html("<div id='dfm_joblist'><i class='fa fa-fw fa-minus-square-o grey-text job'></i>_(No jobs scheduled)_ ...</div>");},100);
|
||||
$('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',true);
|
||||
$('.dfm_control.jobs').prop('disabled',true);
|
||||
@@ -313,25 +332,26 @@ function doJobs(title) {
|
||||
if (dfm.running) $('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',true);
|
||||
$('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
|
||||
}
|
||||
|
||||
var filemonitor = new NchanSubscriber('/sub/filemonitor',{subscriber:'websocket'});
|
||||
filemonitor.on('message', function(state) {
|
||||
if (state==1 && !dfm.running && !timers.filemonitor) timers.filemonitor = setTimeout(function(){if (dfm.running) clearTimeout(timers.filemonitor); else refresh();},1500);
|
||||
if (state == 1 && !dfm.running && !timers.filemonitor) timers.filemonitor = setTimeout(function(){if (dfm.running) clearTimeout(timers.filemonitor); else refresh();},1500);
|
||||
});
|
||||
setTimeout(function(){filemonitor.start();},3000);
|
||||
|
||||
function doAction(action,title,id) {
|
||||
var link = id.substr(0,1)=='/';
|
||||
function doAction(action, title, id) {
|
||||
var link = id.substr(0,1) == '/';
|
||||
var source = link ? id : data($('#'+id));
|
||||
var path = source.substr(1).split('/');
|
||||
var zfs = '';
|
||||
<?if ($dfm['zfs']):?>
|
||||
if ([1,4].includes(action) && path[0]=='mnt') {
|
||||
if ([1,4].includes(action) && path[0] == 'mnt') {
|
||||
switch (path.length) {
|
||||
case 3:
|
||||
if (path[2]=='') zfs = path[1]+'/';
|
||||
if (path[2] == '') zfs = path[1]+'/';
|
||||
break;
|
||||
case 4:
|
||||
if (path[3]=='') zfs = path[1]+'/'+path[2];
|
||||
if (path[3] == '') zfs = path[1]+'/'+path[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -344,7 +364,7 @@ function doAction(action,title,id) {
|
||||
var ud = ['disks','remotes'].includes(path[1]); // unassigned devices
|
||||
var match = ud||user ? '' : '^(?!\\/mnt\\/user0?\\/).*$';
|
||||
var name = path.pop()||path.pop();
|
||||
var hdlink = "<?=$var['fuse_directio']==1?'1':''?>";
|
||||
var hdlink = "<?=$var['fuse_directio'] == 1 ? '1' : ''?>";
|
||||
dfm.window = $("#dfm_dialogWindow");
|
||||
switch (action) {
|
||||
case 0: // create folder
|
||||
@@ -446,7 +466,7 @@ function doAction(action,title,id) {
|
||||
break;
|
||||
}
|
||||
dfm.window.dialog({
|
||||
dialogClass: 'ui-dfm',
|
||||
classes: {'ui-dialog': 'ui-dfm'},
|
||||
autoOpen: true,
|
||||
title: title,
|
||||
height: dfm.height,
|
||||
@@ -472,7 +492,7 @@ function doAction(action,title,id) {
|
||||
// check if 'mv' can be used
|
||||
if (path.length > 2) {
|
||||
if (user) {
|
||||
if (home(source,target)==1) action++;
|
||||
if (home(source,target) == 1) action++;
|
||||
} else {
|
||||
var mv = '/'+path[0]+'/'+path[1]+'/';
|
||||
if (target.substr(0,mv.length) == mv) action++;
|
||||
@@ -481,7 +501,7 @@ function doAction(action,title,id) {
|
||||
break;
|
||||
case 11: // change owner
|
||||
var valid = /.+/;
|
||||
target += (target=='root' ? ':root' : ':users');
|
||||
target += (target == 'root' ? ':root' : ':users');
|
||||
break;
|
||||
case 12: // change permission
|
||||
var valid = /.+/;
|
||||
@@ -511,7 +531,7 @@ function doAction(action,title,id) {
|
||||
dfm.window.find('#dfm_exist').prop('disabled',true);
|
||||
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
|
||||
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
|
||||
if (action==11) {
|
||||
if (action == 11) {
|
||||
dfm.window.find('#dfm_owner').prop('disabled',true);
|
||||
dfm.window.find('#dfm_group').prop('disabled',true);
|
||||
dfm.window.find('#dfm_other').prop('disabled',true);
|
||||
@@ -542,7 +562,7 @@ function doAction(action,title,id) {
|
||||
// check if 'mv' can be used
|
||||
if (path.length > 2) {
|
||||
if (user) {
|
||||
if (home(source,target)==1) action++;
|
||||
if (home(source,target) == 1) action++;
|
||||
} else {
|
||||
var mv = '/'+path[0]+'/'+path[1]+'/';
|
||||
if (target.substr(0,mv.length) == mv) action++;
|
||||
@@ -551,7 +571,7 @@ function doAction(action,title,id) {
|
||||
break;
|
||||
case 11: // change owner
|
||||
var valid = /.+/;
|
||||
target += (target=='root' ? ':root' : ':users');
|
||||
target += (target == 'root' ? ':root' : ':users');
|
||||
break;
|
||||
case 12: // change permission
|
||||
var valid = /.+/;
|
||||
@@ -581,10 +601,11 @@ function doAction(action,title,id) {
|
||||
}
|
||||
});
|
||||
dfm_close_button();
|
||||
if (action==15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
|
||||
if (action == 15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
|
||||
setTimeout(function(){if (dfm.window.find('#dfm_target').length) dfm.window.find('#dfm_target').focus().click(); else $('.ui-dfm .ui-dialog-buttonset button:eq(0)').focus();});
|
||||
}
|
||||
function doActions(action,title) {
|
||||
|
||||
function doActions(action, title) {
|
||||
var source = [], type = [], owner = [], perm = [], zfs = [];
|
||||
if (action > 0) {
|
||||
$('i[id^="check_"]').each(function(){
|
||||
@@ -608,7 +629,7 @@ function doActions(action,title) {
|
||||
var ud = ['disks','remotes'].includes(path[1]); // unassigned devices
|
||||
var match = ud||user ? '' : '^(?!.*(user0?|rootshare)).*$';
|
||||
var name = path.pop()||path.pop();
|
||||
var hdlink = "<?=$var['fuse_directio']==1?'1':''?>";
|
||||
var hdlink = "<?=$var['fuse_directio'] == 1 ? '1' : ''?>";
|
||||
var u = false;
|
||||
var d = false;
|
||||
if (bulk) {
|
||||
@@ -618,7 +639,7 @@ function doActions(action,title) {
|
||||
var p = s.substr(1).split('/');
|
||||
if (/^user0?$/.test(p[1])) u = true; else d = true;
|
||||
<?if ($dfm['zfs']):?>
|
||||
if ([1,4].includes(action) && p[0]=='mnt' && type[i]=='d') {
|
||||
if ([1,4].includes(action) && p[0] == 'mnt' && type[i] == 'd') {
|
||||
switch (p.length) {
|
||||
case 2:
|
||||
zfs.push(p[1]+'/');
|
||||
@@ -631,7 +652,7 @@ function doActions(action,title) {
|
||||
}
|
||||
} else {
|
||||
var p = source[0].substr(1).dfm_strip().split('/');
|
||||
if ([1,4].includes(action) && p[0]=='mnt' && type[0]=='d') {
|
||||
if ([1,4].includes(action) && p[0] == 'mnt' && type[0] == 'd') {
|
||||
switch (p.length) {
|
||||
case 2:
|
||||
zfs.push(p[1]+'/');
|
||||
@@ -667,10 +688,10 @@ function doActions(action,title) {
|
||||
dfm.window.html($('#dfm_templateCopyObject').html());
|
||||
dfm_createSource(source);
|
||||
dfm.window.find('#dfm_target').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match);
|
||||
if (bulk || type[0]=='d') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
|
||||
if (bulk || type[0] == 'd') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
|
||||
dfm.window.find('#dfm_target').fileTreeAttach(null,null,function(path){
|
||||
var bits = path.substr(1).split('/');
|
||||
var auto = bulk || bits.length>3 ? '' : (type[0]=='d' ? share : '');
|
||||
var auto = bulk || bits.length>3 ? '' : (type[0] == 'd' ? share : '');
|
||||
dfm.window.find('#dfm_target').val(path+auto).change();
|
||||
});
|
||||
dfm.height = 630;
|
||||
@@ -679,10 +700,10 @@ function doActions(action,title) {
|
||||
dfm.window.html($('#dfm_templateMoveObject').html());
|
||||
dfm_createSource(source);
|
||||
dfm.window.find('#dfm_target').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match);
|
||||
if (bulk || type[0]=='d') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
|
||||
if (bulk || type[0] == 'd') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
|
||||
dfm.window.find('#dfm_target').fileTreeAttach(null,null,function(path){
|
||||
var bits = path.substr(1).split('/');
|
||||
var auto = bulk || bits.length>3 ? '' : (type[0]=='d' ? share : '');
|
||||
var auto = bulk || bits.length > 3 ? '' : (type[0] == 'd' ? share : '');
|
||||
dfm.window.find('#dfm_target').val(path+auto).change();
|
||||
});
|
||||
dfm.height = 630;
|
||||
@@ -716,7 +737,7 @@ function doActions(action,title) {
|
||||
// folders only
|
||||
for (var i=0,t; t=type[i]; i++) if (t != 'd') source[i] = '';
|
||||
source = source.filter(n=>n);
|
||||
if (source.length==0) source[0] = dir;
|
||||
if (source.length == 0) source[0] = dir;
|
||||
dfm_createSource(source);
|
||||
dfm.window.find('.dfm_loc').html(' ').css({'line-height':'normal'});
|
||||
dfm.window.find('.dfm_text').html('').css({'line-height':'normal'});
|
||||
@@ -725,7 +746,7 @@ function doActions(action,title) {
|
||||
}
|
||||
dfm.window.find('#dfm_source').attr('size',Math.min(dfm.tsize[action],source.length));
|
||||
dfm.window.dialog({
|
||||
dialogClass: 'ui-dfm',
|
||||
classes: {'ui-dialog': 'ui-dfm'},
|
||||
autoOpen: true,
|
||||
title: title,
|
||||
height: dfm.height,
|
||||
@@ -750,7 +771,7 @@ function doActions(action,title) {
|
||||
// check if 'mv' can be used
|
||||
if (path.length > 2) {
|
||||
if (user) {
|
||||
if (home(source.join('\n'),target)==1) action++;
|
||||
if (home(source.join('\n'),target) == 1) action++;
|
||||
} else {
|
||||
var mv = '/'+path[0]+'/'+path[1]+'/';
|
||||
if (target.substr(0,mv.length) == mv) action++;
|
||||
@@ -759,7 +780,7 @@ function doActions(action,title) {
|
||||
break;
|
||||
case 11: // change owner
|
||||
var valid = /.+/;
|
||||
target += (target=='root' ? ':root' : ':users');
|
||||
target += (target == 'root' ? ':root' : ':users');
|
||||
bulk = false;
|
||||
break;
|
||||
case 12: // change permission
|
||||
@@ -791,7 +812,7 @@ function doActions(action,title) {
|
||||
dfm.window.find('#dfm_exist').prop('disabled',true);
|
||||
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
|
||||
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
|
||||
if (action==12) {
|
||||
if (action == 12) {
|
||||
dfm.window.find('#dfm_owner').prop('disabled',true);
|
||||
dfm.window.find('#dfm_group').prop('disabled',true);
|
||||
dfm.window.find('#dfm_other').prop('disabled',true);
|
||||
@@ -822,7 +843,7 @@ function doActions(action,title) {
|
||||
// check if 'mv' can be used
|
||||
if (path.length > 2) {
|
||||
if (user) {
|
||||
if (home(source.join('\n'),target)==1) action++;
|
||||
if (home(source.join('\n'),target) == 1) action++;
|
||||
} else {
|
||||
var mv = '/'+path[0]+'/'+path[1]+'/';
|
||||
if (target.substr(0,mv.length) == mv) action++;
|
||||
@@ -831,7 +852,7 @@ function doActions(action,title) {
|
||||
break;
|
||||
case 11: // change owner
|
||||
var valid = /.+/;
|
||||
target += (target=='root' ? ':root' : ':users');
|
||||
target += (target == 'root' ? ':root' : ':users');
|
||||
bulk = false;
|
||||
break;
|
||||
case 12: // change permission
|
||||
@@ -863,9 +884,10 @@ function doActions(action,title) {
|
||||
}
|
||||
});
|
||||
dfm_close_button();
|
||||
if (action==15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
|
||||
if (action == 15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
|
||||
setTimeout(function(){if (dfm.window.find('#dfm_target').length) dfm.window.find('#dfm_target').focus().click(); else $('.ui-dfm .ui-dialog-buttonset button:eq(0)').focus();});
|
||||
}
|
||||
|
||||
function stopUpload(file,error) {
|
||||
window.onbeforeunload = null;
|
||||
$.post('/webGui/include/Control.php',{mode:'stop',file:encodeURIComponent(dfm_htmlspecialchars(file))});
|
||||
@@ -876,6 +898,7 @@ function stopUpload(file,error) {
|
||||
loadList();
|
||||
if (error) setTimeout(function(){swal({title:"_(Upload Error)_",text:"_(File is removed)_",html:true,confirmButtonText:"_(Ok)_"});},200);
|
||||
}
|
||||
|
||||
function downloadFile(source) {
|
||||
var a = document.createElement('a');
|
||||
a.setAttribute('href',source);
|
||||
@@ -885,6 +908,7 @@ function downloadFile(source) {
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
function uploadFile(files,index,start,time) {
|
||||
var file = files[index];
|
||||
var slice = 2097152; // 2M
|
||||
@@ -893,8 +917,8 @@ function uploadFile(files,index,start,time) {
|
||||
reader.onloadend = function(e){
|
||||
if (e.target.readyState !== FileReader.DONE) return;
|
||||
$.post('/webGui/include/Control.php',{mode:'upload',file:encodeURIComponent(dir+'/'+dfm_htmlspecialchars(file.name)),start:start,data:window.btoa(e.target.result),cancel:cancel},function(reply){
|
||||
if (reply=='stop') {stopUpload(file.name); return;}
|
||||
if (reply=='error') {stopUpload(file.name,true); return;}
|
||||
if (reply == 'stop') {stopUpload(file.name); return;}
|
||||
if (reply == 'error') {stopUpload(file.name,true); return;}
|
||||
if (next < file.size) {
|
||||
var total = 0;
|
||||
for (var i=0,f; f=files[i]; i++) {
|
||||
@@ -913,11 +937,12 @@ function uploadFile(files,index,start,time) {
|
||||
};
|
||||
reader.readAsBinaryString(blob);
|
||||
}
|
||||
|
||||
var reader = {};
|
||||
var cancel = 0;
|
||||
|
||||
function startUpload(files) {
|
||||
if (files.length==0) return;
|
||||
if (files.length == 0) return;
|
||||
reader = new FileReader();
|
||||
window.onbeforeunload = function(e){return '';};
|
||||
$('#dfm_uploadButton').val("_(Cancel)_").prop('onclick',null).off('click').click(function(){cancel=1;});
|
||||
@@ -925,17 +950,20 @@ function startUpload(files) {
|
||||
const d = new Date();
|
||||
uploadFile(files,0,0,d.getTime());
|
||||
}
|
||||
|
||||
function filter(ext) {
|
||||
$('td.ext').each(function(){
|
||||
if ($(this).attr('data').search(ext)==-1) $(this).parent().hide(); else $(this).parent().show();
|
||||
if ($(this).attr('data').search(ext) == -1) $(this).parent().hide(); else $(this).parent().show();
|
||||
});
|
||||
}
|
||||
|
||||
function toggleTime(init) {
|
||||
$('.my_time').toggle();
|
||||
$('.my_age').toggle();
|
||||
if (init) return;
|
||||
$.cookie('my_time')==null ? $.cookie('my_time','age') : $.removeCookie('my_time');
|
||||
$.cookie('my_time') == null ? $.cookie('my_time','age') : $.removeCookie('my_time');
|
||||
}
|
||||
|
||||
function loadList() {
|
||||
var col = $.cookie('col')||2;
|
||||
var ord = $.cookie('dir')||0;
|
||||
@@ -952,15 +980,17 @@ function loadList() {
|
||||
$('div#buttons').show();
|
||||
});
|
||||
}
|
||||
|
||||
function xlink(link) {
|
||||
swal({title:'',text:decodeURIComponent(link),html:true,confirmButtonText:"_(Ok)_"});
|
||||
}
|
||||
|
||||
$(function(){
|
||||
var dirs = dir.split('/'), url = [];
|
||||
if (dirs.length > 1) {
|
||||
for (var n=1; n < dirs.length; n++) {
|
||||
var subdir = dirs.slice(1,n+1);
|
||||
url.push('<a class="none" href="/<?=$path?>?dir=/'+encodeURIComponent(subdir.join('/'))+'" oncontextmenu="xlink(\'/'+encodeURIComponent(subdir.join('/'))+'\');return false">'+(n==1 ? '<i class="fa fa-home"></i>' : dirs[n])+'</a>');
|
||||
url.push('<a class="none" href="/<?=$path?>?dir=/'+encodeURIComponent(subdir.join('/'))+'" oncontextmenu="xlink(\'/'+encodeURIComponent(subdir.join('/'))+'\');return false">'+(n == 1 ? '<i class="fa fa-home"></i>' : dirs[n])+'</a>');
|
||||
}
|
||||
} else {
|
||||
url.push('<i class="fa fa-home red-text"></i>');
|
||||
@@ -985,6 +1015,7 @@ $(function(){
|
||||
<?endif;?>
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="autoheight">
|
||||
<table class="indexer tablesorter shift"><thead><tr><th><?if($dir){?><i id="check_0" class="fa fa-fw fa-square-o" onclick="selectAll()"></i><?}?></th><th>_(Type)_</th><th class='sorter-text'>_(Name)_</th><th>_(Owner)_</th><th>_(Permission)_</th><th>_(Size)_</th><th>_(Last Modified)_</th><th style="width:200px">_(Location)_</th><th>_(Action)_</th></tr></thead></table>
|
||||
</div>
|
||||
|
||||
@@ -4,8 +4,8 @@ Icon="icon-u-duplicate"
|
||||
Code="e963"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* Copyright 2005-2025, Lime Technology
|
||||
* Copyright 2012-2025, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -17,7 +17,7 @@ Code="e963"
|
||||
?>
|
||||
<?
|
||||
$dfm = [
|
||||
'browser' => $myPage['name']=='Browse',
|
||||
'browser' => $myPage['name'] == 'Browse',
|
||||
'running' => file_exists('/var/tmp/file.manager.active'),
|
||||
'jobs' => file_exists('/var/tmp/file.manager.jobs'),
|
||||
'zfs' => is_executable('/usr/sbin/zfs')
|
||||
@@ -28,6 +28,7 @@ if ($dfm['running'] || $dfm['browser']) eval('?>'.parse_file("$docroot/webGui/in
|
||||
function BrowseButton() {
|
||||
location.replace('/<?=$task?>/Browse?dir=/mnt');
|
||||
}
|
||||
|
||||
// Prototypes
|
||||
String.prototype.dfm_patch = function(){return this.replace('rw','x+rw').replace('r-','wx+r').replace('--','rwx');}
|
||||
String.prototype.dfm_proxy = function(){return this.replace('name','row');}
|
||||
@@ -43,7 +44,7 @@ String.prototype.dfm_wedge = function(len){len=len||70;return this.length<=len ?
|
||||
const dfm = {window:null, dialog:false, running:false, previous:'', height:0, tsize:{0:0,1:6,2:3,3:3,4:3,11:2,12:2,14:0,15:3}};
|
||||
var dfm_read = {};
|
||||
|
||||
function dfm_footer(action,text) {
|
||||
function dfm_footer(action, text) {
|
||||
switch (action) {
|
||||
case 'show':
|
||||
$('#countdown').show();
|
||||
@@ -54,7 +55,7 @@ function dfm_footer(action,text) {
|
||||
$('#user-notice').hide();
|
||||
break;
|
||||
case 'write':
|
||||
if ($('#countdown').html()=='') $('#countdown').html('<a class="hand" onclick="dfm_openDialog(true)" title="_(File Manager)_"><i class="icon-u-duplicate dfm"></i></a>');
|
||||
if ($('#countdown').html() == '') $('#countdown').html('<a class="hand" onclick="dfm_openDialog(true)" title="_(File Manager)_"><i class="icon-u-duplicate dfm"></i></a>');
|
||||
$('#user-notice').html(text);
|
||||
break;
|
||||
case 'clear':
|
||||
@@ -63,26 +64,32 @@ function dfm_footer(action,text) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function dfm_done() {
|
||||
dfm_footer('write',"<i class='fa fa-circle-thin dfm'></i>_(Searching)_... _(Done)_");
|
||||
dfm_footer('write', "<i class='fa fa-circle-thin dfm'></i>_(Searching)_... _(Done)_");
|
||||
}
|
||||
|
||||
function dfm_minimize() {
|
||||
dfm.window.dialog('close');
|
||||
dfm_footer('show');
|
||||
}
|
||||
|
||||
function dfm_close_button() {
|
||||
$('.ui-dfm .ui-dialog-titlebar-close').html('<i class="fa fa-window-minimize"></i>').prop({'title':"_(Minimize)_"}).prop('onclick',null).off('click').click(function(){dfm_minimize();}).show();
|
||||
}
|
||||
|
||||
function dfm_htmlspecialchars(text) {
|
||||
var map = {'&':'&','<':'<','>':'>','"':'"',"'":'''};
|
||||
return text.replace(/[&<>"']/g,function(m){return map[m];});
|
||||
return text.replace(/[&<>"']/g, function(m){return map[m];});
|
||||
}
|
||||
|
||||
function dfm_escapeHTML(name) {
|
||||
const data = document.createElement('div');
|
||||
const text = document.createTextNode(name);
|
||||
data.appendChild(text);
|
||||
return data.innerHTML;
|
||||
}
|
||||
|
||||
function dfm_createSource(source) {
|
||||
var select = dfm.window.find('#dfm_source');
|
||||
if (Array.isArray(source)) {
|
||||
@@ -98,6 +105,7 @@ function dfm_createSource(source) {
|
||||
select.html('<option selected>'+source+'</option>');
|
||||
}
|
||||
}
|
||||
|
||||
function dfm_showProgress(data) {
|
||||
if (!data) return 0;
|
||||
let file = null;
|
||||
@@ -105,7 +113,7 @@ function dfm_showProgress(data) {
|
||||
let line = text[0].split('... ');
|
||||
let strict = /^mnt|^boot/;
|
||||
let footer = false;
|
||||
if (text[0]=='#cat#') {
|
||||
if (text[0] == '#cat#') {
|
||||
let loc = [], cat = [];
|
||||
for (let i=1,row; row=text[i]; i++) {
|
||||
if (!row) continue;
|
||||
@@ -119,7 +127,7 @@ function dfm_showProgress(data) {
|
||||
dfm.window.find('#dfm_files').html(loc.length+" "+"_(files)_");
|
||||
}
|
||||
return cat.length;
|
||||
} else if (text.length==1) {
|
||||
} else if (text.length == 1) {
|
||||
text = text[0].dfm_wedge(80);
|
||||
footer = text.indexOf("_(Searching)_") != -1;
|
||||
} else {
|
||||
@@ -134,10 +142,11 @@ function dfm_showProgress(data) {
|
||||
footer = true;
|
||||
}
|
||||
}
|
||||
if (file==null || strict.test(file)) dfm.window.find('.dfm_text').html((file?line[0]+'... /'+dfm_escapeHTML(file.dfm_wedge())+'<br>':'')+text);
|
||||
if (file == null || strict.test(file)) dfm.window.find('.dfm_text').html((file?line[0]+'... /'+dfm_escapeHTML(file.dfm_wedge())+'<br>':'')+text);
|
||||
if (footer) dfm_footer('write',text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
function dfm_fileManager(action) {
|
||||
switch (action) {
|
||||
case 'start':
|
||||
@@ -161,14 +170,15 @@ function dfm_fileManager(action) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function dfm_makeDialog(open) {
|
||||
if (open && dfm_read.action==15) {
|
||||
if (open && dfm_read.action == 15) {
|
||||
dfm.window.dialog('open');
|
||||
dfm_footer('hide');
|
||||
return;
|
||||
}
|
||||
dfm.window = $('#dfm_dialogWindow');
|
||||
if (dfm.window.dialog('instance') !== undefined) dfm.dialog = dfm.window.dialog('isOpen');
|
||||
if (dfm.window.dialog('instance') !== undefined) dfm.dialog = dfm.window.dialog('isOpen');
|
||||
var dfm_source = dfm_read.source.split('\r').slice(0,9);
|
||||
switch (dfm_read.action) {
|
||||
case 0: // create folder/object
|
||||
@@ -245,8 +255,8 @@ function dfm_makeDialog(open) {
|
||||
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
|
||||
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
|
||||
dfm.window.dialog({
|
||||
dialogClass: 'ui-dfm',
|
||||
autoOpen: open||dfm.dialog,
|
||||
classes: {'ui-dialog': 'ui-dfm'},
|
||||
autoOpen: open || dfm.dialog,
|
||||
title: dfm_read.title,
|
||||
height: dfm.height,
|
||||
width: 900,
|
||||
@@ -254,7 +264,7 @@ function dfm_makeDialog(open) {
|
||||
modal: true,
|
||||
buttons: {
|
||||
"_(Start)_": function(){
|
||||
if (dfm_read.action==15) {
|
||||
if (dfm_read.action == 15) {
|
||||
var dfm_target = dfm.window.find('#dfm_target').val();
|
||||
dfm.window.find('.dfm_loc').html(' ');
|
||||
dfm.window.find('.dfm_text').html("_(Running)_...");
|
||||
@@ -280,6 +290,7 @@ function dfm_makeDialog(open) {
|
||||
setTimeout(function(){$('.ui-dfm .ui-dialog-buttonset button:eq(2)').focus();});
|
||||
if (open||dfm.dialog) dfm_footer('hide'); else dfm_footer('show');
|
||||
}
|
||||
|
||||
function dfm_openDialog(open) {
|
||||
$.post('/webGui/include/Control.php',{mode:'read'},function(data){
|
||||
if (data) {
|
||||
@@ -289,6 +300,7 @@ function dfm_openDialog(open) {
|
||||
dfm_makeDialog(open);
|
||||
});
|
||||
}
|
||||
|
||||
var nchan_filemanager = new NchanSubscriber('/sub/filemanager',{subscriber:'websocket'});
|
||||
nchan_filemanager.on('message', function(msg) {
|
||||
let data = $.parseJSON(msg);
|
||||
@@ -304,7 +316,7 @@ nchan_filemanager.on('message', function(msg) {
|
||||
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',false);
|
||||
} else {
|
||||
let cat = dfm_showProgress(data.status);
|
||||
if (data.done==1) {
|
||||
if (data.done == 1) {
|
||||
setTimeout(function(){$.post('/webGui/include/Control.php',{mode:'start'},function(queue){
|
||||
switch (parseInt(queue)) {
|
||||
case 0:
|
||||
@@ -324,16 +336,17 @@ nchan_filemanager.on('message', function(msg) {
|
||||
break;
|
||||
}
|
||||
})});
|
||||
} else if (data.done==2) {
|
||||
} else if (data.done == 2) {
|
||||
nchan_filemanager.stop();
|
||||
dfm.running = false;
|
||||
dfm.window.find('#dfm_target').prop('disabled',false).focus();
|
||||
$('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',false);
|
||||
if (cat==0) dfm.window.find('.dfm_text').html("_(No results found)_");
|
||||
if (cat == 0) dfm.window.find('.dfm_text').html("_(No results found)_");
|
||||
if ($('#user-notice:visible')) dfm_done();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
<?if ($dfm['running']):?>
|
||||
$(function(){
|
||||
dfm_openDialog();
|
||||
|
||||
@@ -23,9 +23,6 @@ function sharename($share) {
|
||||
return basename($share,'.cfg');
|
||||
}
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<script>
|
||||
function validate(poolname) {
|
||||
var valid = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/;
|
||||
|
||||
@@ -105,11 +105,20 @@ $fans = exec("sensors -uA 2>/dev/null|grep -c 'fan[0-9]_input'");
|
||||
$autofan = is_executable("$docroot/plugins/dynamix.system.autofan/scripts/rc.autofan");
|
||||
$group = _var($var,'shareSMBEnabled')=='yes' | _var($var,'shareNFSEnabled')=='yes';
|
||||
$names = [];
|
||||
$cache_only = $encrypted = 0;
|
||||
|
||||
foreach ($shares as $share) {
|
||||
if ($share['useCache']=='only') $cache_only++;
|
||||
if ($share['luksStatus']>0) $encrypted++;
|
||||
$SMBpublic = $NFSpublic= 0;
|
||||
foreach ($sec as $share => $prop) {
|
||||
if ( $prop['export'] == "-") continue;
|
||||
if ( $prop['security'] == "public") $SMBpublic++;
|
||||
if ( ($var['shareDisk']??"") == "no" && $share !=="flash" ) continue;
|
||||
if ( ! $started && isset($disks[$share]) && $share !=="flash" ) continue;
|
||||
if ( ! isset($shares[$share]) && isset($disks[$share]) ) {$shares[$share]=$disks[$share]; $shares[$share]['diskexport'] = true;}
|
||||
}
|
||||
foreach ($sec_nfs as $share => $prop) {
|
||||
if ( $prop['export'] == "-") continue;
|
||||
if ( $prop['security'] == "public") $NFSpublic++;
|
||||
if ( ($var['shareDisk']??"") == "no" && $share !=="flash" ) continue;
|
||||
if ( ! $started && isset($disks[$share]) && $share !=="flash" ) continue;
|
||||
if ( ! isset($shares[$share]) && isset($disks[$share]) ) {$shares[$share]=$disks[$share]; $shares[$share]['diskexport'] = true;}
|
||||
}
|
||||
|
||||
$passwd = $nopass = 0;
|
||||
@@ -180,8 +189,6 @@ switch ($theme) {
|
||||
}
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.ui.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.apexcharts.js')?>"></script>
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
@@ -451,7 +458,7 @@ echo "</td></tr>";
|
||||
</select></span>
|
||||
<?endif;?>
|
||||
<br><span>
|
||||
<?=sprintf(_("Share count: %s with %s cache only and %s encrypted"),count($shares),$cache_only,$encrypted)?>
|
||||
<?=sprintf(_("Share count: %s with %s public SMB and %s public NFS"),count($shares),$SMBpublic,$NFSpublic)?>
|
||||
</span><br></div>
|
||||
<a href='/Shares' title="_(Go to Share settings)_"><i class='fa fa-fw fa-cog control'></i></a>
|
||||
</td></tr>
|
||||
@@ -460,9 +467,7 @@ echo "</td></tr>";
|
||||
if (_var($var,'shareSMBEnabled')=='yes') {
|
||||
$i = 0;
|
||||
foreach ($shares as $name => $share) {
|
||||
$list = "<a href=\"/Dashboard/Shares/Share?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
|
||||
if ($share['luksStatus']>0) $list = str_replace('blue-text','green-text',$list);
|
||||
elseif ($share['useCache']=='only') $list = str_replace('blue-text','orange-text',$list);
|
||||
$list = "<a href=\"/Dashboard/Shares/".(isset($share['diskexport']) ? "Disk" : "Share")."?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
|
||||
$comment = $share['comment'] ?: '-';
|
||||
$security = export_settings(_var($var,'shareSMBEnabled'), $sec[$name]);
|
||||
$last = $name==array_key_last($shares) ? ' last' : '';
|
||||
@@ -472,9 +477,8 @@ if (_var($var,'shareSMBEnabled')=='yes') {
|
||||
}
|
||||
if (_var($var,'shareNFSEnabled')=='yes') {
|
||||
foreach ($shares as $name => $share) {
|
||||
$list = "<a href=\"/Dashboard/Shares/Share?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
|
||||
if ($share['luksStatus']>0) $list = str_replace('blue-text','green-text',$list);
|
||||
elseif ($share['useCache']=='only') $list = str_replace('blue-text','orange-text',$list);
|
||||
if ( ! isset($sec_nfs[$name]) ) continue;
|
||||
$list = "<a href=\"/Dashboard/Shares/".(isset($share['diskexport']) ? "Disk" : "Share")."?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
|
||||
$comment = $share['comment'] ?: '-';
|
||||
$security = export_settings(_var($var,'shareNFSEnabled'), $sec_nfs[$name]);
|
||||
$last = $name==array_key_last($shares) ? ' last' : '';
|
||||
@@ -484,9 +488,7 @@ if (_var($var,'shareNFSEnabled')=='yes') {
|
||||
}
|
||||
if (!$group) {
|
||||
foreach ($shares as $name => $share) {
|
||||
$list = "<a href=\"/Dashboard/Shares/Share?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
|
||||
if ($share['luksStatus']>0) $list = str_replace('blue-text','green-text',$list);
|
||||
elseif ($share['useCache']=='only') $list = str_replace('blue-text','orange-text',$list);
|
||||
$list = "<a href=\"/Dashboard/Shares/".(isset($share['diskexport']) ? "Disk" : "Share")."?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
|
||||
$comment = $share['comment'] ?: '-';
|
||||
echo "<tr class='share'><td><span class='w26'><i class='icon-folder f14'></i>$list</span><span class='w44'>".htmlspecialchars($comment)."</span><span class='w18'>-</span><span>-</span></td></tr>";
|
||||
}
|
||||
@@ -810,7 +812,7 @@ var options_cpu = {
|
||||
colors:['#ff8c2f'],
|
||||
markers:{size:0},
|
||||
xaxis:{type:'datetime', range:cpuline-1, labels:{show:false}, axisTicks:{show:false}, axisBorder:{show:false}},
|
||||
yaxis:{max:100, tickAmount:4, labels:{formatter:function(v,i){return v.toFixed(0)+' %';}, style:{colors:'<?=$color?>'}}, axisBorder:{show:false}, axisTicks:{show:false}},
|
||||
yaxis:{max:100, min:0, tickAmount:4, labels:{formatter:function(v,i){return v.toFixed(0)+' %';}, style:{colors:'<?=$color?>'}}, axisBorder:{show:false}, axisTicks:{show:false}},
|
||||
grid:{show:true, borderColor:'<?=$grid?>'},
|
||||
legend:{show:false}
|
||||
};
|
||||
@@ -865,31 +867,30 @@ function sanitizeMultiCookie(cookieName, delimiter, removeDuplicates=false) {
|
||||
}
|
||||
|
||||
function initCharts(clear) {
|
||||
$.post('/webGui/include/InitCharts.php',{cmd:'get'},function(data) {
|
||||
data = JSON.parse(data);
|
||||
// initialize graphs entries
|
||||
var now = new Date().getTime();
|
||||
if (!clear) {
|
||||
var c = data.cpu.split(';');
|
||||
var r = data.rxd.split(';');
|
||||
var t = data.txd.split(';');
|
||||
for (var i=0; i < cpuline; i++) {
|
||||
var x = now + i;
|
||||
var y = c[i]||0; cpu.push({x,y});
|
||||
}
|
||||
cputime = x + 1;
|
||||
} else {
|
||||
// clear network graph
|
||||
var r = ''; var t = '';
|
||||
rxd = []; txd = [];
|
||||
}
|
||||
for (var i=0; i < netline; i++) {
|
||||
// initialize graphs entries
|
||||
var data = [];
|
||||
data.cpu = data.rxd = data.txd ="";
|
||||
var now = new Date().getTime();
|
||||
if (!clear) {
|
||||
var c = data.cpu.split(';');
|
||||
var r = data.rxd.split(';');
|
||||
var t = data.txd.split(';');
|
||||
for (var i=0; i < cpuline; i++) {
|
||||
var x = now + i;
|
||||
var y = r[i]||0; rxd.push({x,y});
|
||||
var y = t[i]||0; txd.push({x,y});
|
||||
var y = c[i]||0; cpu.push({x,y});
|
||||
}
|
||||
nettime = x + 1;
|
||||
});
|
||||
cputime = x + 1;
|
||||
} else {
|
||||
// clear network graph
|
||||
var r = ''; var t = '';
|
||||
rxd = []; txd = [];
|
||||
}
|
||||
for (var i=0; i < netline; i++) {
|
||||
var x = now + i;
|
||||
var y = r[i]||0; rxd.push({x,y});
|
||||
var y = t[i]||0; txd.push({x,y});
|
||||
}
|
||||
nettime = x + 1;
|
||||
}
|
||||
|
||||
function resetCharts() {
|
||||
@@ -1406,11 +1407,7 @@ function contentMgmt() {
|
||||
modal: true,
|
||||
buttons: {
|
||||
"_(Reset)_": function(){
|
||||
delete cookie.db_box1;
|
||||
delete cookie.db_box2;
|
||||
delete cookie.db_box3;
|
||||
delete cookie.inactive_content;
|
||||
delete cookie.hidden_content;
|
||||
cookie = {};
|
||||
saveCookie();
|
||||
box.dialog('close');
|
||||
location.reload();
|
||||
@@ -1608,7 +1605,7 @@ function cpu_parse(msg) {
|
||||
}
|
||||
|
||||
<?if ($vmusage == "Y"):?>
|
||||
var vmdashusage = new NchanSubscriber('/sub/vm_dashusage',{subscriber:'websocket'});
|
||||
var vmdashusage = new NchanSubscriber('/sub/vm_dashusage',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
vmdashusage.on('message', function(msg){
|
||||
var data = JSON.parse(msg);
|
||||
for (const [vm, vmdata] of Object.entries(data)) {
|
||||
@@ -1619,7 +1616,7 @@ vmdashusage.on('message', function(msg){
|
||||
});
|
||||
<?endif;?>
|
||||
|
||||
var dashboard = new NchanSubscriber('/sub/cpuload,update1,update2,update3<?=$wireguard?",wireguard":""?>',{subscriber:'websocket'});
|
||||
var dashboard = new NchanSubscriber('/sub/cpuload,update1,update2,update3<?=$wireguard?",wireguard":""?>',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
dashboard.on('message',function(msg,meta) {
|
||||
switch (meta.id.channel()) {
|
||||
case 0:
|
||||
@@ -1764,7 +1761,7 @@ dashboard.on('message',function(msg,meta) {
|
||||
});
|
||||
|
||||
<?if ($apcupsd):?>
|
||||
var apcups = new NchanSubscriber('/sub/apcups',{subscriber:'websocket'});
|
||||
var apcups = new NchanSubscriber('/sub/apcups',{subscriber:'websocket', reconnectTimeout:5000});
|
||||
apcups.on('message',function(msg) {
|
||||
var get = JSON.parse(msg);
|
||||
$('#ups_model').html(get[0]);
|
||||
@@ -1789,12 +1786,12 @@ $(function() {
|
||||
<?endif;?>
|
||||
dropdown('enter_view');
|
||||
startup = false;
|
||||
dashboard.start();
|
||||
dashboard.start().monitor();
|
||||
<?if ($vmusage == "Y"):?>
|
||||
vmdashusage.start();
|
||||
vmdashusage.start().monitor();
|
||||
<?endif;?>
|
||||
<?if ($apcupsd):?>
|
||||
apcups.start();
|
||||
apcups.start().monitor();
|
||||
<?endif;?>
|
||||
update900();
|
||||
toggleChart(true);
|
||||
@@ -1807,22 +1804,13 @@ $(function() {
|
||||
$('#netline').val(netline);
|
||||
$.removeCookie('lockbutton');
|
||||
// remember latest graph values
|
||||
$(window).on('beforeunload',function(e){
|
||||
var data = {};
|
||||
data.cpu = cpu.tail(cpuline);
|
||||
data.rxd = rxd.tail(netline);
|
||||
data.txd = txd.tail(netline);
|
||||
$.post('/webGui/include/InitCharts.php',{cmd:'set',data:JSON.stringify(data)});
|
||||
});
|
||||
});
|
||||
|
||||
window.onunload = function(){
|
||||
dashboard.stop();
|
||||
<?if ($vmusage == "Y"):?>
|
||||
vmdashusage.stop();
|
||||
<?endif;?>
|
||||
<?if ($apcupsd):?>
|
||||
apcups.stop();
|
||||
<?endif;?>
|
||||
// Start graphs over again when window back in focus
|
||||
function pageFocusFunction() {
|
||||
cpu = [];
|
||||
rxd = [];
|
||||
txd = [];
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -135,9 +135,6 @@ function is_upgraded_ZFS_pool($pool_name) {
|
||||
return ($upgrade ? false : true);
|
||||
}
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<script>
|
||||
<?if (empty($disk)):?>
|
||||
done();
|
||||
|
||||
@@ -4,8 +4,8 @@ Icon="icon-display"
|
||||
Tag="desktop"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* Copyright 2005-2025, Lime Technology
|
||||
* Copyright 2012-2025, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -251,9 +251,9 @@ _(Temperature unit)_:
|
||||
|
||||
_(Dynamix color theme)_:
|
||||
: <select name="theme">
|
||||
<?foreach (glob("$docroot/webGui/styles/dynamix-*.css") as $themes):?>
|
||||
<?$theme = substr(basename($themes,'.css'),8);?>
|
||||
<?=mk_option($display['theme'], $theme, _(ucfirst($theme)))?>
|
||||
<?foreach (glob("$docroot/webGui/styles/themes/*.css") as $themes):?>
|
||||
<?$theme = basename($themes, '.css');?>
|
||||
<?=mk_option($display['theme'], $theme, _(ucfirst($theme)))?>
|
||||
<?endforeach;?>
|
||||
</select>
|
||||
|
||||
@@ -323,6 +323,12 @@ _(Favorites enabled)_:
|
||||
|
||||
:display_favorites_enabled_help:
|
||||
|
||||
_(Allow realtime updates on inactive browsers)_:
|
||||
: <select name='liveUpdate'>
|
||||
<?=mk_option($display['liveUpdate'],"no",_('No'))?>
|
||||
<?=mk_option($display['liveUpdate'],"yes",_('Yes'))?>
|
||||
</select>
|
||||
|
||||
<input type="submit" name="#default" value="_(Default)_" onclick="filename='reset'">
|
||||
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
|
||||
@@ -48,17 +48,17 @@ function locked($source, $port) {
|
||||
}
|
||||
|
||||
function vlanID($cfg) {
|
||||
return array_filter($cfg,function($key){return strpos($key,'VLANID:')===0;},ARRAY_FILTER_USE_KEY);
|
||||
return array_filter($cfg, function($key){return strpos($key, 'VLANID:')===0;}, ARRAY_FILTER_USE_KEY);
|
||||
}
|
||||
|
||||
function index($key) {
|
||||
return filter_var($key,FILTER_SANITIZE_NUMBER_INT);
|
||||
return filter_var($key, FILTER_SANITIZE_NUMBER_INT);
|
||||
}
|
||||
|
||||
function metric($eth, $prot, $index) {
|
||||
$system = '/sys/class/net';
|
||||
$bridge = str_replace('eth','br',$eth);
|
||||
$bond = str_replace('eth','bond',$eth);
|
||||
$bridge = str_replace('eth','br', $eth);
|
||||
$bond = str_replace('eth','bond', $eth);
|
||||
$port = file_exists("$system/$bridge") ? $bridge : (file_exists("$system/$bond") ? $bond : $eth);
|
||||
$metric = exec("ip -$prot route show default dev $port 2>/dev/null | grep -Pom1 ' metric \K\d+'");
|
||||
if ($metric) return $metric + $index;
|
||||
@@ -67,8 +67,8 @@ function metric($eth, $prot, $index) {
|
||||
}
|
||||
|
||||
// remove non-existing ethernet ports
|
||||
foreach (glob("$docroot/webGui/Eth[1-9]*.page",GLOB_NOSORT) as $port) {
|
||||
if (!in_array(strtolower(basename($port,'.page')), $ports)) {
|
||||
foreach (glob("$docroot/webGui/Eth[1-9]*.page", GLOB_NOSORT) as $port) {
|
||||
if (!in_array(strtolower(basename($port, '.page')), $ports)) {
|
||||
@unlink($port);
|
||||
$build = true;
|
||||
}
|
||||
@@ -78,8 +78,8 @@ foreach (glob("$docroot/webGui/Eth[1-9]*.page",GLOB_NOSORT) as $port) {
|
||||
foreach ($ports as $ethX) {
|
||||
$file = "$docroot/webGui/".ucfirst($ethX).".page";
|
||||
if (!file_exists($file)) {
|
||||
$X = filter_var($ethX,FILTER_SANITIZE_NUMBER_INT);
|
||||
file_put_contents($file,str_replace(['parentname:nnn','tabX','bondX','brX','ethX'],['NetworkSettings:'.($X+100),'tab'.($X+1),'bond'.$X,'br'.$X,$ethX],file_get_contents($template)));
|
||||
$X = filter_var($ethX, FILTER_SANITIZE_NUMBER_INT);
|
||||
file_put_contents($file, str_replace(['parentname:nnn','tabX','bondX','brX','ethX'],['NetworkSettings:'.($X+100),'tab'.($X+1),'bond'.$X,'br'.$X,$ethX], file_get_contents($template)));
|
||||
$build = true;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ $no_eth0 = exec("ip -br link show eth0 | awk '{print \$2;exit}'")=='DOWN';
|
||||
// get VLAN interfaces
|
||||
$vlan_eth0 = $sort_eth0 = [];
|
||||
if (isset($eth0)) foreach (vlanID($eth0) as $key => $val) {$vlan_eth0[] = index($key); $sort_eth0[] = (int)$val;}
|
||||
array_multisort($sort_eth0,$vlan_eth0);
|
||||
array_multisort($sort_eth0, $vlan_eth0);
|
||||
?>
|
||||
|
||||
<script>
|
||||
@@ -162,13 +162,8 @@ function prepareSettings(form) {
|
||||
if (brnics.length > 1) form.BRSTP.value = 'yes';
|
||||
if ($(form).find('input[name="#arg[1]"]').val() == 'none') return true;
|
||||
|
||||
var metrics = [], metrics6 = [];
|
||||
$(form).find('input[name^="METRIC:"]').each(function(){if($(this).val()>0) metrics.push($(this).val());});
|
||||
$(form).find('input[name^="METRIC6:"]').each(function(){if($(this).val()>0) metrics6.push($(this).val());});
|
||||
if (metrics.same() || metrics6.same()) {
|
||||
swal({title:'Duplicate metrics',text:'List of default gateways contains duplicate metric values',animation:'none',type:'error',html:true,confirmButtonText:"_(Ok)_"});
|
||||
return false;
|
||||
}
|
||||
// enable form items for submission
|
||||
$(form).find('input,select').prop('disabled',false);
|
||||
if (form.TYPE.value == 'access') {
|
||||
$(form).find('input[name^="VLANID:"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name^="DESCRIPTION:"]').not('input[name$=":0"]').prop('disabled',false).val('');
|
||||
@@ -195,41 +190,39 @@ function prepareSettings(form) {
|
||||
var protocol = $(this).val() || 'ipv4';
|
||||
var i = $(this).prop('name').split(':')[1];
|
||||
if (protocol == 'ipv6') {
|
||||
$(form).find('input[name="IPADDR:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('select[name="NETMASK:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="GATEWAY:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="METRIC:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="IPADDR:'+i+'"]').val('');
|
||||
$(form).find('select[name="NETMASK:'+i+'"]').val('');
|
||||
$(form).find('input[name="GATEWAY:'+i+'"]').val('');
|
||||
$(form).find('input[name="METRIC:'+i+'"]').val('');
|
||||
}
|
||||
if (protocol == 'ipv4') {
|
||||
$(form).find('input[name="IPADDR6:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="NETMASK6:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="GATEWAY6:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="METRIC6:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('select[name="PRIVACY6:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="IPADDR6:'+i+'"]').val('');
|
||||
$(form).find('input[name="NETMASK6:'+i+'"]').val('');
|
||||
$(form).find('input[name="GATEWAY6:'+i+'"]').val('');
|
||||
$(form).find('input[name="METRIC6:'+i+'"]').val('');
|
||||
$(form).find('select[name="PRIVACY6:'+i+'"]').val('');
|
||||
}
|
||||
});
|
||||
$(form).find('select[name^="USE_DHCP:"]').each(function() {
|
||||
var i = $(this).prop('name').split(':')[1];
|
||||
var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4';
|
||||
var metric = $(form).find('input[name="METRIC:'+i+'"]').val();
|
||||
var gw4 = (port == 'eth0') ? true : $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked');
|
||||
if (protocol != 'ipv6' && $(this).val() != 'no') {
|
||||
$(form).find('input[name="IPADDR:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="GATEWAY:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="METRIC:'+i+'"]').prop('disabled',false).val(gw4?'':'0');
|
||||
$(form).find('input[name="IPADDR:'+i+'"]').val('');
|
||||
$(form).find('input[name="GATEWAY:'+i+'"]').val('');
|
||||
$(form).find('input[name="METRIC:'+i+'"]').val(gw4?'':'0');
|
||||
}
|
||||
});
|
||||
$(form).find('select[name^="USE_DHCP6:"]').each(function() {
|
||||
var i = $(this).prop('name').split(':')[1];
|
||||
var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4';
|
||||
var metric = $(form).find('input[name="METRIC6:'+i+'"]').val();
|
||||
var gw6 = (port == 'eth0') ? true : $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked');
|
||||
if (protocol != 'ipv4' && $(this).val() != 'no') {
|
||||
$(form).find('input[name="IPADDR6:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="GATEWAY6:'+i+'"]').prop('disabled',false).val('');
|
||||
$(form).find('input[name="METRIC6:'+i+'"]').prop('disabled',false).val(gw6?'':'0');
|
||||
$(form).find('input[name="IPADDR6:'+i+'"]').val('');
|
||||
$(form).find('input[name="GATEWAY6:'+i+'"]').val('');
|
||||
$(form).find('input[name="METRIC6:'+i+'"]').val(gw6?'':'0');
|
||||
}
|
||||
if ($(this).val() != 'yes') $(form).find('input[name="PRIVACY6:'+i+'"]').prop('disabled',false).val('');
|
||||
if ($(this).val() != 'yes') $(form).find('input[name="PRIVACY6:'+i+'"]').val('');
|
||||
});
|
||||
if (port == 'eth0') {
|
||||
$(dns).find('select,input').each(function(){
|
||||
@@ -238,6 +231,13 @@ function prepareSettings(form) {
|
||||
$(form).find('input[name="'+name+'"]').val(data);
|
||||
});
|
||||
}
|
||||
var metrics = [], metrics6 = [];
|
||||
$(form).find('input[name^="METRIC:"]').each(function(){if($(this).val() > 0) metrics.push($(this).val());});
|
||||
$(form).find('input[name^="METRIC6:"]').each(function(){if($(this).val() > 0) metrics6.push($(this).val());});
|
||||
if (metrics.same() || metrics6.same()) {
|
||||
swal({title:"_(Duplicate metrics)_", text:"_(List of default gateways contains duplicate metric values)_", animation:'none', type:'error', html:true, confirmButtonText:"_(Ok)_"});
|
||||
return false;
|
||||
}
|
||||
// force default MTU if jumbo frames are not enabled
|
||||
if ($(form).find('input[name="USE_MTU"]').prop('checked') == false) $(form).find('input[name="MTU"]').val('');
|
||||
$(form).find('input[name="#arg[1]"]').val(arg1[port]);
|
||||
@@ -466,6 +466,7 @@ function checkNetworkAccess(form) {
|
||||
}
|
||||
|
||||
function addVLAN(port) {
|
||||
$('input[value="<?=_("Apply")?>"],input[value="Apply"]').prop('disabled',false);
|
||||
var index = 1;
|
||||
while ($('#index-'+port+'-'+index).length) index++;
|
||||
var template = $($('<div/>').loadTemplate($('#network-template-'+port)).html().replace(/INDEX/g,index));
|
||||
@@ -556,7 +557,7 @@ function networkInfo(port, vlan) {
|
||||
</script>
|
||||
|
||||
<div class="title nocontrol shift"> </div>
|
||||
<div class="shade-<?=$display['theme']?> uplift">
|
||||
<div class="shade uplift">
|
||||
<form name="dns_settings" onchange="signalRun(this,1)">
|
||||
<div markdown="1" id="dns4" class="hide">
|
||||
_(IPv4 DNS server assignment)_:
|
||||
@@ -785,7 +786,7 @@ _(Enable VLANs)_:
|
||||
<div id="index-eth0-0"></div>
|
||||
<div id="vlan-list-eth0" class="hide">
|
||||
<?foreach ($vlan_eth0 as $i):?>
|
||||
<div markdown="1" id="index-eth0-<?=$i?>" class="access-eth0 shade-<?=$display['theme']?> hide">
|
||||
<div markdown="1" id="index-eth0-<?=$i?>" class="access-eth0 shade hide">
|
||||
_(Interface description)_:
|
||||
: <input type="text" name="DESCRIPTION:<?=$i?>" maxlength="80" autocomplete="off" spellcheck="false" value="<?=htmlspecialchars(_var($eth0,"DESCRIPTION:$i"))?>">
|
||||
<input type="button" class="form" value="_(Info)_" onclick="networkInfo('eth0',<?=_var($eth0,"VLANID:$i")?>)">
|
||||
@@ -887,7 +888,7 @@ _(IPv6 privacy extensions)_:
|
||||
</form>
|
||||
|
||||
<script markdown="1" type="text/html" id="network-template-eth0">
|
||||
<div markdown="1" id="index-eth0-INDEX" class="access-eth0 shade-<?=$display['theme']?>">
|
||||
<div markdown="1" id="index-eth0-INDEX" class="access-eth0 shade">
|
||||
_(Interface description)_:
|
||||
: <input type="text" name="DESCRIPTION:INDEX" maxlength="80" autocomplete="off" spellcheck="false" value="<?=htmlspecialchars(_var($eth0,"DESCRIPTION:INDEX"))?>">
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ _(Enable VLANs)_:
|
||||
<div id='index-ethX-0'></div>
|
||||
<div id="vlan-list-ethX" class="hide">
|
||||
<?foreach ($vlan_ethX as $i):?>
|
||||
<div markdown="1" id="index-ethX-<?=$i?>" class="access-ethX shade-<?=$display['theme']?> hide">
|
||||
<div markdown="1" id="index-ethX-<?=$i?>" class="access-ethX shade hide">
|
||||
_(Interface description)_:
|
||||
: <input type="text" name="DESCRIPTION:<?=$i?>" maxlength="80" autocomplete="off" spellcheck="false" value="<?=htmlspecialchars(_var($ethX,"DESCRIPTION:$i"))?>">
|
||||
<input type="button" class="form" value="_(Info)_" onclick="networkInfo('eth0',<?=_var($ethX,"VLANID:$i")?>)">
|
||||
@@ -350,7 +350,7 @@ _(IPv6 privacy extensions)_:
|
||||
</form>
|
||||
|
||||
<script markdown="1" type="text/html" id="network-template-ethX">
|
||||
<div markdown="1" id="index-ethX-INDEX" class="access-ethX shade-<?=$display['theme']?>">
|
||||
<div markdown="1" id="index-ethX-INDEX" class="access-ethX shade">
|
||||
_(Interface description)_:
|
||||
: <input type="text" name="DESCRIPTION:INDEX" maxlength="80" autocomplete="off" spellcheck="false" value="<?=htmlspecialchars(_var($ethX,"DESCRIPTION:INDEX"))?>">
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ $installed = ['English'];
|
||||
$plugins = '/var/log/plugins';
|
||||
|
||||
$keys = parse_ini_file('webGui/include/languages.key',false,INI_SCANNER_RAW);
|
||||
$head = '<i class="fa fa-fw fa-trash" title="_(Remove the installed language)_" style="cursor:pointer" onclick="remove("';
|
||||
$head = '<i class="fa fa-fw fa-trash" title="_(Remove the installed language)_" style="cursor:pointer" onclick="removeLanguage("';
|
||||
$tail = '")"></i>';
|
||||
|
||||
foreach (glob("$plugins/lang-*.xml",GLOB_NOSORT) as $xml_file) $installed[] = language('LanguageLocal',$xml_file).$head.str_replace('lang-','',basename($xml_file,'.xml')).$tail;
|
||||
@@ -47,7 +47,7 @@ function execute(cmd,title,language,name,filedata) {
|
||||
}
|
||||
});
|
||||
}
|
||||
function remove(language) {
|
||||
function removeLanguage(language) {
|
||||
execute('rm', "_(Language support deleted)_", language, '', '');
|
||||
}
|
||||
function upload(form) {
|
||||
|
||||
@@ -21,8 +21,6 @@ $ini = "/etc/php.d/errors-php.ini";
|
||||
$conf = file_exists($ini) ? parse_ini_file($ini) : [];
|
||||
if (!file_exists($log)) touch($log);
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<div markdown="1" style="width:43%;margin-bottom:40px;padding:5px 15px;border:solid 1px">
|
||||
:php_settings_plug:
|
||||
|
||||
@@ -57,7 +57,7 @@ $(function(){
|
||||
<tbody id="route_list"></tbody>
|
||||
</table>
|
||||
|
||||
<div class="shade-<?=$display['theme']?>" style="margin-top:12px;padding:12px 4px;">
|
||||
<div class="shade" style="margin-top:12px;padding:12px 4px;">
|
||||
<form markdown="1" name="add_routes" method="POST" action="/webGui/include/RoutingTable.php" target="progressFrame" onsubmit="setTimeout(resetTable,500)">
|
||||
_(Enter route + gateway + metric)_:
|
||||
: <input type="text" name="route" maxlength="39" value="" class="fixed" placeholder="_(IPv4/nn or IPv6/nn route)_" required>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user