diff --git a/wren-ui/public/images/dataSource/duckDb.svg b/wren-ui/public/images/dataSource/duckDb.svg new file mode 100644 index 000000000..5ff71631f --- /dev/null +++ b/wren-ui/public/images/dataSource/duckDb.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/wren-ui/public/images/dataSource/postgreSql.svg b/wren-ui/public/images/dataSource/postgreSql.svg new file mode 100644 index 000000000..94749d78a --- /dev/null +++ b/wren-ui/public/images/dataSource/postgreSql.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/wren-ui/src/components/modals/AddRelationModal.tsx b/wren-ui/src/components/modals/AddRelationModal.tsx index 97ac4d62e..ad1d9c7b3 100644 --- a/wren-ui/src/components/modals/AddRelationModal.tsx +++ b/wren-ui/src/components/modals/AddRelationModal.tsx @@ -1,40 +1,54 @@ import { useEffect } from 'react'; import { isEmpty } from 'lodash'; -import { Modal, Form, Input, Select, Row, Col } from 'antd'; +import { Modal, Form, Select, Row, Col } from 'antd'; import { ModalAction } from '@/hooks/useModalAction'; import { ERROR_TEXTS } from '@/utils/error'; import CombineFieldSelector from '@/components/selectors/CombineFieldSelector'; import { JOIN_TYPE } from '@/utils/enum'; -import { RelationData, getJoinTypeText } from '@/utils/data'; +import { getJoinTypeText } from '@/utils/data'; import useCombineFieldOptions from '@/hooks/useCombineFieldOptions'; import { RelationsDataType } from '@/components/table/ModelRelationSelectionTable'; +import { SelectedRecommendRelations } from '@/components/pages/setup/DefineRelations'; export type RelationFieldValue = { [key: string]: any } & Pick< - RelationData, - 'name' | 'joinType' | 'fromField' | 'toField' | 'properties' + RelationsDataType, + 'name' | 'type' | 'fromField' | 'toField' | 'properties' >; type Props = ModalAction & { model: string; loading?: boolean; - allowSetDescription?: boolean; + relations: SelectedRecommendRelations; }; export default function RelationModal(props: Props) { const { - allowSetDescription = true, defaultValue, loading, model, onClose, onSubmit, + relations, visible, } = props; const [form] = Form.useForm(); + const fromCombineField = useCombineFieldOptions({ model }); + + const toFieldModel = defaultValue?.toField.model; + const toCombineField = useCombineFieldOptions({ + model: toFieldModel, + excludeModels: [model], + }); + useEffect(() => { if (!visible) return; + fromCombineField.onModelChange(model); form.setFieldsValue(defaultValue || {}); + + if (toFieldModel) { + toCombineField.onModelChange(toFieldModel); + } }, [form, defaultValue, visible]); const relationTypeOptions = Object.keys(JOIN_TYPE).map((key) => ({ @@ -42,11 +56,37 @@ export default function RelationModal(props: Props) { value: JOIN_TYPE[key], })); - const fromCombineField = useCombineFieldOptions({ model }); - const toCombineField = useCombineFieldOptions({ - model: defaultValue?.toField.model, - excludeModels: [model], - }); + const toCombineModelOptions = toCombineField.modelOptions.map( + (modelOption) => { + const modelList = Object.entries(relations).reduce( + (acc, [modelName, modelRelations]) => { + // For add relation, if the Model option has been selected in the From model relations, the Model option should be disabled + if (modelName === model) { + acc = [ + ...acc, + ...modelRelations.map((relation) => relation.toField.model), + ]; + } else { + const toFieldModelList = modelRelations.map( + (relation) => relation.toField.model, + ); + if (toFieldModelList.includes(model)) { + acc = [...acc, modelName]; + } + } + return acc; + }, + [], + ); + + const disabled = modelList.includes(modelOption.value); + + return { + ...modelOption, + disabled, + }; + }, + ); const submit = () => { form @@ -70,25 +110,13 @@ export default function RelationModal(props: Props) { maskClosable={false} destroyOnClose afterClose={() => form.resetFields()} + centered >
- - - @@ -129,7 +157,7 @@ export default function RelationModal(props: Props) { - {allowSetDescription && ( - - - - )}
); diff --git a/wren-ui/src/components/pages/setup/ConnectDataSource.tsx b/wren-ui/src/components/pages/setup/ConnectDataSource.tsx index c745ab91e..6c6142fbb 100644 --- a/wren-ui/src/components/pages/setup/ConnectDataSource.tsx +++ b/wren-ui/src/components/pages/setup/ConnectDataSource.tsx @@ -1,6 +1,6 @@ import Image from 'next/image'; import Link from 'next/link'; -import { Typography, Form, Row, Col, Button } from 'antd'; +import { Alert, Typography, Form, Row, Col, Button } from 'antd'; import styled from 'styled-components'; import { DATA_SOURCES } from '@/utils/enum/dataSources'; import { getDataSource } from './utils'; @@ -19,10 +19,14 @@ interface Props { dataSource: DATA_SOURCES; onNext: (data: any) => void; onBack: () => void; + connectInfo?: { + connected: boolean; + errorMessage?: string; + }; } export default function ConnectDataSource(props: Props) { - const { dataSource, onNext, onBack } = props; + const { connectInfo, dataSource, onNext, onBack } = props; const [form] = Form.useForm(); const current = getDataSource(dataSource); @@ -43,18 +47,18 @@ export default function ConnectDataSource(props: Props) { Connect the data source - We only support BigQuery for now. You can vote for your warehouse in our{' '} + Vote for your preferred data source to be our next option on our{' '} - GitHub issues + GitHub - ! + . - + @@ -69,20 +73,38 @@ export default function ConnectDataSource(props: Props) { - Learn {current.label} setup guide. + Learn more information in {current.label}{' '} + setup guide. + {connectInfo && !connectInfo.connected && ( + + )} + - - diff --git a/wren-ui/src/components/pages/setup/ContainerCard.tsx b/wren-ui/src/components/pages/setup/ContainerCard.tsx index c12c435ea..2f8ad06ff 100644 --- a/wren-ui/src/components/pages/setup/ContainerCard.tsx +++ b/wren-ui/src/components/pages/setup/ContainerCard.tsx @@ -20,8 +20,8 @@ export default function ContainerCard(props: Props) { - - + +
{props.children}
diff --git a/wren-ui/src/components/pages/setup/CreateModels.tsx b/wren-ui/src/components/pages/setup/CreateModels.tsx deleted file mode 100644 index 36c72abfe..000000000 --- a/wren-ui/src/components/pages/setup/CreateModels.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { useMemo } from 'react'; -import Link from 'next/link'; -import { Button, Col, Form, Row, TableColumnsType, Typography } from 'antd'; -import { getColumnTypeIcon } from '@/utils/columnType'; -import { ERROR_TEXTS } from '@/utils/error'; -import { makeIterable, IterableComponent } from '@/utils/iteration'; -import ModelRelationSelectionTable, { - SourceTable, - SourceTableColumn, -} from '@/components/table/ModelRelationSelectionTable'; - -const { Title, Text } = Typography; - -export interface SelectedSourceTables { - [tableName: string]: SourceTableColumn[]; -} - -interface Props { - onNext: (data: { models: SelectedSourceTables }) => void; - onBack: () => void; - selectedModels: string[]; - tables: SourceTable[]; -} - -const columns: TableColumnsType = [ - { - title: 'Field name', - dataIndex: 'name', - width: '65%', - }, - { - title: 'Type', - dataIndex: 'type', - width: '35%', - render: (type) => ( -
- {getColumnTypeIcon({ type }, { className: 'mr-1' })} - {type} -
- ), - }, -]; - -const SelectModelTemplate: IterableComponent = ({ index, name, fields }) => ( - - `${name}-${record.name}-${index}`} - /> - -); - -const SelectModelIterator = makeIterable(SelectModelTemplate); - -export default function CreateModels(props: Props) { - const { onBack, onNext, selectedModels, tables } = props; - - const [form] = Form.useForm(); - - const selectModelFields = useMemo(() => { - return selectedModels.map((modelName) => { - const table = tables.find((table) => table.displayName === modelName); - return { - name: modelName, - fields: table.columns, - }; - }); - }, [selectedModels, tables]); - - const submit = () => { - form - .validateFields() - .then((values) => { - onNext && onNext({ models: { ...values } }); - }) - .catch((error) => { - console.error(error); - }); - }; - - return ( -
- - Create data model from tables - - - Data models are created directly from your data source tables. It act as - a “view” of your underlying table to transform and extend on the - original data.{` `} - - Learn more - - - -
- - - - - - - - - - - -
- ); -} diff --git a/wren-ui/src/components/pages/setup/DefineRelations.tsx b/wren-ui/src/components/pages/setup/DefineRelations.tsx index 452a503af..0957445b3 100644 --- a/wren-ui/src/components/pages/setup/DefineRelations.tsx +++ b/wren-ui/src/components/pages/setup/DefineRelations.tsx @@ -1,5 +1,4 @@ import { useState } from 'react'; -import Link from 'next/link'; import { omit } from 'lodash'; import { Button, Col, Popconfirm, Row, Space, Typography } from 'antd'; import type { ColumnsType } from 'antd/es/table'; @@ -9,9 +8,9 @@ import PlusOutlined from '@ant-design/icons/PlusOutlined'; import ModelRelationSelectionTable, { RelationsDataType, } from '@/components/table/ModelRelationSelectionTable'; -import { columns as defaultColumns } from '@/components/pages/setup/RecommendRelations'; +import { getJoinTypeText } from '@/utils/data'; import useModalAction from '@/hooks/useModalAction'; -import AddRelationModal from '@/components/modals/AddRelationModal'; +import RelationModal from '@/components/modals/AddRelationModal'; const { Title, Text } = Typography; @@ -20,9 +19,10 @@ export interface SelectedRecommendRelations { } interface Props { - selectedRecommendRelations: SelectedRecommendRelations; + recommendRelations: SelectedRecommendRelations; onNext: (data: { relations: SelectedRecommendRelations }) => void; onBack: () => void; + onSkip: () => void; } interface EditableRelationTableProps { @@ -40,7 +40,36 @@ function EditableRelationTable(props: EditableRelationTableProps) { const { index, modelName, onSetRelation, onDeleteRow, relations } = props; const columns: ColumnsType = [ - ...defaultColumns, + { + title: 'From', + dataIndex: 'fromField', + key: 'fromField', + render: (fromField) => `${fromField.model}.${fromField.field}`, + width: '35%', + }, + { + title: 'To', + dataIndex: 'toField', + key: 'toField', + render: (toField) => `${toField.model}.${toField.field}`, + width: '35%', + }, + { + title: 'Relation type', + dataIndex: 'type', + key: 'type', + render: (type, relation) => ( + <> + {getJoinTypeText(type)} + {relation.isAutoGenerated && ( + + (auto-generated) + + )} + + ), + width: '30%', + }, { title: '', key: 'action', @@ -85,7 +114,7 @@ function EditableRelationTable(props: EditableRelationTableProps) { title="Add relation" > - Add relation + Add )} rowKey={(record: RelationsDataType) => @@ -97,30 +126,27 @@ function EditableRelationTable(props: EditableRelationTableProps) { } export default function DefineRelations(props: Props) { - const { selectedRecommendRelations, onBack, onNext } = props; + const { recommendRelations, onBack, onNext, onSkip } = props; - const [relations, setRelations] = useState( - selectedRecommendRelations, - ); + const [relations, setRelations] = + useState(recommendRelations); const [selectedRelation, setSelectedRelation] = useState<{ modelName: string; defaultValue?: RelationsDataType; }>(null); - const addRelationModal = useModalAction(); + const relationModal = useModalAction(); // check is the relation is auto-generated or not const isRecommendRelation = ( modelName: string, relation: RelationsDataType, ) => { - const isOriginalRelation = ( - selectedRecommendRelations[modelName] || [] - ).find( + const isOriginalRelation = (recommendRelations[modelName] || []).find( (originalRelation) => - JSON.stringify(omit(originalRelation, ['isAutoGenerated'])) === - JSON.stringify(relation), + JSON.stringify(omit(originalRelation, ['name', 'isAutoGenerated'])) === + JSON.stringify(omit(relation, ['name', 'isAutoGenerated'])), ); return isOriginalRelation?.isAutoGenerated || false; }; @@ -139,7 +165,7 @@ export default function DefineRelations(props: Props) { const onCloseModal = () => { setSelectedRelation(null); - addRelationModal.closeModal(); + relationModal.closeModal(); }; const onDeleteRow = ( @@ -161,7 +187,7 @@ export default function DefineRelations(props: Props) { defaultValue?: RelationsDataType; }) => { setSelectedRelation(payload); - addRelationModal.openModal(); + relationModal.openModal(); }; const onUpdateRelation = ( @@ -192,16 +218,13 @@ export default function DefineRelations(props: Props) { return (
- Define the relations + Define relations - After creating your data models in step 2, you can specify how they - should be joined together by defining the relationships. We will - automatically create the relations based on the 'primary' and 'foreign' - in your data sources.{` `} - - Learn more - + You can define the relations among selected tables. We will + automatically list suggested relations based on the primary and foreign + key you have already defined in your data source. Relations will be + added into data models.
{Object.entries(relations).map(([modelName, relations = []], index) => ( @@ -217,19 +240,32 @@ export default function DefineRelations(props: Props) {
- - + - { if (selectedRelation?.defaultValue) { onUpdateRelation( @@ -243,12 +279,12 @@ export default function DefineRelations(props: Props) { setSelectedRelation(null); }} onClose={onCloseModal} - allowSetDescription={false} defaultValue={ selectedRelation?.defaultValue ? omit(selectedRelation.defaultValue, ['isAutoGenerated']) : undefined } + relations={relations} />
); diff --git a/wren-ui/src/components/pages/setup/RecommendRelations.tsx b/wren-ui/src/components/pages/setup/RecommendRelations.tsx deleted file mode 100644 index 3591c4a66..000000000 --- a/wren-ui/src/components/pages/setup/RecommendRelations.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import Link from 'next/link'; -import { Button, Col, Form, Row, Typography } from 'antd'; -import type { ColumnsType } from 'antd/es/table'; -import ModelRelationSelectionTable, { - RelationsDataType, -} from '@/components/table/ModelRelationSelectionTable'; -import { SelectedRecommendRelations } from '@/components/pages/setup/DefineRelations'; -import { makeIterable, IterableComponent } from '@/utils/iteration'; -import { getJoinTypeText } from '@/utils/data'; - -const { Title, Text } = Typography; - -interface Props { - // TODO: update type when connecting to backend - recommendRelations: Array<{ - name: string; - relations: RelationsDataType[]; - }>; - onNext: (data: SelectedRecommendRelations) => void; - onBack: () => void; -} - -export const columns: ColumnsType = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name', - width: '25%', - }, - { - title: 'From field', - dataIndex: 'fromField', - key: 'fromField', - render: (fromField) => `${fromField.model}.${fromField.field}`, - width: '25%', - }, - { - title: 'To field', - dataIndex: 'toField', - key: 'toField', - render: (toField) => `${toField.model}.${toField.field}`, - width: '25%', - }, - { - title: 'Relation type', - dataIndex: 'type', - key: 'type', - render: (type, relation) => ( - <> - {getJoinTypeText(type)} - {relation.isAutoGenerated && ( - - (auto-generated) - - )} - - ), - width: '25%', - }, -]; - -const SelectRelationTemplate: IterableComponent = ({ - name, - index, - relations, -}) => ( - - `${name}-${record.name}-${index}`} - /> - -); - -const SelectRelationIterator = makeIterable(SelectRelationTemplate); - -export default function RecommendRelations(props: Props) { - const { recommendRelations, onBack, onNext } = props; - const [form] = Form.useForm(); - - const submit = () => { - form - .validateFields() - .then((values) => { - onNext && onNext({ selectedRecommendRelations: values }); - }) - .catch((error) => { - console.error(error); - }); - }; - - return ( - <> - - Define the relations - - - After creating your data models in step 2, you can specify how they - should be joined together by defining the relationships. We will - automatically create the relations based on the 'primary' and 'foreign' - in your data sources.{` `} - - Learn more - - - -
- - - - - - - - - - - - - ); -} diff --git a/wren-ui/src/components/pages/setup/SelectModels.tsx b/wren-ui/src/components/pages/setup/SelectModels.tsx index 5fd834880..1858800f4 100644 --- a/wren-ui/src/components/pages/setup/SelectModels.tsx +++ b/wren-ui/src/components/pages/setup/SelectModels.tsx @@ -3,20 +3,23 @@ import { Button, Col, Form, Row, Typography } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { ERROR_TEXTS } from '@/utils/error'; import MultiSelectBox from '@/components/table/MultiSelectBox'; -import { SourceTable } from '@/components/table/ModelRelationSelectionTable'; const { Title, Text } = Typography; +export interface SourceTable { + name: string; +} + interface Props { tables: SourceTable[]; - onNext: (data: { selectedModels: string[] }) => void; + onNext: (data: { selectedTables: string[] }) => void; onBack: () => void; } const columns: ColumnsType = [ { title: 'Table name', - dataIndex: 'displayName', + dataIndex: 'name', }, ]; @@ -26,14 +29,14 @@ export default function SelectModels(props: Props) { const items = tables.map((item) => ({ ...item, - value: item.displayName, + value: item.name, })); const submit = () => { form .validateFields() .then((values) => { - onNext && onNext({ selectedModels: values.models }); + onNext && onNext({ selectedTables: values.tables }); }) .catch((error) => { console.error(error); @@ -43,20 +46,21 @@ export default function SelectModels(props: Props) { return (
- Create data model from tables + Select tables to create data models - Data models are created directly from your data source tables. It act as - a “view” of your underlying table to transform and extend on the - original data.{` `} + We will create data models from selected tables. It will help AI to + better know your data. +
Learn more - + {' '} + about data models.
- - diff --git a/wren-ui/src/components/pages/setup/Starter.tsx b/wren-ui/src/components/pages/setup/Starter.tsx index df9a271e1..a8520557b 100644 --- a/wren-ui/src/components/pages/setup/Starter.tsx +++ b/wren-ui/src/components/pages/setup/Starter.tsx @@ -87,29 +87,29 @@ export default function Starter(props) { return ( <> - Connect the data source + Connect a data source - We only support BigQuery for now. You can vote for your warehouse in our{' '} + Vote for your preferred data source to be our next option on our{' '} - GitHub issues + GitHub - ! + . - +
- or play around with a template + Play around with sample data - + diff --git a/wren-ui/src/components/pages/setup/dataSources/BigQueryProperties.tsx b/wren-ui/src/components/pages/setup/dataSources/BigQueryProperties.tsx index 73e018d7b..0238898f1 100644 --- a/wren-ui/src/components/pages/setup/dataSources/BigQueryProperties.tsx +++ b/wren-ui/src/components/pages/setup/dataSources/BigQueryProperties.tsx @@ -59,7 +59,6 @@ export default function BigQueryProperties() { label="Display name" required name="displayName" - extra="The name will be called in VulcanSQL." rules={[ { required: true, @@ -83,30 +82,17 @@ export default function BigQueryProperties() { - - - - + & React.ComponentProps & React.ComponentProps & - React.ComponentProps & - React.ComponentProps & React.ComponentProps, ) => JSX.Element; maxWidth?: number; @@ -36,19 +32,12 @@ export const SETUP_STEPS = { [SETUP.CREATE_DATA_SOURCE]: { step: 0, component: ConnectDataSource, - maxWidth: 800, + maxWidth: 960, }, [SETUP.SELECT_MODELS]: { step: 1, component: SelectModels, - }, - [SETUP.CREATE_MODELS]: { - step: 1, - component: CreateModels, - }, - [SETUP.RECOMMEND_RELATIONS]: { - step: 2, - component: RecommendRelations, + maxWidth: 960, }, [SETUP.DEFINE_RELATIONS]: { step: 2, @@ -63,21 +52,15 @@ export const DATA_SOURCE_OPTIONS = { guide: '', disabled: false, }, - [DATA_SOURCES.DATA_BRICKS]: { - label: 'Databricks', - logo: '/images/dataSource/dataBricks.svg', + [DATA_SOURCES.DUCKDB]: { + label: 'DuckDB', + logo: '/images/dataSource/duckDb.svg', guide: '', disabled: true, }, - [DATA_SOURCES.SNOWFLAKE]: { - label: 'Snowflake', - logo: '/images/dataSource/snowflake.svg', - guide: '', - disabled: true, - }, - [DATA_SOURCES.TRINO]: { - label: 'Trino', - logo: '', + [DATA_SOURCES.PG_SQL]: { + label: 'PostgreSQL', + logo: '/images/dataSource/postgreSql.svg', guide: '', disabled: true, }, diff --git a/wren-ui/src/components/table/ModelRelationSelectionTable.tsx b/wren-ui/src/components/table/ModelRelationSelectionTable.tsx index ecc771881..e2f9b9553 100644 --- a/wren-ui/src/components/table/ModelRelationSelectionTable.tsx +++ b/wren-ui/src/components/table/ModelRelationSelectionTable.tsx @@ -8,30 +8,18 @@ interface ModelField { field: string; } -export interface SourceTableColumn { - name: string; - type: string; -} - -export interface SourceTable { - id: string; - sqlName: string; - displayName: string; - columns: SourceTableColumn[]; -} - export interface RelationsDataType { name: string; fromField: ModelField; isAutoGenerated: boolean; - joinType: JOIN_TYPE; + type: JOIN_TYPE; toField: ModelField; properties: Record; } interface Props { - columns: ColumnsType | ColumnsType; - dataSource: RelationsDataType[] | SourceTableColumn[]; + columns: ColumnsType; + dataSource: RelationsDataType[]; enableRowSelection?: boolean; extra?: ( onCollapseOpen: ( @@ -41,7 +29,7 @@ interface Props { ) => React.ReactNode; onChange?: (value: any | null) => void; tableTitle: string; - rowKey: (record: RelationsDataType | SourceTableColumn) => string; + rowKey: (record: RelationsDataType) => string; } export default function ModelRelationSelectionTable(props: Props) { diff --git a/wren-ui/src/hooks/useCombineFieldOptions.tsx b/wren-ui/src/hooks/useCombineFieldOptions.tsx index 5c5a37b50..5ee548bcd 100644 --- a/wren-ui/src/hooks/useCombineFieldOptions.tsx +++ b/wren-ui/src/hooks/useCombineFieldOptions.tsx @@ -19,6 +19,12 @@ export default function useCombineFieldOptions(props: Props) { name: 'orders', properties: { type: 'Orders' }, }, + { + name: 'custkey', + }, + { + name: 'id', + }, ], }, { @@ -28,6 +34,9 @@ export default function useCombineFieldOptions(props: Props) { name: 'lineitem', properties: { type: 'Lineitem' }, }, + { + name: 'orderkey', + }, ], }, { @@ -41,6 +50,23 @@ export default function useCombineFieldOptions(props: Props) { name: 'discount', properties: { type: 'REAL' }, }, + { + name: 'orderkey', + }, + ], + }, + { + name: 'trans', + columns: [ + { + name: 'custkey', + }, + { + name: 'col_a', + }, + { + name: 'col_b', + }, ], }, ].filter((item) => !(excludeModels && excludeModels.includes(item.name))); diff --git a/wren-ui/src/hooks/useSetupModels.tsx b/wren-ui/src/hooks/useSetupModels.tsx index 89f4c38b9..670bf1858 100644 --- a/wren-ui/src/hooks/useSetupModels.tsx +++ b/wren-ui/src/hooks/useSetupModels.tsx @@ -1,46 +1,29 @@ import { useState } from 'react'; import { SETUP } from '@/utils/enum'; import { useRouter } from 'next/router'; -import { SelectedSourceTables } from '@/components/pages/setup/CreateModels'; +import { SourceTable } from '@/components/pages/setup/SelectModels'; export default function useSetupModels() { - const [stepKey, setStepKey] = useState(SETUP.SELECT_MODELS); - const [selectedModels, setSelectedModels] = useState( - undefined, - ); + const [stepKey] = useState(SETUP.SELECT_MODELS); const router = useRouter(); - const submitModels = async (_models: SelectedSourceTables) => { + const submitModels = async (_tables: SourceTable[]) => { // TODO: implement submitModels API router.push('/setup/relations'); }; const onBack = () => { - if (stepKey === SETUP.CREATE_MODELS) { - setStepKey(SETUP.SELECT_MODELS); - } else { - router.push('/setup/connection'); - } + router.push('/setup/connection'); }; - const onNext = (data?: { - selectedModels: string[]; - models: SelectedSourceTables; - }) => { - if (stepKey === SETUP.SELECT_MODELS) { - setSelectedModels(data.selectedModels); - setStepKey(SETUP.CREATE_MODELS); - } - - if (stepKey === SETUP.CREATE_MODELS) { - submitModels(data.models); - } + const onNext = (data?: { selectedTables: string[] }) => { + const tables = data.selectedTables.map((table) => ({ name: table })); + submitModels(tables); }; return { stepKey, - selectedModels, tables, onBack, onNext, @@ -50,163 +33,12 @@ export default function useSetupModels() { // TODO: remove it when connecting to backend const tables = [ { - id: 'a3e9aba0-c1a7-43bb-8bae-da65256ec5a3', - sqlName: 'customer', - displayName: 'customer', - columns: [ - { - name: 'address', - type: 'VARCHAR', - }, - { - name: 'custkey', - type: 'BIGINT', - }, - { - name: 'name', - type: 'VARCHAR', - }, - { - name: 'nationkey', - type: 'BIGINT', - }, - ], + name: 'orders', }, { - id: '3f74ab82-aa22-476c-9577-273db3d1f75c', - sqlName: 'lineitem', - displayName: 'lineitem', - columns: [ - { - name: 'comment', - type: 'VARCHAR', - }, - { - name: 'commitdate', - type: 'DATE', - }, - { - name: 'discount', - type: 'DOUBLE', - }, - { - name: 'extendedprice', - type: 'DOUBLE', - }, - { - name: 'linenumber', - type: 'INTEGER', - }, - { - name: 'linestatus', - type: 'VARCHAR', - }, - { - name: 'orderkey', - type: 'BIGINT', - }, - { - name: 'partkey', - type: 'BIGINT', - }, - { - name: 'quantity', - type: 'DOUBLE', - }, - { - name: 'receiptdate', - type: 'DATE', - }, - { - name: 'returnflag', - type: 'VARCHAR', - }, - { - name: 'shipdate', - type: 'DATE', - }, - { - name: 'shipinstruct', - type: 'VARCHAR', - }, - { - name: 'shipmode', - type: 'VARCHAR', - }, - { - name: 'suppkey', - type: 'BIGINT', - }, - { - name: 'tax', - type: 'DOUBLE', - }, - ], + name: 'customers', }, { - id: 'a6339b68-0ffb-4268-8cfd-68b8206a852f', - sqlName: 'nation', - displayName: 'nation', - columns: [ - { - name: 'comment', - type: 'VARCHAR', - }, - { - name: 'name', - type: 'VARCHAR', - }, - { - name: 'nationkey', - type: 'BIGINT', - }, - { - name: 'regionkey', - type: 'BIGINT', - }, - ], - }, - { - id: '1e6b4ca6-c1ba-43de-ad5c-dcd203e5fed2', - sqlName: 'orders', - displayName: 'orders', - columns: [ - { - name: 'clerk', - type: 'VARCHAR', - }, - { - name: 'comment', - type: 'VARCHAR', - }, - { - name: 'custkey', - type: 'BIGINT', - }, - { - name: 'orderdate', - type: 'DATE', - }, - { - name: 'orderkey', - type: 'BIGINT', - }, - { - name: 'orderpriority', - type: 'VARCHAR', - }, - { - name: 'orderstatus', - type: 'VARCHAR', - }, - { - name: 'shippriority', - type: 'INTEGER', - }, - { - name: 'totalprice', - type: 'DOUBLE', - }, - ], + name: 'products', }, ]; diff --git a/wren-ui/src/hooks/useSetupRelations.tsx b/wren-ui/src/hooks/useSetupRelations.tsx index f2431bb49..e5de4218e 100644 --- a/wren-ui/src/hooks/useSetupRelations.tsx +++ b/wren-ui/src/hooks/useSetupRelations.tsx @@ -5,51 +5,44 @@ import { SelectedRecommendRelations } from '@/components/pages/setup/DefineRelat import { Path } from '@/utils/enum'; export default function useSetupRelations() { - const [stepKey, setStepKey] = useState(SETUP.RECOMMEND_RELATIONS); - const [selectedRecommendRelations, setSelectedRecommendRelations] = useState< - SelectedRecommendRelations | undefined - >(undefined); - + const [stepKey] = useState(SETUP.DEFINE_RELATIONS); const router = useRouter(); const submitReleations = async (_relations: SelectedRecommendRelations) => { // TODO: implement submitReleations API - router.push(Path.Exploration); + router.push(Path.HOME); }; const onBack = () => { - if (stepKey === SETUP.DEFINE_RELATIONS) { - setStepKey(SETUP.RECOMMEND_RELATIONS); - } else { - router.push('/setup/models'); - } + router.push('/setup/models'); }; - const onNext = (data: { - selectedRecommendRelations: SelectedRecommendRelations; - relations: SelectedRecommendRelations; - }) => { - if (stepKey === SETUP.RECOMMEND_RELATIONS) { - setSelectedRecommendRelations(data.selectedRecommendRelations); - setStepKey(SETUP.DEFINE_RELATIONS); - } - - if (stepKey === SETUP.DEFINE_RELATIONS) { - submitReleations(data.relations); - } + const onNext = (data: { relations: SelectedRecommendRelations }) => { + submitReleations(data.relations); }; + const onSkip = () => router.push(Path.HOME); + + const recommendRelations = recommendRelationsData.reduce( + (acc, currentValue) => { + const { name, relations } = currentValue; + acc[name] = relations; + return acc; + }, + {}, + ); + return { stepKey, recommendRelations, - selectedRecommendRelations, onBack, onNext, + onSkip, }; } // TODO: remove it when connecting to backend -const recommendRelations = [ +const recommendRelationsData = [ { name: 'Customer', relations: [ @@ -70,15 +63,19 @@ const recommendRelations = [ ], }, { - name: 'Order', + name: 'Orders', relations: [ { - name: 'Order_Lineitem', - fromField: { model: 'Order', field: 'orderkey' }, + name: 'Orders_Lineitem', + fromField: { model: 'Orders', field: 'orderkey' }, toField: { model: 'Lineitem', field: 'orderkey' }, type: JOIN_TYPE.ONE_TO_MANY, isAutoGenerated: true, }, ], }, + { + name: 'trans', + relations: [], + }, ]; diff --git a/wren-ui/src/pages/setup/models.tsx b/wren-ui/src/pages/setup/models.tsx index d1d659b5b..3e75d4118 100644 --- a/wren-ui/src/pages/setup/models.tsx +++ b/wren-ui/src/pages/setup/models.tsx @@ -5,19 +5,14 @@ import useSetupModels from '@/hooks/useSetupModels'; import { SETUP_STEPS } from '@/components/pages/setup/utils'; export default function SetupModels() { - const { stepKey, selectedModels, tables, onNext, onBack } = useSetupModels(); + const { stepKey, tables, onNext, onBack } = useSetupModels(); const current = useMemo(() => SETUP_STEPS[stepKey], [stepKey]); return ( - + ); diff --git a/wren-ui/src/pages/setup/relations.tsx b/wren-ui/src/pages/setup/relations.tsx index b20950507..bbf14e933 100644 --- a/wren-ui/src/pages/setup/relations.tsx +++ b/wren-ui/src/pages/setup/relations.tsx @@ -5,13 +5,8 @@ import useSetupRelations from '@/hooks/useSetupRelations'; import { SETUP_STEPS } from '@/components/pages/setup/utils'; export default function SetupRelations() { - const { - stepKey, - recommendRelations, - selectedRecommendRelations, - onNext, - onBack, - } = useSetupRelations(); + const { stepKey, recommendRelations, onNext, onBack, onSkip } = + useSetupRelations(); const current = useMemo(() => SETUP_STEPS[stepKey], [stepKey]); @@ -20,9 +15,9 @@ export default function SetupRelations() { diff --git a/wren-ui/src/styles/components/button.less b/wren-ui/src/styles/components/button.less index 83b2c633a..9854bb700 100644 --- a/wren-ui/src/styles/components/button.less +++ b/wren-ui/src/styles/components/button.less @@ -21,4 +21,8 @@ line-height: 1.2; height: auto; border: none; +} + +.adm-onboarding-btn { + width: 130px; } \ No newline at end of file diff --git a/wren-ui/src/utils/data/adapter.ts b/wren-ui/src/utils/data/adapter.ts index 658ff908a..8d414345e 100644 --- a/wren-ui/src/utils/data/adapter.ts +++ b/wren-ui/src/utils/data/adapter.ts @@ -1,9 +1,5 @@ import { Manifest } from '@/utils/data/type'; -import { - MetricData, - ModelData, - ViewData, -} from '@/utils/data/model'; +import { MetricData, ModelData, ViewData } from '@/utils/data/model'; export interface AdaptedData extends Omit { diff --git a/wren-ui/src/utils/data/dictionary.ts b/wren-ui/src/utils/data/dictionary.ts index 0f1f80c54..4ed7e0cbc 100644 --- a/wren-ui/src/utils/data/dictionary.ts +++ b/wren-ui/src/utils/data/dictionary.ts @@ -5,7 +5,7 @@ export const getJoinTypeText = (type) => [JOIN_TYPE.MANY_TO_ONE]: 'Many-to-one', [JOIN_TYPE.ONE_TO_MANY]: 'One-to-many', [JOIN_TYPE.ONE_TO_ONE]: 'One-to-one', - }[type] || 'Unknown'); + })[type] || 'Unknown'; export const getCachePeriodText = (period) => ({ @@ -13,4 +13,4 @@ export const getCachePeriodText = (period) => [CACHED_PERIOD.HOUR]: 'hour(s)', [CACHED_PERIOD.MINUTE]: 'minute(s)', [CACHED_PERIOD.SECOND]: 'second(s)', - }[period] || 'Unknown'); + })[period] || 'Unknown'; diff --git a/wren-ui/src/utils/data/model/metric.ts b/wren-ui/src/utils/data/model/metric.ts index 845bffb26..8850d0058 100644 --- a/wren-ui/src/utils/data/model/metric.ts +++ b/wren-ui/src/utils/data/model/metric.ts @@ -46,26 +46,26 @@ export class MetricData { (column) => new MetricColumnData( column as MetricColumn, - metricType as METRIC_TYPE - ) + metricType as METRIC_TYPE, + ), ), ]; }, []); this.measures = this.columns.filter( - (column) => column.metricType === METRIC_TYPE.MEASURE + (column) => column.metricType === METRIC_TYPE.MEASURE, ); this.timeGrains = this.columns.filter( - (column) => column.metricType === METRIC_TYPE.TIME_GRAIN + (column) => column.metricType === METRIC_TYPE.TIME_GRAIN, ); this.dimensions = !isCumulative ? this.columns.filter( - (column) => column.metricType === METRIC_TYPE.DIMENSION + (column) => column.metricType === METRIC_TYPE.DIMENSION, ) : undefined; this.windows = isCumulative ? this.columns.filter( - (column) => column.metricType === METRIC_TYPE.WINDOW + (column) => column.metricType === METRIC_TYPE.WINDOW, ) : undefined; } diff --git a/wren-ui/src/utils/data/model/model.ts b/wren-ui/src/utils/data/model/model.ts index b51c3433d..c58e76223 100644 --- a/wren-ui/src/utils/data/model/model.ts +++ b/wren-ui/src/utils/data/model/model.ts @@ -1,11 +1,6 @@ import { v4 as uuidv4 } from 'uuid'; import { JOIN_TYPE, NODE_TYPE } from '@/utils/enum'; -import { - Relationship, - ModelColumn, - Model, - Manifest, -} from '@/utils/data/type'; +import { Relationship, ModelColumn, Model, Manifest } from '@/utils/data/type'; export class ModelData { public readonly nodeType: NODE_TYPE = NODE_TYPE.MODEL; @@ -39,19 +34,19 @@ export class ModelData { this.refreshTime = model.refreshTime; this.relations = data.relationships .filter((relationship) => - relationship.models.includes(this.referenceName) + relationship.models.includes(this.referenceName), ) .map((relationship) => new RelationData(relationship)); this.columns = model.columns.map( - (column) => new ModelColumnData(column, model, this.relations) + (column) => new ModelColumnData(column, model, this.relations), ); this.fields = this.columns.filter( - (column) => !column.isCalculated && !column.relation + (column) => !column.isCalculated && !column.relation, ); this.relationFields = this.columns.filter((column) => column.relation); this.calculatedFields = this.columns.filter( - (column) => column.isCalculated && !column.relation + (column) => column.isCalculated && !column.relation, ); } } @@ -76,7 +71,7 @@ export class ModelColumnData { this.type = column.type; if (column?.relationship) { const relation = relations.find( - (item) => item.referenceName === column?.relationship + (item) => item.referenceName === column?.relationship, ); this.relation = relation; } diff --git a/wren-ui/src/utils/data/model/view.ts b/wren-ui/src/utils/data/model/view.ts index 0f4637ff0..bbe3ad411 100644 --- a/wren-ui/src/utils/data/model/view.ts +++ b/wren-ui/src/utils/data/model/view.ts @@ -27,7 +27,7 @@ export class ViewData { this.properties = view.properties; this.fields = (view.columns || []).map( - (column) => new ViewColumnData(column) + (column) => new ViewColumnData(column), ); } } diff --git a/wren-ui/src/utils/enum/dataSources.ts b/wren-ui/src/utils/enum/dataSources.ts index ea2da0594..bd41cd606 100644 --- a/wren-ui/src/utils/enum/dataSources.ts +++ b/wren-ui/src/utils/enum/dataSources.ts @@ -1,6 +1,5 @@ export enum DATA_SOURCES { - BIG_QUERY = 'bigQuery', - DATA_BRICKS = 'dataBricks', - SNOWFLAKE = 'snowflake', - TRINO = 'trino', + BIG_QUERY = 'BIG_QUERY', + DUCKDB = 'DUCK_DB', + PG_SQL = 'PG_SQL', } diff --git a/wren-ui/src/utils/enum/path.ts b/wren-ui/src/utils/enum/path.ts index e382732eb..095dcd0ec 100644 --- a/wren-ui/src/utils/enum/path.ts +++ b/wren-ui/src/utils/enum/path.ts @@ -1,6 +1,6 @@ export enum Path { Exploration = '/exploration', + HOME = '/home', Modeling = '/modeling', Onboarding = '/setup', - Home = '/home', } diff --git a/wren-ui/src/utils/enum/setup.ts b/wren-ui/src/utils/enum/setup.ts index c5b36d328..b1effe9bd 100644 --- a/wren-ui/src/utils/enum/setup.ts +++ b/wren-ui/src/utils/enum/setup.ts @@ -2,7 +2,6 @@ export enum SETUP { STARTER = 'starter', CREATE_DATA_SOURCE = 'createDataSource', SELECT_MODELS = 'selectModels', - CREATE_MODELS = 'createModels', RECOMMEND_RELATIONS = 'recommendRelations', DEFINE_RELATIONS = 'defineRelations', } diff --git a/wren-ui/src/utils/error/dictionary.ts b/wren-ui/src/utils/error/dictionary.ts index 14a4d3631..bc9b55687 100644 --- a/wren-ui/src/utils/error/dictionary.ts +++ b/wren-ui/src/utils/error/dictionary.ts @@ -6,11 +6,8 @@ export const ERROR_TEXTS = { PROJECT_ID: { REQUIRED: 'Please input project id.', }, - DATASET: { - REQUIRED: 'Please input dataset name.', - }, - LOCATION: { - REQUIRED: 'Please input data location.', + DATASET_ID: { + REQUIRED: 'Please input dataset ID.', }, CREDENTIAL: { REQUIRED: 'Please upload credential.', @@ -60,9 +57,6 @@ export const ERROR_TEXTS = { }, }, ADD_RELATION: { - NAME: { - REQUIRED: 'Please input name.', - }, FROM_FIELD: { REQUIRED: 'Please select a field.', }, @@ -112,9 +106,6 @@ export const ERROR_TEXTS = { TABLE: { REQUIRED: 'Please select at least one table.', }, - FIELDS: { - REQUIRED: 'Please select at least one field.', - }, }, SAVE_AS_VIEW: { DISPLAY_NAME: {