mirror of
https://github.com/unraid/webgui.git
synced 2026-03-13 14:30:29 -05:00
Merge pull request #338 from bergware/master
Docker: support custom bridge networks without port bindings
This commit is contained in:
@@ -31,10 +31,8 @@ $DockerTemplates = new DockerTemplates();
|
||||
|
||||
$custom = DockerUtil::docker("network ls --filter driver='bridge' --filter driver='macvlan' --format='{{.Name}}'|grep -v '^bridge$'",true);
|
||||
$subnet = ['bridge'=>'', 'host'=>'', 'none'=>''];
|
||||
$driver = [];
|
||||
|
||||
foreach ($custom as $network) $subnet[$network] = substr(DockerUtil::docker("network inspect --format='{{range .IPAM.Config}}{{.Subnet}}, {{end}}' $network"),0,-1);
|
||||
foreach (DockerUtil::docker("network ls --format='{{.Name}}|{{.Driver}}'",true) as $network) {list($name,$type) = explode('|',$network); $driver[$name] = $type;}
|
||||
|
||||
function stopContainer($name) {
|
||||
global $DockerClient;
|
||||
@@ -564,9 +562,7 @@ if (isset($_POST['contName'])) {
|
||||
// remove old template
|
||||
@unlink("$userTmplDir/my-$existing.xml");
|
||||
}
|
||||
if ($startContainer) {
|
||||
$cmd = str_replace('/plugins/dynamix.docker.manager/scripts/docker create ', '/plugins/dynamix.docker.manager/scripts/docker run -d ', $cmd);
|
||||
}
|
||||
if ($startContainer) $cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
|
||||
execCommand($cmd);
|
||||
echo '<div style="text-align:center"><button type="button" onclick="done()">Done</button></div><br>';
|
||||
goto END;
|
||||
|
||||
@@ -31,9 +31,11 @@ $dockerManPaths = [
|
||||
if (!isset($eth0)) extract(parse_ini_file("$docroot/state/network.ini",true));
|
||||
$host = $eth0['IPADDR:0'] ?? '0.0.0.0';
|
||||
|
||||
// get network drivers
|
||||
$driver = DockerUtil::driver();
|
||||
|
||||
// Docker configuration file - guaranteed to exist
|
||||
$docker_cfgfile = '/boot/config/docker.cfg';
|
||||
$dockercfg = parse_ini_file($docker_cfgfile);
|
||||
$dockercfg = parse_ini_file('/boot/config/docker.cfg');
|
||||
|
||||
#######################################
|
||||
## DOCKERTEMPLATES CLASS ##
|
||||
@@ -698,6 +700,7 @@ class DockerClient {
|
||||
}
|
||||
|
||||
public function getDockerContainers() {
|
||||
global $driver;
|
||||
// Return cached values
|
||||
if (is_array($this::$containersCache)) return $this::$containersCache;
|
||||
$this::$containersCache = [];
|
||||
@@ -717,7 +720,7 @@ class DockerClient {
|
||||
$c['NetworkMode'] = $ct['HostConfig']['NetworkMode'];
|
||||
$c['BaseImage'] = $ct['Labels']['BASEIMAGE'] ?? false;
|
||||
$c['Ports'] = [];
|
||||
if (!empty($info['HostConfig']['PortBindings'])) {
|
||||
if ($driver[$c['NetworkMode']]=='bridge') {
|
||||
$ports = &$info['HostConfig']['PortBindings'];
|
||||
$nat = true;
|
||||
} else {
|
||||
@@ -819,5 +822,10 @@ class DockerUtil {
|
||||
$ipaddr = $version==4 ? 'IPAddress' : 'GlobalIPv6Address';
|
||||
return static::docker("inspect --format='{{range .NetworkSettings.Networks}}{{.$ipaddr}}{{end}}' $name");
|
||||
}
|
||||
public static function driver() {
|
||||
$list = [];
|
||||
foreach (static::docker("network ls --format='{{.Name}}={{.Driver}}'",true) as $network) {list($name,$driver) = explode('=',$network); $list[$name] = $driver;}
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -556,6 +556,7 @@ IPv4 address assignment:
|
||||
<div class="more-ipv4-eth0-<?=$i?>" style="display:none" markdown="1">
|
||||
IPv4 address:
|
||||
: <input type="text" name="IPADDR:<?=$i?>" maxlength="15" value="<?=$eth0["IPADDR:$i"]?>" class="narrow" pattern="<?=$validIP4?>" title="IPv4 address A.B.C.D">/ <select name="NETMASK:<?=$i?>" size="1" class="slim">
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.0.0.0", "8");?>
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.255.0.0", "16");?>
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.255.128.0", "17");?>
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.255.192.0", "18");?>
|
||||
@@ -730,6 +731,7 @@ IPv4 address assignment:
|
||||
<div class="more-ipv4-eth0-<?=$i?>" style="display:none" markdown="1">
|
||||
IPv4 address:
|
||||
: <input type="text" name="IPADDR:<?=$i?>" maxlength="15" value="<?=$eth0["IPADDR:$i"]?>" class="narrow" pattern="<?=$validIP4?>" title="IPv4 address A.B.C.D">/ <select name="NETMASK:<?=$i?>" size="1" class="slim">
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.0.0.0", "8");?>
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.255.0.0", "16");?>
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.255.128.0", "17");?>
|
||||
<?=mk_option($eth0["NETMASK:$i"], "255.255.192.0", "18");?>
|
||||
@@ -837,6 +839,7 @@ IPv4 address assignment:
|
||||
<div class="more-ipv4-eth0-INDEX" style="display:none" markdown="1">
|
||||
IPv4 address:
|
||||
: <input type="text" name="IPADDR:INDEX" maxlength="15" value="<?=$eth0["IPADDR:INDEX"]?>" class="narrow" pattern="<?=$validIP4?>" title="IPv4 address A.B.C.D">/ <select name="NETMASK:INDEX" size="1" class="slim">
|
||||
<?=mk_option($eth0["NETMASK:INDEX"], "255.0.0.0", "8");?>
|
||||
<?=mk_option($eth0["NETMASK:INDEX"], "255.255.0.0", "16");?>
|
||||
<?=mk_option($eth0["NETMASK:INDEX"], "255.255.128.0", "17");?>
|
||||
<?=mk_option($eth0["NETMASK:INDEX"], "255.255.192.0", "18");?>
|
||||
|
||||
@@ -227,6 +227,7 @@ IPv4 address assignment:
|
||||
<div class="more-ipv4-ethX-<?=$i?>" style="display:none" markdown="1">
|
||||
IPv4 address:
|
||||
: <input type="text" name="IPADDR:<?=$i?>" maxlength="15" value="<?=$ethX["IPADDR:$i"]?>" class="narrow" pattern="<?=$validIP4?>" title="IPv4 address A.B.C.D">/ <select name="NETMASK:<?=$i?>" size="1" class="slim">
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.0.0.0", "8");?>
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.255.0.0", "16");?>
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.255.128.0", "17");?>
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.255.192.0", "18");?>
|
||||
@@ -341,6 +342,7 @@ IPv4 address assignment:
|
||||
<div class="more-ipv4-ethX-<?=$i?>" style="display:none" markdown="1">
|
||||
IPv4 address:
|
||||
: <input type="text" name="IPADDR:<?=$i?>" maxlength="15" value="<?=$ethX["IPADDR:$i"]?>" class="narrow" pattern="<?=$validIP4?>" title="IPv4 address A.B.C.D">/ <select name="NETMASK:<?=$i?>" size="1" class="slim">
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.0.0.0", "8");?>
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.255.0.0", "16");?>
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.255.128.0", "17");?>
|
||||
<?=mk_option($ethX["NETMASK:$i"], "255.255.192.0", "18");?>
|
||||
@@ -446,6 +448,7 @@ IPv4 address assignment:
|
||||
<div class="more-ipv4-ethX-INDEX" style="display:none" markdown="1">
|
||||
IPv4 address:
|
||||
: <input type="text" name="IPADDR:INDEX" maxlength="15" value="<?=$ethX["IPADDR:INDEX"]?>" class="narrow" pattern="<?=$validIP4?>" title="IPv4 address A.B.C.D">/ <select name="NETMASK:INDEX" size="1" class="slim">
|
||||
<?=mk_option($ethX["NETMASK:INDEX"], "255.0.0.0", "8");?>
|
||||
<?=mk_option($ethX["NETMASK:INDEX"], "255.255.0.0", "16");?>
|
||||
<?=mk_option($ethX["NETMASK:INDEX"], "255.255.128.0", "17");?>
|
||||
<?=mk_option($ethX["NETMASK:INDEX"], "255.255.192.0", "18");?>
|
||||
|
||||
@@ -20,14 +20,21 @@ Tag="share-alt-square"
|
||||
|
||||
<?
|
||||
$file = "/boot/config/smb-extra.conf";
|
||||
$text = @file_get_contents($file);
|
||||
$text = @file_get_contents($file) ?: '';
|
||||
$text = preg_replace(["/\r\n/","/\r/"],"\n",$text);
|
||||
?>
|
||||
<script>
|
||||
$(function(){
|
||||
$('form').find('textarea').on('input change',function(){
|
||||
$(this).prop('rows',($(this).val().match(/\n/g)||[]).length+1);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<form markdown="1" method="POST" action="/update.php" target="progressFrame">
|
||||
<input type="hidden" name="#include" value="/webGui/include/update.file.php">
|
||||
<input type="hidden" name="#file" value="<?=$file;?>">
|
||||
Samba extra configuration:
|
||||
|
||||
: <textarea spellcheck="false" cols="80" rows="22" maxlength="2048" name="text" style="font-family:bitstream;width:66%"><?=htmlspecialchars($text)?></textarea>
|
||||
: <textarea spellcheck="false" cols="80" rows="<?=substr_count($text,"\n")+1?>" maxlength="2048" name="text" style="resize:none;font-family:bitstream;width:65.5%"><?=htmlspecialchars($text)?></textarea>
|
||||
|
||||
|
||||
: <input type="submit" value="Apply" disabled><input type="button" value="Done" onclick="done()">
|
||||
|
||||
@@ -3,8 +3,8 @@ Title="Syslinux Configuration"
|
||||
Tag="edit"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2017, Lime Technology
|
||||
* Copyright 2012-2017, Bergware International.
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, 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,
|
||||
@@ -14,46 +14,226 @@ Tag="edit"
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
> Use this page to make changes to your `syslinux.cfg` file. You will
|
||||
> need to reboot your server for these changes to take effect.
|
||||
> Use this page to make changes to your `syslinux.cfg` file.
|
||||
> You will need to reboot your server for these changes to take effect.
|
||||
|
||||
<?
|
||||
$file = "/boot/syslinux/syslinux.cfg";
|
||||
$text = file_get_contents($file);
|
||||
$default_text = @file_get_contents("$file-");
|
||||
if ($default_text === false) $default_text = $text;
|
||||
function strip($area) {
|
||||
return preg_replace(["/^|(\n) /","/\n$/"],["$1",""],$area);
|
||||
}
|
||||
$file = '/boot/syslinux/syslinux.cfg';
|
||||
$current = file_get_contents($file);
|
||||
$default = @file_get_contents("$file-") ?: $current;
|
||||
$current = preg_replace(["/\r\n/","/\r/","/\n$/"],["\n","\n",""],$current);
|
||||
$default = preg_replace(["/\r\n/","/\r/","/\n$/"],["\n","\n",""],$default);
|
||||
|
||||
$title = 'Global Configuration';
|
||||
$menu = 'menu default';
|
||||
$mark = 'label ';
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="/webGui/styles/jquery.switchbutton.css">
|
||||
<style>
|
||||
div.basic{display:block}
|
||||
div.advanced{display:none}
|
||||
<?
|
||||
switch ($display['theme']) {
|
||||
case 'gray':
|
||||
case 'azure':
|
||||
echo "span.array,span.system{margin-left:33.33%;width:65.5%;padding:2px 10px;font-weight:bold;border:solid 1px #606E7F;border-bottom:none}\n";
|
||||
echo "textarea.menu{margin-left:33.33%;width:65.5%;margin-bottom:12px;font-family:bitstream;resize:none;border-top:none}\n";
|
||||
break;
|
||||
case 'white':
|
||||
echo "span.array,span.system{margin-left:33.33%;width:65.5%;padding:1px 8px;font-weight:bold;border:solid 1px #E0E0E0;border-bottom:none}\n";
|
||||
echo "textarea.menu{margin-left:33.33%;width:65.5%;margin-bottom:12px;font-family:bitstream;resize:none;border-top:none;border-radius:0}\n";
|
||||
break;
|
||||
case 'black':
|
||||
echo "span.array,span.system{margin-left:33.33%;width:65.5%;padding:1px 8px;font-weight:bold;border:solid 1px #404040;border-bottom:none}\n";
|
||||
echo "textarea.menu{margin-left:33.33%;width:65.5%;margin-bottom:12px;font-family:bitstream;resize:none;border-top:none;border-radius:0}\n";
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</style>
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
<script>
|
||||
function setArg(boot) {
|
||||
$('input[name="#arg[1]"]').val(boot?1:0);
|
||||
const menu = '<?=$menu?>';
|
||||
const title = '<?=$title?>';
|
||||
const mark = '<?=$mark?>';
|
||||
|
||||
Array.prototype.indent = function(o) {
|
||||
if (o) for (var i=0; i < this.length; i++) this[i] = ' '+this[i];
|
||||
return this;
|
||||
};
|
||||
Array.prototype.spliceArray = function(i,n,a) {
|
||||
return Array.prototype.splice.apply(this,[i,n].concat(a));
|
||||
};
|
||||
function prepareMenu(form) {
|
||||
$('input[name="#arg[1]"]').val(form.boot.checked?1:0);
|
||||
if ($('div.basic').is(':visible')) {
|
||||
form.text.value = form.basic.value+'\n';
|
||||
} else {
|
||||
var label = [], area = [];
|
||||
$(form).find('span[id^=label]').each(function(){
|
||||
label.push($(this).text());
|
||||
});
|
||||
$(form).find('textarea.menu').each(function(i){
|
||||
var start = $('#input-'+i).prop('checked') ? menu+'\n' : '';
|
||||
area.push(start+$(this).val());
|
||||
});
|
||||
var text = [];
|
||||
for (var i=0; i < label.length; i++) {
|
||||
if (i==0) {
|
||||
text.push(area[i]);
|
||||
} else {
|
||||
text.push(mark+label[i]);
|
||||
text.push(area[i].replace(/^|(\n)/g,'$1 '));
|
||||
}
|
||||
}
|
||||
form.text.value = text.join('\n')+'\n';
|
||||
}
|
||||
form.basic.disabled = true;
|
||||
}
|
||||
function setDefault(form) {
|
||||
form.elements['text'].value = <?=json_encode($default_text);?>;
|
||||
var text = <?=json_encode(array_map('strip',explode($mark,$default)))?>;
|
||||
$(form).find('textarea.menu').each(function(i){
|
||||
if (i < text.length) {
|
||||
var area = text[i].split('\n');
|
||||
var label = (i) ? area.shift():title;
|
||||
var start = (area[0]==menu);
|
||||
var checked = start ? ' checked':'';
|
||||
if (i) label += "<span style='float:right'><input type='checkbox' id='input-"+i+"' title='Set default boot menu' onchange='changeMenu(this.form,this.id,true)'"+checked+"></span>";
|
||||
$('#label-'+i).html(label).prop('class',start ? 'array':'system');
|
||||
if (start) area.shift();
|
||||
$(this).val(area.join('\n')).prop('rows',area.length).trigger('change');
|
||||
} else {
|
||||
$('#label-'+i).remove();
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
$(form).find('textarea.text').val(<?=json_encode($default)?>).prop('rows',$(this).val().match(/\n/g).length+1).trigger('change');
|
||||
}
|
||||
function changeMenu(form,id,update) {
|
||||
$(form).find('input.menu').each(function(){
|
||||
// highlight default boot menu
|
||||
var i = $(this).prop('id');
|
||||
var label = $('#'+i.replace('input','label'));
|
||||
if (i == id) {
|
||||
label.prop('class','array');
|
||||
$(this).prop('checked',true);
|
||||
} else {
|
||||
label.prop('class','system');
|
||||
$(this).prop('checked',false);
|
||||
}
|
||||
});
|
||||
if (update) {
|
||||
// advanced view -> update basic view
|
||||
var n = 0, o = null;
|
||||
var x = id.split('-')[1];
|
||||
var text = form.basic.value.split('\n');
|
||||
for (var i=0; i < text.length; i++) {
|
||||
if (text[i].indexOf(mark) >= 0) if (++n == x) o = i + 1;
|
||||
if (text[i].indexOf(menu) >= 0) text.splice(i,1);
|
||||
}
|
||||
if (o) text.splice(o,0,' '+menu);
|
||||
$(form).find('textarea.text').val(text.join('\n')).prop('rows',text.length);
|
||||
}
|
||||
}
|
||||
$(function(){
|
||||
$('form').find('textarea').each(function(){$(this).on('input change',function(event){
|
||||
$(this).prop('rows',($(this).val().match(/\n/g)||[]).length+1);
|
||||
if (event.type == 'input') return;
|
||||
// propogate changes to 'other' view mode
|
||||
var form = $(this).closest('form');
|
||||
if ($(this).prop('class')=='menu') {
|
||||
// advanced view -> update basic view
|
||||
var n = 0, o = 0, x = null;
|
||||
var id = $(this).prop('id').split('-')[1];
|
||||
var area = $(this).val().split('\n');
|
||||
var basic = form.find('textarea.text');
|
||||
var text = basic.val().split('\n');
|
||||
for (var i=0; i < text.length; i++) {
|
||||
if (text[i].indexOf(mark) >= 0) {
|
||||
if (n++ == id) x = i; else o = i + 1;
|
||||
}
|
||||
if (text[i].indexOf(menu) >= 0) o++;
|
||||
if (x) break;
|
||||
}
|
||||
text.spliceArray(o,(x||text.length)-o,area.indent(o));
|
||||
basic.val(text.join('\n')).prop('rows',text.length);
|
||||
} else {
|
||||
// basic view -> update advanced view
|
||||
var n = 0, id = null, area = [];
|
||||
var text = $(this).val().split('\n');
|
||||
for (var i=0; i < text.length; i++) {
|
||||
if (text[i].indexOf(mark) >= 0) {
|
||||
$('#text-'+n).val(area.join('\n')).prop('rows',area.length);
|
||||
area = [];
|
||||
n++;
|
||||
} else {
|
||||
if (text[i].indexOf(menu) >= 0) id = 'input-'+n; else if (text[i].length) area.push(text[i].replace(/^ /,''));
|
||||
}
|
||||
}
|
||||
$('#text-'+n).val(area.join('\n')).prop('rows',area.length);
|
||||
if (id) changeMenu(form,id,false);
|
||||
}
|
||||
});});
|
||||
if ($.cookie('syslinux_viewmode')=='advanced') {
|
||||
$('.advanced').show();
|
||||
$('.basic').hide();
|
||||
}
|
||||
$('.advancedview').switchButton({
|
||||
labels_placement: 'left',
|
||||
on_label: 'Advanced View',
|
||||
off_label: 'Basic View',
|
||||
checked: $.cookie('syslinux_viewmode')=='advanced'
|
||||
});
|
||||
$('.advancedview').change(function() {
|
||||
$('.advanced').toggle('slow');
|
||||
$('.basic').toggle('slow');
|
||||
$.cookie('syslinux_viewmode', $('.advancedview').is(':checked') ? 'advanced':'basic', {expires:3650});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="setArg(this.boot.checked)">
|
||||
<span class="status" style="margin-top:-44px"><input type="checkbox" class="advancedview"></span>
|
||||
|
||||
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareMenu(this)">
|
||||
<input type="hidden" name="#include" value="/webGui/include/update.file.php">
|
||||
<input type="hidden" name="#file" value="<?=$file;?>">
|
||||
<input type="hidden" name="#command" value="/webGui/scripts/bootmode">
|
||||
<input type="hidden" name="#arg[1]" value="">
|
||||
<input type="hidden" name="text" value="">
|
||||
<div markdown="1" class="basic">
|
||||
Syslinux configuration:
|
||||
: <textarea class="text" name="basic" spellcheck="false" cols="80" rows="<?=substr_count($current,"\n")+1?>" maxlength="2048" style="resize:none;font-family:bitstream;width:65.5%"><?=$current?></textarea>
|
||||
|
||||
: <textarea spellcheck="false" cols="80" rows="22" maxlength="2048" name="text" style="font-family:bitstream;width:66%"><?=$text;?></textarea>
|
||||
</div>
|
||||
<div markdown="1" class="advanced">
|
||||
Syslinux configuration:
|
||||
: <?$i=0;
|
||||
foreach (array_map('strip',explode($mark,$current)) as $area):
|
||||
$area = explode("\n", $area);
|
||||
$label = ($i) ? array_shift($area):$title;
|
||||
$start = in_array($menu,$area);
|
||||
if ($start) unset($area[array_search($menu,$area)]);
|
||||
?><span id="label-<?=$i?>" class="<?=$start?'array':'system'?>"><?=$label?>
|
||||
<?if ($i):?><span style="float:right"><input type="checkbox" id="input-<?=$i?>" class="menu" <?=$start?'checked':''?> title="Set default boot menu" onchange="changeMenu(this.form,this.id,true)"></span><?endif;?></span>
|
||||
<textarea class="menu" id="text-<?=$i++?>" spellcheck="false" cols="80" rows="<?=count($area)?>" maxlength="2048"><?=implode("\n",$area)?></textarea>
|
||||
<?endforeach;?>
|
||||
|
||||
</div>
|
||||
Server boot mode:
|
||||
: <?=is_dir('/sys/firmware/efi') ? 'UEFI' : 'Legacy'?>
|
||||
|
||||
Permit UEFI boot mode <input type="checkbox" name="boot" <?=is_dir('/boot/EFI') ? 'checked' : ''?>>
|
||||
Permit UEFI boot mode <input type="checkbox" name="boot" <?=is_dir('/boot/EFI')?'checked':''?>>
|
||||
: *Boot system in UEFI mode. Please check your system settings to support UEFI boot mode.*
|
||||
|
||||
<input type="button" value="Default" onclick="setDefault(this.form)">
|
||||
: <input type="submit" value="Apply"/><input type="button" value="Done" onclick="done()">
|
||||
: <input type="submit" value="Apply"><input type="button" value="Done" onclick="done()">
|
||||
|
||||
> Click the **Apply** button to commit the current edits. Click **Reset** to
|
||||
> undo any changes you make (before Saving). Click **Done** to exit this page.
|
||||
>
|
||||
> Click the **Default** button to initialize the edit box with the
|
||||
> factory-default contents. You still need to click **Apply** in order to
|
||||
>commit the change.
|
||||
>
|
||||
> Click the **Apply** button to commit the current edits. Click **Reset** to
|
||||
> undo any changes you make (before Saving). Click **Done** to exit this page.
|
||||
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user