Merge branch 'develop'

This commit is contained in:
Jan Prochazka
2021-12-30 11:04:51 +01:00
124 changed files with 1891 additions and 2076 deletions

View File

@@ -22,10 +22,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 12.x
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x
- name: yarn install
run: |
yarn install

View File

@@ -26,10 +26,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 12.x
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x
- name: yarn install
run: |
yarn install

View File

@@ -24,10 +24,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 12.x
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x
- name: yarn install
run: |
yarn install

View File

@@ -30,10 +30,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 12.x
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x
- name: yarn install
run: |
yarn install

View File

@@ -30,10 +30,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 12.x
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x
- name: Configure NPM token
env:

View File

@@ -8,7 +8,7 @@ on:
jobs:
test-runner:
runs-on: ubuntu-latest
container: node:12.22
container: node:14.18
steps:
- name: Context

View File

@@ -5,10 +5,8 @@
"author": "Jan Prochazka <jenasoft.database@gmail.com>",
"description": "Opensource database administration tool",
"dependencies": {
"better-sqlite3-with-prebuilds": "^7.1.8",
"electron-log": "^4.3.1",
"electron-store": "^5.1.1",
"electron-updater": "^4.3.5",
"electron-log": "^4.4.1",
"electron-updater": "^4.6.1",
"patch-package": "^6.4.7"
},
"repository": {
@@ -90,23 +88,25 @@
},
"homepage": "./",
"scripts": {
"start": "cross-env ELECTRON_START_URL=http://localhost:5000 electron .",
"start": "cross-env ELECTRON_START_URL=http://localhost:5000 DEVMODE=1 electron .",
"start:local": "cross-env electron .",
"dist": "electron-builder",
"build": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && yarn dist",
"build:mac": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && node setMacPlatform x64 && yarn dist && node setMacPlatform arm64 && yarn dist",
"build:local": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && yarn predist",
"postinstall": "electron-builder install-app-deps && patch-package",
"postinstall": "yarn rebuild && patch-package",
"rebuild": "electron-builder install-app-deps",
"predist": "copyfiles ../packages/api/dist/* packages && copyfiles \"../packages/web/public/*\" packages && copyfiles \"../packages/web/public/**/*\" packages && copyfiles --up 3 \"../plugins/dist/**/*\" packages/plugins"
},
"main": "src/electron.js",
"devDependencies": {
"copyfiles": "^2.2.0",
"cross-env": "^6.0.3",
"electron": "11.2.3",
"electron-builder": "22.10.5"
"electron": "13.6.3",
"electron-builder": "22.14.5"
},
"optionalDependencies": {
"msnodesqlv8": "^2.4.0"
"better-sqlite3": "7.4.5",
"msnodesqlv8": "^2.4.4"
}
}

View File

