GuglielmoTor commited on
Commit
d3914e5
·
verified ·
1 Parent(s): e5163d2

Create dashboard_sync_handlers.py

Browse files
Files changed (1) hide show
  1. services/dashboard_sync_handlers.py +147 -0
services/dashboard_sync_handlers.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # handlers/dashboard_sync_handlers.py
2
+ import gradio as gr
3
+ import logging
4
+
5
+ # Assuming these functions are in the specified paths and are importable
6
+ from services.state_manager import process_and_store_bubble_token
7
+ from services.sync_logic import sync_all_linkedin_data_orchestrator
8
+ from ui.ui_generators import display_main_dashboard
9
+
10
+ class DashboardSyncHandlers:
11
+ def __init__(self, dashboard_components, token_state_ref, url_user_token_display_ref, org_urn_display_ref, status_box_ref):
12
+ self.components = dashboard_components
13
+ self.token_state = token_state_ref # gr.State object
14
+ self.url_user_token_display = url_user_token_display_ref # gr.Textbox object
15
+ self.org_urn_display = org_urn_display_ref # gr.Textbox object
16
+ self.status_box = status_box_ref # gr.Textbox object
17
+
18
+ logging.info("DashboardSyncHandlers initialized.")
19
+
20
+ def initial_load_sequence(self, url_token, org_urn_val, current_token_state_value):
21
+ """
22
+ Handles the initial loading sequence after URL parameters are fetched.
23
+ This is called by app.load().then() or org_urn_display.change().
24
+ """
25
+ logging.info(f"Initial load sequence triggered. URL Token: {'Set' if url_token else 'Not Set'}, Org URN: {org_urn_val}")
26
+
27
+ # process_and_store_bubble_token is expected to return:
28
+ # status_msg, new_state_dict, btn_update_dict (for sync_data_btn)
29
+ status_msg, new_state_dict, btn_update_dict = process_and_store_bubble_token(
30
+ url_token,
31
+ org_urn_val,
32
+ current_token_state_value # Pass the current value of the state
33
+ )
34
+
35
+ # display_main_dashboard expects the new state dictionary
36
+ dashboard_content_html = display_main_dashboard(new_state_dict)
37
+
38
+ # Returns:
39
+ # 1. Update for status_box (value)
40
+ # 2. New value for token_state (this will update the gr.State object)
41
+ # 3. Update for sync_data_btn (e.g., gr.update(visible=True, interactive=True))
42
+ # 4. Update for dashboard_display_html (value)
43
+ return status_msg, new_state_dict, btn_update_dict, dashboard_content_html
44
+
45
+ async def trigger_sync_and_refresh(self, current_token_state_value, url_token, org_urn_val):
46
+ """
47
+ Orchestrates the full sync process when the sync button is clicked.
48
+ This combines sync_all_linkedin_data_orchestrator and subsequent updates.
49
+ Yields updates for a chained sequence.
50
+ """
51
+ logging.info("Sync data button clicked. Starting sync process.")
52
+
53
+ # Part 1: sync_all_linkedin_data_orchestrator
54
+ # Expected to return: html_status_update_str, updated_token_state_dict
55
+ sync_status_html, updated_token_state_after_sync = await sync_all_linkedin_data_orchestrator(current_token_state_value)
56
+ yield sync_status_html, updated_token_state_after_sync # Updates sync_status_html_output, token_state
57
+
58
+ # Part 2: process_and_store_bubble_token again with potentially updated token_state
59
+ # This ensures the state is consistent after sync and reflects any new data fetched by sync_all_linkedin_data_orchestrator
60
+ # It might also re-evaluate if sync button should be visible/interactive
61
+ status_msg_after_sync, final_token_state_dict, sync_btn_update_after_sync = process_and_store_bubble_token(
62
+ url_token, # url_token and org_urn_val might be stale if not re-fetched, but usually static for a session
63
+ org_urn_val,
64
+ updated_token_state_after_sync # Use the state updated by sync_all_linkedin_data_orchestrator
65
+ )
66
+ yield status_msg_after_sync, final_token_state_dict, sync_btn_update_after_sync # Updates status_box, token_state, sync_data_btn
67
+
68
+ # Part 3: Refresh dashboard display
69
+ dashboard_html_after_sync = display_main_dashboard(final_token_state_dict)
70
+ yield dashboard_html_after_sync # Updates dashboard_display_html
71
+
72
+ # The subsequent calls to refresh_analytics_graphs_ui and run_agentic_pipeline_autonomously
73
+ # will be chained in app.py using .then() on this sync event, using the updated token_state.
74
+
75
+ def setup_event_handlers(self, initial_load_trigger_component, agentic_handlers_ref, analytics_handlers_ref):
76
+ """
77
+ Sets up event handlers for the dashboard and sync tab.
78
+ initial_load_trigger_component is typically org_urn_display.
79
+ """
80
+ logging.info("Setting up dashboard/sync event handlers.")
81
+
82
+ # Initial load sequence
83
+ # This is more complex due to the chained .then() calls for analytics and agentic pipeline
84
+ # The main app.py will handle the .then() chaining. This handler provides the core functions.
85
+ # The initial_load_sequence method itself will be the 'fn' for the first .change() or .load().
86
+
87
+ # Sync button click
88
+ # The sync_data_btn.click event will also have .then() chains in app.py
89
+ # We define the primary function here.
90
+ self.components['sync_data_btn'].click(
91
+ fn=self.trigger_sync_and_refresh,
92
+ inputs=[
93
+ self.token_state,
94
+ self.url_user_token_display, # Pass the component to get its current value
95
+ self.org_urn_display # Pass the component to get its current value
96
+ ],
97
+ outputs=[
98
+ self.components['sync_status_html_output'], # Output 1 from sync_all_linkedin_data
99
+ self.token_state, # Output 2 from sync_all_linkedin_data
100
+ self.status_box, # Output 1 from process_and_store (after sync)
101
+ self.token_state, # Output 2 from process_and_store (after sync)
102
+ self.components['sync_data_btn'], # Output 3 from process_and_store (after sync)
103
+ self.components['dashboard_display_html'] # Output from display_main_dashboard (after sync)
104
+ ],
105
+ show_progress="full",
106
+ api_name="sync_linkedin_data_full_flow"
107
+ # Note: The number of outputs here must match the total number of yields in trigger_sync_and_refresh
108
+ # trigger_sync_and_refresh yields:
109
+ # 1. sync_status_html (for sync_status_html_output)
110
+ # 2. updated_token_state_after_sync (for token_state)
111
+ # --- then ---
112
+ # 3. status_msg_after_sync (for status_box)
113
+ # 4. final_token_state_dict (for token_state)
114
+ # 5. sync_btn_update_after_sync (for sync_data_btn)
115
+ # --- then ---
116
+ # 6. dashboard_html_after_sync (for dashboard_display_html)
117
+ # This means the Gradio event needs to be structured to handle these yields if they are separate updates.
118
+ # However, Gradio's .click typically expects a single function that returns all outputs or a generator
119
+ # that yields tuples of updates for all outputs at each step.
120
+ # For simplicity, trigger_sync_and_refresh should be an async generator yielding tuples for all outputs.
121
+ # Let's refine trigger_sync_and_refresh to yield tuples.
122
+ )
123
+ logging.info("Dashboard/sync event handlers setup complete.")
124
+
125
+ async def refined_trigger_sync_and_refresh(self, current_token_state_value, url_token, org_urn_val):
126
+ """
127
+ Refined orchestrator for sync process, yielding tuples for all outputs at each step.
128
+ Outputs:
129
+ 1. self.components['sync_status_html_output']
130
+ 2. self.token_state
131
+ 3. self.status_box
132
+ 4. self.components['sync_data_btn'] (this is tricky, might need to be separate or handled by token_state change)
133
+ 5. self.components['dashboard_display_html']
134
+
135
+ Let's simplify the outputs for the direct click and handle subsequent updates via .then() in app.py
136
+ The click will call sync_all_linkedin_data_orchestrator.
137
+ Then, .then() will call process_and_store_bubble_token.
138
+ Then, .then() will call display_main_dashboard.
139
+ And further .then() for agentic and analytics.
140
+ So, this handler will provide the individual functions.
141
+ """
142
+ pass # The original structure in app.py with chained .then() is better.
143
+ # This class will hold the functions called by those .then() chains.
144
+ # sync_all_linkedin_data_orchestrator
145
+ # process_and_store_bubble_token (already imported)
146
+ # display_main_dashboard (already imported)
147
+