mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-21 17:36:01 +00:00
query grid
This commit is contained in:
29
packages/web/src/datagrid/JslDataGrid.svelte
Normal file
29
packages/web/src/datagrid/JslDataGrid.svelte
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createGridCache, createGridConfig, JslGridDisplay } from 'dbgate-datalib';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import socket from '../utility/socket';
|
||||||
|
import useEffect from '../utility/useEffect';
|
||||||
|
|
||||||
|
import useFetch from '../utility/useFetch';
|
||||||
|
import DataGrid from './DataGrid.svelte';
|
||||||
|
import JslDataGridCore from './JslDataGridCore.svelte';
|
||||||
|
|
||||||
|
export let jslid;
|
||||||
|
|
||||||
|
$: info = useFetch({
|
||||||
|
params: { jslid },
|
||||||
|
url: 'jsldata/get-info',
|
||||||
|
defaultValue: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
$: columns = ($info && $info.columns) || [];
|
||||||
|
const config = writable(createGridConfig());
|
||||||
|
const cache = writable(createGridCache());
|
||||||
|
|
||||||
|
$: display = new JslGridDisplay(jslid, columns, $config, config.update, $cache, cache.update);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#key jslid}
|
||||||
|
<DataGrid {display} {jslid} gridCoreComponent={JslDataGridCore} />
|
||||||
|
{/key}
|
||||||
83
packages/web/src/datagrid/JslDataGridCore.svelte
Normal file
83
packages/web/src/datagrid/JslDataGridCore.svelte
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<script context="module" lang="ts">
|
||||||
|
async function loadDataPage(props, offset, limit) {
|
||||||
|
const { jslid, display } = props;
|
||||||
|
|
||||||
|
const response = await axios.post('jsldata/get-rows', {
|
||||||
|
jslid,
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
filters: display ? display.compileFilters() : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dataPageAvailable(props) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadRowCount(props) {
|
||||||
|
const { jslid } = props;
|
||||||
|
|
||||||
|
const response = await axios.request({
|
||||||
|
url: 'jsldata/get-stats',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
jslid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return response.data.rowCount;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import axios from '../utility/axios';
|
||||||
|
import socket from '../utility/socket';
|
||||||
|
import useEffect from '../utility/useEffect';
|
||||||
|
|
||||||
|
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
|
||||||
|
import RowsArrayGrider from './RowsArrayGrider';
|
||||||
|
|
||||||
|
export let jslid;
|
||||||
|
|
||||||
|
let loadedRows = [];
|
||||||
|
let domGrid;
|
||||||
|
|
||||||
|
let changeIndex = 0;
|
||||||
|
let rowCountLoaded = null;
|
||||||
|
|
||||||
|
const throttleLoadNext = _.throttle(() => domGrid.loadNextData(), 500);
|
||||||
|
|
||||||
|
const handleJslDataStats = stats => {
|
||||||
|
if (stats.changeIndex < changeIndex) return;
|
||||||
|
changeIndex = stats.changeIndex;
|
||||||
|
rowCountLoaded = stats.rowCount;
|
||||||
|
throttleLoadNext();
|
||||||
|
};
|
||||||
|
|
||||||
|
$: effect = useEffect(() => onJslId(jslid));
|
||||||
|
function onJslId(jslidVal) {
|
||||||
|
if (jslidVal) {
|
||||||
|
socket.on(`jsldata-stats-${jslidVal}`, handleJslDataStats);
|
||||||
|
return () => {
|
||||||
|
socket.off(`jsldata-stats-${jslidVal}`, handleJslDataStats);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$: $effect;
|
||||||
|
|
||||||
|
$: grider = new RowsArrayGrider(loadedRows);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<LoadingDataGridCore
|
||||||
|
bind:this={domGrid}
|
||||||
|
{...$$props}
|
||||||
|
bind:loadedRows
|
||||||
|
{loadDataPage}
|
||||||
|
{dataPageAvailable}
|
||||||
|
{loadRowCount}
|
||||||
|
{grider}
|
||||||
|
{rowCountLoaded}
|
||||||
|
/>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
let loadedTime = new Date().getTime();
|
let loadedTime = new Date().getTime();
|
||||||
let allRowCount = null;
|
let allRowCount = null;
|
||||||
let errorMessage = null;
|
let errorMessage = null;
|
||||||
let loadNextDataToken = 0;
|
const loadNextDataRef = { current: false };
|
||||||
const loadedTimeRef = { current: null };
|
const loadedTimeRef = { current: null };
|
||||||
|
|
||||||
const handleLoadRowCount = async () => {
|
const handleLoadRowCount = async () => {
|
||||||
@@ -23,8 +23,9 @@
|
|||||||
allRowCount = rowCount;
|
allRowCount = rowCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function loadNextData() {
|
export async function loadNextData() {
|
||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
|
loadNextDataRef.current = false;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
const loadStart = new Date().getTime();
|
const loadStart = new Date().getTime();
|
||||||
@@ -60,6 +61,9 @@
|
|||||||
// }));
|
// }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loadNextDataRef.current) {
|
||||||
|
loadNextData();
|
||||||
|
}
|
||||||
// console.log('LOADED', nextRows, loadedRows);
|
// console.log('LOADED', nextRows, loadedRows);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +86,8 @@
|
|||||||
isLoadedAll = false;
|
isLoadedAll = false;
|
||||||
loadedTime = new Date().getTime();
|
loadedTime = new Date().getTime();
|
||||||
errorMessage = null;
|
errorMessage = null;
|
||||||
loadNextDataToken = 0;
|
loadNextDataRef.current = false;
|
||||||
|
// loadNextDataToken = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (display.cache.refreshTime > loadedTime) {
|
$: if (display.cache.refreshTime > loadedTime) {
|
||||||
|
|||||||
13
packages/web/src/datagrid/RowsArrayGrider.ts
Normal file
13
packages/web/src/datagrid/RowsArrayGrider.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import Grider, { GriderRowStatus } from './Grider';
|
||||||
|
|
||||||
|
export default class RowsArrayGrider extends Grider {
|
||||||
|
constructor(private rows: any[]) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
getRowData(index: any) {
|
||||||
|
return this.rows[index];
|
||||||
|
}
|
||||||
|
get rowCount() {
|
||||||
|
return this.rows.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,13 @@
|
|||||||
export let tabs: TabDef[];
|
export let tabs: TabDef[];
|
||||||
export let value = 0;
|
export let value = 0;
|
||||||
export let isInline = false;
|
export let isInline = false;
|
||||||
|
|
||||||
|
export function setValue(index) {
|
||||||
|
value = index;
|
||||||
|
}
|
||||||
|
export function getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="main">
|
<div class="main">
|
||||||
|
|||||||
66
packages/web/src/query/ResultTabs.svelte
Normal file
66
packages/web/src/query/ResultTabs.svelte
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
|
import JslDataGrid from '../datagrid/JslDataGrid.svelte';
|
||||||
|
import TabControl from '../elements/TabControl.svelte';
|
||||||
|
import socket from '../utility/socket';
|
||||||
|
import useEffect from '../utility/useEffect';
|
||||||
|
|
||||||
|
export let tabs = [];
|
||||||
|
export let sessionId;
|
||||||
|
export let executeNumber;
|
||||||
|
|
||||||
|
let resultInfos = [];
|
||||||
|
let domTabs;
|
||||||
|
|
||||||
|
const handleResultSet = async props => {
|
||||||
|
const { jslid, resultIndex } = props;
|
||||||
|
resultInfos = [...resultInfos, { jslid, resultIndex }];
|
||||||
|
await tick();
|
||||||
|
const currentTab = allTabs[domTabs.getValue()];
|
||||||
|
if (!currentTab?.isResult) domTabs.setValue(_.findIndex(allTabs, x => x.isResult));
|
||||||
|
};
|
||||||
|
|
||||||
|
$: allTabs = [
|
||||||
|
...tabs,
|
||||||
|
...resultInfos.map((info, index) => ({
|
||||||
|
label: `Result ${index + 1}`,
|
||||||
|
isResult: true,
|
||||||
|
component: JslDataGrid,
|
||||||
|
props: { jslid: info.jslid },
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (executeNumber >= 0) {
|
||||||
|
resultInfos = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: effect = useEffect(() => {
|
||||||
|
return onSession(sessionId);
|
||||||
|
});
|
||||||
|
function onSession(sid) {
|
||||||
|
if (sid) {
|
||||||
|
socket.on(`session-recordset-${sid}`, handleResultSet);
|
||||||
|
return () => {
|
||||||
|
socket.off(`session-recordset-${sid}`, handleResultSet);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return () => {};
|
||||||
|
}
|
||||||
|
$: $effect;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<TabControl bind:this={domTabs} tabs={allTabs}>
|
||||||
|
<slot name="0" slot="0" />
|
||||||
|
<slot name="1" slot="1" />
|
||||||
|
<slot name="2" slot="2" />
|
||||||
|
<slot name="3" slot="3" />
|
||||||
|
<slot name="4" slot="4" />
|
||||||
|
<slot name="5" slot="5" />
|
||||||
|
<slot name="6" slot="6" />
|
||||||
|
<slot name="7" slot="7" />
|
||||||
|
</TabControl>
|
||||||
@@ -18,12 +18,10 @@
|
|||||||
let displayedMessages = [];
|
let displayedMessages = [];
|
||||||
|
|
||||||
const displayCachedMessages = _.throttle(() => {
|
const displayCachedMessages = _.throttle(() => {
|
||||||
console.log('THROTTLE', cachedMessagesRef.current);
|
|
||||||
displayedMessages = [...cachedMessagesRef.current];
|
displayedMessages = [...cachedMessagesRef.current];
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
const handleInfo = info => {
|
const handleInfo = info => {
|
||||||
console.log('ACCEPTED', info);
|
|
||||||
cachedMessagesRef.current.push(info);
|
cachedMessagesRef.current.push(info);
|
||||||
displayCachedMessages();
|
displayCachedMessages();
|
||||||
};
|
};
|
||||||
@@ -40,15 +38,12 @@
|
|||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (executeNumber >= 0) {
|
if (executeNumber >= 0) {
|
||||||
console.log('CLEAR');
|
|
||||||
displayedMessages = [];
|
displayedMessages = [];
|
||||||
cachedMessagesRef.current = [];
|
cachedMessagesRef.current = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: $effect;
|
$: $effect;
|
||||||
|
|
||||||
$: console.log('displayedMessages', displayedMessages);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !displayedMessages || displayedMessages.length == 0}
|
{#if !displayedMessages || displayedMessages.length == 0}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
import SocketMessageView from '../query/SocketMessageView.svelte';
|
import SocketMessageView from '../query/SocketMessageView.svelte';
|
||||||
import memberStore from '../utility/memberStore';
|
import memberStore from '../utility/memberStore';
|
||||||
import useEffect from '../utility/useEffect';
|
import useEffect from '../utility/useEffect';
|
||||||
|
import ResultTabs from '../query/ResultTabs.svelte';
|
||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
export let conid;
|
export let conid;
|
||||||
@@ -71,15 +72,17 @@
|
|||||||
$: connection = useConnectionInfo({ conid });
|
$: connection = useConnectionInfo({ conid });
|
||||||
|
|
||||||
$: effect = useEffect(() => {
|
$: effect = useEffect(() => {
|
||||||
if (sessionId) {
|
return onSession(sessionId);
|
||||||
const sid = sessionId;
|
});
|
||||||
|
function onSession(sid) {
|
||||||
|
if (sid) {
|
||||||
socket.on(`session-done-${sid}`, handleSessionDone);
|
socket.on(`session-done-${sid}`, handleSessionDone);
|
||||||
return () => {
|
return () => {
|
||||||
socket.off(`session-done-${sid}`, handleSessionDone);
|
socket.off(`session-done-${sid}`, handleSessionDone);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return () => {};
|
return () => {};
|
||||||
});
|
}
|
||||||
$: $effect;
|
$: $effect;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
@@ -161,12 +164,16 @@
|
|||||||
/>
|
/>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="2">
|
<svelte:fragment slot="2">
|
||||||
<SocketMessageView
|
<ResultTabs tabs={[{ label: 'Messages', slot: 0 }]} {sessionId} {executeNumber}>
|
||||||
eventName={sessionId ? `session-info-${sessionId}` : null}
|
<svelte:fragment slot="0">
|
||||||
on:messageClick={handleMesageClick}
|
<SocketMessageView
|
||||||
{executeNumber}
|
eventName={sessionId ? `session-info-${sessionId}` : null}
|
||||||
showProcedure
|
on:messageClick={handleMesageClick}
|
||||||
showLine
|
{executeNumber}
|
||||||
/>
|
showProcedure
|
||||||
|
showLine
|
||||||
|
/>
|
||||||
|
</svelte:fragment>
|
||||||
|
</ResultTabs>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</VerticalSplitter>
|
</VerticalSplitter>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export default function memberStore(store, extractStore) {
|
|||||||
if (unsubscribeSub) unsubscribeSub();
|
if (unsubscribeSub) unsubscribeSub();
|
||||||
unsubscribeSub = subStore.subscribe(subValue => {
|
unsubscribeSub = subStore.subscribe(subValue => {
|
||||||
if (res) {
|
if (res) {
|
||||||
console.log('subValue', subValue);
|
|
||||||
res.set(subValue);
|
res.set(subValue);
|
||||||
} else {
|
} else {
|
||||||
res = writable(subValue);
|
res = writable(subValue);
|
||||||
|
|||||||
21
packages/web/src/utility/useFetch.ts
Normal file
21
packages/web/src/utility/useFetch.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import axios from './axios';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export default function useFetch({ url, data = undefined, params = undefined, defaultValue = undefined, ...config }) {
|
||||||
|
const result = writable(defaultValue);
|
||||||
|
|
||||||
|
axios
|
||||||
|
.request({
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
...config,
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
result.set(resp.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user