diff --git a/app/assets/javascripts/collapsibleCheckboxes.js b/app/assets/javascripts/collapsibleCheckboxes.js index 0333b8dc3..11c14a2e4 100644 --- a/app/assets/javascripts/collapsibleCheckboxes.js +++ b/app/assets/javascripts/collapsibleCheckboxes.js @@ -5,7 +5,7 @@ function Summary (module) { this.module = module; - this.$el = module.$formGroup.find('.selection-summary').first(); + this.$el = module.$formGroup.find('.selection-summary'); this.fieldLabel = module.fieldLabel; this.total = module.total; this.addContent(); @@ -25,7 +25,6 @@ if (this.fieldLabel === 'folder') { this.$text.addClass('selection-summary__text--folders'); } this.$el.append(this.$text); - this.module.$formGroup.find('.govuk-hint').remove(); }; Summary.prototype.update = function(selection) { let template; @@ -87,13 +86,12 @@ .focus(); }; CollapsibleCheckboxes.prototype.start = function(component) { - this.$component = $(component); - this.$formGroup = this.$component.find('.govuk-form-group').first(); - this.$fieldset = this.$formGroup.find('fieldset').first(); + this.$formGroup = $(component); + this.$fieldset = this.$formGroup.find('fieldset'); this.$checkboxes = this.$fieldset.find('input[type=checkbox]'); - this.fieldLabel = this.$component.data('fieldLabel'); + this.fieldLabel = this.$formGroup.data('fieldLabel'); this.total = this.$checkboxes.length; - this.legendText = this.$fieldset.find('legend').first().text().trim(); + this.legendText = this.$fieldset.find('legend').text().trim(); this.expanded = false; this.addHeadingHideLegend(); @@ -115,7 +113,7 @@ }; CollapsibleCheckboxes.prototype.getSelection = function() { return this.$checkboxes.filter(':checked').length; }; CollapsibleCheckboxes.prototype.addHeadingHideLegend = function() { - const headingLevel = this.$component.data('heading-level') || '2'; + const headingLevel = this.$formGroup.data('heading-level') || '2'; this.$heading = $(`${this.legendText}`); this.$fieldset.before(this.$heading); diff --git a/app/assets/stylesheets/components/checkboxes.scss b/app/assets/stylesheets/components/checkboxes.scss index 094c37d7a..3986c65bf 100644 --- a/app/assets/stylesheets/components/checkboxes.scss +++ b/app/assets/stylesheets/components/checkboxes.scss @@ -1,7 +1,3 @@ -// Taken from https://github.com/alphagov/govuk-frontend/blob/v2.13.0/src/components/checkboxes/_checkboxes.scss -$govuk-touch-target-size: 44px; -$govuk-checkboxes-size: 40px; - .selection-summary { .selection-summary__text { @@ -69,30 +65,6 @@ $govuk-checkboxes-size: 40px; } -.govuk-form-group--nested { - - $border-thickness: $govuk-touch-target-size - $govuk-checkboxes-size; - $border-indent: $govuk-touch-target-size / 2; - - position: relative; - - // To equalise the spacing between the line and the top/bottom of - // the radio - margin-top: govuk-spacing(1) + ($border-thickness / 2); - margin-bottom: govuk-spacing(1) * -1; - padding-left: govuk-spacing(2) + 2; - - &:before { - content: ""; - position: absolute; - bottom: 0; - left: $border-indent * -1; - width: $border-thickness; - height: 100%; - background: $govuk-border-colour; - } -} - .selection-content { margin-bottom: govuk-spacing(4); diff --git a/app/assets/stylesheets/components/message.scss b/app/assets/stylesheets/components/message.scss index c4dc7bff4..3d63ff455 100644 --- a/app/assets/stylesheets/components/message.scss +++ b/app/assets/stylesheets/components/message.scss @@ -24,9 +24,6 @@ } } -$message-text-left-spacing: 22px; -$message-type-bottom-spacing: govuk-spacing(4); - .message { &-name { @@ -66,18 +63,39 @@ $message-type-bottom-spacing: govuk-spacing(4); } &-type { - color: $govuk-secondary-text-colour; - margin: 0 0 $message-type-bottom-spacing 0; - padding-left: 0; + color: $secondary-text-colour; + margin: 0 0 govuk-spacing(4) 0; pointer-events: none; } } +#template-list { + + margin-top: govuk-spacing(6); + + &.top-gutter-5px { + margin-top: 5px; + } + +} + .template-list { &-item { + &-with-checkbox { + + position: relative; + padding-left: govuk-spacing(9); + + .multiple-choice { + position: absolute; + left: 0; + } + + } + &-hidden-by-default { display: none; } @@ -105,22 +123,6 @@ $message-type-bottom-spacing: govuk-spacing(4); } - &-hint, - &-label { - padding-left: $message-text-left-spacing; - } - - &-label { - padding-top: 0px; - padding-bottom: 0px; - } - - // Fix for GOVUK Frontend selector with high precendence - // https://github.com/alphagov/govuk-frontend/blob/v2.13.0/src/components/hint/_hint.scss - &-label:not(.govuk-label--m):not(.govuk-label--l):not(.govuk-label--xl)+.template-list-item-hint { - margin-bottom: $message-type-bottom-spacing; - } - } &-folder { diff --git a/app/assets/stylesheets/govuk-frontend/_all.scss b/app/assets/stylesheets/govuk-frontend/_all.scss index 6776fb95a..9b8755367 100644 --- a/app/assets/stylesheets/govuk-frontend/_all.scss +++ b/app/assets/stylesheets/govuk-frontend/_all.scss @@ -26,7 +26,6 @@ $govuk-assets-path: "/static/"; @import 'components/button/_button'; @import 'components/details/_details'; @import 'components/radios/_radios'; -@import 'components/checkboxes/_checkboxes'; @import "utilities/all"; @import "overrides/all"; diff --git a/app/main/forms.py b/app/main/forms.py index 799f37e8a..0312537ef 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -3,7 +3,7 @@ from datetime import datetime, timedelta from itertools import chain import pytz -from flask import Markup, render_template, request +from flask import request from flask_login import current_user from flask_wtf import FlaskForm as Form from flask_wtf.file import FileAllowed @@ -16,7 +16,6 @@ from notifications_utils.recipients import ( normalise_phone_number, validate_phone_number, ) -from werkzeug.utils import cached_property from wtforms import ( BooleanField, DateField, @@ -318,16 +317,13 @@ class RadioFieldWithNoneOption(FieldWithNoneOption, RadioField): class NestedFieldMixin: - def children(self): - # start map with root option as a single child entry child_map = {None: [option for option in self if option.data == self.NONE_OPTION_VALUE]} # add entries for all other children for option in self: - # assign all options with a NONE_OPTION_VALUE (not always None) to the None key if option.data == self.NONE_OPTION_VALUE: child_ids = [ folder['id'] for folder in self.all_template_folders @@ -343,47 +339,6 @@ class NestedFieldMixin: return child_map - # to be used as the only version of .children once radios are converted - @cached_property - def _children(self): - return self.children() - - def get_items_from_options(self, field): - items = [] - - for option in self._children[None]: - item = self.get_item_from_option(option) - if option.data in self._children: - item['children'] = self.render_children(field.name, option.label.text, self._children[option.data]) - items.append(item) - - return items - - def render_children(self, name, label, options): - params = { - "name": name, - "fieldset": { - "legend": { - "text": label, - "classes": "govuk-visually-hidden" - } - }, - "formGroup": { - "classes": "govuk-form-group--nested" - }, - "asList": True, - "items": [] - } - for option in options: - item = self.get_item_from_option(option) - - if len(self._children[option.data]): - item['children'] = self.render_children(name, option.label.text, self._children[option.data]) - - params['items'].append(item) - - return render_template('forms/fields/checkboxes/template.njk', params=params) - class NestedRadioField(RadioFieldWithNoneOption, NestedFieldMixin): pass @@ -532,201 +487,12 @@ class RegisterUserFromOrgInviteForm(StripWhitespaceForm): auth_type = HiddenField('auth_type', validators=[DataRequired()]) -class govukCheckboxesMixin: - - def extend_params(self, params, extensions): - items = None - param_items = len(params['items']) if 'items' in params else 0 - - # split items off from params to make it a pure dict - if 'items' in extensions: - items = extensions['items'] - del extensions['items'] - - # merge dicts - params.update(extensions) - - # merge items - if items: - if 'items' not in params: - params['items'] = items - else: - for idx, _item in enumerate(items): - if idx >= param_items: - params['items'].append(items[idx]) - else: - params['items'][idx].update(items[idx]) +PermissionsAbstract = type("PermissionsAbstract", (StripWhitespaceForm,), { + permission: BooleanField(label) for permission, label in permissions +}) -class govukCheckboxField(govukCheckboxesMixin, BooleanField): - - def __init__(self, label='', validators=None, param_extensions=None, **kwargs): - super(govukCheckboxField, self).__init__(label, validators, false_values=None, **kwargs) - self.param_extensions = param_extensions - - # self.__call__ renders the HTML for the field by: - # 1. delegating to self.meta.render_field which - # 2. calls field.widget - # this bypasses that by making self.widget a method with the same interface as widget.__call__ - def widget(self, field, param_extensions=None, **kwargs): - - # error messages - error_message = None - if field.errors: - error_message = {"text": " ".join(field.errors).strip()} - - params = { - 'name': field.name, - 'errorMessage': error_message, - 'items': [ - { - "name": field.name, - "id": field.id, - "text": field.label.text, - "value": 'y', - "checked": field.data - } - ] - - } - - # extend default params with any sent in during instantiation - if self.param_extensions: - self.extend_params(params, self.param_extensions) - - # add any sent in though use in templates - if param_extensions: - self.extend_params(params, param_extensions) - - return Markup( - render_template('forms/fields/checkboxes/macro.njk', params=params)) - - -# based on work done by @richardjpope: https://github.com/richardjpope/recourse/blob/master/recourse/forms.py#L6 -class govukCheckboxesField(govukCheckboxesMixin, SelectMultipleField): - - render_as_list = False - - def __init__(self, label='', validators=None, param_extensions=None, **kwargs): - super(govukCheckboxesField, self).__init__(label, validators, **kwargs) - self.param_extensions = param_extensions - - def get_item_from_option(self, option): - return { - "name": option.name, - "id": option.id, - "text": option.label.text, - "value": str(option.data), # to protect against non-string types like uuids - "checked": option.checked - } - - def get_items_from_options(self, field): - return [self.get_item_from_option(option) for option in field] - - def extend_params(self, params, extensions): - items = None - param_items = len(params['items']) if 'items' in params else 0 - - # split items off from params to make it a pure dict - if 'items' in extensions: - items = extensions['items'] - del extensions['items'] - - # merge dicts - params.update(extensions) - - # merge items - if items: - if 'items' not in params: - params['items'] = items - else: - for idx, _item in enumerate(items): - if idx >= param_items: - params['items'].append(items[idx]) - else: - params['items'][idx].update(items[idx]) - - # self.__call__ renders the HTML for the field by: - # 1. delegating to self.meta.render_field which - # 2. calls field.widget - # this bypasses that by making self.widget a method with the same interface as widget.__call__ - def widget(self, field, param_extensions=None, **kwargs): - - # error messages - error_message = None - if field.errors: - error_message = {"text": " ".join(field.errors).strip()} - - # returns either a list or a hierarchy of lists - # depending on how get_items_from_options is implemented - items = self.get_items_from_options(field) - - params = { - 'name': field.name, - "fieldset": { - "attributes": {"id": field.name}, - "legend": { - "text": field.label.text, - "classes": "govuk-fieldset__legend--s" - } - }, - "asList": self.render_as_list, - 'errorMessage': error_message, - 'items': items - } - - # extend default params with any sent in during instantiation - if self.param_extensions: - self.extend_params(params, self.param_extensions) - - # add any sent in though use in templates - if param_extensions: - self.extend_params(params, param_extensions) - - return Markup( - render_template('forms/fields/checkboxes/macro.njk', params=params)) - - -# Extends fields using the govukCheckboxesField interface to wrap their render in HTML needed by the collapsible JS -class govukCollapsibleCheckboxesMixin: - def __init__(self, label='', validators=None, field_label='', param_extensions=None, **kwargs): - - super(govukCollapsibleCheckboxesMixin, self).__init__(label, validators, param_extensions, **kwargs) - self.field_label = field_label - - def widget(self, field, **kwargs): - - # add a blank hint to act as an ARIA live-region - if self.param_extensions is not None: - self.param_extensions.update( - {"hint": {"html": "
"}}) - else: - self.param_extensions = \ - {"hint": {"html": "
"}} - - # wrap the checkboxes HTML in the HTML needed by the collapisble JS - return Markup( - f'
' - f' {super(govukCollapsibleCheckboxesMixin, self).widget(field, **kwargs)}' - f'
' - ) - - -class govukCollapsibleCheckboxesField(govukCollapsibleCheckboxesMixin, govukCheckboxesField): - pass - - -# govukCollapsibleCheckboxesMixin adds an ARIA live-region to the hint and wraps the render in HTML needed by the -# collapsible JS -# NestedFieldMixin puts the items into a tree hierarchy, pre-rendering the sub-trees of the top-level items -class govukCollapsibleNestedCheckboxesField(govukCollapsibleCheckboxesMixin, NestedFieldMixin, govukCheckboxesField): - NONE_OPTION_VALUE = None - render_as_list = True - - -class PermissionsForm(StripWhitespaceForm): +class PermissionsForm(PermissionsAbstract): def __init__(self, all_template_folders=None, *args, **kwargs): super().__init__(*args, **kwargs) self.folder_permissions.choices = [] @@ -736,9 +502,7 @@ class PermissionsForm(StripWhitespaceForm): (item['id'], item['name']) for item in ([{'name': 'Templates', 'id': None}] + all_template_folders) ] - folder_permissions = govukCollapsibleNestedCheckboxesField( - 'Folders this team member can see', - field_label='folder') + folder_permissions = NestedCheckboxesField('Folders this team member can see') login_authentication = RadioField( 'Sign in using', @@ -750,23 +514,21 @@ class PermissionsForm(StripWhitespaceForm): validators=[DataRequired()] ) - permissions_field = govukCheckboxesField( - 'Permssions', - choices=[ - (value, label) for value, label in permissions - ], - param_extensions={ - "hint": {"text": "All team members can see sent messages."} - } - ) + @property + def permissions(self): + return {role for role in roles.keys() if self[role].data is True} + + @property + def permissions_fields(self): + return (getattr(self, permission) for permission, _ in permissions) @classmethod def from_user(cls, user, service_id, **kwargs): return cls( **kwargs, **{ - "permissions_field": [ - role for role in roles.keys() if user.has_permission_for_service(service_id, role)] + role: user.has_permission_for_service(service_id, role) + for role in roles.keys() }, login_authentication=user.auth_type ) @@ -1323,7 +1085,7 @@ class ServiceContactDetailsForm(StripWhitespaceForm): class ServiceReplyToEmailForm(StripWhitespaceForm): email_address = email_address(label='Reply-to email address', gov_user=False) - is_default = govukCheckboxField("Make this email address the default") + is_default = BooleanField("Make this email address the default") class ServiceSmsSenderForm(StripWhitespaceForm): @@ -1337,11 +1099,11 @@ class ServiceSmsSenderForm(StripWhitespaceForm): DoesNotStartWithDoubleZero(), ] ) - is_default = govukCheckboxField("Make this text message sender the default") + is_default = BooleanField("Make this text message sender the default") class ServiceEditInboundNumberForm(StripWhitespaceForm): - is_default = govukCheckboxField("Make this text message sender the default") + is_default = BooleanField("Make this text message sender the default") class ServiceLetterContactBlockForm(StripWhitespaceForm): @@ -1351,7 +1113,7 @@ class ServiceLetterContactBlockForm(StripWhitespaceForm): NoCommasInPlaceHolders() ] ) - is_default = govukCheckboxField("Set as your default address") + is_default = BooleanField("Set as your default address") def validate_letter_contact_block(self, field): line_count = field.data.strip().count('\n') @@ -1517,7 +1279,7 @@ class Whitelist(StripWhitespaceForm): class DateFilterForm(StripWhitespaceForm): start_date = DateField("Start Date", [validators.optional()]) end_date = DateField("End Date", [validators.optional()]) - include_from_test_key = govukCheckboxField("Include test keys") + include_from_test_key = BooleanField("Include test keys", default="checked", false_values={"N"}) class RequiredDateFilterForm(StripWhitespaceForm): @@ -1829,9 +1591,7 @@ class TemplateFolderForm(StripWhitespaceForm): (item.id, item.name) for item in all_service_users ] - users_with_permission = govukCollapsibleCheckboxesField( - 'Team members who can see this folder', - field_label='folder') + users_with_permission = MultiCheckboxField('Team members who can see this folder') name = StringField('Folder name', validators=[DataRequired(message='Cannot be empty')]) @@ -1921,18 +1681,9 @@ class TemplateAndFoldersSelectionForm(Form): return self.move_to_new_folder_name.data return None - templates_and_folders = govukCheckboxesField( - 'Choose templates or folders', - validators=[required_for_ops('move-to-new-folder', 'move-to-existing-folder')], - choices=[], # added to keep order of arguments, added properly in __init__ - param_extensions={ - "fieldset": { - "legend": { - "classes": "govuk-visually-hidden" - } - } - } - ) + templates_and_folders = MultiCheckboxField('Choose templates or folders', validators=[ + required_for_ops('move-to-new-folder', 'move-to-existing-folder') + ]) # if no default set, it is set to None, which process_data transforms to '__NONE__' # this means '__NONE__' (self.ALL_TEMPLATES option) is selected when no form data has been submitted # set default to empty string so process_data method doesn't perform any transformation diff --git a/app/main/views/manage_users.py b/app/main/views/manage_users.py index f404309fd..8102ba521 100644 --- a/app/main/views/manage_users.py +++ b/app/main/views/manage_users.py @@ -63,7 +63,7 @@ def invite_user(service_id): current_user.id, service_id, email_address, - set(form.permissions_field.data), + form.permissions, form.login_authentication.data, form.folder_permissions.data, ) @@ -102,7 +102,7 @@ def edit_user_permissions(service_id, user_id): if form.validate_on_submit(): user.set_permissions( service_id, - permissions=set(form.permissions_field.data), + permissions=form.permissions, folder_permissions=form.folder_permissions.data, ) if service_has_email_auth: diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index 5e86c539b..49e381248 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -168,11 +168,9 @@ def platform_admin_services(): # Default to True if the user hasn’t done any filtering, # otherwise respect their choice form.include_from_test_key.data = True - - include_from_test_key = form.include_from_test_key.data api_args = {'detailed': True, 'only_active': False, # specifically DO get inactive services - 'include_from_test_key': include_from_test_key, + 'include_from_test_key': form.include_from_test_key.data, } if form.start_date.data: @@ -186,7 +184,7 @@ def platform_admin_services(): return render_template( 'views/platform-admin/services.html', - include_from_test_key=include_from_test_key, + include_from_test_key=form.include_from_test_key.data, form=form, services=list(format_stats_by_service(services)), page_title='{} services'.format( diff --git a/app/templates/components/checkbox.html b/app/templates/components/checkbox.html new file mode 100644 index 000000000..3647c4f1c --- /dev/null +++ b/app/templates/components/checkbox.html @@ -0,0 +1,46 @@ +{% from "components/select-input.html" import select_nested, select %} + +{% macro checkbox( + field, + hint=False, + width='2-3' +) %} +
+ {{ checkbox_input(field.id, field.name, field.data) }} + +
+{% endmacro %} + + +{% macro checkboxes_nested(field, child_map, hint=None, disable=[], option_hints={}, hide_legend=False, collapsible_opts={}, legend_style="text") %} + {{ select_nested(field, child_map, hint, disable, option_hints, hide_legend, collapsible_opts, legend_style, input="checkbox") }} +{% endmacro %} + + +{% macro checkboxes(field, hint=None, disable=[], option_hints={}, hide_legend=False, collapsible_opts={}) %} + {{ select(field, hint, disable, option_hints, hide_legend, collapsible_opts, input="checkbox") }} +{% endmacro %} + + +{% macro checkbox_input(id, name, data=None, value="y") %} + +{% endmacro %} + +{% macro unlabelled_checkbox(id, name, data=None, value="y") %} +
+ {{ checkbox_input(id, name, data, value) }} + +
+{% endmacro %} diff --git a/app/templates/forms/fields/checkboxes/macro.njk b/app/templates/forms/fields/checkboxes/macro.njk deleted file mode 100644 index c91452053..000000000 --- a/app/templates/forms/fields/checkboxes/macro.njk +++ /dev/null @@ -1,4 +0,0 @@ -{%- macro govukCheckboxes(params) %} - {%- include "./template.njk" -%} -{%- endmacro %} -{{ govukCheckboxes(params) }} diff --git a/app/templates/forms/fields/checkboxes/template.njk b/app/templates/forms/fields/checkboxes/template.njk deleted file mode 100644 index 2ac9cf68b..000000000 --- a/app/templates/forms/fields/checkboxes/template.njk +++ /dev/null @@ -1,134 +0,0 @@ -{% from "components/error-message/macro.njk" import govukErrorMessage -%} -{% from "components/fieldset/macro.njk" import govukFieldset %} -{% from "components/hint/macro.njk" import govukHint %} -{% from "components/label/macro.njk" import govukLabel %} - - -{#- Copied from https://github.com/alphagov/govuk-frontend/blob/v2.13.0/src/components/checkboxes/template.njk - Changes: - - `classes` option added to `item` allow custom classes on the `.govuk-checkboxes__item` element - - `classes` option added to `item.hint` allow custom classes on the `.govuk-hint` element (added to GOVUK Frontend in v3.5.0 - remove when we update) - - `asList` option added the root `params` object to allow setting of the `.govuk-checkboxes` and `.govuk-checkboxes__item` element types - - `children` option added to `item` allowing the sending in of prerendered child checkboxes (allowing the creation of tree structures through recursion) -#} -{#- 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 = params.describedBy if params.describedBy else "" %} -{% if params.fieldset.describedBy %} - {% set describedBy = params.fieldset.describedBy %} -{% endif %} - -{#- set the types of element used for the checkboxes and their group based on - whether asList is set -#} -{% if params.asList %} - {% set groupElement = 'ul' %} - {% set groupItemElement = 'li' %} -{% else %} - {% set groupElement = 'div' %} - {% set groupItemElement = 'div' %} -{% endif %} - -{% 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 - }) | indent(2) | trim }} -{% 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, - visuallyHiddenText: params.errorMessage.visuallyHiddenText - }) | indent(2) | trim }} -{% endif %} - <{{ groupElement }} class="govuk-checkboxes {%- if params.classes %} {{ params.classes }}{% endif %}" - {%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor %} - {%- if isConditional %} data-module="checkboxes"{% endif -%}> - {% for item in params.items %} - {% set id = item.id if item.id else idPrefix + "-" + loop.index %} - {% set name = item.name if item.name else params.name %} - {% set conditionalId = "conditional-" + id %} - {% set hasHint = true if item.hint.text or item.hint.html %} - {% set itemHintId = id + "-item-hint" if hasHint else "" %} - {% set itemDescribedBy = describedBy if not hasFieldset else "" %} - {% set itemDescribedBy = (itemDescribedBy + " " + itemHintId) | trim %} - <{{ groupItemElement }} class="govuk-checkboxes__item {%- if item.classes %} {{ item.classes }}{% endif %}"> - - {{ govukLabel({ - html: item.html, - text: item.text, - classes: 'govuk-checkboxes__label' + (' ' + item.label.classes if item.label.classes), - attributes: item.label.attributes, - for: id - }) | indent(6) | trim }} - {%- if hasHint %} - {{ govukHint({ - id: itemHintId, - classes: 'govuk-checkboxes__hint' + (' ' + item.hint.classes if item.hint.classes), - attributes: item.hint.attributes, - html: item.hint.html, - text: item.hint.text - }) | indent(6) | trim }} - {%- endif %} - {%- if item.children %} - {{ item.children | safe }} - {%- endif %} - {% if params.asList and item.conditional %} -
- {{ item.conditional.html | safe }} -
- {% endif %} - - {% if not params.asList and 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 | trim | safe }} - {% endcall %} -{% else %} - {{ innerHtml | trim | safe }} -{% endif %} -
diff --git a/app/templates/views/invite-user.html b/app/templates/views/invite-user.html index 11ae6a050..6ffb0ba04 100644 --- a/app/templates/views/invite-user.html +++ b/app/templates/views/invite-user.html @@ -1,4 +1,5 @@ {% extends "withnav_template.html" %} +{% from "components/checkbox.html" import checkbox %} {% from "components/textbox.html" import textbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} diff --git a/app/templates/views/manage-users/permissions.html b/app/templates/views/manage-users/permissions.html index 77189dcb0..e6ee7637d 100644 --- a/app/templates/views/manage-users/permissions.html +++ b/app/templates/views/manage-users/permissions.html @@ -1,9 +1,20 @@ +{% from "components/checkbox.html" import checkbox, checkboxes_nested %} {% from "components/radios.html" import radio, radios, conditional_radio_panel %} -{{ form.permissions_field }} +
+ + Permissions + + + All team members can see sent messages. + + {% for field in form.permissions_fields %} + {{ checkbox(field) }} + {% endfor %} +
{% if form.folder_permissions.all_template_folders %} - {{ form.folder_permissions }} + {{ checkboxes_nested(form.folder_permissions, form.folder_permissions.children(), hide_legend=True, collapsible_opts={ 'field': 'folder' }) }} {% elif user and user.platform_admin %}

