1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-03-09 07:57:55 +01:00

Results table improvements

This commit is contained in:
Fabio 2020-07-24 13:26:56 +02:00
parent fdf5bef5ad
commit 60132c94a1
16 changed files with 266 additions and 213 deletions

View File

@ -1,11 +1,11 @@
import connection from './connection'; import connection from './connection';
import structure from './structure'; import tables from './tables';
import updates from './updates'; import updates from './updates';
const connections = {}; const connections = {};
export default () => { export default () => {
connection(connections); connection(connections);
structure(connections); tables(connections);
updates(); updates();
}; };

View File

@ -1,6 +1,6 @@
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import InformationSchema from '../models/InformationSchema'; import InformationSchema from '../models/InformationSchema';
import Generic from '../models/Generic'; import Tables from '../models/Tables';
// TODO: remap objects based on client // TODO: remap objects based on client
@ -17,7 +17,7 @@ export default (connections) => {
ipcMain.handle('getTableData', async (event, { uid, schema, table }) => { ipcMain.handle('getTableData', async (event, { uid, schema, table }) => {
try { try {
const result = await Generic.getTableData(connections[uid], schema, table); const result = await Tables.getTableData(connections[uid], schema, table);
return { status: 'success', response: result }; return { status: 'success', response: result };
} }
catch (err) { catch (err) {
@ -27,7 +27,7 @@ export default (connections) => {
ipcMain.handle('updateTableCell', async (event, params) => { ipcMain.handle('updateTableCell', async (event, params) => {
try { try {
const result = await Generic.updateTableCell(connections[params.uid], params); const result = await Tables.updateTableCell(connections[params.uid], params);
return { status: 'success', response: result }; return { status: 'success', response: result };
} }
catch (err) { catch (err) {
@ -37,7 +37,7 @@ export default (connections) => {
ipcMain.handle('deleteTableRows', async (event, params) => { ipcMain.handle('deleteTableRows', async (event, params) => {
try { try {
const result = await Generic.deleteTableRows(connections[params.uid], params); const result = await Tables.deleteTableRows(connections[params.uid], params);
return { status: 'success', response: result }; return { status: 'success', response: result };
} }
catch (err) { catch (err) {

View File

@ -11,30 +11,4 @@ export default class {
} }
return connection.raw(query); return connection.raw(query);
} }
static async getTableData (connection, schema, table) {
return connection
.select('*')
.schema(schema)
.from(table)
.limit(1000)
.run();
}
static async updateTableCell (connection, params) { // TODO: Handle different field types
return connection
.update({ [params.field]: `= "${params.content}"` })
.schema(params.schema)
.from(params.table)
.where({ [params.primary]: `= ${params.id}` })
.run();
}
static async deleteTableRows (connection, params) {
return connection
.schema(params.schema)
.delete(params.table)
.where({ [params.primary]: `IN (${params.rows.join(',')})` })
.run();
}
} }

28
src/main/models/Tables.js Normal file
View File

@ -0,0 +1,28 @@
'use strict';
export default class {
static async getTableData (connection, schema, table) {
return connection
.select('*')
.schema(schema)
.from(table)
.limit(1000)
.run();
}
static async updateTableCell (connection, params) { // TODO: Handle different field types
return connection
.update({ [params.field]: `= "${params.content}"` })
.schema(params.schema)
.from(params.table)
.where({ [params.primary]: `= ${params.id}` })
.run();
}
static async deleteTableRows (connection, params) {
return connection
.schema(params.schema)
.delete(params.table)
.where({ [params.primary]: `IN (${params.rows.join(',')})` })
.run();
}
}

View File

@ -152,9 +152,14 @@ export default {
border-left: none; border-left: none;
border-bottom-width: 2px; border-bottom-width: 2px;
border-color: $bg-color-light; border-color: $bg-color-light;
padding: .1rem .4rem; padding: 0;
font-weight: 700; font-weight: 700;
font-size: .7rem; font-size: .7rem;
> div {
padding: .1rem .4rem;
min-width: -webkit-fill-available;
}
} }
.td{ .td{

View File

@ -43,7 +43,7 @@
<script> <script>
import Connection from '@/ipc-api/Connection'; import Connection from '@/ipc-api/Connection';
import Structure from '@/ipc-api/Structure'; import Tables from '@/ipc-api/Tables';
import QueryEditor from '@/components/QueryEditor'; import QueryEditor from '@/components/QueryEditor';
import WorkspaceQueryTable from '@/components/WorkspaceQueryTable'; import WorkspaceQueryTable from '@/components/WorkspaceQueryTable';
import { mapGetters, mapActions } from 'vuex'; import { mapGetters, mapActions } from 'vuex';
@ -132,7 +132,7 @@ export default {
table: this.table table: this.table
}; };
const { status, response } = await Structure.getTableColumns(params); const { status, response } = await Tables.getTableColumns(params);
if (status === 'success') if (status === 'success')
this.fields = response.rows; this.fields = response.rows;
else else

View File

@ -10,7 +10,7 @@
<BaseVirtualScroll <BaseVirtualScroll
v-if="results.rows" v-if="results.rows"
ref="resultTable" ref="resultTable"
:items="localResults" :items="sortedResults"
:item-height="25" :item-height="25"
class="vscroll" class="vscroll"
:style="{'height': resultsSize+'px'}" :style="{'height': resultsSize+'px'}"
@ -22,9 +22,10 @@
<div <div
v-for="field in fields" v-for="field in fields"
:key="field.name" :key="field.name"
class="th" class="th c-hand"
> >
<div class="table-column-title"> <div ref="columnResize" class="column-resizable">
<div class="table-column-title" @click="sort(field.name)">
<i <i
v-if="field.key" v-if="field.key"
class="material-icons column-key c-help" class="material-icons column-key c-help"
@ -32,6 +33,8 @@
:title="keyName(field.key)" :title="keyName(field.key)"
>vpn_key</i> >vpn_key</i>
<span>{{ field.name }}</span> <span>{{ field.name }}</span>
<i v-if="currentSort === field.name" class="material-icons sort-icon">{{ currentSortDir === 'asc' ? 'arrow_upward':'arrow_downward' }}</i>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -87,16 +90,34 @@ export default {
isContext: false, isContext: false,
contextEvent: null, contextEvent: null,
selectedCell: null, selectedCell: null,
selectedRows: [] selectedRows: [],
currentSort: '',
currentSortDir: 'asc'
}; };
}, },
computed: { computed: {
primaryField () { primaryField () {
return this.fields.filter(field => field.key === 'pri')[0] || false; return this.fields.filter(field => field.key === 'pri')[0] || false;
},
sortedResults () {
if (this.currentSort) {
return [...this.localResults].sort((a, b) => {
let modifier = 1;
const valA = typeof a[this.currentSort] === 'string' ? a[this.currentSort].toLowerCase() : a[this.currentSort];
const valB = typeof b[this.currentSort] === 'string' ? b[this.currentSort].toLowerCase() : b[this.currentSort];
if (this.currentSortDir === 'desc') modifier = -1;
if (valA < valB) return -1 * modifier;
if (valA > valB) return 1 * modifier;
return 0;
});
}
else
return this.localResults;
} }
}, },
watch: { watch: {
results () { results () {
this.resetSort();
this.localResults = this.results.rows ? this.results.rows.map(item => { this.localResults = this.results.rows ? this.results.rows.map(item => {
return { ...item, _id: uidGen() }; return { ...item, _id: uidGen() };
}) : []; }) : [];
@ -104,7 +125,7 @@ export default {
}, },
updated () { updated () {
if (this.$refs.resultTable) if (this.$refs.resultTable)
this.resizeResults(); this.refreshScroller();
}, },
mounted () { mounted () {
window.addEventListener('resize', this.resizeResults); window.addEventListener('resize', this.resizeResults);
@ -225,6 +246,22 @@ export default {
this.selectedRows = [cell.id]; this.selectedRows = [cell.id];
this.contextEvent = event; this.contextEvent = event;
this.isContext = true; this.isContext = true;
},
sort (field) {
if (field === this.currentSort) {
if (this.currentSortDir === 'asc')
this.currentSortDir = 'desc';
else
this.resetSort();
}
else {
this.currentSortDir = 'asc';
this.currentSort = field;
}
},
resetSort () {
this.currentSort = '';
this.currentSortDir = 'asc';
} }
} }
}; };
@ -237,11 +274,25 @@ export default {
overflow-anchor: none; overflow-anchor: none;
} }
.column-resizable{
&:hover,
&:active{
resize: horizontal;
overflow: hidden;
}
}
.table-column-title{ .table-column-title{
display: flex; display: flex;
align-items: center; align-items: center;
} }
.sort-icon{
font-size: .7rem;
line-height: 1;
margin-left: .2rem;
}
.column-key{ .column-key{
transform: rotate(90deg); transform: rotate(90deg);
font-size: .7rem; font-size: .7rem;

View File

@ -48,7 +48,7 @@ export default {
filters: { filters: {
cutText (val) { cutText (val) {
if (typeof val !== 'string') return val; if (typeof val !== 'string') return val;
return val.length > 50 ? `${val.substring(0, 50)}[...]` : val; return val.length > 128 ? `${val.substring(0, 128)}[...]` : val;
}, },
typeFormat (val, type, precision) { typeFormat (val, type, precision) {
if (!val) return val; if (!val) return val;
@ -167,14 +167,12 @@ export default {
border: none; border: none;
line-height: 1; line-height: 1;
width: 100%; width: 100%;
max-width: 200px;
} }
.cell-content{ .cell-content{
display: block; display: block;
min-height: .8rem; min-height: .8rem;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: 200px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }

View File

@ -40,7 +40,7 @@
</template> </template>
<script> <script>
import Structure from '@/ipc-api/Structure'; import Tables from '@/ipc-api/Tables';
import WorkspaceQueryTable from '@/components/WorkspaceQueryTable'; import WorkspaceQueryTable from '@/components/WorkspaceQueryTable';
import { mapGetters, mapActions } from 'vuex'; import { mapGetters, mapActions } from 'vuex';
import tableTabs from '@/mixins/tableTabs'; import tableTabs from '@/mixins/tableTabs';
@ -85,13 +85,13 @@ export default {
} }
}, },
watch: { watch: {
table: function () { table () {
if (this.isSelected) { if (this.isSelected) {
this.getTableData(); this.getTableData();
this.lastTable = this.table; this.lastTable = this.table;
} }
}, },
isSelected: function (val) { isSelected (val) {
if (val && this.lastTable !== this.table) { if (val && this.lastTable !== this.table) {
this.getTableData(); this.getTableData();
this.lastTable = this.table; this.lastTable = this.table;
@ -117,7 +117,7 @@ export default {
}; };
try { try {
const { status, response } = await Structure.getTableColumns(params); const { status, response } = await Tables.getTableColumns(params);
if (status === 'success') if (status === 'success')
this.fields = response.rows; this.fields = response.rows;
else else
@ -128,7 +128,7 @@ export default {
} }
try { try {
const { status, response } = await Structure.getTableData(params); const { status, response } = await Tables.getTableData(params);
if (status === 'success') if (status === 'success')
this.results = response; this.results = response;

View File

@ -1,4 +1,4 @@
import Structure from '@/ipc-api/Structure'; import Tables from '@/ipc-api/Tables';
export default { export default {
methods: { methods: {
@ -6,12 +6,12 @@ export default {
const params = { const params = {
uid: this.connection.uid, uid: this.connection.uid,
schema: this.workspace.breadcrumbs.schema, schema: this.workspace.breadcrumbs.schema,
table: this.workspace.breadcrumbs.table, table: this.table,
...payload ...payload
}; };
try { try {
const { status, response } = await Structure.updateTableCell(params); const { status, response } = await Tables.updateTableCell(params);
if (status === 'success') if (status === 'success')
this.$refs.queryTable.applyUpdate(payload); this.$refs.queryTable.applyUpdate(payload);
else else
@ -30,7 +30,7 @@ export default {
}; };
try { try {
const { status, response } = await Structure.deleteTableRows(params); const { status, response } = await Tables.deleteTableRows(params);
if (status === 'success') { if (status === 'success') {
const { primary, rows } = params; const { primary, rows } = params;
this.results = { ...this.results, rows: this.results.rows.filter(row => !rows.includes(row[primary])) }; this.results = { ...this.results, rows: this.results.rows.filter(row => !rows.includes(row[primary])) };

View File

@ -3,44 +3,41 @@
.type-#{$type} { .type-#{$type} {
color: $color; color: $color;
@if $type == 'number'{ @if $type == "number" {
text-align: right; text-align: right;
} }
} }
} }
} }
@include type-colors(( @include type-colors(
(
"char": seagreen, "char": seagreen,
"varchar": seagreen, "varchar": seagreen,
"text": seagreen, "text": seagreen,
"mediumtext": seagreen, "mediumtext": seagreen,
"longtext": seagreen, "longtext": seagreen,
"int": cornflowerblue, "int": cornflowerblue,
"tinyint": cornflowerblue, "tinyint": cornflowerblue,
"smallint": cornflowerblue, "smallint": cornflowerblue,
"mediumint": cornflowerblue, "mediumint": cornflowerblue,
"bigint": cornflowerblue, "bigint": cornflowerblue,
"datetime": coral, "datetime": coral,
"date": coral, "date": coral,
"time": coral, "time": coral,
"timestamp": coral, "timestamp": coral,
"bit": lightskyblue, "bit": lightskyblue,
"blob": darkorchid, "blob": darkorchid,
"mediumblob": darkorchid, "mediumblob": darkorchid,
"longblob": darkorchid, "longblob": darkorchid,
"unknown": gray, "unknown": gray,
)); )
);
.is-null{ .is-null {
color: gray; color: gray;
&::after{ &::after {
content: 'NULL'; content: "NULL";
} }
} }

View File

@ -1,26 +1,26 @@
.dbi{ .dbi {
display: inline-block; display: inline-block;
width: 42px; width: 42px;
height: 42px; height: 42px;
background-size: cover; background-size: cover;
&.dbi-mysql{ &.dbi-mysql {
background-image: url('../images/svg/mysql.svg'); background-image: url("../images/svg/mysql.svg");
} }
&.dbi-maria{ &.dbi-maria {
background-image: url('../images/svg/mariadb.svg'); background-image: url("../images/svg/mariadb.svg");
} }
&.dbi-mssql{ &.dbi-mssql {
background-image: url('../images/svg/mssql.svg'); background-image: url("../images/svg/mssql.svg");
} }
&.dbi-pg{ &.dbi-pg {
background-image: url('../images/svg/pg.svg'); background-image: url("../images/svg/pg.svg");
} }
&.dbi-oracledb{ &.dbi-oracledb {
background-image: url('../images/svg/oracledb.svg'); background-image: url("../images/svg/oracledb.svg");
} }
} }

View File

@ -3,6 +3,7 @@
border-spacing: 0; border-spacing: 0;
width: 100%; width: 100%;
display: table; display: table;
table-layout: fixed;
&.table-striped { &.table-striped {
.tbody { .tbody {
@ -16,8 +17,8 @@
&.table-striped { &.table-striped {
.tbody { .tbody {
.tr { .tr {
&.selected{ &.selected {
background: #333!important; background: #333 !important;
} }
&.active { &.active {
background: $bg-color-dark; background: $bg-color-dark;
@ -40,19 +41,19 @@
&.table-scroll { &.table-scroll {
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding-bottom: .75rem; padding-bottom: 0.75rem;
white-space: nowrap; white-space: nowrap;
} }
.thead{ .thead {
display: table-header-group; display: table-header-group;
} }
.tbody{ .tbody {
display: table-row-group; display: table-row-group;
} }
.tr{ .tr {
display: table-row; display: table-row;
} }
@ -65,4 +66,4 @@
.th { .th {
border-bottom-width: $border-width-lg; border-bottom-width: $border-width-lg;
} }
} }

View File

@ -1,10 +1,11 @@
.slide-fade-enter-active { .slide-fade-enter-active {
transition: all .3s ease; transition: all 0.3s ease;
} }
.slide-fade-leave-active { .slide-fade-leave-active {
transition: all .3s cubic-bezier(1.0, 0.5, 0.8, 1.0); transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
} }
.slide-fade-enter, .slide-fade-leave-to { .slide-fade-enter,
.slide-fade-leave-to {
transform: translateX(10px); transform: translateX(10px);
opacity: 0; opacity: 0;
} }

View File

@ -1,4 +1,3 @@
@import "~spectre.css/src/variables"; @import "~spectre.css/src/variables";
@import "variables"; @import "variables";
@import "transitions"; @import "transitions";
@ -9,7 +8,7 @@
@import "~spectre.css/src/spectre"; @import "~spectre.css/src/spectre";
@import "~spectre.css/src/spectre-exp"; @import "~spectre.css/src/spectre-exp";
body{ body {
user-select: none; user-select: none;
} }
@ -19,21 +18,21 @@ body{
@include padding-variant(3, $unit-3); @include padding-variant(3, $unit-3);
@include padding-variant(4, $unit-4); @include padding-variant(4, $unit-4);
.btn.btn-gray{ .btn.btn-gray {
color: #fff; color: #fff;
background: $bg-color-gray; background: $bg-color-gray;
&:hover{ &:hover {
background: $bg-color; background: $bg-color;
} }
} }
.p-vcentered{ .p-vcentered {
display: flex!important; display: flex !important;
align-items: center; align-items: center;
} }
.c-help{ .c-help {
cursor: help; cursor: help;
} }
@ -47,11 +46,11 @@ body{
background: $bg-color-light; background: $bg-color-light;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background: rgba($color: #FFF, $alpha: .5); background: rgba($color: #fff, $alpha: 0.5);
&:hover { &:hover {
background: rgba($color: #FFF, $alpha: 1); background: rgba($color: #fff, $alpha: 1);
} }
} }
@ -66,52 +65,52 @@ body{
} }
.rotate { .rotate {
animation: rotation .8s infinite linear; animation: rotation 0.8s infinite linear;
} }
/*Override*/ /*Override*/
.modal{ .modal {
.modal-overlay, .modal-overlay,
&.active .modal-overlay{ &.active .modal-overlay {
background: rgba(255, 255, 255, 0.15); background: rgba(255, 255, 255, 0.15);
} }
.modal-sm .modal-container, .modal-sm .modal-container,
.modal-container{ .modal-container {
box-shadow: 0 0 1px 0px #000; box-shadow: 0 0 1px 0px #000;
padding: 0; padding: 0;
background: $bg-color; background: $bg-color;
.modal-header{ .modal-header {
padding: .4rem .8rem; padding: 0.4rem 0.8rem;
text-transform: uppercase; text-transform: uppercase;
background: $bg-color-gray; background: $bg-color-gray;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
color: #FFF; color: #fff;
} }
} }
} }
.tab{ .tab {
border-color: #272727; border-color: #272727;
} }
.panel{ .panel {
border: none; border: none;
} }
.badge{ .badge {
&[data-badge], &[data-badge],
&:not([data-badge]){ &:not([data-badge]) {
&::after { &::after {
box-shadow: none; box-shadow: none;
} }
} }
} }
.form-select{ .form-select {
cursor: pointer; cursor: pointer;
} }
@ -119,32 +118,31 @@ body{
.form-select:not([multiple]):not([size]), .form-select:not([multiple]):not([size]),
.form-input, .form-input,
.form-checkbox .form-icon, .form-checkbox .form-icon,
.form-radio .form-icon{ .form-radio .form-icon {
border-color: $bg-color-light; border-color: $bg-color-light;
background: $bg-color-gray; background: $bg-color-gray;
} }
.form-select:not([multiple]):not([size]):focus{ .form-select:not([multiple]):not([size]):focus {
border-color: $primary-color; border-color: $primary-color;
} }
.menu{ .menu {
font-size: .7rem; font-size: 0.7rem;
.menu-item { .menu-item {
+ .menu-item{ + .menu-item {
margin-top: 0; margin-top: 0;
} }
} }
} }
.accordion-body { .accordion-body {
max-height: 500rem!important; max-height: 500rem !important;
} }
.btn.loading { .btn.loading {
> .material-icons, > .material-icons,
> span{ > span {
visibility: hidden; visibility: hidden;
} }
} }