Merge branch 'develop'

This commit is contained in:
Jan Prochazka
2022-05-23 19:16:09 +02:00
66 changed files with 742 additions and 610 deletions

View File

@@ -8,6 +8,18 @@ Builds:
- linux - application for linux
- win - application for Windows
### 5.0.0 - unreleased
- CHANGED: Connection workflow, connections are opened on tabs instead of modals
- ADDED: Posibility to connect to DB without saving connection
- ADDED(mac): Support for SQLite on Mac M1
- FIXED(mac): Unable to drag window on MacOS #281 #283
- CHANGED: Renamed dbgate-data directory to .dbgate #248
- FIXED: Exported SQL has table name undefined #277
- ADDED: More data types in table create dialogt #285
- ADDED(app): Open previously saved ERD diagrams #278
- CHANGED: Better app loading progress UX
- FIXED: Removed SSL tab on Redis connection (SSL is not supported for Redis)
### 4.8.8
- CHANGED: New app icon
- ADDED: SQL dump, SQL import - also from/to saved queries

View File

@@ -93,8 +93,8 @@ There are many database managers now, so why DbGate?
## Design goals
* Application simplicity - DbGate takes the best and only the best from old [DbGate](http://www.jenasoft.com/dbgate), [DatAdmin](http://www.jenasoft.com/datadmin) and [DbMouse](http://www.jenasoft.com/dbmouse) .
* Minimal dependencies
* Frontend - Svelte, socket.io
* Backend - NodeJs, ExpressJs, socket.io, database connection drivers
* Frontend - Svelte
* Backend - NodeJs, ExpressJs, database connection drivers
* JavaScript + TypeScript
* App - electron
* Platform independent - runs as web application in single docker container on server, or as application using Electron platform on Linux, Windows and Mac

1
app/.npmrc Normal file
View File

@@ -0,0 +1 @@
better-sqlite3_local_prebuilds=../../prebuilds

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"private": true,
"author": "Jan Prochazka <jenasoft.database@gmail.com>",
"description": "Opensource database administration tool",
@@ -112,7 +112,7 @@
"electron-builder-notarize": "^1.4.0"
},
"optionalDependencies": {
"better-sqlite3": "7.4.5",
"better-sqlite3": "7.5.0",
"msnodesqlv8": "^2.4.4"
}
}

View File

@@ -333,14 +333,13 @@ base64-js@^1.3.1, base64-js@^1.5.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
better-sqlite3@7.4.5:
version "7.4.5"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-7.4.5.tgz#acfc48d786114227f550a0a45e22ace51336e2d0"
integrity sha512-mybC3dgrtJeHkIRGP36tST7wjBlIMgTRAXhhO4bMpPZ17EG23FZxZeFcwKWy6o8mV1SKQFnQNyeAZlQpGrgheQ==
better-sqlite3@7.5.0:
version "7.5.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-7.5.0.tgz#2a91cb616453f002096743b0e5b66a7021cd1c63"
integrity sha512-6FdG9DoytYGDhLW7VWW1vxjEz7xHkqK6LnaUQYA8d6GHNgZhu9PFX2xwKEEnSBRoT1J4PjTUPeg217ShxNmuPg==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.0.0"
tar "^6.1.11"
bindings@^1.5.0:
version "1.5.0"
@@ -514,11 +513,6 @@ chownr@^1.1.1:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
chownr@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
chromium-pickle-js@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205"
@@ -1131,13 +1125,6 @@ fs-extra@^9.0.0, fs-extra@^9.0.1:
jsonfile "^6.0.1"
universalify "^2.0.0"
fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
dependencies:
minipass "^3.0.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1687,21 +1674,6 @@ minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
minipass@^3.0.0:
version "3.1.6"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee"
integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==
dependencies:
yallist "^4.0.0"
minizlib@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
dependencies:
minipass "^3.0.0"
yallist "^4.0.0"
mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
@@ -1714,7 +1686,7 @@ mkdirp@^0.5.4:
dependencies:
minimist "^1.2.5"
mkdirp@^1.0.3, mkdirp@^1.0.4:
mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
@@ -2465,18 +2437,6 @@ tar-stream@^2.1.4:
inherits "^2.0.3"
readable-stream "^3.1.1"
tar@^6.1.11:
version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
dependencies:
chownr "^2.0.0"
fs-minipass "^2.0.0"
minipass "^3.0.0"
minizlib "^2.1.1"
mkdirp "^1.0.3"
yallist "^4.0.0"
temp-file@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.4.0.tgz#766ea28911c683996c248ef1a20eea04d51652c7"

View File

