Skip to content

Commit

Permalink
Persist action checkboxes (#61)
Browse files Browse the repository at this point in the history
* Handle links and references more effectively

Now works consistently across actions, descriptions and timeline and avoids nasty HTML

* Show actions which are done

* Move webpack output to `./dist`

* Permit watching and hot-reloading of FE assets

Mount the output folder so you can run `yarn watch` locally to see your change live

* Add rest_framework to INSTALLED_APPS

We need this for the internal API to work

* Add markup for actions module

* Add Actions module

This automatically sends an AJAX request to update the `done` and `done_date` fields of an action when you (un)check the checkbox

* Load JS asynchronously

Ensures the DOM has loaded before trying to run JavaScript
  • Loading branch information
gregtyler authored Dec 4, 2020
1 parent cc13114 commit b2658ad
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Dockerfile.nginx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ COPY nginx/etc /etc
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY opgincidentresponse/static /app/opgincidentresponse/static
COPY --from=node /home/node /app/opgincidentresponse/static
COPY --from=asset-env /app/build /app/opgincidentresponse/static
COPY --from=asset-env /app/dist /app/opgincidentresponse/static


RUN mkdir -p /var/www/public
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ services:
environment:
APP_HOST: response
APP_PORT: 8000
volumes:
- ./nginx/webpack/dist:/app/opgincidentresponse/static
ports:
- 80:80
depends_on:
Expand Down
5 changes: 4 additions & 1 deletion nginx/webpack/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import './main.scss';
import GOVUKFrontend from 'govuk-frontend/govuk/all.js';
import MOJFrontend from '@ministryofjustice/frontend/moj/all.js';
// import MOJFrontend from '@ministryofjustice/frontend/moj/all.js';
import { initAll } from './src/all.js';

GOVUKFrontend.initAll();
initAll();

3 changes: 2 additions & 1 deletion nginx/webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"version": "0.1.0",
"license": "MIT",
"scripts": {
"build": "webpack"
"build": "webpack",
"watch": "webpack --watch"
},
"dependencies": {
"@ministryofjustice/frontend": "^0.0.21",
Expand Down
26 changes: 26 additions & 0 deletions nginx/webpack/src/action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { nodeListForEach } from 'govuk-frontend/govuk/common'
import api from './lib/api';

function Actions ($module) {
this.$module = $module;
this.incidentId = $module.getAttribute('data-incident-id');
this.$actions = $module.querySelectorAll('input[type="checkbox"]');
}

Actions.prototype.init = function init() {
nodeListForEach(this.$actions, $action => {
$action.addEventListener('change', this.handleCheck.bind(this));
});
}

Actions.prototype.handleCheck = function handleCheck(event) {
const actionId = event.target.value;

const form = new FormData();
form.set('done', event.target.checked);
form.set('done_date', event.target.checked ? (new Date()).toISOString() : '');

api('PATCH', `/incidents/${this.incidentId}/actions/${actionId}/`, form);
}

export default Actions;
11 changes: 11 additions & 0 deletions nginx/webpack/src/all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { nodeListForEach } from 'govuk-frontend/govuk/common'
import Actions from './action.js'

function initAll() {
const $actions = document.querySelectorAll('[data-module="app-actions"]');
nodeListForEach($actions, ($el) => {
new Actions($el).init();
})
}

export { initAll, Actions }
14 changes: 14 additions & 0 deletions nginx/webpack/src/lib/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import getCookie from "./getCookie";

export default function api(method, path, body = null, config = {}) {
const csrftoken = getCookie('csrftoken');

return fetch(`/core${path}`, Object.assign({
method,
mode: 'same-origin',
body,
headers: {
'X-CSRFToken': csrftoken
}
}, config));
}
15 changes: 15 additions & 0 deletions nginx/webpack/src/lib/getCookie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
6 changes: 3 additions & 3 deletions nginx/webpack/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ module.exports = {
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'build')
path: path.resolve(__dirname, 'dist')
},
plugins: [
new CopyPlugin({
patterns: [
{ from: 'node_modules/govuk-frontend/govuk/assets', to: path.resolve(__dirname, 'build/assets') },
{ from: 'node_modules/@ministryofjustice/frontend/moj/assets', to: path.resolve(__dirname, 'build/assets') },
{ from: 'node_modules/govuk-frontend/govuk/assets', to: path.resolve(__dirname, 'dist/assets') },
{ from: 'node_modules/@ministryofjustice/frontend/moj/assets', to: path.resolve(__dirname, 'dist/assets') },
]
}),
new MiniCssExtractPlugin({
Expand Down
1 change: 1 addition & 0 deletions opgincidentresponse/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"after_response",
"bootstrap4",
"response.apps.ResponseConfig",
"rest_framework",
'health_check',
'social_django',
'opgincidentresponse',
Expand Down
2 changes: 1 addition & 1 deletion opgincidentresponse/templates/govuk_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,6 @@
</div>
</footer>

<script src="{% static "all.js" %}"></script>
<script src="{% static "all.js" %}" async></script>
</body>
</html>
8 changes: 4 additions & 4 deletions opgincidentresponse/templates/incident.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h1 class="govuk-heading-xl">{{ incident.report | unslackify }}</h1>
Summary
</dt>
<dd class="govuk-summary-list__value">
{% if incident.summary %}{{ incident.summary | unslackify }}{% else %}<em>None</em>{% endif %}
{% if incident.summary %}{{ incident.summary | slack_format | unslackify | safe }}{% else %}<em>None</em>{% endif %}
</dd>
<dd class="govuk-summary-list__actions"></dd>
</div>
Expand All @@ -26,7 +26,7 @@ <h1 class="govuk-heading-xl">{{ incident.report | unslackify }}</h1>
Impact
</dt>
<dd class="govuk-summary-list__value">
{% if incident.impact %}{{ incident.impact | unslackify }}{% else %}<em>None</em>{% endif %}
{% if incident.impact %}{{ incident.impact | slack_format | unslackify | safe }}{% else %}<em>None</em>{% endif %}
</dd>
<dd class="govuk-summary-list__actions"></dd>
</div>
Expand Down Expand Up @@ -81,15 +81,15 @@ <h1 class="govuk-heading-xl">{{ incident.report | unslackify }}</h1>
</dl>

<div class="govuk-form-group">
<fieldset class="govuk-fieldset">
<fieldset class="govuk-fieldset" data-module="app-actions" data-incident-id="{{ incident.id }}">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--m">
<h2 class="govuk-heading-l">Actions</h2>
</legend>
{% if actions %}
<div class="govuk-checkboxes govuk-checkboxes--small">
{% for action in actions %}
<div class="govuk-checkboxes__item">
<input class="govuk-checkboxes__input" id="action-{{ action.id }}" name="action[{{action.id}}]" type="checkbox">
<input class="govuk-checkboxes__input" id="action-{{ action.id }}" name="action[{{action.id}}]" value="{{ action.id }}" type="checkbox" {% if action.done %}checked{% endif %}>
<label class="govuk-label govuk-checkboxes__label" for="action-{{ action.id }}">
{{ action.details | slack_format | unslackify | safe }}
</label>
Expand Down
6 changes: 4 additions & 2 deletions opgincidentresponse/templatetags/opg_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,20 @@ def slack_format(value):
if type(value) is not str:
return value

value = value.replace('<', '&lt;').replace('>', '&gt;')

user_links = re.findall(r"&lt;@(U.+?)&gt;", value)

for user_id in user_links:
user = ExternalUser.objects.get(external_id=user_id)

value = value.replace('&lt;@' + user_id + '&gt;', '<a class="govuk-link" href="slack://user?team=T02DYEB3A&amp;id=' + user.external_id + '">' + user.full_name + '</a>')

links = re.findall(r"<(https?://.+?)(?:\|(.+?))?>", value)
links = re.findall(r"&lt;(https?://.+?)(?:\|(.+?))?&gt;", value)

for (link, label) in links:
match = (link + '|' + label) if label else link
value = value.replace('<' + match + '>', '<a class="govuk-link" href="' + link + '">' + (label if label else link) + '</a>')
value = value.replace('&lt;' + match + '&gt;', '<a class="govuk-link" href="' + link + '">' + (label if label else link) + '</a>')

return value.replace('\n', '<br />')

Expand Down

0 comments on commit b2658ad

Please sign in to comment.