feat(integrations): add Discord/Telegram Coming soon placeholders

Show greyed non-interactive messenger cards with a Coming soon badge
(matching integration card chrome, no expandable controls), and refresh
third-party statuses immediately after Apply & Restart clears pending
plugin restarts.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
Serhii Dziupin
2026-08-14 15:19:25 +00:00
committed by Cursor Agent
co-authored by Serhii Dziupin
parent 2303740b4a
commit a838f62b41
9 changed files with 203 additions and 1 deletions
@@ -227,6 +227,7 @@ export const iconSpriteData = {
"target": `<path d="M12 1.99999C12.5523 1.99999 13 2.4477 13 2.99999C12.9999 3.55224 12.5522 3.99999 12 3.99999C7.58172 3.99999 4 7.58171 4 12C4.00004 16.4182 7.58174 20 12 20C16.4182 20 19.9999 16.4182 20 12C20 11.4477 20.4477 11 21 11C21.5523 11 22 11.4477 22 12C21.9999 17.5228 17.5228 22 12 22C6.47717 22 2.00004 17.5228 2 12C2 6.47714 6.47715 1.99999 12 1.99999ZM12 5.99999C12.5523 5.99999 13 6.4477 13 6.99999C12.9999 7.55224 12.5522 7.99999 12 7.99999C9.79085 7.99999 7.99999 9.79085 7.99999 12C8.00004 14.2091 9.79088 16 12 16C14.2091 16 15.9999 14.2091 16 12C16 11.4477 16.4477 11 17 11C17.5523 11 18 11.4477 18 12C17.9999 15.3137 15.3137 18 12 18C8.68631 18 6.00004 15.3137 6 12C6 8.68628 8.68629 5.99999 12 5.99999ZM17.6562 2.10057C18.0468 1.71005 18.6807 1.71005 19.0713 2.10057C19.4614 2.49105 19.4615 3.12419 19.0713 3.51463L18.3633 4.22069L18.3642 4.22167C17.9737 4.61219 17.9737 5.2452 18.3642 5.63573C18.7548 6.02612 19.3878 6.02621 19.7783 5.63573L20.4853 4.9287C20.8759 4.53839 21.5089 4.53826 21.8994 4.9287C22.2899 5.31915 22.2897 5.95222 21.8994 6.34276L19.7783 8.46483C19.5909 8.65223 19.3363 8.75671 19.0713 8.75682H16.6572L12.707 12.707C12.3165 13.0974 11.6834 13.0974 11.293 12.707C10.9025 12.3165 10.9026 11.6835 11.293 11.293L15.2422 7.34374V4.9287C15.2422 4.66356 15.3477 4.40916 15.5351 4.22167L17.6562 2.10057Z" fill="currentColor"/>`,
"target-fill": `<path d="M12 2C12.5523 2 13 2.44772 13 3C13 3.55228 12.5523 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 11.4477 20.4477 11 21 11C21.5523 11 22 11.4477 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 6C12.5523 6 13 6.44772 13 7C13 7.55228 12.5523 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 11.4477 16.4477 11 17 11C17.5523 11 18 11.4477 18 12C18 15.3137 15.3137 18 12 18C8.68629 18 6 15.3137 6 12C6 8.68629 8.68629 6 12 6ZM18.5713 2.10059C18.8474 2.1006 19.0712 2.32449 19.0713 2.60059V4.42969C19.0716 4.70553 19.2954 4.92866 19.5713 4.92871H21.3994C21.6754 4.92871 21.8992 5.15275 21.8994 5.42871V6.34375L20.0107 8.23242C19.6358 8.60719 19.1268 8.81824 18.5967 8.81836H16.5967L12.707 12.707C12.3165 13.0974 11.6835 13.0975 11.293 12.707C10.9027 12.3165 10.9026 11.6834 11.293 11.293L15.1826 7.4043V5.4043C15.1826 4.87411 15.3928 4.36526 15.7676 3.99023L17.6572 2.10059H18.5713Z" fill="currentColor"/>`,
"task": `<path d="M19 4H5V20H19V4ZM3 2.9918C3 2.44405 3.44749 2 3.9985 2H19.9997C20.5519 2 20.9996 2.44772 20.9997 3L21 20.9925C21 21.5489 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5447 3 21.0082V2.9918ZM11.2929 13.1213L15.5355 8.87868L16.9497 10.2929L11.2929 15.9497L7.40381 12.0607L8.81802 10.6464L11.2929 13.1213Z" fill="currentColor"/>`,
"telegram-fill": `<path d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM12.3584 9.38246C11.3857 9.78702 9.4418 10.6244 6.5266 11.8945C6.05321 12.0827 5.80524 12.2669 5.78266 12.4469C5.74451 12.7513 6.12561 12.8711 6.64458 13.0343C6.71517 13.0565 6.78832 13.0795 6.8633 13.1039C7.37388 13.2698 8.06071 13.464 8.41776 13.4717C8.74164 13.4787 9.10313 13.3452 9.50222 13.0711C12.226 11.2325 13.632 10.3032 13.7203 10.2832C13.7826 10.269 13.8689 10.2513 13.9273 10.3032C13.9858 10.3552 13.98 10.4536 13.9739 10.48C13.9361 10.641 12.4401 12.0318 11.666 12.7515C11.4351 12.9661 11.2101 13.1853 10.9833 13.4039C10.509 13.8611 10.1533 14.204 11.003 14.764C11.8644 15.3317 12.7323 15.8982 13.5724 16.4971C13.9867 16.7925 14.359 17.0579 14.8188 17.0156C15.0861 16.991 15.3621 16.7397 15.5022 15.9903C15.8335 14.2193 16.4847 10.3821 16.6352 8.80083C16.6484 8.6623 16.6318 8.485 16.6185 8.40717C16.6052 8.32934 16.5773 8.21844 16.4762 8.13635C16.3563 8.03913 16.1714 8.01863 16.0887 8.02009C15.7125 8.02672 15.1355 8.22737 12.3584 9.38246Z" fill="currentColor"/>`,
"terminal": `<path d="M10.9999 12L3.92886 19.0711L2.51465 17.6569L8.1715 12L2.51465 6.34317L3.92886 4.92896L10.9999 12ZM10.9999 19H20.9999V21H10.9999V19Z" fill="currentColor"/>`,
"terminal-box": `<path d="M3 3H21C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3ZM4 5V19H20V5H4ZM12 15H18V17H12V15ZM8.66685 12L5.83842 9.17157L7.25264 7.75736L11.4953 12L7.25264 16.2426L5.83842 14.8284L8.66685 12Z" fill="currentColor"/>`,
"terminal-window": `<path d="M20 9V5H4V9H20ZM20 11H4V19H20V11ZM3 3H21C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3ZM5 12H8V17H5V12ZM5 6H7V8H5V6ZM9 6H11V8H9V6Z" fill="currentColor"/>`,
@@ -0,0 +1,74 @@
import React from 'react';
import { Icon } from '@/components/icon/Icon';
import { SettingsSection } from '@/components/sections/shared/SettingsSection';
import type { IconName } from '@/components/icon/icons';
import { useI18n, type I18nKey } from '@/lib/i18n';
import { cn } from '@/lib/utils';
type ComingSoonMessenger = {
id: 'discord' | 'telegram';
icon: IconName;
brandClassName: string;
nameKey: I18nKey;
descriptionKey: I18nKey;
};
const COMING_SOON_MESSENGERS: readonly ComingSoonMessenger[] = [
{
id: 'discord',
icon: 'discord-fill',
brandClassName: 'text-[#5865F2]',
nameKey: 'settings.integrations.messengers.discord.name',
descriptionKey: 'settings.integrations.messengers.discord.description',
},
{
id: 'telegram',
icon: 'telegram-fill',
brandClassName: 'text-[#2AABEE]',
nameKey: 'settings.integrations.messengers.telegram.name',
descriptionKey: 'settings.integrations.messengers.telegram.description',
},
] as const;
/**
* Non-interactive Discord/Telegram placeholders same card chrome as live
* integrations, greyed out, with a Coming soon badge and no expandable body.
*/
export const ComingSoonMessengersSection: React.FC = () => {
const { t } = useI18n();
return (
<SettingsSection
title={t('settings.integrations.messengers.title')}
info={t('settings.integrations.messengers.info')}
divider={false}
settingsItem="integrations.messengers"
contentClassName="space-y-3"
>
{COMING_SOON_MESSENGERS.map((messenger) => (
<div
key={messenger.id}
data-settings-item={`integrations.messengers.${messenger.id}`}
aria-disabled="true"
className={cn(
'flex min-w-0 items-center gap-3 rounded-xl border border-[var(--interactive-border)] bg-[var(--surface-elevated)] px-4 py-3',
'pointer-events-none opacity-60',
)}
>
<div className="flex size-10 shrink-0 items-center justify-center rounded-[10px] bg-[var(--surface-muted)]">
<Icon name={messenger.icon} className={cn('size-5', messenger.brandClassName)} />
</div>
<div className="min-w-0 flex-1">
<div className="truncate text-sm font-semibold text-foreground">{t(messenger.nameKey)}</div>
<p className="mt-0.5 line-clamp-1 text-xs leading-snug text-muted-foreground">
{t(messenger.descriptionKey)}
</p>
</div>
<span className="max-w-36 shrink-0 truncate rounded-full bg-[var(--surface-muted)] px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
{t('settings.common.state.comingSoon')}
</span>
</div>
))}
</SettingsSection>
);
};
@@ -1,6 +1,7 @@
import React from 'react';
import { SettingsPageLayout } from '@/components/sections/shared/SettingsPageLayout';
import { useI18n } from '@/lib/i18n';
import { ComingSoonMessengersSection } from './ComingSoonMessengersSection';
import { ThirdPartyIntegrationsSection } from './ThirdPartyIntegrationsSection';
interface IntegrationsPageProps {
@@ -20,6 +21,7 @@ export const IntegrationsPage: React.FC<IntegrationsPageProps> = ({
description={t('settings.page.integrations.description')}
showSaveStatus={false}
>
<ComingSoonMessengersSection />
<ThirdPartyIntegrationsSection
onOpenProviderSetup={onOpenProviderSetup}
onOpenPluginManager={onOpenPluginManager}
@@ -20,6 +20,7 @@ import {
usePluginsStore,
type PluginMutationResult,
} from '@/stores/usePluginsStore';
import { usePendingOpenCodeRestartStore } from '@/stores/usePendingOpenCodeRestartStore';
import {
getCatalogPluginPrimaryAction,
getCatalogPluginPresentation,
@@ -112,6 +113,30 @@ export const ThirdPartyIntegrationsSection: React.FC<ThirdPartyIntegrationsSecti
void refresh();
}, [refresh]);
const pendingPluginRestartCount = usePendingOpenCodeRestartStore(
(state) => state.changes.filter((change) => change.scope === 'plugins').length,
);
const isApplyingRestart = usePendingOpenCodeRestartStore((state) => state.isApplying);
const previousPluginRestartCountRef = React.useRef(pendingPluginRestartCount);
// When deferred plugin restarts are applied (pending plugins scope clears), drop
// local restart/unavailable flags and reload so statuses update immediately.
React.useEffect(() => {
const previousCount = previousPluginRestartCountRef.current;
previousPluginRestartCountRef.current = pendingPluginRestartCount;
if (isApplyingRestart) {
return;
}
if (previousCount <= 0 || pendingPluginRestartCount > 0) {
return;
}
setRestartRequiredIds(new Set());
setProviderUnavailableIds(new Set());
void refresh();
}, [isApplyingRestart, pendingPluginRestartCount, refresh]);
const setRestartRequired = React.useCallback((pluginId: string, required: boolean) => {
setRestartRequiredIds((current) => {
const next = new Set(current);
@@ -6,6 +6,9 @@ const locales = ['en', 'de', 'fr', 'es', 'ja', 'pt-BR', 'uk', 'ko', 'pl', 'zh-CN
const requiredKeys = [
'settings.page.integrations.title',
'settings.page.integrations.description',
'settings.integrations.messengers.title',
'settings.integrations.messengers.discord.name',
'settings.integrations.messengers.telegram.name',
'settings.integrations.thirdParty.title',
'settings.integrations.thirdParty.actions.install',
'settings.integrations.thirdParty.actions.update',
@@ -3,6 +3,12 @@ export const thirdPartyIntegrationI18n = {
en: {
'settings.page.integrations.title': 'Integrations',
'settings.page.integrations.description': 'Connect third-party providers to OpenCode.',
'settings.integrations.messengers.title': 'Messengers',
'settings.integrations.messengers.info': 'Chat with OpenChamber from Discord or Telegram. These bridges are not available yet.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Connect a Discord bot to chat with OpenChamber.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Connect a Telegram bot to chat with OpenChamber.',
'settings.integrations.thirdParty.title': 'Third-party integrations',
'settings.integrations.thirdParty.info': 'Install and manage supported OpenCode provider plugins. Setup opens the providers existing authentication settings.',
'settings.integrations.thirdParty.actions.install': 'Install',
@@ -39,6 +45,12 @@ export const thirdPartyIntegrationI18n = {
de: {
'settings.page.integrations.title': 'Integrationen',
'settings.page.integrations.description': 'Verbinde Drittanbieter-Provider mit OpenCode.',
'settings.integrations.messengers.title': 'Messenger',
'settings.integrations.messengers.info': 'Chatte mit OpenChamber über Discord oder Telegram. Diese Bridges sind noch nicht verfügbar.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Verbinde einen Discord-Bot, um mit OpenChamber zu chatten.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Verbinde einen Telegram-Bot, um mit OpenChamber zu chatten.',
'settings.integrations.thirdParty.title': 'Drittanbieter-Integrationen',
'settings.integrations.thirdParty.info': 'Installiere und verwalte unterstützte OpenCode-Provider-Plugins. Die Einrichtung öffnet die bestehenden Authentifizierungseinstellungen des Providers.',
'settings.integrations.thirdParty.actions.install': 'Installieren',
@@ -75,6 +87,12 @@ export const thirdPartyIntegrationI18n = {
fr: {
'settings.page.integrations.title': 'Intégrations',
'settings.page.integrations.description': 'Connectez des fournisseurs tiers à OpenCode.',
'settings.integrations.messengers.title': 'Messagers',
'settings.integrations.messengers.info': 'Discutez avec OpenChamber depuis Discord ou Telegram. Ces ponts ne sont pas encore disponibles.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Connectez un bot Discord pour discuter avec OpenChamber.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Connectez un bot Telegram pour discuter avec OpenChamber.',
'settings.integrations.thirdParty.title': 'Intégrations tierces',
'settings.integrations.thirdParty.info': 'Installez et gérez les plugins de fournisseurs OpenCode pris en charge. La configuration ouvre les réglages dauthentification existants du fournisseur.',
'settings.integrations.thirdParty.actions.install': 'Installer',
@@ -111,6 +129,12 @@ export const thirdPartyIntegrationI18n = {
es: {
'settings.page.integrations.title': 'Integraciones',
'settings.page.integrations.description': 'Conecta proveedores de terceros a OpenCode.',
'settings.integrations.messengers.title': 'Mensajeros',
'settings.integrations.messengers.info': 'Chatea con OpenChamber desde Discord o Telegram. Estos puentes aún no están disponibles.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Conecta un bot de Discord para chatear con OpenChamber.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Conecta un bot de Telegram para chatear con OpenChamber.',
'settings.integrations.thirdParty.title': 'Integraciones de terceros',
'settings.integrations.thirdParty.info': 'Instala y administra los plugins de proveedores OpenCode compatibles. La configuración abre los ajustes de autenticación existentes del proveedor.',
'settings.integrations.thirdParty.actions.install': 'Instalar',
@@ -147,6 +171,12 @@ export const thirdPartyIntegrationI18n = {
ja: {
'settings.page.integrations.title': '連携',
'settings.page.integrations.description': 'サードパーティープロバイダーを OpenCode に接続します。',
'settings.integrations.messengers.title': 'メッセンジャー',
'settings.integrations.messengers.info': 'Discord または Telegram から OpenChamber とチャットできます。これらの連携はまだ利用できません。',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Discord ボットを接続して OpenChamber とチャットします。',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Telegram ボットを接続して OpenChamber とチャットします。',
'settings.integrations.thirdParty.title': 'サードパーティー連携',
'settings.integrations.thirdParty.info': '対応する OpenCode プロバイダープラグインをインストールして管理します。設定ではプロバイダーの既存の認証設定を開きます。',
'settings.integrations.thirdParty.actions.install': 'インストール',
@@ -183,6 +213,12 @@ export const thirdPartyIntegrationI18n = {
ko: {
'settings.page.integrations.title': '통합',
'settings.page.integrations.description': '서드파티 프로바이더를 OpenCode에 연결합니다.',
'settings.integrations.messengers.title': '메신저',
'settings.integrations.messengers.info': 'Discord 또는 Telegram에서 OpenChamber와 채팅하세요. 이 브리지는 아직 사용할 수 없습니다.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Discord 봇을 연결해 OpenChamber와 채팅하세요.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Telegram 봇을 연결해 OpenChamber와 채팅하세요.',
'settings.integrations.thirdParty.title': '서드파티 통합',
'settings.integrations.thirdParty.info': '지원되는 OpenCode 프로바이더 플러그인을 설치하고 관리합니다. 설정을 누르면 프로바이더의 기존 인증 설정이 열립니다.',
'settings.integrations.thirdParty.actions.install': '설치',
@@ -219,6 +255,12 @@ export const thirdPartyIntegrationI18n = {
pl: {
'settings.page.integrations.title': 'Integracje',
'settings.page.integrations.description': 'Połącz zewnętrznych dostawców z OpenCode.',
'settings.integrations.messengers.title': 'Komunikatory',
'settings.integrations.messengers.info': 'Czatuj z OpenChamber przez Discord lub Telegram. Te mosty nie są jeszcze dostępne.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Połącz bota Discord, aby czatować z OpenChamber.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Połącz bota Telegram, aby czatować z OpenChamber.',
'settings.integrations.thirdParty.title': 'Integracje zewnętrzne',
'settings.integrations.thirdParty.info': 'Instaluj i zarządzaj obsługiwanymi wtyczkami dostawców OpenCode. Konfiguracja otwiera istniejące ustawienia uwierzytelniania dostawcy.',
'settings.integrations.thirdParty.actions.install': 'Zainstaluj',
@@ -255,6 +297,12 @@ export const thirdPartyIntegrationI18n = {
'pt-BR': {
'settings.page.integrations.title': 'Integrações',
'settings.page.integrations.description': 'Conecte provedores de terceiros ao OpenCode.',
'settings.integrations.messengers.title': 'Mensageiros',
'settings.integrations.messengers.info': 'Converse com o OpenChamber pelo Discord ou Telegram. Essas pontes ainda não estão disponíveis.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Conecte um bot do Discord para conversar com o OpenChamber.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Conecte um bot do Telegram para conversar com o OpenChamber.',
'settings.integrations.thirdParty.title': 'Integrações de terceiros',
'settings.integrations.thirdParty.info': 'Instale e gerencie plugins compatíveis de provedores do OpenCode. A configuração abre as definições de autenticação existentes do provedor.',
'settings.integrations.thirdParty.actions.install': 'Instalar',
@@ -291,6 +339,12 @@ export const thirdPartyIntegrationI18n = {
uk: {
'settings.page.integrations.title': 'Інтеграції',
'settings.page.integrations.description': 'Підключайте сторонніх провайдерів до OpenCode.',
'settings.integrations.messengers.title': 'Месенджери',
'settings.integrations.messengers.info': 'Спілкуйтеся з OpenChamber у Discord або Telegram. Ці мости ще недоступні.',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': 'Підключіть бота Discord, щоб спілкуватися з OpenChamber.',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': 'Підключіть бота Telegram, щоб спілкуватися з OpenChamber.',
'settings.integrations.thirdParty.title': 'Сторонні інтеграції',
'settings.integrations.thirdParty.info': 'Встановлюйте й керуйте підтримуваними плагінами провайдерів OpenCode. Налаштування відкриває наявні параметри автентифікації провайдера.',
'settings.integrations.thirdParty.actions.install': 'Встановити',
@@ -327,6 +381,12 @@ export const thirdPartyIntegrationI18n = {
'zh-CN': {
'settings.page.integrations.title': '集成',
'settings.page.integrations.description': '将第三方提供商连接到 OpenCode。',
'settings.integrations.messengers.title': '即时通讯',
'settings.integrations.messengers.info': '通过 Discord 或 Telegram 与 OpenChamber 聊天。这些桥接尚不可用。',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': '连接 Discord 机器人以与 OpenChamber 聊天。',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': '连接 Telegram 机器人以与 OpenChamber 聊天。',
'settings.integrations.thirdParty.title': '第三方集成',
'settings.integrations.thirdParty.info': '安装和管理受支持的 OpenCode 提供商插件。设置会打开该提供商已有的身份验证设置。',
'settings.integrations.thirdParty.actions.install': '安装',
@@ -363,6 +423,12 @@ export const thirdPartyIntegrationI18n = {
'zh-TW': {
'settings.page.integrations.title': '整合',
'settings.page.integrations.description': '將第三方供應商連接到 OpenCode。',
'settings.integrations.messengers.title': '即時通訊',
'settings.integrations.messengers.info': '透過 Discord 或 Telegram 與 OpenChamber 聊天。這些橋接尚不可用。',
'settings.integrations.messengers.discord.name': 'Discord',
'settings.integrations.messengers.discord.description': '連接 Discord 機器人以與 OpenChamber 聊天。',
'settings.integrations.messengers.telegram.name': 'Telegram',
'settings.integrations.messengers.telegram.description': '連接 Telegram 機器人以與 OpenChamber 聊天。',
'settings.integrations.thirdParty.title': '第三方整合',
'settings.integrations.thirdParty.info': '安裝並管理支援的 OpenCode 供應商外掛。設定會開啟供應商既有的驗證設定。',
'settings.integrations.thirdParty.actions.install': '安裝',
+1 -1
View File
@@ -202,7 +202,7 @@ export const SETTINGS_PAGE_METADATA: readonly SettingsPageMeta[] = [
{ slug: 'voice', title: 'Voice', group: 'general', kind: 'single', keywords: ['tts', 'speech', 'voice'], isAvailable: (ctx) => !ctx.isVSCode },
{ slug: 'tunnel', title: 'External Tunnel', group: 'projects', kind: 'single', keywords: ['tunnel', 'external', 'cloudflare', 'qr', 'remote', 'mobile', 'share'], isAvailable: (ctx) => !ctx.isVSCode },
{ slug: 'about', title: 'About', group: 'general', kind: 'single', keywords: ['about', 'version', 'updates', 'release', 'changelog'], isAvailable: (ctx) => ctx.isMobile && !ctx.isVSCode },
{ slug: 'integrations', title: 'Integrations', group: 'general', kind: 'single', keywords: ['integration', 'plugin', 'provider', 'oauth', 'claude', 'cursor', 'command code', 'connect'] },
{ slug: 'integrations', title: 'Integrations', group: 'general', kind: 'single', keywords: ['integration', 'plugin', 'provider', 'oauth', 'claude', 'cursor', 'command code', 'connect', 'discord', 'telegram', 'messenger'] },
] as const;
const LEGACY_SIDEBAR_SECTION_TO_SETTINGS_SLUG: Record<SidebarSection, SettingsPageSlug> = {
@@ -27,4 +27,15 @@ describe('settings search', () => {
expect(results.some((result) => result.id === 'integrations.third-party.opencode-claude')).toBe(true);
});
test('finds coming-soon messenger placeholders', () => {
const results = buildSettingsSearchResults({
query: 'discord',
runtimeCtx,
t,
getPageTitle: (page) => page,
});
expect(results.some((result) => result.id === 'integrations.messengers.discord')).toBe(true);
});
});
+20
View File
@@ -934,6 +934,26 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
isAvailable: (ctx) => ctx.isWeb && !ctx.isDesktop && !ctx.isVSCode,
},
{
id: 'integrations.messengers',
page: 'integrations',
titleKey: 'settings.integrations.messengers.title',
keywords: ['messenger', 'discord', 'telegram', 'bot', 'coming soon'],
},
{
id: 'integrations.messengers.discord',
page: 'integrations',
titleKey: 'settings.integrations.messengers.discord.name',
descriptionKey: 'settings.integrations.messengers.discord.description',
keywords: ['discord', 'bot', 'messenger', 'coming soon'],
},
{
id: 'integrations.messengers.telegram',
page: 'integrations',
titleKey: 'settings.integrations.messengers.telegram.name',
descriptionKey: 'settings.integrations.messengers.telegram.description',
keywords: ['telegram', 'bot', 'messenger', 'coming soon'],
},
{
id: 'integrations.third-party',
page: 'integrations',