Compare commits

...

5 Commits

13 changed files with 147 additions and 19 deletions

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.7.23-beta.1](https://github.com/antares-sql/antares/compare/v0.7.23-beta.0...v0.7.23-beta.1) (2024-04-02)
### Features
* add the page reference in the export file name, closes [#772](https://github.com/antares-sql/antares/issues/772) ([2064294](https://github.com/antares-sql/antares/commit/2064294119ed9dfab2a9968dfb5b35d52e2ae03b))
* move connections out of folder from context menu, related to [#773](https://github.com/antares-sql/antares/issues/773) ([62e3115](https://github.com/antares-sql/antares/commit/62e311586073ae7ee4896305198c7168f637c1af))
* move connections to folders from context menu, related to [#773](https://github.com/antares-sql/antares/issues/773) ([9aef287](https://github.com/antares-sql/antares/commit/9aef287a983754158cdbdc9b2a72db9ab82f76c8))
### Bug Fixes
* bad format of timestamp fields on CSV export, fixes 776 ([65ec4c5](https://github.com/antares-sql/antares/commit/65ec4c5da6187a7ab2dfff59326cd12bfa788c3b))
### [0.7.23-beta.0](https://github.com/antares-sql/antares/compare/v0.7.22...v0.7.23-beta.0) (2024-03-21)

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "antares",
"version": "0.7.23-beta.0",
"version": "0.7.23-beta.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "antares",
"version": "0.7.23-beta.0",
"version": "0.7.23-beta.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {

View File

@ -1,7 +1,7 @@
{
"name": "antares",
"productName": "Antares",
"version": "0.7.23-beta.0",
"version": "0.7.23-beta.1",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT",
"repository": "https://github.com/antares-sql/antares.git",

View File

@ -127,8 +127,8 @@ app.on('ready', async () => {
if (isWindows)
mainWindow.show();
// if (isDevelopment)
// mainWindow.webContents.openDevTools();
if (isDevelopment && !isWindows)// Because on Windows you can open devtools from title-bar
mainWindow.webContents.openDevTools();
process.on('uncaughtException', error => {
mainWindow.webContents.send('unhandled-exception', error);

View File

@ -15,6 +15,56 @@
:size="18"
/> {{ t('connection.disconnect') }}</span>
</div>
<div v-if="!contextConnection.isFolder" class="context-element">
<span class="d-flex">
<BaseIcon
class="text-light mt-1 mr-1"
icon-name="mdiFolderMove"
:size="18"
/> {{ t('general.moveTo') }}</span>
<BaseIcon
class="text-light ml-1"
icon-name="mdiChevronRight"
:size="18"
/>
<div class="context-submenu">
<div class="context-element" @click.stop="moveToFolder(null)">
<span class="d-flex">
<BaseIcon
class="text-light mt-1 mr-1"
icon-name="mdiFolderPlus"
:size="18"
/> {{ t('application.newFolder') }}</span>
</div>
<div
v-for="folder in filteredFolders"
:key="folder.uid"
class="context-element"
@click.stop="moveToFolder(folder.uid)"
>
<span class="d-flex">
<BaseIcon
class="text-light mt-1 mr-1"
icon-name="mdiFolder"
:size="18"
:style="`color: ${folder.color}!important`"
/> {{ folder.name || t('general.folder') }}</span>
</div>
<div
v-if="isInFolder"
class="context-element"
@click="outOfFolder"
>
<span class="d-flex">
<BaseIcon
class="text-light mt-1 mr-1"
icon-name="mdiFolderOff"
:size="18"
/> {{ t('application.outOfFolder') }}</span>
</div>
</div>
</div>
<div class="context-element" @click.stop="showAppearanceModal">
<span class="d-flex">
<BaseIcon
@ -79,6 +129,7 @@
<script setup lang="ts">
import { uidGen } from 'common/libs/uidGen';
import { storeToRefs } from 'pinia';
import { computed, Prop, ref } from 'vue';
import { useI18n } from 'vue-i18n';
@ -98,9 +149,14 @@ const {
getConnectionByUid,
getConnectionName,
addConnection,
deleteConnection
deleteConnection,
addFolder,
addToFolder,
removeFromFolders
} = connectionsStore;
const { getFolders: folders } = storeToRefs(connectionsStore);
const workspacesStore = useWorkspacesStore();
const {
@ -121,6 +177,8 @@ const isConnectionEdit = ref(false);
const connectionName = computed(() => props.contextConnection.name || getConnectionName(props.contextConnection.uid) || t('general.folder', 1));
const isConnected = computed(() => getWorkspace(props.contextConnection.uid)?.connectionStatus === 'connected');
const filteredFolders = computed(() => folders.value.filter(f => !f.connections.includes(props.contextConnection.uid)));
const isInFolder = computed(() => folders.value.some(f => f.connections.includes(props.contextConnection.uid)));
const confirmDeleteConnection = () => {
if (isConnected.value)
@ -129,6 +187,27 @@ const confirmDeleteConnection = () => {
closeContext();
};
const moveToFolder = (folderUid?: string) => {
if (!folderUid) {
addFolder({
connections: [props.contextConnection.uid]
});
}
else {
addToFolder({
folder: folderUid,
connection: props.contextConnection.uid
});
}
closeContext();
};
const outOfFolder = () => {
removeFromFolders(props.contextConnection.uid);
closeContext();
};
const duplicateConnection = () => {
let connectionCopy = getConnectionByUid(props.contextConnection.uid);
connectionCopy = {

View File

@ -101,7 +101,13 @@ const props = defineProps({
selectedField: Object
});
const emit = defineEmits(['close-context', 'duplicate-selected', 'delete-selected', 'add-new-index', 'add-to-index']);
const emit = defineEmits([
'close-context',
'duplicate-selected',
'delete-selected',
'add-new-index',
'add-to-index'
]);
const hasPrimary = computed(() => props.indexes.some(index => index.type === 'PRIMARY'));

View File

@ -150,7 +150,13 @@ const props = defineProps({
mode: String
});
const emit = defineEmits(['add-new-index', 'add-to-index', 'rename-field', 'duplicate-field', 'remove-field']);
const emit = defineEmits([
'add-new-index',
'add-to-index',
'rename-field',
'duplicate-field',
'remove-field'
]);
const workspacesStore = useWorkspacesStore();
const consoleStore = useConsoleStore();

View File

@ -292,6 +292,10 @@ const props = defineProps({
results: Array as Prop<QueryResult[]>,
connUid: String,
mode: String as Prop<'table' | 'query'>,
page: {
type: Number,
required: false
},
isSelected: Boolean,
elementType: { type: String, default: 'table' }
});
@ -868,6 +872,7 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, po
},
client: workspaceClient.value,
table,
page: props.page,
sqlOptions: popup ? { ...sqlExportOptions.value } : null,
csvOptions: popup ? { ...csvExportOptions.value } : null
});

View File

@ -202,6 +202,7 @@
v-if="results"
ref="queryTable"
:results="results"
:page="page"
:tab-uid="tabUid"
:conn-uid="connection.uid"
:is-selected="isSelected"

View File

@ -79,7 +79,8 @@ export const enUS = {
search: 'Search',
title: 'Title',
archive: 'Archive', // verb
undo: 'Undo'
undo: 'Undo',
moveTo: 'Move to'
},
connection: { // Database connection
connection: 'Connection',
@ -332,7 +333,7 @@ export const enUS = {
wrapLongLines: 'Wrap long lines',
markdownSupported: 'Markdown supported',
plantATree: 'Plant a Tree',
dataTabPageSize: 'DATA tab page size',
dataTabPageSize: 'Results per page',
noOpenTabs: 'There are no open tabs, navigate on the left bar or:',
restorePreviousSession: 'Restore previous session',
closeTab: 'Close tab',
@ -363,6 +364,8 @@ export const enUS = {
editFolder: 'Edit folder',
folderName: 'Folder name',
deleteFolder: 'Delete folder',
newFolder: 'New folder',
outOfFolder: 'Out of folder',
editConnectionAppearance: 'Edit connection appearance',
defaultCopyType: 'Default copy type',
showTableSize: 'Show table size in sidebar',

View File

@ -1,11 +1,13 @@
import { ClientCode } from 'common/interfaces/antares';
import { jsonToSqlInsert } from 'common/libs/sqlUtils';
import * as json2php from 'json2php';
import * as moment from 'moment';
export const exportRows = (args: {
type: 'csv' | 'json'| 'sql' | 'php';
content: object[];
table: string;
page?: number;
client?: ClientCode;
fields?: {
[key: string]: {type: string; datePrecision: number};
@ -41,6 +43,7 @@ export const exportRows = (args: {
for (const row of args.content) {
csv.push(Object.values(row).map(col => {
if (typeof col === 'string') return `${sd}${col}${sd}`;
if (col instanceof Date) return `${sd}${moment(col).format('YYYY-MM-DD HH:mm:ss')}${sd}`;
if (col instanceof Buffer) return col.toString('base64');
if (col instanceof Uint8Array) return Buffer.from(col).toString('base64');
return col;
@ -81,7 +84,7 @@ export const exportRows = (args: {
const file = new Blob([content], { type: mime });
const downloadLink = document.createElement('a');
downloadLink.download = `${args.sqlOptions?.targetTable || args.table}.${args.type}`;
downloadLink.download = `${args.sqlOptions?.targetTable || args.table}${args.page ? `-${args.page}` : ''}.${args.type}`;
downloadLink.href = window.URL.createObjectURL(file);
downloadLink.style.display = 'none';
document.body.appendChild(downloadLink);

View File

@ -90,8 +90,12 @@ export const useConnectionsStore = defineStore('connections', {
});
persistentStore.set('connectionsOrder', this.connectionsOrder);
},
addFolder (params: {after: string; connections: [string, string]}) {
const index = this.connectionsOrder.findIndex((conn: SidebarElement) => conn.uid === params.after);
addFolder (params: {after?: string; connections: [string, string?]}) {
const index = params.after
? this.connectionsOrder.findIndex((conn: SidebarElement) => conn.uid === params.after)
: this.connectionsOrder.length;
this.removeFromFolders(...params.connections);
this.connectionsOrder.splice(index, 0, {
isFolder: true,
@ -102,7 +106,18 @@ export const useConnectionsStore = defineStore('connections', {
});
persistentStore.set('connectionsOrder', this.connectionsOrder);
},
removeFromFolders (...connections: string[]) { // Removes connections from folders
this.connectionsOrder = (this.connectionsOrder as SidebarElement[]).map(el => {
if (el.isFolder)
el.connections = el.connections.filter(uid => !connections.includes(uid));
return el;
});
this.clearEmptyFolders();
},
addToFolder (params: {folder: string; connection: string}) {
this.removeFromFolders(params.connection);
this.connectionsOrder = this.connectionsOrder.map((conn: SidebarElement) => {
if (conn.uid === params.folder)
conn.connections.push(params.connection);
@ -113,11 +128,7 @@ export const useConnectionsStore = defineStore('connections', {
this.clearEmptyFolders();
},
deleteConnection (connection: SidebarElement | ConnectionParams) {
this.connectionsOrder = (this.connectionsOrder as SidebarElement[]).map(el => { // Removes connection from folders
if (el.isFolder && el.connections.includes(connection.uid))
el.connections = el.connections.filter(uid => uid !== connection.uid);
return el;
});
this.removeFromFolders(connection.uid);
this.connectionsOrder = (this.connectionsOrder as SidebarElement[]).filter(el => el.uid !== connection.uid);
this.lastConnections = (this.lastConnections as SidebarElement[]).filter(el => el.uid !== connection.uid);

View File

@ -66,7 +66,7 @@ export interface Workspace {
uid: string;
client?: ClientCode;
database?: string;
connectionStatus: 'connected' | 'disconnected' | 'failed';
connectionStatus: 'connected' | 'connecting' | 'disconnected' | 'failed';
selectedTab: string;
searchTerm: string;
tabs: WorkspaceTab[];