mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-12 18:15:33 +00:00
Remove the Add knowledge forms for synced services
Nothing opens the Google Drive, SharePoint, Confluence, S3 or Reddit forms in Add knowledge any more: those services sync through the connect wizard. Their pickers, saved-key account logic, setup notice, advanced fields and strings go, and the remote upload sends the form's own fields.
This commit is contained in:
1 parent
6ccc506b8c
commit
cdab471c22
10 files changed
+55
-1013
No files matched your search
@@ -1677,14 +1677,6 @@
|
||||
"link": "Link",
|
||||
"urlLink": "URL-Link",
|
||||
"repoUrl": "Repository-URL",
|
||||
"reddit": {
|
||||
"id": "Client-ID",
|
||||
"secret": "Client-Secret",
|
||||
"agent": "User-Agent",
|
||||
"searchQueries": "Suchanfragen",
|
||||
"numberOfPosts": "Anzahl der Beiträge",
|
||||
"addQuery": "Anfrage hinzufügen"
|
||||
},
|
||||
"drag": {
|
||||
"title": "Anhänge hier ablegen",
|
||||
"description": "Loslassen, um deine Anhänge hochzuladen"
|
||||
@@ -1706,8 +1698,6 @@
|
||||
"clear": "Löschen",
|
||||
"ingestionFailed": "Aufnahme fehlgeschlagen."
|
||||
},
|
||||
"showAdvanced": "Erweiterte Optionen anzeigen",
|
||||
"hideAdvanced": "Erweiterte Optionen ausblenden",
|
||||
"ingestors": {
|
||||
"local_file": {
|
||||
"label": "Datei hochladen",
|
||||
@@ -1725,26 +1715,6 @@
|
||||
"label": "GitHub",
|
||||
"heading": "Inhalt von GitHub hinzufügen"
|
||||
},
|
||||
"reddit": {
|
||||
"label": "Reddit",
|
||||
"heading": "Inhalt von Reddit hinzufügen"
|
||||
},
|
||||
"google_drive": {
|
||||
"label": "Google Drive",
|
||||
"heading": "Von Google Drive hochladen"
|
||||
},
|
||||
"s3": {
|
||||
"label": "Amazon S3",
|
||||
"heading": "Inhalt von Amazon S3 hinzufügen"
|
||||
},
|
||||
"share_point": {
|
||||
"label": "SharePoint",
|
||||
"heading": "Von SharePoint hochladen"
|
||||
},
|
||||
"confluence": {
|
||||
"label": "Confluence",
|
||||
"heading": "Von Confluence hochladen"
|
||||
},
|
||||
"wiki": {
|
||||
"label": "Neues Wiki",
|
||||
"heading": "Lebendiges Wiki erstellen"
|
||||
@@ -1798,15 +1768,8 @@
|
||||
},
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"awsAccessKeyId": "AWS-Zugriffsschlüssel-ID",
|
||||
"awsSecretAccessKey": "Geheimer AWS-Zugriffsschlüssel",
|
||||
"bucket": "Bucket-Name",
|
||||
"prefix": "Pfadpräfix (optional)",
|
||||
"region": "AWS-Region",
|
||||
"endpointUrl": "Benutzerdefinierte Endpunkt-URL (optional)",
|
||||
"initialContent": "Anfangsinhalt (optional)"
|
||||
},
|
||||
"newCredentials": "Neue Zugangsdaten eingeben",
|
||||
"github": {
|
||||
"privateHint": "Privates Repository? Verbinde dein GitHub-Konto, um es zu synchronisieren.",
|
||||
"connectedHint": "Private Repositorys werden über deine GitHub-Verbindung ({{account}}) synchronisiert.",
|
||||
|
||||
@@ -1683,14 +1683,6 @@
|
||||
"link": "Link",
|
||||
"urlLink": "URL Link",
|
||||
"repoUrl": "Repository URL",
|
||||
"reddit": {
|
||||
"id": "Client ID",
|
||||
"secret": "Client Secret",
|
||||
"agent": "User agent",
|
||||
"searchQueries": "Search queries",
|
||||
"numberOfPosts": "Number of posts",
|
||||
"addQuery": "Add Query"
|
||||
},
|
||||
"drag": {
|
||||
"title": "Drop attachments here",
|
||||
"description": "Release to upload your attachments"
|
||||
@@ -1712,8 +1704,6 @@
|
||||
"clear": "Clear",
|
||||
"ingestionFailed": "Ingestion failed."
|
||||
},
|
||||
"showAdvanced": "Show advanced options",
|
||||
"hideAdvanced": "Hide advanced options",
|
||||
"ingestors": {
|
||||
"local_file": {
|
||||
"label": "Upload File",
|
||||
@@ -1731,26 +1721,6 @@
|
||||
"label": "GitHub",
|
||||
"heading": "Add content from GitHub"
|
||||
},
|
||||
"reddit": {
|
||||
"label": "Reddit",
|
||||
"heading": "Add content from Reddit"
|
||||
},
|
||||
"google_drive": {
|
||||
"label": "Google Drive",
|
||||
"heading": "Upload from Google Drive"
|
||||
},
|
||||
"s3": {
|
||||
"label": "Amazon S3",
|
||||
"heading": "Add content from Amazon S3"
|
||||
},
|
||||
"share_point": {
|
||||
"label": "SharePoint",
|
||||
"heading": "Upload from SharePoint"
|
||||
},
|
||||
"confluence": {
|
||||
"label": "Confluence",
|
||||
"heading": "Upload from Confluence"
|
||||
},
|
||||
"wiki": {
|
||||
"label": "New wiki",
|
||||
"heading": "Create a living wiki"
|
||||
@@ -1804,15 +1774,8 @@
|
||||
},
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"awsAccessKeyId": "AWS Access Key ID",
|
||||
"awsSecretAccessKey": "AWS Secret Access Key",
|
||||
"bucket": "Bucket Name",
|
||||
"prefix": "Path Prefix (optional)",
|
||||
"region": "AWS Region",
|
||||
"endpointUrl": "Custom Endpoint URL (optional)",
|
||||
"initialContent": "Initial content (optional)"
|
||||
},
|
||||
"newCredentials": "Enter new credentials",
|
||||
"github": {
|
||||
"privateHint": "Private repository? Connect your GitHub account to sync it.",
|
||||
"connectedHint": "Private repositories sync from your GitHub connection ({{account}}).",
|
||||
|
||||
@@ -1677,14 +1677,6 @@
|
||||
"link": "Enlace",
|
||||
"urlLink": "Enlace URL",
|
||||
"repoUrl": "URL del Repositorio",
|
||||
"reddit": {
|
||||
"id": "ID del Cliente",
|
||||
"secret": "Secreto del Cliente",
|
||||
"agent": "Agente de usuario",
|
||||
"searchQueries": "Consultas de búsqueda",
|
||||
"numberOfPosts": "Número de publicaciones",
|
||||
"addQuery": "Agregar Consulta"
|
||||
},
|
||||
"drag": {
|
||||
"title": "Suelta los archivos adjuntos aquí",
|
||||
"description": "Suelta para subir tus archivos adjuntos"
|
||||
@@ -1706,8 +1698,6 @@
|
||||
"clear": "Limpiar",
|
||||
"ingestionFailed": "La ingesta falló."
|
||||
},
|
||||
"showAdvanced": "Mostrar opciones avanzadas",
|
||||
"hideAdvanced": "Ocultar opciones avanzadas",
|
||||
"ingestors": {
|
||||
"local_file": {
|
||||
"label": "Subir archivo",
|
||||
@@ -1725,26 +1715,6 @@
|
||||
"label": "GitHub",
|
||||
"heading": "Agregar contenido desde GitHub"
|
||||
},
|
||||
"reddit": {
|
||||
"label": "Reddit",
|
||||
"heading": "Agregar contenido desde Reddit"
|
||||
},
|
||||
"google_drive": {
|
||||
"label": "Google Drive",
|
||||
"heading": "Subir desde Google Drive"
|
||||
},
|
||||
"s3": {
|
||||
"label": "Amazon S3",
|
||||
"heading": "Agregar contenido desde Amazon S3"
|
||||
},
|
||||
"share_point": {
|
||||
"label": "SharePoint",
|
||||
"heading": "Subir desde SharePoint"
|
||||
},
|
||||
"confluence": {
|
||||
"label": "Confluence",
|
||||
"heading": "Subir desde Confluence"
|
||||
},
|
||||
"wiki": {
|
||||
"label": "Nueva wiki",
|
||||
"heading": "Crear una wiki viva"
|
||||
@@ -1798,15 +1768,8 @@
|
||||
},
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"awsAccessKeyId": "ID de clave de acceso de AWS",
|
||||
"awsSecretAccessKey": "Clave de acceso secreta de AWS",
|
||||
"bucket": "Nombre del bucket",
|
||||
"prefix": "Prefijo de ruta (opcional)",
|
||||
"region": "Región de AWS",
|
||||
"endpointUrl": "URL de endpoint personalizada (opcional)",
|
||||
"initialContent": "Contenido inicial (opcional)"
|
||||
},
|
||||
"newCredentials": "Introducir credenciales nuevas",
|
||||
"github": {
|
||||
"privateHint": "¿Repositorio privado? Conecta tu cuenta de GitHub para sincronizarlo.",
|
||||
"connectedHint": "Los repositorios privados se sincronizan desde tu conexión de GitHub ({{account}}).",
|
||||
|
||||
@@ -1666,14 +1666,6 @@
|
||||
"link": "リンク",
|
||||
"urlLink": "URLリンク",
|
||||
"repoUrl": "リポジトリURL",
|
||||
"reddit": {
|
||||
"id": "クライアントID",
|
||||
"secret": "クライアントシークレット",
|
||||
"agent": "ユーザーエージェント",
|
||||
"searchQueries": "検索クエリ",
|
||||
"numberOfPosts": "投稿数",
|
||||
"addQuery": "クエリを追加"
|
||||
},
|
||||
"drag": {
|
||||
"title": "添付ファイルをここにドロップ",
|
||||
"description": "リリースして添付ファイルをアップロード"
|
||||
@@ -1695,8 +1687,6 @@
|
||||
"clear": "クリア",
|
||||
"ingestionFailed": "取り込みに失敗しました。"
|
||||
},
|
||||
"showAdvanced": "詳細オプションを表示",
|
||||
"hideAdvanced": "詳細オプションを非表示",
|
||||
"ingestors": {
|
||||
"local_file": {
|
||||
"label": "ファイルをアップロード",
|
||||
@@ -1714,26 +1704,6 @@
|
||||
"label": "GitHub",
|
||||
"heading": "GitHubからコンテンツを追加"
|
||||
},
|
||||
"reddit": {
|
||||
"label": "Reddit",
|
||||
"heading": "Redditからコンテンツを追加"
|
||||
},
|
||||
"google_drive": {
|
||||
"label": "Google Drive",
|
||||
"heading": "Google Driveからアップロード"
|
||||
},
|
||||
"s3": {
|
||||
"label": "Amazon S3",
|
||||
"heading": "Amazon S3からコンテンツを追加"
|
||||
},
|
||||
"share_point": {
|
||||
"label": "SharePoint",
|
||||
"heading": "SharePointからアップロード"
|
||||
},
|
||||
"confluence": {
|
||||
"label": "Confluence",
|
||||
"heading": "Confluenceからアップロード"
|
||||
},
|
||||
"wiki": {
|
||||
"label": "新しいWiki",
|
||||
"heading": "リビングWikiを作成"
|
||||
@@ -1787,15 +1757,8 @@
|
||||
},
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"awsAccessKeyId": "AWS アクセスキー ID",
|
||||
"awsSecretAccessKey": "AWS シークレットアクセスキー",
|
||||
"bucket": "バケット名",
|
||||
"prefix": "パスプレフィックス(任意)",
|
||||
"region": "AWS リージョン",
|
||||
"endpointUrl": "カスタムエンドポイント URL(任意)",
|
||||
"initialContent": "初期コンテンツ(任意)"
|
||||
},
|
||||
"newCredentials": "新しい認証情報を入力",
|
||||
"github": {
|
||||
"privateHint": "プライベートリポジトリですか?同期するには GitHub アカウントを接続してください。",
|
||||
"connectedHint": "プライベートリポジトリは GitHub 接続({{account}})から同期されます。",
|
||||
|
||||
@@ -1761,14 +1761,6 @@
|
||||
"link": "Ссылка",
|
||||
"urlLink": "URL ссылка",
|
||||
"repoUrl": "URL репозитория",
|
||||
"reddit": {
|
||||
"id": "ID клиента",
|
||||
"secret": "Секрет клиента",
|
||||
"agent": "Пользовательский агент",
|
||||
"searchQueries": "Поисковые запросы",
|
||||
"numberOfPosts": "Количество сообщений",
|
||||
"addQuery": "Добавить запрос"
|
||||
},
|
||||
"drag": {
|
||||
"title": "Перетащите вложения сюда",
|
||||
"description": "Отпустите, чтобы загрузить ваши вложения"
|
||||
@@ -1790,8 +1782,6 @@
|
||||
"clear": "Очистить",
|
||||
"ingestionFailed": "Не удалось загрузить данные."
|
||||
},
|
||||
"showAdvanced": "Показать расширенные настройки",
|
||||
"hideAdvanced": "Скрыть расширенные настройки",
|
||||
"ingestors": {
|
||||
"local_file": {
|
||||
"label": "Загрузить файл",
|
||||
@@ -1809,26 +1799,6 @@
|
||||
"label": "GitHub",
|
||||
"heading": "Добавить контент из GitHub"
|
||||
},
|
||||
"reddit": {
|
||||
"label": "Reddit",
|
||||
"heading": "Добавить контент из Reddit"
|
||||
},
|
||||
"google_drive": {
|
||||
"label": "Google Drive",
|
||||
"heading": "Загрузить из Google Drive"
|
||||
},
|
||||
"s3": {
|
||||
"label": "Amazon S3",
|
||||
"heading": "Добавить контент из Amazon S3"
|
||||
},
|
||||
"share_point": {
|
||||
"label": "SharePoint",
|
||||
"heading": "Загрузить из SharePoint"
|
||||
},
|
||||
"confluence": {
|
||||
"label": "Confluence",
|
||||
"heading": "Загрузить из Confluence"
|
||||
},
|
||||
"wiki": {
|
||||
"label": "Новая вики",
|
||||
"heading": "Создать живую вики"
|
||||
@@ -1882,15 +1852,8 @@
|
||||
},
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"awsAccessKeyId": "Идентификатор ключа доступа AWS",
|
||||
"awsSecretAccessKey": "Секретный ключ доступа AWS",
|
||||
"bucket": "Имя бакета",
|
||||
"prefix": "Префикс пути (необязательно)",
|
||||
"region": "Регион AWS",
|
||||
"endpointUrl": "Пользовательский URL эндпоинта (необязательно)",
|
||||
"initialContent": "Исходное содержимое (необязательно)"
|
||||
},
|
||||
"newCredentials": "Ввести новые учётные данные",
|
||||
"github": {
|
||||
"privateHint": "Приватный репозиторий? Подключите аккаунт GitHub, чтобы синхронизировать его.",
|
||||
"connectedHint": "Приватные репозитории синхронизируются через ваше подключение GitHub ({{account}}).",
|
||||
|
||||
@@ -1666,14 +1666,6 @@
|
||||
"link": "連結",
|
||||
"urlLink": "URL 連結",
|
||||
"repoUrl": "儲存庫 URL",
|
||||
"reddit": {
|
||||
"id": "客戶端ID",
|
||||
"secret": "客戶端密鑰",
|
||||
"agent": "使用者代理",
|
||||
"searchQueries": "搜尋查詢",
|
||||
"numberOfPosts": "貼文數量",
|
||||
"addQuery": "新增查詢"
|
||||
},
|
||||
"drag": {
|
||||
"title": "將附件拖放到此處",
|
||||
"description": "釋放以上傳您的附件"
|
||||
@@ -1695,8 +1687,6 @@
|
||||
"clear": "清除",
|
||||
"ingestionFailed": "匯入失敗。"
|
||||
},
|
||||
"showAdvanced": "顯示進階選項",
|
||||
"hideAdvanced": "隱藏進階選項",
|
||||
"ingestors": {
|
||||
"local_file": {
|
||||
"label": "上傳檔案",
|
||||
@@ -1714,26 +1704,6 @@
|
||||
"label": "GitHub",
|
||||
"heading": "從GitHub新增內容"
|
||||
},
|
||||
"reddit": {
|
||||
"label": "Reddit",
|
||||
"heading": "從Reddit新增內容"
|
||||
},
|
||||
"google_drive": {
|
||||
"label": "Google Drive",
|
||||
"heading": "從Google Drive上傳"
|
||||
},
|
||||
"s3": {
|
||||
"label": "Amazon S3",
|
||||
"heading": "從Amazon S3新增內容"
|
||||
},
|
||||
"share_point": {
|
||||
"label": "SharePoint",
|
||||
"heading": "從SharePoint上傳"
|
||||
},
|
||||
"confluence": {
|
||||
"label": "Confluence",
|
||||
"heading": "從Confluence上傳"
|
||||
},
|
||||
"wiki": {
|
||||
"label": "新 Wiki",
|
||||
"heading": "建立動態 Wiki"
|
||||
@@ -1787,15 +1757,8 @@
|
||||
},
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"awsAccessKeyId": "AWS 存取金鑰 ID",
|
||||
"awsSecretAccessKey": "AWS 秘密存取金鑰",
|
||||
"bucket": "儲存貯體名稱",
|
||||
"prefix": "路徑前綴(選填)",
|
||||
"region": "AWS 區域",
|
||||
"endpointUrl": "自訂端點 URL(選填)",
|
||||
"initialContent": "初始內容(選填)"
|
||||
},
|
||||
"newCredentials": "輸入新的憑證",
|
||||
"github": {
|
||||
"privateHint": "私人儲存庫?連結你的 GitHub 帳號即可同步。",
|
||||
"connectedHint": "私人儲存庫透過你的 GitHub 連線({{account}})同步。",
|
||||
|
||||
@@ -1666,14 +1666,6 @@
|
||||
"link": "链接",
|
||||
"urlLink": "URL 链接",
|
||||
"repoUrl": "存储库 URL",
|
||||
"reddit": {
|
||||
"id": "客户端ID",
|
||||
"secret": "客户端密钥",
|
||||
"agent": "用户代理",
|
||||
"searchQueries": "搜索查询",
|
||||
"numberOfPosts": "帖子数量",
|
||||
"addQuery": "添加查询"
|
||||
},
|
||||
"drag": {
|
||||
"title": "将附件拖放到此处",
|
||||
"description": "释放以上传您的附件"
|
||||
@@ -1695,8 +1687,6 @@
|
||||
"clear": "清除",
|
||||
"ingestionFailed": "导入失败。"
|
||||
},
|
||||
"showAdvanced": "显示高级选项",
|
||||
"hideAdvanced": "隐藏高级选项",
|
||||
"ingestors": {
|
||||
"local_file": {
|
||||
"label": "上传文件",
|
||||
@@ -1714,26 +1704,6 @@
|
||||
"label": "GitHub",
|
||||
"heading": "从GitHub添加内容"
|
||||
},
|
||||
"reddit": {
|
||||
"label": "Reddit",
|
||||
"heading": "从Reddit添加内容"
|
||||
},
|
||||
"google_drive": {
|
||||
"label": "Google Drive",
|
||||
"heading": "从Google Drive上传"
|
||||
},
|
||||
"s3": {
|
||||
"label": "Amazon S3",
|
||||
"heading": "从Amazon S3添加内容"
|
||||
},
|
||||
"share_point": {
|
||||
"label": "SharePoint",
|
||||
"heading": "从SharePoint上传"
|
||||
},
|
||||
"confluence": {
|
||||
"label": "Confluence",
|
||||
"heading": "从Confluence上传"
|
||||
},
|
||||
"wiki": {
|
||||
"label": "新建 Wiki",
|
||||
"heading": "创建动态 Wiki"
|
||||
@@ -1787,15 +1757,8 @@
|
||||
},
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"awsAccessKeyId": "AWS 访问密钥 ID",
|
||||
"awsSecretAccessKey": "AWS 秘密访问密钥",
|
||||
"bucket": "存储桶名称",
|
||||
"prefix": "路径前缀(可选)",
|
||||
"region": "AWS 区域",
|
||||
"endpointUrl": "自定义端点 URL(可选)",
|
||||
"initialContent": "初始内容(可选)"
|
||||
},
|
||||
"newCredentials": "输入新的凭据",
|
||||
"github": {
|
||||
"privateHint": "私有仓库?连接你的 GitHub 账号即可同步。",
|
||||
"connectedHint": "私有仓库通过你的 GitHub 连接({{account}})同步。",
|
||||
|
||||
@@ -51,25 +51,6 @@ vi.mock('../connectors/useConnectorLauncher', () => ({
|
||||
default: () => ({ launch, modals: null }),
|
||||
}));
|
||||
|
||||
// The file picker reports its default account and a pick as it mounts.
|
||||
vi.mock('../components/FilePicker', async () => {
|
||||
const { useEffect } = await import('react');
|
||||
return {
|
||||
FilePicker: function Picker(props: {
|
||||
onConnectionChange: (id: string | null) => void;
|
||||
onSelectionChange: (files: string[], folders?: string[]) => void;
|
||||
onFirstPickName: (name: string) => void;
|
||||
}) {
|
||||
useEffect(() => {
|
||||
props.onConnectionChange('drive-1');
|
||||
props.onSelectionChange(['file-1'], []);
|
||||
props.onFirstPickName('Handbook');
|
||||
}, []);
|
||||
return null;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
import Upload from './Upload';
|
||||
|
||||
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });
|
||||
@@ -308,92 +289,57 @@ describe('Upload source-type tiles', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('picks the saved account once connections finish loading', async () => {
|
||||
connectorsState.catalog = [
|
||||
{
|
||||
key: 's3',
|
||||
icon: 's3',
|
||||
sync_ingestor: 's3',
|
||||
auth_kind: 'api_key',
|
||||
available: true,
|
||||
missing_settings: [],
|
||||
credential_fields: [
|
||||
{ key: 'aws_access_key_id', label: 'Access key ID', secret: false },
|
||||
],
|
||||
},
|
||||
];
|
||||
const props = {
|
||||
receivedFile: [],
|
||||
setModalState: vi.fn(),
|
||||
isOnboarding: false,
|
||||
renderTab: null,
|
||||
close: vi.fn(),
|
||||
initialIngestor: 's3' as const,
|
||||
};
|
||||
await act(async () => root.render(<Upload {...props} />));
|
||||
const triggers = () =>
|
||||
Array.from(
|
||||
document.body.querySelectorAll('[data-slot="select-trigger"]'),
|
||||
).map((el) => el.textContent);
|
||||
expect(triggers()).not.toContain('modals.uploadDoc.newCredentials');
|
||||
connectorsState.connections = [
|
||||
{
|
||||
id: 'k1',
|
||||
connector_key: 's3',
|
||||
status: 'connected',
|
||||
account_label: '…WXYZ',
|
||||
},
|
||||
];
|
||||
await act(async () => root.render(<Upload {...props} />));
|
||||
expect(triggers()).toContain('settings.connectors.detail.keyEnding');
|
||||
connectorsState.catalog = [];
|
||||
connectorsState.connections = [];
|
||||
});
|
||||
|
||||
it("sends the picker's account, not one cleared by the type change", async () => {
|
||||
connectorsState.catalog = [
|
||||
{
|
||||
key: 'google_drive',
|
||||
icon: 'drive',
|
||||
sync_ingestor: 'google_drive',
|
||||
auth_kind: 'oauth',
|
||||
available: true,
|
||||
missing_settings: [],
|
||||
},
|
||||
];
|
||||
const sent: FormData[] = [];
|
||||
it('sends a crawler source to the remote ingest with its URL', async () => {
|
||||
const sent: { url: string; body: FormData }[] = [];
|
||||
class FakeXhr {
|
||||
upload = { addEventListener() {} };
|
||||
url = '';
|
||||
addEventListener() {}
|
||||
open() {}
|
||||
open(_method: string, url: string) {
|
||||
this.url = url;
|
||||
}
|
||||
setRequestHeader() {}
|
||||
send(body: FormData) {
|
||||
sent.push(body);
|
||||
sent.push({ url: this.url, body });
|
||||
}
|
||||
}
|
||||
vi.stubGlobal('XMLHttpRequest', FakeXhr);
|
||||
await act(async () =>
|
||||
root.render(
|
||||
<Upload
|
||||
receivedFile={[]}
|
||||
setModalState={vi.fn()}
|
||||
isOnboarding={false}
|
||||
renderTab={null}
|
||||
close={vi.fn()}
|
||||
initialIngestor="google_drive"
|
||||
/>,
|
||||
),
|
||||
await render();
|
||||
const crawler = tiles().find((tile) =>
|
||||
tile.textContent?.includes('modals.uploadDoc.ingestors.crawler.label'),
|
||||
)!;
|
||||
await act(async () => crawler.click());
|
||||
const type = async (input: HTMLInputElement, value: string) => {
|
||||
const setter = Object.getOwnPropertyDescriptor(
|
||||
HTMLInputElement.prototype,
|
||||
'value',
|
||||
)!.set!;
|
||||
await act(async () => {
|
||||
setter.call(input, value);
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
});
|
||||
};
|
||||
const inputs = Array.from(
|
||||
document.body.querySelectorAll<HTMLInputElement>('input[type="text"]'),
|
||||
);
|
||||
// The source's name first, then the crawler's URL field.
|
||||
await type(inputs[0], 'Docs site');
|
||||
await type(
|
||||
document.body.querySelector<HTMLInputElement>('input[name="url"]')!,
|
||||
'https://docs.example',
|
||||
);
|
||||
const train = Array.from(document.body.querySelectorAll('button')).find(
|
||||
(b) => b.textContent === 'modals.uploadDoc.train',
|
||||
)!;
|
||||
expect(train.disabled).toBe(false);
|
||||
await act(async () => train.click());
|
||||
expect(sent).toHaveLength(1);
|
||||
expect(JSON.parse(String(sent[0].get('data'))).connection_id).toBe(
|
||||
'drive-1',
|
||||
);
|
||||
expect(sent[0].url).toContain('/api/remote');
|
||||
expect(sent[0].body.get('source')).toBe('crawler');
|
||||
expect(JSON.parse(String(sent[0].body.get('data')))).toEqual({
|
||||
url: 'https://docs.example',
|
||||
});
|
||||
vi.unstubAllGlobals();
|
||||
connectorsState.catalog = [];
|
||||
});
|
||||
|
||||
it('leaves the disabled Train button on the default variant', async () => {
|
||||
|
||||
+15
-446
@@ -1,7 +1,6 @@
|
||||
import { ChevronLeft, FileText, Lock, Plug } from 'lucide-react';
|
||||
import { envVar } from '@/env';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { nanoid } from '@reduxjs/toolkit';
|
||||
import type { FileRejection } from 'react-dropzone';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -14,20 +13,9 @@ import { Alert, AlertDescription } from '../components/ui/alert';
|
||||
import { Button } from '../components/ui/button';
|
||||
import { Input } from '../components/ui/input';
|
||||
import { FormField as UiFormField } from '../components/ui/form-field';
|
||||
import { Label } from '../components/ui/label';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '../components/ui/select';
|
||||
import { Switch } from '../components/ui/switch';
|
||||
import { Textarea } from '../components/ui/textarea';
|
||||
import { Modal } from '../components/ui/modal';
|
||||
import { Separator } from '../components/ui/separator';
|
||||
import { OptionCard } from '../components/ui/option-card';
|
||||
import ConnectorSetupNotice from '../connectors/ConnectorSetupNotice';
|
||||
import useConnectorLauncher from '../connectors/useConnectorLauncher';
|
||||
import { connectorName } from '../connectors/i18n';
|
||||
import { intlLocale } from '../utils/dateTimeUtils';
|
||||
@@ -53,7 +41,6 @@ import {
|
||||
setSourceDocs,
|
||||
} from '../preferences/preferenceSlice';
|
||||
import {
|
||||
CONNECTION_INGESTORS,
|
||||
IngestorDefaultConfigs,
|
||||
IngestorFormSchemas,
|
||||
getIngestorSchema,
|
||||
@@ -64,8 +51,6 @@ import { addUploadTask, updateUploadTask } from './uploadSlice';
|
||||
|
||||
import { FormField, IngestorConfig, IngestorType } from './types/ingestor';
|
||||
|
||||
import { FilePicker } from '../components/FilePicker';
|
||||
import GoogleDrivePicker from '../components/GoogleDrivePicker';
|
||||
import { FILE_UPLOAD_ACCEPT } from '../constants/fileUpload';
|
||||
import RetrievalOptions, {
|
||||
DEFAULT_RETRIEVAL_OPTIONS,
|
||||
@@ -86,7 +71,6 @@ function Upload({
|
||||
close,
|
||||
onSuccessfulUpload = () => undefined,
|
||||
selectUploadedDoc = true,
|
||||
initialIngestor,
|
||||
}: {
|
||||
receivedFile: File[];
|
||||
setModalState: (state: ActiveState) => void;
|
||||
@@ -101,8 +85,6 @@ function Upload({
|
||||
* uploading never repoints the conversation the user left open.
|
||||
*/
|
||||
selectUploadedDoc?: boolean;
|
||||
/** Open straight on this source type's form (Connect from a connector card). */
|
||||
initialIngestor?: IngestorType;
|
||||
}) {
|
||||
const token = useSelector(selectToken);
|
||||
const selectedDocs = useSelector(selectSelectedDocs);
|
||||
@@ -124,82 +106,18 @@ function Upload({
|
||||
// an unaccepted type), shown under the dropzone.
|
||||
const [rejectedFiles, setRejectedFiles] = useState<string[]>([]);
|
||||
const [activeTab, setActiveTab] = useState<boolean>(true);
|
||||
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
|
||||
const [retrievalOptions, setRetrievalOptions] =
|
||||
useState<RetrievalOptionsValue>(DEFAULT_RETRIEVAL_OPTIONS);
|
||||
const { graphRAGAvailable, hybridAvailable, availableModels } =
|
||||
useRetrievalAvailability(token);
|
||||
|
||||
// File picker state
|
||||
const [selectedFiles, setSelectedFiles] = useState<string[]>([]);
|
||||
const [selectedFolders, setSelectedFolders] = useState<string[]>([]);
|
||||
// The connection (account) the source syncs from. Pickers report it; S3
|
||||
// and Reddit pick it here ('' means "enter new credentials").
|
||||
const [connectionId, setConnectionId] = useState<string | null>(null);
|
||||
|
||||
const renderFormFields = () => {
|
||||
if (!ingestor.type) return null;
|
||||
const ingestorSchema = getIngestorSchema(ingestor.type as IngestorType);
|
||||
if (!ingestorSchema) return null;
|
||||
const schema: FormField[] = ingestorSchema.fields;
|
||||
|
||||
const generalFields = schema.filter(
|
||||
(field: FormField) =>
|
||||
!field.advanced && !(usingSavedKeys && credentialKeys.has(field.name)),
|
||||
);
|
||||
const advancedFields = schema.filter((field: FormField) => field.advanced);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
{keyAccounts.length > 0 && (
|
||||
<UiFormField label={t('filePicker.account')}>
|
||||
<Select
|
||||
value={connectionId ?? 'new'}
|
||||
onValueChange={(value) => {
|
||||
accountPicked.current = true;
|
||||
setConnectionId(value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full" size="field" shape="pill">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{keyAccounts.map((account) => (
|
||||
<SelectItem key={account.id} value={account.id}>
|
||||
{t('settings.connectors.detail.keyEnding', {
|
||||
hint: account.account_label,
|
||||
interpolation: { escapeValue: false },
|
||||
})}
|
||||
</SelectItem>
|
||||
))}
|
||||
<SelectItem value="new">
|
||||
{t('modals.uploadDoc.newCredentials')}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</UiFormField>
|
||||
)}
|
||||
<div className="flex flex-col gap-5">
|
||||
{generalFields.map((field: FormField) => renderField(field))}
|
||||
</div>
|
||||
|
||||
{advancedFields.length > 0 && (
|
||||
<div
|
||||
className={cn(
|
||||
'grid transition-[grid-template-rows,opacity] duration-300 ease-out',
|
||||
showAdvancedOptions
|
||||
? 'grid-rows-[1fr] opacity-100'
|
||||
: 'grid-rows-[0fr] opacity-0',
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col gap-4 overflow-hidden">
|
||||
<Separator className="my-4" />
|
||||
<div className="flex flex-col gap-5">
|
||||
{advancedFields.map((field: FormField) => renderField(field))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{ingestorSchema.fields.map((field: FormField) => renderField(field))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -227,81 +145,6 @@ function Upload({
|
||||
required={isRequired}
|
||||
/>
|
||||
);
|
||||
case 'number':
|
||||
return (
|
||||
<Input
|
||||
key={field.name}
|
||||
label={fieldLabel}
|
||||
type="number"
|
||||
name={field.name}
|
||||
value={String(
|
||||
ingestor.config[field.name as keyof typeof ingestor.config],
|
||||
)}
|
||||
onChange={(e) =>
|
||||
handleIngestorChange(
|
||||
field.name as keyof IngestorConfig['config'],
|
||||
Number(e.target.value),
|
||||
)
|
||||
}
|
||||
required={isRequired}
|
||||
/>
|
||||
);
|
||||
case 'enum': {
|
||||
const currentValue = String(
|
||||
ingestor.config[field.name as keyof typeof ingestor.config] ?? '',
|
||||
);
|
||||
return (
|
||||
<UiFormField
|
||||
key={field.name}
|
||||
label={fieldLabel}
|
||||
required={isRequired}
|
||||
>
|
||||
<Select
|
||||
value={currentValue || undefined}
|
||||
onValueChange={(value) => {
|
||||
handleIngestorChange(
|
||||
field.name as keyof IngestorConfig['config'],
|
||||
value,
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full" size="field" shape="pill">
|
||||
<SelectValue placeholder={fieldLabel} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(field.options || []).map((opt) => (
|
||||
<SelectItem key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</UiFormField>
|
||||
);
|
||||
}
|
||||
case 'boolean':
|
||||
return (
|
||||
<div
|
||||
key={field.name}
|
||||
className="mt-2 flex flex-row items-center gap-3 text-base"
|
||||
>
|
||||
<Label htmlFor={`field-${field.name}`} className="text-foreground">
|
||||
{fieldLabel}
|
||||
</Label>
|
||||
<Switch
|
||||
id={`field-${field.name}`}
|
||||
checked={Boolean(
|
||||
ingestor.config[field.name as keyof typeof ingestor.config],
|
||||
)}
|
||||
onCheckedChange={(checked: boolean) => {
|
||||
handleIngestorChange(
|
||||
field.name as keyof IngestorConfig['config'],
|
||||
checked,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
case 'textarea':
|
||||
return (
|
||||
<UiFormField
|
||||
@@ -371,98 +214,6 @@ function Upload({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
case 'remote_file_picker':
|
||||
return (
|
||||
<FilePicker
|
||||
key={field.name}
|
||||
onSelectionChange={(
|
||||
selectedFileIds: string[],
|
||||
selectedFolderIds: string[] = [],
|
||||
) => {
|
||||
setSelectedFiles(selectedFileIds);
|
||||
setSelectedFolders(selectedFolderIds);
|
||||
}}
|
||||
onFirstPickName={prefillName}
|
||||
onConnectionChange={setConnectionId}
|
||||
provider={ingestor.type as unknown as string}
|
||||
token={token}
|
||||
initialSelectedFiles={selectedFiles}
|
||||
initialSelectedFolders={selectedFolders}
|
||||
/>
|
||||
);
|
||||
case 'google_drive_picker':
|
||||
// Google's own picker needs the client id in the browser; without it
|
||||
// the server-side file browser lists the same Drive.
|
||||
return envVar('VITE_GOOGLE_CLIENT_ID') ? (
|
||||
<GoogleDrivePicker
|
||||
key={field.name}
|
||||
onSelectionChange={(
|
||||
selectedFileIds: string[],
|
||||
selectedFolderIds: string[] = [],
|
||||
) => {
|
||||
setSelectedFiles(selectedFileIds);
|
||||
setSelectedFolders(selectedFolderIds);
|
||||
}}
|
||||
onFirstPickName={prefillName}
|
||||
onConnectionChange={setConnectionId}
|
||||
token={token}
|
||||
/>
|
||||
) : (
|
||||
<FilePicker
|
||||
key={field.name}
|
||||
onSelectionChange={(
|
||||
selectedFileIds: string[],
|
||||
selectedFolderIds: string[] = [],
|
||||
) => {
|
||||
setSelectedFiles(selectedFileIds);
|
||||
setSelectedFolders(selectedFolderIds);
|
||||
}}
|
||||
onFirstPickName={prefillName}
|
||||
onConnectionChange={setConnectionId}
|
||||
provider="google_drive"
|
||||
token={token}
|
||||
initialSelectedFiles={selectedFiles}
|
||||
initialSelectedFolders={selectedFolders}
|
||||
/>
|
||||
);
|
||||
case 'share_point_picker':
|
||||
return (
|
||||
<FilePicker
|
||||
key={field.name}
|
||||
onSelectionChange={(
|
||||
selectedFileIds: string[],
|
||||
selectedFolderIds: string[] = [],
|
||||
) => {
|
||||
setSelectedFiles(selectedFileIds);
|
||||
setSelectedFolders(selectedFolderIds);
|
||||
}}
|
||||
onFirstPickName={prefillName}
|
||||
onConnectionChange={setConnectionId}
|
||||
provider="share_point"
|
||||
token={token}
|
||||
initialSelectedFiles={selectedFiles}
|
||||
initialSelectedFolders={selectedFolders}
|
||||
/>
|
||||
);
|
||||
case 'confluence_picker':
|
||||
return (
|
||||
<FilePicker
|
||||
key={field.name}
|
||||
onSelectionChange={(
|
||||
selectedFileIds: string[],
|
||||
selectedFolderIds: string[] = [],
|
||||
) => {
|
||||
setSelectedFiles(selectedFileIds);
|
||||
setSelectedFolders(selectedFolderIds);
|
||||
}}
|
||||
onFirstPickName={prefillName}
|
||||
onConnectionChange={setConnectionId}
|
||||
provider="confluence"
|
||||
token={token}
|
||||
initialSelectedFiles={selectedFiles}
|
||||
initialSelectedFolders={selectedFolders}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -484,50 +235,6 @@ function Upload({
|
||||
if (!connectorsLoaded) dispatch(loadConnectors({ token }));
|
||||
}, [connectorsLoaded, dispatch, token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialIngestor) handleIngestorTypeChange(initialIngestor);
|
||||
// Only the type the modal opened with; later picks are the user's.
|
||||
}, []);
|
||||
|
||||
/** The name field follows the first picked item until the user edits it. */
|
||||
const prefillName = (name: string) => {
|
||||
if (nameTouched || !name) return;
|
||||
setIngestor((prev) => (prev.name ? prev : { ...prev, name }));
|
||||
};
|
||||
|
||||
const connectorFor = (type: IngestorType | null) =>
|
||||
type && CONNECTION_INGESTORS.includes(type)
|
||||
? connectorCatalog.find((c) => c.sync_ingestor === type)
|
||||
: undefined;
|
||||
const selectedConnector = connectorFor(ingestor.type);
|
||||
const needsSetup = !!selectedConnector && !selectedConnector.available;
|
||||
// S3 and Reddit keep their keys on a connection: once an account is
|
||||
// chosen the key fields go away ("enter secrets once").
|
||||
const keyAccounts =
|
||||
selectedConnector?.auth_kind === 'api_key'
|
||||
? connections.filter(
|
||||
(c) =>
|
||||
c.connector_key === selectedConnector.key &&
|
||||
c.status === 'connected',
|
||||
)
|
||||
: [];
|
||||
const credentialKeys = new Set(
|
||||
(selectedConnector?.credential_fields ?? []).map((f) => f.key),
|
||||
);
|
||||
const usingSavedKeys =
|
||||
keyAccounts.length > 0 && !!connectionId && connectionId !== 'new';
|
||||
|
||||
// Default to the first saved account, also when the connections arrive
|
||||
// after the modal opened on S3 or Reddit, but never over a choice the
|
||||
// user made in the account picker.
|
||||
const accountPicked = useRef(false);
|
||||
const firstKeyAccount = keyAccounts[0]?.id;
|
||||
useEffect(() => {
|
||||
if (selectedConnector?.auth_kind !== 'api_key' || accountPicked.current)
|
||||
return;
|
||||
setConnectionId(firstKeyAccount ?? 'new');
|
||||
}, [ingestor.type, selectedConnector?.auth_kind, firstKeyAccount]);
|
||||
|
||||
const ingestorOptions: IngestorOption[] = IngestorFormSchemas.map(
|
||||
(schema) => ({
|
||||
label: schema.label,
|
||||
@@ -541,9 +248,6 @@ function Upload({
|
||||
setIngestor({ type: null, name: '', config: {} });
|
||||
setfiles([]);
|
||||
setRejectedFiles([]);
|
||||
setSelectedFiles([]);
|
||||
setSelectedFolders([]);
|
||||
setShowAdvancedOptions(false);
|
||||
setRetrievalOptions(DEFAULT_RETRIEVAL_OPTIONS);
|
||||
setNameTouched(false);
|
||||
}, []);
|
||||
@@ -824,62 +528,11 @@ function Upload({
|
||||
JSON.stringify(optionsToConfig(retrievalOptions)),
|
||||
);
|
||||
|
||||
const ingestorSchema = getIngestorSchema(ingestor.type as IngestorType);
|
||||
if (!ingestorSchema) {
|
||||
handleTaskFailure(clientTaskId);
|
||||
return;
|
||||
}
|
||||
|
||||
const schema: FormField[] = ingestorSchema.fields;
|
||||
const hasLocalFilePicker = schema.some(
|
||||
(field: FormField) => field.type === 'local_file_picker',
|
||||
);
|
||||
const hasRemoteFilePicker = schema.some(
|
||||
(field: FormField) => field.type === 'remote_file_picker',
|
||||
);
|
||||
const hasGoogleDrivePicker = schema.some(
|
||||
(field: FormField) => field.type === 'google_drive_picker',
|
||||
);
|
||||
const hasSharePointPicker = schema.some(
|
||||
(field: FormField) => field.type === 'share_point_picker',
|
||||
);
|
||||
const hasConfluencePicker = schema.some(
|
||||
(field: FormField) => field.type === 'confluence_picker',
|
||||
);
|
||||
|
||||
let configData: Record<string, unknown> = { ...ingestor.config };
|
||||
|
||||
if (hasLocalFilePicker) {
|
||||
files.forEach((file) => {
|
||||
formData.append('file', file);
|
||||
});
|
||||
} else if (
|
||||
hasRemoteFilePicker ||
|
||||
hasGoogleDrivePicker ||
|
||||
hasSharePointPicker ||
|
||||
hasConfluencePicker
|
||||
) {
|
||||
configData = {
|
||||
provider: ingestor.type as string,
|
||||
connection_id: connectionId,
|
||||
file_ids: selectedFiles,
|
||||
folder_ids: selectedFolders,
|
||||
};
|
||||
}
|
||||
|
||||
if (usingSavedKeys) {
|
||||
configData = Object.fromEntries(
|
||||
Object.entries(configData).filter(([key]) => !credentialKeys.has(key)),
|
||||
);
|
||||
configData.connection_id = connectionId;
|
||||
}
|
||||
formData.append('data', JSON.stringify(configData));
|
||||
formData.append('data', JSON.stringify(ingestor.config));
|
||||
|
||||
const apiHost: string = envVar('VITE_API_HOST');
|
||||
const endpoint =
|
||||
ingestor.type === 'local_file'
|
||||
? `${apiHost}/api/upload`
|
||||
: `${apiHost}/api/remote`;
|
||||
// Local files go through uploadFile; everything else is fetched remotely.
|
||||
const endpoint = `${apiHost}/api/remote`;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
@@ -1041,72 +694,14 @@ function Upload({
|
||||
if (!isPrescreenConfigValid(retrievalOptions)) return true;
|
||||
|
||||
if (!ingestor.type) return true;
|
||||
if (needsSetup) return true;
|
||||
const ingestorSchemaForValidation = getIngestorSchema(
|
||||
ingestor.type as IngestorType,
|
||||
);
|
||||
if (!ingestorSchemaForValidation) return true;
|
||||
const schema: FormField[] = ingestorSchemaForValidation.fields;
|
||||
const hasLocalFilePicker = schema.some(
|
||||
(field: FormField) => field.type === 'local_file_picker',
|
||||
);
|
||||
const hasRemoteFilePicker = schema.some(
|
||||
(field: FormField) => field.type === 'remote_file_picker',
|
||||
);
|
||||
const hasGoogleDrivePicker = schema.some(
|
||||
(field: FormField) => field.type === 'google_drive_picker',
|
||||
);
|
||||
const hasSharePointPicker = schema.some(
|
||||
(field: FormField) => field.type === 'share_point_picker',
|
||||
);
|
||||
const hasConfluencePicker = schema.some(
|
||||
(field: FormField) => field.type === 'confluence_picker',
|
||||
);
|
||||
|
||||
if (hasLocalFilePicker) {
|
||||
if (files.length === 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (
|
||||
hasRemoteFilePicker ||
|
||||
hasGoogleDrivePicker ||
|
||||
hasSharePointPicker ||
|
||||
hasConfluencePicker
|
||||
) {
|
||||
if (selectedFiles.length === 0 && selectedFolders.length === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const ingestorSchemaForFields = getIngestorSchema(
|
||||
ingestor.type as IngestorType,
|
||||
);
|
||||
if (!ingestorSchemaForFields) return false;
|
||||
const formFields: FormField[] = ingestorSchemaForFields.fields;
|
||||
for (const field of formFields) {
|
||||
if (usingSavedKeys && credentialKeys.has(field.name)) continue;
|
||||
if (field.required) {
|
||||
// Validate only required fields
|
||||
const value =
|
||||
ingestor.config[field.name as keyof typeof ingestor.config];
|
||||
|
||||
if (typeof value === 'string' && !value.trim()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof value === 'number' &&
|
||||
(value === null || value === undefined || value <= 0)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean' && value === undefined) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
const schema = getIngestorSchema(ingestor.type);
|
||||
if (!schema) return true;
|
||||
return schema.fields.some((field: FormField) => {
|
||||
if (field.type === 'local_file_picker') return files.length === 0;
|
||||
if (!field.required) return false;
|
||||
const value = ingestor.config[field.name];
|
||||
return typeof value === 'string' && !value.trim();
|
||||
});
|
||||
};
|
||||
const handleIngestorChange = (
|
||||
key: keyof IngestorConfig['config'],
|
||||
@@ -1121,11 +716,6 @@ function Upload({
|
||||
}));
|
||||
};
|
||||
const handleIngestorTypeChange = (type: IngestorType | null) => {
|
||||
// The account resets with the type, here rather than in an effect: the
|
||||
// new type's picker reports its default account as it mounts, and an
|
||||
// effect would run after that and clear it.
|
||||
accountPicked.current = false;
|
||||
setConnectionId(null);
|
||||
if (type === null) {
|
||||
setIngestor({
|
||||
type: null,
|
||||
@@ -1259,10 +849,6 @@ function Upload({
|
||||
</Alert>
|
||||
) : null;
|
||||
|
||||
const renderSetupNotice = () =>
|
||||
selectedConnector && needsSetup ? (
|
||||
<ConnectorSetupNotice connector={selectedConnector} />
|
||||
) : null;
|
||||
if (handedOver) return <>{connectModals}</>;
|
||||
|
||||
return (
|
||||
@@ -1331,9 +917,9 @@ function Upload({
|
||||
required={true}
|
||||
className="w-full"
|
||||
/>
|
||||
{needsSetup ? renderSetupNotice() : renderFormFields()}
|
||||
{renderFormFields()}
|
||||
{ingestor.type === 'github' && renderGitHubHandOver()}
|
||||
{ingestor.type !== 'wiki' && !needsSetup && (
|
||||
{ingestor.type !== 'wiki' && (
|
||||
<RetrievalOptions
|
||||
value={retrievalOptions}
|
||||
onChange={setRetrievalOptions}
|
||||
@@ -1344,23 +930,6 @@ function Upload({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{ingestor.type &&
|
||||
getIngestorSchema(ingestor.type as IngestorType)?.fields.some(
|
||||
(field: FormField) => field.advanced,
|
||||
) && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="link"
|
||||
size="sm"
|
||||
onClick={() => setShowAdvancedOptions(!showAdvancedOptions)}
|
||||
className="-ml-3 w-fit justify-start"
|
||||
>
|
||||
{showAdvancedOptions
|
||||
? t('modals.uploadDoc.hideAdvanced')
|
||||
: t('modals.uploadDoc.showAdvanced')}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -2,24 +2,9 @@ import CrawlerIcon from '../../assets/crawler.svg';
|
||||
import FileUploadIcon from '../../assets/file_upload.svg';
|
||||
import UrlIcon from '../../assets/url.svg';
|
||||
import GithubIcon from '../../assets/github.svg';
|
||||
import RedditIcon from '../../assets/reddit.svg';
|
||||
import DriveIcon from '../../assets/drive.svg';
|
||||
import S3Icon from '../../assets/s3.svg';
|
||||
import SharePoint from '../../assets/sharepoint.svg';
|
||||
import ConfluenceIcon from '../../assets/confluence.svg';
|
||||
import BookIcon from '../../assets/book-mono.svg';
|
||||
|
||||
export type IngestorType =
|
||||
| 'confluence'
|
||||
| 'crawler'
|
||||
| 'github'
|
||||
| 'reddit'
|
||||
| 'url'
|
||||
| 'google_drive'
|
||||
| 'local_file'
|
||||
| 's3'
|
||||
| 'share_point'
|
||||
| 'wiki';
|
||||
export type IngestorType = 'crawler' | 'github' | 'url' | 'local_file' | 'wiki';
|
||||
|
||||
export interface IngestorConfig {
|
||||
type: IngestorType | null;
|
||||
@@ -34,17 +19,7 @@ export type IngestorFormData = {
|
||||
data: string;
|
||||
};
|
||||
|
||||
export type FieldType =
|
||||
| 'string'
|
||||
| 'number'
|
||||
| 'enum'
|
||||
| 'boolean'
|
||||
| 'textarea'
|
||||
| 'local_file_picker'
|
||||
| 'remote_file_picker'
|
||||
| 'google_drive_picker'
|
||||
| 'share_point_picker'
|
||||
| 'confluence_picker';
|
||||
export type FieldType = 'string' | 'textarea' | 'local_file_picker';
|
||||
|
||||
export interface FormField {
|
||||
name: string;
|
||||
@@ -53,8 +28,6 @@ export interface FormField {
|
||||
labelKey?: string;
|
||||
type: FieldType;
|
||||
required?: boolean;
|
||||
advanced?: boolean;
|
||||
options?: { label: string; value: string }[];
|
||||
}
|
||||
|
||||
export interface IngestorSchema {
|
||||
@@ -66,9 +39,8 @@ export interface IngestorSchema {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Source tiles: what needs no account. The connection types sync from
|
||||
* the Connectors page; their forms open only when a connector card hands
|
||||
* one over (`initialIngestor`).
|
||||
* Add knowledge tiles: the source types that need no account. Services
|
||||
* that sync into Knowledge are connected through the connect wizard.
|
||||
*/
|
||||
export const UPLOAD_AND_WEB_INGESTORS: IngestorType[] = [
|
||||
'local_file',
|
||||
@@ -77,13 +49,6 @@ export const UPLOAD_AND_WEB_INGESTORS: IngestorType[] = [
|
||||
'github',
|
||||
'wiki',
|
||||
];
|
||||
export const CONNECTION_INGESTORS: IngestorType[] = [
|
||||
'google_drive',
|
||||
'share_point',
|
||||
'confluence',
|
||||
's3',
|
||||
'reddit',
|
||||
];
|
||||
|
||||
export const IngestorFormSchemas: IngestorSchema[] = [
|
||||
{
|
||||
@@ -145,141 +110,6 @@ export const IngestorFormSchemas: IngestorSchema[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'reddit',
|
||||
label: 'Reddit',
|
||||
icon: RedditIcon,
|
||||
heading: 'Add content from Reddit',
|
||||
fields: [
|
||||
{
|
||||
name: 'client_id',
|
||||
label: 'Client ID',
|
||||
labelKey: 'modals.uploadDoc.reddit.id',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'client_secret',
|
||||
label: 'Client Secret',
|
||||
labelKey: 'modals.uploadDoc.reddit.secret',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'user_agent',
|
||||
label: 'User Agent',
|
||||
labelKey: 'modals.uploadDoc.reddit.agent',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'search_queries',
|
||||
label: 'Search Queries',
|
||||
labelKey: 'modals.uploadDoc.reddit.searchQueries',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'number_posts',
|
||||
label: 'Number of Posts',
|
||||
labelKey: 'modals.uploadDoc.reddit.numberOfPosts',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'google_drive',
|
||||
label: 'Google Drive',
|
||||
icon: DriveIcon,
|
||||
heading: 'Upload from Google Drive',
|
||||
fields: [
|
||||
{
|
||||
name: 'files',
|
||||
label: 'Select Files from Google Drive',
|
||||
type: 'google_drive_picker',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 's3',
|
||||
label: 'Amazon S3',
|
||||
icon: S3Icon,
|
||||
heading: 'Add content from Amazon S3',
|
||||
fields: [
|
||||
{
|
||||
name: 'aws_access_key_id',
|
||||
label: 'AWS Access Key ID',
|
||||
labelKey: 'modals.uploadDoc.fields.awsAccessKeyId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'aws_secret_access_key',
|
||||
label: 'AWS Secret Access Key',
|
||||
labelKey: 'modals.uploadDoc.fields.awsSecretAccessKey',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'bucket',
|
||||
label: 'Bucket Name',
|
||||
labelKey: 'modals.uploadDoc.fields.bucket',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'prefix',
|
||||
label: 'Path Prefix (optional)',
|
||||
labelKey: 'modals.uploadDoc.fields.prefix',
|
||||
type: 'string',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'region',
|
||||
label: 'AWS Region',
|
||||
labelKey: 'modals.uploadDoc.fields.region',
|
||||
type: 'string',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'endpoint_url',
|
||||
label: 'Custom Endpoint URL (optional)',
|
||||
labelKey: 'modals.uploadDoc.fields.endpointUrl',
|
||||
type: 'string',
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'share_point',
|
||||
label: 'Share Point',
|
||||
icon: SharePoint,
|
||||
heading: 'Upload from Share Point',
|
||||
fields: [
|
||||
{
|
||||
name: 'files',
|
||||
label: 'Select Files from Share Point',
|
||||
type: 'share_point_picker',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'confluence',
|
||||
label: 'Confluence',
|
||||
icon: ConfluenceIcon,
|
||||
heading: 'Upload from Confluence',
|
||||
fields: [
|
||||
{
|
||||
name: 'files',
|
||||
label: 'Select Pages from Confluence',
|
||||
type: 'confluence_picker',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'wiki',
|
||||
label: 'New wiki',
|
||||
@@ -303,52 +133,8 @@ export const IngestorDefaultConfigs: Record<
|
||||
> = {
|
||||
crawler: { name: '', config: { url: '' } },
|
||||
url: { name: '', config: { url: '' } },
|
||||
reddit: {
|
||||
name: '',
|
||||
config: {
|
||||
client_id: '',
|
||||
client_secret: '',
|
||||
user_agent: '',
|
||||
search_queries: '',
|
||||
number_posts: 10,
|
||||
},
|
||||
},
|
||||
github: { name: '', config: { repo_url: '' } },
|
||||
google_drive: {
|
||||
name: '',
|
||||
config: {
|
||||
file_ids: '',
|
||||
folder_ids: '',
|
||||
recursive: true,
|
||||
},
|
||||
},
|
||||
local_file: { name: '', config: { files: [] } },
|
||||
s3: {
|
||||
name: '',
|
||||
config: {
|
||||
aws_access_key_id: '',
|
||||
aws_secret_access_key: '',
|
||||
bucket: '',
|
||||
prefix: '',
|
||||
region: 'us-east-1',
|
||||
endpoint_url: '',
|
||||
},
|
||||
},
|
||||
share_point: {
|
||||
name: '',
|
||||
config: {
|
||||
file_ids: '',
|
||||
folder_ids: '',
|
||||
recursive: true,
|
||||
},
|
||||
},
|
||||
confluence: {
|
||||
name: '',
|
||||
config: {
|
||||
file_ids: '',
|
||||
folder_ids: '',
|
||||
},
|
||||
},
|
||||
wiki: {
|
||||
name: '',
|
||||
config: {
|
||||
|
||||
Reference in new issue
Block a user