mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-11-14 12:54:10 +01:00
602 lines
28 KiB
HTML
602 lines
28 KiB
HTML
<!-- Proxy Create Form-->
|
|
<style>
|
|
.rulesInstructions{
|
|
background: var(--theme_background) !important;
|
|
color: var(--theme_lgrey);
|
|
border-radius: 1em !important;
|
|
}
|
|
|
|
.ui.form .sub.field{
|
|
background-color: var(--theme_advance);
|
|
border-radius: 0.6em;
|
|
padding: 1em;
|
|
}
|
|
|
|
.descheader{
|
|
display:none !important;
|
|
}
|
|
|
|
@media (min-width: 1367px) {
|
|
.descheader{
|
|
display:auto !important;
|
|
|
|
}
|
|
}
|
|
</style>
|
|
<div class="standardContainer">
|
|
<div class="ui stackable grid">
|
|
<div class="ten wide column">
|
|
<div class="ui basic segment" style="border-radius: 1em; padding: 1em !important;">
|
|
<h2>New Proxy Rule</h2>
|
|
<p>You can add more proxy rules to support more site via domain / subdomains</p>
|
|
<div class="ui form">
|
|
<div class="field" tourstep="matchingkeyword">
|
|
<label>Matching Keyword / Domain</label>
|
|
<input type="text" id="rootname" placeholder="mydomain.com">
|
|
<small>Support subdomain and wildcard, e.g. s1.mydomain.com or *.test.mydomain.com. Use comma (,) for alias hostnames. </small>
|
|
</div>
|
|
<div class="field" tourstep="targetdomain">
|
|
<label>Target IP Address or Domain Name with port</label>
|
|
<input type="text" id="proxyDomain" onchange="autoFillTargetTLS(this);">
|
|
<small>e.g. 192.168.0.101:8000 or example.com</small>
|
|
</div>
|
|
<div class="field dockerOptimizations" style="display:none;">
|
|
<button style="margin-top: -2em;" class="ui basic small button" onclick="openDockerContainersList();"><i class="blue docker icon"></i> Pick from Docker Containers</button>
|
|
</div>
|
|
<div class="field" tourstep="requireTLS">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="reqTls">
|
|
<label>Proxy Target require TLS Connection <br><small>(i.e. Your proxy target starts with https://)</small></label>
|
|
</div>
|
|
</div>
|
|
<!-- Advance configs -->
|
|
<div class="ui basic segment advanceoptions">
|
|
<div id="advanceProxyRules" class="ui fluid accordion">
|
|
<div class="title">
|
|
<i class="dropdown icon"></i>
|
|
Advance Settings
|
|
</div>
|
|
<div class="content">
|
|
<div class="field">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="useStickySessionLB">
|
|
<label>Sticky Session<br><small>Enable stick session on upstream load balancing</small></label>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="enableUtm" checked>
|
|
<label>Enable uptime monitor<br><small>Automatically check upstream status and switch to another if offline</small>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="disableLog">
|
|
<label>Disable Requests Logging<br><small>Disable requests logging for this host, recommended for high traffic sites</small>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<label>Tags</label>
|
|
<input type="text" id="proxyTags" placeholder="e.g. mediaserver, management">
|
|
<small>Comma-separated list of tags for this proxy host.</small>
|
|
</div>
|
|
<div class="ui horizontal divider">
|
|
<i class="ui green lock icon"></i>
|
|
Security
|
|
</div>
|
|
<div class="field" tourstep="skipTLSValidation">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="skipTLSValidation">
|
|
<label>Ignore TLS/SSL Verification Error<br><small>For targets that is using self-signed, expired certificate (Not Recommended)</small></label>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="skipWebsocketOriginCheck" checked>
|
|
<label>Skip WebSocket Origin Check<br><small>Allow cross-origin websocket requests (Usually not a security concern)</small></label>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="bypassGlobalTLS">
|
|
<label>Allow plain HTTP access<br><small>Allow this subdomain to be connected without TLS (Require HTTP server enabled on port 80)</small></label>
|
|
</div>
|
|
</div>
|
|
<div class="ui horizontal divider">
|
|
<i class="ui red ban icon"></i>
|
|
Access Control
|
|
</div>
|
|
<div class="field">
|
|
<label>Access Rule</label>
|
|
<div class="ui selection dropdown">
|
|
<input type="hidden" id="newProxyRuleAccessFilter" value="default">
|
|
<i class="dropdown icon"></i>
|
|
<div class="default text">Default</div>
|
|
<div class="menu" id="newProxyRuleAccessList">
|
|
<div class="item" data-value="default"><i class="ui yellow star icon"></i> Default</div>
|
|
</div>
|
|
</div>
|
|
<small>Allow regional access control using blacklist or whitelist. Use "default" for "allow all".</small>
|
|
</div>
|
|
<div class="field">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="requireBasicAuth">
|
|
<label>Require Basic Auth<br><small>Require client to login in order to view the page</small></label>
|
|
</div>
|
|
</div>
|
|
<div id="basicAuthCredentials" class="field">
|
|
<p>Enter the username and password for allowing them to access this proxy endpoint</p>
|
|
<table class="ui very basic celled table">
|
|
<thead>
|
|
<tr>
|
|
<th>Username</th>
|
|
<th>Password</th>
|
|
<th>Remove</th>
|
|
</tr></thead>
|
|
<tbody id="basicAuthCredentialTable">
|
|
<tr>
|
|
<td colspan="3"><i class="ui green circle check icon"></i> No Entered Credential</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<div class="three small fields credentialEntry">
|
|
<div class="field">
|
|
<input id="basicAuthCredUsername" type="text" placeholder="Username" autocomplete="off">
|
|
</div>
|
|
<div class="field">
|
|
<input id="basicAuthCredPassword" type="password" placeholder="Password" autocomplete="off">
|
|
</div>
|
|
<div class="field">
|
|
<button class="ui basic button" onclick="addCredentials();"><i class="blue add icon"></i> Add Credential</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="ui checkbox">
|
|
<input type="checkbox" id="requireRateLimit">
|
|
<label>Require Rate Limit<br><small>This proxy endpoint will be rate limited.</small></label>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<label>Rate Limit</label>
|
|
<div class="ui fluid right labeled input">
|
|
<input type="number" id="proxyRateLimit" placeholder="100" min="1" max="1000" value="100">
|
|
<div class="ui basic label">
|
|
req / sec / IP
|
|
</div>
|
|
</div>
|
|
<small>Return a 429 error code if request rate exceed the rate limit.</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<br>
|
|
<div tourstep="newProxyRule" style="display: inline-block;">
|
|
<button class="ui basic button" onclick="newProxyEndpoint();"><i class="green add icon"></i> Create Endpoint</button>
|
|
</div>
|
|
<br><br>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="six wide column">
|
|
<div class="ui basic segment rulesInstructions">
|
|
<div class="ui fluid styled accordion" id="matchingKeywordExamplesAccordion" style="background-color: transparent !important;">
|
|
<div class="title active" style="color: white;">
|
|
<i class="dropdown icon"></i>
|
|
Matching Keyword Examples
|
|
</div>
|
|
<div class="content active">
|
|
<span style="font-size: 1.2em; font-weight: 300;"><i class="ui yellow star icon"></i> Domain</span><br>
|
|
Example of domain matching keyword:<br>
|
|
<code>aroz.org</code> <br>Any acess requesting aroz.org will be proxy to the IP address below<br>
|
|
<div class="ui divider"></div>
|
|
<span style="font-size: 1.2em; font-weight: 300;"><i class="ui yellow star icon"></i> Subdomain</span><br>
|
|
Example of subdomain matching keyword:<br>
|
|
<code>s1.aroz.org</code> <br>Any request starting with s1.aroz.org will be proxy to the IP address below<br>
|
|
<div class="ui divider"></div>
|
|
<span style="font-size: 1.2em; font-weight: 300;"><i class="ui yellow star icon"></i> Wildcard</span><br>
|
|
Example of wildcard matching keyword:<br>
|
|
<code>*.aroz.org</code> <br>Any request with a host name matching *.aroz.org will be proxy to the IP address below. Here are some examples.<br>
|
|
<div class="ui list">
|
|
<div class="item"><code>www.aroz.org</code></div>
|
|
<div class="item"><code>foo.bar.aroz.org</code></div>
|
|
</div>
|
|
<br>
|
|
</div>
|
|
|
|
<div class="title" style="color: white;">
|
|
<i class="dropdown icon"></i>
|
|
Remote Target Require TLS
|
|
</div>
|
|
<div class="content">
|
|
<span style="font-size: 1.2em; font-weight: 300;"><i class="ui green lock icon"></i> Upstream TLS Requirement</span><br>
|
|
<p>
|
|
When you enable <b>Proxy Target require TLS Connection</b>, it means the <b>upstream server</b> (the target you are proxying to) requires a secure (HTTPS) connection.<br>
|
|
<b>This does not affect whether clients connect to this proxy endpoint using HTTP or HTTPS.</b>
|
|
</p>
|
|
<div class="ui divider"></div>
|
|
<span style="font-size: 1.2em; font-weight: 300;"><i class="ui yellow star icon"></i> Example</span><br>
|
|
<code>Matching Keyword: mydomain.com<br>
|
|
Target: example.com:443 (TLS enabled)</code><br>
|
|
<ul>
|
|
<li>Client connects to <b>mydomain.com</b> (HTTP or HTTPS, depending on your proxy setup)</li>
|
|
<li>Proxy forwards requests to <b>example.com:443</b> using <b>HTTPS</b></li>
|
|
</ul>
|
|
<small>
|
|
Use this option if your upstream server only accepts secure connections.<br>
|
|
If your upstream uses a self-signed certificate, check the <b>Ignore TLS/SSL Verification Error</b> option in Advance Settings.
|
|
</small>
|
|
</div>
|
|
|
|
<div class="title" style="color: white;">
|
|
<i class="dropdown icon"></i>
|
|
What is Sticky Session?
|
|
</div>
|
|
<div class="content">
|
|
<span style="font-size: 1.2em; font-weight: 300;"><i class="ui green sync icon"></i> Sticky Session (Session Affinity)</span><br>
|
|
<p>
|
|
Sticky session ensures that requests from the same client are always forwarded to the same upstream server. This is useful for applications that store session data locally and require the client to consistently connect to the same backend.<br>
|
|
</p>
|
|
<div class="ui divider"></div>
|
|
<span style="font-size: 1.2em; font-weight: 300;"><i class="ui yellow star icon"></i> How to Add Multiple Upstreams</span><br>
|
|
<ul>
|
|
<li>Go to <b>HTTP Proxy</b> in the sidebar.</li>
|
|
<li>Click <b>Edit</b> on your proxy rule.</li>
|
|
<li>Use the <b>Upstreams</b> section to add more upstream endpoints for load balancing.</li>
|
|
</ul>
|
|
<small>
|
|
Sticky session will only work if you have more than one upstream endpoint configured.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
$('#matchingKeywordExamplesAccordion').accordion();
|
|
</script>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
|
|
//New Proxy Endpoint
|
|
function newProxyEndpoint(){
|
|
let rootname = $("#rootname").val();
|
|
let proxyDomain = $("#proxyDomain").val();
|
|
let useTLS = $("#reqTls")[0].checked;
|
|
let skipTLSValidation = $("#skipTLSValidation")[0].checked;
|
|
let bypassGlobalTLS = $("#bypassGlobalTLS")[0].checked;
|
|
let requireBasicAuth = $("#requireBasicAuth")[0].checked;
|
|
let proxyRateLimit = $("#proxyRateLimit").val();
|
|
let requireRateLimit = $("#requireRateLimit")[0].checked;
|
|
let skipWebSocketOriginCheck = $("#skipWebsocketOriginCheck")[0].checked;
|
|
let accessRuleToUse = $("#newProxyRuleAccessFilter").val();
|
|
let useStickySessionLB = $("#useStickySessionLB")[0].checked;
|
|
let tags = $("#proxyTags").val().trim();
|
|
let enableUtm = $("#enableUtm")[0].checked;
|
|
let disableLog = $("#disableLog")[0].checked;
|
|
|
|
if (rootname.trim() == ""){
|
|
$("#rootname").parent().addClass("error");
|
|
return
|
|
}else{
|
|
$("#rootname").parent().removeClass("error");
|
|
}
|
|
|
|
if (proxyDomain.trim() == ""){
|
|
$("#proxyDomain").parent().addClass("error");
|
|
return
|
|
}else{
|
|
$("#proxyDomain").parent().removeClass("error");
|
|
}
|
|
|
|
//Create the endpoint by calling add
|
|
$.cjax({
|
|
url: "/api/proxy/add",
|
|
method: "POST",
|
|
data: {
|
|
type: "host",
|
|
rootname: rootname,
|
|
tls: useTLS,
|
|
ep: proxyDomain,
|
|
tlsval: skipTLSValidation,
|
|
bpwsorg: skipWebSocketOriginCheck,
|
|
bypassGlobalTLS: bypassGlobalTLS,
|
|
bauth: requireBasicAuth,
|
|
rate: requireRateLimit,
|
|
ratenum: proxyRateLimit,
|
|
cred: JSON.stringify(credentials),
|
|
access: accessRuleToUse,
|
|
stickysess: useStickySessionLB,
|
|
tags: tags,
|
|
enableUtm: enableUtm,
|
|
disableLog: disableLog,
|
|
},
|
|
success: function(data){
|
|
if (data.error != undefined){
|
|
msgbox(data.error, false, 5000);
|
|
}else{
|
|
//Clear old data
|
|
$("#rootname").val("");
|
|
$("#proxyDomain").val("");
|
|
$("#proxyTags").val("");
|
|
credentials = [];
|
|
updateTable();
|
|
reloadUptimeList();
|
|
//Check if it is a new subdomain and TLS enabled
|
|
if ($("#tls").checkbox("is checked")){
|
|
confirmBox("Request new SSL Cert for this subdomain?", function(choice){
|
|
if (choice == true){
|
|
//Load the prefer CA from TLS page
|
|
let defaultCA = $("#defaultCA").dropdown("get value");
|
|
if (defaultCA.trim() == ""){
|
|
defaultCA = "Let's Encrypt";
|
|
}
|
|
//Get a new cert using ACME
|
|
msgbox("Requesting certificate via " + defaultCA +"...");
|
|
console.log("Trying to get a new certificate via ACME");
|
|
|
|
//Request ACME for certificate, see cert.html component
|
|
obtainCertificate(rootname, defaultCA.trim(), function(){
|
|
// Renew the parent certificate list
|
|
initManagedDomainCertificateList();
|
|
});
|
|
}else{
|
|
msgbox("Proxy Endpoint Added");
|
|
}
|
|
});
|
|
}else{
|
|
msgbox("Proxy Endpoint Added");
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
//Clearn the proxy target value, make sure user do not enter http:// or https://
|
|
//and auto select TLS checkbox if https:// exists
|
|
function autoFillTargetTLS(input){
|
|
let targetDomain = $(input).val().trim();
|
|
if (targetDomain.startsWith("http://")){
|
|
targetDomain = targetDomain.substr(7);
|
|
$(input).val(targetDomain);
|
|
$("#reqTls").parent().checkbox("set unchecked");
|
|
}else if (targetDomain.startsWith("https://")){
|
|
targetDomain = targetDomain.substr(8);
|
|
$(input).val(targetDomain);
|
|
$("#reqTls").parent().checkbox("set checked");
|
|
}else{
|
|
//No http or https was given. Sniff it
|
|
autoCheckTls(targetDomain);
|
|
}
|
|
}
|
|
|
|
|
|
//Automatic check if the site require TLS and check the checkbox if needed
|
|
function autoCheckTls(targetDomain){
|
|
$.cjax({
|
|
url: "/api/proxy/tlscheck?selfsignchk=true",
|
|
data: {url: targetDomain},
|
|
success: function(data){
|
|
if (data.error != undefined){
|
|
msgbox(data.error, false);
|
|
}else{
|
|
//Check if the site require TLS
|
|
if (data.protocol == "https"){
|
|
$("#reqTls").parent().checkbox("set checked");
|
|
}else if (data.protocol == "http"){
|
|
$("#reqTls").parent().checkbox("set unchecked");
|
|
}
|
|
//Check if the site is using self-signed cert
|
|
if (data.selfsign){
|
|
$("#skipTLSValidation").parent().checkbox("set checked");
|
|
}else{
|
|
$("#skipTLSValidation").parent().checkbox("set unchecked");
|
|
}
|
|
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
function toggleBasicAuth() {
|
|
var basicAuthDiv = document.getElementById('basicAuthOnly');
|
|
if ($("#requireBasicAuth").parent().checkbox("is checked")) {
|
|
$("#basicAuthCredentials").removeClass("disabled");
|
|
} else {
|
|
$("#basicAuthCredentials").addClass("disabled");
|
|
}
|
|
}
|
|
$("#requireBasicAuth").on('change', toggleBasicAuth);
|
|
toggleBasicAuth();
|
|
|
|
function toggleRateLimit() {
|
|
if ($("#requireRateLimit").parent().checkbox("is checked")) {
|
|
$("#proxyRateLimit").parent().parent().removeClass("disabled");
|
|
} else {
|
|
$("#proxyRateLimit").parent().parent().addClass("disabled");
|
|
}
|
|
}
|
|
$("#requireRateLimit").on('change', toggleRateLimit);
|
|
toggleRateLimit();
|
|
|
|
|
|
/*
|
|
Credential Managements
|
|
|
|
*/
|
|
let credentials = []; // Global variable to store credentials
|
|
|
|
function addCredentials() {
|
|
// Retrieve the username and password input values
|
|
var username = $('#basicAuthCredUsername').val();
|
|
var password = $('#basicAuthCredPassword').val();
|
|
|
|
if(username == "" || password == ""){
|
|
msgbox("Username or password cannot be empty", false, 5000);
|
|
return;
|
|
}
|
|
|
|
// Create a new credential object
|
|
var credential = {
|
|
username: username,
|
|
password: password
|
|
};
|
|
|
|
// Add the credential to the global credentials array
|
|
credentials.push(credential);
|
|
|
|
// Clear the input fields
|
|
$('#basicAuthCredUsername').val('');
|
|
$('#basicAuthCredPassword').val('');
|
|
|
|
// Update the table body with the credentials
|
|
updateTable();
|
|
}
|
|
|
|
function updateTable() {
|
|
var tableBody = $('#basicAuthCredentialTable');
|
|
tableBody.empty();
|
|
|
|
if (credentials.length === 0) {
|
|
tableBody.append('<tr><td colspan="3"><i class="ui green circle check icon"></i> No Entered Credential</td></tr>');
|
|
} else {
|
|
for (var i = 0; i < credentials.length; i++) {
|
|
var credential = credentials[i];
|
|
var username = credential.username;
|
|
var password = credential.password.replace(/./g, '*'); // Replace each character with '*'
|
|
|
|
var row = '<tr>' +
|
|
'<td>' + username + '</td>' +
|
|
'<td>' + password + '</td>' +
|
|
'<td><button class="ui basic button" onclick="removeCredential(' + i + ');"><i class="red remove icon"></i> Remove</button></td>' +
|
|
'</tr>';
|
|
|
|
tableBody.append(row);
|
|
}
|
|
}
|
|
}
|
|
|
|
function removeCredential(index) {
|
|
// Remove the credential from the credentials array
|
|
credentials.splice(index, 1);
|
|
|
|
// Update the table body
|
|
updateTable();
|
|
}
|
|
|
|
|
|
|
|
//Update v3.0.0
|
|
//Since some proxy rules now contains wildcard characters
|
|
//all uuid are converted to hex code before use in DOM selector
|
|
|
|
String.prototype.hexEncode = function(){
|
|
var hex, i;
|
|
|
|
var result = "";
|
|
for (i=0; i<this.length; i++) {
|
|
hex = this.charCodeAt(i).toString(16);
|
|
result += ("000"+hex).slice(-4);
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
String.prototype.hexDecode = function(){
|
|
var j;
|
|
var hexes = this.match(/.{1,4}/g) || [];
|
|
var back = "";
|
|
for(j = 0; j<hexes.length; j++) {
|
|
back += String.fromCharCode(parseInt(hexes[j], 16));
|
|
}
|
|
|
|
return back;
|
|
}
|
|
|
|
/*
|
|
Access Rule dropdown Initialization
|
|
*/
|
|
|
|
function initNewProxyRuleAccessDropdownList(callback=undefined){
|
|
$.get("/api/access/list", function(data){
|
|
if (data.error == undefined){
|
|
$("#newProxyRuleAccessList").html("");
|
|
data.forEach(function(rule){
|
|
let icon = `<i class="ui grey filter icon"></i>`;
|
|
if (rule.ID == "default"){
|
|
icon = `<i class="ui yellow star icon"></i>`;
|
|
}else if (rule.BlacklistEnabled && !rule.WhitelistEnabled){
|
|
//This is a blacklist filter
|
|
icon = `<i class="ui red filter icon"></i>`;
|
|
}else if (rule.WhitelistEnabled && !rule.BlacklistEnabled){
|
|
//This is a whitelist filter
|
|
icon = `<i class="ui green filter icon"></i>`;
|
|
}
|
|
$("#newProxyRuleAccessList").append(`<div class="item" data-value="${rule.ID}">${icon} ${rule.Name}</div>`);
|
|
});
|
|
$("#newProxyRuleAccessFilter").parent().dropdown();
|
|
if (callback != undefined){
|
|
callback();
|
|
}
|
|
}else{
|
|
msgbox("Access rule load failed: " + data.error, false);
|
|
}
|
|
})
|
|
}
|
|
initNewProxyRuleAccessDropdownList();
|
|
|
|
//Bind on tab switch events
|
|
tabSwitchEventBind["rules"] = function(){
|
|
//Update the access rule list
|
|
initNewProxyRuleAccessDropdownList();
|
|
}
|
|
|
|
/* Docker Optimizations */
|
|
function initDockerUXOptimizations(){
|
|
$.get("/api/docker/available", function(dockerAvailable){
|
|
if (dockerAvailable){
|
|
$(".dockerOptimizations").show();
|
|
}else{
|
|
$(".dockerOptimizations").hide();
|
|
}
|
|
});
|
|
}
|
|
initDockerUXOptimizations();
|
|
|
|
function openDockerContainersList(){
|
|
showSideWrapper('snippet/dockerContainersList.html');
|
|
}
|
|
|
|
function addContainerItem(item) {
|
|
$('#rootname').val(item.name);
|
|
$('#proxyDomain').val(`${item.ip}:${item.port}`)
|
|
hideSideWrapper(true);
|
|
}
|
|
|
|
/* UI Element Initialization */
|
|
function initAdvanceSettingsAccordion(){
|
|
function hasClickEvent(element) {
|
|
var events = $._data(element, "events");
|
|
return events && events.click && events.click.length > 0;
|
|
}
|
|
|
|
if (!hasClickEvent($("#advanceProxyRules"))){
|
|
// Not sure why sometime the accordion events are not binding
|
|
// to the DOM element. This makes sure the element is binded
|
|
// correctly by checking it again after 300ms
|
|
$("#advanceProxyRules").accordion();
|
|
$("#newProxyRuleAccessFilter").parent().dropdown();
|
|
setTimeout(function(){
|
|
initAdvanceSettingsAccordion();
|
|
}, 300);
|
|
}
|
|
}
|
|
initAdvanceSettingsAccordion();
|
|
|
|
|
|
|
|
</script> |