@planning-inspectorate/dynamic-forms 1.8.0 → 1.9.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planning-inspectorate/dynamic-forms",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "This package is for building GDS forms using a configuration-based approach.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -1,12 +1,12 @@
1
1
  {% extends layoutTemplate %}
2
2
 
3
- {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
4
- {% from "govuk/components/textarea/macro.njk" import govukTextarea %}
5
- {% from "govuk/components/label/macro.njk" import govukLabel %}
6
3
  {% from "govuk/components/button/macro.njk" import govukButton %}
7
4
  {% from "govuk/components/checkboxes/macro.njk" import govukCheckboxes %}
8
- {% from "govuk/components/inset-text/macro.njk" import govukInsetText %}
5
+ {% from "govuk/components/details/macro.njk" import govukDetails %}
6
+ {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
7
+ {% from "govuk/components/label/macro.njk" import govukLabel %}
9
8
  {% from "govuk/components/table/macro.njk" import govukTable %}
9
+ {% from "govuk/components/textarea/macro.njk" import govukTextarea %}
10
10
 
11
11
  {% block before_content %}
12
12
  <div class="govuk-grid-row">
@@ -24,14 +24,9 @@
24
24
  {{ super() }}
25
25
  {% endblock before_content %}
26
26
 
27
- {% set columnWidth = 'govuk-grid-column-two-thirds' %}
28
- {% if showSuggestionsUi %}
29
- {% set columnWidth = 'govuk-grid-column-one-half' %}
30
- {% endif %}
31
-
32
27
  {% block content %}
33
28
  <div class="govuk-grid-row">
34
- <div class="{{ columnWidth }}">
29
+ <div class="govuk-grid-column-two-thirds">
35
30
  <form action="" method="post" novalidate>
36
31
  <input type="hidden" name="_csrf" value="{{ _csrf }}">
37
32
 
@@ -53,15 +48,59 @@
53
48
  {% include question.html ignore missing %}
54
49
  {% endif %}
55
50
 
56
- <label class="govuk-label govuk-label--s govuk-!-margin-top-5" for="{{ question.fieldName }}-unredacted">
57
- Original
58
- <a href="#" class="govuk-link govuk-!-margin-left-2" id="toggle-original">Hide</a>
59
- </label>
51
+ {% if showSuggestionsUi %}
52
+ <h2 class="govuk-heading-m">Redaction suggestions</h2>
53
+ {% set hasSuggestions = redactionSuggestions.length > 0 %}
54
+ {% if hasSuggestions %}
55
+ <p class="govuk-body">
56
+ We have suggested some common redactions and hidden these for you.
57
+ To make these visible again, 'Reject' each suggestion.
58
+ </p>
59
+ {% set suggestionTableRows = [] %}
60
+ {% for s in redactionSuggestions %}
61
+ {% set category = s.category %}
62
+ {% if s.subCategory %}
63
+ {% set category = category + " (" + s.subCategory + ")" %}
64
+ {% endif %}
65
+ {% set action = 'Accept' %}
66
+ {% if s.accepted %}
67
+ {% set action = 'Reject' %}
68
+ {% endif %}
69
+ {% set suggestionTableRows = (suggestionTableRows.push([
70
+ {text: s.text},
71
+ {text: category },
72
+ {
73
+ html: '<a href="#" class="govuk-link" data-redact="suggestion-reject-' + loop.index0 + '">' + action + '</a>'
74
+ }
75
+ ]), suggestionTableRows) %}
76
+ {% endfor %}
77
+ {{ govukTable({
78
+ head: [
79
+ {
80
+ text: "Redaction suggestion"
81
+ },
82
+ {
83
+ text: "Type of information"
84
+ },
85
+ {
86
+ text: "Action"
87
+ }
88
+ ],
89
+ rows: suggestionTableRows
90
+ }) }}
91
+ {% else %}
92
+ <p class="govuk-body">
93
+ No redaction suggestions found.
94
+ </p>
95
+ {% endif %}
96
+ {% endif %}
60
97
 
61
- {{ govukInsetText({
98
+ <h2 class="govuk-heading-m">Redaction preview</h2>
99
+
100
+ {{ govukDetails({
101
+ summaryText: question.summaryText or "Original",
62
102
  html: question.value,
63
- id: question.fieldName + "-unredacted",
64
- classes: "govuk-!-margin-top-0"
103
+ id: question.fieldName + "-unredacted"
65
104
  }) }}
66
105
 
67
106
  {{ govukTextarea({
@@ -75,7 +114,11 @@
75
114
  errorMessage: errors[question.fieldName] and {
76
115
  text: errors[question.fieldName].msg
77
116
  },
78
- classes: question.inputClasses
117
+ classes: question.inputClasses,
118
+ attributes: {
119
+ readonly: true
120
+ },
121
+ rows: textAreaRows or 8
79
122
  }) }}
80
123
 
81
124
  <div class="govuk-button-group">
@@ -108,48 +151,6 @@
108
151
  }) }}
109
152
  </form>
110
153
  </div>
111
- {% if showSuggestionsUi %}
112
- <div class="govuk-grid-column-one-half">
113
- <h2 class="govuk-heading-m">Redaction suggestions</h2>
114
- <p class="govuk-body">
115
- This section includes system suggestions for redactions.
116
- Each row shows the text that is suggested for redaction and the category detected.
117
- They are all redacted by default, you can reject any that should not be redacted by clicking the "Reject" link next to each suggestion.
118
- </p>
119
- {% set suggestionTableRows = [] %}
120
- {% for s in redactionSuggestions %}
121
- {% set category = s.category %}
122
- {% if s.subCategory %}
123
- {% set category = category + " (" + s.subCategory + ")" %}
124
- {% endif %}
125
- {% set action = 'Accept' %}
126
- {% if s.accepted %}
127
- {% set action = 'Reject' %}
128
- {% endif %}
129
- {% set suggestionTableRows = (suggestionTableRows.push([
130
- {text: s.text},
131
- {text: category },
132
- {
133
- html: '<a href="#" class="govuk-link" data-redact="suggestion-reject-' + loop.index0 + '">' + action + '</a>'
134
- }
135
- ]), suggestionTableRows) %}
136
- {% endfor %}
137
- {{ govukTable({
138
- head: [
139
- {
140
- text: "Text"
141
- },
142
- {
143
- text: "Category"
144
- },
145
- {
146
- text: "Action"
147
- }
148
- ],
149
- rows: suggestionTableRows
150
- }) }}
151
- </div>
152
- {% endif %}
153
154
 
154
155
  <script {% if cspNonce %}nonce={{ cspNonce }}{% endif %}>
155
156
  /**
@@ -27,8 +27,18 @@ export default class TextEntryRedactQuestion extends Question {
27
27
  * @param {string|undefined} [params.label] if defined this show as a label for the input and the question will just be a standard h1
28
28
  * @param {boolean} [params.onlyShowRedactedValueForSummary] whether to only show redacted value for summary
29
29
  * @param {boolean} [params.useRedactedFieldNameForSave] whether to use the redacted field name when saving answers
30
+ * @param {boolean} [params.showSuggestionsUi] use the suggestions UI for this question
31
+ * @param {string} [params.summaryText] summaryText to use with the details component
30
32
  */
31
- constructor({ textEntryCheckbox, label, onlyShowRedactedValueForSummary, useRedactedFieldNameForSave, ...params }) {
33
+ constructor({
34
+ textEntryCheckbox,
35
+ label,
36
+ onlyShowRedactedValueForSummary,
37
+ useRedactedFieldNameForSave,
38
+ showSuggestionsUi,
39
+ summaryText,
40
+ ...params
41
+ }) {
32
42
  super({
33
43
  ...params,
34
44
  viewFolder: 'text-entry-redact'
@@ -38,6 +48,8 @@ export default class TextEntryRedactQuestion extends Question {
38
48
  this.label = label;
39
49
  this.onlyShowRedactedValueForSummary = onlyShowRedactedValueForSummary;
40
50
  this.useRedactedFieldNameForSave = useRedactedFieldNameForSave;
51
+ this.showSuggestionsUi = showSuggestionsUi;
52
+ this.summaryText = summaryText;
41
53
  }
42
54
 
43
55
  async getDataToSave(req, journeyResponse) {
@@ -58,6 +70,8 @@ export default class TextEntryRedactQuestion extends Question {
58
70
  viewModel.question.value = payload ? payload[viewModel.question.fieldName] : viewModel.question.value;
59
71
  viewModel.question.valueRedacted =
60
72
  journey.response.answers[this.fieldName + 'Redacted'] || viewModel.question.value;
73
+ viewModel.question.summaryText = this.summaryText;
74
+ viewModel.showSuggestionsUi = this.showSuggestionsUi;
61
75
  return viewModel;
62
76
  }
63
77
 
@@ -12,7 +12,7 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
12
12
  const HINT = 'hint';
13
13
  const LABEL = 'A label';
14
14
 
15
- function createQuestion() {
15
+ function createQuestion(showSuggestionsUi = false) {
16
16
  return new TextEntryRedactQuestion({
17
17
  title: TITLE,
18
18
  question: QUESTION,
@@ -20,7 +20,8 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
20
20
  validators: VALIDATORS,
21
21
  html: HTML,
22
22
  hint: HINT,
23
- label: LABEL
23
+ label: LABEL,
24
+ showSuggestionsUi
24
25
  });
25
26
  }
26
27
  it('should create', () => {
@@ -72,11 +73,10 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
72
73
  const view = mockRes.render.mock.calls[0].result;
73
74
  assert.ok(view);
74
75
  assert.match(view, /Redaction Question/);
75
- assert.match(view, /govuk-grid-column-two-thirds">\s+<form/);
76
76
  assert.doesNotMatch(view, /Redaction suggestions/);
77
77
  });
78
78
  it('should render suggestions view', () => {
79
- const question = createQuestion();
79
+ const question = createQuestion(true);
80
80
  const section = {
81
81
  name: 'section-name'
82
82
  };
@@ -94,7 +94,6 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
94
94
  }
95
95
  };
96
96
  const customViewData = {
97
- showSuggestionsUi: true,
98
97
  layoutTemplate: 'lib/test-layout.njk',
99
98
  question: {
100
99
  question: 'Redaction Question',
@@ -113,8 +112,51 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
113
112
  const view = mockRes.render.mock.calls[0].result;
114
113
  assert.ok(view);
115
114
  assert.match(view, /Redaction Question/);
116
- assert.match(view, /govuk-grid-column-one-half">\s+<form/);
117
- assert.doesNotMatch(view, /govuk-grid-column-two-thirds">\s+<form/);
118
115
  assert.match(view, /Redaction suggestions/);
116
+ assert.match(view, /No redaction suggestions found\./);
117
+ });
118
+ it('should render suggestions view with data', () => {
119
+ const question = createQuestion(true);
120
+ const section = {
121
+ name: 'section-name'
122
+ };
123
+ const journey = {
124
+ baseUrl: '',
125
+ taskListUrl: 'task',
126
+ journeyTemplate: 'template',
127
+ journeyTitle: 'title',
128
+ journeyId: 'manage-representations',
129
+ getBackLink: () => {
130
+ return 'back';
131
+ },
132
+ response: {
133
+ answers: {}
134
+ }
135
+ };
136
+ const customViewData = {
137
+ layoutTemplate: 'lib/test-layout.njk',
138
+ question: {
139
+ question: 'Redaction Question',
140
+ fieldName: 'field-name',
141
+ value: 'value',
142
+ valueRedacted: 'value-redacted'
143
+ },
144
+ redactionSuggestions: [
145
+ { category: 'Person', suggestion: 'Test Person' },
146
+ { category: 'Address', suggestion: '123 Fake Street' }
147
+ ]
148
+ };
149
+ const nunjucks = configureNunjucks();
150
+ const mockRes = {
151
+ render: mock.fn((view, data) => nunjucks.render(view + '.njk', data))
152
+ };
153
+ const viewModel = question.prepQuestionForRendering(section, journey, customViewData);
154
+ question.renderAction(mockRes, viewModel);
155
+ assert.strictEqual(mockRes.render.mock.callCount(), 1);
156
+ const view = mockRes.render.mock.calls[0].result;
157
+ assert.ok(view);
158
+ assert.match(view, /Redaction Question/);
159
+ assert.match(view, /Redaction suggestions/);
160
+ assert.match(view, /We have suggested some common redactions/);
119
161
  });
120
162
  });