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} + +
+ +
+ + )} + + {/* Privacy & data (integration-specific) */} + {landingContent?.privacy && ( + <> +
+

+ Privacy & data +

+

+ {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..8fc5c3856ff 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", @@ -13288,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 new file mode 100644 index 00000000000..7004c1f785a --- /dev/null +++ b/apps/sim/app/(landing)/integrations/data/landing-content.ts @@ -0,0 +1,41 @@ +/** + * 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. + */ + +import type { IntegrationLandingContent } from '@/app/(landing)/integrations/data/types' + +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. 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', + }, + }, +} 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] } : {}), }) } }