Skip to content

Commit 8a2cb90

Browse files
authored
Merge pull request #73 from amito/bugfix/ui-navigation
Fix navigation between tabs in UI
2 parents 1192ce6 + 95f6bdf commit 8a2cb90

File tree

1 file changed

+101
-95
lines changed

1 file changed

+101
-95
lines changed

ui/app.py

Lines changed: 101 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,11 @@ def format_display_name(raw_name: str) -> str:
14971497
st.session_state.slo_approved = None
14981498
if "edited_extraction" not in st.session_state:
14991499
st.session_state.edited_extraction = None
1500+
# Tab switching flags
1501+
if "switch_to_tab2" not in st.session_state:
1502+
st.session_state.switch_to_tab2 = False
1503+
if "switch_to_tab3" not in st.session_state:
1504+
st.session_state.switch_to_tab3 = False
15001505
# Editable SLO values
15011506
if "edit_slo" not in st.session_state:
15021507
st.session_state.edit_slo = False
@@ -4212,7 +4217,44 @@ def main():
42124217
with tab4:
42134218
render_about_section(models_df)
42144219

4215-
4220+
# Handle tab switching after approval
4221+
if st.session_state.get('switch_to_tab2', False):
4222+
st.session_state.switch_to_tab2 = False
4223+
import streamlit.components.v1 as components
4224+
components.html("""
4225+
<script>
4226+
setTimeout(function() {
4227+
const tabs = window.parent.document.querySelectorAll('[data-baseweb="tab"]');
4228+
if (tabs.length > 1) tabs[1].click();
4229+
}, 100);
4230+
</script>
4231+
""", height=0)
4232+
4233+
if st.session_state.get('switch_to_tab3', False):
4234+
st.session_state.switch_to_tab3 = False
4235+
import streamlit.components.v1 as components
4236+
components.html("""
4237+
<script>
4238+
setTimeout(function() {
4239+
const tabs = window.parent.document.querySelectorAll('[data-baseweb="tab"]');
4240+
if (tabs.length > 2) tabs[2].click();
4241+
}, 100);
4242+
</script>
4243+
""", height=0)
4244+
4245+
if st.session_state.get('switch_to_tab1', False):
4246+
st.session_state.switch_to_tab1 = False
4247+
import streamlit.components.v1 as components
4248+
components.html("""
4249+
<script>
4250+
setTimeout(function() {
4251+
const tabs = window.parent.document.querySelectorAll('[data-baseweb="tab"]');
4252+
if (tabs.length > 0) tabs[0].click();
4253+
}, 100);
4254+
</script>
4255+
""", height=0)
4256+
4257+
42164258
def render_use_case_input_tab(priority: str, models_df: pd.DataFrame):
42174259
"""Tab 1: Use case input interface."""
42184260

@@ -4223,40 +4265,62 @@ def clear_dialog_states():
42234265
st.session_state.show_winner_dialog = False
42244266
st.session_state.show_options_list_expanded = False
42254267

4268+
# Transfer pending input from button clicks before rendering the text_area widget
4269+
if "pending_user_input" in st.session_state:
4270+
st.session_state.user_input = st.session_state.pending_user_input
4271+
del st.session_state.pending_user_input
4272+
42264273
st.markdown('<div class="section-header">Describe your use case or select from 9 predefined scenarios</div>', unsafe_allow_html=True)
42274274

4275+
# Input area with validation
4276+
st.markdown('<div class="input-container">', unsafe_allow_html=True)
4277+
st.text_area(
4278+
"Your requirements:",
4279+
key="user_input",
4280+
height=120,
4281+
max_chars=2000, # Corporate standard: limit input length
4282+
placeholder="Describe your LLM use case in natural language...\n\nExample: I need a chatbot for customer support with 30 users. Low latency is important, and we have H100 GPUs available.",
4283+
label_visibility="collapsed"
4284+
)
4285+
st.markdown('</div>', unsafe_allow_html=True)
4286+
42284287
# Row 1: 5 task buttons
42294288
col1, col2, col3, col4, col5 = st.columns(5)
42304289

42314290
with col1:
42324291
if st.button("Chat Completion", use_container_width=True, key="task_chat"):
42334292
clear_dialog_states()
42344293
# Simple prompt - no priority, no hardware = show all configs
4235-
st.session_state.user_input = "Customer service chatbot for 300 users."
4294+
st.session_state.pending_user_input = "Customer service chatbot for 30 users."
4295+
st.rerun()
42364296

