From eb98b9b78184043fdd467aa067b1ff290fbd74d1 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 17 Sep 2026 10:47:10 +0300 Subject: [PATCH] =?UTF-8?q?:sparkles:=20feat(settings):=20=D1=83=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=B6=D0=B4=D0=BE=D0=B3=D0=BE=20=D0=BF=D0=BE=D0=B4=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81=D1=81=D1=8B?= =?UTF-8?q?=D0=BB=D0=BA=D0=B0=20=D0=BD=D0=B0=20=D1=81=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=D1=8E=20=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Токен бота, ключ доступа сообщества, пароль ящика — всё это выдаёт не наша система, и человек уходит искать инструкцию в поиске, хотя она написана и лежит в Центре помощи. Теперь под выбором типа стоит ссылка на статью именно про этот тип: Telegram, MAX, ВКонтакте, почтовый ящик, веб-виджет. Адрес Центра помощи один на продукт — это документация Chatballs, а не портал организации, поэтому он лежит константой в shared/help и от установки не зависит. Статья у типа подключения необязательна: у LLM-провайдеров ссылки пока нет, и форма просто её не рисует. Ссылка оформлена общим классом `.link` в роли второстепенной и стоит подписью к полю «Тип» — своего стиля у неё нет. Проверено: tsc, тесты каталога переводов и модели подключений, вид формы на изолированном макете со штатными стилями. Co-Authored-By: Claude Opus 5 --- .../src/features/integrations/IntegrationForm.tsx | 7 +++++++ apps/internal-ui/src/features/integrations/model.ts | 12 +++++++----- .../internal-ui/src/features/integrations/styles.css | 8 ++++++++ apps/internal-ui/src/i18n/en.ts | 1 + apps/internal-ui/src/i18n/ru.ts | 1 + apps/internal-ui/src/shared/help.ts | 12 ++++++++++++ 6 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 apps/internal-ui/src/shared/help.ts diff --git a/apps/internal-ui/src/features/integrations/IntegrationForm.tsx b/apps/internal-ui/src/features/integrations/IntegrationForm.tsx index 435da3f..41a1061 100644 --- a/apps/internal-ui/src/features/integrations/IntegrationForm.tsx +++ b/apps/internal-ui/src/features/integrations/IntegrationForm.tsx @@ -2,6 +2,7 @@ import { Modal } from "antd"; import { useEffect, useState } from "react"; import { api } from "../../api/client"; +import { helpArticleUrl } from "../../shared/help"; import { Icon } from "../../shared/icons"; import { FormField, SelectField } from "../../shared/form-controls"; import { Button } from "../../shared/ui-controls"; @@ -124,6 +125,12 @@ export function IntegrationForm({ initial, kind, onClose, onSaved }: { initial: ) : ( setProvider(value as IntegrationProvider)} options={options} /> )} + {meta.helpSlug && ( + + {t("settings.how_to_connect")} + + + )} {isEmail && } {meta.testable && ( diff --git a/apps/internal-ui/src/features/integrations/model.ts b/apps/internal-ui/src/features/integrations/model.ts index 48c68bf..27608b0 100644 --- a/apps/internal-ui/src/features/integrations/model.ts +++ b/apps/internal-ui/src/features/integrations/model.ts @@ -67,6 +67,8 @@ type ProviderMeta = { // (у Web-виджета секрета нет, но backend проверяет привязку к каналу). testable: boolean; checkable: boolean; + // Статья Центра помощи про этот тип подключения (shared/help). + helpSlug?: string; }; export const PROVIDERS: Record = { @@ -76,14 +78,14 @@ export const PROVIDERS: Record = { CUSTOM: { label: "Custom (OpenAI-compatible)", kind: "LLM_PROVIDER", secretLabel: t("settings.api_key"), defaultBaseUrl: "", hasModel: true, testable: true, checkable: true }, // Демо-провайдер — живой AI без ключей и сети для знакомства с системой: отвечает по знаниям агента. DEMO: { label: t("settings.demo_provider_no_key"), kind: "LLM_PROVIDER", secretLabel: "", defaultBaseUrl: "", hasModel: false, testable: false, checkable: true }, - MAX: { label: "MAX", kind: "MESSENGER", secretLabel: t("settings.bot_token"), defaultBaseUrl: "https://platform-api.max.ru", hasModel: false, testable: true, checkable: true }, - TELEGRAM: { label: "Telegram", kind: "MESSENGER", secretLabel: t("settings.bot_token"), defaultBaseUrl: "https://api.telegram.org", hasModel: false, testable: true, checkable: true }, + MAX: { label: "MAX", kind: "MESSENGER", secretLabel: t("settings.bot_token"), defaultBaseUrl: "https://platform-api.max.ru", hasModel: false, testable: true, checkable: true, helpSlug: "max" }, + TELEGRAM: { label: "Telegram", kind: "MESSENGER", secretLabel: t("settings.bot_token"), defaultBaseUrl: "https://api.telegram.org", hasModel: false, testable: true, checkable: true, helpSlug: "telegram" }, // ВКонтакте — сообщество: секрет это ключ доступа сообщества, идентификатор // сообщества подставляет проверка подключения (ADR-CHATBALLS-0020). - VK: { label: "ВКонтакте", kind: "MESSENGER", secretLabel: t("settings.vk_community_key"), defaultBaseUrl: "https://api.vk.com/method", hasModel: false, testable: true, checkable: true }, - WEB: { label: t("common.web_widget"), kind: "MESSENGER", secretLabel: "", defaultBaseUrl: "", hasModel: false, testable: false, checkable: true }, + VK: { label: "ВКонтакте", kind: "MESSENGER", secretLabel: t("settings.vk_community_key"), defaultBaseUrl: "https://api.vk.com/method", hasModel: false, testable: true, checkable: true, helpSlug: "vkontakte" }, + WEB: { label: t("common.web_widget"), kind: "MESSENGER", secretLabel: "", defaultBaseUrl: "", hasModel: false, testable: false, checkable: true, helpSlug: "veb-vidzhet" }, // Email — подключение-ящик IMAP/SMTP (ADR-CHATBALLS-0035); секрет — пароль приложения. - EMAIL: { label: "Email (IMAP/SMTP)", kind: "MESSENGER", secretLabel: t("common.password"), defaultBaseUrl: "", hasModel: false, testable: true, checkable: true }, + EMAIL: { label: "Email (IMAP/SMTP)", kind: "MESSENGER", secretLabel: t("common.password"), defaultBaseUrl: "", hasModel: false, testable: true, checkable: true, helpSlug: "pochtovyj-yashchik" }, }; export const STATUS_META: Record = { diff --git a/apps/internal-ui/src/features/integrations/styles.css b/apps/internal-ui/src/features/integrations/styles.css index cd3de0b..5591664 100644 --- a/apps/internal-ui/src/features/integrations/styles.css +++ b/apps/internal-ui/src/features/integrations/styles.css @@ -138,6 +138,14 @@ font-size: 11.5px; } +/* Ссылка на статью Центра помощи про выбранный тип подключения: стоит под + полем «Тип» подписью к нему, поэтому подтянута к нему вплотную. */ +.integration-form-help { + align-self: flex-start; + margin-top: -10px; + font-size: 12.5px; +} + /* Секции Email-формы: IMAP / SMTP (SPEC-CHATBALLS-0025 §3.2). */ .integration-email-section { display: flex; diff --git a/apps/internal-ui/src/i18n/en.ts b/apps/internal-ui/src/i18n/en.ts index 4d0cd67..bfe7455 100644 --- a/apps/internal-ui/src/i18n/en.ts +++ b/apps/internal-ui/src/i18n/en.ts @@ -1482,6 +1482,7 @@ export const en: Record = { "settings.bot": "Bot", "settings.bot_token": "Bot token", "settings.vk_community_key": "Community access key", + "settings.how_to_connect": "How to connect", "settings.bots_email_web_widget_entry": "Bots, email and the web widget are the entry points for conversations. Each is bound to the agent that answers first.", "settings.bucket": "Bucket", "settings.check": "Check", diff --git a/apps/internal-ui/src/i18n/ru.ts b/apps/internal-ui/src/i18n/ru.ts index 7304ce2..392df62 100644 --- a/apps/internal-ui/src/i18n/ru.ts +++ b/apps/internal-ui/src/i18n/ru.ts @@ -1483,6 +1483,7 @@ export const ru = { "settings.bot": "Бот", "settings.bot_token": "Токен бота", "settings.vk_community_key": "Ключ доступа сообщества", + "settings.how_to_connect": "Как подключить", "settings.bots_email_web_widget_entry": "Боты, почта и Web-виджет — точки входа диалогов. Каждая привязана к агенту, который отвечает первым.", "settings.bucket": "Бакет", "settings.check": "Проверить", diff --git a/apps/internal-ui/src/shared/help.ts b/apps/internal-ui/src/shared/help.ts new file mode 100644 index 0000000..4309a1c --- /dev/null +++ b/apps/internal-ui/src/shared/help.ts @@ -0,0 +1,12 @@ +/* Ссылки на Центр помощи продукта. + + Центр помощи один на продукт и живёт на домене разработчика: это + документация Chatballs, а не портал организации, поэтому адрес здесь + постоянный и от установки не зависит. Порталы самой организации + настраиваются в разделе «Порталы» и к этим ссылкам отношения не имеют. */ + +const HELP_CENTER_URL = "https://chatballs.com.edevs.tech"; + +export function helpArticleUrl(slug: string): string { + return `${HELP_CENTER_URL}/articles/${slug}`; +}