diff --git a/daras_ai_v2/base.py b/daras_ai_v2/base.py index ecd44a77d..c013cc134 100644 --- a/daras_ai_v2/base.py +++ b/daras_ai_v2/base.py @@ -296,7 +296,11 @@ def _render_header(self): if tbreadcrumbs.has_breadcrumbs() or self.run_user: # only render title here if the above row was not empty self._render_title(tbreadcrumbs.h1_title) - if published_run and published_run.notes: + if ( + published_run + and published_run.notes + and MenuTabs.integrations != self.tab + ): st.write(published_run.notes) elif is_root_example: st.write(self.preview_description(current_run.to_dict())) @@ -309,6 +313,17 @@ def can_user_edit_run(self, current_run: SavedRun | None = None) -> bool: and current_run.uid == self.request.user.uid ) + def can_user_edit_published_run( + self, published_run: PublishedRun | None = None + ) -> bool: + published_run = published_run or self.get_current_published_run() + return self.is_current_user_admin() or bool( + published_run + and self.request + and self.request.user + and published_run.created_by == self.request.user + ) + def _render_title(self, title: str): st.write(f"# {title}") @@ -338,6 +353,7 @@ def _render_published_run_buttons( *, current_run: SavedRun, published_run: PublishedRun, + redirect_to: str | None = None, ): is_update_mode = ( self.is_current_user_admin() @@ -395,6 +411,7 @@ def _render_published_run_buttons( published_run=published_run, modal=publish_modal, is_update_mode=is_update_mode, + redirect_to=redirect_to, ) def _render_publish_modal( @@ -404,6 +421,7 @@ def _render_publish_modal( published_run: PublishedRun, modal: Modal, is_update_mode: bool = False, + redirect_to: str | None = None, ): if published_run.is_root() and self.is_current_user_admin(): with st.div(className="text-danger"): @@ -507,7 +525,7 @@ def _render_publish_modal( notes=published_run_notes.strip(), visibility=published_run_visibility, ) - force_redirect(published_run.get_app_url()) + force_redirect(redirect_to or published_run.get_app_url()) def _validate_published_run_title(self, title: str): if slugify(title) in settings.DISALLOWED_TITLE_SLUGS: diff --git a/daras_ai_v2/bot_integration_widgets.py b/daras_ai_v2/bot_integration_widgets.py index b8e5f36c6..53feec596 100644 --- a/daras_ai_v2/bot_integration_widgets.py +++ b/daras_ai_v2/bot_integration_widgets.py @@ -135,7 +135,7 @@ def broadcast_input(bi: BotIntegration): ) text = st.text_area( f""" - #### Broadcast Message 📢 + ###### Broadcast Message 📢 Broadcast a message to all users of this integration using this bot account. \\ You can also do this via the [API]({api_docs_url}) which allows filtering by phone number and more! """, diff --git a/recipes/VideoBots.py b/recipes/VideoBots.py index 560bd3728..f2001768a 100644 --- a/recipes/VideoBots.py +++ b/recipes/VideoBots.py @@ -921,50 +921,66 @@ def render_selected_tab(self, selected_tab): super().render_selected_tab(selected_tab) if selected_tab == MenuTabs.integrations: + st.newline() + # not signed in case if not self.request.user or self.request.user.is_anonymous: self.integration_welcome_screen() + st.newline() + with st.center(): + st.anchor( + "Get Started", + href=self.get_auth_url(self.app_url(query_params={})), + type="primary", + ) return - # signed in but not on a run the user can edit - if not self.can_user_edit_run(): + current_run, published_run = self.get_runs_from_query_params( + *extract_query_params(gooey_get_query_params()) + ) # type: ignore + + # signed in but not on a run the user can edit (admins will never see this) + if not self.can_user_edit_run(current_run): self.integration_welcome_screen( title="Create your Saved Copilot", - get_started_text="🏃🏽♂️ Run & Save this Copilot", ) + st.newline() + with st.center(): + st.anchor( + "Run & Save this Copilot", + href=self.get_auth_url(self.app_url(query_params={})), + type="primary", + ) return - current_run, published_run = self.get_runs_from_query_params( - *extract_query_params(gooey_get_query_params()) - ) # type: ignore - - # automatically connect to all the user's unconnected integrations - # TODO: fix - unconnected_q = Q(saved_run=None) | Q(published_run=None) - unconnected_q &= Q(billing_account_uid=self.request.user.uid) - for bi in BotIntegration.objects.filter(unconnected_q): - bi.streaming_enabled = True - bi.user_language = ( - st.session_state.get("user_language") or bi.user_language + # signed, has submitted run, but not published (admins will never see this) + # note: this means we no longer allow botintegrations on non-published runs which is a breaking change requested by Sean + if not self.can_user_edit_published_run(published_run): + self.integration_welcome_screen( + title="Save your Published Copilot", ) - bi.saved_run = current_run - if published_run and published_run.saved_run_id == current_run.id: - bi.published_run = published_run - else: - bi.published_run = None - if bi.platform == Platform.SLACK: - from daras_ai_v2.slack_bot import send_confirmation_msg - - send_confirmation_msg(bi) - bi.save() - - integrations_q = Q(saved_run=current_run) - if published_run and published_run.saved_run_id == current_run.id: - integrations_q |= Q(published_run=published_run) - if published_run.published_run_id: - integrations_q |= Q( - saved_run__example_id=published_run.published_run_id + st.newline() + with st.center(): + self._render_published_run_buttons( + current_run=current_run, + published_run=published_run, + redirect_to=self.get_tab_url(MenuTabs.integrations), ) + return + + # if we come from an integration redirect, we connect the integrations + if "connect_ids" in self.request.query_params: + self.integrations_on_connect( + self.request.query_params.getlist("connect_ids"), + current_run, + published_run, + ) + + # see which integrations are available to the user for the current published run + assert published_run, "At this point, published_run should be available" + integrations_q = Q(published_run=published_run) | Q( + saved_run__example_id=published_run.published_run_id + ) if not self.is_current_user_admin(): integrations_q &= Q(billing_account_uid=self.request.user.uid) @@ -982,11 +998,39 @@ def render_selected_tab(self, selected_tab): integrations, current_run, published_run ) - def integration_welcome_screen( - self, title="Connect your Copilot", get_started_text="🏃🏽♂️ Get Started" - ): + def integrations_on_connect(self, ids: list[int], current_run, published_run): + from app_users.models import AppUser + from daras_ai_v2.base import RedirectException + from daras_ai_v2.slack_bot import send_confirmation_msg + + for bid in self.request.query_params.getlist("connect_ids"): + bi = BotIntegration.objects.filter(id=bid).first() + if not bi: + continue + if bi.saved_run is not None: + + st.write( + f"{bi.name} is already connected to a different run by {AppUser.objects.filter(uid=bi.billing_account_uid)}. Please disconnect it first." + ) + continue + + bi.streaming_enabled = True + bi.user_language = st.session_state.get("user_language") or bi.user_language + bi.saved_run = current_run + if published_run and published_run.saved_run_id == current_run.id: + bi.published_run = published_run + else: + bi.published_run = None + if bi.platform == Platform.SLACK: + + send_confirmation_msg(bi) + bi.save() + + raise RedirectException(self.get_tab_url(MenuTabs.integrations)) + + def integration_welcome_screen(self, title="Connect your Copilot"): with st.center(): - st.markdown(f"## {title}") + st.markdown(f"#### {title}") col1, col2, col3 = st.columns( 3, @@ -1018,14 +1062,6 @@ def integration_welcome_screen( st.markdown("3. Test, Analyze & Iterate") st.caption("Analyze your usage. Update your Saved Run to test changes.") - st.newline() - with st.center(): - st.anchor( - get_started_text, - href=self.get_auth_url(self.app_url(query_params={})), - type="primary", - ) - def integration_connect_screen( self, title="Connect your Copilot", status: str | None = None ): @@ -1033,18 +1069,19 @@ def integration_connect_screen( from routers.slack_api import slack_connect_url show_landbot = self.request.query_params.get("show-landbot") == "true" + on_connect = self.get_tab_url(MenuTabs.integrations) with st.center(): st.markdown( f""" - ## {title} + #### {title} {status or f'Run Saved ✅ ~ Connect ~ Test & Configure'} """, unsafe_allow_html=True, ) LINKSTYLE = 'class="btn btn-theme btn-secondary" style="margin: 0; display: flex; justify-content: center; align-items: center; padding: 8px; border: 1px solid black; min-width: 164px; width: 200px; aspect-ratio: 5 / 2; overflow: hidden; border-radius: 10px" draggable="false"' - IMGSTYLE = 'style="width: 100%" draggable="false"' + IMGSTYLE = 'style="width: 80%" draggable="false"' ROWSTYLE = 'style="display: flex; align-items: center; gap: 1em; margin-bottom: 1rem" draggable="false"' DESCRIPTIONSTYLE = f'style="color: {GRAYCOLOR}; text-align: left"' st.markdown( @@ -1052,25 +1089,25 @@ def integration_connect_screen( f"""