diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 050cec929..2b5c73a84 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,6 @@ defaults: shell: bash working-directory: ./api -# Note, jobs do not share the same working environment, whereas steps do. Also, jobs will run in parallel unless the 'needs' tag is used to flag a dependency jobs: php-build: name: Checkout, build, test and lint PHP code @@ -33,6 +32,9 @@ jobs: with: php-version: 7.3 tools: psalm:4 + # Added extensions and coverage here so they are ready for the native run + extensions: mysqli, zip, xdebug + coverage: xdebug - name: Validate composer.json and composer.lock run: composer validate @@ -49,17 +51,12 @@ jobs: - name: Install dependencies run: composer install --prefer-dist --no-progress + # CHANGED: Replaced php-actions/phpunit with native execution + # This runs the PHPUnit located in your vendor folder, avoiding the PHAR crash - name: PHPUnit Tests - uses: php-actions/phpunit@v3 + run: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text env: XDEBUG_MODE: coverage - with: - bootstrap: api/vendor/autoload.php - configuration: api/tests/phpunit.xml - php_extensions: xdebug mysqli zip - args: --coverage-text - php_version: 7.3 - version: 9 - name: Run Psalm run: psalm --output-format=github @@ -77,8 +74,7 @@ jobs: node-version: 18.x - name: JavaScript build, lint and test working-directory: ./client - # hack the output from the linting steps to avoid these stopping the builds - we are not going to get - # to a clean output without considerable effort, but it's useful to see the output + # hack the output from the linting steps to avoid these stopping the builds run: | cp src/js/config_sample.json src/js/config.json node --version diff --git a/api/composer.json b/api/composer.json index 8ec82129d..725677a26 100644 --- a/api/composer.json +++ b/api/composer.json @@ -14,9 +14,9 @@ } ], "require": { - "apereo/phpcas": "1.3.8", + "apereo/phpcas": "1.6.1", "ezyang/htmlpurifier": "4.12.0", - "firebase/php-jwt": "2.2.0", + "firebase/php-jwt": "6.0.0", "jdorn/sql-formatter": "1.2.9", "mpdf/mpdf": "8.1.2", "ralouphie/getallheaders": "2.0.5", diff --git a/api/config_sample.php b/api/config_sample.php index 9be9cf64f..4fb94bc03 100644 --- a/api/config_sample.php +++ b/api/config_sample.php @@ -264,7 +264,6 @@ $use_shipping_service_incoming_shipments = null; $use_shipping_service_redirect = null; $use_shipping_service_redirect_incoming_shipments = null; - $shipping_service_api_url = null; $shipping_service_api_user = null; $shipping_service_api_password = null; $shipping_service_app_url = null; diff --git a/api/src/Authentication/Type/CAS.php b/api/src/Authentication/Type/CAS.php index 0160dbe63..34bddba26 100644 --- a/api/src/Authentication/Type/CAS.php +++ b/api/src/Authentication/Type/CAS.php @@ -27,7 +27,13 @@ function check() /** * @psalm-suppress UndefinedConstant define in CAS.php */ - phpCAS::client(CAS_VERSION_2_0, $cas_url, 443, '/cas'); + $protocol = 'http'; + if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { + $protocol = 'https'; + } + $hostname = $_SERVER['HTTP_HOST']; + $service_base_url = $protocol . '://' . $hostname; + phpCAS::client(CAS_VERSION_2_0, $cas_url, 443, '/cas', $service_base_url); phpCAS::setCasServerCACert($cacert); try { diff --git a/api/src/Controllers/AuthenticationController.php b/api/src/Controllers/AuthenticationController.php index 2f1c2f9b2..82744bec4 100644 --- a/api/src/Controllers/AuthenticationController.php +++ b/api/src/Controllers/AuthenticationController.php @@ -3,7 +3,8 @@ namespace SynchWeb\Controllers; use Exception; -use JWT; +use Firebase\JWT\JWT; +use Firebase\JWT\Key; use Slim\Slim; use SynchWeb\Model\User; @@ -280,7 +281,7 @@ private function checkForAndValidateAuthenticationToken() try { - $token = JWT::decode($jwt, $jwt_key, array('HS512')); + $token = JWT::decode($jwt, new Key($jwt_key, 'HS512'), array('HS512')); $this->loginId = $token->data->login; } catch (\Exception $e) diff --git a/api/src/Downstream/Type/Dimple.php b/api/src/Downstream/Type/Dimple.php index 814e18b78..f8bb859b7 100644 --- a/api/src/Downstream/Type/Dimple.php +++ b/api/src/Downstream/Type/Dimple.php @@ -22,22 +22,12 @@ function _get_blobs() { ); } - # This will break if dimple is run more than once on the same scalingid - # TODO: Change structure of MXMRRun to link to autoprocprogram - # https://jira.diamond.ac.uk/browse/SCI-7941 function _find_mrrun() { - if (!array_key_exists("scaling_id", $this->process['PARAMETERS'])) { - return; - } - $mrrun = $this->db->pq( - "SELECT mxmrrunid, processingstatus, processingmessage, - rvaluestart, rvalueend, rfreevaluestart, rfreevalueend + "SELECT m.mxmrrunid FROM mxmrrun m - INNER JOIN autoprocprogram app - ON m.autoprocprogramid = app.autoprocprogramid - WHERE autoprocscalingid=:1", - array($this->process['PARAMETERS']["scaling_id"]) + WHERE m.autoprocprogramid=:1", + array($this->autoprocprogramid) ); if (!sizeof($mrrun)) { diff --git a/api/src/Downstream/Type/MetalId.php b/api/src/Downstream/Type/MetalId.php new file mode 100644 index 000000000..48044ee63 --- /dev/null +++ b/api/src/Downstream/Type/MetalId.php @@ -0,0 +1,80 @@ +_get_blobs(); + if (sizeof($blobs)) { + $headings = array('Peak', 'Height', 'XYZ'); + } else { + $headings = array('No peaks found'); + } + $peaks = array($headings); + foreach($blobs as $n => $blob) { + $peak = array($n+1, $blob['HEIGHT'], '('.$blob['X'].', '.$blob['Y'].', '.$blob['Z'].')'); + array_push($peaks, $peak); + } + $dat = array(); + $dat['BLOBS'] = sizeof($blobs); + $dat['PEAKS'] = $peaks; + + $integrator = $this->_lookup_autoproc( + null, + $this->process['PARAMETERS']['scaling_id'] + ); + if ($integrator) { + $dat['PARENTAUTOPROCPROGRAM'] = $integrator['PROCESSINGPROGRAMS']; + $dat['PARENTAUTOPROCPROGRAMID'] = $integrator['AUTOPROCPROGRAMID']; + } + + $results = new DownstreamResult($this); + $results->data = $dat; + + return $results; + } + + function _find_mrrun() { + $mrrun = $this->db->pq( + "SELECT m.mxmrrunid + FROM mxmrrun m + WHERE m.autoprocprogramid=:1", + array($this->autoprocprogramid) + ); + + if (!sizeof($mrrun)) { + return; + } + + $this->_mrrun = $mrrun[0]; + return true; + } + + function _get_blobs() { + if (!$this->_find_mrrun()) { + return array(); + } + return $this->db->pq( + "SELECT view1, filepath, x, y, z, height + FROM mxmrrunblob + WHERE mxmrrunid = :1 + AND filepath is not NULL", + array($this->_mrrun["MXMRRUNID"]) + ); + } + + function images($n = 0) { + $blobs = $this->_get_blobs(); + if ($n < sizeof($blobs)) { + return $blobs[$n]["FILEPATH"] . '/' . $blobs[$n]["VIEW1"]; + } + } +} diff --git a/api/src/Page/Download.php b/api/src/Page/Download.php index 9f9794d20..df6ce88eb 100644 --- a/api/src/Page/Download.php +++ b/api/src/Page/Download.php @@ -268,8 +268,8 @@ function _get_file($id, $file) $response->headers->set("Content-Length", filesize($filename)); } elseif ($filesystem->exists($filename.'.gz')) { $filename = $filename.'.gz'; - if ($this->arg('download') == 1) { - // View log file, so unzip and serve + if ($this->has_arg('download') && $this->arg('download') < 3) { + // View/open file, so unzip and serve $response = new Response(readgzfile($filename)); $this->set_mime_content($response, $file['FILENAME'], $id); } else { @@ -549,21 +549,20 @@ function set_mime_content($response, $filename, $prefix = null) if (in_array($path_ext, array('html', 'htm'))) { $response->headers->set("Content-Type", "text/html"); - $this->_set_disposition_inline($response); } elseif ($path_ext == 'pdf') { $response->headers->set("Content-Type", "application/pdf"); - $this->_set_disposition_attachment($response, $saved_filename); } elseif ($path_ext == 'png') { $response->headers->set("Content-Type", "image/png"); - $this->_set_disposition_attachment($response, $saved_filename); } elseif (in_array($path_ext, array('jpg', 'jpeg'))) { $response->headers->set("Content-Type", "image/jpeg"); - $this->_set_disposition_attachment($response, $saved_filename); - } elseif (in_array($path_ext, array('log', 'txt', 'error', 'LP', 'json', 'lsa'))) { + } elseif (in_array($path_ext, array('log', 'txt', 'error', 'LP', 'json', 'lsa', 'lst'))) { $response->headers->set("Content-Type", "text/plain"); - $this->_set_disposition_inline($response); } else { $response->headers->set("Content-Type", "application/octet-stream"); + } + if ($this->has_arg('download') && $this->arg('download') < 3) { + $this->_set_disposition_inline($response); + } else { $this->_set_disposition_attachment($response, $saved_filename); } } diff --git a/api/src/Page/Process.php b/api/src/Page/Process.php index b41cb22d9..317c0b19d 100644 --- a/api/src/Page/Process.php +++ b/api/src/Page/Process.php @@ -383,7 +383,7 @@ function _enqueue() ); $this->_send_zocalo_message($rabbitmq_zocalo_vhost, $message); - $this->_output(new \stdClass); + $this->_output('Job successfully submitted'); } function _enqueue_downstream() @@ -413,7 +413,7 @@ function _enqueue_downstream() $this->_submit_zocalo_recipe($this->arg('RECIPE'), $parameters); - $this->_output(new \stdClass); + $this->_output('Job successfully submitted'); } /* diff --git a/api/src/Page/Shipment.php b/api/src/Page/Shipment.php index 5607eeac5..0019c1e77 100644 --- a/api/src/Page/Shipment.php +++ b/api/src/Page/Shipment.php @@ -1017,6 +1017,7 @@ function _transfer_dewar() function _create_dewars_shipment_request( array $dewars, string $proposal, + int $session_number, int $external_id, int $shipping_id, string $callback_url="" @@ -1026,6 +1027,8 @@ function _create_dewars_shipment_request( foreach (array_values($dewars) as $dew) { $package = [ "external_id" => (int) $dew['DEWARID'], + "container_name" => $dew['NAME'], + "serial_number" => $dew['MANUFACTURERSERIALNUMBER'], "shippable_item_type" => "CRYOGENIC_DRY_SHIPPER_CASE", "line_items" => [ [ @@ -1064,6 +1067,7 @@ function _create_dewars_shipment_request( $protocol = isset($_SERVER["HTTPS"]) ? 'https' : 'http'; $shipment_request_info = array( "proposal" => $proposal, + "session_number" => $session_number, "external_id" => $external_id, "origin_url" => "{$protocol}://{$_SERVER['SERVER_NAME']}{$server_port}/shipments/sid/{$shipping_id}", "packages" => $packages @@ -1084,6 +1088,7 @@ function _dispatch_dewar_shipment_request($dewar) $dewars = [$dewar]; $proposal = $dewar['PROPOSAL']; + $session_number = $dewar['VIS']; $external_id = (int) $dewar['DEWARID']; $shipping_id = (int) $dewar['SHIPPINGID']; $token = Utils::generateRandomMd5(); @@ -1093,7 +1098,7 @@ function _dispatch_dewar_shipment_request($dewar) ); $callback_url = "/api/shipment/dewars/confirmdispatch/did/{$external_id}/token/{$token}"; - $external_shipping_id = $this->_create_dewars_shipment_request($dewars, $proposal, $external_id, $shipping_id, $callback_url); + $external_shipping_id = $this->_create_dewars_shipment_request($dewars, $proposal, $session_number, $external_id, $shipping_id, $callback_url); $this->db->pq( "UPDATE dewar SET externalShippingIdFromSynchrotron=:1 WHERE dewarid=:2", @@ -1111,11 +1116,7 @@ function _dispatch_dewar_in_shipping_service($dispatch_info, $dewar) global $facility_country; global $facility_phone; global $facility_contact; - global $shipping_service_api_url; global $facility_email; - if (!isset($shipping_service_api_url)) { - throw new Exception("Could not send request to shipping service: shipping_service_api_url not set"); - } # Create shipment $shipment_data = array( @@ -1138,7 +1139,12 @@ function _dispatch_dewar_in_shipping_service($dispatch_info, $dewar) "shipment_reference" => $dispatch_info['VISIT'], "external_id" => (int) $dispatch_info['DEWARID'], "journey_type" => ShippingService::JOURNEY_FROM_FACILITY, - "packages" => array(array("external_id" => (int) $dispatch_info['DEWARID'])) + "packages" => array( + array( + "external_id" => (int) $dispatch_info['DEWARID'], + "container_name" => $dewar['NAME'], + ) + ) ); # Split up address. Necessary as address is a single field in ispyb @@ -1195,12 +1201,18 @@ function _dispatch_dewar() } $dew = $this->db->pq( - "SELECT d.dewarid, d.barcode, d.storagelocation, d.dewarstatus, d.externalShippingIdFromSynchrotron, s.shippingid, p.proposalcode, CONCAT(p.proposalcode, p.proposalnumber) as proposal, count(distinct c.containerId) as num_pucks, count(b.blsampleId) as num_samples + "SELECT d.dewarid, d.barcode, d.storagelocation, d.dewarstatus, d.externalShippingIdFromSynchrotron, + s.shippingid, p.proposalcode, CONCAT(p.proposalcode, p.proposalnumber) as proposal, + count(distinct c.containerId) as num_pucks, count(b.blsampleId) as num_samples, + ifnull(bls.visit_number, 0) as vis, IF(d.facilitycode, d.facilitycode, d.code) as name, + dr.manufacturerserialnumber FROM dewar d INNER JOIN shipping s ON s.shippingid = d.shippingid INNER JOIN proposal p ON p.proposalid = s.proposalid LEFT JOIN container c on c.dewarid = d.dewarid LEFT JOIN BLSample b on b.containerId = c.containerId + LEFT JOIN blsession bls ON bls.sessionid = d.firstexperimentid + LEFT JOIN dewarregistry dr ON dr.dewarregistryid = d.dewarregistryid WHERE d.dewarid=:1 and p.proposalid=:2", array($this->arg('DEWARID'), $this->proposalid) ); @@ -3308,10 +3320,15 @@ function _book_shipment_in_shipping_service($user, $shipment, $dewars, $journey_ "contact_email" => trim($user["email"]) ); $shipment_data = array( - "shipment_reference" => $shipment["PROP"], + "shipment_reference" => $shipment["PROP"] . '-' . ($shipment["session_number"] ?? 0), "external_id" => $shipment['SHIPPINGID'], "packages" => array_map( - function($dewar) {return array("external_id" => $dewar["DEWARID"]);}, + function($dewar) { + return array( + "external_id" => $dewar["DEWARID"], + "container_name" => $dewar["NAME"], + ); + }, $dewars ) ); @@ -3365,6 +3382,7 @@ function _create_shipment_shipment_request($shipment, array $dewars): int $external_shipping_id = $this->_create_dewars_shipment_request( $dewars, $shipment['PROP'], + isset($shipment['session_number']) ? $shipment['session_number'] : 0, $shipping_id, $shipping_id, $callback_url @@ -3409,15 +3427,25 @@ function _create_awb() $args = array_merge(array($ship['SHIPPINGID']), $this->arg('DEWARS')); $dewars = $this->db->pq( - "SELECT d.dewarid, d.weight, IF(d.facilitycode, d.facilitycode, d.code) as name, count(distinct c.containerId) as num_pucks, count(b.blsampleId) as num_samples + "SELECT d.dewarid, d.weight, IF(d.facilitycode, d.facilitycode, d.code) as name, + count(distinct c.containerId) as num_pucks, count(b.blsampleId) as num_samples, + bls.visit_number, dr.manufacturerserialnumber FROM dewar d LEFT JOIN container c on c.dewarid = d.dewarid LEFT JOIN BLSample b on b.containerId = c.containerId + LEFT JOIN blsession bls on bls.sessionid = d.firstexperimentid + LEFT JOIN dewarregistry dr on dr.dewarregistryid = d.dewarregistryid WHERE d.shippingid=:1 AND d.dewarid IN (:" . implode(',:', $ids) . ") GROUP BY d.dewarid", $args ); + foreach ($dewars as $d) { + if ($d['VISIT_NUMBER']) { + $ship['session_number'] = $d['VISIT_NUMBER']; + } + } + if ( Utils::getValueOrDefault($use_shipping_service_incoming_shipments) && in_array($this->arg('COUNTRY'), $facility_courier_countries) diff --git a/api/src/Shipment/ShippingService.php b/api/src/Shipment/ShippingService.php index ade0a35ce..eb5974bb7 100644 --- a/api/src/Shipment/ShippingService.php +++ b/api/src/Shipment/ShippingService.php @@ -40,10 +40,9 @@ function _build_headers() function __construct() { - global $shipping_service_api_url; global $shipping_service_app_url; - $this->shipping_api_url = $shipping_service_api_url; $this->shipping_app_url = $shipping_service_app_url; + $this->shipping_api_url = $shipping_service_app_url . "/api"; } diff --git a/client/src/js/modules/dc/views/autoprocattachments.js b/client/src/js/modules/dc/views/autoprocattachments.js index 40858be83..e330bf887 100644 --- a/client/src/js/modules/dc/views/autoprocattachments.js +++ b/client/src/js/modules/dc/views/autoprocattachments.js @@ -19,7 +19,7 @@ define(['marionette', }, render: function() { - var filePath = this.model.get('FILEPATH') + var filePath = this.model.get('FILEPATH') || '' var displayedPath = filePath.split('/').length > 4 ? filePath.split('/').slice(0, 4).join('/') + '/...' : filePath this.$el.html(` @@ -34,19 +34,19 @@ define(['marionette', copyPathToClipboard: function(e) { e.preventDefault() - var fullPath = this.model.get('FILEPATH') + var filePath = this.model.get('FILEPATH') || '' if (navigator.clipboard && navigator.clipboard.writeText) { - navigator.clipboard.writeText(fullPath).then(() => { + navigator.clipboard.writeText(filePath).then(() => { var $icon = $(e.currentTarget).find('i') $icon.removeClass('fa-clipboard').addClass('fa-check') setTimeout(() => { $icon.removeClass('fa-check').addClass('fa-clipboard') }, 2000) }).catch(err => { - alert('Failed to copy path. Please try again or copy manually: ' + fullPath) + alert('Failed to copy path. Please try again or copy manually: ' + filePath) }) } else { - alert('Full path: ' + fullPath) + alert('Full path: ' + filePath) } } }) @@ -65,21 +65,23 @@ define(['marionette', var iCatBaseUrl = this.column.escape('iCatUrl'); var isIndustry = this.column.escape('isIndustryProposal').toLowerCase() === 'true'; var isPurgedSession = this.column.escape('isPurgedSession').toLowerCase() === 'true'; + var filePath = this.model.get('FILEPATH') || ''; // Files with "visit_persist_storage_dir_segment" (config.php) in their path are assumed to exist permanently and ignore the BLSESSION purged value - var isPersistentFile = persistentStorageSegment ? this.model.get('FILEPATH').includes(persistentStorageSegment) : false; + var isPersistentFile = persistentStorageSegment ? filePath.includes(persistentStorageSegment) : false; if (isPersistentFile == true | isPurgedSession == false) { var baseDownloadUrl = `${app.apiurl}/download/${this.column.escape('urlRoot')}/attachments/${this.model.escape(this.column.get('idParam'))}` // Default behaviour for download btn - this.$el.html(` Download`) + this.$el.html(` Download`) // Additional btns per filetype switch (this.model.get('FILETYPE')) { case 'Log': case 'Logfile': + this.$el.append(` Open`) this.$el.append(` View `); break; diff --git a/client/src/js/modules/dc/views/downstream.js b/client/src/js/modules/dc/views/downstream.js index 4da0da300..0be64f4ea 100644 --- a/client/src/js/modules/dc/views/downstream.js +++ b/client/src/js/modules/dc/views/downstream.js @@ -8,11 +8,12 @@ define(['backbone', 'marionette', 'modules/dc/views/mrbump', 'modules/dc/views/bigep', 'modules/dc/views/shelxt', + 'modules/dc/views/metalid', 'modules/dc/views/ligandfit', ], function(Backbone, Marionette, TabView, DownStreams, DownstreamWrapper, TableView, - FastEP, DIMPLE, MrBUMP, BigEP, Shelxt, LigandFit) { + FastEP, DIMPLE, MrBUMP, BigEP, Shelxt, MetalId, LigandFit) { var dcPurgedProcessedData = "0"; // dataCollection.PURGEDPROCESSEDDATA via options from DC.js @@ -65,6 +66,7 @@ define(['backbone', 'marionette', 'Crank2': BigEP, 'AutoSHARP': BigEP, 'Shelxt': Shelxt, + 'Metal Id': MetalId, 'LigandFit': LigandFit, } diff --git a/client/src/js/modules/dc/views/downstreamreprocess.js b/client/src/js/modules/dc/views/downstreamreprocess.js index 1ea5f86d7..b9b58e603 100644 --- a/client/src/js/modules/dc/views/downstreamreprocess.js +++ b/client/src/js/modules/dc/views/downstreamreprocess.js @@ -138,12 +138,19 @@ define(['backbone', 'marionette', 'views/dialog', submit: function(e) { e.preventDefault() - + this._disableIntegrateButton() this._enqueue({ RECIPE: this.model.get('PIPELINE'), DATACOLLECTIONID: this.model.get('ID'), SCALINGID: this.scalingid }) app.message({ message: 'Downstream processing job successfully submitted'}) }, + _disableIntegrateButton: function() { + var btn = $('.ui-dialog-buttonpane button:contains("Submit")') + btn.button('disable').button('option', 'label', 'Submitted!') + setTimeout(function() { + btn.button('enable').button('option', 'label', 'Submit') + }, 5000) + }, _enqueue: function(options) { Backbone.ajax({ diff --git a/client/src/js/modules/dc/views/downstreamwrapper.js b/client/src/js/modules/dc/views/downstreamwrapper.js index d435a6e43..97bb31cfd 100644 --- a/client/src/js/modules/dc/views/downstreamwrapper.js +++ b/client/src/js/modules/dc/views/downstreamwrapper.js @@ -102,7 +102,10 @@ define(['backbone', 'marionette', ' Download Zip', ] - if (!this.getOption('mapLink')) { + if ( + !this.getOption('mapLink') || + this.model.get('FEATURES')?.MAPMODEL?.[0] === 0 + ) { links = links.slice(1) } diff --git a/client/src/js/modules/dc/views/metalid.js b/client/src/js/modules/dc/views/metalid.js new file mode 100644 index 000000000..ad4ba2eb5 --- /dev/null +++ b/client/src/js/modules/dc/views/metalid.js @@ -0,0 +1,40 @@ +define([ + 'marionette', 'templates/dc/dc_metalid.html', 'utils', 'utils/xhrimage' +], function(Marionette, template, utils, XHRImage) { + + return Marionette.ItemView.extend({ + template: template, + className: 'clearfix', + + ui: { + blob: '.blobs img', + blobs: '.blobs', + }, + + showBlob: function() { + this.ui.blob.attr('src', this.blob.src).show() + this.ui.blobs.addClass('loaded').removeClass('pending') + }, + + onDomRefresh: function() { + this.ui.blobs.magnificPopup({ + delegate: 'a', type: 'image', + gallery: { + enabled: true, + navigateByImgClick: true, + } + }) + + this.ui.blob.hide() + if (this.model.get('BLOBS') > 0) { + this.blob = new XHRImage() + this.blob.onload = this.showBlob.bind(this) + this.ui.blobs.addClass('pending') + this.blob.load(app.apiurl+'/processing/downstream/images/'+this.model.get('AID')) + } + + }, + + }) + +}) diff --git a/client/src/js/modules/dc/views/reprocess.js b/client/src/js/modules/dc/views/reprocess.js index 27a8a5b6d..8ed8b3f5d 100644 --- a/client/src/js/modules/dc/views/reprocess.js +++ b/client/src/js/modules/dc/views/reprocess.js @@ -352,6 +352,7 @@ define(['backbone', 'marionette', 'views/dialog', integrate: function(e) { e.preventDefault() + this._disableIntegrateButton() var s = this.collection.where({ selected: true }) if (!s.length) { @@ -449,10 +450,10 @@ define(['backbone', 'marionette', 'views/dialog', }, this) $.when.apply($, reqs).done(function() { - app.message({ message: jobs+' reprocessing job(s) successfully submitted'}) _.each(rps, function(rp) { self._enqueue({ PROCESSINGJOBID: rp.get('PROCESSINGJOBID') }) }) + app.message({ message: jobs+' reprocessing job(s) successfully submitted'}) }) @@ -541,9 +542,9 @@ define(['backbone', 'marionette', 'views/dialog', reqs.push(reprocessingsweeps.save()) $.when.apply($, reqs).done(function() { - app.message({ message: '1 reprocessing job successfully submitted'}) self._enqueue({ PROCESSINGJOBID: reprocessing.get('PROCESSINGJOBID') }) }) + app.message({ message: '1 reprocessing job successfully submitted'}) }, error: function() { @@ -555,6 +556,15 @@ define(['backbone', 'marionette', 'views/dialog', }, + _disableIntegrateButton: function() { + var btn = $('.ui-dialog-buttonpane button:contains("Integrate")') + btn.button('disable').button('option', 'label', 'Submitted!') + setTimeout(function() { + btn.button('enable').button('option', 'label', 'Integrate') + }, 5000) + }, + + _enqueue: function(options) { Backbone.ajax({ url: app.apiurl+'/process/enqueue', diff --git a/client/src/js/modules/mc/views/datacollections.js b/client/src/js/modules/mc/views/datacollections.js index 1e5c70493..5ca413450 100644 --- a/client/src/js/modules/mc/views/datacollections.js +++ b/client/src/js/modules/mc/views/datacollections.js @@ -60,7 +60,7 @@ define(['backbone', 'marionette', events: { 'click .integrate': 'integrate', - 'click a.opt': 'toggleOpts', + 'click button.opt': 'toggleOpts', 'change @ui.pipeline': 'updatePipeline', }, @@ -106,11 +106,12 @@ define(['backbone', 'marionette', integrate: function(e) { e.preventDefault() + this._disableIntegrateButton() var s = this.collection.where({ selected: true }) if (!s.length) { - utils.confirm({ title: 'No data collections selected', content: 'Please selected some data sets to integrate' }) + utils.confirm({ title: 'No data collections selected', content: 'Please select some data sets to integrate', buttons: {'Ok': 'closeDialog'}}) return } @@ -198,8 +199,8 @@ define(['backbone', 'marionette', var reprocessingsweeps = new ReprocessingImageSweeps(sweeps) reprocessingsweeps.save() - app.message({ message: '1 reprocessing job successfully submitted'}) self._enqueue({ PROCESSINGJOBID: reprocessing.get('PROCESSINGJOBID') }) + app.message({ message: 'Reprocessing job successfully submitted'}) }, error: function() { @@ -210,6 +211,16 @@ define(['backbone', 'marionette', }, + _disableIntegrateButton: function() { + var btn = $('button.integrate') + var btnHtml = btn.html() + btn.prop('disabled', true).html(' Submitted!'); + setTimeout(function() { + btn.prop('disabled', false).html(btnHtml); + }, 5000) + }, + + _enqueue: function(options) { Backbone.ajax({ url: app.apiurl+'/process/enqueue', diff --git a/client/src/js/templates/dc/dc_metalid.html b/client/src/js/templates/dc/dc_metalid.html new file mode 100644 index 000000000..852196268 --- /dev/null +++ b/client/src/js/templates/dc/dc_metalid.html @@ -0,0 +1,32 @@ +
+
+ <% _.each(_.range(BLOBS), function(i) { %> + + <% if (i == 0) { %> + Peak 1 + <% } %> + + <% }) %> + +
+ + + <% if (PEAKS.length) { %> + <% _.each(PEAKS, function(r) { %> + + <% _.each(r, function(j) { %> + + <% }) %> + + <% }) %> + <% } else { %> + + + + + + + <% } %> +
<%-j%>
Peak
No Peaks Found
+ +
diff --git a/client/src/js/templates/mc/datacollections.html b/client/src/js/templates/mc/datacollections.html index 9af214cb3..6cad6eb85 100644 --- a/client/src/js/templates/mc/datacollections.html +++ b/client/src/js/templates/mc/datacollections.html @@ -32,8 +32,8 @@

Data Collections for <%-VISIT%>

- Integrate - Xia2 Options + +
diff --git a/client/src/js/utils.js b/client/src/js/utils.js index aea8e7fda..a469e020f 100644 --- a/client/src/js/utils.js +++ b/client/src/js/utils.js @@ -81,10 +81,10 @@ define(['backbone', }, events: { - 'click a.dismiss': 'disimss', + 'click a.dismiss': 'dismiss', }, - disimss: function(e) { + dismiss: function(e) { e.preventDefault() this.destroy() }, @@ -118,13 +118,15 @@ define(['backbone', var ConfirmDialog = DialogView.extend({ title: options.title, template: _.template(options.content), - buttons: { + buttons: options.buttons || { 'Ok': 'onOK', 'Cancel': 'closeDialog', }, onOK: function() { - options.callback() + if (typeof options.callback === 'function') { + options.callback(); + } this.closeDialog() }, }) @@ -236,4 +238,4 @@ define(['backbone', return utils -}) \ No newline at end of file +})