diff --git a/app/assets/stylesheets/components/browse-list.scss b/app/assets/stylesheets/components/browse-list.scss new file mode 100644 index 000000000..1393aa352 --- /dev/null +++ b/app/assets/stylesheets/components/browse-list.scss @@ -0,0 +1,27 @@ +.browse-list { + + margin-bottom: $gutter; + + &-item { + list-style: none; + margin-bottom: $gutter-two-thirds; + } + + a.browse-list-link { + + @include bold-24; + + &-destructive, + &-destructive:visited { + @include bold-24; + color: $error-colour; + } + + } + + &-hint { + @include core-16; + margin-top: 5px; + } + +} diff --git a/app/assets/stylesheets/components/submit-form.scss b/app/assets/stylesheets/components/submit-form.scss index 041c71773..7a6681e46 100644 --- a/app/assets/stylesheets/components/submit-form.scss +++ b/app/assets/stylesheets/components/submit-form.scss @@ -9,4 +9,10 @@ margin-left: 5px; } + .button {} + + .button-destructive { + @include button($error-colour) + } + } diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index ece58780a..ce2093c01 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -39,6 +39,7 @@ @import 'components/big-number'; @import 'components/banner'; @import 'components/textbox'; +@import 'components/browse-list'; @import 'views/job'; diff --git a/app/main/__init__.py b/app/main/__init__.py index 93354853b..9354e06db 100644 --- a/app/main/__init__.py +++ b/app/main/__init__.py @@ -5,5 +5,5 @@ main = Blueprint('main', __name__) from app.main.views import ( index, sign_in, sign_out, register, two_factor, verify, sms, add_service, - code_not_received, jobs, dashboard, templates + code_not_received, jobs, dashboard, templates, service_settings ) diff --git a/app/main/views/index.py b/app/main/views/index.py index 9c9ef1f6c..dec87cf89 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -54,11 +54,6 @@ def manageusers(): return render_template('views/manage-users.html') -@main.route("/service-settings") -def servicesettings(): - return render_template('views/service-settings.html') - - @main.route("/api-keys") def apikeys(): return render_template('views/api-keys.html') diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py new file mode 100644 index 000000000..0bdd9ba71 --- /dev/null +++ b/app/main/views/service_settings.py @@ -0,0 +1,62 @@ +from flask import render_template, redirect, request, url_for +from flask_login import login_required + +from app.main import main + +service = { + 'name': 'Service name', + 'live': False, + 'active': True +} + + +@main.route("/service-settings") +def service_settings(): + return render_template( + 'views/service-settings.html', + service=service + ) + + +@main.route("/service-settings/name", methods=['GET', 'POST']) +def name(): + if request.method == 'GET': + return render_template( + 'views/service-settings/name.html', + service=service + ) + elif request.method == 'POST': + return redirect(url_for('.service_settings')) + + +@main.route("/service-settings/request-to-go-live", methods=['GET', 'POST']) +def request_to_go_live(): + if request.method == 'GET': + return render_template( + 'views/service-settings/request-to-go-live.html', + service=service + ) + elif request.method == 'POST': + return redirect(url_for('.service_settings')) + + +@main.route("/service-settings/status", methods=['GET', 'POST']) +def status(): + if request.method == 'GET': + return render_template( + 'views/service-settings/status.html', + service=service + ) + elif request.method == 'POST': + return redirect(url_for('.service_settings')) + + +@main.route("/service-settings/delete", methods=['GET', 'POST']) +def delete(): + if request.method == 'GET': + return render_template( + 'views/service-settings/delete.html', + service=service + ) + elif request.method == 'POST': + return redirect(url_for('.index')) diff --git a/app/templates/components/browse-list.html b/app/templates/components/browse-list.html new file mode 100644 index 000000000..d59e9ae37 --- /dev/null +++ b/app/templates/components/browse-list.html @@ -0,0 +1,20 @@ +{% macro browse_list(items) %} + {% if items %} + + {% endif %} +{% endmacro %} diff --git a/app/templates/components/list.html b/app/templates/components/list.html new file mode 100644 index 000000000..71025a8ed --- /dev/null +++ b/app/templates/components/list.html @@ -0,0 +1,11 @@ +{% macro list(items) %} + {% if items %} + + {% endif %} +{% endmacro %} diff --git a/app/templates/components/submit-form.html b/app/templates/components/submit-form.html index 012d0a580..4627b6204 100644 --- a/app/templates/components/submit-form.html +++ b/app/templates/components/submit-form.html @@ -1,9 +1,9 @@ -{% macro submit_form(button_text, back_link=False) %} +{% macro submit_form(button_text, back_link=False, back_link_text="Back", destructive=False) %}
- + {% if back_link %} - Back + {{ back_link_text }} {% endif %}
{% endmacro %} diff --git a/app/templates/components/table.html b/app/templates/components/table.html index ee3c2838f..bfa53232d 100644 --- a/app/templates/components/table.html +++ b/app/templates/components/table.html @@ -1,4 +1,4 @@ -{% macro table(items, caption='', field_headings='', field_headings_visible=True, caption_visible=True) -%} +{% macro mapping_table(caption='', field_headings=[], field_headings_visible=True, caption_visible=True) -%} - {% if items %} - {% for item in items %} - - {{ caller(item) }} - - {% endfor %} - {% else %} -

