Skip to content
Merged
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ If you prefer to learn by example, you can refer to this Trino [issue](https://g
- Implement the data source form template in this file

3. Set up the data source template:
- Navigate to `wren-ui/src/components/pages/setup/utils` > `DATA_SOURCE_FORM`
- Navigate to `wren-ui/src/utils/dataSourceType.ts`
- Add new data source image, name, properties
- Update the necessary files to include the new data source template settings

4. Update the data source list:
Expand Down
11 changes: 11 additions & 0 deletions wren-ui/src/apollo/client/graphql/__types__.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type Scalars = {
Boolean: boolean;
Int: number;
Float: number;
DialectSQL: any;
JSON: any;
};

Expand Down Expand Up @@ -551,6 +552,10 @@ export type ModelInfo = {
sourceTableName: Scalars['String'];
};

export type ModelSubstituteInput = {
sql: Scalars['DialectSQL'];
};

export type ModelSyncResponse = {
__typename?: 'ModelSyncResponse';
status: SyncStatus;
Expand Down Expand Up @@ -592,6 +597,7 @@ export type Mutation = {
generateThreadResponseAnswer: ThreadResponse;
generateThreadResponseBreakdown: ThreadResponse;
generateThreadResponseChart: ThreadResponse;
modelSubstitute: Scalars['String'];
previewBreakdownData: Scalars['JSON'];
previewData: Scalars['JSON'];
previewItemSQL: Scalars['JSON'];
Expand Down Expand Up @@ -773,6 +779,11 @@ export type MutationGenerateThreadResponseChartArgs = {
};


export type MutationModelSubstituteArgs = {
data: ModelSubstituteInput;
};


export type MutationPreviewBreakdownDataArgs = {
where: PreviewDataInput;
};
Expand Down
40 changes: 39 additions & 1 deletion wren-ui/src/apollo/client/graphql/sql.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export type GenerateQuestionMutationVariables = Types.Exact<{

export type GenerateQuestionMutation = { __typename?: 'Mutation', generateQuestion: string };

export type ModelSubstituteMutationVariables = Types.Exact<{
data: Types.ModelSubstituteInput;
}>;


export type ModelSubstituteMutation = { __typename?: 'Mutation', modelSubstitute: string };


export const PreviewSqlDocument = gql`
mutation PreviewSQL($data: PreviewSQLDataInput!) {
Expand Down Expand Up @@ -79,4 +86,35 @@ export function useGenerateQuestionMutation(baseOptions?: Apollo.MutationHookOpt
}
export type GenerateQuestionMutationHookResult = ReturnType<typeof useGenerateQuestionMutation>;
export type GenerateQuestionMutationResult = Apollo.MutationResult<GenerateQuestionMutation>;
export type GenerateQuestionMutationOptions = Apollo.BaseMutationOptions<GenerateQuestionMutation, GenerateQuestionMutationVariables>;
export type GenerateQuestionMutationOptions = Apollo.BaseMutationOptions<GenerateQuestionMutation, GenerateQuestionMutationVariables>;
export const ModelSubstituteDocument = gql`
mutation ModelSubstitute($data: ModelSubstituteInput!) {
modelSubstitute(data: $data)
}
`;
export type ModelSubstituteMutationFn = Apollo.MutationFunction<ModelSubstituteMutation, ModelSubstituteMutationVariables>;

/**
* __useModelSubstituteMutation__
*
* To run a mutation, you first call `useModelSubstituteMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useModelSubstituteMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [modelSubstituteMutation, { data, loading, error }] = useModelSubstituteMutation({
* variables: {
* data: // value for 'data'
* },
* });
*/
export function useModelSubstituteMutation(baseOptions?: Apollo.MutationHookOptions<ModelSubstituteMutation, ModelSubstituteMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<ModelSubstituteMutation, ModelSubstituteMutationVariables>(ModelSubstituteDocument, options);
}
export type ModelSubstituteMutationHookResult = ReturnType<typeof useModelSubstituteMutation>;
export type ModelSubstituteMutationResult = Apollo.MutationResult<ModelSubstituteMutation>;
export type ModelSubstituteMutationOptions = Apollo.BaseMutationOptions<ModelSubstituteMutation, ModelSubstituteMutationVariables>;
6 changes: 6 additions & 0 deletions wren-ui/src/apollo/client/graphql/sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ export const GENERATE_QUESTION = gql`
generateQuestion(data: $data)
}
`;

export const MODEL_SUBSTITUDE = gql`
mutation ModelSubstitute($data: ModelSubstituteInput!) {
modelSubstitute(data: $data)
}
`;
2 changes: 1 addition & 1 deletion wren-ui/src/components/editor/MarkdownEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useState, useContext, useRef } from 'react';
import ReadOutlined from '@ant-design/icons/ReadOutlined';
import EditOutlined from '@ant-design/icons/EditOutlined';
import { nextTick } from '@/utils/time';
import { Mention } from '@/hooks/useMentions';
import { Mention } from '@/hooks/useAutoComplete';
import { FormItemInputContext } from 'antd/lib/form/context';
import MarkdownBlock from './MarkdownBlock';

Expand Down
129 changes: 111 additions & 18 deletions wren-ui/src/components/editor/SQLEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,130 @@
import { useState } from 'react';
import clsx from 'clsx';
import { useState, useContext, useRef, useEffect } from 'react';
import styled from 'styled-components';
import AceEditor from '@/components/editor/AceEditor';
import { FormItemInputContext } from 'antd/lib/form/context';
import useAutoComplete from '@/hooks/useAutoComplete';

const Wrapper = styled.div`
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);

&:hover {
border-color: var(--geekblue-5) !important;
}

&.adm-markdown-editor-error {
border-color: var(--red-5) !important;

.adm-markdown-editor-length {
color: var(--red-5) !important;
}
}
&:not(.adm-markdown-editor-error).adm-markdown-editor-focused {
border-color: var(--geekblue-5) !important;
box-shadow: 0 0 0 2px rgba(47, 84, 235, 0.2);
}

&.adm-markdown-editor-focused.adm-markdown-editor-error {
borer-color: var(--red-4) !important;
box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.2);
}
`;

const Toolbar = styled.div`
color: var(--gray-8);
background-color: var(--gray-3);
border-bottom: 1px solid var(--gray-5);
height: 32px;
padding: 4px 8px;
border-radius: 4px 4px 0px 0px;
`;

interface Props {
value?: string;
onChange?: (value: string) => void;
autoFocus?: boolean;
autoComplete?: boolean;
toolbar?: React.ReactNode;
}

const getLangTools = () => {
const { ace } = window as any;
return ace ? ace.require('ace/ext/language_tools') : null;
};

export default function SQLEditor(props: Props) {
const { value, onChange, autoFocus } = props;
const { value, onChange, autoFocus, autoComplete, toolbar } = props;
const $wrapper = useRef<HTMLDivElement>(null);
const [focused, setFocused] = useState<boolean>(false);

const formItemContext = useContext(FormItemInputContext);
const { status } = formItemContext;

const completers = useAutoComplete({
includeColumns: true,
skip: !autoComplete,
});

const resetCompleters = () => {
// clear custom completer
const langTools = getLangTools();
langTools?.setCompleters([
langTools.keyWordCompleter,
langTools.snippetCompleter,
langTools.textCompleter,
]);
};

useEffect(() => {
resetCompleters();
if (!autoComplete || completers.length === 0) return;

const langTools = getLangTools();
const customCompleter = {
getCompletions: (_editor, _session, _pos, _prefix, callback) => {
callback(null, completers);
},
};
langTools?.addCompleter(customCompleter);

return () => resetCompleters();
}, [focused, autoComplete, completers]);

const [sql, setSql] = useState(value || '');

const change = (sql) => {
setSql(sql);
onChange && onChange(sql);
onChange?.(sql);
};

return (
<AceEditor
mode="sql"
width="100%"
height="300px"
fontSize={14}
theme="tomorrow"
value={value || sql}
onChange={change}
name="sql_editor"
editorProps={{ $blockScrolling: true }}
enableLiveAutocompletion
enableBasicAutocompletion
showPrintMargin={false}
focus={autoFocus}
/>
<Wrapper
ref={$wrapper}
className={clsx(
'border border-gray-5 rounded overflow-hidden',
status ? `adm-markdown-editor-${status}` : '',
focused ? 'adm-markdown-editor-focused' : '',
)}
tabIndex={-1}
>
{!!toolbar && <Toolbar>{toolbar}</Toolbar>}
<AceEditor
mode="sql"
width="100%"
height="300px"
fontSize={14}
theme="tomorrow"
value={value || sql}
onChange={change}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
name="sql_editor"
editorProps={{ $blockScrolling: true }}
enableLiveAutocompletion
enableBasicAutocompletion
showPrintMargin={false}
focus={autoFocus}
/>
</Wrapper>
);
}
8 changes: 6 additions & 2 deletions wren-ui/src/components/modals/AdjustReasoningStepsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled from 'styled-components';
import { Form, Modal, Select, Tag } from 'antd';
import QuestionCircleOutlined from '@ant-design/icons/QuestionCircleOutlined';
import { ERROR_TEXTS } from '@/utils/error';
import useMentions from '@/hooks/useMentions';
import useAutoComplete, { convertMention } from '@/hooks/useAutoComplete';
import { ModalAction } from '@/hooks/useModalAction';
import MarkdownEditor from '@/components/editor/MarkdownEditor';
import { useListModelsQuery } from '@/apollo/client/graphql/model.generated';
Expand Down Expand Up @@ -36,7 +36,11 @@ export default function AdjustReasoningStepsModal(props: Props) {
const { visible, defaultValue, loading, onSubmit, onClose } = props;
const [form] = Form.useForm();

const { mentions } = useMentions({ includeColumns: true, skip: !visible });
const mentions = useAutoComplete({
convertor: convertMention,
includeColumns: true,
skip: !visible,
});
const listModelsResult = useListModelsQuery({ skip: !visible });
const modelNameMap = keyBy(
listModelsResult.data?.listModels,
Expand Down
2 changes: 1 addition & 1 deletion wren-ui/src/components/modals/AdjustSQLModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export default function AdjustSQLModal(props: Props) {
},
]}
>
<SQLEditor autoFocus />
<SQLEditor autoComplete autoFocus />
</Form.Item>
</Form>
<div className="my-3">
Expand Down
2 changes: 1 addition & 1 deletion wren-ui/src/components/modals/FixSQLModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function FixSQLModal(props: Props) {
},
]}
>
<SQLEditor autoFocus />
<SQLEditor autoComplete autoFocus />
</Form.Item>
</Form>
<div className="my-3">
Expand Down
Loading