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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
67 changes: 57 additions & 10 deletions content/FLASHDeconv/FLASHDeconvDownload.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

file_manager = FileManager(
st.session_state["workspace"],
Path(st.session_state['workspace'], 'flashdeconv', 'cache')
Path(st.session_state['workspace'], 'cache')
)

targets = [
Expand All @@ -30,18 +30,64 @@
st.error('No results to show yet. Please run a workflow first!')
else:
# Table Header
columns = st.columns(3)
columns[0].write('**Run**')
columns = st.columns([1.1, 1, 1])
columns[0].write('**Name**')
columns[1].write('**Download**')
columns[2].write('**Delete Result Set**')

# Table Body
for i, experiment in enumerate(experiments):
st.divider()
columns = st.columns(3)
columns[0].empty().write(experiment)
columns = st.columns([0.1, 1, 1, 1])
current_name = file_manager.get_display_name(experiment)

# Initialize edit mode session state for this experiment
edit_mode_key = f"edit_mode_{experiment}"
if edit_mode_key not in st.session_state:
st.session_state[edit_mode_key] = False

# Display Name or Edit Input
with columns[1]:
if st.session_state[edit_mode_key]:
# Edit mode: Show text input with current display name
new_name = st.text_input(
"New name",
value=current_name,
key=f"input_{experiment}",
label_visibility="collapsed"
)
else:
st.write(current_name)

# Edit/Save Button
with columns[0]:
if st.session_state[edit_mode_key]:
# Show save button in edit mode
if st.button("💾", key=f"save_{experiment}", help="Save new name", use_container_width=True):
new_name = st.session_state.get(f"input_{experiment}", "").strip()

# Validate input
if not new_name:
st.error("Name cannot be empty")
elif len(new_name) > 100:
st.error("Name is too long (max 100 characters)")
else:
# Attempt to rename
success = file_manager.rename_dataset(experiment, new_name)
if success:
st.success(f"Renamed to: {new_name}")
st.session_state[edit_mode_key] = False
st.rerun()
else:
st.error("Failed to rename dataset")
else:
# Show edit button in normal mode
if st.button("✏️", key=f"edit_{experiment}", help="Edit name", use_container_width=True):
st.session_state[edit_mode_key] = True
st.rerun()

# Download
with columns[2]:
button_placeholder = st.empty()

# Show placeholder button before download is prepared
Expand All @@ -55,8 +101,8 @@
):
zip_buffer = BytesIO()
with ZipFile(zip_buffer, 'w', ZIP_DEFLATED) as f:
for filepath in file_manager.get_results(
experiment, targets, partial=True
for filepath in file_manager.get_all_files_except(
experiment, ['download_archive']
).values():
f.write(filepath, arcname=Path(filepath).name)
zip_buffer.seek(0)
Expand All @@ -71,11 +117,12 @@
with open(out_zip, 'rb') as f:
button_placeholder.download_button(
"Download ⬇️", f,
file_name = f'{experiment}.zip',
file_name = f'{current_name}.zip',
use_container_width=True
)

with columns[2]:
if st.button(f"🗑️ {experiment}", use_container_width=True):
# Delete
with columns[3]:
if st.button(f"🗑️ {current_name}", use_container_width=True):
file_manager.remove_results(experiment)
st.rerun()
2 changes: 1 addition & 1 deletion content/FLASHDeconv/FLASHDeconvSequenceInput.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Setup cache access
file_manager = FileManager(
st.session_state["workspace"],
Path(st.session_state['workspace'], 'flashdeconv', 'cache')
Path(st.session_state['workspace'], 'cache')
)

def set_sequence(input_sequence, fixed_mod_cysteine=None, fixed_mod_methionine=None):
Expand Down
32 changes: 20 additions & 12 deletions content/FLASHDeconv/FLASHDeconvViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,22 @@
['anno_spectrum', 'deconv_spectrum'], ['3D_SN_plot']]

def select_experiment():
st.session_state.selected_experiment0 = st.session_state.selected_experiment_dropdown
# Map display name back to experiment ID
st.session_state.selected_experiment0 = display_name_to_id[st.session_state.selected_experiment_dropdown]
if len(layout) > 1:
for exp_index in range(1, len(layout)):
if st.session_state[f'selected_experiment_dropdown_{exp_index}'] is None:
continue
st.session_state[f"selected_experiment{exp_index}"] = st.session_state[f'selected_experiment_dropdown_{exp_index}']
st.session_state[f"selected_experiment{exp_index}"] = display_name_to_id[st.session_state[f'selected_experiment_dropdown_{exp_index}']]

