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

Compare commits

...

19 Commits

Author SHA1 Message Date
d12c6f5210 chore(release): 0.5.7 2022-06-19 16:11:12 +02:00
ee623b0a0f fix: unable to add new table fields 2022-06-14 11:48:36 +02:00
c37138c6f5 ci: fix linux upload artifacts github action [skip ci] 2022-06-12 19:58:22 +02:00
e754877ee6 Merge branch 'master' of https://github.com/antares-sql/antares 2022-06-12 18:30:48 +02:00
ed38a9e7ff ci: linux upload artifacts github action 2022-06-12 18:30:44 +02:00
6bad032f0d fix(Linux): setting bar tooltip position 2022-06-11 14:26:51 +02:00
d214c1f35b fix: reload tab content on tab sort 2022-06-11 01:11:08 +02:00
77d9cac092 fix: fields sorting in table setting tabs 2022-06-10 23:29:34 +02:00
cba2ce2e37 fix: selected foreign key value not visible in the insert row modal 2022-06-10 20:02:26 +02:00
5b33419b64 fix: exception on app start setting window title 2022-06-08 14:55:29 +02:00
00242697a1 feat: dynamic app window title 2022-06-08 13:24:14 +02:00
85cec05f70 perf(Linux): title bar improvements 2022-06-08 13:04:19 +02:00
5fa8bf38e4 perf(Windows): title bar improvements 2022-06-07 18:32:37 +02:00
23acf00def fix: main process not closed after window close on some conditions 2022-06-07 09:33:03 +02:00
1c666a07d8 Merge pull request #289 from toriphes/feat/hotkeys
Feat: Hokeys to navigate between tabs and result sets
2022-06-04 15:20:08 +02:00
Giulio Ganci
49abd1ea7f feat: hotkeys to navigate inside a table resultset 2022-06-04 08:45:48 +02:00
Giulio Ganci
d3b9e08446 feat: hotkeys to navigate forward or backward between tabs 2022-06-03 18:56:19 +02:00
20b814378b chore: package.json changes 2022-06-02 12:50:05 +02:00
8ce1d1a964 chore(release): 0.5.6 2022-06-02 11:31:10 +02:00
26 changed files with 464 additions and 130 deletions

View File

@@ -1,4 +1,4 @@
name: Build/release [linux]
name: Build/release [LINUX]
on: push

View File

@@ -1,4 +1,4 @@
name: Build/release [mac]
name: Build/release [MAC]
on: push

View File

@@ -1,4 +1,4 @@
name: Build/release [windows]
name: Build/release [WINDOWS]
on: push

View File

