[pgAdmin4][Patch]: To fix Function/Procedures messages issue in query tool
Hi, PFA patch to fix the issue where in query tool, messages were not displaying from functions/procedures properly. RM#2555 Needs to be reviewed with (Success/Fail/Error scenarios): 1) Table output 2) Function output 3) Procedure output (EPAS) 4) Adhoc query output (like vacuum) -- Regards, Murtuza Zabuawala EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py index 2ffc74a..15ec8c4 100644 --- a/web/pgadmin/tools/sqleditor/__init__.py +++ b/web/pgadmin/tools/sqleditor/__init__.py @@ -528,7 +528,6 @@ def poll(trans_id): rows_fetched_from = 0 rows_fetched_to = 0 has_more_rows = False -additional_result = [] columns = dict() columns_info = None primary_keys = None @@ -640,30 +639,23 @@ def poll(trans_id): status = 'NotConnected' result = error_msg -# Procedure/Function output may comes in the form of Notices from the -# database server, so we need to append those outputs with the -# original result. - -if status == 'Success' and result is None: -result = conn.status_message() -messages = conn.messages() -if messages: -additional_result = ''.join(messages) -else: -additional_result = '' -if result != 'SELECT 1' and result is not None: -result = additional_result + result -else: -result = additional_result - # There may be additional messages even if result is present # eg: Function can provide result as well as RAISE messages additional_messages = None -if status == 'Success' and result is not None: +if status == 'Success': messages = conn.messages() if messages: additional_messages = ''.join(messages) +# Procedure/Function output may comes in the form of Notices from the +# database server, so we need to append those outputs with the +# original result. +if status == 'Success' and result is None: +result = conn.status_message() +if (result != 'SELECT 1' or result != 'SELECT 0') \ +and result is not None and additional_messages: +result = additional_messages + result + return make_json_response( data={ 'status': status, 'result': result, diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js index 6452744..3e61f10 100644 --- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js @@ -1889,14 +1889,13 @@ define('tools.querytool', [ var _msg = msg1 + '\n' + msg2; - self.update_msg_history(true, _msg, false); // If there is additional messages from server then add it to message if(!_.isNull(data.additional_messages) && !_.isUndefined(data.additional_messages)) { _msg = data.additional_messages + '\n' + _msg; } - $('.sql-editor-message').text(_msg); + self.update_msg_history(true, _msg, false); /* Add the data to the collection and render the grid. * In case of Explain draw the graph on explain panel @@ -2080,7 +2079,7 @@ define('tools.querytool', [ $('.sql-editor-message').text(msg); } else { -$('.sql-editor-message').append(msg); +$('.sql-editor-message').append(_.escape(msg)); } // Scroll automatically when msgs appends to element
[pgAdmin4][Patch]: RM_ 2620 - Getting error "Violates check constraint" while creating pgAgent job
Hi It gives error because database value is passed in query generated when jobstep > kind == 'batch'. the database value must be ‘’, if jobstep > kind == 'batch' as per check constraint: "pga_jobstep_check1" CHECK (jstdbname <> ''::name AND jstkind = 's'::bpchar OR jstdbname = ''::name AND (jstkind = 'b'::bpchar OR jstconnstr <> '' ::text)) Please find attached patch and review. Thanks, Surinder RM_2620.patch Description: Binary data
[pgAdmin4][RM2586] Cleanup feature test
Hi, Please find attached patch to improve feature test execution time. Now on my machine overall execution time is cut down to 280 seconds from 400+ seconds Changes: 1. Removed fixed python time.sleeps where ever possible. 2. Removed connect to server test cases. 3. Query tool test cases: i. Merged 3 test cases On demand result on scroll, grid select all and column select all. ii. Merged 3 test cases Explain query, Explain query with verbose and Explain query with cost. iii. Merged 3 test cases Explain analyze query, Explain analyze with buffers and Explain analyze with timing. 4. Improved debugger XSS test case execution time. -- *Harshal Dhumal* *Sr. Software Engineer* EnterpriseDB India: http://www.enterprisedb.com The Enterprise PostgreSQL Company diff --git a/web/pgadmin/feature_tests/connect_to_server_feature_test.py b/web/pgadmin/feature_tests/connect_to_server_feature_test.py deleted file mode 100644 index 97e96f2..000 --- a/web/pgadmin/feature_tests/connect_to_server_feature_test.py +++ /dev/null @@ -1,84 +0,0 @@ -## -# -# pgAdmin 4 - PostgreSQL Tools -# -# Copyright (C) 2013 - 2017, The pgAdmin Development Team -# This software is released under the PostgreSQL Licence -# -## - -import time -from selenium.webdriver import ActionChains - -import config as app_config -from regression.feature_utils.base_feature_test import BaseFeatureTest -from regression.python_test_utils import test_utils - - -class ConnectsToServerFeatureTest(BaseFeatureTest): -""" -Tests that a database connection can be created from the UI -""" -scenarios = [ -("Test database connection", dict()) -] - -def before(self): -connection = test_utils.get_db_connection(self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode']) -test_utils.drop_database(connection, "acceptance_test_db") -test_utils.create_database(self.server, "acceptance_test_db") -test_utils.create_table(self.server, "acceptance_test_db", "test_table") - -def runTest(self): -"""This function tests that a database connection can be created from -the UI""" -self.assertEqual(app_config.APP_NAME, self.page.driver.title) -self.page.wait_for_spinner_to_disappear() - -self._connects_to_server() -self._tables_node_expandable() - -def after(self): -self.page.remove_server(self.server) - -connection = test_utils.get_db_connection(self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode']) -test_utils.drop_database(connection, "acceptance_test_db") - -def _connects_to_server(self): -self.page.find_by_xpath("//*[@class='aciTreeText' and .='Servers']").click() -time.sleep(2) -self.page.driver.find_element_by_link_text("Object").click() -ActionChains(self.page.driver) \ -.move_to_element(self.page.driver.find_element_by_link_text("Create")) \ -.perform() -self.page.find_by_partial_link_text("Server...").click() - -server_config = self.server -self.page.fill_input_by_field_name("name", server_config['name']) -self.page.find_by_partial_link_text("Connection").click() -self.page.fill_input_by_field_name("host", server_config['host']) -self.page.fill_input_by_field_name("port", server_config['port']) -self.page.fill_input_by_field_name("username", server_config['username']) -self.page.fill_input_by_field_name("password", server_config['db_password']) -self.page.find_by_xpath("//button[contains(.,'Save')]").click() - -def _tables_node_expandable(self): -self.page.toggle_open_server(self.server['name']) -self.page.toggle_open_tree_item('Databases') -self.page.toggle_open_tree_item('acceptance_test_db') -# wait until all database dependant modules/js are loaded. -time.sleep(5) -self.page.toggle_open_tree_item('Schemas') -self.page.toggle_open_tree_item('public') -self.page.toggle_open_tree_item('Tables') -self.page.toggle_open_tree_item('test_table') diff --git a/web/pgadmin/feature_tests/copy_selected_query_res
Add basic function search
Please add a file finder in the PgAdmin4 query tool Files are listed but there is no search engine with PgAdmin3 I was used to looking there the script I needed I guess more people work that way Check the option to do the backup I worked the third attempt did not create the file I'm using windows 7 with pgadmin4 Sorry for the writing I do with google translate -- José Mercedes Venegas Acevedo cel Mov RPC 964185205 Member of the PHP Documentation Group (Spanish)
[gpAdmin4][patch] query history updates
Hi Hackers, Here is a patch for query tools history UX improvements: - Add copy button for query text - Historical queries are binned by day Thanks, Sarah & Hao diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py index 0795028c..4ffcff8f 100644 --- a/web/pgadmin/feature_tests/query_tool_journey_test.py +++ b/web/pgadmin/feature_tests/query_tool_journey_test.py @@ -72,13 +72,14 @@ class QueryToolJourneyTest(BaseFeatureTest): self.__clear_query_tool() editor_input = self.page.find_by_id("output-panel") self.page.click_element(editor_input) -self._execute_query("SELECT * FROM shoes") +self._execute_query("SELECT * FROM table_that_doesnt_exist") -self.page.click_tab("History") +self.page.click_tab("Query History") selected_history_entry = self.page.find_by_css_selector("#query_list .selected") -self.assertIn("SELECT * FROM shoes", selected_history_entry.text) +self.assertIn("SELECT * FROM table_that_doesnt_exist", selected_history_entry.text) failed_history_detail_pane = self.page.find_by_id("query_detail") -self.assertIn("ERROR: relation \"shoes\" does not exist", failed_history_detail_pane.text) + +self.assertIn("Error Message relation \"table_that_doesnt_exist\" does not exist", failed_history_detail_pane.text) ActionChains(self.page.driver) \ .send_keys(Keys.ARROW_DOWN) \ .perform() @@ -86,10 +87,30 @@ class QueryToolJourneyTest(BaseFeatureTest): self.assertIn("SELECT * FROM test_table ORDER BY value", selected_history_entry.text) selected_history_detail_pane = self.page.find_by_id("query_detail") self.assertIn("SELECT * FROM test_table ORDER BY value", selected_history_detail_pane.text) -newly_selected_history_entry = self.page.find_by_xpath("//*[@id='query_list']/ul/li[1]") +newly_selected_history_entry = self.page.find_by_xpath("//*[@id='query_list']/ul/li[2]") self.page.click_element(newly_selected_history_entry) selected_history_detail_pane = self.page.find_by_id("query_detail") -self.assertIn("SELECT * FROM shoes", selected_history_detail_pane.text) +self.assertIn("SELECT * FROM table_that_doesnt_exist", selected_history_detail_pane.text) + +self.__clear_query_tool() + +self.page.click_element(editor_input) +for _ in range(15): +self._execute_query("SELECT * FROM hats") + +self.page.click_tab("Query History") + +query_we_need_to_scroll_to = self.page.find_by_xpath("//*[@id='query_list']/ul/li[17]") + +self.page.click_element(query_we_need_to_scroll_to) + self._assert_not_clickable_because_out_of_view(query_we_need_to_scroll_to) + +for _ in range(17): +ActionChains(self.page.driver) \ +.send_keys(Keys.ARROW_DOWN) \ +.perform() + +self._assert_clickable(query_we_need_to_scroll_to) self.__clear_query_tool() self.page.click_element(editor_input) diff --git a/web/pgadmin/static/css/webcabin.overrides.css b/web/pgadmin/static/css/webcabin.overrides.css index cfad4eb5..0fbbdb98 100644 --- a/web/pgadmin/static/css/webcabin.overrides.css +++ b/web/pgadmin/static/css/webcabin.overrides.css @@ -268,6 +268,7 @@ .wcFrameTitleBar { background-color: #e8e8e8; height: 35px; + border-bottom: #cc; } .wcFloating .wcFrameTitleBar { diff --git a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx index b3eab01f..317cb3ab 100644 --- a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx +++ b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx @@ -12,11 +12,49 @@ import 'codemirror/mode/sql/sql'; import CodeMirror from './code_mirror'; import Shapes from '../../react_shapes'; +import clipboard from '../../../js/selection/clipboard'; export default class HistoryDetailQuery extends React.Component { + + constructor(props) { +super(props); + +this.copyAllHandler = this.copyAllHandler.bind(this); +this.state = {isCopied: false}; +this.timeout = undefined; + } + + copyAllHandler() { +clipboard.copyTextToClipboard(this.props.historyEntry.query); + +this.clearPreviousTimeout(); + +this.setState({isCopied: true}); +this.timeout = setTimeout(() => { + this.setState({isCopied: false}); +}, 1500); + } + + clearPreviousTimeout() { +if (this.timeout !== undefined) { + clearTimeout(this.timeout); + this.timeout = undefined; +} + } + + copyButtonText() { +return this.state.isCopied ? 'Copied!' : 'Copy All'; + } + + copyButtonClass() { +return this.state.isCopied ? 'was-copied' : 'copy-all'; + } + render() { return ( +{this.copyButtonText()} { - this.re