mirror of
https://github.com/Fabio286/antares.git
synced 2024-12-25 08:20:39 +01:00
Improvements
This commit is contained in:
parent
cd42b65b9e
commit
268688cdb8
@ -2,6 +2,7 @@
|
||||
import { ipcMain } from 'electron';
|
||||
import knex from 'knex';
|
||||
import InformationSchema from '../models/InformationSchema';
|
||||
import { RawQuery } from '../models/RawQuery';
|
||||
|
||||
const connections = {};
|
||||
|
||||
@ -74,4 +75,19 @@ export default () => {
|
||||
return { status: 'error', response: err.toString() };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('runQuery', async (event, { connection, query, database }) => {
|
||||
const knexIstance = connections[connection.uid];
|
||||
const Query = new RawQuery({ knexIstance, database });
|
||||
try {
|
||||
Query.runQuery(query);
|
||||
|
||||
Query.on('row', row => {
|
||||
event.sender.send('row', row);
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
return { status: 'error', response: err.toString() };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
22
src/main/models/RawQuery.js
Normal file
22
src/main/models/RawQuery.js
Normal file
@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export class RawQuery extends EventEmitter {
|
||||
constructor ({ knexIstance, database }) {
|
||||
super();
|
||||
this.conn = knexIstance;
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
async runQuery (query) {
|
||||
if (this.database) await this.conn.raw(`USE \`${this.database}\``);
|
||||
const stream = this.conn.raw(query).stream();
|
||||
stream.on('data', row => {
|
||||
this.emit('row', row);
|
||||
});
|
||||
|
||||
stream.on('error', err => {
|
||||
this.emit('error', err);
|
||||
});
|
||||
}
|
||||
}
|
@ -89,6 +89,7 @@ export default {
|
||||
padding: 0;
|
||||
justify-content: flex-start;
|
||||
height: calc(100vh - #{$excluding-size});
|
||||
width: calc(100% - #{$settingbar-width});
|
||||
|
||||
> .columns{
|
||||
height: calc(100vh - #{$footer-height});
|
||||
|
@ -85,7 +85,7 @@ export default {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
max-width: 25rem;
|
||||
max-width: 30rem;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<div v-show="isSelected" class="workspace column columns">
|
||||
<div v-show="isSelected" class="workspace column columns col-gapless">
|
||||
<WorkspaceExploreBar :connection="connection" :is-selected="isSelected" />
|
||||
<div class="workspace-tabs column p-0">
|
||||
<ul class="tab tab-block">
|
||||
<div v-if="workspace.connected" class="workspace-tabs column columns col-gapless">
|
||||
<ul class="tab tab-block column col-12">
|
||||
<li
|
||||
v-for="(tab, key) of workspace.tabs"
|
||||
:key="tab.uid"
|
||||
class="tab-item"
|
||||
:class="{'active': selectedTab === tab.uid}"
|
||||
>
|
||||
<a href="#">Query #{{ key }} <span class="btn btn-clear" /></a>
|
||||
<a href="#">Query #{{ key }} <span v-if="workspace.tabs.length > 1" class="btn btn-clear" /></a>
|
||||
</li>
|
||||
</ul>
|
||||
<QueryEditor v-model="query" />
|
||||
<WorkspaceQueryTab :connection="connection" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -21,22 +21,17 @@
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import WorkspaceQueryTab from '@/components/WorkspaceQueryTab';
|
||||
|
||||
export default {
|
||||
name: 'Workspace',
|
||||
components: {
|
||||
WorkspaceExploreBar,
|
||||
QueryEditor
|
||||
WorkspaceQueryTab
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
query: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="p-relative">
|
||||
<div class="column col-auto p-relative">
|
||||
<div ref="resizer" class="workspace-explorebar-resizer" />
|
||||
<div
|
||||
ref="explorebar"
|
||||
|
145
src/renderer/components/WorkspaceQueryTab.vue
Normal file
145
src/renderer/components/WorkspaceQueryTab.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<QueryEditor v-model="query" />
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
<i class="material-icons text-success" @click="runQuery">play_arrow</i>
|
||||
</div>
|
||||
<div>
|
||||
Schema: <b>{{ workspace.breadcrumbs.database }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="resultTable" class="workspace-query-results column col-12">
|
||||
<table v-if="results.length" class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="field in fields" :key="field">
|
||||
{{ field }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rKey) in results" :key="rKey">
|
||||
<td v-for="(col, cKey) in row" :key="cKey">
|
||||
{{ col }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ipcRenderer } from 'electron';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceQueryTab',
|
||||
components: {
|
||||
QueryEditor
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
query: '',
|
||||
results: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
fields () {
|
||||
return Object.keys(this.results[0]);
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.resizeResults);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.resizeResults);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
async runQuery () {
|
||||
this.results = [];
|
||||
this.resizeResults();
|
||||
|
||||
const params = {
|
||||
connection: this.connection,
|
||||
query: this.query,
|
||||
database: this.workspace.breadcrumbs.database
|
||||
};
|
||||
|
||||
try {
|
||||
ipcRenderer.send('runQuery', params);
|
||||
|
||||
ipcRenderer.on('row', (event, row) => {
|
||||
this.results.push(row);
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
resizeResults (e) {
|
||||
const el = this.$refs.resultTable;
|
||||
const footer = document.getElementById('footer');
|
||||
|
||||
if (el) {
|
||||
const size = window.innerHeight - el.getBoundingClientRect().top - footer.offsetHeight;
|
||||
el.style.height = size + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.workspace-tabs{
|
||||
align-content: baseline;
|
||||
|
||||
.workspace-query-runner{
|
||||
|
||||
.workspace-query-runner-footer{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: .2rem .6rem;
|
||||
align-items: center;
|
||||
|
||||
.workspace-query-buttons{
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-results{
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
|
||||
th{
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: $bg-color;
|
||||
border-color: $bg-color-light;
|
||||
}
|
||||
|
||||
td{
|
||||
border-color: $bg-color-light;
|
||||
padding: 0 .4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user