@benwatsonuk/govuk-pages-plugin 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENCE.txt +21 -0
  3. package/README.md +192 -0
  4. package/dist/assets/images/arrow.svg +27 -0
  5. package/dist/assets/images/page-types/arrow-base.svg +13 -0
  6. package/dist/assets/images/page-types/arrow-head.svg +13 -0
  7. package/dist/assets/images/page-types/check-answers.svg +142 -0
  8. package/dist/assets/images/page-types/checkbox-input.svg +85 -0
  9. package/dist/assets/images/page-types/confirmation.svg +73 -0
  10. package/dist/assets/images/page-types/content-page.svg +84 -0
  11. package/dist/assets/images/page-types/email.svg +56 -0
  12. package/dist/assets/images/page-types/radio-input.svg +115 -0
  13. package/dist/assets/images/page-types/start-page.svg +101 -0
  14. package/dist/assets/images/page-types/task-list.svg +179 -0
  15. package/dist/assets/images/page-types/text-input.svg +65 -0
  16. package/dist/assets/javascripts/all.js +1 -0
  17. package/dist/assets/styles/all.scss +2 -0
  18. package/dist/assets/styles/scss/_pages.scss +169 -0
  19. package/dist/assets/styles/scss/_variables.scss +19 -0
  20. package/dist/functions/pages/getPages.js +9 -0
  21. package/dist/functions/stages/getStages.js +65 -0
  22. package/dist/index.js +39 -0
  23. package/dist/schema.json +89 -0
  24. package/dist/types.js +2 -0
  25. package/dist/validate.js +27 -0
  26. package/dist/views/page-index.html +34 -0
  27. package/dist/views/stage-index.html +41 -0
  28. package/govuk-prototype-kit.config.json +12 -0
  29. package/index.js +22 -0
  30. package/package.json +43 -0
  31. package/src/assets/images/arrow.svg +27 -0
  32. package/src/assets/images/page-types/arrow-base.svg +13 -0
  33. package/src/assets/images/page-types/arrow-head.svg +13 -0
  34. package/src/assets/images/page-types/check-answers.svg +142 -0
  35. package/src/assets/images/page-types/checkbox-input.svg +85 -0
  36. package/src/assets/images/page-types/confirmation.svg +73 -0
  37. package/src/assets/images/page-types/content-page.svg +84 -0
  38. package/src/assets/images/page-types/email.svg +56 -0
  39. package/src/assets/images/page-types/radio-input.svg +115 -0
  40. package/src/assets/images/page-types/start-page.svg +101 -0
  41. package/src/assets/images/page-types/task-list.svg +179 -0
  42. package/src/assets/images/page-types/text-input.svg +65 -0
  43. package/src/assets/javascripts/all.js +1 -0
  44. package/src/assets/styles/all.scss +2 -0
  45. package/src/assets/styles/scss/_pages.scss +169 -0
  46. package/src/assets/styles/scss/_variables.scss +19 -0
  47. package/src/functions/pages/getPages.ts +7 -0
  48. package/src/functions/stages/getStages.ts +78 -0
  49. package/src/index.ts +40 -0
  50. package/src/schema.json +89 -0
  51. package/src/types.ts +40 -0
  52. package/src/validate.ts +35 -0
  53. package/src/views/page-index.html +34 -0
  54. package/src/views/stage-index.html +41 -0
  55. package/test/data/outputs.ts +197 -0
  56. package/test/data/pages.ts +61 -0
  57. package/test/data/stages.ts +87 -0
  58. package/test/getPages.test.js +19 -0
  59. package/test/getStages.test.js +46 -0
  60. package/tsconfig.json +14 -0
