Fixed copy/paste issues for PSQL tool terminal. Fixes #6547.

This commit is contained in:
Nikhil Mohite 2021-06-24 20:00:52 +05:30 committed by Akshay Joshi
parent cfb68d73a0
commit 6645625e6b
4 changed files with 41 additions and 179 deletions

View File

@ -25,4 +25,5 @@ Bug fixes
| `Issue #6489 <https://redmine.postgresql.org/issues/6489>`_ - Fixed an issue where Execute/Refresh button should not be disabled when we run the empty query.
| `Issue #6505 <https://redmine.postgresql.org/issues/6505>`_ - Fixed an issue where the New Connection Drop Down has lost default maintenance database, auto-select, and tab-through functionality.
| `Issue #6541 <https://redmine.postgresql.org/issues/6541>`_ - Ensure that setting 'Open in new browser tab' should be visible, it should not be based on the value of 'ENABLE_PSQL'.
| `Issue #6547 <https://redmine.postgresql.org/issues/6547>`_ - Fixed copy/paste issues for PSQL tool terminal.
| `Issue #6555 <https://redmine.postgresql.org/issues/6555>`_ - Fixed Czech translation string for 'Login' keyword.

View File

@ -1,4 +1,12 @@
#!/usr/bin/env python3
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2021, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import os
import re
import select
@ -32,8 +40,6 @@ else:
import pty
session_input = dict()
session_input_cursor = dict()
session_last_cmd = dict()
pdata = dict()
cdata = dict()
@ -113,7 +119,8 @@ def panel(trans_id):
is_enable=config.ENABLE_PSQL,
title=underscore_unescape(params['title']),
theme=params['theme'],
o_db_name=o_db_name
o_db_name=o_db_name,
platform=_platform
)
@ -143,13 +150,6 @@ def connect():
if config.ENABLE_PSQL:
sio.emit('connected', {'sid': request.sid}, namespace='/pty',
to=request.sid)
if request.sid in session_last_cmd:
session_last_cmd[request.sid]['is_new_connection'] = False
else:
session_last_cmd[request.sid] = {'cmd': '', 'arrow_up': False,
'invalid_cmd': False,
'is_new_connection': False}
else:
sio.emit('conn_not_allow', {'sid': request.sid}, namespace='/pty',
to=request.sid)
@ -193,36 +193,11 @@ def read_terminal_data(parent, data_ready, max_read_bytes, sid):
if parent in data_ready:
# Read the output from parent fd (terminal).
output = os.read(parent, max_read_bytes)
emit_output = True
if sid in session_last_cmd and session_last_cmd[sid][
'arrow_up'] and not session_last_cmd[request.sid][
'arrow_left_right']:
session_last_cmd[sid]['cmd'] = output.decode()
session_input_cursor[request.sid] = len(
session_last_cmd[sid]['cmd'])
session_last_cmd[sid]['arrow_up'] = True
if sid in session_last_cmd and session_last_cmd[sid]['invalid_cmd']:
# If command is invalid then emit error to user.
emit_output = False
sio.emit(
'pty-output',
{
'result': gettext(
"ERROR: Shell commands are disabled "
"in psql for security\r\n"),
'error': True
},
namespace='/pty', room=sid)
# If command is valid then emit output to user.
if emit_output:
sio.emit('pty-output',
{'result': output.decode(),
'error': False},
namespace='/pty', room=sid)
else:
session_last_cmd[request.sid]['invalid_cmd'] = False
sio.emit('pty-output',
{'result': output.decode(),
'error': False},
namespace='/pty', room=sid)
def read_stdout(process, sid, max_read_bytes, win_emit_output=True):
@ -436,37 +411,12 @@ def get_conn_str_win(manager, db):
return conn_attr
def check_last_exe_cmd(data):
"""
Check the is user try to execute last executed command.
:param data:
:return:
"""
# If user get previous executed command from history then set
# current command as previous executed command.
if session_last_cmd[request.sid]['cmd'] and session_last_cmd[request.sid][
'arrow_up']:
user_input = str(
session_last_cmd[request.sid]['cmd']).strip()
session_last_cmd[request.sid]['arrow_up'] = False
session_last_cmd[request.sid]['cmd'] = ''
else:
if request.sid not in session_input:
session_input[request.sid] = data['input']
user_input = str(session_input[request.sid]).strip()
else:
user_input = str(session_input[request.sid]).strip()
return user_input
def enter_key_press(data):
"""
Handel the Enter key press event.
:param data:
"""
user_input = check_last_exe_cmd(data)
session_input_cursor[request.sid] = 0
user_input = data['input']
if user_input == '\q' or user_input == 'q\\q' or user_input in\
['\quit', 'exit', 'exit;']:
@ -496,63 +446,6 @@ def enter_key_press(data):
os.write(app.config['sessions'][request.sid],
data['input'].encode())
session_input[request.sid] = ''
session_last_cmd[request.sid]['is_new_connection'] = False
def backspace_key_press():
"""
Handel the backspace key press event.
:return:
:rtype:
"""
session_last_cmd[request.sid]['arrow_left_right'] = True
if session_last_cmd[request.sid]['cmd']:
session_input[request.sid] = \
session_last_cmd[request.sid]['cmd']
user_input = list(session_input[request.sid])
if session_input_cursor[request.sid] == 1:
index = 0
session_input_cursor[request.sid] -= 1
else:
if session_input_cursor[request.sid] > 0:
index = (session_input_cursor[request.sid]) - 1
session_input_cursor[request.sid] -= 1
else:
index = session_input_cursor[request.sid]
session_input_cursor[request.sid] = 0
if len(user_input):
del user_input[index]
session_input[request.sid] = "".join(user_input)
if len(session_input[request.sid]) == 0:
session_input_cursor[request.sid] = 0
session_last_cmd[request.sid]['cmd'] = ''
def set_user_input(data):
"""
Check and set current input as user input in session_input.
:param data:
"""
if session_last_cmd[request.sid]['cmd'] and \
session_input[request.sid] == '':
session_input[request.sid] = \
session_last_cmd[request.sid]['cmd']
session_input_cursor[request.sid] = len(
session_input[request.sid])
else:
session_last_cmd[request.sid]['arrow_up'] = False
session_last_cmd[request.sid]['cmd'] = ''
user_input = list(session_input[request.sid])
user_input.insert(session_input_cursor[request.sid],
data['input'])
session_input[request.sid] = ''.join(user_input)
session_input_cursor[request.sid] += 1
session_last_cmd[request.sid]['arrow_left_right'] = False
def other_key_press(data):
@ -563,36 +456,7 @@ def other_key_press(data):
:return:
:rtype:
"""
if data['key_name'] == 'ArrowLeft':
session_last_cmd[request.sid]['arrow_left_right'] = True
if session_input_cursor[request.sid] > 0:
session_input_cursor[request.sid] -= 1
elif data['key_name'] == 'ArrowRight':
session_last_cmd[request.sid]['arrow_left_right'] = True
if session_input_cursor[request.sid] < len(
session_input[request.sid]):
session_input_cursor[request.sid] += 1
elif data['key_name'] == 'ArrowUp':
session_last_cmd[request.sid]['arrow_up'] = True
session_last_cmd[request.sid]['arrow_left_right'] = False
session_input[request.sid] = session_last_cmd[request.sid][
'cmd']
session_input_cursor[request.sid] = len(
session_last_cmd[request.sid]['cmd'])
elif request.sid in session_input and \
data['key_name'] == 'Backspace' and \
(len(session_input[request.sid]) or
len(session_last_cmd[request.sid])):
backspace_key_press()
elif request.sid in session_input:
set_user_input(data)
else:
session_input_cursor[request.sid] = 0
session_input[request.sid] = data['input']
session_input_cursor[request.sid] += 1
session_input[request.sid] = data['input']
if _platform == 'win32':
app.config['sessions'][request.sid].write(

View File

@ -13,7 +13,6 @@ import { SearchAddon } from 'xterm-addon-search';
import { io } from 'socketio';
import Alertify from 'pgadmin.alertifyjs';
import {enable} from 'pgadmin.browser.toolbar';
import clipboard from 'sources/selection/clipboard';
import 'wcdocker';
import {getRandomInt, hasBinariesConfiguration} from 'sources/utils';
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
@ -354,33 +353,31 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
term.write('\r\nServer disconnected, Connection terminated, To create new connection please open another psql tool.');
});
},
psql_terminal_io: function(term, socket) {
psql_terminal_io: function(term, socket, platform) {
// Listen key press event from terminal and emit socket event.
let selected_text = '';
term.attachCustomKeyEventHandler(e => {
e.stopPropagation();
if(e.type=='keydown' && e.metaKey &&(e.key == 'v' || e.key == 'V')) {
if(selected_text != '') {
if (selected_text.length > 0) {
socket.emit('socket_input', {'input': selected_text, 'key_name': e.code});
selected_text = '';
if(e.type=='keydown' && (e.metaKey || e.ctrlKey) &&(e.key == 'v' || e.key == 'V')) {
navigator.permissions.query({ name: 'clipboard-read' }).then(function(result) {
if(result.state === 'granted' || result.state === 'prompt') {
navigator.clipboard.readText().then( clipText => {
var selected_text = clipText;
if (selected_text.length > 0) {
socket.emit('socket_input', {'input': selected_text, 'key_name': e.code});
}
});
} else{
Alertify.alert(gettext('Clipboard read permission required'), gettext('To paste data on the PSQL terminal, Clipboard read permission required.'));
}
} else {
navigator.clipboard.readText().then( clipText => {
selected_text = clipText;
if (selected_text.length > 0) {
socket.emit('socket_input', {'input': selected_text, 'key_name': e.code});
selected_text = '';
}
});
}
}else if(e.type=='keydown' && e.metaKey && (e.key == 'c' || e.key == 'C')) {
if (term.hasSelection()) {
selected_text = term.getSelection();
} else {
selected_text = clipboard.readText();
}
});
}else if(e.type=='keydown' && (e.metaKey || e.ctrlKey) && (e.key == 'c' || e.key == 'C')) {
document.execCommand('copy');
}
if (e.ctrlKey && platform == 'win32') {
return false;
}
return true;
});

View File

@ -33,7 +33,7 @@ require(
<!-- Socket-->
const socket = self.pgAdmin.Browser.psql.psql_socket();
self.pgAdmin.Browser.psql.psql_socket_io(socket, '{{is_enable}}', '{{sid}}', '{{db | replace("'", "\'")| replace('"', '\"') | replace('\\', '\\\\')}}', '{{server_type}}', fitAddon, term);
self.pgAdmin.Browser.psql.psql_terminal_io(term, socket);
self.pgAdmin.Browser.psql.psql_terminal_io(term, socket, '{{platform}}');
self.pgAdmin.Browser.psql.check_db_name_change('{{db}}', '{{o_db_name}}');
<!-- Resize the terminal -->
@ -51,8 +51,8 @@ require(
}
}
const wait_ms = 50;;
window.onresize = debounce(fitToscreen, wait_ms)
const wait_ms = 25;
window.onresize = debounce(fitToscreen, wait_ms);
});
{% endblock %}