mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 10:10:19 -06:00
Add a (configurable) limit to the number of pgAgent job history rows displayed on the statistics tab. Fixes #3072
This commit is contained in:
parent
fa1854bd85
commit
8ec51412c3
Binary file not shown.
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 110 KiB |
@ -45,6 +45,8 @@ Use fields on the *Properties* panel to specify browser properties:
|
||||
|
||||
* Include a value in the *Count rows if estimated less than* field to perform a SELECT count(*) if the estimated number of rows in a table (as read from the table statistics) is below the specified limit. After performing the SELECT count(*), pgAdmin will display the row count. The default is 2000.
|
||||
|
||||
* Provide a value in the *Maximum job history rows* field to limit the number of rows to show on the statistics tab for pgAgent jobs. The default is 250.
|
||||
|
||||
**The Dashboards Node**
|
||||
|
||||
Expand the *Dashboards* node to specify your dashboard display preferences.
|
||||
|
@ -88,6 +88,7 @@ Bug fixes
|
||||
| `Bug #3060 <https://redmine.postgresql.org/issues/3060>`_ - Fix quoting of function names in RE-SQL
|
||||
| `Bug #3066 <https://redmine.postgresql.org/issues/3066>`_ - Ensure column names on indexes on views are properly quoted in RE-SQL
|
||||
| `Bug #3067 <https://redmine.postgresql.org/issues/3067>`_ - Prevent the filter dialog CodeMirror from overflowing onto the button bar of the dialog
|
||||
| `Bug #3072 <https://redmine.postgresql.org/issues/3072>`_ - Add a (configurable) limit to the number of pgAgent job history rows displayed on the statistics tab
|
||||
| `Bug #3073 <https://redmine.postgresql.org/issues/3073>`_ - Ensure the pgAgent job start/end time grid fields synchronise with the subnode control and validate correctly
|
||||
| `Bug #3075 <https://redmine.postgresql.org/issues/3075>`_ - Runtime issue causing Select, Update, and Insert script generation for a table fails to load
|
||||
| `Bug #3077 <https://redmine.postgresql.org/issues/3077>`_ - Remove dependency on standards_conforming_strings being enabled
|
||||
|
@ -37,6 +37,8 @@ from pgadmin.settings import get_setting
|
||||
from pgadmin.utils import PgAdminModule
|
||||
from pgadmin.utils.ajax import make_json_response
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.browser.register_browser_preferences import \
|
||||
register_browser_preferences
|
||||
|
||||
try:
|
||||
import urllib.request as urlreq
|
||||
@ -211,275 +213,7 @@ class BrowserModule(PgAdminModule):
|
||||
return scripts
|
||||
|
||||
def register_preferences(self):
|
||||
self.show_system_objects = self.preference.register(
|
||||
'display', 'show_system_objects',
|
||||
gettext("Show system objects?"), 'boolean', False,
|
||||
category_label=gettext('Display')
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'display', 'enable_acitree_animation',
|
||||
gettext("Enable browser tree animation?"), 'boolean', True,
|
||||
category_label=gettext('Display')
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'display', 'enable_alertify_animation',
|
||||
gettext("Enable dialogue/notification animation?"), 'boolean',
|
||||
True, category_label=gettext('Display')
|
||||
)
|
||||
|
||||
self.table_row_count_threshold = self.preference.register(
|
||||
'properties', 'table_row_count_threshold',
|
||||
gettext("Count rows if estimated less than"), 'integer', 2000,
|
||||
category_label=gettext('Properties')
|
||||
)
|
||||
fields = [
|
||||
{'name': 'key', 'type': 'keyCode', 'label': gettext('Key')},
|
||||
{'name': 'shift', 'type': 'checkbox', 'label': gettext('Shift')},
|
||||
{'name': 'control', 'type': 'checkbox', 'label': gettext('Ctrl')},
|
||||
{'name': 'alt', 'type': 'checkbox', 'label': gettext('Alt/Option')}
|
||||
]
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'browser_tree',
|
||||
gettext('Browser tree'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 66, 'char': 'b'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'tabbed_panel_backward',
|
||||
gettext('Tabbed panel backward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 91, 'char': '['}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'tabbed_panel_forward',
|
||||
gettext('Tabbed panel forward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 93, 'char': ']'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_file',
|
||||
gettext('File main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 70, 'char': 'f'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_object',
|
||||
gettext('Object main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 79, 'char': 'o'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_tools',
|
||||
gettext('Tools main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 76, 'char': 'l'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_help',
|
||||
gettext('Help main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 72, 'char': 'h'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_query_tool',
|
||||
gettext('Open query tool'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 81, 'char': 'q'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_view_data',
|
||||
gettext('View data'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 86, 'char': 'v'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_create',
|
||||
gettext('Create object'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 78, 'char': 'n'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_properties',
|
||||
gettext('Edit object properties'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 69, 'char': 'e'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_delete',
|
||||
gettext('Delete object'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 68, 'char': 'd'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'context_menu',
|
||||
gettext('Open context menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 67, 'char': 'c'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'direct_debugging',
|
||||
gettext('Direct debugging'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 71, 'char': 'g'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'dialog_tab_forward',
|
||||
gettext('Dialog tab forward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': False,
|
||||
'shift': True,
|
||||
'control': True,
|
||||
'key': {'key_code': 93, 'char': ']'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'dialog_tab_backward',
|
||||
gettext('Dialog tab backward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': False,
|
||||
'shift': True,
|
||||
'control': True,
|
||||
'key': {'key_code': 91, 'char': '['}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
register_browser_preferences(self)
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
"""
|
||||
|
293
web/pgadmin/browser/register_browser_preferences.py
Normal file
293
web/pgadmin/browser/register_browser_preferences.py
Normal file
@ -0,0 +1,293 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
from flask_babelex import gettext
|
||||
|
||||
|
||||
def register_browser_preferences(self):
|
||||
self.show_system_objects = self.preference.register(
|
||||
'display', 'show_system_objects',
|
||||
gettext("Show system objects?"), 'boolean', False,
|
||||
category_label=gettext('Display')
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'display', 'enable_acitree_animation',
|
||||
gettext("Enable browser tree animation?"), 'boolean', True,
|
||||
category_label=gettext('Display')
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'display', 'enable_alertify_animation',
|
||||
gettext("Enable dialogue/notification animation?"), 'boolean',
|
||||
True, category_label=gettext('Display')
|
||||
)
|
||||
|
||||
self.table_row_count_threshold = self.preference.register(
|
||||
'properties', 'table_row_count_threshold',
|
||||
gettext("Count rows if estimated less than"), 'integer', 2000,
|
||||
category_label=gettext('Properties')
|
||||
)
|
||||
|
||||
self.pg_agent_row_threshold = self.preference.register(
|
||||
'properties', 'pgagent_row_threshold',
|
||||
gettext("Maximum job history rows"), 'integer', 250,
|
||||
category_label=gettext('Properties'),
|
||||
min_val=1, max_val=9999,
|
||||
help_str=gettext(
|
||||
'The maximum number of history rows to show on '
|
||||
'the Statistics tab for pgAgent jobs'
|
||||
)
|
||||
)
|
||||
|
||||
fields = [
|
||||
{'name': 'key', 'type': 'keyCode', 'label': gettext('Key')},
|
||||
{'name': 'shift', 'type': 'checkbox', 'label': gettext('Shift')},
|
||||
{'name': 'control', 'type': 'checkbox', 'label': gettext('Ctrl')},
|
||||
{'name': 'alt', 'type': 'checkbox', 'label': gettext('Alt/Option')}
|
||||
]
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'browser_tree',
|
||||
gettext('Browser tree'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 66, 'char': 'b'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'tabbed_panel_backward',
|
||||
gettext('Tabbed panel backward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 91, 'char': '['}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'tabbed_panel_forward',
|
||||
gettext('Tabbed panel forward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 93, 'char': ']'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_file',
|
||||
gettext('File main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 70, 'char': 'f'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_object',
|
||||
gettext('Object main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 79, 'char': 'o'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_tools',
|
||||
gettext('Tools main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 76, 'char': 'l'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'main_menu_help',
|
||||
gettext('Help main menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 72, 'char': 'h'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_query_tool',
|
||||
gettext('Open query tool'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 81, 'char': 'q'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_view_data',
|
||||
gettext('View data'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 86, 'char': 'v'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_create',
|
||||
gettext('Create object'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 78, 'char': 'n'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_properties',
|
||||
gettext('Edit object properties'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 69, 'char': 'e'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'sub_menu_delete',
|
||||
gettext('Delete object'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 68, 'char': 'd'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'context_menu',
|
||||
gettext('Open context menu'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 67, 'char': 'c'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'direct_debugging',
|
||||
gettext('Direct debugging'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 71, 'char': 'g'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'dialog_tab_forward',
|
||||
gettext('Dialog tab forward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': False,
|
||||
'shift': True,
|
||||
'control': True,
|
||||
'key': {'key_code': 93, 'char': ']'}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'dialog_tab_backward',
|
||||
gettext('Dialog tab backward'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': False,
|
||||
'shift': True,
|
||||
'control': True,
|
||||
'key': {'key_code': 91, 'char': '['}
|
||||
},
|
||||
category_label=gettext('Keyboard shortcuts'),
|
||||
fields=fields
|
||||
)
|
@ -22,6 +22,7 @@ from pgadmin.browser.server_groups import servers
|
||||
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
|
||||
make_response as ajax_response, gone, success_return
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
|
||||
|
||||
class JobModule(CollectionNodeModule):
|
||||
@ -415,10 +416,16 @@ SELECT EXISTS(
|
||||
otherwise it will return statistics for all the databases in that
|
||||
server.
|
||||
"""
|
||||
pref = Preferences.module('browser')
|
||||
rows_threshold = pref.preference(
|
||||
'pgagent_row_threshold'
|
||||
)
|
||||
|
||||
status, res = self.conn.execute_dict(
|
||||
render_template(
|
||||
"/".join([self.template_path, 'stats.sql']),
|
||||
jid=jid, conn=self.conn
|
||||
jid=jid, conn=self.conn,
|
||||
rows_threshold=rows_threshold.get()
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -19,6 +19,7 @@ from pgadmin.browser.utils import PGChildNodeView
|
||||
from pgadmin.utils.ajax import make_json_response, gone, \
|
||||
make_response as ajax_response, internal_server_error
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
|
||||
@ -570,10 +571,16 @@ SELECT EXISTS(
|
||||
otherwise it will return statistics for all the databases in that
|
||||
server.
|
||||
"""
|
||||
pref = Preferences.module('browser')
|
||||
rows_threshold = pref.preference(
|
||||
'pgagent_row_threshold'
|
||||
)
|
||||
|
||||
status, res = self.conn.execute_dict(
|
||||
render_template(
|
||||
"/".join([self.template_path, 'stats.sql']),
|
||||
jid=jid, jstid=jstid, conn=self.conn
|
||||
jid=jid, jstid=jstid, conn=self.conn,
|
||||
rows_threshold=rows_threshold.get()
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -8,4 +8,5 @@ FROM
|
||||
pgagent.pga_joblog
|
||||
WHERE
|
||||
jlgjobid = {{ jid|qtLiteral }}::integer
|
||||
ORDER BY jlgid DESC;
|
||||
ORDER BY jlgid DESC
|
||||
LIMIT {{ rows_threshold }};
|
||||
|
@ -10,4 +10,5 @@ FROM
|
||||
pgagent.pga_jobsteplog
|
||||
WHERE
|
||||
jsljstid = {{ jstid|qtLiteral }}::integer
|
||||
ORDER BY jslid DESC;
|
||||
ORDER BY jslid DESC
|
||||
LIMIT {{ rows_threshold }};
|
||||
|
@ -0,0 +1,15 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
|
||||
|
||||
class PgAgentCreateTestCase(BaseTestGenerator):
|
||||
def runTest(self):
|
||||
return
|
@ -0,0 +1,89 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import simplejson as json
|
||||
import uuid
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as pgagent_utils
|
||||
|
||||
|
||||
class PgAgentAddTestCase(BaseTestGenerator):
|
||||
"""This class will test the add pgAgent job API"""
|
||||
scenarios = [
|
||||
('Add pgAgent job', dict(url='/browser/pga_job/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
flag, msg = pgagent_utils.is_valid_server_to_run_pgagent(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
flag, msg = pgagent_utils.is_pgagent_installed_on_server(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will adds pgAgent job"""
|
||||
self.pgagent_job = "test_job_add%s" % str(uuid.uuid4())[1:8]
|
||||
data = {
|
||||
'jobname': self.pgagent_job,
|
||||
'jobenabled': True,
|
||||
'jobhostagent': '',
|
||||
'jobjclid': 1,
|
||||
'jobdesc': '',
|
||||
'jsteps': [{
|
||||
'jstid': None,
|
||||
'jstjobid': None,
|
||||
'jstname': 'test_step',
|
||||
'jstdesc': '',
|
||||
'jstenabled': True,
|
||||
'jstkind': True,
|
||||
'jstconntype': True,
|
||||
'jstcode': 'SELECT 1;',
|
||||
'jstconnstr': None,
|
||||
'jstdbname': 'postgres',
|
||||
'jstonerror': 'f',
|
||||
'jstnextrun': '',
|
||||
}],
|
||||
'jschedules': [{
|
||||
'jscid': None,
|
||||
'jscjobid': None,
|
||||
'jscname': 'test_sch',
|
||||
'jscdesc': '',
|
||||
'jscenabled': True,
|
||||
'jscstart': '2050-01-01 12:14:21 +05:30',
|
||||
'jscend': None,
|
||||
'jscweekdays': [False] * 7,
|
||||
'jscmonthdays': [False] * 32,
|
||||
'jscmonths': [False] * 12,
|
||||
'jschours': [False] * 24,
|
||||
'jscminutes': [False] * 60,
|
||||
'jscexceptions': [],
|
||||
}],
|
||||
}
|
||||
|
||||
response = self.tester.post(
|
||||
'{0}{1}/{2}/'.format(
|
||||
self.url, str(utils.SERVER_GROUP), str(self.server_id)
|
||||
),
|
||||
data=json.dumps(data),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
response_data = json.loads(response.data)
|
||||
self.job_id = response_data['node']['_id']
|
||||
is_present = pgagent_utils.verify_pgagent_job(self)
|
||||
self.assertTrue(
|
||||
is_present, "pgAgent job was not created successfully"
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up code"""
|
||||
pgagent_utils.delete_pgagent_job(self)
|
@ -0,0 +1,49 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as pgagent_utils
|
||||
|
||||
|
||||
class PgAgentDeleteTestCase(BaseTestGenerator):
|
||||
"""This class will test the delete pgAgent job API"""
|
||||
scenarios = [
|
||||
('Delete pgAgent job', dict(url='/browser/pga_job/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
flag, msg = pgagent_utils.is_valid_server_to_run_pgagent(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
flag, msg = pgagent_utils.is_pgagent_installed_on_server(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
name = "test_job_delete%s" % str(uuid.uuid4())[1:8]
|
||||
self.job_id = pgagent_utils.create_pgagent_job(self, name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will deletes pgAgent job"""
|
||||
response = self.tester.delete(
|
||||
'{0}{1}/{2}/{3}'.format(
|
||||
self.url, str(utils.SERVER_GROUP), str(self.server_id),
|
||||
str(self.job_id)
|
||||
),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
is_present = pgagent_utils.verify_pgagent_job(self)
|
||||
self.assertFalse(
|
||||
is_present, "pgAgent job was not deleted successfully"
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up code"""
|
||||
pgagent_utils.delete_pgagent_job(self)
|
@ -0,0 +1,51 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
import simplejson as json
|
||||
import uuid
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as pgagent_utils
|
||||
|
||||
|
||||
class PgAgentPutTestCase(BaseTestGenerator):
|
||||
"""This class will test the put pgAgent job API"""
|
||||
scenarios = [
|
||||
('Put pgAgent job', dict(url='/browser/pga_job/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
flag, msg = pgagent_utils.is_valid_server_to_run_pgagent(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
flag, msg = pgagent_utils.is_pgagent_installed_on_server(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
name = "test_job_put%s" % str(uuid.uuid4())[1:8]
|
||||
self.job_id = pgagent_utils.create_pgagent_job(self, name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will put pgAgent job"""
|
||||
data = {
|
||||
"jobdesc": "This is a test comment",
|
||||
}
|
||||
|
||||
response = self.tester.put(
|
||||
'{0}{1}/{2}/{3}'.format(
|
||||
self.url, str(utils.SERVER_GROUP), str(self.server_id),
|
||||
str(self.job_id)
|
||||
),
|
||||
data=json.dumps(data),
|
||||
follow_redirects=True,
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up code"""
|
||||
pgagent_utils.delete_pgagent_job(self)
|
@ -0,0 +1,45 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as pgagent_utils
|
||||
|
||||
|
||||
class PgAgentGetTestCase(BaseTestGenerator):
|
||||
"""This class will test the get pgAgent job API"""
|
||||
scenarios = [
|
||||
('Get pgAgent job', dict(url='/browser/pga_job/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
flag, msg = pgagent_utils.is_valid_server_to_run_pgagent(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
flag, msg = pgagent_utils.is_pgagent_installed_on_server(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
name = "test_job_get%s" % str(uuid.uuid4())[1:8]
|
||||
self.job_id = pgagent_utils.create_pgagent_job(self, name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will get pgAgent job"""
|
||||
response = self.tester.get(
|
||||
'{0}{1}/{2}/{3}'.format(
|
||||
self.url, str(utils.SERVER_GROUP), str(self.server_id),
|
||||
str(self.job_id)
|
||||
),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up code"""
|
||||
pgagent_utils.delete_pgagent_job(self)
|
@ -0,0 +1,45 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as pgagent_utils
|
||||
|
||||
|
||||
class PgAgentStatsTestCase(BaseTestGenerator):
|
||||
"""This class will test the stats pgAgent job API"""
|
||||
scenarios = [
|
||||
('Check the stats of pgAgent job', dict(url='/browser/pga_job/stats/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
flag, msg = pgagent_utils.is_valid_server_to_run_pgagent(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
flag, msg = pgagent_utils.is_pgagent_installed_on_server(self)
|
||||
if not flag:
|
||||
self.skipTest(msg)
|
||||
name = "test_job_get%s" % str(uuid.uuid4())[1:8]
|
||||
self.job_id = pgagent_utils.create_pgagent_job(self, name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will check stats of pgAgent job"""
|
||||
response = self.tester.get(
|
||||
'{0}{1}/{2}/{3}'.format(
|
||||
self.url, str(utils.SERVER_GROUP), str(self.server_id),
|
||||
str(self.job_id)
|
||||
),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up code"""
|
||||
pgagent_utils.delete_pgagent_job(self)
|
175
web/pgadmin/browser/server_groups/servers/pgagent/tests/utils.py
Normal file
175
web/pgadmin/browser/server_groups/servers/pgagent/tests/utils.py
Normal file
@ -0,0 +1,175 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from regression import parent_node_dict
|
||||
from pgadmin.utils import server_utils as server_utils
|
||||
|
||||
|
||||
def is_valid_server_to_run_pgagent(self):
|
||||
"""
|
||||
This function checks if server is valid for the pgAgent job.
|
||||
"""
|
||||
self.server_id = parent_node_dict["server"][-1]["server_id"]
|
||||
server_con = server_utils.connect_server(self, self.server_id)
|
||||
if not server_con["info"] == "Server connected.":
|
||||
raise Exception("Could not connect to server to add pgAgent job.")
|
||||
if "type" in server_con["data"]:
|
||||
if server_con["data"]["type"] == "gpdb":
|
||||
message = "pgAgent is not supported by Greenplum."
|
||||
return False, message
|
||||
return True, None
|
||||
|
||||
|
||||
def is_pgagent_installed_on_server(self):
|
||||
"""
|
||||
This function checks if the pgAgent is installed properly.
|
||||
"""
|
||||
try:
|
||||
connection = utils.get_db_connection(
|
||||
self.server['db'],
|
||||
self.server['username'],
|
||||
self.server['db_password'],
|
||||
self.server['host'],
|
||||
self.server['port'],
|
||||
self.server['sslmode']
|
||||
)
|
||||
pg_cursor = connection.cursor()
|
||||
|
||||
SQL = """
|
||||
SELECT
|
||||
has_table_privilege(
|
||||
'pgagent.pga_job', 'INSERT, SELECT, UPDATE'
|
||||
) has_priviledge
|
||||
WHERE EXISTS(
|
||||
SELECT has_schema_privilege('pgagent', 'USAGE')
|
||||
WHERE EXISTS(
|
||||
SELECT cl.oid FROM pg_class cl
|
||||
LEFT JOIN pg_namespace ns ON ns.oid=relnamespace
|
||||
WHERE relname='pga_job' AND nspname='pgagent'
|
||||
)
|
||||
)
|
||||
"""
|
||||
pg_cursor.execute(SQL)
|
||||
result = pg_cursor.fetchone()
|
||||
if result is None:
|
||||
connection.close()
|
||||
message = "Make sure pgAgent is installed properly."
|
||||
return False, message
|
||||
|
||||
SQL = """
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE
|
||||
table_schema='pgagent' AND table_name='pga_jobstep' AND
|
||||
column_name='jstconnstr'
|
||||
) has_connstr
|
||||
"""
|
||||
pg_cursor.execute(SQL)
|
||||
result = pg_cursor.fetchone()
|
||||
if result is None:
|
||||
connection.close()
|
||||
message = "Make sure pgAgent is installed properly."
|
||||
return False, message
|
||||
|
||||
connection.close()
|
||||
return True, None
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
|
||||
def create_pgagent_job(self, name):
|
||||
"""
|
||||
This function create the pgAgent job.
|
||||
"""
|
||||
try:
|
||||
connection = utils.get_db_connection(
|
||||
self.server['db'],
|
||||
self.server['username'],
|
||||
self.server['db_password'],
|
||||
self.server['host'],
|
||||
self.server['port'],
|
||||
self.server['sslmode']
|
||||
)
|
||||
old_isolation_level = connection.isolation_level
|
||||
connection.set_isolation_level(0)
|
||||
pg_cursor = connection.cursor()
|
||||
pg_cursor.execute(
|
||||
"""
|
||||
INSERT INTO pgagent.pga_job(
|
||||
jobjclid, jobname, jobdesc, jobhostagent, jobenabled
|
||||
) VALUES (
|
||||
1::integer, '{0}'::text, ''::text, ''::text, true
|
||||
) RETURNING jobid;
|
||||
""".format(name)
|
||||
)
|
||||
job_id = pg_cursor.fetchone()
|
||||
connection.set_isolation_level(old_isolation_level)
|
||||
connection.commit()
|
||||
connection.close()
|
||||
return job_id[0]
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
|
||||
def delete_pgagent_job(self):
|
||||
"""
|
||||
This function deletes the pgAgent job.
|
||||
"""
|
||||
try:
|
||||
connection = utils.get_db_connection(
|
||||
self.server['db'],
|
||||
self.server['username'],
|
||||
self.server['db_password'],
|
||||
self.server['host'],
|
||||
self.server['port'],
|
||||
self.server['sslmode']
|
||||
)
|
||||
old_isolation_level = connection.isolation_level
|
||||
connection.set_isolation_level(0)
|
||||
pg_cursor = connection.cursor()
|
||||
pg_cursor.execute(
|
||||
"DELETE FROM pgagent.pga_job "
|
||||
"WHERE jobid = '%s'::integer;" % self.job_id
|
||||
)
|
||||
connection.set_isolation_level(old_isolation_level)
|
||||
connection.commit()
|
||||
connection.close()
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
|
||||
def verify_pgagent_job(self):
|
||||
"""
|
||||
This function deletes the pgAgent job.
|
||||
"""
|
||||
try:
|
||||
connection = utils.get_db_connection(
|
||||
self.server['db'],
|
||||
self.server['username'],
|
||||
self.server['db_password'],
|
||||
self.server['host'],
|
||||
self.server['port'],
|
||||
self.server['sslmode']
|
||||
)
|
||||
pg_cursor = connection.cursor()
|
||||
pg_cursor.execute(
|
||||
"SELECT COUNT(*) FROM pgagent.pga_job "
|
||||
"WHERE jobid = '%s'::integer;" % self.job_id
|
||||
)
|
||||
result = pg_cursor.fetchone()
|
||||
count = result[0]
|
||||
connection.close()
|
||||
return count is not None and int(count) != 0
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
Loading…
Reference in New Issue
Block a user