def validate_selected_index(file_manager, selected_experiment):
results = file_manager.get_results_list(['deconv_dfs', 'anno_dfs'])
if selected_experiment in st.session_state:
if st.session_state[selected_experiment] in results:
return name_to_index[st.session_state[selected_experiment]]
# Map experiment ID to display name for the dropdown index
exp_id = st.session_state[selected_experiment]
display_name = file_manager.get_display_name(exp_id)
return display_name_to_index[display_name]
else:
del st.session_state[selected_experiment]
return None
Expand All @@ -32,7 +36,7 @@ def validate_selected_index(file_manager, selected_experiment):
# Get available results
file_manager = FileManager(
st.session_state["workspace"],
Path(st.session_state['workspace'], 'flashdeconv', 'cache')
Path(st.session_state['workspace'], 'cache')
)

def get_sequence():
Expand All @@ -47,7 +51,7 @@ def get_sequence():
if get_sequence() is not None:
DEFAULT_LAYOUT = DEFAULT_LAYOUT + [['sequence_view']]

results = file_manager.get_results_list(['deconv_dfs', 'anno_dfs'])
results = file_manager.get_results_list(['threedim_SN_plot'])

if file_manager.result_exists('layout', 'layout'):
layout = file_manager.get_results('layout', 'layout')['layout']
Expand All @@ -63,15 +67,19 @@ def get_sequence():
st.error('No results to show yet. Please run a workflow first!')
st.stop()

# Map names to index
# Create display names and mappings
display_names = [file_manager.get_display_name(exp_id) for exp_id in results]
display_name_to_id = {file_manager.get_display_name(exp_id): exp_id for exp_id in results}
display_name_to_index = {n : i for i, n in enumerate(display_names)}
# Keep backward compatibility mapping for experiment IDs
Comment on lines +70 to +74
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Duplicate display names hijack viewer selections.

Here too we key both display_name_to_id and display_name_to_index by the human-friendly label. If two runs share the same name (perfectly possible after renaming), the later entry clobbers the earlier one. The dropdown then always resolves to the last dataset with that label, so the wrong experiment loads and previously stored selections jump indices. Please keep the dataset ID as the canonical option value—e.g. pass results to the selectbox and supply a format_func that renders file_manager.get_display_name(exp_id)—or otherwise guarantee uniqueness when building the mapping.

🤖 Prompt for AI Agents
In content/FLASHDeconv/FLASHDeconvViewer.py around lines 70-74, the mappings use
human-friendly display names as keys which allows duplicate names to clobber
earlier entries; change the select/options to use the canonical experiment ID as
the option value (i.e. use results list/IDs as the selectbox values) and render
the label with a format_func that calls file_manager.get_display_name(exp_id),
or alternatively build maps keyed by exp_id (display_name_to_id =>
id->display_name and display_name_to_index => id->index) so every option is
unique and selections reliably map back to the correct experiment ID.

name_to_index = {n : i for i, n in enumerate(results)}

