diff --git a/api/config_sample.php b/api/config_sample.php index c84bb5f1e..97d9fc85d 100644 --- a/api/config_sample.php +++ b/api/config_sample.php @@ -395,6 +395,12 @@ 'i04' => False, ); + # puck capacity of beamlines which take pucks, sample capacity of those which take samples + $bl_capacity = array( + "i03" => array("pucks" => 37, "samples" => 0), + "i04" => array("pucks" => 37, "samples" => 0), + ); + # Dials server values $dials_rest_url = ""; $dials_rest_jwt = ""; diff --git a/api/index.php b/api/index.php index 3ee429c4e..60d180f74 100644 --- a/api/index.php +++ b/api/index.php @@ -73,7 +73,8 @@ function setupApplication($mode): Slim $valid_components, $enabled_container_types, $synchweb_version, $redirects, $shipping_service_app_url, $use_shipping_service_redirect, $use_shipping_service_redirect_incoming_shipments, $dials_rest_url_rings, $closed_proposal_link, $ccp4_cloud_upload_url, - $only_staff_can_assign, $industrial_prop_codes, $prop_codes_data_deleted, $container_types_with_parents; + $only_staff_can_assign, $industrial_prop_codes, $prop_codes_data_deleted, $container_types_with_parents, + $bl_capacity; $app->contentType('application/json'); $options = $app->container['options']; $app->response()->body(json_encode(array( @@ -106,6 +107,7 @@ function setupApplication($mode): Slim 'container_types_with_parents' => $container_types_with_parents, 'industrial_prop_codes' => $industrial_prop_codes, 'prop_codes_data_deleted' => $prop_codes_data_deleted ?? array(), + 'bl_capacity' => $bl_capacity, ))); }); return $app; diff --git a/api/src/Controllers/AssignController.php b/api/src/Controllers/AssignController.php index 4cc3f4f31..d5f959e81 100644 --- a/api/src/Controllers/AssignController.php +++ b/api/src/Controllers/AssignController.php @@ -11,7 +11,7 @@ class AssignController extends Page { private $assignData; - public static $arg_list = array('visit' => '\w+\d+-\d+', 'cid' => '\d+', 'did' => '\d+', 'pos' => '\d+', 'bl' => '[\w\-]+'); + public static $arg_list = array('visit' => '\w+\d+-\d+', 'cid' => '\d+', 'did' => '\d+', 'sid' => '\d+', 'pos' => '\d+', 'bl' => '[\w\-]+'); public static $dispatch = array( array('/assign', 'get', 'assignContainer'), @@ -32,15 +32,24 @@ function __construct(Slim $app, $db, $user, AssignData $assignData) function assignContainer() { global $only_staff_can_assign; - $cs = $this->assignData->getContainer($this->arg('visit'), $this->arg('cid')); + if ($this->has_arg('cid')) { + $cs = $this->assignData->getContainer($this->arg('visit'), $this->arg('cid')); + } else if ($this->has_arg('sid')) { + $cs = $this->assignData->getSample($this->arg('visit'), $this->arg('sid')); + } else { + $cs = array(); + } if (sizeof($cs) > 0) { $bl = $cs[0]['BEAMLINENAME']; if (is_array($only_staff_can_assign) && array_key_exists($bl, $only_staff_can_assign) && $only_staff_can_assign[$bl] == true && !$this->staff) { $this->_error("Only staff can assign containers on this beamline"); - } else { + } else if ($this->has_arg('cid')) { $this->assignData->assignContainer($cs[0], $this->arg('pos')); $this->_output(1); + } else if ($this->has_arg('sid')) { + $this->assignData->assignSample($cs[0], $this->arg('pos')); + $this->_output(1); } } else @@ -52,16 +61,25 @@ function assignContainer() function unassignContainer() { global $only_staff_can_assign; - $cs = $this->assignData->getContainer($this->arg('visit'), $this->arg('cid')); + if ($this->has_arg('cid')) { + $cs = $this->assignData->getContainer($this->arg('visit'), $this->arg('cid')); + } else if ($this->has_arg('sid')) { + $cs = $this->assignData->getSample($this->arg('visit'), $this->arg('sid')); + } else { + $cs = array(); + } if (sizeof($cs) > 0) { $bl = $cs[0]['BEAMLINENAME']; if (is_array($only_staff_can_assign) && array_key_exists($bl, $only_staff_can_assign) && $only_staff_can_assign[$bl] == true && !$this->staff) { $this->_error("Only staff can unassign containers on this beamline"); - } else { + } else if ($this->has_arg('cid')) { $this->assignData->unassignContainer($cs[0]); $this->_output(1); + } else if ($this->has_arg('sid')) { + $this->assignData->unassignSample($cs[0]); + $this->_output(1); } } else diff --git a/api/src/Downstream/Type/Dimple.php b/api/src/Downstream/Type/Dimple.php index 932487436..b23330703 100644 --- a/api/src/Downstream/Type/Dimple.php +++ b/api/src/Downstream/Type/Dimple.php @@ -120,6 +120,8 @@ function results() { $dat['PKLIST'] = $pklist; } + $dat['ANODE_PEAKS'] = $this->_get_anode_peaks($this->process['PARAMETERS']['scaling_id']); + $results = new DownstreamResult($this); $results->data = $dat; @@ -165,4 +167,36 @@ function mapmodel($n = 0, $map = false) { return $pdb['FILE']; } } + + function _get_anode_peaks($scaling_id) { + + $peaks = array(); + $plot = array(); + + $blobs = $this->db->pq( + "SELECT mb.x, mb.y, mb.z, mb.height, mb.occupancy, + mb.nearestatomdistance, mb.nearestatomname, mb.nearestatomchainid, + mb.nearestatomresname, mb.nearestatomresseq + FROM mxmrrunblob mb + INNER JOIN mxmrrun m ON mb.mxmrrunid = m.mxmrrunid + WHERE mb.maptype='anomalous' and m.autoprocscalingid=:1 + ORDER BY mb.height DESC + LIMIT 10", + array($scaling_id) + ); + + foreach ($blobs as $n => $blob) { + array_push($peaks, array( + number_format($blob['X'], 2), + number_format($blob['Y'], 2), + number_format($blob['Z'], 2), + number_format($blob['HEIGHT'], 2), + number_format($blob['OCCUPANCY'], 1), + $blob['NEARESTATOMDISTANCE'] . ' ' . $blob['NEARESTATOMNAME'] . '_' . $blob['NEARESTATOMCHAINID'] + . ':' . $blob['NEARESTATOMRESNAME'] . $blob['NEARESTATOMRESSEQ'], + )); + array_push($plot, array($n+1, $blob['HEIGHT'])); + } + return array('TABLE' => $peaks, 'PLOT' => $plot); + } } diff --git a/api/src/Model/Services/AssignData.php b/api/src/Model/Services/AssignData.php index ed3e4bbaf..75c414903 100644 --- a/api/src/Model/Services/AssignData.php +++ b/api/src/Model/Services/AssignData.php @@ -27,6 +27,18 @@ function getContainer($visitId, $containerId) AND c.containerid=:2", array($visitId, $containerId)); } + function getSample($visitId, $sampleId) + { + return $this->db->pq("SELECT b.blsampleid,b.name,d.dewarid,bl.beamlinename,c.containerid,c.code FROM blsample b + INNER JOIN container c ON c.containerid = b.containerid + INNER JOIN dewar d ON d.dewarid = c.dewarid + INNER JOIN shipping s ON s.shippingid = d.shippingid + INNER JOIN blsession bl ON bl.proposalid = s.proposalid + INNER JOIN proposal p ON s.proposalid = p.proposalid + WHERE CONCAT(p.proposalcode, p.proposalnumber, '-', bl.visit_number) LIKE :1 + AND b.blsampleid=:2", array($visitId, $sampleId)); + } + function assignContainer($container, $location) { $this->updateDewar($container['DEWARID'], 'processing'); @@ -36,11 +48,27 @@ function assignContainer($container, $location) $this->updateDewarHistory($container['DEWARID'], 'processing', $container['BEAMLINENAME'], $container['CODE'] . ' => ' . $location); } + function assignSample($sample, $location) + { + $this->updateSample($sample['BLSAMPLEID'], $location); + + $this->updateDewar($sample['DEWARID'], 'processing'); + + $this->updateContainerAndHistory($sample['CONTAINERID'], 'processing', $sample['BEAMLINENAME'], null); + + $this->updateDewarHistory($sample['DEWARID'], 'processing', $sample['BEAMLINENAME'], $sample['NAME'] . ' => ' . $location); + } + function unassignContainer($container) { $this->updateContainerAndHistory($container['CONTAINERID'], 'at facility', '', ''); } + function unassignSample($sample) + { + $this->updateSample($sample['BLSAMPLEID'], null); + } + function updateContainerAndHistory($containerId, $status, $beamlineName, $location) { $this->updateContainer($containerId, $status, $beamlineName, $location); @@ -61,6 +89,12 @@ function updateContainer($containerId, $status, $beamlineName, $location) WHERE containerid=:4", array($beamlineName, $location, $status, $containerId)); } + function updateSample($sampleId, $location) + { + $this->db->pq("UPDATE blsample SET isinsamplechanger=:1 + WHERE blsampleid=:2", array($location, $sampleId)); + } + function getDewar($dewarId, $proposalId, $visitId) { $where = "p.proposalid=:1"; diff --git a/api/src/Page/Sample.php b/api/src/Page/Sample.php index ac87180d9..24b57298d 100644 --- a/api/src/Page/Sample.php +++ b/api/src/Page/Sample.php @@ -120,6 +120,8 @@ class Sample extends Page 'BEAMLINENAME' => '[\w\-]+', 'SOURCE' => '[\w\-]+', + 'assigned' => '[\w\-]+', + 'unassigned' => '[\w\-]+', 'queued' => '\d', 'UNQUEUE' => '\d', 'nodata' => '\d', @@ -1145,6 +1147,16 @@ function _samples() array_push($args, $sessionid); } + if ($this->has_arg('assigned')) { + $where .= " AND d.dewarstatus LIKE 'processing' AND b.isinsamplechanger > 0 AND c.beamlinelocation LIKE :" . (sizeof($args) + 1); + array_push($args, $this->arg('assigned')); + } + + if ($this->has_arg('unassigned')) { + $where .= " AND b.isinsamplechanger is null AND c.beamlinelocation=:" . (sizeof($args) + 1); + array_push($args, $this->arg('unassigned')); + } + // Search if ($this->has_arg('s')) { $st = sizeof($args) + 1; @@ -1219,7 +1231,7 @@ function _samples() , TO_CHAR(cq.createdtimestamp, 'DD-MM-YYYY HH24:MI') as queuedtimestamp, b.smiles , $cseq $sseq string_agg(cpr.name) as componentnames, string_agg(cpr.density) as componentdensities , string_agg(cpr.proteinid) as componentids, string_agg(cpr.acronym) as componentacronyms, string_agg(cpr.global) as componentglobals, string_agg(chc.abundance) as componentamounts, string_agg(ct.symbol) as componenttypesymbols, b.volume, pct.symbol,ROUND(cr.abundance,3) as abundance, TO_CHAR(b.recordtimestamp, 'DD-MM-YYYY') as recordtimestamp, dp.radiationsensitivity, dp.energy, dp.userpath, dp.strategyoption, dp.minimalresolution as minimumresolution - , count(distinct dc.dataCollectionId) as dcc + , count(distinct dc.dataCollectionId) as dcc, b.isinsamplechanger FROM blsample b diff --git a/client/src/css/partials/_content.scss b/client/src/css/partials/_content.scss index b1d6b8bd6..8eef90377 100644 --- a/client/src/css/partials/_content.scss +++ b/client/src/css/partials/_content.scss @@ -790,6 +790,10 @@ li:last-child .visit_users { display: none; overflow: auto; + .larger { + font-size: 14px; + } + .dcap { padding: 1% 1% 0 1%; @@ -895,6 +899,10 @@ li:last-child .visit_users { } } + &.align_center td { + text-align: center; + } + } @@ -997,7 +1005,7 @@ li:last-child .visit_users { height: auto; } - .plot_dimple { + .plot_dimple, .plot_anode { width: 70%; float: right; diff --git a/client/src/js/config_sample.json b/client/src/js/config_sample.json index cc71a60f8..2518bf926 100644 --- a/client/src/js/config_sample.json +++ b/client/src/js/config_sample.json @@ -6,12 +6,7 @@ "production": false, "pucks": { - "i02": 10, - "i03": 23, - "i04": 37, - "i04-1": 9, - "i24": 9, - "i23": 4 + "moved to": "config.php" }, "_gsMajorAxisOrientation" : "Determines whether the major grid scan axis determines the orientation of the view", diff --git a/client/src/js/modules/assign/views/assign.js b/client/src/js/modules/assign/views/assign.js index 97cc77e8e..c613fd0c2 100644 --- a/client/src/js/modules/assign/views/assign.js +++ b/client/src/js/modules/assign/views/assign.js @@ -2,8 +2,10 @@ define(['marionette', 'backbone', 'views/pages', 'collections/shipments', 'collections/containers', 'collections/dewars', + 'collections/samples', 'models/shipment', 'models/dewar', + 'models/container', 'modules/assign/collections/pucknames', 'utils', @@ -15,8 +17,10 @@ define(['marionette', 'backbone', 'views/pages', Shipments, Containers, Dewars, + Samples, Shipment, Dewar, + Container, PuckNames, utils, @@ -46,15 +50,13 @@ define(['marionette', 'backbone', 'views/pages', 'drop:unassign': 'unassignContainer', }, - // possible circular reference - onDestroy: function() { - this.model.view = null - }, - - // Assign Containers assignContainer: function(e, options) { console.log('confirm container on to', options.id, this.model) + if (options.id == this.model.get("SAMPLECHANGERLOCATION")) { + // already assigned in this location + return + } staffOnly = false const onlyStaffCanAssign = app.options.get('only_staff_can_assign') || {} if (options.bl in onlyStaffCanAssign) { @@ -63,6 +65,7 @@ define(['marionette', 'backbone', 'views/pages', if (staffOnly && !app.staff) { app.alert({ message: 'Only staff are able to assign containers on '+options.bl }) } else { + options.shipments = this.getOption('shipments') utils.confirm({ title: 'Confirm Container Assignment', content: 'Are you sure you want to assign "'+this.model.get('NAME')+'" to sample changer position '+options.id+'?', @@ -153,9 +156,131 @@ define(['marionette', 'backbone', 'views/pages', }, }) - - - + + + var SampleView = Marionette.CompositeView.extend({ + template: _.template(' View Sample

