2021-03-03 19:31:05 +01:00
|
|
|
<template>
|
|
|
|
<div class="modal active">
|
|
|
|
<a class="modal-overlay" @click.stop="closeModal" />
|
2021-03-04 19:34:18 +01:00
|
|
|
<div class="modal-container p-0 pb-4">
|
2021-03-03 19:31:05 +01:00
|
|
|
<div class="modal-header pl-2">
|
|
|
|
<div class="modal-title h6">
|
|
|
|
<div class="d-flex">
|
2021-06-13 11:16:21 +02:00
|
|
|
<i class="mdi mdi-24px mdi-memory mr-1" />
|
|
|
|
<span class="cut-text">{{ $t('message.processesList') }}: {{ connectionName }}</span>
|
2021-03-03 19:31:05 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
|
|
|
</div>
|
|
|
|
<div class="processes-toolbar py-2 px-4">
|
|
|
|
<div class="dropdown">
|
|
|
|
<div class="btn-group">
|
|
|
|
<button
|
|
|
|
class="btn btn-dark btn-sm mr-0 pr-1 d-flex"
|
|
|
|
:class="{'loading':isQuering}"
|
|
|
|
title="F5"
|
|
|
|
@click="getProcessesList"
|
|
|
|
>
|
2021-07-29 16:45:28 +02:00
|
|
|
<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" />
|
2021-03-03 19:31:05 +01:00
|
|
|
<span>{{ $t('word.refresh') }}</span>
|
|
|
|
</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"
|
2021-03-05 17:23:13 +01:00
|
|
|
max="15"
|
2021-03-04 19:34:18 +01:00
|
|
|
step="0.5"
|
2021-03-03 19:31:05 +01:00
|
|
|
@change="setRefreshInterval"
|
|
|
|
>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="workspace-query-info">
|
|
|
|
<div v-if="sortedResults.length">
|
2021-03-04 19:34:18 +01:00
|
|
|
{{ $t('word.processes') }}: <b>{{ sortedResults.length.toLocaleString() }}</b>
|
2021-03-03 19:31:05 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-03-04 19:34:18 +01:00
|
|
|
<div class="modal-body py-0 workspace-query-results">
|
|
|
|
<div
|
|
|
|
ref="tableWrapper"
|
|
|
|
class="vscroll"
|
|
|
|
:style="{'height': resultsSize+'px'}"
|
|
|
|
>
|
2021-03-03 19:31:05 +01:00
|
|
|
<div ref="table" class="table table-hover">
|
|
|
|
<div class="thead">
|
|
|
|
<div class="tr">
|
|
|
|
<div
|
|
|
|
v-for="(field, index) in fields"
|
|
|
|
:key="index"
|
|
|
|
class="th c-hand"
|
|
|
|
>
|
|
|
|
<div ref="columnResize" class="column-resizable">
|
|
|
|
<div class="table-column-title" @click="sort(field)">
|
|
|
|
<span>{{ field.toUpperCase() }}</span>
|
|
|
|
<i
|
|
|
|
v-if="currentSort === field"
|
|
|
|
class="mdi sort-icon"
|
|
|
|
:class="currentSortDir === 'asc' ? 'mdi-sort-ascending':'mdi-sort-descending'"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<BaseVirtualScroll
|
|
|
|
ref="resultTable"
|
|
|
|
:items="sortedResults"
|
|
|
|
:item-height="22"
|
|
|
|
class="tbody"
|
|
|
|
:visible-height="resultsSize"
|
|
|
|
:scroll-element="scrollElement"
|
|
|
|
>
|
|
|
|
<template slot-scope="{ items }">
|
|
|
|
<ProcessesListRow
|
|
|
|
v-for="row in items"
|
|
|
|
:key="row._id"
|
|
|
|
class="process-row"
|
|
|
|
:row="row"
|
|
|
|
@contextmenu="contextMenu"
|
2021-03-04 19:34:18 +01:00
|
|
|
@stop-refresh="stopRefresh"
|
2021-03-03 19:31:05 +01:00
|
|
|
/>
|
|
|
|
</template>
|
|
|
|
</BaseVirtualScroll>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import { mapGetters, mapActions } from 'vuex';
|
2021-03-17 11:15:14 +01:00
|
|
|
import Schema from '@/ipc-api/Schema';
|
2021-03-03 19:31:05 +01:00
|
|
|
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
|
|
|
import ProcessesListRow from '@/components/ProcessesListRow';
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'ModalProcessesList',
|
|
|
|
components: {
|
|
|
|
BaseVirtualScroll,
|
|
|
|
ProcessesListRow
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
connection: Object
|
|
|
|
},
|
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
resultsSize: 1000,
|
|
|
|
isQuering: false,
|
|
|
|
autorefreshTimer: 0,
|
|
|
|
refreshInterval: null,
|
|
|
|
results: [],
|
|
|
|
fields: [],
|
|
|
|
currentSort: '',
|
|
|
|
currentSortDir: 'asc',
|
|
|
|
scrollElement: null
|
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
...mapGetters({
|
|
|
|
getConnectionName: 'connections/getConnectionName'
|
|
|
|
}),
|
|
|
|
connectionName () {
|
|
|
|
return this.getConnectionName(this.connection.uid);
|
|
|
|
},
|
|
|
|
sortedResults () {
|
|
|
|
if (this.currentSort) {
|
|
|
|
return [...this.results].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.results;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
created () {
|
|
|
|
window.addEventListener('keydown', this.onKey, { capture: true });
|
|
|
|
},
|
|
|
|
updated () {
|
|
|
|
if (this.$refs.table)
|
|
|
|
this.refreshScroller();
|
|
|
|
|
|
|
|
if (this.$refs.tableWrapper)
|
|
|
|
this.scrollElement = this.$refs.tableWrapper;
|
|
|
|
},
|
|
|
|
mounted () {
|
|
|
|
this.getProcessesList();
|
|
|
|
window.addEventListener('resize', this.resizeResults);
|
|
|
|
},
|
|
|
|
beforeDestroy () {
|
|
|
|
window.removeEventListener('keydown', this.onKey, { capture: true });
|
|
|
|
window.removeEventListener('resize', this.resizeResults);
|
|
|
|
clearInterval(this.refreshInterval);
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
...mapActions({
|
|
|
|
addNotification: 'notifications/addNotification'
|
|
|
|
}),
|
|
|
|
async getProcessesList () {
|
|
|
|
this.isQuering = true;
|
|
|
|
|
|
|
|
// if table changes clear cached values
|
|
|
|
if (this.lastTable !== this.table)
|
|
|
|
this.results = [];
|
|
|
|
|
|
|
|
try { // Table data
|
2021-03-17 11:15:14 +01:00
|
|
|
const { status, response } = await Schema.getProcesses(this.connection.uid);
|
2021-03-03 19:31:05 +01:00
|
|
|
|
|
|
|
if (status === 'success') {
|
|
|
|
this.results = response;
|
|
|
|
this.fields = response.length ? Object.keys(response[0]) : [];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
this.addNotification({ status: 'error', message: response });
|
|
|
|
}
|
|
|
|
catch (err) {
|
|
|
|
this.addNotification({ status: 'error', message: err.stack });
|
|
|
|
}
|
|
|
|
|
|
|
|
this.isQuering = false;
|
|
|
|
},
|
|
|
|
setRefreshInterval () {
|
|
|
|
this.clearRefresh();
|
|
|
|
|
|
|
|
if (+this.autorefreshTimer) {
|
|
|
|
this.refreshInterval = setInterval(() => {
|
|
|
|
if (!this.isQuering)
|
|
|
|
this.getProcessesList();
|
|
|
|
}, this.autorefreshTimer * 1000);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
clearRefresh () {
|
|
|
|
if (this.refreshInterval)
|
|
|
|
clearInterval(this.refreshInterval);
|
|
|
|
},
|
|
|
|
resizeResults () {
|
|
|
|
if (this.$refs.resultTable) {
|
2021-03-04 19:34:18 +01:00
|
|
|
const el = this.$refs.tableWrapper.parentElement;
|
2021-03-03 19:31:05 +01:00
|
|
|
|
|
|
|
if (el) {
|
|
|
|
const size = el.offsetHeight;
|
|
|
|
this.resultsSize = size;
|
|
|
|
}
|
|
|
|
this.$refs.resultTable.updateWindow();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
refreshScroller () {
|
|
|
|
this.resizeResults();
|
|
|
|
},
|
|
|
|
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';
|
|
|
|
},
|
2021-03-04 19:34:18 +01:00
|
|
|
stopRefresh () {
|
2021-03-03 19:31:05 +01:00
|
|
|
this.autorefreshTimer = 0;
|
|
|
|
this.clearRefresh();
|
|
|
|
},
|
|
|
|
contextMenu () {},
|
|
|
|
closeModal () {
|
|
|
|
this.$emit('close');
|
|
|
|
},
|
|
|
|
onKey (e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
if (e.key === 'Escape')
|
|
|
|
this.closeModal();
|
|
|
|
if (e.key === 'F5')
|
|
|
|
this.getProcessesList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.vscroll {
|
|
|
|
height: 1000px;
|
|
|
|
overflow: auto;
|
|
|
|
overflow-anchor: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.column-resizable {
|
|
|
|
&:hover,
|
|
|
|
&:active {
|
|
|
|
resize: horizontal;
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.table-column-title {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
.sort-icon {
|
|
|
|
font-size: 0.7rem;
|
|
|
|
line-height: 1;
|
|
|
|
margin-left: 0.2rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
.result-tabs {
|
|
|
|
background: transparent !important;
|
|
|
|
margin: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.modal {
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
|
|
.modal-container {
|
|
|
|
max-width: 75vw;
|
|
|
|
margin-top: 10vh;
|
2021-03-05 17:23:13 +01:00
|
|
|
|
|
|
|
.modal-body {
|
|
|
|
height: 80vh;
|
|
|
|
}
|
2021-03-03 19:31:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.processes-toolbar {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
}
|
|
|
|
</style>
|