@@ -1,9 +1,8 @@
const electron = require('electron');
const os = require('os');
const fs = require('fs');
const { Menu, ipcMain } = require('electron');
const { fork } = require('child_process');
const { autoUpdater } = require('electron-updater');
const Store = require('electron-store');
const log = require('electron-log');
// Module to control application life.
@@ -14,7 +13,17 @@ const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
const store = new Store();
// require('@electron/remote/main').initialize();
const configRootPath = path.join(app.getPath('userData'), 'config-root.json');
let initialConfig = {};
try {
initialConfig = JSON.parse(fs.readFileSync(configRootPath, { encoding: 'utf-8' }));
} catch (err) {
console.log('Error loading config-root:', err.message);
initialConfig = {};
}
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
@@ -36,7 +45,7 @@ function commandItem(id) {
accelerator: command ? command.keyText : undefined,
enabled: command ? command.enabled : false,
click() {
mainWindow.webContents.executeJavaScript(`dbgate_runCommand('${id}')`);
mainWindow.webContents.send('run-command', id);
},
};
}
@@ -49,7 +58,7 @@ function buildMenu() {
commandItem('new.connection'),
commandItem('new.sqliteDatabase'),
commandItem('new.modelCompare'),
commandItem('new.freetable'),
commandItem('new.freetable'),
{ type: 'separator' },
commandItem('file.open'),
commandItem('file.openArchive'),
@@ -99,25 +108,25 @@ function buildMenu() {
{
label: 'dbgate.org',
click() {
require('electron').shell.openExternal('https://dbgate.org');
electron.shell.openExternal('https://dbgate.org');
},
},
{
label: 'DbGate on GitHub',
click() {
require('electron').shell.openExternal('https://github.com/dbgate/dbgate');
electron.shell.openExternal('https://github.com/dbgate/dbgate');
},
},
{
label: 'DbGate on docker hub',
click() {
require('electron').shell.openExternal('https://hub.docker.com/r/dbgate/dbgate');
electron.shell.openExternal('https://hub.docker.com/r/dbgate/dbgate');
},
},
{
label: 'Report problem or feature request',
click() {
require('electron').shell.openExternal('https://github.com/dbgate/dbgate/issues/new');
electron.shell.openExternal('https://github.com/dbgate/dbgate/issues/new');
},
},
commandItem('tabs.changelog'),
@@ -146,10 +155,27 @@ ipcMain.on('update-commands', async (event, arg) => {
menu.enabled = command.enabled;
}
});
ipcMain.on('close-window', async (event, arg) => {
mainWindow.close();
});
ipcMain.handle('showOpenDialog', async (event, options) => {
const res = electron.dialog.showOpenDialogSync(mainWindow, options);
return res;
});
ipcMain.handle('showSaveDialog', async (event, options) => {
const res = electron.dialog.showSaveDialogSync(mainWindow, options);
return res;
});
ipcMain.handle('showItemInFolder', async (event, path) => {
electron.shell.showItemInFolder(path);
});
ipcMain.handle('openExternal', async (event, url) => {
electron.shell.openExternal(url);
});
function createWindow() {
const bounds = store.get('winBounds');
const bounds = initialConfig['winBounds'];
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
@@ -158,10 +184,11 @@ function createWindow() {
icon: os.platform() == 'win32' ? 'icon.ico' : path.resolve(__dirname, '../icon.png'),
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false,
},
});
if (store.get('winIsMaximized')) {
if (initialConfig['winIsMaximized']) {
mainWindow.maximize();
}
@@ -176,12 +203,15 @@ function createWindow() {
protocol: 'file:',
slashes: true,
});
mainWindow.webContents.on('did-finish-load', function () {
// hideSplash();
});
mainWindow.on('close', () => {
store.set('winBounds', mainWindow.getBounds());
store.set('winIsMaximized', mainWindow.isMaximized());
fs.writeFileSync(
configRootPath,
JSON.stringify({
winBounds: mainWindow.getBounds(),
winIsMaximized: mainWindow.isMaximized(),
}),
'utf-8'
);
});
mainWindow.loadURL(startUrl);
if (os.platform() == 'linux') {
@@ -189,31 +219,27 @@ function createWindow() {
}
}
if (process.env.ELECTRON_START_URL) {
loadMainWindow();
} else {
const apiProcess = fork(path.join(__dirname, '../packages/api/dist/bundle.js'), [
'--dynport',
'--is-electron-bundle',
'--native-modules',
path.join(__dirname, 'nativeModules'),
// '../../../src/nativeModules'
]);
apiProcess.on('message', msg => {
if (msg.msgtype == 'listening') {
const { port, authorization } = msg;
global['port'] = port;
global['authorization'] = authorization;
loadMainWindow();
}
});
}
const apiPackage = path.join(
__dirname,
process.env.DEVMODE ? '../../packages/api/src/index' : '../packages/api/dist/bundle.js'
);
// and load the index.html of the app.
// mainWindow.loadURL('http://localhost:3000');
global.API_PACKAGE = apiPackage;
global.NATIVE_MODULES = path.join(__dirname, 'nativeModules');
// Open the DevTools.
// mainWindow.webContents.openDevTools();
// console.log('global.API_PACKAGE', global.API_PACKAGE);
const api = require(apiPackage);
// console.log(
// 'REQUIRED',
// path.resolve(
// path.join(__dirname, process.env.DEVMODE ? '../../packages/api/src/index' : '../packages/api/dist/bundle.js')
// )
// );
const main = api.getMainModule();
main.initializeElectronSender(mainWindow.webContents);
main.useAllControllers(null, electron);
loadMainWindow();
// Emitted when the window is closed.
mainWindow.on('closed', function () {
@@ -225,7 +251,9 @@ function createWindow() {
}
function onAppReady() {
autoUpdater.checkForUpdatesAndNotify();
if (!process.env.DEVMODE) {
autoUpdater.checkForUpdatesAndNotify();
}
createWindow();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
FROM node:12-alpine
FROM node:14-alpine
WORKDIR /home/dbgate-docker

View File

@@ -5,7 +5,7 @@ let fillContent = '';
if (process.platform == 'win32') {
fillContent += `content.msnodesqlv8 = () => require('msnodesqlv8');`;
}
fillContent += `content['better-sqlite3-with-prebuilds'] = () => require('better-sqlite3-with-prebuilds');`;
fillContent += `content['better-sqlite3'] = () => require('better-sqlite3');`;
const getContent = (empty) => `
// this file is generated automatically by script fillNativeModules.js, do not edit it manually

View File

@@ -1,6 +1,6 @@
{
"private": true,
"version": "4.4.5-beta.2",
"version": "4.4.5-beta.24",
"name": "dbgate-all",
"workspaces": [
"packages/*",
@@ -9,6 +9,7 @@
],
"scripts": {
"start:api": "yarn workspace dbgate-api start",
"start:app": "cd app && yarn start",
"start:api:portal": "yarn workspace dbgate-api start:portal",
"start:api:covid": "yarn workspace dbgate-api start:covid",
"start:web": "yarn workspace dbgate-web dev",

View File

@@ -1,6 +1,6 @@
DEVMODE=1
CONNECTIONS=mysql,postgres
CONNECTIONS=mysql,postgres,mongo,mongo2
LABEL_mysql=MySql localhost
SERVER_mysql=localhost
@@ -15,3 +15,13 @@ USER_postgres=postgres
PASSWORD_postgres=test
PORT_postgres=5433
ENGINE_postgres=postgres@dbgate-plugin-postgres
LABEL_mongo=Mongo URL
URL_mongo=mongodb://localhost:27017
ENGINE_mongo=mongo@dbgate-plugin-mongo
LABEL_mongo2=Mongo Server
SERVER_mongo2=localhost
ENGINE_mongo2=mongo@dbgate-plugin-mongo
# docker run -p 3000:3000 -e CONNECTIONS=mongo -e URL_mongo=mongodb://localhost:27017 -e ENGINE_mongo=mongo@dbgate-plugin-mongo -e LABEL_mongo=mongo dbgate/dbgate:beta

View File

@@ -19,7 +19,6 @@
"dependencies": {
"async-lock": "^1.2.4",
"axios": "^0.21.1",
"better-sqlite3-with-prebuilds": "^7.1.8",
"body-parser": "^1.19.0",
"bufferutil": "^4.0.1",
"byline": "^5.0.0",
@@ -39,6 +38,7 @@
"fs-reverse": "^0.0.3",
"get-port": "^5.1.1",
"http": "^0.0.0",
"is-electron": "^2.2.1",
"js-yaml": "^4.1.0",
"json-stable-stringify": "^1.0.1",
"line-reader": "^0.4.0",
@@ -49,7 +49,6 @@
"node-ssh-forward": "^0.7.2",
"portfinder": "^1.0.28",
"simple-encryptor": "^4.0.0",
"socket.io": "^2.3.0",
"tar": "^6.0.5",
"uuid": "^3.4.0"
},
@@ -74,6 +73,7 @@
"webpack-cli": "^3.3.11"
},
"optionalDependencies": {
"msnodesqlv8": "^2.4.0"
"better-sqlite3": "7.4.5",
"msnodesqlv8": "^2.4.4"
}
}

View File

@@ -10,7 +10,7 @@ const { saveFreeTableData } = require('../utility/freeTableStorage');
const loadFilesRecursive = require('../utility/loadFilesRecursive');
module.exports = {
folders_meta: 'get',
folders_meta: true,
async folders() {
const folders = await fs.readdir(archivedir());
return [
@@ -27,14 +27,14 @@ module.exports = {
];
},
createFolder_meta: 'post',
createFolder_meta: true,
async createFolder({ folder }) {
await fs.mkdir(path.join(archivedir(), folder));
socket.emitChanged('archive-folders-changed');
return true;
},
createLink_meta: 'post',
createLink_meta: true,
async createLink({ linkedFolder }) {
const folder = await this.getNewArchiveFolder({ database: path.parse(linkedFolder).name + '.link' });
fs.writeFile(path.join(archivedir(), folder), linkedFolder);
@@ -43,7 +43,7 @@ module.exports = {
return folder;
},
files_meta: 'get',
files_meta: true,
async files({ folder }) {
const dir = resolveArchiveFolder(folder);
if (!(await fs.exists(dir))) return [];
@@ -70,23 +70,23 @@ module.exports = {
];
},
refreshFiles_meta: 'post',
refreshFiles_meta: true,
async refreshFiles({ folder }) {
socket.emitChanged(`archive-files-changed-${folder}`);
},
refreshFolders_meta: 'post',
refreshFolders_meta: true,
async refreshFolders() {
socket.emitChanged(`archive-folders-changed`);
},
deleteFile_meta: 'post',
deleteFile_meta: true,
async deleteFile({ folder, file, fileType }) {
await fs.unlink(path.join(resolveArchiveFolder(folder), `${file}.${fileType}`));
socket.emitChanged(`archive-files-changed-${folder}`);
},
renameFile_meta: 'post',
renameFile_meta: true,
async renameFile({ folder, file, newFile, fileType }) {
await fs.rename(
path.join(resolveArchiveFolder(folder), `${file}.${fileType}`),
@@ -95,14 +95,14 @@ module.exports = {
socket.emitChanged(`archive-files-changed-${folder}`);
},
renameFolder_meta: 'post',
renameFolder_meta: true,
async renameFolder({ folder, newFolder }) {
const uniqueName = await this.getNewArchiveFolder({ database: newFolder });
await fs.rename(path.join(archivedir(), folder), path.join(archivedir(), uniqueName));
socket.emitChanged(`archive-folders-changed`);
},
deleteFolder_meta: 'post',
deleteFolder_meta: true,
async deleteFolder({ folder }) {
if (!folder) throw new Error('Missing folder parameter');
if (folder.endsWith('.link')) {
@@ -113,14 +113,14 @@ module.exports = {
socket.emitChanged(`archive-folders-changed`);
},
saveFreeTable_meta: 'post',
saveFreeTable_meta: true,
async saveFreeTable({ folder, file, data }) {
await saveFreeTableData(path.join(resolveArchiveFolder(folder), `${file}.jsonl`), data);
socket.emitChanged(`archive-files-changed-${folder}`);
return true;
},
loadFreeTable_meta: 'post',
loadFreeTable_meta: true,
async loadFreeTable({ folder, file }) {
return new Promise((resolve, reject) => {
const fileStream = fs.createReadStream(path.join(resolveArchiveFolder(folder), `${file}.jsonl`));

View File

@@ -21,7 +21,7 @@ module.exports = {
}
},
get_meta: 'get',
get_meta: true,
async get() {
const permissions = process.env.PERMISSIONS ? process.env.PERMISSIONS.split(',') : null;
@@ -33,17 +33,17 @@ module.exports = {
};
},
platformInfo_meta: 'get',
platformInfo_meta: true,
async platformInfo() {
return platformInfo;
},
getSettings_meta: 'get',
getSettings_meta: true,
async getSettings() {
return this.settingsValue;
},
updateSettings_meta: 'post',
updateSettings_meta: true,
async updateSettings(values) {
if (!hasPermission(`settings/change`)) return false;
try {
@@ -60,7 +60,7 @@ module.exports = {
}
},
changelog_meta: 'get',
changelog_meta: true,
async changelog() {
const resp = await axios.default.get('https://raw.githubusercontent.com/dbgate/dbgate/master/CHANGELOG.md');
return resp.data;

View File

@@ -8,6 +8,9 @@ const { datadir, filesdir } = require('../utility/directories');
const socket = require('../utility/socket');
const { encryptConnection } = require('../utility/crypting');
const { handleProcessCommunication } = require('../utility/processComm');
const { pickSafeConnectionInfo } = require('../utility/crypting');
const processArgs = require('../utility/processArgs');
function getNamedArgs() {
const res = {};
@@ -37,7 +40,7 @@ function getDatabaseFileLabel(databaseFile) {
function getPortalCollections() {
if (process.env.CONNECTIONS) {
return _.compact(process.env.CONNECTIONS.split(',')).map(id => ({
const connections = _.compact(process.env.CONNECTIONS.split(',')).map(id => ({
_id: id,
engine: process.env[`ENGINE_${id}`],
server: process.env[`SERVER_${id}`],
@@ -45,11 +48,22 @@ function getPortalCollections() {
password: process.env[`PASSWORD_${id}`],
port: process.env[`PORT_${id}`],
databaseUrl: process.env[`URL_${id}`],
useDatabaseUrl: !!process.env[`URL_${id}`],
databaseFile: process.env[`FILE_${id}`],
defaultDatabase: process.env[`DATABASE_${id}`],
singleDatabase: !!process.env[`DATABASE_${id}`],
displayName: process.env[`LABEL_${id}`],
}));
console.log('Using connections from ENV variables:');
console.log(JSON.stringify(connections.map(pickSafeConnectionInfo), undefined, 2));
const noengine = connections.filter(x => !x.engine);
if (noengine.length > 0) {
console.log(
'Warning: Invalid CONNECTIONS configutation, missing ENGINE for connection ID:',
noengine.map(x => x._id)
);
}
return connections;
}
const args = getNamedArgs();
@@ -126,29 +140,34 @@ module.exports = {
}
},
list_meta: 'get',
list_meta: true,
async list() {
return portalConnections || this.datastore.find();
},
test_meta: {
method: 'post',
raw: true,
},
test(req, res) {
const subprocess = fork(process.argv[1], ['--start-process', 'connectProcess', ...process.argv.slice(3)]);
subprocess.on('message', resp => {
if (handleProcessCommunication(resp, subprocess)) return;
// @ts-ignore
const { msgtype } = resp;
if (msgtype == 'connected' || msgtype == 'error') {
res.json(resp);
}
test_meta: true,
test(connection) {
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
'connectProcess',
...processArgs.getPassArgs(),
// ...process.argv.slice(3),
]);
subprocess.send(connection);
return new Promise(resolve => {
subprocess.on('message', resp => {
if (handleProcessCommunication(resp, subprocess)) return;
// @ts-ignore
const { msgtype } = resp;
if (msgtype == 'connected' || msgtype == 'error') {
resolve(resp);
}
});
});
subprocess.send(req.body);
},
save_meta: 'post',
save_meta: true,
async save(connection) {
if (portalConnections) return;
let res;
@@ -162,7 +181,7 @@ module.exports = {
return res;
},
update_meta: 'post',
update_meta: true,
async update({ _id, values }) {
if (portalConnections) return;
const res = await this.datastore.update({ _id }, { $set: values });
@@ -170,7 +189,7 @@ module.exports = {
return res;
},
updateDatabase_meta: 'post',
updateDatabase_meta: true,
async updateDatabase({ conid, database, values }) {
if (portalConnections) return;
const conn = await this.datastore.find({ _id: conid });
@@ -185,7 +204,7 @@ module.exports = {
return res;
},
delete_meta: 'post',
delete_meta: true,
async delete(connection) {
if (portalConnections) return;
const res = await this.datastore.remove(_.pick(connection, '_id'));
@@ -193,14 +212,14 @@ module.exports = {
return res;
},
get_meta: 'get',
get_meta: true,
async get({ conid }) {
if (portalConnections) return portalConnections.find(x => x._id == conid);
if (portalConnections) return portalConnections.find(x => x._id == conid) || null;
const res = await this.datastore.find({ _id: conid });
return res[0];
return res[0] || null;
},
newSqliteDatabase_meta: 'post',
newSqliteDatabase_meta: true,
async newSqliteDatabase({ file }) {
const sqliteDir = path.join(filesdir(), 'sqlite');
if (!(await fs.exists(sqliteDir))) {

View File

@@ -25,6 +25,7 @@ const requireEngineDriver = require('../utility/requireEngineDriver');
const generateDeploySql = require('../shell/generateDeploySql');
const { createTwoFilesPatch } = require('diff');
const diff2htmlPage = require('../utility/diff2htmlPage');
const processArgs = require('../utility/processArgs');
module.exports = {
/** @type {import('dbgate-types').OpenedDatabaseConnection[]} */
@@ -74,10 +75,12 @@ module.exports = {
const existing = this.opened.find(x => x.conid == conid && x.database == database);
if (existing) return existing;
const connection = await connections.get({ conid });
const subprocess = fork(process.argv[1], [
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
'databaseConnectionProcess',
...process.argv.slice(3),
...processArgs.getPassArgs(),
// ...process.argv.slice(3),
]);
const lastClosed = this.closed[`${conid}/${database}`];
const newOpened = {
@@ -121,7 +124,7 @@ module.exports = {
return promise;
},
queryData_meta: 'post',
queryData_meta: true,
async queryData({ conid, database, sql }) {
console.log(`Processing query, conid=${conid}, database=${database}, sql=${sql}`);
const opened = await this.ensureOpened(conid, database);
@@ -132,7 +135,7 @@ module.exports = {
return res;
},
runScript_meta: 'post',
runScript_meta: true,
async runScript({ conid, database, sql }) {
console.log(`Processing script, conid=${conid}, database=${database}, sql=${sql}`);
const opened = await this.ensureOpened(conid, database);
@@ -140,21 +143,21 @@ module.exports = {
return res;
},
collectionData_meta: 'post',
collectionData_meta: true,
async collectionData({ conid, database, options }) {
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
return res.result;
},
updateCollection_meta: 'post',
updateCollection_meta: true,
async updateCollection({ conid, database, changeSet }) {
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
return res.result;
},
status_meta: 'get',
status_meta: true,
async status({ conid, database }) {
const existing = this.opened.find(x => x.conid == conid && x.database == database);
if (existing) {
@@ -176,7 +179,7 @@ module.exports = {
};
},
ping_meta: 'post',
ping_meta: true,
async ping({ conid, database }) {
let existing = this.opened.find(x => x.conid == conid && x.database == database);
@@ -192,7 +195,7 @@ module.exports = {
};
},
refresh_meta: 'post',
refresh_meta: true,
async refresh({ conid, database, keepOpen }) {
if (!keepOpen) this.close(conid, database);
@@ -200,7 +203,7 @@ module.exports = {
return { status: 'ok' };
},
syncModel_meta: 'post',
syncModel_meta: true,
async syncModel({ conid, database }) {
const conn = await this.ensureOpened(conid, database);
conn.subprocess.send({ msgtype: 'syncModel' });
@@ -224,13 +227,13 @@ module.exports = {
}
},
disconnect_meta: 'post',
disconnect_meta: true,
async disconnect({ conid, database }) {
await this.close(conid, database, true);
return { status: 'ok' };
},
structure_meta: 'get',
structure_meta: true,
async structure({ conid, database }) {
if (conid == '__model') {
const model = await importDbModel(database);
@@ -247,13 +250,14 @@ module.exports = {
// };
},
serverVersion_meta: 'get',
serverVersion_meta: true,
async serverVersion({ conid, database }) {
if (!conid) return null;
const opened = await this.ensureOpened(conid, database);
return opened.serverVersion;
return opened.serverVersion || null;
},
sqlPreview_meta: 'post',
sqlPreview_meta: true,
async sqlPreview({ conid, database, objects, options }) {
// wait for structure
await this.structure({ conid, database });
@@ -263,7 +267,7 @@ module.exports = {
return res;
},
exportModel_meta: 'post',
exportModel_meta: true,
async exportModel({ conid, database }) {
const archiveFolder = await archive.getNewArchiveFolder({ database });
await fs.mkdir(path.join(archivedir(), archiveFolder));
@@ -273,10 +277,13 @@ module.exports = {
return { archiveFolder };
},
generateDeploySql_meta: 'post',
generateDeploySql_meta: true,
async generateDeploySql({ conid, database, archiveFolder }) {
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'generateDeploySql', modelFolder: resolveArchiveFolder(archiveFolder) });
const res = await this.sendRequest(opened, {
msgtype: 'generateDeploySql',
modelFolder: resolveArchiveFolder(archiveFolder),
});
return res;
// const connection = await connections.get({ conid });
@@ -285,7 +292,7 @@ module.exports = {
// analysedStructure: await this.structure({ conid, database }),
// modelFolder: resolveArchiveFolder(archiveFolder),
// });
// const deployedModel = generateDbPairingId(await importDbModel(path.join(archivedir(), archiveFolder)));
// const currentModel = generateDbPairingId(await this.structure({ conid, database }));
// const currentModelPaired = matchPairedObjects(deployedModel, currentModel);
@@ -300,7 +307,7 @@ module.exports = {
// };
// return sql;
},
// runCommand_meta: 'post',
// runCommand_meta: true,
// async runCommand({ conid, database, sql }) {
// console.log(`Running SQL command , conid=${conid}, database=${database}, sql=${sql}`);
// const opened = await this.ensureOpened(conid, database);
@@ -343,7 +350,7 @@ module.exports = {
return res;
},
generateDbDiffReport_meta: 'post',
generateDbDiffReport_meta: true,
async generateDbDiffReport({ filePath, sourceConid, sourceDatabase, targetConid, targetDatabase }) {
const unifiedDiff = await this.getUnifiedDiff({ sourceConid, sourceDatabase, targetConid, targetDatabase });

View File

@@ -20,7 +20,7 @@ function deserialize(format, text) {
}
module.exports = {
list_meta: 'get',
list_meta: true,
async list({ folder }) {
if (!hasPermission(`files/${folder}/read`)) return [];
const dir = path.join(filesdir(), folder);
@@ -29,7 +29,7 @@ module.exports = {
return files;
},
listAll_meta: 'get',
listAll_meta: true,
async listAll() {
const folders = await fs.readdir(filesdir());
const res = [];
@@ -42,7 +42,7 @@ module.exports = {
return res;
},
delete_meta: 'post',
delete_meta: true,
async delete({ folder, file }) {
if (!hasPermission(`files/${folder}/write`)) return;
await fs.unlink(path.join(filesdir(), folder, file));
@@ -50,7 +50,7 @@ module.exports = {
socket.emitChanged(`all-files-changed`);
},
rename_meta: 'post',
rename_meta: true,
async rename({ folder, file, newFile }) {
if (!hasPermission(`files/${folder}/write`)) return;
await fs.rename(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
@@ -58,7 +58,7 @@ module.exports = {
socket.emitChanged(`all-files-changed`);
},
copy_meta: 'post',
copy_meta: true,
async copy({ folder, file, newFile }) {
if (!hasPermission(`files/${folder}/write`)) return;
await fs.copyFile(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
@@ -66,7 +66,7 @@ module.exports = {
socket.emitChanged(`all-files-changed`);
},
load_meta: 'post',
load_meta: true,
async load({ folder, file, format }) {
if (folder.startsWith('archive:')) {
const text = await fs.readFile(path.join(resolveArchiveFolder(folder.substring('archive:'.length)), file), {
@@ -80,7 +80,7 @@ module.exports = {
}
},
save_meta: 'post',
save_meta: true,
async save({ folder, file, data, format }) {
if (folder.startsWith('archive:')) {
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
@@ -101,12 +101,12 @@ module.exports = {
}
},
saveAs_meta: 'post',
saveAs_meta: true,
async saveAs({ filePath, data, format }) {
await fs.writeFile(filePath, serialize(format, data));
},
favorites_meta: 'get',
favorites_meta: true,
async favorites() {
if (!hasPermission(`files/favorites/read`)) return [];
const dir = path.join(filesdir(), 'favorites');
@@ -125,7 +125,7 @@ module.exports = {
return res;
},
generateUploadsFile_meta: 'get',
generateUploadsFile_meta: true,
async generateUploadsFile() {
const fileName = `${uuidv1()}.html`;
return {
@@ -134,7 +134,7 @@ module.exports = {
};
},
exportChart_meta: 'post',
exportChart_meta: true,
async exportChart({ filePath, title, config, image }) {
const fileName = path.parse(filePath).base;
const imageFile = fileName.replace('.html', '-preview.png');

View File

@@ -104,7 +104,7 @@ module.exports = {
return datastore;
},
getInfo_meta: 'get',
getInfo_meta: true,
async getInfo({ jslid }) {
const file = getJslFileName(jslid);
const firstLine = await readFirstLine(file);
@@ -112,13 +112,13 @@ module.exports = {
return null;
},
getRows_meta: 'post',
getRows_meta: true,
async getRows({ jslid, offset, limit, filters }) {
const datastore = await this.ensureDatastore(jslid);
return datastore.getRows(offset, limit, _.isEmpty(filters) ? null : filters);
},
getStats_meta: 'get',
getStats_meta: true,
getStats({ jslid }) {
const file = `${getJslFileName(jslid)}.stats`;
if (fs.existsSync(file)) {
@@ -146,7 +146,7 @@ module.exports = {
// }
},
saveFreeTable_meta: 'post',
saveFreeTable_meta: true,
async saveFreeTable({ jslid, data }) {
saveFreeTableData(getJslFileName(jslid), data);
return true;

View File

@@ -7,14 +7,14 @@ function pickObjectNames(array) {
}
module.exports = {
// tableData_meta: 'get',
// tableData_meta: true,
// async tableData({ conid, database, schemaName, pureName }) {
// const opened = await databaseConnections.ensureOpened(conid, database);
// const res = await databaseConnections.sendRequest(opened, { msgtype: 'tableData', schemaName, pureName });
// return res;
// },
listObjects_meta: 'get',
listObjects_meta: true,
async listObjects({ conid, database }) {
const opened = await databaseConnections.ensureOpened(conid, database);
const types = ['tables', 'collections', 'views', 'procedures', 'functions', 'triggers'];
@@ -27,7 +27,7 @@ module.exports = {
);
},
tableInfo_meta: 'get',
tableInfo_meta: true,
async tableInfo({ conid, database, schemaName, pureName }) {
const opened = await databaseConnections.ensureOpened(conid, database);
const table = opened.structure.tables.find(x => x.pureName == pureName && x.schemaName == schemaName);
@@ -38,7 +38,7 @@ module.exports = {
};
},
sqlObjectInfo_meta: 'get',
sqlObjectInfo_meta: true,
async sqlObjectInfo({ objectTypeField, conid, database, schemaName, pureName }) {
const opened = await databaseConnections.ensureOpened(conid, database);
const res = opened.structure[objectTypeField].find(x => x.pureName == pureName && x.schemaName == schemaName);

View File

@@ -12,7 +12,7 @@ const _ = require('lodash');
const packagedPluginsContent = require('../packagedPluginsContent');
module.exports = {
script_meta: 'get',
script_meta: true,
async script({ packageName }) {
const packagedContent = packagedPluginsContent();
@@ -30,7 +30,7 @@ module.exports = {
return data;
},
search_meta: 'get',
search_meta: true,
async search({ filter }) {
// DOCS: https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#get-v1search
const resp = await axios.default.get(
@@ -40,7 +40,7 @@ module.exports = {
return (objects || []).map(x => x.package);
},
info_meta: 'get',
info_meta: true,
async info({ packageName }) {
try {
const infoResp = await axios.default.get(`https://registry.npmjs.org/${packageName}`);
@@ -63,7 +63,7 @@ module.exports = {
}
},
installed_meta: 'get',
installed_meta: true,
async installed() {
const packagedContent = packagedPluginsContent();
@@ -107,7 +107,7 @@ module.exports = {
// await fs.writeFile(path.join(datadir(), 'removed-plugins'), this.removedPlugins.join('\n'));
// },
install_meta: 'post',
install_meta: true,
async install({ packageName }) {
if (!hasPermission(`plugins/install`)) return;
const dir = path.join(pluginsdir(), packageName);
@@ -120,7 +120,7 @@ module.exports = {
// await this.saveRemovePlugins();
},
uninstall_meta: 'post',
uninstall_meta: true,
async uninstall({ packageName }) {
if (!hasPermission(`plugins/install`)) return;
const dir = path.join(pluginsdir(), packageName);
@@ -130,7 +130,7 @@ module.exports = {
await this.saveRemovePlugins();
},
upgrade_meta: 'post',
upgrade_meta: true,
async upgrade({ packageName }) {
if (!hasPermission(`plugins/install`)) return;
const dir = path.join(pluginsdir(), packageName);
@@ -143,13 +143,13 @@ module.exports = {
socket.emitChanged(`installed-plugins-changed`);
},
command_meta: 'post',
command_meta: true,
async command({ packageName, command, args }) {
const content = requirePlugin(packageName);
return content.commands[command](args);
},
authTypes_meta: 'get',
authTypes_meta: true,
async authTypes({ engine }) {
const packageName = extractPackageName(engine);
const content = requirePlugin(packageName);

View File

@@ -34,7 +34,7 @@ function readCore(reader, skip, limit, filter) {
}
module.exports = {
read_meta: 'get',
read_meta: true,
async read({ skip, limit, filter }) {
const fileName = path.join(datadir(), 'query-history.jsonl');
// @ts-ignore
@@ -44,7 +44,7 @@ module.exports = {
return res;
},
write_meta: 'post',
write_meta: true,
async write({ data }) {
const fileName = path.join(datadir(), 'query-history.jsonl');
await fs.appendFile(fileName, JSON.stringify(data) + '\n');

View File

@@ -8,6 +8,7 @@ const { fork } = require('child_process');
const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
const { extractShellApiPlugins, extractShellApiFunctionName } = require('dbgate-tools');
const { handleProcessCommunication } = require('../utility/processComm');
const processArgs = require('../utility/processArgs');
function extractPlugins(script) {
const requireRegex = /\s*\/\/\s*@require\s+([^\s]+)\s*\n/g;
@@ -98,15 +99,22 @@ module.exports = {
const pluginNames = _.union(fs.readdirSync(pluginsdir()), packagedPluginList);
console.log(`RUNNING SCRIPT ${scriptFile}`);
// const subprocess = fork(scriptFile, ['--checkParent', '--max-old-space-size=8192'], {
const subprocess = fork(scriptFile, ['--checkParent', ...process.argv.slice(3)], {
cwd: directory,
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
env: {
...process.env,
DBGATE_API: global['dbgateApiModulePath'] || process.argv[1],
..._.fromPairs(pluginNames.map(name => [`PLUGIN_${_.camelCase(name)}`, getPluginBackendPath(name)])),
},
});
const subprocess = fork(
scriptFile,
[
'--checkParent', // ...process.argv.slice(3)
...processArgs.getPassArgs(),
],
{
cwd: directory,
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
env: {
...process.env,
DBGATE_API: global['API_PACKAGE'] || global['dbgateApiModulePath'] || process.argv[1],
..._.fromPairs(pluginNames.map(name => [`PLUGIN_${_.camelCase(name)}`, getPluginBackendPath(name)])),
},
}
);
const pipeDispatcher = severity => data =>
this.dispatchMessage(runid, { severity, message: data.toString().trim() });
@@ -136,21 +144,21 @@ module.exports = {
if (handleProcessCommunication(message, subprocess)) return;
this[`handle_${msgtype}`](runid, message);
});
return newOpened;
return _.pick(newOpened, ['runid']);
},
start_meta: 'post',
start_meta: true,
async start({ script }) {
const runid = uuidv1();
return this.startCore(runid, scriptTemplate(script, false));
},
getNodeScript_meta: 'post',
getNodeScript_meta: true,
async getNodeScript({ script }) {
return scriptTemplate(script, true);
},
cancel_meta: 'post',
cancel_meta: true,
async cancel({ runid }) {
const runner = this.opened.find(x => x.runid == runid);
if (!runner) {
@@ -160,7 +168,7 @@ module.exports = {
return { state: 'ok' };
},
files_meta: 'get',
files_meta: true,
async files({ runid }) {
const directory = path.join(rundir(), runid);
const files = await fs.readdir(directory);
@@ -176,7 +184,7 @@ module.exports = {
return res;
},
loadReader_meta: 'post',
loadReader_meta: true,
async loadReader({ functionName, props }) {
const promise = new Promise((resolve, reject) => {
const runid = uuidv1();

View File

@@ -6,6 +6,7 @@ const AsyncLock = require('async-lock');
const { handleProcessCommunication } = require('../utility/processComm');
const lock = new AsyncLock();
const config = require('./config');
const processArgs = require('../utility/processArgs');
module.exports = {
opened: [],
@@ -37,10 +38,12 @@ module.exports = {
const existing = this.opened.find(x => x.conid == conid);
if (existing) return existing;
const connection = await connections.get({ conid });
const subprocess = fork(process.argv[1], [
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
'serverConnectionProcess',
...process.argv.slice(3),
...processArgs.getPassArgs(),
// ...process.argv.slice(3),
]);
const newOpened = {
conid,
@@ -86,25 +89,25 @@ module.exports = {
}
},
disconnect_meta: 'post',
disconnect_meta: true,
async disconnect({ conid }) {
await this.close(conid, true);
return { status: 'ok' };
},
listDatabases_meta: 'get',
listDatabases_meta: true,
async listDatabases({ conid }) {
const opened = await this.ensureOpened(conid);
return opened.databases;
},
version_meta: 'get',
version_meta: true,
async version({ conid }) {
const opened = await this.ensureOpened(conid);
return opened.version;
},
serverStatus_meta: 'get',
serverStatus_meta: true,
async serverStatus() {
return {
...this.closed,
@@ -112,7 +115,7 @@ module.exports = {
};
},
ping_meta: 'post',
ping_meta: true,
async ping({ connections }) {
await Promise.all(
_.uniq(connections).map(async conid => {
@@ -128,7 +131,7 @@ module.exports = {
return { status: 'ok' };
},
refresh_meta: 'post',
refresh_meta: true,
async refresh({ conid, keepOpen }) {
if (!keepOpen) this.close(conid);
@@ -136,7 +139,7 @@ module.exports = {
return { status: 'ok' };
},
createDatabase_meta: 'post',
createDatabase_meta: true,
async createDatabase({ conid, name }) {
const opened = await this.ensureOpened(conid);
opened.subprocess.send({ msgtype: 'createDatabase', name });

View File

@@ -5,6 +5,7 @@ const socket = require('../utility/socket');
const { fork } = require('child_process');
const jsldata = require('./jsldata');
const { handleProcessCommunication } = require('../utility/processComm');
const processArgs = require('../utility/processArgs');
module.exports = {
/** @type {import('dbgate-types').OpenedSession[]} */
@@ -61,11 +62,17 @@ module.exports = {
handle_ping() {},
create_meta: 'post',
create_meta: true,
async create({ conid, database }) {
const sesid = uuidv1();
const connection = await connections.get({ conid });
const subprocess = fork(process.argv[1], ['--start-process', 'sessionProcess', ...process.argv.slice(3)]);
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
'sessionProcess',
...processArgs.getPassArgs(),
// ...process.argv.slice(3),
]);
const newOpened = {
conid,
database,
@@ -81,10 +88,10 @@ module.exports = {
this[`handle_${msgtype}`](sesid, message);
});
subprocess.send({ msgtype: 'connect', ...connection, database });
return newOpened;
return _.pick(newOpened, ['conid', 'database', 'sesid']);
},
executeQuery_meta: 'post',
executeQuery_meta: true,
async executeQuery({ sesid, sql }) {
const session = this.opened.find(x => x.sesid == sesid);
if (!session) {
@@ -98,7 +105,7 @@ module.exports = {
return { state: 'ok' };
},
// cancel_meta: 'post',
// cancel_meta: true,
// async cancel({ sesid }) {
// const session = this.opened.find((x) => x.sesid == sesid);
// if (!session) {
@@ -108,7 +115,7 @@ module.exports = {
// return { state: 'ok' };
// },
kill_meta: 'post',
kill_meta: true,
async kill({ sesid }) {
const session = this.opened.find(x => x.sesid == sesid);
if (!session) {
@@ -119,7 +126,7 @@ module.exports = {
return { state: 'ok' };
},
// runCommand_meta: 'post',
// runCommand_meta: true,
// async runCommand({ conid, database, sql }) {
// console.log(`Running SQL command , conid=${conid}, database=${database}, sql=${sql}`);
// const opened = await this.ensureOpened(conid, database);

View File

@@ -8,7 +8,7 @@ if (processArgs.startProcess) {
const proc = require('./proc');
const module = proc[processArgs.startProcess];
module.start();
} else if (!module['parent'] && !processArgs.checkParent) {
} else if (!processArgs.checkParent && !global['API_PACKAGE'] && !global['dbgateApiModulePath']) {
const main = require('./main');
main.start();

View File

@@ -4,12 +4,8 @@ const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload');
const http = require('http');
const cors = require('cors');
const io = require('socket.io');
const fs = require('fs');
const getPort = require('get-port');
const childProcessChecker = require('./utility/childProcessChecker');
const path = require('path');
const crypto = require('crypto');
const useController = require('./utility/useController');
const socket = require('./utility/socket');
@@ -31,10 +27,7 @@ const queryHistory = require('./controllers/queryHistory');
const { rundir } = require('./utility/directories');
const platformInfo = require('./utility/platformInfo');
const processArgs = require('./utility/processArgs');
const timingSafeCheckToken = require('./utility/timingSafeCheckToken');
let authorization = null;
let checkLocalhostOrigin = null;
function start() {
@@ -43,7 +36,6 @@ function start() {
const app = express();
const server = http.createServer(app);
socket.set(io(server));
if (process.env.LOGIN && process.env.PASSWORD) {
app.use(
@@ -58,9 +50,6 @@ function start() {
}
app.use(function (req, res, next) {
if (authorization && !timingSafeCheckToken(req.headers.authorization, authorization)) {
return res.status(403).json({ error: 'Not authorized!' });
}
if (checkLocalhostOrigin) {
if (
req.headers.origin &&
@@ -81,6 +70,20 @@ function start() {
});
app.use(cors());
app.get('/stream', async function (req, res) {
res.set({
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
});
res.flushHeaders();
// Tell the client to retry every 10 seconds if connectivity is lost
res.write('retry: 10000\n\n');
socket.setSseResponse(res);
});
app.use(bodyParser.json({ limit: '50mb' }));
app.use(
@@ -90,20 +93,7 @@ function start() {
})
);
useController(app, '/connections', connections);
useController(app, '/server-connections', serverConnections);
useController(app, '/database-connections', databaseConnections);
useController(app, '/metadata', metadata);
useController(app, '/sessions', sessions);
useController(app, '/runners', runners);
useController(app, '/jsldata', jsldata);
useController(app, '/config', config);
useController(app, '/archive', archive);
useController(app, '/uploads', uploads);
useController(app, '/plugins', plugins);
useController(app, '/files', files);
useController(app, '/scheduler', scheduler);
useController(app, '/query-history', queryHistory);
useAllControllers(app, null);
// if (process.env.PAGES_DIRECTORY) {
// app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
@@ -122,19 +112,7 @@ function start() {
}
}
if (processArgs.dynport) {
childProcessChecker();
authorization = crypto.randomBytes(32).toString('hex');
getPort().then(port => {
checkLocalhostOrigin = `localhost:${port}`;
server.listen(port, () => {
console.log(`DbGate API listening on port ${port}`);
process.send({ msgtype: 'listening', port, authorization });
});
});
} else if (platformInfo.isNpmDist) {
if (platformInfo.isNpmDist) {
app.use(express.static(path.join(__dirname, '../../dbgate-web/public')));
getPort({ port: 5000 }).then(port => {
server.listen(port, () => {
@@ -142,8 +120,47 @@ function start() {
});
});
} else {
server.listen(3000);
const port = process.env.PORT || 3000;
console.log('DbGate API listening on port', port);
server.listen(port);
}
function shutdown() {
console.log('\nShutting down DbGate API server');
server.close(() => {
console.log('Server shut down, terminating');
process.exit(0);
});
setTimeout(() => {
console.log('Server close timeout, terminating');
process.exit(0);
}, 1000);
}
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
process.on('SIGBREAK', shutdown);
}
module.exports = { start };
function useAllControllers(app, electron) {
useController(app, electron, '/connections', connections);
useController(app, electron, '/server-connections', serverConnections);
useController(app, electron, '/database-connections', databaseConnections);
useController(app, electron, '/metadata', metadata);
useController(app, electron, '/sessions', sessions);
useController(app, electron, '/runners', runners);
useController(app, electron, '/jsldata', jsldata);
useController(app, electron, '/config', config);
useController(app, electron, '/archive', archive);
useController(app, electron, '/uploads', uploads);
useController(app, electron, '/plugins', plugins);
useController(app, electron, '/files', files);
useController(app, electron, '/scheduler', scheduler);
useController(app, electron, '/query-history', queryHistory);
}
function initializeElectronSender(electronSender) {
socket.setElectronSender(electronSender);
}
module.exports = { start, useAllControllers, initializeElectronSender };

View File

@@ -1,5 +1,13 @@
const argIndex = process.argv.indexOf('--native-modules');
const redirectFile = argIndex > 0 ? process.argv[argIndex + 1] : null;
const redirectFile = global['NATIVE_MODULES'] || (argIndex > 0 ? process.argv[argIndex + 1] : null);
// @ts-ignore
module.exports = redirectFile ? __non_webpack_require__(redirectFile) : require('./nativeModulesContent');
function requireDynamic(file) {
try {
// @ts-ignore
return __non_webpack_require__(redirectFile);
} catch (err) {
return require(redirectFile);
}
}
module.exports = redirectFile ? requireDynamic(redirectFile) : require('./nativeModulesContent');

View File

@@ -2,17 +2,9 @@ const childProcessChecker = require('../utility/childProcessChecker');
const requireEngineDriver = require('../utility/requireEngineDriver');
const connectUtility = require('../utility/connectUtility');
const { handleProcessCommunication } = require('../utility/processComm');
const { pickSafeConnectionInfo } = require('../utility/crypting');
const _ = require('lodash');
function pickSafeConnectionInfo(connection) {
return _.mapValues(connection, (v, k) => {
if (k == 'engine' || k == 'port' || k == 'authType' || k == 'sshMode' || k == 'passwordMode') return v;
if (v === null || v === true || v === false) return v;
if (v) return '***';
return undefined;
});
}
const formatErrorDetail = (e, connection) => `${e.stack}
Error JSON: ${JSON.stringify(e, undefined, 2)}

View File

@@ -270,6 +270,7 @@ function start() {
try {
await handleMessage(message);
} catch (e) {
console.error('Error in DB connection', e);
process.send({ msgtype: 'error', error: e.message });
}
});

View File

@@ -1,6 +1,7 @@
const { fork } = require('child_process');
const uuidv1 = require('uuid/v1');
const { handleProcessCommunication } = require('./processComm');
const processArgs = require('../utility/processArgs');
class DatastoreProxy {
constructor(file) {
@@ -29,7 +30,13 @@ class DatastoreProxy {
async ensureSubprocess() {
if (!this.subprocess) {
this.subprocess = fork(process.argv[1], ['--start-process', 'jslDatastoreProcess', ...process.argv.slice(3)]);
this.subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
'jslDatastoreProcess',
...processArgs.getPassArgs(),
// ...process.argv.slice(3),
]);
this.subprocess.on('message', message => {
// @ts-ignore

View File

@@ -2,6 +2,7 @@ const crypto = require('crypto');
const simpleEncryptor = require('simple-encryptor');
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
const { datadir } = require('./directories');
@@ -81,8 +82,18 @@ function decryptConnection(connection) {
return connection;
}
function pickSafeConnectionInfo(connection) {
return _.mapValues(connection, (v, k) => {
if (k == 'engine' || k == 'port' || k == 'authType' || k == 'sshMode' || k == 'passwordMode') return v;
if (v === null || v === true || v === false) return v;
if (v) return '***';
return undefined;
});
}
module.exports = {
loadEncryptionKey,
encryptConnection,
decryptConnection,
pickSafeConnectionInfo,
};

View File

@@ -41,6 +41,10 @@ const archivedir = dirFunc('archive');
const filesdir = dirFunc('files');
function packagedPluginsDir() {
// console.log('CALL DIR FROM', new Error('xxx').stack);
// console.log('__dirname', __dirname);
// console.log('platformInfo.isElectronBundle', platformInfo.isElectronBundle);
// console.log('platformInfo.isForkedApi', platformInfo.isForkedApi);
if (platformInfo.isDevMode) {
return path.resolve(__dirname, '../../../../plugins');
}
@@ -53,6 +57,12 @@ function packagedPluginsDir() {
}
if (platformInfo.isElectronBundle) {
return path.resolve(__dirname, '../../plugins');
// if (platformInfo.isForkedApi) {
// return path.resolve(__dirname, '../plugins');
// } else {
// return path.resolve(__dirname, '../../plugins');
// }
}
return null;
}

View File

@@ -2,6 +2,7 @@ const fs = require('fs');
const os = require('os');
const path = require('path');
const processArgs = require('./processArgs');
const isElectron = require('is-electron');
const platform = process.env.OS_OVERRIDE ? process.env.OS_OVERRIDE : process.platform;
const isWindows = platform === 'win32';
@@ -10,6 +11,7 @@ const isLinux = platform === 'linux';
const isDocker = fs.existsSync('/home/dbgate-docker/public');
const isDevMode = process.env.DEVMODE == '1';
const isNpmDist = !!global['dbgateApiModulePath'];
const isForkedApi = processArgs.isForkedApi;
// function moduleAvailable(name) {
// try {
@@ -20,14 +22,14 @@ const isNpmDist = !!global['dbgateApiModulePath'];
// }
// }
const isElectronBundle = processArgs.isElectronBundle;
const platformInfo = {
isWindows,
isMac,
isLinux,
isDocker,
isElectronBundle,
isElectronBundle: isElectron() && !isDevMode,
isForkedApi,
isElectron: isElectron(),
isDevMode,
isNpmDist,
isSnap: process.env.ELECTRON_SNAP == 'true',

View File

@@ -7,15 +7,17 @@ function getNamedArg(name) {
}
const checkParent = process.argv.includes('--checkParent');
const dynport = process.argv.includes('--dynport');
const nativeModules = getNamedArg('--native-modules');
const startProcess = getNamedArg('--start-process');
const isElectronBundle = process.argv.includes('--is-electron-bundle');
const isForkedApi = process.argv.includes('--is-forked-api');
function getPassArgs() {
if (global['NATIVE_MODULES']) return ['--native-modules', global['NATIVE_MODULES']];
return [];
}
module.exports = {
checkParent,
nativeModules,
startProcess,
dynport,
isElectronBundle,
isForkedApi,
getPassArgs,
};

View File

@@ -1,5 +1,6 @@
const _ = require('lodash');
const requirePlugin = require('../shell/requirePlugin');
const { pickSafeConnectionInfo } = require('./crypting');
/** @returns {import('dbgate-types').EngineDriver} */
function requireEngineDriver(connection) {
@@ -10,14 +11,14 @@ function requireEngineDriver(connection) {
engine = connection.engine;
}
if (!engine) {
throw new Error('Could not get driver from connection');
throw new Error(`Could not get driver from connection ${JSON.stringify(pickSafeConnectionInfo(connection))}`);
}
if (engine.includes('@')) {
const [shortName, packageName] = engine.split('@');
const plugin = requirePlugin(packageName);
return plugin.drivers.find(x => x.engine == engine);
}
throw new Error(`Could not found engine driver ${engine}`);
throw new Error(`Could not find engine driver ${engine}`);
}
module.exports = requireEngineDriver;

View File

@@ -1,19 +1,29 @@
let socket = null;
let sseResponse = null;
let electronSender = null;
let init = '';
module.exports = {
set(value) {
socket = value;
setSseResponse(value) {
sseResponse = value;
},
get() {
return socket;
setElectronSender(value) {
electronSender = value;
},
emit(message, data) {
// console.log('EMIT:', message, data);
socket.emit(message, data);
if (electronSender) {
electronSender.send(message, data == null ? null : data);
} else if (sseResponse) {
if (init) {
sseResponse.write(init);
init = '';
}
sseResponse.write(`event: ${message}\ndata: ${JSON.stringify(data == null ? null : data)}\n\n`);
} else {
init += sseResponse;
}
},
emitChanged(key) {
// console.log('EMIT_CHANGED:', key);
socket.emit('clean-cache', key);
socket.emit(key);
this.emit('clean-cache', key);
this.emit(key);
},
};

View File

@@ -4,7 +4,7 @@ const express = require('express');
/**
* @param {string} route
*/
module.exports = function useController(app, route, controller) {
module.exports = function useController(app, electron, route, controller) {
const router = express.Router();
if (controller._init) {
@@ -23,24 +23,39 @@ module.exports = function useController(app, route, controller) {
const meta = controller[`${key}_meta`];
if (!meta) continue;
let method = 'get';
const routeAction = `/${_.kebabCase(key)}`;
if (electron) {
if (meta === true) {
const handler = `${route.substring(1)}-${_.kebabCase(key)}`;
// console.log('REGISTERING HANDLER', handler);
electron.ipcMain.handle(handler, async (event, args) => {
const data = await controller[key](args);
// console.log('HANDLED API', handler, data);
return data;
});
}
continue;
}
let method = 'post';
let raw = false;
let rawParams = false;
if (_.isString(meta)) {
method = meta;
}
// if (_.isString(meta)) {
// method = meta;
// }
if (_.isPlainObject(meta)) {
method = meta.method;
raw = meta.raw;
rawParams = meta.rawParams;
}
const route = `/${_.kebabCase(key)}`;
if (raw) {
router[method](route, controller[key]);
router[method](routeAction, controller[key]);
} else {
router[method](route, async (req, res) => {
router[method](routeAction, async (req, res) => {
// if (controller._init && !controller._init_called) {
// await controller._init();
// controller._init_called = true;
@@ -58,5 +73,7 @@ module.exports = function useController(app, route, controller) {
}
}
app.use(route, router);
if (app) {
app.use(route, router);
}
};

View File

@@ -43,9 +43,7 @@
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0",
"rollup-plugin-web-worker-loader": "^1.6.1",
"sirv-cli": "^1.0.0",
"socket.io-client": "^2.3.0",
"sql-formatter": "^2.3.3",
"svelte": "^3.43.0",
"svelte-check": "^1.0.0",

View File

@@ -7,10 +7,8 @@ import { terser } from 'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';
import replace from '@rollup/plugin-replace';
import webWorkerLoader from 'rollup-plugin-web-worker-loader';
import css from 'rollup-plugin-css-only';
const production = !process.env.ROLLUP_WATCH;
function serve() {
@@ -34,77 +32,96 @@ function serve() {
};
}
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js',
export default [
{
input: 'src/query/QueryParserWorker.js',
output: {
sourcemap: true,
format: 'iife',
file: 'public/build/query-parser-worker.js',
},
plugins: [
commonjs(),
resolve({
browser: true,
}),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
},
plugins: [
copy({
targets: [
{
src: '../../node_modules/@mdi/font/css/materialdesignicons.css',
dest: 'public/build/fonts/',
{
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js',
},
plugins: [
copy({
targets: [
{
src: '../../node_modules/@mdi/font/css/materialdesignicons.css',
dest: 'public/build/fonts/',
},
{
src: '../../node_modules/@mdi/font/fonts/*',
dest: 'public/build/fonts/',
},
{
src: '../../node_modules/diff2html/bundles/css/diff2html.min.css',
dest: 'public/build/',
},
],
}),
replace({
'process.env.API_URL': JSON.stringify(process.env.API_URL),
}),
svelte({
preprocess: sveltePreprocess({ sourceMap: !production }),
compilerOptions: {
// enable run-time checks when not in production
dev: !production,
},
{
src: '../../node_modules/@mdi/font/fonts/*',
dest: 'public/build/fonts/',
},
{
src: '../../node_modules/diff2html/bundles/css/diff2html.min.css',
dest: 'public/build/',
},
],
}),
}),
// we'll extract any component CSS out into
// a separate file - better for performance
css({ output: 'bundle.css' }),
replace({
'process.env.API_URL': JSON.stringify(process.env.API_URL),
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte'],
}),
commonjs(),
typescript({
sourceMap: !production,
inlineSources: !production,
}),
svelte({
preprocess: sveltePreprocess({ sourceMap: !production }),
compilerOptions: {
// enable run-time checks when not in production
dev: !production,
},
}),
// we'll extract any component CSS out into
// a separate file - better for performance
css({ output: 'bundle.css' }),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte'],
}),
commonjs(),
typescript({
sourceMap: !production,
inlineSources: !production,
}),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
webWorkerLoader(),
],
watch: {
clearScreen: false,
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
watch: {
clearScreen: true,
},
},
};
];

View File

@@ -7,20 +7,37 @@
import PluginsProvider from './plugins/PluginsProvider.svelte';
import Screen from './Screen.svelte';
import { loadingPluginStore } from './stores';
import { loadingPluginStore, subscribeApiDependendStores } from './stores';
import { setAppLoaded } from './utility/appLoadManager';
import axiosInstance from './utility/axiosInstance';
import ErrorHandler from './utility/ErrorHandler.svelte';
import OpenTabsOnStartup from './utility/OpenTabsOnStartup.svelte';
// import { shouldWaitForElectronInitialize } from './utility/getElectron';
import { subscribeConnectionPingers } from './utility/connectionsPinger';
import { subscribePermissionCompiler } from './utility/hasPermission';
import { apiCall } from './utility/api';
let loadedApi = false;
async function loadApi() {
// if (shouldWaitForElectronInitialize()) {
// setTimeout(loadApi, 100);
// return;
// }
try {
const settings = await axiosInstance.get('config/get-settings');
const connections = await axiosInstance.get('connections/list');
const config = await axiosInstance.get('config/get');
loadedApi = settings?.data && connections?.data && config?.data;
// console.log('************** LOADING API');
const settings = await apiCall('config/get-settings');
const connections = await apiCall('connections/list');
const config = await apiCall('config/get');
loadedApi = settings && connections && config;
if (loadedApi) {
subscribeApiDependendStores();
subscribeConnectionPingers();
subscribePermissionCompiler();
}
if (!loadedApi) {
console.log('API not initialized correctly, trying again in 1s');
setTimeout(loadApi, 1000);
@@ -43,14 +60,13 @@
setAppLoaded();
}
}
</script>
<DataGridRowHeightMeter />
<ErrorHandler />
<CommandListener />
{#if loadedApi}
<DataGridRowHeightMeter />
<CommandListener />
<PluginsProvider />
{#if $loadingPluginStore?.loaded}
<OpenTabsOnStartup />

View File

@@ -16,7 +16,7 @@
const connProps: any = {};
let tooltip = undefined;
const resp = await axiosInstance.post('files/load', {
const resp = await apiCall('files/load', {
folder: 'archive:' + folderName,
file: fileName + '.' + fileType,
format: 'text',
@@ -36,7 +36,7 @@
...connProps,
},
},
{ editor: resp.data }
{ editor: resp }
);
}
@@ -69,7 +69,6 @@
import { archiveFilesAsDataSheets, currentArchive, extensions, getCurrentDatabase } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import createQuickExportMenu from '../utility/createQuickExportMenu';
import { exportElectronFile } from '../utility/exportElectronFile';
import openNewTab from '../utility/openNewTab';
@@ -82,6 +81,7 @@
markArchiveFileAsDataSheet,
markArchiveFileAsReadonly,
} from '../utility/archiveTools';
import { apiCall } from '../utility/api';
export let data;
@@ -91,7 +91,7 @@
label: 'New file name',
header: 'Rename file',
onConfirm: newFile => {
axiosInstance.post('archive/rename-file', {
apiCall('archive/rename-file', {
file: data.fileName,
folder: data.folderName,
fileType: data.fileType,
@@ -105,7 +105,7 @@
showModal(ConfirmModal, {
message: `Really delete file ${data.fileName}?`,
onConfirm: () => {
axiosInstance.post('archive/delete-file', {
apiCall('archive/delete-file', {
file: data.fileName,
folder: data.folderName,
fileType: data.fileType,

View File

@@ -9,7 +9,6 @@
import { currentArchive, currentDatabase } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import openNewTab from '../utility/openNewTab';
import AppObjectCore from './AppObjectCore.svelte';
import newQuery from '../query/newQuery';
@@ -17,6 +16,7 @@
import ConfirmModal from '../modals/ConfirmModal.svelte';
import InputTextModal from '../modals/InputTextModal.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { apiCall } from '../utility/api';
export let data;
@@ -26,7 +26,7 @@
? `Really delete link to folder ${data.name}? Folder content remains untouched.`
: `Really delete folder ${data.name}?`,
onConfirm: () => {
axiosInstance.post('archive/delete-folder', { folder: data.name });
apiCall('archive/delete-folder', { folder: data.name });
},
});
};
@@ -41,7 +41,7 @@
label: 'New folder name',
header: 'Rename folder',
onConfirm: async newFolder => {
await axiosInstance.post('archive/rename-folder', {
await apiCall('archive/rename-folder', {
folder: data.name,
newFolder: newFolder + suffix,
});
@@ -78,16 +78,16 @@ await dbgateApi.deployDb(${JSON.stringify(
};
const handleGenerateDeploySql = async () => {
const resp = await axiosInstance.post('database-connections/generate-deploy-sql', {
const resp = await apiCall('database-connections/generate-deploy-sql', {
conid: $currentDatabase.connection._id,
database: $currentDatabase.name,
archiveFolder: data.name,
});
if (resp.data.errorMessage) {
showModal(ErrorMessageModal, { message: resp.data.errorMessage });
if (resp.errorMessage) {
showModal(ErrorMessageModal, { message: resp.errorMessage });
} else {
newQuery({ initialData: resp.data.sql });
newQuery({ initialData: resp.sql });
}
};

View File

@@ -17,7 +17,6 @@
import _ from 'lodash';
import AppObjectCore from './AppObjectCore.svelte';
import { currentDatabase, extensions, getCurrentConfig, getOpenedConnections, openedConnections } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import { filterName } from 'dbgate-tools';
import { showModal } from '../modals/modalTools';
import ConnectionModal from '../modals/ConnectionModal.svelte';
@@ -29,6 +28,7 @@
import getConnectionLabel from '../utility/getConnectionLabel';
import { getDatabaseList } from '../utility/metadataLoaders';
import { getLocalStorage } from '../utility/storageCache';
import { apiCall } from '../utility/api';
export let data;
export let passProps;
@@ -44,14 +44,14 @@
const handleConnect = () => {
if (data.singleDatabase) {
$currentDatabase = { connection: data, name: data.defaultDatabase };
axiosInstance.post('database-connections/refresh', {
apiCall('database-connections/refresh', {
conid: data._id,
database: data.defaultDatabase,
keepOpen: true,
});
} else {
$openedConnections = _.uniq([...$openedConnections, data._id]);
axiosInstance.post('server-connections/refresh', {
apiCall('server-connections/refresh', {
conid: data._id,
keepOpen: true,
});
@@ -61,16 +61,16 @@
const getContextMenu = () => {
const config = getCurrentConfig();
const handleRefresh = () => {
axiosInstance.post('server-connections/refresh', { conid: data._id });
apiCall('server-connections/refresh', { conid: data._id });
};
const handleDisconnect = () => {
openedConnections.update(list => list.filter(x => x != data._id));
if (electron) {
axiosInstance.post('server-connections/disconnect', { conid: data._id });
apiCall('server-connections/disconnect', { conid: data._id });
}
if (_.get($currentDatabase, 'connection._id') == data._id) {
if (electron) {
axiosInstance.post('database-connections/disconnect', { conid: data._id, database: $currentDatabase.name });
apiCall('database-connections/disconnect', { conid: data._id, database: $currentDatabase.name });
}
currentDatabase.set(null);
}
@@ -81,11 +81,11 @@
const handleDelete = () => {
showModal(ConfirmModal, {
message: `Really delete connection ${getConnectionLabel(data)}?`,
onConfirm: () => axiosInstance.post('connections/delete', data),
onConfirm: () => apiCall('connections/delete', data),
});
};
const handleDuplicate = () => {
axiosInstance.post('connections/save', {
apiCall('connections/save', {
...data,
_id: undefined,
displayName: `${getConnectionLabel(data)} - copy`,
@@ -97,7 +97,7 @@
value: 'newdb',
label: 'Database name',
onConfirm: name =>
axiosInstance.post('server-connections/create-database', {
apiCall('server-connections/create-database', {
conid: data._id,
name,
}),

View File

@@ -1,6 +1,5 @@
<script lang="ts" context="module">
export const extractKey = props => props.name;
const electron = getElectron();
export function getDatabaseMenuItems(connection, name, $extensions, $currentDatabase) {
const handleNewQuery = () => {
@@ -48,13 +47,11 @@
header: 'Create collection',
onConfirm: async newCollection => {
const dbid = { conid: connection._id, database: name };
await axiosInstance.request({
url: 'database-connections/run-script',
method: 'post',
params: dbid,
data: { sql: `db.createCollection('${newCollection}')` },
await apiCall('database-connections/run-script', {
...dbid,
sql: `db.createCollection('${newCollection}')`,
});
axiosInstance.post('database-connections/sync-model', dbid);
await apiCall('database-connections/sync-model', dbid);
},
});
};
@@ -89,20 +86,21 @@
};
const handleDisconnect = () => {
const electron = getElectron();
if (electron) {
axiosInstance.post('database-connections/disconnect', { conid: connection._id, database: name });
apiCall('database-connections/disconnect', { conid: connection._id, database: name });
}
currentDatabase.set(null);
};
const handleExportModel = async () => {
const resp = await axiosInstance.post('database-connections/export-model', {
const resp = await apiCall('database-connections/export-model', {
conid: connection._id,
database: name,
});
currentArchive.set(resp.data.archiveFolder);
currentArchive.set(resp.archiveFolder);
selectedWidget.set('archive');
showSnackbarSuccess(`Saved to archive ${resp.data.archiveFolder}`);
showSnackbarSuccess(`Saved to archive ${resp.archiveFolder}`);
};
const handleCompareWithCurrentDb = () => {
@@ -173,7 +171,6 @@
pinnedDatabases,
selectedWidget,
} from '../stores';
import axiosInstance from '../utility/axiosInstance';
import getElectron from '../utility/getElectron';
import openNewTab from '../utility/openNewTab';
import AppObjectCore from './AppObjectCore.svelte';
@@ -182,6 +179,7 @@
import InputTextModal from '../modals/InputTextModal.svelte';
import { getDatabaseInfo } from '../utility/metadataLoaders';
import { openJsonDocument } from '../tabs/JsonTab.svelte';
import { apiCall } from '../utility/api';
export let data;
export let passProps;

View File

@@ -408,9 +408,9 @@
import { exportElectronFile } from '../utility/exportElectronFile';
import createQuickExportMenu from '../utility/createQuickExportMenu';
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
import axiosInstance from '../utility/axiosInstance';
import { alterDatabaseDialog, renameDatabaseObjectDialog } from '../utility/alterDatabaseTools';
import ConfirmModal from '../modals/ConfirmModal.svelte';
import { apiCall } from '../utility/api';
export let data;
export let passProps;
@@ -559,13 +559,11 @@
message: `Really drop collection ${data.pureName}?`,
onConfirm: async () => {
const dbid = _.pick(data, ['conid', 'database']);
await axiosInstance.request({
url: 'database-connections/run-script',
method: 'post',
params: dbid,
data: { sql: `db.dropCollection('${data.pureName}')` },
await apiCall('database-connections/run-script', {
...dbid,
sql: `db.dropCollection('${data.pureName}')`,
});
axiosInstance.post('database-connections/sync-model', dbid);
apiCall('database-connections/sync-model', dbid);
},
});
} else {

View File

@@ -7,14 +7,14 @@
const { icon, tabComponent, title, props, tabdata } = favorite;
let tabdataNew = tabdata;
if (props.savedFile) {
const resp = await axiosInstance.post('files/load', {
const resp = await apiCall('files/load', {
folder: props.savedFolder,
file: props.savedFile,
format: props.savedFormat,
});
tabdataNew = {
...tabdata,
editor: resp.data,
editor: resp,
};
}
openNewTab(
@@ -30,13 +30,13 @@
</script>
<script lang="ts">
import axiosInstance from '../utility/axiosInstance';
import openNewTab from '../utility/openNewTab';
import { copyTextToClipboard } from '../utility/clipboard';
import { showModal } from '../modals/modalTools';
import ConfirmModal from '../modals/ConfirmModal.svelte';
import getElectron from '../utility/getElectron';
import FavoriteModal from '../modals/FavoriteModal.svelte';
import { apiCall } from '../utility/api';
export let data;
@@ -47,7 +47,7 @@
};
const editFavoriteJson = async () => {
const resp = await axiosInstance.post('files/load', {
const resp = await apiCall('files/load', {
folder: 'favorites',
file: data.file,
format: 'text',
@@ -64,7 +64,7 @@
savedFolder: 'favorites',
},
},
{ editor: JSON.stringify(JSON.parse(resp.data), null, 2) }
{ editor: JSON.stringify(JSON.parse(resp), null, 2) }
);
};
@@ -76,7 +76,7 @@
showModal(ConfirmModal, {
message: `Really delete favorite ${data.title}?`,
onConfirm: () => {
axiosInstance.post('files/delete', { file: data.file, folder: 'favorites' });
apiCall('files/delete', { file: data.file, folder: 'favorites' });
},
});
};

View File

@@ -74,8 +74,8 @@
import { showModal } from '../modals/modalTools';
import { currentDatabase } from '../stores';
import { apiCall } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import getConnectionLabel from '../utility/getConnectionLabel';
import hasPermission from '../utility/hasPermission';
import openNewTab from '../utility/openNewTab';
@@ -114,7 +114,7 @@
showModal(ConfirmModal, {
message: `Really delete file ${data.file}?`,
onConfirm: () => {
axiosInstance.post('files/delete', data);
apiCall('files/delete', data);
},
});
};
@@ -125,7 +125,7 @@
label: 'New file name',
header: 'Rename file',
onConfirm: newFile => {
axiosInstance.post('files/rename', { ...data, newFile });
apiCall('files/rename', { ...data, newFile });
},
});
};
@@ -136,13 +136,13 @@
label: 'New file name',
header: 'Rename file',
onConfirm: newFile => {
axiosInstance.post('files/copy', { ...data, newFile });
apiCall('files/copy', { ...data, newFile });
},
});
};
async function openTab() {
const resp = await axiosInstance.post('files/load', { folder, file: data.file, format: handler.format });
const resp = await apiCall('files/load', { folder, file: data.file, format: handler.format });
const connProps: any = {};
let tooltip = undefined;
@@ -168,7 +168,7 @@
...connProps,
},
},
{ editor: resp.data }
{ editor: resp }
);
}
</script>

View File

@@ -20,7 +20,7 @@
<script lang="ts">
import { onMount, afterUpdate, onDestroy } from 'svelte';
import registerCommand from '../commands/registerCommand';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
import contextMenu, { getContextMenu, registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
@@ -61,7 +61,7 @@
export async function exportChart() {
saveFileToDisk(async filePath => {
await axiosInstance.post('files/export-chart', {
await apiCall('files/export-chart', {
title,
filePath,
config: {

View File

@@ -1,7 +1,7 @@
import { dumpSqlSelect, Select } from 'dbgate-sqltree';
import { EngineDriver } from 'dbgate-types';
import axiosInstance from '../utility/axiosInstance';
import _ from 'lodash';
import { apiCall } from '../utility/api';
export async function loadChartStructure(driver: EngineDriver, conid, database, sql) {
const select: Select = {
@@ -16,9 +16,9 @@ export async function loadChartStructure(driver: EngineDriver, conid, database,
const dmp = driver.createDumper();
dumpSqlSelect(dmp, select);
const resp = await axiosInstance.post('database-connections/query-data', { conid, database, sql: dmp.s });
if (resp.data.errorMessage) throw new Error(resp.data.errorMessage);
return resp.data.columns.map(x => x.columnName);
const resp = await apiCall('database-connections/query-data', { conid, database, sql: dmp.s });
if (resp.errorMessage) throw new Error(resp.errorMessage);
return resp.columns.map(x => x.columnName);
}
export async function loadChartData(driver: EngineDriver, conid, database, sql, config) {
@@ -74,8 +74,8 @@ export async function loadChartData(driver: EngineDriver, conid, database, sql,
const dmp = driver.createDumper();
dumpSqlSelect(dmp, select);
const resp = await axiosInstance.post('database-connections/query-data', { conid, database, sql: dmp.s });
let { rows, columns, errorMessage } = resp.data;
const resp = await apiCall('database-connections/query-data', { conid, database, sql: dmp.s });
let { rows, columns, errorMessage } = resp;
if (errorMessage) {
throw new Error(errorMessage);
}

View File

@@ -1,6 +1,4 @@
<script context="module">
const electron = getElectron();
registerCommand({
id: 'commandPalette.show',
category: 'Command palette',
@@ -20,7 +18,7 @@
category: 'Database',
toolbarName: 'Database search',
name: 'Search',
keyText: electron ? 'Ctrl+P' : 'F3',
keyText: isElectronAvailable() ? 'Ctrl+P' : 'F3',
onClick: () => visibleCommandPalette.set('database'),
testEnabled: () => getVisibleCommandPalette() != 'database',
});
@@ -75,7 +73,7 @@
} from '../stores';
import clickOutside from '../utility/clickOutside';
import getConnectionLabel from '../utility/getConnectionLabel';
import getElectron from '../utility/getElectron';
import { isElectronAvailable } from '../utility/getElectron';
import keycodes from '../utility/keycodes';
import { useConnectionList, useDatabaseInfo } from '../utility/metadataLoaders';
import { getLocalStorage } from '../utility/storageCache';

View File

@@ -2,9 +2,7 @@ import _ from 'lodash';
import { currentDatabase, getCurrentDatabase } from '../stores';
import getElectron from '../utility/getElectron';
import registerCommand from './registerCommand';
import axiosInstance from '../utility/axiosInstance';
const electron = getElectron();
import { apiCall } from '../utility/api';
registerCommand({
id: 'database.changeState',
@@ -22,19 +20,20 @@ registerCommand({
{
text: 'Sync model',
onClick: () => {
axiosInstance.post('database-connections/sync-model', dbid);
apiCall('database-connections/sync-model', dbid);
},
},
{
text: 'Reopen',
onClick: () => {
axiosInstance.post('database-connections/refresh', dbid);
apiCall('database-connections/refresh', dbid);
},
},
{
text: 'Disconnect',
onClick: () => {
if (electron) axiosInstance.post('database-connections/disconnect', dbid);
const electron = getElectron();
if (electron) apiCall('database-connections/disconnect', dbid);
currentDatabase.set(null);
},
},

View File

@@ -18,8 +18,6 @@ export default function runCommand(id) {
}
}
window['dbgate_runCommand'] = runCommand;
export function runGroupCommand(group) {
const commandsValue = getCommands();
const values = Object.values(commandsValue) as GlobalCommand[];
@@ -32,3 +30,4 @@ export function findCommand(id) {
const command = commandsValue[id];
return command;
}

View File

@@ -18,15 +18,14 @@ import { getCurrentConfig, getCurrentDatabase } from '../stores';
import './recentDatabaseSwitch';
import './changeDatabaseStatusCommand';
import hasPermission from '../utility/hasPermission';
import axiosInstance from '../utility/axiosInstance';
import _ from 'lodash';
import { findEngineDriver } from 'dbgate-tools';
import { openArchiveFolder } from '../utility/openArchiveFolder';
import InputTextModal from '../modals/InputTextModal.svelte';
import { removeLocalStorage } from '../utility/storageCache';
import { showSnackbarSuccess } from '../utility/snackbar';
const electron = getElectron();
import { apiCall } from '../utility/api';
import runCommand from './runCommand';
function themeCommand(theme: ThemeDefinition) {
return {
@@ -123,7 +122,7 @@ registerCommand({
label: 'New archive folder name',
header: 'Create archive folder',
onConfirm: async folder => {
axiosInstance.post('archive/create-folder', { folder });
apiCall('archive/create-folder', { folder });
},
});
},
@@ -190,13 +189,8 @@ registerCommand({
label: 'New collection name',
header: 'Create collection',
onConfirm: async newCollection => {
await axiosInstance.request({
url: 'database-connections/run-script',
method: 'post',
params: dbid,
data: { sql: `db.createCollection('${newCollection}')` },
});
axiosInstance.post('database-connections/sync-model', dbid);
await apiCall('database-connections/run-script', { ...dbid, sql: `db.createCollection('${newCollection}')` });
apiCall('database-connections/sync-model', dbid);
},
});
},
@@ -258,8 +252,8 @@ registerCommand({
label: 'New database name',
header: 'Create SQLite database',
onConfirm: async file => {
const resp = await axiosInstance.post('connections/new-sqlite-database', { file });
const connection = resp.data;
const resp = await apiCall('connections/new-sqlite-database', { file });
const connection = resp;
currentDatabase.set({ connection, name: `${file}.sqlite` });
},
});
@@ -316,22 +310,22 @@ registerCommand({
group: 'redo',
});
if (electron) {
registerCommand({
id: 'file.open',
category: 'File',
name: 'Open',
keyText: 'Ctrl+O',
onClick: openElectronFile,
});
registerCommand({
id: 'file.open',
category: 'File',
name: 'Open',
keyText: 'Ctrl+O',
testEnabled: () => getElectron() != null,
onClick: openElectronFile,
});
registerCommand({
id: 'file.openArchive',
category: 'File',
name: 'Open DB Model/Archive',
onClick: openArchiveFolder,
});
}
registerCommand({
id: 'file.openArchive',
category: 'File',
name: 'Open DB Model/Archive',
testEnabled: () => getElectron() != null,
onClick: openArchiveFolder,
});
registerCommand({
id: 'file.import',
@@ -419,14 +413,13 @@ if (hasPermission('settings/change')) {
});
}
if (electron) {
registerCommand({
id: 'file.exit',
category: 'File',
name: 'Exit',
onClick: () => electron.remote.getCurrentWindow().close(),
});
}
registerCommand({
id: 'file.exit',
category: 'File',
name: 'Exit',
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('close-window'),
});
export function registerFileCommands({
idPrefix,
@@ -541,3 +534,8 @@ export function registerFileCommands({
});
}
}
const electron = getElectron();
if (electron) {
electron.addEventListener('run-command', (e, commandId) => runCommand(commandId));
}

View File

@@ -63,26 +63,20 @@
export async function loadCollectionDataPage(props, offset, limit) {
const { conid, database } = props;
const response = await axiosInstance.request({
url: 'database-connections/collection-data',
method: 'post',
params: {
conid,
database,
},
data: {
options: {
pureName: props.pureName,
limit,
skip: offset,
condition: buildGridMongoCondition(props),
sort: buildMongoSort(props),
},
const response = await apiCall('database-connections/collection-data', {
conid,
database,
options: {
pureName: props.pureName,
limit,
skip: offset,
condition: buildGridMongoCondition(props),
sort: buildMongoSort(props),
},
});
if (response.data.errorMessage) return response.data;
return response.data.rows;
if (response.errorMessage) return response;
return response.rows;
}
function dataPageAvailable(props) {
@@ -95,23 +89,17 @@
async function loadRowCount(props) {
const { conid, database } = props;
const response = await axiosInstance.request({
url: 'database-connections/collection-data',
method: 'post',
params: {
conid,
database,
},
data: {
options: {
pureName: props.pureName,
countDocuments: true,
condition: buildGridMongoCondition(props),
},
const response = await apiCall('database-connections/collection-data', {
conid,
database,
options: {
pureName: props.pureName,
countDocuments: true,
condition: buildGridMongoCondition(props),
},
});
return response.data.count;
return response.count;
}
</script>
@@ -127,8 +115,8 @@
import ImportExportModal from '../modals/ImportExportModal.svelte';
import { showModal } from '../modals/modalTools';
import { extensions } from '../stores';
import { apiCall } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createQuickExportMenu from '../utility/createQuickExportMenu';

View File

@@ -262,7 +262,6 @@
import createReducer from '../utility/createReducer';
import keycodes from '../utility/keycodes';
import { copyRowsFormat, selectedCellsCallback } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import {
copyRowsFormatDefs,
copyRowsToClipboard,
@@ -285,6 +284,7 @@
import { findCommand } from '../commands/runCommand';
import { openJsonDocument } from '../tabs/JsonTab.svelte';
import EditJsonModal from '../modals/EditJsonModal.svelte';
import { apiCall } from '../utility/api';
export let onLoadNextData = undefined;
export let grider = undefined;
@@ -404,7 +404,7 @@
}
export async function reconnect() {
await axiosInstance.post('database-connections/refresh', { conid, database });
await apiCall('database-connections/refresh', { conid, database });
display.reload();
}

View File

@@ -1,10 +1,8 @@
<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 { useApiCall } from '../utility/api';
import useFetch from '../utility/useFetch';
import DataGrid from './DataGrid.svelte';
import JslDataGridCore from './JslDataGridCore.svelte';
@@ -12,11 +10,7 @@
let loadedRows;
$: info = useFetch({
params: { jslid },
url: 'jsldata/get-info',
defaultValue: {},
});
$: info = useApiCall('jsldata/get-info', { jslid }, {});
// $: columns = ($info && $info.columns) || [];
const config = writable(createGridConfig());

View File

@@ -13,14 +13,14 @@
async function loadDataPage(props, offset, limit) {
const { jslid, display } = props;
const response = await axiosInstance.post('jsldata/get-rows', {
const response = await apiCall('jsldata/get-rows', {
jslid,
offset,
limit,
filters: display ? display.compileFilters() : null,
});
return response.data;
return response;
}
function dataPageAvailable(props) {
@@ -30,16 +30,9 @@
async function loadRowCount(props) {
const { jslid } = props;
const response = await axiosInstance.request({
url: 'jsldata/get-stats',
method: 'get',
params: {
jslid,
},
});
return response.data.rowCount;
const response = await apiCall('jsldata/get-stats', { jslid });
return response.rowCount;
}
</script>
<script lang="ts">
@@ -48,13 +41,12 @@
import ImportExportModal from '../modals/ImportExportModal.svelte';
import { showModal } from '../modals/modalTools';
import { extensions } from '../stores';
import { apiCall, apiOff, apiOn } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createQuickExportMenu from '../utility/createQuickExportMenu';
import { exportElectronFile } from '../utility/exportElectronFile';
import socket from '../utility/socket';
import useEffect from '../utility/useEffect';
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
@@ -82,9 +74,9 @@
$: effect = useEffect(() => onJslId(jslid));
function onJslId(jslidVal) {
if (jslidVal) {
socket.on(`jsldata-stats-${jslidVal}`, handleJslDataStats);
apiOn(`jsldata-stats-${jslidVal}`, handleJslDataStats);
return () => {
socket.off(`jsldata-stats-${jslidVal}`, handleJslDataStats);
apiOff(`jsldata-stats-${jslidVal}`, handleJslDataStats);
};
}
}
@@ -140,7 +132,6 @@
},
{ command: 'jslTableGrid.export', tag: 'export' }
);
</script>
<LoadingDataGridCore

View File

@@ -31,18 +31,14 @@
const sql = display.getPageQuery(offset, limit);
const response = await axiosInstance.request({
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql },
const response = await apiCall('database-connections/query-data', {
conid,
database,
sql,
});
if (response.data.errorMessage) return response.data;
return response.data.rows;
if (response.errorMessage) return response;
return response.rows;
}
function dataPageAvailable(props) {
@@ -56,17 +52,13 @@
const sql = display.getCountQuery();
const response = await axiosInstance.request({
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql },
const response = await apiCall('database-connections/query-data', {
conid,
database,
sql,
});
return parseInt(response.data.rows[0].count);
return parseInt(response.rows[0].count);
}
</script>
@@ -77,8 +69,8 @@
import ImportExportModal from '../modals/ImportExportModal.svelte';
import { showModal } from '../modals/modalTools';
import { extensions } from '../stores';
import { apiCall } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createQuickExportMenu from '../utility/createQuickExportMenu';

View File

@@ -2,7 +2,7 @@
import InputTextModal from '../modals/InputTextModal.svelte';
import { showModal } from '../modals/modalTools';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
import { useArchiveFolders } from '../utility/metadataLoaders';
import { getFormContext } from './FormProviderCore.svelte';
@@ -34,7 +34,7 @@
];
const createOption = folder => {
axiosInstance.post('archive/create-folder', { folder });
apiCall('archive/create-folder', { folder });
setFieldValue(name, folder);
};

View File

@@ -11,10 +11,10 @@
const { values, setFieldValue } = getFormContext();
function handleBrowse() {
async function handleBrowse() {
const electron = getElectron();
if (!electron) return;
const filePaths = electron.remote.dialog.showOpenDialogSync(electron.remote.getCurrentWindow(), {
const filePaths = await electron.showOpenDialog({
defaultPath: values[name],
properties: ['showHiddenFiles'],
filters: [{ name: 'All Files', extensions: ['*'] }],

View File

@@ -174,8 +174,8 @@
import FontIcon from '../icons/FontIcon.svelte';
import DictionaryLookupModal from '../modals/DictionaryLookupModal.svelte';
import { showModal } from '../modals/modalTools';
import { apiCall } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import { copyTextToClipboard, extractRowCopiedValue } from '../utility/clipboard';
import contextMenu, { getContextMenu, registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
@@ -260,7 +260,7 @@
}
export async function reconnect() {
await axiosInstance.post('database-connections/refresh', { conid, database });
await apiCall('database-connections/refresh', { conid, database });
formDisplay.reload();
}

View File

@@ -4,25 +4,21 @@
if (!sql) return null;
const response = await axiosInstance.request({
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql },
const response = await apiCall('database-connections/query-data', {
conid,
database,
sql,
});
if (response.data.errorMessage) return response.data;
return response.data.rows[0];
if (response.errorMessage) return response;
return response.rows[0];
}
</script>
<script lang="ts">
import axiosInstance from '../utility/axiosInstance';
import ChangeSetFormer from './ChangeSetFormer';
import FormView from './FormView.svelte';
import { apiCall } from '../utility/api';
export let formDisplay;
export let changeSetState;
@@ -122,42 +118,6 @@
$: former = new ChangeSetFormer(rowData, changeSetState, dispatchChangeSet, formDisplay);
$: if (onReferenceSourceChanged && rowData) onReferenceSourceChanged([rowData], loadedTime);
// async function handleConfirmSql(sql) {
// const resp = await axiosInstance.request({
// url: 'database-connections/query-data',
// method: 'post',
// params: {
// conid,
// database,
// },
// data: { sql },
// });
// const { errorMessage } = resp.data || {};
// if (errorMessage) {
// showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
// } else {
// dispatchChangeSet({ type: 'reset', value: createChangeSet() });
// formDisplay.reload();
// }
// }
// function handleSave() {
// const script = changeSetToSql(changeSetState && changeSetState.value, formDisplay.dbinfo);
// const sql = scriptToSql(formDisplay.driver, script);
// showModal(ConfirmSqlModal, {
// sql,
// onConfirm: () => handleConfirmSql(sql),
// engine: formDisplay.engine,
// });
// }
</script>
<FormView
{...$$props}
{former}
isLoading={isLoadingData}
{allRowCount}
{rowCountBefore}
onNavigate={handleNavigate}
/>
<FormView {...$$props} {former} isLoading={isLoadingData} {allRowCount} {rowCountBefore} onNavigate={handleNavigate} />

View File

@@ -20,7 +20,7 @@
import DataGridCore from '../datagrid/DataGridCore.svelte';
import ImportExportModal from '../modals/ImportExportModal.svelte';
import { showModal } from '../modals/modalTools';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import FreeTableGrider from './FreeTableGrider';
@@ -45,7 +45,7 @@
export async function exportGrid() {
const jslid = uuidv1();
await axiosInstance.post('jsldata/save-free-table', { jslid, data: modelState.value });
await apiCall('jsldata/save-free-table', { jslid, data: modelState.value });
const initialValues: any = {};
initialValues.sourceStorageType = 'jsldata';
initialValues.sourceJslId = jslid;

View File

@@ -19,11 +19,11 @@
let isLoading = false;
const electron = getElectron();
const { values } = getFormContext();
const handleClick = async () => {
const files = electron.remote.dialog.showOpenDialogSync(electron.remote.getCurrentWindow(), {
const electron = getElectron();
const files = await electron.showOpenDialog({
properties: ['openFile', 'multiSelections'],
filters: getFileFilters($extensions, $values.sourceStorageType),
});

View File

@@ -6,7 +6,7 @@
import RowsArrayGrider from '../datagrid/RowsArrayGrider';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
export let reader;
@@ -27,14 +27,16 @@
}
errorMessage = null;
isLoading = true;
const resp = await axiosInstance.post('runners/load-reader', sourceReader);
const resp = await apiCall('runners/load-reader', sourceReader);
// @ts-ignore
model = resp.data;
grider = new RowsArrayGrider(resp.data.rows);
model = resp;
grider = new RowsArrayGrider(resp.rows);
isLoading = false;
} catch (err) {
isLoading = false;
errorMessage = (err && err.response && err.response.data && err.response.data.error) || 'Loading failed';
// errorMessage = (err && err.response && err.response.data && err.response.data.error) || 'Loading failed';
// TODO API
errorMessage = 'Loading failed';
console.error(err.response);
}
};

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import ColorSelector from '../forms/ColorSelector.svelte';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
import { useConnectionColor } from '../utility/useConnectionColor';
import ModalBase from './ModalBase.svelte';
@@ -27,13 +27,13 @@
value = e.detail;
if (database) {
axiosInstance.post('connections/update-database', {
apiCall('connections/update-database', {
conid,
database,
values: { connectionColor: e.detail },
});
} else {
axiosInstance.post('connections/update', {
apiCall('connections/update', {
_id: conid,
values: { connectionColor: e.detail },
});

View File

@@ -11,7 +11,7 @@
import FormTextField from '../forms/FormTextField.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import { commandsSettings } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
import KeyboardModal from './KeyboardModal.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal, showModal } from './modalTools';
@@ -42,7 +42,7 @@
value="OK"
on:click={e => {
closeCurrentModal();
axiosInstance.post('config/update-settings', {
apiCall('config/update-settings', {
commands: {
...$commandsSettings,
[command.id]: {
@@ -58,7 +58,7 @@
value="Reset"
on:click={() => {
closeCurrentModal();
axiosInstance.post('config/update-settings', {
apiCall('config/update-settings', {
commands: _.omit($commandsSettings, [command.id]),
});
}}

View File

@@ -4,7 +4,6 @@
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import axiosInstance from '../utility/axiosInstance';
import TabControl from '../elements/TabControl.svelte';
import ConnectionModalDriverFields from './ConnectionModalDriverFields.svelte';
import ConnectionModalSshTunnelFields from './ConnectionModalSshTunnelFields.svelte';
@@ -21,6 +20,7 @@
import { extensions } from '../stores';
import _ from 'lodash';
import { getDatabaseFileLabel } from '../utility/getConnectionLabel';
import { apiCall } from '../utility/api';
export let connection;
@@ -38,11 +38,11 @@
isTesting = true;
testIdRef.update(x => x + 1);
const testid = testIdRef.get();
const resp = await axiosInstance.post('connections/test', e.detail);
const resp = await apiCall('connections/test', e.detail);
if (testIdRef.get() != testid) return;
isTesting = false;
sqlConnectResult = resp.data;
sqlConnectResult = resp;
}
function handleCancelTest() {
@@ -70,10 +70,9 @@
let connection = _.omit(e.detail, omitProps);
if (driver?.beforeConnectionSave) connection = driver?.beforeConnectionSave(connection);
axiosInstance.post('connections/save', connection);
apiCall('connections/save', connection);
closeCurrentModal();
}
</script>
<FormProviderCore template={FormFieldTemplateLarge} {values}>
@@ -156,5 +155,4 @@
.error-result {
white-space: normal;
}
</style>

View File

@@ -6,7 +6,6 @@
import { closeCurrentModal, showModal } from './modalTools';
import DefineDictionaryDescriptionModal from './DefineDictionaryDescriptionModal.svelte';
import ScrollableTableControl from '../elements/ScrollableTableControl.svelte';
import axiosInstance from '../utility/axiosInstance';
import { getTableInfo } from '../utility/metadataLoaders';
import { getDictionaryDescription } from '../utility/dictionaryDescriptionTools';
import { onMount } from 'svelte';
@@ -15,6 +14,7 @@
import SearchInput from '../elements/SearchInput.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import _ from 'lodash';
import { apiCall } from '../utility/api';
export let onConfirm;
export let conid;
@@ -100,17 +100,13 @@
dumpSqlSelect(dmp, select);
isLoading = true;
const response = await axiosInstance.request({
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql: dmp.s },
const response = await apiCall('database-connections/query-data', {
conid,
database,
sql: dmp.s,
});
rows = response.data.rows;
rows = response.rows;
isLoading = false;
}

View File

@@ -5,7 +5,6 @@
import hasPermission from '../utility/hasPermission';
import localforage from 'localforage';
import ModalBase from './ModalBase.svelte';
import axiosInstance from '../utility/axiosInstance';
import uuidv1 from 'uuid/v1';
import { closeCurrentModal } from './modalTools';
import { copyTextToClipboard } from '../utility/clipboard';
@@ -14,8 +13,9 @@
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import FormValues from '../forms/FormValues.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormButton from '../forms/FormButton.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormButton from '../forms/FormButton.svelte';
import { apiCall } from '../utility/api';
export let editingData;
export let savingTab;
@@ -69,7 +69,7 @@ import FormButton from '../forms/FormButton.svelte';
const saveTab = async values => {
const data = await getTabSaveData(values);
axiosInstance.post('files/save', {
apiCall('files/save', {
folder: 'favorites',
file: uuidv1(),
format: 'json',
@@ -78,18 +78,18 @@ import FormButton from '../forms/FormButton.svelte';
};
const saveFile = async values => {
const oldDataResp = await axiosInstance.post('files/load', {
const oldDataResp = await apiCall('files/load', {
folder: 'favorites',
file: editingData.file,
format: 'json',
});
axiosInstance.post('files/save', {
apiCall('files/save', {
folder: 'favorites',
file: editingData.file,
format: 'json',
data: {
...oldDataResp.data,
...oldDataResp,
...values,
},
});

View File

@@ -16,10 +16,9 @@
import RunnerOutputFiles from '../query/RunnerOutputFiles.svelte';
import SocketMessageView from '../query/SocketMessageView.svelte';
import { currentArchive, currentDatabase, extensions, selectedWidget } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import { apiCall, apiOff, apiOn } from '../utility/api';
import createRef from '../utility/createRef';
import openNewTab from '../utility/openNewTab';
import socket from '../utility/socket';
import useEffect from '../utility/useEffect';
import WidgetColumnBar from '../widgets/WidgetColumnBar.svelte';
import WidgetColumnBarItem from '../widgets/WidgetColumnBarItem.svelte';
@@ -67,9 +66,9 @@
function registerRunnerDone(rid) {
if (rid) {
socket.on(`runner-done-${rid}`, handleRunnerDone);
apiOn(`runner-done-${rid}`, handleRunnerDone);
return () => {
socket.off(`runner-done-${rid}`, handleRunnerDone);
apiOff(`runner-done-${rid}`, handleRunnerDone);
};
} else {
return () => {};
@@ -81,8 +80,8 @@
const handleRunnerDone = () => {
busy = false;
if (refreshArchiveFolderRef.get()) {
axiosInstance.post('archive/refresh-folders', {});
axiosInstance.post('archive/refresh-files', { folder: refreshArchiveFolderRef.get() });
apiCall('archive/refresh-folders', {});
apiCall('archive/refresh-files', { folder: refreshArchiveFolderRef.get() });
$currentArchive = refreshArchiveFolderRef.get();
$selectedWidget = 'archive';
}
@@ -108,8 +107,8 @@
const script = await createImpExpScript($extensions, values);
executeNumber += 1;
let runid = runnerId;
const resp = await axiosInstance.post('runners/start', { script });
runid = resp.data.runid;
const resp = await apiCall('runners/start', { script });
runid = resp.runid;
runnerId = runid;
if (values.targetStorageType == 'archive') {
@@ -120,7 +119,7 @@
};
const handleCancel = () => {
axiosInstance.post('runners/cancel', {
apiCall('runners/cancel', {
runid: runnerId,
});
};

View File

@@ -4,8 +4,8 @@
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import { apiCall } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import getElectron from '../utility/getElectron';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
@@ -22,7 +22,7 @@
const handleSubmit = async e => {
const { name } = e.detail;
await axiosInstance.post('files/save', { folder, file: name, data, format });
await apiCall('files/save', { folder, file: name, data, format });
closeCurrentModal();
if (onSave) {
onSave(name, {
@@ -38,7 +38,7 @@
const parsed = path.parse(filePath);
// if (!parsed.ext) filePath += `.${fileExtension}`;
await axiosInstance.post('files/save-as', { filePath, data, format });
await apiCall('files/save-as', { filePath, data, format });
closeCurrentModal();
if (onSave) {
@@ -61,8 +61,8 @@
<FormStyledButton
type="button"
value="Save to disk"
on:click={() => {
const file = electron.remote.dialog.showSaveDialogSync(electron.remote.getCurrentWindow(), {
on:click={async () => {
const file = await electron.showSaveDialog({
filters: [
{ name: `${fileExtension.toUpperCase()} files`, extensions: [fileExtension] },
{ name: `All files`, extensions: ['*'] },

View File

@@ -18,7 +18,6 @@
import FontIcon from '../icons/FontIcon.svelte';
import SqlEditor from '../query/SqlEditor.svelte';
import axiosInstance from '../utility/axiosInstance';
import createRef from '../utility/createRef';
import { useDatabaseInfo } from '../utility/metadataLoaders';
import WidgetColumnBar from '../widgets/WidgetColumnBar.svelte';
@@ -32,6 +31,7 @@
import ErrorInfo from '../elements/ErrorInfo.svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import { getObjectTypeFieldLabel } from '../utility/common';
import { apiCall } from '../utility/api';
export let conid;
export let database;
@@ -86,7 +86,7 @@
const loadid = uuidv1();
loadRef.set(loadid);
busy = true;
const response = await axiosInstance.post('database-connections/sql-preview', {
const response = await apiCall('database-connections/sql-preview', {
conid,
database,
objects,
@@ -96,7 +96,7 @@
// newer load exists
return;
}
const { sql, isTruncated, isError, errorMessage } = response.data || {};
const { sql, isTruncated, isError, errorMessage } = response || {};
truncated = isTruncated;
if (isError) {
@@ -127,7 +127,6 @@
);
closeCurrentModal();
}
</script>
<FormProviderCore values={valuesStore} template={FormFieldTemplateTiny}>
@@ -257,5 +256,4 @@
.dbname {
color: var(--theme-font-3);
}
</style>

View File

@@ -6,7 +6,6 @@
import { closeCurrentModal, showModal } from './modalTools';
import DefineDictionaryDescriptionModal from './DefineDictionaryDescriptionModal.svelte';
import ScrollableTableControl from '../elements/ScrollableTableControl.svelte';
import axiosInstance from '../utility/axiosInstance';
import { getDictionaryDescription } from '../utility/dictionaryDescriptionTools';
import { onMount } from 'svelte';
import { dumpSqlSelect } from 'dbgate-sqltree';
@@ -14,6 +13,7 @@
import SearchInput from '../elements/SearchInput.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import _ from 'lodash';
import { apiCall } from '../utility/api';
export let onConfirm;
export let conid;
@@ -34,7 +34,7 @@
let checkedKeys = [];
async function reload() {
const dmp = driver.createDumper();
const dmp = driver.createDumper();
const select = {
commandType: 'select',
distinct: true,
@@ -85,17 +85,13 @@
dumpSqlSelect(dmp, select);
isLoading = true;
const response = await axiosInstance.request({
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql: dmp.s },
const response = await apiCall('database-connections/query-data', {
conid,
database,
sql: dmp.s,
});
rows = response.data.rows;
rows = response.rows;
isLoading = false;
}

View File

@@ -3,20 +3,14 @@
import SearchBoxWrapper from '../elements/SearchBoxWrapper.svelte';
import SearchInput from '../elements/SearchInput.svelte';
import useFetch from '../utility/useFetch';
import { useApiCall } from '../utility/api';
import WidgetsInnerContainer from '../widgets/WidgetsInnerContainer.svelte';
import PluginsList from './PluginsList.svelte';
let filter = '';
let search = '';
$: plugins = useFetch({
url: 'plugins/search',
params: {
filter: search,
},
defaultValue: [],
});
$: plugins = useApiCall('plugins/search', { filter: search }, []);
const setDebouncedFilter = _.debounce(value => (search = value), 500);

View File

@@ -1,6 +1,6 @@
<script lang="ts" context="module">
const dbgateEnv = {
axios: axiosInstance,
apiCall,
};
async function loadPlugins(pluginsDict, installedPlugins) {
@@ -14,14 +14,10 @@
loaded: false,
loadingPackageName: installed.name,
});
const resp = await axiosInstance.request({
method: 'get',
url: 'plugins/script',
params: {
packageName: installed.name,
},
const resp = await apiCall('plugins/script', {
packageName: installed.name,
});
const module = eval(`${resp.data}; plugin`);
const module = eval(`${resp}; plugin`);
console.log('Loaded plugin', module);
const moduleContent = module.__esModule ? module.default : module;
if (moduleContent.initialize) moduleContent.initialize(dbgateEnv);
@@ -55,17 +51,16 @@
};
return extensions;
}
</script>
<script lang="ts">
import _ from 'lodash';
import { extensions, loadingPluginStore } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import { useInstalledPlugins } from '../utility/metadataLoaders';
import { buildFileFormats, buildQuickExports } from './fileformats';
import { buildThemes } from './themes';
import dbgateTools from 'dbgate-tools';
import { apiCall } from '../utility/api';
let pluginsDict = {};
const installedPlugins = useInstalledPlugins();
@@ -87,5 +82,4 @@
.filter(x => x.content);
$: $extensions = buildExtensions(plugins);
</script>

View File

@@ -25,8 +25,6 @@
import _ from 'lodash';
import { handleCommandKeyDown } from '../commands/CommandListener.svelte';
import resizeObserver from '../utility/resizeObserver';
// @ts-ignore
import QueryParserWorker from 'web-worker:./QueryParserWorker';
import queryParserWorkerFallback from './queryParserWorkerFallback';
const EDITOR_ID = `svelte-ace-editor-div:${Math.floor(Math.random() * 10000000000)}`;
@@ -138,11 +136,14 @@
if (enabled) {
if (!queryParserWorker) {
try {
queryParserWorker = new QueryParserWorker();
queryParserWorker = new Worker('build/query-parser-worker.js');
// console.log('WORKER', queryParserWorker);
queryParserWorker.onmessage = e => {
processParserResult(e.data);
};
} catch (err) {
// console.error('WORKER ERROR', err);
console.log('WORKER ERROR, using fallback worker', err.message);
queryParserWorker = 'fallback';
}
}

View File

@@ -6,7 +6,7 @@
import JslDataGrid from '../datagrid/JslDataGrid.svelte';
import TabControl from '../elements/TabControl.svelte';
import { allResultsInOneTabDefault } from '../stores';
import socket from '../utility/socket';
import { apiOff, apiOn } from '../utility/api';
import useEffect from '../utility/useEffect';
import AllResultsTab from './AllResultsTab.svelte';
@@ -66,9 +66,9 @@
});
function onSession(sid) {
if (sid) {
socket.on(`session-recordset-${sid}`, handleResultSet);
apiOn(`session-recordset-${sid}`, handleResultSet);
return () => {
socket.off(`session-recordset-${sid}`, handleResultSet);
apiOff(`session-recordset-${sid}`, handleResultSet);
};
}
return () => {};

View File

@@ -1,12 +1,11 @@
<script>
import ErrorInfo from '../elements/ErrorInfo.svelte';
import TableControl from '../elements/TableControl.svelte';
import { apiOff, apiOn, apiCall } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import formatFileSize from '../utility/formatFileSize';
import getElectron from '../utility/getElectron';
import resolveApi from '../utility/resolveApi';
import socket from '../utility/socket';
import useEffect from '../utility/useEffect';
export let runnerId;
@@ -22,9 +21,9 @@
function registerRunnerDone(rid) {
if (rid) {
socket.on(`runner-done-${rid}`, handleRunnerDone);
apiOn(`runner-done-${rid}`, handleRunnerDone);
return () => {
socket.off(`runner-done-${rid}`, handleRunnerDone);
apiOff(`runner-done-${rid}`, handleRunnerDone);
};
} else {
return () => {};
@@ -34,8 +33,8 @@
$: $effect;
const handleRunnerDone = async () => {
const resp = await axiosInstance.get(`runners/files?runid=${runnerId}`);
files = resp.data;
const resp = await apiCall('runners/files', { runid: runnerId });
files = resp;
};
</script>
@@ -78,8 +77,8 @@
slot="1"
let:row
href="#"
on:click={() => {
const file = electron.remote.dialog.showSaveDialogSync(electron.remote.getCurrentWindow(), {});
on:click={async () => {
const file = await electron.showSaveDialog({});
if (file) {
const fs = window.require('fs');
fs.copyFile(row.path, file, () => {});
@@ -94,7 +93,7 @@
let:row
href="#"
on:click={() => {
electron.remote.shell.showItemInFolder(row.path);
electron.showItemInFolder(row.path);
}}
>
show

View File

@@ -1,10 +1,9 @@
<script lang="ts">
import _ from 'lodash';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import { apiOff, apiOn } from '../utility/api';
import createRef from '../utility/createRef';
import socket from '../utility/socket';
import useEffect from '../utility/useEffect';
import MessageView from './MessageView.svelte';
@@ -30,9 +29,9 @@
$: effect = useEffect(() => {
if (eventName) {
socket.on(eventName, handleInfo);
apiOn(eventName, handleInfo);
return () => {
socket.off(eventName, handleInfo);
apiOff(eventName, handleInfo);
};
}
return () => {};

View File

@@ -13,10 +13,10 @@
import ModalBase from '../modals/ModalBase.svelte';
import { closeCurrentModal } from '../modals/modalTools';
import { getCurrentSettings, getVisibleToolbar, getZoomKoef, visibleToolbar, zoomKoef } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
function handleOk(e) {
axiosInstance.post(
apiCall(
'config/update-settings',
_.omitBy(e.detail, (v, k) => k.startsWith(':'))
);

View File

@@ -44,7 +44,7 @@ export const activeTab = derived([openedTabs], ([$openedTabs]) => $openedTabs.fi
export const recentDatabases = writableWithStorage([], 'recentDatabases');
export const pinnedDatabases = writableWithStorage([], 'pinnedDatabases');
export const pinnedTables = writableWithStorage([], 'pinnedTables');
export const commandsSettings = derived(useSettings(), (config: any) => (config || {}).commands || {});
export const commandsSettings = writable({});
export const allResultsInOneTabDefault = writableWithStorage(false, 'allResultsInOneTabDefault');
export const archiveFilesAsDataSheets = writableWithStorage([], 'archiveFilesAsDataSheets');
export const commandsCustomized = derived([commands, commandsSettings], ([$commands, $commandsSettings]) =>
@@ -74,8 +74,6 @@ export const currentThemeDefinition = derived([currentTheme, extensions], ([$cur
$extensions.themes.find(x => x.className == $currentTheme)
);
const electron = getElectron();
subscribeCssVariable(selectedWidget, x => (x ? 1 : 0), '--dim-visible-left-panel');
subscribeCssVariable(visibleToolbar, x => (x ? 1 : 0), '--dim-visible-toolbar');
subscribeCssVariable(leftPanelWidth, x => `${x}px`, '--dim-left-panel-width');
@@ -119,9 +117,9 @@ let commandsValue = null;
commands.subscribe(value => {
commandsValue = value;
const electron = getElectron();
if (electron) {
const { ipcRenderer } = electron;
ipcRenderer.send('update-commands', JSON.stringify(value));
electron.send('update-commands', JSON.stringify(value));
}
});
export const getCommands = () => commandsValue;
@@ -132,15 +130,7 @@ activeTab.subscribe(value => {
});
export const getActiveTab = () => activeTabValue;
const currentConfigStore = useConfig();
let currentConfigValue = null;
currentConfigStore.subscribe(value => {
currentConfigValue = value;
invalidateCommands();
if (value.singleDatabase) {
currentDatabase.set(value.singleDatabase);
}
});
export const getCurrentConfig = () => currentConfigValue;
let recentDatabasesValue = null;
@@ -163,10 +153,6 @@ currentDatabase.subscribe(value => {
export const getCurrentDatabase = () => currentDatabaseValue;
let currentSettingsValue = null;
useSettings().subscribe(value => {
currentSettingsValue = value;
invalidateCommands();
});
export const getCurrentSettings = () => currentSettingsValue || {};
let extensionsValue = null;
@@ -180,3 +166,19 @@ openedConnections.subscribe(value => {
openedConnectionsValue = value;
});
export const getOpenedConnections = () => openedConnectionsValue;
export function subscribeApiDependendStores() {
useSettings().subscribe(value => {
currentSettingsValue = value;
commandsSettings.set((value || {}).commands || {});
invalidateCommands();
});
useConfig().subscribe(value => {
currentConfigValue = value;
invalidateCommands();
if (value.singleDatabase) {
currentDatabase.set(value.singleDatabase);
}
});
}

View File

@@ -6,16 +6,15 @@
import { onMount } from 'svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import Markdown from '../elements/Markdown.svelte';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
let isLoading = false;
let text = null;
const handleLoad = async () => {
isLoading = true;
const resp = await axiosInstance.get('config/changelog');
text = resp.data;
const resp = await apiCall('config/changelog');
text = resp;
isLoading = false;
};

View File

@@ -26,7 +26,6 @@
import LoadingInfo from '../elements/LoadingInfo.svelte';
import useEditorData from '../query/useEditorData';
import axiosInstance from '../utility/axiosInstance';
import { getContextMenu, registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createUndoReducer from '../utility/createUndoReducer';

View File

@@ -40,7 +40,6 @@
import { extensions } from '../stores';
import CollectionJsonView from '../jsonview/CollectionJsonView.svelte';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import axiosInstance from '../utility/axiosInstance';
import { showModal } from '../modals/modalTools';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import ConfirmNoSqlModal from '../modals/ConfirmNoSqlModal.svelte';
@@ -50,6 +49,7 @@
import ChangeSetGrider from '../datagrid/ChangeSetGrider';
import { setContext } from 'svelte';
import _ from 'lodash';
import { apiCall } from '../utility/api';
export let tabid;
export let conid;
@@ -91,16 +91,12 @@
// $: console.log('LOADED ROWS MONGO', loadedRows);
async function handleConfirmChange(changeSet) {
const resp = await axiosInstance.request({
url: 'database-connections/update-collection',
method: 'post',
params: {
conid,
database,
},
data: { changeSet },
const resp = await apiCall('database-connections/update-collection', {
conid,
database,
changeSet,
});
const { errorMessage } = resp.data || {};
const { errorMessage } = resp || {};
if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
} else {

View File

@@ -154,7 +154,7 @@
import SqlEditor from '../query/SqlEditor.svelte';
import useEditorData from '../query/useEditorData';
import { extensions } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
import { changeTab } from '../utility/common';
import contextMenu, { getContextMenu, registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
@@ -228,7 +228,7 @@
export async function showReport() {
saveFileToDisk(async filePath => {
await axiosInstance.post('database-connections/generate-db-diff-report', {
await apiCall('database-connections/generate-db-diff-report', {
filePath,
sourceConid: $values?.sourceConid,
sourceDatabase: $values?.sourceDatabase,
@@ -261,11 +261,11 @@
}
export function refreshModels() {
axiosInstance.post('database-connections/sync-model', {
apiCall('database-connections/sync-model', {
conid: $values?.targetConid,
database: $values?.targetDatabase,
});
axiosInstance.post('database-connections/sync-model', {
apiCall('database-connections/sync-model', {
conid: $values?.sourceConid,
database: $values?.sourceDatabase,
});
@@ -275,18 +275,13 @@
const conid = $values?.targetConid;
const database = $values?.targetDatabase;
const resp = await axiosInstance.request({
url: 'database-connections/run-script',
method: 'post',
params: { conid, database },
data: { sql },
});
const { errorMessage } = resp.data || {};
const resp = await apiCall('database-connections/run-script', { conid, database, sql });
const { errorMessage } = resp || {};
if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
} else {
$values = _.omitBy($values, (v, k) => k.startsWith('isChecked_'));
await axiosInstance.post('database-connections/sync-model', { conid, database });
await apiCall('database-connections/sync-model', { conid, database });
showSnackbarSuccess('Saved to database');
}
}

View File

@@ -38,11 +38,11 @@
import AceEditor from '../query/AceEditor.svelte';
import useEditorData from '../query/useEditorData';
import invalidateCommands from '../commands/invalidateCommands';
import axiosInstance from '../utility/axiosInstance';
import { showModal } from '../modals/modalTools';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { openFavorite } from '../appobj/FavoriteFileAppObject.svelte';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import { apiCall } from '../utility/api';
export let tabid;
export let savedFile;
@@ -97,7 +97,7 @@
export function save() {
try {
const data = JSON.parse(getData());
axiosInstance.post('files/save', {
apiCall('files/save', {
file: savedFile,
folder: 'favorites',
format: 'json',

View File

@@ -41,8 +41,8 @@
import { showModal } from '../modals/modalTools';
import SaveArchiveModal from '../modals/SaveArchiveModal.svelte';
import useEditorData from '../query/useEditorData';
import { apiCall } from '../utility/api';
import { markArchiveFileAsDataSheet } from '../utility/archiveTools';
import axiosInstance from '../utility/axiosInstance';
import { changeTab } from '../utility/common';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
@@ -61,10 +61,7 @@
const { setEditorData, editorState } = useEditorData({
tabid,
loadFromArgs:
initialArgs && initialArgs.functionName
? () => axiosInstance.post('runners/load-reader', initialArgs).then(x => x.data)
: null,
loadFromArgs: initialArgs && initialArgs.functionName ? () => apiCall('runners/load-reader', initialArgs) : null,
onInitialData: value => {
dispatchModel({ type: 'reset', value });
},
@@ -84,7 +81,7 @@
}
const doSave = async (folder, file) => {
await axiosInstance.post('archive/save-free-table', { folder, file, data: $modelState.value });
await apiCall('archive/save-free-table', { folder, file, data: $modelState.value });
changeTab(tabid, tab => ({
...tab,
title: file,

View File

@@ -6,8 +6,7 @@
import { onMount } from 'svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import Markdown from '../elements/Markdown.svelte';
import axiosInstance from '../utility/axiosInstance';
import { apiCall } from '../utility/api';
export let savedFile;
@@ -16,12 +15,12 @@
const handleLoad = async () => {
isLoading = true;
const resp = await axiosInstance.post('files/load', {
const resp = await apiCall('files/load', {
folder: 'markdown',
file: savedFile,
format: 'text',
});
text = resp.data;
text = resp;
isLoading = false;
};

View File

@@ -7,33 +7,28 @@
import FormStyledButton from '../elements/FormStyledButton.svelte';
import Markdown from '../elements/Markdown.svelte';
import { extractPluginAuthor, extractPluginIcon } from '../plugins/manifestExtractors';
import { apiCall, useApiCall } from '../utility/api';
import axiosInstance from '../utility/axiosInstance';
import hasPermission from '../utility/hasPermission';
import { useInstalledPlugins } from '../utility/metadataLoaders';
import useFetch from '../utility/useFetch';
export let packageName;
$: installed = useInstalledPlugins();
$: info = useFetch({
params: { packageName },
url: 'plugins/info',
defaultValue: null,
});
$: info = useApiCall('plugins/info', { packageName }, null);
$: readme = $info?.readme;
$: manifest = $info?.manifest;
$: isPackaged = $info?.isPackaged;
const handleInstall = async () => {
axiosInstance.post('plugins/install', { packageName });
apiCall('plugins/install', { packageName });
};
const handleUninstall = async () => {
axiosInstance.post('plugins/uninstall', { packageName });
apiCall('plugins/uninstall', { packageName });
};
const handleUpgrade = async () => {
axiosInstance.post('plugins/upgrade', { packageName });
apiCall('plugins/upgrade', { packageName });
};
$: installedFound = $installed?.find(x => x.name == packageName);

View File

@@ -21,10 +21,8 @@
import SqlEditor from '../query/SqlEditor.svelte';
import useEditorData from '../query/useEditorData';
import { extensions } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import { changeTab } from '../utility/common';
import { useConnectionInfo } from '../utility/metadataLoaders';
import socket from '../utility/socket';
import SocketMessageView from '../query/SocketMessageView.svelte';
import useEffect from '../utility/useEffect';
import ResultTabs from '../query/ResultTabs.svelte';
@@ -38,6 +36,7 @@
import QueryDesignColumns from '../elements/QueryDesignColumns.svelte';
import useTimerLabel from '../utility/useTimerLabel';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import { apiCall, apiOff, apiOn } from '../utility/api';
export let tabid;
export let conid;
@@ -62,9 +61,9 @@
});
function onSession(sid) {
if (sid) {
socket.on(`session-done-${sid}`, handleSessionDone);
apiOn(`session-done-${sid}`, handleSessionDone);
return () => {
socket.off(`session-done-${sid}`, handleSessionDone);
apiOff(`session-done-${sid}`, handleSessionDone);
};
}
return () => {};
@@ -105,23 +104,23 @@
let sesid = sessionId;
if (!sesid) {
const resp = await axiosInstance.post('sessions/create', {
const resp = await apiCall('sessions/create', {
conid,
database,
});
sesid = resp.data.sesid;
sesid = resp.sesid;
sessionId = sesid;
}
busy = true;
timerLabel.start();
await axiosInstance.post('sessions/execute-query', {
await apiCall('sessions/execute-query', {
sesid,
sql: sqlPreview,
});
}
export async function kill() {
await axiosInstance.post('sessions/kill', {
await apiCall('sessions/kill', {
sesid: sessionId,
});
sessionId = null;

View File

@@ -52,10 +52,8 @@
import useEditorData from '../query/useEditorData';
import { extensions } from '../stores';
import applyScriptTemplate from '../utility/applyScriptTemplate';
import axiosInstance from '../utility/axiosInstance';
import { changeTab } from '../utility/common';
import { getDatabaseInfo, useConnectionInfo } from '../utility/metadataLoaders';
import socket from '../utility/socket';
import SocketMessageView from '../query/SocketMessageView.svelte';
import useEffect from '../utility/useEffect';
import ResultTabs from '../query/ResultTabs.svelte';
@@ -69,6 +67,7 @@
import AceEditor from '../query/AceEditor.svelte';
import StatusBarTabItem from '../widgets/StatusBarTabItem.svelte';
import { showSnackbarError } from '../utility/snackbar';
import { apiCall, apiOff, apiOn } from '../utility/api';
export let tabid;
export let conid;
@@ -95,9 +94,9 @@
});
function onSession(sid) {
if (sid) {
socket.on(`session-done-${sid}`, handleSessionDone);
apiOn(`session-done-${sid}`, handleSessionDone);
return () => {
socket.off(`session-done-${sid}`, handleSessionDone);
apiOff(`session-done-${sid}`, handleSessionDone);
};
}
return () => {};
@@ -150,20 +149,20 @@
let sesid = sessionId;
if (!sesid) {
const resp = await axiosInstance.post('sessions/create', {
const resp = await apiCall('sessions/create', {
conid,
database,
});
sesid = resp.data.sesid;
sesid = resp.sesid;
sessionId = sesid;
}
busy = true;
timerLabel.start();
await axiosInstance.post('sessions/execute-query', {
await apiCall('sessions/execute-query', {
sesid,
sql,
});
await axiosInstance.post('query-history/write', {
await apiCall('query-history/write', {
data: {
sql,
conid,
@@ -184,7 +183,7 @@
}
export async function kill() {
await axiosInstance.post('sessions/kill', {
await apiCall('sessions/kill', {
sesid: sessionId,
});
sessionId = null;

View File

@@ -48,12 +48,11 @@
import AceEditor from '../query/AceEditor.svelte';
import RunnerOutputPane from '../query/RunnerOutputPane.svelte';
import useEditorData from '../query/useEditorData';
import axiosInstance from '../utility/axiosInstance';
import { apiCall, apiOff, apiOn } from '../utility/api';
import { copyTextToClipboard } from '../utility/clipboard';
import { changeTab } from '../utility/common';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import { showSnackbarError } from '../utility/snackbar';
import socket from '../utility/socket';
import useEffect from '../utility/useEffect';
import useTimerLabel from '../utility/useTimerLabel';
@@ -101,9 +100,9 @@
function registerRunnerDone(rid) {
if (rid) {
socket.on(`runner-done-${rid}`, handleRunnerDone);
apiOn(`runner-done-${rid}`, handleRunnerDone);
return () => {
socket.off(`runner-done-${rid}`, handleRunnerDone);
apiOff(`runner-done-${rid}`, handleRunnerDone);
};
} else {
return () => {};
@@ -140,8 +139,8 @@
}
export async function copyNodeScript() {
const resp = await axiosInstance.post('runners/get-node-script', { script: getActiveScript() });
copyTextToClipboard(resp.data);
const resp = await apiCall('runners/get-node-script', { script: getActiveScript() });
copyTextToClipboard(resp);
}
// export function openWizardEnabled() {
@@ -172,10 +171,10 @@
executeNumber += 1;
let runid = runnerId;
const resp = await axiosInstance.post('runners/start', {
const resp = await apiCall('runners/start', {
script: getActiveScript(),
});
runid = resp.data.runid;
runid = resp.runid;
runnerId = runid;
busy = true;
timerLabel.start();
@@ -186,7 +185,7 @@
}
export function kill() {
axiosInstance.post('runners/cancel', {
apiCall('runners/cancel', {
runid: runnerId,
});
timerLabel.stop();

View File

@@ -38,7 +38,6 @@
import { writable } from 'svelte/store';
import createUndoReducer from '../utility/createUndoReducer';
import invalidateCommands from '../commands/invalidateCommands';
import axiosInstance from '../utility/axiosInstance';
import { showModal } from '../modals/modalTools';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
@@ -53,6 +52,7 @@
import openNewTab from '../utility/openNewTab';
import { getBoolSettingsValue } from '../settings/settingsTools';
import { setContext } from 'svelte';
import { apiCall } from '../utility/api';
export let tabid;
export let conid;
@@ -70,16 +70,8 @@
const [changeSetStore, dispatchChangeSet] = createUndoReducer(createChangeSet());
async function handleConfirmSql(sql) {
const resp = await axiosInstance.request({
url: 'database-connections/run-script',
method: 'post',
params: {
conid,
database,
},
data: { sql },
});
const { errorMessage } = resp.data || {};
const resp = await apiCall('database-connections/run-script', { conid, database, sql });
const { errorMessage } = resp || {};
if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
} else {

View File

@@ -51,13 +51,13 @@
import { useConnectionInfo, useDatabaseInfo, useDbCore } from '../utility/metadataLoaders';
import { showModal } from '../modals/modalTools';
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
import axiosInstance from '../utility/axiosInstance';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { showSnackbarSuccess } from '../utility/snackbar';
import InputTextModal from '../modals/InputTextModal.svelte';
import { changeTab } from '../utility/common';
import StatusBarTabItem from '../widgets/StatusBarTabItem.svelte';
import openNewTab from '../utility/openNewTab';
import { apiCall } from '../utility/api';
export let tabid;
export let conid;
@@ -130,16 +130,8 @@
}
async function handleConfirmSql(sql, createTableName) {
const resp = await axiosInstance.request({
url: 'database-connections/run-script',
method: 'post',
params: {
conid,
database,
},
data: { sql },
});
const { errorMessage } = resp.data || {};
const resp = await apiCall('database-connections/run-script', { conid, database, sql });
const { errorMessage } = resp || {};
if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
} else {
@@ -154,14 +146,14 @@
}));
}
await axiosInstance.post('database-connections/sync-model', { conid, database });
await apiCall('database-connections/sync-model', { conid, database });
showSnackbarSuccess('Saved to database');
clearEditorData();
}
}
export async function reset() {
await axiosInstance.post('database-connections/sync-model', { conid, database });
await apiCall('database-connections/sync-model', { conid, database });
clearEditorData();
}

View File

@@ -1,7 +1,6 @@
<script lang="ts">
import localforage from 'localforage';
import _ from 'lodash';
import { openedTabs } from '../stores';
import { getLocalStorage, setLocalStorage } from './storageCache';
let counter = 0;

View File

@@ -5,7 +5,7 @@ import { showModal } from '../modals/modalTools';
import { getExtensions } from '../stores';
import { getConnectionInfo, getDatabaseInfo } from './metadataLoaders';
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
import axiosInstance from './axiosInstance';
import { apiCall } from './api';
export async function alterDatabaseDialog(conid, database, updateFunc) {
const conn = await getConnectionInfo({ conid });
@@ -21,16 +21,8 @@ export async function alterDatabaseDialog(conid, database, updateFunc) {
sql,
recreates,
onConfirm: async () => {
const resp = await axiosInstance.request({
url: 'database-connections/run-script',
method: 'post',
params: {
conid,
database,
},
data: { sql },
});
await axiosInstance.post('database-connections/sync-model', { conid, database });
const resp = await apiCall('database-connections/run-script', { conid, database, sql });
await apiCall('database-connections/sync-model', { conid, database });
},
engine: driver.engine,
});

View File

@@ -0,0 +1,89 @@
import resolveApi, { resolveApiHeaders } from './resolveApi';
import { writable } from 'svelte/store';
import { cacheClean } from './cache';
import getElectron from './getElectron';
// import socket from './socket';
let eventSource;
let cacheCleanerRegistered;
function wantEventSource() {
if (!eventSource) {
eventSource = new EventSource(`${resolveApi()}/stream`);
// eventSource.addEventListener('clean-cache', e => cacheClean(JSON.parse(e.data)));
}
}
export async function apiCall(route: string, args: {} = undefined) {
const electron = getElectron();
if (electron) {
// console.log('CALLING API', route.replace('/', '-'), JSON.stringify(args == null ? null : args));
const resp = await electron.invoke(route.replace('/', '-'), args);
return resp;
} else {
const resp = await fetch(`${resolveApi()}/${route}`, {
method: 'POST',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
...resolveApiHeaders(),
},
body: JSON.stringify(args),
});
return resp.json();
}
}
const apiHandlers = new WeakMap();
export function apiOn(event: string, handler: Function) {
const electron = getElectron();
if (electron) {
if (!apiHandlers.has(handler)) {
const handlerProxy = (e, data) => {
handler(data);
};
apiHandlers.set(handler, handlerProxy);
}
electron.addEventListener(event, apiHandlers.get(handler));
} else {
wantEventSource();
if (!apiHandlers.has(handler)) {
const handlerProxy = e => {
// console.log('RECEIVED', e.type, JSON.parse(e.data));
handler(JSON.parse(e.data));
};
apiHandlers.set(handler, handlerProxy);
}
eventSource.addEventListener(event, apiHandlers.get(handler));
}
if (!cacheCleanerRegistered) {
cacheCleanerRegistered = true;
apiOn('clean-cache', reloadTrigger => cacheClean(reloadTrigger));
}
}
export function apiOff(event: string, handler: Function) {
const electron = getElectron();
if (apiHandlers.has(handler)) {
if (electron) {
electron.removeEventListener(event, apiHandlers.get(handler));
} else {
wantEventSource();
eventSource.removeEventListener(event, apiHandlers.get(handler));
}
}
}
export function useApiCall(route, args, defaultValue) {
const result = writable(defaultValue);
apiCall(route, args).then(resp => {
result.set(resp);
});
return result;
}

Some files were not shown because too many files have changed in this diff Show More