diff --git a/app/assets/javascript/modal.js b/app/assets/javascript/modal.js
index 671e4119..355df9b4 100644
--- a/app/assets/javascript/modal.js
+++ b/app/assets/javascript/modal.js
@@ -194,12 +194,15 @@ class AppModal {
// forgot 'parentLayout or'. Bail out to a direct navigation rather than
// injecting the full site into the modal.
if (this.isFullPage(html)) {
+ // Capture the destination before close() — close() resets _loadUrl to
+ // null, so reading it after would navigate to a literal "null" URL.
+ const dest = this._loadUrl
console.warn(
'Modal: full page returned — falling back to direct navigation',
- this._loadUrl
+ dest
)
this.close()
- window.location.href = this._loadUrl
+ window.location.href = dest
return
}
diff --git a/app/assets/sass/components/_annotate-v2.scss b/app/assets/sass/components/_annotate-v2.scss
index 8ce421e0..94e2ea33 100644
--- a/app/assets/sass/components/_annotate-v2.scss
+++ b/app/assets/sass/components/_annotate-v2.scss
@@ -335,6 +335,7 @@ $ann-marker-shadow:
// Cursor preview: yellow circle+plus that follows the mouse on image panels
.app-ann-cursor-preview {
position: absolute;
+ z-index: 4; // above zoom button (z-index: 3) and active markers (z-index: 2)
width: $ann-marker-size;
height: $ann-marker-size;
border: $ann-marker-border-width solid $nhsuk-focus-colour;
diff --git a/app/lib/generators/medical-information/symptoms-generator.js b/app/lib/generators/medical-information/symptoms-generator.js
index 24b3b83f..4e79f84c 100644
--- a/app/lib/generators/medical-information/symptoms-generator.js
+++ b/app/lib/generators/medical-information/symptoms-generator.js
@@ -199,7 +199,7 @@ const generateSymptom = (options = {}) => {
const dateTypeWeights = {
...Object.fromEntries(DATE_RANGE_OPTIONS.map((range) => [range, 0.1])),
dateKnown: 0.3,
- notSure: 0.1
+ notKnown: 0.1
}
// Generate basic symptom data matching form structure
@@ -332,16 +332,16 @@ const generateSymptom = (options = {}) => {
}
}
- // 20% chance of additional info
+ // 20% chance of symptom notes
if (Math.random() < 0.2) {
- const additionalInfoOptions = [
+ const symptomNotesOptions = [
'Noticed during self-examination',
'Partner noticed the change',
'Gets worse during certain times of month',
'No family history of breast problems',
'Concerned as mother had similar symptoms'
]
- symptom.additionalInfo = faker.helpers.arrayElement(additionalInfoOptions)
+ symptom.symptomNotes = faker.helpers.arrayElement(symptomNotesOptions)
}
return symptom
diff --git a/app/lib/generators/participant-generator.js b/app/lib/generators/participant-generator.js
index 63d08361..c8c2c1be 100644
--- a/app/lib/generators/participant-generator.js
+++ b/app/lib/generators/participant-generator.js
@@ -103,20 +103,20 @@ const generatePhoneNumbers = () => {
})
const result = {
- mobilePhone: null,
- homePhone: null
+ phone1: null,
+ phone2: null
}
switch (phoneConfig) {
case 'mobile_only':
- result.mobilePhone = generateUKMobileNumber()
+ result.phone1 = generateUKMobileNumber()
break
case 'both':
- result.mobilePhone = generateUKMobileNumber()
- result.homePhone = generateUKHomeNumber()
+ result.phone1 = generateUKMobileNumber()
+ result.phone2 = generateUKHomeNumber()
break
case 'home_only':
- result.homePhone = generateUKHomeNumber()
+ result.phone2 = generateUKHomeNumber()
break
}
@@ -216,8 +216,8 @@ const generateParticipant = ({
lastName: faker.person.lastName(),
dateOfBirth: generateDateOfBirth(participantRiskLevel),
address: generateBSUAppropriateAddress(assignedBSU),
- mobilePhone: phoneNumbers.mobilePhone,
- homePhone: phoneNumbers.homePhone,
+ phone1: phoneNumbers.phone1,
+ phone2: phoneNumbers.phone2,
email: `${faker.internet.username().toLowerCase()}@example.com`,
ethnicGroup: ethnicityData.ethnicGroup,
ethnicBackground: ethnicityData.ethnicBackground
diff --git a/app/lib/utils/prior-mammograms.js b/app/lib/utils/prior-mammograms.js
index 2dc56105..86d753aa 100644
--- a/app/lib/utils/prior-mammograms.js
+++ b/app/lib/utils/prior-mammograms.js
@@ -129,21 +129,19 @@ const summarisePriorMammogram = (mammogram, options = {}) => {
let location = ''
switch (mammogram.location) {
case 'bsu':
- location = mammogram.bsu || 'NHS breast screening unit'
+ location = 'At another BSU'
break
case 'otherUk':
- location = mammogram.otherUk || 'Other UK location'
+ location = 'Elsewhere in the UK'
break
case 'otherNonUk':
- location = mammogram.otherNonUk
- ? `Outside UK: ${mammogram.otherNonUk}`
- : 'Outside UK'
+ location = 'Outside the UK'
break
case 'currentBsu':
- location = unitName || 'Current BSU'
+ location = `At ${unitName || 'this BSU'}`
break
case 'preferNotToSay':
- location = 'Location not given'
+ location = 'Location not provided'
break
default:
location = ''
@@ -152,14 +150,14 @@ const summarisePriorMammogram = (mammogram, options = {}) => {
// Date detail — combine formatted date and relative time into parenthesised suffix
const dateParts = []
if (mammogram.dateType === 'dateKnown' && mammogram.dateTaken) {
- dateParts.push(formatDate(mammogram.dateTaken, 'MMMM YYYY'))
+ dateParts.push(formatDate(mammogram.dateTaken, 'MMM YYYY'))
if (mammogram._rawDate) {
dateParts.push(formatRelativeDate(mammogram._rawDate))
}
} else if (mammogram.dateType === 'moreThanSixMonths') {
- dateParts.push(mammogram.approximateDate || 'over 6 months ago')
+ dateParts.push('over 6 months ago')
} else if (mammogram.dateType === 'lessThanSixMonths') {
- dateParts.push(mammogram.approximateDate || 'less than 6 months ago')
+ dateParts.push('less than 6 months ago')
}
const dateDetail = dateParts.length > 0 ? `(${dateParts.join(', ')})` : ''
diff --git a/app/lib/utils/reading.js b/app/lib/utils/reading.js
index acc88ace..491b3b23 100644
--- a/app/lib/utils/reading.js
+++ b/app/lib/utils/reading.js
@@ -1366,6 +1366,16 @@ const shouldShowComparePage = function (
* @param {object} [options] - Options for determining eligibility
* @returns {boolean} Whether the current user can read this event
*/
+/**
+ * Check if an event has been deferred from reading
+ *
+ * @param {object} event - The event to check
+ * @returns {boolean} Whether the event has been deferred
+ */
+const isDeferred = (event) => {
+ return !!event?.imageReading?.deferral?.deferredAt
+}
+
const canUserReadEvent = function (event, userId = null, options = {}) {
const { maxReadsPerEvent = 2 } = options
@@ -1383,6 +1393,11 @@ const canUserReadEvent = function (event, userId = null, options = {}) {
return false
}
+ // Can't read if event has been deferred
+ if (isDeferred(event)) {
+ return false
+ }
+
const metadata = getReadingMetadata(event)
// If we already have enough unique readers, no more reads needed
@@ -1821,17 +1836,23 @@ const getSessionReadingProgress = (
const resolvedTargetSize = session.targetSize || sessionEvents.length
+ // Count deferred events so they count toward the session target
+ const deferredCount = sessionEvents.filter(isDeferred).length
+
return {
...progress,
// How many events are currently loaded vs the overall target
populatedCount: sessionEvents.length,
targetSize: resolvedTargetSize,
+ // Deferred events count as 'done' for session progress purposes
+ deferredCount,
// Remaining reads against the target (not just currently loaded events)
targetRemaining: Math.max(
0,
resolvedTargetSize -
progress.userReadCount -
- progress.userAwaitingPriorsCount
+ progress.userAwaitingPriorsCount -
+ deferredCount
)
}
}
@@ -1884,6 +1905,7 @@ module.exports = {
// Booleans
userHasReadEvent,
canUserReadEvent,
+ isDeferred,
hasReads,
needsArbitration,
needsFirstRead,
diff --git a/app/lib/utils/status.js b/app/lib/utils/status.js
index 37e833ab..6937927e 100644
--- a/app/lib/utils/status.js
+++ b/app/lib/utils/status.js
@@ -283,6 +283,7 @@ const getStatusTagColour = (status) => {
'prior_pending': 'orange',
'prior_requested': 'yellow',
'priors_requested': 'yellow',
+ 'deferred': 'orange',
'prior_received': 'green',
'prior_not_available': 'grey',
'prior_not_needed': 'grey'
diff --git a/app/lib/utils/strings.js b/app/lib/utils/strings.js
index 5e58181c..f142468b 100644
--- a/app/lib/utils/strings.js
+++ b/app/lib/utils/strings.js
@@ -325,6 +325,8 @@ const formatPhoneNumber = (phoneNumber) => {
if (!phoneNumber) return ''
if (typeof phoneNumber !== 'string') return phoneNumber
+ phoneNumber = phoneNumber.replace(/\s/g, '')
+
if (phoneNumber.startsWith('07')) {
return `${phoneNumber.slice(0, 5)} ${phoneNumber.slice(5)}`
}
diff --git a/app/routes/events.js b/app/routes/events.js
index 1f5e5bd2..9ea633be 100644
--- a/app/routes/events.js
+++ b/app/routes/events.js
@@ -804,6 +804,17 @@ module.exports = (router) => {
return res.redirect(modalBreakout(`/clinics/${clinicId}/`))
}
+ // Normalise approximateDate in session now, before any redirect, so the
+ // warning page doesn't display a raw array (e.g. ",June 2025") caused by
+ // both conditional inputs being submitted together.
+ if (
+ previousMammogramTemp &&
+ Array.isArray(previousMammogramTemp.approximateDate)
+ ) {
+ previousMammogramTemp.approximateDate =
+ previousMammogramTemp.approximateDate.find((v) => v) || ''
+ }
+
// Check if this is a recent mammogram (within 6 months)
const isRecentMammogram = checkIfRecentMammogram(previousMammogramTemp)
@@ -1131,17 +1142,12 @@ module.exports = (router) => {
})
}
- // Validate whether the symptom has been investigated (required)
- if (!data.event?.symptomTemp?.hasBeenInvestigated) {
- validationErrors.push({
- name: 'event[symptomTemp][hasBeenInvestigated]',
- text: 'Select whether this has been investigated',
- href: '#hasBeenInvestigated'
- })
- } else if (
- data.event.symptomTemp.hasBeenInvestigated === 'yes' &&
- !data.event.symptomTemp.investigatedDescription
- ) {
+ // Validate investigation details if the checkbox is checked
+ const hasBeenInvestigated = data.event?.symptomTemp?.hasBeenInvestigated
+ const isInvestigated = Array.isArray(hasBeenInvestigated)
+ ? hasBeenInvestigated.includes('yes')
+ : hasBeenInvestigated === 'yes'
+ if (isInvestigated && !data.event?.symptomTemp?.investigatedDescription) {
validationErrors.push({
name: 'event[symptomTemp][investigatedDescription]',
text: 'Provide details of the investigation',
@@ -1210,8 +1216,7 @@ module.exports = (router) => {
id: symptomTemp.id || generateId(),
type: symptomType,
dateType: symptomTemp.dateType,
- hasBeenInvestigated: symptomTemp.hasBeenInvestigated,
- additionalInfo: symptomTemp.additionalInfo
+ symptomNotes: symptomTemp.symptomNotes
}
// For new symptoms, add the creation timestamp
@@ -1229,8 +1234,13 @@ module.exports = (router) => {
}
}
- // Add investigation details if investigated
- if (symptomTemp.hasBeenInvestigated === 'yes') {
+ // Normalise checkbox value and add investigation details if checked
+ const savedHasBeenInvestigated = symptomTemp.hasBeenInvestigated
+ const savedIsInvestigated = Array.isArray(savedHasBeenInvestigated)
+ ? savedHasBeenInvestigated.includes('yes')
+ : savedHasBeenInvestigated === 'yes'
+ symptom.hasBeenInvestigated = savedIsInvestigated ? 'yes' : 'no'
+ if (savedIsInvestigated) {
symptom.investigatedDescription = symptomTemp.investigatedDescription
}
@@ -1247,7 +1257,7 @@ module.exports = (router) => {
].includes(symptomTemp.dateType)
) {
symptom.approximateDuration = symptomTemp.dateType
- } else if (symptomTemp.dateType === 'notSure') {
+ } else if (symptomTemp.dateType === 'notKnown') {
delete symptom.approximateDuration
}
@@ -3342,6 +3352,17 @@ module.exports = (router) => {
res.redirect(modalBreakout(returnUrl))
}
)
+ // Save participant data when contact details are updated from the participant tab.
+ // The contact-details form posts back to the participant tab URL via referrerChain,
+ // so we need this POST handler to persist the temp participant to the participants array.
+ router.post('/clinics/:clinicId/events/:eventId/participant', (req, res) => {
+ const { clinicId, eventId } = req.params
+ const data = req.session.data
+ saveTempParticipantToParticipant(data)
+ req.flash('success', 'Participant details updated')
+ res.redirect(`/clinics/${clinicId}/events/${eventId}/participant`)
+ })
+
// General purpose dynamic template route for events
// This should come after any more specific routes
router.get(
diff --git a/app/routes/reading.js b/app/routes/reading.js
index 919c95cb..3631637b 100644
--- a/app/routes/reading.js
+++ b/app/routes/reading.js
@@ -40,9 +40,8 @@ module.exports = (router) => {
// Reading index — choose layout based on setting
router.get('/reading', (req, res) => {
const layout = req.session.data?.settings?.reading?.indexLayout || 'simple'
- const template = layout === 'complex'
- ? 'reading/index-complex'
- : 'reading/index-simple'
+ const template =
+ layout === 'complex' ? 'reading/index-complex' : 'reading/index-simple'
res.render(template)
})
@@ -550,6 +549,14 @@ module.exports = (router) => {
)
}
+ // Check if event has been deferred from reading
+ const { isDeferred } = require('../lib/utils/reading')
+ if (isDeferred(event)) {
+ return res.redirect(
+ `/reading/session/${sessionId}/events/${eventId}/existing-read`
+ )
+ }
+
// Delete temporary data from previous steps
delete data.imageReadingTemp
@@ -653,12 +660,16 @@ module.exports = (router) => {
editHref: `/reading/session/${sessionId}/events/${eventId}/existing-read`
}
res.redirect(
- `/reading/session/${sessionId}/events/${nextUnreadEvent.id}`
+ modalBreakout(
+ `/reading/session/${sessionId}/events/${nextUnreadEvent.id}`
+ )
)
} else if (session.skippedEvents.length > 0) {
- res.redirect(`/reading/session/${sessionId}/skipped-review`)
+ res.redirect(
+ modalBreakout(`/reading/session/${sessionId}/skipped-review`)
+ )
} else {
- res.redirect(`/reading/session/${sessionId}`)
+ res.redirect(modalBreakout(`/reading/session/${sessionId}`))
}
}
)
@@ -698,6 +709,143 @@ module.exports = (router) => {
}
)
+ /************************************************************************
+ // Case deferral
+ /***********************************************************************/
+
+ // Handle deferring a case from reading
+ router.post(
+ '/reading/session/:sessionId/events/:eventId/defer-case-answer',
+ (req, res) => {
+ const data = req.session.data
+ const { sessionId, eventId } = req.params
+ const currentUserId = data.currentUser?.id
+
+ const reason = req.body.deferralReason || ''
+
+ // Find the event and save deferral data
+ const event = data.events.find((e) => e.id === eventId)
+ if (event) {
+ if (!event.imageReading) {
+ event.imageReading = {}
+ }
+
+ // Remove any existing read by this user — deferral replaces a prior opinion
+ if (event.imageReading.reads?.[currentUserId]) {
+ delete event.imageReading.reads[currentUserId]
+ }
+
+ event.imageReading.deferral = {
+ deferredAt: new Date().toISOString(),
+ deferredBy: currentUserId,
+ reason: reason || null
+ }
+
+ // Also update the mirrored event in data.event
+ if (data.event && data.event.id === eventId) {
+ data.event.imageReading = event.imageReading
+ }
+ }
+
+ // Top up the session with the next eligible event if under target size
+ topUpSession(data, sessionId)
+
+ // Find next readable event after current position
+ const session = getReadingSession(data, sessionId)
+ const sessionEvents = session.eventIds
+ .map((id) => data.events.find((e) => e.id === id))
+ .filter(Boolean)
+ const nextUnreadEvent = getNextUserReadableEvent(
+ sessionEvents,
+ eventId,
+ currentUserId,
+ { wrap: false }
+ )
+
+ // Show a banner on the next case if there is one
+ if (nextUnreadEvent) {
+ const participant = data.participants.find(
+ (person) => person.id === event?.participantId
+ )
+ const shortName = getShortName(participant)
+ data.readingOpinionBanner = {
+ text: `Case deferred for ${shortName}`,
+ participantName: shortName,
+ editHref: `/reading/session/${sessionId}/events/${eventId}/existing-read`
+ }
+ res.redirect(
+ modalBreakout(
+ `/reading/session/${sessionId}/events/${nextUnreadEvent.id}`
+ )
+ )
+ } else if (session.skippedEvents.length > 0) {
+ res.redirect(
+ modalBreakout(`/reading/session/${sessionId}/skipped-review`)
+ )
+ } else {
+ res.redirect(modalBreakout(`/reading/session/${sessionId}`))
+ }
+ }
+ )
+
+ // Undo a case deferral — removes the deferral so the case returns to reading
+ router.all(
+ '/reading/session/:sessionId/events/:eventId/undo-defer',
+ (req, res) => {
+ const data = req.session.data
+ const { sessionId, eventId } = req.params
+
+ const event = data.events.find((e) => e.id === eventId)
+ if (event?.imageReading?.deferral) {
+ delete event.imageReading.deferral
+
+ // Also update the mirrored event in data.event
+ if (data.event && data.event.id === eventId) {
+ data.event.imageReading = event.imageReading
+ }
+ }
+
+ res.redirect(`/reading/session/${sessionId}/events/${eventId}/opinion`)
+ }
+ )
+
+ // Deferred cases management page
+ router.get('/reading/deferred', (req, res) => {
+ res.render('reading/deferred')
+ })
+
+ // Unflag a deferral from the deferred cases management page
+ // Keeps a record of the resolved deferral so the reason stays visible
+ router.post('/reading/deferred/undo', (req, res) => {
+ const data = req.session.data
+ const { eventId } = req.body
+
+ const event = data.events.find((e) => e.id === eventId)
+ if (event?.imageReading?.deferral) {
+ if (!event.imageReading.deferralHistory) {
+ event.imageReading.deferralHistory = []
+ }
+ event.imageReading.deferralHistory.push({
+ ...event.imageReading.deferral,
+ resolvedAt: new Date().toISOString(),
+ resolvedBy: data.currentUser?.id
+ })
+ delete event.imageReading.deferral
+
+ if (data.event && data.event.id === eventId) {
+ data.event.imageReading = event.imageReading
+ }
+
+ const participant = data.participants.find(
+ (p) => p.id === event.participantId
+ )
+ const shortName = getShortName(participant)
+ req.flash('success', `${shortName} returned to reading queue`)
+ }
+
+ res.redirect('/reading/deferred')
+ })
+
// Render appropriate template for reading views
router.get(
'/reading/session/:sessionId/events/:eventId/:step',
@@ -719,6 +867,7 @@ module.exports = (router) => {
'existing-read',
'compare',
'request-priors',
+ 'defer-case',
'medical-information'
]
@@ -1311,7 +1460,8 @@ module.exports = (router) => {
for (const side of ['right', 'left']) {
const assessment = side === 'right' ? rightAssessment : leftAssessment
- const annotations = side === 'right' ? rightAnnotations : leftAnnotations
+ const annotations =
+ side === 'right' ? rightAnnotations : leftAnnotations
const sideLabel = side
if (!assessment) continue
@@ -1352,8 +1502,7 @@ module.exports = (router) => {
})
}
}
- }
- else if (assessment === 'normal' || assessment === 'clinical') {
+ } else if (assessment === 'normal' || assessment === 'clinical') {
// Normal/clinical breast must not have annotations of M3 or higher
if (highLevelAnnotations.length > 0) {
errors.push({
diff --git a/app/views/_includes/forms/contact-details.njk b/app/views/_includes/forms/contact-details.njk
index e42d1b68..00a50037 100644
--- a/app/views/_includes/forms/contact-details.njk
+++ b/app/views/_includes/forms/contact-details.njk
@@ -74,24 +74,24 @@
{{ input({
label: {
- text: "Mobile (optional)",
+ text: "Phone number 1 (optional)",
_classes: "nhsuk-label--m"
},
- value: participant.demographicInformation.mobilePhone,
- id: "mobile-phone-number",
- name: "participant[demographicInformation][mobilePhone]",
+ value: participant.demographicInformation.phone1,
+ id: "phone-number-1",
+ name: "participant[demographicInformation][phone1]",
classes: "nhsuk-u-width-one-half"
}) }}
{{ input({
label: {
- text: "Home (optional)",
+ text: "Phone number 2 (optional)",
_classes: "nhsuk-label--m"
},
- value: participant.demographicInformation.homePhone,
- id: "home-phone-number",
- name: "participant[demographicInformation][homePhone]",
+ value: participant.demographicInformation.phone2,
+ id: "phone-number-2",
+ name: "participant[demographicInformation][phone2]",
classes: "nhsuk-u-width-one-half"
}) }}
diff --git a/app/views/_includes/medical-information/index.njk b/app/views/_includes/medical-information/index.njk
index eedbcb8e..b0849ca3 100644
--- a/app/views/_includes/medical-information/index.njk
+++ b/app/views/_includes/medical-information/index.njk
@@ -12,7 +12,7 @@
{# Mammogram history #}
{% set sectionHeading = "Mammogram history" %}
-{% set subHeading = "The last confirmed mammogram and any added manually since then" %}
+{% set subHeading = "Previous mammograms from screening records and any reported by the participant" %}
{% set sectionId = sectionHeading | kebabCase %}
{% set scrollTo = sectionId %}
@@ -275,4 +275,4 @@
html: otherRelevantInformationHtml,
status: "To review"
}) }}
-{% endswitch %}
\ No newline at end of file
+{% endswitch %}
diff --git a/app/views/_includes/medical-information/mammogram-history.njk b/app/views/_includes/medical-information/mammogram-history.njk
index da6e6e47..46b52967 100644
--- a/app/views/_includes/medical-information/mammogram-history.njk
+++ b/app/views/_includes/medical-information/mammogram-history.njk
@@ -3,9 +3,6 @@
{% set hasAdditionalMammograms = event.previousMammograms | length > 0 %}
{# System record - last known mammogram from BSU records #}
-{% if hasAdditionalMammograms %}
-
From screening records
-{% endif %}
{% set systemRecordHtml %}
{% set mostRecentClinic = data | getParticipantMostRecentClinic(participant.id) %}
@@ -15,7 +12,7 @@
{{ mostRecentClinic.location.name }}
{{ mostRecentClinic.event.type | sentenceCase }}
{% else %}
- {{ "Not known" | asHint }}
+ {{ "No information" | asHint }}
{% endif %}
{% endset %}
@@ -23,7 +20,7 @@
rows: [
{
key: {
- text: "Last known mammogram"
+ text: "Most recent mammogram on record"
},
value: {
html: systemRecordHtml
@@ -126,4 +123,4 @@
{{ summaryList({
rows: userMammogramRows
} | openInModal | removeLastRowBorder) }}
-{% endif %}
\ No newline at end of file
+{% endif %}
diff --git a/app/views/_includes/reading/reading-status-bar.njk b/app/views/_includes/reading/reading-status-bar.njk
index 1cb32a52..39623ce4 100644
--- a/app/views/_includes/reading/reading-status-bar.njk
+++ b/app/views/_includes/reading/reading-status-bar.njk
@@ -32,6 +32,9 @@
{%- if progress.userAwaitingPriorsCount > 0 -%}
, {{ progress.userAwaitingPriorsCount }} awaiting priors
{%- endif -%}
+ {%- if progress.deferredCount > 0 -%}
+ , {{ progress.deferredCount }} deferred
+ {%- endif -%}
, {{ progress.targetRemaining }} remaining
{%- if progress.skippedEvents | length > 0 %}
({{ progress.skippedEvents | length }} skipped)
diff --git a/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk b/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk
index 6b4ca60a..fe32d5b4 100644
--- a/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk
+++ b/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk
@@ -86,34 +86,35 @@
{{ symptom.dateStarted | formatMonthYear }} ({{ symptom.dateStarted | formatRelativeDate }})
{% elseif symptom.approximateDuration %}
{{ symptom.approximateDuration }} ago
- {% elseif symptom.dateType == 'notSure' %}
- not sure
+ {% elseif symptom.dateType == 'notKnown' %}
+ not known
{% else %}
not provided
{% endif %}
{% endset %}
{% set valueLines = valueLines | push(startText) %}
- {# Stop date if applicable #}
+ {# Additional symptom information #}
{% if symptom.isIntermittent %}
{% set valueLines = valueLines | push("Symptom is intermittent") %}
{% endif %}
- {# Stop date if applicable #}
{% if symptom.hasStopped and symptom.approximateDateStopped %}
- {% set valueLines = valueLines | push("Stopped: " + symptom.approximateDateStopped) %}
+ {% set valueLines = valueLines | push("Recently resolved (" + symptom.approximateDateStopped + ")") %}
{% endif %}
{# Investigation status #}
- {% if symptom.hasBeenInvestigated == "yes" and symptom.investigatedDescription %}
- {% set valueLines = valueLines | push("Investigated: " + symptom.investigatedDescription) %}
- {% elseif symptom.hasBeenInvestigated == "no" %}
- {% set valueLines = valueLines | push("Not investigated") %}
+ {% if symptom.hasBeenInvestigated == "yes" %}
+ {% if symptom.investigatedDescription %}
+ {% set valueLines = valueLines | push("Previously investigated: " + symptom.investigatedDescription) %}
+ {% else %}
+ {% set valueLines = valueLines | push("Previously investigated") %}
+ {% endif %}
{% endif %}
- {# Additional info #}
- {% if symptom.additionalInfo %}
- {% set valueLines = valueLines | push("Additional info: " + symptom.additionalInfo) %}
+ {# Symptom notes #}
+ {% if symptom.symptomNotes %}
+ {% set valueLines = valueLines | push("Notes: " + symptom.symptomNotes) %}
{% endif %}
{# Join all value lines with line breaks #}
diff --git a/app/views/_includes/summary-lists/rows/phone-numbers.njk b/app/views/_includes/summary-lists/rows/phone-numbers.njk
index 345eebdd..9aee4346 100644
--- a/app/views/_includes/summary-lists/rows/phone-numbers.njk
+++ b/app/views/_includes/summary-lists/rows/phone-numbers.njk
@@ -1,6 +1,6 @@
{# /app/views/_includes/summary-lists/rows/phone-numbers.njk #}
-{% set phoneNumbers = [participant.demographicInformation.mobilePhone, participant.demographicInformation.homePhone] | removeEmpty %}
+{% set phoneNumbers = [participant.demographicInformation.phone1, participant.demographicInformation.phone2] | removeEmpty %}
{% set phoneNumbersHtml %}
{{ phoneNumbers | map("formatPhoneNumber") | join(" ") | safe }}
diff --git a/app/views/events/medical-information/symptoms/details.html b/app/views/events/medical-information/symptoms/details.html
index eda86e94..771c23ee 100644
--- a/app/views/events/medical-information/symptoms/details.html
+++ b/app/views/events/medical-information/symptoms/details.html
@@ -467,13 +467,11 @@
}) %}
{% set dateRadioItems = dateRadioItems | push({
- value: "notSure",
- text: "Not sure"
+ value: "notKnown",
+ text: "Not known"
}) %}
-
-
- {# Radios for when were they taken - choices 'Date known' and 'Enter approximate date' and 'Not sure' #}
+ {# Radios for when were they taken - choices 'Date known' and 'Enter approximate date' and 'Not known' #}
{{ radios({
idPrefix: "dateType",
name: "event[symptomTemp][dateType]",
@@ -503,18 +501,38 @@
} | populateErrors) }}
{% endset %}
- {# TODO: don't use br for spacing! #}
-
+ {% set investigatedDescriptionHtml %}
+ {{ textarea({
+ id: "investigatedDescription",
+ name: "event[symptomTemp][investigatedDescription]",
+ label: {
+ text: "Provide details"
+ },
+ hint: {
+ text: "Include where, when and the outcome"
+ },
+ value: event.symptomTemp.investigatedDescription
+ } | populateErrors) }}
+ {% endset %}
-
+ {% call fieldset({
+ legend: {
+ text: "Additional symptom information",
+ size: "m",
+ isPageHeading: false
+ }
+ }) %}
{{ checkboxes({
idPrefix: "isIntermittent",
name: "event[symptomTemp][isIntermittent]",
+ formGroup: {
+ classes: "nhsuk-u-margin-bottom-3"
+ },
items: [
{
value: "yes",
- text: "The symptom is intermittent",
+ text: "Intermittent",
checked: true if event.symptomTemp.isIntermittent else false
}
]
@@ -523,10 +541,13 @@
{{ checkboxes({
idPrefix: "hasStopped",
name: "event[symptomTemp][hasStopped]",
+ formGroup: {
+ classes: "nhsuk-u-margin-bottom-3"
+ },
items: [
{
value: "yes",
- text: "The symptom has recently resolved",
+ text: "Recently resolved",
checked: true if event.symptomTemp.hasStopped else false,
conditional: {
html: stymptomStoppedHtml
@@ -535,42 +556,22 @@
]
}) }}
- {{ radios({
- idPrefix: "hasBeenInvestigated",
- name: "event[symptomTemp][hasBeenInvestigated]",
- value: event.symptomTemp.hasBeenInvestigated,
- fieldset: {
- legend: {
- text: "Has this been investigated?",
- size: "m",
- isPageHeading: false
- }
- },
- items: [
- {
- value: "yes",
- text: "Yes",
- conditional: {
- html: textarea({
- id: "investigatedDescription",
- name: "event[symptomTemp][investigatedDescription]",
- label: {
- text: "Provide details"
- },
- hint: {
- text: "Include where, when and the outcome"
- },
- value: event.symptomTemp.investigatedDescription,
- _classes: "nhsuk-u-width-two-thirds"
- } | populateErrors)
+ {{ checkboxes({
+ idPrefix: "hasBeenInvestigated",
+ name: "event[symptomTemp][hasBeenInvestigated]",
+ values: event.symptomTemp.hasBeenInvestigated,
+ items: [
+ {
+ value: "yes",
+ text: "Investigated by a medical professional",
+ conditional: {
+ html: investigatedDescriptionHtml
+ }
}
- },
- {
- value: "no",
- text: "No"
- }
- ]
- } | populateErrors) }}
+ ]
+ }) }}
+
+ {% endcall %}
{# Only show if not significant by default #}
{% if not symptomType.isSignificantByDefault %}
@@ -611,29 +612,16 @@
]
} | populateErrors) }}
- {# {{ checkboxes({
- idPrefix: "isSignificant",
- name: "event[symptomTemp][isSignificant]",
- items: [
- {
- value: "yes",
- text: "Highlight this symptom to image readers",
- checked: true if event.symptomTemp.isSignificant else false
- }
- ]
- }) }} #}
{% endif %}
-
-
{{ textarea({
- name: "event[symptomTemp][additionalInfo]",
+ name: "event[symptomTemp][symptomNotes]",
label: {
- text: "Additional info (optional)",
+ text: "Symptom notes (optional)",
size: "m"
},
rows: 4,
- value: event.symptomTemp.additionalInfo
+ value: event.symptomTemp.symptomNotes
}) }}
diff --git a/app/views/events/previous-mammograms/appointment-should-not-take-place.html b/app/views/events/previous-mammograms/appointment-should-not-take-place.html
new file mode 100644
index 00000000..8f1c660f
--- /dev/null
+++ b/app/views/events/previous-mammograms/appointment-should-not-take-place.html
@@ -0,0 +1,66 @@
+{# app/views/events/previous-mammograms/appointment-should-not-begin.html #}
+
+{% extends parentLayout or 'layout-appointment.html' %}
+
+{% set previousMammogramCount = event.previousMammograms | length %}
+
+{% set pageHeading = "This appointment should not take place" %}
+
+{% set formAction = './save' | urlWithReferrer(referrerChain, query.scrollTo) %}
+
+{% block pageContent %}
+
+ {% set previousMammograms = event.previousMammograms %}
+
+ {% set unit = data.breastScreeningUnits | findById(clinic.breastScreeningUnitId) %}
+
+
+
+ {{ participant | getFullName }}
+
+ {{ pageHeading }}
+
+
+
+ There is a mammogram on this participant's record from within the last 6 months. Breast x-rays should not be taken within 6 months of a previous mammogram.
+
+
+{% set mammogramHistoryHtml %}
+ {% include "_includes/medical-information/mammogram-history.njk" %}
+{% endset %}
+
+ {{ radios({
+ name: "event[appointmentStopped][needsReschedule]",
+ value: event.appointmentStopped.needsReschedule,
+ fieldset: {
+ legend: {
+ text: "Should the appointment be rescheduled?",
+ size: "m",
+ isPageHeading: false
+ }
+ },
+ items: [
+ {
+ value: "yes",
+ text: "Yes"
+ },
+ {
+ value: "no-invite",
+ text: "No, invite to next routine appointment"
+ }
+ ]
+ } | populateErrors) }}
+
+ {# Prevents redirect loop - signals to the save route that we've already shown this warning page #}
+
+
+
+ {{ button({
+ text: "Continue"
+ }) }}
+
+
+
+ Proceed with this appointment
+
+{% endblock %}
diff --git a/app/views/events/previous-mammograms/form.html b/app/views/events/previous-mammograms/form.html
index e1a9f166..78098e9b 100644
--- a/app/views/events/previous-mammograms/form.html
+++ b/app/views/events/previous-mammograms/form.html
@@ -289,7 +289,7 @@
},
value: event.previousMammogramTemp.otherDetails,
hint: {
- text: "For example, the reason for the mammograms and the outcome of the assessment"
+ text: "For example, the reason for the mammogram, the participant's previous address, and the outcome of the assessment"
}
}) }}
diff --git a/app/views/reading/deferred.html b/app/views/reading/deferred.html
new file mode 100644
index 00000000..22398762
--- /dev/null
+++ b/app/views/reading/deferred.html
@@ -0,0 +1,168 @@
+{# app/views/reading/deferred.html #}
+
+{% extends 'layout-app.html' %}
+
+{% from '_components/summary-list/macro.njk' import appSummaryList %}
+
+{% set pageHeading = "Deferred cases" %}
+{% set gridColumn = "nhsuk-grid-column-two-thirds" %}
+
+{% set back = {
+ href: "/reading",
+ text: "Back"
+} %}
+
+{% block pageContent %}
+
+ {# Get all events that have been deferred #}
+ {% set deferredEvents = [] %}
+ {% for thisEvent in data.events %}
+ {% if thisEvent | isDeferred %}
+ {% set deferredEvents = deferredEvents | push(thisEvent) %}
+ {% endif %}
+ {% endfor %}
+
+ {# Sort by deferral date, most recent first #}
+ {% set deferredEvents = deferredEvents | sort(true, false, 'imageReading.deferral.deferredAt') %}
+
+ {# Collect resolved deferrals across all events, most recently resolved first #}
+ {% set resolvedDeferrals = [] %}
+ {% for thisEvent in data.events %}
+ {% for pastDeferral in thisEvent.imageReading.deferralHistory %}
+ {% set resolvedDeferrals = resolvedDeferrals | push({ event: thisEvent, deferral: pastDeferral }) %}
+ {% endfor %}
+ {% endfor %}
+ {% set resolvedDeferrals = resolvedDeferrals | sort(true, false, 'deferral.resolvedAt') %}
+
+ Image reading
+ {{ pageHeading }}
+
+ Cases deferred from reading require manual review before they can be returned to the reading queue.
+
+ {% if deferredEvents | length == 0 %}
+
No deferred cases.
+ {% else %}
+
+ {% for thisEvent in deferredEvents %}
+ {% set thisParticipant = data | getParticipant(thisEvent.participantId) %}
+ {% set deferral = thisEvent.imageReading.deferral %}
+
+ {% set screenedHtml %}
+ {% set daysSinceScreening = thisEvent.timing.startTime | daysSince %}
+ {% if daysSinceScreening >= data.config.reading.urgentThreshold %}
+ {{ "Urgent" | toTag }}
+ {% elseif daysSinceScreening >= data.config.reading.priorityThreshold %}
+ {{ "Due soon" | toTag }}
+ {% endif %}
+ {{ thisEvent.timing.startTime | formatDate }}
+
({{ thisEvent.timing.startTime | formatRelativeDate }})
+ {% endset %}
+
+ {% set deferredHtml %}
+ {{ deferral.deferredAt | formatDate("D MMM YYYY") }}
+
({{ deferral.deferredAt | formatRelativeDate }})
+ {% endset %}
+
+ {% set reasonHtml %}
+ {% if deferral.reason %}
+ {{ deferral.reason }}
+ {% else %}
+
No reason given
+ {% endif %}
+ {% if deferral.deferredBy %}
+
+
+ {{ deferral.deferredBy | getUsername({ format: "short", identifyCurrentUser: true }) }}
+
+ {% endif %}
+ {% endset %}
+
+
+
+
+ {{ appSummaryList({
+ rows: [
+ { key: { text: "Screened" }, value: { html: screenedHtml } },
+ { key: { text: "Deferred" }, value: { html: deferredHtml } },
+ { key: { text: "Reason" }, value: { html: reasonHtml } }
+ ]
+ }) }}
+
+
+ {% endfor %}
+
+ {% endif %}
+
+ {% if resolvedDeferrals | length > 0 %}
+
+
Recently resolved
+
These cases have been unflagged and returned to the reading queue.
+
+ {% for row in resolvedDeferrals %}
+ {% set thisEvent = row.event %}
+ {% set deferral = row.deferral %}
+ {% set thisParticipant = data | getParticipant(thisEvent.participantId) %}
+
+ {% set deferredHtml %}
+ {{ deferral.deferredAt | formatDate("D MMM YYYY") }}
+
({{ deferral.deferredAt | formatRelativeDate }})
+ {% endset %}
+
+ {% set reasonHtml %}
+ {% if deferral.reason %}
+ {{ deferral.reason }}
+ {% else %}
+
No reason given
+ {% endif %}
+ {% if deferral.deferredBy %}
+
+
+ {{ deferral.deferredBy | getUsername({ format: "short", identifyCurrentUser: true }) }}
+
+ {% endif %}
+ {% endset %}
+
+ {% set resolvedHtml %}
+ {{ deferral.resolvedAt | formatDate("D MMM YYYY") }}
+ {% if deferral.resolvedBy %}
+ by {{ deferral.resolvedBy | getUsername({ format: "short", identifyCurrentUser: true }) }}
+ {% endif %}
+ {% endset %}
+
+
+
+
+ {{ appSummaryList({
+ rows: [
+ { key: { text: "Deferred" }, value: { html: deferredHtml } },
+ { key: { text: "Reason" }, value: { html: reasonHtml } },
+ { key: { text: "Returned to queue" }, value: { html: resolvedHtml } }
+ ]
+ }) }}
+
+
+ {% endfor %}
+
+ {% endif %}
+
+{% endblock %}
diff --git a/app/views/reading/index-complex.html b/app/views/reading/index-complex.html
index 2ec79f03..5bd5475b 100644
--- a/app/views/reading/index-complex.html
+++ b/app/views/reading/index-complex.html
@@ -12,17 +12,21 @@
{{ pageHeading }}
Start new reading session
-{# Awaiting priors not automatically filtered #}
+{# Awaiting priors — count across all eligible events, not just those needing reads #}
+{% set awaitingPriorsEvents = [] %}
+{% for thisEvent in data.events | filterEventsByEligibleForReading %}
+ {% if thisEvent | awaitingPriors %}
+ {% set awaitingPriorsEvents = awaitingPriorsEvents | push(thisEvent) %}
+ {% endif %}
+{% endfor %}
+
{% set allReadsEventsWithAwaitingPriors = data.events | filterEventsByEligibleForReading | filterEventsByNeedsAnyRead | sortEventsByScreeningDate %}
-{# Split into awaiting priors and available for reading #}
+{# Split readable events into awaiting priors and available for reading #}
{# Events with 'requested' status mammograms are held from reading #}
{% set allReadsEvents = [] %}
-{% set awaitingPriorsEvents = [] %}
{% for thisEvent in allReadsEventsWithAwaitingPriors %}
- {% if thisEvent | awaitingPriors %}
- {% set awaitingPriorsEvents = awaitingPriorsEvents | push(thisEvent) %}
- {% else %}
+ {% if not (thisEvent | awaitingPriors) %}
{% set allReadsEvents = allReadsEvents | push(thisEvent) %}
{% endif %}
{% endfor %}
@@ -70,7 +74,7 @@
Start new reading session
{% endif %}
- {% set defaultSessionSize = 25 %}
+ {% set defaultSessionSize = data.settings.reading.defaultSessionSize or 25 %}
{% set maxCases = allReadCount if allReadCount < defaultSessionSize else defaultSessionSize %}
{% set actionLinkHtml %}
@@ -172,6 +176,14 @@ Other options
href: "/reading/priors"
}) }}
+
+ {{ card({
+ heading: "Deferred cases",
+ headingClasses: "nhsuk-heading-s",
+ clickable: true,
+ href: "/reading/deferred"
+ }) }}
+
{{ card({
heading: "Reading statistics",
diff --git a/app/views/reading/index-simple.html b/app/views/reading/index-simple.html
index 7e5bccab..21e702e5 100644
--- a/app/views/reading/index-simple.html
+++ b/app/views/reading/index-simple.html
@@ -7,7 +7,7 @@
{% set gridColumn = "none" %}
{% set currentUserId = data.currentUser.id %}
-{% set defaultSessionSize = 25 %}
+{% set defaultSessionSize = data.settings.reading.defaultSessionSize or 25 %}
{#
Build a list of the current user's sessions, most-recent first.
@@ -71,6 +71,20 @@
{% endif %}
{% endfor %}
+{% set deferredCount = 0 %}
+{% for thisEvent in data.events %}
+ {% if thisEvent | isDeferred %}
+ {% set deferredCount = deferredCount + 1 %}
+ {% endif %}
+{% endfor %}
+
+{% set awaitingPriorsCount = 0 %}
+{% for thisEvent in data.events | filterEventsByEligibleForReading %}
+ {% if thisEvent | awaitingPriors %}
+ {% set awaitingPriorsCount = awaitingPriorsCount + 1 %}
+ {% endif %}
+{% endfor %}
+
{% set newlyArrivedPriorsCount = 2 %}
{% set actionTotal = arbitrationCount + newlyArrivedPriorsCount %}
@@ -115,17 +129,31 @@ Start image reading
{% endif %}
- {% if actionTotal > 0 %}
+ {# Awaiting priors inset #}
+ {% if awaitingPriorsCount > 0 %}
+ {% set insetHtml %}
+ {{ awaitingPriorsCount }} {{ "case" if awaitingPriorsCount == 1 else "cases" }} awaiting priors
+ These cases are on hold pending prior mammogram images.
+ Manage prior mammograms
+ {% endset %}
+ {{ insetText({
+ html: insetHtml | safe
+ }) }}
+ {% endif %}
+
+ {# Deferred cases inset #}
+ {% if deferredCount > 0 %}
{% set insetHtml %}
- {{ actionTotal }} flagged {{ "case" if actionTotal == 1 else "cases" }}
- Flagged cases require action before they can be read.
- Review flagged cases
+ {{ deferredCount }} deferred {{ "case" if deferredCount == 1 else "cases" }}
+ Deferred cases require review before they can be returned to the reading queue.
+ Review deferred cases
{% endset %}
{{ insetText({
html: insetHtml | safe
}) }}
{% endif %}
+ {# Previous sessions inset #}
{% if previousSessions | length > 0 %}
Your previous image reading sessions
@@ -140,10 +168,8 @@ Your previous image reading sessions
See all
{% endif %}
-
-
-
-
+
+
{% endblock %}
diff --git a/app/views/reading/session.html b/app/views/reading/session.html
index 3a169468..5356a2bf 100644
--- a/app/views/reading/session.html
+++ b/app/views/reading/session.html
@@ -104,7 +104,7 @@
{# YOUR READS VIEW - Shows cases from user's perspective #}
{% set userReadableEvents = [] %}
{% for event in events %}
- {% if event | canUserReadEvent or event | userHasReadEvent or event | userRequestedPriors(data.currentUser.id) %}
+ {% if event | canUserReadEvent or event | userHasReadEvent or event | userRequestedPriors(data.currentUser.id) or event | isDeferred %}
{% set userReadableEvents = userReadableEvents | push(event) %}
{% endif %}
{% endfor %}
@@ -118,6 +118,7 @@
{% set technicalRecallEvents = [] %}
{% set recallForAssessmentEvents = [] %}
{% set priorsRequestedEvents = [] %}
+ {% set deferredEvents = [] %}
{% for event in userReadableEvents %}
{% if event | userHasReadEvent %}
@@ -131,6 +132,8 @@
{% endif %}
{% elseif event | userRequestedPriors(data.currentUser.id) %}
{% set priorsRequestedEvents = priorsRequestedEvents | push(event) %}
+ {% elseif event | isDeferred %}
+ {% set deferredEvents = deferredEvents | push(event) %}
{% endif %}
{% endfor %}
@@ -139,6 +142,7 @@
{% set technicalRecallCount = technicalRecallEvents | length %}
{% set recallForAssessmentCount = recallForAssessmentEvents | length %}
{% set priorsRequestedCount = priorsRequestedEvents | length %}
+ {% set deferredCount = deferredEvents | length %}
{% set normalPercent = (normalCount / totalCount * 100) | round %}
{% set technicalRecallPercent = (technicalRecallCount / totalCount * 100) | round %}
@@ -213,10 +217,10 @@ Opinion summary
{% endif %}
Reading session cases
- {% set userSessionRemainingCount = session.targetSize - readingStatus.userReadCount - readingStatus.userAwaitingPriorsCount %}
+ {% set userSessionRemainingCount = session.targetSize - readingStatus.userReadCount - readingStatus.userAwaitingPriorsCount - deferredCount %}
{% set userSessionRemainingCount = 0 if userSessionRemainingCount < 0 else userSessionRemainingCount %}
- {% if userSessionRemainingCount > 0 or readingStatus.userAwaitingPriorsCount > 0 %}
- Progress: {{ readingStatus.userReadCount }} read{%- if readingStatus.userAwaitingPriorsCount > 0 -%}, {{ readingStatus.userAwaitingPriorsCount }} awaiting priors{%- endif -%}, {{ userSessionRemainingCount }} remaining
+ {% if userSessionRemainingCount > 0 or readingStatus.userAwaitingPriorsCount > 0 or deferredCount > 0 %}
+ Progress: {{ readingStatus.userReadCount }} read{%- if readingStatus.userAwaitingPriorsCount > 0 -%}, {{ readingStatus.userAwaitingPriorsCount }} awaiting priors{%- endif -%}{%- if deferredCount > 0 -%}, {{ deferredCount }} deferred{%- endif -%}, {{ userSessionRemainingCount }} remaining
{% endif %}
@@ -288,6 +292,8 @@ Reading session cases
{% if read.opinion %}
{{ read.opinion | toTag }}
{% endif %}
+ {% elseif event | isDeferred %}
+ {{ "Deferred" | toTag }}
{% elseif event | userRequestedPriors(data.currentUser.id) %}
{{ "Priors requested" | toTag }}
{% elseif session.skippedEvents | includes(event.id) %}
diff --git a/app/views/reading/workflow/defer-case.html b/app/views/reading/workflow/defer-case.html
new file mode 100644
index 00000000..48515a08
--- /dev/null
+++ b/app/views/reading/workflow/defer-case.html
@@ -0,0 +1,50 @@
+{# app/views/reading/workflow/defer-case.html #}
+
+{% extends parentLayout or 'layout-reading.html' %}
+
+{% set pageHeading = "Defer this case" %}
+{% set formAction = './defer-case-answer' | urlWithReferrer(referrerChain) %}
+{% set back = {
+ href: "./opinion",
+ text: "Back"
+} %}
+
+{% block pageContent %}
+
+ {% set caption %}
+ {{ participant | getFullName }}
+ {% endset %}
+
+
+
+
+
+ {{ caption }}
+ {{ pageHeading }}
+
+
+
+ This case will be removed from the reading queue. It must be manually reviewed before it can be read.
+
+
+ {{ textarea({
+ name: "deferralReason",
+ id: "deferralReason",
+ label: {
+ text: "Reason for deferring",
+ size: "s"
+ },
+ hint: {
+ text: "Explain why you are unable to give an opinion on this case"
+ },
+ rows: 4
+ }) }}
+
+ {{ button({
+ text: "Confirm deferral"
+ }) }}
+
+
+
+
+{% endblock %}
diff --git a/app/views/reading/workflow/existing-read.html b/app/views/reading/workflow/existing-read.html
index 2f2e41ae..d4b1c4fe 100644
--- a/app/views/reading/workflow/existing-read.html
+++ b/app/views/reading/workflow/existing-read.html
@@ -10,12 +10,59 @@
{% set isAwaitingPriors = event | awaitingPriors %}
{% set hasUserRead = event | userHasReadEvent %}
+ {% set isDeferredCase = event | isDeferred %}
{{ participant | getFullName }}
- {% if isAwaitingPriors and not hasUserRead %}
+ {% if isDeferredCase and not hasUserRead %}
+ {# Event has been deferred - show deferral summary #}
+ Your opinion
+
+ {% set deferral = event.imageReading.deferral %}
+ {% set canUndo = deferral.deferredBy == data.currentUser.id %}
+
+ {% set deferralSummaryHtml %}
+ {% call appSummaryList() %}
+ {{ appSummaryListRow({
+ key: {
+ text: "Opinion"
+ },
+ value: {
+ html: "Deferred" | toTag
+ },
+ actions: {
+ items: [{
+ href: "./undo-defer",
+ text: "Undo deferral",
+ visuallyHiddenText: "case deferral"
+ }]
+ } if canUndo
+ }) }}
+
+ {% if deferral.reason %}
+ {{ appSummaryListRow({
+ key: {
+ text: "Reason"
+ },
+ value: {
+ text: deferral.reason
+ }
+ }) }}
+ {% endif %}
+
+ {% endcall %}
+ {% endset %}
+
+ {{ card({
+ heading: "Your read",
+ headingLevel: "2",
+ feature: true,
+ descriptionHtml: deferralSummaryHtml
+ }) }}
+
+ {% elseif isAwaitingPriors and not hasUserRead %}
{# Event is awaiting priors - show as the reader's opinion #}
Your opinion
diff --git a/app/views/reading/workflow/opinion.html b/app/views/reading/workflow/opinion.html
index 96279889..e5e4e659 100644
--- a/app/views/reading/workflow/opinion.html
+++ b/app/views/reading/workflow/opinion.html
@@ -153,7 +153,7 @@
{% endfor %}
- Request priors
+ {{ appLink({ text: "Request priors", href: "./request-priors", classes: "nhsuk-link--no-visited-state" } | openInModal) }}
{% endset %}
@@ -375,7 +375,6 @@ {{ questionText }}
-
{# Image notes - moved above opinion section #}
{% include "_includes/reading/image-warnings.njk" %}
@@ -407,6 +406,15 @@ {{ questionText }}
}
}) }}
+ {# Defer case option #}
+
+
+
+ {{ appLink({ text: "Defer this case", href: "./defer-case", classes: "nhsuk-link--no-visited-state" } | openInModal) }}
+
+
+
+
{% endblock %}
{% block pageScripts %}
diff --git a/app/views/reading/workflow/recall-for-assessment-details.html b/app/views/reading/workflow/recall-for-assessment-details.html
index 169ac52f..bcf2abde 100644
--- a/app/views/reading/workflow/recall-for-assessment-details.html
+++ b/app/views/reading/workflow/recall-for-assessment-details.html
@@ -254,9 +254,6 @@
var side = nameMatch[1]
var value = e.target.value
- // Persist the breast assessment to session immediately
- fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value))
-
// Switch the active tab to match the selected side (tab-based modes)
if (window._annotationInstance && window._annotationInstance.switchSide) {
window._annotationInstance.switchSide(side)
@@ -274,21 +271,43 @@
}
}
- if (value !== 'abnormal') return
+ if (value !== 'abnormal') {
+ // Still persist the breast assessment for non-abnormal selections
+ fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value))
+ return
+ }
var countEl = document.querySelector('[data-annotation-count="' + side + '"]')
var count = countEl ? parseInt(countEl.dataset.count || '0', 10) : 0
// In full tabbed mode, user clicks images directly — no auto-open
- if (count === 0 && annotationsMode === 'with-images') return
+ if (count === 0 && annotationsMode === 'with-images') {
+ // Still persist the breast assessment to session
+ fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value))
+ return
+ }
if (count === 0) {
- var url = './annotation/add?side=' + side
- if (useModals && typeof window.openModal === 'function') {
- window.openModal('app-form-modal', { loadUrl: url })
- } else {
- window.location.href = url
- }
+ // Wait for the save to complete before opening the modal,
+ // so the server has the breast side info in the session when rendering the annotation page
+ fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value))
+ .then(() => {
+ var url = './annotation/add?side=' + side
+ if (useModals && typeof window.openModal === 'function') {
+ window.openModal('app-form-modal', { loadUrl: url })
+ } else {
+ window.location.href = url
+ }
+ })
+ .catch(() => {
+ // Graceful degradation: open modal even if save fails
+ var url = './annotation/add?side=' + side
+ if (useModals && typeof window.openModal === 'function') {
+ window.openModal('app-form-modal', { loadUrl: url })
+ } else {
+ window.location.href = url
+ }
+ })
}
})
})()
diff --git a/app/views/reading/workflow/request-priors.html b/app/views/reading/workflow/request-priors.html
index 0ff46aef..56ddfeb4 100644
--- a/app/views/reading/workflow/request-priors.html
+++ b/app/views/reading/workflow/request-priors.html
@@ -1,8 +1,9 @@
{# app/views/reading/workflow/request-priors.html #}
-{% extends 'layout-reading.html' %}
+{% extends parentLayout or 'layout-reading.html' %}
{% set pageHeading = "Request prior images" %}
+{% set formAction = './request-priors-answer' | urlWithReferrer(referrerChain) %}
{% set back = {
href: "./opinion",
text: "Back"
@@ -19,12 +20,10 @@
diff --git a/app/views/settings.html b/app/views/settings.html
index efd6c10f..16586d08 100755
--- a/app/views/settings.html
+++ b/app/views/settings.html
@@ -76,7 +76,7 @@ Error
Modal forms: off
Compare page: off
Review pages off
- Annotations mode: inline form (no image markers)
+ Annotations mode: inline form (no image markers)
diff --git a/package-lock.json b/package-lock.json
index c187cdf0..d515156a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,9 +21,9 @@
"weighted": "^1.0.0"
},
"devDependencies": {
- "cssnano": "^8.0.1",
+ "cssnano": "^8.0.2",
"postcss": "^8.5.15",
- "prettier": "^3.8.3",
+ "prettier": "^3.8.4",
"purgecss": "^8.0.0"
},
"engines": {
@@ -45,9 +45,9 @@
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
- "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
+ "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
"cpu": [
"ppc64"
],
@@ -61,9 +61,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
- "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
+ "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
"cpu": [
"arm"
],
@@ -77,9 +77,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
- "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
+ "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
"cpu": [
"arm64"
],
@@ -93,9 +93,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
- "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
+ "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
"cpu": [
"x64"
],
@@ -109,9 +109,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
- "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
+ "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
"cpu": [
"arm64"
],
@@ -125,9 +125,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
- "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
+ "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
"cpu": [
"x64"
],
@@ -141,9 +141,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
- "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
"cpu": [
"arm64"
],
@@ -157,9 +157,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
- "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
"cpu": [
"x64"
],
@@ -173,9 +173,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
- "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
+ "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
"cpu": [
"arm"
],
@@ -189,9 +189,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
- "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
+ "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
"cpu": [
"arm64"
],
@@ -205,9 +205,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
- "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
+ "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
"cpu": [
"ia32"
],
@@ -221,9 +221,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
- "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
+ "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
"cpu": [
"loong64"
],
@@ -237,9 +237,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
- "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
+ "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
"cpu": [
"mips64el"
],
@@ -253,9 +253,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
- "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
+ "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
"cpu": [
"ppc64"
],
@@ -269,9 +269,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
- "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
+ "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
"cpu": [
"riscv64"
],
@@ -285,9 +285,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
- "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
+ "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
"cpu": [
"s390x"
],
@@ -301,9 +301,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
- "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
+ "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
"cpu": [
"x64"
],
@@ -317,9 +317,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
- "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
"cpu": [
"arm64"
],
@@ -333,9 +333,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
- "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
"cpu": [
"x64"
],
@@ -349,9 +349,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
- "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
"cpu": [
"arm64"
],
@@ -365,9 +365,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
- "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
"cpu": [
"x64"
],
@@ -381,9 +381,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
- "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
+ "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
"cpu": [
"arm64"
],
@@ -397,9 +397,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
- "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
+ "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
"cpu": [
"x64"
],
@@ -413,9 +413,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
- "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
+ "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
"cpu": [
"arm64"
],
@@ -429,9 +429,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
- "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
+ "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
"cpu": [
"ia32"
],
@@ -445,9 +445,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
- "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
+ "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
"cpu": [
"x64"
],
@@ -1010,9 +1010,6 @@
"cpu": [
"arm"
],
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1033,9 +1030,6 @@
"cpu": [
"arm"
],
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1056,9 +1050,6 @@
"cpu": [
"arm64"
],
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1079,9 +1070,6 @@
"cpu": [
"arm64"
],
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1102,9 +1090,6 @@
"cpu": [
"x64"
],
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1125,9 +1110,6 @@
"cpu": [
"x64"
],
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1252,6 +1234,7 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz",
"integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": ">=7.24.0 <7.24.7"
}
@@ -1269,15 +1252,13 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
"integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
"license": "MIT",
- "peer": true,
"dependencies": {
"mime-types": "^3.0.0",
"negotiator": "^1.0.0"
@@ -1359,8 +1340,7 @@
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/async": {
"version": "2.6.4",
@@ -1417,9 +1397,9 @@
}
},
"node_modules/baseline-browser-mapping": {
- "version": "2.10.34",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz",
- "integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==",
+ "version": "2.10.35",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.35.tgz",
+ "integrity": "sha512-honAfLBde0HAFLdNyBEfuuENkF6zR+ozxqxa/2zJKHBe1qzLqyTSeRKpdPEHAP03rlDGyQOPnCSxnVpVqQo9Mg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -1692,6 +1672,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782",
@@ -1751,22 +1732,20 @@
}
},
"node_modules/caniuse-api": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
- "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-4.0.0.tgz",
+ "integrity": "sha512-B0hQ1OLyJuHTQSOWXvwibWqM6DCoqJdvBA6X1S/53bd4XU7LJ1yurIPlrsouol3mw1jh9pGI4ivubSpmJeIqCA==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.0.0",
- "caniuse-lite": "^1.0.0",
- "lodash.memoize": "^4.1.2",
- "lodash.uniq": "^4.5.0"
+ "caniuse-lite": "^1.0.0"
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001797",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz",
- "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==",
+ "version": "1.0.30001799",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
+ "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==",
"dev": true,
"funding": [
{
@@ -1811,6 +1790,7 @@
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -1894,7 +1874,6 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">= 6"
}
@@ -2005,7 +1984,6 @@
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz",
"integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
},
@@ -2126,13 +2104,13 @@
}
},
"node_modules/cssnano": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.1.tgz",
- "integrity": "sha512-oSiOnPQNNYjusTUlYJiE6xvFQG4don3N0QavaoV1BxIsC1zjvxOwikXlR7lG1EVmZNDDaJkHbQx1VRB8kaoMHA==",
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.2.tgz",
+ "integrity": "sha512-K+a76gA1v0/CsYgcsE95HGGyIuPKxpQSetwSwz4nHEM8fFXqSkzq2JzEXFL8v5+CCjxzVVVhPcTK3Oo8SaF/xA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "cssnano-preset-default": "^8.0.1",
+ "cssnano-preset-default": "^8.0.2",
"lilconfig": "^3.1.3"
},
"engines": {
@@ -2143,64 +2121,64 @@
"url": "https://opencollective.com/cssnano"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/cssnano-preset-default": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.1.tgz",
- "integrity": "sha512-OTdKeYMlvQ8KBgyej5ysktnWJoeyo7rGrVnm+bdpIHGvxhbTGPsOkB+7T1EdTuX00dGlQQb2UEbSPB1OpMXULw==",
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.2.tgz",
+ "integrity": "sha512-+jQAqIKCqMmBjZs7741XkilU93ITZ/EW8gjAkMmujdCzfDkfjrDBv2VqkSu29Fzeig/0rZ3S9IAwfPLlmXEUfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.2",
- "cssnano-utils": "^6.0.0",
+ "cssnano-utils": "^6.0.1",
"postcss-calc": "^10.1.1",
- "postcss-colormin": "^8.0.0",
- "postcss-convert-values": "^8.0.0",
- "postcss-discard-comments": "^8.0.0",
- "postcss-discard-duplicates": "^8.0.0",
- "postcss-discard-empty": "^8.0.0",
- "postcss-discard-overridden": "^8.0.0",
- "postcss-merge-longhand": "^8.0.0",
- "postcss-merge-rules": "^8.0.0",
- "postcss-minify-font-values": "^8.0.0",
- "postcss-minify-gradients": "^8.0.0",
- "postcss-minify-params": "^8.0.0",
- "postcss-minify-selectors": "^8.0.1",
- "postcss-normalize-charset": "^8.0.0",
- "postcss-normalize-display-values": "^8.0.0",
- "postcss-normalize-positions": "^8.0.0",
- "postcss-normalize-repeat-style": "^8.0.0",
- "postcss-normalize-string": "^8.0.0",
- "postcss-normalize-timing-functions": "^8.0.0",
- "postcss-normalize-unicode": "^8.0.0",
- "postcss-normalize-url": "^8.0.0",
- "postcss-normalize-whitespace": "^8.0.0",
- "postcss-ordered-values": "^8.0.0",
- "postcss-reduce-initial": "^8.0.0",
- "postcss-reduce-transforms": "^8.0.0",
- "postcss-svgo": "^8.0.0",
- "postcss-unique-selectors": "^8.0.0"
+ "postcss-colormin": "^8.0.1",
+ "postcss-convert-values": "^8.0.1",
+ "postcss-discard-comments": "^8.0.1",
+ "postcss-discard-duplicates": "^8.0.1",
+ "postcss-discard-empty": "^8.0.1",
+ "postcss-discard-overridden": "^8.0.1",
+ "postcss-merge-longhand": "^8.0.1",
+ "postcss-merge-rules": "^8.0.1",
+ "postcss-minify-font-values": "^8.0.1",
+ "postcss-minify-gradients": "^8.0.1",
+ "postcss-minify-params": "^8.0.1",
+ "postcss-minify-selectors": "^8.0.2",
+ "postcss-normalize-charset": "^8.0.1",
+ "postcss-normalize-display-values": "^8.0.1",
+ "postcss-normalize-positions": "^8.0.1",
+ "postcss-normalize-repeat-style": "^8.0.1",
+ "postcss-normalize-string": "^8.0.1",
+ "postcss-normalize-timing-functions": "^8.0.1",
+ "postcss-normalize-unicode": "^8.0.1",
+ "postcss-normalize-url": "^8.0.1",
+ "postcss-normalize-whitespace": "^8.0.1",
+ "postcss-ordered-values": "^8.0.1",
+ "postcss-reduce-initial": "^8.0.1",
+ "postcss-reduce-transforms": "^8.0.1",
+ "postcss-svgo": "^8.0.1",
+ "postcss-unique-selectors": "^8.0.1"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/cssnano-utils": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.0.tgz",
- "integrity": "sha512-ztS9W/+uaDn+bkYmDhs+GdMveHJ3CL8IPNHpRqDUQXv5GJOTQAJjV1XUOInr9esLXSabQV1pLRZlJpyUwEqDyQ==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.1.tgz",
+ "integrity": "sha512-zk65GIxA8tCjqVk7nTm1mE+ZKxtnxAvU5JSUaBLXbAr3ZF7IOvz3fbPOnEDvZKhnS7GOIitXTS5BgehLzNoc8Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/csso": {
@@ -2434,9 +2412,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.368",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz",
- "integrity": "sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==",
+ "version": "1.5.371",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.371.tgz",
+ "integrity": "sha512-e9htk9mAYL6AzmkEhSvVVw7IWGSBJ/Bqdn2eRyRLrj1g6sncN4WbFt5qnILYoCktktr45pyjIrOiRvBThQ808w==",
"dev": true,
"license": "ISC"
},
@@ -2456,9 +2434,9 @@
}
},
"node_modules/engine.io": {
- "version": "6.6.8",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz",
- "integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==",
+ "version": "6.6.9",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz",
+ "integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
@@ -2470,22 +2448,22 @@
"cors": "~2.8.5",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
- "ws": "~8.20.1"
+ "ws": "~8.21.0"
},
"engines": {
"node": ">=10.2.0"
}
},
"node_modules/engine.io-client": {
- "version": "6.6.5",
- "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.5.tgz",
- "integrity": "sha512-QCwxUDULPlXv8F6tqMMKx5dNkTe6OaBYRMPYeXKBlyOoKvAmE0ac6pW7fFhSscJ/5SI7666/U/B+MElbsrJlIg==",
+ "version": "6.6.6",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.6.tgz",
+ "integrity": "sha512-iY6QdftLQ9pyiPoX082bpf/u1UewnOaJrtJIF9T0++QB34lZrj0uP+Q/bj8AlUsAxqhnkTV2BS8SBZSxOmoV5Q==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
- "ws": "~8.20.1",
+ "ws": "~8.21.0",
"xmlhttprequest-ssl": "~2.1.1"
}
},
@@ -2599,11 +2577,12 @@
}
},
"node_modules/esbuild": {
- "version": "0.28.0",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
- "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
+ "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
"hasInstallScript": true,
"license": "MIT",
+ "peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -2611,32 +2590,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.28.0",
- "@esbuild/android-arm": "0.28.0",
- "@esbuild/android-arm64": "0.28.0",
- "@esbuild/android-x64": "0.28.0",
- "@esbuild/darwin-arm64": "0.28.0",
- "@esbuild/darwin-x64": "0.28.0",
- "@esbuild/freebsd-arm64": "0.28.0",
- "@esbuild/freebsd-x64": "0.28.0",
- "@esbuild/linux-arm": "0.28.0",
- "@esbuild/linux-arm64": "0.28.0",
- "@esbuild/linux-ia32": "0.28.0",
- "@esbuild/linux-loong64": "0.28.0",
- "@esbuild/linux-mips64el": "0.28.0",
- "@esbuild/linux-ppc64": "0.28.0",
- "@esbuild/linux-riscv64": "0.28.0",
- "@esbuild/linux-s390x": "0.28.0",
- "@esbuild/linux-x64": "0.28.0",
- "@esbuild/netbsd-arm64": "0.28.0",
- "@esbuild/netbsd-x64": "0.28.0",
- "@esbuild/openbsd-arm64": "0.28.0",
- "@esbuild/openbsd-x64": "0.28.0",
- "@esbuild/openharmony-arm64": "0.28.0",
- "@esbuild/sunos-x64": "0.28.0",
- "@esbuild/win32-arm64": "0.28.0",
- "@esbuild/win32-ia32": "0.28.0",
- "@esbuild/win32-x64": "0.28.0"
+ "@esbuild/aix-ppc64": "0.28.1",
+ "@esbuild/android-arm": "0.28.1",
+ "@esbuild/android-arm64": "0.28.1",
+ "@esbuild/android-x64": "0.28.1",
+ "@esbuild/darwin-arm64": "0.28.1",
+ "@esbuild/darwin-x64": "0.28.1",
+ "@esbuild/freebsd-arm64": "0.28.1",
+ "@esbuild/freebsd-x64": "0.28.1",
+ "@esbuild/linux-arm": "0.28.1",
+ "@esbuild/linux-arm64": "0.28.1",
+ "@esbuild/linux-ia32": "0.28.1",
+ "@esbuild/linux-loong64": "0.28.1",
+ "@esbuild/linux-mips64el": "0.28.1",
+ "@esbuild/linux-ppc64": "0.28.1",
+ "@esbuild/linux-riscv64": "0.28.1",
+ "@esbuild/linux-s390x": "0.28.1",
+ "@esbuild/linux-x64": "0.28.1",
+ "@esbuild/netbsd-arm64": "0.28.1",
+ "@esbuild/netbsd-x64": "0.28.1",
+ "@esbuild/openbsd-arm64": "0.28.1",
+ "@esbuild/openbsd-x64": "0.28.1",
+ "@esbuild/openharmony-arm64": "0.28.1",
+ "@esbuild/sunos-x64": "0.28.1",
+ "@esbuild/win32-arm64": "0.28.1",
+ "@esbuild/win32-ia32": "0.28.1",
+ "@esbuild/win32-x64": "0.28.1"
}
},
"node_modules/esbuild-clean-plugin": {
@@ -2703,7 +2682,6 @@
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.1",
@@ -2802,7 +2780,6 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=6.6.0"
}
@@ -2873,7 +2850,6 @@
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"debug": "^4.4.0",
"encodeurl": "^2.0.0",
@@ -2911,16 +2887,16 @@
}
},
"node_modules/form-data": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
- "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
+ "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
- "hasown": "^2.0.2",
- "mime-types": "^2.1.12"
+ "hasown": "^2.0.4",
+ "mime-types": "^2.1.35"
},
"engines": {
"node": ">= 6"
@@ -2952,7 +2928,6 @@
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">= 0.6"
}
@@ -2962,7 +2937,6 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">= 0.8"
}
@@ -3257,7 +3231,6 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">= 0.10"
}
@@ -3365,8 +3338,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/is-wsl": {
"version": "1.1.0",
@@ -3453,20 +3425,6 @@
"integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==",
"license": "MIT"
},
- "node_modules/lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.uniq": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/markdown-it": {
"version": "14.2.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
@@ -3530,7 +3488,6 @@
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
},
@@ -3666,7 +3623,6 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">= 0.6"
}
@@ -3676,6 +3632,7 @@
"resolved": "https://registry.npmjs.org/nhsuk-frontend/-/nhsuk-frontend-10.5.2.tgz",
"integrity": "sha512-lTOmzSDJkEn8uhuEuj3NKAW5MYuG/5tqMRsp15An2oLKlpGEoEAoREp+tHYJ7DLOPDRp9Z/zmp6/pLea75ae1g==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": "^20.9.0 || ^22.11.0 || >= 24.11.0"
},
@@ -3900,7 +3857,6 @@
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
- "peer": true,
"dependencies": {
"wrappy": "1"
}
@@ -3949,7 +3905,6 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
"integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
@@ -4029,6 +3984,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.12",
"picocolors": "^1.1.1",
@@ -4056,28 +4012,28 @@
}
},
"node_modules/postcss-colormin": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.0.tgz",
- "integrity": "sha512-KKwMmsSgsmdYXqrjQeqL3tnuIFtctiR1GEMHdjNpDpz/TCRkkkok2mMcreK2zVV3l7POWOmAkR2xYHUpRUK1DA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.1.tgz",
+ "integrity": "sha512-qBY4ABQ6d8/mk5RRZHwMllrZMxeMey3azVY2dZUEk+RgiUC4ARdPR3/AITzNqqKTbvW/3y/MJKinDrzwqn8RDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@colordx/core": "^5.4.3",
"browserslist": "^4.28.2",
- "caniuse-api": "^3.0.0",
+ "caniuse-api": "^4.0.0",
"postcss-value-parser": "^4.2.0"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-convert-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.0.tgz",
- "integrity": "sha512-Ohtj3rNZWawTRePv5NCHTy8VJSdJ/G/uKuxcxJreOMichuqcT6uEl2TAnopVeJCJ/c13jaSqg7m63yFLM5zBsA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.1.tgz",
+ "integrity": "sha512-IdOSIX3BzfMvCc1TAHIha2gfy17xnb5vfML8e2BIKARnFOghksESfaSAB/3CXgyLfMozZAbTRPVQF5dbuKOidw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4088,104 +4044,104 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-discard-comments": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.0.tgz",
- "integrity": "sha512-zGpvVLj2sbagEp+BTVETvAfkZdGVA6rALNujDK/WTIjdf1/rQOxOG8BBzkI8UQgnw8SkL6xffAfbtGMHFypadw==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.1.tgz",
+ "integrity": "sha512-FDvzm3tXlEsQBO2XQgnta5ugsAqwBrgWH+j5QgXpegEIDYA0VPnZg2aP7LtmWtC49POskeIhXesFiU/k3NyFHA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "postcss-selector-parser": "^7.1.1"
+ "postcss-selector-parser": "^7.1.2"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-discard-duplicates": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.0.tgz",
- "integrity": "sha512-zjRyYmNGI3PTipKBBtCgExlmZXQn49KvKoaiNnR2g+iXxeNk7GY5Js2ULtZXPrCYeqjPagrzKIBNcBocvXCR7g==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.1.tgz",
+ "integrity": "sha512-stTDXkI8YkCUfADurQhp03oq5ynsgSx6Qrw5B1swds6oTHtAeOZ9I0SHGK8cY/VpWUsIYFDWMs3IWf9jIEfFvA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-discard-empty": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.0.tgz",
- "integrity": "sha512-kxPJg6EqahbBvm+l7hpYYCtpsv8dlz7Tv6wJXUXZaeuY0WGS61DxfGdZR4uVB/Cx+yi3iOHQVSqpSHKMFaBg6Q==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.1.tgz",
+ "integrity": "sha512-Zv4fM1Yfhk71tbt6gfiptbL6jDHi+7apSnaMeaO9n1uET+1embrXQw5m93Zp5x28UyQSuv+AVkFY193jdwZ33w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-discard-overridden": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.0.tgz",
- "integrity": "sha512-sW2OWH3l9p0FmBSVr228uztFseqroZxwgD7SGF0Ks0dRPDttSo3P8FK5ZBLtWBH2A5+chpB0J2fB/T8heKHLBw==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.1.tgz",
+ "integrity": "sha512-ykt4fvrC7yYGzbxKyqBVjDCbsjF/11JgWK8enrdkobRyqqEtb/uDUCbKOGdvrK8X7BrShW8Lv5cCRNbdkNHGkQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-merge-longhand": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.0.tgz",
- "integrity": "sha512-YDmAmQ8H+ljfomVpSXvr9NA0GP01fraQJqjWBYoMVGg6rOT+PJLwPyeVo2ekn4WB4ZVSH5ddtK3DTRxbz6CFzg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.1.tgz",
+ "integrity": "sha512-huTfSYgQ13O81SFvAuOi7GWnO48vvybjj3xF+X3qUoPjzvvaLpJH5DcUqqXcwOEulZUcvaV4s0V9WtWs+IAQPA==",
"dev": true,
"license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0",
- "stylehacks": "^8.0.0"
+ "stylehacks": "^8.0.1"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-merge-rules": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.0.tgz",
- "integrity": "sha512-bgstL5mpi41dDpnYGDUcI3M814NWkCMcIWpwDqEHXkHg3BT7b4XRAfNEuwJncZOVn/67kVKvWzhfv/7xyrp2uQ==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.1.tgz",
+ "integrity": "sha512-o3rk4UpnPNg469tklYwbR/NtvKc/f/wJiVDTnNQ/EFPw/LeiPOHUCvV1GIBQIZHGrBAYdPjToK6a+ojYprsrxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.2",
- "caniuse-api": "^3.0.0",
- "cssnano-utils": "^6.0.0",
- "postcss-selector-parser": "^7.1.1"
+ "caniuse-api": "^4.0.0",
+ "cssnano-utils": "^6.0.1",
+ "postcss-selector-parser": "^7.1.2"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-minify-font-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.0.tgz",
- "integrity": "sha512-EnOHQEnSt6oH5NrL1DMFAQuwB2IOimFXTCzc9bKfUeH1jREbqIF5MAK4gQJQOC4mPUwJt4sWifAmNZ1qLu6j3Q==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.1.tgz",
+ "integrity": "sha512-L8Nzs/PRlBSPrLdY/7rAiU5ZN5800+2J/4LRbfyG8SJnPljmgMaXVmQiCklvRS+yObfVRNtvmk/Ean/eoYcSeg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4195,81 +4151,81 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-minify-gradients": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.0.tgz",
- "integrity": "sha512-43iAnYIGk0ZjNx5X/rkIcHi6dhmu/vEjY0kqfUfxPuJRO+V7jx8uKIdcnL0dpfNoC5J9TSh3EtzLWbq0gpqnWA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.1.tgz",
+ "integrity": "sha512-qf+4s/hZMqTwpWN2teqf6+1yvR/SZK5HgHqXYuACeJXV7ABe7AXtBEomgxagUzcN4bSnmqBh5vnIml0dYqykYg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@colordx/core": "^5.4.3",
- "cssnano-utils": "^6.0.0",
+ "cssnano-utils": "^6.0.1",
"postcss-value-parser": "^4.2.0"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-minify-params": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.0.tgz",
- "integrity": "sha512-z7w4QO7G55l4vMUK1Lmx03GW7iyRLgf2V5Dz/7ioSPLnXRjeD+b7m0XfAXUGrbBYYrJ6bXPk+3LoX5u4JfAcSg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.1.tgz",
+ "integrity": "sha512-L0h3H59deFfFg0wQN1NVaS/8E/LfGvaMuZKGO7siwlG995zo3OshtQyRkqKdVqcBwAORBvZ1nDZrKPLRapYkQw==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.2",
- "cssnano-utils": "^6.0.0",
+ "cssnano-utils": "^6.0.1",
"postcss-value-parser": "^4.2.0"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-minify-selectors": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.1.tgz",
- "integrity": "sha512-c31D46811kTkQDxV1KTTow79axX6gj/01AY5G7cGZg3s31KvAwP13jEFXGAzQbJ7NvOFV1pRqEia6nrAdHU7qg==",
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.2.tgz",
+ "integrity": "sha512-3icdxc/zght5UAizdwqZBDE2KOWHf1jMQCxET6iLACeNlRxfTPyXS0/COpGk8CQ2cECyaEKTRUd/i/k8Gxmz4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.1",
- "caniuse-api": "^3.0.0",
+ "caniuse-api": "^4.0.0",
"cssesc": "^3.0.0",
- "postcss-selector-parser": "^7.1.1"
+ "postcss-selector-parser": "^7.1.2"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-charset": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.0.tgz",
- "integrity": "sha512-s88FUNDSUD8m0wBYvTQQcubVts6zhXwBU8zCD4vkRKiecd0v8cOjHVIF9r/i+5xzS/WG3f98qq4XsOM0JqvfLA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.1.tgz",
+ "integrity": "sha512-xzqr36F8UeIZOvOHsf3aul+RVJCADvSwuwpMLgizqKjisHZpBfztgW0XFLBfJvz9pJgaStaOXAtGb0zLqT6B0w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-display-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.0.tgz",
- "integrity": "sha512-gG2nBxD27fiw6Luinb1QYKdM/Co5GornRJgSD+JTwNH4PGKxImP0qyruDDav49aHUPLY3qrL3qN3LvybO7IzxQ==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.1.tgz",
+ "integrity": "sha512-ZDWOijOK1FFMlpgiQCUO9fCNKd7HJ9L7z9HWEq4iyubnUFWzdTSwm/LcrMbNW6iZ1oAtqeLYA0WA3xHszOI08g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4279,13 +4235,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-positions": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.0.tgz",
- "integrity": "sha512-t/wGqpehS20Ke7kc4QAsWpH+AJjUdMK/V5qV2RhrXkj8hO/fT1t1MJ8NL7sedWYk7ZqC7eISEJQonW5j0tU1MQ==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.1.tgz",
+ "integrity": "sha512-uuivan2poSqbE48ST4do20dGaFUeXey9/H8rhHzoyVHB2I6BmkoVLZ/C9+BRjUlpaAFYVOoDY7epkiidzaYbvA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4295,13 +4251,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-repeat-style": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.0.tgz",
- "integrity": "sha512-3ebOmGdCYKrBYyGKc1xhj0unEnW7beZpVU7JohVeGl7mTxR+7T6egpaawTWAVsB0pEIhcsbJVOjPKCJSoRO6Zg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.1.tgz",
+ "integrity": "sha512-q2hq5fmKxk29K6DjKA3nZ17Q2dtjhLYFNmFweKALmooUqx6UWAHF1bBoWTu/EqlJ88josb82A/J0Atj9LJUmpQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4311,13 +4267,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-string": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.0.tgz",
- "integrity": "sha512-TvWCGZ/e04Tv31uJvOUtbexkfgUnqmQ3M2P5DkAaVzvOj+BvTkG2QjpA5Y71SL1SPxJcj4M23fNh+RDVCmG8kA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.1.tgz",
+ "integrity": "sha512-+Wf+kQJhm1WgSGEAuUaswE9rdpR9QbrKRVemcVHs6rhOoOTVIdAbgaicftfYA6vLM346P8onRzkEVbFN29ktKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4327,13 +4283,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-timing-functions": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.0.tgz",
- "integrity": "sha512-uEfaXst5Xgqxv7geYUuz6vs9mn88K2NPY2RoIzM3BMmSjsdTSeppV9x2qIgrxsisdbSqF6IVhzI2occcte3hTA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.1.tgz",
+ "integrity": "sha512-W8/tvwRlm3T+yjGkg0IRTF4bvHj0vILYr/LOogCrJKHz2ey2HFRwfsAA8Bk9N4BGR7z7WmmDu/KzzwhJ6FoGPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4343,13 +4299,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-unicode": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.0.tgz",
- "integrity": "sha512-+WYngZaChEeTHZmWhmKtnJ4gTzWdINEaFcgWBnu6WdVu8Ftim8OBTcw768DuCC/3Aax9bZ9WkwrLGHym2Lzf+A==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.1.tgz",
+ "integrity": "sha512-Ad0YHNRBp4WHEOYUM/4wL/8MoL2fimEF8se/0q+Rt/owMzYpbxsypC1P8fN/oluwoRmRKdNVX7X2oycEobPWcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4360,13 +4316,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-url": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.0.tgz",
- "integrity": "sha512-4Mz9hZHn/QIB+YtFqTXrDmE2193GYxGb3F8uMfLvMicaEXCCUlDIJ658gFFJbqEGl9FYzwPtRiuNgbwlO9kkBg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.1.tgz",
+ "integrity": "sha512-tkYcip6pCDY806xuxpJYqMW2M3/623jzGFJmz3m5Us47q8P28+gbRZxaea3Rr/CmwwLUiVlh+BTGYwQ6gvaP8A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4376,13 +4332,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-normalize-whitespace": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.0.tgz",
- "integrity": "sha512-V1f8tYnwIP5tscOXQFTKK8Y5EJ+R2GMpFJ6FjzwoKoQnhbqQy3IeSrDjJJb8JjVos8ut6Osi80Zybpayv/XjIQ==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.1.tgz",
+ "integrity": "sha512-XzORadNfSrKWDZZpgAEHPKINKx8r9r9RIfE9c70g/HThdpbmPHhDYCodHSVESDxmKeySAYw1p4liuBCf7j6LyA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4392,47 +4348,47 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-ordered-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.0.tgz",
- "integrity": "sha512-Dg9+itb6lmD0bxqhQyHCtXAwYRh0wUrx6Mp4/BNXgkLoJmdYMmWi+V+Pypw79Q6iQhxA8KFMHqLBITQJV2gKMA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.1.tgz",
+ "integrity": "sha512-OLXq5lR1yk3KWQ1FPK6aWjFFdktHE9f9kb8cnt4LmIw7w30DnzgD9+sOVYJc5HenkWCX8i1MJhhFwmqc/GYqLg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "cssnano-utils": "^6.0.0",
+ "cssnano-utils": "^6.0.1",
"postcss-value-parser": "^4.2.0"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-reduce-initial": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.0.tgz",
- "integrity": "sha512-DChcE9d528AKrlpCTHjhsAiOsWCk4H9ApHPS1QqRT3praObWTiWyn6W1UddGpc46K9LQnHwUu4YwaPUukGtXVA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.1.tgz",
+ "integrity": "sha512-+aQsR6+61KRoIfcFNLP3v9RM7+0iYOTtPnjl1wr6JqMW1zx6S+t2ktHRefXwacFdHIDj5+ETG0KY7K3+SGQ4Nw==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.2",
- "caniuse-api": "^3.0.0"
+ "caniuse-api": "^4.0.0"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-reduce-transforms": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.0.tgz",
- "integrity": "sha512-cLZT0som7vvumQT9XQCnSKOSnRinNQZd1Hm+J723Ney13E8CIydDhw6JwzsjPtgnYThTqn9Q45906gz6wxaAsw==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.1.tgz",
+ "integrity": "sha512-x71slHVykiFi5RuKEXM0wgYpY2PngC78x6R8TnZhHF3lhqt+u/w3MGwYLX+2t5O87ssRiMfEAhQH+3J4QwVzCw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4442,13 +4398,13 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-selector-parser": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
- "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.3.tgz",
+ "integrity": "sha512-ajnd7iZnqjJDkyHNfznl/ZVO0lWqvBmQXfKKENx9/p/bEiF/L3eHwdydNUg9RXZx6xfZWOCmXmBa5oeB+YrAPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4460,9 +4416,9 @@
}
},
"node_modules/postcss-svgo": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.0.tgz",
- "integrity": "sha512-Q2fMSYEiNE1ioDc/3sxvI24NdgA/MJno2XLNpOxgv8aCcJbym8mZY10/lDY5+AWCIc3Aiqzy2Wcp9/zaIXBZgQ==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.1.tgz",
+ "integrity": "sha512-HpnvWii7W0/FPrsejJa6ZTi0kNtTJP/Iba7CUMPX0xPV6QpnndOp+SDP74tFtgjA2cYKYNWJPOlmLXMsvi/9yA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4473,23 +4429,23 @@
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-unique-selectors": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.0.tgz",
- "integrity": "sha512-iObuolUX+ITJfMU2QQFQdh31JgSjNLPNjVs6YGAqBHvOvAWXMMNget6donQl83aQaeS32i5XeKZURUW/WBxIUw==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.1.tgz",
+ "integrity": "sha512-+xvKI5+/Cl8yYQwxDV39Uhuc4WV951xngFvPPjiPj2NIbIfm6vbbRTXblyw0FioLkIoGlw+7qUcY1h2YhaZYgw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "postcss-selector-parser": "^7.1.1"
+ "postcss-selector-parser": "^7.1.2"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/postcss-value-parser": {
@@ -4512,9 +4468,9 @@
}
},
"node_modules/prettier": {
- "version": "3.8.3",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
- "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
+ "version": "3.8.4",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz",
+ "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==",
"dev": true,
"license": "MIT",
"bin": {
@@ -4532,7 +4488,6 @@
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
@@ -4777,7 +4732,6 @@
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"debug": "^4.4.0",
"depd": "^2.0.0",
@@ -4878,6 +4832,7 @@
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.100.0.tgz",
"integrity": "sha512-Ut8wlQSk19tm7jMK6mz6cF1+e+E7tUnW2tM02zQDPnOTcVbV8qCQG8UWxZkkNlY50+hV3hqP24OOkUlMz8xBpw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@bufbuild/protobuf": "^2.5.0",
"colorjs.io": "^0.5.0",
@@ -5033,7 +4988,6 @@
"cpu": [
"arm"
],
- "libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
@@ -5050,7 +5004,6 @@
"cpu": [
"arm64"
],
- "libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
@@ -5067,7 +5020,6 @@
"cpu": [
"arm"
],
- "libc": "musl",
"license": "MIT",
"optional": true,
"os": [
@@ -5084,7 +5036,6 @@
"cpu": [
"arm64"
],
- "libc": "musl",
"license": "MIT",
"optional": true,
"os": [
@@ -5101,7 +5052,6 @@
"cpu": [
"riscv64"
],
- "libc": "musl",
"license": "MIT",
"optional": true,
"os": [
@@ -5118,7 +5068,6 @@
"cpu": [
"x64"
],
- "libc": "musl",
"license": "MIT",
"optional": true,
"os": [
@@ -5135,7 +5084,6 @@
"cpu": [
"riscv64"
],
- "libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
@@ -5152,7 +5100,6 @@
"cpu": [
"x64"
],
- "libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
@@ -5292,7 +5239,6 @@
"resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
"integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"debug": "^4.4.3",
"encodeurl": "^2.0.0",
@@ -5433,7 +5379,6 @@
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
"integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
@@ -5587,13 +5532,13 @@
}
},
"node_modules/socket.io-adapter": {
- "version": "2.5.7",
- "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz",
- "integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==",
+ "version": "2.5.8",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz",
+ "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==",
"license": "MIT",
"dependencies": {
"debug": "~4.4.1",
- "ws": "~8.20.1"
+ "ws": "~8.21.0"
}
},
"node_modules/socket.io-client": {
@@ -5734,20 +5679,20 @@
}
},
"node_modules/stylehacks": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.0.tgz",
- "integrity": "sha512-sWyjaJvBqHoVKYPbQ8JRvrGSPaYWtWrJsU+fGVtwKB1GE1rRPu3rC7T6UCuXLoL00Dwb+tsHe2T904r8Vnsx8w==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.1.tgz",
+ "integrity": "sha512-Gv095oTD0N+BdJALNFDsxZpETHZLTxbOl5RyIO7y6VAE6sR3z0MnV3Nix7N0IATNldNTrkvSASp2KR1Yt526HA==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.2",
- "postcss-selector-parser": "^7.1.1"
+ "postcss-selector-parser": "^7.1.2"
},
"engines": {
"node": "^22.11.0 || ^24.11.0 || >=26.0"
},
"peerDependencies": {
- "postcss": "^8.5.14"
+ "postcss": "^8.5.15"
}
},
"node_modules/supports-color": {
@@ -6092,13 +6037,12 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "license": "ISC",
- "peer": true
+ "license": "ISC"
},
"node_modules/ws": {
- "version": "8.20.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
- "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
diff --git a/package.json b/package.json
index c553e674..bcef20a1 100644
--- a/package.json
+++ b/package.json
@@ -27,9 +27,9 @@
"npm": "^11.6.1"
},
"devDependencies": {
- "cssnano": "^8.0.1",
+ "cssnano": "^8.0.2",
"postcss": "^8.5.15",
- "prettier": "^3.8.3",
+ "prettier": "^3.8.4",
"purgecss": "^8.0.0"
}
}