Web App package details¶
This package encompass the web app functionality provided by Overwatch. This package includes:
- The web app serving modules, including routing requests for time slices and user directed reprocessing.
- The
html
templates for serving the content. The templates usejinja2
, while the pages themselves are built with Google Polymer. - Overwatch
js
(shared.js
),css
(style.css
), and other static dependencies (jQuery
,jsRoot
, Google Polymer).
Page template layout¶
Web pages are defined via jinja2
templates. This allows the dynamic determination of content. As an overall
design, layout.html
is the main shell for all pages. It provides consistent visual presentation through the
entire web app.
Individual pages are designed around three primary templates. For a page named example
, these three
templates are:
- The page itself, which will be known as
example.html
. This is mostly a thin wrapper around the other templates defined below, which can be imported directly viajinja
. Most of these pages will be approximately the same, with the main different being the title for the particular page. exampleMainContent.html
, which contains the main content of the example page. This could be histograms, information, etc.exampleDrawer.html
, which contains supplemental information to be displayed in the drawer on the left side of the app shell. This could be organizational or navigational information, or information which would want to be available at a glance, such as if the run is ongoing.
While this division may be somewhat unconventional, it is beneficial because it allows us to support regular and AJAX requests with the same underlying content. If a request is made of AJAX, we simply request and replace the new main content and drawer content directly within the app shell. However, if a full page is requested, we simply direct to the full template, which will contain the app shell as well as the main and drawer content.
Note that the page itself could be refactored further to be totally general, but this would require additional JavaScript development to request and set the page title via AJAX. For our purposes, the code duplication is worth the savings in development time and complexity.
The pages themselves are designed using Google Polymer v1. Although they do not take advantage of the more sophisticated features of Polymer, we still benefit heavily because we don’t need to worry about the design - it automatically creates a responsive app shell. We just have to make a few customizations. Ideally, we would update to the most recent version of Polymer, but as of August 2018, it is not a top priority.
AJAX and JSRoot
options¶
As noted above, all content is built such that it can be requested either as full pages or AJAX. There is a
similar option for using either JSRoot
or statically generated images. By default, pages are requested via
AJAX and JSRoot
is used for display. These options can be modified via GET parameters ajaxRequest
and
jsRoot
, respectively, in the HTTP request. See the webApp
and validation
modules for further details.
Flask¶
Flask is a very powerful framework for web apps. The docs are quite good, so they are an excellent place to
start. Since flask is not very opinionated, it is often up to the user to determine the best approach. In
Overwatch, we approach this by using many popular plugins such as flask-login
, flask-wtf
, etc, since these
packages probably have a better grasp of the issue than a home written solution.
Information on how we use flask is available below.
Requests and URL routing¶
For each route, note that the flask.request object is available with information about the request. In
particular, the request.args
dictionary is particularly useful, since it provides access to GET parameters
of the request. The reuest.post
dictionary contains the POST parameters.
When making a request within the web app or a template, remember that the main argument to url_for(...)
is
the name of the function, not the path! Further, named arguments will be passed as GET parameters.
Error Format¶
In an effort to improve the user experience around errors, there are a set of templates for displaying error
messages available in error.html
and the corresponding drawer and main content.
To use these templates, the errors must be constructed according to the dictionary format below. Each type of error is stored under a category (which is the key) and then the particular error messages are a list (which is the value). By appending to that list, new error messages won’t overwrite existing ones.
>>> # General format:
>>> errors = {'hello2': ['world', 'world2', 'world3'], 'hello': ['world', 'world2']}
>>> # We add an error related to the subsystem. Note that by using `setdefault()`, we can created
>>> # the list if necessary, or if it already exists, simply use that.
>>> # See: https://stackoverflow.com/a/2052206
>>> errors.setdefault("subsystem", []).append("Subsystem name \"EMC\" is not available!")
>>> errors
{'hello2': ['world', 'world2', 'world3'], 'hello': ['world', 'world2'], 'subsystem': ['Subsystem name "EMC" is not available!']}
Error handling is built into most routes, so errors will usually be handled seamlessly.
flask-webassets
, webassets
filters, and debugging¶
Overwatch depends on webassets
to deploy compiled and minimized files. In particular, the js
is minimized,
and polymer-bundler
is employed to compile all of the polymer components into one minimized file to reduce
the number of HTTP requests.
A few number of important notes on usage are below:
Most filters, including the
polymer-bundler
andrjsmin
filters, won’t build in debug mode!Disable caching with the below lines. Put these lines in
overwatch.webApp.webApp
oroverewatch.webApp.run
. It is useful for debugging:>>> assets.cache = False >>> assets.manifest = False
To debug, you still need to delete and touch the relevant files in between each change. Usually, that means:
- Counterintuitively, ensure that
flask-assets
debug mode is disabled. Otherwise the filters will not be run! - Deleting the file in the
static/gen/
folder - Removing the
static/.webassets
folder if it exists - Update or otherwise touch the file of interest (for example,
static/polyerComponents.html
)
- Counterintuitively, ensure that
To ease debugging, the debug mode of
flask-assets
can be separately from the overall debug mode via theflaskAssetsDebug
field in the YAML configuration. This allows debug information to flow while still causing the filters to run.Each Asset won’t be built until first access of the particular file. Access the associated
urls
of the asset to force it to built immediately (will still only be built if needed or forced by following the debug procedure above).>>> logger.debug(assets["polymerBundle"].urls())
Monitoring for errors¶
It is important to monitor Overwatch for errors and other issues. For the web app, this monitoring is provided
by sentry
, which hooks into exceptions, logging, and other parts of the app to automatically provide alerts
and information when issues occur.
For successful monitoring, the environment must export the DSN
as export SENTRY_DSN_WEBAPP=<value>
. The
value will be some sort of unique URL. Note that this endpoint is just for Overwatch Web App errors (called
overwatch-webapp
on sentry
). If it is not available, it will look for the general environment variable
SENTRY_DSN
.