Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
/* eslint import/order: "off" */
/* eslint n/no-unpublished-require: "off" */
const Sentry = require('@sentry/node')
const {
APP_PORT,
ENV,
REDIS_URL,
SESSION_SECRET,
SENTRY_DSN
} = require('./config')

Sentry.init({
dsn: 'https://304866cea16570b04e2090537ae9ac77@o345774.ingest.us.sentry.io/4509252675371008',
sendDefaultPii: true
})
const isDev = ENV === 'development'
if (!isDev) {
Sentry.init({
dsn: SENTRY_DSN,
sendDefaultPii: false,
environment: ENV
})
}

const path = require('path')
const redisClient = require('./helpers/redis-client')
Expand All @@ -18,15 +29,12 @@ const RedisStore = require('connect-redis')(session)
const helmet = require('helmet')
const nunjucks = require('nunjucks')
const { xss } = require('express-xss-sanitizer')
const ApplicationError = require('./helpers/application-error')

const rev = require('./filters/rev')

const { APP_PORT, ENV, REDIS_URL, SESSION_SECRET } = require('./config')
const addComponentRoutes = require('./routes/add-component')

const app = express()
const isDev = ENV === 'development'

if (!isDev) {
// Only trust single proxy (Nginx)
Expand Down Expand Up @@ -55,7 +63,7 @@ const sessionOptions = {
secret: SESSION_SECRET,
resave: true,
saveUninitialized: true,
cookie: { secure: !isDev, maxAge: 24 * 60 * 60 * 1000 }
cookie: { secure: !isDev, maxAge: 24 * 60 * 60 * 1000 }
}

if (REDIS_URL) {
Expand Down Expand Up @@ -87,7 +95,7 @@ app.set('view engine', 'njk')
const njk = expressNunjucks(app, {
watch: isDev,
noCache: false,
loader: nunjucks.FileSystemLoader,
loader: nunjucks.FileSystemLoader
})

njk.env.addFilter('rev', rev)
Expand All @@ -107,9 +115,10 @@ app.use(xss())
app.use('/contribute/add-new-component', addComponentRoutes)

// Fallback route to 404
app.get('*', (req, res, next) => {
const error = new ApplicationError('Page not found', 404)
next(error)
app.use((req, res) => {
res.status(404).render('404', {
title: 'Page not found'
})
})

// The error handler must be registered before any other error middleware and after all controllers
Expand Down
44 changes: 44 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,34 @@ const config = {
GITHUB_REPO_NAME: process.env.GITHUB_REPO_NAME || 'your-default-repo-name',
NOTIFY_PR_TEMPLATE: process.env.NOTIFY_PR_TEMPLATE || '',
NOTIFY_SUBMISSION_TEMPLATE: process.env.NOTIFY_SUBMISSION_TEMPLATE || '',
NOTIFY_VERIFICATION_TEMPLATE: process.env.NOTIFY_VERIFICATION_TEMPLATE || '',
NOTIFY_EMAIL: process.env.NOTIFY_EMAIL || 'your-email',
NOTIFY_TOKEN: process.env.NOTIFY_TOKEN || 'your-default-repo-token',
NOTIFY_EMAIL_RETRY_MS:
parseInt(process.env.NOTIFY_EMAIL_RETRY_MS, 10) || 5000,
NOTIFY_EMAIL_MAX_RETRIES:
parseInt(process.env.NOTIFY_EMAIL_MAX_RETRIES, 10) || 5,
APP_URL: process.env.APP_URL,
APP_PORT: parseInt(process.env.APP_PORT, 10) || 3001,
REDIS_URL: process.env.REDIS_URL,
REDIS_AUTH_TOKEN: process.env.REDIS_AUTH_TOKEN,
REDIS_PORT: parseInt(process.env.REDIS_PORT, 10) || 6379,
SESSION_SECRET: process.env.SESSION_SECRET || 'your-secret-key',
ENV: process.env.ENV || 'development',
SENTRY_DSN: process.env.SENTRY_DSN,
ALLOWED_EMAIL_DOMAINS: ['justice.gov.uk'],
COMPONENT_FORM_PAGES: {
'email': {
title: 'Enter your email address',
fields: {
emailAddress: {
label: 'Email address',
hint: 'Enter an email address ending @justice.gov.uk'
}
},
showOnCya: false,
removable: false
},
'component-details': {
title: 'Component details',
fields: {
Expand Down Expand Up @@ -231,6 +246,35 @@ const config = {
SHARE_YOUR_DETAILS: {
addNameToComponentPage: 'add my name to the component page',
addTeamNameToComponentPage: 'add my team name to the component page'
},
MESSAGES: {
emailVerificationExpired: {
type: 'error',
title: 'Email verification link expired',
text: `Enter your email address below to receive a new verification link.`
},
emailVerificationSuccess: {
type: 'success',
title: 'Your email address has been verified',
text: 'You can now submit a new component'
},
emailVerificationInvalidToken: {
type: 'error',
title: 'Email verification link invalid',
text: `Enter your email address below to receive a new verification link.`
},
componentImageUploaded: (filename) => {
return {
type: 'success',
text: `File ‘${filename}’ has been uploaded.`
}
},
componentImageRemoved: (filename) => {
return {
type: 'success',
message: `File ‘${filename}’ has been removed.`
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion docs/_data/statusInfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"Experimental": {
"link": "How to use ‘experimental’ {{ types }}",
"linkContent": "Anyone can add an ‘experimental’ status {{ type }} to the MoJ Design System. They’re early in development and can be used as a starting point.",
"statusMessage": "Created"
"statusMessage": "Added"
},
"Archived": {
"link": "About ‘archived’ {{ types }}",
Expand Down
2 changes: 1 addition & 1 deletion docs/_includes/layouts/base.njk
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</div>
<div class="app-layout__page app-page {{ 'app-page--tabbed' if tabs }}">
{% block beforeContent %}{% endblock %}
<main id="main-content" class="app-prose-scope">
<main id="main-content" class="{{ 'app-prose-scope' if eleventy }}">
{% block content %}
{{ content | safe }}
{% endblock %}
Expand Down
4 changes: 2 additions & 2 deletions docs/_includes/layouts/partials/building-block-header.njk
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
status,
statusInfo[status],
statusDate,
creatorName,
creatorTeam
contributorName,
contributorTeam
) if statusInfo[status] }}
</div>
</div>
18 changes: 9 additions & 9 deletions docs/_includes/layouts/partials/page-header.njk
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@
text: title,
caption: subsection,
statusTag: { text: status } if status
}) }}
}) }}

{{ statusLabel(
type,
status,
statusInfo[status],
statusDate,
creatorName,
creatorTeam
) if statusInfo[status] }}
{{ statusLabel({
type: type,
status: status,
statusData: statusInfo[status],
statusDate: statusDate,
contributorName: contributorName,
contributorTeam: contributorTeam
}) if statusInfo[status] }}

{% if lede %}
<span class="govuk-caption-xl govuk-!-margin-top-8">{{ lede | safe }}</span>
Expand Down
4 changes: 2 additions & 2 deletions docs/_includes/macros/status-label/macro.njk
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{% macro statusLabel(type, status, statusData, statusDate, creatorName, creatorTeam) %}
{%- include "./template.njk" -%}
{% macro statusLabel(params) %}
{% include "./template.njk" %}
{% endmacro %}
34 changes: 14 additions & 20 deletions docs/_includes/macros/status-label/template.njk
Original file line number Diff line number Diff line change
@@ -1,44 +1,38 @@
{% from "govuk/components/details/macro.njk" import govukDetails %}

<!--
Arguments to be passed:
- type: {string} Variable from layout. Example values: "component", "page", "pattern", "archive".
- status: {string} Status of the item. Accepted values: "Official", "To be reviewed", "Experimental", "Archived".
- statusData: {object} Status data object (by status) from `_data/statusInfo.json` file.
- statusDate: {string} Date of creation (e.g., "Oct 2025").
- creatorName: {string} Name of the creator (e.g., "John Doe").
- creatorTeam: {string} Team responsible for the item (e.g., "MoJ").
-->

{% set statusAttribution -%}
{%- if status == "Experimental" %}
by {{ creatorName | default("someone") }} in {{ creatorTeam | default("the community") }}
{%- endif %}
{%- if statusDate %}
in {{ statusDate }}
{%- if params.status == "Experimental" %}
{%- if params.contributorTeam %}
by {{ params.contributorName | default("someone") }} in {{ params.contributorTeam }}
{%- elif params.contributorName %}
by {{ contributorName }}
{% endif %}
{% endif %}
{%- if params.statusDate %}
in {{ params.statusDate }}
{%- endif %}.
{%- endset %}

{% set typeSingular = type -%}
{% set typePlural = type + "s" -%}
{% set typeSingular = params.type -%}
{% set typePlural = params.type + "s" -%}

{% set linkText -%}
{{ statusData.link | renderString({
{{ params.statusData.link | renderString({
types: typePlural,
type: typeSingular
}) | upperFirst }}
{%- endset %}

{% set linkHtml -%}
{{ statusData.linkContent | renderString({
{{ params.statusData.linkContent | renderString({
types: typePlural,
type: typeSingular
}) | upperFirst }}
<a href="/design-system-statuses">Read about all the Design System statuses</a>.
{%- endset %}

<p class="app-status-message govuk-!-margin-bottom-2">
{{ statusData.statusMessage }} {{ statusAttribution }}
{{ params.statusData.statusMessage }} {{ statusAttribution }}
</p>

{{ govukDetails({
Expand Down
15 changes: 14 additions & 1 deletion docs/stylesheets/components/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@
@include govuk-responsive-padding(6);

@include govuk-media-query(app.$breakpoint) {
@include govuk-responsive-padding(9);
@include govuk-responsive-padding(9, 'top');
@include govuk-responsive-padding(9, 'right');
@include govuk-responsive-padding(9, 'left');
}
}

.app-layout__back-link {
position: absolute;
@include govuk-responsive-padding(6, 'right');
@include govuk-responsive-padding(6, 'left');

@include govuk-media-query(app.$breakpoint) {
@include govuk-responsive-padding(9, 'right');
@include govuk-responsive-padding(9, 'left');
}
}
Loading
Loading