<%-NAME%>

'), + className: function() { return 'container' + (this.getOption('assigned') ? ' assigned' : '') }, + + initialize: function(options) { + this.getOption('model').view = this + }, + + onRender: function() { + this.$el.draggable({ + containment: '#drag_container', + stack: '#unassigned div', + revert: true + }) + }, + + events: { + 'drop:assign': 'assignSample', + 'drop:unassign': 'unassignSample', + }, + + // Assign Samples + assignSample: function(e, options) { + console.log('confirm sample on to', options.id, this.model) + if (options.id == this.model.get("ISINSAMPLECHANGER")) { + // already assigned in this location + return + } + staffOnly = false + const onlyStaffCanAssign = app.options.get('only_staff_can_assign') || {} + if (options.bl in onlyStaffCanAssign) { + staffOnly = onlyStaffCanAssign[options.bl] + } + if (staffOnly && !app.staff) { + app.alert({ message: 'Only staff are able to assign samples on '+options.bl }) + } else { + options.shipments = this.getOption('shipments') + utils.confirm({ + title: 'Confirm Sample Assignment', + content: 'Are you sure you want to assign "'+this.model.get('NAME')+'" to sample changer position '+options.id+'?', + callback: this.doAssign.bind(this, options) + }) + } + }, + + doAssign: function(options) { + console.log('dropped sample on to', options.id, this.model, options.assigned) + var assigned = options.assigned.where({ ISINSAMPLECHANGER: options.id.toString() }) + _.each(assigned, function(c) { + c.view.doUnAssign.call(c.view,options) + }) + + Backbone.ajax({ + url: app.apiurl+'/assign/assign', + data: { visit: options.visit, sid: this.model.get('BLSAMPLEID'), pos: options.id }, + success: this.assignUpdateGUI.bind(this, options), + error: function(xhr, message, options) { + try { + json = JSON.parse(xhr.responseText) + app.alert({ message: json.message }) + } catch { + app.alert({ message: 'Something went wrong assigning this sample.' }) + } + }, + }) + }, + + assignUpdateGUI: function(options) { + this.trigger('remove:container', this.model) + this.model.set({ ISINSAMPLECHANGER: options.id.toString() }) + options.assigned.add(this.model) + }, + + // Unassign Samples + unassignSample: function(e, options) { + console.log('unassign sample', this.model) + staffOnly = false + const onlyStaffCanAssign = app.options.get('only_staff_can_assign') || {} + if (options.bl in onlyStaffCanAssign) { + staffOnly = onlyStaffCanAssign[options.bl] + } + if (staffOnly && !app.staff) { + app.alert({ message: 'Only staff are able to unassign samples on '+options.bl }) + } else { + utils.confirm({ + title: 'Confirm Sample Unassignment', + content: 'Are you sure you want to unassign "'+this.model.get('NAME')+'" from sample changer position '+this.model.get('ISINSAMPLECHANGER')+'?', + callback: this.doUnAssign.bind(this, options) + }) + } + }, + + doUnAssign: function(options) { + console.log('unassigning', this.model) + Backbone.ajax({ + url: app.apiurl+'/assign/unassign', + data: { visit: options.visit, sid: this.model.get('BLSAMPLEID') }, + success: this.unassignUpdateGUI.bind(this, options), + error: function(xhr, message, options) { + try { + json = JSON.parse(xhr.responseText) + app.alert({ message: json.message }) + } catch { + app.alert({ message: 'Something went wrong unassigning this sample.' }) + } + }, + }) + }, + + unassignUpdateGUI: function(options) { + this.model.set({ ISINSAMPLECHANGER: null }) + this.trigger('remove:container', this.model) + var shipments = _.uniq(options.shipments.pluck('SHIPPINGID')) + if (shipments.indexOf(this.model.get('SHIPPINGID')) > -1) { + var s = options.shipments.findWhere({ SHIPPINGID: this.model.get('SHIPPINGID') }) + var d = s.get('DEWARS').findWhere({ CONTAINERID: this.model.get('CONTAINERID') }) + if (d) d.get('CONTAINERS').add(this.model) + console.log('add sample to dewar') + } + }, + }) + + // List of Dewars in Shipment var DewarView = Marionette.CompositeView.extend({ template: _.template('

