feat: copy cell/row or kill connections on context menu from processes list

This commit is contained in:
Fabio Di Stasio 2021-09-26 11:19:48 +02:00
parent 7de3bb9346
commit 85f625daf7
8 changed files with 168 additions and 28 deletions

View File

@ -112,6 +112,17 @@ export default connections => {
}
});
ipcMain.handle('kill-process', async (event, { uid, pid }) => {
try {
const result = await connections[uid].killProcess(pid);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('use-schema', async (event, { uid, schema }) => {
if (!schema) return;

View File

@ -1176,6 +1176,10 @@ export class MySQLClient extends AntaresCore {
});
}
async killProcess (id) {
return await this.raw(`KILL ${id}`);
}
/**
* CREATE TABLE
*

View File

@ -1029,6 +1029,10 @@ export class PostgreSQLClient extends AntaresCore {
});
}
async killProcess (id) {
return await this.raw(`SELECT pg_terminate_backend(${id})`);
}
/**
* CREATE TABLE
*

View File

@ -1,5 +1,15 @@
<template>
<div class="modal active">
<ModalProcessesListContext
v-if="isContext"
:context-event="contextEvent"
:selected-row="selectedRow"
:selected-cell="selectedCell"
@copy-cell="copyCell"
@copy-row="copyRow"
@kill-process="killProcess"
@close-context="closeContext"
/>
<a class="modal-overlay" @click.stop="closeModal" />
<div class="modal-container p-0 pb-4">
<div class="modal-header pl-2">
@ -85,9 +95,10 @@
<template slot-scope="{ items }">
<ModalProcessesListRow
v-for="row in items"
:key="row._id"
:key="row.id"
class="process-row"
:row="row"
@select-row="selectRow(row.id)"
@contextmenu="contextMenu"
@stop-refresh="stopRefresh"
/>
@ -105,12 +116,14 @@ import { mapGetters, mapActions } from 'vuex';
import Schema from '@/ipc-api/Schema';
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
import ModalProcessesListRow from '@/components/ModalProcessesListRow';
import ModalProcessesListContext from '@/components/ModalProcessesListContext';
export default {
name: 'ModalProcessesList',
components: {
BaseVirtualScroll,
ModalProcessesListRow
ModalProcessesListRow,
ModalProcessesListContext
},
props: {
connection: Object
@ -119,8 +132,12 @@ export default {
return {
resultsSize: 1000,
isQuering: false,
isContext: false,
autorefreshTimer: 0,
refreshInterval: null,
contextEvent: null,
selectedCell: null,
selectedRow: null,
results: [],
fields: [],
currentSort: '',
@ -245,7 +262,44 @@ export default {
this.autorefreshTimer = 0;
this.clearRefresh();
},
contextMenu () {},
selectRow (row) {
this.selectedRow = row;
},
contextMenu (event, cell) {
if (event.target.localName === 'input') return;
this.stopRefresh();
this.selectedCell = cell;
this.selectedRow = cell.id;
this.contextEvent = event;
this.isContext = true;
},
async killProcess () {
try { // Table data
const { status, response } = await Schema.killProcess({ uid: this.connection.uid, pid: this.selectedRow });
if (status === 'success')
this.getProcessesList();
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
},
closeContext () {
this.isContext = false;
},
copyCell () {
const row = this.results.find(row => row.id === this.selectedRow);
const valueToCopy = row[this.selectedCell.field];
navigator.clipboard.writeText(valueToCopy);
},
copyRow () {
const row = this.results.find(row => row.id === this.selectedRow);
const rowToCopy = JSON.parse(JSON.stringify(row));
navigator.clipboard.writeText(JSON.stringify(rowToCopy));
},
closeModal () {
this.$emit('close');
},

View File

@ -0,0 +1,75 @@
<template>
<BaseContextMenu
:context-event="contextEvent"
@close-context="closeContext"
>
<div v-if="selectedRow" class="context-element">
<span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ $t('word.copy') }}</span>
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
<div class="context-submenu">
<div
v-if="selectedRow"
class="context-element"
@click="copyCell"
>
<span class="d-flex">
<i class="mdi mdi-18px mdi-numeric-0 mdi-rotate-90 text-light pr-1" /> {{ $tc('word.cell', 1) }}
</span>
</div>
<div
v-if="selectedRow"
class="context-element"
@click="copyRow"
>
<span class="d-flex">
<i class="mdi mdi-18px mdi-table-row text-light pr-1" /> {{ $tc('word.row', 1) }}
</span>
</div>
</div>
</div>
<div
v-if="selectedRow"
class="context-element"
@click="killProcess"
>
<span class="d-flex">
<i class="mdi mdi-18px mdi-close-circle-outline text-light pr-1" /> {{ $t('message.killProcess') }}
</span>
</div>
</BaseContextMenu>
</template>
<script>
import BaseContextMenu from '@/components/BaseContextMenu';
export default {
name: 'ModalProcessesListContext',
components: {
BaseContextMenu
},
props: {
contextEvent: MouseEvent,
selectedRow: Number,
selectedCell: Object
},
computed: {
},
methods: {
closeContext () {
this.$emit('close-context');
},
copyCell () {
this.$emit('copy-cell');
this.closeContext();
},
copyRow () {
this.$emit('copy-row');
this.closeContext();
},
killProcess () {
this.$emit('kill-process');
this.closeContext();
}
}
};
</script>

View File

@ -1,21 +1,18 @@
<template>
<div class="tr" @click="selectRow($event, row._id)">
<div class="tr" @click="selectRow()">
<div
v-for="(col, cKey) in row"
v-show="cKey !== '_id'"
:key="cKey"
class="td p-0"
tabindex="0"
@contextmenu.prevent="openContext($event, { id: row._id, field: cKey })"
@contextmenu.prevent="openContext($event, { id: row.id, field: cKey })"
>
<template v-if="cKey !== '_id'">
<span
v-if="!isInlineEditor[cKey]"
class="cell-content"
:class="`${isNull(col)} type-${typeof col === 'number' ? 'int' : 'varchar'}`"
@dblclick="dblClick(cKey)"
>{{ col | cutText }}</span>
</template>
<span
v-if="!isInlineEditor[cKey]"
class="cell-content"
:class="`${isNull(col)} type-${typeof col === 'number' ? 'int' : 'varchar'}`"
@dblclick="dblClick(cKey)"
>{{ col | cutText }}</span>
</div>
<ConfirmModal
v-if="isInfoModal"
@ -73,25 +70,15 @@ export default {
};
},
computed: {},
watch: {
fields () {
Object.keys(this.fields).forEach(field => {
this.isInlineEditor[field.name] = false;
});
}
},
methods: {
isNull (value) {
return value === null ? ' is-null' : '';
},
selectRow (event, row) {
this.$emit('select-row', event, row);
selectRow () {
this.$emit('select-row');
},
openContext (event, payload) {
if (this.isEditable) {
payload.field = this.fields[payload.field].name;// Ensures field name only
this.$emit('contextmenu', event, payload);
}
this.$emit('contextmenu', event, payload);
},
hideInfoModal () {
this.isInfoModal = false;

View File

@ -242,7 +242,8 @@ module.exports = {
newScheduler: 'New scheduler',
newTriggerFunction: 'New trigger function',
thereIsNoQueriesYet: 'There is no queries yet',
searchForQueries: 'Search for queries'
searchForQueries: 'Search for queries',
killProcess: 'Kill process'
},
faker: {
address: 'Address',

View File

@ -42,6 +42,10 @@ export default class {
return ipcRenderer.invoke('get-processes', uid);
}
static killProcess (params) {
return ipcRenderer.invoke('kill-process', params);
}
static useSchema (params) {
return ipcRenderer.invoke('use-schema', params);
}