Skip to content
Open
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
42 changes: 39 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,12 @@ RUN make -j4 pyopenms
WORKDIR /openms-build/pyOpenMS
RUN pip install dist/*.whl

# Install other dependencies (excluding pyopenms)
COPY requirements.txt ./requirements.txt
RUN grep -Ev '^pyopenms([=<>!~].*)?$' requirements.txt > requirements_cleaned.txt && mv requirements_cleaned.txt requirements.txt
# Install other dependencies (excluding pyopenms and openms-insight).
# openms-insight is installed from source in the run-app stage instead: the
# pinned PyPI release does not yet carry the new FLASHApp visualization
# components, so we build our branch (with its Vue bundle) below.
COPY requirements.txt ./requirements.txt
RUN grep -Ev '^(pyopenms|openms-insight)([=<>!~].*)?$' requirements.txt > requirements_cleaned.txt && mv requirements_cleaned.txt requirements.txt
RUN pip install -r requirements.txt

WORKDIR /
Expand Down Expand Up @@ -144,6 +147,31 @@ WORKDIR /openms-streamlit-vue-component
RUN npm install
RUN npm run build

# Build the OpenMS-Insight Vue bundle and stage its source tree so the Python
# package can be installed (with the bundle baked in) in the run-app stage.
# Like js-build, kept after the slow OpenMS compile so component changes don't
# invalidate that cache.
FROM node:21 AS oi-build

# OpenMS-Insight repo/branch providing the new visualization components.
# Defaults to the migration branch because those components are not yet in the
# published PyPI release. Override via --build-arg once it is merged/released.
ARG OPENMS_INSIGHT_REPO=https://github.com/t0mdavid-m/OpenMS-Insight.git
ARG OPENMS_INSIGHT_BRANCH=claude/flashapp-openms-visualizations-LVv66

# Bust the build cache whenever the branch head moves.
ADD https://api.github.com/repos/t0mdavid-m/OpenMS-Insight/git/refs/heads/$OPENMS_INSIGHT_BRANCH oi-version.json

RUN git clone -b ${OPENMS_INSIGHT_BRANCH} --single-branch ${OPENMS_INSIGHT_REPO} /openms-insight
WORKDIR /openms-insight/js-component
RUN npm install
RUN npm run build
# The runtime bridge and the wheel packaging both expect the built bundle at
# openms_insight/js-component/dist; place it there so the `pip install` in the
# run-app stage bundles it into site-packages.
RUN mkdir -p /openms-insight/openms_insight/js-component \
&& cp -r /openms-insight/js-component/dist /openms-insight/openms_insight/js-component/dist

# Prepare and run streamlit app.
FROM compile-openms AS run-app

Expand Down Expand Up @@ -190,6 +218,14 @@ COPY presets.json /app/presets.json
# Copy the pre-built Vue/JS component (built in the js-build stage above).
COPY --from=js-build openms-streamlit-vue-component/dist /app/js-component/dist

# Install OpenMS-Insight (our branch build, with its freshly built Vue bundle)
# into the streamlit env. requirements.txt has openms-insight stripped, so this
# is the authoritative install and provides the new visualization components.
# The package ships its Vue bundle at openms_insight/js-component/dist (staged
# in the oi-build stage), which the runtime bridge loads in production mode.
COPY --from=oi-build /openms-insight /opt/openms-insight
RUN mamba run -n streamlit-env pip install /opt/openms-insight

# add cron job to the crontab
RUN echo "0 3 * * * /root/miniforge3/envs/streamlit-env/bin/python /app/clean-up-workspaces.py >> /app/clean-up-workspaces.log 2>&1" | crontab -

Expand Down
39 changes: 36 additions & 3 deletions Dockerfile.arm
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,12 @@ RUN make -j4 pyopenms
WORKDIR /openms-build/pyOpenMS
RUN pip install dist/*.whl

# Install other dependencies (excluding pyopenms)
COPY requirements.txt ./requirements.txt
RUN grep -Ev '^pyopenms([=<>!~].*)?$' requirements.txt > requirements_cleaned.txt && mv requirements_cleaned.txt requirements.txt
# Install other dependencies (excluding pyopenms and openms-insight). openms-insight
# is installed from source in the run-app stage: the pinned PyPI release does not
# yet carry the new FLASHApp visualization components, so we build our branch
# (with its Vue bundle) below.
COPY requirements.txt ./requirements.txt
RUN grep -Ev '^(pyopenms|openms-insight)([=<>!~].*)?$' requirements.txt > requirements_cleaned.txt && mv requirements_cleaned.txt requirements.txt
RUN pip install -r requirements.txt

WORKDIR /
Expand Down Expand Up @@ -139,6 +142,28 @@ WORKDIR /openms-streamlit-vue-component
RUN npm install
RUN npm run build

# Build the OpenMS-Insight Vue bundle and stage its source tree so the Python
# package can be installed (with the bundle baked in) in the run-app stage.
FROM node:21 AS oi-build

# OpenMS-Insight repo/branch providing the new visualization components. Defaults
# to the migration branch (its components are not yet in the PyPI release).
# Override via --build-arg once merged/released.
ARG OPENMS_INSIGHT_REPO=https://github.com/t0mdavid-m/OpenMS-Insight.git
ARG OPENMS_INSIGHT_BRANCH=claude/flashapp-openms-visualizations-LVv66

# Bust the build cache whenever the branch head moves.
ADD https://api.github.com/repos/t0mdavid-m/OpenMS-Insight/git/refs/heads/$OPENMS_INSIGHT_BRANCH oi-version.json

RUN git clone -b ${OPENMS_INSIGHT_BRANCH} --single-branch ${OPENMS_INSIGHT_REPO} /openms-insight
WORKDIR /openms-insight/js-component
RUN npm install
RUN npm run build
# The runtime bridge and wheel packaging expect the bundle at
# openms_insight/js-component/dist; place it there so pip install bundles it.
RUN mkdir -p /openms-insight/openms_insight/js-component \
&& cp -r /openms-insight/js-component/dist /openms-insight/openms_insight/js-component/dist

# Prepare and run streamlit app.
FROM compile-openms AS run-app

Expand Down Expand Up @@ -171,6 +196,14 @@ COPY presets.json /app/presets.json
# Copy the pre-built Vue/JS component (built in the js-build stage above).
COPY --from=js-build openms-streamlit-vue-component/dist /app/js-component/dist

# Install OpenMS-Insight (our branch build, with its freshly built Vue bundle)
# into the streamlit env. requirements.txt has openms-insight stripped, so this
# is the authoritative install providing the new visualization components. The
# package ships its Vue bundle at openms_insight/js-component/dist (staged in the
# oi-build stage), which the runtime bridge loads in production mode.
COPY --from=oi-build /openms-insight /opt/openms-insight
RUN mamba run -n streamlit-env pip install /opt/openms-insight

# add cron job to the crontab
RUN echo "0 3 * * * /root/miniforge3/envs/streamlit-env/bin/python /app/clean-up-workspaces.py >> /app/clean-up-workspaces.log 2>&1" | crontab -

Expand Down
8 changes: 5 additions & 3 deletions content/FLASHDeconv/FLASHDeconvLayoutManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,13 @@ def handleSettingButtons():

def setSequenceView():
if get_sequence() is not None:
# Parity with the TnT layout: `internal_fragment_map` was dropped because
# neither the legacy grid nor the OI viewer renders it (it produces
# nothing). Only the sequence view is added on sequence submission.
global COMPONENT_OPTIONS
COMPONENT_OPTIONS = COMPONENT_OPTIONS + ['Sequence view (Mass table needed)',
'Internal fragment map (Mass table needed)']
COMPONENT_OPTIONS = COMPONENT_OPTIONS + ['Sequence view (Mass table needed)']
global COMPONENT_NAMES
COMPONENT_NAMES = COMPONENT_NAMES + ['sequence_view', 'internal_fragment_map']
COMPONENT_NAMES = COMPONENT_NAMES + ['sequence_view']


# page initialization
Expand Down
68 changes: 53 additions & 15 deletions content/FLASHDeconv/FLASHDeconvViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,45 @@

from src.common.common import page_setup, save_params
from src.workflow.FileManager import FileManager
# Legacy bespoke-grid render path (kept importable until OI integration is verified).
from src.render.render import render_grid
# The OpenMS-Insight viewer (Stage B) is imported lazily inside render_panel (see
# below) so an import failure (e.g. a missing openms-insight install) falls back
# to the legacy grid instead of breaking the whole page.


def _use_oi_viewer():
return st.session_state.get("settings", {}).get(
"use_openms_insight_viewer", True
)


def render_panel(experiment_id, layout_info_per_exp, file_manager, identifier,
grid_key, panel_index):
"""Render one experiment panel via the configured viewer.

Routes to the new OpenMS-Insight viewer when enabled, else the legacy grid.
The OI viewer is imported lazily and guarded so an import failure falls back
to the legacy grid rather than breaking the page.
"""
if _use_oi_viewer():
try:
from content.FLASHDeconv.FLASHDeconvViewerOI import (
render_experiment_panel,
)
except Exception as exc: # noqa: BLE001 - OI viewer unavailable
st.warning(
f"OpenMS-Insight viewer unavailable ({exc}); using legacy grid."
)
else:
render_experiment_panel(
experiment_id, layout_info_per_exp, file_manager, panel_index
)
return
render_grid(
experiment_id, layout_info_per_exp, file_manager,
'flashdeconv', identifier, grid_key
)

DEFAULT_LAYOUT = [['ms1_deconv_heat_map'], ['scan_table', 'mass_table'],
['anno_spectrum', 'deconv_spectrum'], ['3D_SN_plot']]
Expand Down Expand Up @@ -84,9 +122,9 @@ def get_sequence():
on_change=select_experiment
)
if 'selected_experiment0' in st.session_state:
render_grid(
st.session_state.selected_experiment0, layout[0], file_manager,
'flashdeconv', "selected_experiment0", 'flash_viewer_grid_0'
render_panel(
st.session_state.selected_experiment0, layout[0], file_manager,
"selected_experiment0", 'flash_viewer_grid_0', panel_index=0
)
with c2:
st.selectbox(
Expand All @@ -97,10 +135,10 @@ def get_sequence():
)
if f"selected_experiment1" in st.session_state:
with st.spinner('Loading component...'):
render_grid(
st.session_state["selected_experiment1"], layout[1],
file_manager, 'flashdeconv', 'selected_experiment1',
'flash_viewer_grid_1'
render_panel(
st.session_state["selected_experiment1"], layout[1],
file_manager, 'selected_experiment1',
'flash_viewer_grid_1', panel_index=1
)

else:
Expand All @@ -114,9 +152,9 @@ def get_sequence():


if 'selected_experiment0' in st.session_state:
render_grid(
st.session_state.selected_experiment0, layout[0], file_manager,
'flashdeconv', 'selected_experiment0'
render_panel(
st.session_state.selected_experiment0, layout[0], file_manager,
'selected_experiment0', 'flash_viewer_grid', panel_index=0
)

### for multiple experiments on one view
Expand All @@ -135,11 +173,11 @@ def get_sequence():
)
# if #experiment input files are less than #layouts, all the pre-selection will be the first experiment
if f"selected_experiment{exp_index}" in st.session_state:
render_grid(
st.session_state["selected_experiment%d" % exp_index],
layout[exp_index], file_manager, 'flashdeconv',
"selected_experiment%d" % exp_index,
'flash_viewer_grid_%d' % exp_index
render_panel(
st.session_state["selected_experiment%d" % exp_index],
layout[exp_index], file_manager,
"selected_experiment%d" % exp_index,
'flash_viewer_grid_%d' % exp_index, panel_index=exp_index
)

save_params(params)
Loading
Loading