Agent Skillsnovuhq/novu › add-channel-connect-button

add-channel-connect-button

GitHub

在 Novu SDK 中为新聊天渠道构建连接按钮组件,涵盖 SolidJS 核心、React 包装器、数据层及注册配置。

.cursor/skills/add-channel-connect-button/SKILL.md novuhq/novu

Trigger Scenarios

需要添加新的聊天渠道连接按钮 实现 OAuth 或深度链接集成 UI

Install

npx skills add novuhq/novu --skill add-channel-connect-button -g -y
More Options

Use without installing

npx skills use novuhq/novu@add-channel-connect-button

指定 Agent (Claude Code)

npx skills add novuhq/novu --skill add-channel-connect-button -a claude-code -g -y

安装 repo 全部 skill

npx skills add novuhq/novu --all -g -y

预览 repo 内 skill

npx skills add novuhq/novu --list

SKILL.md

Frontmatter
{
    "name": "add-channel-connect-button",
    "description": "Build a new channel Connect button (e.g. WhatsApp, Discord, LINE) in @novu\/js and @novu\/react following the existing SlackConnectButton, MsTeamsConnectButton, and TelegramConnectButton pattern. Use when adding connect\/disconnect UI for a new chat channel\/provider to the SDK — covering the SolidJS core component, the React wrapper, the channelConnections (OAuth) vs channelEndpoints (deep-link) data layer, the component registry, and package exports."
}

Add a Channel Connect Button

Build <Channel>ConnectButton for a new chat provider, mirroring Slack, MsTeams, and Telegram. The button lets a subscriber connect (open OAuth popup / deep link) and disconnect a channel, with loading + connected states.

Architecture (3 layers)

packages/js (SolidJS core)          packages/react (public wrapper)
─────────────────────────           ──────────────────────────────
<Channel>ConnectButton.tsx   ◄────  Default<Channel>ConnectButton.tsx  (Mounter → mountComponent)
  uses a data hook                  <Channel>ConnectButton.tsx          (memo → NovuUI → withRenderer)
  calls novu.channel*  SDK
registered in Renderer.tsx

The React component mounts the SolidJS component by name through novuUI.mountComponent. That name must be registered in packages/js/src/ui/components/Renderer.tsx.

Step 0 — Pick the connection model (do this first)

This single decision drives which SDK module, hook, and props you use.

Connection-based — like Slack, MS Teams Endpoint-based — like Telegram
Use when Provider authorizes at workspace/tenant level via OAuth Subscriber links by opening a deep link; no workspace auth
SDK module novu.channelConnections novu.channelEndpoints
Connect call generateConnectOAuthUrl() → OAuth popup URL link({ integrationIdentifier }) → deep-link URL
Detect / poll get(connectionIdentifier) list({ providerId, integrationIdentifier, limit: 1 })
Data hook reuse useChannelConnection new use<Channel>Connection (list-based, copy useTelegramConnection)
Extra props connectionIdentifier, context, scope, connectionMode, autoLinkUser none beyond the base props
Identifier buildDefaultConnectionIdentifier(...) from components/constants.ts not needed

If unsure: OAuth/app-install provider → connection-based; bot deep-link/token provider → endpoint-based.

File checklist

Copy the nearest sibling for your model (Slack/MS Teams = connection, Telegram = endpoint), then rename. Full templates: see reference.md.

Core — packages/js

  • CREATE src/ui/icons/<Channel>Colored.tsx — brand icon (copy TelegramColored.tsx)
  • CREATE src/ui/components/<channel>-connect-button/<Channel>ConnectButton.tsx
  • CREATE (endpoint model only) src/ui/api/hooks/use<Channel>Connection.ts
  • EDIT src/ui/components/Renderer.tsx — import it, add to novuComponents, add the name string to CHANNEL_COMPONENTS
  • EDIT src/ui/components/index.tsexport * from './<channel>-connect-button/<Channel>ConnectButton'
  • EDIT src/ui/index.ts — re-export <Channel>ConnectButtonProps in the type block

React — packages/react

  • CREATE src/components/<channel>-connect-button/Default<Channel>ConnectButton.tsx
  • CREATE src/components/<channel>-connect-button/<Channel>ConnectButton.tsx
  • EDIT src/components/index.tsexport * from './<channel>-connect-button/<Channel>ConnectButton'
  • EDIT src/index.ts — add the component to the value export block and <Channel>ConnectButtonProps to the type block

