Additions

This commit is contained in:
Fabio 2020-06-05 21:00:15 +02:00
parent 1bb3e8c9ac
commit cd42b65b9e
11 changed files with 218 additions and 57 deletions

View File

@ -7,16 +7,22 @@ const connections = {};
export default () => {
ipcMain.handle('testConnection', async (event, conn) => {
const connection = knex({
client: conn.client,
connection: {
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password
},
pool: {
min: 1,
max: 3
}
});
try {
await knex({
client: conn.client,
connection: {
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password
}
}).raw('SELECT 1+1 AS result');
await InformationSchema.testConnection(connection);
return { status: 'success' };
}

View File

@ -1,11 +1,16 @@
'use strict';
export default class {
static testConnection (connection) {
return connection('TABLES')
.select({ result: 1 })
.withSchema('information_schema');
}
static getStructure (connection) {
return connection()
return connection('TABLES')
.select('*')
.withSchema('information_schema')
.from('TABLES')
.orderBy(['TABLE_SCHEMA', 'TABLE_NAME'], 'asc');
}
}

View File

@ -82,6 +82,7 @@ export default {
#window-content{
display: flex;
position: relative;
overflow: hidden;
}
#main-content {

View File

@ -68,8 +68,22 @@ export default {
};
</script>
<style scoped>
<style lang="scss">
.editor-wrapper{
border-bottom: 1px solid #444444;
}
.CodeMirror{
height: 200px;
.CodeMirror-scroll{
max-width: 100%;
}
.CodeMirror-line {
word-break: break-word!important;
white-space: pre-wrap!important;
word-break: normal;
}
}
</style>

View File

@ -13,33 +13,32 @@
v-for="connection in connections"
:key="connection.uid"
draggable="true"
class="settingbar-element btn btn-link tooltip tooltip-right"
class="settingbar-element btn btn-link ex-tooltip"
:class="{'selected': connection.uid === selectedWorkspace}"
:data-tooltip="`${getConnectionName(connection.uid)}`"
@click="selectWorkspace(connection.uid)"
@contextmenu.prevent="contextMenu($event, connection)"
@mouseover.self="tooltipPosition"
>
<i class="settingbar-element-icon dbi" :class="`dbi-${connection.client} ${connected.includes(connection.uid) ? 'badge' : ''}`" />
<span class="ex-tooltip-content">{{ getConnectionName(connection.uid) }}</span>
</li>
</draggable>
<li
class="settingbar-element btn btn-link tooltip tooltip-right pt-3"
:data-tooltip="$t('message.addConnection')"
class="settingbar-element btn btn-link ex-tooltip"
@click="showNewConnModal"
@mouseover.self="tooltipPosition"
>
<i class="settingbar-element-icon material-icons text-light">add</i>
<span class="ex-tooltip-content">{{ $t('message.addConnection') }}</span>
</li>
</ul>
</div>
<div class="settingbar-bottom-elements">
<ul class="settingbar-elements">
<li
class="settingbar-element btn btn-link tooltip tooltip-right mb-2"
:data-tooltip="$t('word.settings')"
@click="showSettingModal('general')"
>
<li class="settingbar-element btn btn-link ex-tooltip" @click="showSettingModal('general')">
<i class="settingbar-element-icon material-icons text-light">settings</i>
<span class="ex-tooltip-content">{{ $t('word.settings') }}</span>
</li>
</ul>
</div>
@ -62,7 +61,8 @@ export default {
dragElement: null,
isContext: false,
contextEvent: null,
contextConnection: {}
contextConnection: {},
scale: 0
};
},
computed: {
@ -95,6 +95,11 @@ export default {
},
workspaceName (connection) {
return connection.ask ? '' : `${connection.user + '@'}${connection.host}:${connection.port}`;
},
tooltipPosition (e) {
const el = e.target;
const fromTop = window.pageYOffset + el.getBoundingClientRect().top - (el.offsetHeight / 4);
el.querySelector('.ex-tooltip-content').style.top = `${fromTop}px`;
}
}
};
@ -113,6 +118,22 @@ export default {
box-shadow: 0 0 1px 0px #000;
z-index: 9;
.settingbar-top-elements{
overflow-x: hidden;
overflow-y: overlay;
max-height: calc((100vh - 3.5rem) - #{$excluding-size});
&::-webkit-scrollbar {
width: 3px;
}
}
.settingbar-bottom-elements{
padding-top: .5rem;
background: $bg-color-light;
z-index: 1;
}
.settingbar-elements{
list-style: none;
text-align: center;
@ -121,14 +142,16 @@ export default {
margin: 0;
.settingbar-element{
height: initial;
height: $settingbar-width;
width: 100%;
padding: 0;
padding: .3rem 0 0;
margin: 0;
border-left: 3px solid transparent;
opacity: .5;
transition: opacity .2s;
display: flex;
align-content: center;
justify-content: center;
flex-direction: column;
&:hover{
opacity: 1;
@ -140,7 +163,6 @@ export default {
}
.settingbar-element-icon{
margin-left: -3px;
&.badge::after{
bottom: -10px;
@ -153,4 +175,32 @@ export default {
}
}
.ex-tooltip{// Because both overflow-x: visible and overflow-y:auto are evil!!!
.ex-tooltip-content{
z-index: 999;
visibility: hidden;
opacity: 0;
display:block;
position:absolute;
background-color:#feffe1;
text-align: center;
margin:.0 0 0 calc(#{$settingbar-width} - 5px);
left: 0;
padding: .2rem .4rem;
font-size: .7rem;
background: rgba(48,55,66,.95);
border-radius: .1rem;
color: #fff;
max-width: 320px;
pointer-events: none;
text-overflow: ellipsis;
transition: opacity .2s;
}
&:hover .ex-tooltip-content{
visibility: visible;
opacity: 1;
}
}
</style>

View File

@ -1,8 +1,18 @@
<template>
<div v-show="isSelected" class="workspace column columns">
<WorkspaceExploreBar :connection="connection" :is-selected="isSelected" />
<div class="workspace-tabs column">
<pre>{{ JSON.stringify(workspace.structure, null, 3) }}</pre>
<div class="workspace-tabs column p-0">
<ul class="tab tab-block">
<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>
</li>
</ul>
<QueryEditor v-model="query" />
</div>
</div>
</template>
@ -11,15 +21,22 @@
import { mapGetters, mapActions } from 'vuex';
import Connection from '@/ipc-api/Connection';
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar';
import QueryEditor from '@/components/QueryEditor';
export default {
name: 'Workspace',
components: {
WorkspaceExploreBar
WorkspaceExploreBar,
QueryEditor
},
props: {
connection: Object
},
data () {
return {
query: ''
};
},
computed: {
...mapGetters({
selectedWorkspace: 'workspaces/getSelected',
@ -30,10 +47,13 @@ export default {
},
isSelected () {
return this.selectedWorkspace === this.connection.uid;
},
selectedTab () {
return this.workspace.tabs.filter(tab => tab.selected).uid || this.workspace.tabs[0].uid;
}
},
async created () {
this.addWorkspace(this.connection.uid);
await this.addWorkspace(this.connection.uid);
const isInitiated = await Connection.checkConnection(this.connection.uid);
if (isInitiated)
this.connectWorkspace(this.connection);
@ -50,13 +70,22 @@ export default {
</script>
<style lang="scss">
.workspace{
padding: 0;
margin: 0;
.workspace{
padding: 0;
margin: 0;
.workspace-tabs{
overflow: auto;
height: calc(100vh - #{$excluding-size});
.workspace-tabs{
overflow: auto;
height: calc(100vh - #{$excluding-size});
.tab-block{
background: $bg-color-light;
margin-top: 0;
.tab-item{
max-width: 6rem;
}
}
}
}
</style>

View File

@ -79,6 +79,5 @@ export default {
background: transparent;
display: flex;
flex-direction: column;
justify-content: center;
}
</style>

View File

@ -22,12 +22,17 @@
>exit_to_app</i>
</span>
</div>
<WorkspaceConnectPanel v-if="!workspace.connected" :connection="connection" />
<div class="workspace-explorebar-body">
<WorkspaceConnectPanel
v-if="!workspace.connected"
class="workspace-explorebar-body"
:connection="connection"
/>
<div v-else class="workspace-explorebar-body">
<WorkspaceExploreBarDatabase
v-for="db of workspace.structure"
:key="db.dbName"
:key="db.name"
:database="db"
:connection="connection"
/>
</div>
</div>
@ -178,7 +183,7 @@ export default {
.workspace-explorebar-body{
width: 100%;
height: calc((100vh - 30px) - #{$excluding-size});
overflow: auto;
overflow: overlay;
padding: 0 .1rem;
}
}

View File

@ -1,9 +1,13 @@
<template>
<details class="accordion workspace-explorebar-database">
<summary class="accordion-header database-name pb-0">
<summary
class="accordion-header database-name pb-0"
:class="{'text-bold': breadcrumbs.database === database.name}"
@click="changeBreadcrumbs({database: database.name, table:null})"
>
<i class="icon material-icons md-18 mr-1">navigate_next</i>
<i class="material-icons md-18 mr-1">view_agenda</i>
<span>{{ database.dbName }}</span>
<span>{{ database.name }}</span>
</summary>
<div class="accordion-body">
<div class="database-bables">
@ -12,6 +16,8 @@
v-for="table of database.tables"
:key="table.TABLE_NAME"
class="menu-item"
:class="{'text-bold': breadcrumbs.database === database.name && breadcrumbs.table === table.TABLE_NAME}"
@click="changeBreadcrumbs({database: database.name, table: table.TABLE_NAME})"
>
<a class="table-name">
<i class="material-icons md-18 mr-1">grid_on</i>
@ -25,10 +31,26 @@
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'WorkspaceExploreBarDatabase',
props: {
database: Object
database: Object,
connection: Object
},
computed: {
...mapGetters({
getWorkspace: 'workspaces/getWorkspace'
}),
breadcrumbs () {
return this.getWorkspace(this.connection.uid).breadcrumbs;
}
},
methods: {
...mapActions({
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
})
}
};
</script>
@ -48,6 +70,12 @@ export default {
display: block;
text-overflow: ellipsis;
}
&:hover{
color: $body-font-color;
background: rgba($color: #FFF, $alpha: .05);
border-radius: 2px;
}
}
.database-bables{

View File

@ -142,19 +142,11 @@ body{
}
.menu{
font-size: .6rem;
font-size: .7rem;
.menu-item {
+ .menu-item{
margin-top: 0;
}
> a{
&:hover{
color: $body-font-color;
background: rgba($color: #FFF, $alpha: .1);
}
}
}
}

View File

@ -1,12 +1,14 @@
'use strict';
import Connection from '@/ipc-api/Connection';
import { uidGen } from 'common/libs/utilities';
function remapStructure (structure) {
const databases = structure.map(table => table.TABLE_SCHEMA)
.filter((value, index, self) => self.indexOf(value) === index);
return databases.map(db => {
return {
dbName: db,
name: db,
tables: structure.filter(table => table.TABLE_SCHEMA === db)
};
});
@ -50,6 +52,25 @@ export default {
},
ADD_WORKSPACE (state, workspace) {
state.workspaces.push(workspace);
},
CHANGE_BREADCRUMBS (state, { uid, breadcrumbs }) {
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, breadcrumbs } : workspace);
},
NEW_TAB (state, uid) {
const newTab = {
uid: uidGen(),
selected: false
};
state.workspaces = state.workspaces.map(workspace => {
if (workspace.uid === uid) {
return {
...workspace,
tabs: [...workspace.tabs, newTab]
};
}
else
return workspace;
});
}
},
actions: {
@ -80,18 +101,29 @@ export default {
dispatch('notifications/addNotification', { status: 'error', message: err.stack }, { root: true });
}
},
async removeConnected ({ commit }, uid) {
removeConnected ({ commit }, uid) {
Connection.disconnect(uid);
commit('REMOVE_CONNECTED', uid);
},
addWorkspace ({ commit }, uid) {
addWorkspace ({ commit, dispatch, getters }, uid) {
const workspace = {
uid,
connected: false,
tabs: [],
structure: {}
structure: {},
breadcrumbs: {}
};
commit('ADD_WORKSPACE', workspace);
if (!getters.getWorkspace(uid).tabs.length)
dispatch('newTab', uid);
},
changeBreadcrumbs ({ commit, getters }, payload) {
commit('CHANGE_BREADCRUMBS', { uid: getters.getSelected, breadcrumbs: payload });
},
newTab ({ commit }, uid) {
commit('NEW_TAB', uid);
}
}
};