mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-19 09:36:01 +00:00
shell script runner
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
import ScriptWriter from './ScriptWriter';
|
||||
|
||||
export default class ScriptCreator {
|
||||
constructor() {
|
||||
this.varCount = 0;
|
||||
this.commands = [];
|
||||
}
|
||||
allocVariable(prefix = 'var') {
|
||||
this.varCount += 1;
|
||||
return `${prefix}${this.varCount}`;
|
||||
}
|
||||
getCode() {
|
||||
const writer = new ScriptWriter();
|
||||
for (const command of this.commands) {
|
||||
const { type } = command;
|
||||
switch (type) {
|
||||
case 'assign':
|
||||
{
|
||||
const { variableName, functionName, props } = command;
|
||||
writer.assign(variableName, functionName, props);
|
||||
}
|
||||
break;
|
||||
case 'copyStream':
|
||||
{
|
||||
const { sourceVar, targetVar } = command;
|
||||
writer.copyStream(sourceVar, targetVar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.finish();
|
||||
return writer.s;
|
||||
}
|
||||
assign(variableName, functionName, props) {
|
||||
this.commands.push({
|
||||
type: 'assign',
|
||||
variableName,
|
||||
functionName,
|
||||
props,
|
||||
});
|
||||
}
|
||||
copyStream(sourceVar, targetVar) {
|
||||
this.commands.push({
|
||||
type: 'copyStream',
|
||||
sourceVar,
|
||||
targetVar,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
export default class ScriptWriter {
|
||||
constructor() {
|
||||
this.s = '';
|
||||
this.put('const dbgateApi = require("@dbgate/api");');
|
||||
this.put();
|
||||
this.put('async function run() {');
|
||||
this.varCount = 0;
|
||||
}
|
||||
|
||||
allocVariable(prefix = 'var') {
|
||||
this.varCount += 1;
|
||||
return `${prefix}${this.varCount}`;
|
||||
}
|
||||
|
||||
put(s = '') {
|
||||
@@ -11,17 +14,11 @@ export default class ScriptWriter {
|
||||
this.s += '\n';
|
||||
}
|
||||
|
||||
finish() {
|
||||
this.put('}');
|
||||
this.put();
|
||||
this.put('dbgateApi.runScript(run);');
|
||||
}
|
||||
|
||||
assign(variableName, functionName, props) {
|
||||
this.put(` const ${variableName} = await dbgateApi.${functionName}(${JSON.stringify(props)});`);
|
||||
this.put(`const ${variableName} = await dbgateApi.${functionName}(${JSON.stringify(props)});`);
|
||||
}
|
||||
|
||||
copyStream(sourceVar, targetVar) {
|
||||
this.put(` await dbgateApi.copyStream(${sourceVar}, ${targetVar});`);
|
||||
this.put(`await dbgateApi.copyStream(${sourceVar}, ${targetVar});`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import _ from 'lodash';
|
||||
import ScriptCreator from './ScriptCreator';
|
||||
import ScriptWriter from './ScriptWriter';
|
||||
import getAsArray from '../utility/getAsArray';
|
||||
import { getConnectionInfo } from '../utility/metadataLoaders';
|
||||
import engines from '@dbgate/engines';
|
||||
import { quoteFullName, fullNameFromString } from '@dbgate/datalib';
|
||||
|
||||
export default async function createImpExpScript(values) {
|
||||
const script = new ScriptCreator();
|
||||
const script = new ScriptWriter();
|
||||
if (values.sourceStorageType == 'database') {
|
||||
const tables = getAsArray(values.sourceTables);
|
||||
for (const table of tables) {
|
||||
@@ -29,7 +29,8 @@ export default async function createImpExpScript(values) {
|
||||
});
|
||||
|
||||
script.copyStream(sourceVar, targetVar);
|
||||
script.put();
|
||||
}
|
||||
}
|
||||
return script.getCode();
|
||||
return script.s;
|
||||
}
|
||||
|
||||
15
packages/web/src/query/ShellToolbar.js
Normal file
15
packages/web/src/query/ShellToolbar.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import ToolbarButton from '../widgets/ToolbarButton';
|
||||
|
||||
export default function ShellToolbar({ execute, cancel, busy}) {
|
||||
return (
|
||||
<>
|
||||
<ToolbarButton disabled={busy} onClick={execute} icon="fas fa-play">
|
||||
Execute
|
||||
</ToolbarButton>
|
||||
<ToolbarButton disabled={!busy} onClick={cancel} icon="fas fa-times">
|
||||
Cancel
|
||||
</ToolbarButton>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import MessagesView from './MessagesView';
|
||||
import useSocket from '../utility/SocketProvider';
|
||||
|
||||
export default function SessionMessagesView({ sessionId, onMessageClick, executeNumber }) {
|
||||
export default function SocketMessagesView({ eventName, onMessageClick = undefined, executeNumber }) {
|
||||
const [displayedMessages, setDisplayedMessages] = React.useState([]);
|
||||
const cachedMessagesRef = React.useRef([]);
|
||||
const socket = useSocket();
|
||||
@@ -27,13 +27,13 @@ export default function SessionMessagesView({ sessionId, onMessageClick, execute
|
||||
}, [executeNumber]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (sessionId && socket) {
|
||||
socket.on(`session-info-${sessionId}`, handleInfo);
|
||||
if (eventName && socket) {
|
||||
socket.on(eventName, handleInfo);
|
||||
return () => {
|
||||
socket.off(`session-info-${sessionId}`, handleInfo);
|
||||
socket.off(eventName, handleInfo);
|
||||
};
|
||||
}
|
||||
}, [sessionId, socket]);
|
||||
}, [eventName, socket]);
|
||||
|
||||
return <MessagesView items={displayedMessages} onMessageClick={onMessageClick} />;
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { useConnectionInfo, getTableInfo, getConnectionInfo, getSqlObjectInfo }
|
||||
import SqlEditor from '../sqleditor/SqlEditor';
|
||||
import { useUpdateDatabaseForTab, useSetOpenedTabs, useOpenedTabs } from '../utility/globalState';
|
||||
import QueryToolbar from '../query/QueryToolbar';
|
||||
import SessionMessagesView from '../query/SessionMessagesView';
|
||||
import SocketMessagesView from '../query/SocketMessagesView';
|
||||
import { TabPage } from '../widgets/TabControl';
|
||||
import ResultTabs from '../sqleditor/ResultTabs';
|
||||
import { VerticalSplitter } from '../widgets/Splitter';
|
||||
@@ -143,6 +143,7 @@ export default function QueryTab({
|
||||
};
|
||||
|
||||
const handleExecute = async () => {
|
||||
if (busy) return;
|
||||
setExecuteNumber((num) => num + 1);
|
||||
const selectedText = editorRef.current.editor.getSelectedText();
|
||||
|
||||
@@ -204,8 +205,8 @@ export default function QueryTab({
|
||||
{sessionId && (
|
||||
<ResultTabs sessionId={sessionId} executeNumber={executeNumber}>
|
||||
<TabPage label="Messages" key="messages">
|
||||
<SessionMessagesView
|
||||
sessionId={sessionId}
|
||||
<SocketMessagesView
|
||||
eventName={sessionId ? `session-info-${sessionId}` : null}
|
||||
onMessageClick={handleMesageClick}
|
||||
executeNumber={executeNumber}
|
||||
/>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useConnectionInfo, getTableInfo, getConnectionInfo, getSqlObjectInfo }
|
||||
import SqlEditor from '../sqleditor/SqlEditor';
|
||||
import { useUpdateDatabaseForTab, useSetOpenedTabs, useOpenedTabs } from '../utility/globalState';
|
||||
import QueryToolbar from '../query/QueryToolbar';
|
||||
import SessionMessagesView from '../query/SessionMessagesView';
|
||||
import SocketMessagesView from '../query/SocketMessagesView';
|
||||
import { TabPage } from '../widgets/TabControl';
|
||||
import ResultTabs from '../sqleditor/ResultTabs';
|
||||
import { VerticalSplitter } from '../widgets/Splitter';
|
||||
@@ -19,11 +19,10 @@ import SaveSqlFileModal from '../modals/SaveSqlFileModal';
|
||||
import useModalState from '../modals/useModalState';
|
||||
import sqlFormatter from 'sql-formatter';
|
||||
import JavaScriptEditor from '../sqleditor/JavaScriptEditor';
|
||||
import ShellToolbar from '../query/ShellToolbar';
|
||||
|
||||
export default function ShellTab({
|
||||
tabid,
|
||||
conid,
|
||||
database,
|
||||
initialArgs,
|
||||
tabVisible,
|
||||
toolbarPortalRef,
|
||||
@@ -43,6 +42,11 @@ export default function ShellTab({
|
||||
const saveToStorageDebounced = React.useMemo(() => _.debounce(saveToStorage, 5000), [saveToStorage]);
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
|
||||
const [executeNumber, setExecuteNumber] = React.useState(0);
|
||||
const [runnerId, setRunnerId] = React.useState(null);
|
||||
|
||||
const socket = useSocket();
|
||||
|
||||
React.useEffect(() => {
|
||||
window.addEventListener('beforeunload', saveToStorage);
|
||||
return () => {
|
||||
@@ -68,8 +72,18 @@ export default function ShellTab({
|
||||
|
||||
const editorRef = React.useRef(null);
|
||||
|
||||
useUpdateDatabaseForTab(tabVisible, conid, database);
|
||||
const connection = useConnectionInfo({ conid });
|
||||
const handleRunnerDone = React.useCallback(() => {
|
||||
setBusy(false);
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (runnerId && socket) {
|
||||
socket.on(`runner-done-${runnerId}`, handleRunnerDone);
|
||||
return () => {
|
||||
socket.off(`runner-done-${runnerId}`, handleRunnerDone);
|
||||
};
|
||||
}
|
||||
}, [runnerId, socket]);
|
||||
|
||||
const handleChange = (text) => {
|
||||
if (text != null) shellTextRef.current = text;
|
||||
@@ -77,12 +91,24 @@ export default function ShellTab({
|
||||
saveToStorageDebounced();
|
||||
};
|
||||
|
||||
const handleExecute = async () => {};
|
||||
const handleExecute = async () => {
|
||||
if (busy) return;
|
||||
setExecuteNumber((num) => num + 1);
|
||||
const selectedText = editorRef.current.editor.getSelectedText();
|
||||
|
||||
let runid = runnerId;
|
||||
const resp = await axios.post('runners/start', {
|
||||
script: selectedText || shellText,
|
||||
});
|
||||
runid = resp.data.runid;
|
||||
setRunnerId(runid);
|
||||
setBusy(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
// axios.post('sessions/cancel', {
|
||||
// sesid: sessionId,
|
||||
// });
|
||||
axios.post('runners/cancel', {
|
||||
runid: runnerId,
|
||||
});
|
||||
};
|
||||
|
||||
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
||||
@@ -102,7 +128,19 @@ export default function ShellTab({
|
||||
onKeyDown={handleKeyDown}
|
||||
editorRef={editorRef}
|
||||
/>
|
||||
<SocketMessagesView eventName={runnerId ? `runner-info-${runnerId}` : null} executeNumber={executeNumber} />
|
||||
</VerticalSplitter>
|
||||
{toolbarPortalRef &&
|
||||
toolbarPortalRef.current &&
|
||||
tabVisible &&
|
||||
ReactDOM.createPortal(
|
||||
<ShellToolbar
|
||||
execute={handleExecute}
|
||||
busy={busy}
|
||||
cancel={handleCancel}
|
||||
/>,
|
||||
toolbarPortalRef.current
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user