mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Added Quick Search functionality for menu items and help articles. Fixes #6148
This commit is contained in:
parent
f7214b7cfe
commit
b948f43dda
@ -11,6 +11,7 @@ New features
|
|||||||
|
|
||||||
| `Issue #5912 <https://redmine.postgresql.org/issues/5912>`_ - Added support for Logical Replication.
|
| `Issue #5912 <https://redmine.postgresql.org/issues/5912>`_ - Added support for Logical Replication.
|
||||||
| `Issue #5967 <https://redmine.postgresql.org/issues/5967>`_ - Implemented runtime using NWjs to open pgAdmin4 in a standalone window instead of the system tray and web browser.
|
| `Issue #5967 <https://redmine.postgresql.org/issues/5967>`_ - Implemented runtime using NWjs to open pgAdmin4 in a standalone window instead of the system tray and web browser.
|
||||||
|
| `Issue #6148 <https://redmine.postgresql.org/issues/6148>`_ - Added Quick Search functionality for menu items and help articles.
|
||||||
| `Issue #6170 <https://redmine.postgresql.org/issues/6170>`_ - Rotate the logfile in the container distribution.
|
| `Issue #6170 <https://redmine.postgresql.org/issues/6170>`_ - Rotate the logfile in the container distribution.
|
||||||
|
|
||||||
Housekeeping
|
Housekeeping
|
||||||
|
@ -443,6 +443,19 @@ def register_browser_preferences(self):
|
|||||||
fields=fields
|
fields=fields
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.preference.register(
|
||||||
|
'keyboard_shortcuts', 'open_quick_search',
|
||||||
|
gettext('Quick Search'), 'keyboardshortcut',
|
||||||
|
{
|
||||||
|
'alt': False,
|
||||||
|
'shift': True,
|
||||||
|
'control': True,
|
||||||
|
'key': {'key_code': 70, 'char': 'f'}
|
||||||
|
},
|
||||||
|
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
|
||||||
|
fields=fields
|
||||||
|
)
|
||||||
|
|
||||||
self.dynamic_tab_title = self.preference.register(
|
self.dynamic_tab_title = self.preference.register(
|
||||||
'tab_settings', 'dynamic_tabs',
|
'tab_settings', 'dynamic_tabs',
|
||||||
gettext("Dynamic tab size"), 'boolean', False,
|
gettext("Dynamic tab size"), 'boolean', False,
|
||||||
|
@ -48,19 +48,22 @@ define('pgadmin.node.package', [
|
|||||||
name: 'create_package_on_coll', node: 'coll-package', module: this,
|
name: 'create_package_on_coll', node: 'coll-package', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Package...'),
|
category: 'create', priority: 4, label: gettext('Package...'),
|
||||||
icon: 'wcTabIcon icon-package', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-package', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'create_package', node: 'package', module: this,
|
name: 'create_package', node: 'package', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Package...'),
|
category: 'create', priority: 4, label: gettext('Package...'),
|
||||||
icon: 'wcTabIcon icon-package', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-package', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'create_package', node: 'schema', module: this,
|
name: 'create_package', node: 'schema', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Package...'),
|
category: 'create', priority: 4, label: gettext('Package...'),
|
||||||
icon: 'wcTabIcon icon-package', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-package', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -47,19 +47,22 @@ define('pgadmin.node.synonym', [
|
|||||||
name: 'create_synonym_on_coll', node: 'coll-synonym', module: this,
|
name: 'create_synonym_on_coll', node: 'coll-synonym', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Synonym...'),
|
category: 'create', priority: 4, label: gettext('Synonym...'),
|
||||||
icon: 'wcTabIcon icon-synonym', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-synonym', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'create_synonym', node: 'synonym', module: this,
|
name: 'create_synonym', node: 'synonym', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Synonym...'),
|
category: 'create', priority: 4, label: gettext('Synonym...'),
|
||||||
icon: 'wcTabIcon icon-synonym', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-synonym', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'create_synonym', node: 'schema', module: this,
|
name: 'create_synonym', node: 'schema', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Synonym...'),
|
category: 'create', priority: 4, label: gettext('Synonym...'),
|
||||||
icon: 'wcTabIcon icon-synonym', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-synonym', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -54,25 +54,29 @@ define('pgadmin.node.compound_trigger', [
|
|||||||
name: 'create_compound_trigger_on_coll', node: 'coll-compound_trigger', module: this,
|
name: 'create_compound_trigger_on_coll', node: 'coll-compound_trigger', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'create_compound_trigger', node: 'compound_trigger', module: this,
|
name: 'create_compound_trigger', node: 'compound_trigger', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'create_compound_trigger_onTable', node: 'table', module: this,
|
name: 'create_compound_trigger_onTable', node: 'table', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'create_compound_trigger_onPartition', node: 'partition', module: this,
|
name: 'create_compound_trigger_onPartition', node: 'partition', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},{
|
},{
|
||||||
name: 'enable_compound_trigger', node: 'compound_trigger', module: this,
|
name: 'enable_compound_trigger', node: 'compound_trigger', module: this,
|
||||||
@ -88,7 +92,8 @@ define('pgadmin.node.compound_trigger', [
|
|||||||
name: 'create_compound_trigger_onView', node: 'view', module: this,
|
name: 'create_compound_trigger_onView', node: 'view', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true,
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -76,12 +76,16 @@ define('pgadmin.node.database', [
|
|||||||
name: 'connect_database', node: 'database', module: this,
|
name: 'connect_database', node: 'database', module: this,
|
||||||
applies: ['object', 'context'], callback: 'connect_database',
|
applies: ['object', 'context'], callback: 'connect_database',
|
||||||
category: 'connect', priority: 4, label: gettext('Connect Database...'),
|
category: 'connect', priority: 4, label: gettext('Connect Database...'),
|
||||||
icon: 'fa fa-link', enable : 'is_not_connected',
|
icon: 'fa fa-link', enable : 'is_not_connected', data: {
|
||||||
|
'data_disabled': gettext('Selected database is already connected.'),
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
name: 'disconnect_database', node: 'database', module: this,
|
name: 'disconnect_database', node: 'database', module: this,
|
||||||
applies: ['object', 'context'], callback: 'disconnect_database',
|
applies: ['object', 'context'], callback: 'disconnect_database',
|
||||||
category: 'drop', priority: 5, label: gettext('Disconnect Database...'),
|
category: 'drop', priority: 5, label: gettext('Disconnect Database...'),
|
||||||
icon: 'fa fa-unlink', enable : 'is_connected',
|
icon: 'fa fa-unlink', enable : 'is_connected',data: {
|
||||||
|
'data_disabled': gettext('Selected database is already disconnected.'),
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
name: 'generate_erd', node: 'database', module: this,
|
name: 'generate_erd', node: 'database', module: this,
|
||||||
applies: ['object', 'context'], callback: 'generate_erd',
|
applies: ['object', 'context'], callback: 'generate_erd',
|
||||||
|
@ -48,7 +48,8 @@ define('pgadmin.node.resource_group', [
|
|||||||
name: 'create_resourcegroup_on_server', node: 'server', module: this,
|
name: 'create_resourcegroup_on_server', node: 'server', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Resource Group...'),
|
category: 'create', priority: 4, label: gettext('Resource Group...'),
|
||||||
icon: 'wcTabIcon icon-resource_group', data: {action: 'create'},
|
icon: 'wcTabIcon icon-resource_group', data: {action: 'create',
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
/* Function is used to check the server type and version.
|
/* Function is used to check the server type and version.
|
||||||
* Resource Group only supported in PPAS 9.4 and above.
|
* Resource Group only supported in PPAS 9.4 and above.
|
||||||
*/
|
*/
|
||||||
@ -62,12 +63,14 @@ define('pgadmin.node.resource_group', [
|
|||||||
name: 'create_resource_group_on_coll', node: 'coll-resource_group', module: this,
|
name: 'create_resource_group_on_coll', node: 'coll-resource_group', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Resource Group...'),
|
category: 'create', priority: 4, label: gettext('Resource Group...'),
|
||||||
icon: 'wcTabIcon icon-resource_group', data: {action: 'create'},
|
icon: 'wcTabIcon icon-resource_group', data: {action: 'create',
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
},{
|
},{
|
||||||
name: 'create_resource_group', node: 'resource_group', module: this,
|
name: 'create_resource_group', node: 'resource_group', module: this,
|
||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 4, label: gettext('Resource Group...'),
|
category: 'create', priority: 4, label: gettext('Resource Group...'),
|
||||||
icon: 'wcTabIcon icon-resource_group', data: {action: 'create'},
|
icon: 'wcTabIcon icon-resource_group', data: {action: 'create',
|
||||||
|
'data_disabled': gettext('This option is only available on EPAS servers.')},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
@ -100,12 +100,16 @@ define('pgadmin.node.server', [
|
|||||||
name: 'reload_configuration', node: 'server', module: this,
|
name: 'reload_configuration', node: 'server', module: this,
|
||||||
applies: ['tools', 'context'], callback: 'reload_configuration',
|
applies: ['tools', 'context'], callback: 'reload_configuration',
|
||||||
category: 'reload', priority: 6, label: gettext('Reload Configuration'),
|
category: 'reload', priority: 6, label: gettext('Reload Configuration'),
|
||||||
icon: 'fa fa-redo-alt', enable : 'enable_reload_config',
|
icon: 'fa fa-redo-alt', enable : 'enable_reload_config',data: {
|
||||||
|
'data_disabled': gettext('Please select a server from the browser tree to reload the configuration files.'),
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
name: 'restore_point', node: 'server', module: this,
|
name: 'restore_point', node: 'server', module: this,
|
||||||
applies: ['tools', 'context'], callback: 'restore_point',
|
applies: ['tools', 'context'], callback: 'restore_point',
|
||||||
category: 'restore', priority: 9, label: gettext('Add Named Restore Point...'),
|
category: 'restore', priority: 9, label: gettext('Add Named Restore Point...'),
|
||||||
icon: 'fa fa-anchor', enable : 'is_applicable',
|
icon: 'fa fa-anchor', enable : 'is_applicable',data: {
|
||||||
|
'data_disabled': gettext('Please select any server from the browser tree to Add Named Restore Point.'),
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
name: 'change_password', node: 'server', module: this,
|
name: 'change_password', node: 'server', module: this,
|
||||||
applies: ['object'], callback: 'change_password',
|
applies: ['object'], callback: 'change_password',
|
||||||
@ -115,12 +119,16 @@ define('pgadmin.node.server', [
|
|||||||
name: 'wal_replay_pause', node: 'server', module: this,
|
name: 'wal_replay_pause', node: 'server', module: this,
|
||||||
applies: ['tools', 'context'], callback: 'pause_wal_replay',
|
applies: ['tools', 'context'], callback: 'pause_wal_replay',
|
||||||
category: 'wal_replay_pause', priority: 7, label: gettext('Pause Replay of WAL'),
|
category: 'wal_replay_pause', priority: 7, label: gettext('Pause Replay of WAL'),
|
||||||
icon: 'fa fa-pause-circle', enable : 'wal_pause_enabled',
|
icon: 'fa fa-pause-circle', enable : 'wal_pause_enabled',data: {
|
||||||
|
'data_disabled': gettext('Please select a connected database as a Super user and run in Recovery mode to Pause Replay of WAL.'),
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
name: 'wal_replay_resume', node: 'server', module: this,
|
name: 'wal_replay_resume', node: 'server', module: this,
|
||||||
applies: ['tools', 'context'], callback: 'resume_wal_replay',
|
applies: ['tools', 'context'], callback: 'resume_wal_replay',
|
||||||
category: 'wal_replay_resume', priority: 8, label: gettext('Resume Replay of WAL'),
|
category: 'wal_replay_resume', priority: 8, label: gettext('Resume Replay of WAL'),
|
||||||
icon: 'fa fa-play-circle', enable : 'wal_resume_enabled',
|
icon: 'fa fa-play-circle', enable : 'wal_resume_enabled',data: {
|
||||||
|
'data_disabled': gettext('Please select a connected database as a Super user and run in Recovery mode to Resume Replay of WAL.'),
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
name: 'clear_saved_password', node: 'server', module: this,
|
name: 'clear_saved_password', node: 'server', module: this,
|
||||||
applies: ['object', 'context'], callback: 'clear_saved_password',
|
applies: ['object', 'context'], callback: 'clear_saved_password',
|
||||||
@ -145,6 +153,9 @@ define('pgadmin.node.server', [
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('SSH Tunnel password is not saved for selected server.'),
|
||||||
|
},
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
_.bindAll(this, 'connection_lost');
|
_.bindAll(this, 'connection_lost');
|
||||||
|
@ -875,6 +875,10 @@ define('pgadmin.browser', [
|
|||||||
var $mnu = navbar.children(o.id).first(),
|
var $mnu = navbar.children(o.id).first(),
|
||||||
$dropdown = $mnu.children('.dropdown-menu').first();
|
$dropdown = $mnu.children('.dropdown-menu').first();
|
||||||
$dropdown.empty();
|
$dropdown.empty();
|
||||||
|
if(o.menu == 'help'){
|
||||||
|
$dropdown.append('<div id="quick-search-component"></div>');
|
||||||
|
$dropdown.append('<div class="menu-groups"><span class="fa fa-list" style="font-weight:900 !important;"></span> SUGGESTED SITES</div>');
|
||||||
|
}
|
||||||
|
|
||||||
if (pgAdmin.Browser.MenuCreator(
|
if (pgAdmin.Browser.MenuCreator(
|
||||||
obj.Nodes, $dropdown, obj.menus[o.menu], obj.menu_categories
|
obj.Nodes, $dropdown, obj.menus[o.menu], obj.menu_categories
|
||||||
@ -902,6 +906,7 @@ define('pgadmin.browser', [
|
|||||||
} else if(type == 'dialog_help') {
|
} else if(type == 'dialog_help') {
|
||||||
window.open(url, 'pgadmin_help');
|
window.open(url, 'pgadmin_help');
|
||||||
}
|
}
|
||||||
|
$('#live-search-field').focus();
|
||||||
},
|
},
|
||||||
_findTreeChildNode: function(_i, _d, _o) {
|
_findTreeChildNode: function(_i, _d, _o) {
|
||||||
var loaded = _o.t.wasLoad(_i),
|
var loaded = _o.t.wasLoad(_i),
|
||||||
@ -2224,6 +2229,8 @@ define('pgadmin.browser', [
|
|||||||
if (pgBrowser.utils.useSpaces == 'True') {
|
if (pgBrowser.utils.useSpaces == 'True') {
|
||||||
pgAdmin.Browser.editor_shortcut_keys.Tab = 'insertSoftTab';
|
pgAdmin.Browser.editor_shortcut_keys.Tab = 'insertSoftTab';
|
||||||
}
|
}
|
||||||
|
setTimeout(function(){
|
||||||
|
$('#mnu_about').closest('li').before('<li class="dropdown-divider"></li>');
|
||||||
|
}, 100);
|
||||||
return pgAdmin.Browser;
|
return pgAdmin.Browser;
|
||||||
});
|
});
|
||||||
|
@ -44,6 +44,7 @@ _.extend(pgBrowser.keyboardNavigation, {
|
|||||||
'drop_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_multiple').value),
|
'drop_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_multiple').value),
|
||||||
'drop_cascade_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_cascade_multiple').value),
|
'drop_cascade_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_cascade_multiple').value),
|
||||||
'add_grid_row': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'add_grid_row').value),
|
'add_grid_row': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'add_grid_row').value),
|
||||||
|
'open_quick_search': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'open_quick_search').value),
|
||||||
|
|
||||||
};
|
};
|
||||||
this.shortcutMethods = {
|
this.shortcutMethods = {
|
||||||
@ -66,6 +67,7 @@ _.extend(pgBrowser.keyboardNavigation, {
|
|||||||
'bindDropMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_multiple_objects}, // Grid Menu Drop Multiple
|
'bindDropMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_multiple_objects}, // Grid Menu Drop Multiple
|
||||||
'bindDropCascadeMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_cascade_multiple_objects}, // Grid Menu Drop Cascade Multiple
|
'bindDropCascadeMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_cascade_multiple_objects}, // Grid Menu Drop Cascade Multiple
|
||||||
'bindAddGridRow': {'shortcuts': this.keyboardShortcut.add_grid_row}, // Subnode Grid Add Row
|
'bindAddGridRow': {'shortcuts': this.keyboardShortcut.add_grid_row}, // Subnode Grid Add Row
|
||||||
|
'bindOpenQuickSearch': {'shortcuts': this.keyboardShortcut.open_quick_search}, // Subnode Grid Refresh Row
|
||||||
};
|
};
|
||||||
this.bindShortcuts();
|
this.bindShortcuts();
|
||||||
}
|
}
|
||||||
@ -383,6 +385,9 @@ _.extend(pgBrowser.keyboardNavigation, {
|
|||||||
|
|
||||||
return new dialogTabNavigator.dialogTabNavigator(dialogContainer, backward_shortcut, forward_shortcut);
|
return new dialogTabNavigator.dialogTabNavigator(dialogContainer, backward_shortcut, forward_shortcut);
|
||||||
},
|
},
|
||||||
|
bindOpenQuickSearch: function() {
|
||||||
|
$('#search_icon').trigger('click');
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = pgAdmin.Browser.keyboardNavigation;
|
module.exports = pgAdmin.Browser.keyboardNavigation;
|
||||||
|
@ -67,12 +67,17 @@ define([
|
|||||||
}, this.menu_items);
|
}, this.menu_items);
|
||||||
this.$el = create_submenu.$el;
|
this.$el = create_submenu.$el;
|
||||||
} else {
|
} else {
|
||||||
|
var data_disabled = null;
|
||||||
|
if(this.data != undefined && this.data.data_disabled != undefined){
|
||||||
|
data_disabled = this.data.data_disabled;
|
||||||
|
}
|
||||||
var url = $('<a></a>', {
|
var url = $('<a></a>', {
|
||||||
'id': this.name,
|
'id': this.name,
|
||||||
'href': this.url,
|
'href': this.url,
|
||||||
'target': this.target,
|
'target': this.target,
|
||||||
'data-toggle': 'pg-menu',
|
'data-toggle': 'pg-menu',
|
||||||
'role': 'menuitem',
|
'role': 'menuitem',
|
||||||
|
'data-disabled': data_disabled,
|
||||||
}).data('pgMenu', {
|
}).data('pgMenu', {
|
||||||
module: this.module || pgAdmin.Browser,
|
module: this.module || pgAdmin.Browser,
|
||||||
cb: this.callback,
|
cb: this.callback,
|
||||||
|
@ -150,6 +150,7 @@ define('pgadmin.browser.node', [
|
|||||||
label: (self.dropAsRemove) ? gettext('Remove %s', self.label) : gettext('Delete/Drop'),
|
label: (self.dropAsRemove) ? gettext('Remove %s', self.label) : gettext('Delete/Drop'),
|
||||||
data: {
|
data: {
|
||||||
'url': 'drop',
|
'url': 'drop',
|
||||||
|
'data_disabled': gettext('The selected tree node does not support this option.'),
|
||||||
},
|
},
|
||||||
icon: 'fa fa-trash-alt',
|
icon: 'fa fa-trash-alt',
|
||||||
enable: _.isFunction(self.canDrop) ?
|
enable: _.isFunction(self.canDrop) ?
|
||||||
@ -232,6 +233,7 @@ define('pgadmin.browser.node', [
|
|||||||
category: gettext('Scripts'),
|
category: gettext('Scripts'),
|
||||||
data: {
|
data: {
|
||||||
'script': stype,
|
'script': stype,
|
||||||
|
'data_disabled': gettext('The selected tree node does not support this option.'),
|
||||||
},
|
},
|
||||||
icon: 'fa fa-pencil-alt',
|
icon: 'fa fa-pencil-alt',
|
||||||
enable: self.check_user_permission,
|
enable: self.check_user_permission,
|
||||||
|
29
web/pgadmin/browser/static/js/quick_search.js
Normal file
29
web/pgadmin/browser/static/js/quick_search.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import {Search} from './quick_search/trigger_search';
|
||||||
|
|
||||||
|
// TODO: GUI, Add the logic to show loading screen while fetching result
|
||||||
|
const onResultFetch = (url, data) => {
|
||||||
|
// URL can be used for displaying all the result in new page
|
||||||
|
// data will be array of search <name> -> <link>
|
||||||
|
console.warn('URL = ' + url);
|
||||||
|
console.warn(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
if (document.getElementById('quick-search-component')) {
|
||||||
|
ReactDOM.render(
|
||||||
|
<Search onResult={onResultFetch} />,
|
||||||
|
document.getElementById('quick-search-component')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},500);
|
@ -0,0 +1,44 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
// Allow us to render IFrame using React
|
||||||
|
// Here we will add the event listener on Iframe load event
|
||||||
|
export class Iframe extends Component {
|
||||||
|
static get propTypes() {
|
||||||
|
return {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
srcURL: PropTypes.string.isRequired,
|
||||||
|
onLoad: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const iframeStyle = {
|
||||||
|
border: '0',
|
||||||
|
display: 'block',
|
||||||
|
position:'absolute',
|
||||||
|
opacity:'0',
|
||||||
|
};
|
||||||
|
const {id, srcURL, onLoad} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<iframe
|
||||||
|
id={id}
|
||||||
|
src={srcURL}
|
||||||
|
onLoad={onLoad}
|
||||||
|
width={'20'}
|
||||||
|
height={'20'}
|
||||||
|
style={iframeStyle}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
91
web/pgadmin/browser/static/js/quick_search/menuitems_help.js
Normal file
91
web/pgadmin/browser/static/js/quick_search/menuitems_help.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
import gettext from 'sources/gettext';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Allow us to
|
||||||
|
const getMenuName = (item) => {
|
||||||
|
let aLinks = item.getElementsByTagName('a');
|
||||||
|
let name;
|
||||||
|
if (aLinks.length > 0) {
|
||||||
|
name = (aLinks[0].text).trim();
|
||||||
|
name = name.replace(/\.+$/g, '');
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function menuSearch(param, props) {
|
||||||
|
let LAST_MENU;
|
||||||
|
param = param.trim();
|
||||||
|
const setState = props.setState;
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
if (window.pgAdmin.Browser.utils.app_name) {
|
||||||
|
LAST_MENU = gettext('About '+ window.pgAdmin.Browser.utils.app_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we will add the matches
|
||||||
|
const parseLI = (_menu, path) => {
|
||||||
|
let _name = getMenuName(_menu);
|
||||||
|
if (_name && _name.toLowerCase().indexOf(param.toLowerCase()) != -1) {
|
||||||
|
let _res = {};
|
||||||
|
_res[_name] = path;
|
||||||
|
_res['element'] = _menu.children[0];
|
||||||
|
result.push(_res);
|
||||||
|
}
|
||||||
|
// Check if last menu then update the parent component's state
|
||||||
|
if (_name === LAST_MENU) {
|
||||||
|
setState(state => ({
|
||||||
|
...state,
|
||||||
|
fetched: true,
|
||||||
|
data: result,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Recursive function to search in UL
|
||||||
|
const parseUL = (menu, path) => {
|
||||||
|
const menus = Array.from(menu.children);
|
||||||
|
menus.forEach((_menu) => {
|
||||||
|
let _name, _path;
|
||||||
|
if (_menu.tagName == 'UL') {
|
||||||
|
_name = getMenuName(_menu);
|
||||||
|
_path = `${path}/${_name}`;
|
||||||
|
iterItem(_menu, _path);
|
||||||
|
} else if (_menu.tagName == 'LI') {
|
||||||
|
if (_menu.classList.contains('dropdown-submenu')) {
|
||||||
|
_name = getMenuName(_menu);
|
||||||
|
_path = `${path}/${_name}`;
|
||||||
|
iterItem(_menu, _path);
|
||||||
|
} else {
|
||||||
|
parseLI(_menu, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expects LI of menus which contains A & UL
|
||||||
|
const iterItem = (menu, path) => {
|
||||||
|
const subMenus = Array.from(menu.children);
|
||||||
|
subMenus.forEach((_menu) => {
|
||||||
|
if (_menu.tagName == 'UL') {
|
||||||
|
parseUL(_menu, path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Starting Point
|
||||||
|
const navbar = document.querySelector('.navbar-nav');
|
||||||
|
const mainMenus = Array.from(navbar.children);
|
||||||
|
|
||||||
|
mainMenus.forEach((menu) => {
|
||||||
|
iterItem(menu, getMenuName(menu));
|
||||||
|
});
|
||||||
|
}
|
101
web/pgadmin/browser/static/js/quick_search/online_help.js
Normal file
101
web/pgadmin/browser/static/js/quick_search/online_help.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import {Iframe} from './iframe_component';
|
||||||
|
import url_for from 'sources/url_for';
|
||||||
|
|
||||||
|
const extractSearchResult = (list) => {
|
||||||
|
let result = {};
|
||||||
|
for (let idx = 0; idx < list.length; idx++) {
|
||||||
|
let link = list[idx].getElementsByTagName('A');
|
||||||
|
// we are not going to display more than first 10 result as per design
|
||||||
|
if (link.length == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let topicName = link[0].text;
|
||||||
|
let topicLink = url_for('help.static', {
|
||||||
|
'filename': link[0].getAttribute('href'),
|
||||||
|
});
|
||||||
|
result[topicName] = topicLink;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function onlineHelpSearch(param, props) {
|
||||||
|
param = param.split(' ').join('+');
|
||||||
|
const setState = props.setState;
|
||||||
|
const helpURL = url_for('help.static', {
|
||||||
|
'filename': 'search.html',
|
||||||
|
});
|
||||||
|
const srcURL = `${helpURL}?q=${param}`;
|
||||||
|
let isIFrameLoaded = false;
|
||||||
|
if(document.getElementById('hidden-quick-search-iframe')){
|
||||||
|
document.getElementById('hidden-quick-search-iframe').contentDocument.location.reload(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Below function will be called when the page will be loaded in Iframe
|
||||||
|
const _iframeLoaded = () => {
|
||||||
|
if (isIFrameLoaded) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
isIFrameLoaded = true;
|
||||||
|
let iframe = document.getElementById('hidden-quick-search-iframe');
|
||||||
|
let content = (iframe.contentWindow || iframe.contentDocument);
|
||||||
|
let iframeHTML = content.document;
|
||||||
|
window.pooling = setInterval(() => {
|
||||||
|
let resultEl = iframeHTML.getElementById('search-results');
|
||||||
|
let searchResultsH2Tags = resultEl.getElementsByTagName('h2');
|
||||||
|
let list = resultEl && resultEl.getElementsByTagName('LI');
|
||||||
|
let pooling = window.pooling;
|
||||||
|
if ((list && list.length > 0 )) {
|
||||||
|
let res = extractSearchResult(list);
|
||||||
|
// After getting the data, we need to call the Parent component function
|
||||||
|
// which will render the data on the screen
|
||||||
|
if (searchResultsH2Tags[0]['childNodes'][0]['textContent'] != 'Searching') {
|
||||||
|
window.clearInterval(pooling);
|
||||||
|
setState(state => ({
|
||||||
|
...state,
|
||||||
|
fetched: true,
|
||||||
|
clearedPooling: true,
|
||||||
|
url: srcURL,
|
||||||
|
data: res,
|
||||||
|
}));
|
||||||
|
isIFrameLoaded = false;
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById('quick-search-iframe-container'));
|
||||||
|
} else {
|
||||||
|
setState(state => ({
|
||||||
|
...state,
|
||||||
|
fetched: true,
|
||||||
|
clearedPooling: false,
|
||||||
|
url: srcURL,
|
||||||
|
data: res,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else if(searchResultsH2Tags[0]['childNodes'][0]['textContent'] == 'Search Results') {
|
||||||
|
setState(state => ({
|
||||||
|
...state,
|
||||||
|
fetched: true,
|
||||||
|
clearedPooling: true,
|
||||||
|
url: srcURL,
|
||||||
|
data: {},
|
||||||
|
}));
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById('quick-search-iframe-container'));
|
||||||
|
isIFrameLoaded = false;
|
||||||
|
window.clearInterval(pooling);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render IFrame
|
||||||
|
ReactDOM.render(
|
||||||
|
<Iframe id='hidden-quick-search-iframe' srcURL={srcURL} onLoad={_iframeLoaded}/>,
|
||||||
|
document.getElementById('quick-search-iframe-container'),
|
||||||
|
);
|
||||||
|
}
|
260
web/pgadmin/browser/static/js/quick_search/trigger_search.js
Normal file
260
web/pgadmin/browser/static/js/quick_search/trigger_search.js
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
import React, {useRef,useState, useEffect} from 'react';
|
||||||
|
import {useDelayDebounce} from 'sources/custom_hooks';
|
||||||
|
import {onlineHelpSearch} from './online_help';
|
||||||
|
import {menuSearch} from './menuitems_help';
|
||||||
|
import $ from 'jquery';
|
||||||
|
import gettext from 'sources/gettext';
|
||||||
|
|
||||||
|
export function Search() {
|
||||||
|
const wrapperRef = useRef(null);
|
||||||
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
const [isShowMinLengthMsg, setIsShowMinLengthMsg] = useState(false);
|
||||||
|
let helpLinkTitles = [];
|
||||||
|
let helpLinks = [];
|
||||||
|
const [isMenuLoading, setIsMenuLoading] = useState(false);
|
||||||
|
const [isHelpLoading, setIsHelpLoading] = useState(false);
|
||||||
|
const [menuSearchResult, setMenuSearchResult] = useState({
|
||||||
|
fetched: false,
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
const [helpSearchResult, setHelpSearchResult] = useState({
|
||||||
|
fetched: false,
|
||||||
|
clearedPooling: true,
|
||||||
|
url: '',
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const [showResults, setShowResults] = useState(false);
|
||||||
|
|
||||||
|
const resetSearchState = () => {
|
||||||
|
setMenuSearchResult(state => ({
|
||||||
|
...state,
|
||||||
|
fetched: false,
|
||||||
|
data: [],
|
||||||
|
}));
|
||||||
|
setHelpSearchResult(state => ({
|
||||||
|
...state,
|
||||||
|
fetched: false,
|
||||||
|
clearedPooling: true,
|
||||||
|
url: '',
|
||||||
|
data: {},
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Below will be called when any changes has been made to state
|
||||||
|
useEffect(() => {
|
||||||
|
helpLinkTitles = Object.keys(helpSearchResult.data);
|
||||||
|
for(let i = 0; i<helpLinkTitles.length;i++){
|
||||||
|
helpLinks.push(<a href={''} target='_blank' rel='noreferrer'>helpLinkTitles[i]</a>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(menuSearchResult.fetched == true){
|
||||||
|
setIsMenuLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(helpSearchResult.fetched == true){
|
||||||
|
setIsHelpLoading(false);
|
||||||
|
}
|
||||||
|
}, [menuSearchResult, helpSearchResult]);
|
||||||
|
|
||||||
|
const initSearch = (param) => {
|
||||||
|
setIsMenuLoading(true);
|
||||||
|
setIsHelpLoading(true);
|
||||||
|
|
||||||
|
onlineHelpSearch(param, {
|
||||||
|
state: helpSearchResult,
|
||||||
|
setState: setHelpSearchResult,
|
||||||
|
});
|
||||||
|
menuSearch(param, {
|
||||||
|
state: menuSearchResult,
|
||||||
|
setState: setMenuSearchResult,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Debounse logic to avoid multiple re-render with each keypress
|
||||||
|
useDelayDebounce(initSearch, searchTerm, 1000);
|
||||||
|
|
||||||
|
const toggleDropdownMenu = () => {
|
||||||
|
let pooling = window.pooling;
|
||||||
|
if(pooling){
|
||||||
|
window.clearInterval(pooling);
|
||||||
|
}
|
||||||
|
document.getElementsByClassName('live-search-field')[0].value = '';
|
||||||
|
setTimeout(function(){
|
||||||
|
document.getElementById('live-search-field').focus();
|
||||||
|
},100);
|
||||||
|
resetSearchState();
|
||||||
|
setShowResults(!showResults);
|
||||||
|
setIsMenuLoading(false);
|
||||||
|
setIsHelpLoading(false);
|
||||||
|
setIsShowMinLengthMsg(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const refactorMenuItems = (items) => {
|
||||||
|
if(items.length > 0){
|
||||||
|
let menuItemsHtmlElement = [];
|
||||||
|
for(let i=0; i < items.length; i++){
|
||||||
|
Object.keys(items[i]).map( (value) => {
|
||||||
|
if(value != 'element' && value != 'No object selected'){
|
||||||
|
menuItemsHtmlElement.push( <li key={ 'li-menu-' + i }><a tabIndex='0' id={ 'li-menu-' + i } href={'#'} className={ (items[i]['element'].classList.contains('disabled') == true ? 'dropdown-item menu-groups-a disabled':'dropdown-item menu-groups-a')} key={ 'menu-' + i } onClick={() => {items[i]['element'].click(); toggleDropdownMenu();}}>
|
||||||
|
{value}
|
||||||
|
<span key={ 'menu-span-' + i }>{refactorPathToMenu(items[i][value])}</span>
|
||||||
|
</a>
|
||||||
|
{ ((items[i]['element'].classList.contains('disabled') == true && items[i]['element'].getAttribute('data-disabled') != undefined) ? <i className='fa fa-info-circle quick-search-tooltip' data-toggle='tooltip' title={items[i]['element'].getAttribute('data-disabled')} aria-label='Test data tooltip' aria-hidden='true'></i> : '' )}
|
||||||
|
</li>);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
return menuItemsHtmlElement;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const refactorPathToMenu = (path) => {
|
||||||
|
if(path){
|
||||||
|
let pathArray = path.split('/');
|
||||||
|
let spanElement = [];
|
||||||
|
for(let i = 0; i < pathArray.length; i++ ){
|
||||||
|
if(i == (pathArray.length -1)){
|
||||||
|
spanElement.push(pathArray[i]);
|
||||||
|
}else{
|
||||||
|
spanElement.push(<span key={ 'menu-span-sub' + i }> {pathArray[i]} <i className='fa fa-angle-right' aria-hidden='true'></i> </span>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spanElement;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInputValueChange = (value) => {
|
||||||
|
let pooling = window.pooling;
|
||||||
|
if(pooling){
|
||||||
|
window.clearInterval(pooling);
|
||||||
|
}
|
||||||
|
resetSearchState();
|
||||||
|
setSearchTerm('');
|
||||||
|
if(value.length >= 3){
|
||||||
|
setSearchTerm(value);
|
||||||
|
setIsMenuLoading(true);
|
||||||
|
setIsHelpLoading(true);
|
||||||
|
setIsShowMinLengthMsg(false);
|
||||||
|
}else{
|
||||||
|
setIsMenuLoading(false);
|
||||||
|
setIsHelpLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value.length < 3 && value.length > 0){
|
||||||
|
setIsShowMinLengthMsg(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value.length == 0){
|
||||||
|
setIsShowMinLengthMsg(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const useOutsideAlerter = (ref) => {
|
||||||
|
useEffect(() => {
|
||||||
|
/**
|
||||||
|
* Alert if clicked on outside of element
|
||||||
|
*/
|
||||||
|
function handleClickOutside(event) {
|
||||||
|
if (ref.current && !ref.current.contains(event.target)) {
|
||||||
|
let input_element = document.getElementById('live-search-field');
|
||||||
|
let input_value = input_element.value;
|
||||||
|
if(input_value && input_value.length > 0){
|
||||||
|
toggleDropdownMenu();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Bind the event listener
|
||||||
|
document.addEventListener('mousedown', handleClickOutside);
|
||||||
|
return () => {
|
||||||
|
// Unbind the event listener on clean up
|
||||||
|
document.removeEventListener('mousedown', handleClickOutside);
|
||||||
|
};
|
||||||
|
}, [ref]);
|
||||||
|
};
|
||||||
|
|
||||||
|
useOutsideAlerter(wrapperRef);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id='quick-search-container' onClick={setSearchTerm}></div>,
|
||||||
|
<ul id='quick-search-container' ref={wrapperRef} className='test' role="menu">
|
||||||
|
<li>
|
||||||
|
<ul id='myDropdown'>
|
||||||
|
<li className='dropdown-item-input'>
|
||||||
|
<input tabIndex='0' autoFocus type='text' autoComplete='off' className='form-control live-search-field'
|
||||||
|
aria-label='live-search-field' id='live-search-field' placeholder={gettext('Quick Search')} onChange={(e) => {onInputValueChange(e.target.value);} } />
|
||||||
|
</li>
|
||||||
|
<div style={{marginBottom:0}}>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
{ isShowMinLengthMsg
|
||||||
|
? (<div className='pad-12 no-results'>
|
||||||
|
<span className='fa fa-info-circle'></span>
|
||||||
|
Please enter minimum 3 characters to search
|
||||||
|
</div>)
|
||||||
|
:''}
|
||||||
|
<div >
|
||||||
|
|
||||||
|
{ (menuSearchResult.fetched == true && isMenuLoading == false ) ?
|
||||||
|
<div>
|
||||||
|
<div className='menu-groups'>
|
||||||
|
<span className='fa fa-window-maximize'></span> {gettext('MENU ITEMS')} ({menuSearchResult.data.length})
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{refactorMenuItems(menuSearchResult.data)}
|
||||||
|
</div> : ( (isMenuLoading) ? (<div className='pad-12'><div className="search-icon">{gettext('Searching...')}</div></div>) : '')}
|
||||||
|
|
||||||
|
{(menuSearchResult.data.length == 0 && menuSearchResult.fetched == true && isMenuLoading == false) ? (<div className='pad-12 no-results'><span className='fa fa-info-circle'></span> {gettext('No search results')}</div>):''}
|
||||||
|
|
||||||
|
{ (helpSearchResult.fetched == true && isHelpLoading == false) ?
|
||||||
|
<div>
|
||||||
|
<div className='help-groups'>
|
||||||
|
<span className='fa fa-question-circle'></span> {gettext('HELP ARTICLES')} {Object.keys(helpSearchResult.data).length > 10 ?
|
||||||
|
<span>(10 of {Object.keys(helpSearchResult.data).length} )
|
||||||
|
</span>:
|
||||||
|
'(' + Object.keys(helpSearchResult.data).length + ')'}
|
||||||
|
{ !helpSearchResult.clearedPooling ? <img src='/static/img/loading.gif' alt={gettext('Loading...')} className='help_loading_icon'/> :''}
|
||||||
|
{ Object.keys(helpSearchResult.data).length > 10 ? <a href={helpSearchResult.url} className='pull-right no-padding' target='_blank' rel='noreferrer'>{gettext('Show all')} <span className='fas fa-external-link-alt' ></span></a> : ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{Object.keys(helpSearchResult.data).map( (value, index) => {
|
||||||
|
if(index <= 9) { return <li key={ 'li-help-' + index }><a tabIndex='0' href={helpSearchResult.data[value]} key={ 'help-' + index } className='dropdown-item' target='_blank' rel='noreferrer'>{value}</a></li>; }
|
||||||
|
})}
|
||||||
|
|
||||||
|
{(Object.keys(helpSearchResult.data).length == 0) ? (<div className='pad-12 no-results'><span className='fa fa-info-circle'></span> {gettext('No search results')}</div>):''}
|
||||||
|
</div> : ( (isHelpLoading && isMenuLoading == false) ? (
|
||||||
|
<div>
|
||||||
|
<div className='help-groups'>
|
||||||
|
<span className='fa fa-question-circle'></span>
|
||||||
|
HELP ARTICLES
|
||||||
|
{Object.keys(helpSearchResult.data).length > 10
|
||||||
|
? '(10 of ' + Object.keys(helpSearchResult.data).length + ')'
|
||||||
|
: '(' + Object.keys(helpSearchResult.data).length + ')'
|
||||||
|
}
|
||||||
|
{ Object.keys(helpSearchResult.data).length > 10
|
||||||
|
? <a href={helpSearchResult.url} className='pull-right no-padding' target='_blank' rel='noreferrer'>
|
||||||
|
Show all <span className='fas fa-external-link-alt' ></span></a> : ''
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className='pad-12'><div className="search-icon">{gettext('Searching...')}</div></div>
|
||||||
|
</div>) : '')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<div id='quick-search-iframe-container' />
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
151
web/pgadmin/browser/static/scss/_quick_search.scss
Normal file
151
web/pgadmin/browser/static/scss/_quick_search.scss
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#myInput {
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-position: 14px 12px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 14px 20px 12px 45px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#myInput:focus {outline: 3px solid #ddd;}
|
||||||
|
|
||||||
|
.custom-dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dropdown-content {
|
||||||
|
background-color: $color-bg;
|
||||||
|
min-width: 376px;
|
||||||
|
overflow: auto;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dropdown-content a {
|
||||||
|
color: $dropdown-link-color;
|
||||||
|
padding: 6px 12px 6px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dropdown-content a:hover {
|
||||||
|
color: $black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#myDropdown a:hover {background-color: $dropdown-link-hover-bg; color:$color-danger-fg !important;}
|
||||||
|
|
||||||
|
.search_icon{
|
||||||
|
color: $white;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
.hidden { display:none; }
|
||||||
|
|
||||||
|
.visible { display:block; }
|
||||||
|
|
||||||
|
.menu-groups, .help-groups{
|
||||||
|
background-color: $color-gray-light;
|
||||||
|
padding: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-groups .fa, .fas{
|
||||||
|
font-weight:normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-groups .fa, .fas{
|
||||||
|
font-weight:600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pad-12{
|
||||||
|
padding:12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results{
|
||||||
|
font-size: 14px;
|
||||||
|
color: #697986;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-padding{
|
||||||
|
padding:0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-groups-a{
|
||||||
|
display:flex !important;
|
||||||
|
flex-direction:column;
|
||||||
|
padding: 6px;
|
||||||
|
color: $dropdown-link-color;
|
||||||
|
padding: 6px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-groups-a span{
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: 100;
|
||||||
|
color: $quick-search-span-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
#myDropdown a:hover span{
|
||||||
|
color: $color-danger-fg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon{
|
||||||
|
background: $loader-icon-small center center no-repeat;
|
||||||
|
margin: auto !important;
|
||||||
|
height: 22px !important;
|
||||||
|
width: 130px !important;
|
||||||
|
background-position: left !important;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $dropdown-link-color;
|
||||||
|
padding-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help_loading_icon{
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
#myDropdown ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-right-search-icon{
|
||||||
|
border-right: 2px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help_submenu{
|
||||||
|
left: 100%;
|
||||||
|
width: 20rem;
|
||||||
|
top:-0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help_menu{
|
||||||
|
min-width:300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item-input{
|
||||||
|
padding:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-groups-a span:focus{
|
||||||
|
color:$color-primary-fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover, .dropdown-item:focus span{
|
||||||
|
color: $color-danger-fg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-search-tooltip{
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
margin-top: -2.1em;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor:pointer;
|
||||||
|
color: $quick-search-info-icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
#myDropdown .dropdown-divider{
|
||||||
|
height: auto;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
@ -133,7 +133,7 @@ window.onload = function(e){
|
|||||||
<li id="mnu_help" class="nav-item active dropdown d-none">
|
<li id="mnu_help" class="nav-item active dropdown d-none">
|
||||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
|
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{
|
||||||
_('Help') }} <span class="caret"></span></a>
|
_('Help') }} <span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu" role="menu"></ul>
|
<ul class="dropdown-menu help_menu" role="menu"></ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% if config.SERVER_MODE %}
|
{% if config.SERVER_MODE %}
|
||||||
|
BIN
web/pgadmin/static/img/loading.gif
Normal file
BIN
web/pgadmin/static/img/loading.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
@ -26,4 +26,16 @@ export function usePrevious(value) {
|
|||||||
ref.current = value;
|
ref.current = value;
|
||||||
});
|
});
|
||||||
return ref.current;
|
return ref.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useDelayDebounce(callback, args, delay) {
|
||||||
|
useEffect(() => {
|
||||||
|
const delayDebounceFn = setTimeout(() => {
|
||||||
|
if (args) {
|
||||||
|
callback(args);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
return () => clearTimeout(delayDebounceFn);
|
||||||
|
}, [args]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1129,3 +1129,10 @@ select:-webkit-autofill:focus {
|
|||||||
.pull-left{
|
.pull-left{
|
||||||
float:left
|
float:left
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-groups-a:hover span{
|
||||||
|
color: $white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#myDropdown a:hover {background-color: $dropdown-link-hover-bg; color:$white !important;}
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ $enable-flex: true;
|
|||||||
$white: #fff;
|
$white: #fff;
|
||||||
$black: #000;
|
$black: #000;
|
||||||
|
|
||||||
|
$span-text-color: #6B6B6B !default;
|
||||||
|
$span-text-color-hover: #6B6B6B !default;
|
||||||
|
|
||||||
$color-bg: $white !default;
|
$color-bg: $white !default;
|
||||||
$color-fg: #222222 !default;
|
$color-fg: #222222 !default;
|
||||||
|
|
||||||
@ -349,6 +352,10 @@ $grid-hover-fg-color: $color-fg !default;
|
|||||||
|
|
||||||
$btn-copied-color-fg: $active-color !default;
|
$btn-copied-color-fg: $active-color !default;
|
||||||
|
|
||||||
|
$quick-search-a-text-color: $black !default;
|
||||||
|
$quick-search-span-text: $span-text-color !default;
|
||||||
|
$quick-search-span-text-hover: $span-text-color-hover !default;
|
||||||
|
$quick-search-info-icon: #646C82 !default;
|
||||||
/** ERD **/
|
/** ERD **/
|
||||||
$erd-row-padding: 0.25rem;
|
$erd-row-padding: 0.25rem;
|
||||||
$erd-node-border-color: $border-color !default;
|
$erd-node-border-color: $border-color !default;
|
||||||
|
@ -122,6 +122,11 @@ $datagrid-selected-color: $color-primary-fg;
|
|||||||
|
|
||||||
$select2-placeholder: #999;
|
$select2-placeholder: #999;
|
||||||
|
|
||||||
|
$span-text-color: #9D9FA1 !default;
|
||||||
|
$span-text-color-hover: $white !default;
|
||||||
|
$quick-search-a-text-color: $white !default;
|
||||||
|
$quick-search-info-icon: #8A8A8A !default;
|
||||||
|
|
||||||
/* ERD */
|
/* ERD */
|
||||||
$erd-row-padding: 0.25rem;
|
$erd-row-padding: 0.25rem;
|
||||||
$erd-node-border-color: $border-color;
|
$erd-node-border-color: $border-color;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
$white: #FFFFFF;
|
$white: #FFFFFF;
|
||||||
|
$black: #000;
|
||||||
$color-bg: #010B15;
|
$color-bg: #010B15;
|
||||||
$color-fg: $white;
|
$color-fg: $white;
|
||||||
|
|
||||||
@ -200,4 +201,7 @@ $grid-hover-fg-color: #010B15;
|
|||||||
|
|
||||||
$btn-copied-color-fg: #010B15;
|
$btn-copied-color-fg: #010B15;
|
||||||
|
|
||||||
|
$span-text-color: #9D9FA1 !default;
|
||||||
|
$span-text-color-hover: $black !default;
|
||||||
|
$quick-search-a-text-color: $black !default;
|
||||||
|
$quick-search-info-icon: #8A8A8A !default;
|
||||||
|
@ -582,6 +582,9 @@ define([
|
|||||||
label: gettext('Backup Globals...'),
|
label: gettext('Backup Globals...'),
|
||||||
icon: 'fa fa-save',
|
icon: 'fa fa-save',
|
||||||
enable: menuUtils.menuEnabledServer,
|
enable: menuUtils.menuEnabledServer,
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any server from the browser tree to take Backup of global objects.'),
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: 'backup_server',
|
name: 'backup_server',
|
||||||
module: this,
|
module: this,
|
||||||
@ -591,6 +594,9 @@ define([
|
|||||||
label: gettext('Backup Server...'),
|
label: gettext('Backup Server...'),
|
||||||
icon: 'fa fa-save',
|
icon: 'fa fa-save',
|
||||||
enable: menuUtils.menuEnabledServer,
|
enable: menuUtils.menuEnabledServer,
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any server from the browser tree to take Server Backup.'),
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: 'backup_global_ctx',
|
name: 'backup_global_ctx',
|
||||||
module: this,
|
module: this,
|
||||||
@ -601,6 +607,9 @@ define([
|
|||||||
label: gettext('Backup Globals...'),
|
label: gettext('Backup Globals...'),
|
||||||
icon: 'fa fa-save',
|
icon: 'fa fa-save',
|
||||||
enable: menuUtils.menuEnabledServer,
|
enable: menuUtils.menuEnabledServer,
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any database or schema or table from the browser tree to take Backup.'),
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: 'backup_server_ctx',
|
name: 'backup_server_ctx',
|
||||||
module: this,
|
module: this,
|
||||||
@ -611,6 +620,9 @@ define([
|
|||||||
label: gettext('Backup Server...'),
|
label: gettext('Backup Server...'),
|
||||||
icon: 'fa fa-save',
|
icon: 'fa fa-save',
|
||||||
enable: menuUtils.menuEnabledServer,
|
enable: menuUtils.menuEnabledServer,
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any server from the browser tree to take Server Backup.'),
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: 'backup_object',
|
name: 'backup_object',
|
||||||
module: this,
|
module: this,
|
||||||
@ -622,6 +634,9 @@ define([
|
|||||||
enable: supportedNodes.enabled.bind(
|
enable: supportedNodes.enabled.bind(
|
||||||
null, pgBrowser.treeMenu, menuUtils.backupSupportedNodes
|
null, pgBrowser.treeMenu, menuUtils.backupSupportedNodes
|
||||||
),
|
),
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any database or schema or table from the browser tree to take Backup.'),
|
||||||
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
for (var idx = 0; idx < menuUtils.backupSupportedNodes.length; idx++) {
|
for (var idx = 0; idx < menuUtils.backupSupportedNodes.length; idx++) {
|
||||||
|
@ -113,6 +113,9 @@ define('pgadmin.datagrid', [
|
|||||||
priority: 1,
|
priority: 1,
|
||||||
label: gettext('Query Tool'),
|
label: gettext('Query Tool'),
|
||||||
icon: 'pg-font-icon icon-query-tool',
|
icon: 'pg-font-icon icon-query-tool',
|
||||||
|
data:{
|
||||||
|
'data_disabled': gettext('Please select a database from the browser tree to access Query Tool.'),
|
||||||
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Create context menu
|
// Create context menu
|
||||||
|
@ -177,6 +177,9 @@ define([
|
|||||||
enable: supportedNodes.enabled.bind(
|
enable: supportedNodes.enabled.bind(
|
||||||
null, pgBrowser.treeMenu, menuUtils.supportedNodes
|
null, pgBrowser.treeMenu, menuUtils.supportedNodes
|
||||||
),
|
),
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any database, schema or schema objects from the browser tree to access Grant Wizard Tool.'),
|
||||||
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Add supported menus into the menus list
|
// Add supported menus into the menus list
|
||||||
|
@ -412,6 +412,9 @@ define([
|
|||||||
enable: supportedNodes.enabled.bind(
|
enable: supportedNodes.enabled.bind(
|
||||||
null, pgBrowser.treeMenu, ['table']
|
null, pgBrowser.treeMenu, ['table']
|
||||||
),
|
),
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any table from the browser tree to Import/Export data.'),
|
||||||
|
},
|
||||||
}]);
|
}]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -184,6 +184,9 @@ define([
|
|||||||
enable: supportedNodes.enabled.bind(
|
enable: supportedNodes.enabled.bind(
|
||||||
null, pgBrowser.treeMenu, menuUtils.maintenanceSupportedNodes
|
null, pgBrowser.treeMenu, menuUtils.maintenanceSupportedNodes
|
||||||
),
|
),
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any database from the browser tree to do Maintenance.'),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pgBrowser.add_menus(menus);
|
pgBrowser.add_menus(menus);
|
||||||
|
@ -398,6 +398,9 @@ define('tools.restore', [
|
|||||||
enable: supportedNodes.enabled.bind(
|
enable: supportedNodes.enabled.bind(
|
||||||
null, pgBrowser.treeMenu, menuUtils.restoreSupportedNodes
|
null, pgBrowser.treeMenu, menuUtils.restoreSupportedNodes
|
||||||
),
|
),
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select any schema or table from the browser tree to Restore data.'),
|
||||||
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
for (var idx = 0; idx < menuUtils.restoreSupportedNodes.length; idx++) {
|
for (var idx = 0; idx < menuUtils.restoreSupportedNodes.length; idx++) {
|
||||||
|
@ -36,6 +36,9 @@ define([
|
|||||||
enable: this.search_objects_enabled,
|
enable: this.search_objects_enabled,
|
||||||
priority: 1,
|
priority: 1,
|
||||||
label: gettext('Search Objects...'),
|
label: gettext('Search Objects...'),
|
||||||
|
data: {
|
||||||
|
'data_disabled': gettext('Please select a database from the browser tree to search the database objects.'),
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: 'search_objects',
|
name: 'search_objects',
|
||||||
module: this,
|
module: this,
|
||||||
|
@ -70,7 +70,7 @@ describe('For Activity', function(){
|
|||||||
expect(pgBrowser.get_epoch_now).not.toHaveBeenCalled();
|
expect(pgBrowser.get_epoch_now).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('set loggin to false after timeout', function(done){
|
it('set login to false after timeout', function(done){
|
||||||
pgBrowser.log_activity();
|
pgBrowser.log_activity();
|
||||||
expect(pgBrowser.logging_activity).toEqual(true);
|
expect(pgBrowser.logging_activity).toEqual(true);
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
|
44
web/regression/javascript/quick_search/quick_search_spec.js
Normal file
44
web/regression/javascript/quick_search/quick_search_spec.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
|
import { Search } from 'browser/quick_search/trigger_search';
|
||||||
|
|
||||||
|
let container;
|
||||||
|
|
||||||
|
describe('quick search test cases', function () {
|
||||||
|
beforeEach(() => {
|
||||||
|
container = document.createElement('div');
|
||||||
|
document.body.appendChild(container);
|
||||||
|
act(() => {
|
||||||
|
ReactDOM.render(<Search />, container);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.removeChild(container);
|
||||||
|
container = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have rendered quick-search-container', () => {
|
||||||
|
expect(container.firstChild.id).toEqual('quick-search-container');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have 2 childs in quick-search-container', () => {
|
||||||
|
expect(container.firstChild.childNodes.length).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('element should be html element', () => {
|
||||||
|
let inputElement = document.getElementById('live-search-field');
|
||||||
|
expect(inputElement instanceof HTMLElement).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -422,6 +422,7 @@ module.exports = [{
|
|||||||
use: {
|
use: {
|
||||||
loader: 'imports-loader?' +
|
loader: 'imports-loader?' +
|
||||||
'pgadmin.dashboard' +
|
'pgadmin.dashboard' +
|
||||||
|
',pgadmin.browser.quick_search' +
|
||||||
',pgadmin.tools.user_management' +
|
',pgadmin.tools.user_management' +
|
||||||
',pgadmin.browser.object_statistics' +
|
',pgadmin.browser.object_statistics' +
|
||||||
',pgadmin.browser.dependencies' +
|
',pgadmin.browser.dependencies' +
|
||||||
|
@ -186,6 +186,7 @@ var webpackShimConfig = {
|
|||||||
'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'),
|
'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'),
|
||||||
'pgadmin.browser.menu': path.join(__dirname, './pgadmin/browser/static/js/menu'),
|
'pgadmin.browser.menu': path.join(__dirname, './pgadmin/browser/static/js/menu'),
|
||||||
'pgadmin.browser.activity': path.join(__dirname, './pgadmin/browser/static/js/activity'),
|
'pgadmin.browser.activity': path.join(__dirname, './pgadmin/browser/static/js/activity'),
|
||||||
|
'pgadmin.browser.quick_search': path.join(__dirname, './pgadmin/browser/static/js/quick_search'),
|
||||||
'pgadmin.browser.messages': '/browser/js/messages',
|
'pgadmin.browser.messages': '/browser/js/messages',
|
||||||
'pgadmin.browser.node': path.join(__dirname, './pgadmin/browser/static/js/node'),
|
'pgadmin.browser.node': path.join(__dirname, './pgadmin/browser/static/js/node'),
|
||||||
'pgadmin.browser.node.ui': path.join(__dirname, './pgadmin/browser/static/js/node.ui'),
|
'pgadmin.browser.node.ui': path.join(__dirname, './pgadmin/browser/static/js/node.ui'),
|
||||||
|
Loading…
Reference in New Issue
Block a user