mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
dea5ec7513 | |||
be816e8588 | |||
1e938adc5d | |||
8735a0c5f9 | |||
3dde1c109e | |||
d0b3e1b1b8 | |||
c20bff7bcb | |||
9f5ec0276c | |||
55932fe115 | |||
d374372e20 | |||
bb5f44681f | |||
49a4e1cb7b | |||
c2f76e490a | |||
e349dd5eab | |||
280697698e | |||
0783f8b57e | |||
c981244d7a | |||
dcb135dd01 | |||
99f7511c4d | |||
fe4c8e12b3 | |||
21728a663d | |||
9ca03f4625 | |||
affb7288b0 | |||
614e0d3275 | |||
feef5e30ee | |||
82c25711b6 | |||
2ca2988832 | |||
e3f259c6e8 | |||
e7401cc96e | |||
13b9840f3d |
26
.github/workflows/build.yml
vendored
Normal file
26
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Build/release
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node.js, NPM and Yarn
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
|
||||
- name: Build/release Electron app
|
||||
uses: samuelmeuli/action-electron-builder@v1
|
||||
with:
|
||||
github_token: ${{ secrets.github_token }}
|
||||
release: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
@@ -8,7 +8,8 @@
|
||||
"stylelint-scss"
|
||||
],
|
||||
"rules": {
|
||||
"at-rule-no-unknown": null
|
||||
"at-rule-no-unknown": null,
|
||||
"no-descending-specificity": null
|
||||
},
|
||||
"syntax": "scss"
|
||||
}
|
46
CHANGELOG.md
46
CHANGELOG.md
@@ -2,6 +2,52 @@
|
||||
|
||||
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.1.2](https://github.com/Fabio286/antares/compare/v0.1.1...v0.1.2) (2021-04-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* in-app last release changelog ([1e938ad](https://github.com/Fabio286/antares/commit/1e938adc5d8eb5ad16ab16342375eecd88f68d20))
|
||||
* **PostgreSQL:** edit timezone in cell editor ([8735a0c](https://github.com/Fabio286/antares/commit/8735a0c5f9e5b6b3bcaadf37ce158aa7beae2c48))
|
||||
* **PostgreSQL:** procedures management ([3dde1c1](https://github.com/Fabio286/antares/commit/3dde1c109e23342d94362626ef7350dc123ea859))
|
||||
* **PostgreSQL:** support of arrays in table settings ([d0b3e1b](https://github.com/Fabio286/antares/commit/d0b3e1b1b8be9d2c038d70e16d4478671315de8f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cell edit doesn't properly use primary or unique index to update if both present, closes [#51](https://github.com/Fabio286/antares/issues/51) ([55932fe](https://github.com/Fabio286/antares/commit/55932fe11583bd5ff48f82b8408965adba4f5071))
|
||||
* deletion of rows from query results ([c20bff7](https://github.com/Fabio286/antares/commit/c20bff7bcbe340ac99ebcacaba3359edd61c068a))
|
||||
* no foreign key select when cell value is NULL, closes [#50](https://github.com/Fabio286/antares/issues/50) ([9f5ec02](https://github.com/Fabio286/antares/commit/9f5ec0276c92904975fdaea34b4c845c92bfe8d4))
|
||||
* wrong datetime conversion when updating a row without an unique key ([d374372](https://github.com/Fabio286/antares/commit/d374372e208318d7e50b258a8041145bdf7992c5))
|
||||
* **PostgreSQL:** issue with selected schema different than public ([49a4e1c](https://github.com/Fabio286/antares/commit/49a4e1cb7b24642641265d5830d3fee370cceeb4))
|
||||
* **UI:** white readonly inputs with dark theme ([bb5f446](https://github.com/Fabio286/antares/commit/bb5f44681f87aacf2cd2f60a6d958c5732289790))
|
||||
|
||||
|
||||
### Improvements
|
||||
|
||||
* **UI:** improved setting modal rendering ([be816e8](https://github.com/Fabio286/antares/commit/be816e85888b4f3d26cbb9caac0adbc4dde0ea94))
|
||||
|
||||
### [0.1.1](https://github.com/Fabio286/antares/compare/v0.1.0...v0.1.1) (2021-04-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* scratchpad to save persistent notes ([e349dd5](https://github.com/Fabio286/antares/commit/e349dd5eaba608591257f2799b830805e4936c27))
|
||||
* **PostgreSQL:** foreign keys management ([fe4c8e1](https://github.com/Fabio286/antares/commit/fe4c8e12b39dd3cdfc233f07e3fe2ff0676252b0))
|
||||
* **PostgreSQL:** indexes management ([9ca03f4](https://github.com/Fabio286/antares/commit/9ca03f462560b634970a19d3d97b878d60509acc))
|
||||
* **PostgreSQL:** table fields edit ([e3f259c](https://github.com/Fabio286/antares/commit/e3f259c6e8327d71bd7dd0a9c33d957dc6ca1fb8))
|
||||
* **PostgreSQL:** tables addition ([feef5e3](https://github.com/Fabio286/antares/commit/feef5e30eec915cbb219223cc428bd4e98d2e9c5))
|
||||
* **PostgreSQL:** unique keys management ([614e0d3](https://github.com/Fabio286/antares/commit/614e0d32758c13b59139d349d4682a5bafc3ca88))
|
||||
* **PostgreSQL:** views management ([99f7511](https://github.com/Fabio286/antares/commit/99f7511c4d5fab4030b30d5134cd03248167faea))
|
||||
* **UI:** light theme ([2806976](https://github.com/Fabio286/antares/commit/280697698ea5fae6d54326970c823878888c196c))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **UI:** editor theme preview not properly loaded in some cases ([c981244](https://github.com/Fabio286/antares/commit/c981244d7aa93ca18ca2de44bf8df06f253b9d20))
|
||||
* fields of ref. table not automatically loaded in foreign keys modal ([e7401cc](https://github.com/Fabio286/antares/commit/e7401cc96e76e00100a88eea9f40541fd8027adb))
|
||||
* hide update tab for Windows Store distributions ([dcb135d](https://github.com/Fabio286/antares/commit/dcb135dd015b8f8c6cfb44021211bb8cf3089192))
|
||||
|
||||
## [0.1.0](https://github.com/Fabio286/antares/compare/v0.0.20...v0.1.0) (2021-03-21)
|
||||
|
||||
|
||||
|
23
README.md
23
README.md
@@ -9,11 +9,11 @@
|
||||
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 an alpha, it lacks many features** and supports only MySQL.
|
||||
Most of its current features might be enough for basic MySQL use, so give it a chance and send me your feedback, I would really appreciate it.
|
||||
I'm actively working on it (yes, i'm a lone dev), hoping to provide cool features and fixes as soon as possible.
|
||||
**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB and PostgreSQL (partially).
|
||||
Many of its current features are enough to have a pleasant user experience with MySQL/MariaDB, and basic functionalites with PostgreSQL, so give it a chance and send me your feedback, I would really appreciate it.
|
||||
I'm actively working on it, hoping to provide cool features and fixes 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/Fabio286/antares/releases).
|
||||
🔗 If you are curious to try Antares you can download and install the [latest release](https://github.com/Fabio286/antares/releases/latest).
|
||||
👁 To stay tuned for new releases watch this repo on **Release only** channel.
|
||||
🌟 Don't forget to **leave a star** if you appreciate this project.
|
||||
|
||||
@@ -21,7 +21,12 @@ I'm actively working on it (yes, i'm a lone dev), hoping to provide cool feature
|
||||
|
||||
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, full featured, cross platform and open source alternative, empowered by JavaScript's ecosystem.
|
||||
An application created with minimalism and semplicity in mind, with features in the right places, not hundreds of tiny buttons or submenu.
|
||||
A modern application created with minimalism and semplicity in mind, with features in the right places, not hundreds of tiny buttons, tabs or submenu.
|
||||
|
||||
## Download
|
||||
|
||||
[](https://snapcraft.io/antares) [](https://www.microsoft.com/p/antares-sql-client/9nhtb9sq51r1?cid=storebadge&ocid=badge&rtc=1&activetab=pivot:overviewtab)
|
||||
🚀 **[Other Downloads](https://github.com/Fabio286/antares/releases/latest)**
|
||||
|
||||
## How to contribute
|
||||
|
||||
@@ -36,7 +41,8 @@ An application created with minimalism and semplicity in mind, with features in
|
||||
- Fake table data filler.
|
||||
- Run queries on multiple tabs.
|
||||
- Query suggestions and auto complete.
|
||||
- Native dark theme.
|
||||
- Dark and light theme.
|
||||
- Scratchpad.
|
||||
- Multi language.
|
||||
- Secure password storage.
|
||||
- Auto updates.
|
||||
@@ -46,7 +52,7 @@ An application created with minimalism and semplicity in mind, with features in
|
||||
This is a roadmap with major features will come in near future.
|
||||
|
||||
- Support for other databases.
|
||||
- Database tools (variables, process list...).
|
||||
- Database tools.
|
||||
- SSH tunnel support.
|
||||
- Users management (add/edit/delete).
|
||||
- UI/UX improvements.
|
||||
@@ -55,7 +61,6 @@ This is a roadmap with major features will come in near future.
|
||||
- More keyboard shortcuts.
|
||||
- Query logs console.
|
||||
- Import/export and migration.
|
||||
- Light theme.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -73,7 +78,7 @@ Depending on your distribution, you will need to run the following command:
|
||||
### Databases
|
||||
|
||||
- [x] MySQL/MariaDB
|
||||
- [ ] PostgreSQL
|
||||
- [x] PostgreSQL (partially, work in progress)
|
||||
- [ ] SQLite
|
||||
- [ ] MSSQL
|
||||
- [ ] OracleDB
|
||||
|
BIN
build/appx/Square150x150Logo.png
Normal file
BIN
build/appx/Square150x150Logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
BIN
build/appx/Square44x44Logo.png
Normal file
BIN
build/appx/Square44x44Logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
BIN
build/appx/StoreLogo.png
Normal file
BIN
build/appx/StoreLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
build/appx/Wide310x150Logo.png
Normal file
BIN
build/appx/Wide310x150Logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
11
package.json
11
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "antares",
|
||||
"productName": "Antares",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.2",
|
||||
"description": "A cross-platform easy to use SQL client.",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/Fabio286/antares.git",
|
||||
@@ -9,9 +9,9 @@
|
||||
"dev": "cross-env NODE_ENV=development electron-webpack dev",
|
||||
"compile": "electron-webpack",
|
||||
"build": "cross-env NODE_ENV=production npm run compile && electron-builder",
|
||||
"build:appx": "npm run build -- --win appx",
|
||||
"release": "standard-version",
|
||||
"release:pre": "npm run release -- --prerelease alpha",
|
||||
"release:snap": "npm run build -- --linux snap && snapcraft upload --release=edge ./dist/Antares-${npm_package_version}-linux_amd64.snap",
|
||||
"test": "npm run lint",
|
||||
"lint": "eslint . --ext .js,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"",
|
||||
"lint:fix": "eslint . --ext .js,.vue --fix && stylelint \"./src/**/*.{css,scss,sass,vue}\" --fix"
|
||||
@@ -53,6 +53,12 @@
|
||||
},
|
||||
"portable": {
|
||||
"artifactName": "${productName}-${version}-portable.exe"
|
||||
},
|
||||
"appx": {
|
||||
"displayName": "Antares SQL Client",
|
||||
"identityName": "62514FabioDiStasio.AntaresSQLClient",
|
||||
"publisher": "CN=1A2729ED-865C-41D2-9038-39AE2A63AA52",
|
||||
"applicationId": "FabioDiStasio.AntaresSQLClient"
|
||||
}
|
||||
},
|
||||
"electronWebpack": {
|
||||
@@ -68,6 +74,7 @@
|
||||
"electron-updater": "^4.3.5",
|
||||
"faker": "^5.3.1",
|
||||
"keytar": "^7.3.0",
|
||||
"marked": "^2.0.2",
|
||||
"moment": "^2.29.1",
|
||||
"mssql": "^6.2.3",
|
||||
"mysql2": "^2.2.5",
|
||||
|
@@ -37,5 +37,20 @@ module.exports = {
|
||||
indexes: false,
|
||||
foreigns: false,
|
||||
sortableFields: false,
|
||||
zerofill: false
|
||||
unsigned: false,
|
||||
nullable: false,
|
||||
zerofill: false,
|
||||
autoIncrement: false,
|
||||
comment: false,
|
||||
collation: false,
|
||||
definer: false,
|
||||
onUpdate: false,
|
||||
tableArray: false,
|
||||
viewAlgorithm: false,
|
||||
viewSqlSecurity: false,
|
||||
viewUpdateOption: false,
|
||||
procedureDeterministic: false,
|
||||
procedureDataAccess: false,
|
||||
procedureSql: false,
|
||||
parametersLength: false
|
||||
};
|
||||
|
@@ -36,5 +36,19 @@ module.exports = {
|
||||
indexes: true,
|
||||
foreigns: true,
|
||||
sortableFields: true,
|
||||
zerofill: true
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
zerofill: true,
|
||||
autoIncrement: true,
|
||||
comment: true,
|
||||
collation: true,
|
||||
definer: true,
|
||||
onUpdate: true,
|
||||
viewAlgorithm: true,
|
||||
viewSqlSecurity: true,
|
||||
viewUpdateOption: true,
|
||||
procedureDeterministic: true,
|
||||
procedureDataAccess: true,
|
||||
procedureSql: 'BEGIN\r\n\r\nEND',
|
||||
parametersLength: true
|
||||
};
|
||||
|
@@ -12,20 +12,28 @@ module.exports = {
|
||||
processesList: true,
|
||||
// Structure
|
||||
tables: true,
|
||||
views: false,
|
||||
views: true,
|
||||
triggers: false,
|
||||
routines: false,
|
||||
routines: true,
|
||||
functions: false,
|
||||
schedulers: false,
|
||||
// Settings
|
||||
tableAdd: true,
|
||||
viewAdd: true,
|
||||
triggerAdd: false,
|
||||
routineAdd: true,
|
||||
functionAdd: false,
|
||||
databaseEdit: false,
|
||||
tableSettings: false,
|
||||
viewSettings: false,
|
||||
tableSettings: true,
|
||||
viewSettings: true,
|
||||
triggerSettings: false,
|
||||
routineSettings: false,
|
||||
routineSettings: true,
|
||||
functionSettings: false,
|
||||
schedulerSettings: false,
|
||||
indexes: true,
|
||||
foreigns: true,
|
||||
sortableFields: false
|
||||
sortableFields: false,
|
||||
nullable: true,
|
||||
tableArray: true,
|
||||
procedureSql: '$BODY$\r\n\r\n$BODY$'
|
||||
};
|
||||
|
@@ -4,7 +4,7 @@ module.exports = [
|
||||
types: [
|
||||
{
|
||||
name: 'TINYINT',
|
||||
length: true,
|
||||
length: 4,
|
||||
collation: false,
|
||||
unsigned: true,
|
||||
zerofill: true
|
||||
|
@@ -4,22 +4,22 @@ module.exports = [
|
||||
types: [
|
||||
{
|
||||
name: 'SMALLINT',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
},
|
||||
{
|
||||
name: 'INTEGER',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
},
|
||||
{
|
||||
name: 'BIGINT',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
},
|
||||
{
|
||||
name: 'DECIMAL',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
},
|
||||
{
|
||||
@@ -29,17 +29,17 @@ module.exports = [
|
||||
},
|
||||
{
|
||||
name: 'SMALLSERIAL',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
},
|
||||
{
|
||||
name: 'SERIAL',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
},
|
||||
{
|
||||
name: 'BIGSERIAL',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
}
|
||||
]
|
||||
@@ -49,12 +49,12 @@ module.exports = [
|
||||
types: [
|
||||
{
|
||||
name: 'REAL',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
},
|
||||
{
|
||||
name: 'DOUBLE PRECISION',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
}
|
||||
]
|
||||
@@ -64,7 +64,7 @@ module.exports = [
|
||||
types: [
|
||||
{
|
||||
name: 'money',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: true
|
||||
}
|
||||
]
|
||||
@@ -77,14 +77,9 @@ module.exports = [
|
||||
length: true,
|
||||
unsigned: false
|
||||
},
|
||||
{
|
||||
name: 'CHAR',
|
||||
length: false,
|
||||
unsigned: false
|
||||
},
|
||||
{
|
||||
name: 'CHARACTER',
|
||||
length: false,
|
||||
length: true,
|
||||
unsigned: false
|
||||
},
|
||||
{
|
||||
@@ -109,7 +104,7 @@ module.exports = [
|
||||
types: [
|
||||
{
|
||||
name: 'BYTEA',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: false
|
||||
}
|
||||
]
|
||||
@@ -129,17 +124,17 @@ module.exports = [
|
||||
},
|
||||
{
|
||||
name: 'DATE',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: false
|
||||
},
|
||||
{
|
||||
name: 'TIME',
|
||||
length: true,
|
||||
name: 'TIME WITHOUT TIME ZONE',
|
||||
length: false,
|
||||
unsigned: false
|
||||
},
|
||||
{
|
||||
name: 'TIME WITH TIME ZONE',
|
||||
length: true,
|
||||
length: false,
|
||||
unsigned: false
|
||||
},
|
||||
{
|
||||
@@ -229,12 +224,12 @@ module.exports = [
|
||||
types: [
|
||||
{
|
||||
name: 'BIT',
|
||||
length: false,
|
||||
length: true,
|
||||
unsigned: false
|
||||
},
|
||||
{
|
||||
name: 'BIT VARYING',
|
||||
length: false,
|
||||
length: true,
|
||||
unsigned: false
|
||||
}
|
||||
]
|
||||
|
@@ -54,6 +54,7 @@ export const TIME = [
|
||||
'TIME',
|
||||
'TIME WITH TIME ZONE'
|
||||
];
|
||||
|
||||
export const DATETIME = [
|
||||
'DATETIME',
|
||||
'TIMESTAMP',
|
||||
@@ -61,6 +62,12 @@ export const DATETIME = [
|
||||
'TIMESTAMP WITH TIME ZONE'
|
||||
];
|
||||
|
||||
// Used to check datetime fields only
|
||||
export const HAS_TIMEZONE = [
|
||||
'TIMESTAMP WITH TIME ZONE',
|
||||
'TIME WITH TIME ZONE'
|
||||
];
|
||||
|
||||
export const BLOB = [
|
||||
'BLOB',
|
||||
'TINYBLOB',
|
||||
|
@@ -1,5 +1,5 @@
|
||||
module.exports = [
|
||||
'PRIMARY',
|
||||
'KEY',
|
||||
'INDEX',
|
||||
'UNIQUE'
|
||||
];
|
||||
|
@@ -8,7 +8,8 @@ export default connections => {
|
||||
host: conn.host,
|
||||
port: +conn.port,
|
||||
user: conn.user,
|
||||
password: conn.password
|
||||
password: conn.password,
|
||||
application_name: 'Antares SQL'
|
||||
};
|
||||
|
||||
if (conn.database)
|
||||
@@ -50,7 +51,8 @@ export default connections => {
|
||||
host: conn.host,
|
||||
port: +conn.port,
|
||||
user: conn.user,
|
||||
password: conn.password
|
||||
password: conn.password,
|
||||
application_name: 'Antares SQL'
|
||||
};
|
||||
|
||||
if (conn.database)
|
||||
|
@@ -157,9 +157,13 @@ export default (connections) => {
|
||||
|
||||
ipcMain.handle('delete-table-rows', async (event, params) => {
|
||||
if (params.primary) {
|
||||
const idString = params.rows.map(row => typeof row[params.primary] === 'string'
|
||||
? `"${row[params.primary]}"`
|
||||
: row[params.primary]).join(',');
|
||||
const idString = params.rows.map(row => {
|
||||
const fieldName = Object.keys(row)[0].includes('.') ? `${params.table}.${params.primary}` : params.primary;
|
||||
|
||||
return typeof row[fieldName] === 'string'
|
||||
? `"${row[fieldName]}"`
|
||||
: row[fieldName];
|
||||
}).join(',');
|
||||
|
||||
try {
|
||||
const result = await connections[params.uid]
|
||||
|
@@ -9,10 +9,13 @@ autoUpdater.allowPrerelease = persistentStore.get('allow_prerelease', true);
|
||||
export default () => {
|
||||
ipcMain.on('check-for-updates', event => {
|
||||
mainWindow = event;
|
||||
|
||||
autoUpdater.checkForUpdatesAndNotify().catch(() => {
|
||||
mainWindow.reply('check-failed');
|
||||
});
|
||||
if (process.windowsStore)
|
||||
mainWindow.reply('no-auto-update');
|
||||
else {
|
||||
autoUpdater.checkForUpdatesAndNotify().catch(() => {
|
||||
mainWindow.reply('check-failed');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('restart-to-update', () => {
|
||||
|
@@ -7,6 +7,8 @@ export class MySQLClient extends AntaresCore {
|
||||
constructor (args) {
|
||||
super(args);
|
||||
|
||||
this._schema = null;
|
||||
|
||||
this.types = {
|
||||
0: 'DECIMAL',
|
||||
1: 'TINYINT',
|
||||
@@ -120,6 +122,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
use (schema) {
|
||||
this._schema = schema;
|
||||
return this.raw(`USE \`${schema}\``);
|
||||
}
|
||||
|
||||
@@ -1049,7 +1052,7 @@ export class MySQLClient extends AntaresCore {
|
||||
options
|
||||
} = params;
|
||||
|
||||
let sql = `ALTER TABLE \`${table}\` `;
|
||||
let sql = `ALTER TABLE \`${this._schema}\`.\`${table}\` `;
|
||||
const alterColumns = [];
|
||||
|
||||
// OPTIONS
|
||||
|
@@ -1,5 +1,5 @@
|
||||
'use strict';
|
||||
import pg, { Pool, Client, types } from 'pg';
|
||||
import { Pool, Client, types } from 'pg';
|
||||
import { parse } from 'pgsql-ast-parser';
|
||||
import { AntaresCore } from '../AntaresCore';
|
||||
import dataTypes from 'common/data-types/postgresql';
|
||||
@@ -8,11 +8,11 @@ function pgToString (value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
pg.types.setTypeParser(1082, pgToString); // date
|
||||
pg.types.setTypeParser(1083, pgToString); // time
|
||||
pg.types.setTypeParser(1114, pgToString); // timestamp
|
||||
pg.types.setTypeParser(1184, pgToString); // timestamptz
|
||||
pg.types.setTypeParser(1266, pgToString); // timetz
|
||||
types.setTypeParser(1082, pgToString); // date
|
||||
types.setTypeParser(1083, pgToString); // time
|
||||
types.setTypeParser(1114, pgToString); // timestamp
|
||||
types.setTypeParser(1184, pgToString); // timestamptz
|
||||
types.setTypeParser(1266, pgToString); // timetz
|
||||
|
||||
export class PostgreSQLClient extends AntaresCore {
|
||||
constructor (args) {
|
||||
@@ -23,54 +23,16 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
this.types = {};
|
||||
for (const key in types.builtins)
|
||||
this.types[types.builtins[key]] = key;
|
||||
}
|
||||
|
||||
_getType (field) {
|
||||
let name = this.types[field.columnType];
|
||||
let length = field.columnLength;
|
||||
|
||||
if (['DATE', 'TIME', 'YEAR', 'DATETIME'].includes(name))
|
||||
length = field.decimals;
|
||||
|
||||
if (name === 'TIMESTAMP')
|
||||
length = 0;
|
||||
|
||||
if (field.charsetNr === 63) { // if binary
|
||||
if (name === 'CHAR')
|
||||
name = 'BINARY';
|
||||
else if (name === 'VARCHAR')
|
||||
name = 'VARBINARY';
|
||||
}
|
||||
|
||||
if (name === 'BLOB') {
|
||||
switch (length) {
|
||||
case 765:
|
||||
name = 'TYNITEXT';
|
||||
break;
|
||||
case 196605:
|
||||
name = 'TEXT';
|
||||
break;
|
||||
case 50331645:
|
||||
name = 'MEDIUMTEXT';
|
||||
break;
|
||||
case 4294967295:
|
||||
name = field.charsetNr === 63 ? 'LONGBLOB' : 'LONGTEXT';
|
||||
break;
|
||||
case 255:
|
||||
name = 'TINYBLOB';
|
||||
break;
|
||||
case 65535:
|
||||
name = 'BLOB';
|
||||
break;
|
||||
case 16777215:
|
||||
name = 'MEDIUMBLOB';
|
||||
break;
|
||||
default:
|
||||
name = field.charsetNr === 63 ? 'BLOB' : 'TEXT';
|
||||
}
|
||||
}
|
||||
|
||||
return { name, length };
|
||||
this._arrayTypes = {
|
||||
_int2: 'SMALLINT',
|
||||
_int4: 'INTEGER',
|
||||
_int8: 'BIGINT',
|
||||
_float4: 'REAL',
|
||||
_float8: 'DOUBLE PRECISION',
|
||||
_char: '"CHAR"',
|
||||
_varchar: 'CHARACTER VARYING'
|
||||
};
|
||||
}
|
||||
|
||||
_getTypeInfo (type) {
|
||||
@@ -79,6 +41,12 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
.filter(_type => _type.name === type.toUpperCase())[0];
|
||||
}
|
||||
|
||||
_getArrayType (type) {
|
||||
if (Object.keys(this._arrayTypes).includes(type))
|
||||
return this._arrayTypes[type];
|
||||
return type.replace('_', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
@@ -109,7 +77,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
*/
|
||||
use (schema) {
|
||||
this._schema = schema;
|
||||
return this.raw(`SET search_path TO '${schema}', '$user'`);
|
||||
return this.raw(`SET search_path TO ${schema}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,16 +157,11 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
});
|
||||
|
||||
// PROCEDURES
|
||||
const remappedProcedures = procedures.filter(procedure => procedure.Db === db.database).map(procedure => {
|
||||
const remappedProcedures = procedures.filter(procedure => procedure.routine_schema === db.database).map(procedure => {
|
||||
return {
|
||||
name: procedure.Name,
|
||||
type: procedure.Type,
|
||||
definer: procedure.Definer,
|
||||
created: procedure.Created,
|
||||
updated: procedure.Modified,
|
||||
comment: procedure.Comment,
|
||||
charset: procedure.character_set_client,
|
||||
security: procedure.Security_type
|
||||
name: procedure.routine_name,
|
||||
type: procedure.routine_type,
|
||||
security: procedure.security_type
|
||||
};
|
||||
});
|
||||
|
||||
@@ -256,7 +219,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Object} table scructure
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async getTableColumns ({ schema, table }) {
|
||||
async getTableColumns ({ schema, table }, arrayRemap = true) {
|
||||
const { rows } = await this
|
||||
.select('*')
|
||||
.schema('information_schema')
|
||||
@@ -266,10 +229,17 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
.run();
|
||||
|
||||
return rows.map(field => {
|
||||
let type = field.data_type;
|
||||
const isArray = type === 'ARRAY';
|
||||
|
||||
if (isArray && arrayRemap)
|
||||
type = this._getArrayType(field.udt_name);
|
||||
|
||||
return {
|
||||
name: field.column_name,
|
||||
key: null,
|
||||
type: field.data_type.toUpperCase(),
|
||||
type: type.toUpperCase(),
|
||||
isArray,
|
||||
schema: field.table_schema,
|
||||
table: field.table_name,
|
||||
numPrecision: field.numeric_precision,
|
||||
@@ -282,7 +252,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
default: field.column_default,
|
||||
charset: field.character_set_name,
|
||||
collation: field.collation_name,
|
||||
autoIncrement: null,
|
||||
autoIncrement: false,
|
||||
onUpdate: null,
|
||||
comment: ''
|
||||
};
|
||||
@@ -297,11 +267,14 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async getTableIndexes ({ schema, table }) {
|
||||
if (schema !== 'public')
|
||||
this.use(schema);
|
||||
|
||||
const { rows } = await this.raw(`WITH ndx_list AS (
|
||||
SELECT pg_index.indexrelid, pg_class.oid
|
||||
FROM pg_index, pg_class
|
||||
WHERE pg_class.relname = '${table}' AND pg_class.oid = pg_index.indrelid), ndx_cols AS (
|
||||
SELECT pg_class.relname, UNNEST(i.indkey) AS col_ndx, CASE i.indisprimary WHEN TRUE THEN 'PRIMARY' ELSE CASE i.indisunique WHEN TRUE THEN 'UNIQUE' ELSE 'KEY' END END AS CONSTRAINT_TYPE, pg_class.oid
|
||||
SELECT pg_class.relname, UNNEST(i.indkey) AS col_ndx, CASE i.indisprimary WHEN TRUE THEN 'PRIMARY' ELSE CASE i.indisunique WHEN TRUE THEN 'UNIQUE' ELSE 'INDEX' END END AS CONSTRAINT_TYPE, pg_class.oid
|
||||
FROM pg_class
|
||||
JOIN pg_index i ON (pg_class.oid = i.indexrelid)
|
||||
JOIN ndx_list ON (pg_class.oid = ndx_list.indexrelid)
|
||||
@@ -317,7 +290,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
name: row.constraint_name,
|
||||
column: row.column_name,
|
||||
indexType: null,
|
||||
type: row.constraint_type
|
||||
type: row.constraint_type,
|
||||
cardinality: null,
|
||||
comment: '',
|
||||
indexComment: ''
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -359,6 +335,8 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
tc.constraint_name,
|
||||
tc.table_name,
|
||||
kcu.column_name,
|
||||
kcu.position_in_unique_constraint,
|
||||
kcu.ordinal_position,
|
||||
ccu.table_schema AS foreign_table_schema,
|
||||
ccu.table_name AS foreign_table_name,
|
||||
ccu.column_name AS foreign_column_name,
|
||||
@@ -449,17 +427,17 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async getViewInformations ({ schema, view }) {
|
||||
const sql = `SHOW CREATE VIEW \`${schema}\`.\`${view}\``;
|
||||
const sql = `SELECT "definition" FROM "pg_views" WHERE "viewname"='${view}' AND "schemaname"='${schema}'`;
|
||||
const results = await this.raw(sql);
|
||||
|
||||
return results.rows.map(row => {
|
||||
return {
|
||||
algorithm: row['Create View'].match(/(?<=CREATE ALGORITHM=).*?(?=\s)/gs)[0],
|
||||
definer: row['Create View'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0],
|
||||
security: row['Create View'].match(/(?<=SQL SECURITY ).*?(?=\s)/gs)[0],
|
||||
updateOption: row['Create View'].match(/(?<=WITH ).*?(?=\s)/gs) ? row['Create View'].match(/(?<=WITH ).*?(?=\s)/gs)[0] : '',
|
||||
sql: row['Create View'].match(/(?<=AS ).*?$/gs)[0],
|
||||
name: row.View
|
||||
algorithm: '',
|
||||
definer: '',
|
||||
security: '',
|
||||
updateOption: '',
|
||||
sql: row.definition,
|
||||
name: view
|
||||
};
|
||||
})[0];
|
||||
}
|
||||
@@ -471,7 +449,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropView (params) {
|
||||
const sql = `DROP VIEW \`${params.view}\``;
|
||||
const sql = `DROP VIEW ${this._schema}.${params.view}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -483,10 +461,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
*/
|
||||
async alterView (params) {
|
||||
const { view } = params;
|
||||
let sql = `ALTER ALGORITHM = ${view.algorithm}${view.definer ? ` DEFINER=${view.definer}` : ''} SQL SECURITY ${view.security} VIEW \`${view.oldName}\` AS ${view.sql} ${view.updateOption ? `WITH ${view.updateOption} CHECK OPTION` : ''}`;
|
||||
let sql = `CREATE OR REPLACE VIEW ${this._schema}.${view.oldName} AS ${view.sql}`;
|
||||
|
||||
if (view.name !== view.oldName)
|
||||
sql += `; RENAME TABLE \`${view.oldName}\` TO \`${view.name}\``;
|
||||
sql += `; ALTER VIEW ${this._schema}.${view.oldName} RENAME TO ${view.name}`;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -498,7 +476,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async createView (view) {
|
||||
const sql = `CREATE ALGORITHM = ${view.algorithm} ${view.definer ? `DEFINER=${view.definer} ` : ''}SQL SECURITY ${view.security} VIEW \`${view.name}\` AS ${view.sql} ${view.updateOption ? `WITH ${view.updateOption} CHECK OPTION` : ''}`;
|
||||
const sql = `CREATE VIEW ${this._schema}.${view.name} AS ${view.sql}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -575,16 +553,16 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async getRoutineInformations ({ schema, routine }) {
|
||||
const sql = `SHOW CREATE PROCEDURE \`${schema}\`.\`${routine}\``;
|
||||
const sql = `SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${routine}'));`;
|
||||
const results = await this.raw(sql);
|
||||
|
||||
return results.rows.map(row => {
|
||||
if (!row['Create Procedure']) {
|
||||
return results.rows.map(async row => {
|
||||
if (!row.pg_get_functiondef) {
|
||||
return {
|
||||
definer: null,
|
||||
sql: '',
|
||||
parameters: [],
|
||||
name: row.Procedure,
|
||||
name: routine,
|
||||
comment: '',
|
||||
security: 'DEFINER',
|
||||
deterministic: false,
|
||||
@@ -592,40 +570,48 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
};
|
||||
}
|
||||
|
||||
const parameters = row['Create Procedure']
|
||||
.match(/(\([^()]*(?:(?:\([^()]*\))[^()]*)*\)\s*)/s)[0]
|
||||
.replaceAll('\r', '')
|
||||
.replaceAll('\t', '')
|
||||
.slice(1, -1)
|
||||
.split(',')
|
||||
.map(el => {
|
||||
const param = el.split(' ');
|
||||
const type = param[2] ? param[2].replace(')', '').split('(') : ['', null];
|
||||
return {
|
||||
name: param[1] ? param[1].replaceAll('`', '') : '',
|
||||
type: type[0].replaceAll('\n', ''),
|
||||
length: +type[1] ? +type[1].replace(/\D/g, '') : '',
|
||||
context: param[0] ? param[0].replace('\n', '') : ''
|
||||
};
|
||||
}).filter(el => el.name);
|
||||
const sql = `SELECT proc.specific_schema AS procedure_schema,
|
||||
proc.specific_name,
|
||||
proc.routine_name AS procedure_name,
|
||||
proc.external_language,
|
||||
args.parameter_name,
|
||||
args.parameter_mode,
|
||||
args.data_type
|
||||
FROM information_schema.routines proc
|
||||
LEFT JOIN information_schema.parameters args
|
||||
ON proc.specific_schema = args.specific_schema
|
||||
AND proc.specific_name = args.specific_name
|
||||
WHERE proc.routine_schema not in ('pg_catalog', 'information_schema')
|
||||
AND proc.routine_type = 'PROCEDURE'
|
||||
AND proc.routine_name = '${routine}'
|
||||
AND proc.specific_schema = '${schema}'
|
||||
ORDER BY procedure_schema,
|
||||
specific_name,
|
||||
procedure_name,
|
||||
args.ordinal_position
|
||||
`;
|
||||
|
||||
let dataAccess = 'CONTAINS SQL';
|
||||
if (row['Create Procedure'].includes('NO SQL'))
|
||||
dataAccess = 'NO SQL';
|
||||
if (row['Create Procedure'].includes('READS SQL DATA'))
|
||||
dataAccess = 'READS SQL DATA';
|
||||
if (row['Create Procedure'].includes('MODIFIES SQL DATA'))
|
||||
dataAccess = 'MODIFIES SQL DATA';
|
||||
const results = await this.raw(sql);
|
||||
|
||||
const parameters = results.rows.map(row => {
|
||||
return {
|
||||
name: row.parameter_name,
|
||||
type: row.data_type.toUpperCase(),
|
||||
length: '',
|
||||
context: row.parameter_mode
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
definer: row['Create Procedure'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0],
|
||||
sql: row['Create Procedure'].match(/(BEGIN|begin)(.*)(END|end)/gs)[0],
|
||||
definer: '',
|
||||
sql: row.pg_get_functiondef.match(/(\$(.*)\$)(.*)(\$(.*)\$)/gs)[0],
|
||||
parameters: parameters || [],
|
||||
name: row.Procedure,
|
||||
comment: row['Create Procedure'].match(/(?<=COMMENT ').*?(?=')/gs) ? row['Create Procedure'].match(/(?<=COMMENT ').*?(?=')/gs)[0] : '',
|
||||
security: row['Create Procedure'].includes('SQL SECURITY INVOKER') ? 'INVOKER' : 'DEFINER',
|
||||
deterministic: row['Create Procedure'].includes('DETERMINISTIC'),
|
||||
dataAccess
|
||||
name: routine,
|
||||
comment: '',
|
||||
security: row.pg_get_functiondef.includes('SECURITY DEFINER') ? 'DEFINER' : 'INVOKER',
|
||||
deterministic: null,
|
||||
dataAccess: null,
|
||||
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0]
|
||||
};
|
||||
})[0];
|
||||
}
|
||||
@@ -637,7 +623,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropRoutine (params) {
|
||||
const sql = `DROP PROCEDURE \`${params.routine}\``;
|
||||
const sql = `DROP PROCEDURE ${this._schema}.${params.routine}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -672,18 +658,18 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
async createRoutine (routine) {
|
||||
const parameters = 'parameters' in routine
|
||||
? routine.parameters.reduce((acc, curr) => {
|
||||
acc.push(`${curr.context} \`${curr.name}\` ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
acc.push(`${curr.context} ${curr.name} ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
return acc;
|
||||
}, []).join(',')
|
||||
: '';
|
||||
|
||||
const sql = `CREATE ${routine.definer ? `DEFINER=${routine.definer} ` : ''}PROCEDURE \`${routine.name}\`(${parameters})
|
||||
if (this._schema !== 'public')
|
||||
this.use(this._schema);
|
||||
|
||||
const sql = `CREATE PROCEDURE ${this._schema}.${routine.name}(${parameters})
|
||||
LANGUAGE SQL
|
||||
${routine.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
|
||||
${routine.dataAccess}
|
||||
SQL SECURITY ${routine.security}
|
||||
COMMENT '${routine.comment}'
|
||||
${routine.sql}`;
|
||||
SECURITY ${routine.security}
|
||||
AS ${routine.sql}`;
|
||||
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
@@ -818,33 +804,33 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} view informations
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async getEventInformations ({ schema, scheduler }) {
|
||||
const sql = `SHOW CREATE EVENT \`${schema}\`.\`${scheduler}\``;
|
||||
const results = await this.raw(sql);
|
||||
// async getEventInformations ({ schema, scheduler }) {
|
||||
// const sql = `SHOW CREATE EVENT \`${schema}\`.\`${scheduler}\``;
|
||||
// const results = await this.raw(sql);
|
||||
|
||||
return results.rows.map(row => {
|
||||
const schedule = row['Create Event'];
|
||||
const execution = schedule.includes('EVERY') ? 'EVERY' : 'ONCE';
|
||||
const every = execution === 'EVERY' ? row['Create Event'].match(/(?<=EVERY )(\s*([^\s]+)){0,2}/gs)[0].replaceAll('\'', '').split(' ') : [];
|
||||
const starts = execution === 'EVERY' && schedule.includes('STARTS') ? schedule.match(/(?<=STARTS ').*?(?='\s)/gs)[0] : '';
|
||||
const ends = execution === 'EVERY' && schedule.includes('ENDS') ? schedule.match(/(?<=ENDS ').*?(?='\s)/gs)[0] : '';
|
||||
const at = execution === 'ONCE' && schedule.includes('AT') ? schedule.match(/(?<=AT ').*?(?='\s)/gs)[0] : '';
|
||||
// return results.rows.map(row => {
|
||||
// const schedule = row['Create Event'];
|
||||
// const execution = schedule.includes('EVERY') ? 'EVERY' : 'ONCE';
|
||||
// const every = execution === 'EVERY' ? row['Create Event'].match(/(?<=EVERY )(\s*([^\s]+)){0,2}/gs)[0].replaceAll('\'', '').split(' ') : [];
|
||||
// const starts = execution === 'EVERY' && schedule.includes('STARTS') ? schedule.match(/(?<=STARTS ').*?(?='\s)/gs)[0] : '';
|
||||
// const ends = execution === 'EVERY' && schedule.includes('ENDS') ? schedule.match(/(?<=ENDS ').*?(?='\s)/gs)[0] : '';
|
||||
// const at = execution === 'ONCE' && schedule.includes('AT') ? schedule.match(/(?<=AT ').*?(?='\s)/gs)[0] : '';
|
||||
|
||||
return {
|
||||
definer: row['Create Event'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0],
|
||||
sql: row['Create Event'].match(/(?<=DO )(.*)/gs)[0],
|
||||
name: row.Event,
|
||||
comment: row['Create Event'].match(/(?<=COMMENT ').*?(?=')/gs) ? row['Create Event'].match(/(?<=COMMENT ').*?(?=')/gs)[0] : '',
|
||||
state: row['Create Event'].includes('ENABLE') ? 'ENABLE' : row['Create Event'].includes('DISABLE ON SLAVE') ? 'DISABLE ON SLAVE' : 'DISABLE',
|
||||
preserve: row['Create Event'].includes('ON COMPLETION PRESERVE'),
|
||||
execution,
|
||||
every,
|
||||
starts,
|
||||
ends,
|
||||
at
|
||||
};
|
||||
})[0];
|
||||
}
|
||||
// return {
|
||||
// definer: row['Create Event'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0],
|
||||
// sql: row['Create Event'].match(/(?<=DO )(.*)/gs)[0],
|
||||
// name: row.Event,
|
||||
// comment: row['Create Event'].match(/(?<=COMMENT ').*?(?=')/gs) ? row['Create Event'].match(/(?<=COMMENT ').*?(?=')/gs)[0] : '',
|
||||
// state: row['Create Event'].includes('ENABLE') ? 'ENABLE' : row['Create Event'].includes('DISABLE ON SLAVE') ? 'DISABLE ON SLAVE' : 'DISABLE',
|
||||
// preserve: row['Create Event'].includes('ON COMPLETION PRESERVE'),
|
||||
// execution,
|
||||
// every,
|
||||
// starts,
|
||||
// ends,
|
||||
// at
|
||||
// };
|
||||
// })[0];
|
||||
// }
|
||||
|
||||
/**
|
||||
* DROP EVENT
|
||||
@@ -852,10 +838,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropEvent (params) {
|
||||
const sql = `DROP EVENT \`${params.scheduler}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
// async dropEvent (params) {
|
||||
// const sql = `DROP EVENT \`${params.scheduler}\``;
|
||||
// return await this.raw(sql);
|
||||
// }
|
||||
|
||||
/**
|
||||
* ALTER EVENT
|
||||
@@ -863,25 +849,25 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async alterEvent (params) {
|
||||
const { scheduler } = params;
|
||||
// async alterEvent (params) {
|
||||
// const { scheduler } = params;
|
||||
|
||||
if (scheduler.execution === 'EVERY' && scheduler.every[0].includes('-'))
|
||||
scheduler.every[0] = `'${scheduler.every[0]}'`;
|
||||
// if (scheduler.execution === 'EVERY' && scheduler.every[0].includes('-'))
|
||||
// scheduler.every[0] = `'${scheduler.every[0]}'`;
|
||||
|
||||
const sql = `ALTER ${scheduler.definer ? ` DEFINER=${scheduler.definer}` : ''} EVENT \`${scheduler.oldName}\`
|
||||
ON SCHEDULE
|
||||
${scheduler.execution === 'EVERY'
|
||||
? `EVERY ${scheduler.every.join(' ')}${scheduler.starts ? ` STARTS '${scheduler.starts}'` : ''}${scheduler.ends ? ` ENDS '${scheduler.ends}'` : ''}`
|
||||
: `AT '${scheduler.at}'`}
|
||||
ON COMPLETION${!scheduler.preserve ? ' NOT' : ''} PRESERVE
|
||||
${scheduler.name !== scheduler.oldName ? `RENAME TO \`${scheduler.name}\`` : ''}
|
||||
${scheduler.state}
|
||||
COMMENT '${scheduler.comment}'
|
||||
DO ${scheduler.sql}`;
|
||||
// const sql = `ALTER ${scheduler.definer ? ` DEFINER=${scheduler.definer}` : ''} EVENT \`${scheduler.oldName}\`
|
||||
// ON SCHEDULE
|
||||
// ${scheduler.execution === 'EVERY'
|
||||
// ? `EVERY ${scheduler.every.join(' ')}${scheduler.starts ? ` STARTS '${scheduler.starts}'` : ''}${scheduler.ends ? ` ENDS '${scheduler.ends}'` : ''}`
|
||||
// : `AT '${scheduler.at}'`}
|
||||
// ON COMPLETION${!scheduler.preserve ? ' NOT' : ''} PRESERVE
|
||||
// ${scheduler.name !== scheduler.oldName ? `RENAME TO \`${scheduler.name}\`` : ''}
|
||||
// ${scheduler.state}
|
||||
// COMMENT '${scheduler.comment}'
|
||||
// DO ${scheduler.sql}`;
|
||||
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
// return await this.raw(sql, { split: false });
|
||||
// }
|
||||
|
||||
/**
|
||||
* CREATE EVENT
|
||||
@@ -889,19 +875,19 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async createEvent (scheduler) {
|
||||
const sql = `CREATE ${scheduler.definer ? ` DEFINER=${scheduler.definer}` : ''} EVENT \`${scheduler.name}\`
|
||||
ON SCHEDULE
|
||||
${scheduler.execution === 'EVERY'
|
||||
? `EVERY ${scheduler.every.join(' ')}${scheduler.starts ? ` STARTS '${scheduler.starts}'` : ''}${scheduler.ends ? ` ENDS '${scheduler.ends}'` : ''}`
|
||||
: `AT '${scheduler.at}'`}
|
||||
ON COMPLETION${!scheduler.preserve ? ' NOT' : ''} PRESERVE
|
||||
${scheduler.state}
|
||||
COMMENT '${scheduler.comment}'
|
||||
DO ${scheduler.sql}`;
|
||||
// async createEvent (scheduler) {
|
||||
// const sql = `CREATE ${scheduler.definer ? ` DEFINER=${scheduler.definer}` : ''} EVENT \`${scheduler.name}\`
|
||||
// ON SCHEDULE
|
||||
// ${scheduler.execution === 'EVERY'
|
||||
// ? `EVERY ${scheduler.every.join(' ')}${scheduler.starts ? ` STARTS '${scheduler.starts}'` : ''}${scheduler.ends ? ` ENDS '${scheduler.ends}'` : ''}`
|
||||
// : `AT '${scheduler.at}'`}
|
||||
// ON COMPLETION${!scheduler.preserve ? ' NOT' : ''} PRESERVE
|
||||
// ${scheduler.state}
|
||||
// COMMENT '${scheduler.comment}'
|
||||
// DO ${scheduler.sql}`;
|
||||
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
// return await this.raw(sql, { split: false });
|
||||
// }
|
||||
|
||||
/**
|
||||
* SELECT * FROM pg_collation
|
||||
@@ -992,13 +978,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
*/
|
||||
async createTable (params) {
|
||||
const {
|
||||
name,
|
||||
collation,
|
||||
comment,
|
||||
engine
|
||||
name
|
||||
} = params;
|
||||
|
||||
const sql = `CREATE TABLE \`${name}\` (\`${name}_ID\` INT NULL) COMMENT='${comment}', COLLATE='${collation}', ENGINE=${engine}`;
|
||||
const sql = `CREATE TABLE ${this._schema}.${name} (${name}_id INTEGER NULL); ALTER TABLE ${this._schema}.${name} DROP COLUMN ${name}_id`;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -1020,8 +1003,11 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
options
|
||||
} = params;
|
||||
|
||||
let sql = `ALTER TABLE \`${table}\` `;
|
||||
let sql = '';
|
||||
const alterColumns = [];
|
||||
const renameColumns = [];
|
||||
const createSequences = [];
|
||||
const manageIndexes = [];
|
||||
|
||||
// OPTIONS
|
||||
if ('comment' in options) alterColumns.push(`COMMENT='${options.comment}'`);
|
||||
@@ -1034,8 +1020,8 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
const typeInfo = this._getTypeInfo(addition.type);
|
||||
const length = typeInfo.length ? addition.numLength || addition.charLength || addition.datePrecision : false;
|
||||
|
||||
alterColumns.push(`ADD COLUMN \`${addition.name}\`
|
||||
${addition.type.toUpperCase()}${length ? `(${length})` : ''}
|
||||
alterColumns.push(`ADD COLUMN ${addition.name}
|
||||
${addition.type.toUpperCase()}${length ? `(${length})` : ''}${addition.isArray ? '[]' : ''}
|
||||
${addition.unsigned ? 'UNSIGNED' : ''}
|
||||
${addition.zerofill ? 'ZEROFILL' : ''}
|
||||
${addition.nullable ? 'NULL' : 'NOT NULL'}
|
||||
@@ -1043,96 +1029,111 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
${addition.default ? `DEFAULT ${addition.default}` : ''}
|
||||
${addition.comment ? `COMMENT '${addition.comment}'` : ''}
|
||||
${addition.collation ? `COLLATE ${addition.collation}` : ''}
|
||||
${addition.onUpdate ? `ON UPDATE ${addition.onUpdate}` : ''}
|
||||
${addition.after ? `AFTER \`${addition.after}\`` : 'FIRST'}`);
|
||||
${addition.onUpdate ? `ON UPDATE ${addition.onUpdate}` : ''}`);
|
||||
});
|
||||
|
||||
// ADD INDEX
|
||||
indexChanges.additions.forEach(addition => {
|
||||
const fields = addition.fields.map(field => `\`${field}\``).join(',');
|
||||
let type = addition.type;
|
||||
const fields = addition.fields.map(field => `${field}`).join(',');
|
||||
const type = addition.type;
|
||||
|
||||
if (type === 'PRIMARY')
|
||||
alterColumns.push(`ADD PRIMARY KEY (${fields})`);
|
||||
else {
|
||||
if (type === 'UNIQUE')
|
||||
type = 'UNIQUE INDEX';
|
||||
|
||||
alterColumns.push(`ADD ${type} \`${addition.name}\` (${fields})`);
|
||||
}
|
||||
else if (type === 'UNIQUE')
|
||||
alterColumns.push(`ADD CONSTRAINT ${addition.name} UNIQUE (${fields})`);
|
||||
else
|
||||
manageIndexes.push(`CREATE INDEX ${addition.name} ON ${table}(${fields})`);
|
||||
});
|
||||
|
||||
// ADD FOREIGN KEYS
|
||||
foreignChanges.additions.forEach(addition => {
|
||||
alterColumns.push(`ADD CONSTRAINT \`${addition.constraintName}\` FOREIGN KEY (\`${addition.field}\`) REFERENCES \`${addition.refTable}\` (\`${addition.refField}\`) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`);
|
||||
alterColumns.push(`ADD CONSTRAINT ${addition.constraintName} FOREIGN KEY (${addition.field}) REFERENCES ${addition.refTable} (${addition.refField}) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`);
|
||||
});
|
||||
|
||||
// CHANGE FIELDS
|
||||
changes.forEach(change => {
|
||||
const typeInfo = this._getTypeInfo(change.type);
|
||||
const length = typeInfo.length ? change.numLength || change.charLength || change.datePrecision : false;
|
||||
let localType;
|
||||
|
||||
alterColumns.push(`CHANGE COLUMN \`${change.orgName}\` \`${change.name}\`
|
||||
${change.type.toUpperCase()}${length ? `(${length})` : ''}
|
||||
${change.unsigned ? 'UNSIGNED' : ''}
|
||||
${change.zerofill ? 'ZEROFILL' : ''}
|
||||
${change.nullable ? 'NULL' : 'NOT NULL'}
|
||||
${change.autoIncrement ? 'AUTO_INCREMENT' : ''}
|
||||
${change.default ? `DEFAULT ${change.default}` : ''}
|
||||
${change.comment ? `COMMENT '${change.comment}'` : ''}
|
||||
${change.collation ? `COLLATE ${change.collation}` : ''}
|
||||
${change.onUpdate ? `ON UPDATE ${change.onUpdate}` : ''}
|
||||
${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`);
|
||||
switch (change.type) {
|
||||
case 'SERIAL':
|
||||
localType = 'integer';
|
||||
break;
|
||||
case 'SMALLSERIAL':
|
||||
localType = 'smallint';
|
||||
break;
|
||||
case 'BIGSERIAL':
|
||||
localType = 'bigint';
|
||||
break;
|
||||
default:
|
||||
localType = change.type.toLowerCase();
|
||||
}
|
||||
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" TYPE ${localType}${length ? `(${length})` : ''}${change.isArray ? '[]' : ''} USING "${change.orgName}"::${localType}`);
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" ${change.nullable ? 'DROP NOT NULL' : 'SET NOT NULL'}`);
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" ${change.default ? `SET DEFAULT ${change.default}` : 'DROP DEFAULT'}`);
|
||||
if (['SERIAL', 'SMALLSERIAL', 'BIGSERIAL'].includes(change.type)) {
|
||||
const sequenceName = `${table}_${change.name}_seq`.replace(' ', '_');
|
||||
createSequences.push(`CREATE SEQUENCE IF NOT EXISTS ${sequenceName} OWNED BY "${table}"."${change.orgName}"`);
|
||||
alterColumns.push(`ALTER COLUMN "${change.orgName}" SET DEFAULT nextval('${sequenceName}')`);
|
||||
}
|
||||
|
||||
if (change.orgName !== change.name)
|
||||
renameColumns.push(`ALTER TABLE "${this._schema}"."${table}" RENAME COLUMN "${change.orgName}" TO "${change.name}"`);
|
||||
});
|
||||
|
||||
// CHANGE INDEX
|
||||
indexChanges.changes.forEach(change => {
|
||||
if (change.oldType === 'PRIMARY')
|
||||
alterColumns.push('DROP PRIMARY KEY');
|
||||
else if (change.oldType === 'UNIQUE')
|
||||
alterColumns.push(`DROP CONSTRAINT ${change.oldName}`);
|
||||
else
|
||||
alterColumns.push(`DROP INDEX \`${change.oldName}\``);
|
||||
manageIndexes.push(`DROP INDEX ${change.oldName}`);
|
||||
|
||||
const fields = change.fields.map(field => `\`${field}\``).join(',');
|
||||
let type = change.type;
|
||||
const fields = change.fields.map(field => `${field}`).join(',');
|
||||
const type = change.type;
|
||||
|
||||
if (type === 'PRIMARY')
|
||||
alterColumns.push(`ADD PRIMARY KEY (${fields})`);
|
||||
else {
|
||||
if (type === 'UNIQUE')
|
||||
type = 'UNIQUE INDEX';
|
||||
|
||||
alterColumns.push(`ADD ${type} \`${change.name}\` (${fields})`);
|
||||
}
|
||||
else if (type === 'UNIQUE')
|
||||
alterColumns.push(`ADD CONSTRAINT ${change.name} UNIQUE (${fields})`);
|
||||
else
|
||||
manageIndexes.push(`CREATE INDEX ${change.name} ON ${table}(${fields})`);
|
||||
});
|
||||
|
||||
// CHANGE FOREIGN KEYS
|
||||
foreignChanges.changes.forEach(change => {
|
||||
alterColumns.push(`DROP FOREIGN KEY \`${change.oldName}\``);
|
||||
alterColumns.push(`ADD CONSTRAINT \`${change.constraintName}\` FOREIGN KEY (\`${change.field}\`) REFERENCES \`${change.refTable}\` (\`${change.refField}\`) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`);
|
||||
alterColumns.push(`DROP CONSTRAINT ${change.oldName}`);
|
||||
alterColumns.push(`ADD CONSTRAINT ${change.constraintName} FOREIGN KEY (${change.field}) REFERENCES ${change.refTable} (${change.refField}) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`);
|
||||
});
|
||||
|
||||
// DROP FIELDS
|
||||
deletions.forEach(deletion => {
|
||||
alterColumns.push(`DROP COLUMN \`${deletion.name}\``);
|
||||
alterColumns.push(`DROP COLUMN ${deletion.name}`);
|
||||
});
|
||||
|
||||
// DROP INDEX
|
||||
indexChanges.deletions.forEach(deletion => {
|
||||
if (deletion.type === 'PRIMARY')
|
||||
alterColumns.push('DROP PRIMARY KEY');
|
||||
if (['PRIMARY', 'UNIQUE'].includes(deletion.type))
|
||||
alterColumns.push(`DROP CONSTRAINT ${deletion.name}`);
|
||||
else
|
||||
alterColumns.push(`DROP INDEX \`${deletion.name}\``);
|
||||
manageIndexes.push(`DROP INDEX ${deletion.name}`);
|
||||
});
|
||||
|
||||
// DROP FOREIGN KEYS
|
||||
foreignChanges.deletions.forEach(deletion => {
|
||||
alterColumns.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``);
|
||||
alterColumns.push(`DROP CONSTRAINT ${deletion.constraintName}`);
|
||||
});
|
||||
|
||||
sql += alterColumns.join(', ');
|
||||
if (alterColumns.length) sql += `ALTER TABLE "${this._schema}"."${table}" ${alterColumns.join(', ')}; `;
|
||||
|
||||
// RENAME
|
||||
if (options.name) sql += `; RENAME TABLE \`${table}\` TO \`${options.name}\``;
|
||||
if (renameColumns.length) sql += `${renameColumns.join(';')}; `;
|
||||
if (createSequences.length) sql = `${createSequences.join(';')}; ${sql}`;
|
||||
if (manageIndexes.length) sql = `${manageIndexes.join(';')}; ${sql}`;
|
||||
if (options.name) sql += `ALTER TABLE "${this._schema}"."${table}" RENAME TO "${options.name}"; `;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -1144,7 +1145,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async truncateTable (params) {
|
||||
const sql = `TRUNCATE TABLE ${params.table}`;
|
||||
const sql = `TRUNCATE TABLE ${this._schema}.${params.table}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1155,7 +1156,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropTable (params) {
|
||||
const sql = `DROP TABLE ${params.table}`;
|
||||
const sql = `DROP TABLE ${this._schema}.${params.table}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1229,6 +1230,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
split: true,
|
||||
...args
|
||||
};
|
||||
|
||||
if (args.nest && this._schema !== 'public')
|
||||
this.use(this._schema);
|
||||
|
||||
const resultsArr = [];
|
||||
let paramsArr = [];
|
||||
const queries = args.split ? sql.split(';') : [sql];
|
||||
@@ -1318,7 +1323,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
if (!paramObj.table || !paramObj.schema) continue;
|
||||
|
||||
try { // Column details
|
||||
const columns = await this.getTableColumns(paramObj);
|
||||
const columns = await this.getTableColumns(paramObj, false);
|
||||
const indexes = await this.getTableIndexes(paramObj);
|
||||
|
||||
remappedFields = remappedFields.map(field => {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="wrapper">
|
||||
<div id="wrapper" :class="`theme-${applicationTheme}`">
|
||||
<TheTitleBar />
|
||||
<div id="window-content">
|
||||
<TheSettingBar />
|
||||
@@ -16,6 +16,7 @@
|
||||
<TheFooter />
|
||||
<TheNotificationsBoard />
|
||||
<ModalNewConnection v-if="isNewConnModal" />
|
||||
<TheScratchpad v-if="isScratchpad" />
|
||||
<ModalSettings v-if="isSettingModal" />
|
||||
<ModalDiscardChanges v-if="isUnsavedDiscardModal" />
|
||||
</div>
|
||||
@@ -37,6 +38,7 @@ export default {
|
||||
Workspace: () => import(/* webpackChunkName: "Workspace" */'@/components/Workspace'),
|
||||
ModalNewConnection: () => import(/* webpackChunkName: "ModalNewConnection" */'@/components/ModalNewConnection'),
|
||||
ModalSettings: () => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings'),
|
||||
TheScratchpad: () => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad'),
|
||||
ModalDiscardChanges: () => import(/* webpackChunkName: "ModalDiscardChanges" */'@/components/ModalDiscardChanges')
|
||||
},
|
||||
data () {
|
||||
@@ -48,12 +50,15 @@ export default {
|
||||
isNewConnModal: 'application/isNewModal',
|
||||
isEditModal: 'application/isEditModal',
|
||||
isSettingModal: 'application/isSettingModal',
|
||||
isScratchpad: 'application/isScratchpad',
|
||||
connections: 'connections/getConnections',
|
||||
applicationTheme: 'settings/getApplicationTheme',
|
||||
isUnsavedDiscardModal: 'workspaces/isUnsavedDiscardModal'
|
||||
})
|
||||
},
|
||||
mounted () {
|
||||
ipcRenderer.send('check-for-updates');
|
||||
this.checkVersionUpdate();
|
||||
|
||||
const Menu = remote.Menu;
|
||||
|
||||
@@ -96,7 +101,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
showNewConnModal: 'application/showNewConnModal'
|
||||
showNewConnModal: 'application/showNewConnModal',
|
||||
checkVersionUpdate: 'application/checkVersionUpdate'
|
||||
})
|
||||
}
|
||||
};
|
||||
|
@@ -71,7 +71,6 @@ export default {
|
||||
<style lang="scss">
|
||||
.context {
|
||||
display: flex;
|
||||
color: $body-font-color;
|
||||
font-size: 16px;
|
||||
z-index: 400;
|
||||
justify-content: center;
|
||||
@@ -87,7 +86,6 @@ export default {
|
||||
.context-container {
|
||||
min-width: 100px;
|
||||
z-index: 10;
|
||||
box-shadow: 0 0 2px 0 #000;
|
||||
padding: 0;
|
||||
background: #1d1d1d;
|
||||
border-radius: 0.1rem;
|
||||
@@ -111,14 +109,10 @@ export default {
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
top: 0;
|
||||
background: #1d1d1d;
|
||||
box-shadow: 0 0 2px 0 #000;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $primary-color;
|
||||
|
||||
.context-submenu {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
|
@@ -22,6 +22,7 @@ export default {
|
||||
editorClass: { type: String, default: '' },
|
||||
autoFocus: { type: Boolean, default: false },
|
||||
readOnly: { type: Boolean, default: false },
|
||||
showLineNumbers: { type: Boolean, default: true },
|
||||
height: { type: Number, default: 200 }
|
||||
},
|
||||
data () {
|
||||
@@ -68,10 +69,12 @@ export default {
|
||||
this.editor = ace.edit(`editor-${this.id}`, {
|
||||
mode: `ace/mode/${this.mode}`,
|
||||
theme: `ace/theme/${this.editorTheme}`,
|
||||
value: this.value,
|
||||
value: this.value || '',
|
||||
fontSize: '14px',
|
||||
printMargin: false,
|
||||
readOnly: this.readOnly
|
||||
readOnly: this.readOnly,
|
||||
showLineNumbers: this.showLineNumbers,
|
||||
showGutter: this.showLineNumbers
|
||||
});
|
||||
|
||||
this.editor.setOptions({
|
||||
@@ -102,8 +105,6 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.editor-wrapper {
|
||||
border-bottom: 1px solid #444;
|
||||
|
||||
.editor {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -113,17 +114,4 @@ export default {
|
||||
display: inline-block;
|
||||
width: 17px;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {
|
||||
background-color: #c9561a99;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_line-hover {
|
||||
background-color: #c9571a33;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_completion-highlight {
|
||||
color: #e0d00c;
|
||||
}
|
||||
</style>
|
||||
|
@@ -63,13 +63,11 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.file-uploader {
|
||||
border: 0.05rem solid $bg-color-light;
|
||||
border-radius: 0.1rem;
|
||||
height: 1.8rem;
|
||||
line-height: 1.2rem;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
background-color: $bg-color-gray;
|
||||
transition: background 0.2s, border 0.2s, box-shadow 0.2s, color 0.2s;
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
@@ -80,8 +78,6 @@ export default {
|
||||
|
||||
.file-uploader-message {
|
||||
display: flex;
|
||||
border-right: 0.05rem solid $bg-color-light;
|
||||
background-color: $bg-color;
|
||||
}
|
||||
|
||||
.file-uploader-input {
|
||||
@@ -105,7 +101,6 @@ export default {
|
||||
:disabled {
|
||||
.file-uploader {
|
||||
cursor: not-allowed;
|
||||
background-color: #151515;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ export default {
|
||||
}),
|
||||
isValidDefault () {
|
||||
if (!this.foreignList.length) return true;
|
||||
return this.foreignList.some(foreign => foreign.foreign_column.toString() === this.value.toString());
|
||||
return this.value === null || this.foreignList.some(foreign => foreign.foreign_column.toString() === this.value.toString());
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
|
@@ -43,6 +43,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { NUMBER, FLOAT } from 'common/fieldTypes';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
|
||||
export default {
|
||||
@@ -57,7 +58,8 @@ export default {
|
||||
}
|
||||
},
|
||||
props: {
|
||||
localRoutine: Object
|
||||
localRoutine: Object,
|
||||
client: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -82,7 +84,22 @@ export default {
|
||||
},
|
||||
runRoutine () {
|
||||
const valArr = Object.keys(this.values).reduce((acc, curr) => {
|
||||
const value = isNaN(this.values[curr]) ? `"${this.values[curr]}"` : this.values[curr];
|
||||
let qc;
|
||||
switch (this.client) {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
qc = '"';
|
||||
break;
|
||||
case 'pg':
|
||||
qc = '\'';
|
||||
break;
|
||||
default:
|
||||
qc = '"';
|
||||
}
|
||||
|
||||
const param = this.localRoutine.parameters.find(param => param.name === curr);
|
||||
|
||||
const value = [...NUMBER, ...FLOAT].includes(param.type) ? this.values[curr] : `${qc}${this.values[curr]}${qc}`;
|
||||
acc.push(value);
|
||||
return acc;
|
||||
}, []);
|
||||
|
@@ -25,7 +25,7 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.definer" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
@@ -53,7 +53,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.comment" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.comment') }}
|
||||
</label>
|
||||
@@ -76,7 +76,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.comment" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('message.dataAccess') }}
|
||||
</label>
|
||||
@@ -89,7 +89,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.procedureDeterministic" class="form-group">
|
||||
<div class="col-4" />
|
||||
<div class="column">
|
||||
<label class="form-checkbox form-inline">
|
||||
@@ -117,7 +117,7 @@ export default {
|
||||
return {
|
||||
localRoutine: {
|
||||
definer: '',
|
||||
sql: 'BEGIN\r\n\r\nEND',
|
||||
sql: '',
|
||||
parameters: [],
|
||||
name: '',
|
||||
comment: '',
|
||||
@@ -131,9 +131,14 @@ export default {
|
||||
computed: {
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.customizations.procedureSql)
|
||||
this.localRoutine.sql = this.customizations.procedureSql;
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
|
@@ -25,7 +25,7 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.comment" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.comment') }}
|
||||
</label>
|
||||
@@ -37,7 +37,7 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.collations" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.collation') }}
|
||||
</label>
|
||||
@@ -53,7 +53,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.engines" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.engine') }}
|
||||
</label>
|
||||
@@ -103,10 +103,14 @@ export default {
|
||||
getDatabaseVariable: 'workspaces/getDatabaseVariable'
|
||||
}),
|
||||
defaultCollation () {
|
||||
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value || '';
|
||||
if (this.workspace.customizations.collations)
|
||||
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value || '';
|
||||
return '';
|
||||
},
|
||||
defaultEngine () {
|
||||
return this.workspace.engines.find(engine => engine.isDefault).name;
|
||||
if (this.workspace.customizations.engines)
|
||||
return this.workspace.engines.find(engine => engine.isDefault).name;
|
||||
return '';
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-6">
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.definer" class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select v-model="localView.definer" class="form-select">
|
||||
<option value="">
|
||||
@@ -44,7 +44,7 @@
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column col-4">
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.viewSqlSecurity" class="form-group">
|
||||
<label class="form-label">{{ $t('message.sqlSecurity') }}</label>
|
||||
<label class="form-radio">
|
||||
<input
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-4">
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.viewAlgorithm" class="form-group">
|
||||
<label class="form-label">{{ $t('word.algorithm') }}</label>
|
||||
<label class="form-radio">
|
||||
<input
|
||||
@@ -99,7 +99,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-4">
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.viewUpdateOption" class="form-group">
|
||||
<label class="form-label">{{ $t('message.updateOption') }}</label>
|
||||
<label class="form-radio">
|
||||
<input
|
||||
|
@@ -30,12 +30,21 @@
|
||||
<a class="c-hand">{{ $t('word.themes') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="updateStatus !== 'disabled'"
|
||||
class="tab-item"
|
||||
:class="{'active': selectedTab === 'update'}"
|
||||
@click="selectTab('update')"
|
||||
>
|
||||
<a class="c-hand" :class="{'badge badge-update': hasUpdates}">{{ $t('word.update') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="updateStatus !== 'disabled'"
|
||||
class="tab-item"
|
||||
:class="{'active': selectedTab === 'changelog'}"
|
||||
@click="selectTab('changelog')"
|
||||
>
|
||||
<a class="c-hand">{{ $t('word.changelog') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item"
|
||||
:class="{'active': selectedTab === 'about'}"
|
||||
@@ -45,7 +54,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'general'" class="panel-body py-4">
|
||||
<div v-show="selectedTab === 'general'" class="panel-body py-4">
|
||||
<div class="container">
|
||||
<form class="form-horizontal columns">
|
||||
<div class="column col-12 h6 text-uppercase mb-1">
|
||||
@@ -133,26 +142,35 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedTab === 'themes'" class="panel-body py-4">
|
||||
<div v-show="selectedTab === 'themes'" class="panel-body py-4">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column col-12 h6 text-uppercase mb-2">
|
||||
{{ $t('message.applicationTheme') }}
|
||||
</div>
|
||||
<div class="column col-6 c-hand theme-block" :class="{'selected': applicationTheme === 'dark'}">
|
||||
<div
|
||||
class="column col-6 c-hand theme-block"
|
||||
:class="{'selected': applicationTheme === 'dark'}"
|
||||
@click="changeApplicationTheme('dark')"
|
||||
>
|
||||
<img :src="require('@/images/dark.png').default" class="img-responsive img-fit-cover s-rounded">
|
||||
<div class="theme-name">
|
||||
<div class="theme-name text-light">
|
||||
<i class="mdi mdi-moon-waning-crescent mdi-48px" />
|
||||
<div class="h6 mt-4">
|
||||
{{ $t('word.dark') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-6 theme-block disabled" :class="{'selected': applicationTheme === 'light'}">
|
||||
<div class="theme-name">
|
||||
<div
|
||||
class="column col-6 c-hand theme-block"
|
||||
:class="{'selected': applicationTheme === 'light'}"
|
||||
@click="changeApplicationTheme('light')"
|
||||
>
|
||||
<img :src="require('@/images/light.png').default" class="img-responsive img-fit-cover s-rounded">
|
||||
<div class="theme-name text-dark">
|
||||
<i class="mdi mdi-white-balance-sunny mdi-48px" />
|
||||
<div class="h6 mt-4">
|
||||
{{ $t('word.light') }} (Coming)
|
||||
{{ $t('word.light') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -185,8 +203,9 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="column col-12">
|
||||
<QueryEditor
|
||||
<BaseTextEditor
|
||||
:value="exampleQuery"
|
||||
mode="sql"
|
||||
:workspace="workspace"
|
||||
:read-only="true"
|
||||
:height="270"
|
||||
@@ -196,11 +215,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedTab === 'update'" class="panel-body py-4">
|
||||
<div v-show="selectedTab === 'update'" class="panel-body py-4">
|
||||
<ModalSettingsUpdate />
|
||||
</div>
|
||||
<div v-show="selectedTab === 'changelog'" class="panel-body py-4">
|
||||
<ModalSettingsChangelog />
|
||||
</div>
|
||||
|
||||
<div v-if="selectedTab === 'about'" class="panel-body py-4">
|
||||
<div v-show="selectedTab === 'about'" class="panel-body py-4">
|
||||
<div class="text-center">
|
||||
<img :src="require('@/images/logo.svg').default" width="128">
|
||||
<h4>{{ appName }}</h4>
|
||||
@@ -222,14 +244,16 @@
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import localesNames from '@/i18n/supported-locales';
|
||||
import ModalSettingsUpdate from '@/components/ModalSettingsUpdate';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import ModalSettingsChangelog from '@/components/ModalSettingsChangelog';
|
||||
import BaseTextEditor from '@/components/BaseTextEditor';
|
||||
const { shell } = require('electron');
|
||||
|
||||
export default {
|
||||
name: 'ModalSettings',
|
||||
components: {
|
||||
ModalSettingsUpdate,
|
||||
QueryEditor
|
||||
ModalSettingsChangelog,
|
||||
BaseTextEditor
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -350,6 +374,7 @@ ORDER BY
|
||||
changeLocale: 'settings/changeLocale',
|
||||
changeAutoComplete: 'settings/changeAutoComplete',
|
||||
changeLineWrap: 'settings/changeLineWrap',
|
||||
changeApplicationTheme: 'settings/changeApplicationTheme',
|
||||
changeEditorTheme: 'settings/changeEditorTheme',
|
||||
updateNotificationsTimeout: 'settings/updateNotificationsTimeout'
|
||||
}),
|
||||
@@ -382,54 +407,58 @@ ORDER BY
|
||||
|
||||
<style lang="scss">
|
||||
#settings {
|
||||
.modal-body {
|
||||
overflow: hidden;
|
||||
.modal-container {
|
||||
position: absolute;
|
||||
top: 17.5vh;
|
||||
|
||||
.panel-body {
|
||||
height: calc(70vh - 70px);
|
||||
overflow: auto;
|
||||
.modal-body {
|
||||
overflow: hidden;
|
||||
|
||||
.theme-block {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
.panel-body {
|
||||
min-height: calc(25vh - 70px);
|
||||
overflow: auto;
|
||||
|
||||
&.selected {
|
||||
img {
|
||||
box-shadow: 0 0 0 3px $primary-color;
|
||||
.theme-block {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
&.selected {
|
||||
img {
|
||||
box-shadow: 0 0 0 3px $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.theme-name {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.theme-name {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
text-shadow: 0 0 8px #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.badge::after {
|
||||
background: #32b643;
|
||||
}
|
||||
.badge::after {
|
||||
background: #32b643;
|
||||
}
|
||||
|
||||
.badge-update::after {
|
||||
bottom: initial;
|
||||
background: $primary-color;
|
||||
}
|
||||
.badge-update::after {
|
||||
bottom: initial;
|
||||
background: $primary-color;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
78
src/renderer/components/ModalSettingsChangelog.vue
Normal file
78
src/renderer/components/ModalSettingsChangelog.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="p-relative">
|
||||
<BaseLoader v-if="isLoading" />
|
||||
<div
|
||||
id="changelog"
|
||||
class="container"
|
||||
v-html="changelog"
|
||||
/>
|
||||
<div v-if="isError" class="empty">
|
||||
<div class="empty-icon">
|
||||
<i class="mdi mdi-48px mdi-alert-outline" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import marked from 'marked';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
|
||||
export default {
|
||||
name: 'ModalSettingsChangelog',
|
||||
components: {
|
||||
BaseLoader
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
changelog: '',
|
||||
isLoading: true,
|
||||
error: '',
|
||||
isError: false
|
||||
};
|
||||
},
|
||||
created () {
|
||||
this.getChangelog();
|
||||
},
|
||||
methods: {
|
||||
async getChangelog () {
|
||||
try {
|
||||
const apiRes = await fetch('https://api.github.com/repos/Fabio286/antares/releases/latest', {
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
const { body } = await apiRes.json();
|
||||
const markdown = body.substr(0, body.indexOf('### Download'));
|
||||
const renderer = {
|
||||
link (href, title, text) {
|
||||
return text;
|
||||
},
|
||||
listitem (text) {
|
||||
return `<li>${text.replace(/ *\([^)]*\) */g, '')}</li>`;
|
||||
}
|
||||
};
|
||||
|
||||
marked.use({ renderer });
|
||||
|
||||
this.changelog = marked(markdown);
|
||||
}
|
||||
catch (err) {
|
||||
this.error = err.message;
|
||||
this.isError = true;
|
||||
}
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
#changelog {
|
||||
h3 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -92,9 +92,3 @@ export default {
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.empty {
|
||||
color: $body-font-color;
|
||||
}
|
||||
</style>
|
||||
|
@@ -312,19 +312,6 @@ export default {
|
||||
width: 17px;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {
|
||||
background-color: #c9561a99;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_line-hover {
|
||||
background-color: #c9571a33;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_completion-highlight {
|
||||
color: #e0d00c;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_breakpoint {
|
||||
&::before {
|
||||
content: '\F0403';
|
||||
|
@@ -64,13 +64,11 @@ export default {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: $primary-color;
|
||||
padding: 0 0.2rem;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
|
||||
.footer-elements {
|
||||
list-style: none;
|
||||
@@ -88,10 +86,6 @@ export default {
|
||||
&.footer-link {
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: rgba($color: #fff, $alpha: 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
75
src/renderer/components/TheScratchpad.vue
Normal file
75
src/renderer/components/TheScratchpad.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<ConfirmModal
|
||||
:confirm-text="$t('word.update')"
|
||||
:cancel-text="$t('word.close')"
|
||||
size="large"
|
||||
:hide-footer="true"
|
||||
@hide="hideScratchpad"
|
||||
>
|
||||
<template :slot="'header'">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-notebook-edit-outline mr-1" /> {{ $t('word.scratchpad') }}
|
||||
</div>
|
||||
</template>
|
||||
<div :slot="'body'">
|
||||
<div>
|
||||
<div>
|
||||
<TextEditor
|
||||
:value.sync="localNotes"
|
||||
editor-class="textarea-editor"
|
||||
mode="markdown"
|
||||
:auto-focus="true"
|
||||
:show-line-numbers="false"
|
||||
/>
|
||||
</div>
|
||||
<small class="text-gray">{{ $t('message.markdownSupported') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</ConfirmModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import TextEditor from '@/components/BaseTextEditor';
|
||||
|
||||
export default {
|
||||
name: 'TheScratchpad',
|
||||
components: {
|
||||
ConfirmModal,
|
||||
TextEditor
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localNotes: '',
|
||||
debounceTimeout: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
notes: 'scratchpad/getNotes'
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
localNotes () {
|
||||
clearTimeout(this.debounceTimeout);
|
||||
|
||||
this.debounceTimeout = setTimeout(() => {
|
||||
this.changeNotes(this.localNotes);
|
||||
}, 200);
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.localNotes = this.notes;
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
hideScratchpad: 'application/hideScratchpad',
|
||||
changeNotes: 'scratchpad/changeNotes'
|
||||
}),
|
||||
hideModal () {
|
||||
this.$emit('hide');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@@ -36,6 +36,10 @@
|
||||
|
||||
<div class="settingbar-bottom-elements">
|
||||
<ul class="settingbar-elements">
|
||||
<li class="settingbar-element btn btn-link ex-tooltip" @click="showScratchpad">
|
||||
<i class="settingbar-element-icon mdi mdi-24px mdi-notebook-edit-outline text-light" />
|
||||
<span class="ex-tooltip-content">{{ $t('word.scratchpad') }}</span>
|
||||
</li>
|
||||
<li class="settingbar-element btn btn-link ex-tooltip" @click="showSettingModal('general')">
|
||||
<i class="settingbar-element-icon mdi mdi-24px mdi-cog text-light" :class="{' badge badge-update': hasUpdates}" />
|
||||
<span class="ex-tooltip-content">{{ $t('word.settings') }}</span>
|
||||
@@ -90,6 +94,7 @@ export default {
|
||||
updateConnections: 'connections/updateConnections',
|
||||
showNewConnModal: 'application/showNewConnModal',
|
||||
showSettingModal: 'application/showSettingModal',
|
||||
showScratchpad: 'application/showScratchpad',
|
||||
selectWorkspace: 'workspaces/selectWorkspace'
|
||||
}),
|
||||
contextMenu (event, connection) {
|
||||
@@ -117,9 +122,7 @@ export default {
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: $bg-color-light;
|
||||
padding: 0;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
z-index: 9;
|
||||
|
||||
.settingbar-top-elements {
|
||||
@@ -134,7 +137,6 @@ export default {
|
||||
|
||||
.settingbar-bottom-elements {
|
||||
padding-top: 0.5rem;
|
||||
background: $bg-color-light;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -162,7 +164,6 @@ export default {
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-left-color: $body-font-color;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -171,12 +172,10 @@ export default {
|
||||
bottom: -10px;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
background: $success-color;
|
||||
}
|
||||
|
||||
&.badge-update::after {
|
||||
bottom: initial;
|
||||
background: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -102,12 +102,10 @@ export default {
|
||||
display: flex;
|
||||
position: relative;
|
||||
justify-content: space-between;
|
||||
background: $bg-color-light;
|
||||
align-items: center;
|
||||
height: $titlebar-height;
|
||||
-webkit-app-region: drag;
|
||||
user-select: none;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
z-index: 9999;
|
||||
|
||||
.titlebar-resizer {
|
||||
@@ -149,11 +147,6 @@ export default {
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
background: rgba($color: #fff, $alpha: 0.2);
|
||||
}
|
||||
|
||||
&.close-button:hover {
|
||||
background: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -304,7 +304,6 @@ export default {
|
||||
height: calc(100vh - #{$excluding-size});
|
||||
|
||||
.tab-block {
|
||||
background: $bg-color-light;
|
||||
margin-top: 0;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
@@ -324,7 +323,6 @@ export default {
|
||||
|
||||
> a {
|
||||
padding: 0.2rem 0.8rem;
|
||||
color: $body-font-color;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -355,7 +353,6 @@ export default {
|
||||
|
||||
&.tools-dropdown {
|
||||
.tab-link:focus {
|
||||
color: $primary-color;
|
||||
opacity: 1;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
@@ -374,11 +371,6 @@ export default {
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
|
||||
.tool-icon {
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
@@ -414,11 +406,9 @@ export default {
|
||||
.th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: $bg-color;
|
||||
border: 1px solid;
|
||||
border-left: none;
|
||||
border-bottom-width: 2px;
|
||||
border-color: $bg-color-light;
|
||||
padding: 0;
|
||||
font-weight: 700;
|
||||
font-size: 0.7rem;
|
||||
@@ -433,7 +423,6 @@ export default {
|
||||
.td {
|
||||
border-right: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
border-color: $bg-color-light;
|
||||
padding: 0 0.4rem;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 200px;
|
||||
@@ -443,8 +432,6 @@ export default {
|
||||
position: relative;
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 1px $body-font-color;
|
||||
background: rgba($color: #000, $alpha: 0.3);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns">
|
||||
<div class="column col-12 empty text-light">
|
||||
<div class="column col-12 empty">
|
||||
<div class="empty-icon">
|
||||
<i class="mdi mdi-48px mdi-power-plug-off" />
|
||||
</div>
|
||||
|
@@ -460,8 +460,6 @@ export default {
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
background: $bg-color-gray;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
z-index: 8;
|
||||
flex: initial;
|
||||
position: relative;
|
||||
|
@@ -32,6 +32,7 @@
|
||||
<ModalAskParameters
|
||||
v-if="isAskingParameters"
|
||||
:local-routine="localElement"
|
||||
:client="workspace.client"
|
||||
@confirm="runElement"
|
||||
@close="hideAskParamsModal"
|
||||
/>
|
||||
@@ -205,13 +206,13 @@ export default {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
case 'pg':
|
||||
sql = `CALL \`${this.localElement.name}\` (${params.join(',')})`;
|
||||
sql = `CALL ${this.localElement.name}(${params.join(',')})`;
|
||||
break;
|
||||
case 'mssql':
|
||||
sql = `EXEC ${this.localElement.name} ${params.join(',')}`;
|
||||
break;
|
||||
default:
|
||||
sql = `CALL \`${this.localElement.name}\` (${params.join(',')})`;
|
||||
sql = `CALL \`${this.localElement.name}\`(${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.workspace.uid, content: sql, autorun: true });
|
||||
|
@@ -171,7 +171,8 @@ export default {
|
||||
...mapGetters({
|
||||
getLoadedSchemas: 'workspaces/getLoadedSchemas',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
getSearchTerm: 'workspaces/getSearchTerm'
|
||||
getSearchTerm: 'workspaces/getSearchTerm',
|
||||
applicationTheme: 'settings/getApplicationTheme'
|
||||
}),
|
||||
searchTerm () {
|
||||
return this.getSearchTerm(this.connection.uid);
|
||||
@@ -239,7 +240,10 @@ export default {
|
||||
},
|
||||
piePercentage (val) {
|
||||
const perc = val / this.maxSize * 100;
|
||||
return { background: `conic-gradient(lime ${perc}%, white 0)` };
|
||||
if (this.applicationTheme === 'dark')
|
||||
return { background: `conic-gradient(lime ${perc}%, white 0)` };
|
||||
else
|
||||
return { background: `conic-gradient(teal ${perc}%, silver 0)` };
|
||||
},
|
||||
setBreadcrumbs (payload) {
|
||||
if (this.breadcrumbs.schema === payload.schema && this.breadcrumbs.table === payload.table) return;
|
||||
@@ -262,7 +266,6 @@ export default {
|
||||
.database-name {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: $bg-color-gray;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@@ -308,26 +311,15 @@ export default {
|
||||
.database-name,
|
||||
.misc-name {
|
||||
&:hover {
|
||||
color: $body-font-color;
|
||||
background: $bg-color-light;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
a.table-name {
|
||||
&:hover {
|
||||
color: inherit;
|
||||
background: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
line-height: 1.2;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
color: $body-font-color;
|
||||
background: rgba($color: #fff, $alpha: 0.05);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
<ConfirmModal
|
||||
:confirm-text="$t('word.confirm')"
|
||||
size="medium"
|
||||
class="options-modal"
|
||||
@confirm="confirmForeignsChange"
|
||||
@hide="$emit('hide')"
|
||||
>
|
||||
@@ -36,7 +37,7 @@
|
||||
v-for="foreign in foreignProxy"
|
||||
:key="foreign._id"
|
||||
class="tile tile-centered c-hand mb-1 p-1"
|
||||
:class="{'selected-foreign': selectedForeignID === foreign._id}"
|
||||
:class="{'selected-element': selectedForeignID === foreign._id}"
|
||||
@click="selectForeign($event, foreign._id)"
|
||||
>
|
||||
<div class="tile-icon">
|
||||
@@ -268,8 +269,10 @@ export default {
|
||||
this.$emit('foreigns-update', this.foreignProxy);
|
||||
},
|
||||
selectForeign (event, id) {
|
||||
if (this.selectedForeignID !== id && !event.target.classList.contains('remove-field'))
|
||||
if (this.selectedForeignID !== id && !event.target.classList.contains('remove-field')) {
|
||||
this.selectedForeignID = id;
|
||||
this.getRefFields();
|
||||
}
|
||||
},
|
||||
getModalInnerHeight () {
|
||||
const modalBody = document.querySelector('.modal-body');
|
||||
@@ -369,23 +372,16 @@ export default {
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-light;
|
||||
|
||||
.tile-action {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected-foreign {
|
||||
background: $bg-color-light;
|
||||
&.selected-element {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-col {
|
||||
border-left: 2px solid $bg-color-light;
|
||||
}
|
||||
|
||||
.fields-list {
|
||||
max-height: 80px;
|
||||
overflow: auto;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
<ConfirmModal
|
||||
:confirm-text="$t('word.confirm')"
|
||||
size="medium"
|
||||
class="options-modal"
|
||||
@confirm="confirmParametersChange"
|
||||
@hide="$emit('hide')"
|
||||
>
|
||||
@@ -36,7 +37,7 @@
|
||||
v-for="param in parametersProxy"
|
||||
:key="param._id"
|
||||
class="tile tile-centered c-hand mb-1 p-1"
|
||||
:class="{'selected-param': selectedParam === param._id}"
|
||||
:class="{'selected-element': selectedParam === param._id}"
|
||||
@click="selectParameter($event, param._id)"
|
||||
>
|
||||
<div class="tile-icon">
|
||||
@@ -249,23 +250,16 @@ export default {
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-light;
|
||||
|
||||
.tile-action {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected-param {
|
||||
background: $bg-color-light;
|
||||
&.selected-element {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-col {
|
||||
border-left: 2px solid $bg-color-light;
|
||||
}
|
||||
|
||||
.fields-list {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
<ConfirmModal
|
||||
:confirm-text="$t('word.confirm')"
|
||||
size="medium"
|
||||
class="options-modal"
|
||||
@confirm="confirmIndexesChange"
|
||||
@hide="$emit('hide')"
|
||||
>
|
||||
@@ -36,7 +37,7 @@
|
||||
v-for="index in indexesProxy"
|
||||
:key="index._id"
|
||||
class="tile tile-centered c-hand mb-1 p-1"
|
||||
:class="{'selected-index': selectedIndexID === index._id}"
|
||||
:class="{'selected-element': selectedIndexID === index._id}"
|
||||
@click="selectIndex($event, index._id)"
|
||||
>
|
||||
<div class="tile-icon">
|
||||
@@ -256,23 +257,16 @@ export default {
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-light;
|
||||
|
||||
.tile-action {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected-index {
|
||||
background: $bg-color-light;
|
||||
&.selected-element {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-col {
|
||||
border-left: 2px solid $bg-color-light;
|
||||
}
|
||||
|
||||
.fields-list {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
|
@@ -26,7 +26,7 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.comment" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.comment') }}
|
||||
</label>
|
||||
@@ -38,7 +38,7 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.autoIncrement" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.autoIncrement') }}
|
||||
</label>
|
||||
@@ -50,7 +50,7 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.collations" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.collation') }}
|
||||
</label>
|
||||
@@ -66,7 +66,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.engines" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.engine') }}
|
||||
</label>
|
||||
|
@@ -26,7 +26,7 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.definer" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
@@ -54,7 +54,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.comment" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('word.comment') }}
|
||||
</label>
|
||||
@@ -77,7 +77,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.procedureDataAccess" class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('message.dataAccess') }}
|
||||
</label>
|
||||
@@ -90,7 +90,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.procedureDeterministic" class="form-group">
|
||||
<div class="col-4" />
|
||||
<div class="column">
|
||||
<label class="form-checkbox form-inline">
|
||||
@@ -124,6 +124,9 @@ export default {
|
||||
computed: {
|
||||
isTableNameValid () {
|
||||
return this.optionsProxy.name !== '';
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
@@ -2,6 +2,7 @@
|
||||
<ConfirmModal
|
||||
:confirm-text="$t('word.confirm')"
|
||||
size="medium"
|
||||
class="options-modal"
|
||||
@confirm="confirmParametersChange"
|
||||
@hide="$emit('hide')"
|
||||
>
|
||||
@@ -36,7 +37,7 @@
|
||||
v-for="param in parametersProxy"
|
||||
:key="param._id"
|
||||
class="tile tile-centered c-hand mb-1 p-1"
|
||||
:class="{'selected-param': selectedParam === param._id}"
|
||||
:class="{'selected-element': selectedParam === param._id}"
|
||||
@click="selectParameter($event, param._id)"
|
||||
>
|
||||
<div class="tile-icon">
|
||||
@@ -105,7 +106,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div v-if="customizations.parametersLength" class="form-group">
|
||||
<label class="form-label col-3">
|
||||
{{ $t('word.length') }}
|
||||
</label>
|
||||
@@ -198,6 +199,9 @@ export default {
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.localParameters) !== JSON.stringify(this.parametersProxy);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
@@ -234,10 +238,10 @@ export default {
|
||||
addParameter () {
|
||||
this.parametersProxy = [...this.parametersProxy, {
|
||||
_id: uidGen(),
|
||||
name: `Param${this.i++}`,
|
||||
type: 'INT',
|
||||
name: `param${this.i++}`,
|
||||
type: this.workspace.dataTypes[0].types[0].name,
|
||||
context: 'IN',
|
||||
length: 10
|
||||
length: ''
|
||||
}];
|
||||
|
||||
if (this.parametersProxy.length === 1)
|
||||
@@ -280,23 +284,16 @@ export default {
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-light;
|
||||
|
||||
.tile-action {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected-param {
|
||||
background: $bg-color-light;
|
||||
&.selected-element {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-col {
|
||||
border-left: 2px solid $bg-color-light;
|
||||
}
|
||||
|
||||
.fields-list {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
|
@@ -433,11 +433,11 @@ export default {
|
||||
_id: uidGen(),
|
||||
name: `${this.$tc('word.field', 1)}_${++this.newFieldsCounter}`,
|
||||
key: '',
|
||||
type: 'int',
|
||||
type: this.workspace.dataTypes[0].types[0].name,
|
||||
schema: this.schema,
|
||||
table: this.table,
|
||||
numPrecision: null,
|
||||
numLength: 11,
|
||||
numLength: this.workspace.dataTypes[0].types[0].length,
|
||||
datePrecision: null,
|
||||
charLength: null,
|
||||
nullable: false,
|
||||
|
@@ -73,6 +73,7 @@
|
||||
<ModalAskParameters
|
||||
v-if="isAskingParameters"
|
||||
:local-routine="localFunction"
|
||||
:client="workspace.client"
|
||||
@confirm="runFunction"
|
||||
@close="hideAskParamsModal"
|
||||
/>
|
||||
|
@@ -74,6 +74,7 @@
|
||||
<ModalAskParameters
|
||||
v-if="isAskingParameters"
|
||||
:local-routine="localRoutine"
|
||||
:client="workspace.client"
|
||||
@confirm="runRoutine"
|
||||
@close="hideAskParamsModal"
|
||||
/>
|
||||
@@ -281,13 +282,13 @@ export default {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
case 'pg':
|
||||
sql = `CALL \`${this.originalRoutine.name}\` (${params.join(',')})`;
|
||||
sql = `CALL ${this.originalRoutine.name}(${params.join(',')})`;
|
||||
break;
|
||||
case 'mssql':
|
||||
sql = `EXEC ${this.originalRoutine.name} ${params.join(',')}`;
|
||||
break;
|
||||
default:
|
||||
sql = `CALL \`${this.originalRoutine.name}\` (${params.join(',')})`;
|
||||
sql = `CALL \`${this.originalRoutine.name}\`(${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.connection.uid, content: sql, autorun: true });
|
||||
|
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto">
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.definer" class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
@@ -68,7 +68,7 @@
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column col-auto mr-2">
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.viewSqlSecurity" class="form-group">
|
||||
<label class="form-label">{{ $t('message.sqlSecurity') }}</label>
|
||||
<label class="form-radio">
|
||||
<input
|
||||
@@ -91,7 +91,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto mr-2">
|
||||
<div class="form-group">
|
||||
<div v-if="workspace.customizations.viewAlgorithm" class="form-group">
|
||||
<label class="form-label">{{ $t('word.algorithm') }}</label>
|
||||
<label class="form-radio">
|
||||
<input
|
||||
@@ -122,7 +122,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto mr-2">
|
||||
<div v-if="workspace.customizations.viewUpdateOption" class="column col-auto mr-2">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('message.updateOption') }}</label>
|
||||
<label class="form-radio">
|
||||
|
@@ -42,6 +42,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.tableArray" class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
{{ $t('word.array') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
@@ -49,21 +56,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th">
|
||||
<div v-if="customizations.unsigned" class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
{{ $t('word.unsigned') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th">
|
||||
<div v-if="customizations.nullable" class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
{{ $t('message.allowNull') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th">
|
||||
<div v-if="customizations.zerofill" class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
{{ $t('message.zeroFill') }}
|
||||
@@ -77,14 +84,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th">
|
||||
<div v-if="customizations.comment" class="th">
|
||||
<div class="column-resizable">
|
||||
<div class="table-column-title">
|
||||
{{ $t('word.comment') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th">
|
||||
<div v-if="customizations.collation" class="th">
|
||||
<div class="column-resizable min-100">
|
||||
<div class="table-column-title">
|
||||
{{ $t('word.collation') }}
|
||||
@@ -106,6 +113,7 @@
|
||||
:indexes="getIndexes(row.name)"
|
||||
:foreigns="getForeigns(row.name)"
|
||||
:data-types="dataTypes"
|
||||
:customizations="customizations"
|
||||
@contextmenu="contextMenu"
|
||||
/>
|
||||
</draggable>
|
||||
@@ -154,6 +162,9 @@ export default {
|
||||
workspaceSchema () {
|
||||
return this.getWorkspace(this.connUid).breadcrumbs.schema;
|
||||
},
|
||||
customizations () {
|
||||
return this.getWorkspace(this.connUid).customizations;
|
||||
},
|
||||
dataTypes () {
|
||||
return this.getWorkspace(this.connUid).dataTypes;
|
||||
},
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="tr" @contextmenu.prevent="$emit('contextmenu', $event, localRow._id)">
|
||||
<div class="td" tabindex="0">
|
||||
<div class="row-draggable">
|
||||
<i class="mdi mdi-drag-horizontal row-draggable-icon" />
|
||||
<div :class="customizations.sortableFields ? 'row-draggable' : 'text-center'">
|
||||
<i v-if="customizations.sortableFields" class="mdi mdi-drag-horizontal row-draggable-icon" />
|
||||
{{ localRow.order }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,6 +76,16 @@
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
v-if="customizations.tableArray"
|
||||
class="td"
|
||||
tabindex="0"
|
||||
>
|
||||
<label class="form-checkbox">
|
||||
<input v-model="localRow.isArray" type="checkbox">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="td type-int" tabindex="0">
|
||||
<template v-if="fieldType.length">
|
||||
<span
|
||||
@@ -96,7 +106,11 @@
|
||||
>
|
||||
</template>
|
||||
</div>
|
||||
<div class="td" tabindex="0">
|
||||
<div
|
||||
v-if="customizations.unsigned"
|
||||
class="td"
|
||||
tabindex="0"
|
||||
>
|
||||
<label class="form-checkbox">
|
||||
<input
|
||||
v-model="localRow.unsigned"
|
||||
@@ -106,7 +120,11 @@
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="td" tabindex="0">
|
||||
<div
|
||||
v-if="customizations.nullable"
|
||||
class="td"
|
||||
tabindex="0"
|
||||
>
|
||||
<label class="form-checkbox">
|
||||
<input
|
||||
v-model="localRow.nullable"
|
||||
@@ -116,7 +134,11 @@
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="td" tabindex="0">
|
||||
<div
|
||||
v-if="customizations.zerofill"
|
||||
class="td"
|
||||
tabindex="0"
|
||||
>
|
||||
<label class="form-checkbox">
|
||||
<input
|
||||
v-model="localRow.zerofill"
|
||||
@@ -131,7 +153,11 @@
|
||||
{{ fieldDefault }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="td type-varchar" tabindex="0">
|
||||
<div
|
||||
v-if="customizations.comment"
|
||||
class="td type-varchar"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
v-if="!isInlineEditor.comment"
|
||||
class="cell-content"
|
||||
@@ -149,7 +175,11 @@
|
||||
@blur="editOFF"
|
||||
>
|
||||
</div>
|
||||
<div class="td" tabindex="0">
|
||||
<div
|
||||
v-if="customizations.collation"
|
||||
class="td"
|
||||
tabindex="0"
|
||||
>
|
||||
<template v-if="fieldType.collation">
|
||||
<span
|
||||
v-if="!isInlineEditor.collation"
|
||||
@@ -220,7 +250,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div v-if="customizations.nullable" class="mb-2">
|
||||
<label class="form-radio form-inline">
|
||||
<input
|
||||
v-model="defaultValue.type"
|
||||
@@ -230,7 +260,7 @@
|
||||
><i class="form-icon" /> NULL
|
||||
</label>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div v-if="customizations.autoIncrement" class="mb-2">
|
||||
<label class="form-radio form-inline">
|
||||
<input
|
||||
v-model="defaultValue.type"
|
||||
@@ -261,7 +291,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="customizations.onUpdate">
|
||||
<div class="form-group">
|
||||
<label class="form-label col-4">
|
||||
{{ $t('message.onUpdate') }}
|
||||
@@ -294,7 +324,8 @@ export default {
|
||||
row: Object,
|
||||
dataTypes: Array,
|
||||
indexes: Array,
|
||||
foreigns: Array
|
||||
foreigns: Array,
|
||||
customizations: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@@ -232,7 +232,6 @@ export default {
|
||||
.btn {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
color: $body-font-color;
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
@@ -86,6 +86,7 @@ import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
||||
import WorkspaceQueryTableRow from '@/components/WorkspaceQueryTableRow';
|
||||
import TableContext from '@/components/WorkspaceQueryTableContext';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import moment from 'moment';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceQueryTable',
|
||||
@@ -122,12 +123,13 @@ export default {
|
||||
return this.getWorkspace(this.connUid).breadcrumbs.schema;
|
||||
},
|
||||
primaryField () {
|
||||
const primaryFields = this.fields.filter(field => ['pri', 'uni'].includes(field.key));
|
||||
const primaryFields = this.fields.filter(field => field.key === 'pri');
|
||||
const uniqueFields = this.fields.filter(field => field.key === 'uni');
|
||||
|
||||
if (primaryFields.length > 1 || !primaryFields.length)
|
||||
if ((primaryFields.length > 1 || !primaryFields.length) && (uniqueFields.length > 1 || !uniqueFields.length))
|
||||
return false;
|
||||
|
||||
return primaryFields[0];
|
||||
return primaryFields[0] || uniqueFields[0];
|
||||
},
|
||||
isSortable () {
|
||||
return this.fields.every(field => field.name);
|
||||
@@ -298,6 +300,17 @@ export default {
|
||||
delete row._id;
|
||||
delete orgRow._id;
|
||||
|
||||
Object.keys(orgRow).forEach(key => { // remap the row
|
||||
if (orgRow[key] instanceof Date && moment(orgRow[key]).isValid()) { // if datetime
|
||||
let datePrecision = '';
|
||||
const precision = this.fields.find(field => field.name === key).datePrecision;
|
||||
for (let i = 0; i < precision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
|
||||
orgRow[key] = moment(orgRow[key]).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
|
||||
}
|
||||
});
|
||||
|
||||
const params = {
|
||||
primary: this.primaryField.name,
|
||||
schema: this.getSchema(this.resultsetIndex),
|
||||
|
@@ -182,7 +182,7 @@ import { mimeFromHex } from 'common/libs/mimeFromHex';
|
||||
import { formatBytes } from 'common/libs/formatBytes';
|
||||
import { bufferToBase64 } from 'common/libs/bufferToBase64';
|
||||
import hexToBinary from 'common/libs/hexToBinary';
|
||||
import { TEXT, LONG_TEXT, ARRAY, TEXT_SEARCH, NUMBER, FLOAT, BOOLEAN, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
|
||||
import { TEXT, LONG_TEXT, ARRAY, TEXT_SEARCH, NUMBER, FLOAT, BOOLEAN, DATE, TIME, DATETIME, BLOB, BIT, HAS_TIMEZONE } from 'common/fieldTypes';
|
||||
import { VueMaskDirective } from 'v-mask';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import TextEditor from '@/components/BaseTextEditor';
|
||||
@@ -286,6 +286,9 @@ export default {
|
||||
for (let i = 0; i < precision; i++)
|
||||
timeMask += i === 0 ? '.#' : '#';
|
||||
|
||||
if (HAS_TIMEZONE.includes(this.editingType))
|
||||
timeMask += 'X##';
|
||||
|
||||
return { type: 'text', mask: timeMask };
|
||||
}
|
||||
|
||||
@@ -299,6 +302,9 @@ export default {
|
||||
for (let i = 0; i < precision; i++)
|
||||
datetimeMask += i === 0 ? '.#' : '#';
|
||||
|
||||
if (HAS_TIMEZONE.includes(this.editingType))
|
||||
datetimeMask += 'X##';
|
||||
|
||||
return { type: 'text', mask: datetimeMask };
|
||||
}
|
||||
|
||||
|
@@ -289,10 +289,6 @@ export default {
|
||||
.export-dropdown {
|
||||
.menu {
|
||||
min-width: 100%;
|
||||
|
||||
.menu-item a:hover {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -101,7 +101,10 @@ module.exports = {
|
||||
tools: 'Tools',
|
||||
variables: 'Variables',
|
||||
processes: 'Processes',
|
||||
database: 'Database'
|
||||
database: 'Database',
|
||||
scratchpad: 'Scratchpad',
|
||||
array: 'Array',
|
||||
changelog: 'Changelog'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Welcome to Antares SQL Client!',
|
||||
@@ -204,7 +207,8 @@ module.exports = {
|
||||
createNewSchema: 'Create new schema',
|
||||
schemaName: 'Schema name',
|
||||
editSchema: 'Edit schema',
|
||||
deleteSchema: 'Delete schema'
|
||||
deleteSchema: 'Delete schema',
|
||||
markdownSupported: 'Markdown supported'
|
||||
},
|
||||
faker: {
|
||||
address: 'Address',
|
||||
|
BIN
src/renderer/images/light.png
Normal file
BIN
src/renderer/images/light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
@@ -42,6 +42,7 @@ export default {
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.deleteTableRows(params);
|
||||
this.isQuering = false;
|
||||
|
||||
if (status === 'success')
|
||||
this.reloadTable();
|
||||
@@ -50,9 +51,8 @@ export default {
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
this.isQuering = false;
|
||||
}
|
||||
|
||||
this.isQuering = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -30,6 +30,7 @@
|
||||
"macaddr": $string-color,
|
||||
"macaddr8": $string-color,
|
||||
"uuid": $string-color,
|
||||
"regproc": $string-color,
|
||||
"int": $number-color,
|
||||
"tinyint": $number-color,
|
||||
"smallint": $number-color,
|
||||
@@ -76,6 +77,7 @@
|
||||
"tsvector": $array-color,
|
||||
"tsquery": $array-color,
|
||||
"pg_node_tree": $array-color,
|
||||
"aclitem": $array-color,
|
||||
"unknown": $unknown-color,
|
||||
)
|
||||
);
|
||||
|
@@ -27,7 +27,6 @@
|
||||
|
||||
.td,
|
||||
.th {
|
||||
border-bottom: $border-width solid $border-color;
|
||||
padding: $unit-3 $unit-2;
|
||||
display: table-cell;
|
||||
}
|
||||
@@ -35,37 +34,4 @@
|
||||
.th {
|
||||
border-bottom-width: $border-width-lg;
|
||||
}
|
||||
|
||||
&,
|
||||
&.table-striped {
|
||||
.tbody {
|
||||
.tr {
|
||||
&.selected {
|
||||
background: #333 !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $bg-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.table-hover {
|
||||
.tbody {
|
||||
.tr {
|
||||
&:hover {
|
||||
background: $bg-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.table-striped {
|
||||
.tbody {
|
||||
.tr:nth-of-type(odd) {
|
||||
background: $bg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,12 @@
|
||||
/* Colors */
|
||||
$body-bg: #1d1d1d;
|
||||
$body-font-color: #fff;
|
||||
$bg-color: #1d1d1d;
|
||||
$bg-color-light: #3f3f3f;
|
||||
$body-bg: #fdfdfd;
|
||||
$body-bg-dark: #1d1d1d;
|
||||
$body-font-color-dark: #fff;
|
||||
$bg-color-dark: #1d1d1d;
|
||||
$bg-color-light-dark: #3f3f3f;
|
||||
$bg-color-gray: #272727;
|
||||
$bg-color-light-gray: #f1f1f1;
|
||||
$light-color: #fdfdfd;
|
||||
$primary-color: #e36929;
|
||||
$success-color: #32b643;
|
||||
$error-color: #de3b28;
|
||||
@@ -14,8 +17,8 @@ $number-color: cornflowerblue;
|
||||
$date-color: coral;
|
||||
$bit-color: lightskyblue;
|
||||
$blob-color: darkorchid;
|
||||
$array-color: greenyellow;
|
||||
$enum-color: gold;
|
||||
$array-color: yellowgreen;
|
||||
$enum-color: goldenrod;
|
||||
$unknown-color: gray;
|
||||
|
||||
/* Sizes */
|
||||
|
@@ -6,6 +6,8 @@
|
||||
@import "fake-tables";
|
||||
@import "mdi-additions";
|
||||
@import "db-icons";
|
||||
@import "themes/dark-theme";
|
||||
@import "themes/light-theme";
|
||||
@import "~spectre.css/src/spectre";
|
||||
@import "~spectre.css/src/spectre-exp";
|
||||
|
||||
@@ -19,27 +21,6 @@ body {
|
||||
@include padding-variant(3, $unit-3);
|
||||
@include padding-variant(4, $unit-4);
|
||||
|
||||
.btn {
|
||||
&.btn-gray {
|
||||
color: #fff;
|
||||
background: $bg-color-gray;
|
||||
|
||||
&:hover {
|
||||
background: $bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-dark {
|
||||
color: #fff;
|
||||
background: $bg-color-light;
|
||||
border-color: $bg-color-light;
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.p-vcentered {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
@@ -55,15 +36,6 @@ body {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.bg-checkered {
|
||||
background-image:
|
||||
linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)),
|
||||
linear-gradient(to right, black 50%, white 50%),
|
||||
linear-gradient(to bottom, black 50%, white 50%);
|
||||
background-blend-mode: normal, difference, normal;
|
||||
background-size: 2em 2em;
|
||||
}
|
||||
|
||||
.workspace-tabs {
|
||||
align-content: baseline;
|
||||
|
||||
@@ -80,13 +52,14 @@ body {
|
||||
.btn {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
color: $body-font-color;
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-info {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
> div + div {
|
||||
padding-left: 0.6rem;
|
||||
@@ -106,18 +79,6 @@ body {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: $bg-color-light;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba($color: #fff, $alpha: 0.5);
|
||||
|
||||
&:hover {
|
||||
background: rgba($color: #fff, $alpha: 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Animations
|
||||
@keyframes rotation {
|
||||
from {
|
||||
@@ -135,32 +96,21 @@ body {
|
||||
|
||||
/* Override */
|
||||
.modal {
|
||||
.modal-overlay,
|
||||
&.active .modal-overlay {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.modal-container,
|
||||
.modal-sm .modal-container {
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
padding: 0;
|
||||
background: $bg-color;
|
||||
|
||||
.modal-header {
|
||||
padding: 0.4rem 0.8rem;
|
||||
text-transform: uppercase;
|
||||
background: $bg-color-gray;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
border-color: #272727;
|
||||
|
||||
.tab-item {
|
||||
.btn-clear {
|
||||
margin-top: -0.1rem;
|
||||
@@ -192,34 +142,11 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.form-select,
|
||||
.form-input,
|
||||
.form-select:not([multiple]):not([size]),
|
||||
.form-checkbox .form-icon,
|
||||
.form-radio .form-icon {
|
||||
border-color: $bg-color-light;
|
||||
background-color: $bg-color-gray;
|
||||
}
|
||||
|
||||
.form-input.is-error,
|
||||
.form-select.is-error {
|
||||
background-color: $bg-color-gray;
|
||||
}
|
||||
|
||||
.form-input:not(:placeholder-shown):invalid:focus {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
|
||||
.form-select:not([multiple]):not([size]):focus {
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
.form-input[type="file"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.input-group .input-group-addon {
|
||||
border-color: #3f3f3f;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -243,7 +170,3 @@ body {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: $body-font-color;
|
||||
}
|
||||
|
440
src/renderer/scss/themes/dark-theme.scss
Normal file
440
src/renderer/scss/themes/dark-theme.scss
Normal file
@@ -0,0 +1,440 @@
|
||||
.theme-dark {
|
||||
color: $body-font-color-dark;
|
||||
background: $body-bg-dark;
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: $bg-color-light-dark;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba($color: #fff, $alpha: 0.5);
|
||||
|
||||
&:hover {
|
||||
background: rgba($color: #fff, $alpha: 1);
|
||||
}
|
||||
}
|
||||
|
||||
:disabled {
|
||||
.file-uploader {
|
||||
background-color: #151515;
|
||||
}
|
||||
}
|
||||
|
||||
// Override Spectre.css
|
||||
.menu {
|
||||
background: $bg-color-light-dark;
|
||||
|
||||
.menu-item a {
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
&.btn-link {
|
||||
color: rgba($body-font-color-dark, 0.8);
|
||||
|
||||
&:hover {
|
||||
color: $body-font-color-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-gray {
|
||||
color: #fff;
|
||||
background: $bg-color-gray;
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-dark {
|
||||
color: #fff;
|
||||
background: $bg-color-light-dark;
|
||||
border-color: $bg-color-light-dark;
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
.modal-overlay,
|
||||
&.active .modal-overlay {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.modal-container,
|
||||
.modal-sm .modal-container {
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
background: $bg-color-dark;
|
||||
|
||||
.modal-header {
|
||||
background: $bg-color-gray;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
border-color: #272727;
|
||||
}
|
||||
|
||||
.form-select,
|
||||
.form-input,
|
||||
.form-select:not([multiple]):not([size]),
|
||||
.form-checkbox .form-icon,
|
||||
.form-radio .form-icon {
|
||||
border-color: $bg-color-light-dark;
|
||||
background-color: $bg-color-gray;
|
||||
color: $body-font-color-dark;
|
||||
}
|
||||
|
||||
.form-input.is-error,
|
||||
.form-select.is-error {
|
||||
background-color: $bg-color-gray;
|
||||
}
|
||||
|
||||
.form-input:not(:placeholder-shown):invalid:focus {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
|
||||
.form-select:not([multiple]):not([size]):focus {
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
.form-input[readonly] {
|
||||
background-color: $bg-color-dark;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.input-group .input-group-addon {
|
||||
border-color: #3f3f3f;
|
||||
background: $bg-color-dark;
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: $body-font-color-dark;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.form-switch .form-icon::before {
|
||||
background: $bg-color-light-dark;
|
||||
}
|
||||
|
||||
// Antares
|
||||
.workspace {
|
||||
.workspace-explorebar {
|
||||
background: $bg-color-gray;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
|
||||
.workspace-explorebar-database {
|
||||
.database-name {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
|
||||
.database-name,
|
||||
.misc-name {
|
||||
&:hover {
|
||||
color: $body-font-color-dark;
|
||||
background: $bg-color-light-dark;
|
||||
}
|
||||
}
|
||||
|
||||
a.table-name {
|
||||
&:hover {
|
||||
color: inherit;
|
||||
background: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
&:hover {
|
||||
color: $body-font-color-dark;
|
||||
background: rgba($color: #fff, $alpha: 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-results {
|
||||
.table {
|
||||
.th {
|
||||
background: $bg-color-dark;
|
||||
border-color: $bg-color-light-dark;
|
||||
}
|
||||
|
||||
.td {
|
||||
border-color: $bg-color-light-dark;
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 1px $body-font-color-dark;
|
||||
background: rgba($color: #000, $alpha: 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-tabs {
|
||||
.tab-block {
|
||||
background: $bg-color-light-dark;
|
||||
|
||||
.tab-item {
|
||||
> a {
|
||||
color: $body-font-color-dark;
|
||||
}
|
||||
|
||||
& &.tools-dropdown {
|
||||
.tab-link:focus {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.menu {
|
||||
.menu-item a {
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-runner .workspace-query-runner-footer .workspace-query-buttons .btn {
|
||||
color: $body-font-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bg-checkered {
|
||||
background-image:
|
||||
linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)),
|
||||
linear-gradient(to right, black 50%, white 50%),
|
||||
linear-gradient(to bottom, black 50%, white 50%);
|
||||
background-blend-mode: normal, difference, normal;
|
||||
background-size: 2em 2em;
|
||||
}
|
||||
|
||||
.context {
|
||||
color: $body-font-color-dark;
|
||||
|
||||
.context-container {
|
||||
box-shadow: 0 0 2px 0 #000;
|
||||
background: #1d1d1d;
|
||||
|
||||
.context-element {
|
||||
.context-submenu {
|
||||
background: #1d1d1d;
|
||||
box-shadow: 0 0 2px 0 #000;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.editor-wrapper {
|
||||
border-bottom: 1px solid #444;
|
||||
}
|
||||
|
||||
.file-uploader {
|
||||
border: 0.05rem solid $bg-color-light-dark;
|
||||
background-color: $bg-color-gray;
|
||||
|
||||
.file-uploader-message {
|
||||
border-right: 0.05rem solid $bg-color-light-dark;
|
||||
background-color: $bg-color-dark;
|
||||
}
|
||||
}
|
||||
|
||||
.tile {
|
||||
&:hover {
|
||||
background: $bg-color-light-dark;
|
||||
}
|
||||
|
||||
&.selected-element {
|
||||
background: $bg-color-light-dark;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-col {
|
||||
border-left: 2px solid $bg-color-light-dark;
|
||||
}
|
||||
|
||||
.table {
|
||||
.td,
|
||||
.th {
|
||||
border-bottom: $border-width solid $border-color;
|
||||
}
|
||||
|
||||
&,
|
||||
&.table-striped {
|
||||
.tbody {
|
||||
.tr {
|
||||
&.selected {
|
||||
background: #333 !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $bg-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.table-hover {
|
||||
.tbody {
|
||||
.tr {
|
||||
&:hover {
|
||||
background: #151515;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.table-striped {
|
||||
.tbody {
|
||||
.tr:nth-of-type(odd) {
|
||||
background: $bg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#titlebar {
|
||||
background: $bg-color-light-dark;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
|
||||
.titlebar-elements {
|
||||
.titlebar-element {
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
background: rgba($color: #fff, $alpha: 0.2);
|
||||
}
|
||||
|
||||
&.close-button:hover {
|
||||
background: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#settingbar {
|
||||
width: $settingbar-width;
|
||||
height: calc(100vh - #{$excluding-size});
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: $bg-color-light-dark;
|
||||
padding: 0;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
z-index: 9;
|
||||
|
||||
.settingbar-top-elements {
|
||||
overflow-x: hidden;
|
||||
overflow-y: overlay;
|
||||
max-height: calc((100vh - 3.5rem) - #{$excluding-size});
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.settingbar-bottom-elements {
|
||||
padding-top: 0.5rem;
|
||||
background: $bg-color-light-dark;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.settingbar-elements {
|
||||
list-style: none;
|
||||
text-align: center;
|
||||
width: $settingbar-width;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.settingbar-element {
|
||||
height: $settingbar-width;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border-left: 3px solid transparent;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-left-color: $body-font-color-dark;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.settingbar-element-icon {
|
||||
&.badge::after {
|
||||
bottom: -10px;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
background: $success-color;
|
||||
}
|
||||
|
||||
&.badge-update::after {
|
||||
bottom: initial;
|
||||
background: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ex-tooltip {
|
||||
.ex-tooltip-content {
|
||||
background: rgba(48, 55, 66, 0.95);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover .ex-tooltip-content {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#footer {
|
||||
background: $primary-color;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
|
||||
.footer-elements {
|
||||
.footer-element {
|
||||
&.footer-link {
|
||||
&:hover {
|
||||
background: rgba($color: #fff, $alpha: 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {
|
||||
background-color: #c9561a99;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_line-hover {
|
||||
background-color: #c9571a33;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ace_dark.ace_editor.ace_autocomplete .ace_completion-highlight {
|
||||
color: #e0d00c;
|
||||
}
|
299
src/renderer/scss/themes/light-theme.scss
Normal file
299
src/renderer/scss/themes/light-theme.scss
Normal file
@@ -0,0 +1,299 @@
|
||||
.theme-light {
|
||||
::-webkit-scrollbar-track {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba($color: $bg-color-light-dark, $alpha: 0.5);
|
||||
|
||||
&:hover {
|
||||
background: rgba($color: $bg-color-light-dark, $alpha: 1);
|
||||
}
|
||||
}
|
||||
|
||||
.form-input:disabled,
|
||||
.form-input.disabled,
|
||||
.form-select:disabled,
|
||||
.form-select.disabled {
|
||||
background: #ababab;
|
||||
}
|
||||
|
||||
#titlebar {
|
||||
background: $bg-color-light;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
|
||||
.titlebar-elements {
|
||||
.titlebar-element {
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
background: rgba($color: rgb(172, 172, 172), $alpha: 0.2);
|
||||
}
|
||||
|
||||
&.close-button:hover {
|
||||
background: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
&.btn-link {
|
||||
color: rgba($body-font-color, 0.8);
|
||||
|
||||
&:hover {
|
||||
color: $body-font-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-gray {
|
||||
color: #fff;
|
||||
background: $bg-color-gray;
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-dark {
|
||||
color: #fff;
|
||||
background: lighten($bg-color-light-dark, 20%);
|
||||
border-color: lighten($bg-color-light-dark, 20%);
|
||||
|
||||
&:hover {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
color: $body-font-color;
|
||||
|
||||
&:target .modal-overlay,
|
||||
&.active .modal-overlay {
|
||||
background: rgba($bg-color-dark, 0.75);
|
||||
}
|
||||
|
||||
.modal-container .modal-header {
|
||||
background: $bg-color-light-dark;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.tile {
|
||||
&:hover {
|
||||
background: $bg-color-light-gray;
|
||||
}
|
||||
|
||||
&.selected-element {
|
||||
background: $bg-color-light-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-col {
|
||||
border-left: 2px solid darken($bg-color-light-gray, 15%);
|
||||
}
|
||||
|
||||
.file-uploader {
|
||||
border: 0.05rem solid $border-color-dark;
|
||||
background-color: $bg-color-light;
|
||||
|
||||
.file-uploader-message {
|
||||
border-right: 0.05rem solid $border-color-dark;
|
||||
background-color: $bg-color-light;
|
||||
}
|
||||
}
|
||||
|
||||
#settingbar {
|
||||
width: $settingbar-width;
|
||||
height: calc(100vh - #{$excluding-size});
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: $bg-color-light-dark;
|
||||
padding: 0;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
z-index: 9;
|
||||
|
||||
.settingbar-top-elements {
|
||||
overflow-x: hidden;
|
||||
overflow-y: overlay;
|
||||
max-height: calc((100vh - 3.5rem) - #{$excluding-size});
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.settingbar-bottom-elements {
|
||||
padding-top: 0.5rem;
|
||||
background: $bg-color-light-dark;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.settingbar-elements {
|
||||
list-style: none;
|
||||
text-align: center;
|
||||
width: $settingbar-width;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.settingbar-element {
|
||||
height: $settingbar-width;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border-left: 3px solid transparent;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-left-color: $body-font-color-dark;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.settingbar-element-icon {
|
||||
&.badge::after {
|
||||
bottom: -10px;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
background: $success-color;
|
||||
}
|
||||
|
||||
&.badge-update::after {
|
||||
bottom: initial;
|
||||
background: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ex-tooltip {
|
||||
.ex-tooltip-content {
|
||||
background: rgba(48, 55, 66, 0.95);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover .ex-tooltip-content {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.workspace {
|
||||
.workspace-explorebar {
|
||||
background: $bg-color-light-gray;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
|
||||
.workspace-explorebar-database {
|
||||
.database-name {
|
||||
background: $bg-color-light-gray;
|
||||
}
|
||||
|
||||
.table-size {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-results {
|
||||
.table {
|
||||
.th {
|
||||
background: $body-bg;
|
||||
border-color: rgba($bg-color-light-dark, 0.5);
|
||||
}
|
||||
|
||||
.td {
|
||||
border-color: rgba($bg-color-light-dark, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.context {
|
||||
color: $body-font-color-dark;
|
||||
|
||||
.context-container {
|
||||
box-shadow: 0 0 2px 0 #000;
|
||||
background: #1d1d1d;
|
||||
|
||||
.context-element {
|
||||
.context-submenu {
|
||||
background: #1d1d1d;
|
||||
box-shadow: 0 0 2px 0 #000;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
.td,
|
||||
.th {
|
||||
border-bottom: $border-width solid $border-color;
|
||||
}
|
||||
|
||||
&,
|
||||
&.table-striped {
|
||||
.tbody {
|
||||
.tr {
|
||||
&.selected {
|
||||
background: rgba($bg-color-gray, 0.2) !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $bg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.table-hover {
|
||||
.tbody {
|
||||
.tr {
|
||||
&:hover {
|
||||
background: $bg-color-light-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.table-striped {
|
||||
.tbody {
|
||||
.tr:nth-of-type(odd) {
|
||||
background: $bg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#footer {
|
||||
background: $primary-color;
|
||||
box-shadow: 0 0 1px 0 #000;
|
||||
|
||||
.footer-elements {
|
||||
.footer-element {
|
||||
&.footer-link {
|
||||
&:hover {
|
||||
background: rgba($color: #fff, $alpha: 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ import Vuex from 'vuex';
|
||||
|
||||
import application from './modules/application.store';
|
||||
import settings from './modules/settings.store';
|
||||
import scratchpad from './modules/scratchpad.store';
|
||||
import connections from './modules/connections.store';
|
||||
import workspaces from './modules/workspaces.store';
|
||||
import notifications from './modules/notifications.store';
|
||||
@@ -18,6 +19,7 @@ export default new Vuex.Store({
|
||||
modules: {
|
||||
application,
|
||||
settings,
|
||||
scratchpad,
|
||||
connections,
|
||||
workspaces,
|
||||
notifications
|
||||
|
@@ -1,16 +1,21 @@
|
||||
'use strict';
|
||||
import Store from 'electron-store';
|
||||
const persistentStore = new Store({ name: 'settings' });
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
strict: true,
|
||||
state: {
|
||||
app_name: 'Antares - SQL Client',
|
||||
app_version: process.env.PACKAGE_VERSION || 0,
|
||||
cached_version: persistentStore.get('cached_version', 0),
|
||||
is_loading: false,
|
||||
is_new_modal: false,
|
||||
is_setting_modal: false,
|
||||
is_scratchpad: false,
|
||||
selected_setting_tab: 'general',
|
||||
selected_conection: {},
|
||||
update_status: 'noupdate', // noupdate, available, checking, nocheck, downloading, downloaded
|
||||
update_status: 'noupdate', // noupdate, available, checking, nocheck, downloading, downloaded, disabled
|
||||
download_progress: 0,
|
||||
base_completer: [] // Needed to reset ace editor, due global-only ace completer
|
||||
},
|
||||
@@ -18,10 +23,12 @@ export default {
|
||||
isLoading: state => state.is_loading,
|
||||
appName: state => state.app_name,
|
||||
appVersion: state => state.app_version,
|
||||
cachedVersion: state => state.cached_version,
|
||||
getBaseCompleter: state => state.base_completer,
|
||||
getSelectedConnection: state => state.selected_conection,
|
||||
isNewModal: state => state.is_new_modal,
|
||||
isSettingModal: state => state.is_setting_modal,
|
||||
isScratchpad: state => state.is_scratchpad,
|
||||
selectedSettingTab: state => state.selected_setting_tab,
|
||||
getUpdateStatus: state => state.update_status,
|
||||
getDownloadProgress: state => Number(state.download_progress.toFixed(1))
|
||||
@@ -46,6 +53,16 @@ export default {
|
||||
HIDE_SETTING_MODAL (state) {
|
||||
state.is_setting_modal = false;
|
||||
},
|
||||
SHOW_SCRATCHPAD (state) {
|
||||
state.is_scratchpad = true;
|
||||
},
|
||||
HIDE_SCRATCHPAD (state) {
|
||||
state.is_scratchpad = false;
|
||||
},
|
||||
CHANGE_CACHED_VERSION (state) {
|
||||
state.cached_version = state.app_version;
|
||||
persistentStore.set('cached_version', state.cached_version);
|
||||
},
|
||||
CHANGE_UPDATE_STATUS (state, status) {
|
||||
state.update_status = status;
|
||||
},
|
||||
@@ -54,6 +71,12 @@ export default {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
checkVersionUpdate ({ getters, commit, dispatch }) {
|
||||
if (getters.appVersion !== getters.cachedVersion) {
|
||||
dispatch('showSettingModal', 'changelog');
|
||||
commit('CHANGE_CACHED_VERSION');
|
||||
}
|
||||
},
|
||||
setLoadingStatus ({ commit }, payload) {
|
||||
commit('SET_LOADING_STATUS', payload);
|
||||
},
|
||||
@@ -72,6 +95,12 @@ export default {
|
||||
},
|
||||
hideSettingModal ({ commit }) {
|
||||
commit('HIDE_SETTING_MODAL');
|
||||
},
|
||||
showScratchpad ({ commit }) {
|
||||
commit('SHOW_SCRATCHPAD');
|
||||
},
|
||||
hideScratchpad ({ commit }) {
|
||||
commit('HIDE_SCRATCHPAD');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
25
src/renderer/store/modules/scratchpad.store.js
Normal file
25
src/renderer/store/modules/scratchpad.store.js
Normal file
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
import Store from 'electron-store';
|
||||
const persistentStore = new Store({ name: 'notes' });
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
strict: true,
|
||||
state: {
|
||||
notes: persistentStore.get('notes', '# HOW TO SUPPORT ANTARES\n\n- [ ] Leave a star to Antares [GitHub repo](https://github.com/Fabio286/antares)\n- [ ] Send feedbacks and advices\n- [ ] Report for bugs\n- [ ] If you enjoy, share Antares with friends\n\n# ABOUT SCRATCHPAD\n\nThis is a scratchpad where you can save your **personal notes**. It supports `markdown` format, but you are free to use plain text.\nThis content is just a placeholder, feel free to clear it to make space for your notes.\n')
|
||||
},
|
||||
getters: {
|
||||
getNotes: state => state.notes
|
||||
},
|
||||
mutations: {
|
||||
SET_NOTES (state, notes) {
|
||||
state.notes = notes;
|
||||
persistentStore.set('notes', state.notes);
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
changeNotes ({ commit }, notes) {
|
||||
commit('SET_NOTES', notes);
|
||||
}
|
||||
}
|
||||
};
|
@@ -52,8 +52,13 @@ export default {
|
||||
state.explorebar_size = size;
|
||||
persistentStore.set('explorebar_size', state.explorebar_size);
|
||||
},
|
||||
SET_APPLICATION_THEME (state, theme) {
|
||||
state.application_theme = theme;
|
||||
persistentStore.set('application_theme', state.application_theme);
|
||||
},
|
||||
SET_EDITOR_THEME (state, theme) {
|
||||
state.editor_theme = theme;
|
||||
persistentStore.set('editor_theme', state.editor_theme);
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@@ -75,6 +80,9 @@ export default {
|
||||
changeLineWrap ({ commit }, val) {
|
||||
commit('SET_LINE_WRAP', val);
|
||||
},
|
||||
changeApplicationTheme ({ commit }, theme) {
|
||||
commit('SET_APPLICATION_THEME', theme);
|
||||
},
|
||||
changeEditorTheme ({ commit }, theme) {
|
||||
commit('SET_EDITOR_THEME', theme);
|
||||
}
|
||||
|
@@ -13,6 +13,9 @@ export default store => {
|
||||
ipcRenderer.on('check-failed', () => {
|
||||
store.commit('application/CHANGE_UPDATE_STATUS', 'nocheck');
|
||||
});
|
||||
ipcRenderer.on('no-auto-update', () => {
|
||||
store.commit('application/CHANGE_UPDATE_STATUS', 'disabled');
|
||||
});
|
||||
ipcRenderer.on('download-progress', (event, data) => {
|
||||
store.commit('application/CHANGE_UPDATE_STATUS', 'downloading');
|
||||
store.commit('application/CHANGE_PROGRESS_PERCENTAGE', data.percent);
|
||||
|
Reference in New Issue
Block a user