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

Compare commits

...

13 Commits

16 changed files with 2306 additions and 125 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,6 +1,6 @@
# These are supported funding model platforms # These are supported funding model platforms
github: [fabio286] github: [antares-sql,fabio286]
patreon: #fabio286 patreon: #fabio286
open_collective: # Replace with a single Open Collective username open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username ko_fi: # Replace with a single Ko-fi username

1
.husky/commit-msg Normal file
View File

@@ -0,0 +1 @@
npx --no -- commitlint --edit $1

1
.husky/pre-commit Normal file
View File

@@ -0,0 +1 @@
npm run lint

View File

@@ -5,14 +5,14 @@
], ],
"fix": true, "fix": true,
"formatter": "verbose", "formatter": "verbose",
"customSyntax": "postcss-html",
"plugins": [ "plugins": [
"stylelint-scss" "stylelint-scss"
], ],
"rules": { "rules": {
"at-rule-no-unknown": null, "at-rule-no-unknown": null,
"no-descending-specificity": null, "no-descending-specificity": null,
"font-family-no-missing-generic-family-keyword": null, "font-family-no-missing-generic-family-keyword": null
"declaration-colon-newline-after": "always-multi-line"
}, },
"syntax": "scss" "syntax": "scss"
} }

View File

@@ -2,6 +2,22 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.7.23-beta.0](https://github.com/antares-sql/antares/compare/v0.7.22...v0.7.23-beta.0) (2024-03-21)
### Bug Fixes
* CSV export does not escape strings when needed, fixes [#770](https://github.com/antares-sql/antares/issues/770) ([dd5b417](https://github.com/antares-sql/antares/commit/dd5b41716a10cf9500f2c611b232f5b5b0756a68))
* query result sort not working with aliased tables, fixes [#765](https://github.com/antares-sql/antares/issues/765) ([de9dac3](https://github.com/antares-sql/antares/commit/de9dac3e8abf3b3261f8c54c88cf2386a5be2207))
* shortcut not working on mac os ([0bb5ced](https://github.com/antares-sql/antares/commit/0bb5cedda6a67ccbeea8c127b799f533395101a2))
### [0.7.22](https://github.com/antares-sql/antares/compare/v0.7.22-beta.2...v0.7.22) (2024-02-26)
### Bug Fixes
* delete record modal pressing del when editing a field, fixes [#767](https://github.com/antares-sql/antares/issues/767) ([586f901](https://github.com/antares-sql/antares/commit/586f901bae9a80c0e53ac1d804cbae3f05e26d8e))
### [0.7.22-beta.2](https://github.com/antares-sql/antares/compare/v0.7.22-beta.1...v0.7.22-beta.2) (2024-02-18) ### [0.7.22-beta.2](https://github.com/antares-sql/antares/compare/v0.7.22-beta.1...v0.7.22-beta.2) (2024-02-18)

View File

@@ -101,7 +101,7 @@ On macOS you can run `.dmg` distribution following [this guide](https://support.
- 🌍 [Translate Antares](https://github.com/Fabio286/antares/wiki/Translate-Antares) - 🌍 [Translate Antares](https://github.com/Fabio286/antares/wiki/Translate-Antares)
- 📖 [Contributors Guide](https://github.com/Fabio286/antares/wiki/Contributors-Guide) - 📖 [Contributors Guide](https://github.com/Fabio286/antares/wiki/Contributors-Guide)
- 🚧 [Project Board](https://github.com/antares-sql/antares/projects/1) - 🚧 [Project Board](https://github.com/orgs/antares-sql/projects/3/views/2)
## Contributors ✨ ## Contributors ✨

33
commitlint.config.js Normal file
View File

@@ -0,0 +1,33 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
// TODO Add Scope Enum Here
// 'scope-enum': [2, 'always', ['yourscope', 'yourscope']],
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'chore',
'style',
'refactor',
'build',
'ci',
'test',
'revert',
'perf'
]
],
'subject-case': [
2,
'never',
[
'upper-case',
'pascal-case',
'start-case'
]
]
}
};

2259
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{ {
"name": "antares", "name": "antares",
"productName": "Antares", "productName": "Antares",
"version": "0.7.22-beta.2", "version": "0.7.23-beta.0",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.", "description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT", "license": "MIT",
"repository": "https://github.com/antares-sql/antares.git", "repository": "https://github.com/antares-sql/antares.git",
@@ -25,7 +25,8 @@
"lint": "eslint . --ext .js,.ts,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"", "lint": "eslint . --ext .js,.ts,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"",
"lint:fix": "eslint . --ext .js,.ts,.vue --fix && stylelint \"./src/**/*.{css,scss,sass,vue}\" --fix", "lint:fix": "eslint . --ext .js,.ts,.vue --fix && stylelint \"./src/**/*.{css,scss,sass,vue}\" --fix",
"contributors:add": "all-contributors add", "contributors:add": "all-contributors add",
"contributors:generate": "all-contributors generate" "contributors:generate": "all-contributors generate",
"prepare": "husky"
}, },
"author": "Fabio Di Stasio <info@fabiodistasio.it>", "author": "Fabio Di Stasio <info@fabiodistasio.it>",
"main": "./dist/main.js", "main": "./dist/main.js",
@@ -179,6 +180,8 @@
"@babel/eslint-parser": "~7.15.7", "@babel/eslint-parser": "~7.15.7",
"@babel/preset-env": "~7.15.8", "@babel/preset-env": "~7.15.8",
"@babel/preset-typescript": "~7.16.7", "@babel/preset-typescript": "~7.16.7",
"@commitlint/cli": "~19.0.3",
"@commitlint/config-conventional": "~19.0.3",
"@playwright/test": "~1.28.1", "@playwright/test": "~1.28.1",
"@types/better-sqlite3": "~7.5.0", "@types/better-sqlite3": "~7.5.0",
"@types/leaflet": "~1.7.9", "@types/leaflet": "~1.7.9",
@@ -198,6 +201,7 @@
"eslint-plugin-promise": "~5.2.0", "eslint-plugin-promise": "~5.2.0",
"eslint-plugin-simple-import-sort": "~10.0.0", "eslint-plugin-simple-import-sort": "~10.0.0",
"eslint-plugin-vue": "~8.0.3", "eslint-plugin-vue": "~8.0.3",
"husky": "~9.0.11",
"playwright": "~1.28.1", "playwright": "~1.28.1",
"playwright-core": "~1.28.1", "playwright-core": "~1.28.1",
"standard-version": "~9.3.1", "standard-version": "~9.3.1",

View File

@@ -70,23 +70,21 @@ export class ShortcutRegister {
} }
private setLocalShortcuts () { private setLocalShortcuts () {
const isMenuVisible = process.platform === 'darwin';
const submenu = [];
for (const shortcut of this.shortcuts) { for (const shortcut of this.shortcuts) {
if (shortcut.os.includes(process.platform)) { if (shortcut.os.includes(process.platform)) {
for (const key of shortcut.keys) { for (const key of shortcut.keys) {
try { try {
this._menu.append(new MenuItem({ submenu.push({
label: '.', label: String(shortcut.event),
visible: false, accelerator: key,
submenu: [{ visible: isMenuVisible,
label: String(key), click: () => {
accelerator: key, this._mainWindow.webContents.send(shortcut.event);
visible: false, if (isDevelopment) console.log('LOCAL EVENT:', shortcut);
click: () => { }
this._mainWindow.webContents.send(shortcut.event); });
if (isDevelopment) console.log('LOCAL EVENT:', shortcut);
}
}]
}));
} }
catch (error) { catch (error) {
if (isDevelopment) console.log(error); if (isDevelopment) console.log(error);
@@ -96,6 +94,11 @@ export class ShortcutRegister {
} }
} }
} }
this._menu.append(new MenuItem({
label: 'Shortcut',
visible: isMenuVisible,
submenu
}));
} }
private setGlobalShortcuts () { private setGlobalShortcuts () {

View File

@@ -31,7 +31,7 @@
:class="{ 'active': resultsetIndex === index }" :class="{ 'active': resultsetIndex === index }"
@click="selectResultset(index)" @click="selectResultset(index)"
> >
<a>{{ result.fields ? result.fields[0]?.table : '' }} ({{ result.rows.length }})</a> <a>{{ result.fields ? result.fields[0]?.tableAlias ?? result.fields[0]?.table : `${t('general.results')} #${index}` }} ({{ result.rows.length }})</a>
</li> </li>
</ul> </ul>
<div ref="table" class="table table-hover"> <div ref="table" class="table table-hover">
@@ -44,7 +44,7 @@
:title="`${field.type} ${fieldLength(field) ? `(${fieldLength(field)})` : ''}`" :title="`${field.type} ${fieldLength(field) ? `(${fieldLength(field)})` : ''}`"
> >
<div ref="columnResize" class="column-resizable"> <div ref="columnResize" class="column-resizable">
<div class="table-column-title" @click="sort(field.name)"> <div class="table-column-title" @click="sort(field)">
<div v-if="field.key" :title="keyName(field.key)"> <div v-if="field.key" :title="keyName(field.key)">
<BaseIcon <BaseIcon
icon-name="mdiKey" icon-name="mdiKey"
@@ -56,8 +56,8 @@
</div> </div>
<span>{{ field.alias || field.name }}</span> <span>{{ field.alias || field.name }}</span>
<BaseIcon <BaseIcon
v-if="isSortable && currentSort === field.name || currentSort === `${field.table}.${field.name}`" v-if="isSortable && currentSort[resultsetIndex]?.field === field.name || currentSort[resultsetIndex]?.field === `${field.tableAlias || field.table}.${field.name}`"
:icon-name="currentSortDir === 'asc' ? 'mdiSortAscending' : 'mdiSortDescending'" :icon-name="currentSort[resultsetIndex].dir === 'asc' ? 'mdiSortAscending' : 'mdiSortDescending'"
:size="18" :size="18"
class="sort-icon ml-1" class="sort-icon ml-1"
/> />
@@ -314,8 +314,7 @@ const hasFocus = ref(false);
const contextEvent = ref(null); const contextEvent = ref(null);
const selectedCell = ref(null); const selectedCell = ref(null);
const selectedRows = ref([]); const selectedRows = ref([]);
const currentSort = ref(''); const currentSort: Ref<{field: string; dir: 'asc' | 'desc'}[]> = ref([]);
const currentSortDir = ref('asc');
const resultsetIndex = ref(0); const resultsetIndex = ref(0);
const scrollElement = ref(null); const scrollElement = ref(null);
const rowHeight = ref(23); const rowHeight = ref(23);
@@ -358,14 +357,16 @@ const isHardSort = computed(() => {
}); });
const sortedResults = computed(() => { const sortedResults = computed(() => {
if (currentSort.value && !isHardSort.value) { if (currentSort.value[resultsetIndex.value] && !isHardSort.value) {
const sortObj = currentSort.value[resultsetIndex.value];
return [...localResults.value].sort((a: any, b: any) => { return [...localResults.value].sort((a: any, b: any) => {
let modifier = 1; let modifier = 1;
let valA = typeof a[currentSort.value] === 'string' ? a[currentSort.value].toLowerCase() : a[currentSort.value]; let valA = typeof a[sortObj.field] === 'string' ? a[sortObj.field].toLowerCase() : a[sortObj.field];
if (!isNaN(valA)) valA = Number(valA); if (!isNaN(valA)) valA = Number(valA);
let valB = typeof b[currentSort.value] === 'string' ? b[currentSort.value].toLowerCase() : b[currentSort.value]; let valB = typeof b[sortObj.field] === 'string' ? b[sortObj.field].toLowerCase() : b[sortObj.field];
if (!isNaN(valB)) valB = Number(valB); if (!isNaN(valB)) valB = Number(valB);
if (currentSortDir.value === 'desc') modifier = -1; if (sortObj.dir === 'desc') modifier = -1;
if (valA < valB) return -1 * modifier; if (valA < valB) return -1 * modifier;
if (valA > valB) return 1 * modifier; if (valA > valB) return 1 * modifier;
return 0; return 0;
@@ -784,32 +785,42 @@ const contextMenu = (event: MouseEvent, cell: any) => {
isContext.value = true; isContext.value = true;
}; };
const sort = (field: string) => { const sort = (field: TableField) => {
if (!isSortable.value) return; if (!isSortable.value) return;
selectedRows.value = []; selectedRows.value = [];
let fieldName = field.name;
const hasTableInFieldname = Object.keys(localResults.value[0]).find(k => k !== '_antares_id').includes('.');
if (props.mode === 'query') if (props.mode === 'query' && hasTableInFieldname)
field = `${getTable(resultsetIndex.value)}.${field}`; fieldName = `${field.tableAlias || field.table}.${field.name}`;
if (field === currentSort.value) { if (fieldName === currentSort.value[resultsetIndex.value]?.field) {
if (currentSortDir.value === 'asc') if (currentSort.value[resultsetIndex.value].dir === 'asc')
currentSortDir.value = 'desc'; currentSort.value[resultsetIndex.value].dir = 'desc';
else else
resetSort(); resetSort();
} }
else { else {
currentSortDir.value = 'asc'; currentSort.value[resultsetIndex.value] = {
currentSort.value = field; field: fieldName,
dir: 'asc'
};
} }
if (isHardSort.value) if (isHardSort.value) {
emit('hard-sort', { field: currentSort.value, dir: currentSortDir.value }); emit('hard-sort', {
field: currentSort.value[resultsetIndex.value].field,
dir: currentSort.value[resultsetIndex.value].dir
});
}
}; };
const resetSort = () => { const resetSort = () => {
currentSort.value = ''; currentSort.value[resultsetIndex.value] = {
currentSortDir.value = 'asc'; field: null,
dir: 'asc'
};
}; };
const selectResultset = (index: number) => { const selectResultset = (index: number) => {

View File

@@ -43,6 +43,7 @@
autofocus autofocus
class="editable-field form-input input-sm px-1" class="editable-field form-input input-sm px-1"
@blur="editOFF" @blur="editOFF"
@keyup.delete.stop
> >
<BaseSelect <BaseSelect
v-else-if="inputProps.type === 'boolean'" v-else-if="inputProps.type === 'boolean'"
@@ -50,6 +51,7 @@
:options="['true', 'false']" :options="['true', 'false']"
class="form-select small-select editable-field" class="form-select small-select editable-field"
@blur="editOFF" @blur="editOFF"
@keyup.delete.stop
/> />
<BaseSelect <BaseSelect
v-else-if="enumArray" v-else-if="enumArray"
@@ -58,6 +60,7 @@
class="form-select small-select editable-field" class="form-select small-select editable-field"
dropdown-class="small-select" dropdown-class="small-select"
@blur="editOFF" @blur="editOFF"
@keyup.delete.stop
/> />
<input <input
v-else v-else
@@ -67,6 +70,7 @@
autofocus autofocus
class="editable-field form-input input-sm px-1" class="editable-field form-input input-sm px-1"
@blur="editOFF" @blur="editOFF"
@keyup.delete.stop
> >
</template> </template>
</template> </template>

View File

@@ -31,7 +31,7 @@ export const exportRows = (args: {
const csv = []; const csv = [];
const sd = args.csvOptions.stringDelimiter === 'single' const sd = args.csvOptions.stringDelimiter === 'single'
? '\'' ? '\''
: args.csvOptions.stringDelimiter === 'single' : args.csvOptions.stringDelimiter === 'double'
? '"' ? '"'
: ''; : '';

View File

@@ -415,8 +415,7 @@
box-shadow: 0 0 1px 0 #000; box-shadow: 0 0 1px 0 #000;
.settingbar-top-elements { .settingbar-top-elements {
overflow-x: hidden; overflow: hidden overlay;
overflow-y: overlay;
max-height: calc((100vh - 3.5rem) - #{$excluding-size}); max-height: calc((100vh - 3.5rem) - #{$excluding-size});
} }

View File

@@ -164,8 +164,7 @@
box-shadow: 0 0 1px 0 #000; box-shadow: 0 0 1px 0 #000;
.settingbar-top-elements { .settingbar-top-elements {
overflow-x: hidden; overflow: hidden overlay;
overflow-y: overlay;
max-height: calc((100vh - 3.5rem) - #{$excluding-size}); max-height: calc((100vh - 3.5rem) - #{$excluding-size});
} }

View File

@@ -55,10 +55,9 @@ export const useApplicationStore = defineStore('application', {
}, },
showScratchpad (tag?: string) { showScratchpad (tag?: string) {
this.isScratchpad = true; this.isScratchpad = true;
if (tag) { if (!tag) tag = 'all';
const { selectedTag } = storeToRefs(useScratchpadStore()); const { selectedTag } = storeToRefs(useScratchpadStore());
selectedTag.value = tag; selectedTag.value = tag;
}
}, },
hideScratchpad () { hideScratchpad () {
this.isScratchpad = false; this.isScratchpad = false;