1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-02-26 08:27:43 +01:00

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 }) => { ipcMain.handle('use-schema', async (event, { uid, schema }) => {
if (!schema) return; 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 * 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 * CREATE TABLE
* *

View File

@ -1,5 +1,15 @@
<template> <template>
<div class="modal active"> <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" /> <a class="modal-overlay" @click.stop="closeModal" />
<div class="modal-container p-0 pb-4"> <div class="modal-container p-0 pb-4">
<div class="modal-header pl-2"> <div class="modal-header pl-2">
@ -85,9 +95,10 @@
<template slot-scope="{ items }"> <template slot-scope="{ items }">
<ModalProcessesListRow <ModalProcessesListRow
v-for="row in items" v-for="row in items"
:key="row._id" :key="row.id"
class="process-row" class="process-row"
:row="row" :row="row"
@select-row="selectRow(row.id)"
@contextmenu="contextMenu" @contextmenu="contextMenu"
@stop-refresh="stopRefresh" @stop-refresh="stopRefresh"
/> />
@ -105,12 +116,14 @@ import { mapGetters, mapActions } from 'vuex';
import Schema from '@/ipc-api/Schema'; import Schema from '@/ipc-api/Schema';
import BaseVirtualScroll from '@/components/BaseVirtualScroll'; import BaseVirtualScroll from '@/components/BaseVirtualScroll';
import ModalProcessesListRow from '@/components/ModalProcessesListRow'; import ModalProcessesListRow from '@/components/ModalProcessesListRow';
import ModalProcessesListContext from '@/components/ModalProcessesListContext';
export default { export default {
name: 'ModalProcessesList', name: 'ModalProcessesList',
components: { components: {
BaseVirtualScroll, BaseVirtualScroll,
ModalProcessesListRow ModalProcessesListRow,
ModalProcessesListContext
}, },
props: { props: {
connection: Object connection: Object
@ -119,8 +132,12 @@ export default {
return { return {
resultsSize: 1000, resultsSize: 1000,
isQuering: false, isQuering: false,
isContext: false,
autorefreshTimer: 0, autorefreshTimer: 0,
refreshInterval: null, refreshInterval: null,
contextEvent: null,
selectedCell: null,
selectedRow: null,
results: [], results: [],
fields: [], fields: [],
currentSort: '', currentSort: '',
@ -245,7 +262,44 @@ export default {
this.autorefreshTimer = 0; this.autorefreshTimer = 0;
this.clearRefresh(); 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 () { closeModal () {
this.$emit('close'); 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> <template>
<div class="tr" @click="selectRow($event, row._id)"> <div class="tr" @click="selectRow()">
<div <div
v-for="(col, cKey) in row" v-for="(col, cKey) in row"
v-show="cKey !== '_id'"
:key="cKey" :key="cKey"
class="td p-0" class="td p-0"
tabindex="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 <span
v-if="!isInlineEditor[cKey]" v-if="!isInlineEditor[cKey]"
class="cell-content" class="cell-content"
:class="`${isNull(col)} type-${typeof col === 'number' ? 'int' : 'varchar'}`" :class="`${isNull(col)} type-${typeof col === 'number' ? 'int' : 'varchar'}`"
@dblclick="dblClick(cKey)" @dblclick="dblClick(cKey)"
>{{ col | cutText }}</span> >{{ col | cutText }}</span>
</template>
</div> </div>
<ConfirmModal <ConfirmModal
v-if="isInfoModal" v-if="isInfoModal"
@ -73,25 +70,15 @@ export default {
}; };
}, },
computed: {}, computed: {},
watch: {
fields () {
Object.keys(this.fields).forEach(field => {
this.isInlineEditor[field.name] = false;
});
}
},
methods: { methods: {
isNull (value) { isNull (value) {
return value === null ? ' is-null' : ''; return value === null ? ' is-null' : '';
}, },
selectRow (event, row) { selectRow () {
this.$emit('select-row', event, row); this.$emit('select-row');
}, },
openContext (event, payload) { 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 () { hideInfoModal () {
this.isInfoModal = false; this.isInfoModal = false;

View File

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

View File

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