Skip to content

Commit c0eed0a

Browse files
ndg63276Mark Williams
andauthored
LIMS-1753: View of all inspection images for a plate (#980)
* LIMS-1753: View of all inspection images for a plate * LIMS-1753: Add flex wrap, dont load images if scrolled past --------- Co-authored-by: Mark Williams <mark.williams@diamond.ac.uk>
1 parent 8a1117d commit c0eed0a

File tree

9 files changed

+152
-9
lines changed

9 files changed

+152
-9
lines changed

api/src/Page/Imaging.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,12 +611,25 @@ function _get_inspection_images()
611611
array_push($args, $this->arg('sid'));
612612
}
613613

614-
$images = $this->db->pq("SELECT i.containerid, si.containerinspectionid, ROUND(TIMESTAMPDIFF('HOUR', min(i2.bltimestamp), i.bltimestamp)/24,1) as delta, si.blsampleimageid, si.blsampleid, si.micronsperpixelx, si.micronsperpixely, si.blsampleimagescoreid, si.comments, TO_CHAR(si.bltimestamp, 'DD-MM-YYYY HH24:MI') as bltimestamp, sc.name as scorename, sc.score, sc.colour as scorecolour, max.maxscore, scorecolours.colour as maxscorecolour
614+
$order = 'i.bltimestamp';
615+
616+
if ($this->has_arg('sort_by')) {
617+
$cols = array(
618+
'BLTIMESTAMP' => 'i.bltimestamp',
619+
'LOCATION' => 'b.location+0'
620+
);
621+
$dir = $this->has_arg('order') ? ($this->arg('order') == 'asc' ? 'ASC' : 'DESC') : 'ASC';
622+
if (array_key_exists($this->arg('sort_by'), $cols))
623+
$order = $cols[$this->arg('sort_by')] . ' ' . $dir;
624+
}
625+
626+
$images = $this->db->pq("SELECT i.containerid, si.containerinspectionid, ROUND(TIMESTAMPDIFF('HOUR', min(i2.bltimestamp), i.bltimestamp)/24,1) as delta, si.blsampleimageid, si.blsampleid, si.micronsperpixelx, si.micronsperpixely, si.blsampleimagescoreid, si.comments, TO_CHAR(si.bltimestamp, 'DD-MM-YYYY HH24:MI') as bltimestamp, sc.name as scorename, sc.score, sc.colour as scorecolour, max.maxscore, scorecolours.colour as maxscorecolour, b.location
615627
FROM blsampleimage si
616628
LEFT OUTER JOIN blsampleimagescore sc ON sc.blsampleimagescoreid = si.blsampleimagescoreid
617629
INNER JOIN containerinspection i ON i.containerinspectionid = si.containerinspectionid
618630
LEFT OUTER JOIN containerinspection i2 ON i.containerid = i2.containerid
619631
632+
INNER JOIN blsample b ON b.blsampleid = si.blsampleid
620633
INNER JOIN container c ON c.containerid = i.containerid
621634
INNER JOIN dewar d ON d.dewarid = c.dewarid
622635
INNER JOIN shipping s ON s.shippingid = d.shippingid
@@ -631,7 +644,7 @@ function _get_inspection_images()
631644
632645
WHERE p.proposalid = :1 $where
633646
GROUP BY i.containerid, si.containerinspectionid, i.bltimestamp, si.blsampleimageid, si.blsampleid, si.micronsperpixelx, si.micronsperpixely, si.blsampleimagescoreid, si.comments, TO_CHAR(si.bltimestamp, 'DD-MM-YYYY HH24:MI'), sc.name, sc.score, sc.colour
634-
ORDER BY i.bltimestamp", $args);
647+
ORDER BY $order", $args);
635648

636649

637650
if ($this->has_arg('imid')) {

client/src/css/partials/_base.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ body {
2121
}
2222
}
2323

24+
body.dialog-open {
25+
overflow: hidden;
26+
position: fixed;
27+
width: 100%;
28+
height: 100%;
29+
}
30+
2431
a {
2532
color: $link-color;
2633

client/src/css/partials/_utility.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
flex: 0 0 auto
7373
}
7474

75+
.wrap {
76+
flex-wrap: wrap;
77+
}
78+
7579
/* TODO: If we can ever get rid of this class, we can also remove the
7680
work-around in plotly support which needs to circumvent it */
7781
.active {
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
define(['views/dialog',
2+
'utils/xhrimage',
3+
'modules/imaging/collections/inspectionimages',
4+
], function(DialogView,
5+
XHRImage,
6+
InspectionImages) {
7+
8+
return DialogView.extend({
9+
template: '<div><ul class="images"></ul></div>',
10+
11+
ui: {
12+
images: '.images',
13+
},
14+
15+
initialize: function(options) {
16+
// disable scrolling on the main page
17+
$('body').addClass('dialog-open')
18+
this.inspectionimages = new InspectionImages()
19+
this.inspectionimages.queryParams.iid = options.CONTAINERINSPECTIONID
20+
this.inspectionimages.queryParams.sort_by = 'LOCATION'
21+
},
22+
23+
inspectionLoaded: function() {
24+
var self = this
25+
const loadDelay = 200 // milliseconds
26+
this.imageTimers = new Map() // Track timers per image
27+
28+
this.observer = new IntersectionObserver(function(entries, observer) {
29+
entries.forEach(entry => {
30+
const img = $(entry.target)
31+
32+
if (entry.isIntersecting) {
33+
// Start a delayed load
34+
const timerId = setTimeout(() => {
35+
let im = new XHRImage()
36+
im.load(img.data('src'), function(loadedImage) {
37+
img.attr('src', loadedImage.src)
38+
})
39+
observer.unobserve(entry.target) // Unobserve after loading
40+
self.imageTimers.delete(entry.target)
41+
}, loadDelay)
42+
43+
// Store timer so we can cancel if needed
44+
self.imageTimers.set(entry.target, timerId)
45+
} else {
46+
// No longer visible: cancel pending load if exists
47+
const timerId = self.imageTimers.get(entry.target)
48+
if (timerId) {
49+
clearTimeout(timerId)
50+
self.imageTimers.delete(entry.target)
51+
}
52+
}
53+
})
54+
})
55+
56+
this.inspectionimages.each(function(inspectionimage) {
57+
let locationEl = $('<li></li>').text(inspectionimage.get('LOCATION'))
58+
59+
let imageEl = $('<img>').css('min-height', '400px')
60+
.data('src', app.apiurl + '/imaging/inspection/image/' + inspectionimage.get('BLSAMPLEIMAGEID') + '?f=1')
61+
62+
locationEl.append(imageEl)
63+
self.ui.images.append(locationEl)
64+
self.observer.observe(imageEl[0])
65+
})
66+
},
67+
68+
onRender: function() {
69+
this.inspectionimages.fetch().done(this.inspectionLoaded.bind(this))
70+
},
71+
72+
closeDialog: function(e) {
73+
DialogView.prototype.closeDialog.apply(this, arguments)
74+
this.destroy()
75+
},
76+
77+
onDestroy: function() {
78+
// re-enable scrolling on the main page
79+
$('body').removeClass('dialog-open')
80+
if (this.observer) {
81+
this.observer.disconnect()
82+
}
83+
84+
// Cancel all pending image timers
85+
if (this.imageTimers) {
86+
for (const timer of this.imageTimers.values()) {
87+
clearTimeout(timer)
88+
}
89+
this.imageTimers.clear()
90+
}
91+
},
92+
})
93+
94+
})

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ define(['marionette',
2121
'modules/imaging/views/imagehistory',
2222

2323
'modules/imaging/views/addinspection',
24+
'modules/imaging/views/inspectionimages',
2425
'modules/imaging/views/actualschedule',
2526
'modules/imaging/views/subtosample',
2627

@@ -64,7 +65,7 @@ define(['marionette',
6465
SingleSample,
6566

6667
ContainerInspections, InspectionImage, InspectionImages, ImageViewer, ImageHistoryView,
67-
AddInspectionView, ActualScheduleView, SubToSampleView,
68+
AddInspectionView, InspectionImagesView, ActualScheduleView, SubToSampleView,
6869

6970
ScreenComponentGroups,
7071
ScreenComponents,
@@ -286,6 +287,7 @@ define(['marionette',
286287
'click a.add_inspection': 'showAddInspection',
287288
'click a.view_sched': 'showViewSchedule',
288289
'click @ui.play': 'playInspection',
290+
'click a.inspection_images': 'showInspectionImages',
289291

290292
'dragover @ui.drop': 'dragHover',
291293
'dragleave @ui.drop': 'dragHover',
@@ -462,6 +464,20 @@ define(['marionette',
462464
} else this.ui.ins.val(m.get('CONTAINERINSPECTIONID')).trigger('change')
463465
},
464466

467+
showInspectionImages: function(e) {
468+
e.preventDefault()
469+
this.inspectionImagesView = new InspectionImagesView({ dialog: true, CONTAINERINSPECTIONID: this.ui.ins.val() })
470+
app.dialog.show(new DialogView({
471+
title: 'Inspection Images',
472+
view: this.inspectionImagesView,
473+
autoSize: true,
474+
destroyOnClose: true,
475+
dOptions: {
476+
height: $(window).height() * 0.8,
477+
},
478+
}))
479+
},
480+
465481

466482
showViewSchedule: function(e) {
467483
e.preventDefault()

client/src/js/templates/imaging/inspectionadd.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ <h1>Add New Container Inspection</h1>
99

1010

1111
<li>
12-
<label>Inpsection Type
12+
<label>Inspection Type
1313
<span class="small">Type of container inspection</span>
1414
</label>
1515
<select name="INSPECTIONTYPEID"></select>

client/src/js/templates/shipment/containerplateimage.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ <h1 class="no_mobile">Container: <span class="NAME"><%-NAME%></span></h1>
5858
<ul>
5959
<li class="nowrap">
6060
<span class="label">Inspections</span>
61-
<select name="inspection"></select>
62-
<a href="#" class="button button-notext add_inspection tw-h-6"><i class="fa fa-plus"></i> <span>Add</span></a>
61+
<div class="flex wrap">
62+
<select name="inspection"></select>&nbsp;
63+
<a href="#" class="button inspection_images tw-h-6"><i class="fa fa-list-ul"></i> <span>See All Images</span></a>&nbsp;
64+
<a href="#" class="button add_inspection tw-h-6"><i class="fa fa-plus"></i> <span>Add Inspection</span></a>
65+
</div>
6366
</li>
6467
<li>
6568
<span class="label">Movie</span>

client/src/js/utils/xhrimage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ define(['marionette'], function() {
4848
var blob = new Blob([this.response], { type: mimeType })
4949
self.src = window.URL.createObjectURL(blob)
5050
app.imagecache[url] = self.src
51-
if (callback) callback(this)
51+
if (callback) callback(self)
5252
}
5353

5454
xhr.onprogress = function(e) {

client/src/js/views/dialog.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@ define(['marionette'], function(Marionette) {
1111
dOptions: {
1212
},
1313

14+
destroyOnClose: false,
15+
1416
dialogOptions: function() {
17+
var self = this
1518
return _.extend({}, {
1619
title: this.getOption('title'),
1720
width: 'auto',
1821
height: 'auto',
1922
resizable: false,
20-
buttons: this.generateButtons(this.getOption('buttons'))
23+
buttons: this.generateButtons(this.getOption('buttons')),
24+
close: function() {
25+
if (self.getOption('destroyOnClose')) self.destroy();
26+
},
2127
}, this.getOption('dOptions'))
2228
},
2329

@@ -84,4 +90,4 @@ define(['marionette'], function(Marionette) {
8490

8591
});
8692

87-
})
93+
})

0 commit comments

Comments
 (0)