Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: support oceanbase monaco plugin #1386

Merged
merged 2 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions web/components/chat/db-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChangeEvent, Key, useEffect, useMemo, useState } from 'react';
import React, { ChangeEvent, Key, useEffect, useMemo, useState } from 'react';
import { useRequest } from 'ahooks';
import { Button, Select, Table, Tooltip } from 'antd';
import { Input, Tree } from 'antd';
import Icon from '@ant-design/icons';
import type { DataNode } from 'antd/es/tree';
import MonacoEditor from './monaco-editor';
import MonacoEditor, { ISession } from './monaco-editor';
import { sendGetRequest, sendSpacePostRequest } from '@/utils/request';
import { useSearchParams } from 'next/navigation';
import { OnChange } from '@monaco-editor/react';
Expand Down Expand Up @@ -45,6 +45,7 @@ interface IProps {
chartData?: any;
tableData?: ITableData;
layout?: 'TB' | 'LR';
tables?: any;
handleChange: OnChange;
}

Expand All @@ -58,7 +59,7 @@ interface ITableTreeItem {
children: Array<ITableTreeItem>;
}

function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, handleChange }: IProps) {
function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, tables, handleChange }: IProps) {
const chartWrapper = useMemo(() => {
if (!chartData) return null;

Expand Down Expand Up @@ -86,9 +87,36 @@ function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, han
return {
columns: tbCols,
dataSource: tbDatas,

};
}, [tableData]);

const session: ISession = useMemo(() => {
const map: Record<string, { columnName: string; columnType: string; }[]> = {};
const db = tables?.data;
const tableList = db?.children;
tableList?.forEach((table: ITableTreeItem) => {
map[table.title] = table.children.map((column: ITableTreeItem) => {
return {
columnName: column.title,
columnType: column.type,
};
})
});
return {
async getTableList(schemaName) {
if (schemaName && schemaName!== db?.title) {
return [];
}
return tableList?.map((table: ITableTreeItem) => table.title) || [];
},
async getTableColumns(tableName) {
return map[tableName] || [];
},
async getSchemaList() {
return db?.title ? [db?.title] : [];
}
};
}, [tables])
return (
<div
className={classNames('flex w-full flex-1 h-full gap-2 overflow-hidden', {
Expand All @@ -97,7 +125,7 @@ function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, han
})}
>
<div className="flex-1 flex overflow-hidden rounded">
<MonacoEditor value={editorValue?.sql || ''} language="mysql" onChange={handleChange} thoughts={editorValue?.thoughts || ''} />
<MonacoEditor value={editorValue?.sql || ''} language="mysql" onChange={handleChange} thoughts={editorValue?.thoughts || ''} session={session} />
</div>
<div className="flex-1 h-full overflow-auto bg-white dark:bg-theme-dark-container rounded p-4">
{!!tableData?.values.length ? (
Expand Down Expand Up @@ -626,6 +654,7 @@ function DbEditor() {
}}
tableData={tableData}
chartData={undefined}
tables={tables}
/>
)}
</div>
Expand Down
49 changes: 41 additions & 8 deletions web/components/chat/monaco-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
import * as monaco from 'monaco-editor';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
import Editor, { OnChange, loader } from '@monaco-editor/react';
import classNames from 'classnames';
import { useContext, useMemo } from 'react';
import { format } from 'sql-formatter';
import { ChatContext } from '@/app/chat-context';
import { formatSql } from '@/utils';
import { getModelService } from './ob-editor/service';
import { useLatest } from 'ahooks';
import { ChatContext } from '@/app/chat-context';
import { github, githubDark } from './ob-editor/theme';
import { register } from './ob-editor/ob-plugin';

loader.config({ monaco });

export interface ISession {
getTableList: (schemaName?: string) => Promise<string[]>;
getTableColumns: (tableName: string) => Promise<{ columnName: string; columnType: string }[]>;
getSchemaList: () => Promise<string[]>;
}

interface MonacoEditorProps {
className?: string;
value: string;
language: string;
onChange?: OnChange;
thoughts?: string;
session?: ISession;

}

export default function MonacoEditor({ className, value, language = 'mysql', onChange, thoughts }: MonacoEditorProps) {
// merge value and thoughts
const { mode } = useContext(ChatContext);
let plugin = null;
monaco.editor.defineTheme('github', github as any);
monaco.editor.defineTheme('githubDark', githubDark as any);

export default function MonacoEditor({ className, value, language = 'mysql', onChange, thoughts, session }: MonacoEditorProps) {
// merge value and thoughts
const editorValue = useMemo(() => {
if (language !== 'mysql') {
return value;
Expand All @@ -30,14 +43,34 @@ export default function MonacoEditor({ className, value, language = 'mysql', onC
return formatSql(value);
}, [value, thoughts]);

const sessionRef = useLatest(session);

const context = useContext(ChatContext);

async function pluginRegister(editor: monaco.editor.IStandaloneCodeEditor) {
const plugin = await register()
plugin.setModelOptions(
editor.getModel()?.id || '',
getModelService({
modelId: editor.getModel()?.id || '',
delimiter: ';',
}, () => sessionRef.current || null)
)
}


return (
<Editor
className={classNames(className)}
onMount={pluginRegister}
value={editorValue}
language={language}
defaultLanguage={language}
onChange={onChange}
theme={mode === 'dark' ? 'vs-dark' : 'light'}
theme={context?.mode !== "dark" ? "github" : "githubDark"}
options={{
minimap: {
enabled: false,
},
wordWrap: 'on',
}}
/>
Expand Down
31 changes: 31 additions & 0 deletions web/components/chat/ob-editor/ob-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import type Plugin from '@oceanbase-odc/monaco-plugin-ob';

let plugin: Plugin;

export async function register(): Promise<Plugin> {
window.obMonaco = {
getWorkerUrl: (type: string) => {
switch (type) {
case 'mysql': {
return location.origin + '/_next/static/ob-workers/mysql.js'
}
case 'obmysql': {
return location.origin + '/_next/static/ob-workers/obmysql.js'
}
case 'oboracle': {
return location.origin + '/_next/static/ob-workers/oracle.js'
}
}
return "";
}
}
const module = await import('@oceanbase-odc/monaco-plugin-ob')
const Plugin = module.default;
if (plugin) {
return plugin;
}
plugin = new Plugin();
plugin.setup(["mysql"]);
return plugin;
}
21 changes: 21 additions & 0 deletions web/components/chat/ob-editor/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { IModelOptions } from '@oceanbase-odc/monaco-plugin-ob/dist/type';
import { ISession } from '../monaco-editor';


export function getModelService(
{ modelId, delimiter }: { modelId: string; delimiter: string },
session?: () => ISession | null
): IModelOptions {
return {
delimiter,
async getTableList(schemaName?: string) {
return session?.()?.getTableList(schemaName) || []
},
async getTableColumns(tableName: string, dbName?: string) {
return session?.()?.getTableColumns(tableName) || []
},
async getSchemaList() {
return session?.()?.getSchemaList() || []
},
};
}
Loading
Loading