<%-CODE%> Deactivate Dewar

'), @@ -165,8 +290,17 @@ define(['marionette', 'backbone', 'views/pages', return classes }, - - childView: ContainerView, + + getChildView: function(model) { + return this.options.pucks > 0 ? ContainerView : SampleView; + }, + + childViewOptions: function() { + return { + shipments: this.options.shipments, + } + }, + childEvents: { 'remove:container': 'removeContainer', }, @@ -213,6 +347,12 @@ define(['marionette', 'backbone', 'views/pages', var ShipmentView = Marionette.CompositeView.extend({ template: _.template('

<%-SHIPPINGNAME%>

'), childView: DewarView, + childViewOptions: function() { + return { + pucks: this.getOption('pucks'), + shipments: this.getOption('shipments'), + } + }, className: 'shipment', initialize: function(options) { @@ -228,8 +368,11 @@ define(['marionette', 'backbone', 'views/pages', template: _.template('<%-id%>
'), childView: ContainerView, - childViewOptions: { - assigned: true, + childViewOptions: function() { + return { + assigned: true, + shipments: this.getOption('shipments') + } }, childViewContainer: '.ac', @@ -296,6 +439,67 @@ define(['marionette', 'backbone', 'views/pages', } }) + + // Sample Changer Positions + var PositionSampleView = Marionette.CompositeView.extend({ + className:'bl_puck', + template: _.template('<%-id%>
'), + + childView: SampleView, + childViewOptions: function() { + return { + assigned: true, + shipments: this.getOption('shipments') + } + }, + childViewContainer: '.ac', + + childEvents: { + 'remove:container': 'removeContainer', + }, + + ui: { + name: '.name', + }, + + removeContainer: function(child, model) { + console.log('remove sample position', model) + this.collection.remove(model) + this.render() + }, + + collectionEvents: { + 'change reset': 'render', + }, + + events: { + 'drop': 'handleDrop', + }, + + initialize: function(options) { + this.collection = new Containers() + this.assigned = options.assigned + this.bl = options.bl + this.listenTo(this.assigned, 'change sync reset add remove', this.updateCollection, this) + this.updateCollection() + }, + + updateCollection: function() { + this.collection.reset(this.assigned.findWhere({ ISINSAMPLECHANGER: this.model.get('id').toString() })) + }, + + onRender: function() { + this.$el.attr('id', 'blpos'+this.model.get('id')) + this.$el.droppable({ + accept: '.container', + hoverClass: 'bl_puck_drag', + }) + }, + + handleDrop: function(e, ui) { + ui.draggable.trigger('drop:assign', { id: this.model.get('id'), assigned: this.assigned, visit: this.getOption('visit'), bl: this.bl }) + } + }) var SampleChangerView = Marionette.CollectionView.extend({ @@ -306,11 +510,24 @@ define(['marionette', 'backbone', 'views/pages', assigned: this.getOption('assigned'), visit: this.getOption('visit'), bl: this.getOption('bl'), - pucknames: this.getOption('pucknames') + pucknames: this.getOption('pucknames'), + shipments: this.getOption('shipments'), } } }) + var SampleChangerSampleView = Marionette.CollectionView.extend({ + className: 'clearfix', + childView: PositionSampleView, + childViewOptions: function() { + return { + assigned: this.getOption('assigned'), + visit: this.getOption('visit'), + bl: this.getOption('bl'), + shipments: this.getOption('shipments'), + } + } + }) return Marionette.CompositeView.extend({ @@ -318,7 +535,17 @@ define(['marionette', 'backbone', 'views/pages', className: 'content', childView: ShipmentView, childViewContainer: '#unassigned', + childViewOptions: function() { + return { + pucks: this.pucks, + shipments: this.collection, + } + }, + ui: { + pcs: '.pcs', + }, + events: { 'drop #unassigned': 'handleDrop', }, @@ -330,7 +557,6 @@ define(['marionette', 'backbone', 'views/pages', templateHelpers: function() { return { VISIT: this.getOption('visit').toJSON(), - APP_TYPE: app.type, } }, @@ -340,51 +566,79 @@ define(['marionette', 'backbone', 'views/pages', }, initialize: function(options) { + this.pucks = 10 + this.samples = 0 + const bl_capacity = app.options.get('bl_capacity') || {} + if (this.getOption('visit').get('BL') in bl_capacity) { + this.pucks = bl_capacity[this.getOption('visit').get('BL')]['pucks'] + this.samples = bl_capacity[this.getOption('visit').get('BL')]['samples'] + } + this.collection = new Shipments() - - this.assigned = new Containers(null, { queryParams: { assigned: 1, bl: this.getOption('visit').get('BL') }, state: { pageSize: 9999 } }) + + if (this.pucks > 0) { + this.assigned = new Containers(null, { queryParams: { assigned: 1, bl: this.getOption('visit').get('BL') }, state: { pageSize: 9999 } }) + this.containers = new Containers(null, { queryParams: { unassigned: this.getOption('visit').get('BL') }, state: { pageSize: 30, currentPage: options.page } }) + } else { + this.assigned = new Samples(null, { queryParams: { assigned: this.getOption('visit').get('BL') }, state: { pageSize: 9999 } }) + this.containers = new Samples(null, { queryParams: { unassigned: this.getOption('visit').get('BL') }, state: { pageSize: 30, currentPage: options.page } }) + } this.assigned.fetch() - - this.containers = new Containers(null, { queryParams: { unassigned: this.getOption('visit').get('BL') }, state: { pageSize: 30, currentPage: options.page } }) - var self = this - this.containers.fetch().done(function() { - console.log(self.containers) - }) + this.containers.fetch() + this.listenTo(this.containers, 'sync', this.generateShipments, this) this.paginator = new Pages({ collection: this.containers }) - this.pucknames = new PuckNames() - this.pucknames.state.pageSize = 100 - this.pucknames.queryParams.bl = this.getOption('visit').get('BL') - this.pucknames.fetch() + if (this.pucks > 0) { + this.pucknames = new PuckNames() + this.pucknames.state.pageSize = 100 + this.pucknames.queryParams.bl = this.getOption('visit').get('BL') + this.pucknames.fetch() + } this.bl = this.getOption('visit').get('BL') }, - + generateShipments: function() { console.log('generate shipments') - var sids = _.uniq(this.containers.pluck('SHIPPINGID')) - var shipments = [] + let sids = _.uniq(this.containers.pluck('SHIPPINGID')) + let shipments = [] _.each(sids, function(sid) { - var conts = new Containers(this.containers.where({ SHIPPINGID: sid })) - - var dids = _.uniq(conts.pluck('DEWARID')) - var dewars = new Dewars() - _.each(dids, function(did) { - var d = conts.findWhere({ DEWARID: did }) - var dewar = new Dewar({ - DEWARID: did, - CODE: d.get('DEWAR'), - DEWARSTATUS: d.get('DEWARSTATUS'), - CONTAINERS: new Containers(conts.where({ DEWARID: did })) - }) - dewars.add(dewar) - }, this) + let conts, items; + + if (this.pucks > 0) { + conts = new Containers(this.containers.where({ SHIPPINGID: sid })) + let dids = _.uniq(conts.pluck('DEWARID')) + items = new Dewars() + _.each(dids, function(did) { + let d = conts.findWhere({ DEWARID: did }) + let dewar = new Dewar({ + DEWARID: did, + CODE: d.get('DEWAR'), + DEWARSTATUS: d.get('DEWARSTATUS'), + CONTAINERS: new Containers(conts.where({ DEWARID: did })) + }) + items.add(dewar) + }, this) + } else { + conts = new Samples(this.containers.where({ SHIPPINGID: sid })) + let cids = _.uniq(conts.pluck('CONTAINERID')) + items = new Containers() + _.each(cids, function(cid) { + let c = conts.findWhere({ CONTAINERID: cid }) + let container = new Container({ + CONTAINERID: cid, + CODE: c.get('CONTAINER'), + CONTAINERS: new Samples(conts.where({ CONTAINERID: cid })) + }) + items.add(container) + }, this) + } - var shipment = new Shipment({ + let shipment = new Shipment({ SHIPPINGID: sid, SHIPPINGNAME: conts.at(0).get('SHIPMENT'), - DEWARS: dewars, + DEWARS: items, }) shipments.push(shipment) }, this) @@ -393,9 +647,10 @@ define(['marionette', 'backbone', 'views/pages', // This means that there is no ability to unassign containers. Fix: add a dummy shipment here. // Dragging a container to a shipment does not associate the container with that shipment - it will still be in the original shipment. if (shipments.length == 0) { - var unassignShipment = new Shipment({ + let unassignText = this.pucks > 0 ? 'Drag a container here to unassign' : 'Drag a sample here to unassign' + let unassignShipment = new Shipment({ SHIPPINGID: 0, - SHIPPINGNAME: 'Drag Container here to unassign', + SHIPPINGNAME: unassignText, }) shipments.push(unassignShipment) } @@ -404,32 +659,48 @@ define(['marionette', 'backbone', 'views/pages', onShow: function() { - var pucks = 10 - if (this.getOption('visit').get('BL') in app.config.pucks) { - pucks = app.config.pucks[this.getOption('visit').get('BL')] + var positions + if (this.pucks > 0) { + positions = new Backbone.Collection(_.map(_.range(1,this.pucks+1), function(i) { return { id: i } })) + this.scview = new SampleChangerView({ + collection: positions, + assigned: this.assigned, + visit: this.getOption('visit').get('VISIT'), + bl: this.bl, + shipments: this.collection, + pucknames: this.pucknames, + }) + } else { + positions = new Backbone.Collection(_.map(_.range(1,this.samples+1), function(i) { return { id: i } })) + this.scview = new SampleChangerSampleView({ + collection: positions, + assigned: this.assigned, + visit: this.getOption('visit').get('VISIT'), + bl: this.bl, + shipments: this.collection, + }) } - var positions = new Backbone.Collection(_.map(_.range(1,pucks+1), function(i) { return { id: i } })) - this.scview = new SampleChangerView({ - collection: positions, - assigned: this.assigned, - visit: this.getOption('visit').get('VISIT'), - bl: this.bl, - shipments: this.collection, - pucknames: this.pucknames, - }) this.$el.find('#assigned').append(this.scview.render().$el) this.$el.find('.page_wrap').append(this.paginator.render().$el) - + this.$el.find('#unassigned').droppable({ accept: '.bl_puck .ac div', hoverClass: 'unassigned_drag', }) + + if (app.type == 'xpdf') { + this.ui.pcs.text('Puck') + } else if (this.pucks > 0) { + this.ui.pcs.text('Container') + } else { + this.ui.pcs.text('Sample') + } }, onDestroy: function() { if (this.scview) this.scview.destroy() - this.pucknames.stop() + if (this.pucknames) this.pucknames.stop() // hmm no destroy? //if (this.paginator) this.paginator.destroy() }, diff --git a/client/src/js/modules/dc/datacollections.js b/client/src/js/modules/dc/datacollections.js index 52b9e1b60..b062b08f9 100644 --- a/client/src/js/modules/dc/datacollections.js +++ b/client/src/js/modules/dc/datacollections.js @@ -114,11 +114,18 @@ function(Marionette, Pages, DCListView, IS_DCG: !(!this.getOption('params').dcg), IS_PJ: !(!this.getOption('params').pjid), IS_STAFF: app.staff, + CONTAINERS: this.containers, IS_ARCHIVED: app.options.get('prop_codes_data_deleted').some(code => app.prop.includes(code)) ? "deleted" : "archived", } }, initialize: function(options) { + this.containers = 'Containers' + const bl_capacity = app.options.get('bl_capacity') || {} + if (this.model && this.model.get('BL') in bl_capacity && bl_capacity[this.model.get('BL')]['pucks'] === 0) { + this.containers = 'Samples' + } + if (this.model && this.model.get('ACTIVE') != "1") { var vis = this.getOption('params').visit if (vis) { diff --git a/client/src/js/modules/dc/views/dimple.js b/client/src/js/modules/dc/views/dimple.js index 02aadb01a..0c156229a 100644 --- a/client/src/js/modules/dc/views/dimple.js +++ b/client/src/js/modules/dc/views/dimple.js @@ -8,7 +8,9 @@ define([ ui: { plot: '.plot_dimple', + plot_anode: '.plot_anode', rstats: '.rstats', + rstats_div: '.rstats_div', blob: '.blobs img', blobs: '.blobs', }, @@ -39,9 +41,10 @@ define([ if (app.mobile()) { this.ui.plot.width(0.93*(this.options.holderWidth-14)) } else { - this.ui.rstats.width(0.20*(this.options.holderWidth-14)) - this.ui.plot.width(0.47*(this.options.holderWidth-14)) + this.ui.rstats.width(0.25*(this.options.holderWidth-14)) + this.ui.plot.width(0.42*(this.options.holderWidth-14)) this.ui.plot.height(this.ui.plot.width()*0.41-80) + this.ui.rstats_div.height(this.ui.plot.width()*0.41-80) } this.ui.blobs.css('min-height', this.ui.plot.width()*0.41-80) @@ -51,8 +54,18 @@ define([ var pl = $.extend({}, utils.default_plot, { series: { lines: { show: true }}}) $.plot(this.ui.plot, data, pl) + const anodePeaks = this.model.get('ANODE_PEAKS'); + if (anodePeaks && anodePeaks.TABLE && anodePeaks.TABLE.length > 0) { + this.ui.plot_anode.width(0.42 * (this.options.holderWidth - 14)) + this.ui.plot_anode.height(this.ui.plot.width() * 0.41 - 80) + + var anode_data = [{ data: anodePeaks.PLOT, label: 'Peak Height (sig)' }] + var anode_pl = $.extend({}, utils.default_plot, { series: { lines: { show: true }}}); + $.plot(this.ui.plot_anode, anode_data, anode_pl) + } + }, - + }) -}) \ No newline at end of file +}) diff --git a/client/src/js/modules/dc/views/samplechanger.js b/client/src/js/modules/dc/views/samplechanger.js index 2ab1e9fd3..a7072022d 100644 --- a/client/src/js/modules/dc/views/samplechanger.js +++ b/client/src/js/modules/dc/views/samplechanger.js @@ -59,8 +59,9 @@ define(['marionette', 'utils/canvas', 'utils', this.listenTo(this.collection, 'change', this.drawStatus, this) this.ready = this.collection.fetch() - if (options.bl in app.config.pucks) { - this.positions = app.config.pucks[options.bl] + const bl_capacity = app.options.get('bl_capacity') || {} + if (options.bl in bl_capacity) { + this.positions = bl_capacity[options.bl]['pucks'] } else this.positions = 10 this.sc = 16 diff --git a/client/src/js/modules/dc/views/samplechangerfull.js b/client/src/js/modules/dc/views/samplechangerfull.js index 60a5b0907..ec156a7bc 100644 --- a/client/src/js/modules/dc/views/samplechangerfull.js +++ b/client/src/js/modules/dc/views/samplechangerfull.js @@ -21,8 +21,9 @@ define(['marionette', }, onRender: function() { - var bl = this.getOption('bl') - var large = bl in app.config.pucks && app.config.pucks[bl] > 10 + const bl = this.getOption('bl') + const bl_capacity = app.options.get('bl_capacity') || {} + const large = bl in bl_capacity && bl_capacity[bl]['pucks'] > 10 console.log('sc large', large) if (!app.mobile() && !large) { this.$el.find('.left').css('width', '25%') @@ -46,4 +47,4 @@ define(['marionette', -}) \ No newline at end of file +}) diff --git a/client/src/js/modules/shipment/models/platetype.js b/client/src/js/modules/shipment/models/platetype.js index 06396dec5..1f79bbe5e 100644 --- a/client/src/js/modules/shipment/models/platetype.js +++ b/client/src/js/modules/shipment/models/platetype.js @@ -47,8 +47,8 @@ define(['backbone'], function(Backbone) { this.set('drop_widthpx', (this.get('well_width')-this.get('drop_pad')*2) / (this.get('drop_per_well_x') / this.get('drop_width'))) this.set('drop_heightpx', (this.get('well_height')-this.get('drop_pad')*2) / (this.get('drop_per_well_y') / this.get('drop_height'))) - this.set('drop_offset_x', this.get('drop_offset_x')*(this.get('well_width')-this.get('drop_pad')*2)) - this.set('drop_offset_y', this.get('drop_offset_y')*(this.get('well_height')-this.get('drop_pad')*2)) + this.set('drop_offset_x_px', this.get('drop_offset_x')*(this.get('well_width')-this.get('drop_pad')*2)) + this.set('drop_offset_y_px', this.get('drop_offset_y')*(this.get('well_height')-this.get('drop_pad')*2)) }, setGeometry: function(width, height, ofx, ofy) { diff --git a/client/src/js/modules/shipment/views/containerplate.js b/client/src/js/modules/shipment/views/containerplate.js index 87980a4c4..b01c6c898 100644 --- a/client/src/js/modules/shipment/views/containerplate.js +++ b/client/src/js/modules/shipment/views/containerplate.js @@ -924,7 +924,9 @@ define(['marionette', doOnShow: function() { this.ui.ins.html(this.inspections.opts()) - this.type = this.ctypes.findWhere({ name: this.model.get('CONTAINERTYPE') }) + this.type = this.ctypes.find(m => + m.get('name').toLowerCase() === this.model.get('CONTAINERTYPE').toLowerCase() + ) this.plateView = new PlateView({ collection: this.samples, type: this.type, showImageStatus: this.model.get('INSPECTIONS') > 0 }) this.listenTo(this.plateView, 'plate:select', this.resetZoom, this) this.plate.show(this.plateView) diff --git a/client/src/js/modules/shipment/views/plate.js b/client/src/js/modules/shipment/views/plate.js index ca2013adb..a37c5a0d0 100644 --- a/client/src/js/modules/shipment/views/plate.js +++ b/client/src/js/modules/shipment/views/plate.js @@ -215,7 +215,7 @@ define(['marionette', 'backbone', 'utils', 'backbone-validation'], function(Mari } else this.ctx.strokeStyle = '#ddd' - this.ctx.rect(this.pt.get('drop_offset_x')+this.pt.get('offset_x')+row*(this.pt.get('well_width')+this.pt.get('well_pad'))+(j*this.pt.get('drop_widthpx')+this.pt.get('drop_pad')), this.pt.get('drop_offset_y')+this.pt.get('offset_y')+col*(this.pt.get('well_height')+this.pt.get('well_pad'))+(k*this.pt.get('drop_heightpx')+this.pt.get('drop_pad')), this.pt.get('drop_widthpx'), this.pt.get('drop_heightpx')) + this.ctx.rect(this.pt.get('drop_offset_x_px')+this.pt.get('offset_x')+row*(this.pt.get('well_width')+this.pt.get('well_pad'))+(j*this.pt.get('drop_widthpx')+this.pt.get('drop_pad')), this.pt.get('drop_offset_y_px')+this.pt.get('offset_y')+col*(this.pt.get('well_height')+this.pt.get('well_pad'))+(k*this.pt.get('drop_heightpx')+this.pt.get('drop_pad')), this.pt.get('drop_widthpx'), this.pt.get('drop_heightpx')) // Highlight Hovered Sample @@ -319,7 +319,7 @@ define(['marionette', 'backbone', 'utils', 'backbone-validation'], function(Mari this.ctx.fillStyle = '#000' this.ctx.font = "8px Arial" this.ctx.lineWidth = 1 - this.ctx.fillText(sampleid,this.pt.get('drop_offset_x')+2+this.pt.get('offset_x')+row*(this.pt.get('well_width')+this.pt.get('well_pad'))+(j*this.pt.get('drop_widthpx')+this.pt.get('drop_pad')), this.pt.get('drop_offset_y')+10+this.pt.get('offset_y')+col*(this.pt.get('well_height')+this.pt.get('well_pad'))+(k*this.pt.get('drop_heightpx')+this.pt.get('drop_pad'))); + this.ctx.fillText(sampleid,this.pt.get('drop_offset_x_px')+2+this.pt.get('offset_x')+row*(this.pt.get('well_width')+this.pt.get('well_pad'))+(j*this.pt.get('drop_widthpx')+this.pt.get('drop_pad')), this.pt.get('drop_offset_y_px')+10+this.pt.get('offset_y')+col*(this.pt.get('well_height')+this.pt.get('well_pad'))+(k*this.pt.get('drop_heightpx')+this.pt.get('drop_pad'))); } } } @@ -333,8 +333,8 @@ define(['marionette', 'backbone', 'utils', 'backbone-validation'], function(Mari var x = Math.floor((cur[0] - this.pt.get('offset_x'))/(this.pt.get('well_width')+this.pt.get('well_pad'))) var y = Math.floor((cur[1] - this.pt.get('offset_y'))/(this.pt.get('well_height')+this.pt.get('well_pad'))) - var wox = cur[0] - this.pt.get('drop_offset_x') - this.pt.get('offset_x') - this.pt.get('drop_pad') - x*(this.pt.get('well_width')+this.pt.get('well_pad')) - var woy = cur[1] - this.pt.get('drop_offset_y') - this.pt.get('offset_y') - this.pt.get('drop_pad') - y*(this.pt.get('well_height')+this.pt.get('well_pad')) + var wox = cur[0] - this.pt.get('drop_offset_x_px') - this.pt.get('offset_x') - this.pt.get('drop_pad') - x*(this.pt.get('well_width')+this.pt.get('well_pad')) + var woy = cur[1] - this.pt.get('drop_offset_y_px') - this.pt.get('offset_y') - this.pt.get('drop_pad') - y*(this.pt.get('well_height')+this.pt.get('well_pad')) if (wox > 0 && wox < this.pt.get('drop_per_well_x')*this.pt.get('drop_widthpx') && woy > 0 && woy < this.pt.get('drop_per_well_y')*this.pt.get('drop_heightpx')) { var dx = Math.floor(wox / this.pt.get('drop_widthpx')) diff --git a/client/src/js/templates/assign/assign.html b/client/src/js/templates/assign/assign.html index 4746eec06..7b7dabb6e 100644 --- a/client/src/js/templates/assign/assign.html +++ b/client/src/js/templates/assign/assign.html @@ -1,7 +1,7 @@ -

