@ministryofjustice/hmpps-digital-prison-reporting-frontend
Version:
The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.
1,087 lines (1,062 loc) • 662 kB
JavaScript
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var dayjs_min$1 = {exports: {}};
var dayjs_min = dayjs_min$1.exports;
var hasRequiredDayjs_min;
function requireDayjs_min () {
if (hasRequiredDayjs_min) return dayjs_min$1.exports;
hasRequiredDayjs_min = 1;
(function (module, exports) {
!function(t,e){module.exports=e();}(dayjs_min,(function(){var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",c="month",f="quarter",h="year",d="date",l="Invalid Date",$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return "["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return !r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return (e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()<n.date())return -t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,c),s=n-i<0,u=e.clone().add(r+(s?-1:1),c);return +(-(r+(n-i)/(s?i-u:u-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return {M:c,y:h,w:o,d:a,D:d,h:u,m:s,s:i,ms:r,Q:f}[t]||String(t||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},g="en",D={};D[g]=M;var p="$isDayjsObject",S=function(t){return t instanceof _||!(!t||!t[p])},w=function t(e,n,r){var i;if(!e)return g;if("string"==typeof e){var s=e.toLowerCase();D[s]&&(i=s),n&&(D[s]=n,i=s);var u=e.split("-");if(!i&&u.length>1)return t(u[0])}else {var a=e.name;D[a]=e,i=a;}return !r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,true),this.parse(t),this.$x=this.$x||t.x||{},this[p]=true;}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init();},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds();},m.$utils=function(){return b},m.isValid=function(){return !(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t)<this.startOf(e)},m.isBefore=function(t,e){return this.endOf(e)<O(t)},m.$g=function(t,e,n){return b.u(t)?this[e]:this.set(n,t)},m.unix=function(){return Math.floor(this.valueOf()/1e3)},m.valueOf=function(){return this.$d.getTime()},m.startOf=function(t,e){var n=this,r=!!b.u(e)||e,f=b.p(t),l=function(t,e){var i=b.w(n.$u?Date.UTC(n.$y,e,t):new Date(n.$y,e,t),n);return r?i:i.endOf(a)},$=function(t,e){return b.w(n.toDate()[t].apply(n.toDate("s"),(r?[0,0,0,0]:[23,59,59,999]).slice(e)),n)},y=this.$W,M=this.$M,m=this.$D,v="set"+(this.$u?"UTC":"");switch(f){case h:return r?l(1,0):l(31,11);case c:return r?l(1,M):l(0,M+1);case o:var g=this.$locale().weekStart||0,D=(y<g?y+7:y)-g;return l(r?m-D:m+(6-D),M);case a:case d:return $(v+"Hours",0);case u:return $(v+"Minutes",1);case s:return $(v+"Seconds",2);case i:return $(v+"Milliseconds",3);default:return this.clone()}},m.endOf=function(t){return this.startOf(t,false)},m.$set=function(t,e){var n,o=b.p(t),f="set"+(this.$u?"UTC":""),l=(n={},n[a]=f+"Date",n[d]=f+"Date",n[c]=f+"Month",n[h]=f+"FullYear",n[u]=f+"Hours",n[s]=f+"Minutes",n[i]=f+"Seconds",n[r]=f+"Milliseconds",n)[o],$=o===a?this.$D+(e-this.$W):e;if(o===c||o===h){var y=this.clone().set(d,1);y.$d[l]($),y.init(),this.$d=y.set(d,Math.min(this.$D,y.daysInMonth())).$d;}else l&&this.$d[l]($);return this.init(),this},m.set=function(t,e){return this.clone().$set(t,e)},m.get=function(t){return this[b.p(t)]()},m.add=function(r,f){var d,l=this;r=Number(r);var $=b.p(f),y=function(t){var e=O(l);return b.w(e.date(e.date()+Math.round(t*r)),l)};if($===c)return this.set(c,this.$M+r);if($===h)return this.set(h,this.$y+r);if($===a)return y(1);if($===o)return y(7);var M=(d={},d[s]=e,d[u]=n,d[i]=t,d)[$]||1,m=this.$d.getTime()+r*M;return b.w(m,this)},m.subtract=function(t,e){return this.add(-1*t,e)},m.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return n.invalidDate||l;var r=t||"YYYY-MM-DDTHH:mm:ssZ",i=b.z(this),s=this.$H,u=this.$m,a=this.$M,o=n.weekdays,c=n.months,f=n.meridiem,h=function(t,n,i,s){return t&&(t[n]||t(e,r))||i[n].slice(0,s)},d=function(t){return b.s(s%12||12,t,"0")},$=f||function(t,e,n){var r=t<12?"AM":"PM";return n?r.toLowerCase():r};return r.replace(y,(function(t,r){return r||function(t){switch(t){case "YY":return String(e.$y).slice(-2);case "YYYY":return b.s(e.$y,4,"0");case "M":return a+1;case "MM":return b.s(a+1,2,"0");case "MMM":return h(n.monthsShort,a,c,3);case "MMMM":return h(c,a);case "D":return e.$D;case "DD":return b.s(e.$D,2,"0");case "d":return String(e.$W);case "dd":return h(n.weekdaysMin,e.$W,o,2);case "ddd":return h(n.weekdaysShort,e.$W,o,3);case "dddd":return o[e.$W];case "H":return String(s);case "HH":return b.s(s,2,"0");case "h":return d(1);case "hh":return d(2);case "a":return $(s,u,true);case "A":return $(s,u,false);case "m":return String(u);case "mm":return b.s(u,2,"0");case "s":return String(e.$s);case "ss":return b.s(e.$s,2,"0");case "SSS":return b.s(e.$ms,3,"0");case "Z":return i}return null}(t)||i.replace(":","")}))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(r,d,l){var $,y=this,M=b.p(d),m=O(r),v=(m.utcOffset()-this.utcOffset())*e,g=this-m,D=function(){return b.m(y,m)};switch(M){case h:$=D()/12;break;case c:$=D();break;case f:$=D()/3;break;case o:$=(g-v)/6048e5;break;case a:$=(g-v)/864e5;break;case u:$=g/n;break;case s:$=g/e;break;case i:$=g/t;break;default:$=g;}return l?$:b.a($)},m.daysInMonth=function(){return this.endOf(c).$D},m.$locale=function(){return D[this.$L]},m.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=w(t,e,true);return r&&(n.$L=r),n},m.clone=function(){return b.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},M}(),Y=_.prototype;return O.prototype=Y,[["$ms",r],["$s",i],["$m",s],["$H",u],["$W",a],["$M",c],["$y",h],["$D",d]].forEach((function(t){Y[t[1]]=function(e){return this.$g(e,t[0],t[1])};})),O.extend=function(t,e){return t.$i||(t(e,_,O),t.$i=true),O},O.locale=w,O.isDayjs=S,O.unix=function(t){return O(1e3*t)},O.en=D[g],O.Ls=D,O.p={},O}));
} (dayjs_min$1));
return dayjs_min$1.exports;
}
var dayjs_minExports = requireDayjs_min();
var dayjs = /*@__PURE__*/getDefaultExportFromCjs(dayjs_minExports);
var customParseFormat$1 = {exports: {}};
var customParseFormat = customParseFormat$1.exports;
var hasRequiredCustomParseFormat;
function requireCustomParseFormat () {
if (hasRequiredCustomParseFormat) return customParseFormat$1.exports;
hasRequiredCustomParseFormat = 1;
(function (module, exports) {
!function(e,t){module.exports=t();}(customParseFormat,(function(){var e={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},t=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,n=/\d/,r=/\d\d/,i=/\d\d?/,o=/\d*[^-_:/,()\s\d]+/,s={},a=function(e){return (e=+e)+(e>68?1900:2e3)};var f=function(e){return function(t){this[e]=+t;}},h=[/[+-]\d\d:?(\d\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if("Z"===e)return 0;var t=e.match(/([+-]|\d\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:"+"===t[0]?-n:n}(e);}],u=function(e){var t=s[e];return t&&(t.indexOf?t:t.s.concat(t.f))},d=function(e,t){var n,r=s.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?"pm":"PM");return n},c={A:[o,function(e){this.afternoon=d(e,false);}],a:[o,function(e){this.afternoon=d(e,true);}],Q:[n,function(e){this.month=3*(e-1)+1;}],S:[n,function(e){this.milliseconds=100*+e;}],SS:[r,function(e){this.milliseconds=10*+e;}],SSS:[/\d{3}/,function(e){this.milliseconds=+e;}],s:[i,f("seconds")],ss:[i,f("seconds")],m:[i,f("minutes")],mm:[i,f("minutes")],H:[i,f("hours")],h:[i,f("hours")],HH:[i,f("hours")],hh:[i,f("hours")],D:[i,f("day")],DD:[r,f("day")],Do:[o,function(e){var t=s.ordinal,n=e.match(/\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\[|\]/g,"")===e&&(this.day=r);}],w:[i,f("week")],ww:[r,f("week")],M:[i,f("month")],MM:[r,f("month")],MMM:[o,function(e){var t=u("months"),n=(u("monthsShort")||t.map((function(e){return e.slice(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n;}],MMMM:[o,function(e){var t=u("months").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t;}],Y:[/[+-]?\d+/,f("year")],YY:[r,function(e){this.year=a(e);}],YYYY:[/\d{4}/,f("year")],Z:h,ZZ:h};function l(n){var r,i;r=n,i=s&&s.formats;for(var o=(n=r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var o=r&&r.toUpperCase();return n||i[r]||e[r]||i[o].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),a=o.length,f=0;f<a;f+=1){var h=o[f],u=c[h],d=u&&u[0],l=u&&u[1];o[f]=l?{regex:d,parser:l}:h.replace(/^\[|\]$/g,"");}return function(e){for(var t={},n=0,r=0;n<a;n+=1){var i=o[n];if("string"==typeof i)r+=i.length;else {var s=i.regex,f=i.parser,h=e.slice(r),u=s.exec(h)[0];f.call(t,u),e=e.replace(u,"");}}return function(e){var t=e.afternoon;if(void 0!==t){var n=e.hours;t?n<12&&(e.hours+=12):12===n&&(e.hours=0),delete e.afternoon;}}(t),t}}return function(e,t,n){n.p.customParseFormat=true,e&&e.parseTwoDigitYear&&(a=e.parseTwoDigitYear);var r=t.prototype,i=r.parse;r.parse=function(e){var t=e.date,r=e.utc,o=e.args;this.$u=r;var a=o[1];if("string"==typeof a){var f=true===o[2],h=true===o[3],u=f||h,d=o[2];h&&(d=o[2]),s=this.$locale(),!f&&d&&(s=n.Ls[d]),this.$d=function(e,t,n,r){try{if(["x","X"].indexOf(t)>-1)return new Date(("X"===t?1e3:1)*e);var i=l(t)(e),o=i.year,s=i.month,a=i.day,f=i.hours,h=i.minutes,u=i.seconds,d=i.milliseconds,c=i.zone,m=i.week,M=new Date,Y=a||(o||s?1:M.getDate()),p=o||M.getFullYear(),v=0;o&&!s||(v=s>0?s-1:M.getMonth());var D,w=f||0,g=h||0,y=u||0,L=d||0;return c?new Date(Date.UTC(p,v,Y,w,g,y,L+60*c.offset*1e3)):n?new Date(Date.UTC(p,v,Y,w,g,y,L)):(D=new Date(p,v,Y,w,g,y,L),m&&(D=r(D).week(m).toDate()),D)}catch(e){return new Date("")}}(t,a,r,n),this.init(),d&&true!==d&&(this.$L=this.locale(d).$L),u&&t!=this.format(a)&&(this.$d=new Date("")),s={};}else if(a instanceof Array)for(var c=a.length,m=1;m<=c;m+=1){o[1]=a[m-1];var M=n.apply(this,o);if(M.isValid()){this.$d=M.$d,this.$L=M.$L,this.init();break}m===c&&(this.$d=new Date(""));}else i.call(this,e);};}}));
} (customParseFormat$1));
return customParseFormat$1.exports;
}
var customParseFormatExports = requireCustomParseFormat();
var customParse = /*@__PURE__*/getDefaultExportFromCjs(customParseFormatExports);
class DprClientClass {
element;
constructor(element) {
this.element = element;
}
static getModuleName() {
throw new Error('Module name not set');
}
getElement() {
return this.element;
}
initialise() {
throw new Error('Initialisation not configured');
}
}
class CardGroup extends DprClientClass {
static getModuleName() {
return 'card-group';
}
initialise() {
const cards = this.getElement().querySelectorAll('[data-click-navigate-to]');
const wrapperClass = 'card-loading';
cards.forEach(card => {
card.addEventListener('click', () => {
card.classList.add(wrapperClass);
cards.forEach(c => {
if (!c.classList.contains('card-loading')) {
const disabledClass = 'card-disabled';
c.classList.add(disabledClass);
}
});
const url = card.dataset['clickNavigateTo'];
if (url) {
window.location.href = url;
}
});
});
}
}
var BookmarkAction;
(function (BookmarkAction) {
BookmarkAction["ADD"] = "add";
BookmarkAction["REMOVE"] = "remove";
})(BookmarkAction || (BookmarkAction = {}));
class BookmarkButton extends DprClientClass {
csrfToken;
reportId;
id;
linkType;
reportType;
endpoint;
baseUrl;
isRunning = false;
static getModuleName() {
return 'bookmark-button';
}
initialise() {
const element = this.getElement();
element.style.pointerEvents = '';
element.style.opacity = '1';
this.id = element.getAttribute('data-id');
this.reportId = element.getAttribute('data-report-id');
this.linkType = this.element.getAttribute('data-link-type') || BookmarkAction.ADD;
this.setReportType();
this.endpoint = element.getAttribute('data-endpoint') || '';
this.csrfToken = element.getAttribute('data-csrf-token') || '';
this.initEventListener();
}
/**
* Updates the bookmark button UI so that it shows:
* - the correct text
* - toggles the bookmark on and off correctly
*
* @memberof BookmarkButton
*/
updateUI() {
this.linkType = this.linkType === BookmarkAction.ADD ? BookmarkAction.REMOVE : BookmarkAction.ADD;
const textContent = this.linkType === BookmarkAction.ADD ? 'Add bookmark' : 'Remove bookmark';
const element = this.getElement();
element.setAttribute('data-link-type', this.linkType);
element.textContent = textContent;
}
/**
* Inits the bookmark button click event
*
* @memberof BookmarkButton
*/
initEventListener() {
this.getElement().addEventListener('click', (e) => this.activateBookmark(e));
this.getElement().addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
this.activateBookmark(e);
}
});
}
async activateBookmark(e) {
e.preventDefault();
if (this.isRunning)
return;
this.isRunning = true;
this.getElement().classList.add('bookmark-disabled');
try {
await fetch(this.endpoint, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'CSRF-Token': this.csrfToken,
},
body: JSON.stringify({
type: this.linkType,
id: this.id,
reportId: this.reportId,
reportType: this.reportType,
}),
})
.then(() => {
// The page should not reload if on the report/dashboard page so not to have to reload the data and cause a delay
// Should instead update the UI labels to signify the change has been made
if (!window.location.href.includes('/report') && !window.location.href.includes('/dashboard')) {
window.location.reload();
}
else {
this.updateUI();
}
})
.catch(error => console.error('Error:', error));
}
finally {
this.isRunning = false;
this.getElement().classList.remove('bookmark-disabled');
}
}
setReportType() {
const rawReportTypeValue = this.element.getAttribute('data-report-type') || '';
if (!['dashboard', 'report'].includes(rawReportTypeValue)) {
throw new Error(`Report type for bookmark setup was unexpected: ${rawReportTypeValue}`);
}
this.reportType = rawReportTypeValue;
}
}
class dprTruncate extends DprClientClass {
static getModuleName() {
return 'dpr-truncate';
}
initialise() {
this.initShowMore();
}
initShowMore() {
const container = this.getElement();
const content = container.querySelector('.js-content');
const button = container.querySelector('.js-show-more');
if (!content || !button) {
return;
}
const fullHtml = content.dataset['fullHtml'] ?? '';
const truncatedHtml = content.dataset['truncatedHtml'] ?? '';
button.addEventListener('click', () => {
const expanded = container.dataset['expanded'] === 'true';
if (expanded) {
content.innerHTML = truncatedHtml;
button.textContent = 'Show more';
button.setAttribute('aria-expanded', String(!expanded));
}
else {
content.innerHTML = fullHtml;
button.textContent = 'Show less';
button.setAttribute('aria-expanded', String(!expanded));
}
container.dataset['expanded'] = String(!expanded);
});
}
}
// @ts-nocheck
/* eslint-disable class-methods-use-this */
/* eslint-disable no-param-reassign */
class DprCatalogueFilters extends DprClientClass {
initTable() {
this.table = document.getElementById(this.tableId).querySelector('tbody');
this.classes = [
'dpr-search-option-hide',
'dpr-unauthorised-report-hide',
'dpr-live-report-hide',
'dpr-missing-report-hide',
'dpr-report-type-hide',
];
this.totalShown = document.getElementById('total-shown');
this.totalAmount = document.getElementById('total-amount');
this.totalRows = Array.from(this.table.rows).length;
this.shownRows = this.totalRows;
}
updateTotals() {
let count = 0;
this.table = document.getElementById(this.tableId).querySelector('tbody');
Array.from(this.table.rows).forEach(row => {
const hidden = [];
this.classes.forEach(className => {
hidden.push(Array.from(row.classList).includes(className));
});
if (hidden.every(h => h === false)) {
count += 1;
}
});
this.shownRows = count;
this.renderTotals();
}
renderTotals() {
if (this.totalShown) {
this.totalShown.innerText = this.shownRows;
}
if (this.totalAmount) {
this.totalAmount.innerText = this.totalRows;
}
}
}
// @ts-nocheck
/* eslint-disable class-methods-use-this */
/* eslint-disable no-param-reassign */
class DprCatalogueSearch extends DprCatalogueFilters {
static getModuleName() {
return 'dpr-catalogue-search';
}
initialise() {
this.searchBox = this.getElement().querySelector('.dpr-search-box');
this.hideClass = 'dpr-search-option-hide';
if (this.searchBox) {
this.tableId = this.searchBox.dataset.tableId;
this.initTable();
this.initSeachBoxEvents();
this.updateTableRows();
this.initSearchInputFromQueryParams();
this.initProductCollectionSelect();
}
}
initProductCollectionSelect() {
/**
* @type {HTMLSelectElement | undefined}
*/
const productCollections = this.getElement().querySelector('#productCollection');
if (productCollections) {
productCollections.addEventListener('change', e => {
e.preventDefault();
productCollections.closest('form').submit();
});
}
}
initSeachBoxEvents() {
this.searchBox.addEventListener('keyup', e => {
this.updateTableRows(e.target.value);
// Update Query Params
const queryParams = new URLSearchParams(window.location.search);
queryParams.set(this.searchBox.id, e.target.value);
window.history.replaceState(null, null, `?${queryParams.toString()}`);
});
}
updateTableRows(value) {
this.initSearchRows(value);
this.updateSearchListing(value);
this.updateTotals();
}
initSearchRows(value) {
const rows = Array.from(this.table.rows);
if (value) {
rows.forEach(row => row.classList.add(this.hideClass));
}
}
updateSearchListing(value) {
Array.from(this.table.rows)
.filter(row => {
return (!value ||
value.length === 0 ||
Array.from(row.cells).find(cell => {
const searchValue = value.toLowerCase();
return cell.innerText.toLowerCase().includes(searchValue.toLowerCase());
}));
})
.forEach(row => {
row.classList.remove(this.hideClass);
});
}
initSearchInputFromQueryParams() {
const urlParams = new URLSearchParams(window.location.search);
urlParams.forEach((value, key) => {
const element = document.getElementById(key);
if (element && element.classList.contains('dpr-search-box')) {
element.value = value;
this.updateTableRows(element.value);
}
});
}
}
// @ts-nocheck
/* eslint-disable class-methods-use-this */
/* eslint-disable no-param-reassign */
class DprCatalogueUnauthorisedFilter extends DprCatalogueFilters {
static getModuleName() {
return 'dpr-catalogue-show-unauthorised';
}
initialise() {
this.toggleFilters = this.getElement().querySelector('#dpr-toggle-filters');
this.hideClasses = ['dpr-unauthorised-report-hide', 'dpr-live-report-hide', 'dpr-missing-report-hide'];
if (this.toggleFilters) {
this.tableId = this.toggleFilters.dataset.tableId;
this.initTable();
this.initCheckboxToggleEvents();
this.initCheckboxesFromQueryParams();
this.updateTableRows();
}
}
initCheckboxToggleEvents() {
this.toggleFilters.addEventListener('change', e => {
const queryParams = new URLSearchParams(window.location.search);
if (e.target.checked) {
queryParams.set(e.target.id, e.target.value);
}
else {
queryParams.delete(e.target.id, e.target.value);
}
window.history.replaceState(null, null, `?${queryParams.toString()}`);
this.updateTableRows();
});
}
updateTableRows() {
const query = new URLSearchParams(window.location.search);
this.updateUnauthorisedRows(query);
this.updateMissingRows(query);
this.updateLiveRows(query);
this.updateTotals();
}
updateUnauthorisedRows(queryParams) {
const value = queryParams.get('show-unauthorised');
const hideClassName = this.hideClasses[0];
const tag = 'dpr-unauthorised-report';
this.updateRows(value, hideClassName, tag);
}
updateLiveRows(queryParams) {
const value = queryParams.get('hide-live');
const hideClassName = this.hideClasses[1];
const tag = 'dpr-live-report';
this.updateRowsLive(value, hideClassName, tag);
}
updateMissingRows(queryParams) {
const value = queryParams.get('show-missing');
const hideClassName = this.hideClasses[2];
const tag = 'dpr-missing-report';
this.updateRows(value, hideClassName, tag);
}
updateRowsLive(value, hideClassName, tag) {
Array.from(this.table.rows)
.filter(row => {
return Array.from(row.cells).find(cell => {
return cell.innerHTML.includes(tag);
});
})
.forEach(row => {
if (value) {
row.classList.add(hideClassName);
}
else {
row.classList.remove(hideClassName);
}
});
}
updateRows(value, hideClassName, tag) {
Array.from(this.table.rows)
.filter(row => {
return Array.from(row.cells).find(cell => {
return cell.innerHTML.includes(tag);
});
})
.forEach(row => {
if (value) {
row.classList.remove(hideClassName);
}
else if (!row.classList.contains(hideClassName)) {
row.classList.add(hideClassName);
}
});
}
initCheckboxesFromQueryParams() {
const urlParams = new URLSearchParams(window.location.search);
urlParams.forEach((value, key) => {
const element = document.getElementById(key);
if (element && element.id === 'show-unauthorised') {
element.setAttribute('checked', '');
}
if (element && element.id === 'show-missing') {
element.setAttribute('checked', '');
}
if (element && element.id === 'hide-live') {
element.setAttribute('checked', '');
}
});
}
}
// @ts-nocheck
/* eslint-disable class-methods-use-this */
/* eslint-disable no-param-reassign */
class DprCatalogueTypeFilter extends DprCatalogueFilters {
static getModuleName() {
return 'dpr-catalogue-type-filter';
}
initialise() {
this.reportTypeFilter = this.getElement().querySelector('#dpr-report-type-filters');
if (this.reportTypeFilter) {
this.tableId = this.reportTypeFilter.dataset.tableId;
this.initTable();
this.initRadioButtonEvent();
this.updateTableRows();
}
}
initRadioButtonEvent() {
this.reportTypeFilter.addEventListener('change', e => {
const queryParams = new URLSearchParams(window.location.search);
if (e.target.checked) {
queryParams.set(e.target.name, e.target.value);
}
else {
queryParams.delete(e.target.name, e.target.value);
}
window.history.replaceState(null, null, `?${queryParams.toString()}`);
this.updateTableRows();
});
}
updateTableRows() {
const query = new URLSearchParams(window.location.search);
this.updateReportTypeRowsRows(query);
this.updateTotals();
}
updateReportTypeRowsRows(queryParams) {
const value = queryParams.get('report-type');
const hideClassName = `dpr-report-type-hide`;
const tag = `dpr-type__${value}`;
this.updateRows(value, hideClassName, tag);
}
updateRows(value, hideClassName, tag) {
Array.from(this.table.rows).forEach(row => {
row.classList.remove(hideClassName);
});
Array.from(this.table.rows)
.filter(row => {
const isTypeRow = [];
Array.from(row.cells).forEach(cell => {
return isTypeRow.push(cell.innerHTML.includes(tag));
});
return isTypeRow.every(t => t === false);
})
.forEach(row => {
if (value && value !== 'all') {
row.classList.add(hideClassName);
}
});
}
}
let Pagination$1 = class Pagination {
pageSizeSelect;
static getModuleName() {
return 'pagination';
}
initialise() {
this.pageSizeSelect = document.getElementById('page-size-select');
this.initPageSizeSelectEvent();
}
initPageSizeSelectEvent() {
this.pageSizeSelect.addEventListener('change', () => {
const { name, value } = this.pageSizeSelect;
const queryParams = new URLSearchParams(window.location.search);
queryParams.set(name, value);
queryParams.set('selectedPage', '1');
window.history.replaceState(null, '', `?${queryParams.toString()}`);
window.location.reload();
});
}
};
class ReportActions extends DprClientClass {
refreshButton;
printButton;
shareButton;
copyButton;
static getModuleName() {
return 'report-actions';
}
initialise() {
this.refreshButton = document.getElementById('dpr-button-refresh');
this.printButton = document.getElementById('dpr-button-printable');
this.shareButton = document.getElementById('dpr-button-sharable');
this.copyButton = document.getElementById('dpr-button-copy');
this.initRefreshEvent();
this.initPrintButtonEvent();
this.initShareButtonEvent();
this.initCopyButtonEvent();
}
initPrintButtonEvent() {
if (this.printButton) {
const disabled = this.printButton.getAttribute('data-disabled');
this.printButton.addEventListener('click', () => {
if (disabled !== 'true') {
window.print();
}
});
this.printButton.addEventListener('keyup', e => {
if (e.key === 'Enter') {
if (disabled !== 'true') {
window.print();
}
}
});
}
}
initShareButtonEvent() {
if (this.shareButton) {
const href = this.shareButton.getAttribute('data-href');
if (href) {
this.shareButton.addEventListener('click', () => {
window.location.href = href;
});
this.shareButton.addEventListener('keyup', e => {
if (e.key === 'Enter') {
window.location.href = href;
}
});
}
}
}
initCopyButtonEvent() {
if (this.copyButton) {
const href = this.copyButton.getAttribute('data-href');
if (href) {
this.copyButton.addEventListener('click', () => {
navigator.clipboard.writeText(href);
});
this.copyButton.addEventListener('keyup', e => {
if (e.key === 'Enter') {
navigator.clipboard.writeText(href);
}
});
}
}
}
initRefreshEvent() {
if (this.refreshButton) {
const href = this.refreshButton.getAttribute('data-href');
if (href) {
this.refreshButton.addEventListener('click', () => {
window.location.href = href;
});
this.refreshButton.addEventListener('keyup', e => {
if (e.key === 'Enter') {
window.location.href = href;
}
});
}
}
}
}
// @ts-nocheck
class DataTable extends DprClientClass {
static getModuleName() {
return 'data-table';
}
initialise() {
this.element = this.getElement();
this.tableContainer = this.element.querySelector('.dpr-table-wrapper');
this.table = this.element.querySelector('.dpr-data-table');
this.gradient = this.element.querySelector('.dpr-overflow-gradient');
this.createTableHeaderAndFooter();
this.initTableScrollListener();
}
initTableScrollListener() {
this.checkOffsetWidths();
window.addEventListener('resize', () => {
this.checkOffsetWidths();
});
this.tableContainer.addEventListener('scroll', event => {
const endOfScroll = this.table.offsetWidth;
const currentScroll = event.target.offsetWidth + event.target.scrollLeft;
if (endOfScroll === currentScroll) {
this.removeGradient();
}
else {
this.addGradient();
}
});
}
removeGradient(gradient) {
this.gradient.style.display = 'none';
}
addGradient(gradient) {
this.gradient.style.display = 'block';
}
checkOffsetWidths() {
if (this.tableContainer.offsetWidth >= this.table.offsetWidth) {
this.removeGradient();
}
else {
this.addGradient();
}
}
createTableHeaderAndFooter() {
if (this.table) {
const classification = this.table.getAttribute('data-classification');
const headLength = Number(this.table.getAttribute('data-col-length'));
const classificationContent = `<b>${classification}</b>`;
// Headers
const header = this.table.createTHead();
const classificationHeaderRow = header.insertRow(0);
classificationHeaderRow.classList.add('print-header-footer');
const classificationHeaderCell = classificationHeaderRow.insertCell(0);
classificationHeaderCell.outerHTML = `<th class="govuk-table__header govuk-table__cell--content print-header-footer print-header-footer--header" colspan=${headLength}>${classificationContent}</th>`;
// Footers
const footer = this.table.createTFoot();
const classificationFooterRow = footer.insertRow(0);
classificationFooterRow.classList.add('print-header-footer');
const classificationFooterCell = classificationFooterRow.insertCell(0);
classificationFooterCell.outerHTML = `<td class="govuk-table__cell govuk-table__cell--content print-header-footer table-row--no-border print-header-footer--footer" colspan=${headLength}>${classificationContent}</td>`;
}
}
}
class DownloadMessage extends DprClientClass {
downloadMessage;
static getModuleName() {
return 'download-message';
}
initialise() {
this.downloadMessage = this.getElement();
if (window.location.href.includes('download-disabled')) {
this.downloadMessage.classList.remove('dpr-download-message--hidden');
}
}
}
class DprFiltersFormClass extends DprClientClass {
form;
static getModuleName() {
return 'filters-form';
}
initialise() {
if (!(this.element instanceof HTMLFormElement)) {
throw new Error('DprFormQuerySync must be initialised on a form element');
}
this.form = this.element;
this.bindInputEvents();
}
// ----------------------------------
// Events
// ----------------------------------
bindInputEvents() {
this.getAllInputs().forEach(input => {
input.addEventListener('change', () => {
const params = new URLSearchParams(window.location.search);
this.updateQueryFromInput(input, params);
this.markPreventDefault(params, input.name); // TODO: Check if this is needed ?
this.resetPagination(params); // TODO: Check if this is needed ?
this.replaceUrl(params);
});
});
}
// ----------------------------------
// Query updates
// ----------------------------------
updateQueryFromInput(input, params) {
const { name } = input;
if (!name)
return;
if (input instanceof HTMLInputElement) {
if (input.type === 'checkbox') {
this.updateCheckbox(params, input);
}
else if (input.type === 'radio') {
this.updateRadio(params, input);
}
else {
this.updateSingle(params, input);
}
}
else {
this.updateSingle(params, input);
}
}
updateCheckbox(params, input) {
const values = params.getAll(input.name);
// Remove all existing values for this key
params.delete(input.name);
// Re‑add all values except the unchecked one
values
.filter(value => value !== input.value || input.checked)
.forEach(value => {
params.append(input.name, value);
});
// Add the newly checked value
if (input.checked && !values.includes(input.value)) {
params.append(input.name, input.value);
}
}
updateRadio(params, input) {
if (!input.checked)
return;
const name = this.normaliseFilterName(input.name);
params.set(name, input.value);
}
updateSingle(params, input) {
const name = this.normaliseFilterName(input.name);
let value = input.value;
if (input instanceof HTMLInputElement && input.dataset['staticOptionNameValue']) {
value = input.dataset['staticOptionNameValue'];
}
const isDateInput = input instanceof HTMLInputElement && input.classList.contains('moj-js-datepicker-input');
if (isDateInput) {
const formatted = dayjs(value, 'D/M/YYYY').format('YYYY-MM-DD');
value = formatted !== 'Invalid Date' ? formatted : '';
}
const trimmed = value.trim();
if (trimmed) {
params.set(name, trimmed);
}
else {
params.delete(name);
}
}
// ----------------------------------
// Behaviour flags
// ----------------------------------
/**
* Signals to the server that defaults
*/
markPreventDefault(params, changedName) {
if (changedName !== 'columns') {
params.set('preventDefault', 'true');
}
}
/**
* Reset pagination when filters change
*/
resetPagination(params) {
if (params.has('selectedPage')) {
params.set('selectedPage', '1');
}
}
replaceUrl(params) {
const query = params.toString();
const url = query ? `?${query}` : window.location.pathname;
window.history.replaceState(null, '', url);
}
// ----------------------------------
// DOM helpers
// ----------------------------------
getAllInputs() {
return Array.from(this.form.querySelectorAll('input, select, textarea')).filter(el => el.name);
}
normaliseFilterName(name) {
return name.startsWith('label.') ? name.replace(/^label\./, '') : name;
}
}
dayjs.extend(customParse);
/**
* --------------------------------------------
* Date formats
* --------------------------------------------
*/
const UI_INPUT_FORMATS = ['D/M/YYYY', 'DD/MM/YYYY'];
const API_FORMAT = 'YYYY-MM-DD';
const UI_OUTPUT_FORMAT = 'DD/MM/YYYY';
/**
* --------------------------------------------
* Transform helpers
* --------------------------------------------
*/
/**
* DD/MM/YYYY -> YYYY-MM-DD
*
* @export
* @param {string} [value]
* @return {*} {(string | undefined)}
*/
function uiDateToApi(value) {
if (!value)
return undefined;
const parsed = dayjs(value, [...UI_INPUT_FORMATS], true);
return parsed.isValid() ? parsed.format(API_FORMAT) : undefined;
}
/**
* --------------------------------------------
* Display helpers
* --------------------------------------------
*/
function formatDateOrUnset(value) {
if (!value)
return 'unset';
const parsed = dayjs(value, [...UI_INPUT_FORMATS, API_FORMAT], true);
return parsed.isValid() ? parsed.format(UI_OUTPUT_FORMAT) : 'unset';
}
class DprSelectedAsyncFilters extends DprClientClass {
container;
static getModuleName() {
return 'dpr-selected-async-filters';
}
initialise() {
this.container = this.element;
this.renderFromInputs();
this.bindInputEvents();
}
// ----------------------------------
// Input observation
// ----------------------------------
bindInputEvents() {
this.getAllFilterControls().forEach(control => {
control.addEventListener('change', () => {
this.renderFromInputs();
});
});
}
// ----------------------------------
// Rendering
// ----------------------------------
renderFromInputs() {
this.container.innerHTML = '';
const selectedFilters = this.buildSelectedFilters();
if (!selectedFilters.length) {
this.renderEmptyState();
return;
}
selectedFilters.forEach(filter => {
this.container.appendChild(this.createFilterElement(filter));
});
}
renderEmptyState() {
const p = document.createElement('p');
p.className = 'govuk-body-s govuk-!-margin-top-1 govuk-!-margin-bottom-0';
p.textContent = 'No filters selected';
this.container.appendChild(p);
}
// ----------------------------------
// Build selected filters from inputs
// ----------------------------------
buildSelectedFilters() {
const grouped = this.groupControlsByField();
return Object.values(grouped)
.map(controls => this.buildFilterFromControls(controls))
.filter(Boolean);
}
groupControlsByField() {
return this.getAllFilterControls().reduce((acc, control) => {
const parts = control.name.split('.');
// label.filters.fieldX -> filters.fieldX
const fieldKey = parts[0] === 'label' ? parts.slice(1, 3).join('.') : parts.slice(0, 2).join('.');
acc[fieldKey] ??= [];
acc[fieldKey].push(control);
return acc;
}, {});
}
// ----------------------------------
// Orchestration
// ----------------------------------
buildFilterFromControls(controls) {
const activeControls = this.getActiveControls(controls);
if (!activeControls.length)
return null;
const displayName = this.getDisplayName(controls);
if (this.isGranularDateRange(controls)) {
return this.buildGranularDateRangeFilter(displayName, controls);
}
if (this.isDateRange(controls)) {
return this.buildDateRangeFilter(displayName, controls);
}
if (this.isMultiSelect(activeControls)) {
return this.buildMultiSelectFilter(displayName, activeControls, controls);
}
return this.buildSingleValueFilter(displayName, activeControls[0], controls);
}
// ----------------------------------
// Guards
// ----------------------------------
getActiveControls(controls) {
return controls.filter(control => {
if (control instanceof HTMLSelectElement) {
return Boolean(control.value);
}
if (control instanceof HTMLInputElement && (control.type === 'checkbox' || control.type === 'radio')) {
return control.checked;
}
return Boolean(control.value);
});
}
isGranularDateRange(controls) {
return controls.some(c => c.name.includes('granularity'));
}
isDateRange(controls) {
return controls.some(c => c.name.endsWith('.start')) || controls.some(c => c.name.endsWith('.end'));
}
isMultiSelect(active) {
return active.length > 1;
}
// ----------------------------------
// Builders
// ----------------------------------
buildDateRangeFilter(displayName, controls) {
const start = controls.find(c => c.name.endsWith('.start'));
const end = controls.find(c => c.name.endsWith('.end'));
const relativeDuration = controls.find(c => {
if (!c.name.endsWith('.relative-duration'))
return false;
const input = c;
return input.type === 'radio' && input.checked;
});
const rangeDisplay = `${formatDateOrUnset(start?.value)} - ${formatDateOrUnset(end?.value)}`;
const displayValue = relativeDuration && relativeDuration.value !== 'none'
? `${rangeDisplay} / ${this.getDisplayValue(relativeDuration)}`
: rangeDisplay;
return {
displayName,
displayValue,
inputs: controls,
};
}
buildGranularDateRangeFilter(displayName, controls) {
const quick = controls.find(c => c.name.includes('quick-filter') && c.value);
const granularity = controls.find(c => c.name.includes('granularity'));
const start = controls.find(c => c.name.endsWith('.start') && c.value);
const end = controls.find(c => c.name.endsWith('.end') && c.value);
let displayValue = '';
if (quick && quick.value !== 'None') {
displayValue = `${this.humanise(quick.value)} / ${granularity?.value ?? 'unset'}`;
}
else {
displayValue =
`${formatDateOrUnset(start?.value)} - ${formatDateOrUnset(end?.value)}` + ` / ${granularity?.value ?? 'unset'}`;
}
return {
displayName,
displayValue,
inputs: controls,
};
}
buildMultiSelectFilter(displayName, active, controls) {
const values = active.map(c => this.getDisplayValue(c));
const displayValue = values.length > 3 ? `${values.slice(0, 3).join(', ')} + ${values.length - 3} more` : values.join(', ');
return { displayName, displayValue, inputs: controls };
}
buildSingleValueFilter(displayName, control, controls) {
return {
displayName,
displayValue: this.getDisplayValue(control),
inputs: controls,
};
}
// ----------------------------------
// Display helpers
// ----------------------------------
getDisplayName(controls) {
const legend = controls[0]?.closest('fieldset')?.querySelector('legend')?.textContent;
if (legend) {
return legend.trim();
}
const isDateRange = controls.some(c => c.name.endsWith('.start')) && controls.some(c => c.name.endsWith('.end'));
if (isDateRange) {
const explicit = controls.map(c => c.getAttribute('display-name')).find(Boolean);
if (explicit) {
return explicit.replace(/\s+(start|end)$/i, '').trim();
}
}
const explicit = controls.map(c => c.getAttribute('display-name')).find(Boolean);
if (explicit) {
return explicit;
}
const label = controls
.map(c => (c instanceof HTMLInputElement ? c.labels?.[0]?.innerText : undefined))
.find(Boolean);
if (label) {
return label;
}
return controls[0].name;
}
getDisplayValue(control) {
if (control instanceof HTMLSelectElement) {
const option = control.options[control.selectedIndex];
return option?.text ?? '';
}
// Autocomplete & text inputs should use their value
if (control instanceof HTMLInputElement && (control.type === 'search' || control.type === 'text')) {
return control.value;
}
// Static option value for radios & checkboxes
if (control.dataset['staticOptionNameValue']) {
return control.dataset['staticOptionNameValue'];
}
if (control instanceof HTMLInputElement &&
(control.type === 'radio' || control.type === 'checkbox') &&
control.labels?.[0]?.innerText) {
return control.labels[0].innerText;
}
return control.value;
}
// ----------------------------------
// Chip removal
// ----------------------------------
createFilterElement(filter) {
const button = document.createElement('button');
button.type = 'button';
button.className = 'dpr-clear-button-styles govuk-body dpr-selected-filter';
const name = document.createElement('strong');
name.className = 'dpr-selected-filter__name';
name.textContent = filter.displayName;
const value = document.createTextNode(`: ${filter.displayValue}`);
button.append(name, value);
button.addEventListener('click', () => {
const params = new URLSearchParams(window.location.search);
// Remove ALL values for this filter from the query string
filter.inputs.forEach(control => {
params.delete(control.name);
if (control instanceof HTMLSelectElement) {
control.selectedIndex = 0;
}
else if (control instanceof HTMLInputElement) {
if (control.type === 'checkbox' || control.type === 'radio') {
control.checked = false;
}
else {
control.value = '';
}
}
this.removeAutocompleteHiddenInput(control.name, params);
control.dispatchEvent(new Event('change', { bubbles: true }));
});
const query = params.toString();
const url = query ? `?${query}` : window.location.pathname;
window.history.replaceState(null, '', url);
});
return button;
}
removeAutocompleteHiddenInput(name, params) {
if (!name.startsWith('label.')) {
return;
}
const realFilterName = name.repla