Wiki source code of ISMS Management Dashboard
Last modified by Lee Pedley on 2026/09/21 21:59
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | {{velocity}} | ||
| 2 | #set ($settingsDoc = $xwiki.getDocument('ISMS.Settings')) | ||
| 3 | #set ($settings = $settingsDoc.getObject('ISMS.Code.SettingsClass')) | ||
| 4 | #set ($riskLowMax = 4) | ||
| 5 | #set ($riskMediumMax = 9) | ||
| 6 | #set ($riskHighMax = 14) | ||
| 7 | #set ($riskAppetite = 15) | ||
| 8 | #set ($reviewHorizon = 30) | ||
| 9 | #set ($evidenceHorizon = 30) | ||
| 10 | #set ($documentHorizon = 30) | ||
| 11 | #if ($settings) | ||
| 12 | #if ($settings.getProperty('riskLowMax').getValue()) #set ($riskLowMax = $settings.getProperty('riskLowMax').getValue()) #end | ||
| 13 | #if ($settings.getProperty('riskMediumMax').getValue()) #set ($riskMediumMax = $settings.getProperty('riskMediumMax').getValue()) #end | ||
| 14 | #if ($settings.getProperty('riskHighMax').getValue()) #set ($riskHighMax = $settings.getProperty('riskHighMax').getValue()) #end | ||
| 15 | #if ($settings.getProperty('riskAppetiteThreshold').getValue()) #set ($riskAppetite = $settings.getProperty('riskAppetiteThreshold').getValue()) #end | ||
| 16 | #if ($settings.getProperty('reviewHorizonDays').getValue()) #set ($reviewHorizon = $settings.getProperty('reviewHorizonDays').getValue()) #end | ||
| 17 | #if ($settings.getProperty('evidenceHorizonDays').getValue()) #set ($evidenceHorizon = $settings.getProperty('evidenceHorizonDays').getValue()) #end | ||
| 18 | #if ($settings.getProperty('documentHorizonDays').getValue()) #set ($documentHorizon = $settings.getProperty('documentHorizonDays').getValue()) #end | ||
| 19 | #end | ||
| 20 | #set ($riskDocs=$services.query.xwql("from doc.object('Risks.Code.RisksClass') as obj").setLimit(2000).execute()) | ||
| 21 | #set ($treatmentDocs=$services.query.xwql("from doc.object('Risk Treatments.Code.Risk TreatmentsClass') as obj").setLimit(2000).execute()) | ||
| 22 | #set ($controlDocs=$services.query.xwql("from doc.object('Controls and SoA.Code.Controls and SoAClass') as obj").setLimit(2000).execute()) | ||
| 23 | #set ($evidenceDocs=$services.query.xwql("from doc.object('Evidence.Code.EvidenceClass') as obj").setLimit(2000).execute()) | ||
| 24 | #set ($auditDocs=$services.query.xwql("from doc.object('Audits.Code.AuditsClass') as obj").setLimit(2000).execute()) | ||
| 25 | #set ($findingDocs=$services.query.xwql("from doc.object('Findings.Code.FindingsClass') as obj").setLimit(2000).execute()) | ||
| 26 | #set ($actionDocs=$services.query.xwql("from doc.object('Corrective Actions.Code.Corrective ActionsClass') as obj").setLimit(2000).execute()) | ||
| 27 | #set ($controlledDocDocs=$services.query.xwql("from doc.object('Controlled Documents.Code.Controlled DocumentsClass') as obj").setLimit(2000).execute()) | ||
| 28 | #set($openRisks=0)#set($aboveAppetite=0)#set($unassessedResidual=0)#set($openTreatments=0)#set($overdueTreatments=0)#set($controlsDue=0)#set($evidenceAttention=0)#set($activeAudits=0)#set($openFindings=0)#set($overdueFindings=0)#set($overdueActions=0)#set($documentsDue=0)#set($alerts=[]) | ||
| 29 | #foreach($ref in $riskDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Risks.Code.RisksClass'))#if($o)#set($st=$o.getProperty('status').getValue())#set($rs=$o.getProperty('residualScore').getValue())#if($st!='Closed')#set($openRisks=$openRisks+1)#if(!$rs)#set($unassessedResidual=$unassessedResidual+1)#elseif($rs >= $riskAppetite)#set($aboveAppetite=$aboveAppetite+1)#set($x=$alerts.add(['Residual risk >= appetite threshold',$ref,$d.displayTitle,$rs]))#end#end#end#end | ||
| 30 | #foreach($ref in $treatmentDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Risk Treatments.Code.Risk TreatmentsClass'))#if($o)#set($st=$o.getProperty('status').getValue())#if($st!='Complete'&&$st!='Cancelled')#set($openTreatments=$openTreatments+1)#set($due=$o.getProperty('targetDate').getValue())#if($due&&$datetool.whenIs($due).days<0)#set($overdueTreatments=$overdueTreatments+1)#set($x=$alerts.add(['Overdue treatment',$ref,$d.displayTitle,$xwiki.formatDate($due)]))#end#end#end#end | ||
| 31 | #foreach($ref in $controlDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Controls and SoA.Code.Controls and SoAClass'))#if($o)#set($due=$o.getProperty('nextReviewDate').getValue())#if($due&&$datetool.whenIs($due).days<=$reviewHorizon)#set($controlsDue=$controlsDue+1)#set($x=$alerts.add(['Control review',$ref,$d.displayTitle,$xwiki.formatDate($due)]))#end#end#end | ||
| 32 | #foreach($ref in $evidenceDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Evidence.Code.EvidenceClass'))#if($o)#set($due=$o.getProperty('validUntil').getValue())#if($due&&$datetool.whenIs($due).days<=$evidenceHorizon)#set($evidenceAttention=$evidenceAttention+1)#set($x=$alerts.add(['Evidence review / expiry',$ref,$d.displayTitle,$xwiki.formatDate($due)]))#end#end#end | ||
| 33 | #foreach($ref in $auditDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Audits.Code.AuditsClass'))#if($o)#set($st=$o.getProperty('status').getValue())#if($st!='Complete'&&$st!='Cancelled')#set($activeAudits=$activeAudits+1)#end#end#end | ||
| 34 | #foreach($ref in $findingDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Findings.Code.FindingsClass'))#if($o)#set($st=$o.getProperty('status').getValue())#if($st!='Closed')#set($openFindings=$openFindings+1)#set($due=$o.getProperty('dueDate').getValue())#if($due&&$datetool.whenIs($due).days<0)#set($overdueFindings=$overdueFindings+1)#set($x=$alerts.add(['Overdue finding',$ref,$d.displayTitle,$xwiki.formatDate($due)]))#end#end#end#end | ||
| 35 | #foreach($ref in $actionDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Corrective Actions.Code.Corrective ActionsClass'))#if($o)#set($st=$o.getProperty('status').getValue())#set($due=$o.getProperty('dueDate').getValue())#if($due&&$st!='Verified'&&$st!='Cancelled'&&$datetool.whenIs($due).days<0)#set($overdueActions=$overdueActions+1)#set($x=$alerts.add(['Overdue corrective action',$ref,$d.displayTitle,$xwiki.formatDate($due)]))#end#end#end | ||
| 36 | #foreach($ref in $controlledDocDocs)#set($d=$xwiki.getDocument($ref))#set($o=$d.getObject('Controlled Documents.Code.Controlled DocumentsClass'))#if($o)#set($due=$o.getProperty('nextReviewDate').getValue())#if($due&&$datetool.whenIs($due).days<=$documentHorizon)#set($documentsDue=$documentsDue+1)#set($x=$alerts.add(['Document review',$ref,$d.displayTitle,$xwiki.formatDate($due)]))#end#end#end | ||
| 37 | {{html wiki="true" clean="false"}} | ||
| 38 | <style> | ||
| 39 | .isms-dashboard .isms-dash-note{margin-bottom:16px}.isms-quick-actions{display:flex;flex-wrap:wrap;gap:7px;margin:12px 0 20px}.isms-quick-actions form{margin:0}.isms-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;margin:12px 0 24px}.isms-kpi{border:1px solid #d9dfe5;border-radius:8px;padding:14px;background:#fff;min-height:115px}.isms-kpi-title{font-weight:700;color:#263238;margin-bottom:6px}.isms-kpi-value{font-size:2em;font-weight:700;line-height:1.1}.isms-kpi-sub{color:#68737d;font-size:.9em;margin-top:7px;line-height:1.35}.isms-dash-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:10px}.isms-dash-link{border:1px solid #d9dfe5;border-radius:7px;padding:13px;display:block;text-decoration:none}.isms-alerts{width:100%;border-collapse:collapse}.isms-alerts th,.isms-alerts td{border-bottom:1px solid #e1e5e9;padding:8px;text-align:left}.isms-dash-section{margin-top:26px} | ||
| 40 | </style> | ||
| 41 | <div class="isms-dashboard"> | ||
| 42 | <div class="box infomessage isms-dash-note"><strong>Management overview</strong><br/>This page highlights items requiring attention. Thresholds and reminder windows come from <a href="$xwiki.getURL('ISMS.Settings','view')">ISMS Settings</a>. Residual risk review threshold: <strong>$riskAppetite</strong>. Control review reminder: <strong>$reviewHorizon days</strong>.</div> | ||
| 43 | <h2>Quick actions</h2> | ||
| 44 | <div class="isms-quick-actions"> | ||
| 45 | <form action="$xwiki.getURL('Risks.WebHome','create')" method="get"><input type="hidden" name="templateprovider" value="Risks.Code.RisksTemplateProvider"/><button class="btn btn-primary" type="submit">Add Risk</button></form> | ||
| 46 | <form action="$xwiki.getURL('Controls and SoA.WebHome','create')" method="get"><input type="hidden" name="templateprovider" value="Controls and SoA.Code.Controls and SoATemplateProvider"/><button class="btn btn-default" type="submit">Add Control / SoA Entry</button></form> | ||
| 47 | <form action="$xwiki.getURL('Risk Treatments.WebHome','create')" method="get"><input type="hidden" name="templateprovider" value="Risk Treatments.Code.Risk TreatmentsTemplateProvider"/><button class="btn btn-default" type="submit">Add Risk Treatment</button></form> | ||
| 48 | <form action="$xwiki.getURL('Evidence.WebHome','create')" method="get"><input type="hidden" name="templateprovider" value="Evidence.Code.EvidenceTemplateProvider"/><button class="btn btn-default" type="submit">Add Evidence</button></form> | ||
| 49 | <form action="$xwiki.getURL('Audits.WebHome','create')" method="get"><input type="hidden" name="templateprovider" value="Audits.Code.AuditsTemplateProvider"/><button class="btn btn-default" type="submit">Add Audit</button></form> | ||
| 50 | <a class="btn btn-default" href="$xwiki.getURL('ISMS.DataQuality','view')">Check Data Quality</a> | ||
| 51 | </div> | ||
| 52 | <h2>Current position</h2> | ||
| 53 | <div class="isms-kpis"> | ||
| 54 | <div class="isms-kpi"><div class="isms-kpi-title">Open risks</div><div class="isms-kpi-value">$openRisks</div><div class="isms-kpi-sub"><a href="$xwiki.getURL('Risks.WebHome','view')">Open the risk register</a></div></div> | ||
| 55 | <div class="isms-kpi"><div class="isms-kpi-title">Residual risks requiring management review</div><div class="isms-kpi-value">$aboveAppetite</div><div class="isms-kpi-sub">Residual score at or above $riskAppetite. $unassessedResidual open risk(s) still need residual assessment.</div></div> | ||
| 56 | <div class="isms-kpi"><div class="isms-kpi-title">Open risk treatments</div><div class="isms-kpi-value">$openTreatments</div><div class="isms-kpi-sub">$overdueTreatments overdue. <a href="$xwiki.getURL('Risk Treatments.WebHome','view')">Open treatments</a></div></div> | ||
| 57 | <div class="isms-kpi"><div class="isms-kpi-title">Controls due for review</div><div class="isms-kpi-value">$controlsDue</div><div class="isms-kpi-sub">Due within $reviewHorizon days or overdue. <a href="$xwiki.getURL('Controls and SoA.WebHome','view')">Open Controls & SoA</a></div></div> | ||
| 58 | <div class="isms-kpi"><div class="isms-kpi-title">Evidence requiring attention</div><div class="isms-kpi-value">$evidenceAttention</div><div class="isms-kpi-sub">Expiring within $evidenceHorizon days or expired. <a href="$xwiki.getURL('Evidence.WebHome','view')">Open evidence</a></div></div> | ||
| 59 | <div class="isms-kpi"><div class="isms-kpi-title">Open findings</div><div class="isms-kpi-value">$openFindings</div><div class="isms-kpi-sub">$overdueFindings overdue. <a href="$xwiki.getURL('Findings.WebHome','view')">Open findings</a></div></div> | ||
| 60 | <div class="isms-kpi"><div class="isms-kpi-title">Overdue corrective actions</div><div class="isms-kpi-value">$overdueActions</div><div class="isms-kpi-sub"><a href="$xwiki.getURL('Corrective Actions.WebHome','view')">Open corrective actions</a></div></div> | ||
| 61 | <div class="isms-kpi"><div class="isms-kpi-title">Controlled documents due for review</div><div class="isms-kpi-value">$documentsDue</div><div class="isms-kpi-sub">Due within $documentHorizon days or overdue. <a href="$xwiki.getURL('Controlled Documents.WebHome','view')">Open documents</a></div></div> | ||
| 62 | <div class="isms-kpi"><div class="isms-kpi-title">Active audits</div><div class="isms-kpi-value">$activeAudits</div><div class="isms-kpi-sub"><a href="$xwiki.getURL('Audits.WebHome','view')">Open the audit register</a></div></div> | ||
| 63 | </div> | ||
| 64 | <div class="isms-dash-section"><h2>Attention queue</h2>#if($alerts.isEmpty())<div class="box successmessage">No tracked overdue, due-soon or residual-risk-review items were detected.</div>#else<table class="isms-alerts"><thead><tr><th>Reason</th><th>Record</th><th>Date / score</th></tr></thead><tbody>#foreach($a in $alerts)<tr><td>$escapetool.xml($a.get(0))</td><td><a href="$xwiki.getURL($a.get(1),'view')">$escapetool.xml($a.get(2))</a></td><td>$escapetool.xml($a.get(3))</td></tr>#end</tbody></table>#end</div> | ||
| 65 | <div class="isms-dash-section"><h2>Reports and assurance</h2><div class="isms-dash-grid"><a class="isms-dash-link" href="$xwiki.getURL('ISMS.RiskReport','view')"><strong>Risk Report</strong><br/>Inherent and residual exposure, treatment and management-review threshold.</a><a class="isms-dash-link" href="$xwiki.getURL('ISMS.SoAReport','view')"><strong>Statement of Applicability Report</strong><br/>Control applicability, justification, implementation and evidence.</a><a class="isms-dash-link" href="$xwiki.getURL('ISMS.ManagementReview','view')"><strong>Management Review Pack</strong><br/>Management-level snapshot and review agenda.</a><a class="isms-dash-link" href="$xwiki.getURL('ISMS.DataQuality','view')"><strong>Data Quality Check</strong><br/>Find incomplete records before assurance reviews.</a></div></div> | ||
| 66 | <div class="isms-dash-section"><h2>Registers</h2><div class="isms-dash-grid"><a class="isms-dash-link" href="$xwiki.getURL('Controlled Documents.WebHome','view')"><strong>Controlled Documents</strong><br/>Policies, procedures, standards, forms and records.</a><a class="isms-dash-link" href="$xwiki.getURL('Controls and SoA.WebHome','view')"><strong>Controls & SoA</strong><br/>Applicability, implementation, evidence and review.</a><a class="isms-dash-link" href="$xwiki.getURL('Risks.WebHome','view')"><strong>Risks</strong><br/>Risk assessment and treatment decisions.</a><a class="isms-dash-link" href="$xwiki.getURL('Risk Treatments.WebHome','view')"><strong>Risk Treatments</strong><br/>Actions, owners and target dates.</a><a class="isms-dash-link" href="$xwiki.getURL('Evidence.WebHome','view')"><strong>Evidence</strong><br/>Evidence records and validity dates.</a><a class="isms-dash-link" href="$xwiki.getURL('Audits.WebHome','view')"><strong>Audits</strong><br/>Assurance programme and audit activity.</a><a class="isms-dash-link" href="$xwiki.getURL('Findings.WebHome','view')"><strong>Findings</strong><br/>Audit findings, ownership and closure.</a><a class="isms-dash-link" href="$xwiki.getURL('Corrective Actions.WebHome','view')"><strong>Corrective Actions</strong><br/>Remediation and effectiveness review.</a></div></div> | ||
| 67 | </div> | ||
| 68 | {{/html}} | ||
| 69 | {{/velocity}} |