Platform admin users can access all template folders. diff --git a/app/templates/views/platform-admin/_base_template.html b/app/templates/views/platform-admin/_base_template.html index c3dd1e1e1..5d5c13743 100644 --- a/app/templates/views/platform-admin/_base_template.html +++ b/app/templates/views/platform-admin/_base_template.html @@ -1,5 +1,6 @@ {% extends "withoutnav_template.html" %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-footer.html" import page_footer %} diff --git a/app/templates/views/platform-admin/services.html b/app/templates/views/platform-admin/services.html index e9160eb1d..c9e9fb84a 100644 --- a/app/templates/views/platform-admin/services.html +++ b/app/templates/views/platform-admin/services.html @@ -1,5 +1,6 @@ {% extends "views/platform-admin/_base_template.html" %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-footer.html" import page_footer %} {% from "components/big-number.html" import big_number, big_number_with_status %} {% from "components/message-count-label.html" import message_count_label %} @@ -107,7 +108,8 @@ {% call form_wrapper(method="get") %} {{ textbox(form.start_date, hint="Enter start date in format YYYY-MM-DD") }} {{ textbox(form.end_date, hint="Enter end date in format YYYY-MM-DD") }} - {{ form.include_from_test_key }} + {{ checkbox(form.include_from_test_key) }} +
{{ govukButton({ "text": "Filter" }) }} {% endcall %} {% endset %} diff --git a/app/templates/views/service-settings/email-reply-to/_verify-updates.html b/app/templates/views/service-settings/email-reply-to/_verify-updates.html index 9d73d83f6..a6cc0d476 100644 --- a/app/templates/views/service-settings/email-reply-to/_verify-updates.html +++ b/app/templates/views/service-settings/email-reply-to/_verify-updates.html @@ -1,5 +1,6 @@ {% from "components/banner.html" import banner, banner_wrapper %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} {% from "components/button/macro.njk" import govukButton %} @@ -54,7 +55,9 @@ hint='This should be a shared inbox managed by your team, not your own email address' ) }} {% if not first_email_address and not existing_is_default %} - {{ form.is_default }} +