<% if (APP_TYPE == 'xpdf') { %>Puck<% } else { %>Container<% } %> Allocation for <%-VISIT.VISIT%> on <%-VISIT.BL%> at <%-VISIT.ST%>

+

Allocation for <%-VISIT.VISIT%> on <%-VISIT.BL%> at <%-VISIT.ST%>

-

This page allows you to allocate samples from ISPyB to the beamline sample changer. Drag and drop <% if (APP_TYPE == 'xpdf') { %>pucks<% } else { %>containers<% } %> on to the locations on the beamline. Shipments and Dewars can be expanded by clicking on their titles

-

Uassign <% if (APP_TYPE == 'xpdf') { %>pucks<% } else { %>containers<% } %> by dragging them to any shipment listed under "Unassigned <% if (APP_TYPE == 'xpdf') { %>Pucks<% } else { %>Containers<% } %>". The <% if (APP_TYPE == 'xpdf') { %>puck<% } else { %>container<% } %> will still belong to its original shipment.

+

This page allows you to allocate samples from ISPyB to the beamline sample changer. Drag and drop s on to the locations on the beamline. Shipments and Dewars can be expanded by clicking on their titles

+

Uassign s by dragging them to any shipment listed under "Unassigned s". The will still belong to its original shipment.

Data Collections @@ -10,13 +10,13 @@

