diff --git a/docs/en_US/release_notes_5_5.rst b/docs/en_US/release_notes_5_5.rst index 34b25b08d..ae8e8c6d6 100644 --- a/docs/en_US/release_notes_5_5.rst +++ b/docs/en_US/release_notes_5_5.rst @@ -25,4 +25,5 @@ Bug fixes | `Issue #6489 `_ - Fixed an issue where Execute/Refresh button should not be disabled when we run the empty query. | `Issue #6505 `_ - Fixed an issue where the New Connection Drop Down has lost default maintenance database, auto-select, and tab-through functionality. | `Issue #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 `_ - Fixed copy/paste issues for PSQL tool terminal. | `Issue #6555 `_ - Fixed Czech translation string for 'Login' keyword. diff --git a/web/pgadmin/tools/psql/__init__.py b/web/pgadmin/tools/psql/__init__.py index 9e90d8712..1bd57066b 100644 --- a/web/pgadmin/tools/psql/__init__.py +++ b/web/pgadmin/tools/psql/__init__.py @@ -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( diff --git a/web/pgadmin/tools/psql/static/js/psql_module.js b/web/pgadmin/tools/psql/static/js/psql_module.js index 54b2d79c8..1bf9dcd23 100644 --- a/web/pgadmin/tools/psql/static/js/psql_module.js +++ b/web/pgadmin/tools/psql/static/js/psql_module.js @@ -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; }); diff --git a/web/pgadmin/tools/psql/templates/editor_template.html b/web/pgadmin/tools/psql/templates/editor_template.html index 17b8a04d8..df7c0c923 100644 --- a/web/pgadmin/tools/psql/templates/editor_template.html +++ b/web/pgadmin/tools/psql/templates/editor_template.html @@ -33,7 +33,7 @@ require( 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}}'); @@ -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 %}