{
diff --git a/web/src/pages/user-setting/data-source/constant/index.tsx b/web/src/pages/user-setting/data-source/constant/index.tsx
index 12d93500b3..c542ded061 100644
--- a/web/src/pages/user-setting/data-source/constant/index.tsx
+++ b/web/src/pages/user-setting/data-source/constant/index.tsx
@@ -41,6 +41,7 @@ export enum DataSourceKey {
SEAFILE = 'seafile',
MYSQL = 'mysql',
POSTGRESQL = 'postgresql',
+ BIGQUERY = 'bigquery',
REST_API = 'rest_api',
RSS = 'rss',
ONEDRIVE = 'onedrive',
@@ -160,6 +161,9 @@ export const DataSourceFeatureVisibilityMap: Partial<
[DataSourceKey.POSTGRESQL]: {
syncDeletedFiles: true,
},
+ [DataSourceKey.BIGQUERY]: {
+ syncDeletedFiles: true,
+ },
};
const isDataSourceFeatureVisible = (
@@ -333,6 +337,11 @@ export const generateDataSourceInfo = (t: TFunction) => {
description: t(`setting.${DataSourceKey.POSTGRESQL}Description`),
icon: ,
},
+ [DataSourceKey.BIGQUERY]: {
+ name: 'BigQuery',
+ description: t(`setting.${DataSourceKey.BIGQUERY}Description`),
+ icon: ,
+ },
[DataSourceKey.ONEDRIVE]: {
name: 'OneDrive',
description: t(`setting.${DataSourceKey.ONEDRIVE}Description`),
@@ -1483,6 +1492,166 @@ export const DataSourceFormFields = {
tooltip: t('setting.postgresqlTimestampColumnTip'),
},
],
+ [DataSourceKey.BIGQUERY]: [
+ {
+ label: 'Project ID',
+ name: 'config.project_id',
+ type: FormFieldType.Text,
+ required: true,
+ placeholder: 'my-gcp-project',
+ tooltip: t('setting.bigqueryProjectIdTip'),
+ },
+ {
+ label: 'Location',
+ name: 'config.location',
+ type: FormFieldType.Text,
+ required: false,
+ placeholder: 'US',
+ tooltip: t('setting.bigqueryLocationTip'),
+ },
+ {
+ label: 'Service Account JSON',
+ name: 'config.credentials.service_account_json',
+ type: FormFieldType.Password,
+ required: true,
+ placeholder: '{ "type": "service_account", "project_id": "...", ... }',
+ tooltip: t('setting.bigqueryServiceAccountJsonTip'),
+ },
+ {
+ label: 'Dataset ID',
+ name: 'config.dataset_id',
+ type: FormFieldType.Text,
+ required: false,
+ placeholder: 'analytics',
+ tooltip: t('setting.bigqueryDatasetIdTip'),
+ customValidate: (val: string, values: any) => {
+ const hasQuery = !!(values?.config?.query ?? '').trim();
+ const hasTable = !!(values?.config?.table_id ?? '').trim();
+ if (!hasQuery && !((val ?? '').trim() && hasTable)) {
+ return 'Dataset ID is required when not using a custom SQL Query';
+ }
+ return true;
+ },
+ },
+ {
+ label: 'Table ID',
+ name: 'config.table_id',
+ type: FormFieldType.Text,
+ required: false,
+ placeholder: 'customers',
+ tooltip: t('setting.bigqueryTableIdTip'),
+ customValidate: (val: string, values: any) => {
+ const hasQuery = !!(values?.config?.query ?? '').trim();
+ const hasDataset = !!(values?.config?.dataset_id ?? '').trim();
+ if (!hasQuery && !(hasDataset && (val ?? '').trim())) {
+ return 'Table ID is required when not using a custom SQL Query';
+ }
+ return true;
+ },
+ },
+ {
+ label: 'SQL Query',
+ name: 'config.query',
+ type: FormFieldType.Textarea,
+ required: false,
+ placeholder: 'Leave empty to use Dataset ID + Table ID',
+ tooltip: t('setting.bigqueryQueryTip'),
+ customValidate: (val: string, values: any) => {
+ const hasQuery = !!(val ?? '').trim();
+ const hasDataset = !!(values?.config?.dataset_id ?? '').trim();
+ const hasTable = !!(values?.config?.table_id ?? '').trim();
+ if (!hasQuery && !(hasDataset && hasTable)) {
+ return 'Provide a SQL Query, or both Dataset ID and Table ID';
+ }
+ return true;
+ },
+ },
+ {
+ label: 'Content Columns',
+ name: 'config.content_columns',
+ type: FormFieldType.Text,
+ required: true,
+ placeholder: 'name,description,notes',
+ tooltip: t('setting.bigqueryContentColumnsTip'),
+ },
+ {
+ label: 'Metadata Columns',
+ name: 'config.metadata_columns',
+ type: FormFieldType.Text,
+ required: false,
+ placeholder: 'customer_id,status,region',
+ tooltip: t('setting.bigqueryMetadataColumnsTip'),
+ },
+ {
+ label: 'ID Column',
+ name: 'config.id_column',
+ type: FormFieldType.Text,
+ required: false,
+ placeholder: 'customer_id',
+ tooltip: t('setting.bigqueryIdColumnTip'),
+ },
+ {
+ label: 'Timestamp Column',
+ name: 'config.timestamp_column',
+ type: FormFieldType.Text,
+ required: false,
+ placeholder: 'updated_at',
+ tooltip: t('setting.bigqueryTimestampColumnTip'),
+ },
+ {
+ label: 'Max Bytes Billed',
+ name: 'config.maximum_bytes_billed',
+ type: FormFieldType.Number,
+ required: false,
+ placeholder: '1073741824',
+ tooltip: t('setting.bigqueryMaximumBytesBilledTip'),
+ validation: {
+ min: 1,
+ message: 'Max Bytes Billed must be at least 1',
+ },
+ },
+ {
+ label: 'Job Timeout (ms)',
+ name: 'config.job_timeout_ms',
+ type: FormFieldType.Number,
+ required: false,
+ placeholder: '300000',
+ tooltip: t('setting.bigqueryJobTimeoutMsTip'),
+ validation: {
+ min: 1,
+ message: 'Job Timeout must be at least 1',
+ },
+ },
+ {
+ label: 'Page Size',
+ name: 'config.page_size',
+ type: FormFieldType.Number,
+ required: false,
+ placeholder: '1000',
+ validation: {
+ min: 1,
+ message: 'Page Size must be at least 1',
+ },
+ },
+ {
+ label: 'Batch Size',
+ name: 'config.batch_size',
+ type: FormFieldType.Number,
+ required: false,
+ placeholder: '100',
+ validation: {
+ min: 1,
+ message: 'Batch Size must be at least 1',
+ },
+ },
+ {
+ label: 'Use Query Cache',
+ name: 'config.use_query_cache',
+ type: FormFieldType.Checkbox,
+ required: false,
+ defaultValue: true,
+ },
+ ],
[DataSourceKey.REST_API]: [
// ── Essential fields ──────────────────────────────────────────────
{
@@ -2150,6 +2319,29 @@ export const DataSourceFormDefaultValues = {
},
},
},
+ [DataSourceKey.BIGQUERY]: {
+ name: '',
+ source: DataSourceKey.BIGQUERY,
+ config: {
+ project_id: '',
+ dataset_id: '',
+ table_id: '',
+ location: '',
+ query: '',
+ content_columns: '',
+ metadata_columns: '',
+ id_column: '',
+ timestamp_column: '',
+ batch_size: 100,
+ page_size: 1000,
+ maximum_bytes_billed: 1073741824,
+ job_timeout_ms: 300000,
+ use_query_cache: true,
+ credentials: {
+ service_account_json: '',
+ },
+ },
+ },
[DataSourceKey.ONEDRIVE]: {
name: '',
source: DataSourceKey.ONEDRIVE,
diff --git a/web/src/pages/user-setting/data-source/data-source-detail-page/index.tsx b/web/src/pages/user-setting/data-source/data-source-detail-page/index.tsx
index c3c1b80814..ae1f05c873 100644
--- a/web/src/pages/user-setting/data-source/data-source-detail-page/index.tsx
+++ b/web/src/pages/user-setting/data-source/data-source-detail-page/index.tsx
@@ -244,7 +244,8 @@ const SourceDetailPage = () => {
/>
- {detail?.source === DataSourceKey.REST_API && (
+ {(detail?.source === DataSourceKey.REST_API ||
+ detail?.source === DataSourceKey.BIGQUERY) && (