mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
9506bb862a | |||
4cfab365c2 | |||
8d0aa73d1e | |||
30b487c37f | |||
aef17be36c | |||
ea65d8eee7 | |||
|
7dc33c78aa | ||
|
69cd083054 | ||
|
91788054e6 | ||
|
968a67ce3d | ||
f9ee7d0450 | |||
|
0e15c39797 | ||
adf407c1ba | |||
8a86344484 | |||
d2d0c3ca41 | |||
|
9046b858b1 | ||
46987faea8 | |||
|
dd25827e40 | ||
4069ade36d |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -2,6 +2,28 @@
|
||||
|
||||
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.3.8](https://github.com/Fabio286/antares/compare/v0.3.7...v0.3.8) (2021-10-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **UI:** CTRL+A to select all result rows ([4069ade](https://github.com/Fabio286/antares/commit/4069ade36df43e58f198dd1305778b5811824315))
|
||||
* **UI:** ctrl|cmd+t, ctrl|cmd+w shortcut to open/close workspace tabs ([9046b85](https://github.com/Fabio286/antares/commit/9046b858b1e4608af4c01bc4d69e1a49d4009c07))
|
||||
* **UI:** hide filter bar if there are no more rows in it ([9178805](https://github.com/Fabio286/antares/commit/91788054e6302e83cb4a7501ad6c3f72809cb3bb))
|
||||
* **UI:** multi column table filters ([0e15c39](https://github.com/Fabio286/antares/commit/0e15c39797fe34f7a649f85ee62204682d45c98a))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **PostgreSQL:** issue with uppercase characters in table field names ([aef17be](https://github.com/Fabio286/antares/commit/aef17be36cfcf3a6325a954e80f973623e250405))
|
||||
* query failure when a filter with a numeric value is used ([69cd083](https://github.com/Fabio286/antares/commit/69cd083054cae50d64475b9f1f5d7ebd39093e39))
|
||||
* regression during resize results table on filters change ([7dc33c7](https://github.com/Fabio286/antares/commit/7dc33c78aa4152264cc6833437be9af9b8621867))
|
||||
|
||||
|
||||
### Improvements
|
||||
|
||||
* **UI:** resize results table on filters change ([f9ee7d0](https://github.com/Fabio286/antares/commit/f9ee7d0450a1386800223d7b96849e06ae02aece))
|
||||
|
||||
### [0.3.7](https://github.com/Fabio286/antares/compare/v0.3.6...v0.3.7) (2021-10-08)
|
||||
|
||||
|
||||
|
10
package.json
10
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "antares",
|
||||
"productName": "Antares",
|
||||
"version": "0.3.7",
|
||||
"version": "0.3.8",
|
||||
"description": "A cross-platform easy to use SQL client.",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/Fabio286/antares.git",
|
||||
@@ -96,7 +96,7 @@
|
||||
"faker": "^5.5.3",
|
||||
"marked": "^3.0.4",
|
||||
"moment": "^2.29.1",
|
||||
"mysql2": "^2.3.0",
|
||||
"mysql2": "^2.3.2",
|
||||
"pg": "^8.7.1",
|
||||
"pgsql-ast-parser": "^7.2.1",
|
||||
"source-map-support": "^0.5.20",
|
||||
@@ -110,9 +110,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.15.7",
|
||||
"babel-loader": "^8.2.3",
|
||||
"cross-env": "^7.0.2",
|
||||
"electron": "^15.0.0",
|
||||
"electron-builder": "^22.11.7",
|
||||
"electron": "^15.3.0",
|
||||
"electron-builder": "^22.13.1",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-webpack": "^2.8.2",
|
||||
"electron-webpack-vue": "^2.4.0",
|
||||
@@ -129,6 +130,7 @@
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"stylelint-scss": "^3.21.0",
|
||||
"vue": "^2.6.14",
|
||||
"vue-loader": "^15.9.8",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"webpack": "^4.46.0"
|
||||
}
|
||||
|
@@ -22,6 +22,8 @@ module.exports = {
|
||||
functions: false,
|
||||
schedulers: false,
|
||||
// Settings
|
||||
elementsWrapper: '',
|
||||
stringsWrapper: '"',
|
||||
tableAdd: false,
|
||||
viewAdd: false,
|
||||
triggerAdd: false,
|
||||
|
@@ -21,6 +21,8 @@ module.exports = {
|
||||
functions: true,
|
||||
schedulers: true,
|
||||
// Settings
|
||||
elementsWrapper: '',
|
||||
stringsWrapper: '"',
|
||||
tableAdd: true,
|
||||
viewAdd: true,
|
||||
triggerAdd: true,
|
||||
|
@@ -18,6 +18,8 @@ module.exports = {
|
||||
routines: true,
|
||||
functions: true,
|
||||
// Settings
|
||||
elementsWrapper: '"',
|
||||
stringsWrapper: '\'',
|
||||
tableAdd: true,
|
||||
viewAdd: true,
|
||||
triggerAdd: true,
|
||||
|
@@ -4,6 +4,7 @@ export const TEXT = [
|
||||
'CHARACTER',
|
||||
'CHARACTER VARYING'
|
||||
];
|
||||
|
||||
export const LONG_TEXT = [
|
||||
'TEXT',
|
||||
'MEDIUMTEXT',
|
||||
@@ -50,6 +51,7 @@ export const BOOLEAN = [
|
||||
];
|
||||
|
||||
export const DATE = ['DATE'];
|
||||
|
||||
export const TIME = [
|
||||
'TIME',
|
||||
'TIME WITH TIME ZONE'
|
||||
|
@@ -51,8 +51,7 @@ async function createMainWindow () {
|
||||
// const toolName = await installExtension(VUEJS3_DEVTOOLS);
|
||||
// console.log(toolName, 'installed');
|
||||
}
|
||||
else
|
||||
await window.loadURL(new URL(`file:///${path.join(__dirname, 'index.html')}`).href);
|
||||
else await window.loadURL(new URL(`file:///${path.join(__dirname, 'index.html')}`).href);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
@@ -70,10 +69,9 @@ async function createMainWindow () {
|
||||
});
|
||||
|
||||
return window;
|
||||
};
|
||||
}
|
||||
|
||||
if (!gotTheLock)
|
||||
app.quit();
|
||||
if (!gotTheLock) app.quit();
|
||||
else {
|
||||
require('@electron/remote/main').initialize();
|
||||
|
||||
@@ -83,33 +81,53 @@ else {
|
||||
// quit application when all windows are closed
|
||||
app.on('window-all-closed', () => {
|
||||
// on macOS it is common for applications to stay open until the user explicitly quits
|
||||
if (process.platform !== 'darwin')
|
||||
app.quit();
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
||||
|
||||
app.on('activate', async () => {
|
||||
// on macOS it is common to re-create a window even after all windows have been closed
|
||||
if (mainWindow === null) {
|
||||
mainWindow = await createMainWindow();
|
||||
if (isDevelopment)
|
||||
mainWindow.webContents.openDevTools();
|
||||
if (isDevelopment) mainWindow.webContents.openDevTools();
|
||||
}
|
||||
});
|
||||
|
||||
// create main BrowserWindow when electron is ready
|
||||
app.on('ready', async () => {
|
||||
mainWindow = await createMainWindow();
|
||||
Menu.setApplicationMenu(null);
|
||||
createAppMenu();
|
||||
|
||||
if (isDevelopment)
|
||||
mainWindow.webContents.openDevTools();
|
||||
if (isDevelopment) mainWindow.webContents.openDevTools();
|
||||
|
||||
process.on('uncaughtException', error => {
|
||||
process.on('uncaughtException', (error) => {
|
||||
mainWindow.webContents.send('unhandled-exception', error);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', error => {
|
||||
process.on('unhandledRejection', (error) => {
|
||||
mainWindow.webContents.send('unhandled-exception', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createAppMenu () {
|
||||
let menu = null;
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
menu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: app.name,
|
||||
submenu: [
|
||||
{
|
||||
role: 'about'
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
role: 'quit'
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
Menu.setApplicationMenu(menu);
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ export default (connections) => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('get-table-data', async (event, { uid, schema, table, limit, page, sortParams }) => {
|
||||
ipcMain.handle('get-table-data', async (event, { uid, schema, table, limit, page, sortParams, where }) => {
|
||||
try {
|
||||
const offset = (page - 1) * limit;
|
||||
const query = connections[uid]
|
||||
@@ -29,6 +29,9 @@ export default (connections) => {
|
||||
if (sortParams && sortParams.field && sortParams.dir)
|
||||
query.orderBy({ [sortParams.field]: sortParams.dir.toUpperCase() });
|
||||
|
||||
if (where)
|
||||
query.where(where);
|
||||
|
||||
const result = await query.run({ details: true, schema });
|
||||
|
||||
return { status: 'success', response: result };
|
||||
|
@@ -36,6 +36,26 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
};
|
||||
}
|
||||
|
||||
_reducer (acc, curr) {
|
||||
const type = typeof curr;
|
||||
|
||||
switch (type) {
|
||||
case 'number':
|
||||
case 'string':
|
||||
return [...acc, curr];
|
||||
case 'object':
|
||||
if (Array.isArray(curr))
|
||||
return [...acc, ...curr];
|
||||
else {
|
||||
const clausoles = [];
|
||||
for (const key in curr)
|
||||
clausoles.push(`"${key}" ${curr[key]}`);
|
||||
|
||||
return clausoles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getTypeInfo (type) {
|
||||
return dataTypes
|
||||
.reduce((acc, group) => [...acc, ...group.types], [])
|
||||
@@ -1065,7 +1085,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
const typeInfo = this._getTypeInfo(field.type);
|
||||
const length = typeInfo.length ? field.enumValues || field.numLength || field.charLength || field.datePrecision : false;
|
||||
|
||||
newColumns.push(`${field.name}
|
||||
newColumns.push(`"${field.name}"
|
||||
${field.type.toUpperCase()}${length ? `(${length})` : ''}
|
||||
${field.unsigned ? 'UNSIGNED' : ''}
|
||||
${field.zerofill ? 'ZEROFILL' : ''}
|
||||
|
@@ -28,12 +28,11 @@
|
||||
<button
|
||||
class="btn btn-dark btn-sm mr-0 pr-1 d-flex"
|
||||
:class="{'loading':isQuering}"
|
||||
title="F5"
|
||||
:title="`${$t('word.refresh')} (F5)`"
|
||||
@click="getProcessesList"
|
||||
>
|
||||
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh mr-1" />
|
||||
<i v-else class="mdi mdi-24px mdi-history mdi-flip-h mr-1" />
|
||||
<span>{{ $t('word.refresh') }}</span>
|
||||
</button>
|
||||
<div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
|
@@ -586,11 +586,15 @@ export default {
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
await this.addWorkspace(this.connection.uid);
|
||||
const isInitiated = await Connection.checkConnection(this.connection.uid);
|
||||
if (isInitiated)
|
||||
this.connectWorkspace(this.connection);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addWorkspace: 'workspaces/addWorkspace',
|
||||
@@ -604,6 +608,25 @@ export default {
|
||||
addQueryTab () {
|
||||
this.newTab({ uid: this.connection.uid, type: 'query' });
|
||||
},
|
||||
getSelectedTab () {
|
||||
return this.workspace.tabs.find(tab => tab.uid === this.selectedTab);
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!this.isSelected)
|
||||
return;
|
||||
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode === 84 && !e.altKey) { // CTRL|Command + t
|
||||
this.addQueryTab();
|
||||
}
|
||||
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode === 87 && !e.altKey) { // CTRL|Command + w
|
||||
const currentTab = this.getSelectedTab();
|
||||
if (currentTab)
|
||||
this.closeTab(currentTab);
|
||||
}
|
||||
},
|
||||
openAsPermanentTab (tab) {
|
||||
const permanentTabs = {
|
||||
table: 'data',
|
||||
|
@@ -4,7 +4,7 @@
|
||||
class="workspace-query-tab column col-12 columns col-gapless no-outline p-0"
|
||||
tabindex="0"
|
||||
@keydown.116="runQuery(query)"
|
||||
@keydown.ctrl.87="clear"
|
||||
@keydown.ctrl.alt.87="clear"
|
||||
@keydown.ctrl.66="beautify"
|
||||
@keydown.ctrl.71="openHistoryModal"
|
||||
>
|
||||
|
@@ -14,6 +14,12 @@
|
||||
<div class="mb-4">
|
||||
{{ $t('word.history') }}
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
{{ $t('message.openNewTab') }}
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
{{ $t('message.closeTab') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-16">
|
||||
<div class="mb-4">
|
||||
@@ -23,11 +29,17 @@
|
||||
<code>CTRL</code> + <code>B</code>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<code>CTRL</code> + <code>W</code>
|
||||
<code>CTRL</code> + <code>ALT</code> + <code>W</code>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<code>CTRL</code> + <code>G</code>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<code>CTRL</code> + <code>T</code>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<code>CTRL</code> + <code>W</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -5,6 +5,8 @@
|
||||
tabindex="0"
|
||||
:style="{'height': resultsSize+'px'}"
|
||||
@keyup.46="showDeleteConfirmModal"
|
||||
@keydown.ctrl.65="selectAllRows"
|
||||
@keydown.esc="deselectRows"
|
||||
>
|
||||
<TableContext
|
||||
v-if="isContext"
|
||||
@@ -448,6 +450,15 @@ export default {
|
||||
else
|
||||
this.selectedRows = [row];
|
||||
},
|
||||
selectAllRows () {
|
||||
this.selectedRows = this.localResults.reduce((acc, curr) => {
|
||||
acc.push(curr._id);
|
||||
return acc;
|
||||
}, []);
|
||||
},
|
||||
deselectRows () {
|
||||
this.selectedRows = [];
|
||||
},
|
||||
contextMenu (event, cell) {
|
||||
if (event.target.localName === 'input') return;
|
||||
|
||||
|
@@ -8,12 +8,11 @@
|
||||
<button
|
||||
class="btn btn-dark btn-sm mr-0 pr-1"
|
||||
:class="{'loading':isQuering}"
|
||||
title="F5"
|
||||
:title="`${$t('word.refresh')} (F5)`"
|
||||
@click="reloadTable"
|
||||
>
|
||||
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh mr-1" />
|
||||
<i v-else class="mdi mdi-24px mdi-history mdi-flip-h mr-1" />
|
||||
<span>{{ $t('word.refresh') }}</span>
|
||||
</button>
|
||||
<div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
@@ -71,6 +70,14 @@
|
||||
|
||||
<div class="divider-vert py-3" />
|
||||
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
:title="`${$t('word.filter')} (CTRL+F)`"
|
||||
:class="{'btn-primary': isSearch, 'btn-dark': !isSearch}"
|
||||
@click="isSearch = !isSearch"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-magnify" />
|
||||
</button>
|
||||
<button
|
||||
v-if="isTable"
|
||||
class="btn btn-dark btn-sm"
|
||||
@@ -121,6 +128,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<WorkspaceTabTableFilters
|
||||
v-if="isSearch"
|
||||
:fields="fields"
|
||||
:conn-client="connection.client"
|
||||
@filter="updateFilters"
|
||||
@filter-change="onFilterChange"
|
||||
/>
|
||||
<div class="workspace-query-results p-relative column col-12">
|
||||
<BaseLoader v-if="isQuering" />
|
||||
<WorkspaceTabQueryTable
|
||||
@@ -160,6 +174,7 @@
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable';
|
||||
import WorkspaceTabTableFilters from '@/components/WorkspaceTabTableFilters';
|
||||
import ModalNewTableRow from '@/components/ModalNewTableRow';
|
||||
import ModalFakerRows from '@/components/ModalFakerRows';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
@@ -170,6 +185,7 @@ export default {
|
||||
components: {
|
||||
BaseLoader,
|
||||
WorkspaceTabQueryTable,
|
||||
WorkspaceTabTableFilters,
|
||||
ModalNewTableRow,
|
||||
ModalFakerRows
|
||||
},
|
||||
@@ -192,6 +208,7 @@ export default {
|
||||
tabUid: 'data', // ???
|
||||
isQuering: false,
|
||||
isPageMenu: false,
|
||||
isSearch: false,
|
||||
results: [],
|
||||
lastTable: null,
|
||||
isAddModal: false,
|
||||
@@ -199,6 +216,7 @@ export default {
|
||||
autorefreshTimer: 0,
|
||||
refreshInterval: null,
|
||||
sortParams: {},
|
||||
filters: [],
|
||||
page: 1,
|
||||
pageProxy: 1,
|
||||
approximateCount: 0
|
||||
@@ -271,6 +289,13 @@ export default {
|
||||
if (this.lastTable !== this.table)
|
||||
this.getTableData();
|
||||
}
|
||||
},
|
||||
isSearch (val) {
|
||||
if (this.filters.length > 0 && !val) {
|
||||
this.filters = [];
|
||||
this.getTableData();
|
||||
}
|
||||
this.resizeScroller();
|
||||
}
|
||||
},
|
||||
created () {
|
||||
@@ -302,7 +327,8 @@ export default {
|
||||
table: this.table,
|
||||
limit: this.limit,
|
||||
page: this.page,
|
||||
sortParams: this.sortParams
|
||||
sortParams: this.sortParams,
|
||||
where: this.filters || []
|
||||
};
|
||||
|
||||
try { // Table data
|
||||
@@ -389,11 +415,13 @@ export default {
|
||||
if (e.key === 'F5')
|
||||
this.reloadTable();
|
||||
|
||||
if (e.ctrlKey) {
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
if (e.key === 'ArrowRight')
|
||||
this.pageChange('next');
|
||||
if (e.key === 'ArrowLeft')
|
||||
this.pageChange('prev');
|
||||
if (e.keyCode === 70) // f
|
||||
this.isSearch = !this.isSearch;
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -410,6 +438,18 @@ export default {
|
||||
},
|
||||
downloadTable (format) {
|
||||
this.$refs.queryTable.downloadTable(format, this.table);
|
||||
},
|
||||
onFilterChange (clausoles) {
|
||||
this.resizeScroller();
|
||||
if (clausoles.length === 0)
|
||||
this.isSearch = false;
|
||||
},
|
||||
resizeScroller () {
|
||||
setTimeout(() => this.$refs.queryTable.refreshScroller(), 1);
|
||||
},
|
||||
updateFilters (clausoles) {
|
||||
this.filters = clausoles;
|
||||
this.getTableData();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
175
src/renderer/components/WorkspaceTabTableFilters.vue
Normal file
175
src/renderer/components/WorkspaceTabTableFilters.vue
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<form class="workspace-table-filters" @submit.prevent="doFilter">
|
||||
<div
|
||||
v-for="(row, index) of rows"
|
||||
:key="index"
|
||||
class="workspace-table-filters-row"
|
||||
>
|
||||
<label class="form-checkbox my-0">
|
||||
<input
|
||||
v-model="row.active"
|
||||
type="checkbox"
|
||||
@change="doFilter"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
<select v-model="row.field" class="form-select col-auto select-sm">
|
||||
<option
|
||||
v-for="(item, j) of fields"
|
||||
:key="j"
|
||||
:value="item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-model="row.op" class="form-select ml-2 col-auto select-sm">
|
||||
<option
|
||||
v-for="(operator, k) of operators"
|
||||
:key="k"
|
||||
:value="operator"
|
||||
>
|
||||
{{ operator }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="workspace-table-filters-row-value ml-2">
|
||||
<input
|
||||
v-if="!row.op.includes('NULL')"
|
||||
v-model="row.value"
|
||||
type="text"
|
||||
class="form-input input-sm"
|
||||
>
|
||||
<input
|
||||
v-if="row.op === 'BETWEEN'"
|
||||
v-model="row.value2"
|
||||
type="text"
|
||||
class="form-input ml-2 input-sm"
|
||||
>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-sm btn-dark mr-0 ml-2"
|
||||
type="button"
|
||||
@click="removeRow(index)"
|
||||
>
|
||||
<i class="mdi mdi-minus-circle-outline" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="workspace-table-filters-buttons">
|
||||
<button
|
||||
class="btn btn-sm btn-primary mr-0 ml-2"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('word.filter') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-dark mr-0 ml-2"
|
||||
type="button"
|
||||
@click="addRow"
|
||||
>
|
||||
<i class="mdi mdi-plus-circle-outline" />
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import customizations from 'common/customizations';
|
||||
import { NUMBER, FLOAT } from 'common/fieldTypes';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
fields: Array,
|
||||
connClient: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
rows: [],
|
||||
operators: [
|
||||
'=', '!=', '>', '<', '>=', '<=', 'IN', 'NOT IN', 'LIKE', 'BETWEEN', 'IS NULL', 'IS NOT NULL'
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
customizations () {
|
||||
return customizations[this.connClient];
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.addRow();
|
||||
},
|
||||
methods: {
|
||||
addRow () {
|
||||
this.rows.push({ active: true, field: this.fields[0].name, op: '=', value: '', value2: '' });
|
||||
this.$emit('filter-change', this.rows);
|
||||
},
|
||||
removeRow (i) {
|
||||
this.rows = this.rows.filter((_, idx) => idx !== i);
|
||||
this.$emit('filter-change', this.rows);
|
||||
},
|
||||
doFilter () {
|
||||
const clausoles = this.rows.filter(el => el.active).map(el => this.createClausole(el));
|
||||
this.$emit('filter', clausoles);
|
||||
},
|
||||
createClausole (filter) {
|
||||
const field = this.fields.find(field => field.name === filter.field);
|
||||
const isNumeric = [...NUMBER, ...FLOAT].includes(field.type);
|
||||
const { elementsWrapper: ew, stringsWrapper: sw } = this.customizations;
|
||||
let value;
|
||||
|
||||
switch (filter.op) {
|
||||
case '=':
|
||||
case '!=':
|
||||
value = isNumeric ? filter.value : `${sw}${filter.value}${sw}`;
|
||||
break;
|
||||
case 'BETWEEN':
|
||||
value = isNumeric ? filter.value : `${sw}${filter.value}${sw}`;
|
||||
value += ' AND ';
|
||||
value += isNumeric ? filter.value2 : `${sw}${filter.value2}${sw}`;
|
||||
break;
|
||||
case 'IN':
|
||||
case 'NOT IN':
|
||||
value = filter.value.split(',').map(val => {
|
||||
val = val.trim();
|
||||
return isNumeric ? val : `${sw}${val}${sw}`;
|
||||
}).join(',');
|
||||
value = `(${filter.value})`;
|
||||
break;
|
||||
case 'IS NULL':
|
||||
case 'IS NOT NULL':
|
||||
value = '';
|
||||
break;
|
||||
default:
|
||||
value = `${sw}${filter.value}${sw}`;
|
||||
}
|
||||
|
||||
if (isNumeric && !value.length && !['IS NULL', 'IS NOT NULL'].includes(filter.op))
|
||||
value = `${sw}${sw}`;
|
||||
|
||||
return `${ew}${filter.field}${ew} ${filter.op} ${value}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.workspace-table-filters {
|
||||
padding: 0 0.6rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.workspace-table-filters-buttons {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.workspace-table-filters-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.workspace-table-filters-row-value {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
@@ -120,7 +120,8 @@ module.exports = {
|
||||
new: 'New',
|
||||
history: 'History',
|
||||
select: 'Select',
|
||||
passphrase: 'Passphrase'
|
||||
passphrase: 'Passphrase',
|
||||
filter: 'Filter'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Welcome to Antares SQL Client!',
|
||||
@@ -244,7 +245,8 @@ module.exports = {
|
||||
newTriggerFunction: 'New trigger function',
|
||||
thereIsNoQueriesYet: 'There is no queries yet',
|
||||
searchForQueries: 'Search for queries',
|
||||
killProcess: 'Kill process'
|
||||
killProcess: 'Kill process',
|
||||
closeTab: 'Close tab'
|
||||
},
|
||||
faker: {
|
||||
address: 'Address',
|
||||
|
@@ -115,7 +115,13 @@ module.exports = {
|
||||
cell: 'Cella | Celle',
|
||||
triggerFunction: 'Funzione di trigger | Funzioni di trigger',
|
||||
all: 'Tutto',
|
||||
duplicate: 'Duplica'
|
||||
duplicate: 'Duplica',
|
||||
routine: 'Routine',
|
||||
new: 'Nuovo',
|
||||
history: 'Cronologia',
|
||||
select: 'Seleziona',
|
||||
passphrase: 'Passphrase',
|
||||
filter: 'Filtra'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Benvenuto in Antares SQL Client!',
|
||||
|
@@ -119,7 +119,8 @@ module.exports = {
|
||||
routine: 'Routine',
|
||||
new: 'Mới',
|
||||
history: 'Lịch sử',
|
||||
select: 'Chọn'
|
||||
select: 'Chọn',
|
||||
passphrase: 'Cụm mật khẩu'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Chào bạn đến với Antares SQL Client!',
|
||||
|
Reference in New Issue
Block a user