From e4180f50c2dbc62f3cd42fc7f65d7d601bbcaaba Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 25 Aug 2026 02:59:07 -0700 Subject: [PATCH] refactor(slack): canonicalize approval presentation rendering (#129205) --- .../src/approval-handler.runtime.test.ts | 46 +++ .../slack/src/approval-handler.runtime.ts | 298 ++++-------------- 2 files changed, 111 insertions(+), 233 deletions(-) diff --git a/extensions/slack/src/approval-handler.runtime.test.ts b/extensions/slack/src/approval-handler.runtime.test.ts index a82dd0355fa3..22acef6806e3 100644 --- a/extensions/slack/src/approval-handler.runtime.test.ts +++ b/extensions/slack/src/approval-handler.runtime.test.ts @@ -170,6 +170,25 @@ function buildExecResolvedResult() { }); } +function buildExecExpiredResult() { + return slackApprovalNativeRuntime.presentation.buildExpiredResult({ + ...APPROVAL_CONTEXT, + request: { + id: "req-1", + request: { command: "echo hi" }, + ...APPROVAL_TIMING, + }, + view: { + approvalKind: "exec", + approvalId: "req-1", + phase: "expired", + commandText: "echo hi", + metadata: [], + } as never, + entry: APPROVAL_ENTRY, + }); +} + function buildPluginResolvedResult() { return slackApprovalNativeRuntime.presentation.buildResolvedResult({ ...APPROVAL_CONTEXT, @@ -416,6 +435,33 @@ describe("slackApprovalNativeRuntime", () => { ).toBe(false); }); + it("renders expired exec approvals without interactive controls", async () => { + const result = await buildExecExpiredResult(); + + expect(result).toEqual({ + kind: "update", + payload: { + text: "*Exec approval expired*\nThis approval request expired before it was resolved.\n\n*Command*\n```\necho hi\n```", + blocks: [ + { + type: "section", + text: { + type: "mrkdwn", + text: "*Exec approval expired*\nThis approval request expired before it was resolved.", + }, + }, + { + type: "section", + text: { + type: "mrkdwn", + text: "*Command*\n```\necho hi\n```", + }, + }, + ], + }, + }); + }); + it("renders plugin resolved and expired updates without command text", async () => { const resolved = await buildPluginResolvedResult(); const expired = await buildPluginExpiredResult(); diff --git a/extensions/slack/src/approval-handler.runtime.ts b/extensions/slack/src/approval-handler.runtime.ts index 37df10d7e575..8443c64104cb 100644 --- a/extensions/slack/src/approval-handler.runtime.ts +++ b/extensions/slack/src/approval-handler.runtime.ts @@ -3,9 +3,6 @@ import type { App } from "@slack/bolt"; import type { Block, KnownBlock, WebClient } from "@slack/web-api"; import type { ChannelApprovalCapabilityHandlerContext, - ExecApprovalExpiredView, - ExecApprovalPendingView, - ExecApprovalResolvedView, ExpiredApprovalView, PendingApprovalView, PluginApprovalExpiredView, @@ -188,234 +185,78 @@ function buildSlackPluginRequestBlocks(view: SlackPluginApprovalView): SlackBloc ]; } -function buildSlackExecPendingApprovalText(view: ExecApprovalPendingView): string { - const metadataLines = buildSlackMetadataLines(view.metadata); - const lines = [ - "*Exec approval required*", - "A command needs your approval.", +type SlackApprovalRenderInput = + | { phase: "pending"; view: PendingApprovalView } + | { phase: "resolved"; view: ResolvedApprovalView } + | { phase: "expired"; view: ExpiredApprovalView }; + +function buildSlackApprovalPayload(input: SlackApprovalRenderInput): SlackPendingDelivery { + const { phase, view } = input; + const isPlugin = view.approvalKind === "plugin"; + const approvalName = isPlugin ? "Plugin" : "Exec"; + let heading: string; + let description: string; + if (phase === "pending") { + heading = `*${approvalName} approval required*`; + description = + view.approvalKind === "plugin" + ? resolveSlackPluginDescription(view) + : "A command needs your approval."; + } else if (phase === "resolved") { + heading = `*${approvalName} approval: ${resolveSlackApprovalDecisionLabel(view.decision)}*`; + const resolvedBy = formatSlackApprover(view.resolvedBy); + description = resolvedBy ? `Resolved by ${resolvedBy}.` : "Resolved."; + } else { + heading = `*${approvalName} approval expired*`; + description = "This approval request expired before it was resolved."; + } + + const metadata = isPlugin ? buildSlackPluginMetadata(view) : view.metadata; + const bodyLabel = isPlugin ? "*Request*" : "*Command*"; + const bodyText = isPlugin ? view.title : buildSlackCodeBlock(view.commandText); + const includeMetadata = isPlugin || phase === "pending"; + const text = [ + heading, + description, "", - "*Command*", - buildSlackCodeBlock(view.commandText), - ...metadataLines, - ]; - return lines.join("\n"); -} - -function buildSlackPluginPendingApprovalText(view: PluginApprovalPendingView): string { - const metadataLines = buildSlackMetadataLines(buildSlackPluginMetadata(view)); - const lines = [ - "*Plugin approval required*", - resolveSlackPluginDescription(view), - "", - "*Request*", - view.title, - ...metadataLines, - ]; - return lines.join("\n"); -} - -function buildSlackPendingApprovalText(view: PendingApprovalView): string { - return view.approvalKind === "plugin" - ? buildSlackPluginPendingApprovalText(view) - : buildSlackExecPendingApprovalText(view); -} - -function buildSlackExecPendingApprovalBlocks(view: ExecApprovalPendingView): SlackBlock[] { - const interactiveBlocks = - resolveSlackReplyBlocks({ - text: "", - presentation: buildApprovalPresentationFromActionDescriptors(view.actions), - }) ?? []; - return [ - { - type: "section", - block_id: SLACK_APPROVAL_HEADER_BLOCK_ID, - text: { - type: "mrkdwn", - text: "*Exec approval required*\nA command needs your approval.", - }, - }, - { - type: "section", - text: { - type: "mrkdwn", - text: `*Command*\n${buildSlackCodeBlock(truncateSlackMrkdwn(view.commandText, 2600))}`, - }, - }, - ...buildSlackMetadataContextBlocks(view.metadata), - ...interactiveBlocks, - ]; -} - -function buildSlackPluginPendingApprovalBlocks(view: PluginApprovalPendingView): SlackBlock[] { - const interactiveBlocks = - resolveSlackReplyBlocks({ - text: "", - presentation: buildApprovalPresentationFromActionDescriptors(view.actions), - }) ?? []; - return [ - { - type: "section", - block_id: SLACK_APPROVAL_HEADER_BLOCK_ID, - text: { - type: "mrkdwn", - text: `*Plugin approval required*\n${truncateSlackMrkdwn( - resolveSlackPluginDescription(view), - 2600, - )}`, - }, - }, - ...buildSlackPluginRequestBlocks(view), - ...interactiveBlocks, - ]; -} - -function buildSlackPendingApprovalBlocks(view: PendingApprovalView): SlackBlock[] { - return view.approvalKind === "plugin" - ? buildSlackPluginPendingApprovalBlocks(view) - : buildSlackExecPendingApprovalBlocks(view); -} - -function buildSlackExecResolvedText(view: ExecApprovalResolvedView): string { - const resolvedBy = formatSlackApprover(view.resolvedBy); - const lines = [ - `*Exec approval: ${resolveSlackApprovalDecisionLabel(view.decision)}*`, - resolvedBy ? `Resolved by ${resolvedBy}.` : "Resolved.", - "", - "*Command*", - buildSlackCodeBlock(view.commandText), - ]; - return lines.join("\n"); -} - -function buildSlackPluginResolvedText(view: PluginApprovalResolvedView): string { - const resolvedBy = formatSlackApprover(view.resolvedBy); - const metadataLines = buildSlackMetadataLines(buildSlackPluginMetadata(view)); - const lines = [ - `*Plugin approval: ${resolveSlackApprovalDecisionLabel(view.decision)}*`, - resolvedBy ? `Resolved by ${resolvedBy}.` : "Resolved.", - "", - "*Request*", - view.title, - ...metadataLines, - ]; - return lines.join("\n"); -} - -function buildSlackResolvedText(view: ResolvedApprovalView): string { - return view.approvalKind === "plugin" - ? buildSlackPluginResolvedText(view) - : buildSlackExecResolvedText(view); -} - -function buildSlackExecResolvedBlocks(view: ExecApprovalResolvedView): SlackBlock[] { - const resolvedBy = formatSlackApprover(view.resolvedBy); - return [ - { - type: "section", - text: { - type: "mrkdwn", - text: `*Exec approval: ${resolveSlackApprovalDecisionLabel(view.decision)}*\n${ - resolvedBy ? `Resolved by ${resolvedBy}.` : "Resolved." - }`, - }, - }, - { - type: "section", - text: { - type: "mrkdwn", - text: `*Command*\n${buildSlackCodeBlock(truncateSlackMrkdwn(view.commandText, 2600))}`, - }, - }, - ]; -} - -function buildSlackPluginResolvedBlocks(view: PluginApprovalResolvedView): SlackBlock[] { - const resolvedBy = formatSlackApprover(view.resolvedBy); - return [ - { - type: "section", - text: { - type: "mrkdwn", - text: `*Plugin approval: ${resolveSlackApprovalDecisionLabel(view.decision)}*\n${ - resolvedBy ? `Resolved by ${resolvedBy}.` : "Resolved." - }`, - }, - }, - ...buildSlackPluginRequestBlocks(view), - ]; -} - -function buildSlackResolvedBlocks(view: ResolvedApprovalView): SlackBlock[] { - return view.approvalKind === "plugin" - ? buildSlackPluginResolvedBlocks(view) - : buildSlackExecResolvedBlocks(view); -} - -function buildSlackExecExpiredText(view: ExecApprovalExpiredView): string { - return [ - "*Exec approval expired*", - "This approval request expired before it was resolved.", - "", - "*Command*", - buildSlackCodeBlock(view.commandText), + bodyLabel, + bodyText, + ...(includeMetadata ? buildSlackMetadataLines(metadata) : []), ].join("\n"); -} -function buildSlackPluginExpiredText(view: PluginApprovalExpiredView): string { - const metadataLines = buildSlackMetadataLines(buildSlackPluginMetadata(view)); - return [ - "*Plugin approval expired*", - "This approval request expired before it was resolved.", - "", - "*Request*", - view.title, - ...metadataLines, - ].join("\n"); -} - -function buildSlackExpiredText(view: ExpiredApprovalView): string { - return view.approvalKind === "plugin" - ? buildSlackPluginExpiredText(view) - : buildSlackExecExpiredText(view); -} - -function buildSlackExecExpiredBlocks(view: ExecApprovalExpiredView): SlackBlock[] { - return [ + const headerDescription = + isPlugin && phase === "pending" ? truncateSlackMrkdwn(description, 2600) : description; + const blocks: SlackBlock[] = [ { type: "section", + ...(phase === "pending" ? { block_id: SLACK_APPROVAL_HEADER_BLOCK_ID } : {}), text: { type: "mrkdwn", - text: "*Exec approval expired*\nThis approval request expired before it was resolved.", - }, - }, - { - type: "section", - text: { - type: "mrkdwn", - text: `*Command*\n${buildSlackCodeBlock(truncateSlackMrkdwn(view.commandText, 2600))}`, + text: `${heading}\n${headerDescription}`, }, }, + ...(view.approvalKind === "plugin" + ? buildSlackPluginRequestBlocks(view) + : [ + { + type: "section" as const, + text: { + type: "mrkdwn" as const, + text: `*Command*\n${buildSlackCodeBlock(truncateSlackMrkdwn(view.commandText, 2600))}`, + }, + }, + ...(phase === "pending" ? buildSlackMetadataContextBlocks(view.metadata) : []), + ]), ]; -} - -function buildSlackPluginExpiredBlocks(view: PluginApprovalExpiredView): SlackBlock[] { - return [ - { - type: "section", - text: { - type: "mrkdwn", - text: "*Plugin approval expired*\nThis approval request expired before it was resolved.", - }, - }, - ...buildSlackPluginRequestBlocks(view), - ]; -} - -function buildSlackExpiredBlocks(view: ExpiredApprovalView): SlackBlock[] { - return view.approvalKind === "plugin" - ? buildSlackPluginExpiredBlocks(view) - : buildSlackExecExpiredBlocks(view); + if (phase === "pending") { + blocks.push( + ...(resolveSlackReplyBlocks({ + text: "", + presentation: buildApprovalPresentationFromActionDescriptors(view.actions), + }) ?? []), + ); + } + return { text, blocks }; } async function updateMessage(params: { @@ -469,23 +310,14 @@ export const slackApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdap }, }, presentation: { - buildPendingPayload: ({ view }) => ({ - text: buildSlackPendingApprovalText(view), - blocks: buildSlackPendingApprovalBlocks(view), - }), + buildPendingPayload: ({ view }) => buildSlackApprovalPayload({ phase: "pending", view }), buildResolvedResult: ({ view }) => ({ kind: "update", - payload: { - text: buildSlackResolvedText(view), - blocks: buildSlackResolvedBlocks(view), - }, + payload: buildSlackApprovalPayload({ phase: "resolved", view }), }), buildExpiredResult: ({ view }) => ({ kind: "update", - payload: { - text: buildSlackExpiredText(view), - blocks: buildSlackExpiredBlocks(view), - }, + payload: buildSlackApprovalPayload({ phase: "expired", view }), }), }, transport: {