Merge branch 'main' into 2589-may-19-zap-scan-fixes

Resolved conflicts by:
- Taking all backstop images from main branch
- Taking .ds.baseline from main (with updated line numbers)
- Keeping template literal security fixes in listEntry.js while incorporating main's styling changes
- Taking main's config.py updates (LOGO_CDN_DOMAIN and formatting)
This commit is contained in:
alexjanousekGSA
2025-07-31 16:08:12 -04:00
42 changed files with 342 additions and 107 deletions

View File

@@ -316,9 +316,18 @@
return rowSender === currentUserName;
});
userRows.slice(0, 5).forEach(row => {
row.style.display = '';
});
if (userRows.length > 0) {
userRows.slice(0, 5).forEach(row => {
row.style.display = '';
});
} else {
const emptyMessageRow = Array.from(allRows).find(row => {
return row.querySelector('.table-empty-message');
});
if (emptyMessageRow) {
emptyMessageRow.style.display = '';
}
}
} else {
tableHeading.textContent = 'Service activity';

View File

@@ -17,6 +17,7 @@
this.minEntries = 2;
this.listItemName = this.$wrapper.data('listItemName');
this.getSharedAttributes();
this.getOriginalClasses();
this.getValues();
this.maxEntries = this.entries.length;
@@ -28,17 +29,18 @@
ListEntry.prototype.renderEntry = function(data) {
return `
<div class="list-entry">
<label for="${data.id}" class="govuk-input--numbered__label">
<label for="${data.id}" class="usa-label">
<span class="usa-sr-only">${data.listItemName} number </span>${data.number}.
</label>
<input
class="usa-input ${data.classes || ''}"
name="${data.name}"
id="${data.id}"
${data.value ? `value="${data.value}"` : ''}
${data.sharedAttributes}
/>
${data.button ? `
<button type="button" class="usa-button input-list__button--remove">
<button type="button" class="usa-button usa-button--unstyled input-list__button--remove">
Remove<span class="usa-sr-only"> ${data.listItemName} number ${data.number}</span>
</button>
` : ''}
@@ -46,11 +48,11 @@
`;
};
ListEntry.prototype.renderAddButton = function(data) {
return `<button type="button" class="usa-button input-list__button--add">Add another ${data.listItemName} (${data.entriesLeft} remaining)</button>`;
return `<button type="button" class="usa-button usa-button--outline input-list__button--add">Add another ${data.listItemName} (${data.entriesLeft} remaining)</button>`;
};
ListEntry.prototype.getSharedAttributes = function () {
var $inputs = this.$wrapper.find('input'),
generatedAttributes = ['id', 'name', 'value'],
generatedAttributes = ['id', 'name', 'value', 'class'],
attributes = [],
attrIdx,
elmAttributes,
@@ -95,6 +97,20 @@
this.sharedAttributes = (attributes.length) ? getAttributesHTML(attributes) : '';
};
ListEntry.prototype.getOriginalClasses = function () {
var $firstInput = this.$wrapper.find('input').first();
if ($firstInput.length) {
var classList = $firstInput.attr('class');
if (classList) {
// Preserve any additional classes from the original input
this.additionalClasses = classList;
} else {
this.additionalClasses = '';
}
} else {
this.additionalClasses = '';
}
};
ListEntry.prototype.getValues = function () {
this.entries = [];
this.$wrapper.find('input').each(function (idx, elm) {
@@ -183,7 +199,8 @@
'name' : this.getId(entryNumber),
'value' : entry,
'listItemName' : this.listItemName,
'sharedAttributes': this.sharedAttributes
'sharedAttributes': this.sharedAttributes,
'classes': this.additionalClasses
};
if (entryNumber > 1) {

View File

@@ -7,9 +7,6 @@ $(() => GOVUK.modules.start());
$(() => $('.error-message, .usa-error-message').eq(0).parent('label').next('input').trigger('focus'));
$(() => $('.govuk-header__container').on('click', function() {
$(this).css('border-color', '#005ea5');
}));
// Applies our expanded focus style to the siblings of links when that link is wrapped in a heading.
//

View File

@@ -1092,3 +1092,14 @@ nav.nav {
.selection-content .usa-form-group--nested li.usa-checkbox {
margin-top: 0;
}
// Radio button and checkbox legends
.usa-radio legend.usa-legend,
.usa-checkbox legend.usa-legend,
.api-key-radios legend.usa-legend,
.login-auth-radios legend.usa-legend,
.auth-type-radios legend.usa-legend,
.notification-type-radios legend.usa-legend,
.organizations-radios legend.usa-legend {
font-weight: 700;
}

View File

@@ -16,7 +16,12 @@ class Config(object):
API_PUBLIC_WS_URL = getenv("API_PUBLIC_WS_URL", "localhost")
ADMIN_BASE_URL = getenv("ADMIN_BASE_URL", "http://localhost:6012")
HEADER_COLOUR = "#81878b" # mix of dark-grey and mid-grey
HEADER_COLOUR = (
"#81878b" # mix of dark-grey and mid-grey
)
LOGO_CDN_DOMAIN = (
"static-logos.notifications.service.gov.uk" # TODO use our own CDN
)
ASSETS_DEBUG = False

View File

@@ -0,0 +1,20 @@
{% from "components/select-input.html" import select, select_list, select_nested, select_wrapper, select_input %}
{% macro checkboxes(field, hint=None, disable=[], option_hints={}, hide_legend=False) %}
{{ select(field, hint, disable, option_hints, hide_legend, input="checkbox") }}
{% endmacro %}
{% macro checkbox_list(options, child_map, disable=[], option_hints={}) %}
{{ select_list(options, child_map, disable, option_hints, input="checkbox") }}
{% endmacro %}
{% macro checkboxes_nested(field, child_map, hint=None, disable=[], option_hints={}, hide_legend=False) %}
{{ select_nested(field, child_map, hint, disable, option_hints, hide_legend, input="checkbox") }}
{% endmacro %}
{% macro checkbox(option, disable=[], option_hints={}, data_target=None, as_list_item=False) %}
{{ select_input(option, disable, option_hints, data_target, as_list_item, input="checkbox") }}
{% endmacro %}

View File

@@ -36,9 +36,9 @@
{% set autocomplete = "" %}
{% endif %}
{% if entry.errors %}
{% set label_classes = "usa-input--numbered__label usa-input--numbered__label--error" %}
{% set label_classes = "usa-label usa-label--error" %}
{% else %}
{% set label_classes = "usa-input--numbered__label" %}
{% set label_classes = "usa-label" %}
{% endif %}
{% set field_name = field.name + "-" + loop.index|string %}
{{ entry(param_extensions={
@@ -48,7 +48,7 @@
"html": '<span class="usa-sr-only">' + item_name + ' number </span>' + loop.index|string + '.',
"classes": label_classes
},
"classes": "usa-input--numbered ",
"classes": "usa-input",
"value": field.data[loop.index0],
"autocomplete": autocomplete
}) }}

View File

@@ -1,30 +1,30 @@
{% macro previous_next_navigation(previous_page, next_page) %}
{% if previous_page or next_page %}
<nav class="govuk-previous-and-next-navigation" role="navigation" aria-label="Pagination">
<ul class="group">
<nav class="usa-pagination margin-y-5 text-left" role="navigation" aria-label="Pagination">
<ul class="usa-pagination__list flex-justify-start">
{% if previous_page %}
<li class="previous-page">
<a class="usa-link" href="{{previous_page['url']}}" rel="previous" >
<span class="pagination-part-title">
<svg class="pagination-icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17" viewBox="0 0 17 13">
<path fill="currentColor" d="m6.5938-0.0078125-6.7266 6.7266 6.7441 6.4062 1.377-1.449-4.1856-3.9768h12.896v-2h-12.984l4.2931-4.293-1.414-1.414z"/>
</svg>
<li class="usa-pagination__item usa-pagination__arrow">
<a class="usa-pagination__link usa-pagination__previous-page" href="{{previous_page['url']}}" rel="previous">
<svg class="usa-icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17" viewBox="0 0 17 13">
<path fill="currentColor" d="m6.5938-0.0078125-6.7266 6.7266 6.7441 6.4062 1.377-1.449-4.1856-3.9768h12.896v-2h-12.984l4.2931-4.293-1.414-1.414z"/>
</svg>
<span class="usa-pagination__link-text">
{{previous_page['title']}}
</span>
<span class="pagination-label">{{previous_page['label']}}</span>
<span class="usa-sr-only">{{previous_page['label']}}</span>
</a>
</li>
{% endif %}
{% if next_page %}
<li class="next-page">
<a class="usa-link" href="{{next_page['url']}}" rel="next">
<span class="pagination-part-title">
<li class="usa-pagination__item usa-pagination__arrow">
<a class="usa-pagination__link usa-pagination__next-page" href="{{next_page['url']}}" rel="next">
<span class="usa-pagination__link-text">
{{next_page['title']}}
<svg class="pagination-icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17" viewBox="0 0 17 13">
<path fill="currentColor" d="m10.107-0.0078125-1.4136 1.414 4.2926 4.293h-12.986v2h12.896l-4.1855 3.9766 1.377 1.4492 6.7441-6.4062-6.7246-6.7266z"/>
</svg>
</span>
<span class="pagination-label">{{next_page['label']}}</span>
<svg class="usa-icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17" viewBox="0 0 17 13">
<path fill="currentColor" d="m10.107-0.0078125-1.4136 1.414 4.2926 4.293h-12.986v2h12.896l-4.1855 3.9766 1.377 1.4492 6.7441-6.4062-6.7246-6.7266z"/>
</svg>
<span class="usa-sr-only">{{next_page['label']}}</span>
</a>
</li>
{% endif %}

View File

@@ -1,7 +1,7 @@
{% from "components/select-input.html" import select, select_list, select_nested, select_wrapper, select_input %}
{% macro radios(field, hint=None, disable=[], option_hints={}, hide_legend=False, inline=False) %}
{{ select(field, hint, disable, option_hints, hide_legend, input="radio", inline=inline) }}
{% macro radios(field, hint=None, disable=[], option_hints={}, hide_legend=False, inline=False, legend_style="text") %}
{{ select(field, hint, disable, option_hints, hide_legend, legend_style=legend_style, input="radio", inline=inline) }}
{% endmacro %}

View File

@@ -12,12 +12,12 @@
{% macro select_list(options, child_map, disable=[], option_hints={}, input="radio", indent_level=0) %}
{% for option in options %}
{% if child_map[option.data] %}
<div class="{% if indent_level > 0 %}margin-left-{{ indent_level * 4 }}{% endif %}">
<div class="{% if indent_level == 1 %}margin-left-3{% elif indent_level == 2 %}margin-left-4{% elif indent_level >= 3 %}margin-left-5{% endif %}">
{{ select_input(option, disable, option_hints, as_list_item=False, input=input) }}
</div>
{{ select_list(child_map[option.data], child_map, disable, option_hints, input=input, indent_level=indent_level + 1) }}
{% else %}
<div class="{% if indent_level > 0 %}margin-left-{{ indent_level * 4 }}{% endif %}">
<div class="{% if indent_level == 1 %}margin-left-3{% elif indent_level == 2 %}margin-left-4{% elif indent_level >= 3 %}margin-left-5{% endif %}">
{{ select_input(option, disable, option_hints, as_list_item=False, input=input) }}
</div>
{% endif %}
@@ -45,7 +45,11 @@
<fieldset id="{{ field.id }}" class="usa-fieldset" {% if inline %}class="inline"{% endif %}>
<legend class="{{ 'usa-legend' if not hide_legend else '' }}{% if legend_style != 'text' %} {{ legend_style }}{% endif %}">
{% if hide_legend %}<span class="usa-sr-only">{% endif %}
{{ field.label.text|safe }}
{% if legend_style == 'usa-legend--large' %}
<h1 class="usa-legend font-sans-lg">{{ field.label.text|safe }}</h1>
{% else %}
{{ field.label.text|safe }}
{% endif %}
{% if hide_legend %}</span>{% endif %}
{% if hint %}
<span class="form-hint">
@@ -64,9 +68,9 @@
{% endmacro %}
{% macro select_input(option, disable=[], option_hints={}, data_target=None, as_list_item=False, input="radio") %}
<div class="usa-radio" {% if data_target %}data-target="{{ data_target }}"{% endif %}>
<div class="usa-{{ input }}" {% if data_target %}data-target="{{ data_target }}"{% endif %}>
<input
id="{{ option.id }}" class="usa-radio__input" name="{{ option.name }}" type="{{ input }}" value="{{ option.data }}"
id="{{ option.id }}" class="usa-{{ input }}__input" name="{{ option.name }}" type="{{ input }}" value="{{ option.data }}"
{% if option.data in disable %}
disabled
{% endif %}
@@ -74,7 +78,7 @@
checked
{% endif %}
>
<label class="usa-radio__label" for="{{ option.id }}">
<label class="usa-{{ input }}__label" for="{{ option.id }}">
{{ option.label.text }}
{% if option_hints[option.data] %}
<span class="usa-hint">

View File

@@ -4,6 +4,7 @@
{% from "components/banner.html" import banner_wrapper %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% from "components/radios.html" import radios %}
{% block service_page_title %}
Create an API key
@@ -19,7 +20,17 @@
{% call form_wrapper() %}
{{ form.key_name }}
{{ form.key_type }}
<div class="margin-top-5">
{% if current_service.trial_mode %}
{{ radios(
form.key_type,
disable=['normal'],
option_hints={'normal': 'Not available because your service is in <a class="usa-link" href="/features/trial-mode">trial mode</a>'|safe}
) }}
{% else %}
{{ radios(form.key_type) }}
{% endif %}
</div>
{{ page_footer('Continue') }}
{% endcall %}

View File

@@ -3,6 +3,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% from "components/radios.html" import radios %}
{% block per_page_title %}
Set auth type for {{ user.name }}
@@ -19,7 +20,9 @@
{{ page_header('Set auth type for ' + user.name) }}
{% call form_wrapper() %}
{{ form.auth_type }}
<div class="auth-type-radios">
{{ radios(form.auth_type) }}
</div>
{{ page_footer('Save') }}
{% endcall %}
</div>

View File

@@ -11,13 +11,15 @@
{% endif %}
{% if service_has_email_auth %}
{% if not mobile_number %}
{{ radios(
form.login_authentication,
disable=['sms_auth'],
option_hints={'sms_auth': 'Not available because this team member has not added a phone&nbsp;number to their profile'|safe}
) }}
{% else %}
{{ radios(form.login_authentication) }}
{% endif %}
<div class="login-auth-radios">
{% if not mobile_number %}
{{ radios(
form.login_authentication,
disable=['sms_auth'],
option_hints={'sms_auth': 'Not available because this team member has not added a phone&nbsp;number to their profile'|safe}
) }}
{% else %}
{{ radios(form.login_authentication) }}
{% endif %}
</div>
{% endif %}

View File

@@ -1,6 +1,7 @@
{% extends "base.html" %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/radios.html" import radios %}
{% block per_page_title %}
Create an account
@@ -40,7 +41,7 @@ Create an account
{{ page_footer("Continue") }}
{{form.service}}
{{form.email_address}}
{{form.auth_type}}
{{ radios(form.auth_type) }}
{% endcall %}
</div>
</div>

View File

@@ -1,6 +1,7 @@
{% extends "base.html" %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/radios.html" import radios %}
{% block per_page_title %}
Create an account
@@ -26,7 +27,7 @@ Create an account
}) }}
</div>
{{ form.password(param_extensions={"hint": {"text": "At least 8 characters"}, "autocomplete": "new-password"}) }}
{{form.auth_type}}
{{ radios(form.auth_type) }}
{{ page_footer("Continue") }}
{% endcall %}
</div>

View File

@@ -3,6 +3,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% from "components/radios.html" import radios %}
{% block service_page_title %}
Set data retention
@@ -16,7 +17,9 @@
{{ page_header('Set data retention') }}
{% call form_wrapper() %}
{{ form.notification_type }}
<div class="notification-type-radios">
{{ radios(form.notification_type) }}
</div>
{{ form.days_of_retention }}
{{ page_footer('Add') }}
{% endcall %}

