diff --git a/app/main/forms.py b/app/main/forms.py index a269bc385..81ba31ae0 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -655,7 +655,7 @@ class RegisterUserFromOrgInviteForm(StripWhitespaceForm): auth_type = HiddenField("auth_type", validators=[DataRequired()]) -def govuk_checkbox_field_widget(self, field, param_extensions=None, **kwargs): +def uswds_checkbox_field_widget(self, field, param_extensions=None, **kwargs): # error messages error_message = None if field.errors: @@ -695,7 +695,7 @@ def govuk_checkbox_field_widget(self, field, param_extensions=None, **kwargs): ) # nosec -def govuk_checkboxes_field_widget( +def uswds_checkboxes_field_widget( self, field, wrap_in_collapsible=False, param_extensions=None, **kwargs ): def _wrap_in_collapsible(field_label, checkboxes_string): @@ -812,9 +812,9 @@ def govuk_radios_field_widget(self, field, param_extensions=None, **kwargs): ) # nosec -class GovukCheckboxField(BooleanField): +class USWDSCheckboxField(BooleanField): def __init__(self, label="", validators=None, param_extensions=None, **kwargs): - super(GovukCheckboxField, self).__init__( + super(USWDSCheckboxField, self).__init__( label, validators, false_values=None, **kwargs ) self.param_extensions = param_extensions @@ -824,17 +824,17 @@ class GovukCheckboxField(BooleanField): # 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): - return govuk_checkbox_field_widget( + return uswds_checkbox_field_widget( self, field, param_extensions=param_extensions, **kwargs ) # based on work done by @richardjpope: https://github.com/richardjpope/recourse/blob/master/recourse/forms.py#L6 -class GovukCheckboxesField(SelectMultipleField): +class USWDSCheckboxesField(SelectMultipleField): render_as_list = False def __init__(self, label="", validators=None, param_extensions=None, **kwargs): - super(GovukCheckboxesField, self).__init__(label, validators, **kwargs) + super(USWDSCheckboxesField, self).__init__(label, validators, **kwargs) self.param_extensions = param_extensions def get_item_from_option(self, option): @@ -854,32 +854,32 @@ class GovukCheckboxesField(SelectMultipleField): # 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): - return govuk_checkboxes_field_widget( + return uswds_checkboxes_field_widget( self, field, param_extensions=param_extensions, **kwargs ) # Wraps checkboxes rendering in HTML needed by the collapsible JS -class GovukCollapsibleCheckboxesField(GovukCheckboxesField): +class USWDSCollapsibleCheckboxesField(USWDSCheckboxesField): def __init__( self, label="", validators=None, field_label="", param_extensions=None, **kwargs ): - super(GovukCollapsibleCheckboxesField, self).__init__( + super(USWDSCollapsibleCheckboxesField, self).__init__( label, validators, param_extensions, **kwargs ) self.field_label = field_label def widget(self, field, **kwargs): - return govuk_checkboxes_field_widget( + return uswds_checkboxes_field_widget( self, field, wrap_in_collapsible=True, param_extensions=None, **kwargs ) -# GovukCollapsibleCheckboxesField adds an ARIA live-region to the hint and wraps the render in HTML needed by the +# USWDSCollapsibleCheckboxesField 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( - NestedFieldMixin, GovukCollapsibleCheckboxesField +class USWDSCollapsibleNestedCheckboxesField( + NestedFieldMixin, USWDSCollapsibleCheckboxesField ): NONE_OPTION_VALUE = None render_as_list = True @@ -998,7 +998,7 @@ class BasePermissionsForm(StripWhitespaceForm): for item in ([{"name": "Templates", "id": None}] + all_template_folders) ] - folder_permissions = GovukCollapsibleNestedCheckboxesField( + folder_permissions = USWDSCollapsibleNestedCheckboxesField( "Folders this team member can see", field_label="folder" ) @@ -1012,7 +1012,7 @@ class BasePermissionsForm(StripWhitespaceForm): validators=[DataRequired()], ) - permissions_field = GovukCheckboxesField( + permissions_field = USWDSCheckboxesField( "Permissions", filters=[filter_by_permissions], choices=[(value, label) for value, label in permission_options], @@ -1422,7 +1422,7 @@ class ServiceContactDetailsForm(StripWhitespaceForm): class ServiceReplyToEmailForm(StripWhitespaceForm): email_address = email_address(label="Reply-to email address", gov_user=False) - is_default = GovukCheckboxField("Make this email address the default") + is_default = USWDSCheckboxField("Make this email address the default") class ServiceSmsSenderForm(StripWhitespaceForm): @@ -1436,11 +1436,11 @@ class ServiceSmsSenderForm(StripWhitespaceForm): DoesNotStartWithDoubleZero(), ], ) - is_default = GovukCheckboxField("Make this text message sender the default") + is_default = USWDSCheckboxField("Make this text message sender the default") class ServiceEditInboundNumberForm(StripWhitespaceForm): - is_default = GovukCheckboxField("Make this text message sender the default") + is_default = USWDSCheckboxField("Make this text message sender the default") class AdminNotesForm(StripWhitespaceForm): @@ -1528,7 +1528,7 @@ class GuestList(StripWhitespaceForm): class DateFilterForm(StripWhitespaceForm): start_date = GovukDateField("Start Date", [validators.optional()]) end_date = GovukDateField("End Date", [validators.optional()]) - include_from_test_key = GovukCheckboxField("Include test keys") + include_from_test_key = USWDSCheckboxField("Include test keys") class RequiredDateFilterForm(StripWhitespaceForm): @@ -1732,7 +1732,7 @@ class TemplateFolderForm(StripWhitespaceForm): (item.id, item.name) for item in all_service_users ] - users_with_permission = GovukCollapsibleCheckboxesField( + users_with_permission = USWDSCollapsibleCheckboxesField( "Team members who can see this folder", field_label="team member" ) name = GovukTextInputField( @@ -1851,7 +1851,7 @@ class TemplateAndFoldersSelectionForm(Form): return self.move_to_new_folder_name.data return None - templates_and_folders = GovukCheckboxesField( + templates_and_folders = USWDSCheckboxesField( "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__ @@ -1883,7 +1883,7 @@ class TemplateAndFoldersSelectionForm(Form): class AdminClearCacheForm(StripWhitespaceForm): - model_type = GovukCheckboxesField( + model_type = USWDSCheckboxesField( "What do you want to clear today", ) diff --git a/app/templates/components/components/checkboxes/template.njk b/app/templates/components/components/checkboxes/template.njk index 48a6b0b86..4932f3eb7 100644 --- a/app/templates/components/components/checkboxes/template.njk +++ b/app/templates/components/components/checkboxes/template.njk @@ -49,7 +49,7 @@ visuallyHiddenText: params.errorMessage.visuallyHiddenText }) | indent(2) | trim }} {% endif %} -
{% for item in params.items %} @@ -60,8 +60,8 @@ {% set itemHintId = id + "-item-hint" if hasHint else "" %} {% set itemDescribedBy = describedBy if not hasFieldset else "" %} {% set itemDescribedBy = (itemDescribedBy + " " + itemHintId) | trim %} -
- + {% if item.conditional %} -
+
{{ item.conditional.html | safe }}
{% endif %} diff --git a/app/templates/forms/fields/checkboxes/template.njk b/app/templates/forms/fields/checkboxes/template.njk index c1d006310..74d346346 100644 --- a/app/templates/forms/fields/checkboxes/template.njk +++ b/app/templates/forms/fields/checkboxes/template.njk @@ -1,16 +1,16 @@ {% from "components/components/error-message/macro.njk" import usaErrorMessage -%} {% from "components/components/fieldset/macro.njk" import govukFieldset %} {% from "components/components/hint/macro.njk" import usaHint %} -{% from "components/components/radio-label/macro.njk" import usaRadioLabel %} +{% from "components/components/label/macro.njk" import usaLabel %} -{#- Copied from https://github.com/alphagov/govuk-frontend/blob/v2.13.0/src/components/checkboxes/template.njk - Changes: - - `formGroup` option to control whether or not the checkboxes are wrapped with a `usa-form-group` class - - `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 `.usa-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) -#} +{#- Updated from GOV.UK components to USWDS patterns + Changed from original GOV.UK template: + - Uses USWDS checkbox classes (usa-checkbox, usa-checkbox__input, usa-checkbox__label) + - Conditional content uses display-none utility class instead of govuk-specific classes + - Label uses usaLabel macro instead of radio label + - Hint text uses usa-checkbox__label-description class + - Maintains all original functionality including conditional reveals and nested checkboxes -#} {#- 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 %} @@ -92,17 +92,17 @@ {%- if item.conditional %} data-aria-controls="{{ conditionalId }}"{% endif -%} {%- if itemDescribedBy %} aria-describedby="{{ itemDescribedBy }}"{% endif -%} {%- for attribute, value in item.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}> - {{ usaRadioLabel({ + {{ usaLabel({ html: item.html, text: item.text, - classes: (' ' + item.label.classes if item.label.classes), + classes: 'usa-checkbox__label' + (' ' + item.label.classes if item.label.classes), attributes: item.label.attributes, for: id }) | indent(6) | trim }} {%- if hasHint %} {{ usaHint({ id: itemHintId, - classes: 'govuk-checkboxes__hint' + (' ' + item.hint.classes if item.hint.classes), + classes: 'usa-checkbox__label-description' + (' ' + item.hint.classes if item.hint.classes), attributes: item.hint.attributes, html: item.hint.html, text: item.hint.text @@ -112,14 +112,14 @@ {{ item.children | safe }} {%- endif %} {% if params.asList and item.conditional %} -
+
{{ item.conditional.html | safe }}
{% endif %} {%- if item.after %}{{ item.after }}{% endif -%} {% if not params.asList and item.conditional %} -
+
{{ item.conditional.html | safe }}
{% endif %} diff --git a/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png index e823605be..9a985d5e1 100644 Binary files a/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png differ diff --git a/backstop_data/bitmaps_reference/backstop_test_Establish_Trust_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Establish_Trust_0_document_0_desktop.png index e3c06c069..6185e7efa 100644 Binary files a/backstop_data/bitmaps_reference/backstop_test_Establish_Trust_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_Establish_Trust_0_document_0_desktop.png differ diff --git a/backstop_data/bitmaps_reference/backstop_test_Invite_User_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Invite_User_0_document_0_desktop.png new file mode 100644 index 000000000..2c427b325 Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Invite_User_0_document_0_desktop.png differ diff --git a/backstop_data/bitmaps_reference/backstop_test_Platform_Admin_Live_Services_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Platform_Admin_Live_Services_0_document_0_desktop.png new file mode 100644 index 000000000..4de5b957e Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Platform_Admin_Live_Services_0_document_0_desktop.png differ diff --git a/tests/app/main/views/organizations/test_organizations.py b/tests/app/main/views/organizations/test_organizations.py index ceab59519..0e7c35e82 100644 --- a/tests/app/main/views/organizations/test_organizations.py +++ b/tests/app/main/views/organizations/test_organizations.py @@ -63,10 +63,7 @@ def test_organization_page_shows_all_organizations( assert normalize_spaces(archived.text) == "- archived" assert normalize_spaces(archived.parent.text) == "Test 2 - archived 2 live services" - assert ( - normalize_spaces(page.select_one("a.usa-button").text) - == "New organization" - ) + assert normalize_spaces(page.select_one("a.usa-button").text) == "New organization" get_organizations.assert_called_once_with() diff --git a/tests/javascripts/collapsibleCheckboxes.test.js b/tests/javascripts/collapsibleCheckboxes.test.js index 9920f9b92..3d6c6bc1b 100644 --- a/tests/javascripts/collapsibleCheckboxes.test.js +++ b/tests/javascripts/collapsibleCheckboxes.test.js @@ -20,9 +20,9 @@ describe('Collapsible fieldset', () => { for (let num = start; num <= end; num++) { let id = `folder-permissions-${num}`; - result += `
  • - -
  • + +
  • `; @@ -49,7 +49,7 @@ describe('Collapsible fieldset', () => {
    -
      +
        ${_checkboxes(1, 10)}
      @@ -59,7 +59,7 @@ describe('Collapsible fieldset', () => { wrapper = document.querySelector('.selection-wrapper'); formGroup = wrapper.querySelector('.usa-form-group'); fieldset = formGroup.querySelector('fieldset'); - checkboxesContainer = fieldset.querySelector('.govuk-checkboxes'); + checkboxesContainer = fieldset.querySelector('.usa-checkbox-group'); checkboxes = checkboxesContainer.querySelectorAll('input[type=checkbox]'); }); @@ -323,7 +323,7 @@ describe('Collapsible fieldset', () => { const nestedCheckboxes = document.createElement('div'); nestedCheckboxes.className = 'usa-form-group usa-form-group--nested'; nestedCheckboxes.innerHTML = _checkboxes(11, 20); - checkboxesContainer.querySelector('.govuk-checkboxes__item').appendChild(nestedCheckboxes); + checkboxesContainer.querySelector('.usa-checkbox').appendChild(nestedCheckboxes); // start module window.GOVUK.modules.start(); diff --git a/urls.js b/urls.js index e47d8931a..da66b7cc5 100644 --- a/urls.js +++ b/urls.js @@ -58,6 +58,15 @@ const routes = { label: 'Team Members', path: '/services/e6de050d-bd56-4f49-b44b-cb789c4f79fd/users', }, + { + label: 'Invite User', + path: '/services/e6de050d-bd56-4f49-b44b-cb789c4f79fd/users/invite', + }, + // Platform admin pages with checkboxes + { + label: 'Platform Admin Live Services', + path: '/platform-admin/live-services', + }, ], // Using Notify section