+ {{ checkbox(form.is_default) }} +
{% endif %} {{ page_footer('Try again') }} {% endcall %} diff --git a/app/templates/views/service-settings/email-reply-to/add.html b/app/templates/views/service-settings/email-reply-to/add.html index a9b9774d6..65135fe26 100644 --- a/app/templates/views/service-settings/email-reply-to/add.html +++ b/app/templates/views/service-settings/email-reply-to/add.html @@ -1,5 +1,6 @@ {% extends "withnav_template.html" %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} @@ -23,7 +24,9 @@ safe_error_message=True ) }} {% if not first_email_address %} - {{ form.is_default }} +
+ {{ checkbox(form.is_default) }} +
{% endif %} {{ page_footer('Add') }} {% endcall %} diff --git a/app/templates/views/service-settings/email-reply-to/edit.html b/app/templates/views/service-settings/email-reply-to/edit.html index 2d675fb1f..cdf7e66d9 100644 --- a/app/templates/views/service-settings/email-reply-to/edit.html +++ b/app/templates/views/service-settings/email-reply-to/edit.html @@ -1,6 +1,7 @@ {% extends "withnav_template.html" %} {% from "components/banner.html" import banner_wrapper %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} @@ -28,7 +29,9 @@

{{ page_footer('Save') }} {% else %} - {{ form.is_default }} +
+ {{ checkbox(form.is_default) }} +
{{ page_footer( 'Save', delete_link=url_for('.service_confirm_delete_email_reply_to', service_id=current_service.id, reply_to_email_id=reply_to_email_address_id), diff --git a/app/templates/views/service-settings/email-reply-to/verify.html b/app/templates/views/service-settings/email-reply-to/verify.html index 407f693c5..00d4c8c10 100644 --- a/app/templates/views/service-settings/email-reply-to/verify.html +++ b/app/templates/views/service-settings/email-reply-to/verify.html @@ -1,5 +1,6 @@ {% extends "withnav_template.html" %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} diff --git a/app/templates/views/service-settings/letter-contact/add.html b/app/templates/views/service-settings/letter-contact/add.html index ab1ba67b7..46f10b0da 100644 --- a/app/templates/views/service-settings/letter-contact/add.html +++ b/app/templates/views/service-settings/letter-contact/add.html @@ -1,5 +1,6 @@ {% extends "withnav_template.html" %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} @@ -26,7 +27,9 @@ highlight_placeholders=True ) }} {% if not first_contact_block %} - {{ form.is_default }} +
+ {{ checkbox(form.is_default) }} +
{% endif %} {{ page_footer('Add') }} {% endcall %} diff --git a/app/templates/views/service-settings/letter-contact/edit.html b/app/templates/views/service-settings/letter-contact/edit.html index a4be56d40..cb1a63b87 100644 --- a/app/templates/views/service-settings/letter-contact/edit.html +++ b/app/templates/views/service-settings/letter-contact/edit.html @@ -1,5 +1,6 @@ {% extends "withnav_template.html" %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} @@ -30,7 +31,9 @@ This is currently your default address for {{ current_service.name }}.