<% if (APP_TYPE == 'xpdf') { %>Puck<% } else { %>Container<% } %> Allocation
-

Assigned <% if (APP_TYPE == 'xpdf') { %>Pucks<% } else { %>Containers<% } %>: Sample Changer

+

Assigned s: <%-VISIT.BL.toUpperCase()%> Sample Changer

- -

Unassigned <% if (APP_TYPE == 'xpdf') { %>Pucks<% } else { %>Containers<% } %>

+ +

Unassigned s

diff --git a/client/src/js/templates/dc/dc_dimple.html b/client/src/js/templates/dc/dc_dimple.html index e21f9414d..1fd80df41 100644 --- a/client/src/js/templates/dc/dc_dimple.html +++ b/client/src/js/templates/dc/dc_dimple.html @@ -12,23 +12,50 @@
- - <% if (STATS.length) { %> - <% _.each(STATS, function(r, i) { %> +
+
+ <% if (STATS.length) { %> + <% _.each(STATS, function(r, i) { %> + + <% _.each(r, function(j) { %> + + <% }) %> + + <% }) %> + <% } else { %> + + + + + + + <% } %> +
<%-j%>
Refinement Stats
No Stats Available
+
+ +

+
+ <% if (ANODE_PEAKS && ANODE_PEAKS.TABLE && ANODE_PEAKS.TABLE.length) { %> +
+
Top 10 Anode Peaks
+ + + + + + + + + + <% _.each(ANODE_PEAKS.TABLE, function(r, i) { %> <% _.each(r, function(j) { %> <% }) %> <% }) %> - <% } else { %> - - - - - - - <% } %> -
XYZHeight (sig)SOFNearest Atom
<%-j%>
Refinement Stats
No Stats Available
- + + <% } else { %> +
No Anode peaks found
+ <% } %>
diff --git a/client/src/js/templates/dc/dclist.html b/client/src/js/templates/dc/dclist.html index c5f7a1f69..3375820f4 100644 --- a/client/src/js/templates/dc/dclist.html +++ b/client/src/js/templates/dc/dclist.html @@ -22,7 +22,7 @@

<% } %>