diff --git a/CHANGELOG.md b/CHANGELOG.md index 83824d38407..2a64ff914a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Next release (Add entries here in the order of: server, console, cli, docs, others) +- console: add bigquery support (#1000) ## v2.0.0-alpha.8 diff --git a/console/package-lock.json b/console/package-lock.json index 7a6239d3769..5a31127700a 100644 --- a/console/package-lock.json +++ b/console/package-lock.json @@ -6183,16 +6183,6 @@ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", - "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -7796,6 +7786,11 @@ "rsvp": "^4.8.4" } }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", + "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -13133,12 +13128,11 @@ }, "dependencies": { "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, @@ -13152,12 +13146,6 @@ "supports-color": "^7.1.0" } }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -13223,9 +13211,9 @@ } }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -19221,14 +19209,14 @@ }, "onetime": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", "dev": true }, "opencollective-postinstall": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", - "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", "dev": true }, "optimize-css-assets-webpack-plugin": { diff --git a/console/package.json b/console/package.json index 88a6f32f410..cf649f31f26 100644 --- a/console/package.json +++ b/console/package.json @@ -198,7 +198,7 @@ "font-awesome": "4.7.0", "font-awesome-webpack": "0.0.4", "fork-ts-checker-webpack-plugin": "4.1.3", - "husky": "4.2.3", + "husky": "^4.2.3", "identity-obj-proxy": "^3.0.0", "ignore-loader": "0.1.2", "jest": "26.6.3", diff --git a/console/src/components/Common/NotSupportedNote/index.tsx b/console/src/components/Common/NotSupportedNote/index.tsx index e023d02ad24..d6d54282591 100644 --- a/console/src/components/Common/NotSupportedNote/index.tsx +++ b/console/src/components/Common/NotSupportedNote/index.tsx @@ -5,6 +5,7 @@ const driverToLabel: Record = { mysql: 'MySQL', postgres: 'PostgreSQL', mssql: 'MS Server', + bigquery: 'Big Query', }; type NotSupportedNoteProps = { diff --git a/console/src/components/Common/utils/v1QueryUtils.ts b/console/src/components/Common/utils/v1QueryUtils.ts index e247eedb4c3..94a7e866595 100644 --- a/console/src/components/Common/utils/v1QueryUtils.ts +++ b/console/src/components/Common/utils/v1QueryUtils.ts @@ -16,8 +16,8 @@ export const getRunSqlQuery = ( driver = currentDriver ) => { let type = 'run_sql'; - if (driver === 'mssql') { - type = 'mssql_run_sql'; + if (driver === 'mssql' || driver === 'bigquery') { + type = `${driver}_run_sql`; } return { diff --git a/console/src/components/Services/Data/Add/AddExistingTableViewActions.js b/console/src/components/Services/Data/Add/AddExistingTableViewActions.js index 4908af45c8f..e85c1624101 100644 --- a/console/src/components/Services/Data/Add/AddExistingTableViewActions.js +++ b/console/src/components/Services/Data/Add/AddExistingTableViewActions.js @@ -8,8 +8,12 @@ import { getTableModifyRoute, getFunctionModifyRoute, } from '../../../Common/utils/routesUtils'; -import { dataSource } from '../../../../dataSources'; -import { findTable, escapeTableColumns } from '../../../../dataSources/common'; +import { dataSource, currentDriver } from '../../../../dataSources'; +import { + findTable, + escapeTableColumns, + getQualifiedTableDef, +} from '../../../../dataSources/common'; import { exportMetadata } from '../../../../metadata/actions'; import { getUntrackTableQuery, @@ -39,21 +43,24 @@ const addExistingTableSql = (name, customSchema, skipRouting = false) => { : getState().tables.currentSchema; const currentDataSource = getState().tables.currentDataSource; const tableName = name ? name : state.tableName.trim(); - const tableDef = { name: tableName, schema: currentSchema }; + + const tableDef = getQualifiedTableDef( + { + name: tableName, + schema: currentSchema, + }, + currentDriver + ); + const table = findTable(getState().tables.allSchemas, tableDef); + const requestBodyUp = getTrackTableQuery({ tableDef, source: currentDataSource, customColumnNames: escapeTableColumns(table), }); - const requestBodyDown = getUntrackTableQuery( - { - name: tableName, - schema: currentSchema, - }, - currentDataSource - ); + const requestBodyDown = getUntrackTableQuery(tableDef, currentDataSource); const migrationName = `add_existing_table_or_view_${currentSchema}_${tableName}`; @@ -67,19 +74,20 @@ const addExistingTableSql = (name, customSchema, skipRouting = false) => { t => t.table_name === tableName && t.table_schema === currentSchema ); const isTableType = dataSource.isTable(newTable); - const nextRoute = isTableType - ? getTableModifyRoute( - currentSchema, - currentDataSource, - tableName, - isTableType - ) - : getTableBrowseRoute( - currentSchema, - currentDataSource, - tableName, - isTableType - ); + const nextRoute = + isTableType && currentDriver !== 'bigquery' + ? getTableModifyRoute( + currentSchema, + currentDataSource, + tableName, + isTableType + ) + : getTableBrowseRoute( + currentSchema, + currentDataSource, + tableName, + isTableType + ); if (!skipRouting) { dispatch(_push(nextRoute)); } @@ -178,12 +186,17 @@ const addAllUntrackedTablesSql = tableList => { dispatch(showSuccessNotification('Adding...')); const bulkQueryUp = []; const bulkQueryDown = []; + for (let i = 0; i < tableList.length; i++) { if (tableList[i].table_name !== 'schema_migrations') { - const tableDef = { - name: tableList[i].table_name, - schema: currentSchema, - }; + const tableDef = getQualifiedTableDef( + { + name: tableList[i].table_name, + schema: currentSchema, + }, + currentDriver + ); + const table = findTable(getState().tables.allSchemas, tableDef); bulkQueryUp.push( getTrackTableQuery({ @@ -197,7 +210,9 @@ const addAllUntrackedTablesSql = tableList => { { table: { name: tableList[i].table_name, - schema: currentSchema, + [currentDriver === 'bigquery' + ? 'dataset' + : 'schema']: currentSchema, }, }, currentDataSource @@ -205,6 +220,7 @@ const addAllUntrackedTablesSql = tableList => { ); } } + const migrationName = 'add_all_existing_table_or_view_' + currentSchema; const requestMsg = 'Adding existing table/view...'; diff --git a/console/src/components/Services/Data/DataActions.js b/console/src/components/Services/Data/DataActions.js index d70441669b0..874fe50b2c1 100644 --- a/console/src/components/Services/Data/DataActions.js +++ b/console/src/components/Services/Data/DataActions.js @@ -26,7 +26,11 @@ import { cascadeUpQueries, getDependencyError, } from './utils'; -import { mergeDataMssql, mergeLoadSchemaDataPostgres } from './mergeData'; +import { + mergeDataMssql, + mergeLoadSchemaDataPostgres, + mergeDataBigQuery, +} from './mergeData'; import _push from './push'; import { convertArrayToJson } from './TableModify/utils'; import { CLI_CONSOLE_MODE, SERVER_CONSOLE_MODE } from '../../../constants'; @@ -146,7 +150,9 @@ const loadSchema = configOptions => { (!configOptions.tables || configOptions.tables.length === 0)) ) { configOptions = { - schemas: [getState().tables.currentSchema], + schemas: [ + getState().tables.currentSchema || getState().tables.schemaList[0], + ], }; } @@ -171,7 +177,6 @@ const loadSchema = configOptions => { ); } } - const body = { type: 'bulk', source, @@ -225,6 +230,9 @@ const loadSchema = configOptions => { case 'mssql': mergedData = mergeDataMssql(data, metadataTables); break; + case 'bigquery': + mergedData = mergeDataBigQuery(data, metadataTables); + break; default: } @@ -308,9 +316,14 @@ const setConsistentSchema = data => ({ const fetchDataInit = (source, driver) => (dispatch, getState) => { const url = Endpoints.query; - const { schemaFilter } = getState().tables; - const currentSource = source || getState().tables.currentDataSource; + let { schemaFilter } = getState().tables; + if (driver === 'bigquery') + schemaFilter = getState().metadata.metadataObject.sources.find( + x => x.name === source + ).configuration.datasets; + + const currentSource = source || getState().tables.currentDataSource; const query = getRunSqlQuery( dataSource.schemaListSql(schemaFilter), currentSource, @@ -340,7 +353,6 @@ const fetchDataInit = (source, driver) => (dispatch, getState) => { type: FETCH_SCHEMA_LIST, schemaList, }); - let newSchema = ''; if (schemaList.length) { newSchema = @@ -350,7 +362,6 @@ const fetchDataInit = (source, driver) => (dispatch, getState) => { : schemaList.sort(Intl.Collator().compare)[0]; } dispatch({ type: UPDATE_CURRENT_SCHEMA, currentSchema: newSchema }); - return dispatch(updateSchemaInfo()); // TODO }, error => { @@ -558,7 +569,6 @@ export const getDatabaseTableTypeInfo = ( resolve({}); }); } - const url = Endpoints.query; const sql = services[sourceType].getTableInfo(tables); const query = getRunSqlQuery(sql, sourceName, false, false, sourceType); @@ -582,13 +592,18 @@ export const getDatabaseTableTypeInfo = ( try { if (currentDriver === 'mssql') { res = JSON.parse(result.slice(1).join()); + } else if (currentDriver === 'bigquery') { + res = result.slice(1).map(t => ({ + table_name: t[0], + table_schema: t[1], + table_type: t[2], + })); } else { res = JSON.parse(result[1]); } - } catch { + } catch (err) { res = []; } - res.forEach(i => { if ( !trackedTables.some( diff --git a/console/src/components/Services/Data/DataSourceContainer.tsx b/console/src/components/Services/Data/DataSourceContainer.tsx index 70ee9644341..85cd89c3898 100644 --- a/console/src/components/Services/Data/DataSourceContainer.tsx +++ b/console/src/components/Services/Data/DataSourceContainer.tsx @@ -83,6 +83,7 @@ const DataSourceContainer = ({ dispatch({ type: UPDATE_CURRENT_SCHEMA, currentSchema: schema }); return; } + // eslint-disable-next-line no-useless-return if (!dataLoaded) return; let newSchema = ''; @@ -94,11 +95,10 @@ const DataSourceContainer = ({ ? dataSource.defaultRedirectSchema : schemaList.sort(Intl.Collator().compare)[0]; } - if (location.pathname.includes('schema')) { dispatch(push(`/data/${source}/schema/${newSchema}`)); } - }, [dispatch, schema, schemaList, source, location, dataLoaded]); + }, [dispatch, schema, schemaList, location, source, dataLoaded]); useEffect(() => { const driver = getSourceDriver(dataSources, currentSource); diff --git a/console/src/components/Services/Data/DataSources/ConnectDBForm.tsx b/console/src/components/Services/Data/DataSources/ConnectDBForm.tsx index aa144fb23ae..7c5519cfbee 100644 --- a/console/src/components/Services/Data/DataSources/ConnectDBForm.tsx +++ b/console/src/components/Services/Data/DataSources/ConnectDBForm.tsx @@ -2,7 +2,9 @@ import React, { ChangeEvent, Dispatch, useState } from 'react'; import { ConnectDBActions, ConnectDBState, connectionTypes } from './state'; import { LabeledInput } from '../../../Common/LabeledInput'; +import Tooltip from '../../../Common/Tooltip/Tooltip'; import { Driver } from '../../../../dataSources'; +import { readFile } from './utils'; import styles from './DataSources.scss'; @@ -41,6 +43,7 @@ const dbTypePlaceholders: Record = { mssql: 'Driver={ODBC Driver 17 for SQL Server};Server=serveraddress;Database=dbname;Uid=username;Pwd=password;', mysql: 'MySQL connection string', + bigquery: 'SERVICE_ACCOUNT_KEY_FROM_ENV', }; const defaultTitle = 'Connect Database Via'; @@ -59,6 +62,23 @@ const ConnectDatabaseForm: React.FC = ({ const toggleConnectionParams = (value: boolean) => () => { toggleConnectionParamState(value); }; + + const handleFileUpload = (e: React.ChangeEvent) => { + const file = e.target.files![0]; + const addFileQueries = (content: string) => { + try { + connectionDBStateDispatch({ + type: 'UPDATE_DB_BIGQUERY_SERVICE_ACCOUNT_FILE', + data: content, + }); + } catch (error) { + console.log(error); + } + }; + + readFile(file, addFileQueries); + }; + return ( <>

@@ -132,12 +152,16 @@ const ConnectDatabaseForm: React.FC = ({ + )} - {connectionTypeState.includes(connectionTypes.DATABASE_URL) || - (connectionTypeState.includes(connectionTypes.CONNECTION_PARAMS) && - connectionDBState.dbType === 'mssql') ? ( + {(connectionTypeState.includes(connectionTypes.DATABASE_URL) || + (connectionTypeState.includes(connectionTypes.CONNECTION_PARAMS) && + connectionDBState.dbType === 'mssql')) && + connectionDBState.dbType !== 'bigquery' ? ( @@ -152,7 +176,8 @@ const ConnectDatabaseForm: React.FC = ({ // disabled={isEditState} /> ) : null} - {connectionTypeState.includes(connectionTypes.ENV_VAR) ? ( + {connectionTypeState.includes(connectionTypes.ENV_VAR) && + connectionDBState.dbType !== 'bigquery' ? ( = ({ data: e.target.value, }) } - value={connectionDBState.envVarURLState.envVarURL} + value={connectionDBState.envVarState.envVar} data-test="database-url-env" /> ) : null} + {(connectionTypeState.includes(connectionTypes.DATABASE_URL) || + connectionTypeState.includes(connectionTypes.CONNECTION_PARAMS) || + connectionTypeState.includes(connectionTypes.ENV_VAR)) && + connectionDBState.dbType === 'bigquery' ? ( + <> + {connectionTypeState.includes(connectionTypes.ENV_VAR) ? ( + + connectionDBStateDispatch({ + type: 'UPDATE_DB_URL_ENV_VAR', + data: e.target.value, + }) + } + value={connectionDBState.envVarState.envVar} + data-test="service-account-env-var" + /> + ) : ( +
+
+ Service Account File: + +
+ +
+ )} + + connectionDBStateDispatch({ + type: 'UPDATE_DB_BIGQUERY_PROJECT_ID', + data: e.target.value, + }) + } + value={connectionDBState.databaseURLState.projectId} + placeholder="project_id" + data-test="project-id" + /> + + connectionDBStateDispatch({ + type: 'UPDATE_DB_BIGQUERY_DATASETS', + data: e.target.value, + }) + } + value={connectionDBState.databaseURLState.datasets} + placeholder="dataset1, dataset2" + data-test="datasets" + /> + + ) : null} {connectionTypeState.includes(connectionTypes.CONNECTION_PARAMS) && - connectionDBState.dbType !== 'mssql' ? ( + connectionDBState.dbType === 'postgres' ? ( <> = props => { (connectionType === connectionTypes.CONNECTION_PARAMS && connectDBInputState.dbType === 'mssql') ) { - if (!connectDBInputState.databaseURLState.dbURL.trim()) { + if ( + !connectDBInputState.databaseURLState.dbURL.trim() && + connectDBInputState.dbType !== 'bigquery' + ) { dispatch( showErrorNotification( 'Database URL is a mandatory field', @@ -152,7 +156,10 @@ const ConnectDatabase: React.FC = props => { } if (connectionType === connectionTypes.ENV_VAR) { - if (!connectDBInputState.envVarURLState.envVarURL.trim()) { + if ( + !connectDBInputState.envVarState.envVar.trim() && + connectDBInputState.dbType !== 'bigquery' + ) { dispatch( showErrorNotification( 'Environment Variable is a mandatory field', @@ -184,17 +191,19 @@ const ConnectDatabase: React.FC = props => { database, } = connectDBInputState.connectionParamState; - if (!host || !port || !username || !database) { - const errorMessage = getErrorMessageFromMissingFields( - host, - port, - username, - database - ); - dispatch( - showErrorNotification('Required fields are missing', errorMessage) - ); - return; + if (connectDBInputState.dbType !== 'bigquery') { + if (!host || !port || !username || !database) { + const errorMessage = getErrorMessageFromMissingFields( + host, + port, + username, + database + ); + dispatch( + showErrorNotification('Required fields are missing', errorMessage) + ); + return; + } } setLoading(true); connectDataSource( @@ -259,7 +268,9 @@ const ConnectDatabase: React.FC = props => { updateConnectionTypeRadio={onChangeConnectionType} /> {/* Should be rendered only on Pro and Cloud Console */} - {connectDBInputState.dbType !== 'mssql' && + {getSupportedDrivers('connectDbForm.read_replicas').includes( + connectDBInputState.dbType + ) && (window.__env.consoleId || window.__env.userRole) && ( = ({ > Remove -

{isFromEnvVar ? currentState.envVarURLState.envVarURL : host}

+

{isFromEnvVar ? currentState.envVarState.envVar : host}

{/* The connection string is redundant if it's provided via ENV VAR */} {!isFromEnvVar && ( { ...defaultState, displayName: props?.dbConnection.dbName || '', databaseURLState: { + ...defaultState.databaseURLState, dbURL: props?.dbConnection.dbURL || '', }, - envVarURLState: { - envVarURL: props?.dbConnection.envVar || '', + envVarState: { + envVar: props?.dbConnection.envVar || '', }, }; }; @@ -88,12 +95,23 @@ export const connectDataSource = ( cb: () => void, replicas?: Omit[] ) => { - let databaseURL: - | string - | { from_env: string } = currentState.databaseURLState.dbURL.trim(); - if (typeConnection === connectionTypes.ENV_VAR) { - databaseURL = { from_env: currentState.envVarURLState.envVarURL.trim() }; - } else if (typeConnection === connectionTypes.CONNECTION_PARAMS) { + let databaseURL: string | { from_env: string } = + currentState.dbType === 'bigquery' + ? currentState.databaseURLState.serviceAccountFile.trim() + : currentState.databaseURLState.dbURL.trim(); + if ( + typeConnection === connectionTypes.ENV_VAR && + getSupportedDrivers('connectDbForm.environmentVariable').includes( + currentState.dbType + ) + ) { + databaseURL = { from_env: currentState.envVarState.envVar.trim() }; + } else if ( + typeConnection === connectionTypes.CONNECTION_PARAMS && + getSupportedDrivers('connectDbForm.connectionParameters').includes( + currentState.dbType + ) + ) { databaseURL = makeConnectionStringFromConnectionParams({ dbType: currentState.dbType, ...currentState.connectionParamState, @@ -108,6 +126,10 @@ export const connectDataSource = ( name: currentState.displayName.trim(), dbUrl: databaseURL, connection_pool_settings: currentState.connectionSettings, + bigQuery: { + projectId: currentState.databaseURLState.projectId, + datasets: currentState.databaseURLState.datasets, + }, }, }, cb, @@ -128,6 +150,9 @@ export type ConnectDBActions = } | { type: 'UPDATE_DISPLAY_NAME'; data: string } | { type: 'UPDATE_DB_URL'; data: string } + | { type: 'UPDATE_DB_BIGQUERY_SERVICE_ACCOUNT_FILE'; data: string } + | { type: 'UPDATE_DB_BIGQUERY_PROJECT_ID'; data: string } + | { type: 'UPDATE_DB_BIGQUERY_DATASETS'; data: string } | { type: 'UPDATE_DB_URL_ENV_VAR'; data: string } | { type: 'UPDATE_DB_HOST'; data: string } | { type: 'UPDATE_DB_PORT'; data: string } @@ -152,6 +177,7 @@ export const connectDBReducer = ( displayName: action.data.name, dbType: action.data.driver, databaseURLState: { + ...state.databaseURLState, dbURL: action.data.databaseUrl, }, connectionSettings: action.data.connectionSettings, @@ -170,14 +196,15 @@ export const connectDBReducer = ( return { ...state, databaseURLState: { + ...state.databaseURLState, dbURL: action.data, }, }; case 'UPDATE_DB_URL_ENV_VAR': return { ...state, - envVarURLState: { - envVarURL: action.data, + envVarState: { + envVar: action.data, }, }; case 'UPDATE_DB_HOST': @@ -253,6 +280,30 @@ export const connectDBReducer = ( ...state, connectionSettings: action.data, }; + case 'UPDATE_DB_BIGQUERY_SERVICE_ACCOUNT_FILE': + return { + ...state, + databaseURLState: { + ...state.databaseURLState, + serviceAccountFile: action.data, + }, + }; + case 'UPDATE_DB_BIGQUERY_DATASETS': + return { + ...state, + databaseURLState: { + ...state.databaseURLState, + datasets: action.data, + }, + }; + case 'UPDATE_DB_BIGQUERY_PROJECT_ID': + return { + ...state, + databaseURLState: { + ...state.databaseURLState, + projectId: action.data, + }, + }; default: return state; } @@ -310,7 +361,7 @@ export const makeReadReplicaConnectionObject = ( database_url = stateVal.databaseURLState?.dbURL?.trim() ?? ''; } else if (stateVal.chosenConnectionType === connectionTypes.ENV_VAR) { database_url = { - from_env: stateVal.envVarURLState?.envVarURL?.trim() ?? '', + from_env: stateVal.envVarState?.envVar?.trim() ?? '', }; } else { database_url = makeConnectionStringFromConnectionParams({ diff --git a/console/src/components/Services/Data/DataSources/utils.ts b/console/src/components/Services/Data/DataSources/utils.ts index c36ac60f95d..6742749383c 100644 --- a/console/src/components/Services/Data/DataSources/utils.ts +++ b/console/src/components/Services/Data/DataSources/utils.ts @@ -34,3 +34,20 @@ export const getDatasourceURL = ( } return link.from_env.toString(); }; + +export const readFile = ( + file: File | null, + callback: (content: string) => void +) => { + const reader = new FileReader(); + reader.onload = event => { + const content = event.target!.result as string; + callback(content); + }; + + reader.onerror = event => { + console.error(`File could not be read! Code ${event.target!.error!.code}`); + }; + + if (file) reader.readAsText(file); +}; diff --git a/console/src/components/Services/Data/DataSubSidebar.js b/console/src/components/Services/Data/DataSubSidebar.js index 8159aa8ff18..0bd82f0262d 100644 --- a/console/src/components/Services/Data/DataSubSidebar.js +++ b/console/src/components/Services/Data/DataSubSidebar.js @@ -86,9 +86,9 @@ const DataSubSidebar = props => { type: UPDATE_CURRENT_DATA_SOURCE, source: newSourceName, }); - setDriver(driver); dispatch(_push(`/data/${newSourceName}/`)); - dispatch(fetchDataInit()).finally(() => { + setDriver(driver); + dispatch(fetchDataInit(newSourceName, driver)).finally(() => { setDatabaseLoading(false); }); }; @@ -201,7 +201,7 @@ const DataSubSidebar = props => { sources.forEach(source => { const currentSourceTables = sources .filter(i => i.name === source.name)[0] - .tables.map(i => `'${i.table.name}'`); + .tables.map(t => t.table); schemaPromises.push( dispatch( getDatabaseTableTypeInfo( diff --git a/console/src/components/Services/Data/RawSQL/RawSQL.js b/console/src/components/Services/Data/RawSQL/RawSQL.js index be21e728b9d..35ff7fc0661 100644 --- a/console/src/components/Services/Data/RawSQL/RawSQL.js +++ b/console/src/components/Services/Data/RawSQL/RawSQL.js @@ -32,6 +32,8 @@ import DropDownSelector from './DropDownSelector'; import { getSourceDriver } from '../utils'; import { getDataSources } from '../../../../metadata/selector'; import { services } from '../../../../dataSources/services'; +import { isFeatureSupported } from '../../../../dataSources'; + /** * # RawSQL React FC * ## renders raw SQL page on route `/data/sql` @@ -332,17 +334,19 @@ const RawSQL = ({ return (
- + {isFeatureSupported('rawSQL.tracking') && ( + + )} = { mysql: 'MySQL', postgres: 'PostgreSQL', mssql: 'MS Server', + bigquery: 'Big Query', }; type DatabaseListItemProps = { diff --git a/console/src/components/Services/Data/Schema/Schema.js b/console/src/components/Services/Data/Schema/Schema.js index bde0da2c74a..d87351920a8 100644 --- a/console/src/components/Services/Data/Schema/Schema.js +++ b/console/src/components/Services/Data/Schema/Schema.js @@ -34,6 +34,7 @@ import { getUntrackedTables, dataSource, currentDriver, + isFeatureSupported, } from '../../../../dataSources'; import { isEmpty } from '../../../Common/utils/jsUtils'; import { getConfirmation } from '../../../Common/utils/jsUtils'; @@ -47,21 +48,6 @@ import { TrackableFunctionsList } from './FunctionsList'; import { getTrackableFunctions } from './utils'; import BreadCrumb from '../../../Common/Layout/BreadCrumb/BreadCrumb'; -const FEATURES = { - UNTRACKED_TABLES: 'UNTRACKED_TABLES', - UNTRACKED_RELATIONS: 'UNTRACKED_RELATIONS', - UNTRACKED_FUNCTION: 'UNTRACKED_FUNCTION', - NON_TRACKABLE_FUNCTIONS: 'NON_TRACKABLE_FUNCTIONS', -}; - -const supportedFeaturesByDriver = { - postgres: Object.values(FEATURES), - mssql: [FEATURES.UNTRACKED_TABLES, FEATURES.UNTRACKED_RELATIONS], -}; - -const isAllowed = (driver, feature) => - supportedFeaturesByDriver[driver].includes(feature); - const DeleteSchemaButton = ({ dispatch, migrationMode, currentDataSource }) => { const successCb = () => { dispatch(updateCurrentSchema('public', currentDataSource)); @@ -140,17 +126,21 @@ const CreateSchemaSection = React.forwardRef( }) => migrationMode && (
- {createSchemaOpen ? ( - - ) : ( - - )} + {isFeatureSupported('schemas.create.enabled') ? ( + + {createSchemaOpen ? ( + + ) : ( + + )} + + ) : null}
) @@ -261,7 +251,7 @@ class Schema extends Component { const getCreateBtn = () => { let createBtn = null; - if (migrationMode && currentDriver === 'postgres') { + if (migrationMode && isFeatureSupported('tables.create.enabled')) { const handleClick = e => { e.preventDefault(); @@ -295,12 +285,14 @@ class Schema extends Component {
- + {isFeatureSupported('schemas.delete.enabled') ? ( + + ) : null} {getUntrackedTablesSection()} - {getUntrackedRelationsSection()} + {isFeatureSupported('tables.relationships.track') && + getUntrackedRelationsSection()} {getUntrackedFunctionsSection( - isAllowed(currentDriver, FEATURES.NON_TRACKABLE_FUNCTIONS) + isFeatureSupported('functions.track.enabled') )} - {isAllowed(currentDriver, FEATURES.NON_TRACKABLE_FUNCTIONS) && + {isFeatureSupported('functions.nonTrackableFunctions.enabled') && getNonTrackableFunctionsSection()}
diff --git a/console/src/components/Services/Data/SourceView.tsx b/console/src/components/Services/Data/SourceView.tsx index bc877691693..4dc4f42c739 100644 --- a/console/src/components/Services/Data/SourceView.tsx +++ b/console/src/components/Services/Data/SourceView.tsx @@ -12,6 +12,7 @@ import { getSchemaPermissionsRoute, } from '../../Common/utils/routesUtils'; import _push from './push'; +import { isFeatureSupported } from '../../../dataSources'; import BreadCrumb from '../../Common/Layout/BreadCrumb/BreadCrumb'; interface Props { @@ -71,55 +72,59 @@ const SourceView: React.FC = props => {

{currentDataSource}

- {!isCreateActive ? ( - - ) : ( -
-
- { - e.persist(); - setCreateSchemaName(e.target.value); - }} - /> -
- - -
- )} + {isFeatureSupported('schemas.create.enabled') ? ( + + {!isCreateActive ? ( + + ) : ( +
+
+ { + e.persist(); + setCreateSchemaName(e.target.value); + }} + /> +
+ + +
+ )} +
+ ) : null}

@@ -127,11 +132,12 @@ const SourceView: React.FC = props => { {schemaList.length ? ( schemaList.map((schema, key: number) => { return ( -
+
-