Skip to content

Commit 34f7863

Browse files
ndg63276Mark Williamsgfrn
authored
LIMS-148: Improve staff imaging dashboard (#914)
* LIMS-148: Improve staff imaging dashboard * LIMS-148: Add highlighting of queued samples, show queued containers * LIMS-148: Fix display of queued samples in queued containers * LIMS-148: Allow sorting by no of subsamples * LIMS-148: Dont break xpdf containers page * LIMS-148: Use strict equality Co-authored-by: Guilherme Francisco <guilherme.de-freitas@diamond.ac.uk> --------- Co-authored-by: Mark Williams <mark.williams@diamond.ac.uk> Co-authored-by: Guilherme Francisco <guilherme.de-freitas@diamond.ac.uk>
1 parent 611c307 commit 34f7863

File tree

3 files changed

+133
-31
lines changed

3 files changed

+133
-31
lines changed

api/src/Page/Shipment.php

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,8 +2097,73 @@ function _get_all_containers()
20972097
$totalQuery->joinClause("INNER JOIN shipping sh ON sh.shippingid = d.shippingid");
20982098
}
20992099

2100+
$subsamples = '0 as queuedmanualsubsamples,
2101+
0 as completedmanualsubsamples,
2102+
0 as availablemanualsubsamples,
2103+
0 as queuedautosubsamples,
2104+
0 as completedautosubsamples,
2105+
0 as availableautosubsamples,';
2106+
2107+
$manualsubsamples = "
2108+
(SELECT count(distinct ss.blsubsampleid) FROM blsubsample ss
2109+
INNER JOIN blsample s2 ON s2.blsampleid = ss.blsampleid
2110+
LEFT OUTER JOIN containerqueuesample cqs2 ON cqs2.blsubsampleid = ss.blsubsampleid
2111+
LEFT OUTER JOIN containerqueue cq2 ON cq2.containerqueueid = cqs2.containerqueueid
2112+
WHERE s2.containerid = c.containerid AND ss.source='manual'
2113+
AND cqs2.containerqueuesampleid IS NOT NULL AND cq2.completedtimestamp IS NULL) as queuedmanualsubsamples,
2114+
(SELECT count(distinct ss.blsubsampleid) FROM blsubsample ss
2115+
INNER JOIN blsample s2 ON s2.blsampleid = ss.blsampleid
2116+
LEFT OUTER JOIN containerqueuesample cqs2 ON cqs2.blsubsampleid = ss.blsubsampleid
2117+
LEFT OUTER JOIN containerqueue cq2 ON cq2.containerqueueid = cqs2.containerqueueid
2118+
WHERE s2.containerid = c.containerid AND ss.source='manual'
2119+
AND cq2.completedtimestamp IS NOT NULL) as completedmanualsubsamples,
2120+
(SELECT count(distinct ss.blsubsampleid) FROM blsubsample ss
2121+
INNER JOIN blsample s2 ON s2.blsampleid = ss.blsampleid
2122+
LEFT OUTER JOIN containerqueuesample cqs2 ON cqs2.blsubsampleid = ss.blsubsampleid
2123+
WHERE s2.containerid = c.containerid AND ss.source='manual'
2124+
AND cqs2.containerqueuesampleid IS NULL) as availablemanualsubsamples,";
2125+
$autosubsamples = "
2126+
(SELECT COUNT(DISTINCT CASE WHEN cqs3.containerqueuesampleid IS NOT NULL AND cq3.completedtimestamp IS NULL THEN ss3.blsubsampleid ELSE NULL END)
2127+
FROM blsample s3
2128+
LEFT JOIN (
2129+
SELECT si.blsampleid, MAX(si.blsampleimageid) AS max_blsampleimageid
2130+
FROM blsampleimage si
2131+
GROUP BY si.blsampleid
2132+
) AS max_si ON s3.blsampleid = max_si.blsampleid
2133+
LEFT JOIN blsubsample ss3 ON max_si.max_blsampleimageid = ss3.blsampleimageid AND ss3.source = 'auto'
2134+
LEFT OUTER JOIN containerqueuesample cqs3 ON cqs3.blsubsampleid = ss3.blsubsampleid
2135+
LEFT OUTER JOIN containerqueue cq3 ON cq3.containerqueueid = cqs3.containerqueueid
2136+
WHERE s3.containerid = c.containerid
2137+
) AS queuedautosubsamples,
2138+
(SELECT COUNT(DISTINCT CASE WHEN cq3.completedtimestamp IS NOT NULL THEN ss3.blsubsampleid ELSE NULL END)
2139+
FROM blsample s3
2140+
LEFT JOIN (
2141+
SELECT si.blsampleid, MAX(si.blsampleimageid) AS max_blsampleimageid
2142+
FROM blsampleimage si
2143+
GROUP BY si.blsampleid
2144+
) AS max_si ON s3.blsampleid = max_si.blsampleid
2145+
LEFT JOIN blsubsample ss3 ON max_si.max_blsampleimageid = ss3.blsampleimageid AND ss3.source = 'auto'
2146+
LEFT OUTER JOIN containerqueuesample cqs3 ON cqs3.blsubsampleid = ss3.blsubsampleid
2147+
LEFT OUTER JOIN containerqueue cq3 ON cq3.containerqueueid = cqs3.containerqueueid
2148+
WHERE s3.containerid = c.containerid
2149+
) AS completedautosubsamples,
2150+
(SELECT COUNT(DISTINCT CASE WHEN cqs3.containerqueuesampleid IS NULL THEN ss3.blsubsampleid ELSE NULL END)
2151+
FROM blsample s3
2152+
LEFT JOIN (
2153+
SELECT si.blsampleid, MAX(si.blsampleimageid) AS max_blsampleimageid
2154+
FROM blsampleimage si
2155+
GROUP BY si.blsampleid
2156+
) AS max_si ON s3.blsampleid = max_si.blsampleid
2157+
LEFT JOIN blsubsample ss3 ON max_si.max_blsampleimageid = ss3.blsampleimageid AND ss3.source = 'auto'
2158+
LEFT OUTER JOIN containerqueuesample cqs3 ON cqs3.blsubsampleid = ss3.blsubsampleid
2159+
WHERE s3.containerid = c.containerid
2160+
) AS availableautosubsamples,";
2161+
21002162

