make add form a link

This commit is contained in:
Nate Kelley 2025-03-25 10:21:19 -06:00
parent f49b4ef274
commit 4b4ed982a5
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
7 changed files with 90 additions and 97 deletions

15
web/package-lock.json generated
View File

@ -79,6 +79,7 @@
"ts-jest": "^29.2.6",
"use-context-selector": "^2.0.0",
"utility-types": "^3.11.0",
"valibot": "^1.0.0",
"virtua": "^0.40.3",
"zustand": "^5.0.3"
},
@ -21322,6 +21323,20 @@
"node": ">=10.12.0"
}
},
"node_modules/valibot": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0.tgz",
"integrity": "sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==",
"license": "MIT",
"peerDependencies": {
"typescript": ">=5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/vfile": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",

View File

@ -87,6 +87,7 @@
"ts-jest": "^29.2.6",
"use-context-selector": "^2.0.0",
"utility-types": "^3.11.0",
"valibot": "^1.0.0",
"virtua": "^0.40.3",
"zustand": "^5.0.3"
},

View File

@ -1,6 +1,19 @@
import type { DataSource, DataSourceListItem } from '@/api/asset_interfaces/datasources';
import type {
BigQueryCredentials,
DatabricksCredentials,
DataSource,
DataSourceListItem,
MySQLCredentials,
PostgresCredentials,
SnowflakeCredentials,
SQLServerCredentials
} from '@/api/asset_interfaces/datasources';
import mainApi from '../instances';
import { DatasourceUpdateParams } from '@/api/request_interfaces/datasources';
import {
DatasourceUpdateParams,
RedshiftCreateCredentials
} from '@/api/request_interfaces/datasources';
import { MySQLCreateParams } from './types';
export const listDatasources = async () => {
return await mainApi.get<DataSourceListItem[]>('/data_sources').then((res) => res.data);
@ -14,16 +27,7 @@ export const deleteDatasource = async (id: string) => {
return await mainApi.delete(`/data_sources/${id}`).then((res) => res.data);
};
export const createPostgresDataSource = async (params: {
name: string;
type: 'postgres' | 'supabase';
host: string;
port: number;
username: string;
password: string;
default_database: string; //postgres
default_schema: string; //public
}) => {
export const createPostgresDataSource = async (params: PostgresCredentials) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
@ -34,15 +38,7 @@ export const updatePostgresDataSource = async ({
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createMySQLDataSource = async (params: {
name: string;
type: 'mysql' | 'mariadb';
host: string;
port: number;
username: string;
password: string;
default_database: string;
}) => {
export const createMySQLDataSource = async (params: MySQLCredentials) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
@ -53,16 +49,7 @@ export const updateMySQLDataSource = async ({
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createRedshiftDataSource = async (params: {
name: string;
type: 'redshift';
host: string;
port: number;
username: string;
password: string;
default_database: string;
default_schema: string;
}) => {
export const createRedshiftDataSource = async (params: RedshiftCreateCredentials) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
@ -73,13 +60,7 @@ export const updateRedshiftDataSource = async ({
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createBigQueryDataSource = async (params: {
name: string;
type: 'bigquery';
service_role_key: string;
default_project_id: string;
default_dataset_id: string;
}) => {
export const createBigQueryDataSource = async (params: BigQueryCredentials) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
@ -90,17 +71,7 @@ export const updateBigQueryDataSource = async ({
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createSnowflakeDataSource = async (params: {
name: string;
type: 'snowflake';
account_id: string;
warehouse_id: string;
username: string;
password: string;
role: string | null;
default_database: string;
default_schema: string;
}) => {
export const createSnowflakeDataSource = async (params: SnowflakeCredentials) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
@ -111,15 +82,7 @@ export const updateSnowflakeDataSource = async ({
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createDatabricksDataSource = async (params: {
name: string;
type: 'databricks';
host: string;
api_key: string;
warehouse_id: string;
default_catalog: string;
default_schema: string;
}) => {
export const createDatabricksDataSource = async (params: DatabricksCredentials) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};
@ -130,16 +93,7 @@ export const updateDatabricksDataSource = async ({
return mainApi.put<DataSource>(`/data_sources/${id}`, params).then((res) => res.data);
};
export const createSQLServerDataSource = async (params: {
name: string;
type: 'sqlserver';
host: string;
port: number;
username: string;
password: string;
default_database: string;
default_schema: string;
}) => {
export const createSQLServerDataSource = async (params: SQLServerCredentials) => {
return mainApi.post<DataSource>('/data_sources', params).then((res) => res.data);
};

View File

@ -1,6 +1,6 @@
'use client';
import type { DataSource, DataSourceTypes } from '@/api/asset_interfaces';
import { DatabaseNames, type DataSource, type DataSourceTypes } from '@/api/asset_interfaces';
import React from 'react';
import { PostgresForm } from './PostgresForm';
import { MySqlForm } from './MySqlForm';
@ -9,6 +9,8 @@ import { SnowflakeForm } from './SnowflakeForm';
import { RedshiftForm } from './RedshiftForm';
import { DataBricksForm } from './DataBricksForm';
import { SqlServerForm } from './SqlServerForm';
import { AppDataSourceIcon } from '@/components/ui/icons/AppDataSourceIcons';
import { Text } from '@/components/ui/typography';
const FormRecord: Record<
DataSourceTypes,
@ -32,14 +34,19 @@ const FormRecord: Record<
export const DataSourceFormContent: React.FC<{
dataSource?: DataSource;
type: DataSourceTypes;
}> = ({ dataSource, type }) => {
}> = React.memo(({ dataSource, type }) => {
const SelectedForm = FormRecord[type];
const DatabaseName = DatabaseNames[type];
return (
<div className="rounded-lg border">
<div className="bg-item-hover flex items-center px-4 py-2.5">Datasource credentials</div>
<div className="overflow-hidden rounded-lg border shadow">
<div className="bg-item-hover flex items-center space-x-2 px-4 py-2.5">
<Text>{`${DatabaseName} credentials`}</Text>
</div>
<div className="p-4">{SelectedForm && <SelectedForm dataSource={dataSource} />}</div>
</div>
);
};
});
DataSourceFormContent.displayName = 'DataSourceFormContent';

View File

@ -30,7 +30,7 @@ export const SnowflakeForm: React.FC<{
warehouse_id: credentials?.warehouse_id || '',
username: credentials?.username || '',
password: credentials?.password || '',
role: credentials?.role || null,
role: credentials?.role || '',
default_database: credentials?.default_database || '',
default_schema: credentials?.default_schema || '',
type: 'snowflake' as const,

View File

@ -1,6 +1,6 @@
'use client';
import React from 'react';
import React, { useEffect } from 'react';
import { BusterRoutes, createBusterRoute } from '@/routes';
import { HeaderContainer } from '../../_HeaderContainer';
import { useState } from 'react';
@ -10,22 +10,44 @@ import { Title, Text } from '@/components/ui/typography';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { cn } from '@/lib/classMerge';
import { AppDataSourceIcon } from '@/components/ui/icons/AppDataSourceIcons';
import { useRouter } from 'next/navigation';
import { useMemoizedFn } from '@/hooks';
import Link from 'next/link';
export default function Page() {
const [selectedDataSource, setSelectedDataSource] = useState<DataSourceTypes | null>(null);
const { openInfoMessage } = useBusterNotifications();
export default function Page({
searchParams: { type }
}: {
searchParams: { type?: DataSourceTypes };
}) {
const router = useRouter();
const [selectedDataSource, setSelectedDataSource] = useState<DataSourceTypes | null>(
type || null
);
const linkUrl = selectedDataSource
? ''
? createBusterRoute({
route: BusterRoutes.SETTINGS_DATASOURCES_ADD
})
: createBusterRoute({
route: BusterRoutes.SETTINGS_DATASOURCES
});
const onClearSelectedDataSource = useMemoizedFn(() => {
setSelectedDataSource(null);
router.push(createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD }));
});
useEffect(() => {
if (type) {
setSelectedDataSource(type);
}
}, [type]);
return (
<div className="flex flex-col space-y-5">
<HeaderContainer
buttonText={selectedDataSource ? 'Connect a datasource' : 'Datasources'}
onClick={() => setSelectedDataSource(null)}
onClick={onClearSelectedDataSource}
linkUrl={linkUrl}
/>
@ -34,15 +56,7 @@ export default function Page() {
) : (
<div className="flex flex-col space-y-6">
<ConnectHeader />
<DataSourceList
onSelect={(v) => {
if (SUPPORTED_DATASOURCES.includes(v)) {
setSelectedDataSource(v);
} else {
openInfoMessage('This data source is not currently supported');
}
}}
/>
<DataSourceList />
</div>
)}
</div>
@ -58,25 +72,27 @@ const ConnectHeader: React.FC<{}> = ({}) => {
);
};
const DataSourceList: React.FC<{
onSelect: (dataSource: DataSourceTypes) => void;
}> = ({ onSelect }) => {
const DataSourceList: React.FC<{}> = ({}) => {
return (
<div className="grid grid-cols-3 gap-4">
{Object.values(DataSourceTypes).map((dataSource) => {
{SUPPORTED_DATASOURCES.map((dataSource) => {
const name = DatabaseNames[dataSource];
return (
<div
onClick={() => onSelect(dataSource)}
<Link
href={
createBusterRoute({
route: BusterRoutes.SETTINGS_DATASOURCES_ADD
}) + `?type=${dataSource}`
}
key={dataSource}
className={cn(
'flex cursor-pointer items-center space-x-4 px-4 py-3 transition',
'flex cursor-pointer items-center space-x-4 px-4 py-3 shadow transition',
'bg-background hover:bg-item-hover',
'border-border max-h-[48px] rounded border'
)}>
<AppDataSourceIcon size={28} type={dataSource} />
<Text>{name}</Text>
</div>
</Link>
);
})}
</div>