Added support to copy SQL from main window to query tool. Fixes #4904

This commit is contained in:
Pradip Parkale 2021-08-09 14:29:31 +05:30 committed by Akshay Joshi
parent 78b041465e
commit 7483ddf2b2
8 changed files with 206 additions and 2 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 183 KiB

View File

@ -353,6 +353,10 @@ Use the fields on the *Options* panel to manage editor preferences.
* When the *Auto-Rollback?* switch is set to *True*, failed queries are rolled * When the *Auto-Rollback?* switch is set to *True*, failed queries are rolled
back. back.
* When the *Copy SQL from main window to query tool?* switch is set to *True*,
the CREATE sql of the selected object will be copied to query tool when query tool
will open.
* When the *Prompt to save unsaved data changes?* switch is set to *True*, the * When the *Prompt to save unsaved data changes?* switch is set to *True*, the
editor will prompt the user to saved unsaved data when exiting the data editor will prompt the user to saved unsaved data when exiting the data
editor. editor.

View File

@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o
New features New features
************ ************
| `Issue #4904 <https://redmine.postgresql.org/issues/4904>`_ - Added support to copy SQL from main window to query tool.
| `Issue #5198 <https://redmine.postgresql.org/issues/5198>`_ - Added support for formatted JSON viewer/editor when interacting with data in a JSON column. | `Issue #5198 <https://redmine.postgresql.org/issues/5198>`_ - Added support for formatted JSON viewer/editor when interacting with data in a JSON column.
Housekeeping Housekeeping

View File

