mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-27 19:36:00 +00:00
app commands works
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
const _ = require('lodash');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { appdir } = require('../utility/directories');
|
const { appdir } = require('../utility/directories');
|
||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
|
const connections = require('./connections');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
folders_meta: true,
|
folders_meta: true,
|
||||||
@@ -50,6 +52,16 @@ module.exports = {
|
|||||||
return [...refsType(), ...fileType('.command.sql', 'command.sql'), ...fileType('.query.sql', 'query.sql')];
|
return [...refsType(), ...fileType('.command.sql', 'command.sql'), ...fileType('.query.sql', 'query.sql')];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async emitChangedDbApp(folder) {
|
||||||
|
for (const conn of await connections.list()) {
|
||||||
|
for (const db of conn.databases || []) {
|
||||||
|
if (db[`useApp:${folder}`]) {
|
||||||
|
socket.emitChanged(`db-apps-changed-${conn._id}-${db.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
refreshFiles_meta: true,
|
refreshFiles_meta: true,
|
||||||
async refreshFiles({ folder }) {
|
async refreshFiles({ folder }) {
|
||||||
socket.emitChanged(`app-files-changed-${folder}`);
|
socket.emitChanged(`app-files-changed-${folder}`);
|
||||||
@@ -64,6 +76,7 @@ module.exports = {
|
|||||||
async deleteFile({ folder, file, fileType }) {
|
async deleteFile({ folder, file, fileType }) {
|
||||||
await fs.unlink(path.join(appdir(), folder, `${file}.${fileType}`));
|
await fs.unlink(path.join(appdir(), folder, `${file}.${fileType}`));
|
||||||
socket.emitChanged(`app-files-changed-${folder}`);
|
socket.emitChanged(`app-files-changed-${folder}`);
|
||||||
|
this.emitChangedDbApp(folder);
|
||||||
},
|
},
|
||||||
|
|
||||||
renameFile_meta: true,
|
renameFile_meta: true,
|
||||||
@@ -73,6 +86,7 @@ module.exports = {
|
|||||||
path.join(path.join(appdir(), folder), `${newFile}.${fileType}`)
|
path.join(path.join(appdir(), folder), `${newFile}.${fileType}`)
|
||||||
);
|
);
|
||||||
socket.emitChanged(`app-files-changed-${folder}`);
|
socket.emitChanged(`app-files-changed-${folder}`);
|
||||||
|
this.emitChangedDbApp(folder);
|
||||||
},
|
},
|
||||||
|
|
||||||
renameFolder_meta: true,
|
renameFolder_meta: true,
|
||||||
@@ -97,4 +111,54 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
return `${name}${index}`;
|
return `${name}${index}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAppsForDb_meta: true,
|
||||||
|
async getAppsForDb({ conid, database }) {
|
||||||
|
const connection = await connections.get({ conid });
|
||||||
|
if (!connection) return [];
|
||||||
|
const db = (connection.databases || []).find(x => x.name == database);
|
||||||
|
const apps = [];
|
||||||
|
const res = [];
|
||||||
|
if (db) {
|
||||||
|
for (const key of _.keys(db || {})) {
|
||||||
|
if (key.startsWith('useApp:') && db[key]) {
|
||||||
|
apps.push(key.substring('useApp:'.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('APPS', apps);
|
||||||
|
for (const folder of apps) {
|
||||||
|
res.push(await this.loadApp({ folder }));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
loadApp_meta: true,
|
||||||
|
async loadApp({ folder }) {
|
||||||
|
const res = {
|
||||||
|
queries: [],
|
||||||
|
commands: [],
|
||||||
|
name: folder,
|
||||||
|
};
|
||||||
|
const dir = path.join(appdir(), folder);
|
||||||
|
if (await fs.exists(dir)) {
|
||||||
|
const files = await fs.readdir(dir);
|
||||||
|
|
||||||
|
async function processType(ext, field) {
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.endsWith(ext)) {
|
||||||
|
res[field].push({
|
||||||
|
name: file.slice(0, -ext.length),
|
||||||
|
sql: await fs.readFile(path.join(dir, file), { encoding: 'utf-8' }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await processType('.command.sql', 'commands');
|
||||||
|
await processType('.query.sql', 'queries');
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -178,6 +178,9 @@ module.exports = {
|
|||||||
res = await this.datastore.insert(encrypted);
|
res = await this.datastore.insert(encrypted);
|
||||||
}
|
}
|
||||||
socket.emitChanged('connection-list-changed');
|
socket.emitChanged('connection-list-changed');
|
||||||
|
for (const db of connection.databases || []) {
|
||||||
|
socket.emitChanged(`db-apps-changed-${connection._id}-${db.name}`);
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -201,6 +204,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
const res = await this.datastore.update({ _id: conid }, { $set: { databases } });
|
const res = await this.datastore.update({ _id: conid }, { $set: { databases } });
|
||||||
socket.emitChanged('connection-list-changed');
|
socket.emitChanged('connection-list-changed');
|
||||||
|
socket.emitChanged(`db-apps-changed-${conid}-${database}`);
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const hasPermission = require('../utility/hasPermission');
|
|||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
const scheduler = require('./scheduler');
|
const scheduler = require('./scheduler');
|
||||||
const getDiagramExport = require('../utility/getDiagramExport');
|
const getDiagramExport = require('../utility/getDiagramExport');
|
||||||
|
const apps = require('./apps');
|
||||||
|
|
||||||
function serialize(format, data) {
|
function serialize(format, data) {
|
||||||
if (format == 'text') return data;
|
if (format == 'text') return data;
|
||||||
@@ -94,8 +95,10 @@ module.exports = {
|
|||||||
socket.emitChanged(`archive-files-changed-${folder.substring('archive:'.length)}`);
|
socket.emitChanged(`archive-files-changed-${folder.substring('archive:'.length)}`);
|
||||||
return true;
|
return true;
|
||||||
} else if (folder.startsWith('app:')) {
|
} else if (folder.startsWith('app:')) {
|
||||||
await fs.writeFile(path.join(appdir(), folder.substring('app:'.length), file), serialize(format, data));
|
const app = folder.substring('app:'.length);
|
||||||
socket.emitChanged(`app-files-changed-${folder.substring('app:'.length)}`);
|
await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
|
||||||
|
socket.emitChanged(`app-files-changed-${app}`);
|
||||||
|
apps.emitChangedDbApp(folder);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (!hasPermission(`files/${folder}/write`)) return false;
|
if (!hasPermission(`files/${folder}/write`)) return false;
|
||||||
|
|||||||
16
packages/types/appdefs.d.ts
vendored
Normal file
16
packages/types/appdefs.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
interface ApplicationCommand {
|
||||||
|
name: string;
|
||||||
|
sql: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApplicationQuery {
|
||||||
|
name: string;
|
||||||
|
sql: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApplicationDefinition {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
queries: ApplicationQuery[];
|
||||||
|
commands: ApplicationCommand[];
|
||||||
|
}
|
||||||
@@ -42,24 +42,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { filterName } from 'dbgate-tools';
|
import { filterName } from 'dbgate-tools';
|
||||||
import ImportExportModal from '../modals/ImportExportModal.svelte';
|
|
||||||
import { showModal } from '../modals/modalTools';
|
import { showModal } from '../modals/modalTools';
|
||||||
|
|
||||||
import { archiveFilesAsDataSheets, currentArchive, extensions, getCurrentDatabase } from '../stores';
|
|
||||||
|
|
||||||
import createQuickExportMenu from '../utility/createQuickExportMenu';
|
|
||||||
import { exportElectronFile } from '../utility/exportElectronFile';
|
|
||||||
import openNewTab from '../utility/openNewTab';
|
import openNewTab from '../utility/openNewTab';
|
||||||
import AppObjectCore from './AppObjectCore.svelte';
|
import AppObjectCore from './AppObjectCore.svelte';
|
||||||
import getConnectionLabel from '../utility/getConnectionLabel';
|
|
||||||
import InputTextModal from '../modals/InputTextModal.svelte';
|
import InputTextModal from '../modals/InputTextModal.svelte';
|
||||||
import ConfirmModal from '../modals/ConfirmModal.svelte';
|
import ConfirmModal from '../modals/ConfirmModal.svelte';
|
||||||
import {
|
|
||||||
isArchiveFileMarkedAsDataSheet,
|
|
||||||
markArchiveFileAsDataSheet,
|
|
||||||
markArchiveFileAsReadonly,
|
|
||||||
} from '../utility/archiveTools';
|
|
||||||
import { apiCall } from '../utility/api';
|
import { apiCall } from '../utility/api';
|
||||||
|
import { currentDatabase, currentDatabase } from '../stores';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
@@ -108,6 +98,7 @@
|
|||||||
{ text: 'Delete', onClick: handleDelete },
|
{ text: 'Delete', onClick: handleDelete },
|
||||||
{ text: 'Rename', onClick: handleRename },
|
{ text: 'Rename', onClick: handleRename },
|
||||||
data.fileType.endsWith('.sql') && { text: 'Open SQL', onClick: handleOpenSqlFile },
|
data.fileType.endsWith('.sql') && { text: 'Open SQL', onClick: handleOpenSqlFile },
|
||||||
|
|
||||||
// data.fileType.endsWith('.yaml') && { text: 'Open YAML', onClick: handleOpenYamlFile },
|
// data.fileType.endsWith('.yaml') && { text: 'Open YAML', onClick: handleOpenYamlFile },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { filterName } from 'dbgate-tools';
|
import { filterName } from 'dbgate-tools';
|
||||||
|
|
||||||
import { currentApplication } from '../stores';
|
import { currentApplication, currentDatabase } from '../stores';
|
||||||
|
|
||||||
import AppObjectCore from './AppObjectCore.svelte';
|
import AppObjectCore from './AppObjectCore.svelte';
|
||||||
import { showModal } from '../modals/modalTools';
|
import { showModal } from '../modals/modalTools';
|
||||||
@@ -45,10 +45,25 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function setOnCurrentDb(value) {
|
||||||
|
apiCall('connections/update-database', {
|
||||||
|
conid: $currentDatabase?.connection?._id,
|
||||||
|
database: $currentDatabase?.name,
|
||||||
|
values: {
|
||||||
|
[`useApp:${data.name}`]: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function createMenu() {
|
function createMenu() {
|
||||||
return [
|
return [
|
||||||
{ text: 'Delete', onClick: handleDelete },
|
{ text: 'Delete', onClick: handleDelete },
|
||||||
{ text: 'Rename', onClick: handleRename },
|
{ text: 'Rename', onClick: handleRename },
|
||||||
|
|
||||||
|
$currentDatabase && [
|
||||||
|
{ text: 'Enable on current database', onClick: () => setOnCurrentDb(true) },
|
||||||
|
{ text: 'Disable on current database', onClick: () => setOnCurrentDb(false) },
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
import { getDatabaseMenuItems } from './DatabaseAppObject.svelte';
|
import { getDatabaseMenuItems } from './DatabaseAppObject.svelte';
|
||||||
import getElectron from '../utility/getElectron';
|
import getElectron from '../utility/getElectron';
|
||||||
import getConnectionLabel from '../utility/getConnectionLabel';
|
import getConnectionLabel from '../utility/getConnectionLabel';
|
||||||
import { getDatabaseList } from '../utility/metadataLoaders';
|
import { getDatabaseList, useDbApps } from '../utility/metadataLoaders';
|
||||||
import { getLocalStorage } from '../utility/storageCache';
|
import { getLocalStorage } from '../utility/storageCache';
|
||||||
import { apiCall } from '../utility/api';
|
import { apiCall } from '../utility/api';
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
],
|
],
|
||||||
data.singleDatabase && [
|
data.singleDatabase && [
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
getDatabaseMenuItems(data, data.defaultDatabase, $extensions, $currentDatabase),
|
getDatabaseMenuItems(data, data.defaultDatabase, $extensions, $currentDatabase, $apps),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -186,6 +186,8 @@
|
|||||||
statusTitle = null;
|
statusTitle = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: apps = useDbApps({ conid: data?._id, database: data.defaultDatabase });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AppObjectCore
|
<AppObjectCore
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" context="module">
|
<script lang="ts" context="module">
|
||||||
export const extractKey = props => props.name;
|
export const extractKey = props => props.name;
|
||||||
|
|
||||||
export function getDatabaseMenuItems(connection, name, $extensions, $currentDatabase) {
|
export function getDatabaseMenuItems(connection, name, $extensions, $currentDatabase, $apps) {
|
||||||
const handleNewQuery = () => {
|
const handleNewQuery = () => {
|
||||||
const tooltip = `${getConnectionLabel(connection)}\n${name}`;
|
const tooltip = `${getConnectionLabel(connection)}\n${name}`;
|
||||||
openNewTab({
|
openNewTab({
|
||||||
@@ -157,8 +157,20 @@
|
|||||||
openJsonDocument(db, name);
|
openJsonDocument(db, name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function handleConfirmSql(sql) {
|
||||||
|
const resp = await apiCall('database-connections/run-script', { conid: connection._id, database: name, sql });
|
||||||
|
const { errorMessage } = resp || {};
|
||||||
|
if (errorMessage) {
|
||||||
|
showModal(ErrorMessageModal, { title: 'Error when executing script', message: errorMessage });
|
||||||
|
} else {
|
||||||
|
showSnackbarSuccess('Saved to database');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const driver = findEngineDriver(connection, getExtensions());
|
const driver = findEngineDriver(connection, getExtensions());
|
||||||
|
|
||||||
|
const commands = _.flatten(($apps || []).map(x => x.commands || []));
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{ onClick: handleNewQuery, text: 'New query', isNewQuery: true },
|
{ onClick: handleNewQuery, text: 'New query', isNewQuery: true },
|
||||||
!driver?.dialect?.nosql && { onClick: handleNewTable, text: 'New table' },
|
!driver?.dialect?.nosql && { onClick: handleNewTable, text: 'New table' },
|
||||||
@@ -180,6 +192,20 @@
|
|||||||
|
|
||||||
_.get($currentDatabase, 'connection._id') == _.get(connection, '_id') &&
|
_.get($currentDatabase, 'connection._id') == _.get(connection, '_id') &&
|
||||||
_.get($currentDatabase, 'name') == name && { onClick: handleDisconnect, text: 'Disconnect' },
|
_.get($currentDatabase, 'name') == name && { onClick: handleDisconnect, text: 'Disconnect' },
|
||||||
|
|
||||||
|
commands.length > 0 && [
|
||||||
|
{ divider: true },
|
||||||
|
commands.map((cmd: any) => ({
|
||||||
|
text: cmd.name,
|
||||||
|
onClick: () => {
|
||||||
|
showModal(ConfirmSqlModal, {
|
||||||
|
sql: cmd.sql,
|
||||||
|
onConfirm: () => handleConfirmSql(cmd.sql),
|
||||||
|
engine: driver.engine,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -207,18 +233,21 @@
|
|||||||
import { showSnackbarSuccess } from '../utility/snackbar';
|
import { showSnackbarSuccess } from '../utility/snackbar';
|
||||||
import { findEngineDriver } from 'dbgate-tools';
|
import { findEngineDriver } from 'dbgate-tools';
|
||||||
import InputTextModal from '../modals/InputTextModal.svelte';
|
import InputTextModal from '../modals/InputTextModal.svelte';
|
||||||
import { getDatabaseInfo } from '../utility/metadataLoaders';
|
import { getDatabaseInfo, useDbApps } from '../utility/metadataLoaders';
|
||||||
import { openJsonDocument } from '../tabs/JsonTab.svelte';
|
import { openJsonDocument } from '../tabs/JsonTab.svelte';
|
||||||
import { apiCall } from '../utility/api';
|
import { apiCall } from '../utility/api';
|
||||||
|
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
||||||
|
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
export let passProps;
|
export let passProps;
|
||||||
|
|
||||||
function createMenu() {
|
function createMenu() {
|
||||||
return getDatabaseMenuItems(data.connection, data.name, $extensions, $currentDatabase);
|
return getDatabaseMenuItems(data.connection, data.name, $extensions, $currentDatabase, $apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: isPinned = !!$pinnedDatabases.find(x => x.name == data.name && x.connection?._id == data.connection?._id);
|
$: isPinned = !!$pinnedDatabases.find(x => x.name == data.name && x.connection?._id == data.connection?._id);
|
||||||
|
$: apps = useDbApps({ conid: data?.connection?._id, database: data?.name });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AppObjectCore
|
<AppObjectCore
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ const appFilesLoader = ({ folder }) => ({
|
|||||||
reloadTrigger: `app-files-changed-${folder}`,
|
reloadTrigger: `app-files-changed-${folder}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const dbAppsLoader = ({ conid, database }) => ({
|
||||||
|
url: 'apps/get-apps-for-db',
|
||||||
|
params: { conid, database },
|
||||||
|
reloadTrigger: `db-apps-changed-${conid}-${database}`,
|
||||||
|
});
|
||||||
|
|
||||||
const serverStatusLoader = () => ({
|
const serverStatusLoader = () => ({
|
||||||
url: 'server-connections/server-status',
|
url: 'server-connections/server-status',
|
||||||
params: {},
|
params: {},
|
||||||
@@ -427,6 +433,13 @@ export function useAppFolders(args = {}) {
|
|||||||
return useCore(appFoldersLoader, args);
|
return useCore(appFoldersLoader, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDbApps(args = {}) {
|
||||||
|
return getCore(dbAppsLoader, args);
|
||||||
|
}
|
||||||
|
export function useDbApps(args = {}) {
|
||||||
|
return useCore(dbAppsLoader, args);
|
||||||
|
}
|
||||||
|
|
||||||
export function getInstalledPlugins(args = {}) {
|
export function getInstalledPlugins(args = {}) {
|
||||||
return getCore(installedPluginsLoader, args) || [];
|
return getCore(installedPluginsLoader, args) || [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
'command.sql': 'SQL commands',
|
'command.sql': 'SQL commands',
|
||||||
'query.sql': 'SQL queries',
|
'query.sql': 'SQL queries',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const COMMAND_TEMPLATE = `-- Write SQL command here
|
||||||
|
-- After save, you can execute it from database context menu, for all databases, which use this application
|
||||||
|
`;
|
||||||
|
|
||||||
|
const QUERY_TEMPLATE = `-- Write SQL query here
|
||||||
|
-- After save, you can view it in tables list, for all databases, which use this application
|
||||||
|
`;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -39,7 +47,7 @@
|
|||||||
apiCall('apps/refresh-files', { folder });
|
apiCall('apps/refresh-files', { folder });
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleNewSqlFile(fileType, header) {
|
function handleNewSqlFile(fileType, header, initialData) {
|
||||||
showModal(InputTextModal, {
|
showModal(InputTextModal, {
|
||||||
value: '',
|
value: '',
|
||||||
label: 'New file name',
|
label: 'New file name',
|
||||||
@@ -47,6 +55,7 @@
|
|||||||
onConfirm: async file => {
|
onConfirm: async file => {
|
||||||
newQuery({
|
newQuery({
|
||||||
title: file,
|
title: file,
|
||||||
|
initialData,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
savedFile: file + '.' + fileType,
|
savedFile: file + '.' + fileType,
|
||||||
savedFolder: 'app:' + $currentApplication,
|
savedFolder: 'app:' + $currentApplication,
|
||||||
@@ -59,8 +68,11 @@
|
|||||||
|
|
||||||
function createAddMenu() {
|
function createAddMenu() {
|
||||||
return [
|
return [
|
||||||
{ text: 'New SQL command', onClick: () => handleNewSqlFile('command.sql', 'Create new SQL command') },
|
{
|
||||||
{ text: 'New query view', onClick: () => handleNewSqlFile('query.sql', 'Create new SQL query') },
|
text: 'New SQL command',
|
||||||
|
onClick: () => handleNewSqlFile('command.sql', 'Create new SQL command', COMMAND_TEMPLATE),
|
||||||
|
},
|
||||||
|
{ text: 'New query view', onClick: () => handleNewSqlFile('query.sql', 'Create new SQL query', QUERY_TEMPLATE) },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user