diff --git a/.gitignore b/.gitignore index 0a21cad9f..c84489e6a 100644 --- a/.gitignore +++ b/.gitignore @@ -58,10 +58,12 @@ target/ .idea/ .DS_Store -# cache and static rebuild files +# Frontend dependencies and compiled assets app/assets/stylesheets/govuk_template/.sass-cache/ .sass-cache/ cache/ -app/static/* -app/static/stylesheets/*.css - +app/static +node_modules +bower_components +app/templates/govuk_template.html +npm-debug.log diff --git a/.gitmodules b/.gitmodules index 698b9d0b6..090878d9d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "app/assets/stylesheets/govuk_frontend_toolkit"] - path = app/assets/stylesheets/govuk_frontend_toolkit + path = app/assets/govuk_frontend_toolkit url = https://github.com/alphagov/govuk_frontend_toolkit.git [submodule "app/assets/stylesheets/govuk_elements"] - path = app/assets/stylesheets/govuk_elements + path = app/assets/govuk_elements url = https://github.com/alphagov/govuk_elements.git diff --git a/.travis.yml b/.travis.yml index 24b59df39..f7d0352be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,10 @@ addons: postgresql: '9.3' env: secure: jT9BIioqBMkOdLZhU+WJNdnRJ+06G7qUx4QqEVldp96dJwmWpPEvA0XbitdnQt/WXYkpMlDbgSApvvGj2ZNvdpowRRe5HFX8D2Udhi2g9+cXgKrQxH6zv0evJyQLOjCINW6KtgMCJ5wkYR3qQ4BQawlDt6ecpmeboKTmvs2W8jZ09aV4IKKvdd7BwFon10QVPF5ny10G83unLtKnKgRMjSSLnaEiA78pE/LSUkekK4mhmtl+yfQf60cIuQGcN9NCYIt5PrdYYyMkbUaht9ykwL2C11sp5JYPClI9k6lrlpGJCdL9wbJwejGhR/pEqwJ4tKK8Zv+mngmkbzE6fd5ehuRMnIUAifG4t3p6WbhKwY5pJsdVyPgWcRSPXOJA7yEcAeTAvWcC++6mCIFBeMxt/yQNw02jkFHeNKRh2twTRvr4xWZHq9FsVxTEVz89OOuue3IkkyDNmVusGJ9+AVRIn9Oa+U/r3bDnrs7jz+meSwb82GZUBzFpUe2pe8qeBE572Ay7yHB73VHUgp/2A1qkZ4SnTjTpMbnS5RdXTgwtMkOs5MLZgteCVxFL3sHcr9e/B3UIUnzKUSPXXOjHyDxBwrABWo81V9Vp2IPV7P9Ofv8zroudjQxK5MOcbmiPQF+eEB9L4DvkUBNsGxtJ/nmPp6tmN0Xjo0xXVdZCEVj29Og= +before_install: +- nvm install 5.0.0 install: -- bundle install +- npm install - pip install -r requirements_for_test.txt before_script: - psql -c 'create database test_notifications_admin;' -U postgres diff --git a/Gemfile b/Gemfile deleted file mode 100644 index e46ea120f..000000000 --- a/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source 'https://rubygems.org' -gem 'sass' diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index bb229915d..000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,13 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - sass (3.4.19) - -PLATFORMS - ruby - -DEPENDENCIES - sass - -BUNDLED WITH - 1.10.6 diff --git a/Procfile b/Procfile index 33594db01..bd846ba9a 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: python app.py runserver \ No newline at end of file +web: python app.py runserver diff --git a/README.md b/README.md index 82d20a527..5cf8f501b 100644 --- a/README.md +++ b/README.md @@ -14,32 +14,49 @@ Application to handle the admin functions of the notifications application. ### Create a virtual environment for this project - mkvirtualenv -p /usr/local/bin/python3 notifications-admin - +```shell + mkvirtualenv -p /usr/local/bin/python3 notifications-admin +``` -### GOV.UK frontend toolkit - The GOV.UK frontend toolkit is a submodule of this project. - To get the content of the toolkit run the following two commands - - git submodule init - git submodule update + +### Building the frontend + +You need [Node](http://nodejs.org/) which will also get you [NPM](npmjs.org), +Node's package management tool. +```shell + brew install node +``` + +Most of the frontend dependencies are managed using Git Submodules. Some are +managed with NPM and Bower. To install or update *all the things*, run +```shell + git submodule init --update + npm install +``` + +If you want the front end assets to re-compile on changes, leave this running +in a separate terminal from the app +```shell + npm run watch +``` ### Running the application: +```shell pip install -r requirements.txt ./scripts/bootstrap.sh ./scripts/run_app.sh +``` -Note: the ./scripts/bootstrap.sh script only needs to be run the first time to create the database. +Note: the ./scripts/bootstrap.sh script only needs to be run the first time to +create the database. + +URL to test app: - url to test app: - localhost:6012/helloworld ### Domain model -All the domain models are defined in the [models.py](https://github.com/alphagov/notifications-admin/blob/master/app/models.py) file. - - - - +All the domain models are defined in the +[models.py](https://github.com/alphagov/notifications-admin/blob/master/app/models.py) +file. diff --git a/app.py b/app.py index e69af42b5..dc26c70cc 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,6 @@ import os -from flask.ext import assets from flask.ext.script import Manager, Server from flask_migrate import Migrate, MigrateCommand -from webassets.filter import get_filter from app import create_app, db diff --git a/app/__init__.py b/app/__init__.py index cc3705a93..498230fe3 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -3,11 +3,9 @@ import re from flask import Flask, session, Markup from flask._compat import string_types -from flask.ext import assets from flask.ext.sqlalchemy import SQLAlchemy from flask_login import LoginManager from flask_wtf import CsrfProtect -from webassets.filter import get_filter from werkzeug.exceptions import abort from app.notify_client.api_client import AdminAPIClient @@ -75,78 +73,9 @@ def init_app(app): if key in os.environ: app.config[key] = convert_to_boolean(os.environ[key]) - init_asset_environment(app) - - -def init_asset_environment(app): - env = assets.Environment(app) - - # Tell flask-assets where to look for our sass files. - env.load_path = [ - os.path.join(os.path.dirname(__file__), 'assets'), - os.path.join(os.path.dirname(__file__), 'assets/stylesheets'), - os.path.join(os.path.dirname(__file__), 'assets/stylesheets/stylesheets/govuk_frontend_toolkit'), - os.path.join(os.path.dirname(__file__), 'assets/stylesheets/govuk_template'), - os.path.join(os.path.dirname(__file__), 'assets/stylesheets/views'), - os.path.join(os.path.dirname(__file__), 'assets/stylesheets/components'), - ] - - scss = get_filter('scss', as_output=True) - - env.register( - 'css_all', - assets.Bundle( - 'main.scss', - filters='scss', - output='stylesheets/css_all.css' - ) - ) - - env.register( - 'css_govuk-template', - assets.Bundle( - 'govuk_template/govuk-template.scss', - filters='scss', - output='stylesheets/govuk-template.css', - depends='*.scss' - ) - ) - - env.register( - 'css_govuk-template-ie6', - assets.Bundle( - 'govuk_template/govuk-template-ie6.scss', - filters='scss', - output='stylesheets/govuk-template-ie6.css' - ) - ) - - env.register( - 'css_govuk-template-ie7', - assets.Bundle( - 'govuk_template/govuk-template-ie7.scss', - filters='scss', - output='stylesheets/govuk-template-ie7.css' - ) - ) - - env.register( - 'css_govuk-template-ie8', - assets.Bundle( - 'govuk_template/govuk-template-ie8.scss', - filters='scss', - output='stylesheets/govuk-template-ie8.css' - ) - ) - - env.register( - 'css_govuk-template-print', - assets.Bundle( - 'govuk_template/govuk-template-print.scss', - filters='scss', - output='stylesheets/govuk-template-print.css' - ) - ) + @app.context_processor + def inject_global_template_variables(): + return {'asset_path': '/static/'} def convert_to_boolean(value): diff --git a/app/assets/images/apple-touch-icon-120x120.png b/app/assets/images/apple-touch-icon-120x120.png deleted file mode 100644 index 7cb519ac2..000000000 Binary files a/app/assets/images/apple-touch-icon-120x120.png and /dev/null differ diff --git a/app/assets/images/apple-touch-icon-152x152.png b/app/assets/images/apple-touch-icon-152x152.png deleted file mode 100644 index 4a0b722c7..000000000 Binary files a/app/assets/images/apple-touch-icon-152x152.png and /dev/null differ diff --git a/app/assets/images/apple-touch-icon-60x60.png b/app/assets/images/apple-touch-icon-60x60.png deleted file mode 100644 index 4a78153fe..000000000 Binary files a/app/assets/images/apple-touch-icon-60x60.png and /dev/null differ diff --git a/app/assets/images/apple-touch-icon-76x76.png b/app/assets/images/apple-touch-icon-76x76.png deleted file mode 100644 index 54f7023ef..000000000 Binary files a/app/assets/images/apple-touch-icon-76x76.png and /dev/null differ diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico deleted file mode 100644 index da3760d3b..000000000 Binary files a/app/assets/images/favicon.ico and /dev/null differ diff --git a/app/assets/images/gov.uk_logotype_crown_invert.png b/app/assets/images/gov.uk_logotype_crown_invert.png deleted file mode 100644 index d7c0e929c..000000000 Binary files a/app/assets/images/gov.uk_logotype_crown_invert.png and /dev/null differ diff --git a/app/assets/images/gov.uk_logotype_crown_invert_trans.png b/app/assets/images/gov.uk_logotype_crown_invert_trans.png deleted file mode 100644 index 152b83eab..000000000 Binary files a/app/assets/images/gov.uk_logotype_crown_invert_trans.png and /dev/null differ diff --git a/app/assets/images/opengraph-image.png b/app/assets/images/opengraph-image.png deleted file mode 100644 index 355284fbf..000000000 Binary files a/app/assets/images/opengraph-image.png and /dev/null differ diff --git a/app/assets/javascripts/govuk-template.js b/app/assets/javascripts/govuk-template.js deleted file mode 100644 index 050133013..000000000 --- a/app/assets/javascripts/govuk-template.js +++ /dev/null @@ -1,112 +0,0 @@ -(function () { - "use strict" - var root = this; - if(typeof root.GOVUK === 'undefined') { root.GOVUK = {}; } - - /* - Cookie methods - ============== - - Usage: - - Setting a cookie: - GOVUK.cookie('hobnob', 'tasty', { days: 30 }); - - Reading a cookie: - GOVUK.cookie('hobnob'); - - Deleting a cookie: - GOVUK.cookie('hobnob', null); - */ - GOVUK.cookie = function (name, value, options) { - if(typeof value !== 'undefined'){ - if(value === false || value === null) { - return GOVUK.setCookie(name, '', { days: -1 }); - } else { - return GOVUK.setCookie(name, value, options); - } - } else { - return GOVUK.getCookie(name); - } - }; - GOVUK.setCookie = function (name, value, options) { - if(typeof options === 'undefined') { - options = {}; - } - var cookieString = name + "=" + value + "; path=/"; - if (options.days) { - var date = new Date(); - date.setTime(date.getTime() + (options.days * 24 * 60 * 60 * 1000)); - cookieString = cookieString + "; expires=" + date.toGMTString(); - } - if (document.location.protocol == 'https:'){ - cookieString = cookieString + "; Secure"; - } - document.cookie = cookieString; - }; - GOVUK.getCookie = function (name) { - var nameEQ = name + "="; - var cookies = document.cookie.split(';'); - for(var i = 0, len = cookies.length; i < len; i++) { - var cookie = cookies[i]; - while (cookie.charAt(0) == ' ') { - cookie = cookie.substring(1, cookie.length); - } - if (cookie.indexOf(nameEQ) === 0) { - return decodeURIComponent(cookie.substring(nameEQ.length)); - } - } - return null; - }; -}).call(this); -(function () { - "use strict" - var root = this; - if(typeof root.GOVUK === 'undefined') { root.GOVUK = {}; } - - GOVUK.addCookieMessage = function () { - var message = document.getElementById('global-cookie-message'), - hasCookieMessage = (message && GOVUK.cookie('seen_cookie_message') === null); - - if (hasCookieMessage) { - message.style.display = 'block'; - GOVUK.cookie('seen_cookie_message', 'yes', { days: 28 }); - } - }; -}).call(this); -(function() { - "use strict" - - // add cookie message - if (window.GOVUK && GOVUK.addCookieMessage) { - GOVUK.addCookieMessage(); - } - - // header navigation toggle - if (document.querySelectorAll && document.addEventListener){ - var els = document.querySelectorAll('.js-header-toggle'), - i, _i; - for(i=0,_i=els.length; i<_i; i++){ - els[i].addEventListener('click', function(e){ - e.preventDefault(); - var target = document.getElementById(this.getAttribute('href').substr(1)), - targetClass = target.getAttribute('class') || '', - sourceClass = this.getAttribute('class') || ''; - - if(targetClass.indexOf('js-visible') !== -1){ - target.setAttribute('class', targetClass.replace(/(^|\s)js-visible(\s|$)/, '')); - } else { - target.setAttribute('class', targetClass + " js-visible"); - } - if(sourceClass.indexOf('js-hidden') !== -1){ - this.setAttribute('class', sourceClass.replace(/(^|\s)js-hidden(\s|$)/, '')); - } else { - this.setAttribute('class', sourceClass + " js-hidden"); - } - }); - } - } -}).call(this); - - - diff --git a/app/assets/javascripts/highlightTags.js b/app/assets/javascripts/highlightTags.js new file mode 100644 index 000000000..472d479c7 --- /dev/null +++ b/app/assets/javascripts/highlightTags.js @@ -0,0 +1,43 @@ +(function(Modules) { + "use strict"; + + if ( + !('oninput' in document.createElement('input')) + ) return; + + const tagPattern = /\(\([^\)\(]+\)\)/g; + + Modules.HighlightTags = function() { + + this.start = function(textarea) { + + this.$textbox = $(textarea) + .wrap(` +
+ `) + .after(this.$backgroundMaskForeground = $(` + + + + `)) + .on("input", this.update) + .on("scroll", this.maintainScrollParity); + + this.$textbox + .trigger("input"); + + }; + + this.update = () => this.$backgroundMaskForeground.html( + this.$textbox.val().replace( + tagPattern, match => `${match}` + ) + ); + + this.maintainScrollParity = () => this.$backgroundMaskForeground.scrollTop( + this.$textbox.scrollTop() + ); + + }; + +})(window.GOVUK.Modules); diff --git a/app/assets/javascripts/ie.js b/app/assets/javascripts/ie.js deleted file mode 100644 index 3f31c9ee7..000000000 --- a/app/assets/javascripts/ie.js +++ /dev/null @@ -1,512 +0,0 @@ -/* - HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed -*/ - -(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); -a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; -c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="Users will see your service name:
| Recent activity | -|||
|---|---|---|---|
| Test message 1 | -dispatch_20151114.csv | -Just now | -Queued | -
| Mickey Mouse | -dispatch_20151117.csv | -5 minutes ago | -Delivered | -
| Asdfgg | -remdinder_monday.csv | -30 minutes ago | -Failed | -
| Test message 2 | -appointments_wed.csv | -2 hours ago | -Delivered | -
| Reminder file | -+447889887634 | -11:44 - 21 Nov 2015 | -Delivered | -
See all notifications activity
++ See all notifications activity +
{% endblock %} diff --git a/app/templates/views/edit-template.html b/app/templates/views/edit-template.html index ed29b8074..b17b5b64c 100644 --- a/app/templates/views/edit-template.html +++ b/app/templates/views/edit-template.html @@ -1,4 +1,6 @@ {% extends "withnav_template.html" %} +{% from "components/textbox.html" import textbox %} +{% from "components/submit-form.html" import submit_form %} {% block page_title %} GOV.UK Notify | Edit template @@ -6,13 +8,14 @@ GOV.UK Notify | Edit template {% block maincolumn_content %} +Here's where you can edit an exiting template (including delete) or add a new one
+ - - {% endblock %} diff --git a/app/templates/views/email-not-received.html b/app/templates/views/email-not-received.html index e6f28df80..24bdcf33b 100644 --- a/app/templates/views/email-not-received.html +++ b/app/templates/views/email-not-received.html @@ -4,7 +4,7 @@ GOV.UK Notify {% endblock %} -{% block content %} +{% block fullwidth_content %}This page will be where we list the notifications for a specific job.
++ {{ banner(flash_message) }} +
- - ++ Sent with template {{ template_used }} at {{ uploaded_file_time }} +
+ + {% call(item) table( + messages, + caption='Messages', + caption_visible=False, + field_headings=[ + 'To', + 'Message', + right_aligned_field_heading('Delivery status') + ] + ) %} + {% call field() %} + {{item.phone}} + {% endcall %} + {% call field() %} + {{item.message[:50]}}… + {% endcall %} + {% call field( + align='right', + status='error' if item.status == 'Failed' else 'default' + ) %} + {{ item.status }} {{ item.time }} + {% endcall %} + {% endcall %} {% endblock %} diff --git a/app/templates/views/jobs.html b/app/templates/views/jobs.html index 79a9604d8..b9bda799d 100644 --- a/app/templates/views/jobs.html +++ b/app/templates/views/jobs.html @@ -1,4 +1,5 @@ {% extends "withnav_template.html" %} +{% from "components/table.html" import table, field %} {% block page_title %} GOV.UK Notify | Notifications activity @@ -8,11 +9,25 @@ GOV.UK Notify | Notifications activityThis page will be where we show the list of jobs that this service has processed
- -- view a particular notification job -
+ {% call(item) table( + jobs, + caption="Recent activity", + caption_visible=False, + field_headings=['Job', 'File', 'Time', 'Status'] + ) %} + {% call field() %} + {{ item.file }} + {% endcall %} + {% call field() %} + {{ item.job }} + {% endcall %} + {% call field() %} + {{ item.time }} + {% endcall %} + {% call field() %} + {{ item.status }} + {% endcall %} + {% endcall %} {% endblock %} diff --git a/app/templates/views/manage-templates.html b/app/templates/views/manage-templates.html index 1554f3b09..4c4fa8d88 100644 --- a/app/templates/views/manage-templates.html +++ b/app/templates/views/manage-templates.html @@ -7,15 +7,17 @@ GOV.UK Notify | Manage templates {% block maincolumn_content %} -Here's where you can view templates, choose to add one, or edit/delete one.
+Here's where you can view templates, choose to add one, or edit/delete one.
- + -- Add a new message template -
++ Add a new message template +
{% endblock %} diff --git a/app/templates/views/new-password.html b/app/templates/views/new-password.html index df9e045b9..a1e312642 100644 --- a/app/templates/views/new-password.html +++ b/app/templates/views/new-password.html @@ -4,12 +4,12 @@ GOV.UK Notify {% endblock %} -{% block content %} +{% block fullwidth_content %}You can now create a new password for your account.
diff --git a/app/templates/views/notification.html b/app/templates/views/notification.html index 99a6902db..1dcb034a2 100644 --- a/app/templates/views/notification.html +++ b/app/templates/views/notification.html @@ -1,4 +1,5 @@ {% extends "withnav_template.html" %} +{% from "components/sms-message.html" import sms_message, message_status %} {% block page_title %} GOV.UK Notify | Notifications activity @@ -7,12 +8,21 @@ GOV.UK Notify | Notifications activity {% block maincolumn_content %} -
This page will be where we show what happened for a specific notification.
+- View other notifications in this job + View other notifications in this job
diff --git a/app/templates/views/register-from-invite.html b/app/templates/views/register-from-invite.html index 9945138cc..95a90dea2 100644 --- a/app/templates/views/register-from-invite.html +++ b/app/templates/views/register-from-invite.html @@ -4,7 +4,7 @@ GOV.UK Notify | Create a user account {% endblock %} -{% block content %} +{% block fullwidth_content %}- or create a new template + or create a new template