diff --git a/hyperglass/render/webassets.py b/hyperglass/render/webassets.py
index 7fc9a68..d9b1f5d 100644
--- a/hyperglass/render/webassets.py
+++ b/hyperglass/render/webassets.py
@@ -24,6 +24,20 @@ env = jinja2.Environment(
)
+def render_frontend_config():
+ """
+ Renders user config to JSON file so front end config can be used by
+ Javascript
+ """
+ rendered_frontend_file = hyperglass_root.joinpath("static/frontend.json")
+ try:
+ with rendered_frontend_file.open(mode="w") as frontend_file:
+ frontend_file.write(params.json())
+ except jinja2.exceptions as frontend_error:
+ logger.error(f"Error rendering front end config: {frontend_error}")
+ raise HyperglassError(frontend_error)
+
+
def render_theme():
"""Renders Jinja2 template to Sass file"""
rendered_theme_file = hyperglass_root.joinpath("static/theme.sass")
@@ -63,6 +77,12 @@ def build_assets():
def render_assets():
"""Controller function for rendering sass theme elements and building web assets"""
+ try:
+ logger.debug("Rendering front end config...")
+ render_frontend_config()
+ logger.debug("Rendered front end config")
+ except HyperglassError as frontend_error:
+ raise HyperglassError(frontend_error)
try:
logger.debug("Rendering theme elements...")
render_theme()
diff --git a/hyperglass/static/.gitignore b/hyperglass/static/.gitignore
index ae08843..cff9800 100644
--- a/hyperglass/static/.gitignore
+++ b/hyperglass/static/.gitignore
@@ -7,3 +7,5 @@ old/
yarn-error.log
theme.sass
test*
+frontend.js
+frontend.json
diff --git a/hyperglass/static/hyperglass.es6 b/hyperglass/static/hyperglass.es6
index 66c6dea..99f478a 100644
--- a/hyperglass/static/hyperglass.es6
+++ b/hyperglass/static/hyperglass.es6
@@ -6,11 +6,14 @@ const bootstrap = require('bootstrap');
const selectpicker = require('bootstrap-select');
const animsition = require('animsition');
const ClipboardJS = require('clipboard');
+const frontEndConfig = require('./frontend.json');
+const inputMessages = frontEndConfig.messages;
const queryLocation = $('#location');
const queryType = $('#query_type');
const queryTarget = $('#query_target');
const queryTargetAppend = $('#hg-target-append');
+const submitIcon = $('#hg-submit-icon');
const resultsContainer = $('#hg-results');
const formContainer = $('#hg-form');
const resultsAccordion = $('#hg-accordion');
@@ -20,6 +23,16 @@ const footerTermsBtn = $('#hg-footer-terms-btn');
const footerCreditBtn = $('#hg-footer-credit-btn');
const footerPopoverTemplate = '
';
+class InputInvalid extends Error {
+ constructor(validationMsg, invalidField, fieldContainer) {
+ super(validationMsg, invalidField, fieldContainer);
+ this.name = this.constructor.name;
+ this.message = validationMsg;
+ this.field = invalidField;
+ this.container = fieldContainer;
+ }
+}
+
const resetResults = () => {
queryLocation.selectpicker('deselectAll');
queryLocation.selectpicker('val', '');
@@ -27,6 +40,7 @@ const resetResults = () => {
queryTarget.val('');
resultsContainer.animsition('out', formContainer, '#');
resultsContainer.hide();
+ $('.hg-info-btn').remove();
formContainer.show();
formContainer.animsition('in');
backButton.addClass('d-none');
@@ -93,7 +107,6 @@ $(document).ready(() => {
outDuration: 800,
transition: (url) => { window.location.href = url; },
});
-
formContainer.animsition('in');
});
@@ -117,7 +130,7 @@ const queryApp = (queryType, queryTypeName, locationList, queryTarget) => {
$('#hg-results-title').html(resultsTitle);
- $('#hg-submit-icon').empty().removeClass('hg-loading').html('
');
+ submitIcon.empty().removeClass('hg-loading').html('
');
$.each(locationList, (n, loc) => {
const locationName = $(`#${loc}`).data('display-name');
@@ -227,15 +240,51 @@ const queryApp = (queryType, queryTypeName, locationList, queryTarget) => {
});
};
+$(document).on('InvalidInputEvent', (e, domField) => {
+ console.log('event triggered');
+ const errorField = $(domField);
+ console.log(errorField);
+ if (errorField.hasClass('is-invalid')) {
+ console.log('has class');
+ errorField.on('keyup', () => {
+ console.log('keyup');
+ errorField.removeClass('is-invalid');
+ errorField.nextAll('.invalid-feedback').remove();
+ });
+ }
+});
+
+
// Submit Form Action
$('#lgForm').submit((event) => {
event.preventDefault();
- $('#hg-submit-icon').empty().html('
').addClass('hg-loading');
+ submitIcon.empty().html('
').addClass('hg-loading');
const queryType = $('#query_type').val();
- const queryTypeTitle = $(`#${queryType}`).data('display-name');
const queryLocation = $('#location').val();
const queryTarget = $('#query_target').val();
+ try {
+ // message, thing to circle in red, place to put error text
+ if (!queryTarget) {
+ const queryTargetContainer = $('#query_target');
+ throw new InputInvalid(inputMessages.no_input, queryTargetContainer, queryTargetContainer.parent());
+ }
+ if (!queryType) {
+ const queryTypeContainer = $('#query_type').next('.dropdown-toggle');
+ throw new InputInvalid(inputMessages.no_query_type, queryTypeContainer, queryTypeContainer.parent());
+ }
+ if (queryLocation === undefined || queryLocation.length === 0) {
+ const queryLocationContainer = $('#location').next('.dropdown-toggle');
+ throw new InputInvalid(inputMessages.no_location, queryLocationContainer, queryLocationContainer.parent());
+ }
+ } catch (err) {
+ err.field.addClass('is-invalid');
+ err.container.append(`
${err.message}
`);
+ submitIcon.empty().removeClass('hg-loading').html('
');
+ $(document).trigger('InvalidInputEvent', err.field);
+ return false;
+ }
+ const queryTypeTitle = $(`#${queryType}`).data('display-name');
queryApp(queryType, queryTypeTitle, queryLocation, queryTarget);
$('#hg-form').animsition('out', $('#hg-results'), '#');
$('#hg-form').hide();
diff --git a/hyperglass/static/overrides.sass b/hyperglass/static/overrides.sass
index fede01e..513cd41 100644
--- a/hyperglass/static/overrides.sass
+++ b/hyperglass/static/overrides.sass
@@ -267,6 +267,11 @@
margin-left: 1rem
// Fixes input group issue where button is 1px taller than the input element (default is 2px)
+
+#hg-submit-button
+ border-top-right-radius: .3rem
+ border-bottom-right-radius: .3rem
+
.input-group-lg > .form-control:not(textarea),
.input-group-lg > .custom-select,
.bootstrap-select.form-control-lg .dropdown-toggle
@@ -431,4 +436,5 @@
.modal-title
padding-bottom: 1rem !important
-.popover
\ No newline at end of file
+.form-control.is-invalid, .form-control.is-valid
+ background-image: unset !important