antares/src/renderer/components/WorkspaceTabTable.vue

463 lines
15 KiB
Vue
Raw Normal View History

2020-06-12 18:10:45 +02:00
<template>
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless no-outline p-0">
2020-06-12 18:10:45 +02:00
<div class="workspace-query-runner column col-12">
<div class="workspace-query-runner-footer">
<div class="workspace-query-buttons">
<div class="dropdown">
<div class="btn-group">
<button
class="btn btn-dark btn-sm mr-0 pr-1"
:class="{'loading':isQuering}"
:title="`${$t('word.refresh')} (F5)`"
@click="reloadTable"
>
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh mr-1" />
<i v-else class="mdi mdi-24px mdi-history mdi-flip-h mr-1" />
</button>
<div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
<i class="mdi mdi-24px mdi-menu-down" />
</div>
<div class="menu px-3">
<span>{{ $t('word.autoRefresh') }}: <b>{{ +autorefreshTimer ? `${autorefreshTimer}s` : 'OFF' }}</b></span>
<input
v-model="autorefreshTimer"
class="slider no-border"
type="range"
min="0"
max="30"
step="1"
@change="setRefreshInterval"
>
</div>
</div>
</div>
<div class="btn-group">
<button
class="btn btn-dark btn-sm mr-0"
:disabled="isQuering || page === 1"
title="CTRL+ᐊ"
@click="pageChange('prev')"
>
<i class="mdi mdi-24px mdi-skip-previous" />
</button>
<div class="dropdown" :class="{'active': isPageMenu}">
<div @click="openPageMenu">
<div class="btn btn-dark btn-sm mr-0 no-radius dropdown-toggle text-bold px-3">
{{ page }}
</div>
<div class="menu px-3">
<span>{{ $t('message.pageNumber') }}</span>
<input
ref="pageSelect"
v-model="pageProxy"
type="number"
min="1"
class="form-input"
@blur="setPageNumber"
>
</div>
</div>
</div>
<button
class="btn btn-dark btn-sm mr-0"
:disabled="isQuering || (results.length && results[0].rows.length < limit)"
title="CTRL+ᐅ"
@click="pageChange('next')"
>
<i class="mdi mdi-24px mdi-skip-next" />
</button>
</div>
<div class="divider-vert py-3" />
2021-10-17 23:54:00 +02:00
<button
class="btn btn-sm"
:title="`${$t('word.filter')} (CTRL+F)`"
2021-10-17 23:54:00 +02:00
:class="{'btn-primary': isSearch, 'btn-dark': !isSearch}"
@click="isSearch = !isSearch"
>
<i class="mdi mdi-24px mdi-magnify" />
</button>
<button
v-if="isTable"
class="btn btn-dark btn-sm"
:disabled="isQuering"
@click="showFakerModal"
>
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
2022-02-11 23:19:43 +01:00
<span>{{ $tc('message.insertRow', 2) }}</span>
</button>
2021-02-13 18:45:16 +01:00
2021-06-29 23:31:18 +02:00
<div class="dropdown table-dropdown pr-2">
<button
:disabled="isQuering"
class="btn btn-dark btn-sm dropdown-toggle mr-0 pr-0"
tabindex="0"
>
<i class="mdi mdi-24px mdi-file-export mr-1" />
<span>{{ $t('word.export') }}</span>
<i class="mdi mdi-24px mdi-menu-down" />
</button>
<ul class="menu text-left">
<li class="menu-item">
<a class="c-hand" @click="downloadTable('json')">JSON</a>
</li>
<li class="menu-item">
<a class="c-hand" @click="downloadTable('csv')">CSV</a>
</li>
</ul>
</div>
2020-06-12 18:10:45 +02:00
</div>
<div class="workspace-query-info">
2021-02-26 18:45:00 +01:00
<div
v-if="results.length"
class="d-flex"
:title="$t('message.queryDuration')"
>
<i class="mdi mdi-timer-sand mdi-rotate-180 pr-1" /> <b>{{ results[0].duration / 1000 }}s</b>
</div>
2020-09-14 12:49:09 +02:00
<div v-if="results.length && results[0].rows">
2022-04-21 14:39:24 +02:00
{{ $t('word.results') }}: <b>{{ localeString(results[0].rows.length) }}</b>
</div>
<div v-if="hasApproximately || (page > 1 && approximateCount)">
{{ $t('word.total') }}: <b
:title="!customizations.tableRealCount ? $t('word.approximately') : ''"
>
<span v-if="!customizations.tableRealCount"></span>
2022-04-21 14:39:24 +02:00
{{ localeString(approximateCount) }}
</b>
2020-06-12 18:10:45 +02:00
</div>
2021-07-14 12:31:12 +02:00
<div class="d-flex" :title="$t('word.schema')">
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
2020-06-12 18:10:45 +02:00
</div>
</div>
</div>
</div>
2021-10-17 23:54:00 +02:00
<WorkspaceTabTableFilters
v-if="isSearch"
:fields="fields"
:conn-client="connection.client"
2021-10-17 23:54:00 +02:00
@filter="updateFilters"
@filter-change="onFilterChange"
2021-10-17 23:54:00 +02:00
/>
<div class="workspace-query-results p-relative column col-12">
<BaseLoader v-if="isQuering" />
2021-08-12 09:54:13 +02:00
<WorkspaceTabQueryTable
2020-06-16 18:01:22 +02:00
v-if="results"
2020-06-28 15:31:16 +02:00
ref="queryTable"
:results="results"
:tab-uid="tabUid"
:conn-uid="connection.uid"
:is-selected="isSelected"
mode="table"
:element-type="elementType"
@update-field="updateField"
@delete-selected="deleteSelected"
2020-12-07 17:51:48 +01:00
@hard-sort="hardSort"
2020-06-16 18:01:22 +02:00
/>
2020-06-12 18:10:45 +02:00
</div>
2020-08-12 18:12:30 +02:00
<ModalNewTableRow
v-if="isAddModal"
:fields="fields"
:key-usage="keyUsage"
:tab-uid="tabUid"
2020-08-12 18:12:30 +02:00
@hide="hideAddModal"
@reload="reloadTable"
/>
2021-02-13 18:45:16 +01:00
<ModalFakerRows
v-if="isFakerModal"
:fields="fields"
:key-usage="keyUsage"
:tab-uid="tabUid"
@hide="hideFakerModal"
@reload="reloadTable"
/>
2020-06-12 18:10:45 +02:00
</div>
</template>
<script>
2020-07-24 13:26:56 +02:00
import Tables from '@/ipc-api/Tables';
import BaseLoader from '@/components/BaseLoader';
2021-08-12 09:54:13 +02:00
import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable';
2021-10-17 23:54:00 +02:00
import WorkspaceTabTableFilters from '@/components/WorkspaceTabTableFilters';
2020-08-12 18:12:30 +02:00
import ModalNewTableRow from '@/components/ModalNewTableRow';
2021-02-13 18:45:16 +01:00
import ModalFakerRows from '@/components/ModalFakerRows';
2020-06-12 18:10:45 +02:00
import { mapGetters, mapActions } from 'vuex';
2020-07-23 19:10:14 +02:00
import tableTabs from '@/mixins/tableTabs';
2020-06-12 18:10:45 +02:00
export default {
2021-08-12 09:54:13 +02:00
name: 'WorkspaceTabTable',
2020-06-12 18:10:45 +02:00
components: {
BaseLoader,
2021-08-12 09:54:13 +02:00
WorkspaceTabQueryTable,
2021-10-17 23:54:00 +02:00
WorkspaceTabTableFilters,
2021-02-13 18:45:16 +01:00
ModalNewTableRow,
ModalFakerRows
2020-06-12 18:10:45 +02:00
},
2020-07-23 19:10:14 +02:00
mixins: [tableTabs],
2020-06-12 18:10:45 +02:00
props: {
connection: Object,
isSelected: Boolean,
table: String,
schema: String,
elementType: String
2020-06-12 18:10:45 +02:00
},
data () {
return {
2021-07-13 19:23:02 +02:00
tabUid: 'data', // ???
2020-06-12 18:10:45 +02:00
isQuering: false,
isPageMenu: false,
2021-10-17 23:54:00 +02:00
isSearch: false,
results: [],
lastTable: null,
isAddModal: false,
2021-02-13 18:45:16 +01:00
isFakerModal: false,
autorefreshTimer: 0,
refreshInterval: null,
sortParams: {},
2021-10-17 23:54:00 +02:00
filters: [],
page: 1,
pageProxy: 1,
approximateCount: 0
2020-06-12 18:10:45 +02:00
};
},
computed: {
...mapGetters({
getWorkspace: 'workspaces/getWorkspace',
selectedWorkspace: 'workspaces/getSelected',
limit: 'settings/getDataTabLimit'
2020-06-12 18:10:45 +02:00
}),
workspace () {
return this.getWorkspace(this.connection.uid);
},
customizations () {
return this.workspace.customizations;
},
isTable () {
return !!this.workspace.breadcrumbs.table;
},
fields () {
return this.results.length ? this.results[0].fields : [];
},
keyUsage () {
return this.results.length ? this.results[0].keys : [];
},
tableInfo () {
2020-12-03 16:15:10 +01:00
try {
return this.workspace.structure.find(db => db.name === this.schema).tables.find(table => table.name === this.table);
}
catch (err) {
return { rows: 0 };
}
},
hasApproximately () {
return this.results.length &&
this.results[0].rows &&
this.results[0].rows.length === this.limit &&
this.results[0].rows.length < this.approximateCount;
2020-06-12 18:10:45 +02:00
}
},
watch: {
2021-07-13 16:53:47 +02:00
schema () {
if (this.isSelected) {
this.page = 1;
this.approximateCount = 0;
2021-07-13 16:53:47 +02:00
this.sortParams = {};
this.getTableData();
this.lastTable = this.table;
this.$refs.queryTable.resetSort();
}
},
2020-07-24 13:26:56 +02:00
table () {
2020-06-13 18:14:32 +02:00
if (this.isSelected) {
this.page = 1;
this.approximateCount = 0;
this.sortParams = {};
2020-06-15 18:23:51 +02:00
this.getTableData();
2020-06-13 18:14:32 +02:00
this.lastTable = this.table;
2020-12-07 17:51:48 +01:00
this.$refs.queryTable.resetSort();
2020-06-13 18:14:32 +02:00
}
},
page (val, oldVal) {
if (val && val > 0 && val !== oldVal) {
this.pageProxy = this.page;
this.getTableData();
}
},
2020-07-24 13:26:56 +02:00
isSelected (val) {
if (val) {
this.changeBreadcrumbs({ schema: this.schema, [this.elementType]: this.table });
if (this.lastTable !== this.table)
this.getTableData();
2020-06-13 18:14:32 +02:00
}
2021-10-17 23:54:00 +02:00
},
isSearch (val) {
if (this.filters.length > 0 && !val) {
this.filters = [];
this.getTableData();
}
this.resizeScroller();
2020-06-12 18:10:45 +02:00
}
},
created () {
2020-06-15 18:23:51 +02:00
this.getTableData();
window.addEventListener('keydown', this.onKey);
},
2022-04-21 14:39:24 +02:00
beforeUnmount () {
window.removeEventListener('keydown', this.onKey);
clearInterval(this.refreshInterval);
2020-06-12 18:10:45 +02:00
},
methods: {
...mapActions({
addNotification: 'notifications/addNotification',
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
2020-06-12 18:10:45 +02:00
}),
async getTableData () {
if (!this.table || !this.isSelected) return;
2020-06-12 18:10:45 +02:00
this.isQuering = true;
2020-10-07 20:42:04 +02:00
// if table changes clear cached values
if (this.lastTable !== this.table)
2020-10-07 20:42:04 +02:00
this.results = [];
2020-06-12 18:10:45 +02:00
this.lastTable = this.table;
2020-06-12 18:10:45 +02:00
const params = {
uid: this.connection.uid,
schema: this.schema,
table: this.table,
limit: this.limit,
page: this.page,
2022-04-21 14:39:24 +02:00
sortParams: { ...this.sortParams },
where: [...this.filters] || []
2020-06-12 18:10:45 +02:00
};
2020-10-07 20:42:04 +02:00
try { // Table data
const { status, response } = await Tables.getTableData(params);
2020-10-07 20:42:04 +02:00
if (status === 'success')
this.results = [response];
else
this.addNotification({ status: 'error', message: response });
2020-06-12 18:10:45 +02:00
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
if (this.results.length && this.results[0].rows.length === this.limit) {
try { // Table approximate count
const { status, response } = await Tables.getTableApproximateCount(params);
if (status === 'success')
this.approximateCount = response;
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
}
2020-06-12 18:10:45 +02:00
this.isQuering = false;
},
getTable () {
return this.table;
},
reloadTable () {
this.getTableData();
},
2020-12-07 17:51:48 +01:00
hardSort (sortParams) {
this.sortParams = sortParams;
this.getTableData();
2020-12-07 17:51:48 +01:00
},
openPageMenu () {
if (this.isQuering || (this.results.length && this.results[0].rows.length < this.limit && this.page === 1)) return;
this.isPageMenu = true;
if (this.isPageMenu)
setTimeout(() => this.$refs.pageSelect.focus(), 20);
},
setPageNumber () {
this.isPageMenu = false;
if (this.pageProxy > 0)
this.page = this.pageProxy;
else
this.pageProxy = this.page;
},
pageChange (direction) {
if (this.isQuering) return;
if (direction === 'next' && (this.results.length && this.results[0].rows.length === this.limit)) {
if (!this.page)
this.page = 2;
else
this.page++;
}
else if (direction === 'prev' && this.page > 1)
this.page--;
},
showAddModal () {
this.isAddModal = true;
},
hideAddModal () {
this.isAddModal = false;
},
2021-02-13 18:45:16 +01:00
showFakerModal () {
if (this.isQuering) return;
2021-02-13 18:45:16 +01:00
this.isFakerModal = true;
},
hideFakerModal () {
this.isFakerModal = false;
},
onKey (e) {
2020-11-13 12:39:40 +01:00
if (this.isSelected) {
e.stopPropagation();
if (e.key === 'F5')
this.reloadTable();
2021-10-17 23:54:00 +02:00
if (e.ctrlKey || e.metaKey) {
if (e.key === 'ArrowRight')
this.pageChange('next');
if (e.key === 'ArrowLeft')
this.pageChange('prev');
2021-10-17 23:54:00 +02:00
if (e.keyCode === 70) // f
this.isSearch = !this.isSearch;
}
}
},
setRefreshInterval () {
if (this.refreshInterval)
clearInterval(this.refreshInterval);
if (+this.autorefreshTimer) {
this.refreshInterval = setInterval(() => {
if (!this.isQuering)
this.reloadTable();
}, this.autorefreshTimer * 1000);
}
},
downloadTable (format) {
this.$refs.queryTable.downloadTable(format, this.table);
2021-10-17 23:54:00 +02:00
},
onFilterChange (clausoles) {
this.resizeScroller();
if (clausoles.length === 0)
this.isSearch = false;
},
resizeScroller () {
setTimeout(() => this.$refs.queryTable.refreshScroller(), 1);
},
2021-10-17 23:54:00 +02:00
updateFilters (clausoles) {
this.filters = clausoles;
this.getTableData();
2022-04-21 14:39:24 +02:00
},
localeString (val) {
if (val !== null)
return val.toLocaleString();
}
2020-06-12 18:10:45 +02:00
}
};
</script>