mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-11 10:28:41 -04:00
Merge pull request #3535 from alphagov/try-introducing-govuk-checkboxes-again
Try introducing govuk checkboxes again
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
function Summary (module) {
|
function Summary (module) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.$el = module.$formGroup.find('.selection-summary');
|
this.$el = module.$formGroup.find('.selection-summary').first();
|
||||||
this.fieldLabel = module.fieldLabel;
|
this.fieldLabel = module.fieldLabel;
|
||||||
this.total = module.total;
|
this.total = module.total;
|
||||||
this.addContent();
|
this.addContent();
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
if (this.fieldLabel === 'folder') { this.$text.addClass('selection-summary__text--folders'); }
|
if (this.fieldLabel === 'folder') { this.$text.addClass('selection-summary__text--folders'); }
|
||||||
|
|
||||||
this.$el.append(this.$text);
|
this.$el.append(this.$text);
|
||||||
|
this.module.$formGroup.find('.govuk-hint').remove();
|
||||||
};
|
};
|
||||||
Summary.prototype.update = function(selection) {
|
Summary.prototype.update = function(selection) {
|
||||||
let template;
|
let template;
|
||||||
@@ -86,12 +87,13 @@
|
|||||||
.focus();
|
.focus();
|
||||||
};
|
};
|
||||||
CollapsibleCheckboxes.prototype.start = function(component) {
|
CollapsibleCheckboxes.prototype.start = function(component) {
|
||||||
this.$formGroup = $(component);
|
this.$component = $(component);
|
||||||
this.$fieldset = this.$formGroup.find('fieldset');
|
this.$formGroup = this.$component.find('.govuk-form-group').first();
|
||||||
|
this.$fieldset = this.$formGroup.find('fieldset').first();
|
||||||
this.$checkboxes = this.$fieldset.find('input[type=checkbox]');
|
this.$checkboxes = this.$fieldset.find('input[type=checkbox]');
|
||||||
this.fieldLabel = this.$formGroup.data('fieldLabel');
|
this.fieldLabel = this.$component.data('fieldLabel');
|
||||||
this.total = this.$checkboxes.length;
|
this.total = this.$checkboxes.length;
|
||||||
this.legendText = this.$fieldset.find('legend').text().trim();
|
this.legendText = this.$fieldset.find('legend').first().text().trim();
|
||||||
this.expanded = false;
|
this.expanded = false;
|
||||||
|
|
||||||
this.addHeadingHideLegend();
|
this.addHeadingHideLegend();
|
||||||
@@ -113,7 +115,7 @@
|
|||||||
};
|
};
|
||||||
CollapsibleCheckboxes.prototype.getSelection = function() { return this.$checkboxes.filter(':checked').length; };
|
CollapsibleCheckboxes.prototype.getSelection = function() { return this.$checkboxes.filter(':checked').length; };
|
||||||
CollapsibleCheckboxes.prototype.addHeadingHideLegend = function() {
|
CollapsibleCheckboxes.prototype.addHeadingHideLegend = function() {
|
||||||
const headingLevel = this.$formGroup.data('heading-level') || '2';
|
const headingLevel = this.$component.data('heading-level') || '2';
|
||||||
|
|
||||||
this.$heading = $(`<h${headingLevel} class="heading-small">${this.legendText}</h${headingLevel}>`);
|
this.$heading = $(`<h${headingLevel} class="heading-small">${this.legendText}</h${headingLevel}>`);
|
||||||
this.$fieldset.before(this.$heading);
|
this.$fieldset.before(this.$heading);
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// 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 {
|
||||||
|
|
||||||
.selection-summary__text {
|
.selection-summary__text {
|
||||||
@@ -65,6 +69,30 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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 {
|
.selection-content {
|
||||||
margin-bottom: govuk-spacing(4);
|
margin-bottom: govuk-spacing(4);
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$govuk-checkboxes-size: 40px;
|
||||||
|
$govuk-checkboxes-label-padding-left-right: govuk-spacing(3);
|
||||||
|
$message-type-bottom-spacing: govuk-spacing(4);
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
|
|
||||||
&-name {
|
&-name {
|
||||||
@include bold-24;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@@ -63,37 +66,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-type {
|
&-type {
|
||||||
color: $secondary-text-colour;
|
color: $govuk-secondary-text-colour;
|
||||||
margin: 0 0 govuk-spacing(4) 0;
|
margin: 0 0 $message-type-bottom-spacing 0;
|
||||||
|
padding-left: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#template-list {
|
|
||||||
|
|
||||||
margin-top: govuk-spacing(6);
|
|
||||||
|
|
||||||
&.top-gutter-5px {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.template-list {
|
.template-list {
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
|
|
||||||
&-with-checkbox {
|
&-with-checkbox {
|
||||||
|
padding-left: $govuk-checkboxes-size + $govuk-checkboxes-label-padding-left-right;
|
||||||
position: relative;
|
|
||||||
padding-left: govuk-spacing(9);
|
|
||||||
|
|
||||||
.multiple-choice {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&-hidden-by-default {
|
&-hidden-by-default {
|
||||||
@@ -123,6 +109,29 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-label {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: $govuk-checkboxes-size + $govuk-checkboxes-label-padding-left-right;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-hint {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&-folder,
|
||||||
|
&-template {
|
||||||
|
@include govuk-font($size: 24, $weight: bold, $line-height: 1.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
&-folder {
|
&-folder {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ $govuk-assets-path: "/static/";
|
|||||||
@import 'components/button/_button';
|
@import 'components/button/_button';
|
||||||
@import 'components/details/_details';
|
@import 'components/details/_details';
|
||||||
@import 'components/radios/_radios';
|
@import 'components/radios/_radios';
|
||||||
|
@import 'components/checkboxes/_checkboxes';
|
||||||
|
|
||||||
@import "utilities/all";
|
@import "utilities/all";
|
||||||
@import "overrides/all";
|
@import "overrides/all";
|
||||||
|
|||||||
+338
-21
@@ -3,7 +3,7 @@ from datetime import datetime, timedelta
|
|||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
from flask import request
|
from flask import Markup, render_template, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from flask_wtf import FlaskForm as Form
|
from flask_wtf import FlaskForm as Form
|
||||||
from flask_wtf.file import FileAllowed
|
from flask_wtf.file import FileAllowed
|
||||||
@@ -17,6 +17,7 @@ from notifications_utils.recipients import (
|
|||||||
normalise_phone_number,
|
normalise_phone_number,
|
||||||
validate_phone_number,
|
validate_phone_number,
|
||||||
)
|
)
|
||||||
|
from werkzeug.utils import cached_property
|
||||||
from wtforms import (
|
from wtforms import (
|
||||||
BooleanField,
|
BooleanField,
|
||||||
DateField,
|
DateField,
|
||||||
@@ -37,7 +38,6 @@ from wtforms import (
|
|||||||
)
|
)
|
||||||
from wtforms.fields.html5 import EmailField, SearchField, TelField
|
from wtforms.fields.html5 import EmailField, SearchField, TelField
|
||||||
from wtforms.validators import URL, DataRequired, Length, Optional, Regexp
|
from wtforms.validators import URL, DataRequired, Length, Optional, Regexp
|
||||||
from wtforms.widgets import CheckboxInput, ListWidget
|
|
||||||
|
|
||||||
from app import format_thousands
|
from app import format_thousands
|
||||||
from app.main.validators import (
|
from app.main.validators import (
|
||||||
@@ -117,11 +117,6 @@ def get_next_days_until(until):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class MultiCheckboxField(SelectMultipleField):
|
|
||||||
widget = ListWidget(prefix_label=False)
|
|
||||||
option_widget = CheckboxInput()
|
|
||||||
|
|
||||||
|
|
||||||
class RadioField(WTFormsRadioField):
|
class RadioField(WTFormsRadioField):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -322,13 +317,16 @@ class RadioFieldWithNoneOption(FieldWithNoneOption, RadioField):
|
|||||||
|
|
||||||
|
|
||||||
class NestedFieldMixin:
|
class NestedFieldMixin:
|
||||||
|
|
||||||
def children(self):
|
def children(self):
|
||||||
|
|
||||||
# start map with root option as a single child entry
|
# start map with root option as a single child entry
|
||||||
child_map = {None: [option for option in self
|
child_map = {None: [option for option in self
|
||||||
if option.data == self.NONE_OPTION_VALUE]}
|
if option.data == self.NONE_OPTION_VALUE]}
|
||||||
|
|
||||||
# add entries for all other children
|
# add entries for all other children
|
||||||
for option in self:
|
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:
|
if option.data == self.NONE_OPTION_VALUE:
|
||||||
child_ids = [
|
child_ids = [
|
||||||
folder['id'] for folder in self.all_template_folders
|
folder['id'] for folder in self.all_template_folders
|
||||||
@@ -344,6 +342,47 @@ class NestedFieldMixin:
|
|||||||
|
|
||||||
return child_map
|
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):
|
class NestedRadioField(RadioFieldWithNoneOption, NestedFieldMixin):
|
||||||
pass
|
pass
|
||||||
@@ -492,11 +531,239 @@ class RegisterUserFromOrgInviteForm(StripWhitespaceForm):
|
|||||||
auth_type = HiddenField('auth_type', validators=[DataRequired()])
|
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])
|
||||||
|
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
"attributes": {
|
||||||
|
"data-module": "track-error",
|
||||||
|
"data-error-type": field.errors[0],
|
||||||
|
"data-error-label": field.name
|
||||||
|
},
|
||||||
|
"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 = {
|
||||||
|
"attributes": {
|
||||||
|
"data-module": "track-error",
|
||||||
|
"data-error-type": field.errors[0],
|
||||||
|
"data-error-label": field.name
|
||||||
|
},
|
||||||
|
"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": "<div class=\"selection-summary\" role=\"region\" aria-live=\"polite\"></div>"}})
|
||||||
|
else:
|
||||||
|
self.param_extensions = \
|
||||||
|
{"hint": {"html": "<div class=\"selection-summary\" role=\"region\" aria-live=\"polite\"></div>"}}
|
||||||
|
|
||||||
|
# wrap the checkboxes HTML in the HTML needed by the collapisble JS
|
||||||
|
return Markup(
|
||||||
|
f'<div class="selection-wrapper"'
|
||||||
|
f' data-module="collapsible-checkboxes"'
|
||||||
|
f' data-field-label="{self.field_label}">'
|
||||||
|
f' {super(govukCollapsibleCheckboxesMixin, self).widget(field, **kwargs)}'
|
||||||
|
f'</div>'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# guard against data entries that aren't a role in permissions
|
||||||
|
def filter_by_permissions(valuelist):
|
||||||
|
if valuelist is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return [entry for entry in valuelist if any(entry in role for role in permissions)]
|
||||||
|
|
||||||
|
|
||||||
|
# guard against data entries that aren't a role in broadcast_permissions
|
||||||
|
def filter_by_broadcast_permissions(valuelist):
|
||||||
|
if valuelist is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return [entry for entry in valuelist if any(entry in role for role in broadcast_permissions)]
|
||||||
|
|
||||||
|
|
||||||
|
# Included to support both versions of how user permissions are handled in permissions forms
|
||||||
|
# Remove when changeover to new version (permissions_field) is complete
|
||||||
PermissionsAbstract = type("PermissionsAbstract", (StripWhitespaceForm,), {
|
PermissionsAbstract = type("PermissionsAbstract", (StripWhitespaceForm,), {
|
||||||
permission: BooleanField(label) for permission, label in permissions
|
permission: BooleanField(label) for permission, label in permissions
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
# Included to support both versions of how user permissions are handled in permissions forms
|
||||||
|
# Remove when changeover to new version (permissions_field) is complete
|
||||||
BroadcastPermissionsAbstract = type("BroadcastPermissionsAbstract", (StripWhitespaceForm,), {
|
BroadcastPermissionsAbstract = type("BroadcastPermissionsAbstract", (StripWhitespaceForm,), {
|
||||||
permission: BooleanField(label) for permission, label in broadcast_permissions
|
permission: BooleanField(label) for permission, label in broadcast_permissions
|
||||||
})
|
})
|
||||||
@@ -512,7 +779,9 @@ class BasePermissionsForm(StripWhitespaceForm):
|
|||||||
(item['id'], item['name']) for item in ([{'name': 'Templates', 'id': None}] + all_template_folders)
|
(item['id'], item['name']) for item in ([{'name': 'Templates', 'id': None}] + all_template_folders)
|
||||||
]
|
]
|
||||||
|
|
||||||
folder_permissions = NestedCheckboxesField('Folders this team member can see')
|
folder_permissions = govukCollapsibleNestedCheckboxesField(
|
||||||
|
'Folders this team member can see',
|
||||||
|
field_label='folder')
|
||||||
|
|
||||||
login_authentication = RadioField(
|
login_authentication = RadioField(
|
||||||
'Sign in using',
|
'Sign in using',
|
||||||
@@ -524,10 +793,30 @@ class BasePermissionsForm(StripWhitespaceForm):
|
|||||||
validators=[DataRequired()]
|
validators=[DataRequired()]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
permissions_field = govukCheckboxesField(
|
||||||
|
'Permssions',
|
||||||
|
filters=[filter_by_permissions],
|
||||||
|
choices=[
|
||||||
|
(value, label) for value, label in permissions
|
||||||
|
],
|
||||||
|
param_extensions={
|
||||||
|
"hint": {"text": "All team members can see sent messages."}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Modified to support both versions of how user permissions are handled in permissions forms
|
||||||
|
# Remove when changeover to new version (permissions_field) is complete
|
||||||
@property
|
@property
|
||||||
def permissions(self):
|
def permissions(self):
|
||||||
return {field.id for field in self.permissions_fields if field.data is True}
|
permissions_field_data = set(self.permissions_field.data)
|
||||||
|
permissions_fields_data = {field.id for field in self.permissions_fields if field.data is True}
|
||||||
|
if len(permissions_field_data) == 0 and len(permissions_fields_data) != 0:
|
||||||
|
return permissions_fields_data
|
||||||
|
else:
|
||||||
|
return permissions_field_data
|
||||||
|
|
||||||
|
# Included to support both versions of how user permissions are handled in permissions forms
|
||||||
|
# Remove when changeover to new version (permissions_field) is complete
|
||||||
@property
|
@property
|
||||||
def permissions_fields(self):
|
def permissions_fields(self):
|
||||||
return (
|
return (
|
||||||
@@ -540,19 +829,34 @@ class BasePermissionsForm(StripWhitespaceForm):
|
|||||||
return cls(
|
return cls(
|
||||||
**kwargs,
|
**kwargs,
|
||||||
**{
|
**{
|
||||||
role: user.has_permission_for_service(service_id, role)
|
"permissions_field": [
|
||||||
for role in roles.keys()
|
role for role in roles.keys() if user.has_permission_for_service(service_id, role)]
|
||||||
},
|
},
|
||||||
login_authentication=user.auth_type
|
login_authentication=user.auth_type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Included to support both versions of how user permissions are handled in permissions forms
|
||||||
|
# Remove when changeover to new version (permissions_field) is complete
|
||||||
class PermissionsForm(PermissionsAbstract, BasePermissionsForm):
|
class PermissionsForm(PermissionsAbstract, BasePermissionsForm):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Included to support both versions of how user permissions are handled in permissions forms
|
||||||
|
# Remove when changeover to new version (permissions_field) is complete
|
||||||
class BroadcastPermissionsForm(BroadcastPermissionsAbstract, BasePermissionsForm):
|
class BroadcastPermissionsForm(BroadcastPermissionsAbstract, BasePermissionsForm):
|
||||||
|
|
||||||
|
permissions_field = govukCheckboxesField(
|
||||||
|
'Permssions',
|
||||||
|
choices=[
|
||||||
|
(value, label) for value, label in broadcast_permissions
|
||||||
|
],
|
||||||
|
filters=[filter_by_broadcast_permissions],
|
||||||
|
param_extensions={
|
||||||
|
"hint": {"text": "All team members can see sent messages."}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def permissions(self):
|
def permissions(self):
|
||||||
return {'view_activity'} | super().permissions
|
return {'view_activity'} | super().permissions
|
||||||
@@ -1155,7 +1459,7 @@ class ServiceContactDetailsForm(StripWhitespaceForm):
|
|||||||
|
|
||||||
class ServiceReplyToEmailForm(StripWhitespaceForm):
|
class ServiceReplyToEmailForm(StripWhitespaceForm):
|
||||||
email_address = email_address(label='Reply-to email address', gov_user=False)
|
email_address = email_address(label='Reply-to email address', gov_user=False)
|
||||||
is_default = BooleanField("Make this email address the default")
|
is_default = govukCheckboxField("Make this email address the default")
|
||||||
|
|
||||||
|
|
||||||
class ServiceSmsSenderForm(StripWhitespaceForm):
|
class ServiceSmsSenderForm(StripWhitespaceForm):
|
||||||
@@ -1169,11 +1473,11 @@ class ServiceSmsSenderForm(StripWhitespaceForm):
|
|||||||
DoesNotStartWithDoubleZero(),
|
DoesNotStartWithDoubleZero(),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
is_default = BooleanField("Make this text message sender the default")
|
is_default = govukCheckboxField("Make this text message sender the default")
|
||||||
|
|
||||||
|
|
||||||
class ServiceEditInboundNumberForm(StripWhitespaceForm):
|
class ServiceEditInboundNumberForm(StripWhitespaceForm):
|
||||||
is_default = BooleanField("Make this text message sender the default")
|
is_default = govukCheckboxField("Make this text message sender the default")
|
||||||
|
|
||||||
|
|
||||||
class ServiceLetterContactBlockForm(StripWhitespaceForm):
|
class ServiceLetterContactBlockForm(StripWhitespaceForm):
|
||||||
@@ -1183,7 +1487,7 @@ class ServiceLetterContactBlockForm(StripWhitespaceForm):
|
|||||||
NoCommasInPlaceHolders()
|
NoCommasInPlaceHolders()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
is_default = BooleanField("Set as your default address")
|
is_default = govukCheckboxField("Set as your default address")
|
||||||
|
|
||||||
def validate_letter_contact_block(self, field):
|
def validate_letter_contact_block(self, field):
|
||||||
line_count = field.data.strip().count('\n')
|
line_count = field.data.strip().count('\n')
|
||||||
@@ -1349,7 +1653,7 @@ class GuestList(StripWhitespaceForm):
|
|||||||
class DateFilterForm(StripWhitespaceForm):
|
class DateFilterForm(StripWhitespaceForm):
|
||||||
start_date = DateField("Start Date", [validators.optional()])
|
start_date = DateField("Start Date", [validators.optional()])
|
||||||
end_date = DateField("End Date", [validators.optional()])
|
end_date = DateField("End Date", [validators.optional()])
|
||||||
include_from_test_key = BooleanField("Include test keys", default="checked", false_values={"N"})
|
include_from_test_key = govukCheckboxField("Include test keys")
|
||||||
|
|
||||||
|
|
||||||
class RequiredDateFilterForm(StripWhitespaceForm):
|
class RequiredDateFilterForm(StripWhitespaceForm):
|
||||||
@@ -1661,7 +1965,9 @@ class TemplateFolderForm(StripWhitespaceForm):
|
|||||||
(item.id, item.name) for item in all_service_users
|
(item.id, item.name) for item in all_service_users
|
||||||
]
|
]
|
||||||
|
|
||||||
users_with_permission = MultiCheckboxField('Team members who can see this folder')
|
users_with_permission = govukCollapsibleCheckboxesField(
|
||||||
|
'Team members who can see this folder',
|
||||||
|
field_label='folder')
|
||||||
name = StringField('Folder name', validators=[DataRequired(message='Cannot be empty')])
|
name = StringField('Folder name', validators=[DataRequired(message='Cannot be empty')])
|
||||||
|
|
||||||
|
|
||||||
@@ -1766,9 +2072,18 @@ class TemplateAndFoldersSelectionForm(Form):
|
|||||||
return self.move_to_new_folder_name.data
|
return self.move_to_new_folder_name.data
|
||||||
return None
|
return None
|
||||||
|
|
||||||
templates_and_folders = MultiCheckboxField('Choose templates or folders', validators=[
|
templates_and_folders = govukCheckboxesField(
|
||||||
required_for_ops('move-to-new-folder', 'move-to-existing-folder')
|
'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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
# if no default set, it is set to None, which process_data transforms to '__NONE__'
|
# 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
|
# 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
|
# set default to empty string so process_data method doesn't perform any transformation
|
||||||
@@ -1867,11 +2182,13 @@ class AcceptAgreementForm(StripWhitespaceForm):
|
|||||||
|
|
||||||
class BroadcastAreaForm(StripWhitespaceForm):
|
class BroadcastAreaForm(StripWhitespaceForm):
|
||||||
|
|
||||||
areas = MultiCheckboxField('Choose areas to broadcast to')
|
areas = govukCheckboxesField('Choose areas to broadcast to')
|
||||||
|
|
||||||
def __init__(self, choices, *args, **kwargs):
|
def __init__(self, choices, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.areas.choices = choices
|
self.areas.choices = choices
|
||||||
|
self.areas.render_as_list = True
|
||||||
|
self.areas.param_extensions = {'fieldset': {'legend': {'classes': 'govuk-visually-hidden'}}}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_library(cls, library):
|
def from_library(cls, library):
|
||||||
|
|||||||
@@ -168,9 +168,11 @@ def platform_admin_services():
|
|||||||
# Default to True if the user hasn’t done any filtering,
|
# Default to True if the user hasn’t done any filtering,
|
||||||
# otherwise respect their choice
|
# otherwise respect their choice
|
||||||
form.include_from_test_key.data = True
|
form.include_from_test_key.data = True
|
||||||
|
|
||||||
|
include_from_test_key = form.include_from_test_key.data
|
||||||
api_args = {'detailed': True,
|
api_args = {'detailed': True,
|
||||||
'only_active': False, # specifically DO get inactive services
|
'only_active': False, # specifically DO get inactive services
|
||||||
'include_from_test_key': form.include_from_test_key.data,
|
'include_from_test_key': include_from_test_key,
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.start_date.data:
|
if form.start_date.data:
|
||||||
@@ -184,7 +186,7 @@ def platform_admin_services():
|
|||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'views/platform-admin/services.html',
|
'views/platform-admin/services.html',
|
||||||
include_from_test_key=form.include_from_test_key.data,
|
include_from_test_key=include_from_test_key,
|
||||||
form=form,
|
form=form,
|
||||||
services=list(format_stats_by_service(services)),
|
services=list(format_stats_by_service(services)),
|
||||||
page_title='{} services'.format(
|
page_title='{} services'.format(
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
{% from "components/select-input.html" import select_nested, select %}
|
|
||||||
|
|
||||||
{% macro checkbox(
|
|
||||||
field,
|
|
||||||
hint=False,
|
|
||||||
width='2-3'
|
|
||||||
) %}
|
|
||||||
<div class="multiple-choice">
|
|
||||||
{{ checkbox_input(field.id, field.name, field.data) }}
|
|
||||||
<label for="{{ field.id }}">
|
|
||||||
{{ field.label.text }}
|
|
||||||
{% if hint %}
|
|
||||||
<div class="hint">
|
|
||||||
{{ hint }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
{% 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") %}
|
|
||||||
<input
|
|
||||||
id="{{ id }}" name="{{ name }}" type="checkbox" value="{{ value }}"
|
|
||||||
{% if data %}
|
|
||||||
checked
|
|
||||||
{% endif %}
|
|
||||||
>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
{% macro unlabelled_checkbox(id, name, data=None, value="y") %}
|
|
||||||
<div class="multiple-choice">
|
|
||||||
{{ checkbox_input(id, name, data, value) }}
|
|
||||||
<label></label>
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{%- macro govukCheckboxes(params) %}
|
||||||
|
{%- include "./template.njk" -%}
|
||||||
|
{%- endmacro %}
|
||||||
|
{{ govukCheckboxes(params) }}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
{% 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 %}">
|
||||||
|
{%- if item.before %}{{ item.before }}{% endif -%}
|
||||||
|
<input class="govuk-checkboxes__input" id="{{ id }}" name="{{ name }}" type="checkbox" value="{{ item.value }}"
|
||||||
|
{{-" checked" if item.checked }}
|
||||||
|
{{-" disabled" if item.disabled }}
|
||||||
|
{%- if item.conditional %} data-aria-controls="{{ conditionalId }}"{% endif -%}
|
||||||
|
{%- if itemDescribedBy %} aria-describedby="{{ itemDescribedBy }}"{% endif -%}
|
||||||
|
{%- for attribute, value in item.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}>
|
||||||
|
{{ 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 %}
|
||||||
|
<div class="govuk-checkboxes__conditional{% if not item.checked %} govuk-checkboxes__conditional--hidden{% endif %}" id="{{ conditionalId }}">
|
||||||
|
{{ item.conditional.html | safe }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{%- if item.after %}{{ item.after }}{% endif -%}
|
||||||
|
</{{ groupItemElement }}>
|
||||||
|
{% if not params.asList and item.conditional %}
|
||||||
|
<div class="govuk-checkboxes__conditional{% if not item.checked %} govuk-checkboxes__conditional--hidden{% endif %}" id="{{ conditionalId }}">
|
||||||
|
{{ item.conditional.html | safe }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</{{ groupElement }}>
|
||||||
|
{% endset -%}
|
||||||
|
|
||||||
|
<div class="govuk-form-group {%- if params.errorMessage %} govuk-form-group--error{% endif %} {%- if params.formGroup.classes %} {{ params.formGroup.classes }}{% endif %}">
|
||||||
|
{% 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 %}
|
||||||
|
</div>
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import sticky_page_footer %}
|
{% from "components/page-footer.html" import sticky_page_footer %}
|
||||||
{% from "components/checkbox.html" import checkboxes %}
|
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
{% from "components/live-search.html" import live_search %}
|
{% from "components/live-search.html" import live_search %}
|
||||||
|
|
||||||
@@ -17,10 +16,10 @@
|
|||||||
back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message.id),
|
back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message.id),
|
||||||
)}}
|
)}}
|
||||||
|
|
||||||
{{ live_search(target_selector='.multiple-choice', show=show_search_form, form=search_form, label='Search by name') }}
|
{{ live_search(target_selector='.govuk-checkboxes__item', show=show_search_form, form=search_form, label='Search by name') }}
|
||||||
|
|
||||||
{% call form_wrapper() %}
|
{% call form_wrapper() %}
|
||||||
{{ checkboxes(form.areas, hide_legend=True) }}
|
{{ form.areas }}
|
||||||
{{ sticky_page_footer('Add to broadcast') }}
|
{{ sticky_page_footer('Add to broadcast') }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
|
|||||||
@@ -1,20 +1,9 @@
|
|||||||
{% from "components/checkbox.html" import checkbox, checkboxes_nested %}
|
|
||||||
{% from "components/radios.html" import radio, radios, conditional_radio_panel %}
|
{% from "components/radios.html" import radio, radios, conditional_radio_panel %}
|
||||||
|
|
||||||
<fieldset class="form-group">
|
{{ form.permissions_field }}
|
||||||
<legend class="form-label heading-small">
|
|
||||||
Permissions
|
|
||||||
</legend>
|
|
||||||
<span class="hint">
|
|
||||||
All team members can see sent messages.
|
|
||||||
</span>
|
|
||||||
{% for field in form.permissions_fields %}
|
|
||||||
{{ checkbox(field) }}
|
|
||||||
{% endfor %}
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
{% if form.folder_permissions.all_template_folders %}
|
{% if form.folder_permissions.all_template_folders %}
|
||||||
{{ checkboxes_nested(form.folder_permissions, form.folder_permissions.children(), hide_legend=True, collapsible_opts={ 'field': 'folder' }) }}
|
{{ form.folder_permissions }}
|
||||||
{% elif user and user.platform_admin %}
|
{% elif user and user.platform_admin %}
|
||||||
<p class="bottom-gutter">
|
<p class="bottom-gutter">
|
||||||
Platform admin users can access all template folders.
|
Platform admin users can access all template folders.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "withoutnav_template.html" %}
|
{% extends "withoutnav_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "views/platform-admin/_base_template.html" %}
|
{% extends "views/platform-admin/_base_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/big-number.html" import big_number, big_number_with_status %}
|
{% from "components/big-number.html" import big_number, big_number_with_status %}
|
||||||
{% from "components/message-count-label.html" import message_count_label %}
|
{% from "components/message-count-label.html" import message_count_label %}
|
||||||
@@ -70,8 +69,7 @@
|
|||||||
{% call form_wrapper(method="get") %}
|
{% call form_wrapper(method="get") %}
|
||||||
{{ textbox(form.start_date, hint="Enter start date in format YYYY-MM-DD") }}
|
{{ 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") }}
|
{{ textbox(form.end_date, hint="Enter end date in format YYYY-MM-DD") }}
|
||||||
{{ checkbox(form.include_from_test_key) }}
|
{{ form.include_from_test_key }}
|
||||||
</br>
|
|
||||||
{{ govukButton({ "text": "Filter" }) }}
|
{{ govukButton({ "text": "Filter" }) }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endset %}
|
{% endset %}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% from "components/banner.html" import banner, banner_wrapper %}
|
{% from "components/banner.html" import banner, banner_wrapper %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
{% from "components/button/macro.njk" import govukButton %}
|
{% from "components/button/macro.njk" import govukButton %}
|
||||||
@@ -55,9 +54,7 @@
|
|||||||
hint='This should be a shared inbox managed by your team, not your own email address'
|
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 %}
|
{% if not first_email_address and not existing_is_default %}
|
||||||
<div class="form-group">
|
{{ form.is_default }}
|
||||||
{{ checkbox(form.is_default) }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ page_footer('Try again') }}
|
{{ page_footer('Try again') }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
@@ -24,9 +23,7 @@
|
|||||||
safe_error_message=True
|
safe_error_message=True
|
||||||
) }}
|
) }}
|
||||||
{% if not first_email_address %}
|
{% if not first_email_address %}
|
||||||
<div class="form-group">
|
{{ form.is_default }}
|
||||||
{{ checkbox(form.is_default) }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ page_footer('Add') }}
|
{{ page_footer('Add') }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/banner.html" import banner_wrapper %}
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
@@ -29,9 +28,7 @@
|
|||||||
</p>
|
</p>
|
||||||
{{ page_footer('Save') }}
|
{{ page_footer('Save') }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="form-group">
|
{{ form.is_default }}
|
||||||
{{ checkbox(form.is_default) }}
|
|
||||||
</div>
|
|
||||||
{{ page_footer(
|
{{ page_footer(
|
||||||
'Save',
|
'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),
|
delete_link=url_for('.service_confirm_delete_email_reply_to', service_id=current_service.id, reply_to_email_id=reply_to_email_address_id),
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
@@ -27,9 +26,7 @@
|
|||||||
highlight_placeholders=True
|
highlight_placeholders=True
|
||||||
) }}
|
) }}
|
||||||
{% if not first_contact_block %}
|
{% if not first_contact_block %}
|
||||||
<div class="form-group">
|
{{ form.is_default }}
|
||||||
{{ checkbox(form.is_default) }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ page_footer('Add') }}
|
{{ page_footer('Add') }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
@@ -31,9 +30,7 @@
|
|||||||
This is currently your default address for {{ current_service.name }}.
|
This is currently your default address for {{ current_service.name }}.
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="form-group">
|
{{ form.is_default }}
|
||||||
{{ checkbox(form.is_default) }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{{ page_footer(
|
{{ page_footer(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
@@ -23,9 +22,7 @@
|
|||||||
hint='Up to 11 characters, letters, numbers and spaces only'
|
hint='Up to 11 characters, letters, numbers and spaces only'
|
||||||
) }}
|
) }}
|
||||||
{% if not first_sms_sender %}
|
{% if not first_sms_sender %}
|
||||||
<div class="form-group">
|
{{ form.is_default }}
|
||||||
{{ checkbox(form.is_default) }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ page_footer('Save') }}
|
{{ page_footer('Save') }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/banner.html" import banner_wrapper %}
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
@@ -35,9 +34,7 @@
|
|||||||
</p>
|
</p>
|
||||||
{{ page_footer('Save') }}
|
{{ page_footer('Save') }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="form-group">
|
{{ form.is_default }}
|
||||||
{{ checkbox(form.is_default) }}
|
|
||||||
</div>
|
|
||||||
{% if inbound_number %}
|
{% if inbound_number %}
|
||||||
{{ page_footer('Save') }}
|
{{ page_footer('Save') }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{% extends "withoutnav_template.html" %}
|
{% extends "withoutnav_template.html" %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/page-footer.html" import sticky_page_footer %}
|
{% from "components/page-footer.html" import sticky_page_footer %}
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
{% from "components/checkbox.html" import unlabelled_checkbox %}
|
|
||||||
{% from "components/message-count-label.html" import folder_contents_count, message_count_label %}
|
{% from "components/message-count-label.html" import folder_contents_count, message_count_label %}
|
||||||
|
|
||||||
{% macro format_item_name(name) -%}
|
{% macro format_item_name(name, separators=True) -%}
|
||||||
{%- if name is string -%}
|
{%- if name is string -%}
|
||||||
{{- name -}}
|
{{- name -}}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{%- for part in name -%}
|
{%- for part in name -%}
|
||||||
{{- format_item_name(part) -}}
|
{{- format_item_name(part, separators) -}}
|
||||||
{%- if not loop.last %} <span class="message-name-separator"></span> {% endif -%}
|
{%- if not loop.last -%}
|
||||||
|
{%- if separators %}
|
||||||
|
<span class="message-name-separator"></span>{%- else %} {% endif -%}
|
||||||
|
{% endif -%}
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
@@ -21,37 +23,69 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<nav id="template-list" class="{{ 'top-gutter-5px' if (not show_template_nav and not show_search_box) else '' }}">
|
<nav id="template-list" class="{{ 'govuk-!-margin-top-1' if (not show_template_nav and not show_search_box) else 'govuk-!margin-top-6' }}">
|
||||||
|
{% set checkboxes_data = [] %}
|
||||||
|
|
||||||
{% for item in template_list %}
|
{% for item in template_list %}
|
||||||
<div class="template-list-item {% if current_user.has_permissions('manage_templates') %}template-list-item-with-checkbox{% endif %} {% if item.ancestors %}template-list-item-hidden-by-default{% endif %} {% if not item.ancestors %}template-list-item-without-ancestors{% endif %}">
|
|
||||||
{% if current_user.has_permissions('manage_templates') %}
|
{% set item_link_content %}
|
||||||
{{ unlabelled_checkbox(
|
{% for ancestor in item.ancestors %}
|
||||||
id='templates-or-folder-{}'.format(item.id),
|
<a href="{{ url_for('.choose_template', service_id=current_service.id, template_type=template_type, template_folder_id=ancestor.id) }}" class="govuk-link govuk-link--no-visited-state template-list-folder">
|
||||||
name='templates_and_folders',
|
{{- format_item_name(ancestor.name) -}}
|
||||||
data=templates_and_folders_form.is_selected(item.id),
|
</a> <span class="message-name-separator"></span>
|
||||||
value=item.id,
|
{% endfor %}
|
||||||
) }}
|
{% if item.is_folder %}
|
||||||
|
<a href="{{ url_for('.choose_template', service_id=current_service.id, template_type=template_type, template_folder_id=item.id) }}" class="govuk-link govuk-link--no-visited-state template-list-folder">
|
||||||
|
<span class="live-search-relevant">{{- format_item_name(item.name) -}}</span>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for('.view_template', service_id=current_service.id, template_id=item.id) }}" class="govuk-link govuk-link--no-visited-state template-list-template">
|
||||||
|
<span class="live-search-relevant">{{- format_item_name(item.name) -}}</span>
|
||||||
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h2 class="message-name">
|
{% endset %}
|
||||||
{% for ancestor in item.ancestors %}
|
|
||||||
<a href="{{ url_for('.choose_template', service_id=current_service.id, template_type=template_type, template_folder_id=ancestor.id) }}" class="govuk-link govuk-link--no-visited-state template-list-folder">
|
{% set label_content %}
|
||||||
{{- format_item_name(ancestor.name) -}}
|
<span class="govuk-visually-hidden">
|
||||||
</a> <span class="message-name-separator"></span>
|
{%- for ancestor in item.ancestors %}{{ format_item_name(ancestor.name, separators=False) }} {% endfor -%}
|
||||||
{% endfor %}
|
{{ format_item_name(item.name, separators=False) -}}
|
||||||
{% if item.is_folder %}
|
</span>
|
||||||
<a href="{{ url_for('.choose_template', service_id=current_service.id, template_type=template_type, template_folder_id=item.id) }}" class="govuk-link govuk-link--no-visited-state template-list-folder">
|
{% endset %}
|
||||||
<span class="live-search-relevant">{{ format_item_name(item.name) }}</span>
|
|
||||||
</a>
|
{% set item_meta %}
|
||||||
{% else %}
|
<span id="{{ item.id }}-item-hint" class="govuk-hint govuk-checkboxes__hint template-list-item-hint">
|
||||||
<a href="{{ url_for('.view_template', service_id=current_service.id, template_id=item.id) }}" class="govuk-link govuk-link--no-visited-state template-list-template">
|
|
||||||
<span class="live-search-relevant">{{ format_item_name(item.name) }}</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
<p class="message-type">
|
|
||||||
{{ item.hint }}
|
{{ item.hint }}
|
||||||
</p>
|
</span>
|
||||||
</div>
|
{% endset %}
|
||||||
|
|
||||||
|
{# create the item config now to include the label content -#}
|
||||||
|
{# TODO: "attributes": { "aria-describedby": item.id ~ "-hint" } needs to be added but govuk-frontend-jinja doesn't currently support this -#}
|
||||||
|
{% set checkbox_config = {
|
||||||
|
"html": label_content,
|
||||||
|
"label": {
|
||||||
|
"classes": "template-list-item-label",
|
||||||
|
},
|
||||||
|
"id": "templates-or-folder-" ~ item.id,
|
||||||
|
"classes": "template-list-item template-list-item-with-checkbox {}".format(
|
||||||
|
"template-list-item-hidden-by-default" if item.ancestors else "template-list-item-without-ancestors"),
|
||||||
|
"after": item_link_content ~ item_meta
|
||||||
|
} %}
|
||||||
|
{% set _ = checkboxes_data.append(checkbox_config) %}
|
||||||
|
|
||||||
|
{% if not current_user.has_permissions('manage_templates') %}
|
||||||
|
<div class="template-list-item {%- if item.ancestors %} template-list-item-hidden-by-default {%- else %} template-list-item-without-ancestors{%- endif %}">
|
||||||
|
<h2 class="message-name">
|
||||||
|
{{ item_link_content }}
|
||||||
|
</h2>
|
||||||
|
<p class="message-type govuk-!-margin-bottom-4">
|
||||||
|
{{ item.hint }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if current_user.has_permissions('manage_templates') %}
|
||||||
|
{{ templates_and_folders_form.templates_and_folders(param_extensions={ "items": checkboxes_data }) }}
|
||||||
|
{% endif %}
|
||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
{% from "components/folder-path.html" import folder_path, page_title_folder_path %}
|
{% from "components/folder-path.html" import folder_path, page_title_folder_path %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox, checkboxes %}
|
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@
|
|||||||
{% call form_wrapper(action=url_for('main.manage_template_folder', service_id=current_service.id, template_folder_id=template_folder_id)) %}
|
{% call form_wrapper(action=url_for('main.manage_template_folder', service_id=current_service.id, template_folder_id=template_folder_id)) %}
|
||||||
{{ textbox(form.name, width='1-1') }}
|
{{ textbox(form.name, width='1-1') }}
|
||||||
{% if current_user.has_permissions("manage_service") and form.users_with_permission.all_service_users %}
|
{% if current_user.has_permissions("manage_service") and form.users_with_permission.all_service_users %}
|
||||||
{{ checkboxes(form.users_with_permission, collapsible_opts={ 'field': 'team member' }) }}
|
{{ form.users_with_permission }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{{ page_footer(
|
{{ page_footer(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "withoutnav_template.html" %}
|
{% extends "withoutnav_template.html" %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/checkbox.html" import checkbox %}
|
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/form.html" import form_wrapper %}
|
{% from "components/form.html" import form_wrapper %}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -65,7 +65,12 @@ const copy = {
|
|||||||
'footer',
|
'footer',
|
||||||
'back-link',
|
'back-link',
|
||||||
'details',
|
'details',
|
||||||
'button'
|
'button',
|
||||||
|
'error-message',
|
||||||
|
'fieldset',
|
||||||
|
'hint',
|
||||||
|
'label',
|
||||||
|
'checkboxes'
|
||||||
];
|
];
|
||||||
let done = 0;
|
let done = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -288,11 +288,15 @@ def test_service_without_caseworking_doesnt_show_admin_vs_caseworker(
|
|||||||
service_id=SERVICE_ONE_ID,
|
service_id=SERVICE_ONE_ID,
|
||||||
**extra_args
|
**extra_args
|
||||||
)
|
)
|
||||||
assert page.select('input[type=checkbox]')[0]['name'] == 'view_activity'
|
permission_checkboxes = page.select('input[type=checkbox]')
|
||||||
assert page.select('input[type=checkbox]')[1]['name'] == 'send_messages'
|
|
||||||
assert page.select('input[type=checkbox]')[2]['name'] == 'manage_templates'
|
for idx in range(len(permission_checkboxes)):
|
||||||
assert page.select('input[type=checkbox]')[3]['name'] == 'manage_service'
|
assert permission_checkboxes[idx]['name'] == 'permissions_field'
|
||||||
assert page.select('input[type=checkbox]')[4]['name'] == 'manage_api_keys'
|
assert permission_checkboxes[0]['value'] == 'view_activity'
|
||||||
|
assert permission_checkboxes[1]['value'] == 'send_messages'
|
||||||
|
assert permission_checkboxes[2]['value'] == 'manage_templates'
|
||||||
|
assert permission_checkboxes[3]['value'] == 'manage_service'
|
||||||
|
assert permission_checkboxes[4]['value'] == 'manage_api_keys'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('endpoint, extra_args', [
|
@pytest.mark.parametrize('endpoint, extra_args', [
|
||||||
@@ -320,11 +324,11 @@ def test_broadcast_service_only_shows_relevant_permissions(
|
|||||||
**extra_args
|
**extra_args
|
||||||
)
|
)
|
||||||
assert [
|
assert [
|
||||||
field['name'] for field in page.select('input[type=checkbox]')
|
(field['name'], field['value']) for field in page.select('input[type=checkbox]')
|
||||||
] == [
|
] == [
|
||||||
'send_messages',
|
('permissions_field', 'send_messages'),
|
||||||
'manage_templates',
|
('permissions_field', 'manage_templates'),
|
||||||
'manage_service',
|
('permissions_field', 'manage_service'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -432,8 +436,9 @@ def test_should_show_page_for_one_user(
|
|||||||
assert len(checkboxes) == 5
|
assert len(checkboxes) == 5
|
||||||
|
|
||||||
for index, expected in enumerate(expected_checkboxes):
|
for index, expected in enumerate(expected_checkboxes):
|
||||||
expected_input_name, expected_checked = expected
|
expected_input_value, expected_checked = expected
|
||||||
assert checkboxes[index]['name'] == expected_input_name
|
assert checkboxes[index]['name'] == 'permissions_field'
|
||||||
|
assert checkboxes[index]['value'] == expected_input_value
|
||||||
assert checkboxes[index].has_attr('checked') == expected_checked
|
assert checkboxes[index].has_attr('checked') == expected_checked
|
||||||
|
|
||||||
|
|
||||||
@@ -475,11 +480,13 @@ def test_should_not_show_page_for_non_team_member(
|
|||||||
@pytest.mark.parametrize('submitted_permissions, permissions_sent_to_api', [
|
@pytest.mark.parametrize('submitted_permissions, permissions_sent_to_api', [
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
'view_activity': 'y',
|
'permissions_field': [
|
||||||
'send_messages': 'y',
|
'view_activity',
|
||||||
'manage_templates': 'y',
|
'send_messages',
|
||||||
'manage_service': 'y',
|
'manage_templates',
|
||||||
'manage_api_keys': 'y',
|
'manage_service',
|
||||||
|
'manage_api_keys',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'view_activity',
|
'view_activity',
|
||||||
@@ -491,19 +498,38 @@ def test_should_not_show_page_for_non_team_member(
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
'view_activity': 'y',
|
'permissions_field': [
|
||||||
'send_messages': 'y',
|
'view_activity',
|
||||||
'manage_templates': '',
|
'send_messages',
|
||||||
|
'manage_templates',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'view_activity',
|
'view_activity',
|
||||||
'send_messages',
|
'send_messages',
|
||||||
|
'manage_templates',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{},
|
{},
|
||||||
set(),
|
set(),
|
||||||
),
|
),
|
||||||
|
( # should be able to handle permissions being sent as booleans, until changeover to a list is complete
|
||||||
|
{
|
||||||
|
'view_activity': 'y',
|
||||||
|
'send_messages': 'y',
|
||||||
|
'manage_templates': 'y',
|
||||||
|
'manage_service': 'y',
|
||||||
|
'manage_api_keys': 'y',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'view_activity',
|
||||||
|
'send_messages',
|
||||||
|
'manage_templates',
|
||||||
|
'manage_service',
|
||||||
|
'manage_api_keys',
|
||||||
|
}
|
||||||
|
),
|
||||||
])
|
])
|
||||||
def test_edit_user_permissions(
|
def test_edit_user_permissions(
|
||||||
client_request,
|
client_request,
|
||||||
@@ -542,11 +568,12 @@ def test_edit_user_permissions(
|
|||||||
@pytest.mark.parametrize('submitted_permissions, permissions_sent_to_api', [
|
@pytest.mark.parametrize('submitted_permissions, permissions_sent_to_api', [
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
'view_activity': 'y',
|
'permissions_field': [
|
||||||
'send_messages': 'y',
|
'send_messages',
|
||||||
'manage_templates': 'y',
|
'manage_templates',
|
||||||
'manage_service': 'y',
|
'manage_service',
|
||||||
'manage_api_keys': 'y',
|
'manage_api_keys',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'view_activity',
|
'view_activity',
|
||||||
@@ -557,8 +584,9 @@ def test_edit_user_permissions(
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
'view_activity': 'y',
|
'permissions_field': [
|
||||||
'send_messages': 'y',
|
'send_messages',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'view_activity',
|
'view_activity',
|
||||||
@@ -572,6 +600,20 @@ def test_edit_user_permissions(
|
|||||||
'view_activity',
|
'view_activity',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
( # should be able to handle permissions being sent as booleans, until changeover to a list is complete
|
||||||
|
{
|
||||||
|
'send_messages': 'y',
|
||||||
|
'manage_templates': 'y',
|
||||||
|
'manage_service': 'y',
|
||||||
|
'manage_api_keys': 'y',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'view_activity',
|
||||||
|
'send_messages',
|
||||||
|
'manage_service',
|
||||||
|
'manage_templates',
|
||||||
|
}
|
||||||
|
),
|
||||||
])
|
])
|
||||||
def test_edit_user_permissions_for_broadcast_service(
|
def test_edit_user_permissions_for_broadcast_service(
|
||||||
client_request,
|
client_request,
|
||||||
@@ -748,10 +790,12 @@ def test_edit_user_permissions_including_authentication_with_email_auth_service(
|
|||||||
user_id=active_user_with_permissions['id'],
|
user_id=active_user_with_permissions['id'],
|
||||||
_data={
|
_data={
|
||||||
'email_address': active_user_with_permissions['email_address'],
|
'email_address': active_user_with_permissions['email_address'],
|
||||||
'send_messages': 'y',
|
'permissions_field': [
|
||||||
'manage_templates': 'y',
|
'send_messages',
|
||||||
'manage_service': 'y',
|
'manage_templates',
|
||||||
'manage_api_keys': 'y',
|
'manage_service',
|
||||||
|
'manage_api_keys',
|
||||||
|
],
|
||||||
'login_authentication': auth_type,
|
'login_authentication': auth_type,
|
||||||
},
|
},
|
||||||
_expected_status=302,
|
_expected_status=302,
|
||||||
@@ -810,13 +854,14 @@ def test_should_show_folder_permission_form_if_service_has_folder_permissions_en
|
|||||||
|
|
||||||
assert 'Invite a team member' in page.find('h1').text.strip()
|
assert 'Invite a team member' in page.find('h1').text.strip()
|
||||||
|
|
||||||
folder_checkboxes = page.find('div', class_='checkboxes-nested').find_all('li')
|
folder_checkboxes = page.find('div', class_='selection-wrapper').find_all('li')
|
||||||
assert len(folder_checkboxes) == 3
|
assert len(folder_checkboxes) == 3
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('email_address, gov_user', [
|
@pytest.mark.parametrize('email_address, gov_user, old_permissions', [
|
||||||
('test@example.gov.uk', True),
|
('test@example.gov.uk', True, False),
|
||||||
('test@example.com', False)
|
('test@example.com', False, False),
|
||||||
|
('test@example.gov.uk', True, True)
|
||||||
])
|
])
|
||||||
def test_invite_user(
|
def test_invite_user(
|
||||||
client_request,
|
client_request,
|
||||||
@@ -825,6 +870,7 @@ def test_invite_user(
|
|||||||
sample_invite,
|
sample_invite,
|
||||||
email_address,
|
email_address,
|
||||||
gov_user,
|
gov_user,
|
||||||
|
old_permissions,
|
||||||
mock_get_template_folders,
|
mock_get_template_folders,
|
||||||
mock_get_organisations,
|
mock_get_organisations,
|
||||||
):
|
):
|
||||||
@@ -834,17 +880,25 @@ def test_invite_user(
|
|||||||
mocker.patch('app.models.user.InvitedUsers.client_method', return_value=[sample_invite])
|
mocker.patch('app.models.user.InvitedUsers.client_method', return_value=[sample_invite])
|
||||||
mocker.patch('app.models.user.Users.client_method', return_value=[active_user_with_permissions])
|
mocker.patch('app.models.user.Users.client_method', return_value=[active_user_with_permissions])
|
||||||
mocker.patch('app.invite_api_client.create_invite', return_value=sample_invite)
|
mocker.patch('app.invite_api_client.create_invite', return_value=sample_invite)
|
||||||
|
data = {'email_address': email_address}
|
||||||
|
if old_permissions:
|
||||||
|
data['view_activity'] = 'y'
|
||||||
|
data['send_messages'] = 'y'
|
||||||
|
data['manage_templates'] = 'y'
|
||||||
|
data['manage_service'] = 'y'
|
||||||
|
data['manage_api_keys'] = 'y'
|
||||||
|
else:
|
||||||
|
data['permissions_field'] = [
|
||||||
|
'view_activity',
|
||||||
|
'send_messages',
|
||||||
|
'manage_templates',
|
||||||
|
'manage_service',
|
||||||
|
'manage_api_keys',
|
||||||
|
]
|
||||||
page = client_request.post(
|
page = client_request.post(
|
||||||
'main.invite_user',
|
'main.invite_user',
|
||||||
service_id=SERVICE_ONE_ID,
|
service_id=SERVICE_ONE_ID,
|
||||||
_data={
|
_data=data,
|
||||||
'email_address': email_address,
|
|
||||||
'view_activity': 'y',
|
|
||||||
'send_messages': 'y',
|
|
||||||
'manage_templates': 'y',
|
|
||||||
'manage_service': 'y',
|
|
||||||
'manage_api_keys': 'y',
|
|
||||||
},
|
|
||||||
_follow_redirects=True,
|
_follow_redirects=True,
|
||||||
)
|
)
|
||||||
assert page.h1.string.strip() == 'Team members'
|
assert page.h1.string.strip() == 'Team members'
|
||||||
@@ -894,11 +948,13 @@ def test_invite_user_with_email_auth_service(
|
|||||||
service_id=SERVICE_ONE_ID,
|
service_id=SERVICE_ONE_ID,
|
||||||
_data={
|
_data={
|
||||||
'email_address': email_address,
|
'email_address': email_address,
|
||||||
'view_activity': 'y',
|
'permissions_field': [
|
||||||
'send_messages': 'y',
|
'view_activity',
|
||||||
'manage_templates': 'y',
|
'send_messages',
|
||||||
'manage_service': 'y',
|
'manage_templates',
|
||||||
'manage_api_keys': 'y',
|
'manage_service',
|
||||||
|
'manage_api_keys',
|
||||||
|
],
|
||||||
'login_authentication': auth_type,
|
'login_authentication': auth_type,
|
||||||
},
|
},
|
||||||
_follow_redirects=True,
|
_follow_redirects=True,
|
||||||
@@ -922,9 +978,11 @@ def test_invite_user_with_email_auth_service(
|
|||||||
@pytest.mark.parametrize('post_data, expected_permissions_to_api', (
|
@pytest.mark.parametrize('post_data, expected_permissions_to_api', (
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
'send_messages': 'y',
|
'permissions_field': [
|
||||||
'manage_templates': 'y',
|
'send_messages',
|
||||||
'manage_service': 'y',
|
'manage_templates',
|
||||||
|
'manage_service',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'view_activity',
|
'view_activity',
|
||||||
@@ -935,14 +993,29 @@ def test_invite_user_with_email_auth_service(
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
'view_activity': 'y',
|
'permissions_field': [
|
||||||
'manage_api_keys': 'y',
|
'view_activity',
|
||||||
'foo': 'y',
|
'manage_api_keys',
|
||||||
|
'foo',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'view_activity',
|
'view_activity',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
( # should be able to handle permissions being sent as booleans, until changeover to a list is complete
|
||||||
|
{
|
||||||
|
'send_messages': 'y',
|
||||||
|
'manage_templates': 'y',
|
||||||
|
'manage_service': 'y',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'view_activity',
|
||||||
|
'send_messages',
|
||||||
|
'manage_templates',
|
||||||
|
'manage_service',
|
||||||
|
},
|
||||||
|
)
|
||||||
))
|
))
|
||||||
def test_invite_user_to_broadcast_service(
|
def test_invite_user_to_broadcast_service(
|
||||||
client_request,
|
client_request,
|
||||||
@@ -1084,9 +1157,11 @@ def test_user_cant_invite_themselves(
|
|||||||
service_id=SERVICE_ONE_ID,
|
service_id=SERVICE_ONE_ID,
|
||||||
_data={
|
_data={
|
||||||
'email_address': active_user_with_permissions['email_address'],
|
'email_address': active_user_with_permissions['email_address'],
|
||||||
'send_messages': 'y',
|
'permissions_field': [
|
||||||
'manage_service': 'y',
|
'send_messages',
|
||||||
'manage_api_keys': 'y',
|
'manage_service',
|
||||||
|
'manage_api_keys'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
_follow_redirects=True,
|
_follow_redirects=True,
|
||||||
_expected_status=200,
|
_expected_status=200,
|
||||||
|
|||||||
@@ -54,29 +54,43 @@ def _folder(name, folder_id=None, parent=None, users_with_permission=None):
|
|||||||
{},
|
{},
|
||||||
['Email', 'Text message', 'Letter'],
|
['Email', 'Text message', 'Letter'],
|
||||||
[
|
[
|
||||||
'folder_one 2 folders',
|
'folder_one folder_one 2 folders',
|
||||||
'folder_one folder_one_one 1 template, 1 folder',
|
('folder_one folder_one_one '
|
||||||
'folder_one folder_one_one folder_one_one_one 1 template',
|
'folder_one folder_one_one '
|
||||||
'folder_one folder_one_one folder_one_one_one sms_template_nested Text message template',
|
'1 template, 1 folder'),
|
||||||
'folder_one folder_one_one letter_template_nested Letter template',
|
('folder_one folder_one_one folder_one_one_one '
|
||||||
'folder_one folder_one_two Empty',
|
'folder_one folder_one_one folder_one_one_one '
|
||||||
'folder_two Empty',
|
'1 template'),
|
||||||
'sms_template_one Text message template',
|
('folder_one folder_one_one folder_one_one_one sms_template_nested '
|
||||||
'sms_template_two Text message template',
|
'folder_one folder_one_one folder_one_one_one sms_template_nested '
|
||||||
'email_template_one Email template',
|
'Text message template'),
|
||||||
'email_template_two Email template',
|
('folder_one folder_one_one letter_template_nested '
|
||||||
'letter_template_one Letter template',
|
'folder_one folder_one_one letter_template_nested '
|
||||||
'letter_template_two Letter template',
|
'Letter template'),
|
||||||
|
('folder_one folder_one_two '
|
||||||
|
'folder_one folder_one_two '
|
||||||
|
'Empty'),
|
||||||
|
'folder_two folder_two Empty',
|
||||||
|
('sms_template_one '
|
||||||
|
'sms_template_one '
|
||||||
|
'Text message template'),
|
||||||
|
('sms_template_two '
|
||||||
|
'sms_template_two '
|
||||||
|
'Text message template'),
|
||||||
|
'email_template_one email_template_one Email template',
|
||||||
|
'email_template_two email_template_two Email template',
|
||||||
|
'letter_template_one letter_template_one Letter template',
|
||||||
|
'letter_template_two letter_template_two Letter template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one 2 folders',
|
'folder_one folder_one 2 folders',
|
||||||
'folder_two Empty',
|
'folder_two folder_two Empty',
|
||||||
'sms_template_one Text message template',
|
'sms_template_one sms_template_one Text message template',
|
||||||
'sms_template_two Text message template',
|
'sms_template_two sms_template_two Text message template',
|
||||||
'email_template_one Email template',
|
'email_template_one email_template_one Email template',
|
||||||
'email_template_two Email template',
|
'email_template_two email_template_two Email template',
|
||||||
'letter_template_one Letter template',
|
'letter_template_one letter_template_one Letter template',
|
||||||
'letter_template_two Letter template',
|
'letter_template_two letter_template_two Letter template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one',
|
'folder_one',
|
||||||
@@ -102,29 +116,39 @@ def _folder(name, folder_id=None, parent=None, users_with_permission=None):
|
|||||||
{'template_type': 'all'},
|
{'template_type': 'all'},
|
||||||
['Email', 'Text message', 'Letter'],
|
['Email', 'Text message', 'Letter'],
|
||||||
[
|
[
|
||||||
'folder_one 2 folders',
|
'folder_one folder_one 2 folders',
|
||||||
'folder_one folder_one_one 1 template, 1 folder',
|
('folder_one folder_one_one '
|
||||||
'folder_one folder_one_one folder_one_one_one 1 template',
|
'folder_one folder_one_one '
|
||||||
'folder_one folder_one_one folder_one_one_one sms_template_nested Text message template',
|
'1 template, 1 folder'),
|
||||||
'folder_one folder_one_one letter_template_nested Letter template',
|
('folder_one folder_one_one folder_one_one_one '
|
||||||
'folder_one folder_one_two Empty',
|
'folder_one folder_one_one folder_one_one_one '
|
||||||
'folder_two Empty',
|
'1 template'),
|
||||||
'sms_template_one Text message template',
|
('folder_one folder_one_one folder_one_one_one sms_template_nested '
|
||||||
'sms_template_two Text message template',
|
'folder_one folder_one_one folder_one_one_one sms_template_nested '
|
||||||
'email_template_one Email template',
|
'Text message template'),
|
||||||
'email_template_two Email template',
|
('folder_one folder_one_one letter_template_nested '
|
||||||
'letter_template_one Letter template',
|
'folder_one folder_one_one letter_template_nested '
|
||||||
'letter_template_two Letter template',
|
'Letter template'),
|
||||||
|
('folder_one folder_one_two '
|
||||||
|
'folder_one folder_one_two '
|
||||||
|
'Empty'),
|
||||||
|
'folder_two folder_two Empty',
|
||||||
|
'sms_template_one sms_template_one Text message template',
|
||||||
|
'sms_template_two sms_template_two Text message template',
|
||||||
|
'email_template_one email_template_one Email template',
|
||||||
|
'email_template_two email_template_two Email template',
|
||||||
|
'letter_template_one letter_template_one Letter template',
|
||||||
|
'letter_template_two letter_template_two Letter template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one 2 folders',
|
'folder_one folder_one 2 folders',
|
||||||
'folder_two Empty',
|
'folder_two folder_two Empty',
|
||||||
'sms_template_one Text message template',
|
'sms_template_one sms_template_one Text message template',
|
||||||
'sms_template_two Text message template',
|
'sms_template_two sms_template_two Text message template',
|
||||||
'email_template_one Email template',
|
'email_template_one email_template_one Email template',
|
||||||
'email_template_two Email template',
|
'email_template_two email_template_two Email template',
|
||||||
'letter_template_one Letter template',
|
'letter_template_one letter_template_one Letter template',
|
||||||
'letter_template_two Letter template',
|
'letter_template_two letter_template_two Letter template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one',
|
'folder_one',
|
||||||
@@ -150,17 +174,23 @@ def _folder(name, folder_id=None, parent=None, users_with_permission=None):
|
|||||||
{'template_type': 'sms'},
|
{'template_type': 'sms'},
|
||||||
['All', 'Email', 'Letter'],
|
['All', 'Email', 'Letter'],
|
||||||
[
|
[
|
||||||
'folder_one 1 folder',
|
'folder_one folder_one 1 folder',
|
||||||
'folder_one folder_one_one 1 folder',
|
('folder_one folder_one_one '
|
||||||
'folder_one folder_one_one folder_one_one_one 1 template',
|
'folder_one folder_one_one '
|
||||||
'folder_one folder_one_one folder_one_one_one sms_template_nested Text message template',
|
'1 folder'),
|
||||||
'sms_template_one Text message template',
|
('folder_one folder_one_one folder_one_one_one '
|
||||||
'sms_template_two Text message template',
|
'folder_one folder_one_one folder_one_one_one '
|
||||||
|
'1 template'),
|
||||||
|
('folder_one folder_one_one folder_one_one_one sms_template_nested '
|
||||||
|
'folder_one folder_one_one folder_one_one_one sms_template_nested '
|
||||||
|
'Text message template'),
|
||||||
|
'sms_template_one sms_template_one Text message template',
|
||||||
|
'sms_template_two sms_template_two Text message template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one 1 folder',
|
'folder_one folder_one 1 folder',
|
||||||
'sms_template_one Text message template',
|
'sms_template_one sms_template_one Text message template',
|
||||||
'sms_template_two Text message template',
|
'sms_template_two sms_template_two Text message template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one',
|
'folder_one',
|
||||||
@@ -179,15 +209,21 @@ def _folder(name, folder_id=None, parent=None, users_with_permission=None):
|
|||||||
{'template_folder_id': PARENT_FOLDER_ID},
|
{'template_folder_id': PARENT_FOLDER_ID},
|
||||||
['Email', 'Text message', 'Letter'],
|
['Email', 'Text message', 'Letter'],
|
||||||
[
|
[
|
||||||
'folder_one_one 1 template, 1 folder',
|
'folder_one_one folder_one_one 1 template, 1 folder',
|
||||||
'folder_one_one folder_one_one_one 1 template',
|
('folder_one_one folder_one_one_one '
|
||||||
'folder_one_one folder_one_one_one sms_template_nested Text message template',
|
'folder_one_one folder_one_one_one '
|
||||||
'folder_one_one letter_template_nested Letter template',
|
'1 template'),
|
||||||
'folder_one_two Empty',
|
('folder_one_one folder_one_one_one sms_template_nested '
|
||||||
|
'folder_one_one folder_one_one_one sms_template_nested '
|
||||||
|
'Text message template'),
|
||||||
|
('folder_one_one letter_template_nested '
|
||||||
|
'folder_one_one letter_template_nested '
|
||||||
|
'Letter template'),
|
||||||
|
'folder_one_two folder_one_two Empty',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one_one 1 template, 1 folder',
|
'folder_one_one folder_one_one 1 template, 1 folder',
|
||||||
'folder_one_two Empty',
|
'folder_one_two folder_one_two Empty',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one_one',
|
'folder_one_one',
|
||||||
@@ -205,12 +241,16 @@ def _folder(name, folder_id=None, parent=None, users_with_permission=None):
|
|||||||
{'template_type': 'sms', 'template_folder_id': PARENT_FOLDER_ID},
|
{'template_type': 'sms', 'template_folder_id': PARENT_FOLDER_ID},
|
||||||
['All', 'Email', 'Letter'],
|
['All', 'Email', 'Letter'],
|
||||||
[
|
[
|
||||||
'folder_one_one 1 folder',
|
'folder_one_one folder_one_one 1 folder',
|
||||||
'folder_one_one folder_one_one_one 1 template',
|
('folder_one_one folder_one_one_one '
|
||||||
'folder_one_one folder_one_one_one sms_template_nested Text message template',
|
'folder_one_one folder_one_one_one '
|
||||||
|
'1 template'),
|
||||||
|
('folder_one_one folder_one_one_one sms_template_nested '
|
||||||
|
'folder_one_one folder_one_one_one sms_template_nested '
|
||||||
|
'Text message template'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one_one 1 folder',
|
'folder_one_one folder_one_one 1 folder',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one_one',
|
'folder_one_one',
|
||||||
@@ -240,13 +280,15 @@ def _folder(name, folder_id=None, parent=None, users_with_permission=None):
|
|||||||
{'template_folder_id': CHILD_FOLDER_ID},
|
{'template_folder_id': CHILD_FOLDER_ID},
|
||||||
['Email', 'Text message', 'Letter'],
|
['Email', 'Text message', 'Letter'],
|
||||||
[
|
[
|
||||||
'folder_one_one_one 1 template',
|
'folder_one_one_one folder_one_one_one 1 template',
|
||||||
'folder_one_one_one sms_template_nested Text message template',
|
('folder_one_one_one sms_template_nested '
|
||||||
'letter_template_nested Letter template',
|
'folder_one_one_one sms_template_nested '
|
||||||
|
'Text message template'),
|
||||||
|
'letter_template_nested letter_template_nested Letter template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one_one_one 1 template',
|
'folder_one_one_one folder_one_one_one 1 template',
|
||||||
'letter_template_nested Letter template',
|
'letter_template_nested letter_template_nested Letter template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'folder_one_one_one',
|
'folder_one_one_one',
|
||||||
@@ -266,10 +308,10 @@ def _folder(name, folder_id=None, parent=None, users_with_permission=None):
|
|||||||
{'template_folder_id': GRANDCHILD_FOLDER_ID},
|
{'template_folder_id': GRANDCHILD_FOLDER_ID},
|
||||||
['Email', 'Text message', 'Letter'],
|
['Email', 'Text message', 'Letter'],
|
||||||
[
|
[
|
||||||
'sms_template_nested Text message template',
|
'sms_template_nested sms_template_nested Text message template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'sms_template_nested Text message template',
|
'sms_template_nested sms_template_nested Text message template',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'sms_template_nested',
|
'sms_template_nested',
|
||||||
@@ -395,7 +437,7 @@ def test_should_show_templates_folder_page(
|
|||||||
assert links_in_page[index].text.strip() == expected_link
|
assert links_in_page[index].text.strip() == expected_link
|
||||||
|
|
||||||
all_page_items = page.select('.template-list-item')
|
all_page_items = page.select('.template-list-item')
|
||||||
all_page_items_styled_with_checkboxes = page.select('.template-list-item-with-checkbox')
|
all_page_items_styled_with_checkboxes = page.select('.template-list-item.govuk-checkboxes__item')
|
||||||
|
|
||||||
assert len(all_page_items) == len(all_page_items_styled_with_checkboxes)
|
assert len(all_page_items) == len(all_page_items_styled_with_checkboxes)
|
||||||
|
|
||||||
@@ -527,7 +569,7 @@ def test_get_manage_folder_viewing_permissions_for_users(
|
|||||||
assert normalize_spaces(page.select_one('title').text) == (
|
assert normalize_spaces(page.select_one('title').text) == (
|
||||||
'folder_two – Templates – service one – GOV.UK Notify'
|
'folder_two – Templates – service one – GOV.UK Notify'
|
||||||
)
|
)
|
||||||
form_labels = page.select('legend[class=form-label]')
|
form_labels = page.select('legend.govuk-fieldset__legend')
|
||||||
assert normalize_spaces(form_labels[0].text) == "Team members who can see this folder"
|
assert normalize_spaces(form_labels[0].text) == "Team members who can see this folder"
|
||||||
checkboxes = page.select('input[name=users_with_permission]')
|
checkboxes = page.select('input[name=users_with_permission]')
|
||||||
|
|
||||||
@@ -538,7 +580,7 @@ def test_get_manage_folder_viewing_permissions_for_users(
|
|||||||
assert checkboxes[1]['value'] == team_member_2['id']
|
assert checkboxes[1]['value'] == team_member_2['id']
|
||||||
assert "checked" in checkboxes[1].attrs
|
assert "checked" in checkboxes[1].attrs
|
||||||
|
|
||||||
assert "Test User" in page.find_all('label', {'for': 'users_with_permission-0'})[0].text
|
assert "Test User" in page.find_all('label', {'for': 'users_with_permission-1'})[0].text
|
||||||
|
|
||||||
|
|
||||||
def test_get_manage_folder_viewing_permissions_for_users_not_visible_when_no_manage_settings_permission(
|
def test_get_manage_folder_viewing_permissions_for_users_not_visible_when_no_manage_settings_permission(
|
||||||
@@ -1462,45 +1504,70 @@ def test_show_custom_error_message(
|
|||||||
(
|
(
|
||||||
{},
|
{},
|
||||||
[
|
[
|
||||||
['folder_A', '1 template, 2 folders'],
|
['folder_A', 'folder_A', '1 template, 2 folders'],
|
||||||
['folder_E folder_F folder_G', '1 template'],
|
['folder_E folder_F folder_G',
|
||||||
['email_template_root', 'Email template'],
|
'folder_E', 'folder_F', 'folder_G',
|
||||||
|
'1 template'],
|
||||||
|
['email_template_root', 'email_template_root', 'Email template'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
['folder_A', '1 template, 2 folders'],
|
['folder_A', 'folder_A', '1 template, 2 folders'],
|
||||||
['folder_A', 'folder_C', '1 template'],
|
['folder_A folder_C',
|
||||||
['folder_A', 'folder_C', 'sms_template_C', 'Text message template'],
|
'folder_A', 'folder_C',
|
||||||
['folder_A', 'folder_D', 'Empty'],
|
'1 template'],
|
||||||
['folder_A', 'sms_template_A', 'Text message template'],
|
['folder_A folder_C sms_template_C',
|
||||||
['folder_E folder_F folder_G', '1 template'],
|
'folder_A', 'folder_C', 'sms_template_C',
|
||||||
['folder_E folder_F folder_G', 'email_template_G', 'Email template'],
|
'Text message template'],
|
||||||
['email_template_root', 'Email template'],
|
['folder_A folder_D',
|
||||||
|
'folder_A', 'folder_D',
|
||||||
|
'Empty'],
|
||||||
|
['folder_A sms_template_A',
|
||||||
|
'folder_A', 'sms_template_A',
|
||||||
|
'Text message template'],
|
||||||
|
['folder_E folder_F folder_G',
|
||||||
|
'folder_E', 'folder_F', 'folder_G',
|
||||||
|
'1 template'],
|
||||||
|
['folder_E folder_F folder_G email_template_G',
|
||||||
|
'folder_E', 'folder_F', 'folder_G', 'email_template_G',
|
||||||
|
'Email template'],
|
||||||
|
['email_template_root', 'email_template_root', 'Email template'],
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{'template_type': 'email'},
|
{'template_type': 'email'},
|
||||||
[
|
[
|
||||||
['folder_E folder_F folder_G', '1 template'],
|
['folder_E folder_F folder_G',
|
||||||
['email_template_root', 'Email template'],
|
'folder_E', 'folder_F', 'folder_G',
|
||||||
|
'1 template'],
|
||||||
|
['email_template_root', 'email_template_root', 'Email template'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
['folder_E folder_F folder_G', '1 template'],
|
['folder_E folder_F folder_G',
|
||||||
['folder_E folder_F folder_G', 'email_template_G', 'Email template'],
|
'folder_E', 'folder_F', 'folder_G',
|
||||||
['email_template_root', 'Email template'],
|
'1 template'],
|
||||||
|
['folder_E folder_F folder_G email_template_G',
|
||||||
|
'folder_E', 'folder_F', 'folder_G', 'email_template_G',
|
||||||
|
'Email template'],
|
||||||
|
['email_template_root', 'email_template_root', 'Email template'],
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{'template_type': 'sms'},
|
{'template_type': 'sms'},
|
||||||
[
|
[
|
||||||
['folder_A', '1 template, 1 folder'],
|
['folder_A', 'folder_A', '1 template, 1 folder'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
['folder_A', '1 template, 1 folder'],
|
['folder_A', 'folder_A', '1 template, 1 folder'],
|
||||||
['folder_A', 'folder_C', '1 template'],
|
['folder_A folder_C',
|
||||||
['folder_A', 'folder_C', 'sms_template_C', 'Text message template'],
|
'folder_A', 'folder_C',
|
||||||
['folder_A', 'sms_template_A', 'Text message template'],
|
'1 template'],
|
||||||
|
['folder_A folder_C sms_template_C',
|
||||||
|
'folder_A', 'folder_C', 'sms_template_C',
|
||||||
|
'Text message template'],
|
||||||
|
['folder_A sms_template_A', 'folder_A', 'sms_template_A',
|
||||||
|
'Text message template'],
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ def test_should_show_page_for_choosing_a_template(
|
|||||||
for index, expected_link in enumerate(expected_nav_links):
|
for index, expected_link in enumerate(expected_nav_links):
|
||||||
assert links_in_page[index].text.strip() == expected_link
|
assert links_in_page[index].text.strip() == expected_link
|
||||||
|
|
||||||
template_links = page.select('.message-name a')
|
template_links = page.select('#template-list .govuk-label a, .message-name a')
|
||||||
|
|
||||||
assert len(template_links) == len(expected_templates)
|
assert len(template_links) == len(expected_templates)
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ def test_should_show_live_search_if_list_of_templates_taller_than_screen(
|
|||||||
assert search['data-module'] == 'live-search'
|
assert search['data-module'] == 'live-search'
|
||||||
assert search['data-targets'] == '#template-list .template-list-item'
|
assert search['data-targets'] == '#template-list .template-list-item'
|
||||||
|
|
||||||
assert len(page.select(search['data-targets'])) == len(page.select('.message-name')) == 14
|
assert len(page.select(search['data-targets'])) == len(page.select('#template-list .govuk-label')) == 14
|
||||||
|
|
||||||
|
|
||||||
def test_should_show_live_search_if_service_has_lots_of_folders(
|
def test_should_show_live_search_if_service_has_lots_of_folders(
|
||||||
@@ -278,8 +278,8 @@ def test_should_show_live_search_if_service_has_lots_of_folders(
|
|||||||
service_id=SERVICE_ONE_ID,
|
service_id=SERVICE_ONE_ID,
|
||||||
)
|
)
|
||||||
|
|
||||||
count_of_templates_and_folders = len(page.select('.message-name'))
|
count_of_templates_and_folders = len(page.select('#template-list .govuk-label'))
|
||||||
count_of_folders = len(page.select('.template-list-folder:first-child'))
|
count_of_folders = len(page.select('.template-list-folder:first-of-type'))
|
||||||
count_of_templates = count_of_templates_and_folders - count_of_folders
|
count_of_templates = count_of_templates_and_folders - count_of_folders
|
||||||
|
|
||||||
assert len(page.select('.live-search')) == 1
|
assert len(page.select('.live-search')) == 1
|
||||||
|
|||||||
@@ -14,49 +14,52 @@ afterAll(() => {
|
|||||||
|
|
||||||
describe('Collapsible fieldset', () => {
|
describe('Collapsible fieldset', () => {
|
||||||
|
|
||||||
|
const _checkboxes = (start, end) => {
|
||||||
|
result = '';
|
||||||
|
|
||||||
|
for (let num = start; num <= end; num++) {
|
||||||
|
let id = `folder-permissions-${num}`;
|
||||||
|
|
||||||
|
result += `<li class="govuk-checkboxes__item">
|
||||||
|
<input class="govuk-checkboxes__input" id="${id}" name="folder-permissions" type="checkbox" value="${id}">
|
||||||
|
<label class="govuk-label govuk-checkboxes__label" for="${id}">
|
||||||
|
Folder ${id}
|
||||||
|
</label>
|
||||||
|
</li>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
let wrapper;
|
||||||
|
let formGroup;
|
||||||
let fieldset;
|
let fieldset;
|
||||||
|
let checkboxesContainer;
|
||||||
let checkboxes;
|
let checkboxes;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const _checkboxes = (start, end, descendents) => {
|
|
||||||
result = '';
|
|
||||||
|
|
||||||
for (let num = start; num <= end; num++) {
|
|
||||||
let id = `folder-permissions-${num}`;
|
|
||||||
|
|
||||||
if (!descendents) { descendents = ''; }
|
|
||||||
|
|
||||||
result += `<li class="multiple-choice">
|
|
||||||
<input id="${id}" name="folder_permissions" type="checkbox" value="${id}">
|
|
||||||
<label class="block-label" for="{id}">
|
|
||||||
Folder 18
|
|
||||||
</label>
|
|
||||||
${descendents}
|
|
||||||
</li>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
// set up DOM
|
// set up DOM
|
||||||
document.body.innerHTML =
|
document.body.innerHTML =
|
||||||
`<div class="form-group" data-module="collapsible-checkboxes" data-field-label="folder">
|
`<div class="selection-wrapper" data-module="collapsible-checkboxes" data-field-label="folder">
|
||||||
<div class="selection-summary"></div>
|
<div class="govuk-form-group">
|
||||||
<fieldset id="folder_permissions">
|
<fieldset class="govuk-fieldset" id="folder_permissions">
|
||||||
<legend class="form-label heading-small">
|
<legend class="govuk-fieldset__legend govuk-fieldset__legend--s">
|
||||||
Folders this team member can see
|
Folders this team member can see
|
||||||
</legend>
|
<span class="govuk-hint">
|
||||||
<div class="checkboxes-nested">
|
<div class="selection-summary" role="region" aria-live="polite"></div>
|
||||||
<ul>
|
</span>
|
||||||
|
</legend>
|
||||||
|
<ul class="govuk-checkboxes">
|
||||||
${_checkboxes(1, 10)}
|
${_checkboxes(1, 10)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
formGroup = document.querySelector('.form-group');
|
wrapper = document.querySelector('.selection-wrapper');
|
||||||
|
formGroup = wrapper.querySelector('.govuk-form-group');
|
||||||
fieldset = formGroup.querySelector('fieldset');
|
fieldset = formGroup.querySelector('fieldset');
|
||||||
checkboxesContainer = fieldset.querySelector('.checkboxes-nested');
|
checkboxesContainer = fieldset.querySelector('.govuk-checkboxes');
|
||||||
checkboxes = checkboxesContainer.querySelectorAll('input[type=checkbox]');
|
checkboxes = checkboxesContainer.querySelectorAll('input[type=checkbox]');
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -141,6 +144,12 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("removes the hint", () => {
|
||||||
|
|
||||||
|
expect(document.querySelector('.govuk-hint')).toBeNull();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('has the right summary text when started with no checkboxes selected', () => {
|
test('has the right summary text when started with no checkboxes selected', () => {
|
||||||
@@ -187,7 +196,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("the summary doesn't have a folder icon if fields aren't called 'folder'", () => {
|
test("the summary doesn't have a folder icon if fields aren't called 'folder'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'team member';
|
wrapper.dataset.fieldLabel = 'team member';
|
||||||
|
|
||||||
// start module
|
// start module
|
||||||
window.GOVUK.modules.start();
|
window.GOVUK.modules.start();
|
||||||
@@ -277,35 +286,74 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
describe("the footer (that wraps the button)", () => {
|
describe("the footer (that wraps the button)", () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
describe("is inserted", () => {
|
||||||
|
|
||||||
// track calls to sticky JS
|
test("after the fieldset", () => {
|
||||||
window.GOVUK.stickAtBottomWhenScrolling.recalculate = jest.fn(() => {});
|
|
||||||
|
|
||||||
// start module
|
// start module
|
||||||
window.GOVUK.modules.start();
|
window.GOVUK.modules.start();
|
||||||
|
|
||||||
// show the checkboxes
|
// show the checkboxes
|
||||||
helpers.triggerEvent(formGroup.querySelector('.govuk-button'), 'click');
|
helpers.triggerEvent(formGroup.querySelector('.govuk-button'), 'click');
|
||||||
|
|
||||||
|
expect(formGroup.querySelector('.selection-footer').previousElementSibling.nodeName).toBe('FIELDSET');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("after the root fieldset if the checkboxes are nested", () => {
|
||||||
|
|
||||||
|
// add a nested list of checkboxes to the first checkbox item
|
||||||
|
const nestedCheckboxes = document.createElement('div');
|
||||||
|
nestedCheckboxes.className = 'govuk-form-group govuk-form-group--nested';
|
||||||
|
nestedCheckboxes.innerHTML = _checkboxes(11, 20);
|
||||||
|
checkboxesContainer.querySelector('.govuk-checkboxes__item').appendChild(nestedCheckboxes);
|
||||||
|
|
||||||
|
// start module
|
||||||
|
window.GOVUK.modules.start();
|
||||||
|
|
||||||
|
// show the checkboxes
|
||||||
|
helpers.triggerEvent(formGroup.querySelector('.govuk-button'), 'click');
|
||||||
|
|
||||||
|
expect(formGroup.querySelector('.selection-footer').previousElementSibling.nodeName).toBe('FIELDSET');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("is made sticky when the fieldset is expanded", () => {
|
describe("its stickiness", () => {
|
||||||
|
|
||||||
expect(formGroup.querySelector('.selection-footer').classList.contains('js-stick-at-bottom-when-scrolling')).toBe(true);
|
beforeEach(() => {
|
||||||
expect(window.GOVUK.stickAtBottomWhenScrolling.recalculate.mock.calls.length).toBe(1);
|
|
||||||
|
// track calls to sticky JS
|
||||||
|
window.GOVUK.stickAtBottomWhenScrolling.recalculate = jest.fn(() => {});
|
||||||
|
|
||||||
|
// start module
|
||||||
|
window.GOVUK.modules.start();
|
||||||
|
|
||||||
|
// show the checkboxes
|
||||||
|
helpers.triggerEvent(formGroup.querySelector('.govuk-button'), 'click');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("is added when the fieldset is expanded", () => {
|
||||||
|
|
||||||
|
expect(formGroup.querySelector('.selection-footer').classList.contains('js-stick-at-bottom-when-scrolling')).toBe(true);
|
||||||
|
expect(window.GOVUK.stickAtBottomWhenScrolling.recalculate.mock.calls.length).toBe(1);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("is removed when the fieldset is collapsed", () => {
|
||||||
|
|
||||||
|
// click the button to collapse the fieldset
|
||||||
|
helpers.triggerEvent(formGroup.querySelector('.govuk-button'), 'click');
|
||||||
|
|
||||||
|
expect(formGroup.querySelector('.selection-footer').classList.contains('js-stick-at-bottom-when-scrolling')).toBe(false);
|
||||||
|
expect(window.GOVUK.stickAtBottomWhenScrolling.recalculate.mock.calls.length).toBe(2);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("has its stickiness removed when the fieldset is collapsed", () => {
|
|
||||||
|
|
||||||
// click the button to collapse the fieldset
|
|
||||||
helpers.triggerEvent(formGroup.querySelector('.govuk-button'), 'click');
|
|
||||||
|
|
||||||
expect(formGroup.querySelector('.selection-footer').classList.contains('js-stick-at-bottom-when-scrolling')).toBe(false);
|
|
||||||
expect(window.GOVUK.stickAtBottomWhenScrolling.recalculate.mock.calls.length).toBe(2);
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when the selection changes", () => {
|
describe("when the selection changes", () => {
|
||||||
@@ -339,7 +387,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("if fields are called 'folders'", () => {
|
test("if fields are called 'folders'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'folder';
|
wrapper.dataset.fieldLabel = 'folder';
|
||||||
|
|
||||||
checkFirstCheckbox();
|
checkFirstCheckbox();
|
||||||
|
|
||||||
@@ -359,7 +407,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("if fields are called 'team member'", () => {
|
test("if fields are called 'team member'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'team member';
|
wrapper.dataset.fieldLabel = 'team member';
|
||||||
|
|
||||||
checkFirstCheckbox();
|
checkFirstCheckbox();
|
||||||
|
|
||||||
@@ -379,7 +427,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("if fields are called 'arbitrary thing'", () => {
|
test("if fields are called 'arbitrary thing'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'arbitrary thing';
|
wrapper.dataset.fieldLabel = 'arbitrary thing';
|
||||||
|
|
||||||
checkFirstCheckbox();
|
checkFirstCheckbox();
|
||||||
|
|
||||||
@@ -403,7 +451,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("if fields are called 'folder'", () => {
|
test("if fields are called 'folder'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'folder';
|
wrapper.dataset.fieldLabel = 'folder';
|
||||||
|
|
||||||
checkAllCheckboxes();
|
checkAllCheckboxes();
|
||||||
|
|
||||||
@@ -423,7 +471,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("if fields are called 'team member'", () => {
|
test("if fields are called 'team member'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'team member';
|
wrapper.dataset.fieldLabel = 'team member';
|
||||||
|
|
||||||
checkAllCheckboxes();
|
checkAllCheckboxes();
|
||||||
|
|
||||||
@@ -447,7 +495,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("if fields are called 'folder'", () => {
|
test("if fields are called 'folder'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'folder';
|
wrapper.dataset.fieldLabel = 'folder';
|
||||||
|
|
||||||
checkAllCheckboxesButTheLast();
|
checkAllCheckboxesButTheLast();
|
||||||
|
|
||||||
@@ -466,7 +514,7 @@ describe('Collapsible fieldset', () => {
|
|||||||
|
|
||||||
test("if fields are called 'team member'", () => {
|
test("if fields are called 'team member'", () => {
|
||||||
|
|
||||||
formGroup.dataset.fieldLabel = 'team member';
|
wrapper.dataset.fieldLabel = 'team member';
|
||||||
|
|
||||||
checkAllCheckboxesButTheLast();
|
checkAllCheckboxesButTheLast();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user