- {{ empty_message }} -

- {% endif %} + {{ caller() }}
{{ caption }} @@ -17,21 +17,34 @@
{%- endmacro %} +{% macro list_table(items, caption='', empty_message='', field_headings=[], field_headings_visible=True, caption_visible=True) -%} + {% if items %} + {% set parent_caller = caller %} + {% call mapping_table(caption, field_headings, field_headings_visible, caption_visible) %} + {% for item in items %} + {% call row() %} + {{ parent_caller(item) }} + {% endcall %} + {% endfor %} + {%- endcall %} + {% else %} +

+ {{ empty_message }} +

+ {% endif %} +{%- endmacro %} + +{% macro row() -%} + + {{ caller() }} + +{%- endmacro %} + {% macro field(align='left', status='') -%} {{ caller() }} diff --git a/app/templates/main_nav.html b/app/templates/main_nav.html index f252d98f3..3fab88acb 100644 --- a/app/templates/main_nav.html +++ b/app/templates/main_nav.html @@ -10,7 +10,7 @@ - {% call(item) table( + {% call(item) list_table( jobs[:3], caption="Recent text messages", + empty_message="No recent text messages", field_headings=['Job', 'File', 'Time', 'Status'] ) %} {% call field() %} diff --git a/app/templates/views/job.html b/app/templates/views/job.html index 963ff1810..29ae57ba7 100644 --- a/app/templates/views/job.html +++ b/app/templates/views/job.html @@ -1,5 +1,5 @@ {% extends "withnav_template.html" %} -{% from "components/table.html" import table, field, right_aligned_field_heading %} +{% from "components/table.html" import list_table, field, right_aligned_field_heading %} {% from "components/big-number.html" import big_number %} {% from "components/banner.html" import banner %} @@ -41,7 +41,7 @@ GOV.UK Notify | Notifications activity Sent with template {{ template_used }} at {{ uploaded_file_time }}

- {% call(item) table( + {% call(item) list_table( messages, caption='Messages', caption_visible=False, diff --git a/app/templates/views/jobs.html b/app/templates/views/jobs.html index b9bda799d..bbcfa88fb 100644 --- a/app/templates/views/jobs.html +++ b/app/templates/views/jobs.html @@ -1,5 +1,5 @@ {% extends "withnav_template.html" %} -{% from "components/table.html" import table, field %} +{% from "components/table.html" import list_table, field %} {% block page_title %} GOV.UK Notify | Notifications activity @@ -9,7 +9,7 @@ GOV.UK Notify | Notifications activity

Notifications activity

- {% call(item) table( + {% call(item) list_table( jobs, caption="Recent activity", caption_visible=False, diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html index e53fb9efe..a9e0bce19 100644 --- a/app/templates/views/service-settings.html +++ b/app/templates/views/service-settings.html @@ -1,4 +1,5 @@ {% extends "withnav_template.html" %} +{% from "components/browse-list.html" import browse_list %} {% block page_title %} GOV.UK Notify | Service settings @@ -6,12 +7,33 @@ GOV.UK Notify | Service settings {% block maincolumn_content %} -

Service settings

- -

Here's where users can update their service profile.

- -

Back to dashboard

- +

Service settings

+ {{ browse_list([ + { + 'title': 'Rename service', + 'link': url_for('.name'), + 'hint': 'Your service is named “{}”'.format(service.name) + }, + { + 'title': 'Make service live', + 'link': url_for('.request_to_go_live'), + 'hint': 'A live service can send messages to anyone', + } if not service.live else { + }, + { + 'title': 'Stop sending messages', + 'link': url_for('.status') + } if service.active else { + 'title': 'Unsuspend service', + 'link': url_for('.status') + }, + { + 'title': 'Delete everything', + 'link': url_for('.delete'), + 'hint': '', + 'destructive': True + }, + ]) }} {% endblock %} diff --git a/app/templates/views/service-settings/delete.html b/app/templates/views/service-settings/delete.html new file mode 100644 index 000000000..2449f95bd --- /dev/null +++ b/app/templates/views/service-settings/delete.html @@ -0,0 +1,22 @@ +{% extends "withnav_template.html" %} +{% from "components/submit-form.html" import submit_form %} + +{% block page_title %} + GOV.UK Notify | Service settings +{% endblock %} + +{% block maincolumn_content %} + +

Delete this service

+ +

+ All will be lost. +

+ +
+ {{ submit_form('Delete', destructive=True) }} +
+ +

Back to service settings

+ +{% endblock %} diff --git a/app/templates/views/service-settings/name.html b/app/templates/views/service-settings/name.html new file mode 100644 index 000000000..c12fb377b --- /dev/null +++ b/app/templates/views/service-settings/name.html @@ -0,0 +1,22 @@ +{% extends "withnav_template.html" %} +{% from "components/textbox.html" import textbox %} +{% from "components/submit-form.html" import submit_form %} + +{% block page_title %} +GOV.UK Notify | Service settings +{% endblock %} + +{% block maincolumn_content %} + +

Rename your service

+ +
+ {{ textbox('new_name', 'New name', value=service.name) }} + {{ submit_form('Save') }} +
+ +

Back to service settings

+ + + +{% endblock %} diff --git a/app/templates/views/service-settings/request-to-go-live.html b/app/templates/views/service-settings/request-to-go-live.html new file mode 100644 index 000000000..110f15fb6 --- /dev/null +++ b/app/templates/views/service-settings/request-to-go-live.html @@ -0,0 +1,34 @@ +{% extends "withnav_template.html" %} +{% from "components/submit-form.html" import submit_form %} +{% from "components/list.html" import list %} + +{% block page_title %} +GOV.UK Notify | Service settings +{% endblock %} + +{% block maincolumn_content %} + +

Make your service live

+ +
+
+ +

+ Before you can send messages to anyone, you need to: +

+ + {{ list([ + "Have spoken to someone", + "Have permission from someone else", + "etc." + ]) }} + +
+ {{ submit_form("Request to go live") }} +
+ +

Back to service settings

+
+
+ +{% endblock %} diff --git a/app/templates/views/service-settings/status.html b/app/templates/views/service-settings/status.html new file mode 100644 index 000000000..b7c210a98 --- /dev/null +++ b/app/templates/views/service-settings/status.html @@ -0,0 +1,33 @@ +{% extends "withnav_template.html" %} +{% from "components/submit-form.html" import submit_form %} + +{% block page_title %} +GOV.UK Notify | Service settings +{% endblock %} + +{% block maincolumn_content %} + +
+
+

Suspend your service

+ +

+ Suspending a service means it won’t send messages. Any messages that are + already queued will still be sent. +

+ +

+ You can undo this at any time. +

+ +
+ {{ submit_form('Suspend') }} +
+ +

Back to service settings

+
+
+ + + +{% endblock %} diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py new file mode 100644 index 000000000..115e7121d --- /dev/null +++ b/tests/app/main/views/test_service_settings.py @@ -0,0 +1,61 @@ +def test_should_show_overview(notifications_admin): + response = notifications_admin.test_client().get('/service-settings') + + assert response.status_code == 200 + assert 'Service settings' in response.get_data(as_text=True) + + +def test_should_show_service_name(notifications_admin): + response = notifications_admin.test_client().get('/service-settings/name') + + assert response.status_code == 200 + assert 'Service name' in response.get_data(as_text=True) + + +def test_should_redirect_after_change_service_name(notifications_admin): + response = notifications_admin.test_client().post('/service-settings/request-to-go-live') + + assert response.status_code == 302 + assert 'http://localhost/service-settings' == response.location + + +def test_should_show_request_to_go_live(notifications_admin): + response = notifications_admin.test_client().get('/service-settings/request-to-go-live') + + assert response.status_code == 200 + assert 'Request to go live' in response.get_data(as_text=True) + + +def test_should_redirect_after_request_to_go_live(notifications_admin): + response = notifications_admin.test_client().post('/service-settings/request-to-go-live') + + assert response.status_code == 302 + assert 'http://localhost/service-settings' == response.location + + +def test_should_show_status_page(notifications_admin): + response = notifications_admin.test_client().get('/service-settings/status') + + assert response.status_code == 200 + assert 'Suspend your service' in response.get_data(as_text=True) + + +def test_should_show_redirect_after_status_change(notifications_admin): + response = notifications_admin.test_client().post('/service-settings/status') + + assert response.status_code == 302 + assert 'http://localhost/service-settings' == response.location + + +def test_should_show_delete_page(notifications_admin): + response = notifications_admin.test_client().get('/service-settings/delete') + + assert response.status_code == 200 + assert 'Delete service' in response.get_data(as_text=True) + + +def test_should_show_redirect_after_deleting_service(notifications_admin): + response = notifications_admin.test_client().post('/service-settings/delete') + + assert response.status_code == 302 + assert 'http://localhost/' == response.location