Notification and connection status improvements

This commit is contained in:
Fabio 2020-05-17 19:34:56 +02:00
parent 55b1991869
commit 14a2fad0ac
13 changed files with 226 additions and 96 deletions

54
package-lock.json generated
View File

@ -1065,9 +1065,9 @@
}
},
"@electron/get": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@electron/get/-/get-1.10.0.tgz",
"integrity": "sha512-hlueNXU51c3CwQjBw/i5fwt+VfQgSQVUTdicpCHkhEjNZaa4CXJ5W1GaxSwtLE2dvRmAHjpIjUMHTqJ53uojfg==",
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.2.tgz",
"integrity": "sha512-vAuHUbfvBQpYTJ5wB7uVIDq5c/Ry0fiTBMs7lnEYAo/qXXppIVcWdfBr57u6eRnKdVso7KSiH6p/LbQAG6Izrg==",
"dev": true,
"requires": {
"debug": "^4.1.1",
@ -3894,9 +3894,9 @@
}
},
"electron": {
"version": "8.2.4",
"resolved": "https://registry.npmjs.org/electron/-/electron-8.2.4.tgz",
"integrity": "sha512-Lle0InIgSAHZxD5KDY0wZ1A2Zlc6GHwMhAxoHMzn05mndyP1YBkCYHc0TDDofzUTrsLFofduPjlknO5Oj9fTPA==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-8.3.0.tgz",
"integrity": "sha512-XRjiIJICZCgUr2vKSUI2PTkfP0gPFqCtqJUaTJSfCTuE3nTrxBKOUNeRMuCzEqspKkpFQU3SB3MdbMSHmZARlQ==",
"dev": true,
"requires": {
"@electron/get": "^1.0.1",
@ -9302,24 +9302,24 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pg": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.2.0.tgz",
"integrity": "sha512-EQeWKZv7qBTQZQa7EraR61AOi0bpizvlZLvrPdgAGaraX4YI+y40iQnL39XjPMXVnHOOG3jV6kAGtc0WSJn/+A==",
"version": "8.2.1",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.2.1.tgz",
"integrity": "sha512-DKzffhpkWRr9jx7vKxA+ur79KG+SKw+PdjMb1IRhMiKI9zqYUGczwFprqy+5Veh/DCcFs1Y6V8lRLN5I1DlleQ==",
"requires": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
"pg-connection-string": "^2.2.2",
"pg-pool": "^3.2.0",
"pg-protocol": "^1.2.3",
"pg-connection-string": "^2.2.3",
"pg-pool": "^3.2.1",
"pg-protocol": "^1.2.4",
"pg-types": "^2.1.0",
"pgpass": "1.x",
"semver": "4.3.2"
},
"dependencies": {
"pg-connection-string": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.2.2.tgz",
"integrity": "sha512-+hel4DGuSZCjCZwglAuyi+XlodHnKmrbyTw0hVWlmGN2o4AfJDkDo5obAFzblS5M5PFBMx0uDt5Y1QjlNC+tqg=="
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.2.3.tgz",
"integrity": "sha512-I/KCSQGmOrZx6sMHXkOs2MjddrYcqpza3Dtsy0AjIgBr/bZiPJRK9WhABXN1Uy1UDazRbi9gZEzO2sAhL5EqiQ=="
},
"semver": {
"version": "4.3.2",
@ -9339,14 +9339,14 @@
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
},
"pg-pool": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.0.tgz",
"integrity": "sha512-7BLwDNDEfPFjE9vmZLcJPLFwuDAVGZ5lIZo2MeQfwYG7EPGfdNVis/dz6obI/yKqvQIx2sf6QBKXMLB+y/ftgA=="
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.1.tgz",
"integrity": "sha512-BQDPWUeKenVrMMDN9opfns/kZo4lxmSWhIqo+cSAF7+lfi9ZclQbr9vfnlNaPr8wYF3UYjm5X0yPAhbcgqNOdA=="
},
"pg-protocol": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.2.3.tgz",
"integrity": "sha512-erHFURS0mPmTbq18cn/zNL3Y4IzNCrU4sgCim0qy7zAPe3Vc0rvK5cImJR6lDvIaz3fJU2R1R9FNOlnUtyF10Q=="
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.2.4.tgz",
"integrity": "sha512-/8L/G+vW/VhWjTGXpGh8XVkXOFx1ZDY+Yuz//Ab8CfjInzFkreI+fDG3WjCeSra7fIZwAFxzbGptNbm8xSXenw=="
},
"pg-types": {
"version": "2.2.0",
@ -12582,9 +12582,9 @@
}
},
"vue-i18n": {
"version": "8.17.4",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.17.4.tgz",
"integrity": "sha512-wpk/drIkPf6gHCtvHc8zAZ1nsWBZ+/OOJYtJxqhYD6CKT0FJAG5oypwgF9kABt30FBWhl8NEb/QY+vaaBARlFg=="
"version": "8.17.6",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.17.6.tgz",
"integrity": "sha512-SsKL5D9Ii3zJPsFhUSllY754XuZvP8uCouUm+Mbylu95h3OwenV09uzIIEjkT7EtWyDQuWSMWObrNaD4ukBGZw=="
},
"vue-loader": {
"version": "15.9.1",
@ -12626,9 +12626,9 @@
"dev": true
},
"vuex": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.3.0.tgz",
"integrity": "sha512-1MfcBt+YFd20DPwKe0ThhYm1UEXZya4gVKUvCy7AtS11YAOUR+9a6u4fsv1Rr6ePZCDNxW/M1zuIaswp6nNv8Q=="
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.4.0.tgz",
"integrity": "sha512-ajtqwEW/QhnrBZQsZxCLHThZZaa+Db45c92Asf46ZDXu6uHXgbfVuBaJ4gzD2r4UX0oMJHstFwd2r2HM4l8umg=="
},
"vuex-persist": {
"version": "2.2.0",

View File

@ -32,16 +32,16 @@
"material-design-icons": "^3.0.1",
"mssql": "^6.2.0",
"mysql": "^2.18.1",
"pg": "^8.2.0",
"pg": "^8.2.1",
"source-map-support": "^0.5.16",
"spectre.css": "^0.5.8",
"vue-i18n": "^8.17.4",
"vuex": "^3.3.0",
"vue-i18n": "^8.17.6",
"vuex": "^3.4.0",
"vuex-persist": "^2.2.0"
},
"devDependencies": {
"babel-eslint": "^10.1.0",
"electron": "^8.2.4",
"electron": "^8.3.0",
"electron-builder": "^22.4.1",
"electron-devtools-installer": "^3.0.0",
"electron-webpack": "^2.8.2",

View File

@ -30,8 +30,8 @@ export default () => {
});
ipcMain.handle('connect', async (event, conn) => {
// TODO: make a test before
connections[conn.uid] = knex({
let structure;
const connection = knex({
client: conn.client,
connection: {
host: conn.host,
@ -45,6 +45,14 @@ export default () => {
}
});
return await InformationSchema.getStructure(connections[conn.uid]);
try {
structure = await InformationSchema.getStructure(connection);
}
catch (err) {
return { status: 'error', response: err.toString() };
}
connections[conn.uid] = connection;
return { status: 'success', response: structure };
});
};

View File

@ -1,15 +1,20 @@
<template>
<div class="toast mt-2" :class="notificationStatus.className">
<span class="p-vcentered text-left">
<span class="p-vcentered text-left" :class="{'expanded': isExpanded}">
<i class="material-icons mr-1">{{ notificationStatus.iconName }}</i>
<span class="notification-message">{{ message }}</span>
</span>
<i
v-if="isExpandable"
class="material-icons c-hand"
@click="toggleExpand"
>{{ isExpanded ? 'expand_less' : 'expand_more' }}</i>
<button class="btn btn-clear" @click="hideToast" />
</div>
</template>
<script>
export default { // TODO: open notifications button
export default {
name: 'BaseNotification',
props: {
message: {
@ -21,6 +26,11 @@ export default { // TODO: open notifications button
default: ''
}
},
data () {
return {
isExpanded: false
};
},
computed: {
notificationStatus () {
let className = '';
@ -45,11 +55,17 @@ export default { // TODO: open notifications button
}
return { className, iconName };
},
isExpandable () {
return this.message.length > 80;
}
},
methods: {
hideToast () {
this.$emit('close');
},
toggleExpand () {
this.isExpanded = !this.isExpanded;
}
}
};
@ -60,6 +76,8 @@ export default { // TODO: open notifications button
justify-content: space-between;
user-select: text;
word-break: break-all;
width: fit-content;
margin-left: auto;
}
.notification-message{
@ -67,7 +85,11 @@ export default { // TODO: open notifications button
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
width: 25rem;
max-width: 25rem;
user-select: none;
}
.expanded .notification-message{
white-space: initial;
}
</style>

View File

@ -0,0 +1,77 @@
<template>
<div v-if="!isConnected" class="columns">
<div class="column col-12 empty text-light">
<div class="empty-icon">
<i class="material-icons md-48">cloud_off</i>
</div>
<p class="empty-title h5">
Disconnected
</p>
<div class="empty-action">
<button
class="btn btn-success"
:class="{'loading': isConnecting}"
@click="startConnection"
>
Connect
</button>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import Connection from '@/ipc-api/Connection';
export default {
name: 'DatabaseConnectPanel',
props: {
connection: Object
},
data () {
return {
isConnecting: false
};
},
computed: {
...mapGetters({
connected: 'workspaces/getConnected'
}),
isConnected () {
return this.connected.includes(this.connection.uid);
}
},
methods: {
...mapActions({
addNotification: 'notifications/addNotification',
addConnected: 'workspaces/addConnected'
}),
async startConnection () {
this.isConnecting = true;
try {
const { status, response } = await Connection.connect(this.connection);
if (status === 'error')
this.addNotification({ status, message: response });
else
this.addConnected(this.connection.uid);
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
this.isConnecting = false;
}
}
};
</script>
<style scoped>
.empty{
height: 100%;
border-radius: 0;
background: transparent;
display: flex;
flex-direction: column;
justify-content: center;
}
</style>

View File

@ -3,47 +3,20 @@
<div class="workspace-explorebar-title">
{{ connection.user }}@{{ connection.host }}:{{ connection.port }}
</div>
<button
v-if="!isConnected"
class="btn btn-success mt-4"
:class="{'loading': isConnecting}"
@click="startConnection"
>
Connect
</button>
<DatabaseConnectPanel :connection="connection" />
</div>
</template>
<script>
import { mapActions } from 'vuex';
import Connection from '@/ipc-api/Connection';
import DatabaseConnectPanel from '@/components/DatabaseConnectPanel';
export default {
name: 'DatabaseExploreBar',
components: {
DatabaseConnectPanel
},
props: {
connection: Object
},
data () {
return {
isConnected: false,
isConnecting: false
};
},
methods: {
...mapActions({
addNotification: 'notifications/addNotification'
}),
async startConnection () {
this.isConnecting = true;
try {
this.structure = await Connection.connect(this.connection);
this.isConnected = true;
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
this.isConnecting = false;
}
}
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div v-show="selectedConnection === connection.uid" class="workspace column columns">
<div v-show="selectedWorkspace === connection.uid" class="workspace column columns">
<DatabaseExploreBar :connection="connection" />
<div class="workspace-tabs column">
<p>{{ connection }}</p>
@ -27,23 +27,32 @@ export default {
},
computed: {
...mapGetters({
selectedConnection: 'connections/getSelected'
selectedWorkspace: 'workspaces/getSelected',
getConnected: 'workspaces/getConnected'
})
},
async created () {
this.isConnected = await Connection.checkConnection(this.connection.uid);
if (this.isConnected) {
const isInitiated = await Connection.checkConnection(this.connection.uid);
if (isInitiated) {
try {
this.structure = await Connection.connect(this.connection);// TODO: use refresh
const { status, response } = await Connection.connect(this.connection);
if (status === 'success') {
this.structure = response;
this.addConnected(this.connection.uid);
}
else
this.addNotification({ status, message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
this.addNotification({ status: 'error', message: err.toString() });
}
}
},
methods: {
...mapActions({
addNotification: 'notifications/addNotification'
addNotification: 'notifications/addNotification',
addConnected: 'workspaces/addConnected',
removeConnected: 'workspaces/removeConnected'
})
}
};

View File

@ -5,7 +5,6 @@
v-for="notification in latestNotifications"
:key="notification.uid"
:message="notification.message"
:title="notification.message"
:status="notification.status"
@close="removeNotification(notification.uid)"
/>
@ -42,7 +41,7 @@ export default {
#notifications-board{
position: absolute;
z-index: 9;
right: 1rem;
right: .8rem;
bottom: $footer-height+1rem;
}
</style>

View File

@ -6,11 +6,11 @@
v-for="connection in connections"
:key="connection.uid"
class="settingbar-element btn btn-link tooltip tooltip-right"
:class="{'selected': connection.uid === selectedConnection}"
:class="{'selected': connection.uid === selectedWorkspace}"
:data-tooltip="`${connection.user}@${connection.host}:${connection.port}`"
@click="selectConnection(connection.uid)"
@click="selectWorkspace(connection.uid)"
>
<i class="settingbar-element-icon dbi" :class="`dbi-${connection.client}`" />
<i class="settingbar-element-icon dbi" :class="`dbi-${connection.client} ${connected.includes(connection.uid) ? 'badge' : ''}`" />
</li>
<li
class="settingbar-element btn btn-link tooltip tooltip-right pt-3"
@ -40,13 +40,14 @@ export default {
computed: {
...mapGetters({
connections: 'connections/getConnections',
selectedConnection: 'connections/getSelected'
connected: 'workspaces/getConnected',
selectedWorkspace: 'workspaces/getSelected'
})
},
methods: {
...mapActions({
showNewConnModal: 'connections/showNewConnModal',
selectConnection: 'connections/selectConnection'
selectWorkspace: 'workspaces/selectWorkspace'
})
}
};
@ -92,6 +93,13 @@ export default {
.settingbar-element-icon{
margin-left: -3px;
&.badge::after{
bottom: -10px;
right: 0;
position: absolute;
background: $success-color;
}
}
}

View File

@ -5,6 +5,7 @@ $bg-color: #1d1d1d;
$bg-color-light: #3f3f3f;
$bg-color-gray: #272727;
$primary-color: #e36929;
$success-color: #32b643;
$error-color: #de3b28;
/*Sizes*/

View File

@ -6,6 +6,7 @@ import VuexPersist from 'vuex-persist';
import application from './modules/application.store';
import connections from './modules/connections.store';
import workspaces from './modules/workspaces.store';
import notifications from './modules/notifications.store';
const vuexLocalStorage = new VuexPersist({
@ -23,6 +24,7 @@ export default new Vuex.Store({
modules: {
application,
connections,
workspaces,
notifications
},
plugins: [vuexLocalStorage.plugin]

View File

@ -5,16 +5,10 @@ export default {
strict: true,
state: {
connections: [],
is_new_modal: false,
connection_selected: null
is_new_modal: false
},
getters: {
getConnections: state => state.connections,
getSelected: state => {
if (state.connection_selected) return state.connection_selected;
if (state.connections.length) return state.connections[0].uid;
return null;
},
isNewModal: state => state.is_new_modal
},
mutations: {
@ -26,9 +20,6 @@ export default {
},
HIDE_NEW_CONNECTION_MODAL (state) {
state.is_new_modal = false;
},
SELECT_CONNECTION (state, uid) {
state.connection_selected = uid;
}
},
actions: {
@ -41,9 +32,6 @@ export default {
},
hideNewConnModal ({ commit }) {
commit('HIDE_NEW_CONNECTION_MODAL');
},
selectConnection ({ commit }, uid) {
commit('SELECT_CONNECTION', uid);
}
}
};

View File

@ -0,0 +1,43 @@
'use strict';
// import { uidGen } from 'common/libs/utilities';
export default {
namespaced: true,
strict: true,
state: {
workspaces: [],
connected_workspaces: [],
workspace_selected: null
},
getters: {
getSelected: state => {
if (state.workspace_selected) return state.workspace_selected;
if (state.workspaces.length) return state.workspaces[0].uid;
return null;
},
getWorkspaces: state => state.workspaces,
getConnected: state => state.connected_workspaces
},
mutations: {
SELECT_WORKSPACE (state, uid) {
state.workspace_selected = uid;
},
ADD_CONNECTED (state, uid) {
state.connected_workspaces.push(uid);
},
REMOVE_CONNECTED (state, uid) {
state.connected_workspaces = state.connected_workspaces.filter(item => item.uid !== uid);
}
},
actions: {
selectWorkspace ({ commit }, uid) {
commit('SELECT_WORKSPACE', uid);
},
addConnected ({ commit }, uid) {
commit('ADD_CONNECTED', uid);
},
removeConnected ({ commit }, uid) {
commit('REMOVE_CONNECTED', uid);
}
}
};