From afe4270604542536fefbec566e985c3a1cdf2a44 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 16 Nov 2021 11:14:37 +0000 Subject: [PATCH 1/8] Inital work on moving to GD.CSS and the Django templating system. THIS IS INCOMPLETE and a work in progress. --- controlpanel/frontend/jinja2.py | 23 - controlpanel/frontend/static/app.scss | 31 - .../static/components/alerts/_alerts.scss | 36 - .../static/components/alerts/alerts.js | 13 - .../static/components/alerts/macro.html | 13 - .../frontend/static/components/all.scss | 7 - .../static/components/app-logs/_app-logs.scss | 17 - .../static/components/app-logs/macro.html | 107 -- .../autocomplete/_autocomplete.scss | 7 - .../components/autocomplete/autocomplete.js | 18 - .../static/components/autocomplete/macro.html | 61 - .../static/components/breadcrumbs/macro.html | 19 - .../static/components/checkboxes/macro.html | 108 -- .../components/error-message/macro.html | 5 - .../static/components/fieldset/macro.html | 26 - .../static/components/footer/macro.html | 89 -- .../static/components/header/macro.html | 77 -- .../static/components/hint/macro.html | 6 - .../static/components/input/macro.html | 48 - .../static/components/label/macro.html | 17 - .../modal-dialog/_modal-dialog.scss | 41 - .../static/components/modal-dialog/macro.html | 22 - .../components/modal-dialog/modal-dialog.js | 19 - .../static/components/navbar/macro.html | 38 - .../static/components/radios/macro.html | 106 -- .../selectable-rows/_selectable-rows.scss | 29 - .../components/selectable-rows/macro.html | 3 - .../selectable-rows/selectable-rows.js | 94 -- .../selectable-rows/selectable-rows.test.js | 117 -- .../static/components/skip-link/macro.html | 5 - .../static/components/table/_table.scss | 8 - .../frontend/static/components/tag/_tag.scss | 14 - .../frontend/static/components/tag/macro.html | 3 - .../static/components/user/macro.html | 3 - controlpanel/frontend/static/css/app.css | 41 + controlpanel/frontend/static/css/gd.css | 1062 +++++++++++++++++ .../frontend/static/img/attention.svg | 3 + .../frontend/static/img/govuk-crest.png | Bin 0 -> 3584 bytes controlpanel/frontend/static/img/logo.svg | 8 + .../frontend/static/local/buttons.scss | 27 - controlpanel/frontend/static/local/forms.scss | 10 - .../frontend/static/local/layout.scss | 7 - .../frontend/static/local/markdown.scss | 29 - .../frontend/static/local/messages.scss | 49 - .../frontend/static/local/mixins.scss | 7 - controlpanel/frontend/static/local/modal.scss | 39 - .../frontend/static/local/panels.scss | 5 - controlpanel/frontend/static/local/rules.scss | 3 - .../frontend/static/local/sign-out.scss | 16 - .../frontend/static/local/tables.scss | 15 - controlpanel/frontend/static/local/tabs.scss | 34 - .../frontend/static/local/typeahead.scss | 11 - .../frontend/static/local/typography.scss | 26 - .../frontend/static/local/utilities.scss | 11 - controlpanel/frontend/templates/500.html | 10 + controlpanel/frontend/templates/503.html | 8 + controlpanel/frontend/templates/a11y.html | 96 ++ controlpanel/frontend/templates/base.html | 39 + controlpanel/frontend/templates/footer.html | 16 + controlpanel/frontend/templates/header.html | 33 + controlpanel/frontend/templates/help.html | 58 + controlpanel/frontend/templates/home.html | 14 + .../frontend/templates/login-fail.html | 41 + controlpanel/settings/common.py | 14 +- 64 files changed, 1431 insertions(+), 1531 deletions(-) delete mode 100644 controlpanel/frontend/jinja2.py delete mode 100644 controlpanel/frontend/static/app.scss delete mode 100644 controlpanel/frontend/static/components/alerts/_alerts.scss delete mode 100644 controlpanel/frontend/static/components/alerts/alerts.js delete mode 100644 controlpanel/frontend/static/components/alerts/macro.html delete mode 100644 controlpanel/frontend/static/components/all.scss delete mode 100644 controlpanel/frontend/static/components/app-logs/_app-logs.scss delete mode 100644 controlpanel/frontend/static/components/app-logs/macro.html delete mode 100644 controlpanel/frontend/static/components/autocomplete/_autocomplete.scss delete mode 100644 controlpanel/frontend/static/components/autocomplete/autocomplete.js delete mode 100644 controlpanel/frontend/static/components/autocomplete/macro.html delete mode 100644 controlpanel/frontend/static/components/breadcrumbs/macro.html delete mode 100644 controlpanel/frontend/static/components/checkboxes/macro.html delete mode 100644 controlpanel/frontend/static/components/error-message/macro.html delete mode 100644 controlpanel/frontend/static/components/fieldset/macro.html delete mode 100644 controlpanel/frontend/static/components/footer/macro.html delete mode 100644 controlpanel/frontend/static/components/header/macro.html delete mode 100644 controlpanel/frontend/static/components/hint/macro.html delete mode 100644 controlpanel/frontend/static/components/input/macro.html delete mode 100644 controlpanel/frontend/static/components/label/macro.html delete mode 100644 controlpanel/frontend/static/components/modal-dialog/_modal-dialog.scss delete mode 100644 controlpanel/frontend/static/components/modal-dialog/macro.html delete mode 100644 controlpanel/frontend/static/components/modal-dialog/modal-dialog.js delete mode 100644 controlpanel/frontend/static/components/navbar/macro.html delete mode 100644 controlpanel/frontend/static/components/radios/macro.html delete mode 100644 controlpanel/frontend/static/components/selectable-rows/_selectable-rows.scss delete mode 100644 controlpanel/frontend/static/components/selectable-rows/macro.html delete mode 100644 controlpanel/frontend/static/components/selectable-rows/selectable-rows.js delete mode 100644 controlpanel/frontend/static/components/selectable-rows/selectable-rows.test.js delete mode 100644 controlpanel/frontend/static/components/skip-link/macro.html delete mode 100644 controlpanel/frontend/static/components/table/_table.scss delete mode 100644 controlpanel/frontend/static/components/tag/_tag.scss delete mode 100644 controlpanel/frontend/static/components/tag/macro.html delete mode 100644 controlpanel/frontend/static/components/user/macro.html create mode 100644 controlpanel/frontend/static/css/app.css create mode 100644 controlpanel/frontend/static/css/gd.css create mode 100644 controlpanel/frontend/static/img/attention.svg create mode 100644 controlpanel/frontend/static/img/govuk-crest.png create mode 100644 controlpanel/frontend/static/img/logo.svg delete mode 100644 controlpanel/frontend/static/local/buttons.scss delete mode 100644 controlpanel/frontend/static/local/forms.scss delete mode 100644 controlpanel/frontend/static/local/layout.scss delete mode 100644 controlpanel/frontend/static/local/markdown.scss delete mode 100644 controlpanel/frontend/static/local/messages.scss delete mode 100644 controlpanel/frontend/static/local/mixins.scss delete mode 100644 controlpanel/frontend/static/local/modal.scss delete mode 100644 controlpanel/frontend/static/local/panels.scss delete mode 100644 controlpanel/frontend/static/local/rules.scss delete mode 100644 controlpanel/frontend/static/local/sign-out.scss delete mode 100644 controlpanel/frontend/static/local/tables.scss delete mode 100644 controlpanel/frontend/static/local/tabs.scss delete mode 100644 controlpanel/frontend/static/local/typeahead.scss delete mode 100644 controlpanel/frontend/static/local/typography.scss delete mode 100644 controlpanel/frontend/static/local/utilities.scss create mode 100644 controlpanel/frontend/templates/500.html create mode 100644 controlpanel/frontend/templates/503.html create mode 100644 controlpanel/frontend/templates/a11y.html create mode 100644 controlpanel/frontend/templates/base.html create mode 100644 controlpanel/frontend/templates/footer.html create mode 100644 controlpanel/frontend/templates/header.html create mode 100644 controlpanel/frontend/templates/help.html create mode 100644 controlpanel/frontend/templates/home.html create mode 100644 controlpanel/frontend/templates/login-fail.html diff --git a/controlpanel/frontend/jinja2.py b/controlpanel/frontend/jinja2.py deleted file mode 100644 index b7199380a..000000000 --- a/controlpanel/frontend/jinja2.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import jinja2 -from django.contrib import messages -from django.conf import settings -from django.templatetags.static import static -from django.urls import reverse -from django.utils.timesince import timesince - - -def environment(**kwargs): - env = jinja2.Environment(**kwargs) - env.globals.update( - { - "env": os.environ.get("ENV", "dev"), - "get_messages": messages.get_messages, - "timesince": timesince, - "static": static, - "url": reverse, - "google_analytics_id": settings.GOOGLE_ANALYTICS_ID, - "user_guidance_base_url": settings.USER_GUIDANCE_BASE_URL, - } - ) - return env diff --git a/controlpanel/frontend/static/app.scss b/controlpanel/frontend/static/app.scss deleted file mode 100644 index 9662ec218..000000000 --- a/controlpanel/frontend/static/app.scss +++ /dev/null @@ -1,31 +0,0 @@ -$govuk-global-styles: true; - -// override govuk font because we're not allowed to use Transport New -$govuk-font-family-nta: "Arial"; -$govuk-font-family-nta-tabular: "Arial"; - -$govuk-assets-path: "/static/govuk-frontend/govuk/assets/"; - -// GOV.UK Frontend -@import "govuk-frontend/govuk/all"; - -// MOJ Frontend -@import "@ministryofjustice/frontend/moj/all"; - -// Other component styles -@import "components/all"; - -// App specific -@import "local/buttons"; -@import "local/forms"; -@import "local/layout"; -@import "local/markdown"; -@import "local/utilities"; - -body { - margin: 0; -} - -.moj-phase-banner--border { - border: none; -} diff --git a/controlpanel/frontend/static/components/alerts/_alerts.scss b/controlpanel/frontend/static/components/alerts/_alerts.scss deleted file mode 100644 index e09f0a559..000000000 --- a/controlpanel/frontend/static/components/alerts/_alerts.scss +++ /dev/null @@ -1,36 +0,0 @@ -.alerts--item { - border: 5px solid govuk-colour("blue"); - color: govuk-colour("blue"); - font-size: 0; // Removes white space when using inline-block on child element - margin-bottom: govuk-spacing(6); - padding: govuk-spacing(2); -} - -.alerts--message { - @include govuk-font($size: 19); - display: block; - overflow: hidden; - font-weight: $govuk-font-weight-bold; - - h2 { - margin-bottom: govuk-spacing(2); - } - - h2:last-child { - margin-bottom: 0; - } - - p:last-child { - margin-bottom: 0; - } -} - -.alerts--item.success { - border-color: govuk-colour("green"); - color: govuk-colour("green"); -} - -.alerts--item.warning { - border-color: govuk-colour("red"); - color: govuk-colour("red"); -} diff --git a/controlpanel/frontend/static/components/alerts/alerts.js b/controlpanel/frontend/static/components/alerts/alerts.js deleted file mode 100644 index a5b215bed..000000000 --- a/controlpanel/frontend/static/components/alerts/alerts.js +++ /dev/null @@ -1,13 +0,0 @@ -moj.Modules.alerts = { - alertsClass: 'alerts', - - init() { - this.bindEvents(); - }, - - bindEvents() { - $(document).on('click', `.${this.messageClass}`, (e) => { - $(e.target).fadeOut(); - }); - }, -}; diff --git a/controlpanel/frontend/static/components/alerts/macro.html b/controlpanel/frontend/static/components/alerts/macro.html deleted file mode 100644 index 608f1d2c3..000000000 --- a/controlpanel/frontend/static/components/alerts/macro.html +++ /dev/null @@ -1,13 +0,0 @@ -{% macro alerts() %} - {%- set messages = [] %} - {%- if request %}{% set messages = get_messages(request) %}{% endif %} - {%- if messages %} -
- {% for message in messages -%} -
- {{ message }} -
- {%- endfor %} -
- {%- endif %} -{% endmacro %} diff --git a/controlpanel/frontend/static/components/all.scss b/controlpanel/frontend/static/components/all.scss deleted file mode 100644 index af7c86e33..000000000 --- a/controlpanel/frontend/static/components/all.scss +++ /dev/null @@ -1,7 +0,0 @@ -@import "alerts/alerts"; -@import "app-logs/app-logs"; -@import "autocomplete/autocomplete"; -@import "modal-dialog/modal-dialog"; -@import "selectable-rows/selectable-rows"; -@import "table/table"; -@import "tag/tag"; diff --git a/controlpanel/frontend/static/components/app-logs/_app-logs.scss b/controlpanel/frontend/static/components/app-logs/_app-logs.scss deleted file mode 100644 index f3012891e..000000000 --- a/controlpanel/frontend/static/components/app-logs/_app-logs.scss +++ /dev/null @@ -1,17 +0,0 @@ -.app-logs { - display: flex; - flex-direction: column-reverse; - overflow: scroll; - border: 2px inset govuk-colour('light-grey'); - padding: 10px; - margin-bottom: 1em; - max-height: 20em; - - & pre { - margin: 0; - } - - .timestamp { - color: govuk-colour('dark-grey'); - } -} diff --git a/controlpanel/frontend/static/components/app-logs/macro.html b/controlpanel/frontend/static/components/app-logs/macro.html deleted file mode 100644 index 832e1cb23..000000000 --- a/controlpanel/frontend/static/components/app-logs/macro.html +++ /dev/null @@ -1,107 +0,0 @@ -{% macro app_logs(app, kibana_base_url) %} -
-
{% for entry in app.get_logs() -%}
-{{ entry.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}: {{ entry.message }}
-{% endfor %}
-
-

- View full logs -

-{% endmacro %} - -{% macro kibana_link(app, kibana_base_url) -%} -{% filter replace(" ", "") -%} -{% filter replace("\n", "") -%} -{{ kibana_base_url }}#/discover?_g=( -time:( - from:now-24h, - mode:quick, - to:now -) -)&_a=( -columns:!(message), -filters:!( - ( - '$state':(store:appState), - meta:( - alias:!n, - disabled:!f, - index:'{{env}}-node-*', - key:query, - negate:!f, - type:custom, - value:'{% filter urlencode %}{% filter replace(" ", "") %}{% filter replace("\n", "") -%} - { - "constant_score":{ - "filter":{ - "bool":{ - "must":{ - "exists":{ - "field":"message" - } - }, - "must_not":{ - "term":{ - "message":"" - } - } - } - } - } - } - {%- endfilter %}{% endfilter %}{% endfilter %}' - ), - query:( - constant_score:( - filter:( - bool:( - must:( - exists:( - field:message - ) - ), - must_not:( - term:( - message:'' - ) - ) - ) - ) - ) - ) - ), - ( - '$state':( - store:appState - ), - meta:( - alias:!n, - disabled:!f, - index:'{{env}}-node-*', - key:app_name, - negate:!f, - params:( - query:{{app.release_name}}-webapp, - type:phrase - ), - type:phrase, - value:{{app.release_name}}-webapp - ), - query:( - match:( - app_name:( - query:{{app.release_name}}-webapp, - type:phrase - ) - ) - ) - ) -), -index:'{{env}}-node-*', -interval:auto, -query:(language:lucene,query:''), -sort:!(time_nano,asc), -uiState:(spy:!n)) -{%- endfilter %} -{%- endfilter %} -{%- endmacro %} diff --git a/controlpanel/frontend/static/components/autocomplete/_autocomplete.scss b/controlpanel/frontend/static/components/autocomplete/_autocomplete.scss deleted file mode 100644 index 89813ad25..000000000 --- a/controlpanel/frontend/static/components/autocomplete/_autocomplete.scss +++ /dev/null @@ -1,7 +0,0 @@ -.autocomplete__input { - width: 33.3%; -} - -.autocomplete__option { - @include govuk-font($size: 19); -} diff --git a/controlpanel/frontend/static/components/autocomplete/autocomplete.js b/controlpanel/frontend/static/components/autocomplete/autocomplete.js deleted file mode 100644 index 4f733ba77..000000000 --- a/controlpanel/frontend/static/components/autocomplete/autocomplete.js +++ /dev/null @@ -1,18 +0,0 @@ -moj.Modules.autocomplete = { - selector: ".autocomplete-select", - - init() { - if (document.querySelector(this.selector)) { - this.bindEvents(); - } - }, - - bindEvents() { - document.querySelectorAll(this.selector).forEach(select => { - accessibleAutocomplete.enhanceSelectElement({ - defaultValue: '', - selectElement: select, - }); - }); - }, -}; diff --git a/controlpanel/frontend/static/components/autocomplete/macro.html b/controlpanel/frontend/static/components/autocomplete/macro.html deleted file mode 100644 index 911c8c967..000000000 --- a/controlpanel/frontend/static/components/autocomplete/macro.html +++ /dev/null @@ -1,61 +0,0 @@ -{% from "error-message/macro.html" import govukErrorMessage %} -{% from "hint/macro.html" import govukHint %} -{% from "label/macro.html" import govukLabel %} - -{% macro autocomplete(params) %} -{#- a record of other elements that we need to associate with the input using - aria-describedby – for example hints or error messages -#} -{% set describedBy = "" %} -
- {% if params.label -%} - {{ govukLabel({ - "html": params.label.html, - "text": params.label.text, - "classes": params.label.classes, - "isPageHeading": params.label.isPageHeading, - "attributes": params.label.attributes, - "for": params.id - }) }} - {%- endif -%} -{% if params.hint %} - {% set hintId = params.id|default(params.name) + "-hint" %} - {% set describedBy = describedBy + " " + hintId if describedBy else hintId %} - {{ govukHint({ - "id": hintId, - "classes": params.hint.classes, - "attributes": params.hint.attributes, - "html": params.hint.html, - "text": params.hint.text - }) }} -{% endif %} -{% if params.errorMessage %} - {% set errorId = params.id|default(params.name) + '-error' %} - {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} - {{ govukErrorMessage({ - "id": errorId, - "classes": params.errorMessage.classes, - "attributes": params.errorMessage.attributes, - "html": params.errorMessage.html, - "text": params.errorMessage.text - }) }} -{% endif %} - -
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/breadcrumbs/macro.html b/controlpanel/frontend/static/components/breadcrumbs/macro.html deleted file mode 100644 index 5c8f60d24..000000000 --- a/controlpanel/frontend/static/components/breadcrumbs/macro.html +++ /dev/null @@ -1,19 +0,0 @@ -{% macro govukBreadcrumbs(params) %} -
-
    - {% for item in params['items'] %} - {% if item.href %} -
  1. - {{ item.html | safe if item.html else item.text }} -
  2. - {% else %} -
  3. {{ item.html | safe if item.html else item.text }}
  4. - {% endif %} - {% endfor %} -
-
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/checkboxes/macro.html b/controlpanel/frontend/static/components/checkboxes/macro.html deleted file mode 100644 index 64b966f3d..000000000 --- a/controlpanel/frontend/static/components/checkboxes/macro.html +++ /dev/null @@ -1,108 +0,0 @@ -{% from "error-message/macro.html" import govukErrorMessage -%} -{% from "fieldset/macro.html" import govukFieldset %} -{% from "hint/macro.html" import govukHint %} -{% from "label/macro.html" import govukLabel %} - -{% macro govukCheckboxes(params) %} - -{#- If an id 'prefix' is not passed, fall back to using the name attribute - instead. We need this for error messages and hints as well -#} -{% set idPrefix = params.idPrefix if params.idPrefix else params.name %} - -{#- a record of other elements that we need to associate with the input using - aria-describedby – for example hints or error messages -#} -{% set describedBy = "" %} - -{% set isConditional = false %} -{% for item in params["items"] %} - {% if item.conditional %} - {% set isConditional = true %} - {% endif %} -{% endfor %} - -{#- fieldset is false by default -#} -{% set hasFieldset = true if params.fieldset else false %} - -{#- Capture the HTML so we can optionally nest it in a fieldset -#} -{% set innerHtml %} -{% if params.hint %} - {% set hintId = idPrefix + '-hint' %} - {% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %} - {{ govukHint({ - "id": hintId, - "classes": params.hint.classes, - "attributes": params.hint.attributes, - "html": params.hint.html, - "text": params.hint.text - }) }} -{% endif %} -{% if params.errorMessage %} - {% set errorId = idPrefix + '-error' %} - {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} - {{ govukErrorMessage({ - "id": errorId, - "classes": params.errorMessage.classes, - "attributes": params.errorMessage.attributes, - "html": params.errorMessage.html, - "text": params.errorMessage.text - }) }} -{% endif %} -
- {% for item in params["items"] %} - {% set id = item.id if item.id else idPrefix + "-" + loop.index|string %} - {% set name = item.name if item.name else params.name %} - {% set conditionalId = "conditional-" + id %} - {% set hasHint = item.hint and (item.hint.text or item.hint.html) %} - {% set itemHintId = id + '-item-hint' %} -
- 0) %} aria-describedby="{{ describedBy }}"{% endif -%} - {%- if item.conditional %} data-aria-controls="{{ conditionalId }}"{% endif -%} - {%- if hasHint %} aria-describedby="{{ itemHintId }}"{% endif -%} - {%- for attribute, value in item.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}> - {{ govukLabel({ - "html": item.html, - "text": item.text, - "classes": 'govuk-checkboxes__label' + (' ' + (item.label|default({})).classes|default("")), - "attributes": (item.label|default({})).attributes|default(""), - "for": id - }) }} - {%- if hasHint %} - {{ govukHint({ - "id": itemHintId, - "classes": 'govuk-checkboxes__hint', - "attributes": item.hint.attributes, - "html": item.hint.html, - text: item.hint.text - }) }} - {%- endif %} -
- {% if item.conditional %} -
- {{ item.conditional.html | safe }} -
- {% endif %} - {% endfor %} -
-{% endset -%} - -
-{% if params.fieldset %} - {% call govukFieldset({ - "describedBy": describedBy, - "classes": params.fieldset.classes, - "attributes": params.fieldset.attributes, - "legend": params.fieldset.legend - }) %} - {{ innerHtml }} - {% endcall %} -{% else %} - {{ innerHtml }} -{% endif %} -
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/error-message/macro.html b/controlpanel/frontend/static/components/error-message/macro.html deleted file mode 100644 index 22ab59961..000000000 --- a/controlpanel/frontend/static/components/error-message/macro.html +++ /dev/null @@ -1,5 +0,0 @@ -{% macro govukErrorMessage(params) %} - - {{ params.html | safe if params.html else params.text }} - -{% endmacro %} diff --git a/controlpanel/frontend/static/components/fieldset/macro.html b/controlpanel/frontend/static/components/fieldset/macro.html deleted file mode 100644 index c5dbe5b80..000000000 --- a/controlpanel/frontend/static/components/fieldset/macro.html +++ /dev/null @@ -1,26 +0,0 @@ -{% macro govukFieldset(params) %} -
- {% if params.legend.html or params.legend.text %} - - {%- if params.legend.isPageHeading %} -