@ -902,6 +902,7 @@ define('pgadmin.browser.node', [
// Callback to render query editor // Callback to render query editor
show_query_tool: function(args, item) { show_query_tool: function(args, item) {
var preference = pgBrowser.get_preference('sqleditor', 'copy_sql_to_query_tool');
var t = pgBrowser.tree, var t = pgBrowser.tree,
i = item || t.selected(), i = item || t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined; d = i && i.length == 1 ? t.itemData(i) : undefined;
@ -910,7 +911,17 @@ define('pgadmin.browser.node', [
return; return;
// Here call data grid method to render query tool // Here call data grid method to render query tool
pgAdmin.DataGrid.show_query_tool('', i); //Open query tool with create script if copy_sql_to_query_tool is true else open blank query tool
if(preference.value && !d._type.includes('coll-')){
var stype = d._type.toLowerCase();
var data = {
'script': stype,
data_disabled: gettext('The selected tree node does not support this option.'),
};
pgBrowser.Node.callbacks.show_script(data);
}else{
pgAdmin.DataGrid.show_query_tool('', i);
}
}, },
// Callback to render psql tool. // Callback to render psql tool.

View File

@ -0,0 +1,153 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2021, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import random
import time
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.python_test_utils import test_utils
from regression.feature_utils.tree_area_locators import TreeAreaLocators
from regression.feature_utils.locators import NavMenuLocators, \
QueryToolLocators
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
class CopySQLFeatureTest(BaseFeatureTest):
""" This class test acceptance test scenarios """
scenarios = [
("Test copy sql to query tool", dict())
]
test_table_name = ""
def before(self):
self.page.add_server(self.server)
def runTest(self):
self._update_preferences_setting()
self._create_table()
sql_query = self._get_sql_query()
query_tool_result = self._get_query_tool_result()
self.assertEqual(query_tool_result, sql_query)
def after(self):
self.page.remove_server(self.server)
test_utils.delete_table(
self.server, self.test_db, self.test_table_name)
def _get_sql_query(self):
self.page.click_tab("SQL")
# Wait till data is displayed in SQL Tab
self.assertTrue(self.page.check_if_element_exist_by_xpath(
"//*[contains(@class,'CodeMirror-lines') and "
"contains(.,'CREATE TABLE IF NOT EXISTS public.%s')]"
% self.test_table_name, 10), "No data displayed in SQL tab")
# Fetch the inner html & check for escaped characters
source_code = self.driver.find_elements_by_xpath(
QueryToolLocators.code_mirror_data_xpath)
sql_query = ''
for data in source_code:
sql_query += data.text
sql_query += '\n'
return sql_query
def _get_query_tool_result(self):
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
time.sleep(5)
self.driver.switch_to.default_content()
self.driver.switch_to_frame(
self.driver.find_element_by_tag_name("iframe"))
code_mirror = self.driver.find_elements_by_xpath(
QueryToolLocators.code_mirror_data_xpath)
query_tool_result = ''
for data in code_mirror:
query_tool_result += data.text
query_tool_result += '\n'
return query_tool_result
def _create_table(self):
self.test_table_name = "test_table" + str(random.randint(1000, 3000))
test_utils.create_table(self.server, self.test_db,
self.test_table_name)
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.toggle_open_tables_node(
self.server['name'], self.server['db_password'],
self.test_db, 'public')
self.page.click_a_tree_node(
self.test_table_name,
TreeAreaLocators.sub_nodes_of_tables_node)
def _update_preferences_setting(self):
file_menu = self.page.find_by_css_selector(
NavMenuLocators.file_menu_css)
file_menu.click()
self.page.retry_click(
(By.CSS_SELECTOR, NavMenuLocators.preference_menu_item_css),
(By.XPATH, NavMenuLocators.specified_preference_tree_node
.format('Browser'))
)
wait = WebDriverWait(self.page.driver, 10)
browser_node = self.page.find_by_xpath(
NavMenuLocators.specified_preference_tree_node.format('Browser'))
if self.page.find_by_xpath(
NavMenuLocators.specified_pref_node_exp_status.
format('Browser')).get_attribute('aria-expanded') == 'false':
ActionChains(self.driver).double_click(browser_node).perform()
self.page.retry_click(
(By.XPATH, NavMenuLocators.specified_sub_node_of_pref_tree_node.
format('Browser', 'Display')),
(By.XPATH, NavMenuLocators.show_system_objects_pref_label_xpath))
# Wait till the preference dialogue box is displayed by checking the
# visibility of Show System Object label
wait.until(EC.presence_of_element_located(
(By.XPATH, NavMenuLocators.show_system_objects_pref_label_xpath))
)
specified_preference_tree_node_name = 'Query Tool'
sql_editor = self.page.find_by_xpath(
NavMenuLocators.specified_preference_tree_node.format(
specified_preference_tree_node_name))
if self.page.find_by_xpath(
NavMenuLocators.specified_pref_node_exp_status.
format(specified_preference_tree_node_name)).get_attribute(
'aria-expanded') == 'false':
ActionChains(self.driver).double_click(sql_editor).perform()
option_node = self.page.find_by_xpath(
NavMenuLocators.specified_sub_node_of_pref_tree_node.format(
specified_preference_tree_node_name, 'Options'))
option_node.click()
self.page.set_switch_box_status(
NavMenuLocators.copy_sql_to_query_tool_switch_btn, 'Yes')
# save and close the preference dialog.
self.page.click_modal('Save')

View File

@ -114,6 +114,7 @@ define('pgadmin.datagrid', [
label: gettext('Query Tool'), label: gettext('Query Tool'),
icon: 'pg-font-icon icon-query_tool', icon: 'pg-font-icon icon-query_tool',
data:{ data:{
applies: 'tools',
data_disabled: gettext('Please select a database from the browser tree to access Query Tool.'), data_disabled: gettext('Please select a database from the browser tree to access Query Tool.'),
}, },
}]; }];
@ -210,7 +211,25 @@ define('pgadmin.datagrid', [
// This is a callback function to show query tool when user click on menu item. // This is a callback function to show query tool when user click on menu item.
show_query_tool: function(url, aciTreeIdentifier) { show_query_tool: function(url, aciTreeIdentifier) {
const transId = commonUtils.getRandomInt(1, 9999999); const transId = commonUtils.getRandomInt(1, 9999999);
showQueryTool.showQueryTool(this, pgBrowser, alertify, url, aciTreeIdentifier, transId); var t = pgBrowser.tree,
i = aciTreeIdentifier || t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined;
//Open query tool with create script if copy_sql_to_query_tool is true else open blank query tool
var preference = pgBrowser.get_preference('sqleditor', 'copy_sql_to_query_tool');
if(preference.value && !d._type.includes('coll-') && (url === '' || url['applies'] === 'tools')){
var stype = d._type.toLowerCase();
var data = {
'script': stype,
data_disabled: gettext('The selected tree node does not support this option.'),
};
pgBrowser.Node.callbacks.show_script(data);
}else{
if(d._type.includes('coll-')){
url = '';
}
showQueryTool.showQueryTool(this, pgBrowser, alertify, url, aciTreeIdentifier, transId);
}
}, },
launch_grid: function(trans_id, panel_url, is_query_tool, panel_title, sURL=null, sql_filter=null) { launch_grid: function(trans_id, panel_url, is_query_tool, panel_title, sURL=null, sql_filter=null) {

View File

@ -128,6 +128,17 @@ def register_query_tool_preferences(self):
) )
) )
self.show_prompt_commit_transaction = self.preference.register(
'Options', 'copy_sql_to_query_tool',
gettext("Copy SQL from main window to query tool?"), 'boolean',
False,
category_label=PREF_LABEL_OPTIONS,
help_str=gettext(
'Specifies whether or not to copy SQL to query tool from '
'main window.'
)
)
self.sql_font_size = self.preference.register( self.sql_font_size = self.preference.register(
'Editor', 'plain_editor_mode', 'Editor', 'plain_editor_mode',
gettext("Plain text mode?"), 'boolean', False, gettext("Plain text mode?"), 'boolean', False,

View File

@ -68,6 +68,11 @@ class NavMenuLocators:
"//div[span[normalize-space(text())='Insert bracket pairs?']]" \ "//div[span[normalize-space(text())='Insert bracket pairs?']]" \
"//div[contains(@class,'toggle btn')]" "//div[contains(@class,'toggle btn')]"
copy_sql_to_query_tool_switch_btn = \
"//div[span[normalize-space(text())=" \
"'Copy SQL from main window to query tool?']]" \
"//div[contains(@class,'toggle btn')]"
backup_filename_txt_box_name = "file" backup_filename_txt_box_name = "file"
restore_file_name_txt_box_name = "file" restore_file_name_txt_box_name = "file"