commit
49bd67d3f3
5 changed files with 167 additions and 84 deletions
|
@ -43,6 +43,8 @@ The IP address the service is listening on. By default it is binding to `0.0.0.0
|
||||||
The port the service is listening on. By default it is using 3218, but you can change this if you need to.
|
The port the service is listening on. By default it is using 3218, but you can change this if you need to.
|
||||||
#### BASEPATH (string)
|
#### BASEPATH (string)
|
||||||
It is possible to place configurator.py somewhere else. Set the `BASEPATH` to something like `"/home/homeassistant/.homeassistant"`, and no matter where you are running the configurator from, it will start serving files from there. This is needed if you plan on running the configurator with systemd.
|
It is possible to place configurator.py somewhere else. Set the `BASEPATH` to something like `"/home/homeassistant/.homeassistant"`, and no matter where you are running the configurator from, it will start serving files from there. This is needed if you plan on running the configurator with systemd.
|
||||||
|
#### ENFORCE_BASEPATH (bool)
|
||||||
|
Set ENFORCE_BASEPATH to `True` to lock the configurator into the basepath and thereby prevent it from opening files outside of the BASEPATH
|
||||||
#### SSL_CERTIFICATE / SSL_KEY (string)
|
#### SSL_CERTIFICATE / SSL_KEY (string)
|
||||||
If you're using SSL, set the paths to your SSL files here. This is similar to the SSL setup you can do in HASS.
|
If you're using SSL, set the paths to your SSL files here. This is similar to the SSL setup you can do in HASS.
|
||||||
#### HASS_API (string)
|
#### HASS_API (string)
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
Version 0.2.9 (2018-06-22)
|
||||||
|
- Material Icons and HASS-help now open in new tab instead of modal (Issues #85 and #34) @danielperna84
|
||||||
|
- Open file by URL (Issue #95) @danielperna84
|
||||||
|
- Added ENFORCE_BASEPATH option (Issue #68) @danielperna84
|
||||||
|
- Cosmetic fix for scaled viewports @danielperna84
|
||||||
|
- Added search-function for entities (Issue #99) @danielperna84
|
||||||
|
- Updated Ace Editor to 1.3.3
|
||||||
|
- Updated jQuery to 3.3.1
|
||||||
|
- Updated js-yaml to 3.12.0
|
||||||
|
|
||||||
Version 0.2.8 (2018-04-23)
|
Version 0.2.8 (2018-04-23)
|
||||||
- Updated CDN libraries @jmart518
|
- Updated CDN libraries @jmart518
|
||||||
- Cosmetic improvements @jmart518
|
- Cosmetic improvements @jmart518
|
||||||
|
|
136
configurator.py
136
configurator.py
|
@ -30,6 +30,9 @@ LISTENPORT = 3218
|
||||||
# Set BASEPATH to something like "/home/hass/.homeassistant/" if you're not
|
# Set BASEPATH to something like "/home/hass/.homeassistant/" if you're not
|
||||||
# running the configurator from that path
|
# running the configurator from that path
|
||||||
BASEPATH = None
|
BASEPATH = None
|
||||||
|
# Set ENFORCE_BASEPATH to True to lock the configurator into the basepath and
|
||||||
|
# thereby prevent it from opening files outside of the BASEPATH
|
||||||
|
ENFORCE_BASEPATH = False
|
||||||
# Set the paths to a certificate and the key if you're using SSL,
|
# Set the paths to a certificate and the key if you're using SSL,
|
||||||
# e.g "/etc/ssl/certs/mycert.pem"
|
# e.g "/etc/ssl/certs/mycert.pem"
|
||||||
SSL_CERTIFICATE = None
|
SSL_CERTIFICATE = None
|
||||||
|
@ -74,7 +77,7 @@ SO.setFormatter(
|
||||||
logging.Formatter('%(levelname)s:%(asctime)s:%(name)s:%(message)s'))
|
logging.Formatter('%(levelname)s:%(asctime)s:%(name)s:%(message)s'))
|
||||||
LOG.addHandler(SO)
|
LOG.addHandler(SO)
|
||||||
RELEASEURL = "https://api.github.com/repos/danielperna84/hass-configurator/releases/latest"
|
RELEASEURL = "https://api.github.com/repos/danielperna84/hass-configurator/releases/latest"
|
||||||
VERSION = "0.2.8"
|
VERSION = "0.2.9"
|
||||||
BASEDIR = "."
|
BASEDIR = "."
|
||||||
DEV = False
|
DEV = False
|
||||||
HTTPD = None
|
HTTPD = None
|
||||||
|
@ -201,7 +204,7 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
color: #616161 !important;
|
color: #616161 !important;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 185px;
|
width: 182px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -339,7 +342,7 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
box-shadow: 0 1px 0 0 #03a9f4 !important;
|
box-shadow: 0 1px 0 0 #03a9f4 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#modal_acekeyboard, #modal_components, #modal_icons {
|
#modal_acekeyboard {
|
||||||
top: auto;
|
top: auto;
|
||||||
width: 96%;
|
width: 96%;
|
||||||
min-height: 96%;
|
min-height: 96%;
|
||||||
|
@ -575,9 +578,9 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ext-modelist.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ext-modelist.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ext-language_tools.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ext-language_tools.js" type="text/javascript" charset="utf-8"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="preloader-background">
|
<div class="preloader-background">
|
||||||
|
@ -652,10 +655,10 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<ul id="dropdown_menu" class="dropdown-content z-depth-4">
|
<ul id="dropdown_menu" class="dropdown-content z-depth-4">
|
||||||
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.href, '_blank');">New tab</a></li>
|
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.origin+window.location.pathname, '_blank');">New tab</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li><a class="modal-trigger" target="_blank" href="#modal_components">Components</a></li>
|
<li><a target="_blank" href="https://home-assistant.io/components/">Components</a></li>
|
||||||
<li><a class="modal-trigger" target="_blank" href="#modal_icons">Material Icons</a></li>
|
<li><a target="_blank" href="https://materialdesignicons.com/">Material Icons</a></li>
|
||||||
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
|
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
|
||||||
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
|
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
|
||||||
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
|
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
|
||||||
|
@ -671,7 +674,7 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
<li><a class="modal-trigger" href="#modal_exec_command">Execute shell command</a></li>
|
<li><a class="modal-trigger" href="#modal_exec_command">Execute shell command</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul id="dropdown_menu_mobile" class="dropdown-content z-depth-4">
|
<ul id="dropdown_menu_mobile" class="dropdown-content z-depth-4">
|
||||||
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.href, '_blank');">New tab</a></li>
|
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.origin+window.location.pathname, '_blank');">New tab</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li><a target="_blank" href="https://home-assistant.io/help/">Help</a></li>
|
<li><a target="_blank" href="https://home-assistant.io/help/">Help</a></li>
|
||||||
<li><a target="_blank" href="https://home-assistant.io/components/">Components</a></li>
|
<li><a target="_blank" href="https://home-assistant.io/components/">Components</a></li>
|
||||||
|
@ -700,24 +703,6 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
<li><a class="modal-trigger" href="#modal_commit" class="nowrap waves-effect">git commit</a></li>
|
<li><a class="modal-trigger" href="#modal_commit" class="nowrap waves-effect">git commit</a></li>
|
||||||
<li><a class="modal-trigger" href="#modal_push" class="nowrap waves-effect">git push</a></li>
|
<li><a class="modal-trigger" href="#modal_push" class="nowrap waves-effect">git push</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div id="modal_components" class="modal bottom-sheet modal-fixed-footer">
|
|
||||||
<div class="modal-content_nopad">
|
|
||||||
<iframe src="https://home-assistant.io/components/" style="height: 90vh; width: 100vw"> </iframe>
|
|
||||||
<a target="_blank" href="https://home-assistant.io/components/" class="hide-on-med-and-down modal_btn waves-effect btn-large btn-flat left"><i class="material-icons">launch</i></a>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a class="modal-action modal-close waves-effect btn-flat Right light-blue-text">Close</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="modal_icons" class="modal bottom-sheet modal-fixed-footer">
|
|
||||||
<div class="modal-content_nopad">
|
|
||||||
<iframe src="https://materialdesignicons.com/" style="height: 90vh; width: 100vw"> </iframe>
|
|
||||||
<a target="_blank" href="https://materialdesignicons.com/" class="hide-on-med-and-down modal_btn waves-effect btn-large btn-flat left"><i class="material-icons">launch</i></a>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a class="modal-action modal-close waves-effect btn-flat Right light-blue-text">Close</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="modal_acekeyboard" class="modal bottom-sheet modal-fixed-footer">
|
<div id="modal_acekeyboard" class="modal bottom-sheet modal-fixed-footer">
|
||||||
<div class="modal-content centered">
|
<div class="modal-content centered">
|
||||||
<h4 class="grey-text text-darken-3">Ace Keyboard Shortcuts<i class="mdi mdi-keyboard right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
|
<h4 class="grey-text text-darken-3">Ace Keyboard Shortcuts<i class="mdi mdi-keyboard right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
|
||||||
|
@ -1684,6 +1669,10 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
<select id="events" onchange="insert(this.value)"></select>
|
<select id="events" onchange="insert(this.value)"></select>
|
||||||
<label>Events</label>
|
<label>Events</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="input-field col s12">
|
||||||
|
<input type="text" id="entities-search" class="autocomplete" placeholder="sensor.example">
|
||||||
|
<label>Search entity</label>
|
||||||
|
</div>
|
||||||
<div class="input-field col s12">
|
<div class="input-field col s12">
|
||||||
<select id="entities" onchange="insert(this.value)"></select>
|
<select id="entities" onchange="insert(this.value)"></select>
|
||||||
<label>Entities</label>
|
<label>Entities</label>
|
||||||
|
@ -1783,6 +1772,10 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
<select id="events_side" onchange="insert(this.value)"></select>
|
<select id="events_side" onchange="insert(this.value)"></select>
|
||||||
<label>Events</label>
|
<label>Events</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="input-field col s12">
|
||||||
|
<input type="text" id="entities-search_side" class="autocomplete" placeholder="sensor.example">
|
||||||
|
<label>Search entity</label>
|
||||||
|
</div>
|
||||||
<div class="input-field col s12">
|
<div class="input-field col s12">
|
||||||
<select id="entities_side" onchange="insert(this.value)"></select>
|
<select id="entities_side" onchange="insert(this.value)"></select>
|
||||||
<label>Entities</label>
|
<label>Entities</label>
|
||||||
|
@ -2114,14 +2107,14 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
<input id="wrap_limit" type="number" onchange="editor.setOption('wrap', parseInt(this.value))" min="1" value="80">
|
<input id="wrap_limit" type="number" onchange="editor.setOption('wrap', parseInt(this.value))" min="1" value="80">
|
||||||
<label class="active" for="wrap_limit">Wrap Limit</label>
|
<label class="active" for="wrap_limit">Wrap Limit</label>
|
||||||
</div> <a class="waves-effect waves-light btn light-blue" onclick="save_ace_settings()">Save Settings Locally</a>
|
</div> <a class="waves-effect waves-light btn light-blue" onclick="save_ace_settings()">Save Settings Locally</a>
|
||||||
<p class="center col s12"> Ace Editor 1.2.9 </p>
|
<p class="center col s12"> Ace Editor 1.3.3 </p>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<input type="hidden" id="fb_currentfile" value="" />
|
<input type="hidden" id="fb_currentfile" value="" />
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function ws_connect() {
|
function ws_connect() {
|
||||||
|
@ -2175,6 +2168,7 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
var init_loadfile = $loadfile;
|
||||||
var global_current_filepath = null;
|
var global_current_filepath = null;
|
||||||
var global_current_filename = null;
|
var global_current_filename = null;
|
||||||
|
|
||||||
|
@ -2276,23 +2270,51 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
$(document).on('click', '.drag-target', function(){$('.button-collapse').sideNav('hide');})
|
$(document).on('click', '.drag-target', function(){$('.button-collapse').sideNav('hide');})
|
||||||
listdir('.');
|
listdir('.');
|
||||||
document.getElementById('savePrompt').checked = get_save_prompt();
|
document.getElementById('savePrompt').checked = get_save_prompt();
|
||||||
|
var entities_search = new Object();
|
||||||
|
if (states_list) {
|
||||||
|
for (var i = 0; i < states_list.length; i++) {
|
||||||
|
entities_search[states_list[i].attributes.friendly_name + ' (' + states_list[i].entity_id + ')'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#entities-search').autocomplete({
|
||||||
|
data: entities_search,
|
||||||
|
limit: 40,
|
||||||
|
onAutocomplete: function(val) {
|
||||||
|
insert(val.split("(")[1].split(")")[0]);
|
||||||
|
},
|
||||||
|
minLength: 1,
|
||||||
|
});
|
||||||
|
$('#entities-search_side').autocomplete({
|
||||||
|
data: entities_search,
|
||||||
|
limit: 40,
|
||||||
|
onAutocomplete: function(val) {
|
||||||
|
insert(val.split("(")[1].split(")")[0]);
|
||||||
|
},
|
||||||
|
minLength: 1,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
$('.preloader-background').delay(800).fadeOut('slow');
|
$('.preloader-background').delay(800).fadeOut('slow');
|
||||||
$('.preloader-wrapper').delay(800).fadeOut('slow');
|
$('.preloader-wrapper').delay(800).fadeOut('slow');
|
||||||
if (!localStorage.getItem("new_tab")) {
|
if (init_loadfile) {
|
||||||
var old_file = localStorage.getItem("current_file");
|
init_loadfile_name = init_loadfile.split('/').pop();
|
||||||
if (old_file) {
|
loadfile(init_loadfile, init_loadfile_name);
|
||||||
old_file = JSON.parse(old_file);
|
|
||||||
loadfile(old_file.current_filepath, old_file.current_filename);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
localStorage.removeItem("current_file");
|
if (!localStorage.getItem("new_tab")) {
|
||||||
|
var old_file = localStorage.getItem("current_file");
|
||||||
|
if (old_file) {
|
||||||
|
old_file = JSON.parse(old_file);
|
||||||
|
loadfile(old_file.current_filepath, old_file.current_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
localStorage.removeItem("current_file");
|
||||||
|
}
|
||||||
|
localStorage.removeItem("new_tab");
|
||||||
}
|
}
|
||||||
localStorage.removeItem("new_tab");
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
@ -2398,7 +2420,12 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
|
|
||||||
function listdir(path) {
|
function listdir(path) {
|
||||||
$.get(encodeURI("api/listdir?path=" + path), function(data) {
|
$.get(encodeURI("api/listdir?path=" + path), function(data) {
|
||||||
renderpath(data);
|
if (!data.error) {
|
||||||
|
renderpath(data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("Permission denied.");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
document.getElementById("slide-out").scrollTop = 0;
|
document.getElementById("slide-out").scrollTop = 0;
|
||||||
}
|
}
|
||||||
|
@ -3264,7 +3291,7 @@ INDEX = Template(r"""<!DOCTYPE html>
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.10.0/js-yaml.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.12.0/js-yaml.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var lint_timeout;
|
var lint_timeout;
|
||||||
var lint_status = $('#lint-status'); // speed optimization
|
var lint_status = $('#lint-status'); // speed optimization
|
||||||
|
@ -3325,7 +3352,7 @@ def signal_handler(sig, frame):
|
||||||
def load_settings(settingsfile):
|
def load_settings(settingsfile):
|
||||||
global LISTENIP, LISTENPORT, BASEPATH, SSL_CERTIFICATE, SSL_KEY, HASS_API, \
|
global LISTENIP, LISTENPORT, BASEPATH, SSL_CERTIFICATE, SSL_KEY, HASS_API, \
|
||||||
HASS_API_PASSWORD, CREDENTIALS, ALLOWED_NETWORKS, BANNED_IPS, BANLIMIT, \
|
HASS_API_PASSWORD, CREDENTIALS, ALLOWED_NETWORKS, BANNED_IPS, BANLIMIT, \
|
||||||
DEV, IGNORE_PATTERN, DIRSFIRST, SESAME, VERIFY_HOSTNAME
|
DEV, IGNORE_PATTERN, DIRSFIRST, SESAME, VERIFY_HOSTNAME, ENFORCE_BASEPATH
|
||||||
try:
|
try:
|
||||||
if os.path.isfile(settingsfile):
|
if os.path.isfile(settingsfile):
|
||||||
with open(settingsfile) as fptr:
|
with open(settingsfile) as fptr:
|
||||||
|
@ -3333,6 +3360,7 @@ def load_settings(settingsfile):
|
||||||
LISTENIP = settings.get("LISTENIP", LISTENIP)
|
LISTENIP = settings.get("LISTENIP", LISTENIP)
|
||||||
LISTENPORT = settings.get("LISTENPORT", LISTENPORT)
|
LISTENPORT = settings.get("LISTENPORT", LISTENPORT)
|
||||||
BASEPATH = settings.get("BASEPATH", BASEPATH)
|
BASEPATH = settings.get("BASEPATH", BASEPATH)
|
||||||
|
ENFORCE_BASEPATH = settings.get("ENFORCE_BASEPATH", ENFORCE_BASEPATH)
|
||||||
SSL_CERTIFICATE = settings.get("SSL_CERTIFICATE", SSL_CERTIFICATE)
|
SSL_CERTIFICATE = settings.get("SSL_CERTIFICATE", SSL_CERTIFICATE)
|
||||||
SSL_KEY = settings.get("SSL_KEY", SSL_KEY)
|
SSL_KEY = settings.get("SSL_KEY", SSL_KEY)
|
||||||
HASS_API = settings.get("HASS_API", HASS_API)
|
HASS_API = settings.get("HASS_API", HASS_API)
|
||||||
|
@ -3351,6 +3379,11 @@ def load_settings(settingsfile):
|
||||||
LOG.warning("Not loading static settings")
|
LOG.warning("Not loading static settings")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def is_safe_path(basedir, path, follow_symlinks=True):
|
||||||
|
if follow_symlinks:
|
||||||
|
return os.path.realpath(path).startswith(basedir)
|
||||||
|
return os.path.abspath(path).startswith(basedir)
|
||||||
|
|
||||||
def get_dircontent(path, repo=None):
|
def get_dircontent(path, repo=None):
|
||||||
dircontent = []
|
dircontent = []
|
||||||
if repo:
|
if repo:
|
||||||
|
@ -3487,6 +3520,8 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||||
try:
|
try:
|
||||||
if filename:
|
if filename:
|
||||||
filename = unquote(filename[0]).encode('utf-8')
|
filename = unquote(filename[0]).encode('utf-8')
|
||||||
|
if ENFORCE_BASEPATH and not is_safe_path(BASEPATH.encode('utf-8'), filename):
|
||||||
|
raise OSError('Access denied.')
|
||||||
if os.path.isfile(os.path.join(BASEDIR.encode('utf-8'), filename)):
|
if os.path.isfile(os.path.join(BASEDIR.encode('utf-8'), filename)):
|
||||||
with open(os.path.join(BASEDIR.encode('utf-8'), filename)) as fptr:
|
with open(os.path.join(BASEDIR.encode('utf-8'), filename)) as fptr:
|
||||||
content += fptr.read()
|
content += fptr.read()
|
||||||
|
@ -3503,6 +3538,8 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||||
try:
|
try:
|
||||||
if filename:
|
if filename:
|
||||||
filename = unquote(filename[0]).encode('utf-8')
|
filename = unquote(filename[0]).encode('utf-8')
|
||||||
|
if ENFORCE_BASEPATH and not is_safe_path(BASEPATH.encode('utf-8'), filename):
|
||||||
|
raise OSError('Access denied.')
|
||||||
LOG.info(filename)
|
LOG.info(filename)
|
||||||
if os.path.isfile(os.path.join(BASEDIR.encode('utf-8'), filename)):
|
if os.path.isfile(os.path.join(BASEDIR.encode('utf-8'), filename)):
|
||||||
with open(os.path.join(BASEDIR.encode('utf-8'), filename), 'rb') as fptr:
|
with open(os.path.join(BASEDIR.encode('utf-8'), filename), 'rb') as fptr:
|
||||||
|
@ -3520,7 +3557,7 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||||
self.wfile.write(bytes(content, "utf8"))
|
self.wfile.write(bytes(content, "utf8"))
|
||||||
return
|
return
|
||||||
elif req.path.endswith('/api/listdir'):
|
elif req.path.endswith('/api/listdir'):
|
||||||
content = ""
|
content = {'error': None}
|
||||||
self.send_header('Content-type', 'text/json')
|
self.send_header('Content-type', 'text/json')
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
dirpath = query.get('path', None)
|
dirpath = query.get('path', None)
|
||||||
|
@ -3528,6 +3565,8 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||||
if dirpath:
|
if dirpath:
|
||||||
dirpath = unquote(dirpath[0]).encode('utf-8')
|
dirpath = unquote(dirpath[0]).encode('utf-8')
|
||||||
if os.path.isdir(dirpath):
|
if os.path.isdir(dirpath):
|
||||||
|
if ENFORCE_BASEPATH and not is_safe_path(BASEPATH.encode('utf-8'), dirpath):
|
||||||
|
raise OSError('Access denied.')
|
||||||
repo = None
|
repo = None
|
||||||
activebranch = None
|
activebranch = None
|
||||||
dirty = False
|
dirty = False
|
||||||
|
@ -3547,13 +3586,14 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||||
'parent': os.path.dirname(os.path.abspath(dirpath)).decode('utf-8'),
|
'parent': os.path.dirname(os.path.abspath(dirpath)).decode('utf-8'),
|
||||||
'branches': branches,
|
'branches': branches,
|
||||||
'activebranch': activebranch,
|
'activebranch': activebranch,
|
||||||
'dirty': dirty
|
'dirty': dirty,
|
||||||
|
'error': None
|
||||||
}
|
}
|
||||||
self.wfile.write(bytes(json.dumps(filedata), "utf8"))
|
self.wfile.write(bytes(json.dumps(filedata), "utf8"))
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
LOG.warning(err)
|
LOG.warning(err)
|
||||||
content = str(err)
|
content['error'] = str(err)
|
||||||
self.wfile.write(bytes(content, "utf8"))
|
self.wfile.write(bytes(json.dumps(content), "utf8"))
|
||||||
return
|
return
|
||||||
elif req.path.endswith('/api/abspath'):
|
elif req.path.endswith('/api/abspath'):
|
||||||
content = ""
|
content = ""
|
||||||
|
@ -3715,6 +3755,11 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||||
self.send_header('Content-type', 'text/html')
|
self.send_header('Content-type', 'text/html')
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
|
loadfile = query.get('loadfile', [None])[0]
|
||||||
|
if loadfile is None:
|
||||||
|
loadfile = 'null'
|
||||||
|
else:
|
||||||
|
loadfile = "'%s'" % loadfile
|
||||||
services = "[]"
|
services = "[]"
|
||||||
events = "[]"
|
events = "[]"
|
||||||
states = "[]"
|
states = "[]"
|
||||||
|
@ -3759,6 +3804,7 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||||
html = get_html().safe_substitute(services=services,
|
html = get_html().safe_substitute(services=services,
|
||||||
events=events,
|
events=events,
|
||||||
states=states,
|
states=states,
|
||||||
|
loadfile=loadfile,
|
||||||
current=VERSION,
|
current=VERSION,
|
||||||
versionclass=color,
|
versionclass=color,
|
||||||
separator="\%s" % os.sep if os.sep == "\\" else os.sep,
|
separator="\%s" % os.sep if os.sep == "\\" else os.sep,
|
||||||
|
|
102
dev.html
102
dev.html
|
@ -114,7 +114,7 @@
|
||||||
color: #616161 !important;
|
color: #616161 !important;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 185px;
|
width: 182px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -252,7 +252,7 @@
|
||||||
box-shadow: 0 1px 0 0 #03a9f4 !important;
|
box-shadow: 0 1px 0 0 #03a9f4 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#modal_acekeyboard, #modal_components, #modal_icons {
|
#modal_acekeyboard {
|
||||||
top: auto;
|
top: auto;
|
||||||
width: 96%;
|
width: 96%;
|
||||||
min-height: 96%;
|
min-height: 96%;
|
||||||
|
@ -488,9 +488,9 @@
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ext-modelist.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ext-modelist.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ext-language_tools.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ext-language_tools.js" type="text/javascript" charset="utf-8"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="preloader-background">
|
<div class="preloader-background">
|
||||||
|
@ -565,10 +565,10 @@
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<ul id="dropdown_menu" class="dropdown-content z-depth-4">
|
<ul id="dropdown_menu" class="dropdown-content z-depth-4">
|
||||||
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.href, '_blank');">New tab</a></li>
|
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.origin+window.location.pathname, '_blank');">New tab</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li><a class="modal-trigger" target="_blank" href="#modal_components">Components</a></li>
|
<li><a target="_blank" href="https://home-assistant.io/components/">Components</a></li>
|
||||||
<li><a class="modal-trigger" target="_blank" href="#modal_icons">Material Icons</a></li>
|
<li><a target="_blank" href="https://materialdesignicons.com/">Material Icons</a></li>
|
||||||
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
|
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
|
||||||
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
|
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
|
||||||
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
|
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
|
||||||
|
@ -584,7 +584,7 @@
|
||||||
<li><a class="modal-trigger" href="#modal_exec_command">Execute shell command</a></li>
|
<li><a class="modal-trigger" href="#modal_exec_command">Execute shell command</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul id="dropdown_menu_mobile" class="dropdown-content z-depth-4">
|
<ul id="dropdown_menu_mobile" class="dropdown-content z-depth-4">
|
||||||
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.href, '_blank');">New tab</a></li>
|
<li><a onclick="localStorage.setItem('new_tab', true);window.open(window.location.origin+window.location.pathname, '_blank');">New tab</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li><a target="_blank" href="https://home-assistant.io/help/">Help</a></li>
|
<li><a target="_blank" href="https://home-assistant.io/help/">Help</a></li>
|
||||||
<li><a target="_blank" href="https://home-assistant.io/components/">Components</a></li>
|
<li><a target="_blank" href="https://home-assistant.io/components/">Components</a></li>
|
||||||
|
@ -613,24 +613,6 @@
|
||||||
<li><a class="modal-trigger" href="#modal_commit" class="nowrap waves-effect">git commit</a></li>
|
<li><a class="modal-trigger" href="#modal_commit" class="nowrap waves-effect">git commit</a></li>
|
||||||
<li><a class="modal-trigger" href="#modal_push" class="nowrap waves-effect">git push</a></li>
|
<li><a class="modal-trigger" href="#modal_push" class="nowrap waves-effect">git push</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div id="modal_components" class="modal bottom-sheet modal-fixed-footer">
|
|
||||||
<div class="modal-content_nopad">
|
|
||||||
<iframe src="https://home-assistant.io/components/" style="height: 90vh; width: 100vw"> </iframe>
|
|
||||||
<a target="_blank" href="https://home-assistant.io/components/" class="hide-on-med-and-down modal_btn waves-effect btn-large btn-flat left"><i class="material-icons">launch</i></a>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a class="modal-action modal-close waves-effect btn-flat Right light-blue-text">Close</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="modal_icons" class="modal bottom-sheet modal-fixed-footer">
|
|
||||||
<div class="modal-content_nopad">
|
|
||||||
<iframe src="https://materialdesignicons.com/" style="height: 90vh; width: 100vw"> </iframe>
|
|
||||||
<a target="_blank" href="https://materialdesignicons.com/" class="hide-on-med-and-down modal_btn waves-effect btn-large btn-flat left"><i class="material-icons">launch</i></a>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a class="modal-action modal-close waves-effect btn-flat Right light-blue-text">Close</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="modal_acekeyboard" class="modal bottom-sheet modal-fixed-footer">
|
<div id="modal_acekeyboard" class="modal bottom-sheet modal-fixed-footer">
|
||||||
<div class="modal-content centered">
|
<div class="modal-content centered">
|
||||||
<h4 class="grey-text text-darken-3">Ace Keyboard Shortcuts<i class="mdi mdi-keyboard right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
|
<h4 class="grey-text text-darken-3">Ace Keyboard Shortcuts<i class="mdi mdi-keyboard right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
|
||||||
|
@ -1597,6 +1579,10 @@
|
||||||
<select id="events" onchange="insert(this.value)"></select>
|
<select id="events" onchange="insert(this.value)"></select>
|
||||||
<label>Events</label>
|
<label>Events</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="input-field col s12">
|
||||||
|
<input type="text" id="entities-search" class="autocomplete" placeholder="sensor.example">
|
||||||
|
<label>Search entity</label>
|
||||||
|
</div>
|
||||||
<div class="input-field col s12">
|
<div class="input-field col s12">
|
||||||
<select id="entities" onchange="insert(this.value)"></select>
|
<select id="entities" onchange="insert(this.value)"></select>
|
||||||
<label>Entities</label>
|
<label>Entities</label>
|
||||||
|
@ -1696,6 +1682,10 @@
|
||||||
<select id="events_side" onchange="insert(this.value)"></select>
|
<select id="events_side" onchange="insert(this.value)"></select>
|
||||||
<label>Events</label>
|
<label>Events</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="input-field col s12">
|
||||||
|
<input type="text" id="entities-search_side" class="autocomplete" placeholder="sensor.example">
|
||||||
|
<label>Search entity</label>
|
||||||
|
</div>
|
||||||
<div class="input-field col s12">
|
<div class="input-field col s12">
|
||||||
<select id="entities_side" onchange="insert(this.value)"></select>
|
<select id="entities_side" onchange="insert(this.value)"></select>
|
||||||
<label>Entities</label>
|
<label>Entities</label>
|
||||||
|
@ -2027,14 +2017,14 @@
|
||||||
<input id="wrap_limit" type="number" onchange="editor.setOption('wrap', parseInt(this.value))" min="1" value="80">
|
<input id="wrap_limit" type="number" onchange="editor.setOption('wrap', parseInt(this.value))" min="1" value="80">
|
||||||
<label class="active" for="wrap_limit">Wrap Limit</label>
|
<label class="active" for="wrap_limit">Wrap Limit</label>
|
||||||
</div> <a class="waves-effect waves-light btn light-blue" onclick="save_ace_settings()">Save Settings Locally</a>
|
</div> <a class="waves-effect waves-light btn light-blue" onclick="save_ace_settings()">Save Settings Locally</a>
|
||||||
<p class="center col s12"> Ace Editor 1.2.9 </p>
|
<p class="center col s12"> Ace Editor 1.3.3 </p>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<input type="hidden" id="fb_currentfile" value="" />
|
<input type="hidden" id="fb_currentfile" value="" />
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function ws_connect() {
|
function ws_connect() {
|
||||||
|
@ -2088,6 +2078,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
var init_loadfile = $loadfile;
|
||||||
var global_current_filepath = null;
|
var global_current_filepath = null;
|
||||||
var global_current_filename = null;
|
var global_current_filename = null;
|
||||||
|
|
||||||
|
@ -2189,23 +2180,51 @@
|
||||||
$(document).on('click', '.drag-target', function(){$('.button-collapse').sideNav('hide');})
|
$(document).on('click', '.drag-target', function(){$('.button-collapse').sideNav('hide');})
|
||||||
listdir('.');
|
listdir('.');
|
||||||
document.getElementById('savePrompt').checked = get_save_prompt();
|
document.getElementById('savePrompt').checked = get_save_prompt();
|
||||||
|
var entities_search = new Object();
|
||||||
|
if (states_list) {
|
||||||
|
for (var i = 0; i < states_list.length; i++) {
|
||||||
|
entities_search[states_list[i].attributes.friendly_name + ' (' + states_list[i].entity_id + ')'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#entities-search').autocomplete({
|
||||||
|
data: entities_search,
|
||||||
|
limit: 40,
|
||||||
|
onAutocomplete: function(val) {
|
||||||
|
insert(val.split("(")[1].split(")")[0]);
|
||||||
|
},
|
||||||
|
minLength: 1,
|
||||||
|
});
|
||||||
|
$('#entities-search_side').autocomplete({
|
||||||
|
data: entities_search,
|
||||||
|
limit: 40,
|
||||||
|
onAutocomplete: function(val) {
|
||||||
|
insert(val.split("(")[1].split(")")[0]);
|
||||||
|
},
|
||||||
|
minLength: 1,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
$('.preloader-background').delay(800).fadeOut('slow');
|
$('.preloader-background').delay(800).fadeOut('slow');
|
||||||
$('.preloader-wrapper').delay(800).fadeOut('slow');
|
$('.preloader-wrapper').delay(800).fadeOut('slow');
|
||||||
if (!localStorage.getItem("new_tab")) {
|
if (init_loadfile) {
|
||||||
var old_file = localStorage.getItem("current_file");
|
init_loadfile_name = init_loadfile.split('/').pop();
|
||||||
if (old_file) {
|
loadfile(init_loadfile, init_loadfile_name);
|
||||||
old_file = JSON.parse(old_file);
|
|
||||||
loadfile(old_file.current_filepath, old_file.current_filename);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
localStorage.removeItem("current_file");
|
if (!localStorage.getItem("new_tab")) {
|
||||||
|
var old_file = localStorage.getItem("current_file");
|
||||||
|
if (old_file) {
|
||||||
|
old_file = JSON.parse(old_file);
|
||||||
|
loadfile(old_file.current_filepath, old_file.current_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
localStorage.removeItem("current_file");
|
||||||
|
}
|
||||||
|
localStorage.removeItem("new_tab");
|
||||||
}
|
}
|
||||||
localStorage.removeItem("new_tab");
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
@ -2311,7 +2330,12 @@
|
||||||
|
|
||||||
function listdir(path) {
|
function listdir(path) {
|
||||||
$.get(encodeURI("api/listdir?path=" + path), function(data) {
|
$.get(encodeURI("api/listdir?path=" + path), function(data) {
|
||||||
renderpath(data);
|
if (!data.error) {
|
||||||
|
renderpath(data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("Permission denied.");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
document.getElementById("slide-out").scrollTop = 0;
|
document.getElementById("slide-out").scrollTop = 0;
|
||||||
}
|
}
|
||||||
|
@ -3177,7 +3201,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.10.0/js-yaml.js" type="text/javascript" charset="utf-8"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.12.0/js-yaml.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var lint_timeout;
|
var lint_timeout;
|
||||||
var lint_status = $('#lint-status'); // speed optimization
|
var lint_status = $('#lint-status'); // speed optimization
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"LISTENIP": "0.0.0.0",
|
"LISTENIP": "0.0.0.0",
|
||||||
"LISTENPORT": 3218,
|
"LISTENPORT": 3218,
|
||||||
"BASEPATH": null,
|
"BASEPATH": null,
|
||||||
|
"ENFORCE_BASEPATH": false,
|
||||||
"SSL_CERTIFICATE": null,
|
"SSL_CERTIFICATE": null,
|
||||||
"SSL_KEY": null,
|
"SSL_KEY": null,
|
||||||
"HASS_API": "http://127.0.0.1:8123/api/",
|
"HASS_API": "http://127.0.0.1:8123/api/",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue