mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Ensure the double-click event is listened to even if the user clicks after the label.
This commit is contained in:
@@ -83,29 +83,28 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||||||
const tags = item._metadata.data?.tags ?? [];
|
const tags = item._metadata.data?.tags ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<DoubleClickHandler onDoubleClick={this.handleDoubleClick} onSingleClick={this.handleClick}>
|
||||||
className={cn('file-entry', {
|
<div
|
||||||
renaming: isRenamePrompt,
|
className={cn('file-entry', {
|
||||||
prompt: isRenamePrompt || isNewPrompt,
|
renaming: isRenamePrompt,
|
||||||
new: isNewPrompt,
|
prompt: isRenamePrompt || isNewPrompt,
|
||||||
}, fileOrDir, decorations ? decorations.classlist : null, `depth-${item.depth}`, extraClasses)}
|
new: isNewPrompt,
|
||||||
data-depth={item.depth}
|
}, fileOrDir, decorations ? decorations.classlist : null, `depth-${item.depth}`, extraClasses)}
|
||||||
onContextMenu={this.handleContextMenu}
|
data-depth={item.depth}
|
||||||
onClick={this.handleClick}
|
onContextMenu={this.handleContextMenu}
|
||||||
onDragStart={this.handleDragStartItem}
|
onDragStart={this.handleDragStartItem}
|
||||||
onMouseEnter={this.handleMouseEnter}
|
onMouseEnter={this.handleMouseEnter}
|
||||||
onMouseLeave={this.handleMouseLeave}
|
onMouseLeave={this.handleMouseLeave}
|
||||||
onKeyDown={()=>{/* taken care by parent */}}
|
onKeyDown={()=>{/* taken care by parent */}}
|
||||||
// required for rendering context menus when opened through context menu button on keyboard
|
// required for rendering context menus when opened through context menu button on keyboard
|
||||||
ref={this.handleDivRef}
|
ref={this.handleDivRef}
|
||||||
draggable={true}>
|
draggable={true}>
|
||||||
|
|
||||||
{!isNewPrompt && fileOrDir === 'directory' ?
|
{!isNewPrompt && fileOrDir === 'directory' ?
|
||||||
<i className={cn('directory-toggle', isDirExpanded ? 'open' : '')} />
|
<i className={cn('directory-toggle', isDirExpanded ? 'open' : '')} />
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
|
||||||
<DoubleClickHandler onDoubleClick={this.handleDoubleClick} onSingleClick={this.handleClick} >
|
|
||||||
<span className='file-label'>{
|
<span className='file-label'>{
|
||||||
item._metadata?.data?.icon ?
|
item._metadata?.data?.icon ?
|
||||||
<i className={cn('file-icon', item._metadata?.data?.icon ? item._metadata.data.icon : fileOrDir)} /> : null
|
<i className={cn('file-icon', item._metadata?.data?.icon ? item._metadata.data.icon : fileOrDir)} /> : null
|
||||||
@@ -120,8 +119,9 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
</DoubleClickHandler>
|
</div>
|
||||||
</div>);
|
</DoubleClickHandler>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
|
@@ -11,11 +11,14 @@ import sys
|
|||||||
import secrets
|
import secrets
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from selenium.webdriver.support.wait import WebDriverWait
|
||||||
|
|
||||||
from regression.python_test_utils import test_utils
|
from regression.python_test_utils import test_utils
|
||||||
from regression.feature_utils.locators import BrowserToolBarLocators
|
from regression.feature_utils.locators import BrowserToolBarLocators
|
||||||
from regression.feature_utils.base_feature_test import BaseFeatureTest
|
from regression.feature_utils.base_feature_test import BaseFeatureTest
|
||||||
from regression.feature_utils.tree_area_locators import TreeAreaLocators
|
from regression.feature_utils.tree_area_locators import TreeAreaLocators
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.support import expected_conditions as EC
|
||||||
|
|
||||||
|
|
||||||
class BrowserToolBarFeatureTest(BaseFeatureTest):
|
class BrowserToolBarFeatureTest(BaseFeatureTest):
|
||||||
@@ -68,6 +71,14 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
|
|||||||
'db_password'],
|
'db_password'],
|
||||||
self.test_db),
|
self.test_db),
|
||||||
'Tree is not expanded to database node')
|
'Tree is not expanded to database node')
|
||||||
|
|
||||||
|
WebDriverWait(self.driver, 3).until(
|
||||||
|
EC.visibility_of_element_located(
|
||||||
|
(By.CSS_SELECTOR,
|
||||||
|
BrowserToolBarLocators.open_query_tool_button_css)
|
||||||
|
), "Timed out waiting for execute query button to appear"
|
||||||
|
)
|
||||||
|
|
||||||
self.assertTrue(self.page.retry_click(
|
self.assertTrue(self.page.retry_click(
|
||||||
(By.CSS_SELECTOR,
|
(By.CSS_SELECTOR,
|
||||||
BrowserToolBarLocators.open_query_tool_button_css),
|
BrowserToolBarLocators.open_query_tool_button_css),
|
||||||
@@ -87,7 +98,13 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
|
|||||||
table_node = self.page.check_if_element_exists_with_scroll(
|
table_node = self.page.check_if_element_exists_with_scroll(
|
||||||
TreeAreaLocators.table_node(self.test_table_name))
|
TreeAreaLocators.table_node(self.test_table_name))
|
||||||
table_node.click()
|
table_node.click()
|
||||||
time.sleep(2)
|
|
||||||
|
WebDriverWait(self.driver, 3).until(
|
||||||
|
EC.visibility_of_element_located(
|
||||||
|
(By.CSS_SELECTOR,
|
||||||
|
BrowserToolBarLocators.view_table_data_button_css)
|
||||||
|
), "Timed out waiting for execute query button to appear"
|
||||||
|
)
|
||||||
|
|
||||||
self.assertTrue(self.page.retry_click(
|
self.assertTrue(self.page.retry_click(
|
||||||
(By.CSS_SELECTOR,
|
(By.CSS_SELECTOR,
|
||||||
|
@@ -19,7 +19,7 @@ class TreeAreaLocators:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def server_group_node_exp_status(server_group_name):
|
def server_group_node_exp_status(server_group_name):
|
||||||
return "//i[@class='directory-toggle open']/following-sibling::" \
|
return "//i[@class='directory-toggle open']/following-sibling::" \
|
||||||
"div//span[starts-with(text(),'%s')]" % server_group_name
|
"span//span[starts-with(text(),'%s')]" % server_group_name
|
||||||
|
|
||||||
# Server Node
|
# Server Node
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -31,7 +31,7 @@ class TreeAreaLocators:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def server_node_exp_status(server_name):
|
def server_node_exp_status(server_name):
|
||||||
return "//i[@class='directory-toggle open']/following-sibling::" \
|
return "//i[@class='directory-toggle open']/following-sibling::" \
|
||||||
"div//span[starts-with(text(),'%s')]" % server_name
|
"span//span[starts-with(text(),'%s')]" % server_name
|
||||||
|
|
||||||
# Server Connection
|
# Server Connection
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -49,20 +49,19 @@ class TreeAreaLocators:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def databases_node_exp_status(server_name):
|
def databases_node_exp_status(server_name):
|
||||||
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||||
"following-sibling::div//div[span[span[text()='Databases']]]/" \
|
"following-sibling::div//span[span[text()='Databases']]/" \
|
||||||
"preceding-sibling::i[@class='directory-toggle open']" \
|
"preceding-sibling::i[@class='directory-toggle open']" \
|
||||||
% server_name
|
% server_name
|
||||||
|
|
||||||
# Database Node
|
# Database Node
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def database_node(database_name):
|
def database_node(database_name):
|
||||||
return "//div[@data-depth='4']/div/span/span[text()='%s']" \
|
return "//div[@data-depth='4']/span/span[text()='%s']" % database_name
|
||||||
% database_name
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def database_node_exp_status(database_name):
|
def database_node_exp_status(database_name):
|
||||||
return "//i[@class='directory-toggle open']/following-sibling::" \
|
return "//i[@class='directory-toggle open']/following-sibling::" \
|
||||||
"div//span[text()='%s']" % database_name
|
"span//span[text()='%s']" % database_name
|
||||||
|
|
||||||
# Schemas Node
|
# Schemas Node
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -73,7 +72,7 @@ class TreeAreaLocators:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def schemas_node_exp_status(database_name):
|
def schemas_node_exp_status(database_name):
|
||||||
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||||
"following-sibling::div//div[span[span[text()='Schemas']]]/" \
|
"following-sibling::span//div[span[span[text()='Schemas']]]/" \
|
||||||
"preceding-sibling::i[@class='directory-toggle open']" \
|
"preceding-sibling::i[@class='directory-toggle open']" \
|
||||||
% database_name
|
% database_name
|
||||||
|
|
||||||
@@ -86,25 +85,25 @@ class TreeAreaLocators:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def schema_node_exp_status(schema_name):
|
def schema_node_exp_status(schema_name):
|
||||||
return "//i[@class='directory-toggle open']/" \
|
return "//i[@class='directory-toggle open']/" \
|
||||||
"following-sibling::div//span[text()='%s']" % schema_name
|
"following-sibling::span//span[text()='%s']" % schema_name
|
||||||
|
|
||||||
# Tables Node
|
# Tables Node
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def tables_node(schema_name):
|
def tables_node(schema_name):
|
||||||
return "//div[divdiv[[span[span[starts-with(text(),'%s')]]]]]/" \
|
return ("//div[div[div[span/span[text()='%s']]]]/"
|
||||||
"following-sibling::div//span[text()='Tables']" % schema_name
|
"following-sibling::div//span[text()='Tables']" % schema_name)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def tables_node_exp_status(schema_name):
|
def tables_node_exp_status(schema_name):
|
||||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||||
"following-sibling::div//div[span[span[text()='Tables']]]/" \
|
"following-sibling::span//div[span[span[text()='Tables']]]/" \
|
||||||
"preceding-sibling::i[@class='directory-toggle open']"\
|
"preceding-sibling::i[@class='directory-toggle open']"\
|
||||||
% schema_name
|
% schema_name
|
||||||
|
|
||||||
# Schema child
|
# Schema child
|
||||||
child_node_exp_status = \
|
child_node_exp_status = \
|
||||||
"//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
"//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||||
"following-sibling::div//div[span[span[text()='%s']]]/" \
|
"following-sibling::div//span[span[text()='%s']]/" \
|
||||||
"preceding-sibling::i[@class='directory-toggle open']"
|
"preceding-sibling::i[@class='directory-toggle open']"
|
||||||
|
|
||||||
child_node = "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
child_node = "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||||
@@ -148,129 +147,19 @@ class TreeAreaLocators:
|
|||||||
# Table Node
|
# Table Node
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def table_node(table_name):
|
def table_node(table_name):
|
||||||
return "//div[@data-depth='8']/div/span/span[text()='%s']" % table_name
|
return "//div[@data-depth='8']/span/span[text()='%s']" % table_name
|
||||||
|
|
||||||
# Function Node
|
# Function Node
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def function_node(table_name):
|
def function_node(table_name):
|
||||||
return "//div[@data-depth='8']/div/span/span[text()='%s']" % table_name
|
return "//div[@data-depth='8']/span/span[text()='%s']" % table_name
|
||||||
|
|
||||||
# Role Node
|
# Role Node
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def role_node(role_name):
|
def role_node(role_name):
|
||||||
return "//div[@data-depth='4']/div/span/span[text()='%s']" % role_name
|
return "//div[@data-depth='4']/span/span[text()='%s']" % role_name
|
||||||
|
|
||||||
# Context element option
|
# Context element option
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def context_menu_element(schema_name):
|
def context_menu_element(schema_name):
|
||||||
return "[role='menuitem'][data-label='%s']" % schema_name
|
return "[role='menuitem'][data-label='%s']" % schema_name
|
||||||
|
|
||||||
# Old xpaths
|
|
||||||
# server_group_sub_nodes_exp_status = \
|
|
||||||
# "//div[div[span[span[contains(text(),'Servers')]]]]" \
|
|
||||||
# "/following-sibling::ul/li/div"
|
|
||||||
#
|
|
||||||
# server_group_sub_nodes_connected_status = \
|
|
||||||
# "//div[div[span[span[contains(text(), 'Servers')]]]]/" \
|
|
||||||
# "following-sibling::ul/li/div/div/div/span[2]"
|
|
||||||
#
|
|
||||||
# specified_tree_node = \
|
|
||||||
# "//div[@id='id-object-explorer']//span[@class='aciTreeItem']/" \
|
|
||||||
# "span[(@class='aciTreeText') and text()='{}']"
|
|
||||||
#
|
|
||||||
# specified_tree_node_exp_status = \
|
|
||||||
# "//div[@id='id-object-explorer']//span[@class='aciTreeItem']/" \
|
|
||||||
# "span[(@class='aciTreeText') and text()='{}']" \
|
|
||||||
# "//ancestor::*[@class='aciTreeLine']"
|
|
||||||
#
|
|
||||||
# sub_nodes_of_tables_node = \
|
|
||||||
# "//div[div[div[div[div[div[div[div[span[span[" \
|
|
||||||
# "contains(text(),'Tables')]]]]]]]]]]/" \
|
|
||||||
# "following-sibling::ul/li/div//div/span[2]/span[2]"
|
|
||||||
#
|
|
||||||
# sub_nodes_of_functions_node = \
|
|
||||||
# "//div[div[div[div[div[div[div[div[span[span[" \
|
|
||||||
# "contains(text(),'Functions')]]]]]]]]]]/" \
|
|
||||||
# "following-sibling::ul/li/div//div/span[2]/span[2]"
|
|
||||||
#
|
|
||||||
# sub_nodes_of_login_group_node = \
|
|
||||||
# "//div[div[div[span[span[contains(text(),'Login/Group Roles')]]]]]" \
|
|
||||||
# "/following::ul/li/div[@class='aciTreeLine']"
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_a_server_node(server_name):
|
|
||||||
# xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \
|
|
||||||
# "following-sibling::ul/li/div[@class='aciTreeLine']" % \
|
|
||||||
# server_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_a_server_node_exp_status(server_name):
|
|
||||||
# xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \
|
|
||||||
# "following-sibling::ul/li/div" % server_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def databases_node_of_a_server_node(server_name):
|
|
||||||
# xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \
|
|
||||||
# "following-sibling::ul/li/div/div/div/div/span[2]/span[2 " \
|
|
||||||
# "and text()='Databases ']" % server_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_databases_node(server_name):
|
|
||||||
# xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \
|
|
||||||
# "following-sibling::ul/li[1]/div/following-sibling::ul/li/" \
|
|
||||||
# "div/div/div/div/div/span[2]/span[@class='aciTreeText']" % \
|
|
||||||
# server_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_databases_node_exp_status(server_name):
|
|
||||||
# xpath = "//div[div[div[span[span[contains(text(), '%s')]]]]]/" \
|
|
||||||
# "following-sibling::ul/li[1]/div/following-sibling::ul/li/" \
|
|
||||||
# "div" % server_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_database_node(database_name):
|
|
||||||
# xpath = "//div[div[div[div[div[span[span[contains(text()," \
|
|
||||||
# "'%s')]]]]]]]/following-sibling::" \
|
|
||||||
# "ul/li/div/div/div/div/div/div/span[2]/span[2]"\
|
|
||||||
# % database_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_database_node_exp_status(database_name):
|
|
||||||
# xpath = "//div[div[div[div[div[span[span[contains(text(), " \
|
|
||||||
# "'%s')]]]]]]]/following-sibling::ul/li/div" % database_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_schemas_node(database_name):
|
|
||||||
# xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \
|
|
||||||
# "following-sibling::ul/li[" \
|
|
||||||
# "@role='presentation']/ul/li/div//div/span/span[" \
|
|
||||||
# "@class='aciTreeText']" % database_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_schemas_node_exp_status(database_name):
|
|
||||||
# xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \
|
|
||||||
# "following-sibling::ul/li[@role='presentation']/ul/li/div" \
|
|
||||||
# % database_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_schema_node(database_name):
|
|
||||||
# xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \
|
|
||||||
# "following-sibling::ul/li[@role='presentation']" \
|
|
||||||
# "/ul/li/ul/li/div//div/span[2]/span[2]" % database_name
|
|
||||||
# return xpath
|
|
||||||
#
|
|
||||||
# @staticmethod
|
|
||||||
# def sub_nodes_of_schema_node_exp_status(database_name):
|
|
||||||
# xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \
|
|
||||||
# "following-sibling::ul/li[@role='presentation']" \
|
|
||||||
# "/ul/li/ul/li/div" % database_name
|
|
||||||
# return xpath
|
|
||||||
|
Reference in New Issue
Block a user