{% else %} - {{ form.is_default }} +
+ {{ checkbox(form.is_default) }} +
{% endif %} {{ page_footer( diff --git a/app/templates/views/service-settings/sms-sender/add.html b/app/templates/views/service-settings/sms-sender/add.html index 1bf80bacb..950d5059f 100644 --- a/app/templates/views/service-settings/sms-sender/add.html +++ b/app/templates/views/service-settings/sms-sender/add.html @@ -1,5 +1,6 @@ {% extends "withnav_template.html" %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} @@ -22,7 +23,9 @@ hint='Up to 11 characters, letters, numbers and spaces only' ) }} {% if not first_sms_sender %} - {{ form.is_default }} +
+ {{ checkbox(form.is_default) }} +
{% endif %} {{ page_footer('Save') }} {% endcall %} diff --git a/app/templates/views/service-settings/sms-sender/edit.html b/app/templates/views/service-settings/sms-sender/edit.html index 2eda64235..3e3d543de 100644 --- a/app/templates/views/service-settings/sms-sender/edit.html +++ b/app/templates/views/service-settings/sms-sender/edit.html @@ -1,6 +1,7 @@ {% extends "withnav_template.html" %} {% from "components/banner.html" import banner_wrapper %} {% from "components/textbox.html" import textbox %} +{% from "components/checkbox.html" import checkbox %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} @@ -34,7 +35,9 @@

{{ page_footer('Save') }} {% else %} - {{ form.is_default }} +
+ {{ checkbox(form.is_default) }} +
{% if inbound_number %} {{ page_footer('Save') }} {% else %} diff --git a/app/templates/views/support/form.html b/app/templates/views/support/form.html index dd07a0628..bf5e2c36a 100644 --- a/app/templates/views/support/form.html +++ b/app/templates/views/support/form.html @@ -1,4 +1,5 @@ {% extends "withoutnav_template.html" %} +{% from "components/checkbox.html" import checkbox %} {% from "components/textbox.html" import textbox %} {% from "components/page-footer.html" import sticky_page_footer %} {% from "components/page-header.html" import page_header %} diff --git a/app/templates/views/templates/_template_list.html b/app/templates/views/templates/_template_list.html index 2121a011e..5bcb03501 100644 --- a/app/templates/views/templates/_template_list.html +++ b/app/templates/views/templates/_template_list.html @@ -1,3 +1,4 @@ +{% from "components/checkbox.html" import unlabelled_checkbox %} {% from "components/message-count-label.html" import folder_contents_count, message_count_label %} {% macro format_item_name(name) -%} @@ -20,58 +21,37 @@ {% endif %}

{% else %} -