BrianIsaac commited on
Commit
47fd710
·
1 Parent(s): 4e50d9d

fix: resolve UI issues with landing page gap and missing loading overlay

Browse files

- Implement three-state page system (input → loading → results) with yield-based transitions
- Fix landing page gap by using align-items: flex-start on portfolio row
- Reduce preview-card min-height from 400px to 300px for better column alignment
- Add animated loading page component with rotating educational messages
- Configure show_progress="full" for prominent built-in progress indicator
- WebSocket deprecation warning suppression already in place (waiting for uvicorn update)

Files changed (1) hide show
  1. app.py +85 -5
app.py CHANGED
@@ -613,12 +613,44 @@ def create_interface() -> gr.Blocks:
613
  border: 1px solid rgba(255, 255, 255, 0.2);
614
  border-radius: 12px;
615
  padding: 1.5rem;
616
- min-height: 400px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
  display: flex;
618
  align-items: center;
619
  justify-content: center;
620
  }
621
 
 
 
 
 
 
 
 
 
 
 
 
622
  /* Example buttons styling */
623
  .gr-examples button {
624
  background: linear-gradient(135deg, rgba(4, 140, 252, 0.1), rgba(17, 199, 170, 0.1));
@@ -696,7 +728,7 @@ def create_interface() -> gr.Blocks:
696
  # Input Page with side-by-side layout
697
  with gr.Group(visible=True) as input_page:
698
  # Side-by-side input and preview
699
- with gr.Row():
700
  # Left column: Input
701
  with gr.Column(scale=1):
702
  portfolio_input = gr.Textbox(
@@ -773,6 +805,31 @@ def create_interface() -> gr.Blocks:
773
  """
774
  )
775
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
776
  # Results Page (unified dashboard)
777
  with gr.Group(visible=False) as results_page:
778
  with gr.Row():
@@ -811,14 +868,32 @@ def create_interface() -> gr.Blocks:
811
  }
812
 
813
  async def handle_analysis(portfolio_text, progress=gr.Progress()):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
814
  page, analysis, alloc, risk, perf, corr, opt = await run_analysis_with_ui_update(
815
  portfolio_text, progress
816
  )
817
 
 
818
  if page == "results":
819
- return {
820
  input_page: gr.update(visible=False),
 
821
  results_page: gr.update(visible=True),
 
822
  analysis_output: analysis,
823
  allocation_plot: alloc,
824
  risk_plot: risk,
@@ -827,9 +902,11 @@ def create_interface() -> gr.Blocks:
827
  optimization_plot: opt
828
  }
829
  else:
830
- return {
831
  input_page: gr.update(visible=True),
 
832
  results_page: gr.update(visible=False),
 
833
  analysis_output: analysis,
834
  allocation_plot: None,
835
  risk_plot: None,
@@ -850,14 +927,17 @@ def create_interface() -> gr.Blocks:
850
  inputs=[portfolio_input],
851
  outputs=[
852
  input_page,
 
853
  results_page,
 
854
  analysis_output,
855
  allocation_plot,
856
  risk_plot,
857
  performance_plot,
858
  correlation_plot,
859
  optimization_plot
860
- ]
 
861
  )
862
 
863
  new_analysis_btn.click(
 
613
  border: 1px solid rgba(255, 255, 255, 0.2);
614
  border-radius: 12px;
615
  padding: 1.5rem;
616
+ min-height: 300px;
617
+ display: flex;
618
+ align-items: center;
619
+ justify-content: center;
620
+ }
621
+
622
+ /* Portfolio row - natural heights without stretching */
623
+ .portfolio-row {
624
+ align-items: flex-start !important;
625
+ }
626
+
627
+ /* Loading page styling */
628
+ .loading-header {
629
+ animation: fadeIn 0.5s ease-in;
630
+ }
631
+
632
+ .loading-message {
633
+ text-align: center;
634
+ font-size: 1.1rem;
635
+ color: #048CFC;
636
+ padding: 2rem;
637
+ min-height: 100px;
638
  display: flex;
639
  align-items: center;
640
  justify-content: center;
641
  }
642
 
643
+ @keyframes fadeIn {
644
+ from {
645
+ opacity: 0;
646
+ transform: translateY(-10px);
647
+ }
648
+ to {
649
+ opacity: 1;
650
+ transform: translateY(0);
651
+ }
652
+ }
653
+
654
  /* Example buttons styling */
655
  .gr-examples button {
656
  background: linear-gradient(135deg, rgba(4, 140, 252, 0.1), rgba(17, 199, 170, 0.1));
 
728
  # Input Page with side-by-side layout
729
  with gr.Group(visible=True) as input_page:
730
  # Side-by-side input and preview
731
+ with gr.Row(equal_height=False, elem_classes="portfolio-row"):
732
  # Left column: Input
733
  with gr.Column(scale=1):
734
  portfolio_input = gr.Textbox(
 
805
  """
806
  )
807
 
808
+ # Loading Page
809
+ with gr.Group(visible=False) as loading_page:
810
+ with gr.Row():
811
+ with gr.Column():
812
+ gr.HTML(
813
+ """
814
+ <div style='text-align: center; padding: 4rem 2rem;'>
815
+ <div style='font-size: 3rem; margin-bottom: 1rem;'>⚡</div>
816
+ <h2 style='color: #048CFC; margin-bottom: 1rem;'>Analysing Your Portfolio</h2>
817
+ </div>
818
+ """,
819
+ elem_classes="loading-header"
820
+ )
821
+ loading_message = gr.Markdown(
822
+ value="Initialising analysis...",
823
+ elem_classes="loading-message",
824
+ )
825
+ gr.HTML(
826
+ """
827
+ <div style='text-align: center; padding: 2rem; color: #999; font-size: 14px;'>
828
+ <p>This may take a few seconds as we process real-time market data</p>
829
+ </div>
830
+ """
831
+ )
832
+
833
  # Results Page (unified dashboard)
834
  with gr.Group(visible=False) as results_page:
835
  with gr.Row():
 
868
  }