@@ -14,7 +14,7 @@ const txMatch = (tname, vcolname, nextcol) =>
expect.objectContaining({
columnName: 'id',
notNull: true,
dataType: expect.stringContaining('int'),
dataType: expect.stringMatching(/int/i),
}),
expect.objectContaining({
columnName: vcolname,

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate-integration-tests",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"private": true,
"version": "4.8.9-beta.1",
"version": "5.0.0",
"name": "dbgate-all",
"workspaces": [
"packages/*",
@@ -50,8 +50,7 @@
},
"dependencies": {
"concurrently": "^5.1.0",
"patch-package": "^6.2.1",
"socket.io": "^2.3.0"
"patch-package": "^6.2.1"
},
"devDependencies": {
"copyfiles": "^2.2.0",

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-api",
"main": "src/index.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
@@ -26,8 +26,8 @@
"cors": "^2.8.5",
"cross-env": "^6.0.3",
"dbgate-query-splitter": "^4.9.0",
"dbgate-sqltree": "^4.1.1",
"dbgate-tools": "^4.1.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"diff": "^5.0.0",
"diff2html": "^3.4.13",
"eslint": "^6.8.0",
@@ -63,7 +63,7 @@
"devDependencies": {
"@types/fs-extra": "^9.0.11",
"@types/lodash": "^4.14.149",
"dbgate-types": "^4.1.1",
"dbgate-types": "^5.0.0-alpha.1",
"env-cmd": "^10.1.0",
"node-loader": "^1.0.2",
"nodemon": "^2.0.2",
@@ -72,7 +72,7 @@
"webpack-cli": "^3.3.11"
},
"optionalDependencies": {
"better-sqlite3": "7.4.5",
"better-sqlite3": "7.5.0",
"msnodesqlv8": "^2.4.4"
}
}

View File

@@ -73,7 +73,8 @@ module.exports = {
...value,
};
if (value['app.useNativeMenu'] !== true && value['app.useNativeMenu'] !== false) {
res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
// res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
res['app.useNativeMenu'] = false;
}
return res;
},

View File

@@ -99,6 +99,12 @@ module.exports = {
}
},
loadFrom_meta: true,
async loadFrom({ filePath, format }, req) {
const text = await fs.readFile(filePath, { encoding: 'utf-8' });
return deserialize(format, text);
},
save_meta: true,
async save({ folder, file, data, format }, req) {
if (folder.startsWith('archive:')) {

View File

@@ -162,6 +162,7 @@ module.exports = {
authTypes_meta: true,
async authTypes({ engine }) {
const packageName = extractPackageName(engine);
if (!packageName) return null;
const content = requirePlugin(packageName);
const driver = content.drivers.find(x => x.engine == engine);
if (!driver || !driver.getAuthTypes) return null;

View File

@@ -1,5 +1,5 @@
module.exports = {
version: '4.1.1',
version: '5.0.0-alpha.1',
buildTime: '2021-04-17T07:22:49.702Z'
};

View File

@@ -5,10 +5,11 @@ const { driverBase } = require('dbgate-tools');
const requireEngineDriver = require('../utility/requireEngineDriver');
class SqlizeStream extends stream.Transform {
constructor({ fileName }) {
constructor({ fileName, dataName }) {
super({ objectMode: true });
this.wasHeader = false;
this.tableName = path.parse(fileName).name;
this.dataName = dataName;
this.driver = driverBase;
}
_transform(chunk, encoding, done) {
@@ -28,7 +29,7 @@ class SqlizeStream extends stream.Transform {
const dmp = this.driver.createDumper();
dmp.put(
'^insert ^into %f (%,i) ^values (%,v);\n',
{ pureName: this.tableName },
{ pureName: this.dataName || this.tableName },
Object.keys(chunk),
Object.values(chunk)
);
@@ -38,9 +39,9 @@ class SqlizeStream extends stream.Transform {
}
}
async function sqlDataWriter({ fileName, driver, encoding = 'utf-8' }) {
async function sqlDataWriter({ fileName, dataName, driver, encoding = 'utf-8' }) {
console.log(`Writing file ${fileName}`);
const stringify = new SqlizeStream({ fileName });
const stringify = new SqlizeStream({ fileName, dataName });
const fileStream = fs.createWriteStream(fileName, encoding);
stringify.pipe(fileStream);
stringify['finisher'] = fileStream;

View File

@@ -1,5 +1,5 @@
{
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"name": "dbgate-datalib",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -11,11 +11,11 @@
"lib"
],
"dependencies": {
"dbgate-sqltree": "^4.1.1",
"dbgate-filterparser": "^4.1.1"
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-filterparser": "^5.0.0-alpha.1"
},
"devDependencies": {
"dbgate-types": "^4.1.1",
"dbgate-types": "^5.0.0-alpha.1",
"@types/node": "^13.7.0",
"typescript": "^4.4.3"
}

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",

View File

@@ -1,5 +1,5 @@
{
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"name": "dbgate-filterparser",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -13,7 +13,7 @@
"lib"
],
"devDependencies": {
"dbgate-types": "^4.1.1",
"dbgate-types": "^5.0.0-alpha.1",
"@types/jest": "^25.1.4",
"@types/node": "^13.7.0",
"jest": "^24.9.0",
@@ -22,7 +22,7 @@
},
"dependencies": {
"@types/parsimmon": "^1.10.1",
"dbgate-tools": "^4.1.1",
"dbgate-tools": "^5.0.0-alpha.1",
"lodash": "^4.17.21",
"moment": "^2.24.0",
"parsimmon": "^1.13.0"

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate-serve",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
@@ -18,15 +18,15 @@
"web"
],
"dependencies": {
"dbgate-api": "^4.1.1",
"dbgate-plugin-csv": "^4.1.1",
"dbgate-plugin-excel": "^4.1.1",
"dbgate-plugin-mongo": "^4.1.1",
"dbgate-plugin-mssql": "^4.1.1",
"dbgate-plugin-mysql": "^4.1.1",
"dbgate-plugin-postgres": "^4.1.1",
"dbgate-plugin-xml": "^4.1.1",
"dbgate-web": "^4.1.1",
"dbgate-api": "^5.0.0-alpha.1",
"dbgate-plugin-csv": "^5.0.0-alpha.1",
"dbgate-plugin-excel": "^5.0.0-alpha.1",
"dbgate-plugin-mongo": "^5.0.0-alpha.1",
"dbgate-plugin-mssql": "^5.0.0-alpha.1",
"dbgate-plugin-mysql": "^5.0.0-alpha.1",
"dbgate-plugin-postgres": "^5.0.0-alpha.1",
"dbgate-plugin-xml": "^5.0.0-alpha.1",
"dbgate-web": "^5.0.0-alpha.1",
"dotenv": "^16.0.0"
}
}

View File

@@ -1,5 +1,5 @@
{
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"name": "dbgate-sqltree",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -27,7 +27,7 @@
],
"devDependencies": {
"@types/node": "^13.7.0",
"dbgate-types": "^4.1.1",
"dbgate-types": "^5.0.0-alpha.1",
"typescript": "^4.4.3"
},
"dependencies": {

View File

@@ -1,5 +1,5 @@
{
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"name": "dbgate-tools",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -25,7 +25,7 @@
],
"devDependencies": {
"@types/node": "^13.7.0",
"dbgate-types": "^4.1.1",
"dbgate-types": "^5.0.0-alpha.1",
"jest": "^24.9.0",
"ts-jest": "^25.2.1",
"typescript": "^4.4.3"
@@ -33,7 +33,7 @@
"dependencies": {
"lodash": "^4.17.21",
"dbgate-query-splitter": "^4.9.0",
"dbgate-sqltree": "^4.1.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"uuid": "^3.4.0"
}
}

View File

@@ -111,4 +111,6 @@ export const driverBase = {
dumpSqlSelect(dmp, select);
return this.readQuery(pool, dmp.s, structure);
},
showConnectionField: (field, values) => false,
showConnectionTab: (field) => true,
};

View File

@@ -32,4 +32,6 @@ export interface SqlDialect {
dropReferencesWhenDropTable?: boolean;
disableExplicitTransaction?: boolean;
predefinedDataTypes: string[];
}

View File

@@ -1,5 +1,5 @@
{
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"name": "dbgate-types",
"homepage": "https://dbgate.org/",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate-web",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"scripts": {
"build": "rollup -c",
"dev": "cross-env API_URL=http://localhost:3000 rollup -c -w",
@@ -23,11 +23,11 @@
"chart.js": "^3.6.0",
"chartjs-adapter-moment": "^1.0.0",
"cross-env": "^7.0.3",
"dbgate-datalib": "^4.1.1",
"dbgate-datalib": "^5.0.0-alpha.1",
"dbgate-query-splitter": "^4.9.0",
"dbgate-sqltree": "^4.1.1",
"dbgate-tools": "^4.1.1",
"dbgate-types": "^4.1.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-types": "^5.0.0-alpha.1",
"diff": "^5.0.0",
"diff2html": "^3.4.13",
"file-selector": "^0.2.4",

View File

@@ -71,6 +71,7 @@
draggable={true}
on:click={handleClick}
on:mouseup={handleMouseUp}
on:dblclick
use:contextMenu={disableContextMenu ? null : menu}
on:dragstart={e => {
e.dataTransfer.setData('app_object_drag_data', JSON.stringify(data));

View File

@@ -15,6 +15,8 @@
export let checkedObjectsStore = null;
export let disableContextMenu = false;
export let passProps;
export let getIsExpanded = null;
export let setIsExpanded = null;
export let groupFunc = undefined;
@@ -34,7 +36,6 @@
})
: null;
// let filtered = [];
// $: {
@@ -77,6 +78,8 @@
{disableContextMenu}
{filter}
{passProps}
{getIsExpanded}
{setIsExpanded}
/>
{/each}
{:else}
@@ -95,6 +98,8 @@
{filter}
isExpandedBySearch={childrenMatched.includes(data)}
{passProps}
{getIsExpanded}
{setIsExpanded}
/>
{/each}
{/if}

View File

@@ -22,23 +22,28 @@
export let disableContextMenu = false;
export let isExpandedBySearch = false;
export let passProps;
export let getIsExpanded = null;
export let setIsExpanded = null;
let isExpanded = false;
let isExpandedCore = false;
async function handleExpand() {
if (subItemsComponent && expandOnClick) {
await tick();
isExpanded = !isExpanded;
handleExpandButton();
}
}
function handleExpandButton() {
isExpanded = !isExpanded;
if (getIsExpanded && setIsExpanded) {
setIsExpanded(data, !isExpanded);
} else {
isExpandedCore = !isExpandedCore;
}
}
$: expandable = data && isExpandable && isExpandable(data);
$: if (!expandable && isExpanded) isExpanded = false;
$: isExpanded = expandable ? (getIsExpanded && setIsExpanded ? getIsExpanded(data) : isExpandedCore) : false;
</script>
{#if !isHidden}

View File

@@ -11,15 +11,41 @@
const databases = getLocalStorage(`database_list_${_id}`) || [];
return filterName(filter, ...databases.map(x => x.name));
};
export function openConnection(connection) {
if (connection.singleDatabase) {
currentDatabase.set({ connection, name: connection.defaultDatabase });
apiCall('database-connections/refresh', {
conid: connection._id,
database: connection.defaultDatabase,
keepOpen: true,
});
openedSingleDatabaseConnections.update(x => _.uniq([...x, connection._id]));
} else {
openedConnections.update(x => _.uniq([...x, connection._id]));
apiCall('server-connections/refresh', {
conid: connection._id,
keepOpen: true,
});
expandedConnections.update(x => _.uniq([...x, connection._id]));
}
closeMultipleTabs(x => x.tabComponent == 'ConnectionTab' && x.props?.conid == connection._id, true);
}
</script>
<script lang="ts">
import _ from 'lodash';
import AppObjectCore from './AppObjectCore.svelte';
import { currentDatabase, extensions, getCurrentConfig, getOpenedConnections, openedConnections } from '../stores';
import {
currentDatabase,
expandedConnections,
extensions,
getCurrentConfig,
getOpenedConnections,
openedConnections,
openedSingleDatabaseConnections,
} from '../stores';
import { filterName } from 'dbgate-tools';
import { showModal } from '../modals/modalTools';
import ConnectionModal from '../modals/ConnectionModal.svelte';
import ConfirmModal from '../modals/ConfirmModal.svelte';
import InputTextModal from '../modals/InputTextModal.svelte';
import openNewTab from '../utility/openNewTab';
@@ -30,6 +56,8 @@
import { getLocalStorage } from '../utility/storageCache';
import { apiCall } from '../utility/api';
import ImportDatabaseDumpModal from '../modals/ImportDatabaseDumpModal.svelte';
import { closeMultipleTabs } from '../widgets/TabsPanel.svelte';
import AboutModal from '../modals/AboutModal.svelte';
export let data;
export let passProps;
@@ -43,20 +71,30 @@
const electron = getElectron();
const handleConnect = () => {
if (data.singleDatabase) {
$currentDatabase = { connection: data, name: data.defaultDatabase };
apiCall('database-connections/refresh', {
openConnection(data);
};
const handleOpenConnectionTab = () => {
openNewTab({
title: getConnectionLabel(data),
icon: 'img connection',
tabComponent: 'ConnectionTab',
props: {
conid: data._id,
database: data.defaultDatabase,
keepOpen: true,
});
} else {
$openedConnections = _.uniq([...$openedConnections, data._id]);
apiCall('server-connections/refresh', {
conid: data._id,
keepOpen: true,
});
},
});
};
const handleClick = () => {
if ($openedSingleDatabaseConnections.includes(data._id)) {
currentDatabase.set({ connection: data, name: data.defaultDatabase });
return;
}
if ($openedConnections.includes(data._id)) {
return;
}
handleOpenConnectionTab();
};
const handleSqlRestore = () => {
@@ -82,9 +120,17 @@
}
currentDatabase.set(null);
}
};
const handleEdit = () => {
showModal(ConnectionModal, { connection: data });
closeMultipleTabs(x => x.props.conid == data._id);
if (data.unsaved) {
openNewTab({
title: 'New Connection',
icon: 'img connection',
tabComponent: 'ConnectionTab',
props: {
conid: data._id,
},
});
}
};
const handleDelete = () => {
showModal(ConfirmModal, {
@@ -126,11 +172,11 @@
return [
config.runAsPortal == false && [
{
!$openedConnections.includes(data._id) && {
text: 'Edit',
onClick: handleEdit,
onClick: handleOpenConnectionTab,
},
{
!$openedConnections.includes(data._id) && {
text: 'Delete',
onClick: handleDelete,
},
@@ -163,7 +209,14 @@
],
data.singleDatabase && [
{ divider: true },
getDatabaseMenuItems(data, data.defaultDatabase, $extensions, $currentDatabase, $apps),
getDatabaseMenuItems(
data,
data.defaultDatabase,
$extensions,
$currentDatabase,
$apps,
$openedSingleDatabaseConnections
),
],
driver?.databaseEngineTypes?.includes('sql') && { onClick: handleSqlRestore, text: 'Restore/import SQL dump' },
@@ -205,7 +258,7 @@
<AppObjectCore
{...$$restProps}
{data}
title={getConnectionLabel(data)}
title={getConnectionLabel(data, { showUnsaved: true })}
icon={data.singleDatabase ? 'img database' : 'img server'}
isBold={data.singleDatabase
? _.get($currentDatabase, 'connection._id') == data._id && _.get($currentDatabase, 'name') == data.defaultDatabase
@@ -216,9 +269,10 @@
{extInfo}
colorMark={passProps?.connectionColorFactory && passProps?.connectionColorFactory({ conid: data._id })}
menu={getContextMenu}
on:click={handleConnect}
on:click={handleClick}
on:click
on:expand
on:dblclick={handleConnect}
on:middleclick={() => {
_.flattenDeep(getContextMenu())
.find(x => x.isNewQuery)

View File

@@ -1,7 +1,14 @@
<script lang="ts" context="module">
export const extractKey = props => props.name;
export function getDatabaseMenuItems(connection, name, $extensions, $currentDatabase, $apps) {
export function getDatabaseMenuItems(
connection,
name,
$extensions,
$currentDatabase,
$apps,
$openedSingleDatabaseConnections
) {
const apps = filterAppsForDatabase(connection, name, $apps);
const handleNewQuery = () => {
const tooltip = `${getConnectionLabel(connection)}\n${name}`;
@@ -132,7 +139,10 @@
if (electron) {
apiCall('database-connections/disconnect', { conid: connection._id, database: name });
}
currentDatabase.set(null);
if (getCurrentDatabase()?.connection?._id == connection._id && getCurrentDatabase()?.name == name) {
currentDatabase.set(null);
}
openedSingleDatabaseConnections.update(list => list.filter(x => x != connection._id));
};
const handleExportModel = async () => {
@@ -233,8 +243,9 @@
driver?.databaseEngineTypes?.includes('keyvalue') && { onClick: handleGenerateScript, text: 'Generate script' },
_.get($currentDatabase, 'connection._id') == _.get(connection, '_id') &&
_.get($currentDatabase, 'name') == name && { onClick: handleDisconnect, text: 'Disconnect' },
($openedSingleDatabaseConnections.includes(connection._id) ||
(_.get($currentDatabase, 'connection._id') == _.get(connection, '_id') &&
_.get($currentDatabase, 'name') == name)) && { onClick: handleDisconnect, text: 'Disconnect' },
commands.length > 0 && [
{ divider: true },
@@ -266,7 +277,10 @@
currentArchive,
currentDatabase,
extensions,
getCurrentDatabase,
getExtensions,
openedConnections,
openedSingleDatabaseConnections,
pinnedDatabases,
selectedWidget,
} from '../stores';
@@ -285,13 +299,20 @@
import newQuery from '../query/newQuery';
import { exportSqlDump } from '../utility/exportFileTools';
import ImportDatabaseDumpModal from '../modals/ImportDatabaseDumpModal.svelte';
import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte';
import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte';
export let data;
export let passProps;
function createMenu() {
return getDatabaseMenuItems(data.connection, data.name, $extensions, $currentDatabase, $apps);
return getDatabaseMenuItems(
data.connection,
data.name,
$extensions,
$currentDatabase,
$apps,
$openedSingleDatabaseConnections
);
}
$: isPinned = !!$pinnedDatabases.find(x => x.name == data.name && x.connection?._id == data.connection?._id);

View File

@@ -65,7 +65,7 @@
currentConnection: true,
};
const HANDLERS = {
export const SAVED_FILE_HANDLERS = {
sql,
shell,
markdown,
@@ -97,7 +97,7 @@
export let data;
$: folder = data?.folder;
$: handler = HANDLERS[folder] as FileTypeHandler;
$: handler = SAVED_FILE_HANDLERS[folder] as FileTypeHandler;
const showMarkdownPage = () => {
openNewTab({

View File

@@ -1,10 +1,7 @@
import { currentDatabase, currentTheme, extensions, getExtensions, getVisibleToolbar, visibleToolbar } from '../stores';
import registerCommand from './registerCommand';
import { get } from 'svelte/store';
import { ThemeDefinition } from 'dbgate-types';
import ConnectionModal from '../modals/ConnectionModal.svelte';
import AboutModal from '../modals/AboutModal.svelte';
import AddDbKeyModal from '../modals/AddDbKeyModal.svelte';
import SettingsModal from '../settings/SettingsModal.svelte';
import ImportExportModal from '../modals/ImportExportModal.svelte';
import SqlGeneratorModal from '../modals/SqlGeneratorModal.svelte';
@@ -87,7 +84,13 @@ registerCommand({
toolbarOrder: 1,
name: 'Connection',
testEnabled: () => !getCurrentConfig()?.runAsPortal,
onClick: () => showModal(ConnectionModal),
onClick: () => {
openNewTab({
title: 'New Connection',
icon: 'img connection',
tabComponent: 'ConnectionTab',
});
},
});
registerCommand({

View File

@@ -13,6 +13,8 @@
export let value = 0;
export let menu = null;
export let isInline = false;
export let containerMaxWidth = undefined;
export let flex1 = true;
export function setValue(index) {
value = index;
@@ -22,7 +24,7 @@
}
</script>
<div class="main">
<div class="main" class:flex1>
<div class="tabs">
{#each _.compact(tabs) as tab, index}
<div class="tab-item" class:selected={value == index} on:click={() => (value = index)}>
@@ -38,7 +40,7 @@
<div class="content-container">
{#each _.compact(tabs) as tab, index}
<div class="container" class:isInline class:tabVisible={index == value}>
<div class="container" class:isInline class:tabVisible={index == value} style:max-width={containerMaxWidth}>
<svelte:component this={tab.component} {...tab.props} tabControlHiddenTab={index != value} />
{#if tab.slot != null}
{#if tab.slot == 0}<slot name="0" />
@@ -59,10 +61,13 @@
<style>
.main {
display: flex;
flex: 1;
flex-direction: column;
}
.main.flex1 {
flex: 1;
}
.tabs {
display: flex;
height: var(--dim-tabs-height);

View File

@@ -141,6 +141,7 @@
'img app': 'mdi mdi-layers-triple color-icon-magenta',
'img app-command': 'mdi mdi-flash color-icon-green',
'img app-query': 'mdi mdi-view-comfy color-icon-magenta',
'img connection': 'mdi mdi-connection color-icon-blue',
'img add': 'mdi mdi-plus-circle color-icon-green',
'img minus': 'mdi mdi-minus-circle color-icon-red',

View File

@@ -1,163 +0,0 @@
<script lang="ts">
import registerCommand from '../commands/registerCommand';
import FormButton from '../forms/FormButton.svelte';
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import TabControl from '../elements/TabControl.svelte';
import ConnectionModalDriverFields from './ConnectionModalDriverFields.svelte';
import ConnectionModalSshTunnelFields from './ConnectionModalSshTunnelFields.svelte';
import ConnectionModalSslFields from './ConnectionModalSslFields.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal, closeModal, showModal } from './modalTools';
import createRef from '../utility/createRef';
import Link from '../elements/Link.svelte';
import ErrorMessageModal from './ErrorMessageModal.svelte';
import { writable } from 'svelte/store';
import FormProviderCore from '../forms/FormProviderCore.svelte';
import { extensions, getCurrentConfig } from '../stores';
import _ from 'lodash';
import { getDatabaseFileLabel } from '../utility/getConnectionLabel';
import { apiCall } from '../utility/api';
export let connection;
let isTesting;
let sqlConnectResult;
const values = writable(
connection || {
server: getCurrentConfig().isDocker ? 'dockerhost' : 'localhost',
engine: 'mssql@dbgate-plugin-mssql',
}
);
$: engine = $values.engine;
$: driver = $extensions.drivers.find(x => x.engine == engine);
const testIdRef = createRef(0);
async function handleTest(e) {
isTesting = true;
testIdRef.update(x => x + 1);
const testid = testIdRef.get();
const resp = await apiCall('connections/test', e.detail);
if (testIdRef.get() != testid) return;
isTesting = false;
sqlConnectResult = resp;
}
function handleCancelTest() {
testIdRef.update(x => x + 1); // invalidate current test
isTesting = false;
}
async function handleSubmit(e) {
const allProps = [
'databaseFile',
'useDatabaseUrl',
'databaseUrl',
'authType',
'server',
'port',
'user',
'password',
'defaultDatabase',
'singleDatabase',
];
const visibleProps = allProps.filter(x => !driver?.showConnectionField || driver.showConnectionField(x, $values));
const omitProps = _.difference(allProps, visibleProps);
if (!$values.defaultDatabase) omitProps.push('singleDatabase');
let connection = _.omit(e.detail, omitProps);
if (driver?.beforeConnectionSave) connection = driver?.beforeConnectionSave(connection);
apiCall('connections/save', connection);
closeCurrentModal();
}
</script>
<FormProviderCore template={FormFieldTemplateLarge} {values}>
<ModalBase {...$$restProps} noPadding>
<div slot="header">Add connection</div>
<TabControl
isInline
tabs={[
{
label: 'Main',
component: ConnectionModalDriverFields,
},
(!driver?.showConnectionTab || driver?.showConnectionTab('sshTunnel', $values)) && {
label: 'SSH Tunnel',
component: ConnectionModalSshTunnelFields,
},
(!driver?.showConnectionTab || driver?.showConnectionTab('ssl', $values)) && {
label: 'SSL',
component: ConnectionModalSslFields,
},
]}
/>
<div slot="footer" class="flex">
<div class="buttons">
{#if isTesting}
<FormButton value="Cancel test" on:click={handleCancelTest} />
{:else}
<FormButton value="Test" on:click={handleTest} />
{/if}
<FormSubmit value="Save" on:click={handleSubmit} />
</div>
<div class="test-result">
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'connected'}
<div>
Connected: <FontIcon icon="img ok" />
{sqlConnectResult.version}
</div>
{/if}
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'error'}
<div class="error-result">
Connect failed: <FontIcon icon="img error" />
{sqlConnectResult.error}
<Link
onClick={() =>
showModal(ErrorMessageModal, {
message: sqlConnectResult.detail,
showAsCode: true,
title: 'Database connection error',
})}
>
Show detail
</Link>
</div>
{/if}
{#if isTesting}
<div>
<FontIcon icon="icon loading" /> Testing connection
</div>
{/if}
</div>
</div>
</ModalBase>
</FormProviderCore>
<style>
.buttons {
flex-shrink: 0;
}
.test-result {
margin-left: 10px;
align-self: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.error-result {
white-space: normal;
}
</style>

View File

@@ -48,10 +48,11 @@ const jsonQuickExport = {
const sqlQuickExport = {
label: 'SQL',
extension: 'sql',
createWriter: fileName => ({
createWriter: (fileName, dataName) => ({
functionName: 'sqlDataWriter',
props: {
fileName,
dataName,
},
}),
};

View File

@@ -28,8 +28,8 @@
$: driver = $extensions.drivers.find(x => x.engine == engine);
$: defaultDatabase = $values.defaultDatabase;
$: showUser = !driver?.showConnectionField || driver.showConnectionField('user', $values);
$: showPassword = !driver?.showConnectionField || driver.showConnectionField('password', $values);
$: showUser = driver?.showConnectionField('user', $values);
$: showPassword = driver?.showConnectionField('password', $values);
</script>
<FormSelectField
@@ -47,11 +47,11 @@
]}
/>
{#if !driver?.showConnectionField || driver.showConnectionField('databaseFile', $values)}
{#if driver?.showConnectionField('databaseFile', $values)}
<FormElectronFileSelector label="Database file" name="databaseFile" disabled={!electron} />
{/if}
{#if !driver?.showConnectionField || driver.showConnectionField('useDatabaseUrl', $values)}
{#if driver?.showConnectionField('useDatabaseUrl', $values)}
<div class="radio">
<FormRadioGroupField
name="useDatabaseUrl"
@@ -63,11 +63,11 @@
</div>
{/if}
{#if !driver?.showConnectionField || driver.showConnectionField('databaseUrl', $values)}
{#if driver?.showConnectionField('databaseUrl', $values)}
<FormTextField label="Database URL" name="databaseUrl" placeholder={driver?.databaseUrlPlaceholder} />
{/if}
{#if $authTypes && (!driver?.showConnectionField || driver.showConnectionField('authType', $values))}
{#if $authTypes && driver?.showConnectionField('authType', $values)}
<FormSelectField
label="Authentication"
name="authType"
@@ -80,7 +80,7 @@
/>
{/if}
{#if !driver?.showConnectionField || driver.showConnectionField('server', $values)}
{#if driver?.showConnectionField('server', $values)}
<div class="row">
<div class="col-9 mr-1">
<FormTextField
@@ -90,7 +90,7 @@
templateProps={{ noMargin: true }}
/>
</div>
{#if !driver?.showConnectionField || driver.showConnectionField('port', $values)}
{#if driver?.showConnectionField('port', $values)}
<div class="col-3 mr-1">
<FormTextField
label="Port"
@@ -154,32 +154,34 @@
/>
{/if}
{#if driver.showConnectionField('isReadOnly', $values)}
{#if driver?.showConnectionField('isReadOnly', $values)}
<FormCheckboxField label="Is read only" name="isReadOnly" />
{/if}
{#if !driver?.showConnectionField || driver.showConnectionField('defaultDatabase', $values)}
{#if driver?.showConnectionField('defaultDatabase', $values)}
<FormTextField label="Default database" name="defaultDatabase" />
{/if}
{#if defaultDatabase && (!driver?.showConnectionField || driver.showConnectionField('singleDatabase', $values))}
{#if defaultDatabase && driver?.showConnectionField('singleDatabase', $values)}
<FormCheckboxField label={`Use only database ${defaultDatabase}`} name="singleDatabase" />
{/if}
<div class="row">
<div class="col-6 mr-1">
<FormTextField label="Display name" name="displayName" templateProps={{ noMargin: true }} />
{#if driver}
<div class="row">
<div class="col-6 mr-1">
<FormTextField label="Display name" name="displayName" templateProps={{ noMargin: true }} />
</div>
<div class="col-6 mr-1">
<FormColorField
useSelector
label="Color"
name="connectionColor"
emptyLabel="(not selected)"
templateProps={{ noMargin: true }}
/>
</div>
</div>
<div class="col-6 mr-1">
<FormColorField
useSelector
label="Color"
name="connectionColor"
emptyLabel="(not selected)"
templateProps={{ noMargin: true }}
/>
</div>
</div>
{/if}
<style>
.row {

View File

@@ -47,6 +47,8 @@ function subscribeCssVariable(store, transform, cssVariable) {
export const selectedWidget = writableWithStorage('database', 'selectedWidget');
export const openedConnections = writable([]);
export const openedSingleDatabaseConnections = writable([]);
export const expandedConnections = writable([]);
export const currentDatabase = writable(null);
export const openedTabs = writableWithStorage<TabDefinition[]>([], 'openedTabs');
export const copyRowsFormat = writableWithStorage('textWithoutHeaders', 'copyRowsFormat');
@@ -108,6 +110,7 @@ export const visibleTitleBar = derived(useSettings(), $settings => {
if (nativeMenuOnStartup == null) {
nativeMenuOnStartup = !!$settings['app.useNativeMenu'];
}
// console.log('nativeMenuOnStartup', nativeMenuOnStartup);
return !$settings['app.fullscreen'] && !nativeMenuOnStartup;
});
@@ -186,6 +189,14 @@ export const getPinnedDatabases = () => _.compact(pinnedDatabasesValue);
let currentDatabaseValue = null;
currentDatabase.subscribe(value => {
currentDatabaseValue = value;
if (value?.connection?._id) {
if (value?.connection?.singleDatabase) {
openedSingleDatabaseConnections.update(x => _.uniq([...x, value?.connection?._id]));
} else {
openedConnections.update(x => _.uniq([...x, value?.connection?._id]));
expandedConnections.update(x => _.uniq([...x, value?.connection?._id]));
}
}
invalidateCommands();
});
export const getCurrentDatabase = () => currentDatabaseValue;

View File

@@ -26,7 +26,7 @@
>
<FormTextField name="columnName" label="Column name" focused />
<DataTypeEditor />
<DataTypeEditor dialect={driver?.dialect} />
<FormCheckboxField name="notNull" label="NOT NULL" />
<FormCheckboxField name="isPrimaryKey" label="Is Primary Key" />

View File

@@ -4,7 +4,7 @@
const { values, setFieldValue } = getFormContext();
$: dataTypes = ['int', 'nvarchar(250)', 'datetime', 'numeric(10,2)', 'float'];
$: dataTypes = dialect?.predefinedDataTypes || ['int', 'varchar(250)', 'datetime', 'numeric(10,2)', 'float'];
function createDataTypesMenu() {
return dataTypes.map(type => ({
@@ -13,6 +13,7 @@
}));
}
export let dialect;
</script>
<FormDropDownTextField name="dataType" label="Data type" menu={createDataTypesMenu} />

View File

@@ -0,0 +1,239 @@
<script lang="ts" context="module">
export const matchingProps = ['conid'];
</script>
<script lang="ts">
import FormButton from '../forms/FormButton.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import TabControl from '../elements/TabControl.svelte';
import ConnectionDriverFields from '../settings/ConnectionDriverFields.svelte';
import ConnectionSshTunnelFields from '../settings/ConnectionSshTunnelFields.svelte';
import ConnectionSslFields from '../settings/ConnectionSslFields.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import { showModal } from '../modals/modalTools';
import createRef from '../utility/createRef';
import Link from '../elements/Link.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { writable } from 'svelte/store';
import FormProviderCore from '../forms/FormProviderCore.svelte';
import { extensions, getCurrentConfig, openedTabs } from '../stores';
import _, { Dictionary } from 'lodash';
import { apiCall } from '../utility/api';
import { showSnackbarSuccess } from '../utility/snackbar';
import { changeTab } from '../utility/common';
import getConnectionLabel from '../utility/getConnectionLabel';
import { onMount } from 'svelte';
import { openConnection } from '../appobj/ConnectionAppObject.svelte';
import { closeMultipleTabs } from '../widgets/TabsPanel.svelte';
export let connection;
export let tabid;
export let conid;
let isTesting;
let sqlConnectResult;
const values = writable(
connection || {
server: getCurrentConfig().isDocker ? 'dockerhost' : 'localhost',
engine: '',
}
);
$: engine = $values.engine;
$: driver = $extensions.drivers.find(x => x.engine == engine);
const testIdRef = createRef(0);
async function handleTest(e) {
isTesting = true;
testIdRef.update(x => x + 1);
const testid = testIdRef.get();
const resp = await apiCall('connections/test', e.detail);
if (testIdRef.get() != testid) return;
isTesting = false;
sqlConnectResult = resp;
}
function handleCancelTest() {
testIdRef.update(x => x + 1); // invalidate current test
isTesting = false;
}
function getCurrentConnection() {
const allProps = [
'databaseFile',
'useDatabaseUrl',
'databaseUrl',
'authType',
'server',
'port',
'user',
'password',
'defaultDatabase',
'singleDatabase',
];
const visibleProps = allProps.filter(x => driver?.showConnectionField(x, $values));
const omitProps = _.difference(allProps, visibleProps);
if (!$values.defaultDatabase) omitProps.push('singleDatabase');
let connection: Dictionary<string | boolean> = _.omit($values, omitProps);
if (driver?.beforeConnectionSave) connection = driver?.beforeConnectionSave(connection);
if (!driver?.showConnectionTab('sshTunnel', $values)) {
if (!$values.useSshTunnel) {
connection = _.omitBy(connection, (v, k) => k.startsWith('ssh'));
}
} else {
connection = _.omit(connection, ['useSshTunnel']);
connection = _.omitBy(connection, (v, k) => k.startsWith('ssh'));
}
if (!driver?.showConnectionTab('ssl', $values)) {
if (!$values.useSsl) {
connection = _.omitBy(connection, (v, k) => k.startsWith('ssl'));
}
} else {
connection = _.omit(connection, ['useSsl']);
connection = _.omitBy(connection, (v, k) => k.startsWith('ssl'));
}
return connection;
}
async function handleSave() {
let connection = getCurrentConnection();
connection = {
...connection,
unsaved: false,
};
const saved = await apiCall('connections/save', connection);
$values = {
...$values,
_id: saved._id,
unsaved: false,
};
changeTab(tabid, tab => ({
...tab,
title: getConnectionLabel(saved),
props: {
...tab.props,
conid: saved._id,
},
}));
showSnackbarSuccess('Connection saved');
}
async function handleConnect() {
let connection = getCurrentConnection();
if (!connection._id) {
connection = {
...connection,
unsaved: !connection._id,
};
}
const saved = await apiCall('connections/save', connection);
openConnection(saved);
closeMultipleTabs(x => x.tabid == tabid, true);
}
onMount(async () => {
if (conid) {
$values = await apiCall('connections/get', { conid });
}
});
</script>
<FormProviderCore template={FormFieldTemplateLarge} {values}>
<div class="wrapper">
<TabControl
isInline
containerMaxWidth="800px"
flex1={false}
tabs={[
{
label: 'General',
component: ConnectionDriverFields,
},
driver?.showConnectionTab('sshTunnel', $values) && {
label: 'SSH Tunnel',
component: ConnectionSshTunnelFields,
},
driver?.showConnectionTab('ssl', $values) && {
label: 'SSL',
component: ConnectionSslFields,
},
]}
/>
{#if driver}
<div class="flex">
<div class="buttons">
<FormButton value="Connect" on:click={handleConnect} />
{#if isTesting}
<FormButton value="Cancel test" on:click={handleCancelTest} />
{:else}
<FormButton value="Test" on:click={handleTest} />
{/if}
<FormButton value="Save" on:click={handleSave} />
</div>
<div class="test-result">
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'connected'}
<div>
Connected: <FontIcon icon="img ok" />
{sqlConnectResult.version}
</div>
{/if}
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'error'}
<div class="error-result">
Connect failed: <FontIcon icon="img error" />
{sqlConnectResult.error}
<Link
onClick={() =>
showModal(ErrorMessageModal, {
message: sqlConnectResult.detail,
showAsCode: true,
title: 'Database connection error',
})}
>
Show detail
</Link>
</div>
{/if}
{#if isTesting}
<div>
<FontIcon icon="icon loading" /> Testing connection
</div>
{/if}
</div>
</div>
{/if}
</div>
</FormProviderCore>
<style>
.wrapper {
flex: 1;
display: flex;
flex-direction: column;
}
.buttons {
flex-shrink: 0;
margin: var(--dim-large-form-margin);
}
.test-result {
margin-left: 10px;
align-self: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.error-result {
white-space: normal;
}
</style>

View File

@@ -23,6 +23,7 @@ import * as ChangelogTab from './ChangelogTab.svelte';
import * as DiagramTab from './DiagramTab.svelte';
import * as DbKeyDetailTab from './DbKeyDetailTab.svelte';
import * as QueryDataTab from './QueryDataTab.svelte';
import * as ConnectionTab from './ConnectionTab.svelte';
export default {
TableDataTab,
@@ -50,4 +51,5 @@ export default {
DiagramTab,
DbKeyDetailTab,
QueryDataTab,
ConnectionTab,
};

View File

@@ -6,7 +6,8 @@
import { showModal } from '../modals/modalTools';
import { openedTabs } from '../stores';
import { getConfig, useFavorites } from './metadataLoaders';
import { getConfig, getConnectionList, useFavorites } from './metadataLoaders';
import openNewTab from './openNewTab';
import { showSnackbarInfo } from './snackbar';
$: favorites = useFavorites();
@@ -48,6 +49,14 @@
}
}
if (!$openedTabs.find(x => x.closedTime == null) && !(await getConnectionList()).find(x => !x.unsaved)) {
openNewTab({
title: 'New Connection',
icon: 'img connection',
tabComponent: 'ConnectionTab',
});
}
const config = await getConfig();
const appVersion = localStorage.getItem('appVersion');
if (appVersion && appVersion != config.version) {

View File

@@ -8,6 +8,7 @@ let lastCurrentTab = null;
openedTabs.subscribe(value => {
const newCurrentTab = (value || []).find(x => x.selected);
if (newCurrentTab == lastCurrentTab) return;
if (lastCurrentTab?.tabComponent == 'ConnectionTab') return;
if (newCurrentTab) {
const { conid, database } = newCurrentTab.props || {};

View File

@@ -1,6 +1,13 @@
import _ from 'lodash';
import { openedConnections, currentDatabase } from '../stores';
import { apiCall } from './api';
import { getConnectionList } from './metadataLoaders';
// const doServerPing = async value => {
// const connectionList = getConnectionList();
// const connections = value.filter(id => !connectionList.find(x => x._id == id)?.singleDatabase);
// apiCall('server-connections/ping', { connections });
// };
const doServerPing = value => {
apiCall('server-connections/ping', { connections: value });

View File

@@ -5,7 +5,7 @@ export function getDatabaseFileLabel(databaseFile) {
return databaseFile;
}
export default function getConnectionLabel(connection, { allowExplicitDatabase = true } = {}) {
function getConnectionLabelCore(connection, { allowExplicitDatabase = true } = {}) {
if (!connection) {
return null;
}
@@ -27,3 +27,13 @@ export default function getConnectionLabel(connection, { allowExplicitDatabase =
return '';
}
export default function getConnectionLabel(connection, { allowExplicitDatabase = true, showUnsaved = false } = {}) {
const res = getConnectionLabelCore(connection, { allowExplicitDatabase });
if (res && showUnsaved && connection?.unsaved) {
return `${res} - unsaved`;
}
return res;
}

View File

@@ -3,17 +3,19 @@ import { get } from 'svelte/store';
import newQuery from '../query/newQuery';
import ImportExportModal from '../modals/ImportExportModal.svelte';
import getElectron from './getElectron';
import { currentDatabase, extensions } from '../stores';
import { currentDatabase, extensions, getCurrentDatabase } from '../stores';
import { getUploadListener } from './uploadFiles';
import { getDatabaseFileLabel } from './getConnectionLabel';
import getConnectionLabel, { getDatabaseFileLabel } from './getConnectionLabel';
import { apiCall } from './api';
import openNewTab from './openNewTab';
import { SAVED_FILE_HANDLERS } from '../appobj/SavedFileAppObject.svelte';
import _ from 'lodash';
export function canOpenByElectron(file, extensions) {
if (!file) return false;
const nameLower = file.toLowerCase();
if (nameLower.endsWith('.sql')) return true;
if (nameLower.endsWith('.diagram')) return true;
if (nameLower.endsWith('.db') || nameLower.endsWith('.sqlite') || nameLower.endsWith('.sqlite3')) return true;
for (const format of extensions.fileFormats) {
if (nameLower.endsWith(`.${format.extension}`)) return true;
@@ -65,6 +67,40 @@ function openElectronJsonLinesFile(filePath, parsed) {
});
}
async function openSavedElectronFile(filePath, parsed, folder) {
const handler = SAVED_FILE_HANDLERS[folder];
const resp = await apiCall('files/load-from', { filePath, format: handler.format });
const connProps: any = {};
let tooltip = undefined;
const db = getCurrentDatabase();
if (handler.currentConnection) {
const connection = db?.connection || {};
const database = db?.name;
connProps.conid = db?.connection?._id;
connProps.database = database;
tooltip = `${getConnectionLabel(connection)}\n${database}`;
}
openNewTab(
{
title: parsed.name,
icon: handler.icon,
tabComponent: handler.tabComponent,
tooltip,
props: {
savedFile: null,
savedFolder: null,
savedFilePath: filePath,
savedFormat: handler.format,
...connProps,
},
},
{ editor: resp }
);
}
export function openElectronFileCore(filePath, extensions) {
const nameLower = filePath.toLowerCase();
const path = window.require('path');
@@ -93,6 +129,10 @@ export function openElectronFileCore(filePath, extensions) {
openElectronJsonLinesFile(filePath, parsed);
return;
}
if (nameLower.endsWith('.diagram')) {
openSavedElectronFile(filePath, parsed, 'diagrams');
return;
}
for (const format of extensions.fileFormats) {
if (nameLower.endsWith(`.${format.extension}`)) {
if (uploadListener) {
@@ -134,8 +174,12 @@ export async function openElectronFile() {
const filePaths = await electron.showOpenDialog({
filters: [
{ name: `All supported files`, extensions: ['sql', 'sqlite', 'db', 'sqlite3', ...getFileFormatExtensions(ext)] },
{
name: `All supported files`,
extensions: ['sql', 'sqlite', 'db', 'sqlite3', 'diagram', ...getFileFormatExtensions(ext)],
},
{ name: `SQL files`, extensions: ['sql'] },
{ name: `Diagram files`, extensions: ['diagram'] },
{ name: `SQLite database`, extensions: ['sqlite', 'db', 'sqlite3'] },
...getFileFormatFilters(ext),
],

View File

@@ -148,6 +148,9 @@ export async function duplicateTab(tab) {
}
export function getTabDbKey(tab) {
if (tab.tabComponent == 'ConnectionTab') {
return 'connections.';
}
if (tab.props && tab.props.conid && tab.props.database) {
return `database://${tab.props.database}-${tab.props.conid}`;
}

View File

@@ -8,7 +8,7 @@
import AppObjectList from '../appobj/AppObjectList.svelte';
import * as connectionAppObject from '../appobj/ConnectionAppObject.svelte';
import SubDatabaseList from '../appobj/SubDatabaseList.svelte';
import { commands, commandsCustomized, openedConnections } from '../stores';
import { commands, commandsCustomized, expandedConnections, openedConnections, openedTabs } from '../stores';
import ToolbarButton from '../buttons/ToolbarButton.svelte';
import runCommand from '../commands/runCommand';
import getConnectionLabel from '../utility/getConnectionLabel';
@@ -17,6 +17,7 @@
import CloseSearchButton from '../buttons/CloseSearchButton.svelte';
import { apiCall } from '../utility/api';
import LargeButton from '../buttons/LargeButton.svelte';
import { matchingProps } from '../tabs/TableDataTab.svelte';
const connections = useConnectionList();
const serverStatus = useServerStatus();
@@ -28,6 +29,10 @@
? $connections.map(conn => ({ ...conn, status: $serverStatus[conn._id] }))
: $connections;
$: connectionsWithStatusFiltered = connectionsWithStatus?.filter(
x => !x.unsaved || $openedConnections.includes(x._id)
);
const handleRefreshConnections = () => {
for (const conid of $openedConnections) {
apiCall('server-connections/refresh', { conid });
@@ -51,15 +56,18 @@
</SearchBoxWrapper>
<WidgetsInnerContainer>
<AppObjectList
list={_.sortBy(connectionsWithStatus, connection => (getConnectionLabel(connection) || '').toUpperCase())}
list={_.sortBy(connectionsWithStatusFiltered, connection => (getConnectionLabel(connection) || '').toUpperCase())}
module={connectionAppObject}
subItemsComponent={SubDatabaseList}
expandOnClick
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
{filter}
passProps={{ connectionColorFactory: $connectionColorFactory, showPinnedInsteadOfUnpin: true }}
getIsExpanded={data => $expandedConnections.includes(data._id) && !data.singleDatabase}
setIsExpanded={(data, value) =>
expandedConnections.update(old => (value ? [...old, data._id] : old.filter(x => x != data._id)))}
/>
{#if $connections && $connections.length == 0 && $commandsCustomized['new.connection']?.enabled}
{#if $connections && !$connections.find(x => !x.unsaved) && $openedConnections.length == 0 && $commandsCustomized['new.connection']?.enabled && !$openedTabs.find(x => !x.closedTime && x.tabComponent == 'ConnectionTab' && !x.props?.conid)}
<LargeButton icon="icon new-connection" on:click={() => runCommand('new.connection')} fillHorizontal
>Add new connection</LargeButton
>

View File

@@ -22,12 +22,14 @@
});
};
const closeMultipleTabs = closeCondition => {
export const closeMultipleTabs = (closeCondition, deleteFromHistory = false) => {
openedTabs.update(files => {
const newFiles = files.map(x => ({
...x,
closedTime: x.closedTime || (closeCondition(x) ? new Date().getTime() : undefined),
}));
const newFiles = deleteFromHistory
? files.filter(x => !closeCondition(x))
: files.map(x => ({
...x,
closedTime: x.closedTime || (closeCondition(x) ? new Date().getTime() : undefined),
}));
if (newFiles.find(x => x.selected && x.closedTime == null)) {
return newFiles;
@@ -81,6 +83,7 @@
const closeOthers = closeTabFunc((x, active) => x.tabid != active.tabid);
function getTabDbName(tab, connectionList) {
if (tab.tabComponent == 'ConnectionTab') return 'Connections';
if (tab.props && tab.props.conid && tab.props.database) return tab.props.database;
if (tab.props && tab.props.conid) {
const connection = connectionList?.find(x => x._id == tab.props.conid);
@@ -96,6 +99,7 @@
if (key.startsWith('database://')) return 'icon database';
if (key.startsWith('archive://')) return 'icon archive';
if (key.startsWith('server://')) return 'icon server';
if (key.startsWith('connections.')) return 'icon connection';
}
return 'icon file';
}
@@ -383,7 +387,13 @@
class:selected={draggingDbGroup
? tabGroup.grpid == draggingDbGroupTarget?.grpid
: tabGroup.tabDbKey == currentDbKey}
on:click={() => handleSetDb(tabGroup.tabs[0].props)}
on:mouseup={e => {
if (e.button == 1) {
closeMultipleTabs(tab => tabGroup.tabs.find(x => x.tabid == tab.tabid));
} else {
handleSetDb(tabGroup.tabs[0].props);
}
}}
use:contextMenu={getDatabaseContextMenu(tabGroup.tabs)}
style={$connectionColorFactory(
tabGroup.tabs[0].props,

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-plugin-csv",
"main": "dist/backend.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org",
"description": "CSV import/export plugin for DbGate",
"repository": {

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-plugin-excel",
"main": "dist/backend.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"description": "MS Excel import/export plugin for DbGate",
"homepage": "https://dbgate.org",
"repository": {

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-plugin-mongo",
"main": "dist/backend.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"license": "MIT",
"author": "Jan Prochazka",
"homepage": "https://dbgate.org",
@@ -35,7 +35,7 @@
"dbgate-query-splitter": "^4.9.0",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"dbgate-tools": "^4.1.1",
"dbgate-tools": "^5.0.0-alpha.1",
"is-promise": "^4.0.0",
"mongodb": "^3.6.5",
"mongodb-client-encryption": "^1.2.3"

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-plugin-mssql",
"main": "dist/backend.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org",
"description": "MS SQL connect plugin for DbGate",
"repository": {
@@ -35,7 +35,7 @@
"dbgate-query-splitter": "^4.9.0",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"dbgate-tools": "^4.1.1",
"dbgate-tools": "^5.0.0-alpha.1",
"tedious": "^9.2.3",
"async-lock": "^1.2.6"
}

View File

@@ -40,6 +40,36 @@ const dialect = {
isSparse: true,
isPersisted: true,
},
predefinedDataTypes: [
'bigint',
'bit',
'decimal(10,2)',
'int',
'money',
'numeric',
'smallint',
'smallmoney',
'tinyint',
'float',
'real',
'date',
'datetime2',
'datetime',
'datetimeofffset',
'smalldatetime',
'time',
'char(20)',
'varchar(250)',
'text',
'nchar(20)',
'nvarchar(250)',
'ntext',
'binary(100)',
'varbinary(100)',
'image',
'xml',
],
};
/** @type {import('dbgate-types').EngineDriver} */

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-plugin-mysql",
"main": "dist/backend.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org",
"description": "MySQL connect plugin for DbGate",
"repository": {
@@ -34,7 +34,7 @@
"antares-mysql-dumper": "^0.0.1",
"dbgate-plugin-tools": "^1.0.7",
"dbgate-query-splitter": "^4.9.0",
"dbgate-tools": "^4.1.1",
"dbgate-tools": "^5.0.0-alpha.1",
"mysql2": "^2.2.5",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"

View File

@@ -36,6 +36,38 @@ const dialect = {
isUnsigned: true,
isZerofill: true,
},
predefinedDataTypes: [
'char(20)',
'varchar(250)',
'binary(250)',
'varbinary(250)',
'tinyblob',
'tinytext',
'text(1000)',
'blob(1000)',
'mediumtext',
'mediumblob',
'longtext',
'longblob',
'enum(val1,val2,val3)',
'set(val1,val2,val3)',
'bit(32)',
'tinyint',
'bool',
'smallint',
'mediumint',
'int',
'bigint',
'float',
'double',
'decimal',
'date',
'datetime',
'timestamp',
'time',
'year',
],
};
const mysqlDriverBase = {

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-plugin-postgres",
"main": "dist/backend.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"license": "MIT",
"description": "PostgreSQL connector plugin for DbGate",
"homepage": "https://dbgate.org",
@@ -32,7 +32,7 @@
"devDependencies": {
"dbgate-plugin-tools": "^1.0.7",
"dbgate-query-splitter": "^4.9.0",
"dbgate-tools": "^4.1.1",
"dbgate-tools": "^5.0.0-alpha.1",
"lodash": "^4.17.21",
"pg": "^8.7.1",
"webpack": "^4.42.0",

View File

@@ -32,6 +32,52 @@ const dialect = {
dropCheck: true,
dropReferencesWhenDropTable: true,
predefinedDataTypes: [
'bigint',
'bigserial',
'bit',
'varbit',
'boolean',
'box',
'bytea',
'char(20)',
'varchar(250)',
'cidr',
'circle',
'date',
'double precision',
'inet',
'int',
'interval',
'json',
'jsonb',
'line',
'lseg',
'macaddr',
'macaddr8',
'money',
'numeric(10,2)',
'path',
'pg_lsn',
'pg_snapshot',
'point',
'polygon',
'real',
'smallint',
'smallserial',
'serial',
'text',
'time',
'timetz',
'timestamp',
'timestamptz',
'tsquery',
'tsvector',
'txid_snapshot',
'uuid',
'xml',
],
};
const postgresDriverBase = {

View File

@@ -31,7 +31,7 @@
"devDependencies": {
"dbgate-plugin-tools": "^1.0.7",
"dbgate-query-splitter": "^4.9.0",
"dbgate-tools": "^4.1.1",
"dbgate-tools": "^5.0.0-alpha.1",
"lodash": "^4.17.21",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",

View File

@@ -82,6 +82,8 @@ const driver = {
}
return ['server', 'port', 'password', 'isReadOnly'].includes(field);
},
showConnectionTab: (field) => field == 'sshTunnel',
};
module.exports = driver;

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-plugin-sqlite",
"main": "dist/backend.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org",
"description": "SQLite connect plugin for DbGate",
"repository": {
@@ -30,7 +30,7 @@
"prepublishOnly": "yarn build"
},
"devDependencies": {
"dbgate-tools": "^4.1.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-plugin-tools": "^1.0.4",
"dbgate-query-splitter": "^4.9.0",
"byline": "^5.0.0",

View File

@@ -53,6 +53,8 @@ const driver = {
getQuerySplitterOptions: (usage) => (usage == 'stream' ? noSplitSplitterOptions : sqliteSplitterOptions),
// isFileDatabase: true,
isElectronOnly: true,
predefinedDataTypes: ['integer', 'real', 'text', 'blob'],
};
module.exports = driver;

265
yarn.lock
View File

@@ -1458,7 +1458,7 @@ abort-controller@^3.0.0:
dependencies:
event-target-shim "^5.0.0"
accepts@~1.3.4, accepts@~1.3.7:
accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
@@ -1550,11 +1550,6 @@ adler-32@~1.2.0:
exit-on-epipe "~1.0.1"
printj "~1.1.0"
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
agent-base@6:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
@@ -1788,11 +1783,6 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@@ -2005,21 +1995,11 @@ babel-preset-jest@^27.0.1:
babel-plugin-jest-hoist "^27.0.1"
babel-preset-current-node-syntax "^1.0.0"
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
base64-js@^1.0.2:
version "1.3.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
@@ -2030,11 +2010,6 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
base64id@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
base@^0.11.1:
version "0.11.2"
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
@@ -2062,21 +2037,13 @@ bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
dependencies:
tweetnacl "^0.14.3"
better-assert@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
dependencies:
callsite "1.0.0"
better-sqlite3@7.4.5:
version "7.4.5"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-7.4.5.tgz#acfc48d786114227f550a0a45e22ace51336e2d0"
integrity sha512-mybC3dgrtJeHkIRGP36tST7wjBlIMgTRAXhhO4bMpPZ17EG23FZxZeFcwKWy6o8mV1SKQFnQNyeAZlQpGrgheQ==
better-sqlite3@7.5.0:
version "7.5.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-7.5.0.tgz#2a91cb616453f002096743b0e5b66a7021cd1c63"
integrity sha512-6FdG9DoytYGDhLW7VWW1vxjEz7xHkqK6LnaUQYA8d6GHNgZhu9PFX2xwKEEnSBRoT1J4PjTUPeg217ShxNmuPg==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.0.0"
tar "^6.1.11"
big.js@^5.2.2:
version "5.2.2"
@@ -2124,11 +2091,6 @@ bl@^4.0.3:
inherits "^2.0.4"
readable-stream "^3.4.0"
blob@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
bluebird@^3.5.5:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@@ -2463,11 +2425,6 @@ call-me-maybe@^1.0.1:
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@@ -2836,26 +2793,11 @@ compare-versions@^3.6.0:
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62"
integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==
component-bind@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=
component-emitter@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
component-emitter@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
component-inherit@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -2942,11 +2884,6 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
@@ -3217,10 +3154,10 @@ dbgate-plugin-tools@^1.0.4, dbgate-plugin-tools@^1.0.7:
pacote "^11.1.13"
rimraf "^3.0.2"
dbgate-plugin-xml@^4.1.1:
version "4.7.2"
resolved "https://registry.yarnpkg.com/dbgate-plugin-xml/-/dbgate-plugin-xml-4.7.2.tgz#4a1817a7fc3b1ac5191e45dc7b1016b2f97c3158"
integrity sha512-LA52/Wg+blaRp/H+v4ypT+l6kbi4sYsTD/JdPaTbfwErMXhGZew9wtDolvbDjKZZ/zfRig0TDXj9fhLILw2cGw==
dbgate-plugin-xml@^5.0.0-alpha.1:
version "5.0.0-alpha.1"
resolved "https://registry.yarnpkg.com/dbgate-plugin-xml/-/dbgate-plugin-xml-5.0.0-alpha.1.tgz#5011c808265d56c822c5e4b143208a26cd1c2acc"
integrity sha512-jiqS0cUdKJJlYRMdl0vexDVRGr8Jt4nRjm1ZFWgt5evGWFqTD5SpgUtP2Vx/HsrehXK2Xs9JC9EN3I7B3fesLg==
dbgate-query-splitter@^4.9.0:
version "4.9.0"
@@ -3248,7 +3185,7 @@ debug@^3.1.1, debug@^3.2.6:
dependencies:
ms "^2.1.1"
debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
@@ -3262,13 +3199,6 @@ debug@^4.3.1:
dependencies:
ms "2.1.2"
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
decamelize-keys@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
@@ -3625,46 +3555,6 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
dependencies:
once "^1.4.0"
engine.io-client@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700"
integrity sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==
dependencies:
component-emitter "1.2.1"
component-inherit "0.0.3"
debug "~4.1.0"
engine.io-parser "~2.2.0"
has-cors "1.1.0"
indexof "0.0.1"
parseqs "0.0.5"
parseuri "0.0.5"
ws "~6.1.0"
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2"
engine.io-parser@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==
dependencies:
after "0.8.2"
arraybuffer.slice "~0.0.7"
base64-arraybuffer "0.1.5"
blob "0.0.5"
has-binary2 "~1.0.2"
engine.io@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
integrity sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==
dependencies:
accepts "~1.3.4"
base64id "2.0.0"
cookie "0.3.1"
debug "~4.1.0"
engine.io-parser "~2.2.0"
ws "^7.1.2"
enhanced-resolve@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
@@ -4829,18 +4719,6 @@ has-bigints@^1.0.1:
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
has-binary2@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==
dependencies:
isarray "2.0.1"
has-cors@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -5158,11 +5036,6 @@ indent-string@^4.0.0:
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
indexof@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
infer-owner@^1.0.3, infer-owner@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
@@ -5625,11 +5498,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isarray@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -7884,11 +7752,6 @@ object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-component@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@@ -8217,20 +8080,6 @@ parse5@6.0.1:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
dependencies:
better-assert "~1.0.0"
parseuri@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
dependencies:
better-assert "~1.0.0"
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@@ -9661,61 +9510,6 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
socket.io-adapter@~1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
socket.io-client@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==
dependencies:
backo2 "1.0.2"
base64-arraybuffer "0.1.5"
component-bind "1.0.0"
component-emitter "1.2.1"
debug "~4.1.0"
engine.io-client "~3.4.0"
has-binary2 "~1.0.2"
has-cors "1.1.0"
indexof "0.0.1"
object-component "0.0.3"
parseqs "0.0.5"
parseuri "0.0.5"
socket.io-parser "~3.3.0"
to-array "0.1.4"
socket.io-parser@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
dependencies:
component-emitter "1.2.1"
debug "~3.1.0"
isarray "2.0.1"
socket.io-parser@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a"
integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==
dependencies:
component-emitter "1.2.1"
debug "~4.1.0"
isarray "2.0.1"
socket.io@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==
dependencies:
debug "~4.1.0"
engine.io "~3.4.0"
has-binary2 "~1.0.2"
socket.io-adapter "~1.1.0"
socket.io-client "2.3.0"
socket.io-parser "~3.4.0"
socks-proxy-agent@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60"
@@ -10349,18 +10143,6 @@ tar@^6.0.5:
mkdirp "^1.0.3"
yallist "^4.0.0"
tar@^6.1.11:
version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
dependencies:
chownr "^2.0.0"
fs-minipass "^2.0.0"
minipass "^3.0.0"
minizlib "^2.1.1"
mkdirp "^1.0.3"
yallist "^4.0.0"
task-graph-runner@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/task-graph-runner/-/task-graph-runner-1.0.3.tgz#73b2cd380cef6f51b8179b0d1da4bb7c356b03bf"
@@ -10525,11 +10307,6 @@ tmpl@1.0.x:
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
to-array@0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA=
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
@@ -11316,23 +11093,11 @@ ws@^6.2.1:
dependencies:
async-limiter "~1.0.0"
ws@^7.1.2:
version "7.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
ws@^7.4.5:
version "7.4.6"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
ws@~6.1.0:
version "6.1.4"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
dependencies:
async-limiter "~1.0.0"
xdg-basedir@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
@@ -11382,11 +11147,6 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.5.0.tgz#193cb96b84aa3486127ea6272c4596354cb4962e"
integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
xpath.js@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1"
@@ -11524,8 +11284,3 @@ yargs@^16.0.3:
string-width "^4.2.0"
y18n "^5.0.5"
yargs-parser "^20.2.2"
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=