@@ -0,0 +1,26 @@
name: Create artifact [LINUX]
on:
workflow_dispatch: {}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: npm install & build
run: |
npm install
npm run build:local
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: linux-build
retention-days: 3
path: |
build
!build/*-unpacked
!build/.icon-ico

View File

@@ -1,4 +1,4 @@
name: Test end-to-end [linux]
name: Test end-to-end [LINUX]
on: push

View File

@@ -6,7 +6,8 @@
"PostgreSQL",
"SQLite",
"Windows",
"translation"
"translation",
"Linux"
],
"svg.preview.background": "transparent"
}

View File

@@ -2,6 +2,69 @@
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.7](https://github.com/antares-sql/antares/compare/v0.5.4...v0.5.7) (2022-06-19)
### Features
* added dropdown animation ([5398964](https://github.com/antares-sql/antares/commit/539896419064db9127f6a72acdbb11af2c4aa60a))
* dynamic app window title ([0024269](https://github.com/antares-sql/antares/commit/00242697a102f82dd0c731a3529c984fbdf83b3e))
* hotkeys to navigate forward or backward between tabs ([d3b9e08](https://github.com/antares-sql/antares/commit/d3b9e08446708654b3c6fad565b734d93effe683))
* hotkeys to navigate inside a table resultset ([49abd1e](https://github.com/antares-sql/antares/commit/49abd1ea7f5ec368e9a9201f8fd5b6520c4bd0a8))
* **translation:** russian translation, closes [#266](https://github.com/antares-sql/antares/issues/266) ([9082960](https://github.com/antares-sql/antares/commit/9082960310573a6e4d14bfbe82ed2eb1489f308d))
* **UI:** BaseSelect disabled state ([2b436d8](https://github.com/antares-sql/antares/commit/2b436d8613a1e3dff55d73adbddf5d2cd2452f27))
* **UI:** BaseSelect in table filters ([a037d0c](https://github.com/antares-sql/antares/commit/a037d0cc0148444e8e6c5b87c79f6ba9c2a6f0fe))
* **UI:** BaseSelect option list scrolls automatically using up/down keys ([0043d07](https://github.com/antares-sql/antares/commit/0043d077081fc49724722a5d5a74986d990c539d))
* **UI:** BaseSelect small variant ([5582a12](https://github.com/antares-sql/antares/commit/5582a12bbfade75dbcc7f9d71ada7190ed08d3c2))
* **UI:** BaseSelect supports disabled options ([f7e04d6](https://github.com/antares-sql/antares/commit/f7e04d633340a53420ce1c434e906c9434620e6e))
* **UI:** BaseSelect supports option groups ([1869e6a](https://github.com/antares-sql/antares/commit/1869e6a1482daf9381d9ac2244bf0aeffa758edc))
* **UI:** ForeignKeySelect implements BaseSelect component ([302c664](https://github.com/antares-sql/antares/commit/302c66457deeb50facf4735291640fcf48b78f66))
* **UI:** initial BaseSelect integration ([22622df](https://github.com/antares-sql/antares/commit/22622df2cfcb71054c6f6110b7ad9d4f635553dc))
* **UI:** new BaseSelect component ([745d551](https://github.com/antares-sql/antares/commit/745d551cc9253eae4e39e5d3406ceee051a7d6c1))
* **UI:** select tab replace with BaseSelect component ([42bc919](https://github.com/antares-sql/antares/commit/42bc9196ffc2f64b77f9cb42136255fc74815034))
### Bug Fixes
* empty query tab schema select if no schema selected ([31b7999](https://github.com/antares-sql/antares/commit/31b7999bba5d115913d42087614b9888bc761068))
* exception on app start setting window title ([5b33419](https://github.com/antares-sql/antares/commit/5b33419b6421d7d198a978e79e22d0a76306cdb4))
* fields sorting in table setting tabs ([77d9cac](https://github.com/antares-sql/antares/commit/77d9cac092fbb806810c3463ca066395fcab5307))
* inline field update not working with tables missing primary key ([caf776b](https://github.com/antares-sql/antares/commit/caf776bd55606c793c9763c204aa9f05d1feb27f))
* **Linux:** setting bar tooltip position ([6bad032](https://github.com/antares-sql/antares/commit/6bad032f0d1094736f651b6c06a60d2a0df36c98))
* main process not closed after window close on some conditions ([23acf00](https://github.com/antares-sql/antares/commit/23acf00def77b5662e48b84591a31760737774a7))
* **PostgreSQL:** idle timeout disabled ([a082514](https://github.com/antares-sql/antares/commit/a082514f88040c7e0ffdf4e8357bab45370a4c39))
* query tab content disappears reordering or closing other tabs, closes [#261](https://github.com/antares-sql/antares/issues/261) ([c5baf2b](https://github.com/antares-sql/antares/commit/c5baf2b0d379fdd28ee8cb907628bbfca940e2f6))
* reload tab content on tab sort ([d214c1f](https://github.com/antares-sql/antares/commit/d214c1f35ba231a8a01dbe8c0faad07d4b337752))
* selected foreign key value not visible in the insert row modal ([cba2ce2](https://github.com/antares-sql/antares/commit/cba2ce2e37cedbf0b242cc474b37bf052009ae62))
* **SQLite:** unable to insert rows with TEXT fields ([a7d5e19](https://github.com/antares-sql/antares/commit/a7d5e1973cd59d7d0ef1e74bdcf44d87fba43559))
* SSH tunnel connection error with private key, closes [#260](https://github.com/antares-sql/antares/issues/260) ([c826888](https://github.com/antares-sql/antares/commit/c826888b0dd0908958a4f727ddfa642e846269cf))
* **UI:** BaseSelect keyboard navigation ([7c45203](https://github.com/antares-sql/antares/commit/7c452036368fa0db6b9cde7c35e60a8e57bfece7))
* **UI:** BaseSelect style ([71b0736](https://github.com/antares-sql/antares/commit/71b0736d0ddbd599ab41cde0a6b0823e2bb7da2f))
* **UI:** select closes clicking on scrollbar ([8870304](https://github.com/antares-sql/antares/commit/8870304c15346257a90193807b9ae07c1393e3e2))
* unable to add new table fields ([ee623b0](https://github.com/antares-sql/antares/commit/ee623b0a0f121df0ac53d49d8be437c76ddb8539))
### Improvements
* improved precision of MariaDB or MySQL auto detection ([26aad51](https://github.com/antares-sql/antares/commit/26aad519df6ea1bbc7dffbf540193a7b2ed9ae2a))
* **Linux:** title bar improvements ([85cec05](https://github.com/antares-sql/antares/commit/85cec05f7037a1339ee223554cf127693a527aa1))
* **UI:** max height for query text area increased ([5d5f1da](https://github.com/antares-sql/antares/commit/5d5f1da97b9adfa743197d8fa0bbb6addd565a7a))
* **Windows:** title bar improvements ([5fa8bf3](https://github.com/antares-sql/antares/commit/5fa8bf38e433ef2fb31bcb893cd9e75549bd6a49))
### [0.5.6](https://github.com/antares-sql/antares/compare/v0.5.4...v0.5.6) (2022-06-02)
### Bug Fixes
* empty query tab schema select if no schema selected ([31b7999](https://github.com/antares-sql/antares/commit/31b7999bba5d115913d42087614b9888bc761068))
* inline field update not working with tables missing primary key ([caf776b](https://github.com/antares-sql/antares/commit/caf776bd55606c793c9763c204aa9f05d1feb27f))
* **SQLite:** unable to insert rows with TEXT fields ([a7d5e19](https://github.com/antares-sql/antares/commit/a7d5e1973cd59d7d0ef1e74bdcf44d87fba43559))
* **UI:** select closes clicking on scrollbar ([8870304](https://github.com/antares-sql/antares/commit/8870304c15346257a90193807b9ae07c1393e3e2))
### Improvements
* improved precision of MariaDB or MySQL auto detection ([26aad51](https://github.com/antares-sql/antares/commit/26aad519df6ea1bbc7dffbf540193a7b2ed9ae2a))
### [0.5.5](https://github.com/antares-sql/antares/compare/v0.5.4...v0.5.5) (2022-05-24)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -1,7 +1,7 @@
{
"name": "antares",
"productName": "Antares",
"version": "0.5.5",
"version": "0.5.7",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT",
"repository": "https://github.com/antares-sql/antares.git",
@@ -13,7 +13,7 @@
"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",
"build:local": "npm run build && electron-builder --publish never",
"build:appx": "npm run build:local -- --win appx",
"rebuild:electron": "rimraf ./dist && npm run postinstall",
"release": "standard-version",
@@ -48,7 +48,6 @@
"package.json"
],
"win": {
"icon": "assets/icon.png",
"target": [
"nsis",
"portable"
@@ -87,7 +86,7 @@
"license": "./LICENSE",
"installerIcon": "assets/icon.ico",
"uninstallerIcon": "assets/icon.ico",
"installerHeader": "assets/icon.png"
"installerHeader": "assets/icon.ico"
},
"portable": {
"artifactName": "${productName}-${version}-portable.exe"

View File

@@ -1,4 +1,4 @@
import { app, BrowserWindow, /* session, */ nativeImage, Menu } from 'electron';
import { app, BrowserWindow, /* session, */ nativeImage, Menu, ipcMain } from 'electron';
import * as path from 'path';
import * as Store from 'electron-store';
import * as windowStateKeeper from 'electron-window-state';
@@ -7,9 +7,13 @@ import * as remoteMain from '@electron/remote/main';
import ipcHandlers from './ipc-handlers';
Store.initRenderer();
const persistentStore = new Store({ name: 'settings' });
const appTheme = persistentStore.get('application_theme');
const isDevelopment = process.env.NODE_ENV !== 'production';
const isMacOS = process.platform === 'darwin';
const isLinux = process.platform === 'linux';
const isWindows = process.platform === 'win32';
const gotTheLock = app.requestSingleInstanceLock();
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true';
@@ -28,15 +32,21 @@ async function createMainWindow () {
minWidth: 900,
minHeight: 550,
title: 'Antares SQL',
autoHideMenuBar: true,
icon: nativeImage.createFromDataURL(icon.default),
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
spellcheck: false
},
frame: false,
titleBarStyle: isMacOS ? 'hidden' : 'default',
autoHideMenuBar: true,
titleBarStyle: isLinux ? 'default' :'hidden',
titleBarOverlay: isWindows
? {
color: appTheme === 'dark' ? '#3f3f3f' : '#fff',
symbolColor: appTheme === 'dark' ? '#fff' : '#000',
height: 30
}
: false,
trafficLightPosition: isMacOS ? { x: 10, y: 8 } : undefined,
backgroundColor: '#1d1d1d'
});
@@ -73,10 +83,24 @@ else {
// Initialize ipcHandlers
ipcHandlers();
ipcMain.on('refresh-theme-settings', () => {
const appTheme = persistentStore.get('application_theme');
if (isWindows) {
mainWindow.setTitleBarOverlay({
color: appTheme === 'dark' ? '#3f3f3f' : '#fff',
symbolColor: appTheme === 'dark' ? '#fff' : '#000'
});
}
});
ipcMain.on('change-window-title', (event, title: string) => {
if (mainWindow) mainWindow.setTitle(title);
});
// quit application when all windows are closed
app.on('window-all-closed', () => {
// on macOS it is common for applications to stay open until the user explicitly quits
if (isMacOS) app.quit();
if (!isMacOS) app.quit();
});
app.on('activate', async () => {

View File

@@ -222,8 +222,16 @@ export default defineComponent({
hightlightedIndex.value = 0;
});
watch(() => props.modelValue, (val) => {
internalValue.value = val;
});
watch(() => props.value, (val) => {
internalValue.value = val;
});
const currentOptionLabel = computed(() =>
flattenOptions.value.find(d => d.value === props.modelValue)?.label
flattenOptions.value.find(d => d.value === internalValue.value)?.label
);
const select = (opt) => {
@@ -380,48 +388,49 @@ export default defineComponent({
<style lang="scss" scoped>
.select {
display: block;
display: block;
&:focus, &--open {
z-index: 10;
}
&:focus,
&--open {
z-index: 10;
}
&__search-input {
appearance: none;
border: none;
background: transparent;
outline: none;
color: currentColor;
max-width: 100%;
width: 100%;
}
&__search-input {
appearance: none;
border: none;
background: transparent;
outline: none;
color: currentColor;
max-width: 100%;
width: 100%;
}
&__list-wrapper {
cursor: pointer;
position: fixed;
display: block;
z-index: 5;
-webkit-overflow-scrolling: touch;
max-height: 240px;
overflow: auto;
left: 0;
top: 40px;
}
&__list-wrapper {
cursor: pointer;
position: fixed;
display: block;
z-index: 5;
-webkit-overflow-scrolling: touch;
max-height: 240px;
overflow: auto;
left: 0;
top: 40px;
}
&__list {
list-style: none;
}
&__list {
list-style: none;
}
&__option {
&--disabled {
opacity: 0.6;
cursor: not-allowed;
}
}
&--disabled {
&__option {
&--disabled {
opacity: 0.6;
cursor: not-allowed;
}
}
}
&--disabled {
opacity: 0.6;
cursor: not-allowed;
}
}
</style>

View File

@@ -43,7 +43,7 @@ export default {
data () {
return {
foreignList: [],
currentValue: this.modelValue
currentValue: this.modelValue || null
};
},
computed: {

View File

@@ -98,6 +98,7 @@ export default {
data () {
return {
dragElement: null,
isLinux: process.platform === 'linux',
isContext: false,
isDragging: false,
contextEvent: null,
@@ -129,7 +130,9 @@ export default {
},
tooltipPosition (e) {
const el = e.target ? e.target : e;
const fromTop = window.pageYOffset + el.getBoundingClientRect().top - (el.offsetHeight / 4);
const fromTop = this.isLinux
? window.scrollY + el.getBoundingClientRect().top + (el.offsetHeight / 4)
: window.scrollY + el.getBoundingClientRect().top - (el.offsetHeight / 4)
el.querySelector('.ex-tooltip-content').style.top = `${fromTop}px`;
},
getStatusBadge (uid) {

View File

@@ -1,5 +1,9 @@
<template>
<div id="titlebar" @dblclick="toggleFullScreen">
<div
v-if="!isLinux"
id="titlebar"
@dblclick="toggleFullScreen"
>
<div class="titlebar-resizer" />
<div class="titlebar-elements">
<img
@@ -26,15 +30,16 @@
>
<i class="mdi mdi-24px mdi-refresh" />
</div>
<div
v-if="!isMacOS"
<div v-if="isWindows" style="width: 140px;" />
<!-- <div
v-if="isLinux"
class="titlebar-element"
@click="minimizeApp"
>
<i class="mdi mdi-24px mdi-minus" />
</div>
<div
v-if="!isMacOS"
v-if="isLinux"
class="titlebar-element"
@click="toggleFullScreen"
>
@@ -42,12 +47,12 @@
<i v-else class="mdi mdi-24px mdi-fullscreen" />
</div>
<div
v-if="!isMacOS"
v-if="isLinux"
class="titlebar-element close-button"
@click="closeApp"
>
<i class="mdi mdi-24px mdi-close" />
</div>
</div> -->
</div>
</div>
</template>
@@ -80,7 +85,9 @@ export default {
w: getCurrentWindow(),
isMaximized: getCurrentWindow().isMaximized(),
isDevelopment: process.env.NODE_ENV === 'development',
isMacOS: process.platform === 'darwin'
isMacOS: process.platform === 'darwin',
isWindows: process.platform === 'win32',
isLinux: process.platform === 'linux'
};
},
computed: {
@@ -95,6 +102,11 @@ export default {
return [connectionName, ...breadcrumbs].join(' • ');
}
},
watch: {
windowTitle: function (val) {
ipcRenderer.send('change-window-title', val);
}
},
created () {
window.addEventListener('resize', this.onResize);
},
@@ -171,7 +183,7 @@ export default {
height: $titlebar-height;
line-height: 0;
padding: 0 0.7rem;
opacity: 0.7;
opacity: 0.9;
transition: opacity 0.2s;
-webkit-app-region: no-drag;

View File

@@ -315,10 +315,9 @@
</template>
</Draggable>
<WorkspaceEmptyState v-if="!workspace.tabs.length" @new-tab="addQueryTab" />
<template v-for="tab of workspace.tabs">
<template v-for="tab of workspace.tabs" :key="tab.uid">
<WorkspaceTabQuery
v-if="tab.type==='query'"
:key="tab.uid"
v-if="tab.type ==='query'"
:tab-uid="tab.uid"
:tab="tab"
:is-selected="selectedTab === tab.uid"
@@ -326,7 +325,7 @@
/>
<WorkspaceTabTable
v-else-if="['temp-data', 'data'].includes(tab.type)"
:key="tab.uid"
v-once
:tab-uid="tab.uid"
:connection="connection"
:is-selected="selectedTab === tab.uid"
@@ -336,7 +335,6 @@
/>
<WorkspaceTabNewTable
v-else-if="tab.type === 'new-table'"
:key="tab.uid"
:tab-uid="tab.uid"
:tab="tab"
:connection="connection"
@@ -345,7 +343,6 @@
/>
<WorkspaceTabPropsTable
v-else-if="tab.type === 'table-props'"
:key="tab.uid"
:tab-uid="tab.uid"
:connection="connection"
:is-selected="selectedTab === tab.uid"
@@ -354,7 +351,6 @@
/>
<WorkspaceTabNewView
v-else-if="tab.type === 'new-view'"
:key="tab.uid"
:tab-uid="tab.uid"
:tab="tab"
:connection="connection"
@@ -363,7 +359,6 @@
/>
<WorkspaceTabPropsView
v-else-if="tab.type === 'view-props'"
:key="tab.uid"
:tab-uid="tab.uid"
:is-selected="selectedTab === tab.uid"
:connection="connection"
@@ -372,7 +367,6 @@
/>
<WorkspaceTabNewTrigger
v-else-if="tab.type === 'new-trigger'"
:key="tab.uid"
:tab-uid="tab.uid"
:tab="tab"
:connection="connection"
@@ -382,7 +376,6 @@
/>
<WorkspaceTabPropsTrigger
v-else-if="['temp-trigger-props', 'trigger-props'].includes(tab.type)"
:key="tab.uid"
:tab-uid="tab.uid"
:connection="connection"
:is-selected="selectedTab === tab.uid"
@@ -391,7 +384,6 @@
/>
<WorkspaceTabNewTriggerFunction
v-else-if="tab.type === 'new-trigger-function'"
:key="tab.uid"
:tab-uid="tab.uid"
:tab="tab"
:connection="connection"
@@ -401,7 +393,6 @@
/>
<WorkspaceTabPropsTriggerFunction
v-else-if="['temp-trigger-function-props', 'trigger-function-props'].includes(tab.type)"
:key="tab.uid"
:tab-uid="tab.uid"
:connection="connection"
:is-selected="selectedTab === tab.uid"
@@ -410,7 +401,6 @@
/>
<WorkspaceTabNewRoutine
v-else-if="tab.type === 'new-routine'"
:key="tab.uid"
:tab-uid="tab.uid"
:tab="tab"
:connection="connection"
@@ -420,7 +410,6 @@
/>
<WorkspaceTabPropsRoutine
v-else-if="['temp-routine-props', 'routine-props'].includes(tab.type)"
:key="tab.uid"
:tab-uid="tab.uid"
:connection="connection"
:is-selected="selectedTab === tab.uid"
@@ -429,7 +418,6 @@
/>
<WorkspaceTabNewFunction
v-else-if="tab.type === 'new-function'"
:key="tab.uid"
:tab-uid="tab.uid"
:tab="tab"
:connection="connection"
@@ -439,7 +427,6 @@
/>
<WorkspaceTabPropsFunction
v-else-if="['temp-function-props', 'function-props'].includes(tab.type)"
:key="tab.uid"
:tab-uid="tab.uid"
:connection="connection"
:is-selected="selectedTab === tab.uid"
@@ -448,7 +435,6 @@
/>
<WorkspaceTabNewScheduler
v-else-if="tab.type === 'new-scheduler'"
:key="tab.uid"
:tab-uid="tab.uid"
:tab="tab"
:connection="connection"
@@ -458,7 +444,6 @@
/>
<WorkspaceTabPropsScheduler
v-else-if="['temp-scheduler-props', 'scheduler-props'].includes(tab.type)"
:key="tab.uid"
:tab-uid="tab.uid"
:connection="connection"
:is-selected="selectedTab === tab.uid"
@@ -556,7 +541,9 @@ export default {
selectTab,
newTab,
removeTab,
updateTabs
updateTabs,
selectNextTab,
selectPrevTab
} = workspacesStore;
return {
@@ -568,7 +555,9 @@ export default {
selectTab,
newTab,
removeTab,
updateTabs
updateTabs,
selectNextTab,
selectPrevTab
};
},
data () {
@@ -670,6 +659,22 @@ export default {
if (currentTab)
this.closeTab(currentTab);
}
// select next tab
if (e.altKey && (e.ctrlKey || e.metaKey) && e.key === 'ArrowRight')
this.selectNextTab({ uid: this.connection.uid });
// select prev tab
if (e.altKey && (e.ctrlKey || e.metaKey) && e.key === 'ArrowLeft')
this.selectPrevTab({ uid: this.connection.uid });
// select tab by index (range 1-9). CTRL|CMD number
if ((e.ctrlKey || e.metaKey) && !e.altKey && e.keyCode >= 49 && e.keyCode <= 57) {
const newIndex = parseInt(e.key) - 1;
if (this.workspace.tabs[newIndex])
this.selectTab({ uid: this.connection.uid, tab: this.workspace.tabs[newIndex].uid });
}
},
openAsPermanentTab (tab) {
const permanentTabs = {

View File

@@ -543,9 +543,9 @@ export default {
this.isTesting = false;
},
saveConnection () {
async saveConnection () {
await this.addConnection(this.connection);
this.selectWorkspace(this.connection.uid);
return this.addConnection(this.connection);
},
closeAsking () {
this.isTesting = false;

View File

@@ -438,15 +438,13 @@ export default {
// Fields Changes
const changes = [];
this.originalFields.forEach((originalField, oI) => {
const lI = this.localFields.findIndex(localField => localField._antares_id === originalField._antares_id);
const originalSibling = oI > 0 ? this.originalFields[oI - 1]._antares_id : false;
const localSibling = lI > 0 ? this.localFields[lI - 1]._antares_id : false;
const after = lI > 0 ? this.localFields[lI - 1].name : false;
this.localFields.forEach((field, i) => {
const originalField = this.originalFields.find(oField => oField._antares_id === field._antares_id);
if (!originalField) return;
const after = i > 0 ? this.localFields[i - 1].name : false;
const orgName = originalField.name;
if (JSON.stringify(originalField) !== JSON.stringify(this.localFields[lI]) || originalSibling !== localSibling)
if (this.localFields[lI]) changes.push({ ...this.localFields[lI], after, orgName });
changes.push({ ...field, after, orgName });
});
// OPTIONS

View File

@@ -5,7 +5,6 @@
tabindex="0"
:style="{'height': resultsSize+'px'}"
@keyup.delete="showDeleteConfirmModal"
@keydown.ctrl.a="selectAllRows($event)"
@keydown.esc="deselectRows"
>
<TableContext
@@ -78,7 +77,11 @@
:key-usage="keyUsage"
:element-type="elementType"
:class="{'selected': selectedRows.includes(row._antares_id)}"
@select-row="selectRow($event, row._antares_id)"
:selected="selectedRows.includes(row._antares_id)"
:selected-cell="selectedRows.length === 1 && selectedRows.includes(row._antares_id) ? selectedField : null"
@start-editing="isEditingRow = true"
@stop-editing="isEditingRow = false"
@select-row="selectRow"
@update-field="updateField($event, row)"
@contextmenu="contextMenu"
/>
@@ -162,7 +165,9 @@ export default {
currentSortDir: 'asc',
resultsetIndex: 0,
scrollElement: null,
rowHeight: 23
rowHeight: 23,
selectedField: null,
isEditingRow: false
};
},
computed: {
@@ -268,9 +273,11 @@ export default {
},
mounted () {
window.addEventListener('resize', this.resizeResults);
window.addEventListener('keydown', this.onKey);
},
unmounted () {
window.removeEventListener('resize', this.resizeResults);
window.removeEventListener('keydown', this.onKey);
},
methods: {
fieldType (cKey) {
@@ -447,20 +454,23 @@ export default {
return row;
});
},
selectRow (event, row) {
if (event.ctrlKey) {
if (this.selectedRows.includes(row))
this.selectedRows = this.selectedRows.filter(el => el !== row);
selectRow (event, row, field) {
this.selectedField = field;
const selectedRowId = row._antares_id;
if (event.ctrlKey || event.metaKey) {
if (this.selectedRows.includes(selectedRowId))
this.selectedRows = this.selectedRows.filter(el => el !== selectedRowId);
else
this.selectedRows.push(row);
this.selectedRows.push(selectedRowId);
}
else if (event.shiftKey) {
if (!this.selectedRows.length)
this.selectedRows.push(row);
this.selectedRows.push(selectedRowId);
else {
const lastID = this.selectedRows.slice(-1)[0];
const lastIndex = this.sortedResults.findIndex(el => el._antares_id === lastID);
const clickedIndex = this.sortedResults.findIndex(el => el._antares_id === row);
const clickedIndex = this.sortedResults.findIndex(el => el._antares_id === selectedRowId);
if (lastIndex > clickedIndex) {
for (let i = clickedIndex; i < lastIndex; i++)
this.selectedRows.push(this.sortedResults[i]._antares_id);
@@ -472,18 +482,20 @@ export default {
}
}
else
this.selectedRows = [row];
this.selectedRows = [selectedRowId];
},
selectAllRows (e) {
if (e.target.classList.contains('editable-field')) return;
this.selectedField = 0;
this.selectedRows = this.localResults.reduce((acc, curr) => {
acc.push(curr._antares_id);
return acc;
}, []);
},
deselectRows () {
this.selectedRows = [];
if (!this.isEditingRow)
this.selectedRows = [];
},
contextMenu (event, cell) {
if (event.target.localName === 'input') return;
@@ -536,6 +548,113 @@ export default {
content: rows,
filename
});
},
onKey (e) {
if (!this.isSelected)
return;
if (this.isEditingRow)
return;
if ((e.ctrlKey || e.metaKey) && e.code === 'KeyA' && !e.altKey)
this.selectAllRows(e);
// row naviation stuff
if ((e.code.includes('Arrow') || e.code === 'Tab') && this.sortedResults.length > 0 && !e.altKey) {
e.preventDefault();
const aviableFields= Object.keys(this.sortedResults[0]).slice(0, -1); // removes _antares_id
if (!this.selectedField)
this.selectedField = aviableFields[0];
const selectedId = this.selectedRows[0];
const selectedIndex = this.sortedResults.findIndex(row => row._antares_id === selectedId);
const selectedFieldIndex = aviableFields.findIndex(field => field === this.selectedField);
let nextIndex = 0;
let nextFieldIndex = 0;
if (selectedIndex > -1) {
switch (e.code) {
case 'ArrowDown':
nextIndex = selectedIndex + 1;
nextFieldIndex = selectedFieldIndex;
if (nextIndex > this.sortedResults.length -1)
nextIndex = this.sortedResults.length -1;
break;
case 'ArrowUp':
nextIndex = selectedIndex - 1;
nextFieldIndex = selectedFieldIndex;
if (nextIndex < 0)
nextIndex = 0;
break;
case 'ArrowRight':
nextIndex = selectedIndex;
nextFieldIndex = selectedFieldIndex + 1;
if (nextFieldIndex > aviableFields.length -1)
nextFieldIndex = 0;
break;
case 'ArrowLeft':
nextIndex = selectedIndex;
nextFieldIndex = selectedFieldIndex - 1;
if (nextFieldIndex < 0)
nextFieldIndex = aviableFields.length -1;
break;
case 'Tab':
nextIndex = selectedIndex;
if (e.shiftKey) {
nextFieldIndex = selectedFieldIndex - 1;
if (nextFieldIndex < 0)
nextFieldIndex = aviableFields.length -1;
}
else {
nextFieldIndex = selectedFieldIndex + 1;
if (nextFieldIndex > aviableFields.length -1)
nextFieldIndex = 0;
}
}
}
if (this.sortedResults[nextIndex] && nextIndex !== selectedIndex) {
this.selectedRows = [this.sortedResults[nextIndex]._antares_id];
this.$nextTick(() => this.scrollToCell(this.scrollElement.querySelector('.td.selected')));
}
if (aviableFields[nextFieldIndex] && nextFieldIndex !== selectedFieldIndex) {
this.selectedField = aviableFields[nextFieldIndex];
this.$nextTick(() => this.scrollToCell(this.scrollElement.querySelector('.td.selected')));
}
}
},
scrollToCell (el) {
if (!el) return;
const visYMin = this.scrollElement.scrollTop;
const visYMax = this.scrollElement.scrollTop + this.scrollElement.clientHeight - el.clientHeight;
const visXMin = this.scrollElement.scrollLeft;
const visXMax = this.scrollElement.scrollLeft + this.scrollElement.clientWidth - el.clientWidth;
if (el.offsetTop < visYMin)
this.scrollElement.scrollTop = el.offsetTop;
else if (el.offsetTop >= visYMax)
this.scrollElement.scrollTop = el.offsetTop - this.scrollElement.clientHeight + el.clientHeight;
if (el.offsetLeft < visXMin)
this.scrollElement.scrollLeft = el.offsetLeft;
else if (el.offsetLeft >= visXMax)
this.scrollElement.scrollLeft = el.offsetLeft - this.scrollElement.clientWidth + el.clientWidth;
}
}
};

View File

@@ -2,14 +2,15 @@
<div
class="tr"
:style="{height: itemHeight+'px'}"
@click="selectRow($event, row._antares_id)"
>
<div
v-for="(col, cKey) in row"
v-show="cKey !== '_antares_id'"
:key="cKey"
class="td p-0"
tabindex="0"
:class="{selected: selectedCell === cKey}"
@click="selectRow($event, cKey)"
@contextmenu.prevent="openContext($event, { id: row._antares_id, orgField: cKey })"
>
<template v-if="cKey !== '_antares_id'">
@@ -17,7 +18,7 @@
v-if="!isInlineEditor[cKey] && fields[cKey]"
class="cell-content"
:class="`${isNull(col)} ${typeClass(fields[cKey].type)}`"
@dblclick="editON($event, col, cKey)"
@dblclick="editON(cKey)"
>{{ cutText(typeFormat(col, fields[cKey].type.toLowerCase(), fields[cKey].length)) }}</span>
<ForeignKeySelect
v-else-if="isForeignKey(cKey)"
@@ -105,7 +106,7 @@
<div class="mr-4">
<b>{{ $t('word.size') }}</b>: {{ editingContent ? editingContent.length : 0 }}
</div>
<div>
<div v-if="editingType">
<b>{{ $t('word.type') }}</b>: {{ editingType.toUpperCase() }}
</div>
</div>
@@ -170,7 +171,9 @@
<b>{{ $t('word.size') }}</b>: {{ formatBytes(editingContent.length) }}<br>
<b>{{ $t('word.mimeType') }}</b>: {{ contentInfo.mime }}
</div>
<div><b>{{ $t('word.type') }}</b>: {{ editingType.toUpperCase() }}</div>
<div v-if="editingType">
<b>{{ $t('word.type') }}</b>: {{ editingType.toUpperCase() }}
</div>
</div>
<div class="mt-3">
<label>{{ $t('message.uploadFile') }}</label>
@@ -230,9 +233,11 @@ export default {
fields: Object,
keyUsage: Array,
itemHeight: Number,
elementType: { type: String, default: 'table' }
elementType: { type: String, default: 'table' },
selected: { type: Boolean, default: false },
selectedCell: { type: String, default: null }
},
emits: ['update-field', 'select-row', 'contextmenu'],
emits: ['update-field', 'select-row', 'contextmenu', 'start-editing', 'stop-editing'],
data () {
return {
isInlineEditor: {},
@@ -336,6 +341,9 @@ export default {
return false;
},
isBaseSelectField () {
return this.isForeignKey(this.editingField) || this.inputProps.type === 'boolean' || this.enumArray;
},
enumArray () {
if (this.fields[this.editingField] && this.fields[this.editingField].enumValues)
return this.fields[this.editingField].enumValues.replaceAll('\'', '').split(',');
@@ -362,8 +370,21 @@ export default {
this.editorMode = this.availableLanguages.find(lang => lang.id === filteredLanguages[0].languageId).slug;
})();
}
},
selected (isSelected) {
if (isSelected)
window.addEventListener('keydown', this.onKey);
else {
this.editOFF();
window.removeEventListener('keydown', this.onKey);
}
}
},
beforeUnmount () {
if (this.selected)
window.removeEventListener('keydown', this.onKey);
},
methods: {
isForeignKey (key) {
if (key.includes('.'))
@@ -382,11 +403,10 @@ export default {
bufferToBase64 (val) {
return bufferToBase64(val);
},
editON (event, content, field) {
editON (field) {
if (!this.isEditable || this.editingType === 'none') return;
window.addEventListener('keydown', this.onKey);
const content = this.row[field];
const type = this.fields[field].type.toUpperCase();
this.originalContent = this.typeFormat(content, type, this.fields[field].length);
this.editingType = type;
@@ -396,6 +416,7 @@ export default {
if ([...LONG_TEXT, ...ARRAY, ...TEXT_SEARCH].includes(type)) {
this.isTextareaEditor = true;
this.editingContent = this.typeFormat(content, type);
this.$emit('start-editing', field);
return;
}
@@ -405,6 +426,7 @@ export default {
this.isMapModal = true;
this.editingContent = this.typeFormat(content, type);
}
this.$emit('start-editing', field);
return;
}
@@ -426,19 +448,21 @@ export default {
};
}
}
this.$emit('start-editing', field);
return;
}
// Inline editable fields
this.editingContent = this.originalContent;
this.$nextTick(() => { // Focus on input
event.target.blur();
this.$nextTick(() => document.querySelector('.editable-field').focus());
});
const obj = { [field]: true };
this.isInlineEditor = { ...this.isInlineEditor, ...obj };
this.$nextTick(() => { // Focus on input
document.querySelector('.editable-field').focus();
});
this.$emit('start-editing', field);
},
editOFF () {
if (!this.editingField) return;
@@ -451,7 +475,13 @@ export default {
this.editingContent = this.editingContent.slice(0, -1);
}
if (this.editingContent === this.typeFormat(this.originalContent, this.editingType, this.editingLength)) return;// If not changed
// If not changed
if (this.editingContent === this.typeFormat(this.originalContent, this.editingType, this.editingLength)) {
this.editingType = null;
this.editingField = null;
this.$emit('stop-editing', this.editingField);
return;
}
content = this.editingContent;
}
@@ -472,15 +502,17 @@ export default {
content
});
this.$emit('stop-editing', this.editingField);
this.editingType = null;
this.editingField = null;
window.removeEventListener('keydown', this.onKey);
},
hideEditorModal () {
this.isTextareaEditor = false;
this.isBlobEditor = false;
this.isMapModal = false;
this.isMultiSpatial = false;
this.$emit('stop-editing', this.editingField);
},
downloadFile () {
const downloadLink = document.createElement('a');
@@ -508,8 +540,8 @@ export default {
};
this.willBeDeleted = true;
},
selectRow (event, row) {
this.$emit('select-row', event, row);
selectRow (event, field) {
this.$emit('select-row', event, this.row, field);
},
getKeyUsage (keyName) {
if (keyName.includes('.'))
@@ -523,10 +555,17 @@ export default {
},
onKey (e) {
e.stopPropagation();
if (e.key === 'Escape') {
if (!this.editingField && e.key === 'Enter')
return this.editON(this.selectedCell);
if (this.editingField && e.key === 'Enter' && !this.isBaseSelectField)
return this.editOFF();
if (this.editingField && e.key === 'Escape') {
this.isInlineEditor[this.editingField] = false;
this.editingField = null;
window.removeEventListener('keydown', this.onKey);
this.$emit('stop-editing', this.editingField);
}
},
formatBytes,

View File

@@ -27,4 +27,14 @@ $titlebar-height: 1.5rem;
$settingbar-width: 3rem;
$explorebar-width: 14rem;
$footer-height: 1.5rem;
$excluding-size: $footer-height + $titlebar-height;
@function get-excluding-size(){
@if $platform == linux{
@return $footer-height;
}
@else {
@return $footer-height + $titlebar-height;
}
}
$excluding-size: get-excluding-size();

View File

@@ -231,7 +231,8 @@
.td {
border-color: $body-bg-dark;
&:focus {
&:focus,
&.selected {
box-shadow: inset 0 0 0 2px darken($body-font-color-dark, 40%);
background-color: rgba($color: #000, $alpha: 0.3);
}
@@ -360,7 +361,7 @@
.titlebar-element {
&:hover {
opacity: 1;
background: rgba($color: #fff, $alpha: 0.2);
background: rgba($color: #fff, $alpha: 0.1);
}
&.close-button:hover {

View File

@@ -132,7 +132,7 @@
.titlebar-element {
&:hover {
opacity: 1;
background: rgba($color: rgb(172, 172, 172), $alpha: 0.2);
background: rgba($color: rgb(172, 172, 172), $alpha: 0.3);
}
&.close-button:hover {
@@ -252,7 +252,8 @@
.td {
border-color: $body-bg;
&:focus {
&:focus,
&.selected {
box-shadow: inset 0 0 0 2px lighten($body-font-color, 10%);
background-color: $body-font-color-dark;
}

View File

@@ -1,4 +1,5 @@
import { defineStore, acceptHMRUpdate } from 'pinia';
import { ipcRenderer } from 'electron';
import i18n from '@/i18n';
import Store from 'electron-store';
const persistentStore = new Store({ name: 'settings' });
@@ -54,6 +55,7 @@ export const useSettingsStore = defineStore('settings', {
changeApplicationTheme (theme) {
this.applicationTheme = theme;
persistentStore.set('application_theme', this.applicationTheme);
ipcRenderer.send('refresh-theme-settings');
},
changeEditorTheme (theme) {
this.editorTheme = theme;

View File

@@ -610,6 +610,26 @@ export const useWorkspacesStore = defineStore('workspaces', {
: workspace
);
},
selectNextTab ({ uid }) {
const workspace = this.workspaces.find(workspace => workspace.uid === uid);
let newIndex = workspace.tabs.findIndex(tab => tab.selected || tab.uid === workspace.selectedTab) + 1;
if (newIndex > workspace.tabs.length -1)
newIndex = 0;
this.selectTab({ uid, tab: workspace.tabs[newIndex].uid });
},
selectPrevTab ({ uid }) {
const workspace = this.workspaces.find(workspace => workspace.uid === uid);
let newIndex = workspace.tabs.findIndex(tab => tab.selected || tab.uid === workspace.selectedTab) - 1;
if (newIndex < 0)
newIndex = workspace.tabs.length -1;
this.selectTab({ uid, tab: workspace.tabs[newIndex].uid });
},
updateTabs ({ uid, tabs }) {
this.workspaces = this.workspaces.map(workspace => workspace.uid === uid
? { ...workspace, tabs }

View File

@@ -21,7 +21,7 @@ test('launch app', async () => {
test('main window elements visibility', async () => {
const visibleSelectors = [
'#titlebar',
// '#titlebar',
'#window-content',
'#settingbar',
'#footer'

View File

@@ -104,7 +104,9 @@ const config = {
{
loader: 'sass-loader',
options: {
additionalData: '@import "@/scss/_variables.scss";',
additionalData: `
$platform: ${process.platform};
@import "@/scss/_variables.scss";`,
sassOptions: { quietDeps: true }
}
}