- {{ params.legend.html | safe if params.legend.html else params.legend.text }} -

- {% else %} - {{ params.legend.html | safe if params.legend.html else params.legend.text }} - {% endif -%} -
- {% endif %} - {% if params.help_text -%} - - {{ params.help_text }} - - {%- endif %} - {% if caller %} - {{ caller() }} {#- if statement allows usage of `call` to be optional -#} - {% endif %} -
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/footer/macro.html b/controlpanel/frontend/static/components/footer/macro.html deleted file mode 100644 index 0f1306120..000000000 --- a/controlpanel/frontend/static/components/footer/macro.html +++ /dev/null @@ -1,89 +0,0 @@ -{% macro footerList(items, inline=False, classes="") %} - {%- set list_type = "list" %} - {%- if inline %}{% set list_type = "inline-list" %}{% endif %} - -{% endmacro %} - -{% macro govukFooter(params) %} - -{% endmacro %} diff --git a/controlpanel/frontend/static/components/header/macro.html b/controlpanel/frontend/static/components/header/macro.html deleted file mode 100644 index 09250031c..000000000 --- a/controlpanel/frontend/static/components/header/macro.html +++ /dev/null @@ -1,77 +0,0 @@ -{% macro mojHeader(params) %} - -{% endmacro %} diff --git a/controlpanel/frontend/static/components/hint/macro.html b/controlpanel/frontend/static/components/hint/macro.html deleted file mode 100644 index b66e01f4d..000000000 --- a/controlpanel/frontend/static/components/hint/macro.html +++ /dev/null @@ -1,6 +0,0 @@ -{% macro govukHint(params) %} - - {{ params.html|default(params.text)|safe }} - -{% endmacro %} diff --git a/controlpanel/frontend/static/components/input/macro.html b/controlpanel/frontend/static/components/input/macro.html deleted file mode 100644 index c5ebdeb03..000000000 --- a/controlpanel/frontend/static/components/input/macro.html +++ /dev/null @@ -1,48 +0,0 @@ -{% from "error-message/macro.html" import govukErrorMessage -%} -{% from "hint/macro.html" import govukHint %} -{% from "label/macro.html" import govukLabel %} - -{% macro govukInput(params) %} -{#- a record of other elements that we need to associate with the input using - aria-describedby – for example hints or error messages -#} -{% set describedBy = "" %} -
- {{ govukLabel({ - "html": params.label.html, - "text": params.label.text, - "classes": params.label.classes, - "isPageHeading": params.label.isPageHeading, - "attributes": params.label.attributes, - "for": params.id - }) }} -{% if params.hint %} - {% set hintId = params.id|default(params.name) + '-hint' %} - {% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %} - {{ govukHint({ - "id": hintId, - "classes": params.hint.classes, - "attributes": params.hint.attributes, - "html": params.hint.html, - "text": params.hint.text - }) }} -{% endif %} -{% if params.errorMessage %} - {% set errorId = params.id|default(params.name) + '-error' %} - {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} - {{ govukErrorMessage({ - "id": errorId, - "classes": params.errorMessage.classes, - "attributes": params.errorMessage.attributes, - "html": params.errorMessage.html, - "text": params.errorMessage.text - }) }} -{% endif %} - -
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/label/macro.html b/controlpanel/frontend/static/components/label/macro.html deleted file mode 100644 index 502a91c2f..000000000 --- a/controlpanel/frontend/static/components/label/macro.html +++ /dev/null @@ -1,17 +0,0 @@ -{% macro govukLabel(params) %} -{% if params.html or params.text %} -{% set labelHtml %} - -{% endset %} - -{% if params.isPageHeading %} -

{{ labelHtml | safe | indent(2) }}

-{% else %} -{{ labelHtml | safe }} -{% endif %} -{% endif %} -{% endmacro %} diff --git a/controlpanel/frontend/static/components/modal-dialog/_modal-dialog.scss b/controlpanel/frontend/static/components/modal-dialog/_modal-dialog.scss deleted file mode 100644 index b94c1c8fc..000000000 --- a/controlpanel/frontend/static/components/modal-dialog/_modal-dialog.scss +++ /dev/null @@ -1,41 +0,0 @@ -.modal-dialog--trigger { - display: inline-block; - position: relative; - width: 16px; - height: 16px; - border: none; - border-radius: 50%; - background-color: govuk-colour("light-grey"); - top: 2px; - left: 2px; - - span { - display: none; - } - - &:before { - content: '?'; - position: absolute; - font-style: normal; - font-weight: 400; - font-size: 14px; - width: 16px; - height: 16px; - text-indent: center; - cursor: pointer; - left: 5px; - top: 1px; - } - - &:hover { - background-color: govuk-colour("mid-grey"); - } -} - -.modal-dialog { - max-width: 500px; - - &::backdrop { - background: rgba(0,0,0,0.8); - } -} diff --git a/controlpanel/frontend/static/components/modal-dialog/macro.html b/controlpanel/frontend/static/components/modal-dialog/macro.html deleted file mode 100644 index 8485bf997..000000000 --- a/controlpanel/frontend/static/components/modal-dialog/macro.html +++ /dev/null @@ -1,22 +0,0 @@ -{# HACK: Count dialogs in a template to generate IDs #} -{% set dialogs = [] %} -{% macro generate_dialog_id() -%} -{# Add to the list of dialogs to increment the ID counter #} -{%- set _ = dialogs.append(1) -%} -dialog-{{ dialogs|length }} -{%- endmacro %} - -{% macro modal_dialog(body, trigger="What's this?") %} -{% set id %}{{ generate_dialog_id() }}{% endset %} - - {{ trigger }} - - - -
- -
-
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/modal-dialog/modal-dialog.js b/controlpanel/frontend/static/components/modal-dialog/modal-dialog.js deleted file mode 100644 index b6c5515d9..000000000 --- a/controlpanel/frontend/static/components/modal-dialog/modal-dialog.js +++ /dev/null @@ -1,19 +0,0 @@ -moj.Modules.modals = { - triggerClass: '.modal-dialog--trigger', - - init() { - const triggers = document.querySelectorAll(this.triggerClass); - if (triggers.length) { - this.bindEvents(); - } - }, - - bindEvents() { - document.querySelectorAll(this.triggerClass).forEach(trigger => { - trigger.addEventListener("click", event => { - const dialog = document.getElementById(trigger.dataset.dialogId); - dialog.showModal(); - }); - }); - }, -}; diff --git a/controlpanel/frontend/static/components/navbar/macro.html b/controlpanel/frontend/static/components/navbar/macro.html deleted file mode 100644 index 21cc5f8f6..000000000 --- a/controlpanel/frontend/static/components/navbar/macro.html +++ /dev/null @@ -1,38 +0,0 @@ -{% macro mojPrimaryNavigation(params) %} -
- -
- -
- - - -
- - {%- if params.searchHtml %} - - {% endif -%} - -
- -
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/radios/macro.html b/controlpanel/frontend/static/components/radios/macro.html deleted file mode 100644 index d31be12d9..000000000 --- a/controlpanel/frontend/static/components/radios/macro.html +++ /dev/null @@ -1,106 +0,0 @@ -{% from "error-message/macro.html" import govukErrorMessage -%} -{% from "fieldset/macro.html" import govukFieldset %} -{% from "hint/macro.html" import govukHint %} -{% from "label/macro.html" import govukLabel %} - -{% macro govukRadios(params) %} - -{#- If an id 'prefix' is not passed, fall back to using the name attribute - instead. We need this for error messages and hints as well -#} -{% set idPrefix = params.idPrefix if params.idPrefix else params.name %} - -{#- a record of other elements that we need to associate with the input using - aria-describedby – for example hints or error messages -#} -{% set describedBy = "" %} - -{% set isConditional = false %} -{% for item in params['items'] %} - {% if item.conditional %} - {% set isConditional = true %} - {% endif %} -{% endfor %} - -{#- Capture the HTML so we can optionally nest it in a fieldset -#} -{% set innerHtml %} -{% if params.hint %} - {% set hintId = idPrefix + '-hint' %} - {% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %} - {{ govukHint({ - "id": hintId, - "classes": params.hint.classes, - "attributes": params.hint.attributes, - "html": params.hint.html, - "text": params.hint.text - }) }} -{% endif %} -{% if params.errorMessage %} - {% set errorId = idPrefix + '-error' %} - {% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %} - {{ govukErrorMessage({ - "id": errorId, - "classes": params.errorMessage.classes, - "attributes": params.errorMessage.attributes, - "html": params.errorMessage.html, - "text": params.errorMessage.text - }) }} -{% endif %} -
- {% for item in params['items'] %} - {% set id = item.id if item.id else idPrefix + "-" + loop.index|string %} - {% set conditionalId = "conditional-" + id %} - {%- if item.divider %} -
{{ item.divider }}
- {%- elif not item.hide %} - {% set hasHint = item.hint and (item.hint.text or item.hint.html) %} - {% set itemHintId = id + '-item-hint' %} -
- - {{ govukLabel({ - "html": item.html, - "text": item.text, - "classes": 'govuk-radios__label' + (' ' + (item.label|default({})).classes|default("")), - "attributes": (item.label|default({})).attributes|default(""), - "for": id - }) }} - {%- if hasHint %} - {{ govukHint({ - "id": itemHintId, - "classes": 'govuk-radios__hint', - "attributes": item.hint.attributes, - "html": item.hint.html, - "text": item.hint.text - }) }} - {%- endif %} -
- {% if item.conditional %} -
- {{ item.conditional.html | safe }} -
- {% endif %} - {% endif %} - {% endfor %} -
-{% endset -%} - -
-{% if params.fieldset %} - {% call govukFieldset({ - "describedBy": describedBy, - "classes": params.fieldset.classes, - "attributes": params.fieldset.attributes, - "legend": params.fieldset.legend - }) %} - {{ innerHtml }} - {% endcall %} -{% else %} - {{ innerHtml }} -{% endif %} -
-{% endmacro %} diff --git a/controlpanel/frontend/static/components/selectable-rows/_selectable-rows.scss b/controlpanel/frontend/static/components/selectable-rows/_selectable-rows.scss deleted file mode 100644 index f4b074461..000000000 --- a/controlpanel/frontend/static/components/selectable-rows/_selectable-rows.scss +++ /dev/null @@ -1,29 +0,0 @@ -table.selectable-rows { - - $row-padding: 5px; - - & tr td { - cursor: pointer; - & button { - transition: opacity 0.5s; - } - } - - & tr td:nth-of-type(2) { - padding-left: $row-padding; - } - - & tr td:last-of-type { - padding-right: $row-padding; - } - - & tr.selectable-rows__row-selected { - background-color: govuk-colour("blue"); - color: govuk-colour("white"); - } - - & th:first-of-type, - & td:first-of-type { - display: none; - } -} diff --git a/controlpanel/frontend/static/components/selectable-rows/macro.html b/controlpanel/frontend/static/components/selectable-rows/macro.html deleted file mode 100644 index 1a2ecd62c..000000000 --- a/controlpanel/frontend/static/components/selectable-rows/macro.html +++ /dev/null @@ -1,3 +0,0 @@ -{% macro row_selector(name, value) %} - -{% endmacro %} diff --git a/controlpanel/frontend/static/components/selectable-rows/selectable-rows.js b/controlpanel/frontend/static/components/selectable-rows/selectable-rows.js deleted file mode 100644 index 2dcd1e8a9..000000000 --- a/controlpanel/frontend/static/components/selectable-rows/selectable-rows.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Module to allow selecting entire rows in a table instead of using a small checkbox. - * - * It will disable any in-row actions buttons once a selection is made, but will re-enable them once - * all the selections are cleared. - * - * It can optionally support enabling a (global) - * button(s) that lives outside the table. - * How to use: - * 1. Add the class "selectable-rows" to your - * 2. For any button you want to enable when there are selections add the class "selectable-rows__enable-on-selections" - * 3. Use the macro `row_selector` to put insert an invisible input box in the first column of your table - * The module will automatically disable any action buttons that are in side the row. - * - * WARNING: This module doesn't support more than 1 table on the same page - * @type {{init(): void, onSelectionChanged(*): void, baseClass: string, bindEvents(): void}} - */ - -moj.Modules.selectable_rows = { - baseClass: "selectable-rows", - - init() { - this.tableRowSelector = `.${this.baseClass} tr`; - this.tableRowButtonSelector = `${this.tableRowSelector} button`; - this.selectionClass = `${this.baseClass}__row-selected`; - this.enableOnSelectionSelector = `.${this.baseClass}__enable-on-selections`; - this.selectionChangedEventName = `${this.baseClass}:rowSelectionChanged`; - if (document.querySelector(this.tableRowSelector)) { - this.bindEvents(); - } - }, - - /** - * Runs when rows are selected/deselected - * @param event - */ - onSelectionChanged(event) { - const rowButtons = document.querySelectorAll(this.tableRowButtonSelector); - const enableOnSelectionButtons = document.querySelectorAll( - this.enableOnSelectionSelector - ); - if (event.detail.rowsSelected.length > 0) { - // some rows are selected - rowButtons.forEach(e => (e.disabled = true)); - enableOnSelectionButtons.forEach(e => e.disabled = false); - } else { - rowButtons.forEach(e => (e.disabled = false)); - enableOnSelectionButtons.forEach(e => e.disabled = true); - } - }, - - bindEvents() { - window.addEventListener(this.selectionChangedEventName, e => - this.onSelectionChanged(e) - ); - document.querySelectorAll(this.tableRowSelector).forEach(row => { - row.addEventListener("click", event => { - const checkbox = row.querySelector( - "input[type='checkbox'].row-selector" - ); - - // user clicks on the button, don't select the row - if (event.target.tagName === "BUTTON") { - return true; - } - if (checkbox) { - // user clicks somewhere on the row that isn't the checkbox itself - if (event.target !== checkbox) { - checkbox.checked = !checkbox.checked; - } - // make row state match state of checkbox - if (checkbox.checked) { - row.classList.add(this.selectionClass); - } else { - row.classList.remove(this.selectionClass); - } - - const rowSelectionChangedEvent = new CustomEvent( - this.selectionChangedEventName, - { - bubbles: true, - detail: { - rowsSelected: row - .closest("table") - .querySelectorAll(`tr.${this.selectionClass}`) - } - } - ); - event.target.dispatchEvent(rowSelectionChangedEvent); - } - }); - }); - } -}; diff --git a/controlpanel/frontend/static/components/selectable-rows/selectable-rows.test.js b/controlpanel/frontend/static/components/selectable-rows/selectable-rows.test.js deleted file mode 100644 index 7be946b7e..000000000 --- a/controlpanel/frontend/static/components/selectable-rows/selectable-rows.test.js +++ /dev/null @@ -1,117 +0,0 @@ -const simulant = require('jsdom-simulant'); -require('./selectable-rows'); - -describe('selectable-rows', () => { - beforeEach(() => { - document.documentElement.innerHTML = ` - - - - -
- - - - - - - - - - - - - - - - - - - -
CustomerActions
- - fake@fake - -
- - fake@fake - -
- - - - `; - }); - describe('init()', () => { - test('that bindEvents is called in init - if selector present', () => { - const spy = jest.spyOn(moj.Modules.selectable_rows, 'bindEvents'); - moj.Modules.selectable_rows.init(); - expect(spy).toHaveBeenCalled(); - }); - test('that bindEvents is not called - if selector not present', () => { - document.documentElement.innerHTML = ``; - const spy = jest.spyOn(moj.Modules.selectable_rows, 'bindEvents'); - moj.Modules.selectable_rows.init(); - expect(spy).not.toHaveBeenCalled(); - }); - test('selectors are initialised', () => { - moj.Modules.selectable_rows.init(); - expect(moj.Modules.selectable_rows.tableRowSelector).not.toBeUndefined(); - expect(moj.Modules.selectable_rows.tableRowButtonSelector).not.toBeUndefined(); - expect(moj.Modules.selectable_rows.selectionClass).not.toBeUndefined(); - expect(moj.Modules.selectable_rows.enableOnSelectionSelector).not.toBeUndefined(); - expect(moj.Modules.selectable_rows.selectionChangedEventName).not.toBeUndefined(); - }); - }); - describe("events", () => { - beforeEach(() => { - moj.Modules.selectable_rows.init(); - }); - - test("click on row selects the checkbox on the row", () => { - const rowElem = document.getElementById('row1'); - const checkbox = rowElem.querySelector('input.row-selector'); - expect(checkbox.checked).toBe(false); - simulant.fire(rowElem, 'click'); - expect(checkbox.checked).toBe(true); - }); - test("click on row twice leaves the row deselected", () => { - const rowElem = document.getElementById('row1'); - const checkbox = rowElem.querySelector('input.row-selector'); - expect(checkbox.checked).toBe(false); - simulant.fire(rowElem, 'click'); - expect(checkbox.checked).toBe(true); - simulant.fire(rowElem, 'click'); - expect(checkbox.checked).toBe(false); - }); - test("click on row enables 'enable-on-selections' button", () => { - const rowElem = document.getElementById('row1'); - const mutliActionButton = document.getElementById('outsideButton'); - expect(mutliActionButton).toBeDisabled(); - simulant.fire(rowElem, 'click'); - expect(mutliActionButton).not.toBeDisabled(); - }); - test("click on row disables row action button", () => { - const rowElem = document.getElementById('row1'); - const rowButtons = document.querySelectorAll('.rowButton'); - rowButtons.forEach(elem => expect(elem).not.toBeDisabled()); - simulant.fire(rowElem, 'click'); - rowButtons.forEach(elem => expect(elem).toBeDisabled()); - }); - test("click on row button doesn't select row", () => { - const rowElem = document.getElementById('row1'); - const rowButton = rowElem.querySelector('.rowButton'); - const checkbox = rowElem.querySelector('input.row-selector'); - - expect(checkbox.checked).toBe(false); - - simulant.fire(rowButton, 'click'); - - expect(checkbox.checked).toBe(false); - }); - }); -}); diff --git a/controlpanel/frontend/static/components/skip-link/macro.html b/controlpanel/frontend/static/components/skip-link/macro.html deleted file mode 100644 index 1d3560456..000000000 --- a/controlpanel/frontend/static/components/skip-link/macro.html +++ /dev/null @@ -1,5 +0,0 @@ -{% macro govukSkipLink(params) %} - - {{- params.html | safe if params.html else params.text -}} - -{% endmacro %} diff --git a/controlpanel/frontend/static/components/table/_table.scss b/controlpanel/frontend/static/components/table/_table.scss deleted file mode 100644 index f4212f5f6..000000000 --- a/controlpanel/frontend/static/components/table/_table.scss +++ /dev/null @@ -1,8 +0,0 @@ -.govuk-table__foot { - - .govuk-table__header, - .govuk-table__cell { - border-bottom: none; - color: $govuk-secondary-text-colour; - } -} diff --git a/controlpanel/frontend/static/components/tag/_tag.scss b/controlpanel/frontend/static/components/tag/_tag.scss deleted file mode 100644 index f9ec1332b..000000000 --- a/controlpanel/frontend/static/components/tag/_tag.scss +++ /dev/null @@ -1,14 +0,0 @@ -.govuk-tag { - - &.cpanel-tag--warning { - background-color: govuk-colour("red"); - } - - &.cpanel-tag--idled { - background-color: govuk-colour("dark-grey"); - } - - &.cpanel-tag--deploying { - background-color: govuk-colour("yellow"); - } -} diff --git a/controlpanel/frontend/static/components/tag/macro.html b/controlpanel/frontend/static/components/tag/macro.html deleted file mode 100644 index 4c651543b..000000000 --- a/controlpanel/frontend/static/components/tag/macro.html +++ /dev/null @@ -1,3 +0,0 @@ -{% macro tag(value, type="") -%} -{{ value }} -{%- endmacro %} diff --git a/controlpanel/frontend/static/components/user/macro.html b/controlpanel/frontend/static/components/user/macro.html deleted file mode 100644 index 778862092..000000000 --- a/controlpanel/frontend/static/components/user/macro.html +++ /dev/null @@ -1,3 +0,0 @@ -{% macro user_name(user) -%} -{% if user.name %}{{ user.name }} {% endif %}({{ user.username }}) -{%- endmacro %} diff --git a/controlpanel/frontend/static/css/app.css b/controlpanel/frontend/static/css/app.css new file mode 100644 index 000000000..643b8affd --- /dev/null +++ b/controlpanel/frontend/static/css/app.css @@ -0,0 +1,41 @@ +/* +App specific CSS. + +We use plain old fashioned (modern) CSS. See gd.css for a classic example of +this art. +*/ + +#footer-crest { + /* Image positioning for the crest in the footer */ + margin-left: auto; + margin-right: auto; +} + +/* Responsive embedding of video iframes */ +.responsive-video { + position: relative; + padding-bottom: 56.10%; + height: 0; + overflow: hidden; + border: 2px solid var(--color-body); + margin: 0; +} + +.responsive-video iframe, +.responsive-video object, +.responsive-video embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} + +/* Attention exclamation mark. */ +.attention { + vertical-align: middle; + display: inline; + margin-right: 8px; +} + diff --git a/controlpanel/frontend/static/css/gd.css b/controlpanel/frontend/static/css/gd.css new file mode 100644 index 000000000..329a825c3 --- /dev/null +++ b/controlpanel/frontend/static/css/gd.css @@ -0,0 +1,1062 @@ +:root { + --unit: 1rem; + --unit-2: 2rem; + --unit-3: 3rem; + --leading: 1.4; + --measure: 960px; + --measure-min: 288px; + --font: -apple-system, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + --font-header: var(--font); + --color-body: #1a1a1a; + --color-body-light: #626A6E; + --color-body-inverted: #fff; + --color-select: #b3d4fc; + --color-access: #fd0; + --color-error: #f00; + --color-line: #b1b4b6; + --color-light: #505050; + --color-very-light: #f3f2f1; + --color-primary: #005ea5; + --color-primary-hover: #003078; + --color-primary-active: #2b8cc4; + --color-primary-visited: #4c2c92; + --color-secondary: #005a30; + --color-secondary-hover: #003E21; + --color-secondary-active: #003E21; + --color-secondary-visited: #00703c; + --color-tertiary: #942514; + --color-tertiary-hover: #6F0000; + --color-tertiary-active: #6F0000; + --color-tertiary-visited: #6F0000 +} + +.hide { + position: absolute; + left: -10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden +} + +::placeholder { + color: var(--color-body-light) +} + +::selection { + background: var(--color-select); + text-shadow: none +} + +html { + margin: 0; + padding: 0; + background: var(--color-body) +} + +body { + background: var(--color-body-inverted); + margin: 0; + padding: 0; + font-family: var(--font); + font-size: 100%; + line-height: var(--leading); + color: var(--color-body) +} + +header { + background: var(--color-body); + color: var(--color-body-inverted); + padding: var(--unit); + overflow: hidden; + /* display: grid */ +} + +main header { + padding-top: var(--unit-2); + padding-bottom: var(--unit-2); + color: var(--color-body); + background: none; + text-align: center +} + +nav { + /* display: grid; */ + /* max-width: calc(var(--measure) - var(--unit-2)); */ + /* grid-template-columns: repeat(auto-fit, 1fr); */ + /* margin: var(--unit) auto; */ + /* padding: 0 var(--unit-1); */ + /* width: 100% */ +} + +nav ol, nav ul { + font-size: 1rem +} + +header nav { + /* padding: 0 var(--unit) */ + max-width: var(--measure); + margin: 0 auto; +} + +header nav :last-child { + text-align: right +} + +nav a { + color: var(--color-body) +} + +nav ol, nav ul { + margin: var(--unit) 0; + padding: 0 +} + +header+nav { + border-top: 10px solid var(--color-primary); + max-width: var(--measure); + margin: 0 auto var(--unit); + padding: 0 var(--unit) +} + +nav li { + display: inline +} + +header nav li+li { + margin-left: var(--unit) +} + +header+nav li+li:before { + content: ''; + display: inline-block; + width: .5em; + height: .5em; + border: none; + border-top: 1px solid var(--color-line); + border-right: 1px solid var(--color-line); + transform: rotate(45deg); + margin: 0 .5em 0 0 +} + +article, main { + padding: 0 var(--unit); + margin: 0 auto; + max-width: var(--measure) +} + +main article { + padding: var(--unit) 0; + max-width: 640px +} + +p { + font-size: 1.1875rem +} + +a { + color: var(--color-primary) +} + +a:hover { + color: var(--color-primary-hover) +} + +a:active { + color: var(--color-primary-active) +} + +a:focus { + outline-offset: 0; + outline: 3px solid transparent; + color: var(--color-body); + text-decoration: none; + background-color: var(--color-access); + box-shadow: 0 -2px var(--color-access), 0 2px var(--color-body) +} + +a[href="javascript:history.back()"]:before, a[href="#top"]:before, figcaption:before { + content: ''; + display: inline-block; + width: 0; + height: 0; + border-style: solid; + border-color: transparent; + border-right-color: transparent; + clip-path: polygon(0% 50%, 100% 100%, 100% 0%); + border-width: 5px 6px 5px 0; + border-right-color: inherit; + margin-right: .5em +} + +a[href="#top"]:before { + transform: rotate(90deg) +} + +a[href*="://"]:after { + content: ' ↗'; + text-decoration: none !important +} + +body>header a { + color: var(--color-body-inverted); + font-weight: 700; + text-decoration: none +} + +body>header a:hover { + text-decoration: underline; + color: var(--color-body-inverted) +} + +h1, h2, h3, h4, h5, h6 { + font-weight: bold; + line-height: 1.2; + margin: 1em 0 .6em; +} + +h1 { + font-size: 3.1579rem +} + +h2 { + font-size: 3rem +} + +h3 { + font-size: 2.25rem +} + +h4 { + font-size: 1.6875rem +} + +h5 { + font-size: 1.5rem +} + +h6 { + font-size: 1.1875rem +} + +hgroup { + margin-top: var(--unit-2); + padding: var(--unit-2) var(--unit-1) +} + +hgroup > :first-child { + font-weight: 400; + color: var(--color-body-light) +} + +hgroup :last-child { + font-weight: 700; + margin-top: -.25em +} + +hr { + background: var(--color-line); + height: 1px; + border: none; + margin: var(--unit-3) 0 +} + +section { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(var(--measure-min), 1fr)); + grid-column-gap: var(--unit-3) +} + +section header { + grid-column: 1/-1 +} + +section article { + grid-column: span 2; + padding-top: 0 +} + +form { + display: block; + margin: 0; + padding: 0 +} + +fieldset { + box-sizing: content-box; + position: relative; + border: 1px solid var(--color-line); + border-top: none; + border-right: none; + padding: 1rem; + margin: 0 0 var(--unit-2); + position: relative; + padding-top: 3rem +} + +fieldset:before { + content: ''; + border: 1px solid var(--color-line); + height: 3rem; + position: absolute; + top: -3.0625rem; + top: 0; + left: -1px; + right: -1px; + z-index: 0 +} + +fieldset:after { + content: ''; + border-right: 1px solid var(--color-line); + position: absolute; + top: 0; + bottom: -1px; + right: -1px +} + +legend { + display: block; + position: absolute; + top: 0; + margin: 0 0 0 -1.0625rem; + padding: var(--unit); + border: 1px solid var(--color-line); + border-bottom: none; + font-size: 1rem; + line-height: 1; + background: var(--color-body-inverted) +} + +legend:after { + content: ''; + border-top: 1px solid var(--color-body-inverted); + position: absolute; + bottom: -1px; + left: 0; + right: 0; + z-index: 2 +} + +label { + display: block; + margin-bottom: calc(var(--unit) / 2) +} + +button, input[type="submit"], input[type="button"], input[type="reset"] { + width: auto; + height: 2.5em; + background-color: var(--color-secondary); + border: 2px solid transparent; + box-shadow: var(--color-body) 0 2px 0 0; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: var(--font); + font-size: 1.1875rem; + font-weight: 400; + line-height: 1; + margin-bottom: var(--unit-2); + margin-top: 0; + text-align: center; + vertical-align: baseline; + -moz-appearance: none; + -moz-osx-font-smoothing: grayscale; + padding: 8px 10px 7px +} + +input[type="button"] { + background-color: var(--color-primary) +} + +input[type="button"]:hover { + background-color: var(--color-primary-hover) +} + +input[type="reset"] { + background-color: var(--color-tertiary) +} + +input[type="reset"]:hover { + background-color: var(--color-tertiary-hover) +} + +button:hover, input[type="submit"]:hover { + background: var(--color-secondary-hover) +} + +button:active, input[type="submit"]:active, input[type="button"]:active, input[type="reset"]:active { + transform: translateY(2px) +} + +fieldset button, fieldset input[type="submit"], input[type="button"], input[type="reset"] { + margin-bottom: 0 +} + +input[type="image"] { + width: 40px; + height: 40px; + padding: 0; + display: inline-block; + background: var(--color-body) +} + +input[type="search"] { + width: calc(100% - 40px); + display: inline-block; + float: left +} + +input, output { + display: inline-block; + font-size: 1.1875rem; + line-height: var(--leading); + font-family: var(--font); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-weight: 400; + box-sizing: border-box; + width: 100%; + height: 2.5rem; + margin-top: 0; + padding: 5px; + border: 2px solid var(--color-body); + border-radius: 0; + appearance: none +} + +output { + font-weight: 700 +} + +input[type="file"] { + padding: 0 7px 0 0; + border: none +} + +input[type="color"] { + width: 3rem +} + +input[type="checkbox"], input[type="radio"] { + position: absolute; + left: -10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden +} + +input[type="radio"]+label { + display: inline-block; + position: relative; + padding-left: 3.5rem; + padding-right: 2rem; + padding-bottom: 0.75rem; + cursor: pointer +} + +input[type="radio"]+label:before { + content: ""; + display: inline-block; + box-sizing: border-box; + position: absolute; + left: -.5rem; + top: 0; + margin-top: -.75rem; + vertical-align: baseline; + width: 3rem; + height: 3rem; + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"%3E%3Cg fill="none" fill-rule="evenodd" stroke="%23FFF" transform="translate(1 1)"%3E%3Ccircle cx="23.5" cy="23.5" r="21.5" fill="%23000" stroke-width="4"/%3E%3Ccircle cx="23.5" cy="23.5" r="14" fill="%23FFF" stroke-width="7"/%3E%3C/g%3E%3C/svg%3E'); + cursor: pointer; + background-size: cover +} + +input[type="radio"]:checked+label:before { + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"%3E%3Cg fill="%23000" fill-rule="evenodd" stroke="%23FFF" transform="translate(1 1)"%3E%3Ccircle cx="23.5" cy="23.5" r="21.5" stroke-width="4"/%3E%3Ccircle cx="23.5" cy="23.5" r="14" stroke-width="7"/%3E%3C/g%3E%3C/svg%3E') +} + +input[type="radio"]:focus+label:before { + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"%3E%3Cg fill="none" fill-rule="evenodd" transform="translate(1 1)"%3E%3Ccircle cx="23.5" cy="23.5" r="21.5" fill="%23000" stroke="%23FD0" stroke-width="4"/%3E%3Ccircle cx="23.5" cy="23.5" r="13" fill="%23FFF" stroke="%23FFF" stroke-width="6"/%3E%3C/g%3E%3C/svg%3E%0A') +} + +input[type="radio"]:focus:checked+label:before { + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"%3E%3Cg fill="%23000" fill-rule="evenodd" transform="translate(1 1)"%3E%3Ccircle cx="23.5" cy="23.5" r="21.5" stroke="%23FD0" stroke-width="4"/%3E%3Ccircle cx="23.5" cy="23.5" r="13" stroke="%23FFF" stroke-width="6"/%3E%3C/g%3E%3C/svg%3E') +} + +input[type="checkbox"]+label { + position: relative; + display: inline-block; + padding-left: 3.5rem; + padding-right: 2rem; + padding-bottom: 0.75rem; + cursor: pointer +} + +input[type="checkbox"]+label:before { + content: ""; + display: inline-block; + box-sizing: border-box; + position: absolute; + left: -.25rem; + top: 0; + margin-top: -.75rem; + vertical-align: baseline; + width: 3rem; + height: 3rem; + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 49"%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cpath fill="%23000" stroke="%23FFF" stroke-width="3" d="M2 2h45v45H2z"/%3E%3Cpath fill="%23FFF" stroke="%23000" stroke-width="2" d="M4.5 4.5h40v40h-40z"/%3E%3C/g%3E%3C/svg%3E%0A'); + cursor: pointer; + background-size: cover +} + +input[type="checkbox"]:checked+label:before { + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 49"%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cpath fill="%23000" stroke="%23FFF" stroke-width="3" d="M2 2.4h45v45H2z"/%3E%3Cpath fill="%23FFF" stroke="%23000" stroke-width="2" d="M4.5 5h40v40h-40z"/%3E%3Cpath fill="%23000" d="M15.6 23.4l5 5 12.7-12.8 3.6 3.6-16.3 16.2L12 27z"/%3E%3C/g%3E%3C/svg%3E') +} + +input[type="checkbox"]:focus+label:before { + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 49"%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cpath fill="%23000" stroke="%23FD0" stroke-width="3" d="M2 2h45v45H2z"/%3E%3Cpath fill="%23FFF" stroke="%23000" stroke-width="4" d="M5.5 5.5h38v38h-38z"/%3E%3C/g%3E%3C/svg%3E%0A') +} + +input[type="checkbox"]:focus:checked+label:before { + background: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 49"%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cpath fill="%23000" stroke="%23FD0" stroke-width="3" d="M2 2h45v45H2z"/%3E%3Cpath fill="%23FFF" stroke="%23000" stroke-width="4" d="M5.5 5.5h38v38h-38z"/%3E%3Cpath fill="%23000" d="M15.6 23l5 5 12.7-12.8 3.6 3.5L20.6 35 12 26.5z"/%3E%3C/g%3E%3C/svg%3E%0A') +} + +input:disabled { + cursor: default +} + +input[type="time"] { + width: 7rem +} + +input[type="date"], input[type="week"], input[type="month"] { + width: 14rem +} + +input[type="datetime"], input[type="datetime-local"] { + width: 16rem +} + +select { + font-size: 1.1875rem; + line-height: 1.25; + box-sizing: border-box; + font-family: var(--font); + font-weight: 400; + max-width: 100%; + min-width: 14rem; + height: 40px; + height: 2.5rem; + padding: 5px; + border: 2px solid var(--color-body); + border-radius: 0; + -webkit-border-radius: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +textarea { + display: block; + box-sizing: border-box; + width: 100%; + padding: 5px; + font-family: var(--font); + min-height: 5.375rem; + margin-bottom: var(--unit); + font-size: 1.1875rem; + line-height: 1.25; + font-weight: 400; + resize: vertical; + border: 2px solid var(--color-body); + border-radius: 0; + -webkit-appearance: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-box-sizing: border-box +} + +textarea:focus, input:focus, button:focus, select:focus { + outline: 3px solid var(--color-access); + outline-offset: 0; + box-shadow: inset 0 0 0 2px +} + +input[type=range] { + -webkit-appearance: none; + width: 100%; + margin: 0; + border: none; + padding: 0 +} + +input[type=range]:focus { + outline: none; + box-shadow: none +} + +input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 4px; + cursor: pointer; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); + background: rgba(80, 80, 80, 0.5); + border-radius: 0; + border: 0 solid #1a1a1a +} + +input[type=range]::-webkit-slider-thumb { + box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); + border: 2px solid #000; + height: 32px; + width: 33px; + border-radius: 32px; + background: #fff; + cursor: pointer; + -webkit-appearance: none; + margin-top: -14px +} + +input[type=range]:focus::-webkit-slider-runnable-track { + background: rgba(139, 139, 139, 0.5) +} + +input[type=range]::-moz-range-track { + width: 100%; + height: 4px; + cursor: pointer; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); + background: rgba(80, 80, 80, 0.5); + border-radius: 0; + border: 0 solid #1a1a1a +} + +input[type=range]::-moz-range-thumb { + box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); + border: 2px solid #000; + height: 32px; + width: 33px; + border-radius: 32px; + background: #fff; + cursor: pointer +} + +input[type=range]::-ms-track { + width: 100%; + height: 4px; + cursor: pointer; + background: transparent; + border-color: transparent; + color: transparent +} + +input[type=range]::-ms-fill-lower { + background: rgba(21, 21, 21, 0.5); + border: 0 solid #1a1a1a; + border-radius: 0; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0) +} + +input[type=range]::-ms-fill-upper { + background: rgba(80, 80, 80, 0.5); + border: 0 solid #1a1a1a; + border-radius: 0; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0) +} + +input[type=range]::-ms-thumb { + box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); + border: 2px solid #000; + height: 32px; + width: 33px; + border-radius: 32px; + background: #fff; + cursor: pointer; + height: 4px +} + +input[type=range]:focus::-ms-fill-lower { + background: rgba(80, 80, 80, 0.5) +} + +input[type=range]:focus::-ms-fill-upper { + background: rgba(139, 139, 139, 0.5) +} + +input[type=range]:focus::-webkit-slider-thumb, input[type=range]:focus::-moz-range-thumb, input[type=range]:focus::-ms-thumb { + box-shadow: 2px 2px 0 #fd0 +} + +address { + display: block; + margin: var(--unit) 0 +} + +strong, b { + font-weight: 700 +} + +em, i { + font-style: italic +} + +blockquote { + font-size: 1.1875rem; + padding: var(--unit); + margin: var(--unit-2) 0; + clear: both; + border-left: 10px solid var(--color-line) +} + +cite { + color: var(--color-body-h4); + opacity: .75; + font-style: italic; + padding: .5rem 0 +} + +blockquote q { + font-size: 1.5rem +} + +blockquote cite { + display: block; + font-size: 1rem +} + +q:before { + content: "“" +} + +q:after { + content: "”" +} + +ins { + color: var(--color-secondary) +} + +del { + color: var(--color-tertiary) +} + +code { + font-size: 1rem +} + +kbd { + font-size: 1rem; + background: black; + color: white; + outline: 0.2em solid black; +} + +mark { + font-size: 1rem; + background-color: var(--color-access); + outline: 0.2em solid var(--color-access) +} + +var { + display: inline-block; + color: #fff; + background-color: var(--color-primary); + border-radius: 0.1em; + letter-spacing: 1px; + text-decoration: none; + text-transform: uppercase; + font-style: normal; + font-weight: 700; + line-height: 1; + padding: 0.1em 0.2em; +} + +pre { + max-width: 100%; + display: block; + overflow: auto; + font-size: 1rem; + border: 0; + outline: 1px solid transparent; + background-color: var(--color-very-light); + margin: var(--unit) 0; + padding: var(--unit); + border: 1px solid var(--color-line) +} + +samp { + font-size: 1rem +} + +dl { + display: grid; + grid-column-gap: var(--unit-2); + grid-row-gap: var(--unit); + grid-template-columns: [dt] max-content [dd] 1fr; + margin: var(--unit) 0 var(--unit-2) +} + +dt { + font-weight: 700; + grid-column-start: dt; + grid-column-end: dt +} + +dd { + margin: 0; + padding: 0; + grid-column-start: dd; + grid-column-end: dd +} + +ul, ol { + line-height: var(--leading); + padding-left: 1.25rem; + margin: var(--unit) 0 var(--unit-2); + font-size: 1.1875rem +} + +ul { + list-style-type: disc; + padding-left: 1.25rem +} + +li { + margin-bottom: .3125rem +} + +summary, summary:hover { + margin-left: -1.5rem; + font-size: 1.1875rem; + color: var(--color-primary); + font-weight: 400; + cursor: pointer; + margin-bottom: 1rem +} + +summary:hover { + text-decoration: underline +} + +summary:active { + color: var(--color-primary-active); + text-decoration: underline +} + +summary:focus { + outline: 0 +} + +details { + position: relative; + padding: 0 0 0 1.5625rem; + margin-bottom: var(--unit) +} + +details[open]:before { + content: ''; + border-left: 10px solid var(--color-line); + position: absolute; + top: 2.2rem; + left: .125rem; + bottom: -.625rem +} + +table, table thead { + border-collapse: collapse; + border-radius: var(--border-radius); + padding: 0 +} + +table { + border: 1px solid var(--color-bg-secondary); + border-spacing: 0; + overflow-x: scroll; + overflow-y: hidden; + min-width: 100%; + overflow: scroll; + border: 0; + width: 100%; + table-layout: fixed +} + +caption { + padding: 0.5em 0; + color: var(--color-body-light) +} + +td, th, tr { + padding: .4rem .8rem; + text-align: var(--justify-important) +} + +thead { + background-color: var(--color); + margin: 0; + color: var(--color-text); + background: 0 0; + font-weight: 700 +} + +thead th:first-child { + border-top-left-radius: var(--border-radius) +} + +thead th:last-child { + border-top-right-radius: var(--border-radius) +} + +thead th:first-child, tr td:first-child { + text-align: var(--justify-normal) +} + +tr { + border-bottom: 1px solid gray +} + +tbody th { + text-align: left +} + +frame, frameset, iframe { + border: 2px solid var(--color-body); + margin: 0; + width: 100%; + height: auto +} + +img, picture { + display: block; + max-width: 100%; + height: auto +} + +figure { + margin: 0 0 var(--unit-2) +} + +figcaption { + padding: .5em 0; + color: var(--color-light); + font-size: 1rem +} + +figcaption:before { + transform: rotate(90deg) +} + +audio, embed, object, video, iframe { + width: 100%; +} + +progress, meter { + margin: var(--unit) 0; + width: 100%; + height: var(--unit); + border: none; + border-radius: .25rem; + overflow: hidden; + background: var(--color-very-light); + display: block; + --background: var(--color-very-light); + --optimum: #228b22; + --sub-optimum: #ffd700; + --sub-sub-optimum: #dc143c +} + +progress[value]::-webkit-progress-bar { + background: var(--color-very-light) +} + +progress[value]::-webkit-progress-value { + background: var(--color-primary) +} + +meter::-webkit-meter-bar { + background: var(--color-very-light) +} + +meter:-moz-meter-optimum::-moz-meter-bar { + background: var(--optimum) +} + +meter::-webkit-meter-optimum-value { + background: var(--optimum) +} + +meter:-moz-meter-sub-optimum::-moz-meter-bar { + background: var(--sub-optimum) +} + +meter::-webkit-meter-suboptimum-value { + background: var(--sub-optimum) +} + +meter:-moz-meter-sub-sub-optimum::-moz-meter-bar { + background: var(--sub-sub-optimum) +} + +meter::-webkit-meter-even-less-good-value { + background: var(--sub-sub-optimum) +} + +body>footer { + margin: 0; + margin-top: var(--unit-3); + padding: var(--unit-3) 0; + border-top: 1px solid var(--color-line); + background: var(--color-very-light); + overflow: hidden +} + +body>footer a { + color: var(--color-body) +} + +@media all and (min-width: 640px) { + nav { + display: flex; + } + nav > * { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + } +} + +@media all and (min-width: 960px) { + header+nav { + padding: 0; + } +} + +@media screen and (max-width:640px) { + table thead { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px + } + + table tr { + display: block; + border: 0 + } + + table td, table th { + display: block; + text-align: right !important; + border-bottom: 1px solid + } + + table td::before { + content: attr(data-label); + float: left; + font-weight: 700; + text-transform: uppercase + } +} diff --git a/controlpanel/frontend/static/img/attention.svg b/controlpanel/frontend/static/img/attention.svg new file mode 100644 index 000000000..f7a7d17bf --- /dev/null +++ b/controlpanel/frontend/static/img/attention.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/controlpanel/frontend/static/img/govuk-crest.png b/controlpanel/frontend/static/img/govuk-crest.png new file mode 100644 index 0000000000000000000000000000000000000000..bed4efe418aa66b19004c048d4ee232004ee802f GIT binary patch literal 3584 zcma)9_dgVl|3A)lMsYOkO=OR7+}URn;S$cu-tN+w*?T22Pvj$Ko`|@t?3sOLdJBcq z$yR*(6TXkfbN%pqJzhUQlg&-_nHcUc0000cxPgx4KacoFcRJud{bJ^4_Rr+ajjeS3 z(9i$>_;>WLEY5>W`IlHjEKMJpX9hIzl{rCW)+brJq7MLG)Rjj6Ui!dwU{=o@`U|)H zzNytj-~g;uGE&073cZCYNLFfR(_=~Bt{7sKDtgo9-Hm2)~0N^_C#S}b4wqX z1b>$ijp7Z14?M1cT!Gycq9`yJf$GJE$dFK$CR z1Z9nu{wPMW*RDWot23hHwVZgv!aUm9hz(H1%RU;JP1*8lrY`23Spk>}CSxuiJIeEk-((JF(`ccz zCacYiV78E^*eL&~-RvT#z)T4LwU2Td`Y|ASWiYCxqcx3581M*f@E_vp&-=0)iGPA# zrUAXK$LkyWRtYXmYlW1@y2_uH6S*%y$F#+Pu}5e%v0Sc#aF6<_#-;m4@U@L-jgL8pJ^!%!0pkHZrMFfxs6MYZcXyoIKqWjtRG%24qf=G9X!t7lA)6dQe!iB68vH62 zS5l}%`xA766NSu!M!W)20P`{RpYFd_whR>!I<(TZBFQUMxT% z{=BteWSly9@56}c$L!B9U>|ACZ&4my5F)AvHLm(t}A4NK2Hz=_{Z3BLiAeR@W9z32ZfS~;*WYu z__&sGrH0|^TgJO<1@j*h+Dgjv`bx9+#rW7SNY7XSmCVy#1m~c!A!~1T>+K{J(9S)& z``$b2wjrk|qat5o;+O)(l&$r>E;Sx`;HHjlBIRel?lA<;!$i1n4oL@Q1&8H&v?Pv(w)^t z3}G)aVaoZ&9zv;;#4rpfEN{=0Y~Scn5_%szm}4DFi{H9>N!tml(bkRrs)W2Pq$M$D zA0z3rGzEGib7GGf$dwY;$L~;?2e4S3OP@ZB zM3B&>0@5K^$K)Y^h>|7i%@5sp$g~zMCih4OEoss486819ab7&!wh=hcci{)}frIk4 zMVf0qkB|s~rWES=LaYGRhKZ6k+0}O#;F5eF!?Z8w=^9D@QEg8;wU!J#K}ENpPoSHf zUx+BHLp%z%2G??J%_ur)}D6O-qv%riOv=TMxk?9 zKQ+$e`6F&hGLJyVl+JFSSVVAm*2L?_b{%C9zIZrjD49A#o5(I^0 zQ%dQuV~6Wo8)uN(P0x~je*SxSTdBa|f73-AkgrO9|YP<%svVKMxR z!ok0e`faAt8L4Ci{%po5vQ}vksTn;P9wqAy-G)xg#UFOwPS_Y$z!vu;j+TBoZJ7Fj z$6W4Ql)tNBe*Y7+Slq;+{fOQWuw~fmhgiI93Eu&u+fcE8Yid7A)aI4O%pdgm+HS5& zx1=j;NOstGTxve&V(@++vAj*6$4a3c_M6uqIgjL zup!`FkL=E)->z=a8ewsGlfym^5)gbQQsG)jMKUjoP)fonv_Oh{*rS*BL0w4L(mm5R z&E+Rb7A^KC4A6^++BC>UWZkrk+Q4i}!=q_$P z-gD4M&qEO*0lh;jVZ97ROyhz5r3p$bc8cjPRas?m!7-xH6&4p7uQ=$N+X7%Xp^tg&^PBze@p*wV**9tgj-< z){Q`52y0CDq#8d2-)jHXO$Hn3=C9n&5hVD~vwE`mo`22_t1c2FBhkt|tE1so3iSmc zYr|A?B!&$-zDy;Y6)NxH!!QMd0q~f?sBhDXw8!DpVcwHK^Hknn>cOUUY7bIxK$At2 zR!Vk%3M*nq#C&N-U^pk(K1fFkzf6B#0PQ3$hmMgc7Gl&&n4rtMcy6HLWz&pzpUA;e z;w*_)H8<2$E_0^WdBkOarK31>jIFnLaR}ip!xQOX)dGr3qYjmK@SZQE2sv=3cUTB{ z?`wvipK|kGC=Qo%->Oqy2t6@pq@$fS{GANEL&^gj@svrye?QqCM(s#IHTIUL{@&Aj zH4=QGWt|!1uNmO?7FV3eGDp>Yxinst*H_PlkVlz?5XtYmvMYwQN>HD~RIr85f9$@k zf(fCbzO+0u>!YsL34WA1cOi=TeIN!4d!U?#1imnt%*fSl)Q zBhjlj&CE*lxEmO!d82>kM%#+KBd03SielXRrEfts&UOkjbh=!jhW z>LqcFj*i4sSB%47UKLrwHh0nm?n+#`ANyX;Gbgc5=|L>5C86%~d7-gCvd7Ru98&GL zewV*vzR61SxwtmKeUVqMpi;oxu9n@STs?NtDX>8>3eCIiA}^I1;;%&cF|kwI#j$d( zqhzW`rlU^IPo$@1OB4~X3uwi*E=dr;|u3yI(DYc!8tBzdI%WmhZ z6h+48&vuaTQFVyfFp^scyaReh7s%}2Q-m#%RuvzOEKsEoV^G)vjV@un@w!OANN;rO zYM6Lo?Ya!sG58XEe5amc7E9_erPkl1Fs^#SE0Dkb+@Xmcw>|hDN)}T8k|Eumw#l*a zjj)iT{RT^a?@}ftO0$GA{ygBkloFjY4xbdk!T!+TEIK60*7t45Mk7~Pih|5hf4Bwj z!q=mEbKCt#RbBi32{p`7NE_k4#EgmPHt#AySm#a+;_5>4wLIX51b{E+80zXQD-wOy zaFvSL9#opem;>-Q#%Yf!8U`0r#(uxt@2Gw-Mut(;&pa}yadG} z4mWwshLK~1Hnm-AUsfrMYqi006xpwVS1hM1c_*I9fersQ833+ps#CA!^y2>j&p*p@ literal 0 HcmV?d00001 diff --git a/controlpanel/frontend/static/img/logo.svg b/controlpanel/frontend/static/img/logo.svg new file mode 100644 index 000000000..2f561fc54 --- /dev/null +++ b/controlpanel/frontend/static/img/logo.svg @@ -0,0 +1,8 @@ + + + + + + Analytical Platform + + diff --git a/controlpanel/frontend/static/local/buttons.scss b/controlpanel/frontend/static/local/buttons.scss deleted file mode 100644 index aa55c0bc6..000000000 --- a/controlpanel/frontend/static/local/buttons.scss +++ /dev/null @@ -1,27 +0,0 @@ -.govuk-table__cell .govuk-button { - margin: 0; -} - -.govuk-button.right { - margin-left: 5px; -} - -.cpanel-button--destructive { - $cpanel-destructive-colour: govuk-colour("red"); - $cpanel-destructive-hover-colour: darken($cpanel-destructive-colour, 5%); - $cpanel-destructive-shadow-colour: darken($cpanel-destructive-colour, 15%); - - background-color: $cpanel-destructive-colour; - box-shadow: 0 2px 0 $cpanel-destructive-shadow-colour; - - &:active, - &:link, - &:visited,{ - background-color: $cpanel-destructive-colour; - } - - &:hover, - &:focus{ - background-color: $cpanel-destructive-hover-colour; - } -} diff --git a/controlpanel/frontend/static/local/forms.scss b/controlpanel/frontend/static/local/forms.scss deleted file mode 100644 index 7bc580f64..000000000 --- a/controlpanel/frontend/static/local/forms.scss +++ /dev/null @@ -1,10 +0,0 @@ -.form-control-prefix { - display: inline-block; -} - -.cpanel-input--1-3 { - width: 33.3%; -} - -.tool-action { -} diff --git a/controlpanel/frontend/static/local/layout.scss b/controlpanel/frontend/static/local/layout.scss deleted file mode 100644 index 03b45e510..000000000 --- a/controlpanel/frontend/static/local/layout.scss +++ /dev/null @@ -1,7 +0,0 @@ -.cpanel-section { - margin-bottom: govuk-spacing(9); - - &:last-of-type { - margin-bottom: none; - } -} diff --git a/controlpanel/frontend/static/local/markdown.scss b/controlpanel/frontend/static/local/markdown.scss deleted file mode 100644 index 38bfa98e9..000000000 --- a/controlpanel/frontend/static/local/markdown.scss +++ /dev/null @@ -1,29 +0,0 @@ -.markdown-container { - // since markdown won't render classes, formatting needs to be cascaded from a container - - padding-top: 20px; - - h1 { - @extend .govuk-heading-xl; - } - - h2 { - @extend .govuk-heading-l; - } - - h3 { - @extend .govuk-heading-m; - } - - ol, ul { - @extend .govuk-list; - } - - ul { - @extend .govuk-list--bullet; - } - - ol li { - list-style-type: decimal; - } -} diff --git a/controlpanel/frontend/static/local/messages.scss b/controlpanel/frontend/static/local/messages.scss deleted file mode 100644 index a3d2cc251..000000000 --- a/controlpanel/frontend/static/local/messages.scss +++ /dev/null @@ -1,49 +0,0 @@ -$message-color: $green; -$warning-color: $red; - -.flash-message { - @include bold-19; - color: $message-color; - border: 5px solid $message-color; - margin: 1em 0; - padding: 1em 2em 1em 1em; - position: relative; - cursor: pointer; - - &:after { - content: '\00d7'; - border-radius: 50%; - width: 1em; - height: 1em; - display: inline-block; - text-align: center; - color: $message-color; - - position: absolute; - right: 1em; - top: 1em; - } - - &:hover { - &:after { - color: $white; - background-color: $message-color; - } - } - - &.warning { - color: $warning-color; - border-color: $warning-color; - - &:after { - color: $warning-color; - } - - &:hover { - &:after { - color: $white; - background-color: $warning-color; - } - } - } -} diff --git a/controlpanel/frontend/static/local/mixins.scss b/controlpanel/frontend/static/local/mixins.scss deleted file mode 100644 index c7d2319f5..000000000 --- a/controlpanel/frontend/static/local/mixins.scss +++ /dev/null @@ -1,7 +0,0 @@ -@mixin clearfix { - &:after { - content:""; - display:block; - clear:both; - } -} diff --git a/controlpanel/frontend/static/local/modal.scss b/controlpanel/frontend/static/local/modal.scss deleted file mode 100644 index 2033fec5d..000000000 --- a/controlpanel/frontend/static/local/modal.scss +++ /dev/null @@ -1,39 +0,0 @@ -.modal-dialog--trigger { - display: inline-block; - position: relative; - width: 20px; - height: 20px; - border: none; - border-radius: 50%; - background-color: govuk-colour("light-grey"); - top: 4px; - - span { - display: none; - } - - &:before { - content: '?'; - position: absolute; - font-style: normal; - margin-left: 10px; - width: 20px; - height: 20px; - text-indent: center; - cursor: pointer; - left: -4px; - top: 1px; - } - - &:hover { - background-color: govuk-colour("mid-grey"); - } -} - -.modal-dialog { - max-width: 500px; - - &::backdrop { - background: rgba(0,0,0,0.8); - } -} diff --git a/controlpanel/frontend/static/local/panels.scss b/controlpanel/frontend/static/local/panels.scss deleted file mode 100644 index 48e72e36a..000000000 --- a/controlpanel/frontend/static/local/panels.scss +++ /dev/null @@ -1,5 +0,0 @@ -.change-data-access-level-panel { - padding-top: 0; - padding-bottom: 0; - text-align: left; -} diff --git a/controlpanel/frontend/static/local/rules.scss b/controlpanel/frontend/static/local/rules.scss deleted file mode 100644 index 1ebc9f1a3..000000000 --- a/controlpanel/frontend/static/local/rules.scss +++ /dev/null @@ -1,3 +0,0 @@ -hr { - clear: both; -} diff --git a/controlpanel/frontend/static/local/sign-out.scss b/controlpanel/frontend/static/local/sign-out.scss deleted file mode 100644 index 1d7b5c9f4..000000000 --- a/controlpanel/frontend/static/local/sign-out.scss +++ /dev/null @@ -1,16 +0,0 @@ -.sign-out { - background: none; - border: none; - cursor: pointer; - padding: 0; - color: govuk-colour("white"); - font-weight: 700; - font-size: 1rem; - line-height: 1.25; - white-space: nowrap; - @include govuk-link-common; - - &:hover { - text-decoration: underline; - } -} diff --git a/controlpanel/frontend/static/local/tables.scss b/controlpanel/frontend/static/local/tables.scss deleted file mode 100644 index d11f91709..000000000 --- a/controlpanel/frontend/static/local/tables.scss +++ /dev/null @@ -1,15 +0,0 @@ -table { - th, td { - @include core-16; - } - th { - font-weight: bold; - } - - tr { - th:last-child, - td:last-child { - padding-right: 0; - } - } -} diff --git a/controlpanel/frontend/static/local/tabs.scss b/controlpanel/frontend/static/local/tabs.scss deleted file mode 100644 index e1ba2449a..000000000 --- a/controlpanel/frontend/static/local/tabs.scss +++ /dev/null @@ -1,34 +0,0 @@ -ul.tabs { - @include clearfix; - - border-bottom: 1px solid $light-grey; - - li { - float: left; - display: block; - padding: 5px 10px; - cursor: pointer; - margin-right: 5px; - margin-bottom: -1px; - border: 1px solid $light-grey; - border-bottom: none; - background-color: $light-grey; - - &:hover { - border-color: $mid-grey; - } - - &.active { - font-weight: bold; - background-color: $white; - } - } -} - -section.tab-panel { - display: none; - - &.active { - display: block; - } -} diff --git a/controlpanel/frontend/static/local/typeahead.scss b/controlpanel/frontend/static/local/typeahead.scss deleted file mode 100644 index 77d9f3efb..000000000 --- a/controlpanel/frontend/static/local/typeahead.scss +++ /dev/null @@ -1,11 +0,0 @@ -.typeahead__container { - display: inline-block; - width: 33.33%; - @include core-16; -} - -.typeahead__field { - input { - border: 2px solid $black; - } -} diff --git a/controlpanel/frontend/static/local/typography.scss b/controlpanel/frontend/static/local/typography.scss deleted file mode 100644 index f1e4db518..000000000 --- a/controlpanel/frontend/static/local/typography.scss +++ /dev/null @@ -1,26 +0,0 @@ -strong { - font-weight: bold; -} - -ul { - @include core-16; -} - -.category-count { - display: block; - @include core-19; - color: $dark-grey; -} - -.highlight-current { - font-weight: bold; -} - -pre { - @include core-14; - font-family: monospace; -} - -label.heading-medium { - @include bold-24; -} diff --git a/controlpanel/frontend/static/local/utilities.scss b/controlpanel/frontend/static/local/utilities.scss deleted file mode 100644 index d297a7334..000000000 --- a/controlpanel/frontend/static/local/utilities.scss +++ /dev/null @@ -1,11 +0,0 @@ -.right { - float: right; -} - -.align-right { - text-align: right; -} - -.no-wrap { - white-space: nowrap; -} diff --git a/controlpanel/frontend/templates/500.html b/controlpanel/frontend/templates/500.html new file mode 100644 index 000000000..2fa22cbd2 --- /dev/null +++ b/controlpanel/frontend/templates/500.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

Sorry, there is a problem with the service

+ +

Try again later.

+ +

Contact the Analytical Platform team if you need to make +urgent changes to your webapps or data sources.

+{% endif %} diff --git a/controlpanel/frontend/templates/503.html b/controlpanel/frontend/templates/503.html new file mode 100644 index 000000000..47b201c41 --- /dev/null +++ b/controlpanel/frontend/templates/503.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% block content %} +

Sorry, the service is unavailable

+ +

Contact the Analytical Platform team if you need to make +urgent changes to your webapps or data sources.

+{% endblock %} diff --git a/controlpanel/frontend/templates/a11y.html b/controlpanel/frontend/templates/a11y.html new file mode 100644 index 000000000..4e35322ce --- /dev/null +++ b/controlpanel/frontend/templates/a11y.html @@ -0,0 +1,96 @@ +{% extends "base.html" %} + +{% block content %} +

Accessibility statement for the MoJ Analytical Platform

+ +

This accessibility statement applies to the Ministry of Justice's +Analytical Platform.

+ +

This service is run by Analytical Platform team of the Ministry of +Justice. We want as many people as possible to be able to use this service. +For example, on the Control Panel application (this website) you +should be able to:

+ +
    +
  • zoom in up to 300% without the text spilling off the screen
  • +
  • navigate most of the website using just a keyboard
  • +
  • navigate most of the website using speech recognition software
  • +
  • listen to most of the website using a screen reader (including the + most recent versions of JAWS, NVDA and VoiceOver)
  • +
+ +

We've also made our textual content as simple as possible to understand.

+ +

AbilityNet +has advice on making your device easier to use if you have a disability.

+ +

How accessible this service is

+ +

We know some parts of this service are not fully accessible:

+ +
    +
  • we understand there is reasonable accessibility compliance of + R Studio and Jupyter, and will be updating to the latest versions, but + there may be accessibility issues with older versions we provide via + this platform
  • +
  • you cannot change colours, contrast levels and fonts to aid + readability
  • +
+ +

Feedback and contact information

+ +

Any feedback and/or requests for help should be made via the +Analytical Platform +Slack Channel. We also have a +platform user guide +and +platform support documentation.

+ +

Reporting accessibility problems with this service

+ +

We're always looking to improve the accessibility of this service. If +you find any problems not listed on this page or think we're not meeting +accessibility requirements, please contact us via the links listed in the +feedback and contact information section.

+ +

Enforcement procedure

+ +

The Equality and Human Rights Commission (EHRC) is responsible for +enforcing the Public Sector Bodies (Websites and Mobile Applications) +(No. 2) Accessibility Regulations 2018 (the 'accessibility regulations'). +If you’re not happy with how we respond to your complaint, +contact the Equality Advisory and Support Service (EASS).

+ +

Technical information about this service’s accessibility

+ +

The Ministry of Justice's Analytical Platform team is committed to +making its service accessible, in accordance with the Public Sector Bodies +(Websites and Mobile Applications) (No. 2) Accessibility Regulations +2018.

+ +

Compliance status

+ +
    +
  • we have been through an accessibility checklist for the Control + Panel and believe it is compliant
  • +
  • we are in the process of booking a full accessibility audit of the + Analaytical Platform and will promptly update this statement
  • +
+ +

Preparation of this accessibility statement

+ +

This statement was prepared on 22nd October 2020. It was last reviewed +on 23rd October 2020.

+ +

This service was last tested on 27th August 2020. The test was carried +out by a member of the Analytical Platform team.

+ +

We checked all the pages in the Control Panel application (excluding +those that are parts of Jupyter, Airflow and RStudio) against +this accessibility +checklist.

+ +

A full accessibility audit by an independent third party will take +place very soon.

+{% endblock %} + diff --git a/controlpanel/frontend/templates/base.html b/controlpanel/frontend/templates/base.html new file mode 100644 index 000000000..6d1b21065 --- /dev/null +++ b/controlpanel/frontend/templates/base.html @@ -0,0 +1,39 @@ +{% load static %} + + + + + + {% block title %}MoJ Analytical Platform{% endblock %} + + + + + + + + + + {% block js %}{% endblock %} + + + + Skip to main content + + {% include "header.html" %} +
+ {% if messages %} +

+ Attention! + Attention: +

+ {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %} + {% block content %}{% endblock %} +
+ {% include "footer.html" %} + + + diff --git a/controlpanel/frontend/templates/footer.html b/controlpanel/frontend/templates/footer.html new file mode 100644 index 000000000..a813a1a77 --- /dev/null +++ b/controlpanel/frontend/templates/footer.html @@ -0,0 +1,16 @@ +{% load static %} + diff --git a/controlpanel/frontend/templates/header.html b/controlpanel/frontend/templates/header.html new file mode 100644 index 000000000..b2d5a3341 --- /dev/null +++ b/controlpanel/frontend/templates/header.html @@ -0,0 +1,33 @@ +{% load static i18n %} +
+ +
+ diff --git a/controlpanel/frontend/templates/help.html b/controlpanel/frontend/templates/help.html new file mode 100644 index 000000000..5618a7de5 --- /dev/null +++ b/controlpanel/frontend/templates/help.html @@ -0,0 +1,58 @@ +{% extends "base.html" %} + +{% block content %} +

Help

+ +

Common queries, support tasks and problems are explained in the following +videos.

+ +

Should you still require help, please visit our +help and support documentation. +If you encounter a technical issue with our infrastructure, please visit our +support channel on Slack. +Please remember to tell us your GitHub username and the name of any +affected S3 buckets or applications on the Analytical Platform that are +affected by the problem.

+ +

What is the Analytical Platform?

+ +
+ +
+ +

Related links:

+ + + +

Home Directory Reset

+ +

You need to reset your home directory if any of the following applies:

+ +
    +
  • Your RStudio won't start.
  • +
  • Your Conda environment is a mess.
  • +
  • You need to start RStudio development from a clean state.
  • +
+ +
+ +
+ +
    +
  1. From the Analytic tools page, + follow the link to reset your home page.
  2. +
  3. Read the information about what a home reset entails.
  4. +
  5. Enable the confirmation check-box and click the red "Reset" button.
  6. +
  7. You'll be returned to the Analytic tools page, but will see a + confirmation that the reset is underway.
  8. +
  9. Depending on the size of your home directory, this process can + take between seconds to a couple of minutes. Go make a coffee!
  10. +
  11. Finally, on the Analytic tools + page, click the "Restart" button for RStudio.
  12. +
  13. Give RStudio a few minutes to start up.
  14. +
+{% endblock %} diff --git a/controlpanel/frontend/templates/home.html b/controlpanel/frontend/templates/home.html new file mode 100644 index 000000000..717ed7a7e --- /dev/null +++ b/controlpanel/frontend/templates/home.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block content %} +

Administrative tasks

+ +{% if request.user.is_superuser %} + +{% endif %} +{% endblock %} diff --git a/controlpanel/frontend/templates/login-fail.html b/controlpanel/frontend/templates/login-fail.html new file mode 100644 index 000000000..c56b18002 --- /dev/null +++ b/controlpanel/frontend/templates/login-fail.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} + +{% block content %} +{% if in_wrong_place %} +

You seem to be lost

+

You have migrated to the new infrastructure, but you're trying to use +the old infrastructure. Please update your bookmarks for the control panel +to:

+ +

https://controlpanel.services.analytical-platform.service.justice.gov.uk

+ +

Please +click here +to sign in on the new infrastructure.

+{% else %} +

There is a problem with your session

+ +

It might have timed out, or something went wrong when you tried to +authenticate.

+ +
    +
  • You may need to ensure you are in the + MoJ Analytical Services + team on GitHub.
  • +
  • You may have migrated to a newer version of the platform, so your + account on this version is no longer available.
  • +
  • If you think your session has simply timed out, please + {% if EKS %} + reset your session, + {% else %} + reset your session, + {% endif %} + and try again.
  • +
+

Alternatively, please refer to our guide for +getting started on the Analytical Platform +for more information.

+ +

Thank you.

+{% endif %} +{% endblock %} diff --git a/controlpanel/settings/common.py b/controlpanel/settings/common.py index f08233aa7..0bd5b6460 100644 --- a/controlpanel/settings/common.py +++ b/controlpanel/settings/common.py @@ -2,7 +2,6 @@ import sys from os.path import abspath, dirname, join -from controlpanel.frontend.jinja2 import environment from controlpanel.utils import is_truthy import structlog @@ -108,20 +107,11 @@ TEMPLATES = [ { - "BACKEND": "django.template.backends.jinja2.Jinja2", + "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [ - # find local component templates - join(DJANGO_ROOT, "frontend", "static", "components"), + join(DJANGO_ROOT, "frontend", "templates"), ], "APP_DIRS": True, - "OPTIONS": { - "environment": f"{PROJECT_NAME}.frontend.jinja2.environment", - }, - }, - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], - "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", From 86fb9caa33f5daec1bfc91c5d11e5158e753413a Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 16 Nov 2021 11:28:23 +0000 Subject: [PATCH 2/8] Remove 'migrated' Jinja files. --- controlpanel/frontend/jinja2/404.html | 19 -- controlpanel/frontend/jinja2/500.html | 32 --- controlpanel/frontend/jinja2/503.html | 13 -- controlpanel/frontend/jinja2/a11y.html | 103 ---------- controlpanel/frontend/jinja2/base.html | 205 ------------------- controlpanel/frontend/jinja2/help.html | 75 ------- controlpanel/frontend/jinja2/home.html | 20 -- controlpanel/frontend/jinja2/login-fail.html | 47 ----- controlpanel/frontend/templates/404.html | 13 ++ 9 files changed, 13 insertions(+), 514 deletions(-) delete mode 100644 controlpanel/frontend/jinja2/404.html delete mode 100644 controlpanel/frontend/jinja2/500.html delete mode 100644 controlpanel/frontend/jinja2/503.html delete mode 100644 controlpanel/frontend/jinja2/a11y.html delete mode 100644 controlpanel/frontend/jinja2/base.html delete mode 100644 controlpanel/frontend/jinja2/help.html delete mode 100644 controlpanel/frontend/jinja2/home.html delete mode 100644 controlpanel/frontend/jinja2/login-fail.html create mode 100644 controlpanel/frontend/templates/404.html diff --git a/controlpanel/frontend/jinja2/404.html b/controlpanel/frontend/jinja2/404.html deleted file mode 100644 index ce1786969..000000000 --- a/controlpanel/frontend/jinja2/404.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "Page not found" %} -{% set hide_nav = True %} - -{% block content %} -

{{ page_title }}

- -

- If you typed the web address, check it is correct. -

-

- If you pasted the web address, check you copied the entire address. -

-

- If the web address is correct or you selected a link or button, - contact the Analytical Platform team. -

-{% endblock %} diff --git a/controlpanel/frontend/jinja2/500.html b/controlpanel/frontend/jinja2/500.html deleted file mode 100644 index bbb61a8fb..000000000 --- a/controlpanel/frontend/jinja2/500.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "Sorry, there is a problem with the service" %} -{% set home_url = url("index") %} - -{% block header %} - {{ mojHeader({ - 'organisationLabel': { - 'text': 'Ministry of Justice', - 'href': home_url, - }, - 'serviceLabel': { - 'text': service_name, - 'href': home_url, - }, - 'navigation': [], - }) }} -{% endblock %} - -{% set hide_nav = True %} - -{% block content %} -

{{ page_title }}

- -

- Try again later. -

-

- Contact the Analytical Platform team if you need to make - urgent changes to your webapps or data sources. -

-{% endblock %} diff --git a/controlpanel/frontend/jinja2/503.html b/controlpanel/frontend/jinja2/503.html deleted file mode 100644 index 12e4a51c5..000000000 --- a/controlpanel/frontend/jinja2/503.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "Sorry, the service is unavailable" %} -{% set hide_nav = True %} - -{% block content %} -

{{ page_title }}

- -

- Contact the Analytical Platform team if you need to make - urgent changes to your webapps or data sources. -

-{% endblock %} diff --git a/controlpanel/frontend/jinja2/a11y.html b/controlpanel/frontend/jinja2/a11y.html deleted file mode 100644 index 45bb6430e..000000000 --- a/controlpanel/frontend/jinja2/a11y.html +++ /dev/null @@ -1,103 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "Accessibility Statement" %} - -{% block content %} -
-
- - -

Accessibility statement for the MoJ Analytical Platform

- -

This accessibility statement applies to the Ministry of Justice's - Analytical Platform.

- -

This service is run by Analytical Platform team of the Ministry of - Justice. We want as many people as possible to be able to use this service. - For example, on the Control Panel application (this website) you - should be able to:

- -
    -
  • zoom in up to 300% without the text spilling off the screen
  • -
  • navigate most of the website using just a keyboard
  • -
  • navigate most of the website using speech recognition software
  • -
  • listen to most of the website using a screen reader (including the - most recent versions of JAWS, NVDA and VoiceOver)
  • -
- -

We've also made our textual content as simple as possible to understand.

- -

AbilityNet - has advice on making your device easier to use if you have a disability.

- -

How accessible this service is

- -

We know some parts of this service are not fully accessible:

- -
    -
  • we understand there is reasonable accessibility compliance of - R Studio and Jupyter, and will be updating to the latest versions, but - there may be accessibility issues with older versions we provide via - this platform
  • -
  • you cannot change colours, contrast levels and fonts to aid - readability
  • -
- -

Feedback and contact information

- -

Any feedback and/or requests for help should be made via the - Analytical Platform - Slack Channel. We also have a - platform user guide - and - platform support documentation.

- -

Reporting accessibility problems with this service

- -

We're always looking to improve the accessibility of this service. If - you find any problems not listed on this page or think we're not meeting - accessibility requirements, please contact us via the links listed in the - feedback and contact information section.

- -

Enforcement procedure

- -

The Equality and Human Rights Commission (EHRC) is responsible for - enforcing the Public Sector Bodies (Websites and Mobile Applications) - (No. 2) Accessibility Regulations 2018 (the 'accessibility regulations'). - If you’re not happy with how we respond to your complaint, - contact the Equality Advisory and Support Service (EASS).

- -

Technical information about this service’s accessibility

- -

The Ministry of Justice's Analytical Platform team is committed to - making its service accessible, in accordance with the Public Sector Bodies - (Websites and Mobile Applications) (No. 2) Accessibility Regulations - 2018.

- -

Compliance status

- -
    -
  • we have been through an accessibility checklist for the Control - Panel and believe it is compliant
  • -
  • we are in the process of booking a full accessibility audit of the - Analaytical Platform and will promptly update this statement
  • -
- -

Preparation of this accessibility statement

- -

This statement was prepared on 22nd October 2020. It was last reviewed - on 23rd October 2020.

- -

This service was last tested on 27th August 2020. The test was carried - out by a member of the Analytical Platform team.

- -

We checked all the pages in the Control Panel application (excluding - those that are parts of Jupyter, Airflow and RStudio) against - this accessibility - checklist.

- -

A full accessibility audit by an independent third party will take - place very soon.

-
-
-{% endblock %} diff --git a/controlpanel/frontend/jinja2/base.html b/controlpanel/frontend/jinja2/base.html deleted file mode 100644 index 76d30f16c..000000000 --- a/controlpanel/frontend/jinja2/base.html +++ /dev/null @@ -1,205 +0,0 @@ -{% from "header/macro.html" import mojHeader with context %} -{% from "footer/macro.html" import govukFooter %} -{% from "navbar/macro.html" import mojPrimaryNavigation %} -{% from "alerts/macro.html" import alerts with context %} - -{% extends "govuk-frontend.html" %} - -{% set service_name = "Analytical Platform Control Panel" %} -{% set home_url = url("index") %} -{% set signout_url = url("oidc_logout") %} - -{% block page_title %} - {{ page_title }} | {{ service_name }} -{% endblock %} - -{% block head %} - - - - - - - - - -{% endblock %} - -{% block cookie_message %} -

{{cookieText | safe }}

-{% endblock %} - -{% block header %} - {% if request.user.is_authenticated -%} - {{ mojHeader({ - 'organisationLabel': { - 'text': 'Ministry of Justice', - 'href': home_url, - }, - 'serviceLabel': { - 'text': service_name, - 'href': home_url, - }, - 'navigation': { - 'label': 'Account navigation', - 'items': [ - { - 'href': home_url, - 'text': request.user.name | default(request.user.email), - 'active': True - }, - { - 'href': signout_url, - 'text': 'Sign out' - } - ] - } - }) }} - {%- else -%} - {{ mojHeader({ - 'organisationLabel': { - 'text': 'Ministry of Justice', - 'href': home_url, - }, - 'serviceLabel': { - 'text': service_name, - 'href': home_url, - }, - }) }} - {%- endif %} -{% endblock %} - -{% block beforeContent %} - {% if not hide_nav and request.user.is_authenticated %} - {{ mojPrimaryNavigation({ - "label": "Primary navigation", - "items": [ - { - "hide": not request.user.is_superuser, - "text": "Home", - "href": home_url, - "active": page_name == "home", - "admin": request.user.is_superuser, - }, - { - "text": "Analytical tools", - "href": url("list-tools"), - "active": page_name == "tools", - }, - { - "text": "Warehouse data", - "href": url("list-warehouse-datasources"), - "active": page_name == "warehouse-datasource-list", - }, - { - "hide": not request.user.users3buckets.filter(s3bucket__is_data_warehouse=False).exists(), - "text": "Webapp data", - "href": url("list-webapp-datasources"), - "active": page_name == "webapp-datasource-list", - }, - { - "hide": not request.user.userapps.filter(is_admin=True).exists(), - "text": "Webapps", - "href": url("list-apps"), - "active": page_name == "webapps", - }, - { - "text": "Parameters", - "href": url("list-parameters"), - "active": page_name == "parameters", - }, - { - "hide": not request.user.is_superuser, - "text": "Groups", - "href": url("list-policies"), - "active": page_name == "groups", - "admin": request.user.is_superuser, - }, - { - "text": "Help", - "href": url("help"), - "active": page_name == "help", - }, - ], - }) }} - {% endif %} - - {{ alerts() }} - {% if not hide_nav and request.user.is_authenticated and request.user.migration_state == request.user.PENDING %} -
-
-
- - - Warning - Migrate to our new infrastructure. This cannot be reversed. - Click here to begin. - -
-
-
- {% endif %} -{% endblock %} - -{% block footer %} - {{ govukFooter({ - 'navigation': [ - { - 'title': 'Related resources', - 'items': [ - { - 'href': user_guidance_base_url, - 'text': "Platform user guidance", - }, - { - 'href': user_guidance_base_url + "/support.html", - 'text': "Platform support", - }, - { - 'href': "https://asdslack.slack.com/messages/C1PUCG719/#", - 'text': "R Slack channel", - }, - { - 'href': "https://asdslack.slack.com/messages/C1Q09V86S/#", - 'text': "Python slack channel", - }, - { - 'href': "https://asdslack.slack.com/messages/C4PF7QAJZ#", - 'text': "Analytical platform slack channel", - }, - { - 'href': url('accessibility'), - 'text': "Accessibility statement", - }, - ], - }, - ], - }) }} -{% endblock %} - -{% block body_end %} - {% block scripts %} - - - - - - - - - - - {% block page_scripts %}{% endblock %} - {% endblock %} -{% endblock %} diff --git a/controlpanel/frontend/jinja2/help.html b/controlpanel/frontend/jinja2/help.html deleted file mode 100644 index 27e7ff521..000000000 --- a/controlpanel/frontend/jinja2/help.html +++ /dev/null @@ -1,75 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "Help" %} - -{% block content %} -
-
- - - - -

Help

- -

Common queries, support tasks and problems are - explained in the following videos.

- -

Should you still require help, please visit our - help and support documentation. - If you encounter a technical issue with our infrastructure, please visit our - support channel on Slack. - Please remember to tell us your GitHub username and the name of any - affected S3 buckets or applications on the Analytical Platform that are - affected by the problem.

- -

What is the Analytical Platform?

- - - -

Related links:

- - -

Home Directory Reset

- -

You need to reset your home directory if any of the - following applies:

- -
    -
  • Your RStudio won't start.
  • -
  • Your Conda environment is a mess.
  • -
  • You need to start RStudio development from a clean state.
  • -
- - - -
    -
  1. From the Analytic tools page, - follow the link to reset your home page.
  2. -
  3. Read the information about what a home reset entails.
  4. -
  5. Enable the confirmation check-box and click the red "Reset" button.
  6. -
  7. You'll be returned to the Analytic tools page, but will see a - confirmation that the reset is underway.
  8. -
  9. Depending on the size of your home directory, this process can - take between seconds to a couple of minutes. Go make a coffee!
  10. -
  11. Finally, on the Analytic tools - page, click the "Restart" button for RStudio.
  12. -
  13. Give RStudio a few minutes to start up.
  14. -
- - - -
-
-{% endblock %} diff --git a/controlpanel/frontend/jinja2/home.html b/controlpanel/frontend/jinja2/home.html deleted file mode 100644 index 4f9bf1a13..000000000 --- a/controlpanel/frontend/jinja2/home.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "base.html" %} - -{% set page_name = "home" %} -{% set page_title = "Hello " ~ ( request.user.name if request.user ) %} - -{% block content %} - -

{{ page_title }}

- - {% if request.user.is_superuser %} -

Superuser functions

- - {% endif %} - -{% endblock %} diff --git a/controlpanel/frontend/jinja2/login-fail.html b/controlpanel/frontend/jinja2/login-fail.html deleted file mode 100644 index d55cd4b90..000000000 --- a/controlpanel/frontend/jinja2/login-fail.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "Login Failure" %} - -{% block content %} -
-
- {% if in_wrong_place %} -

You seem to be lost

-

You have migrated to the new infrastructure, but you're trying to use - the old infrastructure. Please update your bookmarks for the control panel - to:

- -

https://controlpanel.services.analytical-platform.service.justice.gov.uk

- -

Please - click here - to sign in on the new infrastructure.

- {% else %} -

There is a problem with your session

- -

It might have timed out, or something went wrong when you tried to - authenticate.

- -
    -
  • You may need to ensure you are in the - MoJ Analytical Services - team on GitHub.
  • -
  • You may have migrated to a newer version of the platform, so your - account on this version is no longer available.
  • -
  • If you think your session has simply timed out, please - {% if EKS %} - reset your session, - {% else %} - reset your session, - {% endif %} - and try again.
  • -
-

Alternatively, please refer to our guide for - getting started on the Analytical Platform - for more information.

- -

Thank you.

- {% endif %} -
-
-{% endblock %} diff --git a/controlpanel/frontend/templates/404.html b/controlpanel/frontend/templates/404.html new file mode 100644 index 000000000..ef332618f --- /dev/null +++ b/controlpanel/frontend/templates/404.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block content %} +