if len(layout) == 2 and side_by_side:
c1, c2 = st.columns(2)
with c1:
st.selectbox(
"choose experiment", results,
key="selected_experiment_dropdown",
"choose experiment", display_names,
key="selected_experiment_dropdown",
index=validate_selected_index(file_manager, 'selected_experiment0'),
on_change=select_experiment
)
Expand All @@ -82,7 +90,7 @@ def get_sequence():
)
with c2:
st.selectbox(
"choose experiment", results,
"choose experiment", display_names,
key=f'selected_experiment_dropdown_1',
index=validate_selected_index(file_manager, 'selected_experiment1'),
on_change=select_experiment
Expand All @@ -98,8 +106,8 @@ def get_sequence():
else:
### for only single experiment on one view
st.selectbox(
"choose experiment", results,
key="selected_experiment_dropdown",
"choose experiment", display_names,
key="selected_experiment_dropdown",
index=validate_selected_index(file_manager, 'selected_experiment0'),
on_change=select_experiment
)
Expand All @@ -120,7 +128,7 @@ def get_sequence():
st.divider() # horizontal line

st.selectbox(
"choose experiment", results,
"choose experiment", display_names,
key=f'selected_experiment_dropdown_{exp_index}',
index=validate_selected_index(file_manager, f'selected_experiment{exp_index}'),
on_change=select_experiment
Expand Down
72 changes: 58 additions & 14 deletions content/FLASHTnT/FLASHTnTDownload.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@

file_manager = FileManager(
st.session_state["workspace"],
Path(st.session_state['workspace'], 'flashtnt', 'cache')
Path(st.session_state['workspace'], 'cache')
)

targets = [
'out_tsv', 'spec1_tsv', 'spec2_tsv', 'spec3_tsv', 'spec4_tsv', 'quant_tsv',
'toppic_ms1_msalign', 'toppic_ms1_feature', 'toppic_ms2_msalign',
'toppic_ms2_feature', 'out_deconv_mzML', 'anno_annotated_mzML',
'FD_parameters_json', 'FTnT_parameters_json', 'tags_tsv', 'protein_tsv'
'FTnT_parameters_json', 'tags_tsv', 'protein_tsv'
]
experiments = file_manager.get_results_list(targets, partial=True)

Expand All @@ -30,18 +27,64 @@
st.error('No results to show yet. Please run a workflow first!')
else:
# Table Header
columns = st.columns(3)
columns[0].write('**Run**')
columns = st.columns([1.1, 1, 1])
columns[0].write('**Name**')
columns[1].write('**Download**')
columns[2].write('**Delete Result Set**')

# Table Body
for i, experiment in enumerate(experiments):
st.divider()
columns = st.columns(3)
columns[0].empty().write(experiment)
columns = st.columns([0.1, 1, 1, 1])
current_name = file_manager.get_display_name(experiment)

# Initialize edit mode session state for this experiment
edit_mode_key = f"edit_mode_{experiment}"
if edit_mode_key not in st.session_state:
st.session_state[edit_mode_key] = False

# Display Name or Edit Input
with columns[1]:
if st.session_state[edit_mode_key]:
# Edit mode: Show text input with current display name
new_name = st.text_input(
"New name",
value=current_name,
key=f"input_{experiment}",
label_visibility="collapsed"
)
else:
st.write(current_name)

# Edit/Save Button
with columns[0]:
if st.session_state[edit_mode_key]:
# Show save button in edit mode
if st.button("💾", key=f"save_{experiment}", help="Save new name", use_container_width=True):
new_name = st.session_state.get(f"input_{experiment}", "").strip()

# Validate input
if not new_name:
st.error("Name cannot be empty")
elif len(new_name) > 100:
st.error("Name is too long (max 100 characters)")
else:
# Attempt to rename
success = file_manager.rename_dataset(experiment, new_name)
if success:
st.success(f"Renamed to: {new_name}")
st.session_state[edit_mode_key] = False
st.rerun()
else:
st.error("Failed to rename dataset")
else:
# Show edit button in normal mode
if st.button("✏️", key=f"edit_{experiment}", help="Edit name", use_container_width=True):
st.session_state[edit_mode_key] = True
st.rerun()

# Download
with columns[2]:
button_placeholder = st.empty()

# Show placeholder button before download is prepared
Expand All @@ -55,8 +98,8 @@
):
zip_buffer = BytesIO()
with ZipFile(zip_buffer, 'w', ZIP_DEFLATED) as f:
for filepath in file_manager.get_results(
experiment, targets, partial=True
for filepath in file_manager.get_all_files_except(
experiment, ['download_archive']
).values():
f.write(filepath, arcname=Path(filepath).name)
zip_buffer.seek(0)
Expand All @@ -71,11 +114,12 @@
with open(out_zip, 'rb') as f:
button_placeholder.download_button(
"Download ⬇️", f,
file_name = f'{experiment}.zip',
file_name = f'{current_name}.zip',
use_container_width=True
)

with columns[2]:
if st.button(f"🗑️ {experiment}", use_container_width=True):
# Delete
with columns[3]:
if st.button(f"🗑️ {current_name}", use_container_width=True):
file_manager.remove_results(experiment)
st.rerun()
Loading