42374297
with col2:
42384298
if st.button("Code Completion", use_container_width=True, key="task_code"):
42394299
clear_dialog_states()
42404300
# Simple prompt - no priority, no hardware = show all configs
4241-
st.session_state.user_input = "IDE code completion tool for 300 developers."
4301+
st.session_state.pending_user_input = "IDE code completion tool for 300 developers."
4302+
st.rerun()
42424303

42434304
with col3:
42444305
if st.button("Document Q&A", use_container_width=True, key="task_rag"):
42454306
clear_dialog_states()
42464307
# Simple prompt - no priority, no hardware = show all configs
4247-
st.session_state.user_input = "Document Q&A system for enterprise knowledge base, 300 users."
4308+
st.session_state.pending_user_input = "Document Q&A system for enterprise knowledge base, 300 users."
4309+
st.rerun()
42484310

42494311
with col4:
42504312
if st.button("Summarization", use_container_width=True, key="task_summ"):
42514313
clear_dialog_states()
42524314
# With priority (cost-effective) to show filtering
4253-
st.session_state.user_input = "News article summarization for 300 users, cost-effective solution preferred."
4315+
st.session_state.pending_user_input = "News article summarization for 300 users, cost-effective solution preferred."
4316+
st.rerun()
42544317

42554318
with col5:
42564319
if st.button("Legal Analysis", use_container_width=True, key="task_legal"):
42574320
clear_dialog_states()
42584321
# With priority (accuracy) to show filtering
4259-
st.session_state.user_input = "Legal document analysis for 300 lawyers, accuracy is critical."
4322+
st.session_state.pending_user_input = "Legal document analysis for 300 lawyers, accuracy is critical."
4323+
st.rerun()
42604324

42614325
# Row 2: 4 more task buttons
42624326
col6, col7, col8, col9 = st.columns(4)
@@ -4265,48 +4329,40 @@ def clear_dialog_states():
42654329
if st.button("Translation", use_container_width=True, key="task_trans"):
42664330
clear_dialog_states()
42674331
# Simple prompt - no priority, no hardware = show all configs
4268-
st.session_state.user_input = "Multi-language translation service for 300 users."
4332+
st.session_state.pending_user_input = "Multi-language translation service for 300 users."
4333+
st.rerun()
42694334

42704335
with col7:
42714336
if st.button("Content Generation", use_container_width=True, key="task_content"):
42724337
clear_dialog_states()
42734338
# Simple prompt - no priority, no hardware = show all configs
4274-
st.session_state.user_input = "Content generation tool for marketing team, 300 users."
4339+
st.session_state.pending_user_input = "Content generation tool for marketing team, 300 users."
4340+
st.rerun()
42754341

42764342
with col8:
42774343
if st.button("Long Doc Summary", use_container_width=True, key="task_longdoc"):
42784344
clear_dialog_states()
42794345
# With priority (accuracy) to show filtering
4280-
st.session_state.user_input = "Long document summarization for research papers, 300 researchers, accuracy matters."
4346+
st.session_state.user_input = "Long document summarization for research papers, 30 researchers, accuracy matters."
4347+
st.rerun()
42814348

42824349
with col9:
42834350
if st.button("Code Generation", use_container_width=True, key="task_codegen"):
42844351
clear_dialog_states()
42854352
# Simple prompt - no priority, no hardware = show all configs
4286-
st.session_state.user_input = "Full code generation tool for implementing features, 300 developers."
4287-
4288-
# Input area with validation
4289-
st.markdown('<div class="input-container">', unsafe_allow_html=True)
4290-
user_input = st.text_area(
4291-
"Your requirements:",
4292-
value=st.session_state.user_input,
4293-
height=120,
4294-
max_chars=2000, # Corporate standard: limit input length
4295-
placeholder="Describe your LLM use case in natural language...\n\nExample: I need a chatbot for customer support with 300 users. Low latency is important, and we have H100 GPUs available.",
4296-
label_visibility="collapsed"
4297-
)
4298-
st.markdown('</div>', unsafe_allow_html=True)
4353+
st.session_state.user_input = "Full code generation tool for implementing features, 30 developers."
4354+
st.rerun()
42994355

43004356
# Show character count - white text
4301-
char_count = len(user_input) if user_input else 0
4357+
char_count = len(st.session_state.user_input) if st.session_state.user_input else 0
43024358
st.markdown(f'<div style="text-align: right; font-size: 0.75rem; color: white; margin-top: -0.5rem;">{char_count}/2000 characters</div>', unsafe_allow_html=True)
43034359