Usually NOT needed

  • The channelConnections / channelEndpoints SDK modules already cover both models. Only add a new method under packages/js/src/channel-* if the provider needs a brand-new server call (rare). Backend lives in apps/api/src/app/channel-connections/.
  • Never edit libs/internal-sdk (auto-generated).

Button behavior contract

Every connect button implements the same state machine — keep it identical:

  • Initial load: <Show when={!loading()} fallback={<Loader/>}>; derive isConnected() from the hook's connection/endpoint, and isLoading() = loading() || actionLoading().
  • Click when connecteddisconnect(identifier)onDisconnectSuccess() / onDisconnectError(err).
  • Click when not connectedsetActionLoading(true), get the URL, window.open(url, '_blank', 'noopener,noreferrer'), then start polling.
  • Polling → fixed interval (2500ms, 120_000ms timeout) or backoff (see MS Teams). Use a one-shot committed flag / ref so only the first success-or-timeout fires side effects. Clear the timer in onCleanup.
  • Resolve → success: mutate(found) + onConnectSuccess(identifier); timeout: onConnectError(new Error(...)).
  • Appearance → reuse the shared keys channelConnectButtonContainer | Button | Inner | Icon | Label, each passed { connected } context. Icons go through IconRendererWrapper (keys channelConnect / channelConnected) with a fallback to <Channel>Colored / CheckCircleFill. Do not add new appearance keys — they are shared across all connect buttons.
  • Base propsintegrationIdentifier (required), subscriberId?, onConnectSuccess?, onConnectError?, onDisconnectSuccess?, onDisconnectError?, connectLabel?, connectedLabel?.

Conventions & gotchas

  • The core is SolidJS, not React: signals over hooks, <Show> over ternaries, read props lazily (() => props.x), cleanup via onCleanup. The React layer is just a mounting shim.
  • The name in mountComponent({ name: '<Channel>ConnectButton' }) must equal the key in novuComponents and be listed in CHANNEL_COMPONENTS, or it renders through the wrong path.
  • <Channel>ConnectButtonProps is defined in the core and imported by React from @novu/js/ui — do not redefine it.
  • Novu conventions: lowercase-dashed dirs, named exports, blank line before every return, no nested ternaries.
  • These packages are published — new exports are a minor bump; keep prop changes additive/backward-compatible.

Build & verify

  1. pnpm build (required after changing packages/).
  2. Type-check + lint the touched files.
  3. Manual test: add a page/tab in playground/nextjs (copy src/components/telegram-end-user-connect.tsx) that wraps <Channel>ConnectButton in <NovuProvider>, then connect/disconnect against a real integration.

Version History

  • 56a8a16 Current 2026-08-29 05:10

Same Skill Collection

.agents/skills/email-best-practices/SKILL.md
.agents/skills/frontend-design/SKILL.md
.agents/skills/linear-release-setup/SKILL.md
.agents/skills/react-email/SKILL.md
.agents/skills/testerarmy-cli/SKILL.md
.claude/skills/better-auth-best-practices/SKILL.md
.cursor/skills/add-channel-setup-guide/SKILL.md
.cursor/skills/address-pr-review/SKILL.md
.cursor/skills/better-auth-best-practices/SKILL.md
.cursor/skills/ink-tui/SKILL.md
.cursor/skills/novu-prepare-pr/SKILL.md
.cursor/skills/nv-implement/SKILL.md
.cursor/skills/nv-park-and-review/SKILL.md
.cursor/skills/nv-worktree-cleanup/SKILL.md
.cursor/skills/nv-worktree-commands/SKILL.md
.cursor/skills/nv-worktree-create/SKILL.md
.cursor/skills/run-api-e2e-tests/SKILL.md
.cursor/skills/sanity-changelog/SKILL.md
.cursor/skills/triage-agent-eval-failures/SKILL.md
docs/.mintlify/skills/dashboard-workflows/SKILL.md
docs/.mintlify/skills/manage-preferences/SKILL.md
docs/.mintlify/skills/manage-subscribers/SKILL.md
docs/.mintlify/skills/trigger-notification/SKILL.md
.agents/skills/figma-use/SKILL.md
.cursor/skills/add-channel-whats-next-onboarding/SKILL.md
.cursor/skills/nv-endpoint-routed-tool-provider/SKILL.md
docs/.mintlify/skills/design-workflow/SKILL.md
docs/.mintlify/skills/framework-integration/SKILL.md
docs/.mintlify/skills/inbox-integration/SKILL.md

Metadata

Files
0
Version
56a8a16
Hash
5200feee
Indexed
2026-08-29 05:10

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-01 21:26
浙ICP备14020137号-1 $Carte des visiteurs$