mirror of https://github.com/Aidaho12/haproxy-wi
parent
8a83efafe5
commit
f696d8ed63
|
@ -50,9 +50,13 @@ else:
|
|||
servers = sql.get_dick_permit()
|
||||
|
||||
if serv is not None:
|
||||
cfg = configs_dir + serv + "-" + funct.get_data('config') + "."+file_format
|
||||
if service == 'nginx':
|
||||
conf_file_name_short = config_file_name.split('/')[-1]
|
||||
cfg = configs_dir + serv + "-" + conf_file_name_short + "-" + funct.get_data('config') + "." + file_format
|
||||
else:
|
||||
cfg = configs_dir + serv + "-" + funct.get_data('config') + "."+file_format
|
||||
|
||||
if serv is not None and form.getvalue('open') is not None:
|
||||
if serv is not None and form.getvalue('open') is not None and form.getvalue('new_config') is None:
|
||||
funct.check_is_server_in_group(serv)
|
||||
if service == 'keepalived':
|
||||
error = funct.get_config(serv, cfg, keepalived=1)
|
||||
|
@ -82,6 +86,9 @@ if serv is not None and form.getvalue('open') is not None:
|
|||
|
||||
os.system("/bin/mv %s %s.old" % (cfg, cfg))
|
||||
|
||||
if form.getvalue('new_config') is not None:
|
||||
config_read = ' '
|
||||
|
||||
if serv is not None and form.getvalue('config') is not None:
|
||||
import sys
|
||||
funct.check_is_server_in_group(serv)
|
||||
|
|
|
@ -29,8 +29,8 @@ def default_values():
|
|||
{'param': 'lists_path', 'value': 'lists', 'section': 'main',
|
||||
'desc': 'Path to the black and the wild list. The value of this paramer should be specified as a relative path beginning with $HOME_ROXY-WI',
|
||||
'group': '1'},
|
||||
{'param': 'haproxy_path_logs', 'value': '/var/log/haproxy/access.log', 'section': 'haproxy',
|
||||
'desc': 'The default local path for saving logs', 'group': '1'},
|
||||
{'param': 'haproxy_path_logs', 'value': '/var/log/haproxy/', 'section': 'haproxy',
|
||||
'desc': 'The path for HAProxy logs', 'group': '1'},
|
||||
{'param': 'syslog_server_enable', 'value': '0', 'section': 'logs',
|
||||
'desc': 'Enable getting logs from a syslog server; (0 - no, 1 - yes)', 'group': '1'},
|
||||
{'param': 'syslog_server', 'value': '', 'section': 'logs', 'desc': 'IP address of the syslog_server',
|
||||
|
@ -57,8 +57,8 @@ def default_values():
|
|||
'group': '1'},
|
||||
{'param': 'apache_log_path', 'value': '/var/log/'+apache_dir+'/', 'section': 'logs', 'desc': 'Path to Apache logs',
|
||||
'group': '1'},
|
||||
{'param': 'nginx_path_error_logs', 'value': '/var/log/nginx/error.log', 'section': 'nginx',
|
||||
'desc': 'Nginx error log', 'group': '1'},
|
||||
{'param': 'nginx_path_logs', 'value': '/var/log/nginx/', 'section': 'nginx',
|
||||
'desc': 'The path for Nginx logs', 'group': '1'},
|
||||
{'param': 'nginx_stats_user', 'value': 'admin', 'section': 'nginx', 'desc': 'Username for accessing Nginx stats page',
|
||||
'group': '1'},
|
||||
{'param': 'nginx_stats_password', 'value': 'password', 'section': 'nginx',
|
||||
|
@ -873,8 +873,30 @@ def update_db_v_5_4_2(**kwargs):
|
|||
print("Updating... DB has been updated to version 5.4.2")
|
||||
|
||||
|
||||
def update_db_v_5_4_3(**kwargs):
|
||||
query = Setting.update(param='nginx_path_logs', value='/var/log/nginx/').where(Setting.param == 'nginx_path_error_logs')
|
||||
try:
|
||||
query.execute()
|
||||
except Exception as e:
|
||||
print("An error occurred:", e)
|
||||
else:
|
||||
if kwargs.get('silent') != 1:
|
||||
print("Updating... DB has been updated to version 5.4.3")
|
||||
|
||||
|
||||
def update_db_v_5_4_3_1(**kwargs):
|
||||
query = Setting.update( value='/etc/nginx/').where(Setting.param == 'nginx_dir')
|
||||
try:
|
||||
query.execute()
|
||||
except Exception as e:
|
||||
print("An error occurred:", e)
|
||||
else:
|
||||
if kwargs.get('silent') != 1:
|
||||
print("Updating... DB has been updated to version 5.4.3-1")
|
||||
|
||||
|
||||
def update_ver():
|
||||
query = Version.update(version='5.4.2.0')
|
||||
query = Version.update(version='5.4.3.0')
|
||||
try:
|
||||
query.execute()
|
||||
except:
|
||||
|
@ -911,6 +933,8 @@ def update_all():
|
|||
update_db_v_5_3_2()
|
||||
update_db_v_5_3_2_2()
|
||||
update_db_v_5_4_2()
|
||||
update_db_v_5_4_3()
|
||||
update_db_v_5_4_3_1()
|
||||
update_ver()
|
||||
|
||||
|
||||
|
@ -944,6 +968,8 @@ def update_all_silent():
|
|||
update_db_v_5_3_2(silent=1)
|
||||
update_db_v_5_3_2_2(silent=1)
|
||||
update_db_v_5_4_2(silent=1)
|
||||
update_db_v_5_4_3(silent=1)
|
||||
update_db_v_5_4_3_1(silent=1)
|
||||
update_ver()
|
||||
|
||||
|
||||
|
|
112
app/funct.py
112
app/funct.py
|
@ -490,19 +490,29 @@ def diff_config(oldcfg, cfg, **kwargs):
|
|||
except IOError:
|
||||
print('<center><div class="alert alert-danger">Can\'t read write change to log. %s</div></center>' % stderr)
|
||||
pass
|
||||
|
||||
|
||||
def get_remote_sections(server_ip: str, service: str) -> str:
|
||||
import sql
|
||||
remote_dir = service+'_dir'
|
||||
config_dir = sql.get_setting(remote_dir)
|
||||
config_dir = return_nice_path(config_dir)
|
||||
if service == 'nginx':
|
||||
section_name = 'server_name'
|
||||
elif service == 'apache':
|
||||
section_name = 'ServerName'
|
||||
commands = ['sudo grep {} {}* -R |grep -v \'$server_name\|#\'|awk \'{{print $1, $3}}\''.format(section_name, config_dir)]
|
||||
|
||||
backends = ssh_command(server_ip, commands)
|
||||
|
||||
return backends
|
||||
|
||||
|
||||
def get_sections(config, **kwargs):
|
||||
return_config = list()
|
||||
with open(config, 'r') as f:
|
||||
for line in f:
|
||||
if kwargs.get('service') == 'nginx':
|
||||
if 'server_name' in line:
|
||||
line = line.split('server_name')[1]
|
||||
line = line.split(';')[0]
|
||||
line = line.strip()
|
||||
return_config.append(line)
|
||||
elif kwargs.get('service') == 'keepalived':
|
||||
if kwargs.get('service') == 'keepalived':
|
||||
import re
|
||||
ip_pattern = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
|
||||
find_ip = re.findall(ip_pattern,line)
|
||||
|
@ -658,7 +668,7 @@ def get_stick_table(table):
|
|||
|
||||
|
||||
def show_installation_output(error, output, service):
|
||||
if error and "WARNING" not in error:
|
||||
if error and "DEPRECATION WARNING" not in error:
|
||||
logging('localhost', error, haproxywi=1)
|
||||
print('error: '+error)
|
||||
return False
|
||||
|
@ -1168,9 +1178,35 @@ def show_log(stdout, **kwargs):
|
|||
return out
|
||||
|
||||
|
||||
def show_finding_in_config(stdout: str, **kwargs) -> str:
|
||||
i = 0
|
||||
out = ''
|
||||
grep = ''
|
||||
line_class = 'line'
|
||||
|
||||
if kwargs.get('grep'):
|
||||
import re
|
||||
grep = kwargs.get('grep')
|
||||
grep = re.sub(r'[?|$|!|^|*|\]|\[|,| |]', r'', grep)
|
||||
|
||||
out += '<div class="line">--</div>'
|
||||
for line in stdout:
|
||||
i = i + 1
|
||||
if kwargs.get('grep'):
|
||||
line = line.replace(grep, '<span style="color: red; font-weight: bold;">'+grep+'</span>')
|
||||
line_class = "line" if '--' in line else "line3"
|
||||
out += '<div class="'+line_class+'">' + line + '</div>'
|
||||
|
||||
out += '<div class="line">--</div>'
|
||||
|
||||
return out
|
||||
|
||||
|
||||
|
||||
def show_haproxy_log(serv, rows=10, waf='0', grep=None, hour='00', minut='00', hour1='24', minut1='00', service='haproxy', **kwargs):
|
||||
import sql
|
||||
exgrep = form.getvalue('exgrep')
|
||||
log_file = form.getvalue('file')
|
||||
date = hour+':'+minut
|
||||
date1 = hour1+':'+minut1
|
||||
cmd = ''
|
||||
|
@ -1189,11 +1225,11 @@ def show_haproxy_log(serv, rows=10, waf='0', grep=None, hour='00', minut='00', h
|
|||
syslog_server_enable = sql.get_setting('syslog_server_enable')
|
||||
if syslog_server_enable is None or syslog_server_enable == 0:
|
||||
if service == 'nginx':
|
||||
local_path_logs = sql.get_setting('nginx_path_error_logs')
|
||||
commands = ["sudo cat %s| awk '$2>\"%s:00\" && $2<\"%s:00\"' |tail -%s %s %s" % (local_path_logs, date, date1, rows, grep_act, exgrep_act)]
|
||||
local_path_logs = sql.get_setting('nginx_path_logs')
|
||||
commands = ["sudo cat %s/%s |tail -%s %s %s" % (local_path_logs, log_file, rows, grep_act, exgrep_act)]
|
||||
else:
|
||||
local_path_logs = sql.get_setting('haproxy_path_logs')
|
||||
commands = ["sudo cat %s| awk '$3>\"%s:00\" && $3<\"%s:00\"' |tail -%s %s %s" % (local_path_logs, date, date1, rows, grep_act, exgrep_act)]
|
||||
commands = ["sudo cat %s/%s| awk '$3>\"%s:00\" && $3<\"%s:00\"' |tail -%s %s %s" % (local_path_logs, log_file, date, date1, rows, grep_act, exgrep_act)]
|
||||
syslog_server = serv
|
||||
else:
|
||||
commands = ["sudo cat /var/log/%s/syslog.log | sed '/ %s:00/,/ %s:00/! d' |tail -%s %s %s %s" % (serv, date, date1, rows, grep_act, grep, exgrep_act)]
|
||||
|
@ -1399,15 +1435,25 @@ def get_files(dir=get_config_var('configs', 'haproxy_save_configs_dir'), format=
|
|||
|
||||
|
||||
def get_remote_files(server_ip: str, config_dir: str, file_format: str):
|
||||
if 'nginx' not in config_dir:
|
||||
return 'error: The path must contain the name of the service. Check it in Roxy-WI settings'
|
||||
if config_dir[-1] != '/':
|
||||
config_dir += '/'
|
||||
commands = ['ls ' + config_dir + '*.' + file_format]
|
||||
config_dir = return_nice_path(config_dir)
|
||||
if file_format == 'conf':
|
||||
commands = ['ls ' + config_dir + '*/*.' + file_format]
|
||||
else:
|
||||
commands = ['ls ' + config_dir + '/*.' + file_format]
|
||||
config_files = ssh_command(server_ip, commands)
|
||||
|
||||
return config_files
|
||||
|
||||
|
||||
def return_nice_path(return_path: str) -> str:
|
||||
if 'nginx' not in return_path and 'haproxy' not in return_path:
|
||||
return 'error: The path must contain the name of the service. Check it in Roxy-WI settings'
|
||||
if return_path[-1] != '/':
|
||||
return_path += '/'
|
||||
|
||||
return return_path
|
||||
|
||||
|
||||
def get_key(item):
|
||||
return item[0]
|
||||
|
||||
|
@ -1693,6 +1739,26 @@ def get_system_info(server_ip: str) -> bool:
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if b['class'] == 'storage':
|
||||
for p, pval in b.items():
|
||||
if isinstance(pval, list):
|
||||
for disks_info in pval:
|
||||
for volume_info in disks_info['children']:
|
||||
if isinstance(volume_info['logicalname'], list):
|
||||
volume_name = volume_info['logicalname'][0]
|
||||
mount_point = volume_info['logicalname'][1]
|
||||
size = round(volume_info['capacity'] / 1073741824)
|
||||
size = str(size) + 'Gb'
|
||||
fs = volume_info['configuration']['mount.fstype']
|
||||
state = volume_info['configuration']['state']
|
||||
disks[volume_name] = {'mount_point': mount_point,
|
||||
'size': size,
|
||||
'fs': fs,
|
||||
'state': state}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if b['class'] == 'bridge':
|
||||
if 'children' in b:
|
||||
|
@ -1764,6 +1830,20 @@ def get_system_info(server_ip: str) -> bool:
|
|||
try:
|
||||
for q in y['children']:
|
||||
for o in q['children']:
|
||||
try:
|
||||
volume_name = o['logicalname']
|
||||
mount_point = ''
|
||||
size = round(o['size'] / 1073741824)
|
||||
size = str(size) + 'Gb'
|
||||
fs = ''
|
||||
state = ''
|
||||
disks[volume_name] = {
|
||||
'mount_point': mount_point,
|
||||
'size': size,
|
||||
'fs': fs,
|
||||
'state': state}
|
||||
except Exception:
|
||||
pass
|
||||
for w in o['children']:
|
||||
try:
|
||||
if isinstance(w['logicalname'], list):
|
||||
|
|
|
@ -39,6 +39,9 @@ except Exception:
|
|||
if service == 'nginx':
|
||||
if funct.check_login(service=2):
|
||||
title = "Nginx`s logs"
|
||||
elif waf == '1':
|
||||
if funct.check_login(service=1):
|
||||
title = "WAF logs"
|
||||
else:
|
||||
if funct.check_login(service=1):
|
||||
title = "HAProxy`s logs"
|
||||
|
|
|
@ -479,36 +479,36 @@ if act == "overviewHapserverBackends":
|
|||
if service == 'haproxy':
|
||||
configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
|
||||
format_file = 'cfg'
|
||||
elif service == 'nginx':
|
||||
configs_dir = funct.get_config_var('configs', 'nginx_save_configs_dir')
|
||||
format_file = 'conf'
|
||||
elif service == 'keepalived':
|
||||
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
|
||||
format_file = 'conf'
|
||||
|
||||
try:
|
||||
sections = funct.get_sections(configs_dir + funct.get_files(dir=configs_dir, format=format_file)[0], service=service)
|
||||
except Exception as e:
|
||||
funct.logging('localhost', str(e), haproxywi=1)
|
||||
if service != 'nginx':
|
||||
try:
|
||||
sections = funct.get_sections(configs_dir + funct.get_files(dir=configs_dir, format=format_file)[0], service=service)
|
||||
except Exception as e:
|
||||
funct.logging('localhost', str(e), haproxywi=1)
|
||||
|
||||
try:
|
||||
cfg = configs_dir + serv + "-" + funct.get_data('config') + '.' + format_file
|
||||
except Exception as e:
|
||||
funct.logging('localhost', ' Cannot generate a cfg path ' + str(e), haproxywi=1)
|
||||
try:
|
||||
if service == 'nginx':
|
||||
error = funct.get_config(serv, cfg, nginx=1)
|
||||
elif service == 'keepalived':
|
||||
error = funct.get_config(serv, cfg, keepalived=1)
|
||||
else:
|
||||
error = funct.get_config(serv, cfg)
|
||||
except Exception as e:
|
||||
funct.logging('localhost', ' Cannot download a config ' + str(e), haproxywi=1)
|
||||
try:
|
||||
sections = funct.get_sections(cfg, service=service)
|
||||
except Exception as e:
|
||||
funct.logging('localhost', ' Cannot get sections from config file ' + str(e), haproxywi=1)
|
||||
sections = 'Cannot get backends'
|
||||
try:
|
||||
cfg = configs_dir + serv + "-" + funct.get_data('config') + '.' + format_file
|
||||
except Exception as e:
|
||||
funct.logging('localhost', ' Cannot generate a cfg path ' + str(e), haproxywi=1)
|
||||
try:
|
||||
if service == 'nginx':
|
||||
error = funct.get_config(serv, cfg, nginx=1)
|
||||
elif service == 'keepalived':
|
||||
error = funct.get_config(serv, cfg, keepalived=1)
|
||||
else:
|
||||
error = funct.get_config(serv, cfg)
|
||||
except Exception as e:
|
||||
funct.logging('localhost', ' Cannot download a config ' + str(e), haproxywi=1)
|
||||
try:
|
||||
sections = funct.get_sections(cfg, service=service)
|
||||
except Exception as e:
|
||||
funct.logging('localhost', ' Cannot get sections from config file ' + str(e), haproxywi=1)
|
||||
sections = 'Cannot get backends'
|
||||
else:
|
||||
sections = funct.get_remote_sections(serv, service)
|
||||
|
||||
template = template.render(backends=sections, serv=serv, service=service)
|
||||
print(template)
|
||||
|
@ -1203,6 +1203,20 @@ if act == 'configShowFiles':
|
|||
template = template.render(serv=serv, return_files=return_files, config_file_name=config_file_name, path_dir=nginx_config_dir)
|
||||
print(template)
|
||||
|
||||
if act == 'showRemoteLogFiles':
|
||||
service = form.getvalue('service')
|
||||
log_path = sql.get_setting(service+'_path_logs')
|
||||
return_files = funct.get_remote_files(serv, log_path, 'log')
|
||||
if 'error: ' in return_files:
|
||||
print(return_files)
|
||||
sys.exit()
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
|
||||
template = env.get_template('ajax/show_log_files.html')
|
||||
template = template.render(serv=serv, return_files=return_files, path_dir=log_path)
|
||||
print(template)
|
||||
|
||||
if form.getvalue('master'):
|
||||
master = form.getvalue('master')
|
||||
slave = form.getvalue('slave')
|
||||
|
@ -3113,7 +3127,7 @@ if form.getvalue('awsvars') or form.getvalue('awseditvars'):
|
|||
print('error: ' + stderr)
|
||||
else:
|
||||
print('ok')
|
||||
|
||||
|
||||
if form.getvalue('dovars') or form.getvalue('doeditvars'):
|
||||
if form.getvalue('dovars'):
|
||||
dovars = form.getvalue('dovars')
|
||||
|
@ -3172,7 +3186,7 @@ if form.getvalue('dovalidate') or form.getvalue('doeditvalidate'):
|
|||
print('error: ' + stderr)
|
||||
else:
|
||||
print('ok')
|
||||
|
||||
|
||||
if form.getvalue('doworkspace'):
|
||||
workspace = form.getvalue('doworkspace')
|
||||
group = form.getvalue('do_create_group')
|
||||
|
@ -3335,7 +3349,7 @@ if form.getvalue('awseditworkspace'):
|
|||
output, stderr = funct.subprocess_execute(cmd)
|
||||
except Exception as e:
|
||||
print('error: ' +str(e))
|
||||
|
||||
|
||||
if stderr != '':
|
||||
stderr = stderr.strip()
|
||||
stderr = repr(stderr)
|
||||
|
@ -4022,3 +4036,19 @@ if act == 'updateSystemInfo':
|
|||
print(template)
|
||||
else:
|
||||
print('error: Cannot update server info')
|
||||
|
||||
if act == 'findInConfigs':
|
||||
server_ip = serv
|
||||
server_ip = funct.is_ip_or_dns(server_ip)
|
||||
finding_words = form.getvalue('words')
|
||||
service = form.getvalue('service')
|
||||
log_path = sql.get_setting(service + '_dir')
|
||||
log_path = funct.return_nice_path(log_path)
|
||||
commands = ['sudo grep "%s" %s* -C 2 -Rn' % (finding_words, log_path)]
|
||||
return_find = funct.ssh_command(server_ip, commands, raw='1')
|
||||
return_find = funct.show_finding_in_config(return_find, grep=finding_words)
|
||||
|
||||
if 'error: ' in return_find:
|
||||
print(return_find)
|
||||
sys.exit()
|
||||
print(return_find)
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
- name: populate service facts
|
||||
service_facts:
|
||||
|
||||
- include: logs.yml
|
||||
|
||||
- include: configure.yml
|
||||
|
||||
- include: installation.yml
|
||||
|
||||
- include: logs.yml
|
||||
|
||||
- name: Add syn_flood tasks
|
||||
include: syn_flood.yml
|
||||
when: (SYN_FLOOD is defined) and (SYN_FLOOD|length > 0)
|
||||
|
|
|
@ -40,6 +40,18 @@
|
|||
http_proxy: "{{PROXY}}"
|
||||
https_proxy: "{{PROXY}}"
|
||||
|
||||
- name: install the el9 RPMS for HAProxy
|
||||
yum:
|
||||
name:
|
||||
- yajl-devel
|
||||
state: latest
|
||||
when:
|
||||
- ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS'
|
||||
- ansible_facts['distribution_major_version'] == '8'
|
||||
environment:
|
||||
http_proxy: "{{PROXY}}"
|
||||
https_proxy: "{{PROXY}}"
|
||||
|
||||
- name: install the common RPMS for HAProxy
|
||||
yum:
|
||||
name:
|
||||
|
|
|
@ -6,11 +6,20 @@
|
|||
{% if backends == 'Cannot get backends' %}
|
||||
{{backends}}
|
||||
{% else %}
|
||||
{% if service == 'nginx' or service == 'apache' %}
|
||||
{% set backends = backends.split('\n') %}
|
||||
{% endif %}
|
||||
{% for b in backends %}
|
||||
{% if service == 'haproxy' %}
|
||||
<a href="/app/sections.py?serv={{ serv}}§ion={{b}}" title="Edit backend {{b}}" target="_blank" style="padding-right: 10px;">
|
||||
{{b}}
|
||||
</a>
|
||||
{% elif service == 'nginx' or service == 'apache' %}
|
||||
{% set full_file = b.split(' ')[0] | replace ('/', '92') %}
|
||||
{% set full_file = full_file.replace(':', '') %}
|
||||
<a href="/app/config.py?service={{ service }}&serv={{serv}}&open=open&config_file_name={{full_file}}" title="Edit config {{b.split(' ')[0]}}" target="_blank" style="padding-right: 10px;">
|
||||
{{b.split(' ')[1] | replace(';', '')}}
|
||||
</a>
|
||||
{% else %}
|
||||
{{b}}
|
||||
{% endif %}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
{% from 'include/input_macros.html' import input %}
|
||||
<form action="" method="post">
|
||||
<div style="text-align: center;margin-top: 20px;">
|
||||
<div style="text-align: center;margin-top: 20px;">
|
||||
{% if 'cannot access' not in return_files %}
|
||||
{% if config_file_name == '' %}
|
||||
<h4>Config files from {{serv}}</h4>
|
||||
{% endif %}
|
||||
<form action="" method="post">
|
||||
<p>
|
||||
<select autofocus required name="config_file_name" id="config_file_name">
|
||||
<select autofocus required name="config_file_name" id="config_file_name" style="width: 365px;">
|
||||
<option disabled selected>Select a config file</option>
|
||||
{% for file in return_files.split() %}
|
||||
{% if file == config_file_name %}
|
||||
|
@ -18,7 +19,79 @@
|
|||
|
||||
{{ input('serv', type='hidden', value=serv) }}
|
||||
{{ input('open', type='hidden', value='open') }}
|
||||
<a class="ui-button ui-widget ui-corner-all" id="show" title="Compare" onclick="showConfig()">Open</a>
|
||||
<a class="ui-button ui-widget ui-corner-all" id="show" title="Open config" onclick="showConfig()">Open</a>
|
||||
<a class="ui-button ui-widget ui-corner-all" title="Create a new config file" onclick="addNewConfig('{{serv}}')">Add</a>
|
||||
<a class="ui-button ui-widget ui-corner-all" title="Lookup in config files" id="open_find_form">Find</a>
|
||||
</p>
|
||||
</form>
|
||||
<form action="" method="post" id="finding_words_from">
|
||||
<p id="find_p" style="display: none;">
|
||||
{{ input('words', type='text', style='height: 32.5px;') }}
|
||||
<button type="submit" name="find" id="find_in_configs" value="Find" title="Find in configs">Find</button>
|
||||
</p>
|
||||
{% else %}
|
||||
<div class="alert alert-warning">{{return_files}}</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="add-new-config" style="display: none">
|
||||
<div style="padding-top: 15px;">
|
||||
Config file name: {{ input('new_config_name', type='text', placeholder='conf.d/config_name', title='Format: sub-directory/config_name') }}
|
||||
{{ input('path_config_name', type='hidden', value=path_dir) }}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#config_file_name').select2();
|
||||
$('#finding_words_from').submit(function() {
|
||||
if ($('#words').val() == '') {
|
||||
toastr.warning('Enter words for seaching');
|
||||
return false;
|
||||
}
|
||||
findInConfig();
|
||||
return false;
|
||||
});
|
||||
$( "input[type=submit], button" ).button()
|
||||
$('#open_find_form').on('click', function (){
|
||||
if ($('#find_p').css('display') == 'none') {
|
||||
$('#find_p').show();
|
||||
} else {
|
||||
$('#find_p').hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
function addNewConfig(serv) {
|
||||
$( "#add-new-config" ).dialog({
|
||||
autoOpen: true,
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 600,
|
||||
modal: true,
|
||||
title: "Create a new config file",
|
||||
show: {
|
||||
effect: "fade",
|
||||
duration: 200
|
||||
},
|
||||
hide: {
|
||||
effect: "fade",
|
||||
duration: 200
|
||||
},
|
||||
buttons: {
|
||||
"Create": function() {
|
||||
let config_file_name = $('#new_config_name').val();
|
||||
let path_dir = $('#path_config_name').val();
|
||||
config_file_name = config_file_name.replaceAll('\/','92');
|
||||
path_dir = path_dir.replaceAll('\/','92');
|
||||
window.location.replace('config.py?service=nginx&serv='+serv+'&open=open&config_file_name='+path_dir+'92'+config_file_name+'.conf&new_config=1');
|
||||
$( this ).dialog( "close" );
|
||||
},
|
||||
Cancel: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
$( "select" ).selectmenu();
|
||||
$("#config_file_name").selectmenu("destroy");
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<select autofocus required name="log_files" id="log_files" style="width: 200px;">
|
||||
<option disabled selected>Select a log file</option>
|
||||
{% for file in return_files.split() %}
|
||||
{% if file == config_file_name %}
|
||||
<option value="{{ file.split('/')[-1] }}" selected>{{ file.split('/')[-1] }}</option>
|
||||
{% else %}
|
||||
<option value="{{ file.split('/')[-1] }}">{{ file.split('/')[-1] }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#log_files').select2();
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.select2-container .select2-selection--single {
|
||||
height: 33px;
|
||||
}
|
||||
</style>
|
|
@ -56,7 +56,7 @@
|
|||
<td>{{ram_info.size}}Gb</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="overview-wi">
|
||||
<table class="overview-wi" style="clear: both;">
|
||||
<tr class="overviewHead">
|
||||
<td class="padding10 first-collumn-wi" colspan=2>
|
||||
CPU
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
<tr>
|
||||
<td class="padding20" style="width: 70%">Current group</td>
|
||||
<td>
|
||||
<select id="newCurrentGroup" name="newCurrentGroup" >
|
||||
{% for g in groups %}
|
||||
{% if g.user_group_id|string() == group|string() %}
|
||||
<option value="{{ g.user_group_id }}" selected>{{ g.groups.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ g.user_group_id }}">{{ g.groups.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<td class="padding20" style="width: 70%">Current group</td>
|
||||
<td>
|
||||
<select id="newCurrentGroup" name="newCurrentGroup">
|
||||
{% for g in groups %}
|
||||
{% if g.user_group_id|string() == group|string() %}
|
||||
<option value="{{ g.user_group_id }}" selected>{{ g.groups.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ g.user_group_id }}">{{ g.groups.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
<script src="/inc/jquery-1.12.4.js"></script>
|
||||
<script src="/inc/jquery-ui.js"></script>
|
||||
<script src="/inc/js.cookie.min.js"></script>
|
||||
<link href="/inc/select2.css" rel="stylesheet" />
|
||||
<script src="/inc/select2.js"></script>
|
||||
<script src="/inc/script.js"></script>
|
||||
<script src="/inc/nprogress.js"></script>
|
||||
<link href="/inc/toastr.css" rel="stylesheet"/>
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<link rel="stylesheet" href="/inc/codemirror/codemirror.css">
|
||||
<link rel="stylesheet" href="/inc/codemirror/dialog.css">
|
||||
<script src="/inc/codemirror/codemirror.js"></script>
|
||||
<script src="/inc/codemirror/nginx.js"></script>
|
||||
<script src="/inc/codemirror/haproxy.js"></script>
|
||||
<script src="/inc/codemirror/dialog.js"></script>
|
||||
<script src="/inc/codemirror/search.js"></script>
|
||||
<script src="/inc/codemirror/searchcursor.js"></script>
|
||||
<script src="/inc/codemirror/jump-to-line.js"></script>
|
||||
<script src="/inc/configshow.js"></script>
|
||||
<center>
|
||||
{% if selects|length == 0 %}
|
||||
|
@ -86,10 +91,10 @@
|
|||
}
|
||||
if (cur_url[1].split('&')[0] == 'service=haproxy' || cur_url[1].split('&')[0] == 'service=None') {
|
||||
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("config_text_area"),
|
||||
{mode: "haproxy", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true});
|
||||
{mode: "haproxy", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true, autoCloseBrackets: true});
|
||||
} else {
|
||||
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("config_text_area"),
|
||||
{mode: "nginx", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true});
|
||||
{mode: "nginx", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true, autoCloseBrackets: true});
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
Server
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if select_id != 'viewlogs' and service != 'nginx' %}
|
||||
<td style="width: 5%;">WAF logs</td>
|
||||
{% if waf != '1' %}
|
||||
<td style="width: 10%;">Log files</td>
|
||||
{% endif %}
|
||||
<td>Number rows</td>
|
||||
<td class="padding10 help_cursor"><span title="Find in a log file(supports regular expressions)">Find<span></td>
|
||||
<td class="padding10 help_cursor"><span title="Exclude from search in a log file(supports regular expressions)">Exclude<span></td>
|
||||
{% if select_id != 'viewlogs' and service != 'nginx' %}
|
||||
{% endif %}
|
||||
<td style="width: 10%;">Number rows</td>
|
||||
<td class="help_cursor" style="width: 10%;"><span title="Find in a log file(supports regular expressions)">Find<span></td>
|
||||
<td class="padding10 help_cursor" style="width: 10%;"><span title="Exclude from search in a log file(supports regular expressions)">Exclude<span></td>
|
||||
<td style="width: 10%;">
|
||||
<label for="time_range_out_hour" style="padding: 0">Time range:</label>
|
||||
{{ input('time_range_out_hour', value=hour, class='time-range', readonly='readonly') }}:{{ input('time_range_out_minut', value=minut, class='time-range', readonly='readonly') }}
|
||||
|
@ -49,28 +51,26 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
{% include 'include/select.html' %}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if select_id != 'viewlogs' and service != 'nginx' %}
|
||||
<td>
|
||||
{{ checkbox('waf') }}
|
||||
{% else %}
|
||||
{% include 'include/select.html' %}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if waf != '1' %}
|
||||
<td id="remote_log_files"></td>
|
||||
{% endif %}
|
||||
<td class="padding10" style="width: 10%;">
|
||||
{{ input('rows', type='number', value=rows, required='required', size='5') }}
|
||||
{{ input('rows', type='number', value=rows, required='required', style='width: 110px;') }}
|
||||
</td>
|
||||
<td class="padding10" style="width: 10%;">
|
||||
{{ input('grep', value=grep) }}
|
||||
{{ input('grep', value=grep, style='width: 110px;') }}
|
||||
</td>
|
||||
<td class="padding10" style="width: 10%;">
|
||||
{{ input('exgrep', value=exgrep) }}
|
||||
{{ input('exgrep', value=exgrep, style='width: 110px;') }}
|
||||
</td>
|
||||
<td class="padding10" style="width: 10%;">
|
||||
<div id="time-range"></div>
|
||||
</td>
|
||||
<td class="padding10 first-collumn" style="width: 10%;">
|
||||
<td class="padding10 first-collumn" style="width: 1%;">
|
||||
<button type="submit" name="Show log" value="Show" id="show_log_button">Show</button>
|
||||
</form>
|
||||
</td>
|
||||
|
@ -101,11 +101,22 @@
|
|||
{% if waf == '1' %}
|
||||
$('#waf').prop('checked', true);
|
||||
{% endif %}
|
||||
showLog()
|
||||
{% if waf != '1' %}
|
||||
showRemoteLogFiles()
|
||||
$( "#serv" ).on('selectmenuchange',function() {
|
||||
showRemoteLogFiles();
|
||||
});
|
||||
{% else %}
|
||||
showLog()
|
||||
{% endif %}
|
||||
|
||||
if (window.matchMedia('(max-width: 786px)').matches || window.matchMedia('(max-width: 1024px)').matches || window.matchMedia('(max-width: 667px)').matches) {
|
||||
$( "#serv" ).selectmenu({
|
||||
width: 150
|
||||
});
|
||||
$( "#log_files" ).selectmenu({
|
||||
width: 150
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
<td class="padding10">WAF mode</td>
|
||||
<td>Metrics</td>
|
||||
<td>Manage rules</td>
|
||||
<td>Log</td>
|
||||
<td>
|
||||
<a onclick="showOverviewWaf(ip, hostnamea)" title="Refresh" style="float: right; margin-right: 25px;">
|
||||
<span class="service-reload"></span>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
.CodeMirror-dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
background: inherit;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-top {
|
||||
border-bottom: 1px solid #eee;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-bottom {
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
width: 20em;
|
||||
color: inherit;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog button {
|
||||
font-size: 70%;
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
||||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
function dialogDiv(cm, template, bottom) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var dialog;
|
||||
dialog = wrap.appendChild(document.createElement("div"));
|
||||
if (bottom)
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||||
else
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
|
||||
if (typeof template == "string") {
|
||||
dialog.innerHTML = template;
|
||||
} else { // Assuming it's a detached DOM element.
|
||||
dialog.appendChild(template);
|
||||
}
|
||||
CodeMirror.addClass(wrap, 'dialog-opened');
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function closeNotification(cm, newVal) {
|
||||
if (cm.state.currentNotificationClose)
|
||||
cm.state.currentNotificationClose();
|
||||
cm.state.currentNotificationClose = newVal;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
if (!options) options = {};
|
||||
|
||||
closeNotification(this, null);
|
||||
|
||||
var dialog = dialogDiv(this, template, options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close(newVal) {
|
||||
if (typeof newVal == 'string') {
|
||||
inp.value = newVal;
|
||||
} else {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
|
||||
if (options.onClose) options.onClose(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
inp.focus();
|
||||
|
||||
if (options.value) {
|
||||
inp.value = options.value;
|
||||
if (options.selectValueOnOpen !== false) {
|
||||
inp.select();
|
||||
}
|
||||
}
|
||||
|
||||
if (options.onInput)
|
||||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
||||
if (options.onKeyUp)
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
||||
inp.blur();
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
}
|
||||
if (e.keyCode == 13) callback(inp.value, e);
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) {
|
||||
if (evt.relatedTarget !== null) close();
|
||||
});
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
me.focus();
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
|
||||
|
||||
button.focus();
|
||||
}
|
||||
return close;
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
}
|
||||
buttons[0].focus();
|
||||
for (var i = 0; i < buttons.length; ++i) {
|
||||
var b = buttons[i];
|
||||
(function(callback) {
|
||||
CodeMirror.on(b, "click", function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
if (callback) callback(me);
|
||||
});
|
||||
})(callbacks[i]);
|
||||
CodeMirror.on(b, "blur", function() {
|
||||
--blurring;
|
||||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||||
});
|
||||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* openNotification
|
||||
* Opens a notification, that can be closed with an optional timer
|
||||
* (default 5000ms timer) and always closes on click.
|
||||
*
|
||||
* If a notification is opened while another is opened, it will close the
|
||||
* currently opened one and open the new one immediately.
|
||||
*/
|
||||
CodeMirror.defineExtension("openNotification", function(template, options) {
|
||||
closeNotification(this, close);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var closed = false, doneTimer;
|
||||
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
|
||||
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
clearTimeout(doneTimer);
|
||||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
|
||||
CodeMirror.on(dialog, 'click', function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
});
|
||||
|
||||
if (duration)
|
||||
doneTimer = setTimeout(close, duration);
|
||||
|
||||
return close;
|
||||
});
|
||||
});
|
|
@ -0,0 +1,274 @@
|
|||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url(//themes.googleusercontent.com/static/fonts/sourcesanspro/v5/ODelI1aHBYDBqgeIAH2zlBM0YzuT7MdOe03otPbuUS0.woff) format('woff');
|
||||
}
|
||||
|
||||
body, html { margin: 0; padding: 0; height: 100%; }
|
||||
section, article { display: block; padding: 0; }
|
||||
|
||||
body {
|
||||
background: #f8f8f8;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
p { margin-top: 0; }
|
||||
|
||||
h2, h3, h1 {
|
||||
font-weight: normal;
|
||||
margin-bottom: .7em;
|
||||
}
|
||||
h1 { font-size: 140%; }
|
||||
h2 { font-size: 120%; }
|
||||
h3 { font-size: 110%; }
|
||||
article > h2:first-child, section:first-child > h2 { margin-top: 0; }
|
||||
|
||||
#nav h1 {
|
||||
margin-right: 12px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 2px;
|
||||
color: #d30707;
|
||||
letter-spacing: .5px;
|
||||
}
|
||||
|
||||
a, a:visited, a:link, .quasilink {
|
||||
color: #A21313;
|
||||
}
|
||||
|
||||
em {
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.quasilink {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
article {
|
||||
max-width: 700px;
|
||||
margin: 0 0 0 160px;
|
||||
border-left: 2px solid #E30808;
|
||||
border-right: 1px solid #ddd;
|
||||
padding: 30px 50px 100px 50px;
|
||||
background: white;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
||||
#nav {
|
||||
position: fixed;
|
||||
padding-top: 30px;
|
||||
max-height: 100%;
|
||||
box-sizing: -moz-border-box;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
left: 0; right: none;
|
||||
width: 160px;
|
||||
text-align: right;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1000px) {
|
||||
article {
|
||||
margin: 0 auto;
|
||||
}
|
||||
#nav {
|
||||
right: 50%;
|
||||
width: auto;
|
||||
border-right: 349px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
#nav ul {
|
||||
display: block;
|
||||
margin: 0; padding: 0;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
#nav a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#nav li {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
#nav li ul {
|
||||
font-size: 80%;
|
||||
margin-bottom: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#nav li.active ul {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#nav li li a {
|
||||
padding-right: 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#nav ul a {
|
||||
color: black;
|
||||
padding: 0 7px 1px 11px;
|
||||
}
|
||||
|
||||
#nav ul a.active, #nav ul a:hover {
|
||||
border-bottom: 1px solid #E30808;
|
||||
margin-bottom: -1px;
|
||||
color: #E30808;
|
||||
}
|
||||
|
||||
#logo {
|
||||
border: 0;
|
||||
margin-right: 12px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
section {
|
||||
border-top: 1px solid #E30808;
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
section.first {
|
||||
border: none;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#demo {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#demolist {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
z-index: 25;
|
||||
}
|
||||
|
||||
.yinyang {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: 0; right: 0;
|
||||
margin: auto;
|
||||
display: block;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin: 1em 0 0;
|
||||
min-height: 100px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.actionspicture {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
height: 100px;
|
||||
top: 0; left: 0; right: 0;
|
||||
}
|
||||
|
||||
.actionlink {
|
||||
pointer-events: auto;
|
||||
font-family: arial;
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
line-height: 1;
|
||||
height: 1em;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.actionlink.download {
|
||||
color: white;
|
||||
right: 50%;
|
||||
margin-right: 13px;
|
||||
text-shadow: -1px 1px 3px #b00, -1px -1px 3px #b00, 1px 0px 3px #b00;
|
||||
}
|
||||
|
||||
.actionlink.fund {
|
||||
color: #b00;
|
||||
left: 50%;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.actionlink:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.actionlink a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.actionsleft {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.actionsright {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.actions {
|
||||
padding-top: 120px;
|
||||
}
|
||||
.actionsleft, .actionsright {
|
||||
float: none;
|
||||
text-align: left;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
text-decoration: underline;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#features ul {
|
||||
list-style: none;
|
||||
margin: 0 0 1em;
|
||||
padding: 0 0 0 1.2em;
|
||||
}
|
||||
|
||||
#features li:before {
|
||||
content: "-";
|
||||
width: 1em;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-left: -1em;
|
||||
}
|
||||
|
||||
.rel {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.rel-note {
|
||||
margin-top: 0;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding-left: 15px;
|
||||
border-left: 2px solid #ddd;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
strong {
|
||||
text-decoration: underline;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.field {
|
||||
border: 1px solid #A21313;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
// Modified for HAProxy by HAProxy-WI
|
||||
// Modified for HAProxy by Roxy-WI
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
||||
// Defines jumpToLine command. Uses dialog.js if present.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../dialog/dialog"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../dialog/dialog"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
// default search panel location
|
||||
CodeMirror.defineOption("search", {bottom: false});
|
||||
|
||||
function dialog(cm, text, shortText, deflt, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom});
|
||||
else f(prompt(shortText, deflt));
|
||||
}
|
||||
|
||||
function getJumpDialog(cm) {
|
||||
return cm.phrase("Jump to line:") + ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">' + cm.phrase("(Use line:column or scroll% syntax)") + '</span>';
|
||||
}
|
||||
|
||||
function interpretLine(cm, string) {
|
||||
var num = Number(string)
|
||||
if (/^[-+]/.test(string)) return cm.getCursor().line + num
|
||||
else return num - 1
|
||||
}
|
||||
|
||||
CodeMirror.commands.jumpToLine = function(cm) {
|
||||
var cur = cm.getCursor();
|
||||
dialog(cm, getJumpDialog(cm), cm.phrase("Jump to line:"), (cur.line + 1) + ":" + cur.ch, function(posStr) {
|
||||
if (!posStr) return;
|
||||
|
||||
var match;
|
||||
if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
|
||||
cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
|
||||
} else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
|
||||
var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
|
||||
if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
|
||||
cm.setCursor(line - 1, cur.ch);
|
||||
} else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
|
||||
cm.setCursor(interpretLine(cm, match[1]), cur.ch);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
|
||||
});
|
|
@ -0,0 +1,155 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
// Modified for Modsec by Roxy-WI
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
CodeMirror.defineMode("modsec", function(config) {
|
||||
function words(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
var keywords = words(
|
||||
/* hapDirectiveControl */ "SecRule" +
|
||||
/* hapDirective */ " SecMarker SecAction"
|
||||
);
|
||||
var keywords_block = words(
|
||||
/* hapDirectiveBlock */ "REQUEST_FILENAME REQUEST_HEADERS REQUEST_PROTOCOL REQUEST_BASENAME REQUEST_HEADERS_NAMES HEADER_NAME ARGS_NAMES ARGS REQUEST_LINE QUERY_STRING REQUEST_BODY"
|
||||
);
|
||||
var keywords_important = words(
|
||||
/*hapDirectiveImportant */ "User-Agent TX tx msg setvar anomaly_score none warning_anomaly_score severity GET HEAD POST PROPFIND OPTIONS phase"
|
||||
);
|
||||
var indentUnit = config.indentUnit, type;
|
||||
function ret(style, tp) {type = tp; return style;}
|
||||
function tokenBase(stream, state) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
var cur = stream.current();
|
||||
if (keywords.propertyIsEnumerable(cur)) {
|
||||
return "keyword";
|
||||
}
|
||||
else if (keywords_block.propertyIsEnumerable(cur)) {
|
||||
return "variable-2";
|
||||
}
|
||||
else if (keywords_important.propertyIsEnumerable(cur)) {
|
||||
return "string-2";
|
||||
}
|
||||
var ch = stream.next();
|
||||
if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
|
||||
else if (ch == "/" && stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
}
|
||||
else if (ch == "<" && stream.eat("!")) {
|
||||
state.tokenize = tokenSGMLComment;
|
||||
return tokenSGMLComment(stream, state);
|
||||
}
|
||||
else if (ch == "=") ret(null, "compare");
|
||||
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
|
||||
else if (ch == "\"" || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
else if (ch == "!") {
|
||||
stream.match(/^\s*\w*/);
|
||||
return ret("keyword", "important");
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("number", "unit");
|
||||
}
|
||||
else if (/[,.+>*\/]/.test(ch)) {
|
||||
return ret(null, "select-op");
|
||||
}
|
||||
else if (/[;{}:\[\]]/.test(ch)) {
|
||||
return ret(null, ch);
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("variable", "variable");
|
||||
}
|
||||
}
|
||||
function tokenCComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (maybeEnd && ch == "/") {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
function tokenSGMLComment(stream, state) {
|
||||
var dashes = 0, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (dashes >= 2 && ch == ">") {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
dashes = (ch == "-") ? dashes + 1 : 0;
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && !escaped)
|
||||
break;
|
||||
escaped = !escaped && ch == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
return {
|
||||
startState: function(base) {
|
||||
return {tokenize: tokenBase,
|
||||
baseIndent: base || 0,
|
||||
stack: []};
|
||||
},
|
||||
token: function(stream, state) {
|
||||
if (stream.eatSpace()) return null;
|
||||
type = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
|
||||
var context = state.stack[state.stack.length-1];
|
||||
if (type == "hash" && context == "rule") style = "atom";
|
||||
else if (style == "variable") {
|
||||
if (context == "rule") style = "number";
|
||||
else if (!context || context == "@media{") style = "tag";
|
||||
}
|
||||
if (context == "rule" && /^[\{\};]$/.test(type))
|
||||
state.stack.pop();
|
||||
if (type == "{") {
|
||||
if (context == "@media") state.stack[state.stack.length-1] = "@media{";
|
||||
else state.stack.push("{");
|
||||
}
|
||||
else if (type == "}") state.stack.pop();
|
||||
else if (type == "@media") state.stack.push("@media");
|
||||
else if (context == "{" && type != "comment") state.stack.push("rule");
|
||||
return style;
|
||||
},
|
||||
indent: function(state, textAfter) {
|
||||
var n = state.stack.length;
|
||||
if (/^\}/.test(textAfter))
|
||||
n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
|
||||
return state.baseIndent + n * indentUnit;
|
||||
},
|
||||
|
||||
electricChars: "}"
|
||||
};
|
||||
});
|
||||
CodeMirror.defineMIME("text/x-modsec-conf", "modsec");
|
||||
});
|
|
@ -0,0 +1,292 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
||||
// Define search commands. Depends on dialog.js or another
|
||||
// implementation of the openDialog method.
|
||||
|
||||
// Replace works a little oddly -- it will do the replace on the next
|
||||
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
|
||||
// replace by making sure the match is no longer selected when hitting
|
||||
// Ctrl-G.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
// default search panel location
|
||||
CodeMirror.defineOption("search", {bottom: false});
|
||||
|
||||
function searchOverlay(query, caseInsensitive) {
|
||||
if (typeof query == "string")
|
||||
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
|
||||
else if (!query.global)
|
||||
query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
|
||||
|
||||
return {token: function(stream) {
|
||||
query.lastIndex = stream.pos;
|
||||
var match = query.exec(stream.string);
|
||||
if (match && match.index == stream.pos) {
|
||||
stream.pos += match[0].length || 1;
|
||||
return "searching";
|
||||
} else if (match) {
|
||||
stream.pos = match.index;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
function SearchState() {
|
||||
this.posFrom = this.posTo = this.lastQuery = this.query = null;
|
||||
this.overlay = null;
|
||||
}
|
||||
|
||||
function getSearchState(cm) {
|
||||
return cm.state.search || (cm.state.search = new SearchState());
|
||||
}
|
||||
|
||||
function queryCaseInsensitive(query) {
|
||||
return typeof query == "string" && query == query.toLowerCase();
|
||||
}
|
||||
|
||||
function getSearchCursor(cm, query, pos) {
|
||||
// Heuristic: if the query string is all lowercase, do a case insensitive search.
|
||||
return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true});
|
||||
}
|
||||
|
||||
function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
|
||||
cm.openDialog(text, onEnter, {
|
||||
value: deflt,
|
||||
selectValueOnOpen: true,
|
||||
closeOnEnter: false,
|
||||
onClose: function() { clearSearch(cm); },
|
||||
onKeyDown: onKeyDown,
|
||||
bottom: cm.options.search.bottom
|
||||
});
|
||||
}
|
||||
|
||||
function dialog(cm, text, shortText, deflt, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom});
|
||||
else f(prompt(shortText, deflt));
|
||||
}
|
||||
|
||||
function confirmDialog(cm, text, shortText, fs) {
|
||||
if (cm.openConfirm) cm.openConfirm(text, fs);
|
||||
else if (confirm(shortText)) fs[0]();
|
||||
}
|
||||
|
||||
function parseString(string) {
|
||||
return string.replace(/\\([nrt\\])/g, function(match, ch) {
|
||||
if (ch == "n") return "\n"
|
||||
if (ch == "r") return "\r"
|
||||
if (ch == "t") return "\t"
|
||||
if (ch == "\\") return "\\"
|
||||
return match
|
||||
})
|
||||
}
|
||||
|
||||
function parseQuery(query) {
|
||||
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
||||
if (isRE) {
|
||||
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
|
||||
catch(e) {} // Not a regular expression after all, do a string search
|
||||
} else {
|
||||
query = parseString(query)
|
||||
}
|
||||
if (typeof query == "string" ? query == "" : query.test(""))
|
||||
query = /x^/;
|
||||
return query;
|
||||
}
|
||||
|
||||
function startSearch(cm, state, query) {
|
||||
state.queryText = query;
|
||||
state.query = parseQuery(query);
|
||||
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
||||
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
|
||||
cm.addOverlay(state.overlay);
|
||||
if (cm.showMatchesOnScrollbar) {
|
||||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
|
||||
}
|
||||
}
|
||||
|
||||
function doSearch(cm, rev, persistent, immediate) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
var q = cm.getSelection() || state.lastQuery;
|
||||
if (q instanceof RegExp && q.source == "x^") q = null
|
||||
if (persistent && cm.openDialog) {
|
||||
var hiding = null
|
||||
var searchNext = function(query, event) {
|
||||
CodeMirror.e_stop(event);
|
||||
if (!query) return;
|
||||
if (query != state.queryText) {
|
||||
startSearch(cm, state, query);
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
}
|
||||
if (hiding) hiding.style.opacity = 1
|
||||
findNext(cm, event.shiftKey, function(_, to) {
|
||||
var dialog
|
||||
if (to.line < 3 && document.querySelector &&
|
||||
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
|
||||
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
|
||||
(hiding = dialog).style.opacity = .4
|
||||
})
|
||||
};
|
||||
persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) {
|
||||
var keyName = CodeMirror.keyName(event)
|
||||
var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
|
||||
if (cmd == "findNext" || cmd == "findPrev" ||
|
||||
cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
|
||||
CodeMirror.e_stop(event);
|
||||
startSearch(cm, getSearchState(cm), query);
|
||||
cm.execCommand(cmd);
|
||||
} else if (cmd == "find" || cmd == "findPersistent") {
|
||||
CodeMirror.e_stop(event);
|
||||
searchNext(query, event);
|
||||
}
|
||||
});
|
||||
if (immediate && q) {
|
||||
startSearch(cm, state, q);
|
||||
findNext(cm, rev);
|
||||
}
|
||||
} else {
|
||||
dialog(cm, getQueryDialog(cm), "Search for:", q, function(query) {
|
||||
if (query && !state.query) cm.operation(function() {
|
||||
startSearch(cm, state, query);
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
findNext(cm, rev);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function findNext(cm, rev, callback) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
|
||||
if (!cursor.find(rev)) {
|
||||
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
|
||||
if (!cursor.find(rev)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
|
||||
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
||||
if (callback) callback(cursor.from(), cursor.to())
|
||||
});}
|
||||
|
||||
function clearSearch(cm) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
state.lastQuery = state.query;
|
||||
if (!state.query) return;
|
||||
state.query = state.queryText = null;
|
||||
cm.removeOverlay(state.overlay);
|
||||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||
});}
|
||||
|
||||
function el(tag, attrs) {
|
||||
var element = tag ? document.createElement(tag) : document.createDocumentFragment();
|
||||
for (var key in attrs) {
|
||||
element[key] = attrs[key];
|
||||
}
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
var child = arguments[i]
|
||||
element.appendChild(typeof child == "string" ? document.createTextNode(child) : child);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
function getQueryDialog(cm) {
|
||||
return el("", null,
|
||||
el("span", {className: "CodeMirror-search-label"}, cm.phrase("Search:")), " ",
|
||||
el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ",
|
||||
el("span", {style: "color: #888", className: "CodeMirror-search-hint"},
|
||||
cm.phrase("(Use /re/ syntax for regexp search)")));
|
||||
}
|
||||
function getReplaceQueryDialog(cm) {
|
||||
return el("", null, " ",
|
||||
el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ",
|
||||
el("span", {style: "color: #888", className: "CodeMirror-search-hint"},
|
||||
cm.phrase("(Use /re/ syntax for regexp search)")));
|
||||
}
|
||||
function getReplacementQueryDialog(cm) {
|
||||
return el("", null,
|
||||
el("span", {className: "CodeMirror-search-label"}, cm.phrase("With:")), " ",
|
||||
el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}));
|
||||
}
|
||||
function getDoReplaceConfirm(cm) {
|
||||
return el("", null,
|
||||
el("span", {className: "CodeMirror-search-label"}, cm.phrase("Replace?")), " ",
|
||||
el("button", {}, cm.phrase("Yes")), " ",
|
||||
el("button", {}, cm.phrase("No")), " ",
|
||||
el("button", {}, cm.phrase("All")), " ",
|
||||
el("button", {}, cm.phrase("Stop")));
|
||||
}
|
||||
|
||||
function replaceAll(cm, query, text) {
|
||||
cm.operation(function() {
|
||||
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
||||
if (typeof query != "string") {
|
||||
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
||||
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||||
} else cursor.replace(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function replace(cm, all) {
|
||||
if (cm.getOption("readOnly")) return;
|
||||
var query = cm.getSelection() || getSearchState(cm).lastQuery;
|
||||
var dialogText = all ? cm.phrase("Replace all:") : cm.phrase("Replace:")
|
||||
var fragment = el("", null,
|
||||
el("span", {className: "CodeMirror-search-label"}, dialogText),
|
||||
getReplaceQueryDialog(cm))
|
||||
dialog(cm, fragment, dialogText, query, function(query) {
|
||||
if (!query) return;
|
||||
query = parseQuery(query);
|
||||
dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) {
|
||||
text = parseString(text)
|
||||
if (all) {
|
||||
replaceAll(cm, query, text)
|
||||
} else {
|
||||
clearSearch(cm);
|
||||
var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
|
||||
var advance = function() {
|
||||
var start = cursor.from(), match;
|
||||
if (!(match = cursor.findNext())) {
|
||||
cursor = getSearchCursor(cm, query);
|
||||
if (!(match = cursor.findNext()) ||
|
||||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
|
||||
confirmDialog(cm, getDoReplaceConfirm(cm), cm.phrase("Replace?"),
|
||||
[function() {doReplace(match);}, advance,
|
||||
function() {replaceAll(cm, query, text)}]);
|
||||
};
|
||||
var doReplace = function(match) {
|
||||
cursor.replace(typeof query == "string" ? text :
|
||||
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||||
advance();
|
||||
};
|
||||
advance();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|
||||
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
|
||||
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
|
||||
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
|
||||
CodeMirror.commands.findNext = doSearch;
|
||||
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
|
||||
CodeMirror.commands.clearSearch = clearSearch;
|
||||
CodeMirror.commands.replace = replace;
|
||||
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
|
||||
});
|
|
@ -0,0 +1,305 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"))
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod)
|
||||
else // Plain browser env
|
||||
mod(CodeMirror)
|
||||
})(function(CodeMirror) {
|
||||
"use strict"
|
||||
var Pos = CodeMirror.Pos
|
||||
|
||||
function regexpFlags(regexp) {
|
||||
var flags = regexp.flags
|
||||
return flags != null ? flags : (regexp.ignoreCase ? "i" : "")
|
||||
+ (regexp.global ? "g" : "")
|
||||
+ (regexp.multiline ? "m" : "")
|
||||
}
|
||||
|
||||
function ensureFlags(regexp, flags) {
|
||||
var current = regexpFlags(regexp), target = current
|
||||
for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1)
|
||||
target += flags.charAt(i)
|
||||
return current == target ? regexp : new RegExp(regexp.source, target)
|
||||
}
|
||||
|
||||
function maybeMultiline(regexp) {
|
||||
return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)
|
||||
}
|
||||
|
||||
function searchRegexpForward(doc, regexp, start) {
|
||||
regexp = ensureFlags(regexp, "g")
|
||||
for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
|
||||
regexp.lastIndex = ch
|
||||
var string = doc.getLine(line), match = regexp.exec(string)
|
||||
if (match)
|
||||
return {from: Pos(line, match.index),
|
||||
to: Pos(line, match.index + match[0].length),
|
||||
match: match}
|
||||
}
|
||||
}
|
||||
|
||||
function searchRegexpForwardMultiline(doc, regexp, start) {
|
||||
if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
|
||||
|
||||
regexp = ensureFlags(regexp, "gm")
|
||||
var string, chunk = 1
|
||||
for (var line = start.line, last = doc.lastLine(); line <= last;) {
|
||||
// This grows the search buffer in exponentially-sized chunks
|
||||
// between matches, so that nearby matches are fast and don't
|
||||
// require concatenating the whole document (in case we're
|
||||
// searching for something that has tons of matches), but at the
|
||||
// same time, the amount of retries is limited.
|
||||
for (var i = 0; i < chunk; i++) {
|
||||
if (line > last) break
|
||||
var curLine = doc.getLine(line++)
|
||||
string = string == null ? curLine : string + "\n" + curLine
|
||||
}
|
||||
chunk = chunk * 2
|
||||
regexp.lastIndex = start.ch
|
||||
var match = regexp.exec(string)
|
||||
if (match) {
|
||||
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
|
||||
var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length
|
||||
return {from: Pos(startLine, startCh),
|
||||
to: Pos(startLine + inside.length - 1,
|
||||
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
|
||||
match: match}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function lastMatchIn(string, regexp, endMargin) {
|
||||
var match, from = 0
|
||||
while (from <= string.length) {
|
||||
regexp.lastIndex = from
|
||||
var newMatch = regexp.exec(string)
|
||||
if (!newMatch) break
|
||||
var end = newMatch.index + newMatch[0].length
|
||||
if (end > string.length - endMargin) break
|
||||
if (!match || end > match.index + match[0].length)
|
||||
match = newMatch
|
||||
from = newMatch.index + 1
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
function searchRegexpBackward(doc, regexp, start) {
|
||||
regexp = ensureFlags(regexp, "g")
|
||||
for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
|
||||
var string = doc.getLine(line)
|
||||
var match = lastMatchIn(string, regexp, ch < 0 ? 0 : string.length - ch)
|
||||
if (match)
|
||||
return {from: Pos(line, match.index),
|
||||
to: Pos(line, match.index + match[0].length),
|
||||
match: match}
|
||||
}
|
||||
}
|
||||
|
||||
function searchRegexpBackwardMultiline(doc, regexp, start) {
|
||||
if (!maybeMultiline(regexp)) return searchRegexpBackward(doc, regexp, start)
|
||||
regexp = ensureFlags(regexp, "gm")
|
||||
var string, chunkSize = 1, endMargin = doc.getLine(start.line).length - start.ch
|
||||
for (var line = start.line, first = doc.firstLine(); line >= first;) {
|
||||
for (var i = 0; i < chunkSize && line >= first; i++) {
|
||||
var curLine = doc.getLine(line--)
|
||||
string = string == null ? curLine : curLine + "\n" + string
|
||||
}
|
||||
chunkSize *= 2
|
||||
|
||||
var match = lastMatchIn(string, regexp, endMargin)
|
||||
if (match) {
|
||||
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
|
||||
var startLine = line + before.length, startCh = before[before.length - 1].length
|
||||
return {from: Pos(startLine, startCh),
|
||||
to: Pos(startLine + inside.length - 1,
|
||||
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
|
||||
match: match}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var doFold, noFold
|
||||
if (String.prototype.normalize) {
|
||||
doFold = function(str) { return str.normalize("NFD").toLowerCase() }
|
||||
noFold = function(str) { return str.normalize("NFD") }
|
||||
} else {
|
||||
doFold = function(str) { return str.toLowerCase() }
|
||||
noFold = function(str) { return str }
|
||||
}
|
||||
|
||||
// Maps a position in a case-folded line back to a position in the original line
|
||||
// (compensating for codepoints increasing in number during folding)
|
||||
function adjustPos(orig, folded, pos, foldFunc) {
|
||||
if (orig.length == folded.length) return pos
|
||||
for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) {
|
||||
if (min == max) return min
|
||||
var mid = (min + max) >> 1
|
||||
var len = foldFunc(orig.slice(0, mid)).length
|
||||
if (len == pos) return mid
|
||||
else if (len > pos) max = mid
|
||||
else min = mid + 1
|
||||
}
|
||||
}
|
||||
|
||||
function searchStringForward(doc, query, start, caseFold) {
|
||||
// Empty string would match anything and never progress, so we
|
||||
// define it to match nothing instead.
|
||||
if (!query.length) return null
|
||||
var fold = caseFold ? doFold : noFold
|
||||
var lines = fold(query).split(/\r|\n\r?/)
|
||||
|
||||
search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) {
|
||||
var orig = doc.getLine(line).slice(ch), string = fold(orig)
|
||||
if (lines.length == 1) {
|
||||
var found = string.indexOf(lines[0])
|
||||
if (found == -1) continue search
|
||||
var start = adjustPos(orig, string, found, fold) + ch
|
||||
return {from: Pos(line, adjustPos(orig, string, found, fold) + ch),
|
||||
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)}
|
||||
} else {
|
||||
var cutFrom = string.length - lines[0].length
|
||||
if (string.slice(cutFrom) != lines[0]) continue search
|
||||
for (var i = 1; i < lines.length - 1; i++)
|
||||
if (fold(doc.getLine(line + i)) != lines[i]) continue search
|
||||
var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1]
|
||||
if (endString.slice(0, lastLine.length) != lastLine) continue search
|
||||
return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch),
|
||||
to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function searchStringBackward(doc, query, start, caseFold) {
|
||||
if (!query.length) return null
|
||||
var fold = caseFold ? doFold : noFold
|
||||
var lines = fold(query).split(/\r|\n\r?/)
|
||||
|
||||
search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) {
|
||||
var orig = doc.getLine(line)
|
||||
if (ch > -1) orig = orig.slice(0, ch)
|
||||
var string = fold(orig)
|
||||
if (lines.length == 1) {
|
||||
var found = string.lastIndexOf(lines[0])
|
||||
if (found == -1) continue search
|
||||
return {from: Pos(line, adjustPos(orig, string, found, fold)),
|
||||
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))}
|
||||
} else {
|
||||
var lastLine = lines[lines.length - 1]
|
||||
if (string.slice(0, lastLine.length) != lastLine) continue search
|
||||
for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++)
|
||||
if (fold(doc.getLine(start + i)) != lines[i]) continue search
|
||||
var top = doc.getLine(line + 1 - lines.length), topString = fold(top)
|
||||
if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search
|
||||
return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)),
|
||||
to: Pos(line, adjustPos(orig, string, lastLine.length, fold))}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SearchCursor(doc, query, pos, options) {
|
||||
this.atOccurrence = false
|
||||
this.afterEmptyMatch = false
|
||||
this.doc = doc
|
||||
pos = pos ? doc.clipPos(pos) : Pos(0, 0)
|
||||
this.pos = {from: pos, to: pos}
|
||||
|
||||
var caseFold
|
||||
if (typeof options == "object") {
|
||||
caseFold = options.caseFold
|
||||
} else { // Backwards compat for when caseFold was the 4th argument
|
||||
caseFold = options
|
||||
options = null
|
||||
}
|
||||
|
||||
if (typeof query == "string") {
|
||||
if (caseFold == null) caseFold = false
|
||||
this.matches = function(reverse, pos) {
|
||||
return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
|
||||
}
|
||||
} else {
|
||||
query = ensureFlags(query, "gm")
|
||||
if (!options || options.multiline !== false)
|
||||
this.matches = function(reverse, pos) {
|
||||
return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
|
||||
}
|
||||
else
|
||||
this.matches = function(reverse, pos) {
|
||||
return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchCursor.prototype = {
|
||||
findNext: function() {return this.find(false)},
|
||||
findPrevious: function() {return this.find(true)},
|
||||
|
||||
find: function(reverse) {
|
||||
var head = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
|
||||
if (this.afterEmptyMatch && this.atOccurrence) {
|
||||
// do not return the same 0 width match twice
|
||||
head = Pos(head.line, head.ch)
|
||||
if (reverse) {
|
||||
head.ch--;
|
||||
if (head.ch < 0) {
|
||||
head.line--;
|
||||
head.ch = (this.doc.getLine(head.line) || "").length;
|
||||
}
|
||||
} else {
|
||||
head.ch++;
|
||||
if (head.ch > (this.doc.getLine(head.line) || "").length) {
|
||||
head.ch = 0;
|
||||
head.line++;
|
||||
}
|
||||
}
|
||||
if (CodeMirror.cmpPos(head, this.doc.clipPos(head)) != 0) {
|
||||
return this.atOccurrence = false
|
||||
}
|
||||
}
|
||||
var result = this.matches(reverse, head)
|
||||
this.afterEmptyMatch = result && CodeMirror.cmpPos(result.from, result.to) == 0
|
||||
|
||||
if (result) {
|
||||
this.pos = result
|
||||
this.atOccurrence = true
|
||||
return this.pos.match || true
|
||||
} else {
|
||||
var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0)
|
||||
this.pos = {from: end, to: end}
|
||||
return this.atOccurrence = false
|
||||
}
|
||||
},
|
||||
|
||||
from: function() {if (this.atOccurrence) return this.pos.from},
|
||||
to: function() {if (this.atOccurrence) return this.pos.to},
|
||||
|
||||
replace: function(newText, origin) {
|
||||
if (!this.atOccurrence) return
|
||||
var lines = CodeMirror.splitLines(newText)
|
||||
this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin)
|
||||
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
|
||||
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0))
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
|
||||
return new SearchCursor(this.doc, query, pos, caseFold)
|
||||
})
|
||||
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
|
||||
return new SearchCursor(this, query, pos, caseFold)
|
||||
})
|
||||
|
||||
CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
|
||||
var ranges = []
|
||||
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold)
|
||||
while (cur.findNext()) {
|
||||
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break
|
||||
ranges.push({anchor: cur.from(), head: cur.to()})
|
||||
}
|
||||
if (ranges.length)
|
||||
this.setSelections(ranges, 0)
|
||||
})
|
||||
});
|
|
@ -293,9 +293,11 @@ function openVersions() {
|
|||
win.focus();
|
||||
}
|
||||
function showLog() {
|
||||
var waf = 0;
|
||||
if ($('#waf').is(':checked')) {
|
||||
waf = '1';
|
||||
var waf = findGetParameter('waf');
|
||||
var file = $('#log_files').val();
|
||||
if (file === null) {
|
||||
toastr.warning('Select a log file first')
|
||||
return false;
|
||||
}
|
||||
var rows = $('#rows').val()
|
||||
var grep = $('#grep').val()
|
||||
|
@ -321,15 +323,60 @@ function showLog() {
|
|||
hour1: hour1,
|
||||
minut1: minut1,
|
||||
service: service,
|
||||
file: file,
|
||||
token: $('#token').val()
|
||||
},
|
||||
type: "POST",
|
||||
success: function( data ) {
|
||||
if (data.indexOf('Internal error:') == '-1') {
|
||||
toastr.clear();
|
||||
$("#ajax").html(data);
|
||||
window.history.pushState("Logs", "Logs", cur_url[0] + "?service=" + service + "&serv=" + $("#serv").val() +
|
||||
'&rows=' + rows +
|
||||
'&exgrep=' + exgrep +
|
||||
'&grep=' + grep +
|
||||
'&hour=' + hour +
|
||||
'&minut=' + minut +
|
||||
'&hour1=' + hour1 +
|
||||
'&minut1=' + minut1 +
|
||||
'&file=' + file +
|
||||
'&waf=' + waf);
|
||||
|
||||
}
|
||||
} );
|
||||
}
|
||||
function showRemoteLogFiles() {
|
||||
let serv = $('#serv').val();
|
||||
if (serv === undefined || serv === null) {
|
||||
toastr.warning('Select a server firts');
|
||||
return false;
|
||||
}
|
||||
var rows = $('#rows').val()
|
||||
var grep = $('#grep').val()
|
||||
var exgrep = $('#exgrep').val()
|
||||
var hour = $('#time_range_out_hour').val()
|
||||
var minut = $('#time_range_out_minut').val()
|
||||
var hour1 = $('#time_range_out_hour1').val()
|
||||
var minut1 = $('#time_range_out_minut1').val()
|
||||
var service = $('#service').val()
|
||||
if (service == 'None') {
|
||||
service = 'haproxy';
|
||||
}
|
||||
$.ajax( {
|
||||
url: "options.py",
|
||||
data: {
|
||||
serv: $("#serv").val(),
|
||||
act: "showRemoteLogFiles",
|
||||
service: service,
|
||||
token: $('#token').val()
|
||||
},
|
||||
type: "POST",
|
||||
success: function( data ) {
|
||||
if (data.indexOf('error:') != '-1' || data.indexOf('ls: cannot access') != '-1') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
toastr.clear();
|
||||
$("#ajax").html(data);
|
||||
$("#remote_log_files").html(data);
|
||||
$.getScript('/inc/configshow.js');
|
||||
window.history.pushState("Logs", "Logs", cur_url[0] + "?service=" + service + "&serv=" + $("#serv").val() +
|
||||
'&rows=' + rows +
|
||||
'&exgrep=' + exgrep +
|
||||
|
@ -338,10 +385,11 @@ function showLog() {
|
|||
'&minut=' + minut +
|
||||
'&hour1=' + hour1 +
|
||||
'&minut1=' + minut1 +
|
||||
'&waf=' + waf);
|
||||
'&waf=0');
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
function clearAllAjaxFields() {
|
||||
$("#ajax").empty();
|
||||
|
@ -429,6 +477,12 @@ function showCompareConfigs() {
|
|||
function showConfig() {
|
||||
var service = $('#service').val();
|
||||
var config_file_name = encodeURI($('#config_file_name').val());
|
||||
if (service == 'nginx') {
|
||||
if ($('#config_file_name').val() === undefined || $('#config_file_name').val() === null) {
|
||||
toastr.warning('Select a config file firts');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
clearAllAjaxFields();
|
||||
$.ajax( {
|
||||
url: "options.py",
|
||||
|
@ -470,7 +524,6 @@ function showConfigFiles() {
|
|||
} else {
|
||||
toastr.clear();
|
||||
$("#ajax-config_file_name").html(data);
|
||||
$( "select" ).selectmenu();
|
||||
window.history.pushState("Show config", "Show config", cur_url[0] + "?service=" + service + "&serv=" + $("#serv").val() + "&showConfigFiles");
|
||||
}
|
||||
}
|
||||
|
@ -497,7 +550,6 @@ function showConfigFilesForEditing() {
|
|||
} else {
|
||||
toastr.clear();
|
||||
$("#ajax-config_file_name").html(data);
|
||||
$("select").selectmenu();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1298,3 +1350,25 @@ function changeUserPasswordItOwn(d) {
|
|||
} );
|
||||
}
|
||||
}
|
||||
function findInConfig() {
|
||||
clearAllAjaxFields();
|
||||
$.ajax( {
|
||||
url: "options.py",
|
||||
data: {
|
||||
serv: $("#serv").val(),
|
||||
act: "findInConfigs",
|
||||
service: $("#service").val(),
|
||||
words: $('#words').val(),
|
||||
token: $('#token').val()
|
||||
},
|
||||
type: "POST",
|
||||
success: function( data ) {
|
||||
if (data.indexOf('error:') != '-1') {
|
||||
toastr.error(data);
|
||||
} else {
|
||||
toastr.clear();
|
||||
$("#ajax").html(data);
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -307,7 +307,7 @@ $( function() {
|
|||
type: "POST",
|
||||
success: function( data ) {
|
||||
data = data.replace(/^\s+|\s+$/g,'');
|
||||
if(data.indexOf('bash') != '-1' || data.indexOf('such') != '-1') {
|
||||
if(data.indexOf('bash') != '-1' || data.indexOf('such') != '-1' || data.indexOf('command not found') != '-1') {
|
||||
$('#cur_nginx_ver').text('Nginx has not installed');
|
||||
$('#nginx_install').text('Install');
|
||||
$('#nginx_install').attr('title', 'Install Nginx');
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
<script src="/inc/toastr.js"></script>
|
||||
<script defer src="/inc/ion.sound.min.js"></script>
|
||||
<script src="/inc/provisioning.js"></script>
|
||||
<link href="/inc/select2.css" rel="stylesheet" />
|
||||
<script src="/inc/select2.js"></script>
|
||||
<meta http-equiv="refresh" content="0; url=/app/overview.py" />
|
||||
</head>
|
||||
<body style="background-color: #239dee;">
|
||||
|
|
Loading…
Reference in New Issue