Page not found

+ +

If you typed the web address, check it is correct.

+ +

If you pasted the web address, check you copied the entire address.

+ +

If the web address is correct or you selected a link or button, +contact the Analytical Platform team.

+{% endblock %} + From 8b739dda914b15155b51bfa4f66bb45a53694e28 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 16 Nov 2021 11:30:20 +0000 Subject: [PATCH 3/8] Remove unused whats-new file. --- controlpanel/frontend/jinja2/whats-new.html | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 controlpanel/frontend/jinja2/whats-new.html diff --git a/controlpanel/frontend/jinja2/whats-new.html b/controlpanel/frontend/jinja2/whats-new.html deleted file mode 100644 index 999eccb04..000000000 --- a/controlpanel/frontend/jinja2/whats-new.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "What's new?" %} - -{% block content %} -
- {{ markdown_body | markdown }} -
-{% endblock %} From 53a6bc974ecf23372ea323dcd58e0b3b0a1db077 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 16 Nov 2021 15:47:42 +0000 Subject: [PATCH 4/8] Reset homepage and user related admin. Use of forms, tables and permissions demonstrated here. --- controlpanel/api/models/user.py | 4 + controlpanel/frontend/jinja2/reset.html | 69 ---------- controlpanel/frontend/jinja2/user-detail.html | 110 ---------------- controlpanel/frontend/jinja2/user-list.html | 61 --------- controlpanel/frontend/static/css/app.css | 24 ++++ controlpanel/frontend/templates/reset.html | 54 ++++++++ .../frontend/templates/user-detail.html | 119 ++++++++++++++++++ .../frontend/templates/user-list.html | 36 ++++++ 8 files changed, 237 insertions(+), 240 deletions(-) delete mode 100644 controlpanel/frontend/jinja2/reset.html delete mode 100644 controlpanel/frontend/jinja2/user-detail.html delete mode 100644 controlpanel/frontend/jinja2/user-list.html create mode 100644 controlpanel/frontend/templates/reset.html create mode 100644 controlpanel/frontend/templates/user-detail.html create mode 100644 controlpanel/frontend/templates/user-list.html diff --git a/controlpanel/api/models/user.py b/controlpanel/api/models/user.py index d77661bc9..bc59f6f89 100644 --- a/controlpanel/api/models/user.py +++ b/controlpanel/api/models/user.py @@ -89,6 +89,10 @@ def github_api_token(self, value): def slug(self): return sanitize_dns_label(self.username) + @property + def data_sources(self): + return self.users3buckets.filter(s3bucket__is_data_warehouse=False) + def is_app_admin(self, app_id): return self.userapps.filter( app_id=app_id, diff --git a/controlpanel/frontend/jinja2/reset.html b/controlpanel/frontend/jinja2/reset.html deleted file mode 100644 index 45094882e..000000000 --- a/controlpanel/frontend/jinja2/reset.html +++ /dev/null @@ -1,69 +0,0 @@ -{% extends "base.html" %} - -{% set page_title = "Hard Reset Home Directory" %} -{% set page_name = "reset" %} - -{% block content %} -
-
- - {% if form.errors %} - - {% endif %} -

Home Directory Reset

-

Even the best curated home directories can get into a bad - state (for example, a broken conda environment or Jupyter and RStudio won't - start).

- -

Reset your home directory to recreate your conda environment and shell - settings to a clean state. This feature automates the - process described here.

- -
- - - Warning - Please ensure you've copied any important files from your home - directory. Important files should be stored in S3 or GitHub. - -
- - -

This process should only take a few seconds to complete.

- -
-
- {{ csrf_input }} -
- {% if form.errors %} - - Error: - Confirm you want to reset your home directory - - {% endif %} -
-
- {{ form.confirm }} - -
-
-
- -
-
-
-
-{% endblock %} diff --git a/controlpanel/frontend/jinja2/user-detail.html b/controlpanel/frontend/jinja2/user-detail.html deleted file mode 100644 index 123abd2ae..000000000 --- a/controlpanel/frontend/jinja2/user-detail.html +++ /dev/null @@ -1,110 +0,0 @@ -{% from "checkboxes/macro.html" import govukCheckboxes %} -{% from "fieldset/macro.html" import govukFieldset %} -{% from "user/macro.html" import user_name %} -{% from "includes/app-list.html" import app_list with context %} -{% from "includes/datasource-list.html" import datasource_list with context %} - -{% extends "base.html" %} - -{% set page_title = user_name(user) %} -{% set pronoun = "Your" if user == request.user else "User's" %} - -{% block content %} -User -

{{ page_title }}

- -{% if unused %} -
-
- - -
-{% endif %} - -{% if request.user.has_perm('api.add_superuser') %} -
-
- {{ csrf_input }} - {{ govukCheckboxes({ - "name": "is_superuser", - "fieldset": { - "legend": { - "text": "Super Admin", - "classes": "govuk-fieldset__legend--m", - }, - }, - "hint": { - "text": "User is a super admin, allowing all privileges on the Control panel." - }, - "items": [ - { - "value": "True", - "text": "Super Admin", - "checked": user.is_superuser - }, - ] - }) }} - -
-
-{% endif %} - -{% if request.user.has_perm('api.reset_mfa') %} -
-
- {{ csrf_input }} - {% call govukFieldset({ - "legend": { - "text": "Reset MFA", - "classes": "govuk-fieldset__legend--m", - }, - "describedBy": "reset-hint" - }) %} - - Reset the user's multi-factor authentication settings, forcing them to - reconfigure. - - - {%- endcall %} -
-
-{% endif %} - -
-

{{ pronoun }} apps

- {{ app_list(user.userapps.all()|map(attribute="app")|list, user) }} -
- -{# user's datasources #} -
-

{{ pronoun }} webapp data sources

- {{ datasource_list(user.users3buckets.filter(s3bucket__is_data_warehouse=False)|map(attribute="s3bucket")|list, "webapp", user) }} -
- -{% if request.user.has_perm('api.destroy_user', user) %} -
-
- {{ csrf_input }} - -
-
-{% endif %} - -{% endblock %} diff --git a/controlpanel/frontend/jinja2/user-list.html b/controlpanel/frontend/jinja2/user-list.html deleted file mode 100644 index 728e335af..000000000 --- a/controlpanel/frontend/jinja2/user-list.html +++ /dev/null @@ -1,61 +0,0 @@ -{% from "user/macro.html" import user_name %} - -{% extends "base.html" %} - -{% set page_title = "Users" %} - -{% block content %} -

{{ page_title }}

- - - - - - - - - - - - {% for user in users %} - - - - - - - {% endfor %} - - - - - - -
UserEmailLast login - Actions -
- - {{ user_name(user) }} - - {{ user.email }} - {%- if user.last_login -%} - - {{ timesince(user.last_login) }} ago - - {%- else -%} - Never logged in. - {%- endif -%} - {%- if user in unused_users -%} - (unused?) - {%- endif -%} - - - Manage user - -
- {{ users|length }} user{% if users|length != 1 %}s{% endif %} -
-{% endblock %} diff --git a/controlpanel/frontend/static/css/app.css b/controlpanel/frontend/static/css/app.css index 643b8affd..c4552e8c2 100644 --- a/controlpanel/frontend/static/css/app.css +++ b/controlpanel/frontend/static/css/app.css @@ -39,3 +39,27 @@ this art. margin-right: 8px; } +/* Button type names. */ +.warning-button { + background-color: var(--color-tertiary) !important; +} + +.warning-button:hover { + background-color: var(--color-tertiary-hover) !important; +} + +.confirm-button { + background-color: var(--color-secondary) !important; +} + +.confirm-button:hover { + background-color: var(--color-secondary-hover) !important; +} + +.standard-button { + background-color: var(--color-primary) !important; +} + +.standard-button:hover { + background-color: var(--color-primary-hover) !important; +} diff --git a/controlpanel/frontend/templates/reset.html b/controlpanel/frontend/templates/reset.html new file mode 100644 index 000000000..1ef8ed8b8 --- /dev/null +++ b/controlpanel/frontend/templates/reset.html @@ -0,0 +1,54 @@ +{% extends "base.html" %} +{% load static %} + +{% block content %} + {% if form.errors %} + +{% endif %} +

Home Directory Reset

+ +

Even the best curated home directories can get into a bad +state (for example, a broken conda environment or Jupyter and RStudio won't +start).

+ +

Reset your home directory to recreate your conda environment and shell +settings to a clean state. This feature automates the +process described here.

+ +
+

+ + Attention! + + Please ensure you've copied any important files from your home + directory. Important files should be stored in S3 or GitHub. +

+
+ +

This process should only take a few seconds to complete.

+ +
+ {{ csrf_input }} + {% if form.errors %} + + Error: + Confirm you want to reset your home directory + + {% endif %} +

+ {{ form.confirm }} + +

+

+ +

+
+{% endblock %} + diff --git a/controlpanel/frontend/templates/user-detail.html b/controlpanel/frontend/templates/user-detail.html new file mode 100644 index 000000000..700891c37 --- /dev/null +++ b/controlpanel/frontend/templates/user-detail.html @@ -0,0 +1,119 @@ +{% extends "base.html" %} +{% load static %} +{% load rules %} + +{% block content %} +

{{ user.get_full_name }}

+ +{% if unused %} +
+

+ + Attention! + + This account could be unused. The user of this account has not + logged in for over 90 days. +

If appropriate, please visit the GitHub page for their membership of the + Ministry of Justice organisation to free up space.

+
+{% endif %} + +{% has_perm 'api.add_superuser' request.user as add_superuser %} +{% if add_superuser %} +

Super Admin

+
+ {{ csrf_input }} +

User is a super admin, allowing all privileges on the Control panel.

+

+ + +

+

+
+{% endif %} + +{% has_perm 'api.reset_mfa' request.user as reset_mfa %} +{% if reset_mfa %} +

Reset MFA

+
+ {{ csrf_input }} +

Reset the user's multi-factor authentication settings, forcing them to + reconfigure.

+

+
+{% endif %} + +

User's apps

+ + + + + + + + + + + {% for app in user.userapps.all %} + + + + + {% endfor %} + + + + + + +
A list of the user's apps on the platform (click the app's name for details).
App name + + Admin access +
{{ app.name }}{% if user in app.admins %}Yes{% else %}No{% endif %}
+ {{ user.userapps|length }} {% if user.userapps.all %}app{{ user.userapps|pluralize:"s" }}{% else %}apps{% endif %} +
+ +

User's webapp data sources

+ + + + + + + + + + + {% for source in user.data_sources %} + + + + + {% endfor %} + + + + + + +
A list of the user's data sources on the platform (click the source's name for details).
NameUser access level
{{ datasource.name }}{% if source.is_admin %}Admin{% else %}{{ source.access_level }}{% endif %}
+ {{ user.data_sources|length }} {% if user.data_source%}webapp data source{{ user.datasource|pluralize:"s" }}{% else %}webapp data sources{% endif %} +
+ +{% has_perm 'api.destroy_user' request.user user as destroy_user %} +{% if destroy_user %} +
+ {{ csrf_input }} +

+
+{% endif %} + +{% endblock %} + diff --git a/controlpanel/frontend/templates/user-list.html b/controlpanel/frontend/templates/user-list.html new file mode 100644 index 000000000..f0121dd2a --- /dev/null +++ b/controlpanel/frontend/templates/user-list.html @@ -0,0 +1,36 @@ +{% extends "base.html" %} + +{% block content %} +

Users

+ + + + + + + + + + + + {% for user in users %} + + + + + + {% endfor %} + + + + + + +
A list of users of the Analytical Platform (click user's name for details).
UserEmailLast login
{{ user.get_full_name }}{{ user.email }}{% if user.last_login %} + {{ user.last_login|timesince }} ago. + {% else %} + Never logged in. + {% endif %}
+ {{ users|length }} user{{ users|pluralize:"s" }} +
+{% endblock %} From 20d8955bc2339c09f34e4c00123516964b22eb60 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 16 Nov 2021 16:57:08 +0000 Subject: [PATCH 5/8] Add form submit alerts for dangerous actions. --- controlpanel/frontend/templates/reset.html | 6 +++++- controlpanel/frontend/templates/user-detail.html | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/controlpanel/frontend/templates/reset.html b/controlpanel/frontend/templates/reset.html index 1ef8ed8b8..35c6d0eb6 100644 --- a/controlpanel/frontend/templates/reset.html +++ b/controlpanel/frontend/templates/reset.html @@ -34,7 +34,11 @@

Home Directory Reset

This process should only take a few seconds to complete.

-
+ {{ csrf_input }} {% if form.errors %} diff --git a/controlpanel/frontend/templates/user-detail.html b/controlpanel/frontend/templates/user-detail.html index 700891c37..9efcc25df 100644 --- a/controlpanel/frontend/templates/user-detail.html +++ b/controlpanel/frontend/templates/user-detail.html @@ -106,7 +106,11 @@

User's webapp data sources

{% has_perm 'api.destroy_user' request.user user as destroy_user %} {% if destroy_user %} - + {{ csrf_input }}

{% endblock %} diff --git a/controlpanel/frontend/templates/user-detail.html b/controlpanel/frontend/templates/user-detail.html index 9efcc25df..884d76a26 100644 --- a/controlpanel/frontend/templates/user-detail.html +++ b/controlpanel/frontend/templates/user-detail.html @@ -22,7 +22,7 @@

{{ user.get_full_name }}

{% if add_superuser %}

Super Admin

- {{ csrf_input }} + {% csrf_token %}

User is a super admin, allowing all privileges on the Control panel.

Super Admin {% if reset_mfa %}

Reset MFA

- {{ csrf_input }} + {% csrf_token %}

Reset the user's multi-factor authentication settings, forcing them to reconfigure.

@@ -111,9 +111,8 @@

User's webapp data sources

onsubmit="return confirm('Please confirm you wish to delete this user.\n\nThis step cannot be undone.');" method="post" > - {{ csrf_input }} -

From b024d17e5f123b37d6575716359cf15dd1f2b1a7 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Mon, 6 Dec 2021 11:03:03 +0000 Subject: [PATCH 7/8] Tool list mockup (not working). --- .../frontend/templates/tool-list.html | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 controlpanel/frontend/templates/tool-list.html diff --git a/controlpanel/frontend/templates/tool-list.html b/controlpanel/frontend/templates/tool-list.html new file mode 100644 index 000000000..9adb2c204 --- /dev/null +++ b/controlpanel/frontend/templates/tool-list.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} + +{% block content %} +

Your tools

+ +

The status of your tools will update automatically.

+ +

If your tools get into a broken state, try +resetting your home directory.

+ +{% for chart_name, tool_info in tools_info.items %} +{% with deployment=tool_info.deployment %} +
+ +

{{ tool_info.name }}

+ +
+
+ {{ csrf_input }} + {% if deployment %} + + {% endif%} + {% for chart_version, app_version in tool_info.versions.items %} +

+ + +

+ {% endfor %} +

+
+
+ +{% endwith %} +{% endfor %} +{% endblock %} From 293463a063683dcfdb5e60c5e34d127a7669260b Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 7 Dec 2021 14:31:05 +0000 Subject: [PATCH 8/8] Added README to new template directory to show state, modus operandi and next steps. --- controlpanel/frontend/templates/README.md | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 controlpanel/frontend/templates/README.md diff --git a/controlpanel/frontend/templates/README.md b/controlpanel/frontend/templates/README.md new file mode 100644 index 000000000..61d4cc8bd --- /dev/null +++ b/controlpanel/frontend/templates/README.md @@ -0,0 +1,100 @@ +# New templates + +The templates in this directory demonstrate how to replace our old templating +systems. + +The old: + +* Jinja2. +* Nunjucks. +* Jinja2 emits Nunjucks emits HTML argh! +* Hacked to work in Django. +* Macros. +* Lots of code indirection (hard to debug). +* Dependencies on JavaScript. +* CSS classes annotated on most HTML tags. + +The new: + +* Django's built in templating system. +* A single _simple_ static CSS file ([GD.CSS](https://gdcss.netlify.app/)) for core styles. +* A single _simple_ static CSS file (`app.css`) for site specific styling. +* POSH (Plain Old Semantic HTML) templates. +* Avoidance of JavaScript both browser and server side. +* Easy to understand, debug and change. +* Boring with no surprises. + +## The Story So Far + +I was once asked to add a select item to one of our templates. What should have +been a 5 minute HTML edit ended up taking me a day or frustration, debugging +and misdirection. + +Our old templates are a significant technical debt because: + +* They are not idiomatic for the Django framework (a Django developer would look at them and ask, "what on earth..?") +* They are confusing to read (both Jinja2 and Nunjucks use the `{%` and `%}` markup, but have to be distinguished via atypical use of `{%-` and `-%}`). +* Nunjucks pulls in a huge number of JavaScript dependencies causing dependabot overload. +* An overly modular set of dependencies between JavaScript, macros and sub-templates means we have the rediculous situation of having, say, a macro for displaying either "yes" or "no". Such massive code indirection makes it hard to figure out how the templates relate to the emitted HTML. +* Styling using the Government based CSS is class based, so the resulting HTML is heavily annotated and difficult to read. + +As part of the firebreak sprint at the end of 2021 I decided to throw it all +away and start again. To this end I valued simplicity, standards, semantics and +sensible abstractions. + +The result is what you see in this branch. + +All that remains of the old system is found in the `jinja2` directory. As I've +rewritten our templates I've deleted the old version in `jinja2` and added the +new one in this directory. + +## Hints and Tips + +There are various common patterns encountered during transitioning from the old +templates to the new: + +Extend `base.html` +: All the core "chrome" HTML is in the base template. You should put content in the `{% block content %} {% endblock %}` (as per usual Django templates). + +The base has a header and footer +: Please see `header.html` and `footer.html` for their definition. + +GD.CSS styles HTML tags and ignores divs +: This means 90% of what we do looks like "normal" government design. We are missing some design elements but these can be recreated with ease (see, for instance, how we do message handling in the `base.html`). + +It's just POSH (plain old semantic HTML) +: If you're adding classes to tags, you're probably doing it wrong. Trust the defaults and put custom CSS in `app.css`. + +Use Django forms +: They integrate really well (unsurprisingly). See `reset.html` for an example. + +Tables are boring (and easy) +: See the `user-list.html` file for an example of how to do the AP version of tables. + +Permissions work in templates too +: Make sure you `{% load rules %}` at the top of the template and then declare a flag like this example, `{% has_perm 'api.add_superuser' request.user as add_superuser %}` (where the permission to check on the current `request.user` is "api.add_superuser" and the truthy flag to be `add_superuser`), then use a standard template conditional like this: `{% if add_superuser %} ... {% endif %}`. See the `user-detail.html` template for an example of how to do this. + +These examples cover all the various aspects of what we do in our templates. + +## Tool List + +The most important page on our site is `tool-list.html`. + +Frankly, the current version is a mess. + +The `tool-list.html` file _in this directory_ is an untested mock-up of what I think it could look like, as a more friendly version of the page. + +Note that I have ensured the expected `id` and `class` attributes are annotated to the tags in the template so the JavaScript used to update state and ensure forms work, has the expected references. + +However, I have NOT tested the updated template with JavaScript or the Django backend... what you're looking at is an afternoon's "doodle" of a "what if..?". + +This template definitely needs doing properly and testing. The other templates I've converted were all relatively simple and should just work (tm). + +## ToDo + +* Finish conversion of all the old templates to new. +* Spend time / love on the `tool-list.html` template to revise and test it properly. +* Check the changes with actual users in a dev instance. +* Delete the `jinja2` directory and any other related files from the old world. + +Best of luck..!