1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-06-05 21:59:22 +02:00

Compare commits

...

21 Commits

Author SHA1 Message Date
51ccce3da4 chore(release): 0.0.6 2020-09-03 13:46:16 +02:00
a1a6f51f2f fix: error when launching queries without a result from query tabs 2020-09-03 13:44:58 +02:00
801a0de186 fix: field name displayed instead of alias 2020-09-02 18:14:30 +02:00
264de9c568 feat: aliases support 2020-09-01 19:23:13 +02:00
8390f8aa55 Merge pull request #31 from EStarium/dependabot/npm_and_yarn/electron-10.1.0
build(deps-dev): bump electron from 9.2.1 to 10.1.0
2020-08-31 17:39:49 +02:00
af7c0e90b8 Merge pull request #30 from EStarium/dependabot/npm_and_yarn/sass-loader-10.0.1
build(deps-dev): bump sass-loader from 9.0.3 to 10.0.1
2020-08-31 14:02:57 +02:00
dependabot[bot]
da33e77361 build(deps-dev): bump electron from 9.2.1 to 10.1.0
Bumps [electron](https://github.com/electron/electron) from 9.2.1 to 10.1.0.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/master/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v9.2.1...v10.1.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-08-31 06:47:39 +00:00
dependabot[bot]
a4841ab63b build(deps-dev): bump sass-loader from 9.0.3 to 10.0.1
Bumps [sass-loader](https://github.com/webpack-contrib/sass-loader) from 9.0.3 to 10.0.1.
- [Release notes](https://github.com/webpack-contrib/sass-loader/releases)
- [Changelog](https://github.com/webpack-contrib/sass-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/sass-loader/compare/v9.0.3...v10.0.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-08-31 06:44:49 +00:00
de3f36a3fe docs: update README.md 2020-08-21 15:56:29 +02:00
8dc74ef2c3 feat: sql suggestions in query editor 2020-08-21 11:38:00 +02:00
256ec76588 feat: middle click to close tabs 2020-08-21 10:57:26 +02:00
196a3e0185 feat: monaco-editor as query editor 2020-08-20 18:06:02 +02:00
bc54fef0aa docs: Update README.md 2020-08-20 15:31:50 +02:00
a5b478e53d Merge pull request #29 from Mohd-PH/master
Add Arabic translation
2020-08-20 15:24:03 +02:00
Mohd-PH
2e235ad2fe Change the name of Arabic in the settings page 2020-08-20 16:21:11 +03:00
Mohd-PH
950bb17b1e Add Arabic translation 2020-08-20 12:37:26 +03:00
3a6ea76b93 feat: tabs horizontal scroll with mouse wheel 2020-08-20 10:38:18 +02:00
d7ed00f4a3 feat: support to multiple query tabs 2020-08-19 18:20:57 +02:00
fd6d5177ef fix: wrong table height calc in some cases 2020-08-19 16:25:42 +02:00
9599b43f78 refactor: changed event names to kebab-case 2020-08-18 18:03:59 +02:00
2cfb223ff6 chore: Improved changelog 2020-08-17 17:48:21 +02:00
42 changed files with 6580 additions and 226 deletions

View File

@@ -2,31 +2,47 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.0.5](https://github.com/EStarium/antares/compare/v0.0.4...v0.0.5) (2020-08-17)
### [0.0.6](https://github.com/EStarium/antares/compare/v0.0.5...v0.0.6) (2020-09-03)
### Features
* badge on setting icon and update tab when update is available ([e8141b6](https://github.com/EStarium/antares/commit/e8141b632154f765ca73fa50b9b7120dc592ead0))
* foreign key support in add/edit row ([0b6a188](https://github.com/EStarium/antares/commit/0b6a188d1959b80b4a66946cc79d2dd3853a428b))
* option to insert table rows ([2f1dfdc](https://github.com/EStarium/antares/commit/2f1dfdc6543b4a6c1d595f0daa00c0832be49c77))
* aliases support ([264de9c](https://github.com/EStarium/antares/commit/264de9c5686fb3a2ef22d96171f45b915ba1b34b))
* middle click to close tabs ([256ec76](https://github.com/EStarium/antares/commit/256ec765883fcf247355190827e943c76e95f13b))
* monaco-editor as query editor ([196a3e0](https://github.com/EStarium/antares/commit/196a3e0185a3d68b7c4ade8dbf187d2b216cc00b))
* sql suggestions in query editor ([8dc74ef](https://github.com/EStarium/antares/commit/8dc74ef2c335e8ae4a69f5d2651df65939139b1b))
* support to multiple query tabs ([d7ed00f](https://github.com/EStarium/antares/commit/d7ed00f4a3613da9015c9fc48c4d8062d292e416))
* tabs horizontal scroll with mouse wheel ([3a6ea76](https://github.com/EStarium/antares/commit/3a6ea76b93682ebd50908df7368c62c2c1e27958))
### Bug Fixes
* insert files via add row option ([3c6e818](https://github.com/EStarium/antares/commit/3c6e818ba06f1b8b5db0ecf80c3b7498d6d2a841))
* newline replaced with undefined inside queries ([59e4a79](https://github.com/EStarium/antares/commit/59e4a79f42076b3fce98a764e9ad6a01c674555b))
* query result table header didn't show just selected fields ([7bc1009](https://github.com/EStarium/antares/commit/7bc10092fe4823e03133e69e0a7bf86e44fde43b))
* table header not fixed on top when fast scrolling ([13b0816](https://github.com/EStarium/antares/commit/13b0816837461119eaab79fdb7e92223e0950630))
* time and datetime precision ([771f8a2](https://github.com/EStarium/antares/commit/771f8a2d682c64105231e3fef199f05150596298))
* update a row with a string key value ([eb348b3](https://github.com/EStarium/antares/commit/eb348b3095b6905321b62eed6cea228374ebc3d1))
* window title not perfectly centered ([7651d05](https://github.com/EStarium/antares/commit/7651d05b37970574d6ae4bdf75c20c69d59c1e6d))
* wrong schema passed in query tab when selected a different database ([6d0724d](https://github.com/EStarium/antares/commit/6d0724dc90cdebb10e0342d2c472bdd07aa345f8))
### [0.0.4](https://github.com/EStarium/antares/compare/v0.0.3-alpha...v0.0.4) (2020-08-06)
* error when launching queries without a result from query tabs ([a1a6f51](https://github.com/EStarium/antares/commit/a1a6f51f2fba5140f5e3bd9cd6557c8a13dfaa2c))
* field name displayed instead of alias ([801a0de](https://github.com/EStarium/antares/commit/801a0de1865dea2a59ff057b7c2cc988cc9c87ed))
* wrong table height calc in some cases ([fd6d517](https://github.com/EStarium/antares/commit/fd6d5177efb6161aab01f9e108eda60df6c7d8c4))
### [0.0.5](https://github.com/EStarium/antares/compare/v0.0.4...v0.0.5) (2020-08-17)
### Features
* blob fields edit/view/download ([712fe9f](https://github.com/EStarium/antares/commit/712fe9f00d210db0f2317eca61e7fb648383e3fe))
* window title in app title bar ([0089c0c](https://github.com/EStarium/antares/commit/0089c0cbac6caf0a6fd195849099f18713580228))
* Badge on setting icon and update tab when update is available ([e8141b6](https://github.com/EStarium/antares/commit/e8141b632154f765ca73fa50b9b7120dc592ead0))
* Foreign key support in add/edit row ([0b6a188](https://github.com/EStarium/antares/commit/0b6a188d1959b80b4a66946cc79d2dd3853a428b))
* Option to insert table rows ([2f1dfdc](https://github.com/EStarium/antares/commit/2f1dfdc6543b4a6c1d595f0daa00c0832be49c77))
### Bug Fixes
* Insert files via add row option ([3c6e818](https://github.com/EStarium/antares/commit/3c6e818ba06f1b8b5db0ecf80c3b7498d6d2a841))
* Newline replaced with undefined inside queries ([59e4a79](https://github.com/EStarium/antares/commit/59e4a79f42076b3fce98a764e9ad6a01c674555b))
* Query result header didn't show just selected fields ([7bc1009](https://github.com/EStarium/antares/commit/7bc10092fe4823e03133e69e0a7bf86e44fde43b))
* Table header not fixed on top when fast scrolling ([13b0816](https://github.com/EStarium/antares/commit/13b0816837461119eaab79fdb7e92223e0950630))
* Time and datetime precision ([771f8a2](https://github.com/EStarium/antares/commit/771f8a2d682c64105231e3fef199f05150596298))
* Update a row with a string key value ([eb348b3](https://github.com/EStarium/antares/commit/eb348b3095b6905321b62eed6cea228374ebc3d1))
* Window title not perfectly centered ([7651d05](https://github.com/EStarium/antares/commit/7651d05b37970574d6ae4bdf75c20c69d59c1e6d))
* Wrong schema passed in query tab when a different database was selected ([6d0724d](https://github.com/EStarium/antares/commit/6d0724dc90cdebb10e0342d2c472bdd07aa345f8))
### [0.0.4](https://github.com/EStarium/antares/compare/v0.0.3-alpha...v0.0.4) (2020-08-06)
### Features
* Blob fields edit/view/download ([712fe9f](https://github.com/EStarium/antares/commit/712fe9f00d210db0f2317eca61e7fb648383e3fe))
* Window title in app title bar ([0089c0c](https://github.com/EStarium/antares/commit/0089c0cbac6caf0a6fd195849099f18713580228))

View File

@@ -9,13 +9,15 @@
Antares is an SQL client based on [Electron.js](https://github.com/electron/electron) and [Vue.js](https://github.com/vuejs/vue) that aims to become a useful tool, especially for developers.
My target is to support as many databases as possible, and all major operating systems, including the ARM versions.
**At the moment this application is in a development state, it lacks many features, and is''t ready as a main SQL client**. However i'm actively working on it, hoping to provide all essential features as soon as possible.
**At the moment this application is an alpha, it lacks many features, and isn't ready as a main SQL client**. However i'm actively working on it, hoping to provide all essential features as soon as possible.
If you are curious to try this early state of Antares you can download and install the [latest release](https://github.com/EStarium/antares/releases), and stay tuned for updates. At moment i'm testing only on Windows.
If you are curious to try this early state of Antares you can download and install the [latest release](https://github.com/EStarium/antares/releases), and stay tuned for updates.
<!--## Philosophy
## Philosophy
Why am I developing an SQL client when there are a lot of thom on the market?-->
Why am I developing an SQL client when there are a lot of them on the market?
The main goal is to develop a totally free, cross platform and open source alternative, empowered by JavaScript's ecosystem.
An application created with minimalism and semplicity in mind, with features in the righ places, not hundreds of tiny buttons or submenu.
## How to contribute
@@ -51,10 +53,19 @@ This is a roadmap with major features will come in near future.
### Operating Systems
#### • x86
- [x] Windows
- [x] Linux
- [x] MacOS (needs tests)
#### • ARM
- [ ] Windows
- [ ] Linux
- [ ] MacOS
## Translations
[Giuseppe Gigliotti](https://github.com/ReverbOD) / [Italian Translation](https://github.com/EStarium/antares/pull/20)
[Giuseppe Gigliotti](https://github.com/ReverbOD) / [Italian Translation](https://github.com/EStarium/antares/pull/20)
[Mohd-PH](https://github.com/Mohd-PH) / [Arabic Translation](https://github.com/EStarium/antares/pull/29)

View File

@@ -1,7 +1,7 @@
{
"name": "antares",
"productName": "Antares",
"version": "0.0.5",
"version": "0.0.6",
"description": "A cross-platform easy to use SQL client.",
"license": "MIT",
"repository": "https://github.com/EStarium/antares.git",
@@ -40,27 +40,24 @@
}
},
"electronWebpack": {
"whiteListedModules": [
"codemirror"
],
"renderer": {
"webpackConfig": "webpack.config.js"
}
},
"dependencies": {
"@mdi/font": "^5.5.55",
"codemirror": "^5.56.0",
"electron-log": "^4.2.2",
"electron-log": "^4.2.4",
"electron-updater": "^4.3.4",
"lodash": "^4.17.19",
"lodash": "^4.17.20",
"moment": "^2.27.0",
"monaco-editor": "^0.20.0",
"mssql": "^6.2.1",
"mysql": "^2.18.1",
"pg": "^8.3.0",
"pg": "^8.3.2",
"source-map-support": "^0.5.16",
"spectre.css": "^0.5.9",
"vue-click-outside": "^1.1.0",
"vue-i18n": "^8.20.0",
"vue-i18n": "^8.21.0",
"vue-the-mask": "^0.11.1",
"vuedraggable": "^2.24.0",
"vuex": "^3.5.1",
@@ -69,20 +66,21 @@
"devDependencies": {
"babel-eslint": "^10.1.0",
"cross-env": "^7.0.2",
"electron": "^9.1.2",
"electron": "^10.1.0",
"electron-builder": "^22.8.0",
"electron-devtools-installer": "^3.1.1",
"electron-webpack": "^2.8.2",
"electron-webpack-vue": "^2.4.0",
"eslint": "^7.6.0",
"eslint": "^7.7.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.2.2",
"monaco-editor-webpack-plugin": "^1.9.0",
"node-sass": "^4.14.1",
"sass-loader": "^9.0.3",
"sass-loader": "^10.0.1",
"standard-version": "^9.0.0",
"stylelint": "^13.6.1",
"stylelint-config-standard": "^20.0.0",

View File

@@ -1,7 +1,7 @@
import { app, ipcMain } from 'electron';
export default () => {
ipcMain.on('closeApp', () => {
ipcMain.on('close-app', () => {
app.exit();
});
};

View File

@@ -4,8 +4,8 @@ import { AntaresConnector } from '../libs/AntaresConnector';
import InformationSchema from '../models/InformationSchema';
import Generic from '../models/Generic';
export default (connections) => {
ipcMain.handle('testConnection', async (event, conn) => {
export default connections => {
ipcMain.handle('test-connection', async (event, conn) => {
const Connection = new AntaresConnector({
client: conn.client,
params: {
@@ -28,7 +28,7 @@ export default (connections) => {
}
});
ipcMain.handle('checkConnection', async (event, uid) => {
ipcMain.handle('check-connection', async (event, uid) => {
return uid in connections;
});
@@ -71,7 +71,7 @@ export default (connections) => {
}
});
ipcMain.handle('rawQuery', async (event, { uid, query, schema }) => {
ipcMain.handle('raw-query', async (event, { uid, query, schema }) => {
if (!query) return;
try {
const result = await Generic.raw(connections[uid], query, schema);

View File

@@ -5,7 +5,7 @@ import Tables from '../models/Tables';
// TODO: remap objects based on client
export default (connections) => {
ipcMain.handle('getTableColumns', async (event, { uid, schema, table }) => {
ipcMain.handle('get-table-columns', async (event, { uid, schema, table }) => {
try {
const result = await InformationSchema.getTableColumns(connections[uid], schema, table);// TODO: uniform column properties
return { status: 'success', response: result };
@@ -15,7 +15,7 @@ export default (connections) => {
}
});
ipcMain.handle('getTableData', async (event, { uid, schema, table }) => {
ipcMain.handle('get-table-data', async (event, { uid, schema, table }) => {
try {
const result = await Tables.getTableData(connections[uid], schema, table);
return { status: 'success', response: result };
@@ -35,7 +35,7 @@ export default (connections) => {
}
});
ipcMain.handle('updateTableCell', async (event, params) => {
ipcMain.handle('update-table-cell', async (event, params) => {
try {
const result = await Tables.updateTableCell(connections[params.uid], params);
return { status: 'success', response: result };
@@ -45,7 +45,7 @@ export default (connections) => {
}
});
ipcMain.handle('deleteTableRows', async (event, params) => {
ipcMain.handle('delete-table-rows', async (event, params) => {
try {
const result = await Tables.deleteTableRows(connections[params.uid], params);
return { status: 'success', response: result };
@@ -55,7 +55,7 @@ export default (connections) => {
}
});
ipcMain.handle('insertTableRows', async (event, params) => {
ipcMain.handle('insert-table-rows', async (event, params) => {
try {
await Tables.insertTableRows(connections[params.uid], params);
return { status: 'success' };

View File

@@ -2,39 +2,40 @@ import { ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
let mainWindow;
autoUpdater.allowPrerelease = true;
export default () => {
ipcMain.on('checkForUpdates', event => {
ipcMain.on('check-for-updates', event => {
mainWindow = event;
autoUpdater.checkForUpdatesAndNotify().catch(() => {
mainWindow.reply('checkFailed');
mainWindow.reply('check-failed');
});
});
ipcMain.on('restartToUpdate', () => {
ipcMain.on('restart-to-update', () => {
autoUpdater.quitAndInstall();
});
// auto-updater events
autoUpdater.on('checking-for-update', () => {
mainWindow.reply('checkingForUpdate');
mainWindow.reply('checking-for-update');
});
autoUpdater.on('update-available', () => {
mainWindow.reply('updateAvailable');
mainWindow.reply('update-available');
});
autoUpdater.on('update-not-available', () => {
mainWindow.reply('updateNotAvailable');
mainWindow.reply('update-not-available');
});
autoUpdater.on('download-progress', (data) => {
mainWindow.reply('downloadProgress', data);
autoUpdater.on('download-progress', data => {
mainWindow.reply('download-progress', data);
});
autoUpdater.on('update-downloaded', () => {
mainWindow.reply('updateDownloaded');
mainWindow.reply('update-downloaded');
});
autoUpdater.logger = require('electron-log');

View File

@@ -285,15 +285,20 @@ export class AntaresConnector {
switch (this._client) { // TODO: uniform fields with every client type, needed table name and fields array
case 'maria':
case 'mysql': {
const { rows, fields } = await new Promise((resolve, reject) => {
this._connection.query(sql, (err, rows, fields) => {
const { rows, report, fields } = await new Promise((resolve, reject) => {
this._connection.query(sql, (err, response, fields) => {
if (err)
reject(err);
else
resolve({ rows, fields });
else {
resolve({
rows: Array.isArray(response) ? response : false,
report: !Array.isArray(response) ? response : false,
fields
});
}
});
});
return { rows, fields };
return { rows, report, fields };
}
case 'mssql': {
const results = await this._connection.request().query(sql);

View File

@@ -4,7 +4,7 @@
<div id="window-content">
<TheSettingBar />
<div id="main-content" class="container">
<TheAppWelcome v-if="!connections.length" @newConn="showNewConnModal" />
<TheAppWelcome v-if="!connections.length" @new-conn="showNewConnModal" />
<div v-else class="columns col-gapless">
<Workspace
v-for="connection in connections"
@@ -52,7 +52,7 @@ export default {
})
},
mounted () {
ipcRenderer.send('checkForUpdates');
ipcRenderer.send('check-for-updates');
},
methods: {
...mapActions({

View File

@@ -46,8 +46,8 @@ export default {
justify-content: center;
align-items: center;
overflow: hidden;
padding: 0.4rem;
position: fixed;
height: 100vh;
right: 0;
top: 0;
left: 0;

View File

@@ -65,7 +65,7 @@ export default {
},
methods: {
closeModal () {
this.$emit('closeAsking');
this.$emit('close-asking');
},
sendCredentials () {
this.$emit('credentials', this.credentials);

View File

@@ -137,7 +137,7 @@
</div>
<ModalAskCredentials
v-if="isAsking"
@closeAsking="closeAsking"
@close-asking="closeAsking"
@credentials="continueTest"
/>
</div>

View File

@@ -141,7 +141,7 @@
</div>
<ModalAskCredentials
v-if="isAsking"
@closeAsking="closeAsking"
@close-asking="closeAsking"
@credentials="continueTest"
/>
</div>

View File

@@ -68,10 +68,10 @@ export default {
},
methods: {
checkForUpdates () {
ipcRenderer.send('checkForUpdates');
ipcRenderer.send('check-for-updates');
},
restartToUpdate () {
ipcRenderer.send('restartToUpdate');
ipcRenderer.send('restart-to-update');
}
}
};

View File

@@ -1,25 +1,15 @@
<template>
<div class="editor-wrapper">
<textarea
ref="codemirror"
:options="cmOptions"
/>
<div ref="editor" class="editor" />
</div>
</template>
<script>
import CodeMirror from 'codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/theme/material-darker.css';
import 'codemirror/mode/sql/sql';
import 'codemirror/addon/edit/closebrackets';
import 'codemirror/addon/selection/active-line';
import 'codemirror/addon/hint/show-hint';
import 'codemirror/addon/hint/show-hint.css';
import 'codemirror/addon/hint/sql-hint';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { completionItemProvider } from '@/suggestions/sql';
CodeMirror.defineOption('sql-hint');
monaco.languages.registerCompletionItemProvider('sql', completionItemProvider(monaco));
export default {
name: 'QueryEditor',
@@ -28,42 +18,31 @@ export default {
},
data () {
return {
cminstance: null,
content: '',
cmOptions: {
tabSize: 3,
smartIndent: true,
styleActiveLine: true,
lineNumbers: true,
line: true,
mode: 'text/x-sql',
theme: 'material-darker',
extraKeys: {
'Ctrl-Space': 'autocomplete'
},
hintOptions: {
tables: {
users: ['name', 'score', 'birthDate'],
countries: ['name', 'population', 'size']
}
},
autoCloseBrackets: true
}
editor: null
};
},
mounted () {
this.initialize();
},
methods: {
initialize () {
this.cminstance = CodeMirror.fromTextArea(this.$refs.codemirror, this.cmOptions);
this.cminstance.setValue(this.value || this.content);
this.editor = monaco.editor.create(this.$refs.editor, {
value: this.value,
language: 'sql',
theme: 'vs-dark',
autoIndent: true,
minimap: {
enabled: false
},
contextmenu: false,
wordBasedSuggestions: true,
acceptSuggestionOnEnter: 'smart',
quickSuggestions: true
});
this.cminstance.on('change', cm => {
this.content = cm.getValue();
this.$emit('input', this.content);
});
}
this.editor.onDidChangeModelContent(e => {
const content = this.editor.getValue();
this.$emit('update:value', content);
});
},
beforeDestroy () {
this.editor && this.editor.dispose();
}
};
</script>
@@ -71,11 +50,14 @@ export default {
<style lang="scss">
.editor-wrapper {
border-bottom: 1px solid #444;
.editor {
height: 200px;
width: 100%;
}
}
.CodeMirror {
height: 200px;
.CodeMirror-scroll {
max-width: 100%;
}

View File

@@ -11,7 +11,7 @@
{{ $t('message.appFirstStep') }}
</p>
<div class="empty-action">
<button class="btn btn-primary" @click="$emit('newConn')">
<button class="btn btn-primary" @click="$emit('new-conn')">
{{ $t('message.createConnection') }}
</button>
</div>

View File

@@ -11,7 +11,7 @@
<div class="footer-right-elements">
<ul class="footer-elements">
<li class="footer-element footer-link" @click="openOutside('https://www.patreon.com/fabio286')">
<li class="footer-element footer-link" @click="openOutside('https://github.com/sponsors/Fabio286')">
<i class="mdi mdi-18px mdi-coffee mr-1" />
<small>{{ $t('word.donate') }}</small>
</li>

View File

@@ -201,6 +201,7 @@ export default {
max-width: 320px;
pointer-events: none;
text-overflow: ellipsis;
overflow: hidden;
transition: opacity 0.2s;
}

View File

@@ -73,7 +73,7 @@ export default {
},
methods: {
closeApp () {
ipcRenderer.send('closeApp');
ipcRenderer.send('close-app');
},
minimizeApp () {
this.w.minimize();

View File

@@ -2,21 +2,23 @@
<div v-show="isSelected" class="workspace column columns col-gapless">
<WorkspaceExploreBar :connection="connection" :is-selected="isSelected" />
<div v-if="workspace.connected" class="workspace-tabs column columns col-gapless">
<ul class="tab tab-block column col-12">
<!-- <li
<ul ref="tabWrap" class="tab tab-block column col-12">
<li
v-if="workspace.breadcrumbs.table"
class="tab-item"
:class="{'active': selectedTab === 'prop'}"
@click="selectTab({uid: workspace.uid, tab: 'prop'})"
>
<a class="tab-link">
<i class="mdi mdi-18px mdi-tune mr-1" />
<span :title="workspace.breadcrumbs.table">{{ $t('word.properties').toUpperCase() }}: {{ workspace.breadcrumbs.table }}</span>
</a>
</li> -->
</li>
<li
v-if="workspace.breadcrumbs.table"
class="tab-item"
:class="{'active': selectedTab === 1}"
@click="selectTab({uid: workspace.uid, tab: 1})"
:class="{'active': selectedTab === 'data'}"
@click="selectTab({uid: workspace.uid, tab: 'data'})"
>
<a class="tab-link">
<i class="mdi mdi-18px mdi-table mr-1" />
@@ -24,25 +26,45 @@
</a>
</li>
<li
v-for="(tab, key) of queryTabs"
v-for="tab of queryTabs"
:key="tab.uid"
class="tab-item"
:class="{'active': selectedTab === tab.uid}"
@click="selectTab({uid: workspace.uid, tab: tab.uid})"
@mousedown.middle="closeTab(tab.uid)"
>
<a><span>Query #{{ key+1 }} <span v-if="queryTabs.length > 1" class="btn btn-clear" /></span></a>
<a>
<span>
Query #{{ tab.index }}
<span
v-if="queryTabs.length > 1"
class="btn btn-clear"
:title="$t('word.close')"
@click.stop="closeTab(tab.uid)"
/>
</span>
</a>
</li>
<li class="tab-item">
<a
class="tab-add"
:title="$t('message.openNewTab')"
@click="addTab"
>
<i class="mdi mdi-24px mdi-plus" />
</a>
</li>
</ul>
<WorkspaceTableTab
v-show="selectedTab === 1"
v-show="selectedTab === 'data'"
:connection="connection"
:table="workspace.breadcrumbs.table"
/>
<WorkspaceQueryTab
v-for="tab of queryTabs"
v-show="selectedTab === tab.uid"
:key="tab.uid"
:tab-uid="tab.uid"
:is-selected="selectedTab === tab.uid"
:connection="connection"
/>
</div>
@@ -78,7 +100,7 @@ export default {
return this.selectedWorkspace === this.connection.uid;
},
selectedTab () {
return this.workspace.selected_tab || this.queryTabs[0].uid;
return this.queryTabs.find(tab => tab.uid === this.workspace.selected_tab) || ['data', 'prop'].includes(this.workspace.selected_tab) ? this.workspace.selected_tab : this.queryTabs[0].uid;
},
queryTabs () {
return this.workspace.tabs.filter(tab => tab.type === 'query');
@@ -90,13 +112,30 @@ export default {
if (isInitiated)
this.connectWorkspace(this.connection);
},
mounted () {
if (this.$refs.tabWrap) {
this.$refs.tabWrap.addEventListener('wheel', e => {
if (e.deltaY > 0) this.$refs.tabWrap.scrollLeft += 50;
else this.$refs.tabWrap.scrollLeft -= 50;
});
}
},
methods: {
...mapActions({
addWorkspace: 'workspaces/addWorkspace',
connectWorkspace: 'workspaces/connectWorkspace',
removeConnected: 'workspaces/removeConnected',
selectTab: 'workspaces/selectTab'
})
selectTab: 'workspaces/selectTab',
newTab: 'workspaces/newTab',
removeTab: 'workspaces/removeTab'
}),
addTab () {
this.newTab(this.connection.uid);
},
closeTab (tUid) {
if (this.queryTabs.length === 1) return;
this.removeTab({ uid: this.connection.uid, tab: tUid });
}
}
};
</script>
@@ -107,12 +146,21 @@ export default {
margin: 0;
.workspace-tabs {
overflow: auto;
overflow: hidden;
height: calc(100vh - #{$excluding-size});
.tab-block {
background: $bg-color-light;
margin-top: 0;
flex-direction: row;
align-items: flex-start;
flex-wrap: nowrap;
overflow: auto;
&::-webkit-scrollbar {
width: 2px;
height: 2px;
}
.tab-item {
max-width: 12rem;
@@ -132,10 +180,17 @@ export default {
opacity: 1;
}
&.tab-add {
padding: 0.2rem 0.4rem;
margin-top: 2px;
border: 0;
}
> span {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding: 0 0.2rem;
}
}

View File

@@ -19,7 +19,7 @@
</div>
<ModalAskCredentials
v-if="isAsking"
@closeAsking="closeAsking"
@close-asking="closeAsking"
@credentials="continueTest"
/>
</div>

View File

@@ -1,7 +1,7 @@
<template>
<div class="workspace-query-tab column col-12 columns col-gapless">
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
<div class="workspace-query-runner column col-12">
<QueryEditor v-model="query" />
<QueryEditor v-if="isSelected" :value.sync="query" />
<div class="workspace-query-runner-footer">
<div class="workspace-query-buttons">
<button
@@ -18,6 +18,9 @@
<div v-if="results.rows">
{{ $t('word.results') }}: <b>{{ results.rows.length }}</b>
</div>
<div v-if="results.report">
{{ $t('message.affectedRows') }}: <b>{{ results.report.affectedRows }}</b>
</div>
<div v-if="workspace.breadcrumbs.schema">
{{ $t('word.schema') }}: <b>{{ workspace.breadcrumbs.schema }}</b>
</div>
@@ -31,8 +34,8 @@
ref="queryTable"
:results="results"
:tab-uid="tabUid"
@updateField="updateField"
@deleteSelected="deleteSelected"
@update-field="updateField"
@delete-selected="deleteSelected"
/>
</div>
</div>
@@ -55,7 +58,8 @@ export default {
mixins: [tableTabs],
props: {
connection: Object,
tabUid: String
tabUid: String,
isSelected: Boolean
},
data () {
return {
@@ -93,8 +97,7 @@ export default {
async runQuery (query) {
if (!query) return;
this.isQuering = true;
this.results = {};
this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields: [] });
this.clearTabData();
try { // Query Data
const params = {
@@ -106,7 +109,54 @@ export default {
const { status, response } = await Connection.rawQuery(params);
if (status === 'success') {
this.results = response;
this.selectedFields = response.fields.map(field => field.orgName);
if (response.rows) { // if is a select
this.selectedFields = response.fields.map(field => field.orgName);
try { // Table data
const params = {
uid: this.connection.uid,
schema: this.schema,
table: this.table
};
const { status, response } = await Tables.getTableColumns(params);
if (status === 'success') {
let fields = response.filter(field => this.selectedFields.includes(field.name));
if (this.selectedFields.length) {
fields = fields.map((field, index) => {
return { ...field, alias: this.results.fields[index].name };
});
}
this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields });
}
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
try { // Key usage (foreign keys)
const params = {
uid: this.connection.uid,
schema: this.schema,
table: this.table
};
const { status, response } = await Tables.getKeyUsage(params);
if (status === 'success')
this.setTabKeyUsage({ cUid: this.connection.uid, tUid: this.tabUid, keyUsage: response });
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
}
else { // if is a query without results
}
}
else
this.addNotification({ status: 'error', message: response });
@@ -115,47 +165,15 @@ export default {
this.addNotification({ status: 'error', message: err.stack });
}
try { // Table data
const params = {
uid: this.connection.uid,
schema: this.schema,
table: this.table
};
const { status, response } = await Tables.getTableColumns(params);
if (status === 'success') {
const fields = response.filter(field => this.selectedFields.includes(field.name));
this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields });
}
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
try { // Key usage (foreign keys)
const params = {
uid: this.connection.uid,
schema: this.schema,
table: this.table
};
const { status, response } = await Tables.getKeyUsage(params);
if (status === 'success')
this.setTabKeyUsage({ cUid: this.connection.uid, tUid: this.tabUid, keyUsage: response });
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
this.isQuering = false;
this.lastQuery = query;
},
reloadTable () {
this.runQuery(this.lastQuery);
},
clearTabData () {
this.results = {};
this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields: [] });
}
}
};

View File

@@ -8,7 +8,7 @@
v-if="isContext"
:context-event="contextEvent"
:selected-rows="selectedRows"
@deleteSelected="deleteSelected"
@delete-selected="deleteSelected"
@close-context="isContext = false"
/>
<div ref="table" class="table table-hover">
@@ -27,7 +27,7 @@
:class="`key-${field.key}`"
:title="keyName(field.key)"
/>
<span>{{ field.name }}</span>
<span>{{ field.alias || field.name }}</span>
<i
v-if="currentSort === field.name"
class="mdi sort-icon"
@@ -56,8 +56,8 @@
:key-usage="keyUsage"
class="tr"
:class="{'selected': selectedRows.includes(row._id)}"
@selectRow="selectRow($event, row._id)"
@updateField="updateField($event, row[primaryField.name])"
@select-row="selectRow($event, row._id)"
@update-field="updateField($event, row[primaryField.alias || primaryField.name])"
@contextmenu="contextMenu"
/>
</template>
@@ -180,7 +180,7 @@ export default {
},
resizeResults () {
if (this.$refs.resultTable) {
const el = this.$refs.table;
const el = this.$refs.tableWrapper;
if (el) {
const footer = document.getElementById('footer');
@@ -202,7 +202,7 @@ export default {
id,
...payload
};
this.$emit('updateField', params);
this.$emit('update-field', params);
}
},
deleteSelected () {
@@ -214,7 +214,7 @@ export default {
primary: this.primaryField.name,
rows: rowIDs
};
this.$emit('deleteSelected', params);
this.$emit('delete-selected', params);
}
},
applyUpdate (params) {

View File

@@ -63,7 +63,7 @@ export default {
this.$emit('close-context');
},
deleteRows () {
this.$emit('deleteSelected');
this.$emit('delete-selected');
this.closeContext();
}
}

View File

@@ -7,15 +7,14 @@
class="td p-0"
tabindex="0"
@contextmenu.prevent="$emit('contextmenu', $event, {id: row._id, field: cKey})"
@updateField="updateField($event, row[primaryField.name])"
>
<template v-if="cKey !== '_id'">
<span
v-if="!isInlineEditor[cKey]"
class="cell-content px-2"
:class="`${isNull(col)} type-${fieldType(cKey)}`"
:class="`${isNull(col)} type-${getFieldType(cKey)}`"
@dblclick="editON($event, col, cKey)"
>{{ col | typeFormat(fieldType(cKey), fieldPrecision(cKey)) | cutText }}</span>
>{{ col | typeFormat(getFieldType(cKey), getFieldPrecision(cKey)) | cutText }}</span>
<ForeignKeySelect
v-else-if="foreignKeys.includes(cKey)"
class="editable-field"
@@ -218,7 +217,7 @@ export default {
if (TIME.includes(this.editingType)) {
let timeMask = '##:##:##';
const precision = this.fieldPrecision(this.editingField);
const precision = this.getFieldPrecision(this.editingField);
for (let i = 0; i < precision; i++)
timeMask += i === 0 ? '.#' : '#';
@@ -231,7 +230,7 @@ export default {
if (DATETIME.includes(this.editingType)) {
let datetimeMask = '####-##-## ##:##:##';
const precision = this.fieldPrecision(this.editingField);
const precision = this.getFieldPrecision(this.editingField);
for (let i = 0; i < precision; i++)
datetimeMask += i === 0 ? '.#' : '#';
@@ -260,22 +259,25 @@ export default {
});
},
methods: {
fieldType (cKey) {
getFieldType (cKey) {
let type = 'unknown';
const field = this.fields.filter(field => field.name === cKey)[0];
const field = this.getFieldObj(cKey);
if (field)
type = field.type;
return type;
},
fieldPrecision (cKey) {
getFieldPrecision (cKey) {
let length = 0;
const field = this.fields.filter(field => field.name === cKey)[0];
const field = this.getFieldObj(cKey);
if (field)
length = field.datePrecision;
return length;
},
getFieldObj (cKey) {
return this.fields.filter(field => field.name === cKey || field.alias === cKey)[0];
},
isNull (value) {
return value === null ? ' is-null' : '';
},
@@ -283,7 +285,7 @@ export default {
return bufferToBase64(val);
},
editON (event, content, field) {
const type = this.fieldType(field);
const type = this.getFieldType(field);
this.originalContent = content;
this.editingType = type;
this.editingField = field;
@@ -316,7 +318,7 @@ export default {
}
// Inline editable fields
this.editingContent = this.$options.filters.typeFormat(this.originalContent, type, this.fieldPrecision(field));
this.editingContent = this.$options.filters.typeFormat(this.originalContent, type, this.getFieldPrecision(field));
this.$nextTick(() => { // Focus on input
event.target.blur();
@@ -346,8 +348,8 @@ export default {
}
}
this.$emit('updateField', {
field: this.editingField,
this.$emit('update-field', {
field: this.getFieldObj(this.editingField).name,
type: this.editingType,
content
});
@@ -385,14 +387,11 @@ export default {
};
this.willBeDeleted = true;
},
updateField (event, id) {
this.$emit('updateField', event, id);
},
contextMenu (event, cell) {
this.$emit('updateField', event, cell);
this.$emit('update-field', event, cell);
},
selectRow (event, row) {
this.$emit('selectRow', event, row);
this.$emit('select-row', event, row);
},
getKeyUsage (keyName) {
return this.keyUsage.find(key => key.column === keyName);

View File

@@ -36,8 +36,8 @@
ref="queryTable"
:results="results"
:tab-uid="tabUid"
@updateField="updateField"
@deleteSelected="deleteSelected"
@update-field="updateField"
@delete-selected="deleteSelected"
/>
</div>
<ModalNewTableRow
@@ -69,7 +69,7 @@ export default {
},
data () {
return {
tabUid: 1,
tabUid: 'data',
isQuering: false,
results: {},
fields: [],
@@ -86,7 +86,7 @@ export default {
return this.getWorkspace(this.connection.uid);
},
isSelected () {
return this.workspace.selected_tab === 1;
return this.workspace.selected_tab === 'data';
}
},
watch: {

View File

@@ -0,0 +1,87 @@
module.exports = {
word: {
edit: 'تعديل',
save: 'حفظ',
close: 'إغلاق',
delete: 'حفظ',
confirm: 'تأكيد',
cancel: 'إلغاء',
send: 'إرسال',
connectionName: 'إسم الإتصال',
client: 'العميل',
hostName: 'إسم المستضيف',
port: 'المنفذ',
user: 'المستخدم',
password: 'الرقم السري',
credentials: 'بيانات الدخول',
connect: 'إتصال',
connected: 'متصل',
disconnect: 'إلغاء الإتصال',
disconnected: 'غير متصل',
refresh: 'تحديث',
settings: 'الإعدادات',
general: 'عام',
themes: 'الأنماط',
update: 'تحديث',
about: 'حول',
language: 'اللغة',
version: 'النسخة',
donate: 'إدعم',
run: 'شغل',
schema: 'Schema',
results: 'النتائج',
size: 'الحجم',
seconds: 'ثواني',
type: 'نوع',
mimeType: 'نوع الميديا',
download: 'تحميل',
add: 'أضف',
data: 'بيانات',
properties: 'خصائص',
insert: 'أدرج'
},
message: {
appWelcome: 'مرحبا بك في عميل الSQL انتاريس!',
appFirstStep: 'خطوتك الأولى قم بإنشاء إتصال جديد بقاعدة بيانات.',
addConnection: 'إضافة إتصال',
createConnection: 'إنشاء إتصال',
createNewConnection: 'إنشاء إتصال جديد',
askCredentials: 'إطلب بيانات الدخول',
testConnection: 'إختبر الإتصال',
editConnection: 'عدل الإتصال',
deleteConnection: 'إحذف الإتصال',
deleteConnectionCorfirm: 'هل أنت متأكد من حذف الإتصال؟',
connectionSuccessfullyMade: 'تم الإتصال بنجاح!',
madeWithJS: 'بني بـ 💛 و جافاسكربت!',
checkForUpdates: 'تأكد من التحديثات',
noUpdatesAvailable: 'لا توجد تحديثات',
checkingForUpdate: 'البحث عن تحديثات',
checkFailure: 'فشل البحث, نرجوا المحاولة في وقت لاحق',
updateAvailable: 'تحديث جديد متوفر',
downloadingUpdate: 'جاري تحميل التحديث',
updateDownloaded: 'تم تحميل التحديث',
restartToInstall: 'قم بإعادة تشغيل انتاريس للتحديث',
unableEditFieldWithoutPrimary: 'لا يمكن تعديل الخانة بدون وجود مفتاح رئيسي في النتائج',
editCell: 'تعديل الخلية',
deleteRows: 'حذف صف | حذف {count} صفوف',
confirmToDeleteRows: 'هل أنت متأكد من حذف صف واحد؟? | هل أنت متأكد من حذف {count} صف?',
notificationsTimeout: 'إنتهاء التنبيهات',
uploadFile: 'رفع ملف',
addNewRow: 'إضافة صف جديد',
numberOfInserts: 'عدد الإدراجات'
},
// Date and Time
short: {
year: 'numeric',
month: 'short',
day: 'numeric'
},
long: {
year: 'numeric',
month: 'short',
day: 'numeric',
weekday: 'short',
hour: 'numeric',
minute: 'numeric'
}
};

View File

@@ -68,7 +68,9 @@ module.exports = {
notificationsTimeout: 'Notifications timeout',
uploadFile: 'Upload file',
addNewRow: 'Add new row',
numberOfInserts: 'Number of inserts'
numberOfInserts: 'Number of inserts',
openNewTab: 'Open a new tab',
affectedRows: 'Affected rows'
},
// Date and Time
short: {

View File

@@ -6,7 +6,8 @@ Vue.use(VueI18n);
const i18n = new VueI18n({
messages: {
'en-US': require('./en-US'),
'it-IT': require('./it-IT')
'it-IT': require('./it-IT'),
'ar-SA': require('./ar-SA')
}
});
export default i18n;

View File

@@ -1,4 +1,5 @@
export default {
'en-US': 'English',
'it-IT': 'Italiano'
'it-IT': 'Italiano',
'ar-SA': 'العربية'
};

View File

@@ -3,11 +3,11 @@ import { ipcRenderer } from 'electron';
export default class {
static makeTest (params) {
return ipcRenderer.invoke('testConnection', params);
return ipcRenderer.invoke('test-connection', params);
}
static checkConnection (params) {
return ipcRenderer.invoke('checkConnection', params);
return ipcRenderer.invoke('check-connection', params);
}
static connect (params) {
@@ -23,6 +23,6 @@ export default class {
}
static rawQuery (params) {
return ipcRenderer.invoke('rawQuery', params);
return ipcRenderer.invoke('raw-query', params);
}
}

View File

@@ -3,11 +3,11 @@ import { ipcRenderer } from 'electron';
export default class {
static getTableColumns (params) {
return ipcRenderer.invoke('getTableColumns', params);
return ipcRenderer.invoke('get-table-columns', params);
}
static getTableData (params) {
return ipcRenderer.invoke('getTableData', params);
return ipcRenderer.invoke('get-table-data', params);
}
static getKeyUsage (params) {
@@ -15,15 +15,15 @@ export default class {
}
static updateTableCell (params) {
return ipcRenderer.invoke('updateTableCell', params);
return ipcRenderer.invoke('update-table-cell', params);
}
static deleteTableRows (params) {
return ipcRenderer.invoke('deleteTableRows', params);
return ipcRenderer.invoke('delete-table-rows', params);
}
static insertTableRows (params) {
return ipcRenderer.invoke('insertTableRows', params);
return ipcRenderer.invoke('insert-table-rows', params);
}
static getForeignList (params) {

View File

@@ -33,6 +33,8 @@
"blob": darkorchid,
"mediumblob": darkorchid,
"longblob": darkorchid,
"enum": gold,
"set": gold,
"unknown": gray,
)
);

View File

@@ -106,6 +106,13 @@ body {
.tab {
border-color: #272727;
.tab-item {
.btn-clear {
margin-top: -0.1rem;
font-size: 0.6rem;
}
}
}
.panel {
@@ -126,12 +133,12 @@ body {
}
.form-select,
.form-select:not([multiple]):not([size]),
.form-input,
.form-select:not([multiple]):not([size]),
.form-checkbox .form-icon,
.form-radio .form-icon {
border-color: $bg-color-light;
background: $bg-color-gray;
background-color: $bg-color-gray;
}
.form-input:not(:placeholder-shown):invalid:focus {

View File

@@ -1,6 +1,7 @@
'use strict';
import Connection from '@/ipc-api/Connection';
import { uidGen } from 'common/libs/uidGen';
const tabIndex = [];
function remapStructure (structure) { // TODO: move to main process and add fields (for autocomplete purpose)
const databases = structure.map(table => table.TABLE_SCHEMA)
@@ -63,8 +64,11 @@ export default {
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, breadcrumbs } : workspace);
},
NEW_TAB (state, uid) {
tabIndex[uid] = tabIndex[uid] ? ++tabIndex[uid] : 1;
const newTab = {
uid: uidGen('T'),
index: tabIndex[uid],
selected: false,
type: 'query',
fields: [],
@@ -81,6 +85,18 @@ export default {
return workspace;
});
},
REMOVE_TAB (state, { uid, tab: tUid }) {
state.workspaces = state.workspaces.map(workspace => {
if (workspace.uid === uid) {
return {
...workspace,
tabs: workspace.tabs.filter(tab => tab.uid !== tUid)
};
}
else
return workspace;
});
},
SELECT_TAB (state, { uid, tab }) {
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, selected_tab: tab } : workspace);
},
@@ -158,7 +174,13 @@ export default {
connected: false,
selected_tab: 0,
tabs: [{
uid: 1,
uid: 'data',
type: 'table',
fields: [],
keyUsage: []
},
{
uid: 'prop',
type: 'table',
fields: [],
keyUsage: []
@@ -169,7 +191,7 @@ export default {
commit('ADD_WORKSPACE', workspace);
if (getters.getWorkspace(uid).tabs.length < 2)
if (getters.getWorkspace(uid).tabs.length < 3)
dispatch('newTab', uid);
},
changeBreadcrumbs ({ commit, getters }, payload) {
@@ -178,6 +200,9 @@ export default {
newTab ({ commit }, uid) {
commit('NEW_TAB', uid);
},
removeTab ({ commit }, payload) {
commit('REMOVE_TAB', payload);
},
selectTab ({ commit }, payload) {
commit('SELECT_TAB', payload);
},

View File

@@ -1,23 +1,23 @@
import { ipcRenderer } from 'electron';
export default store => {
ipcRenderer.on('checkingForUpdate', () => {
ipcRenderer.on('checking-for-update', () => {
store.commit('application/CHANGE_UPDATE_STATUS', 'checking');
});
ipcRenderer.on('updateAvailable', () => {
ipcRenderer.on('update-available', () => {
store.commit('application/CHANGE_UPDATE_STATUS', 'available');
});
ipcRenderer.on('updateNotAvailable', () => {
ipcRenderer.on('update-not-available', () => {
store.commit('application/CHANGE_UPDATE_STATUS', 'noupdate');
});
ipcRenderer.on('checkFailed', () => {
ipcRenderer.on('check-failed', () => {
store.commit('application/CHANGE_UPDATE_STATUS', 'nocheck');
});
ipcRenderer.on('downloadProgress', (event, data) => {
ipcRenderer.on('download-progress', (event, data) => {
store.commit('application/CHANGE_UPDATE_STATUS', 'downloading');
store.commit('application/CHANGE_PROGRESS_PERCENTAGE', data.percent);
});
ipcRenderer.on('updateDownloaded', () => {
ipcRenderer.on('update-downloaded', () => {
store.commit('application/CHANGE_UPDATE_STATUS', 'downloaded');
});
};

View File

@@ -0,0 +1,12 @@
import { functions } from '@/suggestions/sql/sql-functions';
import { keywords } from '@/suggestions/sql/sql-keywords';
import { operators } from '@/suggestions/sql/sql-operators';
import { variables } from '@/suggestions/sql/sql-variables';
export const completionItemProvider = (monaco) => {
return {
provideCompletionItems () {
return { suggestions: [...functions(monaco), ...keywords(monaco), ...operators(monaco), ...variables(monaco)] };
}
};
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
export const operators = (monaco) => {
return [{
label: 'ALL',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'ALL'
},
{
label: 'AND',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'AND'
},
{
label: 'ANY',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'ANY'
},
{
label: 'BETWEEN',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'BETWEEN'
},
{
label: 'EXISTS',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'EXISTS'
},
{
label: 'IN',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'IN'
},
{
label: 'LIKE',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'LIKE'
},
{
label: 'NOT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'NOT'
},
{
label: 'OR',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'OR'
},
{
label: 'SOME',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'SOME'
},
{
label: 'EXCEPT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'EXCEPT'
},
{
label: 'INTERSECT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'INTERSECT'
},
{
label: 'UNION',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'UNION'
},
{
label: 'APPLY',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'APPLY'
},
{
label: 'CROSS',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'CROSS'
},
{
label: 'FULL',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'FULL'
},
{
label: 'INNER',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'INNER'
},
{
label: 'JOIN',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'JOIN'
},
{
label: 'LEFT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'LEFT'
},
{
label: 'OUTER',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'OUTER'
},
{
label: 'RIGHT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'RIGHT'
},
{
label: 'CONTAINS',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'CONTAINS'
},
{
label: 'FREETEXT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'FREETEXT'
},
{
label: 'IS',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'IS'
},
{
label: 'NULL',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'NULL'
},
{
label: 'PIVOT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'PIVOT'
},
{
label: 'UNPIVOT',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'UNPIVOT'
},
{
label: 'MATCHED',
kind: monaco.languages.CompletionItemKind.Operator,
insertText: 'MATCHED'
}];
};

View File

@@ -0,0 +1,172 @@
export const variables = (monaco) => {
return [{
label: '@@DATEFIRST',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@DATEFIRST'
},
{
label: '@@DBTS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@DBTS'
},
{
label: '@@LANGID',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@LANGID'
},
{
label: '@@LANGUAGE',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@LANGUAGE'
},
{
label: '@@LOCK_TIMEOUT',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@LOCK_TIMEOUT'
},
{
label: '@@MAX_CONNECTIONS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@MAX_CONNECTIONS'
},
{
label: '@@MAX_PRECISION',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@MAX_PRECISION'
},
{
label: '@@NESTLEVEL',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@NESTLEVEL'
},
{
label: '@@OPTIONS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@OPTIONS'
},
{
label: '@@REMSERVER',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@REMSERVER'
},
{
label: '@@SERVERNAME',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@SERVERNAME'
},
{
label: '@@SERVICENAME',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@SERVICENAME'
},
{
label: '@@SPID',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@SPID'
},
{
label: '@@TEXTSIZE',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@TEXTSIZE'
},
{
label: '@@VERSION',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@VERSION'
},
{
label: '@@CURSOR_ROWS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@CURSOR_ROWS'
},
{
label: '@@FETCH_STATUS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@FETCH_STATUS'
},
{
label: '@@DATEFIRST',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@DATEFIRST'
},
{
label: '@@PROCID',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@PROCID'
},
{
label: '@@ERROR',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@ERROR'
},
{
label: '@@IDENTITY',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@IDENTITY'
},
{
label: '@@ROWCOUNT',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@ROWCOUNT'
},
{
label: '@@TRANCOUNT',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@TRANCOUNT'
},
{
label: '@@CONNECTIONS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@CONNECTIONS'
},
{
label: '@@CPU_BUSY',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@CPU_BUSY'
},
{
label: '@@IDLE',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@IDLE'
},
{
label: '@@IO_BUSY',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@IO_BUSY'
},
{
label: '@@PACKET_ERRORS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@PACKET_ERRORS'
},
{
label: '@@PACK_RECEIVED',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@PACK_RECEIVED'
},
{
label: '@@PACK_SENT',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@PACK_SENT'
},
{
label: '@@TIMETICKS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@TIMETICKS'
},
{
label: '@@TOTAL_ERRORS',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@TOTAL_ERRORS'
},
{
label: '@@TOTAL_READ',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@TOTAL_READ'
},
{
label: '@@TOTAL_WRITE',
kind: monaco.languages.CompletionItemKind.Variable,
insertText: '@@TOTAL_WRITE'
}];
};

View File

@@ -1,8 +1,11 @@
const webpack = require('webpack');
const MonacoEditorPlugin = require('monaco-editor-webpack-plugin');
module.exports = {
plugins: [
new MonacoEditorPlugin({
languages: ['sql']
}),
new webpack.DefinePlugin({
'process.env': {
PACKAGE_VERSION: JSON.stringify(require('./package.json').version)