Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mxcubeweb/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ def init_logging(log_file, log_level, enabled_logger_list):
else:
logger.disabled = True

for name in ("httpx", "httpcore"):
for name in ("httpx", "httpcore", "geventwebsocket.handler"):
logger = logging.getLogger(name)
logger.setLevel(logging.ERROR)
logger.propagate = False
Expand Down
83 changes: 80 additions & 3 deletions mxcubeweb/core/components/lims.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import re
import sys
from http import HTTPStatus
from time import sleep
from urllib.parse import urljoin

import httpx
Expand Down Expand Up @@ -276,13 +277,89 @@ def synch_with_lims(self, lims_name):
# session_id is not used, so we can pass None as second argument to
# 'db_connection.get_samples'

samples_info_list = HWR.beamline.lims.get_samples(lims_name)
# Try 3 times in case the robot client connection fails
for _ in range(3):
samples_info_list = HWR.beamline.sample_changer.refresh_puck_info()
if not samples_info_list:
logging.getLogger("MX3.HWR").info(
"[LIMS] No sample info retrieved from LIMS, retrying..."
)
sleep(0.5)
continue

break

_sample_list = {}
_sample_order = []
for sample_info in samples_info_list:
sample_location = sample_info.get("sampleLocation")
puck_location = sample_info.get("containerSampleChangerLocation")
if sample_location is None or puck_location is None:
continue

try:
port_int = int(sample_location)
except (TypeError, ValueError):
continue

# The UI filters samples by (cell_no, puck_no) and expects these to
# match the SC contents tree (cell=1 for single-cell changers).
cell_no = 1
puck_no = 1
container_loc_key = str(puck_location)
try:
basket = int(puck_location)
except (TypeError, ValueError):
basket = None
else:
if HWR.beamline.sample_changer.__class__.__TYPE__ in [
"Flex Sample Changer",
"FlexHCD",
"RoboDiff",
]:
cell_no = int(math.ceil((basket) / 3.0))
puck_no = basket - 3 * (cell_no - 1)
container_loc_key = f"{cell_no}:{puck_no}"
else:
puck_no = basket

sample_list_key = f"{container_loc_key}:{port_int:02d}"
sample_name = sample_info.get("sampleName") or ""
_sample_list[sample_list_key] = {
"sampleID": sample_list_key,
"location": sample_list_key,
"sampleName": sample_name,
"crystalUUID": sample_list_key,
"proteinAcronym": "",
"code": sample_info["code"],
"limsID": sample_info.get("sampleId"),
"loadable": True,
"state": 0,
"tasks": [],
"type": "Sample",
"cell_no": cell_no,
"puck_no": puck_no,
"defaultPrefix": sample_name,
"defaultSubDir": sample_name + "/",
}

_sample_order.append(sample_list_key)

self.app.SAMPLE_LIST = {
"sampleList": _sample_list,
"sampleOrder": _sample_order,
}

for sample_info in samples_info_list:
sample_info["limsID"] = sample_info.pop("sampleId")
sample_info["limsID"] = sample_info.pop("sampleId", None)
sample_info["defaultPrefix"] = self.get_default_prefix(sample_info)
sample_info["defaultSubDir"] = self.get_default_subdir(sample_info)

if not VALID_SAMPLE_NAME_REGEXP.match(sample_info["sampleName"]):
sample_name = sample_info.get("sampleName")
if not isinstance(sample_name, str) or not sample_name:
continue

if not VALID_SAMPLE_NAME_REGEXP.match(sample_name):
raise AttributeError(
"sample name for sample %s contains an incorrect character"
% sample_info
Expand Down
8 changes: 4 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mxcubeweb"
version = "4.238.0.53"
version = "4.238.0.54"
license = "LGPL-3.0-or-later"
description = "MXCuBE Web user interface"
authors = ["The MXCuBE collaboration <mxcube@esrf.fr>"]
Expand Down Expand Up @@ -41,7 +41,7 @@ pydantic = ">=2.8.2,<2.11.0"
PyDispatcher = "^2.0.6"
pytz = "^2022.6"
tzlocal = "^4.2"
mxcubecore = {git = "https://github.com/AustralianSynchrotron/mxcubecore.git", rev = "v1.195.0.56", extras=["prefect"]}
mxcubecore = {git = "https://github.com/AustralianSynchrotron/mxcubecore.git", rev = "v1.195.0.57", extras=["prefect"]}
bcrypt = "^4.0.1"
authlib = "^1.3.0"

Expand Down
10 changes: 7 additions & 3 deletions ui/src/actions/sampleGrid.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { showErrorPanel } from './general';
import { setQueue } from './queue'; // eslint-disable-line import/no-cycle
import { fetchSamplesList, sendSyncWithCrims } from '../api/sampleChanger';
import { fetchLimsSamples } from '../api/lims';
import { refresh as refreshSampleChanger } from './sampleChanger';
import { hideWaitDialog, showWaitDialog } from './waitDialog';

export function updateSampleList(sampleList, order) {
Expand Down Expand Up @@ -71,7 +71,9 @@ export function getSamplesList() {
const json = await fetchSamplesList();
const { sampleList, sampleOrder } = json;
dispatch(updateSampleList(sampleList, sampleOrder));
dispatch(setQueue(json));

// Refresh sample changer after updating sample list
await dispatch(refreshSampleChanger());
} catch {
dispatch(showErrorPanel(true, 'Could not get samples list'));
}
Expand All @@ -87,7 +89,9 @@ export function syncSamples(lims) {
try {
const json = await fetchLimsSamples(lims);
dispatch(updateSampleList(json.sampleList, json.sampleOrder));
dispatch(setQueue(json));

// Refresh sample changer after updating sample list
await dispatch(refreshSampleChanger());
} catch (error) {
dispatch(
showErrorPanel(
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/BeamlineCamera/BeamlineCamera.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,4 @@ function CameraStreamImg({ src, alt, width, height }) {
style={{ background: '#222' }}
/>
);
}
}
6 changes: 3 additions & 3 deletions ui/src/components/LoginForm/LoginForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ function LoginForm() {
const useSSO = useSelector((state) => state.login.useSSO);

// Console was showing this warning:
// Can't perform a React state update on an unmounted component.
// This is a no-op, but it indicates a memory leak in your application.
// To fix, cancel all subscriptions and asynchronous tasks
// Can't perform a React state update on an unmounted component.
// This is a no-op, but it indicates a memory leak in your application.
// To fix, cancel all subscriptions and asynchronous tasks
// in a useEffect cleanup function.

// This fixes the warning:
Expand Down
6 changes: 1 addition & 5 deletions ui/src/containers/SampleListViewContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -627,13 +627,9 @@ class SampleListViewContainer extends React.Component {
return (
<TooltipTrigger
id="sync-samples-tooltip"
tooltipContent={`Synchronise sample list with ${this.props.loginData.limsName[0].name}`}
tooltipContent={`Synchronise sample list`}
>
<Button
// TODO: Hide Refresh button for now
// Can be implemented later to show samples from the
// robot matrix
style={{ display: 'none' }}
className="nowrap-style"
variant="outline-secondary"
onClick={() =>
Expand Down
Loading