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:
parent
7de3bb9346
commit
85f625daf7
@ -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;
|
||||||
|
|
||||||
|
@ -1176,6 +1176,10 @@ export class MySQLClient extends AntaresCore {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async killProcess (id) {
|
||||||
|
return await this.raw(`KILL ${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CREATE TABLE
|
* CREATE TABLE
|
||||||
*
|
*
|
||||||
|
@ -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
|
||||||
*
|
*
|
||||||
|
@ -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');
|
||||||
},
|
},
|
||||||
|
75
src/renderer/components/ModalProcessesListContext.vue
Normal file
75
src/renderer/components/ModalProcessesListContext.vue
Normal 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>
|
@ -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;
|
||||||
|
@ -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',
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user