diff --git a/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx b/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx index aa0f42c..8b4a0e0 100644 --- a/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx +++ b/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx @@ -20,7 +20,7 @@ export const QueryTab = () => { }); return ( -
+
diff --git a/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx b/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx index 03b87a4..1eb685a 100644 --- a/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx +++ b/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx @@ -1,15 +1,6 @@ -import { - createCodeMirror, - createEditorControlledValue, - createEditorFocus, -} from 'solid-codemirror'; -import { createEffect, createSignal, Show } from 'solid-js'; -import { - EditorView, - drawSelection, - highlightWhitespace, - highlightActiveLine, -} from '@codemirror/view'; +import { createCodeMirror, createEditorControlledValue, createEditorFocus } from 'solid-codemirror'; +import { createEffect, createSignal } from 'solid-js'; +import { EditorView, drawSelection, highlightWhitespace, highlightActiveLine } from '@codemirror/view'; import { MySQL, sql, SQLite, PostgreSQL } from '@codemirror/lang-sql'; import { dracula } from '@uiw/codemirror-theme-dracula'; import { vim } from '@replit/codemirror-vim'; @@ -19,12 +10,12 @@ import { Copy, EditIcon, FireIcon, VimIcon } from 'components/UI/Icons'; import { useAppSelector } from 'services/Context'; import { QueryTaskEnqueueResult, Dialect } from 'interfaces'; import { t } from 'utils/i18n'; -import { Alert } from 'components/UI'; import { basicSetup } from 'codemirror'; import { createShortcut } from '@solid-primitives/keyboard'; import { search } from '@codemirror/search'; import { createStore } from 'solid-js/store'; import { ActionRowButton } from './components/ActionRowButton'; +import { debounce } from 'utils/utils'; const SQLDialects = { [Dialect.Mysql]: MySQL, @@ -37,7 +28,6 @@ export const QueryTextArea = () => { connections: { updateContentTab, getConnection, - getContent, getContentData, getSchemaTables, contentStore: { idx: tabIdx }, @@ -49,12 +39,21 @@ export const QueryTextArea = () => { const [loading, setLoading] = createSignal(false); const [autoLimit, setAutoLimit] = createSignal(true); - const updateQueryText = async (query: string) => { - updateContentTab('data', { query }); + const updateCursor = debounce(() => { + updateContentTab('data', { query: code() }); + }, 300); + + const updateQueryText = (query: string) => { + setCode(query); + if (focused()) { + updateContentTab('data', { cursor: editorView().state.selection.ranges[0].from }); + } + updateCursor(); }; const { ref, editorView, createExtension } = createCodeMirror({ - onValueChange: setCode, + value: code(), + onValueChange: updateQueryText, }); createEditorControlledValue(editorView, code); createExtension(drawSelection); @@ -64,10 +63,8 @@ export const QueryTextArea = () => { createExtension(search); createExtension(() => basicSetup); createExtension(() => (vimModeOn() ? vim() : [])); - createExtension(() => - sql({ dialect: SQLDialects[getConnection().connection.dialect], schema }) - ); - const { setFocused } = createEditorFocus(editorView); + createExtension(() => sql({ dialect: SQLDialects[getConnection().connection.dialect], schema })); + const { setFocused, focused } = createEditorFocus(editorView); // TODO: add option to scroll inside autocompletion list with c-l and c-k // defaultKeymap.push({ keys: "gq", type: "operator", operator: "hardWrap" }); // Vim.defineOperator( @@ -100,17 +97,15 @@ export const QueryTextArea = () => { updateContentTab('error', undefined); const activeConnection = getConnection(); try { - const { result_sets } = await invoke( - 'enqueue_query', - { - connId: activeConnection.id, - sql: selectedText || code(), - autoLimit: autoLimit(), - tabIdx, - } - ); + const { result_sets } = await invoke('enqueue_query', { + connId: activeConnection.id, + sql: selectedText || code(), + autoLimit: autoLimit(), + tabIdx, + }); updateContentTab('data', { query: code(), + cursor: editorView().state.selection.ranges[0].from, result_sets: result_sets.map((id) => ({ id, })), @@ -143,24 +138,18 @@ export const QueryTextArea = () => { createShortcut(['Control', 'l'], () => setFocused(true)); createShortcut(['Control', 'Shift', 'F'], onFormat); - const onTestClick = () => { - console.log(getContentData('Query')); - } + // const onTestClick = () => { + // console.log(editorView()); + // }; return ( -
+
- } - /> - } - /> + {/* + } /> + */} + } /> { icon={} /> - } - /> + } /> -
+
-
+
@@ -213,9 +190,6 @@ export const QueryTextArea = () => {
- - {getContent().error} -
diff --git a/src/components/Screens/Console/Content/QueryTab/ResultesTable.tsx b/src/components/Screens/Console/Content/QueryTab/ResultesTable.tsx index 8b42f0a..9f0397f 100644 --- a/src/components/Screens/Console/Content/QueryTab/ResultesTable.tsx +++ b/src/components/Screens/Console/Content/QueryTab/ResultesTable.tsx @@ -48,17 +48,21 @@ export const ResultsTable = () => { const [rows, setRows] = createSignal([]); const [page, setPage] = createSignal(0); + const [loading, setLoading] = createSignal(false); const updateRows = async () => { - const result_set = getContentData('Query').result_sets[queryIdx()]; - // console.log(getContentData('Query').result_sets) - // console.log({ result_set }); - if (result_set?.status !== 'Completed') { - setRows([]); - return; + try { + setLoading(true); + const result_set = getContentData('Query').result_sets[queryIdx()]; + if (result_set?.status !== 'Completed') { + setRows([]); + return; + } + const _rows = await getQueryResults(result_set.path!, page()); + setRows(_rows); + } finally { + setLoading(false); } - const _rows = await getQueryResults(result_set.path!, page()); - setRows(_rows); }; createEffect( @@ -107,7 +111,7 @@ export const ResultsTable = () => { }, }, { - label: 'Copy row to clipboard', + label: 'Copy row to clipboard as json', action: function(_e, row) { // @ts-ignore navigator.clipboard.writeText(JSON.stringify(row._row.data)); @@ -154,7 +158,7 @@ export const ResultsTable = () => { - +
); diff --git a/src/components/Screens/Console/Content/QueryTab/components/Pagination.tsx b/src/components/Screens/Console/Content/QueryTab/components/Pagination.tsx index 459a48e..e5899fd 100644 --- a/src/components/Screens/Console/Content/QueryTab/components/Pagination.tsx +++ b/src/components/Screens/Console/Content/QueryTab/components/Pagination.tsx @@ -3,20 +3,24 @@ import { useAppSelector } from 'services/Context'; import { createShortcut } from '@solid-primitives/keyboard'; import { ChevronLeft, ChevronRight } from 'components/UI/Icons'; import { t } from 'utils/i18n'; -import { Accessor, createEffect, Show } from 'solid-js'; +import { Accessor, createEffect, For, Match, Show, Switch } from 'solid-js'; import { createStore } from 'solid-js/store'; import { ResultSet } from 'interfaces'; type PaginationProps = { page: Accessor; + loading: Accessor; + setPage: (n: number) => void; onPrevPage: () => void; onNextPage: () => void; }; +const PAGE_SIZE_OPTIONS = [10, 25, 50, 100]; + export const Pagination = (props: PaginationProps) => { const { connections: { selectNextQuery, selectPrevQuery, queryIdx, getContentData }, - backend: { pageSize }, + backend: { pageSize, setPageSize }, } = useAppSelector(); createShortcut(['Control', 'Shift', 'N'], selectNextQuery); @@ -35,55 +39,74 @@ export const Pagination = (props: PaginationProps) => {
- +
+ +
- +
+ +
- - {resultSet?.status === 'Completed' && resultSet?.info} - + {resultSet?.status === 'Completed' && resultSet?.info} - - {resultSet?.status === 'Error' && resultSet?.error} - + {resultSet?.status === 'Error' && resultSet?.error}
-
- - - +
+ + +
+ +
diff --git a/src/components/Screens/Console/Sidebar/Sidebar.tsx b/src/components/Screens/Console/Sidebar/Sidebar.tsx index 5551878..b6ac34f 100644 --- a/src/components/Screens/Console/Sidebar/Sidebar.tsx +++ b/src/components/Screens/Console/Sidebar/Sidebar.tsx @@ -1,22 +1,25 @@ -import { TableColumnsCollapse } from "./TableColumnsCollapse"; -import { useAppSelector } from "services/Context"; -import { createEffect, createSignal, For, Match, Switch } from "solid-js"; -import { createStore } from "solid-js/store"; -import { t } from "utils/i18n"; -import { Refresh } from "components/UI/Icons"; -import { invoke } from "@tauri-apps/api"; -import { RawQueryResult, Table } from "interfaces"; -import { columnsToSchema } from "utils/utils"; +import { TableColumnsCollapse } from './TableColumnsCollapse'; +import { useAppSelector } from 'services/Context'; +import { createEffect, createSignal, For, Match, Switch } from 'solid-js'; +import { createStore } from 'solid-js/store'; +import { t } from 'utils/i18n'; +import { Refresh, Terminal } from 'components/UI/Icons'; +import { invoke } from '@tauri-apps/api'; +import { RawQueryResult, ResultSet, Table } from 'interfaces'; +import { columnsToSchema } from 'utils/utils'; +import { newContentTab } from 'services/Connections'; export const Sidebar = () => { const { messages: { notify }, connections: { + insertColumnName, getConnection, updateConnectionTab, connectionStore, setConnectionStore, getSchemaTables, + addContentTab, }, } = useAppSelector(); const [tables, setTables] = createStore([]); @@ -29,7 +32,7 @@ export const Sidebar = () => { }); const select = (schema: string) => { - setConnectionStore("schema", schema); + setConnectionStore('schema', schema); setTables(getSchemaTables(schema)); }; @@ -37,25 +40,40 @@ export const Sidebar = () => { const config = getConnection().connection; try { setLoading(true); - await invoke("init_connection", { config }); - const { result } = await invoke("get_columns", { + await invoke('init_connection', { config }); + const { result } = await invoke('get_columns', { connId: config.id, }); const schema = columnsToSchema(result, config.dialect); - updateConnectionTab("schema", schema); + updateConnectionTab('schema', schema); - const procedures = await invoke("get_procedures", { + const procedures = await invoke('get_procedures', { connId: getConnection().id, }); // TODO: add procedures to siderbar console.log({ procedures }); } catch (error) { - notify(String(error), "info"); + notify(String(error), 'info'); } finally { setLoading(false); } }; + const showProcessList = async () => { + try { + const query = 'SHOW PROCESSLIST'; + const res = await invoke('execute_query', { + connId: getConnection().id, + query, + autoLimit: false, + }); + const data = { query, result_sets: [res], cursor: 0 }; + addContentTab(newContentTab('Process list', 'Query', data)); + } catch (error) { + notify(error); + } + }; + return (
@@ -63,8 +81,7 @@ export const Sidebar = () => { id="schema" value={connectionStore.schema} onChange={(e) => select(e.currentTarget.value)} - class="select select-accent select-bordered select-xs w-full" - > + class="select select-accent select-bordered select-xs w-full"> {(_schema) => ( - +
+ +
+
+ +
-
- {t('sidebar.tables')} -
+
{t('sidebar.tables')}
{(table) => (
{(column) => ( -
- - {column.name} - - - {column.props.COLUMN_TYPE} - -
+ )}
diff --git a/src/components/Screens/Console/Sidebar/TableColumnsCollapse.tsx b/src/components/Screens/Console/Sidebar/TableColumnsCollapse.tsx index b7833a3..799d81a 100644 --- a/src/components/Screens/Console/Sidebar/TableColumnsCollapse.tsx +++ b/src/components/Screens/Console/Sidebar/TableColumnsCollapse.tsx @@ -48,7 +48,7 @@ export const TableColumnsCollapse = (props: { query, autoLimit: true, }); - const data = { query, result_sets: [res] }; + const data = { query, cursor: 0, result_sets: [res] }; addContentTab(newContentTab(table, 'Query', data)); } catch (error) { notify(error); diff --git a/src/components/Screens/Main.tsx b/src/components/Screens/Main.tsx index 88fb14b..92b3e11 100644 --- a/src/components/Screens/Main.tsx +++ b/src/components/Screens/Main.tsx @@ -1,18 +1,16 @@ -import { Alerts } from "components/UI"; -import { CloseIcon, HomeIcon, QuestionMark } from "components/UI/Icons"; -import { useAppSelector } from "services/Context"; -import { createSignal, For, Match, Show, Switch } from "solid-js"; -import { Console } from "./Console/Console"; -import { Home } from "./Home/Home"; -import { Settings } from "./Settings/Settings"; +import { Alerts } from 'components/UI'; +import { ThemeSwitch } from 'components/UI/ThemeSwitch'; +import { CloseIcon, HomeIcon, QuestionMark } from 'components/UI/Icons'; +import { useAppSelector } from 'services/Context'; +import { createSignal, For, Match, Show, Switch } from 'solid-js'; +import { Console } from './Console/Console'; +import { Home } from './Home/Home'; +import { Settings } from './Settings/Settings'; +import { t } from 'utils/i18n'; export const Main = () => { const { - connections: { - removeConnectionTab, - connectionStore, - setConnectionStore, - }, + connections: { removeConnectionTab, connectionStore, setConnectionStore }, } = useAppSelector(); const [showSettings, setShowSettings] = createSignal(false); @@ -24,12 +22,11 @@ export const Main = () => { - @@ -63,13 +55,13 @@ export const Main = () => { )}
-
- +
diff --git a/src/components/Screens/Settings/Settings.tsx b/src/components/Screens/Settings/Settings.tsx index 30847e7..06bb6b1 100644 --- a/src/components/Screens/Settings/Settings.tsx +++ b/src/components/Screens/Settings/Settings.tsx @@ -1,4 +1,3 @@ -import { ThemeSwitch } from "components/UI/ThemeSwitch"; import { useAppSelector } from "services/Context"; export const Settings = () => { @@ -10,7 +9,6 @@ export const Settings = () => {

Settings

-