@@ -0,0 +1,65 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="200px" height="160px" viewBox="0 0 200 160" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
4
+ <title>Question page/Text input</title>
5
+ <desc>Created with Sketch.</desc>
6
+ <defs>
7
+ <rect x="2" y="4" width="8.99672131" height="8" id="rect-1"></rect>
8
+ </defs>
9
+ <g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
10
+ <g id="Screen/Question-page/Text-input">
11
+ <g id="Question-page/Text-input">
12
+ <g id="_Canvas/Browser">
13
+ <rect id="BG" fill="#FFFFFF" x="1" y="1" width="196" height="156"></rect>
14
+ <rect id="Top-Bar" fill="#F2F2F2" x="1" y="1" width="196" height="11"></rect>
15
+ <rect id="Divider" fill="#DEE0E2" x="1" y="11" width="196" height="1"></rect>
16
+ <path d="M7.96153846,8 C6.87821068,8 6,7.1045695 6,6 C6,4.8954305 6.87821068,4 7.96153846,4 C9.04486624,4 9.92307692,4.8954305 9.92307692,6 C9.92307692,7.1045695 9.04486624,8 7.96153846,8 Z M14.5,8 C13.4166722,8 12.5384615,7.1045695 12.5384615,6 C12.5384615,4.8954305 13.4166722,4 14.5,4 C15.5833278,4 16.4615385,4.8954305 16.4615385,6 C16.4615385,7.1045695 15.5833278,8 14.5,8 Z M21.0384615,8 C19.9551338,8 19.0769231,7.1045695 19.0769231,6 C19.0769231,4.8954305 19.9551338,4 21.0384615,4 C22.1217893,4 23,4.8954305 23,6 C23,7.1045695 22.1217893,8 21.0384615,8 Z" id="Combined-Shape" fill="#DEE0E2"></path>
17
+ <polygon id="BG_Border_Top_2B99C93C-C2D2-47D8-92D7-E97EC61A7761" fill="#0B0C0C" points="0 0 200 0 197 1 1 1"></polygon>
18
+ <polygon id="BG_Border_Right_2B99C93C-C2D2-47D8-92D7-E97EC61A7761" fill="#0B0C0C" points="200 0 200 160 197 157 197 1"></polygon>
19
+ <polygon id="BG_Border_Bottom_2B99C93C-C2D2-47D8-92D7-E97EC61A7761" fill="#0B0C0C" points="200 160 0 160 1 157 197 157"></polygon>
20
+ <polygon id="BG_Border_Left_2B99C93C-C2D2-47D8-92D7-E97EC61A7761" fill="#0B0C0C" points="0 160 0 0 1 1 1 157"></polygon>
21
+ </g>
22
+ <g id="Button/Primary" transform="translate(5.000000, 92.000000)" fill="#00823B">
23
+ <g id="Fill/$button-colour">
24
+ <rect id="Rectangle" x="0" y="0" width="32" height="8"></rect>
25
+ </g>
26
+ </g>
27
+ <g id="Text/Heading/Large" transform="translate(5.000000, 44.000000)" fill="#0B0C0C">
28
+ <g id="Fill/$text-colour">
29
+ <rect id="Rectangle" x="0" y="0" width="120" height="12"></rect>
30
+ </g>
31
+ </g>
32
+ <g id="Object/Header" transform="translate(3.000000, 12.000000)">
33
+ <g id="👑Crown">
34
+ <image x="2" y="4" width="8.99672131" height="8" xlink:href="data:image/png;base64,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"></image>
35
+ <use fill="#0B0C0C" fill-rule="evenodd" xlink:href="#rect-1"></use>
36
+ </g>
37
+ <text id="🖊️Global_Header_Text" font-family="Helvetica" font-size="8" font-weight="normal" fill="#0B0C0C">
38
+ <tspan x="13" y="11">GOV.UK</tspan>
39
+ </text>
40
+ <g id="Fill/$link-colour" transform="translate(2.000000, 15.000000)" fill="#005EA5" fill-rule="evenodd">
41
+ <rect id="Rectangle" x="0" y="0" width="188" height="1"></rect>
42
+ </g>
43
+ </g>
44
+ <g id="Question/Text-input" transform="translate(5.000000, 64.000000)">
45
+ <g id="Form/Text-input" transform="translate(0.000000, 8.000000)">
46
+ <g id="Fill/$black" fill="#0B0C0C">
47
+ <rect id="Rectangle" x="0" y="0" width="96" height="12"></rect>
48
+ </g>
49
+ <rect id="Inside" fill="#FFFFFF" x="2" y="2" width="92" height="8"></rect>
50
+ </g>
51
+ <g id="Form/Label" fill="#0B0C0C">
52
+ <g id="Fill/$text-colour">
53
+ <rect id="Rectangle" x="0" y="0" width="64" height="4"></rect>
54
+ </g>
55
+ </g>
56
+ </g>
57
+ <g id="Object/Back" transform="translate(5.000000, 32.000000)" fill="#6F777B">
58
+ <g id="Fill/$secondary-text-colour">
59
+ <rect id="Rectangle" x="0" y="0" width="16" height="2"></rect>
60
+ </g>
61
+ </g>
62
+ </g>
63
+ </g>
64
+ </g>
65
+ </svg>
@@ -0,0 +1 @@
1
+ console.log("Page Flow Plugin loaded");
@@ -0,0 +1,2 @@
1
+ @import "scss/variables";
2
+ @import "scss/pages";
@@ -0,0 +1,169 @@
1
+ .govuk-pages-plugin {
2
+
3
+ .screenPreviewContainer {
4
+ height: 400px;
5
+ overflow: hidden;
6
+ border: 1px solid #000;
7
+ .screenPreview {
8
+ width: 200%;
9
+ height: 800px;
10
+ transform: scale(0.5);
11
+ transform-origin: 0 0;
12
+ background: none;
13
+ border: 0;
14
+ }
15
+ }
16
+
17
+ .page-flow-feedback {
18
+ &--positive {
19
+ color: #00a33b;
20
+ }
21
+ &--negative {
22
+ color: #a33038;
23
+ }
24
+ }
25
+
26
+ .page-flow--stages, .user-flow--stages {
27
+ @extend .govuk-body;
28
+ padding: 0;
29
+ }
30
+ .user-flow-item--stage {
31
+ display: inline-block;
32
+ }
33
+
34
+ .user-flow-page-item {
35
+ border-top: 1px solid #333;
36
+ padding-top:1em;
37
+ //margin-bottom: 2em;
38
+ }
39
+
40
+ .page-flow-item--stage, .user-flow-item--stage {
41
+ border-top: 10px solid;
42
+ .page-flow-stage-descriptor {
43
+ padding: 2px 10px;
44
+ display: block;
45
+ //padding: 5px;
46
+ }
47
+ &--1 {
48
+ border-color: $stage-color--1;
49
+ }
50
+ &--2 {
51
+ border-color: $stage-color--2;
52
+ }
53
+ &--3 {
54
+ border-color: $stage-color--3;
55
+ }
56
+ &--4 {
57
+ border-color: $stage-color--4;
58
+ }
59
+ &--authentication {
60
+ border-color: $stage-color--authentication;
61
+ }
62
+ &--documents {
63
+ border-color: $stage-color--documents;
64
+ }
65
+ &--notifications, &--notifications {
66
+ border-color: $stage-color--notifications;
67
+ }
68
+ &:last-of-type {
69
+ .page-flow-item--page{
70
+ &:last-of-type {
71
+ &:before {
72
+ display: none;
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ .page-flow--pages, .user-flow--pages {
80
+ @extend .govuk-body;
81
+ padding: 0;
82
+ .page-flow-item--page {
83
+ display: inline-block;
84
+ font-size: 14px;
85
+ width: 130px;
86
+ //min-height: 200px;
87
+ vertical-align: top;
88
+ position: relative;
89
+ .page-flow-item-screen-icon {
90
+ width: 100px;
91
+ height: 100px;
92
+ display: block;
93
+ background-repeat: no-repeat;
94
+ &--email {
95
+ background-image: url($icons + '/email.svg');
96
+ -webkit-background-size: contain;
97
+ background-size: contain;
98
+ }
99
+ &--text-input {
100
+ background-image: url($icons + '/text-input.svg');
101
+ -webkit-background-size: contain;
102
+ background-size: contain;
103
+ }
104
+ &--dashboard, &--content-page {
105
+ background-image: url($icons + '/content-page.svg');
106
+ -webkit-background-size: contain;
107
+ background-size: contain;
108
+ }
109
+ &--radio-input {
110
+ background-image: url($icons + '/radio-input.svg');
111
+ -webkit-background-size: contain;
112
+ background-size: contain;
113
+ }
114
+ &--checkbox-input {
115
+ background-image: url($icons + '/checkbox-input.svg');
116
+ -webkit-background-size: contain;
117
+ background-size: contain;
118
+ }
119
+ &--check-answers {
120
+ background-image: url($icons + '/check-answers.svg');
121
+ -webkit-background-size: contain;
122
+ background-size: contain;
123
+ }
124
+ &--confirmation {
125
+ background-image: url($icons + '/confirmation.svg');
126
+ -webkit-background-size: contain;
127
+ background-size: contain;
128
+ }
129
+ &--task-list {
130
+ background-image: url($icons + '/task-list.svg');
131
+ -webkit-background-size: contain;
132
+ background-size: contain;
133
+ }
134
+ &--start-page {
135
+ background-image: url($icons + '/start-page.svg');
136
+ -webkit-background-size: contain;
137
+ background-size: contain;
138
+ }
139
+ &--checkbox-page {
140
+ background-image: url($icons + '/checkbox-page.svg');
141
+ -webkit-background-size: contain;
142
+ background-size: contain;
143
+ }
144
+ }
145
+ }
146
+ }
147
+ .user-flow--pages {
148
+ @extend .page-flow--pages;
149
+ .page-flow-item--page {
150
+ display: inline-block;
151
+ font-size: 14px;
152
+ width: 170px;
153
+ //min-height: 200px;
154
+ vertical-align: top;
155
+ position: relative;
156
+
157
+ &:before {
158
+ content: "";
159
+ position: absolute;
160
+ background: url($page-flow-images + '/arrow.svg') no-repeat;
161
+ background-size: contain;
162
+ width: 78px;
163
+ left: 92px;
164
+ height: 20px;
165
+ top: 35px;
166
+ }
167
+ }
168
+ }
169
+ }
@@ -0,0 +1,19 @@
1
+ // Assets - these can all be overridden
2
+ $page-flow-assets: '/extension-assets/govuk-page-flow-plugin/app/assets/';
3
+ $page-flow-images: $page-flow-assets + 'images/';
4
+ $icons: $page-flow-images + 'page-types';
5
+
6
+ // Stock colours for stages
7
+ $stage-color--1: #006c56;
8
+ $stage-color--2: #00beb7;
9
+ $stage-color--3: pink;
10
+ $stage-color--4: #f47738;
11
+ $stage-color--5: #ccc;
12
+ $stage-color--6: #005ea5;
13
+ $stage-color--7: #004432;
14
+ $stage-color--8: #f47738;
15
+ $stage-color--9: #3b1f5f;
16
+ $stage-color--10: #ffdd00;
17
+ $stage-color--documents: purple;
18
+ $stage-color--notifications: teal;
19
+ $stage-color--authentication: crimson;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPages = void 0;
4
+ const validate_1 = require("../../validate");
5
+ const getPages = (pages) => {
6
+ const validatedPages = (0, validate_1.validatePagesArray)(pages);
7
+ return validatedPages;
8
+ };
9
+ exports.getPages = getPages;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapPagesToStages = exports.getStagesWithPages = exports.getStages = void 0;
4
+ const validate_1 = require("../../validate");
5
+ // Get and validate stages from the provided input
6
+ const getStages = (stages) => {
7
+ const validatedStages = (0, validate_1.validateStagesArray)(stages);
8
+ return validatedStages;
9
+ };
10
+ exports.getStages = getStages;
11
+ // Get and validate stages and relevant pages from the provided input. Return an array of Stage objects containing relevant pages.
12
+ const getStagesWithPages = (stages, pages) => {
13
+ const validatedStages = (0, validate_1.validateStagesArray)(stages);
14
+ const validatedPages = (0, validate_1.validatePagesArray)(pages);
15
+ return (0, exports.mapPagesToStages)(validatedStages, validatedPages);
16
+ };
17
+ exports.getStagesWithPages = getStagesWithPages;
18
+ // Below this point is just the helper function used internally for the above functions
19
+ // This function does the heavy lifting of mapping pages to their relevant stages
20
+ const mapPagesToStages = (stages, pages) => {
21
+ let allPages = [...pages]; // Create a copy to avoid mutating the original
22
+ const stagesWithPages = stages.map((stage) => {
23
+ // Filter pages that belong to this stage
24
+ const pagesForStage = pages.filter((page) => page.stage && page.stage.main === stage.id);
25
+ // Only add the stage if it has pages (after all, why return empty stages?)
26
+ if (pagesForStage.length > 0) {
27
+ // Remove the filtered pages from allPages to get unused pages
28
+ allPages = allPages.filter(page => !pagesForStage.some(p => p.id === page.id));
29
+ // Map sub-stages with their relevant pages
30
+ let subStagesWithPages;
31
+ if (stage.subStages) {
32
+ subStagesWithPages = stage.subStages.map((subStage) => {
33
+ // Filter pages that belong to this sub-stage
34
+ const pagesForSubStage = pagesForStage.filter((page) => page.stage && page.stage.subStage === subStage.id);
35
+ if (pagesForSubStage.length > 0) {
36
+ return {
37
+ id: subStage.id,
38
+ title: subStage.title,
39
+ description: subStage.description,
40
+ pages: pagesForSubStage
41
+ };
42
+ }
43
+ }).filter(subStage => subStage !== undefined);
44
+ }
45
+ return {
46
+ id: stage.id,
47
+ title: stage.title,
48
+ description: stage.description,
49
+ subStages: subStagesWithPages,
50
+ pages: pagesForStage
51
+ };
52
+ }
53
+ }).filter(stage => stage !== undefined);
54
+ // add allPages to a misc category and bolt on to stagesWithPages
55
+ if (allPages.length > 0) {
56
+ stagesWithPages.push({
57
+ id: "unassigned",
58
+ title: "Unassigned",
59
+ description: "Pages not assigned to any stage or sub-stage",
60
+ pages: allPages
61
+ });
62
+ }
63
+ return stagesWithPages;
64
+ };
65
+ exports.mapPagesToStages = mapPagesToStages;
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.govukPagesPlugin = exports.stageIndex = exports.stageIndexData = exports.pageIndex = exports.pageIndexData = void 0;
4
+ const express_1 = require("express");
5
+ const getPages_1 = require("./functions/pages/getPages");
6
+ const getStages_1 = require("./functions/stages/getStages");
7
+ /*--- UTILITIES (used by supplied routes AND made available to plugin users) ---*/
8
+ const pageIndexData = (pages) => {
9
+ return (0, getPages_1.getPages)(pages);
10
+ };
11
+ exports.pageIndexData = pageIndexData;
12
+ const pageIndex = (pages, pageType) => {
13
+ pageType = pageType || "page-index";
14
+ return (req, res) => {
15
+ res.render(pageType, { pages: pages });
16
+ };
17
+ };
18
+ exports.pageIndex = pageIndex;
19
+ const stageIndexData = (stages, pages) => {
20
+ return (0, getStages_1.getStagesWithPages)(stages, pages);
21
+ };
22
+ exports.stageIndexData = stageIndexData;
23
+ const stageIndex = (stages, pages, pageType) => {
24
+ pageType = pageType || "stage-index";
25
+ return (req, res) => {
26
+ res.render(pageType, { stages: (0, exports.stageIndexData)(stages, pages) });
27
+ };
28
+ };
29
+ exports.stageIndex = stageIndex;
30
+ // Add user flows, etc here later
31
+ /*--- THE MAIN USER ROUTES ---*/
32
+ const govukPagesPlugin = (pages, stages, pageType) => {
33
+ pageType = pageType || "page-index"; // Options can be 'all', 'page-index', 'stage-index' - in future could be 'user-flow-index', etc
34
+ const router = (0, express_1.Router)();
35
+ // This is the default offering from the plugin - it is expected that must users will use this. It should be robust
36
+ router.get("/", (0, exports.pageIndex)((0, exports.pageIndexData)(pages), pageType));
37
+ return router;
38
+ };
39
+ exports.govukPagesPlugin = govukPagesPlugin;
@@ -0,0 +1,89 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "required": ["mode"],
5
+ "properties": {
6
+ "mode": {
7
+ "type": "string",
8
+ "enum": ["pages", "stages"]
9
+ }
10
+ },
11
+ "allOf": [
12
+ {
13
+ "if": {
14
+ "properties": { "mode": { "const": "pages" } }
15
+ },
16
+ "then": { "$ref": "#/definitions/pages" },
17
+ "else": { "$ref": "#/definitions/stages" }
18
+ }
19
+ ],
20
+ "definitions": {
21
+ "pages": {
22
+ "type": "object",
23
+ "required": ["mode", "pages"],
24
+ "properties": {
25
+ "mode": { "const": "pages" },
26
+ "pages": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "object",
30
+ "required": ["id", "title", "route"],
31
+ "properties": {
32
+ "id": { "type": "integer" },
33
+ "title": { "type": "string" },
34
+ "route": { "type": "string" },
35
+ "type": { "type": ["string", "null"] },
36
+ "stage": {
37
+ "type": ["object"],
38
+ "properties": {
39
+ "main": { "type": ["string"] },
40
+ "subStage": { "type": ["integer", "string"] }
41
+ },
42
+ "additionalProperties": false
43
+ },
44
+ "description": { "type": ["string", "null"] }
45
+ },
46
+ "additionalProperties": true
47
+ }
48
+ }
49
+ },
50
+ "additionalProperties": false
51
+ },
52
+ "stages": {
53
+ "type": "object",
54
+ "required": ["mode", "stages"],
55
+ "properties": {
56
+ "mode": { "const": "stages" },
57
+ "stages": {
58
+ "type": "array",
59
+ "items": {
60
+ "type": "object",
61
+ "required": ["id", "title", "route"],
62
+ "properties": {
63
+ "id": { "type": "string" },
64
+ "title": { "type": "string" },
65
+ "route": { "type": "string" },
66
+ "description": { "type": ["string", "null"] },
67
+ "subStages": {
68
+ "type": "array",
69
+ "items": {
70
+ "type": "object",
71
+ "required": ["id", "title"],
72
+ "properties": {
73
+ "id": { "type": ["string", "integer"] },
74
+ "title": { "type": "string" },
75
+ "route": { "type": "string" },
76
+ "description": { "type": ["string", "null"] }
77
+ },
78
+ "additionalProperties": true
79
+ }
80
+ }
81
+ },
82
+ "additionalProperties": true
83
+ }
84
+ }
85
+ },
86
+ "additionalProperties": false
87
+ }
88
+ }
89
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.validatePagesArray = validatePagesArray;
7
+ exports.validateStagesArray = validateStagesArray;
8
+ const ajv_1 = __importDefault(require("ajv"));
9
+ const schema_json_1 = __importDefault(require("./schema.json"));
10
+ const ajv = new ajv_1.default({ allErrors: true, strict: false });
11
+ const validate = ajv.compile(schema_json_1.default);
12
+ function validatePagesArray(pages) {
13
+ var _a;
14
+ if (!validate({ mode: "pages", pages: pages })) {
15
+ const message = (_a = validate.errors) === null || _a === void 0 ? void 0 : _a.map(err => `${err.instancePath || "Pages"} ${err.message}`).join("\n");
16
+ throw new Error(`Invalid array of PAGES passed to govuk-pages-plugin - please check the documentation to ensure the JSON schema you are passing matches what is expected:\n${message}`);
17
+ }
18
+ return pages;
19
+ }
20
+ function validateStagesArray(stages) {
21
+ var _a;
22
+ if (!validate({ mode: "stages", stages: stages })) {
23
+ const message = (_a = validate.errors) === null || _a === void 0 ? void 0 : _a.map(err => `${err.instancePath || "Stages"} ${err.message}`).join("\n");
24
+ throw new Error(`Invalid array of STAGES passed to govuk-pages-plugin - please check the documentation to ensure the JSON schema you are passing matches what is expected:\n${message}`);
25
+ }
26
+ return stages;
27
+ }
@@ -0,0 +1,34 @@
1
+ {% extends "layouts/main.html" %}
2
+
3
+ {% block pageTitle %}
4
+ Page Index
5
+ {% endblock %}
6
+
7
+ {% block beforeContent %}
8
+ {% from "govuk/components/back-link/macro.njk" import govukBackLink %}
9
+
10
+ {{ govukBackLink({
11
+ text: "Back",
12
+ href: "javascript:history.back(-1);"
13
+ }) }}
14
+ {% endblock %}
15
+
16
+ {% block content %}
17
+
18
+ <div class="page-index ">
19
+ <h1 class="govuk-heading-l">Page Index</h1>
20
+ {% from "govuk/components/details/macro.njk" import govukDetails %}
21
+
22
+ {{ govukDetails({
23
+ summaryText: "What is the 'Page Index'?",
24
+ html: "<p>This page contains links to tracked pages in this prototype. It is useful for navigating the prototype without having to go through flows.</p><p class='govuk-body-s'> Note, the prototype might contain more pages than are listed here.</p>"
25
+ }) }}
26
+
27
+ <ul class="govuk-list govuk-list--number">
28
+ {% for page in pages %}
29
+ <li><a href="{{ page.route }}">{{ page.title }}</a></li>
30
+ {% endfor %}
31
+ </ul>
32
+ </div>
33
+
34
+ {% endblock %}
@@ -0,0 +1,41 @@
1
+ {% extends "layouts/main.html" %}
2
+
3
+ {% block pageTitle %}
4
+ Stage Index
5
+ {% endblock %}
6
+
7
+ {% block beforeContent %}
8
+ {% from "govuk/components/back-link/macro.njk" import govukBackLink %}
9
+
10
+ {{ govukBackLink({
11
+ text: "Back",
12
+ href: "javascript:history.back(-1);"
13
+ }) }}
14
+ {% endblock %}
15
+
16
+ {% block content %}
17
+
18
+ <div class="page-index ">
19
+ <h1 class="govuk-heading-l">Stage Index</h1>
20
+ {% from "govuk/components/details/macro.njk" import govukDetails %}
21
+
22
+ {{ govukDetails({
23
+ summaryText: "What is the 'Stage Index'?",
24
+ html: "<p>This page contains links to tracked pages in this prototype, these pages are grouped by the 'stages' that they are assigned to. It is useful for navigating the prototype without having to go through flows.</p><p>'Stages' are defined by the plugin user but can be throught about as logical groups of pages that work to achieve a common goal, such as 'authenticating' or 'registering'.</p><p class='govuk-body-s'> Note, the prototype might contain more pages than are listed here.</p>"
25
+ }) }}
26
+ <!-- {{ stages | dump }} -->
27
+ {% for stage in stages %}
28
+ <h2>{{ stage.title }}</h2>
29
+ {% if stage.description %}
30
+ <p class="govuk-body-s">{{ stage.description }}</p>
31
+ {% endif %}
32
+ <ol>
33
+ {% for page in stage.pages %}
34
+ <li><a href="{{ page.route }}">{{ page.title }}</a>{% if page.description %} - <span class="govuk-body-s">{{ page.description }}</span> {% endif %}</li>
35
+ {% endfor %}
36
+ </ol>
37
+ <hr/>
38
+ {% endfor %}
39
+ </div>
40
+
41
+ {% endblock %}
@@ -0,0 +1,12 @@
1
+ {
2
+ "meta": {
3
+ "description": "This plugin provides the ability to list desired pages in an index or user-flow view."
4
+ },
5
+ "nunjucksPaths": ["/dist/views"],
6
+ "assets": [
7
+ "/dist/assets"
8
+ ],
9
+ "sass": [
10
+ "/dist/assets/styles/all.scss"
11
+ ]
12
+ }
package/index.js ADDED
@@ -0,0 +1,22 @@
1
+ module.exports = (router) => {
2
+ /**
3
+ * Start url
4
+ *
5
+ * Redirects a user to the start of our journey
6
+ *
7
+ */
8
+ router.get("/dwp-alternative-formats-plugin/start", (req, res) => {
9
+ res.redirect("/dwp-alternative-formats-plugin/v2/journey-1/");
10
+ });
11
+ /**
12
+ * Clear data
13
+ *
14
+ * Clears only alternative formats dwp-alternative-formats-plugin/v1/journey-3 data
15
+ *
16
+ */
17
+ router.post("/dwp-alternative-formats-plugin/v2/journey-1/clear-data", (req, res) => {
18
+ req.session.data.altFormatsV2Journey1 = {};
19
+
20
+ res.redirect("./clear-data-success");
21
+ });
22
+ };
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@benwatsonuk/govuk-pages-plugin",
3
+ "author": "BenWatsonUK",
4
+ "description": "A plugin to visualise selected pages of a GOV.UK prototype with a linear user journey or page index.",
5
+ "version": "1.0.0",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "homepage": "https://github.com/benwatsonuk/govuk-pages-plugin",
9
+ "bugs": {
10
+ "url": "https://github.com/benwatsonuk/govuk-pages-plugin/issues"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/benwatsonuk/govuk-pages-plugin.git"
15
+ },
16
+ "scripts": {
17
+ "test": "mocha --require ts-node/register",
18
+ "clean": "rimraf dist",
19
+ "build": "npm run clean && tsc && cpx \"src/{assets,views}/**/*\" dist"
20
+ },
21
+ "dependencies": {
22
+ "express": "^4.18.2",
23
+ "nunjucks": "^3.2.4"
24
+ },
25
+ "devDependencies": {
26
+ "@types/express": "^5.0.6",
27
+ "@types/mocha": "^10.0.10",
28
+ "@types/node": "^25.0.8",
29
+ "ajv": "^8.17.1",
30
+ "chai": "^4.3.7",
31
+ "cpx": "^1.5.0",
32
+ "json-schema-to-typescript": "^15.0.4",
33
+ "mocha": "^10.2.0",
34
+ "nyc": "^15.1.0",
35
+ "rimraf": "^6.1.2",
36
+ "ts-node": "^10.9.2",
37
+ "typescript": "^5.9.3"
38
+ },
39
+ "license": "MIT",
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }