feat(connectors): reskin the connector catalog (#14993)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Raunak BhagatandClaude Fable 5.1 authored and GitHub committed 2026-09-22 21:16:31 +00:00
1 parent ba60745a0b
commit f7ec47079f
31 files changed
+2193 -346

No files matched your search

+2 -3
View File
@@ -1,17 +1,16 @@
import type { IconProps } from "@opal/types";
const SvgFileText = ({ size, ...props }: IconProps) => (
<svg
width={size}
height={size}
viewBox="0 0 16 20"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
stroke="currentColor"
{...props}
>
<path
d="M9.66634 1.6665H2.99967C2.55765 1.6665 2.13372 1.8421 1.82116 2.15466C1.5086 2.46722 1.33301 2.89114 1.33301 3.33317V16.6665C1.33301 17.1085 1.5086 17.5325 1.82116 17.845C2.13372 18.1576 2.55765 18.3332 2.99967 18.3332H12.9997C13.4417 18.3332 13.8656 18.1576 14.1782 17.845C14.4907 17.5325 14.6663 17.1085 14.6663 16.6665V6.6665M9.66634 1.6665L14.6663 6.6665M9.66634 1.6665L9.66634 6.6665L14.6663 6.6665M11.333 10.8332H4.66634M11.333 14.1665H4.66634M6.33301 7.49984H4.66634"
d="M13.3333 5.33337L9.33334 1.33337H4.00001C3.27378 1.33337 2.66667 1.94048 2.66667 2.66671V13.3334C2.66667 14.0596 3.27378 14.6667 4.00001 14.6667H12C12.7262 14.6667 13.3333 14.0596 13.3333 13.3334V5.33337ZM9.33334 1.33337L9.33334 5.33337L13.3333 5.33337M10.6667 8.66671H5.33334M10.6667 11.3334H5.33334M6.66667 6.00004H5.33334"
strokeWidth={1.5}
strokeLinecap="round"
strokeLinejoin="round"
+1 -7
View File
@@ -1,5 +1,4 @@
import type { IconProps } from "@opal/types";
const SvgGlobe = ({ size, ...props }: IconProps) => (
<svg
width={size}
@@ -12,17 +11,12 @@ const SvgGlobe = ({ size, ...props }: IconProps) => (
>
<g clipPath="url(#clip0_16_2601)">
<path
d="M14.6667 7.99999C14.6667 11.6819 11.6819 14.6667 8.00001 14.6667M14.6667 7.99999C14.6667 4.3181 11.6819 1.33333 8.00001 1.33333M14.6667 7.99999H1.33334M8.00001 14.6667C4.31811 14.6667 1.33334 11.6819 1.33334 7.99999M8.00001 14.6667C9.66753 12.8411 10.6152 10.472 10.6667 7.99999C10.6152 5.52802 9.66753 3.1589 8.00001 1.33333M8.00001 14.6667C6.33249 12.8411 5.38484 10.472 5.33334 7.99999C5.38484 5.52802 6.33249 3.1589 8.00001 1.33333M1.33334 7.99999C1.33334 4.3181 4.31811 1.33333 8.00001 1.33333"
d="M14.6667 7.99998C14.6667 11.6819 11.6819 14.6666 7.99999 14.6666M14.6667 7.99998C14.6667 4.31808 11.6819 1.33331 7.99999 1.33331M14.6667 7.99998H1.33333M7.99999 14.6666C4.3181 14.6666 1.33333 11.6819 1.33333 7.99998M7.99999 14.6666C9.66751 12.8411 10.6152 10.472 10.6667 7.99998C10.6152 5.528 9.66751 3.15888 7.99999 1.33331M7.99999 14.6666C6.33247 12.8411 5.38483 10.472 5.33333 7.99998C5.38483 5.528 6.33247 3.15888 7.99999 1.33331M1.33333 7.99998C1.33333 4.31808 4.3181 1.33331 7.99999 1.33331"
strokeWidth={1.5}
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_16_2601">
<rect width={16} height={16} fill="white" />
</clipPath>
</defs>
</svg>
);
export default SvgGlobe;
@@ -1,7 +1,7 @@
@reference "#reference.css";
.opal-content-action {
@apply flex flex-row w-full gap-4 items-stretch;
@apply flex flex-row w-full items-stretch gap-0;
}
.opal-content-action[data-centered="true"] {
+7
View File
@@ -209,6 +209,13 @@ const nextConfig = {
destination: "/admin/web-search",
permanent: true,
},
// The connector catalog moved from /admin/add-connector to
// /admin/connectors, beside the per-source wizard at /admin/connectors/:source.
{
source: "/admin/add-connector",
destination: "/admin/connectors",
permanent: true,
},
// Replaces the redirect page that used to live at
// /admin/configuration/craft, kept for /admin/craft/access bookmarks.
{
+1
View File
@@ -0,0 +1 @@
export { default } from "@/views/admin/ConnectorsPage";
+1 -1
View File
@@ -223,7 +223,7 @@ export default function Status() {
icon={route.icon}
title={adminRouteTitle(route)}
rightChildren={
<Button href="/admin/add-connector">
<Button href={ADMIN_ROUTES.CONNECTORS.path}>
{t("status.addConnectorButton.label")}
</Button>
}
-44
View File
@@ -1,44 +0,0 @@
import { SourceIcon } from "@/components/SourceIcon";
import Link from "next/link";
import type { Route } from "next";
import { SourceMetadata } from "@/lib/search/types";
import React from "react";
import Text from "@/refresh-components/texts/Text";
interface SourceTileProps {
sourceMetadata: SourceMetadata;
preSelect?: boolean;
navigationUrl: string;
hasExistingSlackCredentials: boolean;
}
export default function SourceTile({
sourceMetadata,
preSelect,
navigationUrl,
}: SourceTileProps) {
return (
<Link
className={`flex
flex-col
items-center
justify-center
p-4
rounded-lg
w-40
cursor-pointer
shadow-md
bg-background-tint-00
hover:bg-background-tint-02
relative
${preSelect ? "subtle-pulse" : ""}
`}
href={navigationUrl as Route}
>
<SourceIcon sourceType={sourceMetadata.internalName} iconSize={24} />
<Text as="p" className="pt-2">
{sourceMetadata.displayName}
</Text>
</Link>
);
}
+202 -14
View File
@@ -779,41 +779,229 @@
"addConnector": {
"categories": {
"codeRepository": {
"label": "مستودع أكواد"
"label": "مستودعات الأكواد"
},
"messaging": {
"label": "المراسلة"
},
"other": {
"label": "أخرى"
},
"sales": {
"label": "المبيعات"
"label": "المبيعات والتسويق"
},
"storage": {
"label": "التخزين السحابي"
},
"ticketingAndTaskManagement": {
"label": "التذاكر وإدارة المهام"
"label": "التذاكر والمهام"
},
"wiki": {
"label": "قواعد المعرفة والويكي"
},
"aiObservability": {
"label": "الذكاء الاصطناعي والمراقبة"
},
"other": {
"label": "أخرى"
}
},
"popular": {
"title": "الشائعة"
"title": "إضافة موصّل",
"description": "اربط {appName} بمصادر بياناتك."
},
"search": {
"placeholder": "البحث في الموصلات"
},
"seeConnectorsButton": {
"label": "عرض الموصلات"
"placeholder": "البحث في الموصلات..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>موصل موحّد مهيأ بالفعل.</strong> انقر لتعديل الموصل الحالي.",
"slackCredentialsFound": "<strong>تم العثور على بيانات اعتماد Slack موجودة.</strong> انقر لإدارة موصل Slack الخاص بك."
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "ربط {source}"
}
},
"sources": {
"web": {
"description": "ربط أي عنوان URL عام"
},
"github": {
"description": "الكود وطلبات السحب"
},
"gitlab": {
"description": "الكود و CI/CD"
},
"slack": {
"description": "مراسلة الفريق"
},
"googleDrive": {
"description": "الملفات والمجلدات المشتركة"
},
"gmail": {
"description": "بريد Google"
},
"bookstack": {
"description": "ويكي مستضاف ذاتيًا"
},
"outline": {
"description": "ويكي فريق مفتوح المصدر"
},
"confluence": {
"description": "ويكي Atlassian"
},
"jira": {
"description": "متتبع مشكلات Atlassian"
},
"productboard": {
"description": "إدارة المنتجات"
},
"slab": {
"description": "ويكي الفريق"
},
"coda": {
"description": "المستندات وقواعد البيانات"
},
"notion": {
"description": "المستندات وقواعد البيانات"
},
"guru": {
"description": "قاعدة معرفة موثّقة"
},
"gong": {
"description": "تحليل مكالمات المبيعات"
},
"zulip": {
"description": "مراسلة مفتوحة المصدر"
},
"linear": {
"description": "متتبع مشكلات الهندسة"
},
"hubspot": {
"description": "التسويق وإدارة علاقات العملاء"
},
"document360": {
"description": "وثائق الخدمة الذاتية"
},
"file": {
"description": "رفع من الملفات المحلية"
},
"userFile": {
"description": "الملفات المرفوعة في الدردشة"
},
"googleSites": {
"description": "صفحات مستضافة على Google"
},
"loopio": {
"description": "الرد على طلبات العروض"
},
"box": {
"description": "الملفات والمجلدات والملاحظات"
},
"dropbox": {
"description": "الملفات والمجلدات المشتركة"
},
"discord": {
"description": "مراسلة المجتمع"
},
"salesforce": {
"description": "المبيعات وإدارة علاقات العملاء"
},
"sharepoint": {
"description": "شبكة Microsoft الداخلية"
},
"teams": {
"description": "دردشات فرق Microsoft"
},
"outlook": {
"description": "رسائل البريد ومجلداته"
},
"zendesk": {
"description": "تذاكر دعم العملاء"
},
"discourse": {
"description": "منتدى المجتمع"
},
"axero": {
"description": "شبكة داخلية اجتماعية"
},
"clickup": {
"description": "متتبع المشاريع والمهام"
},
"wikipedia": {
"description": "قاعدة معرفة عامة"
},
"mediawiki": {
"description": "ويكي بنمط ويكيبيديا"
},
"asana": {
"description": "إدارة العمل"
},
"s3": {
"description": "حاويات تخزين AWS"
},
"r2": {
"description": "حاويات التخزين السحابي"
},
"googleCloudStorage": {
"description": "حاويات Google Cloud"
},
"xenforo": {
"description": "منتدى المجتمع"
},
"ociStorage": {
"description": "تخزين كائنات OCI"
},
"notApplicable": {
"description": "لا يوجد مصدر"
},
"ingestionApi": {
"description": "المستندات المرسلة عبر واجهة البرمجة"
},
"freshdesk": {
"description": "مكتب مساعدة العملاء"
},
"fireflies": {
"description": "ملاحظات الاجتماعات"
},
"egnyte": {
"description": "خدمات ملفات مُدارة"
},
"airtable": {
"description": "قاعدة بيانات ومهام"
},
"gitbook": {
"description": "وثائق المطورين"
},
"highspot": {
"description": "تمكين المبيعات"
},
"drupalWiki": {
"description": "ويكي قائم على نظام إدارة محتوى"
},
"imap": {
"description": "مصدر بريد IMAP"
},
"bitbucket": {
"description": "إدارة الشيفرة من Atlassian"
},
"testrail": {
"description": "تتبع حالات الاختبار"
},
"braintrust": {
"description": "السجلات والتقييمات"
},
"lumapps": {
"description": "صفحات الشبكة الداخلية والمجتمعات"
},
"canvas": {
"description": "الدورات والصفحات والإعلانات"
},
"craftFile": {
"description": "الملفات التي رفعتها"
},
"federatedSlack": {
"description": "البحث في Slack عند الاستعلام"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "تم إنشاء الموصل بنجاح"
},
"empty": {
"message": "يبدو أنه ليس لديك أي موصلات معدّة بعد. زر صفحة [إضافة موصل](/admin/add-connector) للبدء!"
"message": "يبدو أنه ليس لديك أي موصلات معدّة بعد. زر صفحة [إضافة موصل](/admin/connectors) للبدء!"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "إضافة موصل"
"connectors": {
"label": "الموصلات"
},
"agents": {
"label": "الوكلاء"
+202 -14
View File
@@ -779,41 +779,229 @@
"addConnector": {
"categories": {
"codeRepository": {
"label": "Code-Repository"
"label": "Code-Repositories"
},
"messaging": {
"label": "Messaging"
},
"other": {
"label": "Sonstige"
},
"sales": {
"label": "Vertrieb"
"label": "Vertrieb & GTM"
},
"storage": {
"label": "Cloud-Speicher"
},
"ticketingAndTaskManagement": {
"label": "Ticketing & Aufgabenverwaltung"
"label": "Tickets & Aufgaben"
},
"wiki": {
"label": "Wissensbasis & Wikis"
},
"aiObservability": {
"label": "KI & Observability"
},
"other": {
"label": "Sonstige"
}
},
"popular": {
"title": "Beliebt"
"title": "Connector hinzufügen",
"description": "Verbinden Sie {appName} mit Ihren Datenquellen."
},
"search": {
"placeholder": "Konnektoren suchen"
},
"seeConnectorsButton": {
"label": "Konnektoren anzeigen"
"placeholder": "Konnektoren suchen..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>Föderierter Konnektor bereits konfiguriert.</strong> Klicken Sie, um den vorhandenen Konnektor zu bearbeiten.",
"slackCredentialsFound": "<strong>Vorhandene Slack-Anmeldedaten gefunden.</strong> Klicken Sie, um Ihren Slack-Konnektor zu verwalten."
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "{source} verbinden"
}
},
"sources": {
"web": {
"description": "Beliebige öffentliche URL verknüpfen"
},
"github": {
"description": "Code & Pull Requests"
},
"gitlab": {
"description": "Code & CI/CD"
},
"slack": {
"description": "Team-Messaging"
},
"googleDrive": {
"description": "Geteilte Dateien und Ordner"
},
"gmail": {
"description": "Google-E-Mail"
},
"bookstack": {
"description": "Selbst gehostetes Wiki"
},
"outline": {
"description": "Open-Source-Team-Wiki"
},
"confluence": {
"description": "Atlassian-Wiki"
},
"jira": {
"description": "Atlassian-Issue-Tracker"
},
"productboard": {
"description": "Produktmanagement"
},
"slab": {
"description": "Team-Wiki"
},
"coda": {
"description": "Dokumente & Datenbanken"
},
"notion": {
"description": "Dokumente & Datenbanken"
},
"guru": {
"description": "Verifizierte Wissensdatenbank"
},
"gong": {
"description": "Sales-Call-Intelligence"
},
"zulip": {
"description": "Open-Source-Messaging"
},
"linear": {
"description": "Engineering-Issue-Tracker"
},
"hubspot": {
"description": "Marketing & CRM"
},
"document360": {
"description": "Self-Service-Dokumentation"
},
"file": {
"description": "Aus lokalen Dateien hochladen"
},
"userFile": {
"description": "Im Chat hochgeladene Dateien"
},
"googleSites": {
"description": "Von Google gehostete Seiten"
},
"loopio": {
"description": "RFP-Antworten"
},
"box": {
"description": "Dateien, Ordner und Notizen"
},
"dropbox": {
"description": "Geteilte Dateien und Ordner"
},
"discord": {
"description": "Community-Messaging"
},
"salesforce": {
"description": "Vertrieb & CRM"
},
"sharepoint": {
"description": "Microsoft-Intranet"
},
"teams": {
"description": "Microsoft-Team-Chats"
},
"outlook": {
"description": "E-Mails und Postfachordner"
},
"zendesk": {
"description": "Kundensupport-Tickets"
},
"discourse": {
"description": "Community-Forum"
},
"axero": {
"description": "Soziales Intranet"
},
"clickup": {
"description": "Projekt- & Aufgaben-Tracker"
},
"wikipedia": {
"description": "Öffentliche Wissensdatenbank"
},
"mediawiki": {
"description": "Wiki im Wikipedia-Stil"
},
"asana": {
"description": "Arbeitsmanagement"
},
"s3": {
"description": "AWS-Storage-Buckets"
},
"r2": {
"description": "Cloud-Storage-Buckets"
},
"googleCloudStorage": {
"description": "Google-Cloud-Buckets"
},
"xenforo": {
"description": "Community-Forum"
},
"ociStorage": {
"description": "OCI Object Storage"
},
"notApplicable": {
"description": "Keine Quelle"
},
"ingestionApi": {
"description": "Über die API gesendete Dokumente"
},
"freshdesk": {
"description": "Kunden-Helpdesk"
},
"fireflies": {
"description": "Meeting-Notizen"
},
"egnyte": {
"description": "Verwaltete Dateidienste"
},
"airtable": {
"description": "Datenbank & Aufgaben"
},
"gitbook": {
"description": "Entwicklerdokumentation"
},
"highspot": {
"description": "Sales Enablement"
},
"drupalWiki": {
"description": "CMS-basiertes Wiki"
},
"imap": {
"description": "IMAP-E-Mail-Quelle"
},
"bitbucket": {
"description": "Atlassian-Quellcodeverwaltung"
},
"testrail": {
"description": "Testfall-Verwaltung"
},
"braintrust": {
"description": "Logs und Auswertungen"
},
"lumapps": {
"description": "Intranet-Seiten und Communities"
},
"canvas": {
"description": "Kurse, Seiten und Ankündigungen"
},
"craftFile": {
"description": "Von Ihnen hochgeladene Dateien"
},
"federatedSlack": {
"description": "Slack zur Abfragezeit durchsuchen"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "Konnektor erfolgreich erstellt"
},
"empty": {
"message": "Sie haben anscheinend noch keine Konnektoren eingerichtet. Öffnen Sie die Seite [Konnektor hinzufügen](/admin/add-connector), um zu beginnen!"
"message": "Sie haben anscheinend noch keine Konnektoren eingerichtet. Öffnen Sie die Seite [Konnektor hinzufügen](/admin/connectors), um zu beginnen!"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "Konnektor hinzufügen"
"connectors": {
"label": "Konnektoren"
},
"agents": {
"label": "Agenten"
+202 -14
View File
@@ -779,41 +779,229 @@
"addConnector": {
"categories": {
"codeRepository": {
"label": "Code Repository"
"label": "Code Repositories"
},
"messaging": {
"label": "Messaging"
},
"other": {
"label": "Others"
},
"sales": {
"label": "Sales"
"label": "Sales & GTM"
},
"storage": {
"label": "Cloud Storage"
},
"ticketingAndTaskManagement": {
"label": "Ticketing & Task Management"
"label": "Ticketing & Tasks"
},
"wiki": {
"label": "Knowledge Base & Wikis"
},
"aiObservability": {
"label": "AI & Observability"
},
"other": {
"label": "Other"
}
},
"popular": {
"title": "Popular"
"title": "Add Connector",
"description": "Connect {appName} to your data sources."
},
"search": {
"placeholder": "Search Connectors"
},
"seeConnectorsButton": {
"label": "See Connectors"
"placeholder": "Search connectors..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>Federated connector already configured.</strong> Click to edit the existing connector.",
"slackCredentialsFound": "<strong>Existing Slack credentials found.</strong> Click to manage your Slack connector."
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "Connect {source}"
}
},
"sources": {
"web": {
"description": "Link any public URL"
},
"github": {
"description": "Code & pull requests"
},
"gitlab": {
"description": "Code & CI/CD"
},
"slack": {
"description": "Team messaging"
},
"googleDrive": {
"description": "Shared files & folders"
},
"gmail": {
"description": "Google email"
},
"bookstack": {
"description": "Self-hosted wiki"
},
"outline": {
"description": "Open-source team wiki"
},
"confluence": {
"description": "Atlassian wiki"
},
"jira": {
"description": "Atlassian issue tracker"
},
"productboard": {
"description": "Product management"
},
"slab": {
"description": "Team wiki"
},
"coda": {
"description": "Docs & databases"
},
"notion": {
"description": "Docs & databases"
},
"guru": {
"description": "Verified knowledge base"
},
"gong": {
"description": "Sales call intelligence"
},
"zulip": {
"description": "Open-source messaging"
},
"linear": {
"description": "Engineering issue tracker"
},
"hubspot": {
"description": "Marketing & CRM"
},
"document360": {
"description": "Self-service docs"
},
"file": {
"description": "Upload from local files"
},
"userFile": {
"description": "Files uploaded in chat"
},
"googleSites": {
"description": "Google-hosted pages"
},
"loopio": {
"description": "RFP response"
},
"box": {
"description": "Files, folders, & notes"
},
"dropbox": {
"description": "Shared files and folders"
},
"discord": {
"description": "Community messaging"
},
"salesforce": {
"description": "Sales & CRM"
},
"sharepoint": {
"description": "Microsoft intranet"
},
"teams": {
"description": "Microsoft team chats"
},
"outlook": {
"description": "Emails & mail folders"
},
"zendesk": {
"description": "Customer support tickets"
},
"discourse": {
"description": "Community forum"
},
"axero": {
"description": "Social intranet"
},
"clickup": {
"description": "Project & task tracker"
},
"wikipedia": {
"description": "Public knowledge base"
},
"mediawiki": {
"description": "Wikipedia-style wiki"
},
"asana": {
"description": "Work management"
},
"s3": {
"description": "AWS storage buckets"
},
"r2": {
"description": "Cloud storage buckets"
},
"googleCloudStorage": {
"description": "Google cloud buckets"
},
"xenforo": {
"description": "Community forum"
},
"ociStorage": {
"description": "OCI object storage"
},
"notApplicable": {
"description": "No source"
},
"ingestionApi": {
"description": "Documents sent through the API"
},
"freshdesk": {
"description": "Customer helpdesk"
},
"fireflies": {
"description": "Meeting notes"
},
"egnyte": {
"description": "Managed file services"
},
"airtable": {
"description": "Database & tasks"
},
"gitbook": {
"description": "Developer docs"
},
"highspot": {
"description": "Sales enablement"
},
"drupalWiki": {
"description": "CMS-based wiki"
},
"imap": {
"description": "IMAP email source"
},
"bitbucket": {
"description": "Atlassian source control"
},
"testrail": {
"description": "Test case tracking"
},
"braintrust": {
"description": "Logs & evaluations"
},
"lumapps": {
"description": "Intranet pages & communities"
},
"canvas": {
"description": "Courses, pages, & announcements"
},
"craftFile": {
"description": "Files you uploaded"
},
"federatedSlack": {
"description": "Search Slack at query time"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "Connector created successfully"
},
"empty": {
"message": "It looks like you don't have any connectors setup yet. Visit the [Add Connector](/admin/add-connector) page to get started!"
"message": "It looks like you don't have any connectors setup yet. Visit the [Add Connector](/admin/connectors) page to get started!"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "Add Connector"
"connectors": {
"label": "Connectors"
},
"agents": {
"label": "Agents"
+202 -14
View File
@@ -779,41 +779,229 @@
"addConnector": {
"categories": {
"codeRepository": {
"label": "Repositorio de código"
"label": "Repositorios de código"
},
"messaging": {
"label": "Mensajería"
},
"other": {
"label": "Otros"
},
"sales": {
"label": "Ventas"
"label": "Ventas y GTM"
},
"storage": {
"label": "Almacenamiento en la nube"
},
"ticketingAndTaskManagement": {
"label": "Tickets y gestión de tareas"
"label": "Tickets y tareas"
},
"wiki": {
"label": "Bases de conocimiento y wikis"
},
"aiObservability": {
"label": "IA y observabilidad"
},
"other": {
"label": "Otros"
}
},
"popular": {
"title": "Populares"
"title": "Añadir conector",
"description": "Conecta {appName} a tus fuentes de datos."
},
"search": {
"placeholder": "Buscar conectores"
},
"seeConnectorsButton": {
"label": "Ver los conectores"
"placeholder": "Buscar conectores..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>El conector federado ya está configurado.</strong> Haz clic para editar el conector existente.",
"slackCredentialsFound": "<strong>Se encontraron credenciales de Slack existentes.</strong> Haz clic para gestionar tu conector de Slack."
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "Conectar {source}"
}
},
"sources": {
"web": {
"description": "Enlaza cualquier URL pública"
},
"github": {
"description": "Código y pull requests"
},
"gitlab": {
"description": "Código y CI/CD"
},
"slack": {
"description": "Mensajería de equipo"
},
"googleDrive": {
"description": "Archivos y carpetas compartidos"
},
"gmail": {
"description": "Correo de Google"
},
"bookstack": {
"description": "Wiki autoalojada"
},
"outline": {
"description": "Wiki de equipo de código abierto"
},
"confluence": {
"description": "Wiki de Atlassian"
},
"jira": {
"description": "Gestor de issues de Atlassian"
},
"productboard": {
"description": "Gestión de producto"
},
"slab": {
"description": "Wiki de equipo"
},
"coda": {
"description": "Documentos y bases de datos"
},
"notion": {
"description": "Documentos y bases de datos"
},
"guru": {
"description": "Base de conocimiento verificada"
},
"gong": {
"description": "Inteligencia de llamadas de ventas"
},
"zulip": {
"description": "Mensajería de código abierto"
},
"linear": {
"description": "Gestor de issues de ingeniería"
},
"hubspot": {
"description": "Marketing y CRM"
},
"document360": {
"description": "Documentación de autoservicio"
},
"file": {
"description": "Subir archivos locales"
},
"userFile": {
"description": "Archivos subidos en el chat"
},
"googleSites": {
"description": "Páginas alojadas en Google"
},
"loopio": {
"description": "Respuestas a RFP"
},
"box": {
"description": "Archivos, carpetas y notas"
},
"dropbox": {
"description": "Archivos y carpetas compartidos"
},
"discord": {
"description": "Mensajería de la comunidad"
},
"salesforce": {
"description": "Ventas y CRM"
},
"sharepoint": {
"description": "Intranet de Microsoft"
},
"teams": {
"description": "Chats de equipo de Microsoft"
},
"outlook": {
"description": "Correos y carpetas de correo"
},
"zendesk": {
"description": "Tickets de soporte al cliente"
},
"discourse": {
"description": "Foro de la comunidad"
},
"axero": {
"description": "Intranet social"
},
"clickup": {
"description": "Gestor de proyectos y tareas"
},
"wikipedia": {
"description": "Base de conocimiento pública"
},
"mediawiki": {
"description": "Wiki estilo Wikipedia"
},
"asana": {
"description": "Gestión del trabajo"
},
"s3": {
"description": "Buckets de almacenamiento de AWS"
},
"r2": {
"description": "Buckets de almacenamiento en la nube"
},
"googleCloudStorage": {
"description": "Buckets de Google Cloud"
},
"xenforo": {
"description": "Foro de la comunidad"
},
"ociStorage": {
"description": "Almacenamiento de objetos de OCI"
},
"notApplicable": {
"description": "Sin fuente"
},
"ingestionApi": {
"description": "Documentos enviados por la API"
},
"freshdesk": {
"description": "Helpdesk de clientes"
},
"fireflies": {
"description": "Notas de reuniones"
},
"egnyte": {
"description": "Servicios de archivos gestionados"
},
"airtable": {
"description": "Base de datos y tareas"
},
"gitbook": {
"description": "Documentación para desarrolladores"
},
"highspot": {
"description": "Habilitación de ventas"
},
"drupalWiki": {
"description": "Wiki basada en CMS"
},
"imap": {
"description": "Fuente de correo IMAP"
},
"bitbucket": {
"description": "Control de código de Atlassian"
},
"testrail": {
"description": "Seguimiento de casos de prueba"
},
"braintrust": {
"description": "Registros y evaluaciones"
},
"lumapps": {
"description": "Páginas y comunidades de la intranet"
},
"canvas": {
"description": "Cursos, páginas y anuncios"
},
"craftFile": {
"description": "Archivos que subiste"
},
"federatedSlack": {
"description": "Buscar en Slack al consultar"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "El conector se creó correctamente"
},
"empty": {
"message": "Parece que aún no tienes ningún conector configurado. ¡Ve a la página [Añadir conector](/admin/add-connector) para empezar!"
"message": "Parece que aún no tienes ningún conector configurado. ¡Ve a la página [Añadir conector](/admin/connectors) para empezar!"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "Añadir conector"
"connectors": {
"label": "Conectores"
},
"agents": {
"label": "Agentes"
+202 -14
View File
@@ -779,41 +779,229 @@
"addConnector": {
"categories": {
"codeRepository": {
"label": "Dépôt de code"
"label": "Dépôts de code"
},
"messaging": {
"label": "Messagerie"
},
"other": {
"label": "Autres"
},
"sales": {
"label": "Ventes"
"label": "Ventes et GTM"
},
"storage": {
"label": "Stockage cloud"
},
"ticketingAndTaskManagement": {
"label": "Tickets et gestion des tâches"
"label": "Tickets et tâches"
},
"wiki": {
"label": "Bases de connaissances et wikis"
},
"aiObservability": {
"label": "IA et observabilité"
},
"other": {
"label": "Autres"
}
},
"popular": {
"title": "Populaires"
"title": "Ajouter un connecteur",
"description": "Connectez {appName} à vos sources de données."
},
"search": {
"placeholder": "Rechercher des connecteurs"
},
"seeConnectorsButton": {
"label": "Voir les connecteurs"
"placeholder": "Rechercher des connecteurs..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>Connecteur fédéré déjà configuré.</strong> Cliquez pour modifier le connecteur existant.",
"slackCredentialsFound": "<strong>Identifiants Slack existants trouvés.</strong> Cliquez pour gérer votre connecteur Slack."
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "Connecter {source}"
}
},
"sources": {
"web": {
"description": "Lier n'importe quelle URL publique"
},
"github": {
"description": "Code et pull requests"
},
"gitlab": {
"description": "Code et CI/CD"
},
"slack": {
"description": "Messagerie d'équipe"
},
"googleDrive": {
"description": "Fichiers et dossiers partagés"
},
"gmail": {
"description": "Messagerie Google"
},
"bookstack": {
"description": "Wiki auto-hébergé"
},
"outline": {
"description": "Wiki d'équipe open source"
},
"confluence": {
"description": "Wiki Atlassian"
},
"jira": {
"description": "Suivi des tickets Atlassian"
},
"productboard": {
"description": "Gestion de produit"
},
"slab": {
"description": "Wiki d'équipe"
},
"coda": {
"description": "Documents et bases de données"
},
"notion": {
"description": "Documents et bases de données"
},
"guru": {
"description": "Base de connaissances vérifiée"
},
"gong": {
"description": "Analyse des appels commerciaux"
},
"zulip": {
"description": "Messagerie open source"
},
"linear": {
"description": "Suivi des tickets d'ingénierie"
},
"hubspot": {
"description": "Marketing et CRM"
},
"document360": {
"description": "Documentation en libre-service"
},
"file": {
"description": "Importer des fichiers locaux"
},
"userFile": {
"description": "Fichiers importés dans le chat"
},
"googleSites": {
"description": "Pages hébergées par Google"
},
"loopio": {
"description": "Réponses aux RFP"
},
"box": {
"description": "Fichiers, dossiers et notes"
},
"dropbox": {
"description": "Fichiers et dossiers partagés"
},
"discord": {
"description": "Messagerie communautaire"
},
"salesforce": {
"description": "Ventes et CRM"
},
"sharepoint": {
"description": "Intranet Microsoft"
},
"teams": {
"description": "Discussions d'équipe Microsoft"
},
"outlook": {
"description": "E-mails et dossiers de messagerie"
},
"zendesk": {
"description": "Tickets de support client"
},
"discourse": {
"description": "Forum communautaire"
},
"axero": {
"description": "Intranet social"
},
"clickup": {
"description": "Suivi de projets et de tâches"
},
"wikipedia": {
"description": "Base de connaissances publique"
},
"mediawiki": {
"description": "Wiki de type Wikipédia"
},
"asana": {
"description": "Gestion du travail"
},
"s3": {
"description": "Buckets de stockage AWS"
},
"r2": {
"description": "Buckets de stockage cloud"
},
"googleCloudStorage": {
"description": "Buckets Google Cloud"
},
"xenforo": {
"description": "Forum communautaire"
},
"ociStorage": {
"description": "Stockage d'objets OCI"
},
"notApplicable": {
"description": "Aucune source"
},
"ingestionApi": {
"description": "Documents envoyés via l'API"
},
"freshdesk": {
"description": "Helpdesk client"
},
"fireflies": {
"description": "Notes de réunion"
},
"egnyte": {
"description": "Services de fichiers gérés"
},
"airtable": {
"description": "Base de données et tâches"
},
"gitbook": {
"description": "Documentation développeur"
},
"highspot": {
"description": "Sales enablement"
},
"drupalWiki": {
"description": "Wiki basé sur un CMS"
},
"imap": {
"description": "Source e-mail IMAP"
},
"bitbucket": {
"description": "Gestion de code Atlassian"
},
"testrail": {
"description": "Suivi des cas de test"
},
"braintrust": {
"description": "Journaux et évaluations"
},
"lumapps": {
"description": "Pages et communautés de l'intranet"
},
"canvas": {
"description": "Cours, pages et annonces"
},
"craftFile": {
"description": "Fichiers que vous avez importés"
},
"federatedSlack": {
"description": "Rechercher dans Slack à la requête"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "Connecteur créé avec succès"
},
"empty": {
"message": "Il semble que vous n'ayez pas encore configuré de connecteurs. Consultez la page [Ajouter un connecteur](/admin/add-connector) pour commencer !"
"message": "Il semble que vous n'ayez pas encore configuré de connecteurs. Consultez la page [Ajouter un connecteur](/admin/connectors) pour commencer !"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "Ajouter un connecteur"
"connectors": {
"label": "Connecteurs"
},
"agents": {
"label": "Agents"
+201 -13
View File
@@ -784,36 +784,224 @@
"messaging": {
"label": "メッセージング"
},
"other": {
"label": "その他"
},
"sales": {
"label": "営業"
"label": "営業・GTM"
},
"storage": {
"label": "クラウドストレージ"
},
"ticketingAndTaskManagement": {
"label": "チケット管理・タスク管理"
"label": "チケット・タスク"
},
"wiki": {
"label": "ナレッジベース・Wiki"
},
"aiObservability": {
"label": "AI・オブザーバビリティ"
},
"other": {
"label": "その他"
}
},
"popular": {
"title": "人気"
"title": "コネクタを追加",
"description": "{appName} をデータソースに接続します。"
},
"search": {
"placeholder": "コネクターを検索"
},
"seeConnectorsButton": {
"label": "コネクターを表示"
"placeholder": "コネクターを検索..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>フェデレーテッドコネクターは設定済みです。</strong> クリックすると、既存のコネクターを編集できます。",
"slackCredentialsFound": "<strong>既存の Slack 資格情報が見つかりました。</strong> クリックすると、Slack コネクターを管理できます。"
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "{source} を接続"
}
},
"sources": {
"web": {
"description": "任意の公開 URL をリンク"
},
"github": {
"description": "コードとプルリクエスト"
},
"gitlab": {
"description": "コードと CI/CD"
},
"slack": {
"description": "チームメッセージング"
},
"googleDrive": {
"description": "共有ファイルとフォルダー"
},
"gmail": {
"description": "Google のメール"
},
"bookstack": {
"description": "セルフホスト型 Wiki"
},
"outline": {
"description": "オープンソースのチーム Wiki"
},
"confluence": {
"description": "Atlassian の Wiki"
},
"jira": {
"description": "Atlassian の課題管理"
},
"productboard": {
"description": "プロダクトマネジメント"
},
"slab": {
"description": "チーム Wiki"
},
"coda": {
"description": "ドキュメントとデータベース"
},
"notion": {
"description": "ドキュメントとデータベース"
},
"guru": {
"description": "検証済みナレッジベース"
},
"gong": {
"description": "営業通話インテリジェンス"
},
"zulip": {
"description": "オープンソースのメッセージング"
},
"linear": {
"description": "エンジニアリング課題管理"
},
"hubspot": {
"description": "マーケティングと CRM"
},
"document360": {
"description": "セルフサービスドキュメント"
},
"file": {
"description": "ローカルファイルからアップロード"
},
"userFile": {
"description": "チャットでアップロードしたファイル"
},
"googleSites": {
"description": "Google ホストのページ"
},
"loopio": {
"description": "RFP 回答"
},
"box": {
"description": "ファイル、フォルダー、ノート"
},
"dropbox": {
"description": "共有ファイルとフォルダー"
},
"discord": {
"description": "コミュニティメッセージング"
},
"salesforce": {
"description": "営業と CRM"
},
"sharepoint": {
"description": "Microsoft のイントラネット"
},
"teams": {
"description": "Microsoft のチームチャット"
},
"outlook": {
"description": "メールとメールフォルダー"
},
"zendesk": {
"description": "カスタマーサポートのチケット"
},
"discourse": {
"description": "コミュニティフォーラム"
},
"axero": {
"description": "ソーシャルイントラネット"
},
"clickup": {
"description": "プロジェクトとタスクの管理"
},
"wikipedia": {
"description": "公開ナレッジベース"
},
"mediawiki": {
"description": "Wikipedia 型の Wiki"
},
"asana": {
"description": "ワークマネジメント"
},
"s3": {
"description": "AWS ストレージバケット"
},
"r2": {
"description": "クラウドストレージバケット"
},
"googleCloudStorage": {
"description": "Google Cloud バケット"
},
"xenforo": {
"description": "コミュニティフォーラム"
},
"ociStorage": {
"description": "OCI オブジェクトストレージ"
},
"notApplicable": {
"description": "ソースなし"
},
"ingestionApi": {
"description": "API 経由で送信されたドキュメント"
},
"freshdesk": {
"description": "カスタマーヘルプデスク"
},
"fireflies": {
"description": "会議メモ"
},
"egnyte": {
"description": "マネージドファイルサービス"
},
"airtable": {
"description": "データベースとタスク"
},
"gitbook": {
"description": "開発者向けドキュメント"
},
"highspot": {
"description": "セールスイネーブルメント"
},
"drupalWiki": {
"description": "CMS ベースの Wiki"
},
"imap": {
"description": "IMAP メールソース"
},
"bitbucket": {
"description": "Atlassian のソース管理"
},
"testrail": {
"description": "テストケース管理"
},
"braintrust": {
"description": "ログと評価"
},
"lumapps": {
"description": "イントラネットのページとコミュニティ"
},
"canvas": {
"description": "コース、ページ、お知らせ"
},
"craftFile": {
"description": "アップロードしたファイル"
},
"federatedSlack": {
"description": "クエリ時に Slack を検索"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "コネクターを作成しました"
},
"empty": {
"message": "コネクターがまだ設定されていないようです。[コネクターを追加](/admin/add-connector) ページで開始してください。"
"message": "コネクターがまだ設定されていないようです。[コネクターを追加](/admin/connectors) ページで開始してください。"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "コネクターを追加"
"connectors": {
"label": "コネクター"
},
"agents": {
"label": "エージェント"
+201 -13
View File
@@ -784,36 +784,224 @@
"messaging": {
"label": "메시징"
},
"other": {
"label": "기타"
},
"sales": {
"label": "영업"
"label": "영업 및 GTM"
},
"storage": {
"label": "클라우드 스토리지"
},
"ticketingAndTaskManagement": {
"label": "티켓팅 및 작업 관리"
"label": "티켓 및 작업"
},
"wiki": {
"label": "지식 베이스 및 위키"
},
"aiObservability": {
"label": "AI 및 관측 가능성"
},
"other": {
"label": "기타"
}
},
"popular": {
"title": "인기"
"title": "커넥터 추가",
"description": "{appName}을(를) 데이터 소스에 연결하세요."
},
"search": {
"placeholder": "커넥터 검색"
},
"seeConnectorsButton": {
"label": "커넥터 보기"
"placeholder": "커넥터 검색..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>페더레이션 커넥터가 이미 구성되어 있습니다.</strong> 클릭하여 기존 커넥터를 편집하세요.",
"slackCredentialsFound": "<strong>기존 Slack 자격 증명을 찾았습니다.</strong> 클릭하여 Slack 커넥터를 관리하세요."
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "{source} 연결"
}
},
"sources": {
"web": {
"description": "공개 URL 연결"
},
"github": {
"description": "코드 및 풀 리퀘스트"
},
"gitlab": {
"description": "코드 및 CI/CD"
},
"slack": {
"description": "팀 메시징"
},
"googleDrive": {
"description": "공유 파일과 폴더"
},
"gmail": {
"description": "Google 이메일"
},
"bookstack": {
"description": "자체 호스팅 위키"
},
"outline": {
"description": "오픈소스 팀 위키"
},
"confluence": {
"description": "Atlassian 위키"
},
"jira": {
"description": "Atlassian 이슈 트래커"
},
"productboard": {
"description": "제품 관리"
},
"slab": {
"description": "팀 위키"
},
"coda": {
"description": "문서 및 데이터베이스"
},
"notion": {
"description": "문서 및 데이터베이스"
},
"guru": {
"description": "검증된 지식 베이스"
},
"gong": {
"description": "영업 통화 인텔리전스"
},
"zulip": {
"description": "오픈소스 메시징"
},
"linear": {
"description": "엔지니어링 이슈 트래커"
},
"hubspot": {
"description": "마케팅 및 CRM"
},
"document360": {
"description": "셀프서비스 문서"
},
"file": {
"description": "로컬 파일 업로드"
},
"userFile": {
"description": "채팅에서 업로드한 파일"
},
"googleSites": {
"description": "Google 호스팅 페이지"
},
"loopio": {
"description": "RFP 응답"
},
"box": {
"description": "파일, 폴더, 노트"
},
"dropbox": {
"description": "공유 파일과 폴더"
},
"discord": {
"description": "커뮤니티 메시징"
},
"salesforce": {
"description": "영업 및 CRM"
},
"sharepoint": {
"description": "Microsoft 인트라넷"
},
"teams": {
"description": "Microsoft 팀 채팅"
},
"outlook": {
"description": "이메일과 메일 폴더"
},
"zendesk": {
"description": "고객 지원 티켓"
},
"discourse": {
"description": "커뮤니티 포럼"
},
"axero": {
"description": "소셜 인트라넷"
},
"clickup": {
"description": "프로젝트 및 작업 트래커"
},
"wikipedia": {
"description": "공개 지식 베이스"
},
"mediawiki": {
"description": "위키백과 스타일 위키"
},
"asana": {
"description": "업무 관리"
},
"s3": {
"description": "AWS 스토리지 버킷"
},
"r2": {
"description": "클라우드 스토리지 버킷"
},
"googleCloudStorage": {
"description": "Google Cloud 버킷"
},
"xenforo": {
"description": "커뮤니티 포럼"
},
"ociStorage": {
"description": "OCI 오브젝트 스토리지"
},
"notApplicable": {
"description": "소스 없음"
},
"ingestionApi": {
"description": "API로 전송된 문서"
},
"freshdesk": {
"description": "고객 헬프데스크"
},
"fireflies": {
"description": "회의 노트"
},
"egnyte": {
"description": "관리형 파일 서비스"
},
"airtable": {
"description": "데이터베이스 및 작업"
},
"gitbook": {
"description": "개발자 문서"
},
"highspot": {
"description": "세일즈 인에이블먼트"
},
"drupalWiki": {
"description": "CMS 기반 위키"
},
"imap": {
"description": "IMAP 이메일 소스"
},
"bitbucket": {
"description": "Atlassian 소스 관리"
},
"testrail": {
"description": "테스트 케이스 관리"
},
"braintrust": {
"description": "로그와 평가"
},
"lumapps": {
"description": "인트라넷 페이지와 커뮤니티"
},
"canvas": {
"description": "강좌, 페이지, 공지"
},
"craftFile": {
"description": "업로드한 파일"
},
"federatedSlack": {
"description": "질의 시 Slack 검색"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "커넥터를 생성했습니다"
},
"empty": {
"message": "아직 설정된 커넥터가 없는 것 같습니다. [커넥터 추가](/admin/add-connector) 페이지에서 시작하세요!"
"message": "아직 설정된 커넥터가 없는 것 같습니다. [커넥터 추가](/admin/connectors) 페이지에서 시작하세요!"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "커넥터 추가"
"connectors": {
"label": "커넥터"
},
"agents": {
"label": "에이전트"
+202 -14
View File
@@ -779,41 +779,229 @@
"addConnector": {
"categories": {
"codeRepository": {
"label": "Repositório de código"
"label": "Repositórios de código"
},
"messaging": {
"label": "Mensagens"
},
"other": {
"label": "Outros"
},
"sales": {
"label": "Vendas"
"label": "Vendas e GTM"
},
"storage": {
"label": "Armazenamento em nuvem"
},
"ticketingAndTaskManagement": {
"label": "Tíquetes e gestão de tarefas"
"label": "Tíquetes e tarefas"
},
"wiki": {
"label": "Base de conhecimento e wikis"
},
"aiObservability": {
"label": "IA e observabilidade"
},
"other": {
"label": "Outros"
}
},
"popular": {
"title": "Populares"
"title": "Adicionar conector",
"description": "Conecte o {appName} às suas fontes de dados."
},
"search": {
"placeholder": "Pesquisar conectores"
},
"seeConnectorsButton": {
"label": "Ver conectores"
"placeholder": "Pesquisar conectores..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>Conector federado já configurado.</strong> Clique para editar o conector existente.",
"slackCredentialsFound": "<strong>Credenciais do Slack existentes encontradas.</strong> Clique para gerenciar seu conector do Slack."
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "Conectar {source}"
}
},
"sources": {
"web": {
"description": "Vincule qualquer URL pública"
},
"github": {
"description": "Código e pull requests"
},
"gitlab": {
"description": "Código e CI/CD"
},
"slack": {
"description": "Mensagens de equipe"
},
"googleDrive": {
"description": "Arquivos e pastas compartilhados"
},
"gmail": {
"description": "E-mail do Google"
},
"bookstack": {
"description": "Wiki auto-hospedada"
},
"outline": {
"description": "Wiki de equipe de código aberto"
},
"confluence": {
"description": "Wiki da Atlassian"
},
"jira": {
"description": "Rastreador de issues da Atlassian"
},
"productboard": {
"description": "Gestão de produto"
},
"slab": {
"description": "Wiki da equipe"
},
"coda": {
"description": "Documentos e bancos de dados"
},
"notion": {
"description": "Documentos e bancos de dados"
},
"guru": {
"description": "Base de conhecimento verificada"
},
"gong": {
"description": "Inteligência de chamadas de vendas"
},
"zulip": {
"description": "Mensagens de código aberto"
},
"linear": {
"description": "Rastreador de issues de engenharia"
},
"hubspot": {
"description": "Marketing e CRM"
},
"document360": {
"description": "Documentação de autoatendimento"
},
"file": {
"description": "Enviar arquivos locais"
},
"userFile": {
"description": "Arquivos enviados no chat"
},
"googleSites": {
"description": "Páginas hospedadas pelo Google"
},
"loopio": {
"description": "Respostas a RFP"
},
"box": {
"description": "Arquivos, pastas e notas"
},
"dropbox": {
"description": "Arquivos e pastas compartilhados"
},
"discord": {
"description": "Mensagens da comunidade"
},
"salesforce": {
"description": "Vendas e CRM"
},
"sharepoint": {
"description": "Intranet da Microsoft"
},
"teams": {
"description": "Chats de equipe da Microsoft"
},
"outlook": {
"description": "E-mails e pastas de e-mail"
},
"zendesk": {
"description": "Tickets de suporte ao cliente"
},
"discourse": {
"description": "Fórum da comunidade"
},
"axero": {
"description": "Intranet social"
},
"clickup": {
"description": "Rastreador de projetos e tarefas"
},
"wikipedia": {
"description": "Base de conhecimento pública"
},
"mediawiki": {
"description": "Wiki no estilo Wikipédia"
},
"asana": {
"description": "Gestão de trabalho"
},
"s3": {
"description": "Buckets de armazenamento da AWS"
},
"r2": {
"description": "Buckets de armazenamento em nuvem"
},
"googleCloudStorage": {
"description": "Buckets do Google Cloud"
},
"xenforo": {
"description": "Fórum da comunidade"
},
"ociStorage": {
"description": "Armazenamento de objetos da OCI"
},
"notApplicable": {
"description": "Sem fonte"
},
"ingestionApi": {
"description": "Documentos enviados pela API"
},
"freshdesk": {
"description": "Helpdesk de clientes"
},
"fireflies": {
"description": "Notas de reunião"
},
"egnyte": {
"description": "Serviços de arquivos gerenciados"
},
"airtable": {
"description": "Banco de dados e tarefas"
},
"gitbook": {
"description": "Documentação para desenvolvedores"
},
"highspot": {
"description": "Capacitação de vendas"
},
"drupalWiki": {
"description": "Wiki baseada em CMS"
},
"imap": {
"description": "Fonte de e-mail IMAP"
},
"bitbucket": {
"description": "Controle de código da Atlassian"
},
"testrail": {
"description": "Acompanhamento de casos de teste"
},
"braintrust": {
"description": "Logs e avaliações"
},
"lumapps": {
"description": "Páginas e comunidades da intranet"
},
"canvas": {
"description": "Cursos, páginas e avisos"
},
"craftFile": {
"description": "Arquivos que você enviou"
},
"federatedSlack": {
"description": "Pesquisar no Slack na consulta"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "Conector criado com sucesso"
},
"empty": {
"message": "Parece que você ainda não configurou nenhum conector. Acesse a página [Adicionar conector](/admin/add-connector) para começar!"
"message": "Parece que você ainda não configurou nenhum conector. Acesse a página [Adicionar conector](/admin/connectors) para começar!"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "Adicionar conector"
"connectors": {
"label": "Conectores"
},
"agents": {
"label": "Agentes"
+201 -13
View File
@@ -784,36 +784,224 @@
"messaging": {
"label": "即时通讯"
},
"other": {
"label": "其他"
},
"sales": {
"label": "销售"
"label": "销售与 GTM"
},
"storage": {
"label": "云存储"
},
"ticketingAndTaskManagement": {
"label": "工单与任务管理"
"label": "工单与任务"
},
"wiki": {
"label": "知识库与 Wiki"
},
"aiObservability": {
"label": "AI 与可观测性"
},
"other": {
"label": "其他"
}
},
"popular": {
"title": "热门"
"title": "添加连接器",
"description": "将 {appName} 连接到您的数据源。"
},
"search": {
"placeholder": "搜索连接器"
},
"seeConnectorsButton": {
"label": "查看连接器"
"placeholder": "搜索连接器..."
},
"sourceTile": {
"tooltip": {
"federatedConfigured": "<strong>联合连接器已配置。</strong>点击可编辑现有连接器。",
"slackCredentialsFound": "<strong>已找到现有的 Slack 凭据。</strong>点击可管理您的 Slack 连接器。"
}
},
"sourceCard": {
"connectButton": {
"ariaLabel": "连接 {source}"
}
},
"sources": {
"web": {
"description": "链接任意公开 URL"
},
"github": {
"description": "代码与拉取请求"
},
"gitlab": {
"description": "代码与 CI/CD"
},
"slack": {
"description": "团队消息"
},
"googleDrive": {
"description": "共享文件和文件夹"
},
"gmail": {
"description": "Google 邮箱"
},
"bookstack": {
"description": "自托管维基"
},
"outline": {
"description": "开源团队维基"
},
"confluence": {
"description": "Atlassian 维基"
},
"jira": {
"description": "Atlassian 问题跟踪"
},
"productboard": {
"description": "产品管理"
},
"slab": {
"description": "团队维基"
},
"coda": {
"description": "文档与数据库"
},
"notion": {
"description": "文档与数据库"
},
"guru": {
"description": "经验证的知识库"
},
"gong": {
"description": "销售通话智能"
},
"zulip": {
"description": "开源消息"
},
"linear": {
"description": "工程问题跟踪"
},
"hubspot": {
"description": "营销与 CRM"
},
"document360": {
"description": "自助服务文档"
},
"file": {
"description": "从本地文件上传"
},
"userFile": {
"description": "聊天中上传的文件"
},
"googleSites": {
"description": "Google 托管页面"
},
"loopio": {
"description": "RFP 应答"
},
"box": {
"description": "文件、文件夹和笔记"
},
"dropbox": {
"description": "共享文件和文件夹"
},
"discord": {
"description": "社区消息"
},
"salesforce": {
"description": "销售与 CRM"
},
"sharepoint": {
"description": "Microsoft 内网"
},
"teams": {
"description": "Microsoft 团队聊天"
},
"outlook": {
"description": "邮件和邮件文件夹"
},
"zendesk": {
"description": "客户支持工单"
},
"discourse": {
"description": "社区论坛"
},
"axero": {
"description": "社交内网"
},
"clickup": {
"description": "项目与任务跟踪"
},
"wikipedia": {
"description": "公开知识库"
},
"mediawiki": {
"description": "维基百科式维基"
},
"asana": {
"description": "工作管理"
},
"s3": {
"description": "AWS 存储桶"
},
"r2": {
"description": "云存储桶"
},
"googleCloudStorage": {
"description": "Google Cloud 存储桶"
},
"xenforo": {
"description": "社区论坛"
},
"ociStorage": {
"description": "OCI 对象存储"
},
"notApplicable": {
"description": "无来源"
},
"ingestionApi": {
"description": "通过 API 发送的文档"
},
"freshdesk": {
"description": "客户服务台"
},
"fireflies": {
"description": "会议记录"
},
"egnyte": {
"description": "托管文件服务"
},
"airtable": {
"description": "数据库与任务"
},
"gitbook": {
"description": "开发者文档"
},
"highspot": {
"description": "销售赋能"
},
"drupalWiki": {
"description": "基于 CMS 的维基"
},
"imap": {
"description": "IMAP 邮件来源"
},
"bitbucket": {
"description": "Atlassian 源代码管理"
},
"testrail": {
"description": "测试用例跟踪"
},
"braintrust": {
"description": "日志和评估"
},
"lumapps": {
"description": "内网页面和社区"
},
"canvas": {
"description": "课程、页面和公告"
},
"craftFile": {
"description": "你上传的文件"
},
"federatedSlack": {
"description": "查询时搜索 Slack"
}
}
},
"agentStats": {
@@ -5033,7 +5221,7 @@
"toast": "已成功创建连接器"
},
"empty": {
"message": "您似乎还没有设置任何连接器。请访问[添加连接器](/admin/add-connector)页面开始使用!"
"message": "您似乎还没有设置任何连接器。请访问[添加连接器](/admin/connectors)页面开始使用!"
},
"federated": {
"access": {
@@ -13374,8 +13562,8 @@
}
},
"items": {
"addConnector": {
"label": "添加连接器"
"connectors": {
"label": "连接器"
},
"agents": {
"label": "智能体"
+12 -12
View File
@@ -19,6 +19,7 @@ import {
SvgGlobe,
SvgHistory,
SvgImage,
SvgLinkedDots,
SvgMcp,
SvgOnyxOctagon,
SvgPaintBrush,
@@ -29,7 +30,6 @@ import {
SvgSliders,
SvgTerminal,
SvgThumbsUp,
SvgUploadCloud,
SvgUser,
SvgUserCheck,
SvgUserKey,
@@ -231,21 +231,21 @@ export const ADMIN_ROUTES = {
},
// ── Documents & Knowledge ─────────────────────────────────────────
INDEXING_STATUS: {
path: "/admin/indexing/status",
icon: SvgBookOpen,
title: "Existing Connectors",
sidebarLabel: "Existing Connectors",
CONNECTORS: {
path: "/admin/connectors",
icon: SvgLinkedDots,
title: "Connectors",
sidebarLabel: "Connectors",
requiredPermission: Permission.MANAGE_CONNECTORS,
section: "Documents & Knowledge",
requiredTier: null,
visibleWhen: (f: FeatureFlags) => f.vectorDbEnabled,
},
ADD_CONNECTOR: {
path: "/admin/add-connector",
icon: SvgUploadCloud,
title: "Add Connector",
sidebarLabel: "Add Connector",
INDEXING_STATUS: {
path: "/admin/indexing/status",
icon: SvgBookOpen,
title: "Existing Connectors",
sidebarLabel: "Existing Connectors",
requiredPermission: Permission.MANAGE_CONNECTORS,
section: "Documents & Knowledge",
requiredTier: null,
@@ -533,7 +533,7 @@ export function sidebarItem(route: AdminRouteEntry) {
*/
export const VECTOR_DB_REQUIRED_ROUTE_PREFIXES: readonly string[] = [
ADMIN_ROUTES.INDEXING_STATUS.path,
ADMIN_ROUTES.ADD_CONNECTOR.path,
ADMIN_ROUTES.CONNECTORS.path,
// Covers /sets, /explorer, and /feedback — all require a vector DB.
ADMIN_ROUTES.DOCUMENTS.path,
ADMIN_ROUTES.INDEX_SETTINGS.path,
+2 -2
View File
@@ -31,7 +31,7 @@ export type AdminNavItemId =
| "mcpActions"
| "openapiActions"
| "existingConnectors"
| "addConnector"
| "connectors"
| "documentSets"
| "indexSettings"
| "serviceAccounts"
@@ -87,7 +87,7 @@ export const NAV_ITEM_IDS: Record<
MCP_ACTIONS: "mcpActions",
OPENAPI_ACTIONS: "openapiActions",
INDEXING_STATUS: "existingConnectors",
ADD_CONNECTOR: "addConnector",
CONNECTORS: "connectors",
DOCUMENT_SETS: "documentSets",
DOCUMENT_EXPLORER: null,
DOCUMENT_FEEDBACK: null,
+1 -1
View File
@@ -29,7 +29,7 @@ export function useAdminNavLabels(): Record<AdminNavItemId, string> {
mcpActions: t("adminNav.items.mcpActions.label"),
openapiActions: t("adminNav.items.openapiActions.label"),
existingConnectors: t("adminNav.items.existingConnectors.label"),
addConnector: t("adminNav.items.addConnector.label"),
connectors: t("adminNav.items.connectors.label"),
documentSets: t("adminNav.items.documentSets.label"),
indexSettings: t("adminNav.items.indexSettings.label"),
serviceAccounts: t("adminNav.items.serviceAccounts.label"),
+72
View File
@@ -0,0 +1,72 @@
"use client";
import type { Route } from "next";
import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import { Button, SelectCard } from "@opal/components";
import { ContentAction } from "@opal/layouts";
import { SvgPlusCircle } from "@opal/icons";
import type { SourceMetadata } from "@/lib/search/types";
export interface ConnectorSourceCardProps {
sourceMetadata: SourceMetadata;
/** Translated one-line summary of what the source indexes, shown under its name. */
description: string;
/** Where the card and its add button lead: the setup wizard, or an
* existing federated connector's edit page. */
navigationUrl: Route;
}
/**
* One source in the connector catalog: the card counterpart to the
* "Add Provider" cards on the Language Models page. The whole card is the
* target; the add button repeats it for discoverability.
*/
export function ConnectorSourceCard({
sourceMetadata,
description,
navigationUrl,
}: ConnectorSourceCardProps) {
const t = useTranslations("admin.addConnector");
const router = useRouter();
const navigate = () => router.push(navigationUrl);
return (
<SelectCard
state="empty"
padding={2}
rounding={4}
// Lets the catalog find the first card to focus from the search field.
data-source-card=""
// The add button inside is labelled "Connect <name>", so an exact
// match on the bare name reaches the card alone.
aria-label={sourceMetadata.displayName}
onClick={navigate}
>
<ContentAction
icon={sourceMetadata.icon}
title={sourceMetadata.displayName}
description={description}
sizePreset="main-ui"
variant="section"
padding={2}
rightChildren={
<Button
icon={SvgPlusCircle}
prominence="tertiary"
// The card is the tab stop; the button repeats its action for
// pointer users only.
tabIndex={-1}
aria-label={t("sourceCard.connectButton.ariaLabel", {
source: sourceMetadata.displayName,
})}
onClick={(e) => {
e.stopPropagation();
navigate();
}}
/>
}
/>
</SelectCard>
);
}
+90
View File
@@ -0,0 +1,90 @@
import { SourceCategory } from "@/lib/search/types";
import { ValidSources } from "@/lib/types";
/**
* Message key, inside the `admin.addConnector` namespace, for each category
* heading in the connector catalog. The enum values are identifiers shared
* across the app, so the labels live in the catalog rather than the enum.
*/
export const SOURCE_CATEGORY_LABEL_KEYS = {
[SourceCategory.Wiki]: "categories.wiki.label",
[SourceCategory.Storage]: "categories.storage.label",
[SourceCategory.TicketingAndTaskManagement]:
"categories.ticketingAndTaskManagement.label",
[SourceCategory.Messaging]: "categories.messaging.label",
[SourceCategory.Sales]: "categories.sales.label",
[SourceCategory.CodeRepository]: "categories.codeRepository.label",
[SourceCategory.AiObservability]: "categories.aiObservability.label",
[SourceCategory.Other]: "categories.other.label",
} as const satisfies Record<SourceCategory, string>;
/** The catalog sections, in display order. */
export const CATALOG_CATEGORIES = Object.values(SourceCategory);
/**
* Message key, inside the `admin.addConnector` namespace, for the one-line
* summary shown under each source in the connector catalog. Keyed by every
* `ValidSources` member so a new source cannot ship without a summary.
*/
export const SOURCE_DESCRIPTION_KEYS = {
[ValidSources.Web]: "sources.web.description",
[ValidSources.GitHub]: "sources.github.description",
[ValidSources.GitLab]: "sources.gitlab.description",
[ValidSources.Slack]: "sources.slack.description",
[ValidSources.GoogleDrive]: "sources.googleDrive.description",
[ValidSources.Gmail]: "sources.gmail.description",
[ValidSources.Bookstack]: "sources.bookstack.description",
[ValidSources.Outline]: "sources.outline.description",
[ValidSources.Confluence]: "sources.confluence.description",
[ValidSources.Jira]: "sources.jira.description",
[ValidSources.Productboard]: "sources.productboard.description",
[ValidSources.Slab]: "sources.slab.description",
[ValidSources.Coda]: "sources.coda.description",
[ValidSources.Notion]: "sources.notion.description",
[ValidSources.Guru]: "sources.guru.description",
[ValidSources.Gong]: "sources.gong.description",
[ValidSources.Zulip]: "sources.zulip.description",
[ValidSources.Linear]: "sources.linear.description",
[ValidSources.Hubspot]: "sources.hubspot.description",
[ValidSources.Document360]: "sources.document360.description",
[ValidSources.File]: "sources.file.description",
[ValidSources.UserFile]: "sources.userFile.description",
[ValidSources.GoogleSites]: "sources.googleSites.description",
[ValidSources.Loopio]: "sources.loopio.description",
[ValidSources.Box]: "sources.box.description",
[ValidSources.Dropbox]: "sources.dropbox.description",
[ValidSources.Discord]: "sources.discord.description",
[ValidSources.Salesforce]: "sources.salesforce.description",
[ValidSources.Sharepoint]: "sources.sharepoint.description",
[ValidSources.Teams]: "sources.teams.description",
[ValidSources.Outlook]: "sources.outlook.description",
[ValidSources.Zendesk]: "sources.zendesk.description",
[ValidSources.Discourse]: "sources.discourse.description",
[ValidSources.Axero]: "sources.axero.description",
[ValidSources.Clickup]: "sources.clickup.description",
[ValidSources.Wikipedia]: "sources.wikipedia.description",
[ValidSources.Mediawiki]: "sources.mediawiki.description",
[ValidSources.Asana]: "sources.asana.description",
[ValidSources.S3]: "sources.s3.description",
[ValidSources.R2]: "sources.r2.description",
[ValidSources.GoogleCloudStorage]: "sources.googleCloudStorage.description",
[ValidSources.Xenforo]: "sources.xenforo.description",
[ValidSources.OciStorage]: "sources.ociStorage.description",
[ValidSources.NotApplicable]: "sources.notApplicable.description",
[ValidSources.IngestionApi]: "sources.ingestionApi.description",
[ValidSources.Freshdesk]: "sources.freshdesk.description",
[ValidSources.Fireflies]: "sources.fireflies.description",
[ValidSources.Egnyte]: "sources.egnyte.description",
[ValidSources.Airtable]: "sources.airtable.description",
[ValidSources.Gitbook]: "sources.gitbook.description",
[ValidSources.Highspot]: "sources.highspot.description",
[ValidSources.DrupalWiki]: "sources.drupalWiki.description",
[ValidSources.Imap]: "sources.imap.description",
[ValidSources.Bitbucket]: "sources.bitbucket.description",
[ValidSources.TestRail]: "sources.testrail.description",
[ValidSources.Braintrust]: "sources.braintrust.description",
[ValidSources.Lumapps]: "sources.lumapps.description",
[ValidSources.Canvas]: "sources.canvas.description",
[ValidSources.CraftFile]: "sources.craftFile.description",
[ValidSources.FederatedSlack]: "sources.federatedSlack.description",
} as const satisfies Record<ValidSources, string>;
+2 -1
View File
@@ -125,7 +125,8 @@ export enum SourceCategory {
Messaging = "Messaging",
Sales = "Sales",
CodeRepository = "Code Repository",
Other = "Others",
AiObservability = "AI & Observability",
Other = "Other",
}
export interface SourceMetadata {
+1 -1
View File
@@ -445,7 +445,7 @@ export const SOURCE_METADATA_MAP: SourceMap = {
braintrust: {
icon: BraintrustIcon,
displayName: "Braintrust",
category: SourceCategory.Other,
category: SourceCategory.AiObservability,
},
// Other
@@ -1,6 +1,7 @@
"use client";
import { Fragment, useMemo } from "react";
import { ADMIN_ROUTES } from "@/lib/admin-routes";
import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import type { Route } from "next";
@@ -265,7 +266,7 @@ export default function ToolLineItem({ tool }: ToolLineItemProps) {
aria-label={connectorsLabel}
tooltip={connectorsLabel}
onClick={() => {
if (needsConnectors) router.push("/admin/add-connector");
if (needsConnectors) router.push(ADMIN_ROUTES.CONNECTORS.path);
else openSources();
}}
/>
@@ -1,6 +1,7 @@
"use client";
import { Fragment, ReactNode } from "react";
import { ADMIN_ROUTES } from "@/lib/admin-routes";
import { useTranslations } from "next-intl";
import { useFormContext } from "@/components/context/FormContext";
import { credentialTemplates } from "@/lib/connectors/credentials";
@@ -72,7 +73,7 @@ export function CreateConnectorSidebarShell({
{!folded && <Divider paddingPerpendicular={2} />}
<SidebarTab
icon={SvgX}
href="/admin/add-connector"
href={ADMIN_ROUTES.CONNECTORS.path}
variant="sidebar-light"
folded={folded}
>
@@ -1,10 +1,12 @@
"use client";
import type { Route } from "next";
import { useAdminRouteTitle } from "@/lib/adminNavLabels";
import { useTranslations } from "next-intl";
import { SettingsLayouts } from "@opal/layouts";
import { Content, SettingsLayouts } from "@opal/layouts";
import * as GeneralLayouts from "@/layouts/general-layouts";
import { SourceCategory, SourceMetadata } from "@/lib/search/types";
import { listSourceMetadata } from "@/lib/sources";
import { Button } from "@opal/components";
import {
useCallback,
useDeferredValue,
@@ -13,7 +15,8 @@ import {
useRef,
useState,
} from "react";
import { Tooltip } from "@opal/components";
import { Tooltip, InputTypeIn, Text } from "@opal/components";
import { richNodes } from "@opal/utils";
import { useFederatedConnectors } from "@/lib/hooks";
import {
FederatedConnectorDetail,
@@ -25,39 +28,32 @@ import { errorHandlingFetcher } from "@/lib/fetcher";
import { buildSimilarCredentialInfoURL } from "@/app/admin/connector/[ccPairId]/lib";
import { Credential } from "@/lib/connectors/credentials";
import { useSettings } from "@/lib/settings/hooks";
import SourceTile from "@/components/SourceTile";
import { InputTypeIn } from "@opal/components";
import Text from "@/refresh-components/texts/Text";
import { ConnectorSourceCard } from "@/lib/connectors/components";
import { ADMIN_ROUTES } from "@/lib/admin-routes";
import {
CATALOG_CATEGORIES,
SOURCE_CATEGORY_LABEL_KEYS,
SOURCE_DESCRIPTION_KEYS,
} from "@/lib/connectors/constants";
const route = ADMIN_ROUTES.ADD_CONNECTOR;
const route = ADMIN_ROUTES.CONNECTORS;
// The category headings come from the `SourceCategory` enum, whose values are
// identifiers shared across the app. Map each one to a message key (inside the
// `admin.addConnector` namespace) so the component can resolve it with `t`.
const CATEGORY_LABEL_KEYS = {
[SourceCategory.Wiki]: "categories.wiki.label",
[SourceCategory.Storage]: "categories.storage.label",
[SourceCategory.TicketingAndTaskManagement]:
"categories.ticketingAndTaskManagement.label",
[SourceCategory.Messaging]: "categories.messaging.label",
[SourceCategory.Sales]: "categories.sales.label",
[SourceCategory.CodeRepository]: "categories.codeRepository.label",
[SourceCategory.Other]: "categories.other.label",
} as const satisfies Record<SourceCategory, string>;
// Four columns at the full settings width, three and then two as the
// `sourcecards` container narrows.
const SOURCE_CARD_GRID =
"grid grid-cols-2 @xl/sourcecards:grid-cols-3 @3xl/sourcecards:grid-cols-4 gap-2";
function SourceTileTooltipWrapper({
sourceMetadata,
preSelect,
federatedConnectors,
slackCredentials,
}: {
sourceMetadata: SourceMetadata;
preSelect?: boolean;
federatedConnectors?: FederatedConnectorDetail[];
slackCredentials?: Credential<any>[];
}) {
const t = useTranslations("admin.addConnector");
const description = t(SOURCE_DESCRIPTION_KEYS[sourceMetadata.internalName]);
// Check if there's already a federated connector for this source
const existingFederatedConnector = useMemo(() => {
@@ -82,11 +78,11 @@ function SourceTileTooltipWrapper({
const navigationUrl = useMemo(() => {
// If there's an existing federated connector, route to edit it
if (existingFederatedConnector) {
return `/admin/federated/${existingFederatedConnector.id}`;
return `/admin/federated/${existingFederatedConnector.id}` as Route;
}
// For all other sources (including Slack), use the regular admin URL
return sourceMetadata.adminUrl;
return sourceMetadata.adminUrl as Route;
}, [existingFederatedConnector, sourceMetadata]);
// Compute whether to hide the tooltip
@@ -98,11 +94,10 @@ function SourceTileTooltipWrapper({
// If tooltip should be hidden, just render the tile as a component
if (shouldHideTooltip) {
return (
<SourceTile
<ConnectorSourceCard
sourceMetadata={sourceMetadata}
preSelect={preSelect}
description={description}
navigationUrl={navigationUrl}
hasExistingSlackCredentials={!!hasExistingSlackCredentials}
/>
);
}
@@ -112,33 +107,34 @@ function SourceTileTooltipWrapper({
side="top"
tooltip={
existingFederatedConnector ? (
<Text as="p" textLight05 secondaryBody>
{t.rich("sourceTile.tooltip.federatedConfigured", {
strong: (chunks) => <strong>{chunks}</strong>,
})}
<Text as="p" font="secondary-body" color="inherit">
{richNodes(
t.rich("sourceTile.tooltip.federatedConfigured", {
strong: (chunks) => <strong>{chunks}</strong>,
})
)}
</Text>
) : hasExistingSlackCredentials ? (
<Text as="p" textLight05 secondaryBody>
{t.rich("sourceTile.tooltip.slackCredentialsFound", {
strong: (chunks) => <strong>{chunks}</strong>,
})}
<Text as="p" font="secondary-body" color="inherit">
{richNodes(
t.rich("sourceTile.tooltip.slackCredentialsFound", {
strong: (chunks) => <strong>{chunks}</strong>,
})
)}
</Text>
) : undefined
}
>
<div>
<SourceTile
sourceMetadata={sourceMetadata}
preSelect={preSelect}
navigationUrl={navigationUrl}
hasExistingSlackCredentials={!!hasExistingSlackCredentials}
/>
</div>
<ConnectorSourceCard
sourceMetadata={sourceMetadata}
description={description}
navigationUrl={navigationUrl}
/>
</Tooltip>
);
}
export default function Page() {
export default function ConnectorsPage() {
const t = useTranslations("admin.addConnector");
const adminRouteTitle = useAdminRouteTitle();
const sources = useMemo(() => listSourceMetadata(), []);
@@ -148,6 +144,7 @@ export default function Page() {
const { data: federatedConnectors } = useFederatedConnectors();
const settings = useSettings();
const { appName } = settings;
// Fetch Slack credentials to determine navigation behavior
const { data: slackCredentials } = useSWR<Credential<any>[]>(
@@ -188,7 +185,7 @@ export default function Page() {
const categorizedSources = useMemo(() => {
const filtered = filterSources(sources);
const categories = Object.values(SourceCategory).reduce(
const categories = CATALOG_CATEGORIES.reduce(
(acc, category) => {
acc[category] = sources.filter(
(source) =>
@@ -200,10 +197,10 @@ export default function Page() {
},
{} as Record<SourceCategory, SourceMetadata[]>
);
// Filter out the "Other" category if show_extra_connectors is false
// The extra-connectors setting hides the AI & Observability section.
if (settings?.show_extra_connectors === false) {
const filteredCategories = Object.entries(categories).filter(
([category]) => category !== SourceCategory.Other
([category]) => category !== SourceCategory.AiObservability
);
return Object.fromEntries(filteredCategories) as Record<
SourceCategory,
@@ -228,102 +225,104 @@ export default function Page() {
return popularSources.filter((s) => !resultIds.has(s.internalName));
}, [popularSources, resultIds, searchTerm]);
const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
const filteredCategories = Object.entries(categorizedSources).filter(
([_, sources]) => sources.length > 0
);
if (
filteredCategories.length > 0 &&
filteredCategories[0] !== undefined &&
filteredCategories[0][1].length > 0
) {
const firstSource = filteredCategories[0][1][0];
if (firstSource) {
// Check if this source has an existing federated connector
const existingFederatedConnector =
firstSource.federated && federatedConnectors
? federatedConnectors.find(
(connector) =>
connector.source === `federated_${firstSource.internalName}`
)
: null;
const url = existingFederatedConnector
? `/admin/federated/${existingFederatedConnector.id}`
: firstSource.adminUrl;
window.open(url, "_self");
}
}
}
// Enter or ArrowDown in the search field moves focus to the first card;
// a focused card opens on Enter.
const catalogRef = useRef<HTMLDivElement>(null);
const handleSearchKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key !== "Enter" && e.key !== "ArrowDown") return;
const card =
catalogRef.current?.querySelector<HTMLElement>("[data-source-card]");
if (!card) return;
e.preventDefault();
card.focus();
};
return (
<SettingsLayouts.Root width="full">
<SettingsLayouts.Header
icon={route.icon}
title={adminRouteTitle(route)}
rightChildren={
<Button href="/admin/indexing/status">
{t("seeConnectorsButton.label")}
</Button>
}
divider
/>
<SettingsLayouts.Body>
<SettingsLayouts.Root width="lg">
<SettingsLayouts.Header icon={route.icon} title={adminRouteTitle(route)}>
<InputTypeIn
type="text"
searchIcon
placeholder={t("search.placeholder")}
ref={searchInputRef}
value={rawSearchTerm} // keep the input bound to immediate state
onChange={(event) => setSearchTerm(event.target.value)}
onKeyDown={handleKeyPress}
onKeyDown={handleSearchKeyDown}
/>
</SettingsLayouts.Header>
<SettingsLayouts.Body>
<div
ref={catalogRef}
className="@container/sourcecards flex flex-col gap-8"
>
<GeneralLayouts.Section
gap={3}
height="fit"
alignItems="stretch"
justifyContent="start"
>
<Content
title={t("popular.title")}
description={t("popular.description", { appName })}
sizePreset="main-content"
variant="section"
/>
<GeneralLayouts.Section
gap={8}
height="fit"
alignItems="stretch"
justifyContent="start"
>
{dedupedPopular.length > 0 && (
<GeneralLayouts.Section
gap={3}
height="fit"
alignItems="stretch"
justifyContent="start"
>
<div className={SOURCE_CARD_GRID}>
{dedupedPopular.map((source) => (
<SourceTileTooltipWrapper
key={source.internalName}
sourceMetadata={source}
federatedConnectors={federatedConnectors}
slackCredentials={slackCredentials}
/>
))}
</div>
</GeneralLayouts.Section>
)}
{dedupedPopular.length > 0 && (
<div className="pt-8">
<Text as="p" headingH3>
{t("popular.title")}
</Text>
<div className="flex flex-wrap gap-4 p-4">
{dedupedPopular.map((source) => (
<SourceTileTooltipWrapper
preSelect={false}
key={source.internalName}
sourceMetadata={source}
federatedConnectors={federatedConnectors}
slackCredentials={slackCredentials}
/>
))}
</div>
</div>
)}
{Object.entries(categorizedSources)
.filter(([_, sources]) => sources.length > 0)
.map(([category, sources], categoryInd) => (
<div key={category} className="pt-8">
<Text as="p" headingH3>
{t(CATEGORY_LABEL_KEYS[category as SourceCategory])}
</Text>
<div className="flex flex-wrap gap-4 p-4">
{sources.map((source, sourceInd) => (
<SourceTileTooltipWrapper
preSelect={
(searchTerm?.length ?? 0) > 0 &&
categoryInd == 0 &&
sourceInd == 0
}
key={source.internalName}
sourceMetadata={source}
federatedConnectors={federatedConnectors}
slackCredentials={slackCredentials}
/>
{Object.entries(categorizedSources)
.filter(([_, sources]) => sources.length > 0)
.map(([category, sources]) => (
<GeneralLayouts.Section
key={category}
gap={3}
height="fit"
alignItems="stretch"
justifyContent="start"
>
<Text font="main-ui-action" color="text-03">
{t(
SOURCE_CATEGORY_LABEL_KEYS[category as SourceCategory]
)}
</Text>
<div className={SOURCE_CARD_GRID}>
{sources.map((source) => (
<SourceTileTooltipWrapper
key={source.internalName}
sourceMetadata={source}
federatedConnectors={federatedConnectors}
slackCredentials={slackCredentials}
/>
))}
</div>
</GeneralLayouts.Section>
))}
</div>
</div>
))}
</GeneralLayouts.Section>
</GeneralLayouts.Section>
</div>
</SettingsLayouts.Body>
</SettingsLayouts.Root>
);
@@ -0,0 +1,37 @@
/**
* Page Object Model for the connector catalog (`/admin/connectors`).
*
* Every source renders as a card whose add button is labelled
* "Connect <name>". Popular sources appear twice (in the popular grid and in
* their category), so actions target the first match.
*/
import { expect, type Locator, type Page } from "@playwright/test";
export class ConnectorCatalogPage {
readonly page: Page;
readonly pageTitle: Locator;
constructor(page: Page) {
this.page = page;
this.pageTitle = page.locator('[aria-label="admin-page-title"]');
}
async goto() {
await this.page.goto("/admin/connectors");
await expect(this.pageTitle).toBeVisible({ timeout: 10_000 });
}
/** The add button on a source's card, by the source's display name. */
connectButton(displayName: string): Locator {
return this.page
.getByRole("button", { name: `Connect ${displayName}` })
.first();
}
/** Open a source's setup flow from its card. */
async openSource(displayName: string) {
await this.connectButton(displayName).click();
await this.page.waitForLoadState("networkidle");
}
}
@@ -1,5 +1,5 @@
/**
* Page Object Model for the add-connector wizard
* Page Object Model for the connector setup wizard
* (`/admin/connectors/<source>?step=1`).
*
* The wizard renders every connector's configuration form through the shared
@@ -20,7 +20,7 @@ const PAGE_HEADINGS: Record<string, string> = {
[ADMIN_ROUTES.MCP_ACTIONS.path]: "MCP Actions",
[ADMIN_ROUTES.OPENAPI_ACTIONS.path]: "OpenAPI Actions",
[ADMIN_ROUTES.INDEXING_STATUS.path]: "Existing Connectors",
[ADMIN_ROUTES.ADD_CONNECTOR.path]: "Add Connector",
[ADMIN_ROUTES.CONNECTORS.path]: "Connectors",
[ADMIN_ROUTES.DOCUMENT_SETS.path]: "Document Sets",
};
@@ -33,7 +33,7 @@ const ALWAYS_PAGES = [
/** Also require `vectorDbEnabled`. */
const VECTOR_DB_PAGES = [
ADMIN_ROUTES.ADD_CONNECTOR.path,
ADMIN_ROUTES.CONNECTORS.path,
ADMIN_ROUTES.DOCUMENT_SETS.path,
ADMIN_ROUTES.INDEXING_STATUS.path,
];
@@ -273,8 +273,8 @@ test.describe("Permission gating — MANAGE_CONNECTORS", () => {
await page.waitForLoadState("networkidle");
expect(page.url()).toContain("/app");
// Also verify /admin/add-connector redirects
await page.goto(ADMIN_ROUTES.ADD_CONNECTOR.path);
// Also verify /admin/connectors redirects
await page.goto(ADMIN_ROUTES.CONNECTORS.path);
await page.waitForLoadState("networkidle");
expect(page.url()).toContain("/app");
@@ -296,16 +296,16 @@ test.describe("Permission gating — MANAGE_CONNECTORS", () => {
).toBeVisible({ timeout: 10000 });
await expect(page.getByRole("table")).toBeVisible();
// Also verify /admin/add-connector is accessible
await page.goto(ADMIN_ROUTES.ADD_CONNECTOR.path);
// Also verify /admin/connectors is accessible
await page.goto(ADMIN_ROUTES.CONNECTORS.path);
await page.waitForLoadState("networkidle");
expect(page.url()).toContain(ADMIN_ROUTES.ADD_CONNECTOR.path);
expect(page.url()).toContain(ADMIN_ROUTES.CONNECTORS.path);
await expect(
page.getByLabel("admin-page-title").getByText("Add Connector")
page.getByLabel("admin-page-title").getByText("Connectors")
).toBeVisible({ timeout: 10000 });
// Access type and groups live on the wizard's second step, so reaching
// /admin/add-connector says nothing about them. `web` has no credential
// /admin/connectors says nothing about them. `web` has no credential
// template, so the wizard skips straight there.
await page.goto("/admin/connectors/web");
await page.waitForLoadState("networkidle");
@@ -1,6 +1,7 @@
import { test, expect } from "@playwright/test";
import type { Page } from "@playwright/test";
import { loginAs, loginAsRandomUser } from "@tests/e2e/utils/auth";
import { ConnectorCatalogPage } from "@tests/e2e/admin/connector/ConnectorCatalogPage";
test.use({ storageState: "admin_auth.json" });
@@ -8,13 +9,9 @@ const SLACK_CLIENT_ID = process.env.SLACK_CLIENT_ID;
const SLACK_CLIENT_SECRET = process.env.SLACK_CLIENT_SECRET;
async function createFederatedSlackConnector(page: Page) {
// Navigate to add connector page
await page.goto("/admin/add-connector");
await page.waitForLoadState("networkidle");
// Click on Slack connector tile (specifically the one with "Logo Slack" text, not "Slack Bots")
await page.getByRole("link", { name: "Logo Slack" }).first().click();
await page.waitForLoadState("networkidle");
const catalog = new ConnectorCatalogPage(page);
await catalog.goto();
await catalog.openSource("Slack");
if (!SLACK_CLIENT_ID || !SLACK_CLIENT_SECRET) {
throw new Error("SLACK_CLIENT_ID and SLACK_CLIENT_SECRET must be set");