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={}
/>
- }
- />
+ } />
-
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}
-
-
+ insertColumnName(column.name)}
+ class="flex btn-ghost w-full justify-between items-center w-full border-b-2 border-base-300">
+ {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 = () => {
{
setShowSettings(false);
- setConnectionStore("idx", 0);
+ setConnectionStore('idx', 0);
}}
class="tab tab-md"
tabIndex={0}
- classList={{ "tab-active": connectionStore.idx === 0 }}
- >
+ classList={{ 'tab-active': connectionStore.idx === 0 }}>
@@ -40,22 +37,17 @@ export const Main = () => {
{
setShowSettings(false);
- setConnectionStore("idx", idx() + 1);
+ setConnectionStore('idx', idx() + 1);
}}
class="tab tab-md pt-1"
classList={{
- "tab-active": connectionStore.idx === idx() + 1,
+ 'tab-active': connectionStore.idx === idx() + 1,
}}
- tabindex={0}
- >
+ tabindex={0}>
{tab.label}
- removeConnectionTab(tab.id!)}
- class="ml-2"
- >
+ removeConnectionTab(tab.id!)} class="ml-2">
@@ -63,13 +55,13 @@ export const Main = () => {
)}
-
-
setShowSettings((s) => !s)}
- >
+
+
+
+ setShowSettings((s) => !s)}>
+
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
-
await clearStore()}
diff --git a/src/components/UI/Alert.tsx b/src/components/UI/Alert.tsx
index 74ae721..76891a7 100644
--- a/src/components/UI/Alert.tsx
+++ b/src/components/UI/Alert.tsx
@@ -12,7 +12,7 @@ export type AlertTypes = keyof typeof AlertColors;
const Alert = (props: { children: JSX.Element; color: AlertTypes }) => {
return (
diff --git a/src/components/UI/Icons/Terminal.tsx b/src/components/UI/Icons/Terminal.tsx
new file mode 100644
index 0000000..a21952e
--- /dev/null
+++ b/src/components/UI/Icons/Terminal.tsx
@@ -0,0 +1,18 @@
+export const Terminal = () => {
+ return (
+
+ );
+};
diff --git a/src/components/UI/Icons/index.ts b/src/components/UI/Icons/index.ts
index 7335d5a..a3fd230 100644
--- a/src/components/UI/Icons/index.ts
+++ b/src/components/UI/Icons/index.ts
@@ -9,5 +9,6 @@ export * from "./Home";
export * from "./Pen";
export * from "./QuestionMark";
export * from "./Refresh";
+export * from "./Terminal";
export * from "./ThreeDots";
export * from "./Vim";
diff --git a/src/components/UI/ThemeSwitch.tsx b/src/components/UI/ThemeSwitch.tsx
index 7cfbee6..5114627 100644
--- a/src/components/UI/ThemeSwitch.tsx
+++ b/src/components/UI/ThemeSwitch.tsx
@@ -21,13 +21,13 @@ export const ThemeSwitch = () => {
};
return (
-
+
diff --git a/src/services/Backend.ts b/src/services/Backend.ts
index 9e26935..d5d7b1c 100644
--- a/src/services/Backend.ts
+++ b/src/services/Backend.ts
@@ -3,7 +3,7 @@ import { QueryMetadataResult, Row } from 'interfaces';
import { createSignal } from 'solid-js';
export const BackendService = () => {
- const [pageSize, setPageSize] = createSignal(20);
+ const [pageSize, setPageSize] = createSignal(25);
const getQueryResults = async (
path: string,
@@ -14,6 +14,11 @@ export const BackendService = () => {
params: { path, page, page_size },
});
const rows = JSON.parse('[' + res + ']') as unknown as Row[];
+ if (rows.length < page_size) {
+ // pad the results with empty rows
+ const empty_rows = Array(page_size - rows.length).fill({});
+ rows.push(...empty_rows);
+ }
return rows;
};
diff --git a/src/services/Connections.ts b/src/services/Connections.ts
index 8e3bf2e..84bf508 100644
--- a/src/services/Connections.ts
+++ b/src/services/Connections.ts
@@ -55,6 +55,7 @@ export const newContentTab = (label: string, key
export type QueryContentTabData = {
query: string;
+ cursor: number;
result_sets: ResultSet[];
};
@@ -247,14 +248,18 @@ export const ConnectionsService = () => {
const updateContentTab = (key: T, data: ContentTab[T], idx?: number) => {
const tab = getContent();
- console.log('updateContentTab ', data)
if (!tab) return;
setContentStore('tabs', idx ?? contentStore.idx, key, data);
updateStore();
};
+ const insertColumnName = (column: string) => {
+ const { query, cursor } = getContentData('Query');
+ const _query = query.slice(0, cursor) + column + ', ' + query.slice(cursor);
+ setContentStore('tabs', contentStore.idx, 'data', { query: _query, cursor: cursor + column.length + 2 }); // 2 for ', '
+ };
+
const updateResultSet = (tab_idx: number, query_idx: number, data: Partial) => {
- console.log({ query_idx, data });
setContentStore('tabs', tab_idx, 'data', (d) => ({
...d,
result_sets: (d as QueryContentTabData).result_sets.map((r, i) => (i === query_idx ? { ...r, ...data } : r)),
@@ -311,5 +316,6 @@ export const ConnectionsService = () => {
queryIdx,
updateResultSet,
getSchema,
+ insertColumnName,
};
};
diff --git a/src/utils/i18n/en.json b/src/utils/i18n/en.json
index 8d60486..70bc2e5 100644
--- a/src/utils/i18n/en.json
+++ b/src/utils/i18n/en.json
@@ -40,7 +40,11 @@
"vim_mode_on": "Vim mode on",
"copy_query": "Copy query to clipboard",
"limit": "LIMIT 1000",
- "auto_limit": "Apply limit if query does not have one"
+ "auto_limit": "Apply limit if query does not have one",
+ "next_result_set": "Next result set",
+ "previous_result_set": "Previous result set",
+ "next_page": "Next page",
+ "previous_page": "Previous page"
},
"zero_results": "0 rows retuned",
"result_set": "Result set: ",
@@ -51,7 +55,12 @@
"list_data": "List data",
"truncate_table": "Truncate table",
"tables": "Tables",
- "table_was_truncated": "Table {{table}} was truncated"
+ "table_was_truncated": "Table {{table}} was truncated",
+ "refresh_schema": "Refresh schema",
+ "show_process_list": "Show process list"
+ },
+ "settings":{
+ "settings": "Settings"
},
"theme_switch": {
"theme": "Theme"