43044360
col1, col2, col3 = st.columns([1.5, 1, 2])
43054361
with col1:
43064362
# Disable button if input is too short
4307-
analyze_disabled = len(user_input.strip()) < 10 if user_input else True
4363+
analyze_disabled = len(st.session_state.user_input.strip()) < 10 if st.session_state.user_input else True
43084364
analyze_clicked = st.button("Analyze & Recommend", type="primary", use_container_width=True, disabled=analyze_disabled)
4309-
if analyze_disabled and user_input and len(user_input.strip()) < 10:
4365+
if analyze_disabled and st.session_state.user_input and len(st.session_state.user_input.strip()) < 10:
43104366
st.caption("Please enter at least 10 characters")
43114367
with col2:
43124368
if st.button("Clear", use_container_width=True):
@@ -4320,8 +4376,7 @@ def clear_dialog_states():
43204376
st.rerun()
43214377

43224378
# Input validation before analysis
4323-
if analyze_clicked and user_input and len(user_input.strip()) >= 10:
4324-
st.session_state.user_input = user_input
4379+
if analyze_clicked and st.session_state.user_input and len(st.session_state.user_input.strip()) >= 10:
43254380
# Reset workflow state
43264381
st.session_state.extraction_approved = None
43274382
st.session_state.slo_approved = None
@@ -4335,7 +4390,7 @@ def clear_dialog_states():
43354390

43364391
try:
43374392
progress_bar.progress(20, text="Analyzing input text...")
4338-
extraction = extract_business_context(user_input)
4393+
extraction = extract_business_context(st.session_state.user_input)
43394394
progress_bar.progress(80, text="Extraction complete!")
43404395

43414396
if extraction:
@@ -4416,22 +4471,12 @@ def clear_dialog_states():
44164471
if st.session_state.extraction_approved == True:
44174472
render_extraction_result(st.session_state.extraction_result, used_priority)
44184473

4419-
# Left-aligned completion banner and button
4420-
col_btns, col_space = st.columns([2, 2])
4421-
with col_btns:
4422-
st.markdown("""
4423-
<div style="background: #EE0000; color: white; padding: 0.75rem 1rem; border-radius: 8px; font-size: 1rem; margin-bottom: 0.75rem;">
4424-
<strong>Step 1 Complete</strong> · Go to Technical Specification
4425-
</div>
4426-
""", unsafe_allow_html=True)
4427-
if st.button("Next Tab →", key="next_tab_1", type="primary", use_container_width=True):
4428-
import streamlit.components.v1 as components
4429-
components.html("""
4430-
<script>
4431-
const tabs = window.parent.document.querySelectorAll('[data-baseweb="tab"]');
4432-
if (tabs.length > 1) tabs[1].click();
4433-
</script>
4434-
""", height=0)
4474+
# Completion banner (tab auto-advances on approval)
4475+
st.markdown("""
4476+
<div style="background: #EE0000; color: white; padding: 0.75rem 1rem; border-radius: 8px; font-size: 1rem; margin-bottom: 0.75rem; max-width: 50%;">
4477+
<strong>Step 1 Complete</strong> · You can now go to Technical Specification
4478+
</div>
4479+
""", unsafe_allow_html=True)
44354480

44364481

44374482
def render_technical_specs_tab(priority: str, models_df: pd.DataFrame):
@@ -4455,22 +4500,12 @@ def render_technical_specs_tab(priority: str, models_df: pd.DataFrame):
44554500

44564501
# If SLO approved, show navigation message
44574502
if st.session_state.slo_approved == True:
4458-
# Left-aligned completion banner and button
4459-
col_btns2, col_space2 = st.columns([2, 2])
4460-
with col_btns2:
4461-
st.markdown("""
4462-
<div style="background: #EE0000; color: white; padding: 0.75rem 1rem; border-radius: 8px; font-size: 1rem; margin-bottom: 0.75rem;">
4463-
<strong>Step 2 Complete</strong> · Go to Recommendations
4464-
</div>
4465-
""", unsafe_allow_html=True)
4466-
if st.button("Next Tab →", key="next_tab_2", type="primary", use_container_width=True):
4467-
import streamlit.components.v1 as components
4468-
components.html("""
4469-
<script>
4470-
const tabs = window.parent.document.querySelectorAll('[data-baseweb="tab"]');
4471-
if (tabs.length > 2) tabs[2].click();
4472-
</script>
4473-
""", height=0)
4503+
# Completion banner (tab auto-advances on approval)
4504+
st.markdown("""
4505+
<div style="background: #EE0000; color: white; padding: 0.75rem 1rem; border-radius: 8px; font-size: 1rem; margin-bottom: 0.75rem; max-width: 50%;">
4506+
<strong>Step 2 Complete</strong> · You can now view Recommendations
4507+
</div>
4508+
""", unsafe_allow_html=True)
44744509