21012163
if ($this->has_arg('ty')) {
2164+
if ($this->arg('ty') != 'puck') {
2165+
$subsamples = $manualsubsamples . $autosubsamples;
2166+
}
21022167
if ($this->arg('ty') == 'plate') {
21032168
$where .= " AND c.containertype NOT LIKE '%puck'";
21042169
} else if ($this->arg('ty') == 'puck') {
@@ -2120,7 +2185,7 @@ function _get_all_containers()
21202185
} else if ($this->arg('ty') == 'processing') {
21212186
$where .= " AND c.containerstatus = 'processing'";
21222187
} else if ($this->arg('ty') == 'subsamples') {
2123-
$having .= " HAVING subsamples > 0";
2188+
$having .= " HAVING queuedmanualsubsamples+completedmanualsubsamples+availablemanualsubsamples > 0";
21242189
$subsamplesInTotal = ", count(distinct ss.blsubsampleid) as subsamples";
21252190
$totalQuery->joinClause("LEFT OUTER JOIN blsample s ON s.containerid = c.containerid");
21262191
$totalQuery->joinClause("LEFT OUTER JOIN blsubsample ss ON s.blsampleid = ss.blsampleid AND ss.source='manual'");
@@ -2180,16 +2245,18 @@ function _get_all_containers()
21802245
}
21812246

21822247
if ($this->has_arg('imager')) {
2183-
if ($this->arg('imager') == '1')
2248+
if ($this->arg('imager') == '1') {
21842249
$where .= ' AND c.imagerid IS NOT NULL';
2185-
else
2250+
$subsamples = $manualsubsamples . $autosubsamples;
2251+
} else
21862252
$where .= ' AND c.imagerid IS NULL AND c.requestedimagerid IS NULL';
21872253
}
21882254

21892255

21902256
if ($this->has_arg('iid')) {
21912257
$where .= ' AND c.imagerid=:' . (sizeof($args) + 1);
21922258
array_push($args, $this->arg('iid'));
2259+
$subsamples = $manualsubsamples . $autosubsamples;
21932260
}
21942261

21952262
if ($this->has_arg('CONTAINERREGISTRYID')) {
@@ -2202,22 +2269,30 @@ function _get_all_containers()
22022269
array_push($args, $this->user->personId);
22032270
}
22042271

2205-
$tot = $this->db->pq("SELECT count(distinct c.containerid) as tot
2206-
$subsamplesInTotal
2272+
if ($this->has_arg('s')) {
2273+
$totalQuery->joinClause("INNER JOIN dewar d ON d.dewarid = c.dewarid");
2274+
$totalQuery->joinClause("INNER JOIN shipping sh ON sh.shippingid = d.shippingid");
2275+
$totalQuery->joinClause("INNER JOIN proposal p ON p.proposalid = sh.proposalid");
2276+
$searchfields = array('c.code', 'c.barcode', 'd.code', 'sh.shippingname', 'c.containertype', 'concat(p.proposalcode, p.proposalnumber)');
2277+
$conditions = array();
2278+
foreach ($searchfields as $sf) {
2279+
$st = sizeof($args) + 1;
2280+
array_push($conditions, $sf." LIKE CONCAT('%', :".$st.", '%')");
2281+
array_push($args, $this->arg('s'));
2282+
}
2283+
$where .= " AND (" . implode(" OR ", $conditions) . ")";
2284+
}
2285+
2286+
$tot = $this->db->pq("SELECT COUNT(*) as tot FROM
2287+
(SELECT $manualsubsamples
2288+
c.containerid
22072289
FROM container c
22082290
{$totalQuery->getJoins()}
22092291
WHERE $where
2210-
$having", $args);
2292+
group by c.containerid
2293+
$having) as result", $args);
22112294
$tot = sizeof($tot) ? intval($tot[0]['TOT']) : 0;
22122295

2213-
if ($this->has_arg('s')) {
2214-
$st = sizeof($args) + 1;
2215-
$where .= " AND (lower(c.code) LIKE lower(CONCAT(CONCAT('%',:" . $st . "), '%')) OR lower(c.barcode) LIKE lower(CONCAT(CONCAT('%',:" . ($st + 1) . "), '%')))";
2216-
array_push($args, $this->arg('s'));
2217-
array_push($args, $this->arg('s'));
2218-
}
2219-
2220-
22212296
$pp = $this->has_arg('per_page') ? $this->arg('per_page') : 15;
22222297
$pg = $this->has_arg('page') ? $this->arg('page') - 1 : 0;
22232298
$start = $pg * $pp;
@@ -2242,9 +2317,13 @@ function _get_all_containers()
22422317

22432318
if ($this->has_arg('sort_by')) {
22442319
$cols = array(
2245-
'NAME' => 'c.code', 'DEWAR' => 'd.code', 'SHIPMENT' => 'sh.shippingname', 'SAMPLES' => 'count(s.blsampleid)', 'SHIPPINGID' => 'sh.shippingid', 'LASTINSPECTION' => 'max(ci.bltimestamp)', 'INSPECTIONS' => 'count(ci.containerinspectionid)',
2320+
'NAME' => 'c.code', 'DEWAR' => 'd.code', 'SHIPMENT' => 'sh.shippingname', 'SAMPLES' => 'count(distinct s.blsampleid)',
2321+
'SHIPPINGID' => 'sh.shippingid', 'LASTINSPECTION' => 'max(ci.bltimestamp)', 'INSPECTIONS' => 'count(distinct ci.containerinspectionid)',
22462322
'DCCOUNT' => 'COUNT(distinct dc.datacollectionid)', 'SUBSAMPLES' => 'subsamples',
2247-
'LASTQUEUECOMPLETED' => 'max(cq2.completedtimestamp)', 'QUEUEDTIMESTAMP' => 'max(cq.createdtimestamp)'
2323+
'LASTQUEUECOMPLETED' => 'max(cq2.completedtimestamp)', 'QUEUEDTIMESTAMP' => 'max(cq.createdtimestamp)',
2324+
'CONTAINERTYPE' => 'c.containertype', 'CONTAINERSTATUS' => 'c.containerstatus', 'LASTINSPECTIONDAYS' => 'lastinspectiondays',
2325+
'AGE' => 'age', 'VISIT' => 'visit', 'REQUESTEDIMAGER' => 'requestedimager', 'IMAGER' => 'imager',
2326+
'MANUAL' => 'queuedmanualsubsamples', 'AUTO' => 'queuedautosubsamples',
22482327
);
22492328
$dir = $this->has_arg('order') ? ($this->arg('order') == 'asc' ? 'ASC' : 'DESC') : 'ASC';
22502329
if (array_key_exists($this->arg('sort_by'), $cols))
@@ -2256,6 +2335,7 @@ function _get_all_containers()
22562335
(SELECT sch.name FROM schedule sch WHERE sch.scheduleid = c.scheduleid) as schedule,
22572336
(SELECT i2.name FROM imager i2 WHERE i2.imagerid = c.requestedimagerid) as requestedimager,
22582337
(SELECT count(distinct ss.blsubsampleid) FROM blsubsample ss RIGHT OUTER JOIN blsample s2 ON s2.blsampleid = ss.blsampleid WHERE s2.containerid = c.containerid AND ss.source='manual') as subsamples,
2338+
$subsamples
22592339
(SELECT ses3.beamlinename FROM blsession ses3 WHERE d.firstexperimentid = ses3.sessionid) as firstexperimentbeamline,
22602340
(SELECT pp.name FROM processingpipeline pp WHERE c.prioritypipelineid = pp.processingpipelineid) as pipeline,
22612341
TO_CHAR(max(cq2.completedtimestamp), 'HH24:MI DD-MM-YYYY') as lastqueuecompleted, TIMESTAMPDIFF('MINUTE', max(cq2.completedtimestamp), max(cq2.createdtimestamp)) as lastqueuedwell,

client/src/js/modules/imaging/views/admin/dashboard.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ define(['marionette',
127127
this.ty = new FilterView({ collection: this.inspections, filters: filters, mobile: true, url: false, name: 'ty' })
128128
this.insf.show(this.ty)
129129

130-
this.ctrs.show(new ContainersView({ collection: this.containers, params: {}, barcode: true }))
130+
this.ctrs.show(new ContainersView({ collection: this.containers, params: {}, imager: true }))
131131
},
132132

133133
})

client/src/js/modules/shipment/views/containers.js

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,30 @@ define(['marionette',
4848
cookie: true,
4949
})
5050

51+
var CustomHeaderCell = Backgrid.HeaderCell.extend({
52+
render: function() {
53+
// Allow HTML in the column header
54+
this.$el.html(this.column.get("label"));
55+
return this;
56+
}
57+
});
58+
59+
var highlightQueued = function(data, auto) {
60+
const queued = auto ? data.QUEUEDAUTOSUBSAMPLES : data.QUEUEDMANUALSUBSAMPLES;
61+
const completed = auto ? data.COMPLETEDAUTOSUBSAMPLES : data.COMPLETEDMANUALSUBSAMPLES;
62+
const available = auto ? data.AVAILABLEAUTOSUBSAMPLES : data.AVAILABLEMANUALSUBSAMPLES;
63+
return (queued > 0 ? '<span class="minor">'+queued+'</span>' : queued)+' / '+completed+' / '+available;
64+
}
65+
66+
var queuedCompleted = function(data) {
67+
if (data.LASTQUEUECOMPLETED) { return data.LASTQUEUECOMPLETED }
68+
if (data.CONTAINERQUEUEID) { return 'Queued' }
69+
return null
70+
}
71+
5172
return Marionette.LayoutView.extend({
5273
className: 'content',
53-
template: '<div><h1>Containers</h1><div class="filter type"></div><div class="filter"><ul><li><label><input type="checkbox" name="currentuser" /> My Containers</label></li></ul></div><div class="wrapper"></div></div>',
74+
template: '<div><h1>Containers</h1><div class="filter"><span class="type"></span><span><ul><li><label><input type="checkbox" name="currentuser" /> My Containers</label></li></ul></span></div><div class="wrapper"></div></div>',
5475
regions: { wrap: '.wrapper', type: '.type' },
5576

5677
ui: {
@@ -61,18 +82,19 @@ define(['marionette',
6182
'change @ui.cur': 'refresh'
6283
},
6384

64-
hiddenColumns: [1,2,5,6,9,10,11],
85+
hiddenColumns: [1,2,5,6,7,10,11,12],
6586

6687
columns: [
6788
{ name: 'NAME', label: 'Name', cell: 'string', editable: false },
6889
{ name: 'DEWAR', label: 'Dewar', cell: 'string', editable: false },
6990
{ name: 'BARCODE', label: 'Barcode', cell: 'string', editable: false },
7091
{ name: 'SHIPMENT', label: 'Shipment', cell: 'string', editable: false },
7192
{ name: 'SAMPLES', label: '# Samples', cell: 'string', editable: false },
72-
{ name: 'SUBSAMPLES', label: '# Subsamples', cell: 'string', editable: false },
93+
{ name: 'MANUAL', label: '<button>Manual Subsamples<br>Queued / Complete / Avail</button>', cell: table.TemplateCell, template: d=>highlightQueued(d,false), editable: false, headerCell: CustomHeaderCell },
94+
{ name: 'AUTO', label: '<button>Auto Subsamples<br>Queued / Complete / Avail</button>', cell: table.TemplateCell, template: d=>highlightQueued(d,true), editable: false, headerCell: CustomHeaderCell },
7395
{ name: 'CONTAINERTYPE', label: 'Type', cell: 'string', editable: false },
7496
{ name: 'CONTAINERSTATUS', label: 'Status', cell: 'string', editable: false },
75-
{ name: 'LASTQUEUECOMPLETED', label: 'Completed', cell: 'string', editable: false },
97+
{ name: 'LASTQUEUECOMPLETED', label: 'Completed', cell: table.TemplateCell, template: queuedCompleted, editable: false },
7698
{ name: 'INSPECTIONS', label: 'Inspections', cell: 'string', editable: false },
7799
{ name: 'LASTINSPECTIONDAYS', label: 'Last (d)', cell: 'string', editable: false },
78100
{ name: 'AGE', label: 'Age (d)', cell: 'string', editable: false },
@@ -86,7 +108,7 @@ define(['marionette',
86108
{ id: 'queued', name: 'Queued'},
87109
{ id: 'completed', name: 'Completed'},
88110
{ id: 'processing', name: 'Processing'},
89-
{ id: 'subsamples', name: 'Has Subsamples'},
111+
{ id: 'subsamples', name: 'Has Manual Subsamples'},
90112
],
91113

92114
showImaging: true,
@@ -100,7 +122,9 @@ define(['marionette',
100122
},
101123

102124
initialize: function(options) {
103-
var filters = this.getOption('filters').slice(0)
125+
this.imager = options.imager
126+
// dont show Plates/Pucks/In Imager filters if in imager mode
127+
var filters = this.getOption('filters').slice(this.imager ? 3 : 0)
104128
var columns = this.getOption('columns').slice(0)
105129
if (app.user_can('disp_cont') && !app.mobile() && this.getOption('showImaging')) {
106130
columns.push({ name: 'VISIT', label: 'Visit', cell: 'string', editable: false })
@@ -111,12 +135,6 @@ define(['marionette',
111135
filters.push({ id: 'todispose', name: 'To Dispose'})
112136
}
113137

114-
columns[2].renderable = false
115-
if (options.barcode) {
116-
columns[1].renderable = false
117-
columns[2].renderable = true
118-
}
119-
120138
if (app.mobile()) {
121139
_.each(this.getOption('hiddenColumns'), function(v) {
122140
columns[v].renderable = false
@@ -141,12 +159,16 @@ define(['marionette',
141159
},
142160

143161
updateCols: function(selected) {
144-
var isPuck = (selected == null || selected == 'puck')
162+
var isPuck = !this.imager && (selected === null || selected === 'puck')
145163

146164
var dew = this.table.grid.columns.findWhere({ name: 'DEWAR' })
147165
var bc = this.table.grid.columns.findWhere({ name: 'BARCODE' })
166+
var manual = this.table.grid.columns.findWhere({ name: 'MANUAL' })
167+
var auto = this.table.grid.columns.findWhere({ name: 'AUTO' })
148168
dew.set('renderable', isPuck)
149169
bc.set('renderable', !isPuck)
170+
if (manual) manual.set('renderable', !isPuck)
171+
if (auto) auto.set('renderable', !isPuck)
150172
},
151173

152174
onRender: function() {
@@ -158,4 +180,4 @@ define(['marionette',
158180
}
159181
})
160182

161-
})
183+
})

0 commit comments

Comments
 (0)