From 394d345e0c8d9d7da87371e8da090d3becc77ce7 Mon Sep 17 00:00:00 2001 From: hugocasa Date: Tue, 20 Oct 2026 19:07:36 +0200 Subject: [PATCH] fix: give the agent page's API and Slack sections tabs on small screens (#11901) * fix: give the agent page's API and Slack panel a tab on small screens Co-Authored-By: Claude Opus 5.5 * fix: keep the agent pane mounted across the small-screen breakpoint Co-Authored-By: Claude Opus 5.5 * fix: make the covered agent pane inert on the API tab Co-Authored-By: Claude Opus 5.5 * fix: flatten the agent page's API and Slack sections into its small-screen tabs Co-Authored-By: Claude Opus 5.5 * fix: fall back to the API tab when the agent has no Slack section Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- .../flows/content/AgentUsePanel.svelte | 13 +- .../agents/get/[...path]/+page.svelte | 142 +++++++++++------- 2 files changed, 98 insertions(+), 57 deletions(-) diff --git a/frontend/src/lib/components/flows/content/AgentUsePanel.svelte b/frontend/src/lib/components/flows/content/AgentUsePanel.svelte index 3f2c473937..83c8fe4217 100644 --- a/frontend/src/lib/components/flows/content/AgentUsePanel.svelte +++ b/frontend/src/lib/components/flows/content/AgentUsePanel.svelte @@ -41,7 +41,8 @@ runsAs, anyone, canShare, - channels + channels, + section }: { agentPath: string workspace: string @@ -65,10 +66,12 @@ /** Whether the user can change its Slack settings: anyone who can edit it. */ canShare: boolean channels: SlackAgentChannel[] + /** Shows only this section, without the panel's own tabs: the page offers them as its tabs. */ + section?: 'api' | 'slack' } = $props() let pickedTab = $state('api') - let tab = $derived(chat ? pickedTab : 'api') + let tab = $derived(section ?? (chat ? pickedTab : 'api')) let handle = $derived(`+${agentPath.split('/').pop()}`) let userSettings: UserSettings | undefined = $state(undefined) @@ -100,7 +103,11 @@ />
- tab, (t) => (pickedTab = t)} wrapperClass="flex-none w-full"> + tab, (t) => (pickedTab = t)} + hideTabs={section !== undefined} + wrapperClass="flex-none w-full" + > {#if chat} diff --git a/frontend/src/routes/(root)/(logged)/agents/get/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/agents/get/[...path]/+page.svelte index ed50528dbd..426f56c378 100644 --- a/frontend/src/routes/(root)/(logged)/agents/get/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/agents/get/[...path]/+page.svelte @@ -18,7 +18,7 @@ import AgentEditorHost from '$lib/components/flows/content/AgentEditorHost.svelte' import AgentConfigModal from '$lib/components/flows/content/AgentConfigModal.svelte' import RunForm from '$lib/components/RunForm.svelte' - import { Alert } from '$lib/components/common' + import { Alert, Tab, Tabs } from '$lib/components/common' import { keepsManagedMemory } from '$lib/components/flows/agentFormFields' import { agentMenuItems, deleteAgent } from '$lib/components/flows/agentActions' import AgentHistory from '$lib/components/flows/AgentHistory.svelte' @@ -49,6 +49,10 @@ let deleteOpen = $state(false) let evalsModal: AgentEvalsModal | undefined = $state(undefined) let clientWidth = $state(window.innerWidth) + let pickedMobileTab = $state('agent') + // The page is reused across agents, and an agent without managed memory has no Slack tab. + let mobileTab = $derived(pickedMobileTab === 'slack' && !chatAvailable ? 'api' : pickedMobileTab) + let wide = $derived(clientWidth >= 1024) const slack = resource( () => ({ workspace: ws, path }), @@ -62,7 +66,7 @@ // while the chat shows, and the chat's composer owns the key then. function onKeyDown(event: KeyboardEvent) { if (event.defaultPrevented || event.key !== 'Enter' || !(event.ctrlKey || event.metaKey)) return - if (!runForm || testPane?.mode === 'chat') return + if (!runForm || testPane?.mode === 'chat' || (!wide && mobileTab !== 'agent')) return if (isValid) { event.preventDefault() runForm.run() @@ -207,67 +211,97 @@ {/if} {/snippet} -
+ + {#if !wide && ws && config} + mobileTab, (t) => (pickedMobileTab = t)} + wrapperClass="flex-none no-scrollbar" + > + + + {#if chatAvailable} + + {/if} + + {/if} +
- - {#key `${ws}:${path}:${reloaded}`} - configModal?.open()} - > - {#snippet viewForm({ schema, run, loading, actions })} - {#if config && !chatAvailable} - - Each run is answered on its own inputs, so this agent has no chat. That suits - reusing it as a step in a flow.{canEdit - ? ' Turn on managed memory in its configuration to chat with it.' - : ''} - - {/if} - - {/snippet} - - {/key} + +
+ {@render agentPane()} +
- - {#if ws && config && clientWidth >= 1024} + {#if wide && ws && config} - + {@render usePane(ws)} {/if}
+ {#if !wide && ws && config} +
+ {@render usePane(ws, mobileTab === 'slack' ? 'slack' : 'api')} +
+ {/if}
+{#snippet agentPane()} + {#key `${ws}:${path}:${reloaded}`} + configModal?.open()} + > + {#snippet viewForm({ schema, run, loading, actions })} + {#if config && !chatAvailable} + + Each run is answered on its own inputs, so this agent has no chat. That suits reusing it + as a step in a flow.{canEdit + ? ' Turn on managed memory in its configuration to chat with it.' + : ''} + + {/if} + + {/snippet} + + {/key} +{/snippet} + +{#snippet usePane(ws: string, section?: 'api' | 'slack')} + +{/snippet} + {#if ws} {/if}