44754510

44764511
def render_results_tab(priority: str, models_df: pd.DataFrame):
@@ -4647,6 +4682,7 @@ def render_extraction_with_approval(extraction: dict, models_df: pd.DataFrame):
46474682
with col1:
46484683
if st.button("Yes, Continue", type="primary", use_container_width=True, key="approve_extraction"):
46494684
st.session_state.extraction_approved = True
4685+
st.session_state.switch_to_tab2 = True
46504686
st.rerun()
46514687
with col2:
46524688
if st.button("No, Edit", use_container_width=True, key="edit_extraction"):
@@ -4879,6 +4915,7 @@ def render_slo_with_approval(extraction: dict, priority: str, models_df: pd.Data
48794915
# Button disabled if invalid
48804916
if st.button("Generate Recommendations", type="primary", use_container_width=True, key="generate_recs", disabled=not is_valid):
48814917
st.session_state.slo_approved = True
4918+
st.session_state.switch_to_tab3 = True
48824919
st.rerun()
48834920

48844921

@@ -4989,30 +5026,12 @@ def render_recommendation_result(result: dict, priority: str, extraction: dict):
49895026
</div>
49905027
""", unsafe_allow_html=True)
49915028

4992-
# Show buttons to go back or start new case
4993-
col_back, col_new, col_spacer = st.columns([1, 1, 2])
4994-
with col_back:
4995-
if st.button("← Back to Technical Specs", key="back_to_slo", type="primary", use_container_width=True):
4996-
# Reset dialog states to prevent popups
4997-
st.session_state.show_category_dialog = False
4998-
st.session_state.show_full_table_dialog = False
4999-
st.session_state.show_winner_dialog = False
5000-
st.session_state.show_options_list_expanded = False
5001-
st.session_state.explore_category = None
5002-
# Keep slo_approved as True - user can adjust SLOs and click "Generate Recommendations" again
5003-
# The Recommendations tab will regenerate with new values when they return
5004-
# Use JavaScript to switch to Technical Specification tab
5005-
import streamlit.components.v1 as components
5006-
components.html("""
5007-
<script>
5008-
const tabs = window.parent.document.querySelectorAll('[data-baseweb="tab"]');
5009-
if (tabs.length > 1) tabs[1].click();
5010-
</script>
5011-
""", height=0)
5012-
5029+
# Show button to start new case
5030+
col_new, col_spacer = st.columns([1, 3])
5031+
50135032
with col_new:
50145033
if st.button("New Case", key="new_case_btn", type="secondary", use_container_width=True):
5015-
# Complete session state reset - start fresh from Tab 1
5034+
# Complete session state reset - start fresh from Define Use Case tab
50165035
keys_to_clear = [
50175036
'user_input', 'extraction_result', 'recommendation_result',
50185037
'extraction_approved', 'slo_approved', 'edited_extraction',
@@ -5028,19 +5047,6 @@ def render_recommendation_result(result: dict, priority: str, extraction: dict):
50285047
# Set flag to switch to Tab 1 after rerun
50295048
st.session_state.switch_to_tab1 = True
50305049
st.rerun()
5031-
5032-
# Check if we need to switch to Tab 1 (after New Case button)
5033-
if st.session_state.get('switch_to_tab1', False):
5034-
st.session_state.switch_to_tab1 = False
5035-
import streamlit.components.v1 as components
5036-
components.html("""
5037-
<script>
5038-
setTimeout(function() {
5039-
const tabs = window.parent.document.querySelectorAll('[data-baseweb="tab"]');
5040-
if (tabs.length > 0) tabs[0].click();
5041-
}, 100);
5042-
</script>
5043-
""", height=0)
50445050

50455051

50465052
def _render_winner_details(winner: dict, priority: str, extraction: dict):

0 commit comments

Comments
 (0)