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

Compare commits

..

27 Commits

Author SHA1 Message Date
3c1bae540f chore(release): 0.5.13 2022-08-09 09:13:11 +02:00
f64a12a8e9 fix(MySQL): error with ANSI sql_mode 2022-08-07 19:00:12 +02:00
a9fcfd57ec refactor: improved vue-i18n implementation 2022-08-05 17:03:16 +02:00
e2307341f3 Merge pull request #397 from antares-sql/dependabot/npm_and_yarn/vue-i18n-9.2.0
build(deps): bump vue-i18n from 9.1.10 to 9.2.0
2022-08-05 13:17:06 +02:00
09a372e96d refactor: vue-i18n ts improvements 2022-08-05 13:06:08 +02:00
f4da28cca0 refactor: vue-i18n ts improvements 2022-08-05 12:57:56 +02:00
89745b7391 Merge pull request #398 from antares-sql/dependabot/npm_and_yarn/mdi/font-7.0.96
build(deps): bump @mdi/font from 6.9.96 to 7.0.96
2022-08-05 12:26:44 +02:00
104b7c928b fix: set legacy: false 2022-08-05 12:25:14 +02:00
dependabot[bot]
427360d826 build(deps): bump sql-formatter from 4.0.2 to 8.2.0
Bumps [sql-formatter](https://github.com/sql-formatter-org/sql-formatter) from 4.0.2 to 8.2.0.
- [Release notes](https://github.com/sql-formatter-org/sql-formatter/releases)
- [Changelog](https://github.com/sql-formatter-org/sql-formatter/blob/master/.release-it.json)
- [Commits](https://github.com/sql-formatter-org/sql-formatter/compare/v4.0.2...v8.2.0)

---
updated-dependencies:
- dependency-name: sql-formatter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-05 12:18:53 +02:00
Giulio Ganci
0bfa14e1c9 feat: new macos icon 2022-08-03 12:57:17 +02:00
88ba55ec02 build: added deb arm targets 2022-08-03 11:33:26 +02:00
aaff4cf4fe refactor: filter functions as composable 2022-08-03 11:10:16 +02:00
35c54aee84 chore: update README.md 2022-08-02 13:17:13 +02:00
be2e9b21f5 chore: update dependabot.yml 2022-08-02 10:55:19 +02:00
2262278393 Merge branch 'master' of https://github.com/antares-sql/antares 2022-08-02 10:51:43 +02:00
531e17889a chore: update dependabot.yml 2022-08-02 10:51:40 +02:00
a07ed58004 chore: update CONTRIBUTING.md 2022-08-02 10:41:05 +02:00
00dc59a76d ci: remove old ci configs 2022-08-02 10:37:27 +02:00
2f883bfeb2 ci: new ci config 2022-08-02 10:10:20 +02:00
7ff16fccce ci: minor change 2022-08-01 22:32:19 +02:00
dependabot[bot]
3625fbc1b0 build(deps): bump @mdi/font from 6.9.96 to 7.0.96
Bumps [@mdi/font](https://github.com/Templarian/MaterialDesign-Webfont) from 6.9.96 to 7.0.96.
- [Release notes](https://github.com/Templarian/MaterialDesign-Webfont/releases)
- [Commits](https://github.com/Templarian/MaterialDesign-Webfont/compare/v6.9.96...v7.0.96)

---
updated-dependencies:
- dependency-name: "@mdi/font"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-01 19:10:35 +00:00
dependabot[bot]
deee0d637b build(deps): bump vue-i18n from 9.1.10 to 9.2.0
Bumps [vue-i18n](https://github.com/intlify/vue-i18n-next/tree/HEAD/packages/vue-i18n) from 9.1.10 to 9.2.0.
- [Release notes](https://github.com/intlify/vue-i18n-next/releases)
- [Changelog](https://github.com/intlify/vue-i18n-next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n-next/commits/v9.2.0/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-01 19:09:53 +00:00
8c6950cebd refactor: minor refactors 2022-08-01 18:13:14 +02:00
46167e4473 build: general ci config update 2022-08-01 18:06:57 +02:00
c32a4415d1 Update README.md 2022-07-31 10:43:32 +02:00
1c3d7aa30b feat: copy row as CSV, closes #394 2022-07-29 18:53:39 +02:00
664d18efc1 chore: update README.md 2022-07-26 17:21:43 +02:00
67 changed files with 5738 additions and 6024 deletions

View File

@@ -6,6 +6,8 @@
version: 2
updates:
- package-ecosystem: "npm"
allow:
- dependency-type: "production"
directory: "/"
schedule:
interval: "monthly"

View File

@@ -1,29 +0,0 @@
name: Build/release [LINUX]
on: push
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v2
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
with:
node-version: 14
- name: Install dependencies
run: npm i
- name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1
with:
github_token: ${{ secrets.github_token }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

View File

@@ -1,29 +0,0 @@
name: Build/release [MAC]
on: push
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v2
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
with:
node-version: 14
- name: Install dependencies
run: npm i
- name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1
with:
github_token: ${{ secrets.github_token }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

View File

@@ -1,29 +0,0 @@
name: Build/release [WINDOWS]
on: push
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2019]
steps:
- name: Check out Git repository
uses: actions/checkout@v2
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
with:
node-version: 14
- name: Install dependencies
run: npm i
- name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1
with:
github_token: ${{ secrets.github_token }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

37
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Build & release
on:
push:
tags:
- "v*"
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm i
- name: "Build"
run: npm run build
- name: Release
uses: ncipollo/release-action@v1
with:
artifacts: "build/*.AppImage,build/*.yml,build/*.deb,build/*.dmg,build/*.blockmap,build/*.zip,build/*.exe"
allowUpdates: true
draft: true
generateReleaseNotes: true

View File

@@ -10,10 +10,15 @@ jobs:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: npm install & build
run: |
npm install
npm run build:local
npm run build
- name: Upload Artifact
uses: actions/upload-artifact@v3

View File

@@ -12,12 +12,12 @@ jobs:
steps:
- name: Check out Git repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 16
- name: Install dependencies
run: npm i

1
.nvmrc
View File

@@ -1 +0,0 @@
v16.13.0

View File

@@ -2,6 +2,20 @@
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.5.13](https://github.com/antares-sql/antares/compare/v0.5.12...v0.5.13) (2022-08-09)
### Features
* copy row as CSV, closes [#394](https://github.com/antares-sql/antares/issues/394) ([1c3d7aa](https://github.com/antares-sql/antares/commit/1c3d7aa30bb9c2bd900a764ee6b97960729e9263))
* new macos icon ([0bfa14e](https://github.com/antares-sql/antares/commit/0bfa14e1c90320578597df030941530b670a4131))
### Bug Fixes
* **MySQL:** error with ANSI sql_mode ([f64a12a](https://github.com/antares-sql/antares/commit/f64a12a8e9c5f764c3a692f1a032736e008058b5))
* set legacy: false ([104b7c9](https://github.com/antares-sql/antares/commit/104b7c928b9c2abfc056880f16c606a0b1fa7c67))
### [0.5.12](https://github.com/antares-sql/antares/compare/v0.5.11...v0.5.12) (2022-07-26)

View File

@@ -44,8 +44,7 @@ In this folder is located the structure of Vue frontend application.
## Build
The command to build Antares SQL locally is `npm run build:local`.
`build` command (without `:local`) is used exclusively by the GitHub Action.
The command to build Antares SQL locally is `npm run build`.
## Conventions

View File

@@ -18,7 +18,8 @@ We are actively working on it, hoping to provide new cool features, improvements
🔗 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 [follow Antares SQL](https://twitter.com/AntaresSQL) on Twitter.
🌟 Don't forget to **leave a star** if you appreciate this project.
🌟 Don't forget to **leave a star** if you appreciate this project.
🗳️ Poll: **[Which is the main OS you use Antares on?](https://github.com/antares-sql/antares/discussions/379)**
## Current key features
@@ -49,11 +50,11 @@ Since Antares SQL is a free software we don't have a budget to spend on annual l
### Linux
On Linux you can simply download and run the `.AppImage` distribution, install from Snap Store or from AUR.
On Linux you can simply download and run the `.AppImage` distribution, install from Snap Store, from AUR or from our [PPA repository](https://github.com/antares-sql/antares-ppa).
### Windows
On Windows you can choose between downloading the app from Microsoft Store or downloading the `.exe` from our [website](https://antares-sql.app/download.html) or [this github repo](https://github.com/Fabio286/antares/releases/latest). Distributions that are not from Microsoft Store are not signed with a certificate, so to install you need to click on "More info" and then "Run anyway" on SmartScreen prompt.
On Windows you can choose between downloading the app from Microsoft Store or downloading the `.exe` from our [website](https://antares-sql.app/downloads) or [this github repo](https://github.com/Fabio286/antares/releases/latest). Distributions that are not from Microsoft Store are not signed with a certificate, so to install you need to click on "More info" and then "Run anyway" on SmartScreen prompt.
### MacOS
@@ -61,7 +62,7 @@ On macOS you can run `.dmg` distribution following [this guide](https://support.
## Download
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/antares) [![Get it from AUR](https://raw.githubusercontent.com/Fabio286/antares/3e00c4bae6e036300c752c1a40c5a038fea9c169/docs/aur-badge.svg)](https://aur.archlinux.org/packages/antares-sql/) [![Get it from Microsoft Store](https://raw.githubusercontent.com/Fabio286/antares/gh-pages/src/assets/ms-store.png)](https://www.microsoft.com/p/antares-sql-client/9nhtb9sq51r1?cid=storebadge&ocid=badge&rtc=1&activetab=pivot:overviewtab)
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/antares) [![Get it from AUR](https://raw.githubusercontent.com/Fabio286/antares/3e00c4bae6e036300c752c1a40c5a038fea9c169/docs/aur-badge.svg)](https://aur.archlinux.org/packages/antares-sql/) [<img src="https://developer.microsoft.com/store/badges/images/English_get-it-from-MS.png" style="height: 56px">](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)**
## Coming soon

Binary file not shown.

10817
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "antares",
"productName": "Antares",
"version": "0.5.12",
"version": "0.5.13",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT",
"repository": "https://github.com/antares-sql/antares.git",
@@ -12,14 +12,13 @@
"compile:main": "webpack --mode=production --config webpack.main.config.js",
"compile:workers": "webpack --mode=production --config webpack.workers.config.js",
"compile:renderer": "webpack --mode=production --config webpack.renderer.config.js",
"build": "cross-env NODE_ENV=production npm run compile",
"build:local": "npm run build && electron-builder --publish never",
"build:appx": "npm run build:local -- --win appx",
"rebuild:electron": "rimraf ./dist && npm run postinstall",
"build": "cross-env NODE_ENV=production npm run compile && electron-builder --publish never",
"build:appx": "npm run build -- --win appx",
"rebuild:electron": "rimraf ./dist && npm run postinstall && npm run devtools:install",
"release": "standard-version",
"release:pre": "npm run release -- --prerelease alpha",
"devtools:install": "node scripts/devtoolsInstaller",
"postinstall": "electron-builder install-app-deps && npm run devtools:install",
"postinstall": "electron-builder install-app-deps",
"test:e2e": "npm run compile && npm run test:e2e-dry",
"test:e2e-dry": "xvfb-maybe -- playwright test",
"lint": "eslint . --ext .js,.ts,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"",
@@ -65,7 +64,11 @@
"target": [
{
"target": "deb",
"arch": "x64"
"arch": [
"x64",
"armv7l",
"arm64"
]
},
{
"target": "AppImage",
@@ -117,7 +120,7 @@
"dependencies": {
"@electron/remote": "~2.0.1",
"@faker-js/faker": "~6.1.2",
"@mdi/font": "~6.9.96",
"@mdi/font": "~7.0.96",
"@turf/helpers": "~6.5.0",
"@vueuse/core": "~8.7.5",
"ace-builds": "~1.8.1",
@@ -132,16 +135,17 @@
"moment": "~2.29.4",
"mysql2": "~2.3.2",
"pg": "~8.7.1",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3",
"pgsql-ast-parser": "~7.2.1",
"pinia": "~2.0.13",
"source-map-support": "~0.5.20",
"spectre.css": "~0.5.9",
"sql-formatter": "~4.0.2",
"sql-formatter": "~8.2.0",
"ssh2-promise": "~1.0.2",
"v-mask": "~2.3.0",
"vue": "~3.2.37",
"vue-i18n": "~9.1.9",
"vue-i18n": "~9.2.0",
"vuedraggable": "~4.1.0"
},
"devDependencies": {

View File

@@ -192,14 +192,14 @@ export class MySQLClient extends AntaresCore {
// ANSI_QUOTES check
const [response] = await connection.query<mysql.RowDataPacket[]>('SHOW GLOBAL VARIABLES LIKE \'%sql_mode%\'');
const sqlMode = response[0]?.Value?.split(',');
const hasAnsiQuotes = sqlMode.includes('ANSI_QUOTES');
const sqlMode: string[] = response[0]?.Value?.split(',');
const hasAnsiQuotes = sqlMode.includes('ANSI') || sqlMode.includes('ANSI_QUOTES');
if (this._params.readonly)
await connection.query('SET SESSION TRANSACTION READ ONLY');
if (hasAnsiQuotes)
await connection.query(`SET SESSION sql_mode = "${sqlMode.filter((m: string) => m !== 'ANSI_QUOTES').join(',')}"`);
await connection.query(`SET SESSION sql_mode = '${sqlMode.filter((m: string) => !['ANSI', 'ANSI_QUOTES'].includes(m)).join(',')}'`);
return connection;
}
@@ -219,18 +219,18 @@ export class MySQLClient extends AntaresCore {
// ANSI_QUOTES check
const [res] = await connection.query<mysql.RowDataPacket[]>('SHOW GLOBAL VARIABLES LIKE \'%sql_mode%\'');
const sqlMode = res[0]?.Value?.split(',');
const hasAnsiQuotes = sqlMode.includes('ANSI_QUOTES');
const sqlMode: string[] = res[0]?.Value?.split(',');
const hasAnsiQuotes = sqlMode.includes('ANSI') || sqlMode.includes('ANSI_QUOTES');
if (hasAnsiQuotes)
await connection.query(`SET SESSION sql_mode = "${sqlMode.filter((m: string) => m !== 'ANSI_QUOTES').join(',')}"`);
await connection.query(`SET SESSION sql_mode = '${sqlMode.filter((m: string) => !['ANSI', 'ANSI_QUOTES'].includes(m)).join(',')}'`);
connection.on('connection', conn => {
if (this._params.readonly)
conn.query('SET SESSION TRANSACTION READ ONLY');
if (hasAnsiQuotes)
conn.query(`SET SESSION sql_mode = "${sqlMode.filter((m: string) => m !== 'ANSI_QUOTES').join(',')}"`);
conn.query(`SET SESSION sql_mode = '${sqlMode.filter((m: string) => !['ANSI', 'ANSI_QUOTES'].includes(m)).join(',')}'`);
});
return connection;
@@ -1397,7 +1397,7 @@ export class MySQLClient extends AntaresCore {
}
async getVersion () {
const sql = 'SHOW VARIABLES LIKE "%vers%"';
const sql = 'SHOW VARIABLES LIKE \'%vers%\'';
const { rows } = await this.raw(sql);
return rows.reduce((acc, curr) => {

View File

@@ -1,6 +1,5 @@
import * as antares from 'common/interfaces/antares';
import * as mysql from 'mysql2';
import { builtinsTypes } from 'pg-types';
import * as pg from 'pg';
import * as pgAst from 'pgsql-ast-parser';
import { AntaresCore } from '../AntaresCore';
@@ -19,6 +18,68 @@ pg.types.setTypeParser(1114, pgToString); // timestamp
pg.types.setTypeParser(1184, pgToString); // timestamptz
pg.types.setTypeParser(1266, pgToString); // timetz
// from pg-types
type builtinsTypes =
'BOOL' |
'BYTEA' |
'CHAR' |
'INT8' |
'INT2' |
'INT4' |
'REGPROC' |
'TEXT' |
'OID' |
'TID' |
'XID' |
'CID' |
'JSON' |
'XML' |
'PG_NODE_TREE' |
'SMGR' |
'PATH' |
'POLYGON' |
'CIDR' |
'FLOAT4' |
'FLOAT8' |
'ABSTIME' |
'RELTIME' |
'TINTERVAL' |
'CIRCLE' |
'MACADDR8' |
'MONEY' |
'MACADDR' |
'INET' |
'ACLITEM' |
'BPCHAR' |
'VARCHAR' |
'DATE' |
'TIME' |
'TIMESTAMP' |
'TIMESTAMPTZ' |
'INTERVAL' |
'TIMETZ' |
'BIT' |
'VARBIT' |
'NUMERIC' |
'REFCURSOR' |
'REGPROCEDURE' |
'REGOPER' |
'REGOPERATOR' |
'REGCLASS' |
'REGTYPE' |
'UUID' |
'TXID_SNAPSHOT' |
'PG_LSN' |
'PG_NDISTINCT' |
'PG_DEPENDENCIES' |
'TSVECTOR' |
'TSQUERY' |
'GTSVECTOR' |
'REGCONFIG' |
'REGDICTIONARY' |
'JSONB' |
'REGNAMESPACE' |
'REGROLE';
export class PostgreSQLClient extends AntaresCore {
private _schema?: string;
private _runningConnections: Map<string, number>;

View File

@@ -31,13 +31,13 @@
class="btn btn-primary mr-2"
@click.stop="confirmModal"
>
{{ confirmText || $t('word.confirm') }}
{{ confirmText || t('word.confirm') }}
</button>
<button
class="btn btn-link"
@click="hideModal"
>
{{ cancelText || $t('word.cancel') }}
{{ cancelText || t('word.cancel') }}
</button>
</div>
</div>
@@ -49,6 +49,9 @@
<script setup lang="ts">
import { useFocusTrap } from '@/composables/useFocusTrap';
import { computed, onBeforeUnmount, PropType, useSlots } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
size: {

View File

@@ -431,6 +431,12 @@ export default defineComponent({
width: 100%;
}
&__item-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&__list-wrapper {
cursor: pointer;
position: fixed;

View File

@@ -4,7 +4,7 @@
<i class="mdi mdi-folder-open mr-1" />{{ message }}
</span>
<span class="text-ellipsis file-uploader-value">
{{ lastPart(modelValue) }}
{{ lastPart(modelValue, 19) }}
</span>
<i
v-if="modelValue"
@@ -24,6 +24,9 @@
<script setup lang="ts">
import { uidGen } from 'common/libs/uidGen';
import { useFilters } from '@/composables/useFilters';
const { lastPart } = useFilters();
defineProps({
message: {
@@ -43,15 +46,6 @@ const id = uidGen();
const clear = () => {
emit('clear');
};
const lastPart = (string: string) => {
if (!string) return '';
string = string.split(/[/\\]+/).pop();
if (string.length >= 19)
string = `...${string.slice(-19)}`;
return string;
};
</script>
<style lang="scss" scoped>

View File

@@ -4,7 +4,7 @@
v-model="selectedGroup"
class="form-select"
:options="[{name: 'manual'}, ...fakerGroups]"
:option-label="(opt: any) => opt.name === 'manual' ? $t('message.manualValue') : $t(`faker.${opt.name}`)"
:option-label="(opt: any) => opt.name === 'manual' ? t('message.manualValue') : t(`faker.${opt.name}`)"
option-track-by="name"
:disabled="!isChecked"
style="flex-grow: 0;"
@@ -15,7 +15,7 @@
v-if="selectedGroup !== 'manual'"
v-model="selectedMethod"
:options="fakerMethods"
:option-label="(opt: any) => $t(`faker.${opt.name}`)"
:option-label="(opt: any) => t(`faker.${opt.name}`)"
option-track-by="name"
class="form-select"
:disabled="!isChecked"
@@ -41,7 +41,7 @@
<BaseUploadInput
v-else-if="inputProps().type === 'file'"
:model-value="selectedValue"
:message="$t('word.browse')"
:message="t('word.browse')"
@clear="clearValue"
@change="filesChange($event)"
/>
@@ -92,6 +92,9 @@ import BaseUploadInput from '@/components/BaseUploadInput.vue';
import ForeignKeySelect from '@/components/ForeignKeySelect.vue';
import FakerMethods from 'common/FakerMethods';
import BaseSelect from '@/components/BaseSelect.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
type: String,

View File

@@ -21,6 +21,7 @@ import { useWorkspacesStore } from '@/stores/workspaces';
import { TEXT, LONG_TEXT } from 'common/fieldTypes';
import BaseSelect from '@/components/BaseSelect.vue';
import { TableField } from 'common/interfaces/antares';
import { useFilters } from '@/composables/useFilters';
const props = defineProps({
modelValue: [String, Number],
@@ -35,6 +36,7 @@ const emit = defineEmits(['update:modelValue', 'blur']);
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
const { cutText } = useFilters();
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
@@ -53,7 +55,7 @@ const foreigns = computed(() => {
if (!isValidDefault.value)
list.push({ value: props.modelValue, label: props.modelValue === null ? 'NULL' : props.modelValue });
for (const row of foreignList.value)
list.push({ value: row.foreign_column, label: `${row.foreign_column} ${cutText('foreign_description' in row ? ` - ${row.foreign_description}` : '')}` });
list.push({ value: row.foreign_column, label: `${row.foreign_column} ${cutText('foreign_description' in row ? ` - ${row.foreign_description}` : '', 15)}` });
return list;
});
@@ -61,11 +63,6 @@ const onChange = (opt: HTMLSelectElement) => {
emit('update:modelValue', opt.value);
};
const cutText = (val: string) => {
if (typeof val !== 'string') return val;
return val.length > 15 ? `${val.substring(0, 15)}...` : val;
};
watch(() => props.modelValue, () => {
currentValue.value = props.modelValue;
});

View File

@@ -7,7 +7,7 @@
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-apps mr-1" />
<span class="cut-text">{{ $t('message.allConnections') }}</span>
<span class="cut-text">{{ t('message.allConnections') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />

View File

@@ -6,7 +6,7 @@
<div class="modal-header pl-2">
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-key-variant mr-1" /> {{ $t('word.credentials') }}
<i class="mdi mdi-24px mdi-key-variant mr-1" /> {{ t('word.credentials') }}
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -16,7 +16,7 @@
<form class="form-horizontal">
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.user') }}</label>
<label class="form-label">{{ t('word.user') }}</label>
</div>
<div class="col-9">
<input
@@ -29,7 +29,7 @@
</div>
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.password') }}</label>
<label class="form-label">{{ t('word.password') }}</label>
</div>
<div class="col-9">
<input
@@ -44,10 +44,10 @@
</div>
<div class="modal-footer">
<button class="btn btn-primary mr-2" @click.stop="sendCredentials">
{{ $t('word.send') }}
{{ t('word.send') }}
</button>
<button class="btn btn-link" @click.stop="closeModal">
{{ $t('word.close') }}
{{ t('word.close') }}
</button>
</div>
</div>
@@ -58,6 +58,9 @@
<script setup lang="ts">
import { Ref, ref } from 'vue';
import { useFocusTrap } from '@/composables/useFocusTrap';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { trapRef } = useFocusTrap();

View File

@@ -1,7 +1,7 @@
<template>
<ConfirmModal
:confirm-text="$t('word.run')"
:cancel-text="$t('word.cancel')"
:confirm-text="t('word.run')"
:cancel-text="t('word.cancel')"
size="400"
@confirm="runRoutine"
@hide="closeModal"
@@ -9,7 +9,7 @@
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-play mr-1" />
<span class="cut-text">{{ $t('word.parameters') }}: {{ localRoutine.name }}</span>
<span class="cut-text">{{ t('word.parameters') }}: {{ localRoutine.name }}</span>
</div>
</template>
<template #body>
@@ -52,6 +52,12 @@ import { computed, PropType, Ref, ref } from 'vue';
import { NUMBER, FLOAT } from 'common/fieldTypes';
import { FunctionInfos, RoutineInfos } from 'common/interfaces/antares';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import { useFilters } from '@/composables/useFilters';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { wrapNumber } = useFilters();
const props = defineProps({
localRoutine: Object as PropType<RoutineInfos | FunctionInfos>,
@@ -106,11 +112,6 @@ const onKey = (e: KeyboardEvent) => {
closeModal();
};
const wrapNumber = (num: number) => {
if (!num) return '';
return `(${num})`;
};
window.addEventListener('keydown', onKey);
setTimeout(() => {

View File

@@ -1,18 +1,18 @@
<template>
<ConfirmModal
:confirm-text="$t('word.discard')"
:cancel-text="$t('word.stay')"
:confirm-text="t('word.discard')"
:cancel-text="t('word.stay')"
@confirm="emit('confirm')"
@hide="emit('close')"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-content-save-alert mr-1" /> {{ $t('message.unsavedChanges') }}
<i class="mdi mdi-24px mdi-content-save-alert mr-1" /> {{ t('message.unsavedChanges') }}
</div>
</template>
<template #body>
<div>
{{ $t('message.discardUnsavedChanges') }}
{{ t('message.discardUnsavedChanges') }}
</div>
</template>
</ConfirmModal>
@@ -21,6 +21,9 @@
<script setup lang="ts">
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import { onBeforeUnmount } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const emit = defineEmits(['confirm', 'close']);

View File

@@ -7,7 +7,7 @@
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-database-edit mr-1" />
<span class="cut-text">{{ $t('message.editSchema') }}</span>
<span class="cut-text">{{ t('message.editSchema') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -17,7 +17,7 @@
<form class="form-horizontal">
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.name') }}</label>
<label class="form-label">{{ t('word.name') }}</label>
</div>
<div class="col-9">
<input
@@ -26,14 +26,14 @@
class="form-input"
type="text"
required
:placeholder="$t('message.schemaName')"
:placeholder="t('message.schemaName')"
readonly
>
</div>
</div>
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.collation') }}</label>
<label class="form-label">{{ t('word.collation') }}</label>
</div>
<div class="col-9">
<BaseSelect
@@ -43,7 +43,7 @@
option-label="collation"
option-track-by="collation"
/>
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
<small>{{ t('message.serverDefault') }}: {{ defaultCollation }}</small>
</div>
</div>
</form>
@@ -51,10 +51,10 @@
</div>
<div class="modal-footer">
<button class="btn btn-primary mr-2" @click.stop="updateSchema">
{{ $t('word.update') }}
{{ t('word.update') }}
</button>
<button class="btn btn-link" @click.stop="closeModal">
{{ $t('word.close') }}
{{ t('word.close') }}
</button>
</div>
</div>
@@ -70,6 +70,9 @@ import { useWorkspacesStore } from '@/stores/workspaces';
import { useFocusTrap } from '@/composables/useFocusTrap';
import Schema from '@/ipc-api/Schema';
import BaseSelect from '@/components/BaseSelect.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
selectedSchema: String

View File

@@ -7,7 +7,7 @@
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-database-arrow-down mr-1" />
<span class="cut-text">{{ $t('message.exportSchema') }}</span>
<span class="cut-text">{{ t('message.exportSchema') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -16,7 +16,7 @@
<div class="container">
<div class="columns">
<div class="col-3">
<label class="form-label">{{ $t('message.directoryPath') }}</label>
<label class="form-label">{{ t('message.directoryPath') }}</label>
</div>
<div class="col-9">
<fieldset class="input-group">
@@ -26,14 +26,14 @@
type="text"
required
readonly
:placeholder="$t('message.schemaName')"
:placeholder="t('message.schemaName')"
>
<button
type="button"
class="btn btn-primary input-group-btn"
@click.prevent="openPathDialog"
>
{{ $t('word.change') }}
{{ t('word.change') }}
</button>
</fieldset>
</div>
@@ -51,14 +51,14 @@
<div class="column col-auto col-ml-auto ">
<button
class="btn btn-dark btn-sm"
:title="$t('word.refresh')"
:title="t('word.refresh')"
@click="refresh"
>
<i class="mdi mdi-database-refresh" />
</button>
<button
class="btn btn-dark btn-sm mx-1"
:title="$t('message.uncheckAllTables')"
:title="t('message.uncheckAllTables')"
:disabled="isRefreshing"
@click="uncheckAllTables"
>
@@ -66,7 +66,7 @@
</button>
<button
class="btn btn-dark btn-sm"
:title="$t('message.checkAllTables')"
:title="t('message.checkAllTables')"
:disabled="isRefreshing"
@click="checkAllTables"
>
@@ -122,22 +122,22 @@
<div class="tr">
<div class="th" style="width: 50%;">
<div class="table-column-title">
<span>{{ $t('word.table') }}</span>
<span>{{ t('word.table') }}</span>
</div>
</div>
<div class="th text-center">
<div class="table-column-title">
<span>{{ $t('word.structure') }}</span>
<span>{{ t('word.structure') }}</span>
</div>
</div>
<div class="th text-center">
<div class="table-column-title">
<span>{{ $t('word.content') }}</span>
<span>{{ t('word.content') }}</span>
</div>
</div>
<div class="th text-center">
<div class="table-column-title">
<span>{{ $t('word.drop') }}</span>
<span>{{ t('word.drop') }}</span>
</div>
</div>
</div>
@@ -183,19 +183,19 @@
</div>
<div class="column col-4">
<h5 class="h5">
{{ $t('word.options') }}
{{ t('word.options') }}
</h5>
<span class="h6">{{ $t('word.includes') }}:</span>
<span class="h6">{{ t('word.includes') }}:</span>
<label
v-for="(_, key) in options.includes"
:key="key"
class="form-checkbox"
>
<input v-model="options.includes[key]" type="checkbox"><i class="form-icon" /> {{ $tc(`word.${key}`, 2) }}
<input v-model="options.includes[key]" type="checkbox"><i class="form-icon" /> {{ t(`word.${key}`, 2) }}
</label>
<div v-if="clientCustoms.exportByChunks">
<div class="h6 mt-4 mb-2">
{{ $t('message.newInserStmtEvery') }}:
{{ t('message.newInserStmtEvery') }}:
</div>
<div class="columns">
<div class="column col-6">
@@ -209,21 +209,21 @@
<BaseSelect
v-model="options.sqlInsertDivider"
class="form-select"
:options="[{value: 'bytes', label: 'KiB'}, {value: 'rows', label: $tc('word.row', 2)}]"
:options="[{value: 'bytes', label: 'KiB'}, {value: 'rows', label: t('word.row', 2)}]"
/>
</div>
</div>
</div>
<div class="h6 mb-2 mt-4">
{{ $t('message.ourputFormat') }}:
{{ t('message.ourputFormat') }}:
</div>
<div class="columns">
<div class="column h5 mb-4">
<BaseSelect
v-model="options.outputFormat"
class="form-select"
:options="[{value: 'sql', label: $t('message.singleFile', {ext: '.sql'})}, {value: 'sql.zip', label: $t('message.zipCompressedFile', {ext: '.sql'})}]"
:options="[{value: 'sql', label: t('message.singleFile', {ext: '.sql'})}, {value: 'sql.zip', label: t('message.zipCompressedFile', {ext: '.sql'})}]"
/>
</div>
</div>
@@ -245,7 +245,7 @@
</div>
<div class="column col-auto px-0">
<button class="btn btn-link" @click.stop="closeModal">
{{ $t('word.close') }}
{{ t('word.close') }}
</button>
<button
class="btn btn-primary mr-2"
@@ -254,7 +254,7 @@
autofocus
@click.prevent="startExport"
>
{{ $t('word.export') }}
{{ t('word.export') }}
</button>
</div>
</div>

View File

@@ -7,7 +7,7 @@
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
<span class="cut-text">{{ $tc('message.insertRow', 2) }}</span>
<span class="cut-text">{{ t('message.insertRow', 2) }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -39,7 +39,7 @@
<span class="input-group-addon field-type" :class="typeClass(field.type)">
{{ field.type }} {{ wrapNumber(fieldLength(field)) }}
</span>
<label class="form-checkbox ml-3" :title="$t('word.insert')">
<label class="form-checkbox ml-3" :title="t('word.insert')">
<input
type="checkbox"
:checked="!fieldsToExclude.includes(field.name)"
@@ -55,7 +55,7 @@
</div>
<div class="modal-footer columns">
<div class="column d-flex" :class="hasFakes ? 'col-4' : 'col-2'">
<div class="input-group tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
<div class="input-group tooltip tooltip-right" :data-tooltip="t('message.numberOfInserts')">
<input
v-model="nInserts"
type="number"
@@ -70,7 +70,7 @@
<div
v-if="hasFakes"
class="tooltip tooltip-right ml-2"
:data-tooltip="$t('message.fakeDataLanguage')"
:data-tooltip="t('message.fakeDataLanguage')"
>
<BaseSelect
v-model="fakerLocale"
@@ -85,10 +85,10 @@
:class="{'loading': isInserting}"
@click.stop="insertRows"
>
{{ $t('word.insert') }}
{{ t('word.insert') }}
</button>
<button class="btn btn-link" @click.stop="closeModal">
{{ $t('word.close') }}
{{ t('word.close') }}
</button>
</div>
</div>
@@ -109,6 +109,12 @@ import { useFocusTrap } from '@/composables/useFocusTrap';
import Tables from '@/ipc-api/Tables';
import FakerSelect from '@/components/FakerSelect.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import { useFilters } from '@/composables/useFilters';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { wrapNumber } = useFilters();
const props = defineProps({
tabUid: [String, Number],
@@ -267,11 +273,6 @@ const onKey = (e: KeyboardEvent) => {
closeModal();
};
const wrapNumber = (num: number) => {
if (!num) return '';
return `(${num})`;
};
window.addEventListener('keydown', onKey);
onMounted(() => {

View File

@@ -100,14 +100,15 @@
<script setup lang="ts">
import { Component, computed, ComputedRef, onBeforeUnmount, onMounted, onUpdated, Prop, Ref, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import * as moment from 'moment';
import { ConnectionParams } from 'common/interfaces/antares';
import { HistoryRecord, useHistoryStore } from '@/stores/history';
import { useConnectionsStore } from '@/stores/connections';
import { useFocusTrap } from '@/composables/useFocusTrap';
import { useFilters } from '@/composables/useFilters';
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
const { t } = useI18n();
const { formatDate } = useFilters();
const { getHistoryByWorkspace, deleteQueryFromHistory } = useHistoryStore();
const { getConnectionName } = useConnectionsStore();
@@ -164,7 +165,6 @@ const resizeResults = () => {
}
};
const formatDate = (date: Date) => moment(date).isValid() ? moment(date).format('HH:mm:ss - YYYY/MM/DD') : date;
const refreshScroller = () => resizeResults();
const closeModal = () => emit('close');

View File

@@ -7,7 +7,7 @@
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-database-arrow-up mr-1" />
<span class="cut-text">{{ $t('message.importSchema') }}</span>
<span class="cut-text">{{ t('message.importSchema') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -15,7 +15,7 @@
<div class="modal-body pb-0">
{{ sqlFile }}
<div v-if="queryErrors.length > 0" class="mt-2">
<label>{{ $tc('message.importQueryErrors', queryErrors.length) }}</label>
<label>{{ t('message.importQueryErrors', queryErrors.length) }}</label>
<textarea
v-model="formattedQueryErrors"
class="form-input"
@@ -28,7 +28,7 @@
<div class="column col modal-progress-wrapper text-left">
<div class="import-progress">
<span class="progress-status">
{{ progressPercentage }}% - {{ progressStatus }} - {{ $tc('message.executedQueries', queryCount) }}
{{ progressPercentage }}% - {{ progressStatus }} - {{ t('message.executedQueries', queryCount) }}
</span>
<progress
class="progress d-block"
@@ -39,7 +39,7 @@
</div>
<div class="column col-auto px-0">
<button class="btn btn-link" @click.stop="closeModal">
{{ completed ? $t('word.close') : $t('word.cancel') }}
{{ completed ? t('word.close') : t('word.cancel') }}
</button>
</div>
</div>
@@ -57,8 +57,8 @@ import { storeToRefs } from 'pinia';
import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces';
import Schema from '@/ipc-api/Schema';
import { useI18n } from 'vue-i18n';
import { ImportState } from 'common/interfaces/importer';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();

View File

@@ -7,7 +7,7 @@
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-database-plus mr-1" />
<span class="cut-text">{{ $t('message.createNewSchema') }}</span>
<span class="cut-text">{{ t('message.createNewSchema') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -17,7 +17,7 @@
<form class="form-horizontal" @submit.prevent="createSchema">
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.name') }}</label>
<label class="form-label">{{ t('word.name') }}</label>
</div>
<div class="col-9">
<input
@@ -26,13 +26,13 @@
class="form-input"
type="text"
required
:placeholder="$t('message.schemaName')"
:placeholder="t('message.schemaName')"
>
</div>
</div>
<div v-if="customizations.collations" class="form-group">
<div class="col-3">
<label class="form-label">{{ $t('word.collation') }}</label>
<label class="form-label">{{ t('word.collation') }}</label>
</div>
<div class="col-9">
<BaseSelect
@@ -42,7 +42,7 @@
option-label="collation"
option-track-by="collation"
/>
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
<small>{{ t('message.serverDefault') }}: {{ defaultCollation }}</small>
</div>
</div>
</form>
@@ -54,10 +54,10 @@
:class="{'loading': isLoading}"
@click.stop="createSchema"
>
{{ $t('word.add') }}
{{ t('word.add') }}
</button>
<button class="btn btn-link" @click.stop="closeModal">
{{ $t('word.close') }}
{{ t('word.close') }}
</button>
</div>
</div>
@@ -73,6 +73,9 @@ import { useWorkspacesStore } from '@/stores/workspaces';
import { useFocusTrap } from '@/composables/useFocusTrap';
import Schema from '@/ipc-api/Schema';
import BaseSelect from '@/components/BaseSelect.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();

View File

@@ -17,7 +17,7 @@
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-memory mr-1" />
<span class="cut-text">{{ $t('message.processesList') }}: {{ connectionName }}</span>
<span class="cut-text">{{ t('message.processesList') }}: {{ connectionName }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -29,7 +29,7 @@
<button
class="btn btn-dark btn-sm mr-0 pr-1 d-flex"
:class="{'loading':isQuering}"
:title="`${$t('word.refresh')} (F5)`"
:title="`${t('word.refresh')} (F5)`"
@click="getProcessesList"
>
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh mr-1" />
@@ -39,7 +39,7 @@
<i class="mdi mdi-24px mdi-menu-down" />
</div>
<div class="menu px-3">
<span>{{ $t('word.autoRefresh') }}: <b>{{ +autorefreshTimer ? `${autorefreshTimer}s` : 'OFF' }}</b></span>
<span>{{ t('word.autoRefresh') }}: <b>{{ +autorefreshTimer ? `${autorefreshTimer}s` : 'OFF' }}</b></span>
<input
v-model="autorefreshTimer"
class="slider no-border"
@@ -59,7 +59,7 @@
tabindex="0"
>
<i class="mdi mdi-24px mdi-file-export mr-1" />
<span>{{ $t('word.export') }}</span>
<span>{{ t('word.export') }}</span>
<i class="mdi mdi-24px mdi-menu-down" />
</button>
<ul class="menu text-left">
@@ -74,7 +74,7 @@
</div>
<div class="workspace-query-info">
<div v-if="sortedResults.length">
{{ $t('word.processes') }}: <b>{{ sortedResults.length.toLocaleString() }}</b>
{{ t('word.processes') }}: <b>{{ sortedResults.length.toLocaleString() }}</b>
</div>
</div>
</div>
@@ -144,6 +144,9 @@ import { useConnectionsStore } from '@/stores/connections';
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
import ModalProcessesListRow from '@/components/ModalProcessesListRow.vue';
import ModalProcessesListContext from '@/components/ModalProcessesListContext.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { addNotification } = useNotificationsStore();
const { getConnectionName } = useConnectionsStore();

View File

@@ -4,7 +4,7 @@
@close-context="closeContext"
>
<div v-if="props.selectedRow" class="context-element">
<span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ $t('word.copy') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ t('word.copy') }}</span>
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
<div class="context-submenu">
<div
@@ -13,7 +13,7 @@
@click="copyCell"
>
<span class="d-flex">
<i class="mdi mdi-18px mdi-numeric-0 mdi-rotate-90 text-light pr-1" /> {{ $tc('word.cell', 1) }}
<i class="mdi mdi-18px mdi-numeric-0 mdi-rotate-90 text-light pr-1" /> {{ t('word.cell', 1) }}
</span>
</div>
<div
@@ -22,7 +22,7 @@
@click="copyRow"
>
<span class="d-flex">
<i class="mdi mdi-18px mdi-table-row text-light pr-1" /> {{ $tc('word.row', 1) }}
<i class="mdi mdi-18px mdi-table-row text-light pr-1" /> {{ t('word.row', 1) }}
</span>
</div>
</div>
@@ -33,7 +33,7 @@
@click="killProcess"
>
<span class="d-flex">
<i class="mdi mdi-18px mdi-close-circle-outline text-light pr-1" /> {{ $t('message.killProcess') }}
<i class="mdi mdi-18px mdi-close-circle-outline text-light pr-1" /> {{ t('message.killProcess') }}
</span>
</div>
</BaseContextMenu>
@@ -41,6 +41,9 @@
<script setup lang="ts">
import BaseContextMenu from '@/components/BaseContextMenu.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
contextEvent: MouseEvent,

View File

@@ -12,19 +12,19 @@
class="cell-content"
:class="`${isNull(col)} type-${typeof col === 'number' ? 'int' : 'varchar'}`"
@dblclick="dblClick(cKey)"
>{{ cutText(col) }}</span>
>{{ cutText(col, 250) }}</span>
</div>
<ConfirmModal
v-if="isInfoModal"
:confirm-text="$t('word.update')"
:cancel-text="$t('word.close')"
:confirm-text="t('word.update')"
:cancel-text="t('word.close')"
size="medium"
:hide-footer="true"
@hide="hideInfoModal"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-information-outline mr-1" /> {{ $t('message.processInfo') }}
<i class="mdi mdi-24px mdi-information-outline mr-1" /> {{ t('message.processInfo') }}
</div>
</template>
<template #body>
@@ -48,6 +48,12 @@
import { Ref, ref } from 'vue';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import TextEditor from '@/components/BaseTextEditor.vue';
import { useFilters } from '@/composables/useFilters';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { cutText } = useFilters();
const props = defineProps({
row: Object
@@ -79,11 +85,6 @@ const dblClick = (col: string) => {
isInfoModal.value = true;
};
const cutText = (val: string | number) => {
if (typeof val !== 'string') return val;
return val.length > 250 ? `${val.substring(0, 250)}[...]` : val;
};
</script>
<style lang="scss">

View File

@@ -315,7 +315,7 @@
</template>
<script setup lang="ts">
import { onBeforeUnmount, Ref, ref } from 'vue';
import { onBeforeUnmount, Ref, ref, computed } from 'vue';
import { shell } from 'electron';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -328,9 +328,9 @@ import ModalSettingsUpdate from '@/components/ModalSettingsUpdate.vue';
import ModalSettingsChangelog from '@/components/ModalSettingsChangelog.vue';
import BaseTextEditor from '@/components/BaseTextEditor.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import { computed } from '@vue/reactivity';
import { AvailableLocale } from '@/i18n';
const { t, availableLocales } = useI18n();
const { t } = useI18n();
const applicationStore = useApplicationStore();
const settingsStore = useSettingsStore();
@@ -449,7 +449,7 @@ ORDER BY
employee.id ASC;
`;
const localLocale: Ref<string> = ref(null);
const localLocale: Ref<AvailableLocale> = ref(null);
const localPageSize: Ref<number> = ref(null);
const localTimeout: Ref<number> = ref(null);
const localEditorTheme: Ref<string> = ref(null);
@@ -457,7 +457,7 @@ const selectedTab: Ref<string> = ref('general');
const locales = computed(() => {
const locales = [];
for (const locale of availableLocales)
for (const locale of Object.keys(localesNames))
locales.push({ code: locale, name: localesNames[locale] });
return locales;
@@ -517,7 +517,7 @@ const toggleLineWrap = () => {
changeLineWrap(!selectedLineWrap.value);
};
localLocale.value = selectedLocale.value as string;
localLocale.value = selectedLocale.value;
localPageSize.value = pageSize.value as number;
localTimeout.value = notificationsTimeout.value as number;
localEditorTheme.value = editorTheme.value as string;
@@ -538,6 +538,12 @@ onBeforeUnmount(() => {
.modal-body {
overflow: hidden;
.tab-link{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.panel-body {
min-height: calc(25vh - 70px);
max-height: 65vh;

View File

@@ -26,27 +26,27 @@
:class="{'loading': updateStatus === 'checking'}"
@click="checkForUpdates"
>
{{ $t('message.checkForUpdates') }}
{{ t('message.checkForUpdates') }}
</button>
<button
v-else-if="updateStatus === 'downloaded'"
class="btn btn-primary"
@click="restartToUpdate"
>
{{ $t('message.restartToInstall') }}
{{ t('message.restartToInstall') }}
</button>
<button
v-else-if="updateStatus === 'link'"
class="btn btn-primary"
@click="openOutside('https://antares-sql.app/download.html')"
>
{{ $t('message.goToDownloadPage') }}
{{ t('message.goToDownloadPage') }}
</button>
</div>
<div class="form-group mt-4">
<label class="form-switch d-inline-block disabled" @click.prevent="toggleAllowPrerelease">
<input type="checkbox" :checked="allowPrerelease">
<i class="form-icon" /> {{ $t('message.includeBetaUpdates') }}
<i class="form-icon" /> {{ t('message.includeBetaUpdates') }}
</label>
</div>
</div>

View File

@@ -8,27 +8,27 @@
class="context-element"
@click="unpin"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-pin-off text-light pr-1" /> {{ $t('word.unpin') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-pin-off text-light pr-1" /> {{ t('word.unpin') }}</span>
</div>
<div
v-else
class="context-element"
@click="pin"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-pin mdi-rotate-45 text-light pr-1" /> {{ $t('word.pin') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-pin mdi-rotate-45 text-light pr-1" /> {{ t('word.pin') }}</span>
</div>
<div
v-if="isConnected"
class="context-element"
@click="disconnect"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-power text-light pr-1" /> {{ $t('word.disconnect') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-power text-light pr-1" /> {{ t('word.disconnect') }}</span>
</div>
<div class="context-element" @click="duplicateConnection">
<span class="d-flex"><i class="mdi mdi-18px mdi-content-duplicate text-light pr-1" /> {{ $t('word.duplicate') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-content-duplicate text-light pr-1" /> {{ t('word.duplicate') }}</span>
</div>
<div class="context-element" @click="showConfirmModal">
<span class="d-flex"><i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ $t('word.delete') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ t('word.delete') }}</span>
</div>
<ConfirmModal
@@ -38,12 +38,12 @@
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-server-remove mr-1" /> {{ $t('message.deleteConnection') }}
<i class="mdi mdi-24px mdi-server-remove mr-1" /> {{ t('message.deleteConnection') }}
</div>
</template>
<template #body>
<div class="mb-2">
{{ $t('message.deleteCorfirm') }} <b>{{ connectionName }}</b>?
{{ t('message.deleteCorfirm') }} <b>{{ connectionName }}</b>?
</div>
</template>
</ConfirmModal>

View File

@@ -1,14 +1,14 @@
<template>
<ConfirmModal
:confirm-text="$t('word.update')"
:cancel-text="$t('word.close')"
:confirm-text="t('word.update')"
:cancel-text="t('word.close')"
size="large"
:hide-footer="true"
@hide="hideScratchpad"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-notebook-edit-outline mr-1" /> {{ $t('word.scratchpad') }}
<i class="mdi mdi-24px mdi-notebook-edit-outline mr-1" /> {{ t('word.scratchpad') }}
</div>
</template>
<template #body>
@@ -22,7 +22,7 @@
:show-line-numbers="false"
/>
</div>
<small class="text-gray">{{ $t('message.markdownSupported') }}</small>
<small class="text-gray">{{ t('message.markdownSupported') }}</small>
</div>
</template>
</ConfirmModal>
@@ -35,6 +35,9 @@ import { useApplicationStore } from '@/stores/application';
import { useScratchpadStore } from '@/stores/scratchpad';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import TextEditor from '@/components/BaseTextEditor.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const applicationStore = useApplicationStore();
const scratchpadStore = useScratchpadStore();

View File

@@ -55,7 +55,7 @@
@mouseover.self="tooltipPosition"
>
<i class="settingbar-element-icon mdi mdi-24px mdi-dots-horizontal text-light" />
<span class="ex-tooltip-content">{{ $t('message.allConnections') }} (Shift+CTRL+Space)</span>
<span class="ex-tooltip-content">{{ t('message.allConnections') }} (Shift+CTRL+Space)</span>
</li>
<li
class="settingbar-element btn btn-link ex-tooltip"
@@ -64,7 +64,7 @@
@mouseover.self="tooltipPosition"
>
<i class="settingbar-element-icon mdi mdi-24px mdi-plus text-light" />
<span class="ex-tooltip-content">{{ $t('message.addConnection') }}</span>
<span class="ex-tooltip-content">{{ t('message.addConnection') }}</span>
</li>
</ul>
</div>
@@ -77,11 +77,11 @@
@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>
<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>
<span class="ex-tooltip-content">{{ t('word.settings') }}</span>
</li>
</ul>
</div>
@@ -99,6 +99,9 @@ import * as Draggable from 'vuedraggable';
import SettingBarContext from '@/components/SettingBarContext.vue';
import { ConnectionParams } from 'common/interfaces/antares';
import { useElementBounding, useScroll } from '@vueuse/core';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const applicationStore = useApplicationStore();
const connectionsStore = useConnectionsStore();

View File

@@ -31,10 +31,10 @@
>
<i class="mdi mdi-18px mdi-code-tags mr-1" />
<span>
<span>{{ cutText(element.content || 'Query') }} #{{ element.index }}</span>
<span>{{ cutText(element.content || 'Query', 20, true) }} #{{ element.index }}</span>
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -47,11 +47,11 @@
@dblclick="openAsPermanentTab(element)"
>
<i class="mdi mdi-18px mr-1" :class="element.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
<span :title="`${$t('word.data').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
<span class=" text-italic">{{ cutText(element.elementName) }}</span>
<span :title="`${t('word.data').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
<span class=" text-italic">{{ cutText(element.elementName, 20, true) }}</span>
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -60,11 +60,11 @@
<a v-else-if="element.type === 'data'" class="tab-link">
<i class="mdi mdi-18px mr-1" :class="element.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
<span :title="`${$t('word.data').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ cutText(element.elementName) }}
<span :title="`${t('word.data').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ cutText(element.elementName, 20, true) }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -77,11 +77,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ $t('message.newTable') }}
<span :title="`${t('word.new').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ t('message.newTable') }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -94,11 +94,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ cutText(element.elementName) }}
<span :title="`${t('word.settings').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ cutText(element.elementName, 20, true) }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -111,11 +111,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.view`)}`">
{{ cutText(element.elementName) }}
<span :title="`${t('word.settings').toUpperCase()}: ${t(`word.view`)}`">
{{ cutText(element.elementName, 20, true) }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -128,11 +128,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ $t('message.newView') }}
<span :title="`${t('word.new').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ t('message.newView') }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -145,11 +145,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ $t('message.newTrigger') }}
<span :title="`${t('word.new').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ t('message.newTrigger') }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -162,11 +162,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ $t('message.newRoutine') }}
<span :title="`${t('word.new').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ t('message.newRoutine') }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -179,11 +179,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ $t('message.newFunction') }}
<span :title="`${t('word.new').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ t('message.newFunction') }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -196,11 +196,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ $t('message.newTriggerFunction') }}
<span :title="`${t('word.new').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ t('message.newTriggerFunction') }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -213,11 +213,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ $t('message.newScheduler') }}
<span :title="`${t('word.new').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ t('message.newScheduler') }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -231,11 +231,11 @@
@dblclick="openAsPermanentTab(element)"
>
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
<span class=" text-italic">{{ cutText(element.elementName) }}</span>
<span :title="`${t('word.settings').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
<span class=" text-italic">{{ cutText(element.elementName, 20, true) }}</span>
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -248,11 +248,11 @@
:class="{'badge': element.isChanged}"
>
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
{{ cutText(element.elementName) }}
<span :title="`${t('word.settings').toUpperCase()}: ${t(`word.${element.elementType}`)}`">
{{ cutText(element.elementName, 20, true) }}
<span
class="btn btn-clear"
:title="$t('word.close')"
:title="t('word.close')"
@mousedown.left.stop
@click.stop="closeTab(element)"
/>
@@ -268,7 +268,7 @@
<a
class="tab-link workspace-tools-link dropdown-toggle"
tabindex="0"
:title="$t('word.tools')"
:title="t('word.tools')"
>
<i class="mdi mdi-24px mdi-tools" />
</a>
@@ -276,13 +276,13 @@
<li class="menu-item">
<a class="c-hand p-vcentered" @click="showProcessesModal">
<i class="mdi mdi-memory mr-1 tool-icon" />
<span>{{ $t('message.processesList') }}</span>
<span>{{ t('message.processesList') }}</span>
</a>
</li>
<li class="menu-item">
<a class="c-hand p-vcentered" @click="toggleConsole">
<i class="mdi mdi-console-line mr-1 tool-icon" />
<span>{{ $t('word.console') }}</span>
<span>{{ t('word.console') }}</span>
</a>
</li>
<li
@@ -292,7 +292,7 @@
>
<a class="c-hand p-vcentered disabled">
<i class="mdi mdi-shape mr-1 tool-icon" />
<span>{{ $t('word.variables') }}</span>
<span>{{ t('word.variables') }}</span>
</a>
</li>
<li
@@ -302,7 +302,7 @@
>
<a class="c-hand p-vcentered disabled">
<i class="mdi mdi-account-group mr-1 tool-icon" />
<span>{{ $t('message.manageUsers') }}</span>
<span>{{ t('message.manageUsers') }}</span>
</a>
</li>
</ul>
@@ -312,7 +312,7 @@
<li class="tab-item">
<a
class="tab-add"
:title="$t('message.openNewTab')"
:title="t('message.openNewTab')"
@click="addQueryTab"
>
<i class="mdi mdi-24px mdi-plus" />
@@ -485,6 +485,7 @@ import Connection from '@/ipc-api/Connection';
import { useWorkspacesStore, WorkspaceTab } from '@/stores/workspaces';
import { useConsoleStore } from '@/stores/console';
import { ConnectionParams } from 'common/interfaces/antares';
import { useFilters } from '@/composables/useFilters';
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState.vue';
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar.vue';
@@ -510,7 +511,11 @@ import WorkspaceTabPropsFunction from '@/components/WorkspaceTabPropsFunction.vu
import WorkspaceTabPropsScheduler from '@/components/WorkspaceTabPropsScheduler.vue';
import ModalProcessesList from '@/components/ModalProcessesList.vue';
import ModalDiscardChanges from '@/components/ModalDiscardChanges.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const { cutText } = useFilters();
const workspacesStore = useWorkspacesStore();
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
@@ -640,14 +645,6 @@ const addWheelEvent = () => {
}
};
const cutText = (string: string) => {
const limit = 20;
const escapedString = string.replace(/\s{2,}/g, ' ');
if (escapedString.length > limit)
return `${escapedString.substr(0, limit)}...`;
return escapedString;
};
(async () => {
await addWorkspace(props.connection.uid);
const isInitiated = await Connection.checkConnection(props.connection.uid);

View File

@@ -15,18 +15,18 @@
<i
v-if="customizations.schemas"
class="mdi mdi-18px mdi-database-plus c-hand mr-2"
:title="$t('message.createNewSchema')"
:title="t('message.createNewSchema')"
@click="showNewDBModal"
/>
<i
class="mdi mdi-18px mdi-refresh c-hand mr-2"
:class="{'rotate':isRefreshing}"
:title="$t('word.refresh')"
:title="t('word.refresh')"
@click="refresh"
/>
<i
class="mdi mdi-18px mdi-power c-hand"
:title="$t('word.disconnect')"
:title="t('word.disconnect')"
@click="disconnectWorkspace(connection.uid)"
/>
</span>
@@ -38,7 +38,7 @@
v-model="searchTerm"
class="form-input input-sm"
type="text"
:placeholder="$t('message.searchForElements')"
:placeholder="t('message.searchForElements')"
>
<i v-if="!searchTerm" class="form-icon mdi mdi-magnify mdi-18px" />
<i
@@ -133,6 +133,9 @@ import TableContext from '@/components/WorkspaceExploreBarTableContext.vue';
import MiscContext from '@/components/WorkspaceExploreBarMiscContext.vue';
import MiscFolderContext from '@/components/WorkspaceExploreBarMiscFolderContext.vue';
import ModalNewSchema from '@/components/ModalNewSchema.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
connection: Object,

View File

@@ -8,7 +8,7 @@
class="context-element"
@click="runElementCheck"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-play text-light pr-1" /> {{ $t('word.run') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-play text-light pr-1" /> {{ t('word.run') }}</span>
</div>
<div
v-if="selectedMisc.type === 'trigger' && customizations.triggerEnableDisable"
@@ -16,10 +16,10 @@
@click="toggleTrigger"
>
<span v-if="!selectedMisc.enabled" class="d-flex">
<i class="mdi mdi-18px mdi-play text-light pr-1" /> {{ $t('word.enable') }}
<i class="mdi mdi-18px mdi-play text-light pr-1" /> {{ t('word.enable') }}
</span>
<span v-else class="d-flex">
<i class="mdi mdi-18px mdi-pause text-light pr-1" /> {{ $t('word.disable') }}
<i class="mdi mdi-18px mdi-pause text-light pr-1" /> {{ t('word.disable') }}
</span>
</div>
<div
@@ -28,14 +28,14 @@
@click="toggleScheduler"
>
<span v-if="!selectedMisc.enabled" class="d-flex">
<i class="mdi mdi-18px mdi-play text-light pr-1" /> {{ $t('word.enable') }}
<i class="mdi mdi-18px mdi-play text-light pr-1" /> {{ t('word.enable') }}
</span>
<span v-else class="d-flex">
<i class="mdi mdi-18px mdi-pause text-light pr-1" /> {{ $t('word.disable') }}
<i class="mdi mdi-18px mdi-pause text-light pr-1" /> {{ t('word.disable') }}
</span>
</div>
<div class="context-element" @click="showDeleteModal">
<span class="d-flex"><i class="mdi mdi-18px mdi-table-remove text-light pr-1" /> {{ $t('word.delete') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-remove text-light pr-1" /> {{ t('word.delete') }}</span>
</div>
<ConfirmModal
v-if="isDeleteModal"
@@ -50,7 +50,7 @@
</template>
<template #body>
<div class="mb-2">
{{ $t('message.deleteCorfirm') }} "<b>{{ selectedMisc.name }}</b>"?
{{ t('message.deleteCorfirm') }} "<b>{{ selectedMisc.name }}</b>"?
</div>
</template>
</ConfirmModal>

View File

@@ -4,7 +4,7 @@
@close-context="closeContext"
>
<div class="context-element">
<span class="d-flex"><i class="mdi mdi-18px mdi-plus text-light pr-1" /> {{ $t('word.add') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-plus text-light pr-1" /> {{ t('word.add') }}</span>
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
<div class="context-submenu">
<div
@@ -12,49 +12,49 @@
class="context-element"
@click="openCreateTableTab"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-table text-light pr-1" /> {{ $t('word.table') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-table text-light pr-1" /> {{ t('word.table') }}</span>
</div>
<div
v-if="workspace.customizations.viewAdd"
class="context-element"
@click="openCreateViewTab"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-eye text-light pr-1" /> {{ $t('word.view') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-eye text-light pr-1" /> {{ t('word.view') }}</span>
</div>
<div
v-if="workspace.customizations.triggerAdd"
class="context-element"
@click="openCreateTriggerTab"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ $tc('word.trigger', 1) }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ t('word.trigger', 1) }}</span>
</div>
<div
v-if="workspace.customizations.routineAdd"
class="context-element"
@click="openCreateRoutineTab"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-sync-circle pr-1" /> {{ $tc('word.storedRoutine', 1) }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-sync-circle pr-1" /> {{ t('word.storedRoutine', 1) }}</span>
</div>
<div
v-if="workspace.customizations.functionAdd"
class="context-element"
@click="openCreateFunctionTab"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-arrow-right-bold-box pr-1" /> {{ $tc('word.function', 1) }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-arrow-right-bold-box pr-1" /> {{ t('word.function', 1) }}</span>
</div>
<div
v-if="workspace.customizations.triggerFunctionAdd"
class="context-element"
@click="openCreateTriggerFunctionTab"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-cog-clockwise pr-1" /> {{ $tc('word.triggerFunction', 1) }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-cog-clockwise pr-1" /> {{ t('word.triggerFunction', 1) }}</span>
</div>
<div
v-if="workspace.customizations.schedulerAdd"
class="context-element"
@click="openCreateSchedulerTab"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-calendar-clock text-light pr-1" /> {{ $tc('word.scheduler', 1) }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-calendar-clock text-light pr-1" /> {{ t('word.scheduler', 1) }}</span>
</div>
</div>
</div>
@@ -63,28 +63,28 @@
class="context-element"
@click="showExportSchemaModal"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-arrow-down text-light pr-1" /> {{ $t('word.export') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-arrow-down text-light pr-1" /> {{ t('word.export') }}</span>
</div>
<div
v-if="workspace.customizations.schemaImport"
class="context-element"
@click="initImport"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-arrow-up text-light pr-1" /> {{ $t('word.import') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-arrow-up text-light pr-1" /> {{ t('word.import') }}</span>
</div>
<div
v-if="workspace.customizations.schemaEdit"
class="context-element"
@click="showEditModal"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-edit text-light pr-1" /> {{ $t('word.edit') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-edit text-light pr-1" /> {{ t('word.edit') }}</span>
</div>
<div
v-if="workspace.customizations.schemaDrop"
class="context-element"
@click="showDeleteModal"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-remove text-light pr-1" /> {{ $t('word.delete') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-database-remove text-light pr-1" /> {{ t('word.delete') }}</span>
</div>
<ConfirmModal
@@ -95,12 +95,12 @@
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-database-remove mr-1" />
<span class="cut-text">{{ $t('message.deleteSchema') }}</span>
<span class="cut-text">{{ t('message.deleteSchema') }}</span>
</div>
</template>
<template #body>
<div class="mb-2">
{{ $t('message.deleteCorfirm') }} "<b>{{ selectedSchema }}</b>"?
{{ t('message.deleteCorfirm') }} "<b>{{ selectedSchema }}</b>"?
</div>
</template>
</ConfirmModal>
@@ -135,6 +135,9 @@ import ModalExportSchema from '@/components/ModalExportSchema.vue';
import ModalImportSchema from '@/components/ModalImportSchema.vue';
import Schema from '@/ipc-api/Schema';
import Application from '@/ipc-api/Application';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
contextEvent: MouseEvent,

View File

@@ -35,7 +35,7 @@
@close-context="isContext = false"
>
<div class="context-element" @click="copyQuery">
<span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ $t('word.copy') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ t('word.copy') }}</span>
</div>
</BaseContextMenu>
</template>

View File

@@ -11,27 +11,27 @@
@click="saveChanges"
>
<i class="mdi mdi-24px mdi-content-save mr-1" />
<span>{{ $t('word.save') }}</span>
<span>{{ t('word.save') }}</span>
</button>
<button
:disabled="!isChanged"
class="btn btn-link btn-sm mr-0"
:title="$t('message.clearChanges')"
:title="t('message.clearChanges')"
@click="clearChanges"
>
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
<span>{{ $t('word.clear') }}</span>
<span>{{ t('word.clear') }}</span>
</button>
<div class="divider-vert py-3" />
<button class="btn btn-dark btn-sm" @click="showParamsModal">
<i class="mdi mdi-24px mdi-dots-horizontal mr-1" />
<span>{{ $t('word.parameters') }}</span>
<span>{{ t('word.parameters') }}</span>
</button>
</div>
<div class="workspace-query-info">
<div class="d-flex" :title="$t('word.schema')">
<div class="d-flex" :title="t('word.schema')">
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
</div>
</div>
@@ -42,7 +42,7 @@
<div class="column col-auto">
<div class="form-group">
<label class="form-label">
{{ $t('word.name') }}
{{ t('word.name') }}
</label>
<input
ref="firstInput"
@@ -55,7 +55,7 @@
<div v-if="customizations.languages" class="column col-auto">
<div class="form-group">
<label class="form-label">
{{ $t('word.language') }}
{{ t('word.language') }}
</label>
<BaseSelect
v-model="localRoutine.language"
@@ -67,11 +67,11 @@
<div v-if="customizations.definer" class="column col-auto">
<div class="form-group">
<label class="form-label">
{{ $t('word.definer') }}
{{ t('word.definer') }}
</label>
<BaseSelect
v-model="localRoutine.definer"
:options="[{value: '', name:$t('message.currentUser')}, ...workspace.users]"
:options="[{value: '', name:t('message.currentUser')}, ...workspace.users]"
:option-label="(user: any) => user.value === '' ? user.name : `${user.name}@${user.host}`"
:option-track-by="(user: any) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
class="form-select"
@@ -81,7 +81,7 @@
<div v-if="customizations.comment" class="column">
<div class="form-group">
<label class="form-label">
{{ $t('word.comment') }}
{{ t('word.comment') }}
</label>
<input
v-model="localRoutine.comment"
@@ -93,7 +93,7 @@
<div class="column col-auto">
<div class="form-group">
<label class="form-label">
{{ $t('message.sqlSecurity') }}
{{ t('message.sqlSecurity') }}
</label>
<BaseSelect
v-model="localRoutine.security"
@@ -105,7 +105,7 @@
<div v-if="customizations.procedureDataAccess" class="column col-auto">
<div class="form-group">
<label class="form-label">
{{ $t('message.dataAccess') }}
{{ t('message.dataAccess') }}
</label>
<BaseSelect
v-model="localRoutine.dataAccess"
@@ -118,7 +118,7 @@
<div class="form-group">
<label class="form-label d-invisible">.</label>
<label class="form-checkbox form-inline">
<input v-model="localRoutine.deterministic" type="checkbox"><i class="form-icon" /> {{ $t('word.deterministic') }}
<input v-model="localRoutine.deterministic" type="checkbox"><i class="form-icon" /> {{ t('word.deterministic') }}
</label>
</div>
</div>
@@ -126,7 +126,7 @@
</div>
<div class="workspace-query-results column col-12 mt-2 p-relative">
<BaseLoader v-if="isLoading" />
<label class="form-label ml-2">{{ $t('message.routineBody') }}</label>
<label class="form-label ml-2">{{ t('message.routineBody') }}</label>
<QueryEditor
v-show="isSelected"
ref="queryEditor"
@@ -160,6 +160,9 @@ import BaseLoader from '@/components/BaseLoader.vue';
import WorkspaceTabPropsRoutineParamsModal from '@/components/WorkspaceTabPropsRoutineParamsModal.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import { FunctionParam } from 'common/interfaces/antares';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
tabUid: String,

View File

@@ -449,6 +449,18 @@ const copyRow = (format: string) => {
}
navigator.clipboard.writeText(sqlInserts.join('\n'));
}
else if (format === 'csv') {
const csv = [];
if (!Array.isArray(contentToCopy)) contentToCopy = [contentToCopy];
if (contentToCopy.length)
csv.push(Object.keys(contentToCopy[0]).join(';'));
for (const row of contentToCopy)
csv.push(Object.values(row).map(col => typeof col === 'string' ? `"${col}"` : col).join(';'));
navigator.clipboard.writeText(csv.join('\n'));
}
};
const duplicateRow = () => {

View File

@@ -21,6 +21,11 @@
<i class="mdi mdi-18px mdi-table-row text-light pr-1" /> {{ t('word.row', selectedRows.length) }} (JSON)
</span>
</div>
<div class="context-element" @click="copyRow('csv')">
<span class="d-flex">
<i class="mdi mdi-18px mdi-table-row text-light pr-1" /> {{ t('word.row', selectedRows.length) }} (CSV)
</span>
</div>
<div class="context-element" @click="copyRow('sql')">
<span class="d-flex">
<i class="mdi mdi-18px mdi-table-row text-light pr-1" /> {{ t('word.row', selectedRows.length) }} (SQL INSERT)

View File

@@ -19,7 +19,7 @@
class="cell-content"
:class="`${isNull(col)} ${typeClass(fields[cKey].type)}`"
@dblclick="editON(cKey)"
>{{ cutText(typeFormat(col, fields[cKey].type.toLowerCase(), fields[cKey].length) as string) }}</span>
>{{ cutText(typeFormat(col, fields[cKey].type.toLowerCase(), fields[cKey].length) as string, 250) }}</span>
<ForeignKeySelect
v-else-if="isForeignKey(cKey)"
v-model="editingContent"
@@ -221,9 +221,11 @@ import TextEditor from '@/components/BaseTextEditor.vue';
import BaseMap from '@/components/BaseMap.vue';
import ForeignKeySelect from '@/components/ForeignKeySelect.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import { useFilters } from '@/composables/useFilters';
import { QueryForeign, TableField } from 'common/interfaces/antares';
const { t } = useI18n();
const { cutText } = useFilters();
const props = defineProps({
row: Object,
@@ -546,11 +548,6 @@ const onKey = (e: KeyboardEvent) => {
}
};
const cutText = (val: string) => {
if (typeof val !== 'string') return val;
return val.length > 128 ? `${val.substring(0, 128)}[...]` : val;
};
const typeFormat = (val: string | number | Date | number[], type: string, precision?: number | false) => {
if (!val) return val;

View File

@@ -85,7 +85,7 @@
@click="showFakerModal()"
>
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
<span>{{ $tc('message.insertRow', 2) }}</span>
<span>{{ t('message.insertRow', 2) }}</span>
</button>
<div class="dropdown table-dropdown pr-2">
@@ -189,6 +189,9 @@ import WorkspaceTabTableFilters from '@/components/WorkspaceTabTableFilters.vue'
import ModalFakerRows from '@/components/ModalFakerRows.vue';
import { ConnectionParams } from 'common/interfaces/antares';
import { TableFilterClausole } from 'common/interfaces/tableApis';
import { useFilters } from '@/composables/useFilters';
const { localeString } = useFilters();
const { t } = useI18n();
@@ -398,11 +401,6 @@ const updateFilters = (clausoles: TableFilterClausole[]) => {
getTableData();
};
const localeString = (val: number | null) => {
if (val !== null)
return val.toLocaleString();
};
const hasApproximately = computed(() => {
return results.value.length &&
results.value[0].rows &&

View File

@@ -51,7 +51,7 @@
class="btn btn-sm btn-primary mr-0 ml-2"
type="submit"
>
{{ $t('word.filter') }}
{{ t('word.filter') }}
</button>
<button
class="btn btn-sm btn-dark mr-0 ml-2"
@@ -71,6 +71,9 @@ import customizations from 'common/customizations';
import { NUMBER, FLOAT } from 'common/fieldTypes';
import BaseSelect from '@/components/BaseSelect.vue';
import { TableFilterClausole } from 'common/interfaces/tableApis';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
fields: Array as Prop<TableField[]>,

View File

@@ -0,0 +1,38 @@
import * as moment from 'moment';
export function useFilters () {
const cutText = (string: string, length: number, escape?: boolean) => {
if (typeof string !== 'string') return string;
if (escape) string = string.replace(/\s{2,}/g, ' ');
return string.length > length ? `${string.substring(0, length)}...` : string;
};
const lastPart = (string: string, length: number) => {
if (!string) return '';
string = string.split(/[/\\]+/).pop();
if (string.length >= length)
string = `...${string.slice(-length)}`;
return string;
};
const formatDate = (date: Date) => moment(date).isValid() ? moment(date).format('HH:mm:ss - YYYY/MM/DD') : date;
const localeString = (number: number | null) => {
if (number !== null)
return number.toLocaleString();
};
const wrapNumber = (num: number) => {
if (!num) return '';
return `(${num})`;
};
return {
cutText,
formatDate,
wrapNumber,
lastPart,
localeString
};
}

View File

@@ -1,4 +1,4 @@
module.exports = {
export const arSA = {
word: {
edit: 'تعديل',
save: 'حفظ',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const deDE = {
word: {
edit: 'Bearbeiten',
save: 'Speichern',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const enUS = {
word: {
edit: 'Edit',
save: 'Save',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const esES = {
word: {
edit: 'Editar',
save: 'Guardar',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const frFR = {
word: {
edit: 'Editer',
save: 'Sauver',

View File

@@ -1,19 +1,41 @@
import { createI18n } from 'vue-i18n';
import { enUS } from './en-US';
import { itIT } from './it-IT';
import { arSA } from './ar-SA';
import { esES } from './es-ES';
import { frFR } from './fr-FR';
import { ptBR } from './pt-BR';
import { deDE } from './de-DE';
import { viVN } from './vi-VN';
import { jaJP } from './ja-JP';
import { zhCN } from './zh-CN';
import { ruRU } from './ru-RU';
const i18n = createI18n({
const messages = {
'en-US': enUS,
'it-IT': itIT,
'ar-SA': arSA,
'es-ES': esES,
'fr-FR': frFR,
'pt-BR': ptBR,
'de-DE': deDE,
'vi-VN': viVN,
'ja-JP': jaJP,
'zh-CN': zhCN,
'ru-RU': ruRU
};
type NestedPartial<T> = {
[K in keyof T]?: T[K] extends Array<infer R> ? Array<NestedPartial<R>> : (T[K] extends unknown ? unknown : NestedPartial<T[K]>)
};
export type MessageSchema = typeof enUS
export type AvailableLocale = keyof typeof messages
const i18n = createI18n<[NestedPartial<MessageSchema>], AvailableLocale>({
fallbackLocale: 'en-US',
messages: {
'en-US': require('./en-US'),
'it-IT': require('./it-IT'),
'ar-SA': require('./ar-SA'),
'es-ES': require('./es-ES'),
'fr-FR': require('./fr-FR'),
'pt-BR': require('./pt-BR'),
'de-DE': require('./de-DE'),
'vi-VN': require('./vi-VN'),
'ja-JP': require('./ja-JP'),
'zh-CN': require('./zh-CN'),
'ru-RU': require('./ru-RU')
}
allowComposition: true,
messages
});
export default i18n;
export { i18n };

View File

@@ -1,4 +1,4 @@
module.exports = {
export const itIT = {
word: {
edit: 'Modifica',
save: 'Salva',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const jaJP = {
word: {
edit: '編集',
save: '保存',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const ptBR = {
word: {
edit: 'Editar',
save: 'Salvar',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const ruRU = {
word: {
edit: 'Редактировать',
save: 'Сохранить',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const viVN = {
word: {
edit: 'Chỉnh sửa',
save: 'Lưu',

View File

@@ -1,4 +1,4 @@
module.exports = {
export const zhCN = {
word: {
edit: '编辑',
save: '保存',

View File

@@ -2,10 +2,10 @@
import { ipcRenderer } from 'electron';
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import { VueMaskDirective } from 'v-mask';
import '@mdi/font/css/materialdesignicons.css';
import 'leaflet/dist/leaflet.css';
import '@/scss/main.scss';
import { VueMaskDirective } from 'v-mask';
import { useApplicationStore } from '@/stores/application';
import { useSettingsStore } from '@/stores/settings';
@@ -13,7 +13,7 @@ import { useNotificationsStore } from '@/stores/notifications';
import { useConsoleStore } from '@/stores/console';
import App from '@/App.vue';
import i18n from '@/i18n';
import { i18n } from '@/i18n';
// https://github.com/probil/v-mask/issues/498#issuecomment-827027834
const vMaskV2 = VueMaskDirective;

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { ipcRenderer } from 'electron';
import i18n from '@/i18n';
import { i18n, AvailableLocale } from '@/i18n';
import * as Store from 'electron-store';
const persistentStore = new Store({ name: 'settings' });
const isDarkTheme = window.matchMedia('(prefers-color-scheme: dark)');
@@ -12,7 +12,7 @@ export type ApplicationTheme = 'light' | 'dark';
export const useSettingsStore = defineStore('settings', {
state: () => ({
locale: persistentStore.get('locale', 'en-US') as string,
locale: persistentStore.get('locale', 'en-US') as AvailableLocale,
allowPrerelease: persistentStore.get('allow_prerelease', true) as boolean,
explorebarSize: persistentStore.get('explorebar_size', null) as number,
notificationsTimeout: persistentStore.get('notifications_timeout', 5) as number,
@@ -27,7 +27,7 @@ export const useSettingsStore = defineStore('settings', {
disableScratchpad: persistentStore.get('disable_scratchpad', false) as boolean
}),
actions: {
changeLocale (locale: string) {
changeLocale (locale: AvailableLocale) {
this.locale = locale;
i18n.global.locale = locale;
persistentStore.set('locale', this.locale);

View File

@@ -23,12 +23,13 @@ test('main window elements visibility', async () => {
const visibleSelectors = [
// '#titlebar',
'#window-content',
'#settingbar'
// '#footer'
'#settingbar',
'#footer'
];
for (const selector of visibleSelectors)
expect(await appWindow.isVisible(selector), `expect ${selector} visible`).toBe(true);
setTimeout(async () => {
for (const selector of visibleSelectors)
expect(await appWindow.isVisible(selector), `expect ${selector} visible`).toBe(true);
}, 3000);
});
// test('SQLite connection', async () => {// FIXME: not working on GitHub Actions