mirror of
https://github.com/block/buzz.git
synced 2026-10-30 22:11:36 +00:00
refactor(desktop): extract the channel agent session surface from ChannelPane
**Category:** refactor The file-size ratchet grandfathers `ChannelPane.tsx` above the 1000-line cap but forbids growth, and `#6575` landed it at 1011 lines on main — so this branch's +35 became a hard gate failure on rebase rather than the +35 it was when the branch was cut. Extracting rather than trimming, and specifically extracting *this branch's* own additions rather than anything `#6575` just added: the agent-session branch of the auxiliary-surface chain moves into `ChannelAgentSessionSurface`, taking the cross-channel re-scoping rule, the cover-drawer-vs-split-pane choice, and its layout-prop resolution with it. `ChannelPane` keeps what it owns — the surface resolution, the shared `AnimatePresence` key, and the split pane's resize affordances, which it passes down as `wrapSplitPane`. No behaviour change: the same panel with the same props in both presentations. `ChannelPane.tsx` is now 1006 lines, back under the ratchet's recorded 1011. Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz> Co-authored-by: Bradley Axen <baxen@squareup.com> Signed-off-by: Bradley Axen <baxen@squareup.com>
This commit is contained in:
105
desktop/src/features/channels/ui/ChannelAgentSessionSurface.tsx
Normal file
105
desktop/src/features/channels/ui/ChannelAgentSessionSurface.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import type * as React from "react";
|
||||
|
||||
import * as agentSessionSelection from "@/features/channels/ui/agentSessionSelection";
|
||||
import type { ChannelAgentSessionAgent } from "@/features/channels/ui/useChannelAgentSessions";
|
||||
import { getAgentSessionPanelPresentation } from "@/features/channels/lib/agentSessionPanelPresentation";
|
||||
import { AgentActivityDrawer } from "@/features/channels/ui/AgentActivityDrawer";
|
||||
import { AgentSessionThreadPanel } from "@/features/channels/ui/AgentSessionThreadPanel";
|
||||
import type { BotActivityAgent } from "@/features/channels/ui/BotActivityBar";
|
||||
import type { UserProfileLookup } from "@/features/profile/lib/identity";
|
||||
import type { Channel } from "@/shared/api/types";
|
||||
|
||||
type ChannelAgentSessionSurfaceProps = {
|
||||
activeChannel: Channel;
|
||||
activeChannelId: string | null;
|
||||
activityAgents: BotActivityAgent[];
|
||||
agent: ChannelAgentSessionAgent;
|
||||
/** Render the panel inside the cover drawer instead of the split pane. */
|
||||
isCoverDrawer: boolean;
|
||||
isSinglePanelView: boolean;
|
||||
onBack?: () => void;
|
||||
onClose: () => void;
|
||||
openAgentSessionChannelId: string | null;
|
||||
profiles?: UserProfileLookup;
|
||||
useSplitAuxiliaryPane: boolean;
|
||||
widthPx: number;
|
||||
/**
|
||||
* Applies the split-pane presentation, including its resize affordances.
|
||||
* Supplied by `ChannelPane` because that pane owns the resize state; the
|
||||
* cover-drawer presentation is applied here.
|
||||
*/
|
||||
wrapSplitPane: (panel: React.ReactNode) => React.ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* The channel's agent activity surface: the session panel plus the channel
|
||||
* re-scoping its content and actions depend on.
|
||||
*
|
||||
* Split out of `ChannelPane` so the re-scoping rule below has one home and is
|
||||
* not another branch inside that component's auxiliary-surface chain. Which
|
||||
* presentation this lands in is decided upstream and applied through `wrap`.
|
||||
*/
|
||||
export function ChannelAgentSessionSurface({
|
||||
activeChannel,
|
||||
activeChannelId,
|
||||
activityAgents,
|
||||
agent,
|
||||
isCoverDrawer,
|
||||
isSinglePanelView,
|
||||
onBack,
|
||||
onClose,
|
||||
openAgentSessionChannelId,
|
||||
profiles,
|
||||
useSplitAuxiliaryPane,
|
||||
widthPx,
|
||||
wrapSplitPane,
|
||||
}: ChannelAgentSessionSurfaceProps) {
|
||||
// When the panel was opened from a different channel than the currently
|
||||
// active one, re-scope it to the active channel so that both the
|
||||
// content/header AND channel-backed actions (e.g. Stop current turn) operate
|
||||
// on the same channel object.
|
||||
const effectiveAgentSessionChannelId =
|
||||
openAgentSessionChannelId && activeChannel.id !== openAgentSessionChannelId
|
||||
? activeChannelId
|
||||
: openAgentSessionChannelId;
|
||||
const channel = effectiveAgentSessionChannelId
|
||||
? effectiveAgentSessionChannelId === activeChannel.id
|
||||
? activeChannel
|
||||
: null
|
||||
: agentSessionSelection.isAgentInActivityList({
|
||||
activityAgents,
|
||||
selectedAgent: agent,
|
||||
})
|
||||
? activeChannel
|
||||
: null;
|
||||
|
||||
const layoutProps = getAgentSessionPanelPresentation({
|
||||
isCoverDrawer,
|
||||
isSinglePanelView,
|
||||
useSplitAuxiliaryPane,
|
||||
});
|
||||
const panel = (
|
||||
<AgentSessionThreadPanel
|
||||
agent={agent}
|
||||
canInterruptTurn={agent.canInterruptTurn}
|
||||
channel={channel}
|
||||
channelId={effectiveAgentSessionChannelId}
|
||||
{...layoutProps}
|
||||
profiles={profiles}
|
||||
onBack={onBack}
|
||||
onClose={onClose}
|
||||
widthPx={widthPx}
|
||||
/>
|
||||
);
|
||||
|
||||
return isCoverDrawer ? (
|
||||
<AgentActivityDrawer
|
||||
channelName={activeChannel.name ?? "channel"}
|
||||
onClose={onClose}
|
||||
>
|
||||
{panel}
|
||||
</AgentActivityDrawer>
|
||||
) : (
|
||||
wrapSplitPane(panel)
|
||||
);
|
||||
}
|
||||
@@ -25,16 +25,12 @@ import {
|
||||
import { buildVideoReviewPresentationByMessageId } from "@/features/messages/lib/videoReviewContext";
|
||||
import { useComposerHeightPadding } from "@/features/messages/ui/useComposerHeightPadding";
|
||||
import { UserProfilePanel } from "@/features/profile/ui/UserProfilePanel";
|
||||
import { AgentSessionThreadPanel } from "@/features/channels/ui/AgentSessionThreadPanel";
|
||||
import { ChannelManagementAuxiliaryPanel } from "@/features/channels/ui/ChannelManagementAuxiliaryPanel";
|
||||
import { RightAuxiliaryPane } from "@/features/channels/ui/RightAuxiliaryPane";
|
||||
import { ThreadViewModeToggle } from "@/features/channels/ui/ThreadViewModeToggle";
|
||||
import { AgentActivityDrawer } from "@/features/channels/ui/AgentActivityDrawer";
|
||||
import { ChannelAgentSessionSurface } from "@/features/channels/ui/ChannelAgentSessionSurface";
|
||||
import { FocusThreadDrawer } from "@/features/channels/ui/FocusThreadDrawer";
|
||||
import {
|
||||
AGENT_SESSION_SURFACE_KEY,
|
||||
getAgentSessionPanelPresentation,
|
||||
} from "@/features/channels/lib/agentSessionPanelPresentation";
|
||||
import { AGENT_SESSION_SURFACE_KEY } from "@/features/channels/lib/agentSessionPanelPresentation";
|
||||
import {
|
||||
resolveChannelAuxiliarySurface,
|
||||
resolveChannelCoverDrawer,
|
||||
@@ -534,20 +530,10 @@ export const ChannelPane = React.memo(function ChannelPane({
|
||||
) : (
|
||||
wrapAux(panel, "message-thread-panel", { key: THREAD_SURFACE_KEY })
|
||||
);
|
||||
const wrapAgentSessionPanel = (panel: React.ReactNode) =>
|
||||
useAgentActivityDrawer ? (
|
||||
<AgentActivityDrawer
|
||||
channelName={activeChannel?.name ?? "channel"}
|
||||
key={AGENT_SESSION_SURFACE_KEY}
|
||||
onClose={onCloseAgentSession}
|
||||
>
|
||||
{panel}
|
||||
</AgentActivityDrawer>
|
||||
) : (
|
||||
wrapAux(panel, "agent-session-thread-panel", {
|
||||
key: AGENT_SESSION_SURFACE_KEY,
|
||||
})
|
||||
);
|
||||
const wrapAgentSessionSplitPane = (panel: React.ReactNode) =>
|
||||
wrapAux(panel, "agent-session-thread-panel", {
|
||||
key: AGENT_SESSION_SURFACE_KEY,
|
||||
});
|
||||
const threadHeaderLeading = useSplitAuxiliaryPane ? (
|
||||
<ThreadViewModeToggle onChange={changeThreadViewMode} />
|
||||
) : undefined;
|
||||
@@ -557,11 +543,6 @@ export const ChannelPane = React.memo(function ChannelPane({
|
||||
isSinglePanelView,
|
||||
useSplitAuxiliaryPane,
|
||||
});
|
||||
const agentSessionLayoutProps = getAgentSessionPanelPresentation({
|
||||
isCoverDrawer: useAgentActivityDrawer,
|
||||
isSinglePanelView,
|
||||
useSplitAuxiliaryPane,
|
||||
});
|
||||
const timelineReplyHandler =
|
||||
activeChannel?.archivedAt || isHuddleTranscript ? undefined : onOpenThread;
|
||||
return (
|
||||
@@ -910,42 +891,22 @@ export const ChannelPane = React.memo(function ChannelPane({
|
||||
) : auxiliarySurface === "agent-session" &&
|
||||
activeChannel &&
|
||||
selectedAgent ? (
|
||||
(() => {
|
||||
// When the panel was opened from a different channel than the
|
||||
// currently active one, re-scope it to the active channel so
|
||||
// that both the content/header AND channel-backed actions (e.g.
|
||||
// Stop current turn) operate on the same channel object.
|
||||
const effectiveAgentSessionChannelId =
|
||||
openAgentSessionChannelId &&
|
||||
activeChannel.id !== openAgentSessionChannelId
|
||||
? activeChannelId
|
||||
: openAgentSessionChannelId;
|
||||
const panel = (
|
||||
<AgentSessionThreadPanel
|
||||
agent={selectedAgent}
|
||||
canInterruptTurn={selectedAgent.canInterruptTurn}
|
||||
channel={
|
||||
effectiveAgentSessionChannelId
|
||||
? effectiveAgentSessionChannelId === activeChannel.id
|
||||
? activeChannel
|
||||
: null
|
||||
: agentSessionSelection.isAgentInActivityList({
|
||||
activityAgents,
|
||||
selectedAgent,
|
||||
})
|
||||
? activeChannel
|
||||
: null
|
||||
}
|
||||
channelId={effectiveAgentSessionChannelId}
|
||||
{...agentSessionLayoutProps}
|
||||
profiles={profiles}
|
||||
onBack={onBackFromAgentSession}
|
||||
onClose={onCloseAgentSession}
|
||||
widthPx={threadPanelWidthPx}
|
||||
/>
|
||||
);
|
||||
return wrapAgentSessionPanel(panel);
|
||||
})()
|
||||
<ChannelAgentSessionSurface
|
||||
activeChannel={activeChannel}
|
||||
activeChannelId={activeChannelId}
|
||||
activityAgents={activityAgents}
|
||||
agent={selectedAgent}
|
||||
key={AGENT_SESSION_SURFACE_KEY}
|
||||
isCoverDrawer={useAgentActivityDrawer}
|
||||
isSinglePanelView={isSinglePanelView}
|
||||
useSplitAuxiliaryPane={useSplitAuxiliaryPane}
|
||||
onBack={onBackFromAgentSession}
|
||||
onClose={onCloseAgentSession}
|
||||
openAgentSessionChannelId={openAgentSessionChannelId}
|
||||
profiles={profiles}
|
||||
widthPx={threadPanelWidthPx}
|
||||
wrapSplitPane={wrapAgentSessionSplitPane}
|
||||
/>
|
||||
) : auxiliarySurface === "profile" && profilePanelPubkey ? (
|
||||
(() => {
|
||||
const panel = (
|
||||
|
||||
Reference in New Issue
Block a user