[pgAdmin4][Patch]: To fix Function/Procedures messages issue in query tool

2017-08-02 Thread Murtuza Zabuawala
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

2017-08-02 Thread Surinder Kumar
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

2017-08-02 Thread Harshal Dhumal
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

2017-08-02 Thread jvenegasperu .
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

2017-08-02 Thread Hao Wang
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