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

Compare commits

..

13 Commits

20 changed files with 150 additions and 98 deletions

View File

@@ -2,6 +2,33 @@
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. 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.7.19-beta.1](https://github.com/antares-sql/antares/compare/v0.7.19-beta.0...v0.7.19-beta.1) (2023-10-25)
### Features
* **MySQL:** RLIKE and NOT RLIKE regular expression filters, closes [#688](https://github.com/antares-sql/antares/issues/688) ([e4eb27d](https://github.com/antares-sql/antares/commit/e4eb27d503e8f912178359c01c62a9b523d17848))
### [0.7.19-beta.0](https://github.com/antares-sql/antares/compare/v0.7.18...v0.7.19-beta.0) (2023-10-14)
### Features
* "now" and "random" options added in datetime related data in insert rows tool, closes [#402](https://github.com/antares-sql/antares/issues/402) ([9f9c63b](https://github.com/antares-sql/antares/commit/9f9c63bfcc3423bfeef143cd835f48c62900a799))
### Bug Fixes
* IN and NOT IN filters not working properly, fixes [#687](https://github.com/antares-sql/antares/issues/687) ([c0dcf30](https://github.com/antares-sql/antares/commit/c0dcf30e73a69b25b01ba31d21b27c1983ed2db6))
* timeout issue on long time sql import ([ddd290c](https://github.com/antares-sql/antares/commit/ddd290c90344241eaa70cb528552e942fd7edec0))
### [0.7.18](https://github.com/antares-sql/antares/compare/v0.7.17...v0.7.18) (2023-10-03)
### Bug Fixes
* hotfix for Microsoft Store unauthorized process ([b3b698b](https://github.com/antares-sql/antares/commit/b3b698b3a23a3c848921ab40fc0fec5d8178ef0e))
### [0.7.17](https://github.com/antares-sql/antares/compare/v0.7.17-beta.2...v0.7.17) (2023-09-30) ### [0.7.17](https://github.com/antares-sql/antares/compare/v0.7.17-beta.2...v0.7.17) (2023-09-30)
### [0.7.17-beta.2](https://github.com/antares-sql/antares/compare/v0.7.17-beta.1...v0.7.17-beta.2) (2023-09-28) ### [0.7.17-beta.2](https://github.com/antares-sql/antares/compare/v0.7.17-beta.1...v0.7.17-beta.2) (2023-09-28)

View File

@@ -61,7 +61,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at reported to the community leaders responsible for enforcement at
fabio286@gmail.com. info@fabiodistasio.it.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

12
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "antares", "name": "antares",
"version": "0.7.17", "version": "0.7.19-beta.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "antares", "name": "antares",
"version": "0.7.17", "version": "0.7.19-beta.1",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -63,7 +63,7 @@
"chalk": "~4.1.2", "chalk": "~4.1.2",
"cross-env": "~7.0.2", "cross-env": "~7.0.2",
"css-loader": "~6.5.0", "css-loader": "~6.5.0",
"electron": "~22.3.23", "electron": "~22.3.27",
"electron-builder": "~22.10.3", "electron-builder": "~22.10.3",
"eslint": "~7.32.0", "eslint": "~7.32.0",
"eslint-config-standard": "~16.0.3", "eslint-config-standard": "~16.0.3",
@@ -5744,9 +5744,9 @@
} }
}, },
"node_modules/electron": { "node_modules/electron": {
"version": "22.3.23", "version": "22.3.27",
"resolved": "https://registry.npmjs.org/electron/-/electron-22.3.23.tgz", "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.27.tgz",
"integrity": "sha512-2p6NsLFPfM2RmgATchjKZKBUP3O6NxQMWOrHt9W5U2GRtfI8qWlicUR1wnh5D1VLt4c1YsjvpF6dct+1JNRubA==", "integrity": "sha512-7Rht21vHqj4ZFRnKuZdFqZFsvMBCmDqmjetiMqPtF+TmTBiGne1mnstVXOA/SRGhN2Qy5gY5bznJKpiqogjM8A==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@electron/get": "^2.0.0", "@electron/get": "^2.0.0",

View File

@@ -1,7 +1,7 @@
{ {
"name": "antares", "name": "antares",
"productName": "Antares", "productName": "Antares",
"version": "0.7.17", "version": "0.7.19-beta.1",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.", "description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT", "license": "MIT",
"repository": "https://github.com/antares-sql/antares.git", "repository": "https://github.com/antares-sql/antares.git",
@@ -27,7 +27,7 @@
"contributors:add": "all-contributors add", "contributors:add": "all-contributors add",
"contributors:generate": "all-contributors generate" "contributors:generate": "all-contributors generate"
}, },
"author": "Fabio Di Stasio <fabio286@gmail.com>", "author": "Fabio Di Stasio <info@fabiodistasio.it>",
"main": "./dist/main.js", "main": "./dist/main.js",
"antares": { "antares": {
"devtoolsId": "nhdogjmejiglipccpnnnanhbledajbpd" "devtoolsId": "nhdogjmejiglipccpnnnanhbledajbpd"
@@ -171,7 +171,7 @@
"chalk": "~4.1.2", "chalk": "~4.1.2",
"cross-env": "~7.0.2", "cross-env": "~7.0.2",
"css-loader": "~6.5.0", "css-loader": "~6.5.0",
"electron": "~22.3.23", "electron": "~22.3.27",
"electron-builder": "~22.10.3", "electron-builder": "~22.10.3",
"eslint": "~7.32.0", "eslint": "~7.32.0",
"eslint-config-standard": "~16.0.3", "eslint-config-standard": "~16.0.3",

View File

@@ -51,6 +51,7 @@ export default class {
{ name: 'collation', group: 'database', types: ['string'] }, { name: 'collation', group: 'database', types: ['string'] },
{ name: 'engine', group: 'database', types: ['string'] }, { name: 'engine', group: 'database', types: ['string'] },
{ name: 'now', group: 'date', types: ['string', 'datetime'] },
{ name: 'past', group: 'date', types: ['string', 'datetime'] }, { name: 'past', group: 'date', types: ['string', 'datetime'] },
{ name: 'future', group: 'date', types: ['string', 'datetime'] }, { name: 'future', group: 'date', types: ['string', 'datetime'] },
// { name: 'between', group: 'date', types: ['string'] }, // { name: 'between', group: 'date', types: ['string'] },
@@ -161,7 +162,9 @@ export default class {
{ name: 'filePath', group: 'system', types: ['string'] }, { name: 'filePath', group: 'system', types: ['string'] },
{ name: 'semver', group: 'system', types: ['string'] }, { name: 'semver', group: 'system', types: ['string'] },
{ name: 'now', group: 'time', types: ['string', 'time'] },
{ name: 'recent', group: 'time', types: ['string', 'time'] }, { name: 'recent', group: 'time', types: ['string', 'time'] },
{ name: 'random', group: 'time', types: ['string', 'time'] },
{ name: 'vehicle', group: 'vehicle', types: ['string'] }, { name: 'vehicle', group: 'vehicle', types: ['string'] },
{ name: 'manufacturer', group: 'vehicle', types: ['string'] }, { name: 'manufacturer', group: 'vehicle', types: ['string'] },

View File

@@ -9,6 +9,7 @@ export const defaults: Customizations = {
dataTypes: [], dataTypes: [],
indexTypes: [], indexTypes: [],
foreignActions: [], foreignActions: [],
operators: ['=', '!=', '>', '<', '>=', '<=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'BETWEEN', 'IS NULL', 'IS NOT NULL'],
// Core // Core
database: false, database: false,
collations: false, collations: false,

View File

@@ -9,6 +9,7 @@ export const customizations: Customizations = {
defaultUser: 'root', defaultUser: 'root',
defaultDatabase: null, defaultDatabase: null,
dataTypes: mysqlTypes, dataTypes: mysqlTypes,
operators: ['=', '!=', '>', '<', '>=', '<=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'RLIKE', 'NOT RLIKE', 'BETWEEN', 'IS NULL', 'IS NOT NULL'],
indexTypes: [ indexTypes: [
'PRIMARY', 'PRIMARY',
'INDEX', 'INDEX',

View File

@@ -363,8 +363,7 @@ export interface QueryBuilderObject {
offset: number; offset: number;
join: string[]; join: string[];
update: string[]; update: string[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any insert: {[key: string]: string | boolean | number }[];
insert: {[key: string]: any}[];
delete: boolean; delete: boolean;
} }

View File

@@ -1,4 +1,5 @@
import { TypesGroup } from './antares'; import { TypesGroup } from './antares';
import { TableFilterOperator } from './tableApis';
export interface Customizations { export interface Customizations {
// Defaults // Defaults
@@ -8,6 +9,7 @@ export interface Customizations {
dataTypes?: TypesGroup[]; dataTypes?: TypesGroup[];
indexTypes?: string[]; indexTypes?: string[];
foreignActions?: string[]; foreignActions?: string[];
operators?: TableFilterOperator[];
// Core // Core
database?: boolean; database?: boolean;
collations?: boolean; collations?: boolean;

View File

@@ -21,7 +21,7 @@ export interface TableDeleteParams {
rows: {[key: string]: any}; rows: {[key: string]: any};
} }
export type TableFilterOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'BETWEEN' | 'IS NULL' | 'IS NOT NULL' export type TableFilterOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'RLIKE' | 'NOT RLIKE' | 'BETWEEN' | 'IS NULL' | 'IS NOT NULL'
export interface TableFilterClausole { export interface TableFilterClausole {
active: boolean; active: boolean;

View File

@@ -0,0 +1,17 @@
import { faker } from '@faker-js/faker';
import * as moment from 'moment';
export const fakerCustom = {
seed: faker.seed,
setLocale: faker.setLocale,
...faker,
date: {
now: () => moment().format('YYYY-MM-DD HH:mm:ss'),
...faker.date
},
time: {
now: () => moment().format('HH:mm:ss'),
random: () => moment(faker.date.recent()).format('HH:mm:ss'),
...faker.time
}
};

View File

@@ -1,8 +1,8 @@
import { faker } from '@faker-js/faker';
import customizations from 'common/customizations'; import customizations from 'common/customizations';
import { ARRAY, BIT, BLOB, BOOLEAN, DATE, DATETIME, FLOAT, LONG_TEXT, NUMBER, TEXT, TEXT_SEARCH } from 'common/fieldTypes'; import { ARRAY, BIT, BLOB, BOOLEAN, DATE, DATETIME, FLOAT, LONG_TEXT, NUMBER, TEXT, TEXT_SEARCH } from 'common/fieldTypes';
import * as antares from 'common/interfaces/antares'; import * as antares from 'common/interfaces/antares';
import { InsertRowsParams } from 'common/interfaces/tableApis'; import { InsertRowsParams } from 'common/interfaces/tableApis';
import { fakerCustom } from 'common/libs/fakerCustom';
import { sqlEscaper } from 'common/libs/sqlUtils'; import { sqlEscaper } from 'common/libs/sqlUtils';
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import * as fs from 'fs'; import * as fs from 'fs';
@@ -371,19 +371,19 @@ export default (connections: {[key: string]: antares.Client}) => {
let fakeValue; let fakeValue;
if (params.locale) if (params.locale)
faker.locale = params.locale; fakerCustom.locale = params.locale;
if (Object.keys(params.row[key].params).length) { if (Object.keys(params.row[key].params).length) {
Object.keys(params.row[key].params).forEach(param => { Object.keys(params.row[key].params).forEach(param => {
if (!isNaN(params.row[key].params[param])) if (!isNaN(params.row[key].params[param]))// Converts string numerics params to number
parsedParams[param] = +params.row[key].params[param]; parsedParams[param] = Number(params.row[key].params[param]);
}); });
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
fakeValue = (faker as any)[params.row[key].group][params.row[key].method](parsedParams); fakeValue = (fakerCustom as any)[params.row[key].group][params.row[key].method](parsedParams);
} }
else else
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
fakeValue = (faker as any)[params.row[key].group][params.row[key].method](); fakeValue = (fakerCustom as any)[params.row[key].group][params.row[key].method]();
if (typeof fakeValue === 'string') { if (typeof fakeValue === 'string') {
if (params.row[key].length) if (params.row[key].length)

View File

@@ -256,10 +256,13 @@ export class MySQLClient extends AntaresCore {
} }
private async keepAlive () { private async keepAlive () {
try {
const connection = await (this._connection as mysql.Pool).getConnection(); const connection = await (this._connection as mysql.Pool).getConnection();
await connection.ping(); await connection.ping();
connection.release(); connection.release();
} }
catch (_) {}
}
use (schema: string) { use (schema: string) {
this._schema = schema; this._schema = schema;

View File

@@ -240,10 +240,13 @@ export class PostgreSQLClient extends AntaresCore {
} }
private async keepAlive () { private async keepAlive () {
try {
const connection = await this._connection.connect() as pg.PoolClient; const connection = await this._connection.connect() as pg.PoolClient;
await connection.query('SELECT 1+1'); await connection.query('SELECT 1+1');
connection.release(); connection.release();
} }
catch (_) {}
}
use (schema: string, connection?: pg.Client | pg.PoolClient) { use (schema: string, connection?: pg.Client | pg.PoolClient) {
this._schema = schema; this._schema = schema;

View File

@@ -6,6 +6,7 @@ const isWindows = process.platform === 'win32';
const indexPath = path.resolve(__dirname, 'index.html').split(path.sep).join('/'); const indexPath = path.resolve(__dirname, 'index.html').split(path.sep).join('/');
export function validateSender (frame: WebFrameMain) { export function validateSender (frame: WebFrameMain) {
if (process.windowsStore) return true; // TEMP HOTFIX
const frameUrl = new URL(frame.url); const frameUrl = new URL(frame.url);
const prefix = isWindows ? 'file:///' : 'file://'; const prefix = isWindows ? 'file:///' : 'file://';
const framePath = frameUrl.href.replace(prefix, ''); const framePath = frameUrl.href.replace(prefix, '');

View File

@@ -27,11 +27,7 @@
:title="t('general.cancel')" :title="t('general.cancel')"
@click="killTabQuery()" @click="killTabQuery()"
> >
<BaseIcon <BaseIcon icon-name="mdiWindowClose" :size="24" />
class="mr-1"
icon-name="mdiWindowCLose"
:size="24"
/>
<span class="d-invisible pr-1">{{ t('general.run') }}</span> <span class="d-invisible pr-1">{{ t('general.run') }}</span>
</button> </button>
<button <button

View File

@@ -3,7 +3,7 @@
ref="tableWrapper" ref="tableWrapper"
class="vscroll no-outline" class="vscroll no-outline"
tabindex="0" tabindex="0"
:style="{'height': resultsSize+'px'}" :style="{ 'height': resultsSize + 'px' }"
@blur="deselectRows" @blur="deselectRows"
@focus="hasFocus = true" @focus="hasFocus = true"
@keyup.delete="showDeleteConfirmModal" @keyup.delete="showDeleteConfirmModal"
@@ -28,7 +28,7 @@
v-for="(result, index) in resultsWithRows" v-for="(result, index) in resultsWithRows"
:key="index" :key="index"
class="tab-item" class="tab-item"
:class="{'active': resultsetIndex === index}" :class="{ 'active': resultsetIndex === index }"
@click="selectResultset(index)" @click="selectResultset(index)"
> >
<a>{{ result.fields ? result.fields[0]?.table : '' }} ({{ result.rows.length }})</a> <a>{{ result.fields ? result.fields[0]?.table : '' }} ({{ result.rows.length }})</a>
@@ -57,7 +57,7 @@
<span>{{ field.alias || field.name }}</span> <span>{{ field.alias || field.name }}</span>
<BaseIcon <BaseIcon
v-if="isSortable && currentSort === field.name || currentSort === `${field.table}.${field.name}`" v-if="isSortable && currentSort === field.name || currentSort === `${field.table}.${field.name}`"
:icon-name="currentSortDir === 'asc' ? 'mdiSortAscending':'mdiSortDescending'" :icon-name="currentSortDir === 'asc' ? 'mdiSortAscending' : 'mdiSortDescending'"
:size="18" :size="18"
class="sort-icon ml-1" class="sort-icon ml-1"
/> />
@@ -90,7 +90,7 @@
:fields="fieldsObj" :fields="fieldsObj"
:key-usage="keyUsage" :key-usage="keyUsage"
:element-type="elementType" :element-type="elementType"
:class="{'selected': selectedRows.includes(row._antares_id)}" :class="{ 'selected': selectedRows.includes(row._antares_id) }"
:selected="selectedRows.includes(row._antares_id)" :selected="selectedRows.includes(row._antares_id)"
:selected-cell="selectedRows.length === 1 && selectedRows.includes(row._antares_id) ? selectedField : null" :selected-cell="selectedRows.length === 1 && selectedRows.includes(row._antares_id) ? selectedField : null"
@start-editing="isEditingRow = true" @start-editing="isEditingRow = true"
@@ -163,7 +163,7 @@
<BaseSelect <BaseSelect
v-model="sqlExportOptions.sqlInsertDivider" v-model="sqlExportOptions.sqlInsertDivider"
class="form-select" class="form-select"
:options="[{value: 'bytes', label: 'KiB'}, {value: 'rows', label: t('database.row', 2)}]" :options="[{ value: 'bytes', label: 'KiB' }, { value: 'rows', label: t('database.row', 2) }]"
/> />
</div> </div>
</div> </div>
@@ -208,9 +208,9 @@
v-model="csvExportOptions.stringDelimiter" v-model="csvExportOptions.stringDelimiter"
class="form-select" class="form-select"
:options="[ :options="[
{value: '', label: t('general.none')}, { value: '', label: t('general.none') },
{value: 'single', label: t('general.singleQuote')}, { value: 'single', label: t('general.singleQuote') },
{value: 'double', label: t('general.doubleQuote')} { value: 'double', label: t('general.doubleQuote') }
]" ]"
/> />
</div> </div>
@@ -235,7 +235,10 @@
</label> </label>
</div> </div>
<div class="column col-7"> <div class="column col-7">
<label class="form-switch d-inline-block" @click.prevent="csvExportOptions.header = !csvExportOptions.header"> <label
class="form-switch d-inline-block"
@click.prevent="csvExportOptions.header = !csvExportOptions.header"
>
<input type="checkbox" :checked="csvExportOptions.header"> <input type="checkbox" :checked="csvExportOptions.header">
<i class="form-icon" /> <i class="form-icon" />
</label> </label>
@@ -249,10 +252,10 @@
<script setup lang="ts"> <script setup lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import faker from '@faker-js/faker';
import { BLOB, DATE, DATETIME, LONG_TEXT, TEXT, TIME } from 'common/fieldTypes'; import { BLOB, DATE, DATETIME, LONG_TEXT, TEXT, TIME } from 'common/fieldTypes';
import { QueryResult, TableField } from 'common/interfaces/antares'; import { QueryResult, TableField } from 'common/interfaces/antares';
import { TableUpdateParams } from 'common/interfaces/tableApis'; import { TableUpdateParams } from 'common/interfaces/tableApis';
import { fakerCustom } from 'common/libs/fakerCustom';
import { jsonToSqlInsert } from 'common/libs/sqlUtils'; import { jsonToSqlInsert } from 'common/libs/sqlUtils';
import { uidGen } from 'common/libs/uidGen'; import { uidGen } from 'common/libs/uidGen';
import * as json2php from 'json2php'; import * as json2php from 'json2php';
@@ -299,7 +302,7 @@ const emit = defineEmits([
'duplicate-row' 'duplicate-row'
]); ]);
const resultTable: Ref<Component & {updateWindow: () => void}> = ref(null); const resultTable: Ref<Component & { updateWindow: () => void }> = ref(null);
const tableWrapper: Ref<HTMLDivElement> = ref(null); const tableWrapper: Ref<HTMLDivElement> = ref(null);
const table: Ref<HTMLDivElement> = ref(null); const table: Ref<HTMLDivElement> = ref(null);
const resultsSize = ref(0); const resultsSize = ref(0);
@@ -377,7 +380,7 @@ const keyUsage = computed(() => resultsWithRows.value.length ? resultsWithRows.v
const fieldsObj = computed(() => { const fieldsObj = computed(() => {
if (sortedResults.value.length) { if (sortedResults.value.length) {
const fieldsObj: {[key: string]: TableField} = {}; const fieldsObj: { [key: string]: TableField } = {};
for (const key in sortedResults.value[0]) { for (const key in sortedResults.value[0]) {
if (key === '_antares_id') continue; if (key === '_antares_id') continue;
@@ -483,7 +486,7 @@ const resizeResults = () => {
const refreshScroller = () => resizeResults(); const refreshScroller = () => resizeResults();
const updateField = (payload: { field: string; type: string; content: any }, row: {[key: string]: any}) => { const updateField = (payload: { field: string; type: string; content: any }, row: { [key: string]: any }) => {
const orgRow: any = localResults.value.find((lr: any) => lr._antares_id === row._antares_id); const orgRow: any = localResults.value.find((lr: any) => lr._antares_id === row._antares_id);
Object.keys(orgRow).forEach(key => { // remap the row Object.keys(orgRow).forEach(key => { // remap the row
@@ -598,7 +601,7 @@ const copyRow = (format: string) => {
json: contentToCopy, json: contentToCopy,
client: workspaceClient.value, client: workspaceClient.value,
fields: fieldsObj.value as { fields: fieldsObj.value as {
[key: string]: {type: string; datePrecision: number}; [key: string]: { type: string; datePrecision: number };
}, },
table: getTable(resultsetIndex.value) table: getTable(resultsetIndex.value)
}); });
@@ -670,16 +673,7 @@ const fillCell = (event: { name: string; group: string; type: string }) => {
datePrecision += i === 0 ? '.S' : 'S'; datePrecision += i === 0 ? '.S' : 'S';
} }
if (event.group === 'custom') { fakeValue = (fakerCustom as any)[event.group][event.name]();
if (event.type === 'time' && event.name === 'now')
fakeValue = moment().format(`HH:mm:ss${datePrecision}`);
else if (event.type === 'time' && event.name === 'random')
fakeValue = moment(faker.date.recent()).format(`HH:mm:ss${datePrecision}`);
else if (event.type === 'datetime' && event.name === 'now')
fakeValue = moment().format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
}
else {
fakeValue = (faker as any)[event.group][event.name]();
if (['string', 'number'].includes(typeof fakeValue)) { if (['string', 'number'].includes(typeof fakeValue)) {
if (typeof fakeValue === 'number') if (typeof fakeValue === 'number')
fakeValue = String(fakeValue); fakeValue = String(fakeValue);
@@ -691,7 +685,6 @@ const fillCell = (event: { name: string; group: string; type: string }) => {
fakeValue = moment(fakeValue).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`); fakeValue = moment(fakeValue).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
else if (TIME.includes(selectedCell.value.type)) else if (TIME.includes(selectedCell.value.type))
fakeValue = moment(fakeValue).format(`HH:mm:ss${datePrecision}`); fakeValue = moment(fakeValue).format(`HH:mm:ss${datePrecision}`);
}
const params = { const params = {
primary: primaryField.value?.name, primary: primaryField.value?.name,
@@ -859,12 +852,12 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, po
type: format, type: format,
content: rows, content: rows,
fields: JSON.parse(JSON.stringify(fieldsObj.value)) as { fields: JSON.parse(JSON.stringify(fieldsObj.value)) as {
[key: string]: {type: string; datePrecision: number}; [key: string]: { type: string; datePrecision: number };
}, },
client: workspaceClient.value, client: workspaceClient.value,
table, table,
sqlOptions: popup ? { ...sqlExportOptions.value }: null, sqlOptions: popup ? { ...sqlExportOptions.value } : null,
csvOptions: popup ? { ...csvExportOptions.value }: null csvOptions: popup ? { ...csvExportOptions.value } : null
}); });
}; };
@@ -897,7 +890,7 @@ const onKey = async (e: KeyboardEvent) => {
if (!(e.ctrlKey || e.metaKey) && (e.code.includes('Arrow') || e.code === 'Tab') && sortedResults.value.length > 0 && !e.altKey) { if (!(e.ctrlKey || e.metaKey) && (e.code.includes('Arrow') || e.code === 'Tab') && sortedResults.value.length > 0 && !e.altKey) {
e.preventDefault(); e.preventDefault();
const aviableFields= Object.keys(sortedResults.value[0]).slice(0, -1); // removes _antares_id const aviableFields = Object.keys(sortedResults.value[0]).slice(0, -1); // removes _antares_id
if (!selectedField.value) if (!selectedField.value)
selectedField.value = aviableFields[0]; selectedField.value = aviableFields[0];
@@ -914,8 +907,8 @@ const onKey = async (e: KeyboardEvent) => {
nextIndex = selectedIndex + 1; nextIndex = selectedIndex + 1;
nextFieldIndex = selectedFieldIndex; nextFieldIndex = selectedFieldIndex;
if (nextIndex > sortedResults.value.length -1) if (nextIndex > sortedResults.value.length - 1)
nextIndex = sortedResults.value.length -1; nextIndex = sortedResults.value.length - 1;
break; break;
case 'ArrowUp': case 'ArrowUp':
@@ -931,7 +924,7 @@ const onKey = async (e: KeyboardEvent) => {
nextIndex = selectedIndex; nextIndex = selectedIndex;
nextFieldIndex = selectedFieldIndex + 1; nextFieldIndex = selectedFieldIndex + 1;
if (nextFieldIndex > aviableFields.length -1) if (nextFieldIndex > aviableFields.length - 1)
nextFieldIndex = 0; nextFieldIndex = 0;
break; break;
@@ -941,7 +934,7 @@ const onKey = async (e: KeyboardEvent) => {
nextFieldIndex = selectedFieldIndex - 1; nextFieldIndex = selectedFieldIndex - 1;
if (nextFieldIndex < 0) if (nextFieldIndex < 0)
nextFieldIndex = aviableFields.length -1; nextFieldIndex = aviableFields.length - 1;
break; break;
@@ -950,11 +943,11 @@ const onKey = async (e: KeyboardEvent) => {
if (e.shiftKey) { if (e.shiftKey) {
nextFieldIndex = selectedFieldIndex - 1; nextFieldIndex = selectedFieldIndex - 1;
if (nextFieldIndex < 0) if (nextFieldIndex < 0)
nextFieldIndex = aviableFields.length -1; nextFieldIndex = aviableFields.length - 1;
} }
else { else {
nextFieldIndex = selectedFieldIndex + 1; nextFieldIndex = selectedFieldIndex + 1;
if (nextFieldIndex > aviableFields.length -1) if (nextFieldIndex > aviableFields.length - 1)
nextFieldIndex = 0; nextFieldIndex = 0;
} }
} }
@@ -1055,6 +1048,7 @@ onUnmounted(() => {
} }
.column-resizable { .column-resizable {
&:hover, &:hover,
&:active { &:active {
resize: horizontal; resize: horizontal;

View File

@@ -197,13 +197,13 @@ const fakerMethods = {
{ name: 'amount', group: 'finance' } { name: 'amount', group: 'finance' }
], ],
datetime: [ datetime: [
{ name: 'now', group: 'custom' }, { name: 'now', group: 'date' },
{ name: 'past', group: 'date' }, { name: 'past', group: 'date' },
{ name: 'future', group: 'date' } { name: 'future', group: 'date' }
], ],
time: [ time: [
{ name: 'now', group: 'custom' }, { name: 'now', group: 'time' },
{ name: 'random', group: 'custom' } { name: 'random', group: 'time' }
], ],
uuid: [ uuid: [
{ name: 'uuid', group: 'random' } { name: 'uuid', group: 'random' }

View File

@@ -183,6 +183,7 @@
<WorkspaceTabTableFilters <WorkspaceTabTableFilters
v-if="isSearch" v-if="isSearch"
:fields="fields" :fields="fields"
:is-quering="isQuering"
:conn-client="connection.client" :conn-client="connection.client"
@filter="updateFilters" @filter="updateFilters"
@filter-change="onFilterChange" @filter-change="onFilterChange"

View File

@@ -9,6 +9,7 @@
<input <input
v-model="row.active" v-model="row.active"
type="checkbox" type="checkbox"
:disabled="isQuering"
@change="doFilter" @change="doFilter"
><i class="form-icon" /> ><i class="form-icon" />
</label> </label>
@@ -18,11 +19,13 @@
:options="fields" :options="fields"
option-track-by="name" option-track-by="name"
option-label="name" option-label="name"
:disabled="isQuering"
/> />
<BaseSelect <BaseSelect
v-model="row.op" v-model="row.op"
class="form-select ml-2 col-auto select-sm" class="form-select ml-2 col-auto select-sm"
:options="operators" :options="operators"
:disabled="isQuering"
/> />
<div class="workspace-table-filters-row-value ml-2"> <div class="workspace-table-filters-row-value ml-2">
<input <input
@@ -30,12 +33,14 @@
v-model="row.value" v-model="row.value"
type="text" type="text"
class="form-input input-sm" class="form-input input-sm"
:disabled="isQuering"
> >
<input <input
v-if="row.op === 'BETWEEN'" v-if="row.op === 'BETWEEN'"
v-model="row.value2" v-model="row.value2"
type="text" type="text"
class="form-input ml-2 input-sm" class="form-input ml-2 input-sm"
:disabled="isQuering"
> >
</div> </div>
<button <button
@@ -87,15 +92,14 @@ const { t } = useI18n();
const props = defineProps({ const props = defineProps({
fields: Array as Prop<TableField[]>, fields: Array as Prop<TableField[]>,
connClient: String as Prop<ClientCode> connClient: String as Prop<ClientCode>,
isQuering: Boolean
}); });
const emit = defineEmits(['filter-change', 'filter']); const emit = defineEmits(['filter-change', 'filter']);
const rows = ref([]); const rows = ref([]);
const operators = ref<TableFilterOperator[]>([ const operators: TableFilterOperator[] = customizations[props.connClient].operators;
'=', '!=', '>', '<', '>=', '<=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'BETWEEN', 'IS NULL', 'IS NOT NULL'
]);
const clientCustomizations = computed(() => customizations[props.connClient]); const clientCustomizations = computed(() => customizations[props.connClient]);
@@ -122,7 +126,7 @@ const createClausole = (filter: TableFilterClausole) => {
const { elementsWrapper: ew, stringsWrapper: sw } = clientCustomizations.value; const { elementsWrapper: ew, stringsWrapper: sw } = clientCustomizations.value;
let value; let value;
if (isNumeric) { if (isNumeric && !['IN', 'NOT IN', 'RLIKE', 'NOT RLIKE'].includes(filter.op)) {
if (isNaN(Number(filter.value))) if (isNaN(Number(filter.value)))
filter.value = ''; filter.value = '';
if (isNaN(Number(filter.value2))) if (isNaN(Number(filter.value2)))
@@ -145,7 +149,7 @@ const createClausole = (filter: TableFilterClausole) => {
val = val.trim(); val = val.trim();
return isNumeric ? val : `${sw}${val}${sw}`; return isNumeric ? val : `${sw}${val}${sw}`;
}).join(','); }).join(',');
value = `(${filter.value})`; value = `(${value})`;
break; break;
case 'IS NULL': case 'IS NULL':
case 'IS NOT NULL': case 'IS NOT NULL':