View File

@@ -4,6 +4,7 @@
{% from "components/live-search.html" import live_search %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% from "components/radios.html" import radios %}
{% set page_title = "Link service to organization" %}
@@ -26,7 +27,9 @@
) }}
{% call form_wrapper(data_force_focus=True) %}
{% if has_organizations %}
{{ form.organizations }}
<div class="organizations-radios">
{{ radios(form.organizations) }}
</div>
{{ sticky_page_footer('Save') }}
{% else %}
<p class="hint"> No organizations </p>

View File

@@ -2,6 +2,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/select/macro.njk" import usaSelect -%}
{% from "components/radios.html" import radios %}
{% block per_page_title %}
Set up your profile
@@ -68,7 +69,7 @@ Set up your profile
]
})
}}-->
{{form.auth_type}}
{{ radios(form.auth_type) }}
{{ page_footer("Save") }}
{% endcall %}
</div>

View File

@@ -1,3 +1,5 @@
{% from "components/checkboxes.html" import checkboxes %}
{% macro format_item_name(name, separators=True) -%}
{%- if name is string -%}
{{- name -}}

View File

@@ -2,6 +2,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% from "components/radios.html" import radios %}
{% block service_page_title %}
{{ sender_context.title }}
@@ -15,20 +16,11 @@
<div class="grid-row">
{% call form_wrapper() %}
{{ form.sender(param_extensions={
'fieldset': {
'legend': {
'isPageHeading': True,
'text': sender_context.title
}
},
'classes': 'grid-col-9'
}) }}
{{ radios(form.sender, legend_style='usa-legend--large', option_hints=option_hints) }}
<div class="grid-col-9">
{{ page_footer('Continue') }}
</div>
{% endcall %}
</div>
</div>
{% endblock %}

View File

@@ -2,6 +2,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% from "components/radios.html" import radios %}
{% set page_title = 'Set letter contact block' %}
@@ -17,19 +18,10 @@
<div class="grid-row">
{% call form_wrapper() %}
{{ form.sender(param_extensions={
'fieldset': {
'legend': {
'isPageHeading': True,
'text': page_title
}
},
'classes': 'grid-col-9'
}) }}
{{ radios(form.sender) }}
<div class="grid-col-9">
{{ page_footer('Continue') }}
<a class="usa-link" href="{{ url_for('.service_add_letter_contact', service_id=current_service.id, from_template=template_id) }}">Add new sender</a>
</div>
</div>
{% endcall %}
</div>