From 4eeb624aa30e8cb572283b417a1551e368a67674 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Fri, 29 May 2026 15:15:04 -0700 Subject: [PATCH 1/4] feat(slack): add install + privacy section to integration landing page Adds a hand-authored, slug-keyed landing-content module (separate from the generated integrations.json so it survives regeneration) and renders an install walkthrough + privacy-policy link on integration pages when present. Also refreshes generated docs (data-enrichment entry, icon mappings, tool mdx). --- apps/docs/components/icons.tsx | 18 +++++- apps/docs/components/ui/icon-mapping.ts | 5 +- apps/docs/content/docs/en/tools/apollo.mdx | 7 ++- .../docs/content/docs/en/tools/enrichment.mdx | 13 +--- apps/docs/content/docs/en/tools/resend.mdx | 27 +++++--- apps/docs/content/docs/en/tools/wiza.mdx | 2 +- apps/docs/content/docs/en/tools/zoominfo.mdx | 4 +- .../integrations/(shell)/[slug]/page.tsx | 61 +++++++++++++++++++ .../integrations/data/icon-mapping.ts | 5 +- .../integrations/data/integrations.json | 20 +++++- .../integrations/data/landing-content.ts | 61 +++++++++++++++++++ 11 files changed, 193 insertions(+), 30 deletions(-) create mode 100644 apps/sim/app/(landing)/integrations/data/landing-content.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 765920716b2..7985328c089 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -1,6 +1,22 @@ import type { SVGProps } from 'react' import { useId } from 'react' +export function EnrichmentIcon(props: SVGProps) { + return ( + + + + + + ) +} + export function AgentMailIcon(props: SVGProps) { return ( @@ -4731,7 +4747,7 @@ export function ZoomInfoIcon(props: SVGProps) { return (

+ {landingContent.install.heading} +

+

+ {landingContent.install.intro} +

+
    + {landingContent.install.steps.map((item, index) => ( +
  1. + +
    +

    + {item.title} +

    +

    + {item.body} +

    +
    +
  2. + ))} +
+
+ + Add to {name} + +
+ {landingContent.privacy && ( +

+ {landingContent.privacy.body}{' '} + + Privacy Policy + + . +

+ )} + +
+ + )} + {/* How to automate */}

= { ashby: AshbyIcon, athena: AthenaIcon, attio: AttioIcon, - azure_devops: AzureDevOpsIcon, + azure_devops: AzureIcon, box: BoxCompanyIcon, brandfetch: BrandfetchIcon, brightdata: BrightDataIcon, @@ -262,6 +262,7 @@ export const blockTypeToIconMap: Record = { elevenlabs: ElevenLabsIcon, emailbison: EmailBisonIcon, enrich: EnrichSoIcon, + enrichment: EnrichmentIcon, evernote: EvernoteIcon, exa: ExaAIIcon, extend_v2: ExtendIcon, diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index d859c6c3223..2786490cb3c 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -1889,7 +1889,7 @@ "description": "Interact with Azure DevOps pipelines, builds, and work items", "longDescription": "Integrate Azure DevOps into your workflow. List and inspect pipelines and builds, query and manage work items, and add or read comments.", "bgColor": "#0078D4", - "iconName": "AzureDevOpsIcon", + "iconName": "AzureIcon", "docsUrl": "https://docs.sim.ai/tools/azure_devops", "operations": [ { @@ -3137,6 +3137,24 @@ "integrationTypes": ["analytics", "developer-tools"], "tags": ["data-analytics", "automation"] }, + { + "type": "enrichment", + "slug": "data-enrichment", + "name": "Data Enrichment", + "description": "Enrich data with a Sim enrichment", + "longDescription": "Run a Sim enrichment to look up data — work email, phone number, company domain, company info, and more — from the fields you map in. Uses the same provider cascade as table enrichments.", + "bgColor": "#9333EA", + "iconName": "EnrichmentIcon", + "docsUrl": "https://docs.sim.ai/tools/enrichment", + "operations": [], + "operationCount": 0, + "triggers": [], + "triggerCount": 0, + "authType": "none", + "category": "tools", + "integrationTypes": ["sales"], + "tags": ["enrichment"] + }, { "type": "databricks", "slug": "databricks", diff --git a/apps/sim/app/(landing)/integrations/data/landing-content.ts b/apps/sim/app/(landing)/integrations/data/landing-content.ts new file mode 100644 index 00000000000..4cc2ebac558 --- /dev/null +++ b/apps/sim/app/(landing)/integrations/data/landing-content.ts @@ -0,0 +1,61 @@ +/** + * Hand-authored, integration-specific landing content that augments the + * generated `integrations.json`. Kept in a separate module so it survives + * regeneration by `scripts/generate-docs.ts`. Keyed by integration slug; + * the integration detail page renders these sections only when present. + */ + +export interface IntegrationInstallStep { + title: string + body: string +} + +export interface IntegrationLandingContent { + /** + * Install walkthrough for OAuth apps whose connection lives behind sign-in. + * Provides the "Add to {app}" instructions that app marketplaces require + * when the install button sits behind a login. + */ + install?: { + heading: string + intro: string + steps: IntegrationInstallStep[] + } + /** Short data-handling summary shown next to a privacy-policy link. */ + privacy?: { + body: string + href: string + } +} + +export const INTEGRATION_LANDING_CONTENT: Record = { + slack: { + install: { + heading: 'Add Sim to your Slack workspace', + intro: + 'Sim connects to Slack through Slack’s official OAuth flow. You add the connection from inside your Sim account, then the Sim bot is installed in your Slack workspace.', + steps: [ + { + title: 'Create your free Sim account', + body: 'Sign up at sim.ai — no credit card required.', + }, + { + title: 'Add a Slack block', + body: 'Open a workflow, drag in a Slack block, and open its credential dropdown.', + }, + { + title: 'Connect Slack', + body: 'Click Connect Slack, choose your workspace, and approve the requested permissions. This installs the Sim bot in your Slack workspace.', + }, + { + title: 'Invite the bot and build', + body: 'Invite the Sim bot to the channels it should act in, pick a Slack action, wire it into your agent, and run.', + }, + ], + }, + privacy: { + body: 'Sim requests only the Slack permissions its actions and triggers need, and never shows private channel names or messages to people who are not members of those channels in Slack.', + href: '/privacy', + }, + }, +} From 611f55dd0f4da8ce88a74789c96bfb45d4a505a8 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Fri, 29 May 2026 15:29:25 -0700 Subject: [PATCH 2/4] fix(landing): render privacy section independently, align CTA analytics label --- .../integrations/(shell)/[slug]/page.tsx | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx b/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx index 40c296b0f2b..bcce1f37e28 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx +++ b/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx @@ -482,24 +482,37 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
Add to {name}
- {landingContent.privacy && ( -

- {landingContent.privacy.body}{' '} - - Privacy Policy - - . -

- )} +

+
+ + )} + + {/* Privacy & data (integration-specific) */} + {landingContent?.privacy && ( + <> +
+

+ Privacy & data +

+

+ {landingContent.privacy.body}{' '} + + Privacy Policy + + . +

From 3707d45bd0a6c79d45740cd958fbdae62d12daf8 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Fri, 29 May 2026 15:48:05 -0700 Subject: [PATCH 3/4] docs(landing): clarify the Slack install button is behind sign-in --- apps/sim/app/(landing)/integrations/data/landing-content.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sim/app/(landing)/integrations/data/landing-content.ts b/apps/sim/app/(landing)/integrations/data/landing-content.ts index 4cc2ebac558..30a9ecff2ea 100644 --- a/apps/sim/app/(landing)/integrations/data/landing-content.ts +++ b/apps/sim/app/(landing)/integrations/data/landing-content.ts @@ -33,7 +33,7 @@ export const INTEGRATION_LANDING_CONTENT: Record Date: Fri, 29 May 2026 16:20:14 -0700 Subject: [PATCH 4/4] refactor(landing): bake integration landing content into generated json via docs-gen Moves landing content (install walkthrough + privacy) out of a render-time augment and into the generation pipeline: generate-docs reads the pure-data content map and writes landingContent into integrations.json, so the page reads a single source (integration.landingContent). Canonical types live in integrations/data/types.ts. --- .../integrations/(shell)/[slug]/page.tsx | 3 +- .../integrations/data/integrations.json | 30 ++++++++++++++++- .../integrations/data/landing-content.ts | 32 ++++--------------- .../app/(landing)/integrations/data/types.ts | 24 ++++++++++++++ scripts/generate-docs.ts | 17 +++++++++- 5 files changed, 76 insertions(+), 30 deletions(-) diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx b/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx index bcce1f37e28..441bfb72b69 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx +++ b/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx @@ -9,7 +9,6 @@ import { TemplateCardButton } from '@/app/(landing)/integrations/(shell)/[slug]/ import { IntegrationIcon } from '@/app/(landing)/integrations/components/integration-icon' import { blockTypeToIconMap } from '@/app/(landing)/integrations/data/icon-mapping' import integrations from '@/app/(landing)/integrations/data/integrations.json' -import { INTEGRATION_LANDING_CONTENT } from '@/app/(landing)/integrations/data/landing-content' import type { AuthType, FAQItem, Integration } from '@/app/(landing)/integrations/data/types' import { TEMPLATES } from '@/app/workspace/[workspaceId]/home/components/template-prompts/consts' @@ -218,7 +217,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl const { name, description, longDescription, bgColor, docsUrl, operations, triggers, authType } = integration - const landingContent = INTEGRATION_LANDING_CONTENT[slug] + const landingContent = integration.landingContent const IconComponent = blockTypeToIconMap[integration.type] const faqs = buildFAQs(integration) diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 2786490cb3c..8fc5c3856ff 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -13306,7 +13306,35 @@ "authType": "oauth", "category": "tools", "integrationTypes": ["communication", "developer-tools"], - "tags": ["messaging", "webhooks", "automation"] + "tags": ["messaging", "webhooks", "automation"], + "landingContent": { + "install": { + "heading": "Add Sim to your Slack workspace", + "intro": "Sim connects to Slack through Slack’s official OAuth flow. The “Add to Slack” button lives inside your Sim account (after sign-in) — connect from there and the Sim bot is installed in your Slack workspace. The steps below show exactly how to reach it.", + "steps": [ + { + "title": "Create your free Sim account", + "body": "Sign up at sim.ai — no credit card required." + }, + { + "title": "Add a Slack block", + "body": "Open a workflow, drag in a Slack block, and open its credential dropdown." + }, + { + "title": "Connect Slack", + "body": "Click Connect Slack, choose your workspace, and approve the requested permissions. This installs the Sim bot in your Slack workspace." + }, + { + "title": "Invite the bot and build", + "body": "Invite the Sim bot to the channels it should act in, pick a Slack action, wire it into your agent, and run." + } + ] + }, + "privacy": { + "body": "Sim requests only the Slack permissions its actions and triggers need, and never shows private channel names or messages to people who are not members of those channels in Slack.", + "href": "/privacy" + } + } }, { "type": "smtp", diff --git a/apps/sim/app/(landing)/integrations/data/landing-content.ts b/apps/sim/app/(landing)/integrations/data/landing-content.ts index 30a9ecff2ea..7004c1f785a 100644 --- a/apps/sim/app/(landing)/integrations/data/landing-content.ts +++ b/apps/sim/app/(landing)/integrations/data/landing-content.ts @@ -1,32 +1,12 @@ /** - * Hand-authored, integration-specific landing content that augments the - * generated `integrations.json`. Kept in a separate module so it survives - * regeneration by `scripts/generate-docs.ts`. Keyed by integration slug; - * the integration detail page renders these sections only when present. + * Hand-authored, integration-specific landing content, keyed by integration + * slug. This is a pure-data generation input: `scripts/generate-docs.ts` reads + * it and bakes the matching entry into `integrations.json`, so the landing page + * consumes a single source (`integration.landingContent`) with no render-time + * augmentation. Has no app imports so the build script can import it safely. */ -export interface IntegrationInstallStep { - title: string - body: string -} - -export interface IntegrationLandingContent { - /** - * Install walkthrough for OAuth apps whose connection lives behind sign-in. - * Provides the "Add to {app}" instructions that app marketplaces require - * when the install button sits behind a login. - */ - install?: { - heading: string - intro: string - steps: IntegrationInstallStep[] - } - /** Short data-handling summary shown next to a privacy-policy link. */ - privacy?: { - body: string - href: string - } -} +import type { IntegrationLandingContent } from '@/app/(landing)/integrations/data/types' export const INTEGRATION_LANDING_CONTENT: Record = { slack: { diff --git a/apps/sim/app/(landing)/integrations/data/types.ts b/apps/sim/app/(landing)/integrations/data/types.ts index 7ba6483d6b8..bcdc0f732ac 100644 --- a/apps/sim/app/(landing)/integrations/data/types.ts +++ b/apps/sim/app/(landing)/integrations/data/types.ts @@ -19,6 +19,29 @@ export interface FAQItem { answer: string } +export interface IntegrationInstallStep { + title: string + body: string +} + +export interface IntegrationLandingContent { + /** + * Install walkthrough for OAuth apps whose connection lives behind sign-in. + * Provides the "Add to {app}" instructions that app marketplaces require + * when the install button sits behind a login. + */ + install?: { + heading: string + intro: string + steps: IntegrationInstallStep[] + } + /** Short data-handling summary shown next to a privacy-policy link. */ + privacy?: { + body: string + href: string + } +} + export interface Integration { type: string slug: string @@ -36,4 +59,5 @@ export interface Integration { category: string integrationTypes?: string[] tags?: string[] + landingContent?: IntegrationLandingContent } diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index c2c50cbbc6a..9b806264a4d 100755 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -1,7 +1,7 @@ #!/usr/bin/env ts-node import fs from 'fs' import path from 'path' -import { fileURLToPath } from 'url' +import { fileURLToPath, pathToFileURL } from 'url' import { glob } from 'glob' console.log('Starting documentation generator...') @@ -183,6 +183,7 @@ interface IntegrationEntry { category: string integrationTypes?: string[] tags?: string[] + landingContent?: Record } /** @@ -665,6 +666,19 @@ async function writeIntegrationsJson(iconMapping: Record): Promi const triggerRegistry = await buildTriggerRegistry() const { desc: toolDescMap, name: toolNameMap } = await buildToolDescriptionMap() + + // Hand-authored, integration-specific landing content (install walkthrough, + // privacy blurb), keyed by slug. Imported as pure data — its only import is + // type-only and erased at runtime — and baked into the entries below so the + // landing page reads a single source instead of augmenting at render time. + const landingContentModule = await import( + pathToFileURL(path.join(LANDING_INTEGRATIONS_DATA_PATH, 'landing-content.ts')).href + ) + const landingContentMap = (landingContentModule.INTEGRATION_LANDING_CONTENT ?? {}) as Record< + string, + Record + > + const integrations: IntegrationEntry[] = [] const seenBaseTypes = new Set() const blockFiles = (await glob(`${BLOCKS_PATH}/*.ts`)).sort() @@ -778,6 +792,7 @@ async function writeIntegrationsJson(iconMapping: Record): Promi } : {}), ...(config.tags ? { tags: config.tags } : {}), + ...(landingContentMap[slug] ? { landingContent: landingContentMap[slug] } : {}), }) } }