869
 
870
  async def handle_analysis(portfolio_text, progress=gr.Progress()):
871
+ # Show loading page immediately
872
+ yield {
873
+ input_page: gr.update(visible=False),
874
+ loading_page: gr.update(visible=True),
875
+ results_page: gr.update(visible=False),
876
+ loading_message: random.choice(LOADING_MESSAGES),
877
+ analysis_output: "",
878
+ allocation_plot: None,
879
+ risk_plot: None,
880
+ performance_plot: None,
881
+ correlation_plot: None,
882
+ optimization_plot: None
883
+ }
884
+
885
+ # Run analysis with progress updates
886
  page, analysis, alloc, risk, perf, corr, opt = await run_analysis_with_ui_update(
887
  portfolio_text, progress
888
  )
889
 
890
+ # Show results or return to input
891
  if page == "results":
892
+ yield {
893
  input_page: gr.update(visible=False),
894
+ loading_page: gr.update(visible=False),
895
  results_page: gr.update(visible=True),
896
+ loading_message: "Analysis complete!",
897
  analysis_output: analysis,
898
  allocation_plot: alloc,
899
  risk_plot: risk,
 
902
  optimization_plot: opt
903
  }
904
  else:
905
+ yield {
906
  input_page: gr.update(visible=True),
907
+ loading_page: gr.update(visible=False),
908
  results_page: gr.update(visible=False),
909
+ loading_message: "",
910
  analysis_output: analysis,
911
  allocation_plot: None,
912
  risk_plot: None,
 
927
  inputs=[portfolio_input],
928
  outputs=[
929
  input_page,
930
+ loading_page,
931
  results_page,
932
+ loading_message,
933
  analysis_output,
934
  allocation_plot,
935
  risk_plot,
936
  performance_plot,
937
  correlation_plot,
938
  optimization_plot
939
+ ],
940
+ show_progress="full"
941
  )
942
 
943
  new_analysis_btn.click(