Monitor connection and transaction status in the query tool. Fixes #2475
parent
82aa8035c2
commit
8520871bc6
|
@ -886,9 +886,12 @@ class ServerNode(PGChildNodeView):
|
|||
if server is None:
|
||||
return bad_request(gettext("Server not found."))
|
||||
|
||||
# Fetch User Details.
|
||||
user = User.query.filter_by(id=current_user.id).first()
|
||||
if user is None:
|
||||
if current_user and hasattr(current_user, 'id'):
|
||||
# Fetch User Details.
|
||||
user = User.query.filter_by(id=current_user.id).first()
|
||||
if user is None:
|
||||
return unauthorized(gettext("Unauthorized request."))
|
||||
else:
|
||||
return unauthorized(gettext("Unauthorized request."))
|
||||
|
||||
data = request.form if request.form else json.loads(
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
.icon-database-not-connected {
|
||||
background-image: url('{{ url_for('NODE-database.static', filename='img/databasebad.svg') }}') !important;
|
||||
border-radius: 10px
|
||||
border-radius: 10px;
|
||||
background-size: 20px !important;
|
||||
}
|
||||
|
|
|
@ -1438,3 +1438,9 @@ body {
|
|||
.multi-checkbox .check.partial:after {
|
||||
content: "\003F";
|
||||
}
|
||||
|
||||
/* Override default bootstrap popover fonts & size */
|
||||
.popover-content {
|
||||
font-family: 'Open Sans';
|
||||
font-size: 13px;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
// This file contains common utilities functions used in sqleditor modules
|
||||
|
||||
define(['jquery'],
|
||||
function ($) {
|
||||
define(['jquery', 'sources/gettext'],
|
||||
function ($, gettext) {
|
||||
var sqlEditorUtils = {
|
||||
/* Reference link http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
||||
* Modified as per requirement.
|
||||
|
@ -56,6 +56,143 @@ define(['jquery'],
|
|||
capitalizeFirstLetter: function (string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
},
|
||||
|
||||
// Status flag
|
||||
previousStatus: null,
|
||||
|
||||
// This function will fetch the connection status via ajax
|
||||
fetchConnectionStatus: function(url, $el, $status_el) {
|
||||
// If user has switch the browser Tab or Minimized window or
|
||||
// if wcDocker panel is not in focus then don't fire AJAX
|
||||
if (document.visibilityState !== 'visible' ||
|
||||
$el.data('panel-visible') !== 'visible' ) {
|
||||
return;
|
||||
}
|
||||
// Start polling..
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
success: function (res) {
|
||||
if(res && res.data) {
|
||||
var status = res.data.status,
|
||||
msg = res.data.message,
|
||||
is_status_changed = false;
|
||||
|
||||
// Inject CSS as required
|
||||
switch(status) {
|
||||
// Busy
|
||||
case 1:
|
||||
// if received busy status more than once then only
|
||||
if(status == sqlEditorUtils.previousStatus &&
|
||||
!$status_el.hasClass('fa-hourglass-half')) {
|
||||
$status_el.removeClass()
|
||||
.addClass('fa fa-hourglass-half');
|
||||
is_status_changed = true;
|
||||
}
|
||||
break;
|
||||
// Idle in transaction
|
||||
case 2:
|
||||
if(sqlEditorUtils.previousStatus != status &&
|
||||
!$status_el.hasClass('fa-clock-o')) {
|
||||
$status_el.removeClass()
|
||||
.addClass('fa fa-clock-o');
|
||||
is_status_changed = true;
|
||||
}
|
||||
break;
|
||||
// Failed in transaction
|
||||
case 3:
|
||||
if(sqlEditorUtils.previousStatus != status &&
|
||||
!$status_el.hasClass('fa-exclamation-circle')) {
|
||||
$status_el.removeClass()
|
||||
.addClass('fa fa-exclamation-circle');
|
||||
is_status_changed = true;
|
||||
}
|
||||
break;
|
||||
// Failed in transaction with unknown server side error
|
||||
case 4:
|
||||
if(sqlEditorUtils.previousStatus != status &&
|
||||
!$status_el.hasClass('fa-exclamation-triangle')) {
|
||||
$status_el.removeClass()
|
||||
.addClass('fa fa-exclamation-triangle');
|
||||
is_status_changed = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(sqlEditorUtils.previousStatus != status &&
|
||||
!$status_el.hasClass('fa-query_tool_connected')) {
|
||||
$status_el.removeClass()
|
||||
.addClass('fa-custom fa-query-tool-connected');
|
||||
is_status_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
sqlEditorUtils.previousStatus = status;
|
||||
// Set bootstrap popover message
|
||||
if(is_status_changed) {
|
||||
$el.popover('hide');
|
||||
$el.attr('data-content', msg);
|
||||
}
|
||||
} else {
|
||||
// We come here means we did not receive expected response
|
||||
// from server, we need to error out
|
||||
sqlEditorUtils.previousStatus = -99;
|
||||
msg = gettext("An unexpected error occurred - " +
|
||||
"ensure sure you are logged into the application.");
|
||||
$el.attr('data-content', msg);
|
||||
if(!$status_el.hasClass('fa-query-tool-disconnected')) {
|
||||
$el.popover('hide');
|
||||
$status_el.removeClass()
|
||||
.addClass('fa-custom fa-query-tool-disconnected');
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
sqlEditorUtils.previousStatus = -1;
|
||||
var msg = gettext("Transaction status check failed.");
|
||||
if (e.readyState == 0) {
|
||||
msg = gettext("Not connected to the server or the connection to " +
|
||||
"the server has been closed.");
|
||||
} else if (e.responseJSON && e.responseJSON.errormsg) {
|
||||
msg = e.responseJSON.errormsg;
|
||||
}
|
||||
|
||||
// Set bootstrap popover
|
||||
$el.attr('data-content', msg);
|
||||
// Add error class
|
||||
if(!$status_el.hasClass('fa-query-tool-disconnected')) {
|
||||
$el.popover('hide');
|
||||
$status_el.removeClass()
|
||||
.addClass('fa-custom fa-query-tool-disconnected');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// This function will update the connection status
|
||||
updateConnectionStatus: function(url, poll_time) {
|
||||
var $el = $(".connection_status"),
|
||||
$status_el = $($($el).find(".fa-custom"));
|
||||
|
||||
// Apply popover on element
|
||||
$el.popover();
|
||||
|
||||
// To set initial connection status
|
||||
sqlEditorUtils.fetchConnectionStatus(url, $el, $status_el);
|
||||
|
||||
// Calling it again in specified interval
|
||||
setInterval(
|
||||
sqlEditorUtils.fetchConnectionStatus.bind(null, url, $el, $status_el),
|
||||
poll_time * 1000
|
||||
);
|
||||
},
|
||||
|
||||
// Updates the flag for connection status poll
|
||||
updateConnectionStatusFlag: function(status) {
|
||||
var $el = $(".connection_status");
|
||||
if ($el.data('panel-visible') != status) {
|
||||
$el.data('panel-visible', status);
|
||||
}
|
||||
},
|
||||
};
|
||||
return sqlEditorUtils;
|
||||
});
|
||||
|
|
|
@ -149,10 +149,11 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
|
|||
else:
|
||||
sql_grid_data = session['gridData']
|
||||
|
||||
# Use pickle to store the command object which will be used
|
||||
# later by the sql grid module.
|
||||
# Use pickle to store the command object which will be used later by the
|
||||
# sql grid module.
|
||||
sql_grid_data[trans_id] = {
|
||||
'command_obj': pickle.dumps(command_obj, -1) # -1 specify the highest protocol version available
|
||||
# -1 specify the highest protocol version available
|
||||
'command_obj': pickle.dumps(command_obj, -1)
|
||||
}
|
||||
|
||||
# Store the grid dictionary into the session variable
|
||||
|
@ -195,15 +196,20 @@ def panel(trans_id, is_query_tool, editor_title):
|
|||
user_agent = UserAgent(request.headers.get('User-Agent'))
|
||||
|
||||
"""
|
||||
Animations and transitions are not automatically GPU accelerated and by default use browser's slow rendering engine.
|
||||
We need to set 'translate3d' value of '-webkit-transform' property in order to use GPU.
|
||||
After applying this property under linux, Webkit calculates wrong position of the elements so panel contents are not visible.
|
||||
To make it work, we need to explicitly set '-webkit-transform' property to 'none' for .ajs-notifier, .ajs-message, .ajs-modal classes.
|
||||
Animations and transitions are not automatically GPU accelerated and by
|
||||
default use browser's slow rendering engine. We need to set 'translate3d'
|
||||
value of '-webkit-transform' property in order to use GPU. After applying
|
||||
this property under linux, Webkit calculates wrong position of the elements
|
||||
so panel contents are not visible. To make it work, we need to explicitly
|
||||
set '-webkit-transform' property to 'none' for .ajs-notifier,
|
||||
.ajs-message, .ajs-modal classes.
|
||||
|
||||
This issue is only with linux runtime application and observed in Query tool and debugger.
|
||||
When we open 'Open File' dialog then whole Query-tool panel content is not visible though it contains HTML element in back end.
|
||||
This issue is only with linux runtime application and observed in Query
|
||||
tool and debugger. When we open 'Open File' dialog then whole Query tool
|
||||
panel content is not visible though it contains HTML element in back end.
|
||||
|
||||
The port number should have already been set by the runtime if we're running in desktop mode.
|
||||
The port number should have already been set by the runtime if we're
|
||||
running in desktop mode.
|
||||
"""
|
||||
is_linux_platform = False
|
||||
|
||||
|
@ -218,15 +224,18 @@ def panel(trans_id, is_query_tool, editor_title):
|
|||
new_browser_tab = 'false'
|
||||
|
||||
if is_query_tool == 'true':
|
||||
prompt_save_changes = pref.preference('prompt_save_query_changes').get()
|
||||
prompt_save_changes = pref.preference(
|
||||
'prompt_save_query_changes'
|
||||
).get()
|
||||
else:
|
||||
prompt_save_changes = pref.preference('prompt_save_data_changes').get()
|
||||
|
||||
display_connection_status = pref.preference('connection_status').get()
|
||||
|
||||
# Fetch the server details
|
||||
#
|
||||
bgcolor = None
|
||||
fgcolor = None
|
||||
if str(trans_id) in session['gridData']:
|
||||
if 'gridData' in session and str(trans_id) in session['gridData']:
|
||||
# Fetch the object for the specified transaction id.
|
||||
# Use pickle.loads function to get the command object
|
||||
session_obj = session['gridData'][str(trans_id)]
|
||||
|
@ -240,9 +249,12 @@ def panel(trans_id, is_query_tool, editor_title):
|
|||
fgcolor = s.fgcolor or 'black'
|
||||
|
||||
return render_template(
|
||||
"datagrid/index.html", _=gettext, uniqueId=trans_id,
|
||||
"datagrid/index.html",
|
||||
_=gettext,
|
||||
uniqueId=trans_id,
|
||||
is_query_tool=is_query_tool,
|
||||
editor_title=editor_title, script_type_url=sURL,
|
||||
editor_title=editor_title,
|
||||
script_type_url=sURL,
|
||||
is_desktop_mode=app.PGADMIN_RUNTIME,
|
||||
is_linux=is_linux_platform,
|
||||
is_new_browser_tab=new_browser_tab,
|
||||
|
@ -252,7 +264,8 @@ def panel(trans_id, is_query_tool, editor_title):
|
|||
fgcolor=fgcolor,
|
||||
# convert python boolean value to equivalent js boolean literal before
|
||||
# passing it to html template.
|
||||
prompt_save_changes='true' if prompt_save_changes else 'false'
|
||||
prompt_save_changes='true' if prompt_save_changes else 'false',
|
||||
display_connection_status=display_connection_status
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}{{ config.APP_NAME }} - Datagrid{% endblock %}
|
||||
{% block css_link %}
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('sqleditor.static', filename='css/sqleditor.css') }}">
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<style>
|
||||
body {padding: 0px;}
|
||||
|
@ -13,6 +10,14 @@
|
|||
.alertify .ajs-dialog.ajs-shake{-webkit-animation-name: none;}
|
||||
.sql-editor-busy-icon.fa-pulse{-webkit-animation: none;}
|
||||
{% endif %}
|
||||
|
||||
{# Note: If we will display connection status then we have to provide some
|
||||
space to display status icon else we can use all the space available #}
|
||||
.editor-title {
|
||||
width:{% if display_connection_status -%} calc(100% - 43px)
|
||||
{% else %} 100% {%- endif %};
|
||||
}
|
||||
|
||||
</style>
|
||||
<div id="main-editor_panel">
|
||||
<div id="fetching_data" class="wcLoadingIconContainer sql-editor-busy-fetching hide">
|
||||
|
@ -284,7 +289,26 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-title" style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% else %}{{ bgcolor or '#2C76B4' }}{% endif %}; color: {{ fgcolor or 'white' }};"></div>
|
||||
|
||||
<div class="connection_status_wrapper">
|
||||
{% if display_connection_status %}
|
||||
<div style="display: inline-block;"
|
||||
title="{{ _('Connection status (click for details) (<accesskey>+T)') }}">
|
||||
<div class="connection_status" data-container="body"
|
||||
data-toggle="popover" data-placement="bottom"
|
||||
data-content=""
|
||||
data-panel-visible="visible"
|
||||
accesskey="t">
|
||||
<i class="fa-custom fa-query-tool-disconnected" aria-hidden="true"
|
||||
title="{{ _('Connection status (click for details) (<accesskey>+T)') }}">
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="editor-title"
|
||||
style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% else %}{{ bgcolor or '#2C76B4' }}{% endif %}; color: {{ fgcolor or 'white' }};"></div>
|
||||
</div>
|
||||
|
||||
<div id="filter" class="filter-container hidden">
|
||||
<div class="filter-title">Filter</div>
|
||||
<div class="sql-textarea">
|
||||
|
@ -368,7 +392,13 @@
|
|||
{% endif %}
|
||||
|
||||
// Start the query tool.
|
||||
sqlEditorController.start({{ is_query_tool }}, "{{ editor_title }}",
|
||||
script_sql, {{ is_new_browser_tab }}, "{{ server_type }}", {{ prompt_save_changes }});
|
||||
sqlEditorController.start(
|
||||
{{ is_query_tool }},
|
||||
"{{ editor_title }}",
|
||||
script_sql,
|
||||
{{ is_new_browser_tab }},
|
||||
"{{ server_type }}",
|
||||
{{ prompt_save_changes }}
|
||||
);
|
||||
});
|
||||
{% endblock %}
|
||||
|
|
|
@ -21,7 +21,7 @@ from pgadmin.tools.sqleditor.command import QueryToolCommand
|
|||
from pgadmin.utils import PgAdminModule
|
||||
from pgadmin.utils import get_storage_directory
|
||||
from pgadmin.utils.ajax import make_json_response, bad_request, \
|
||||
success_return, internal_server_error
|
||||
success_return, internal_server_error, unauthorized
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.sqlautocomplete.autocomplete import SQLAutoComplete
|
||||
from pgadmin.misc.file_manager import Filemanager
|
||||
|
@ -50,6 +50,14 @@ TX_STATUS__ACTIVE = 1
|
|||
TX_STATUS_INTRANS = 2
|
||||
TX_STATUS_INERROR = 3
|
||||
|
||||
# Connection status codes mapping
|
||||
CONNECTION_STATUS_MESSAGE_MAPPING = dict({
|
||||
0: 'The session is idle and there is no current transaction.',
|
||||
1: 'A command is currently in progress.',
|
||||
2: 'The session is idle in a valid transaction block.',
|
||||
3: 'The session is idle in a failed transaction block.',
|
||||
4: 'The connection with the server is bad.'
|
||||
})
|
||||
|
||||
class SqlEditorModule(PgAdminModule):
|
||||
"""
|
||||
|
@ -107,7 +115,8 @@ class SqlEditorModule(PgAdminModule):
|
|||
'sqleditor.autocomplete',
|
||||
'sqleditor.load_file',
|
||||
'sqleditor.save_file',
|
||||
'sqleditor.query_tool_download'
|
||||
'sqleditor.query_tool_download',
|
||||
'sqleditor.connection_status'
|
||||
]
|
||||
|
||||
def register_preferences(self):
|
||||
|
@ -333,6 +342,24 @@ class SqlEditorModule(PgAdminModule):
|
|||
}
|
||||
)
|
||||
|
||||
self.display_connection_status = self.preference.register(
|
||||
'display', 'connection_status',
|
||||
gettext("Connection status"), 'boolean', True,
|
||||
category_label=gettext('Display'),
|
||||
help_str=gettext('If set to True, the Query Tool '
|
||||
'will monitor and display the connection and '
|
||||
'transaction status.')
|
||||
)
|
||||
|
||||
self.connection_status = self.preference.register(
|
||||
'display', 'connection_status_fetch_time',
|
||||
gettext("Connection status refresh rate"), 'integer', 2,
|
||||
min_val=1, max_val=600,
|
||||
category_label=gettext('Display'),
|
||||
help_str=gettext('The number of seconds between connection/transaction '
|
||||
'status polls.')
|
||||
)
|
||||
|
||||
blueprint = SqlEditorModule(MODULE_NAME, __name__, static_url_path='/static')
|
||||
|
||||
|
||||
|
@ -345,10 +372,10 @@ def index():
|
|||
|
||||
|
||||
def update_session_grid_transaction(trans_id, data):
|
||||
grid_data = session['gridData']
|
||||
grid_data[str(trans_id)] = data
|
||||
|
||||
session['gridData'] = grid_data
|
||||
if 'gridData' in session:
|
||||
grid_data = session['gridData']
|
||||
grid_data[str(trans_id)] = data
|
||||
session['gridData'] = grid_data
|
||||
|
||||
|
||||
def check_transaction_status(trans_id):
|
||||
|
@ -363,6 +390,10 @@ def check_transaction_status(trans_id):
|
|||
Returns: status and connection object
|
||||
|
||||
"""
|
||||
if 'gridData' not in session:
|
||||
return False, unauthorized(gettext("Unauthorized request.")), \
|
||||
None, None, None
|
||||
|
||||
grid_data = session['gridData']
|
||||
|
||||
# Return from the function if transaction id not found
|
||||
|
@ -497,13 +528,23 @@ def start_query_tool(trans_id):
|
|||
else:
|
||||
sql = request.args or request.form
|
||||
|
||||
if 'gridData' not in session:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'result': gettext('Transaction ID not found in the session.'),
|
||||
'can_edit': False, 'can_filter': False
|
||||
}
|
||||
)
|
||||
|
||||
grid_data = session['gridData']
|
||||
|
||||
# Return from the function if transaction id not found
|
||||
if str(trans_id) not in grid_data:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False, 'result': gettext('Transaction ID not found in the session.'),
|
||||
'status': False,
|
||||
'result': gettext('Transaction ID not found in the session.'),
|
||||
'can_edit': False, 'can_filter': False
|
||||
}
|
||||
)
|
||||
|
@ -1809,3 +1850,50 @@ def start_query_download_tool(trans_id):
|
|||
return internal_server_error(
|
||||
errormsg=gettext("Transaction status check failed.")
|
||||
)
|
||||
|
||||
@blueprint.route(
|
||||
'/status/<int:trans_id>',
|
||||
methods=["GET"],
|
||||
endpoint='connection_status'
|
||||
)
|
||||
@login_required
|
||||
def query_tool_status(trans_id):
|
||||
"""
|
||||
The task of this function to return the status of the current connection
|
||||
used in query tool instance with given transaction ID.
|
||||
Args:
|
||||
trans_id: Transaction ID
|
||||
|
||||
Returns:
|
||||
Response with the connection status
|
||||
|
||||
Psycopg2 Status Code Mapping:
|
||||
-----------------------------
|
||||
TRANSACTION_STATUS_IDLE = 0
|
||||
TRANSACTION_STATUS_ACTIVE = 1
|
||||
TRANSACTION_STATUS_INTRANS = 2
|
||||
TRANSACTION_STATUS_INERROR = 3
|
||||
TRANSACTION_STATUS_UNKNOWN = 4
|
||||
"""
|
||||
status, error_msg, conn, trans_obj, \
|
||||
session_obj = check_transaction_status(trans_id)
|
||||
|
||||
if not status and error_msg and type(error_msg) == str:
|
||||
return internal_server_error(
|
||||
errormsg=error_msg
|
||||
)
|
||||
|
||||
if conn and trans_obj and session_obj:
|
||||
status = conn.conn.get_transaction_status()
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': status,
|
||||
'message': gettext(
|
||||
CONNECTION_STATUS_MESSAGE_MAPPING.get(status)
|
||||
)
|
||||
}
|
||||
)
|
||||
else:
|
||||
return internal_server_error(
|
||||
errormsg=gettext("Transaction status check failed.")
|
||||
)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
.sql-editor-busy-fetching {
|
||||
position:absolute;
|
||||
left: 0;
|
||||
top: 41px;
|
||||
top: 65px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
margin:0;
|
||||
|
@ -33,11 +33,6 @@
|
|||
z-index: 0;
|
||||
}
|
||||
|
||||
.editor-title {
|
||||
padding: 4px 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sql-editor-grid-container {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
@ -524,3 +519,56 @@ input.editor-checkbox:focus {
|
|||
#datagrid .slick-row .slick-cell {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* CSS for connection status icon */
|
||||
#output-panel .CodeMirror {
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.connection_status_wrapper {
|
||||
width: 100%;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.editor-title {
|
||||
padding: 4px 5px;
|
||||
font-size: 13px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.connection_status {
|
||||
width: 11px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-top: 2px;
|
||||
margin-left: 12px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.connection_status .fa {
|
||||
font-size: 16px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.connection_status .fa-clock-o,
|
||||
.connection_status .fa-hourglass-half {
|
||||
color: #e8a735;
|
||||
}
|
||||
|
||||
.connection_status .fa-exclamation-circle,
|
||||
.connection_status .fa-exclamation-triangle {
|
||||
color: #d0021b;
|
||||
}
|
||||
|
||||
.connection_status .fa-custom {
|
||||
height: 18px;
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
|
||||
.connection_status .fa-query-tool-connected {
|
||||
content: url('../img/connect.svg');
|
||||
}
|
||||
|
||||
.connection_status .fa-query-tool-disconnected {
|
||||
content: url('../img/disconnect.svg');
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:#2c76b4;}</style></defs><title>connect</title><path class="cls-1" d="M21.27,4.25c.12-.12.12-.18,0-.29-.32-.3-.63-.61-.92-.93-.12-.13-.19-.13-.31,0-.69.71-1.4,1.4-2.1,2.11L17.7,4.9a4.22,4.22,0,0,0-5.26-.82,9.75,9.75,0,0,0-1.69,1.46l-.58.55c-.18-.18-.36-.35-.53-.53s-.14-.1-.23,0c-.31.33-.63.65-1,1-.12.12-.13.18,0,.3.69.67,1.36,1.37,2.05,2,.15.14.13.21,0,.34l-2.05,2c-.12.12-.12.18,0,.29.32.3.63.61.92.93.12.13.19.13.31,0l2-2.05c.12-.13.19-.15.33,0,.61.63,1.24,1.25,1.87,1.87.13.12.12.19,0,.31l-2.07,2.06c-.11.11-.13.17,0,.29q.47.44.91.91c.13.14.2.16.35,0,.67-.69,1.36-1.36,2-2.05.12-.13.19-.12.31,0l2.08,2.09c.09.1.15.12.25,0,.32-.34.66-.67,1-1,.1-.1.07-.15,0-.23l-.61-.6c.48-.45,1-.86,1.41-1.32a4.13,4.13,0,0,0,1.2-3.67,4,4,0,0,0-1.42-2.55c-.14-.12-.14-.19,0-.32C20,5.56,20.61,4.9,21.27,4.25Zm-3.05,7.41c-.43.39-.81.83-1.2,1.23L11.37,7.25l1.42-1.34a2.52,2.52,0,0,1,3.48-.06C17,6.55,17.74,7.27,18.43,8A2.51,2.51,0,0,1,18.22,11.67Z"/><path class="cls-1" d="M15.52,17.16c-2-1.95-8-8-9-9C6.4,8,6.34,8,6.22,8.14c-.3.32-.62.64-.94.94-.11.11-.14.17,0,.28s.35.33.6.57c-.49.45-1,.88-1.42,1.34a4.16,4.16,0,0,0-1.12,4,4.37,4.37,0,0,0,1.33,2.22c.13.13.13.2,0,.33-.65.63-1.28,1.28-1.93,1.91-.13.13-.12.19,0,.31.32.3.62.61.92.92.11.12.18.12.29,0,.53-.55,1.07-1.08,1.62-1.62.15-.15.29-.42.47-.41s.31.25.47.39a4.21,4.21,0,0,0,5.81,0c.5-.47.94-1,1.43-1.53.25.26.43.44.6.63s.14.11.24,0c.3-.32.61-.63.93-.92C15.67,17.38,15.68,17.31,15.52,17.16Zm-3-.38c-.43.43-.84.87-1.27,1.29a2.53,2.53,0,0,1-3.74-.17c-.53-.57-1.1-1.11-1.66-1.64a2.58,2.58,0,0,1,0-3.93c.41-.41.79-.84,1.19-1.27l5.52,5.52C12.57,16.66,12.58,16.7,12.49,16.78Z"/></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:#d0021b;}</style></defs><title>disconnect</title><path class="cls-1" d="M22.49,2.73c.12-.11.12-.18,0-.29-.31-.3-.62-.6-.91-.91-.12-.13-.18-.13-.31,0-.68.69-1.37,1.38-2.07,2.07L19,3.36a4.15,4.15,0,0,0-5.18-.81A9.59,9.59,0,0,0,12.14,4l-.57.54c-.18-.17-.36-.34-.53-.52s-.13-.09-.22,0c-.31.32-.62.64-.95.94-.12.11-.13.18,0,.3.68.66,1.34,1.34,2,2,.14.14.12.21,0,.34l-2,2c-.12.11-.12.18,0,.29.31.29.62.6.91.91.12.13.18.12.3,0l2-2c.12-.13.19-.15.32,0,.6.62,1.22,1.23,1.84,1.84.12.12.12.18,0,.3l-2,2c-.11.11-.13.17,0,.29q.46.43.89.89c.13.13.2.15.34,0,.66-.68,1.34-1.34,2-2,.12-.13.18-.12.3,0l2,2.05c.09.09.14.11.24,0,.32-.33.65-.66,1-1,.1-.09.07-.14,0-.22l-.6-.59c.47-.44.95-.85,1.38-1.3A4.06,4.06,0,0,0,22,7.47,4,4,0,0,0,20.56,5c-.14-.12-.14-.18,0-.31C21.2,4,21.84,3.36,22.49,2.73Zm-3,7.29c-.42.38-.8.81-1.18,1.21L12.75,5.68l1.39-1.32a2.48,2.48,0,0,1,3.42-.06C18.3,5,19,5.7,19.69,6.44A2.47,2.47,0,0,1,19.48,10Z"/><path class="cls-1" d="M14.1,18.75c-1.93-1.92-7.84-7.83-8.87-8.87-.11-.11-.16-.13-.28,0-.3.32-.61.63-.93.93-.11.1-.14.17,0,.28s.35.33.59.56c-.48.45-1,.86-1.4,1.32a4.09,4.09,0,0,0-1.1,3.93,4.3,4.3,0,0,0,1.31,2.19c.13.13.13.2,0,.33-.64.62-1.26,1.26-1.9,1.88-.13.12-.12.19,0,.3.31.29.61.6.91.91.11.12.17.12.29,0,.52-.54,1.06-1.07,1.59-1.59.15-.15.28-.41.46-.41s.31.24.46.38a4.14,4.14,0,0,0,5.72,0c.5-.46.92-1,1.4-1.51.25.26.42.43.59.62s.14.11.24,0c.3-.31.6-.62.91-.91C14.24,19,14.25,18.9,14.1,18.75Zm-3-.37c-.42.42-.82.86-1.25,1.27a2.49,2.49,0,0,1-3.68-.17c-.52-.56-1.08-1.09-1.64-1.62a2.54,2.54,0,0,1,0-3.87c.4-.4.78-.83,1.17-1.25l5.43,5.43C11.2,18.25,11.21,18.29,11.12,18.38Z"/></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -107,6 +107,8 @@ define('tools.querytool', [
|
|||
filter = self.$el.find('#sql_filter');
|
||||
|
||||
$('.editor-title').text(_.unescape(self.editor_title));
|
||||
self.checkConnectionStatus();
|
||||
|
||||
self.filter_obj = CodeMirror.fromTextArea(filter.get(0), {
|
||||
lineNumbers: true,
|
||||
mode: self.handler.server_type === 'gpdb' ? 'text/x-gpsql' : 'text/x-pgsql',
|
||||
|
@ -114,8 +116,12 @@ define('tools.querytool', [
|
|||
widget: '\u2026',
|
||||
},
|
||||
foldGutter: {
|
||||
rangeFinder: CodeMirror.fold.combine(CodeMirror.pgadminBeginRangeFinder, CodeMirror.pgadminIfRangeFinder,
|
||||
CodeMirror.pgadminLoopRangeFinder, CodeMirror.pgadminCaseRangeFinder),
|
||||
rangeFinder: CodeMirror.fold.combine(
|
||||
CodeMirror.pgadminBeginRangeFinder,
|
||||
CodeMirror.pgadminIfRangeFinder,
|
||||
CodeMirror.pgadminLoopRangeFinder,
|
||||
CodeMirror.pgadminCaseRangeFinder
|
||||
),
|
||||
},
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||
extraKeys: pgBrowser.editor_shortcut_keys,
|
||||
|
@ -127,6 +133,20 @@ define('tools.querytool', [
|
|||
matchBrackets: pgAdmin.Browser.editor_options.brace_matching,
|
||||
});
|
||||
|
||||
// Updates connection status flag
|
||||
self.gain_focus = function() {
|
||||
setTimeout(function() {
|
||||
SqlEditorUtils.updateConnectionStatusFlag('visible');
|
||||
}, 100);
|
||||
};
|
||||
// Updates connection status flag
|
||||
self.lost_focus = function() {
|
||||
setTimeout(function() {
|
||||
SqlEditorUtils.updateConnectionStatusFlag('hidden');
|
||||
}, 100);
|
||||
};
|
||||
|
||||
|
||||
// Create main wcDocker instance
|
||||
var main_docker = new wcDocker(
|
||||
'#editor-panel', {
|
||||
|
@ -136,7 +156,7 @@ define('tools.querytool', [
|
|||
'filename': 'css',
|
||||
}),
|
||||
theme: 'webcabin.overrides.css',
|
||||
});
|
||||
});
|
||||
|
||||
var sql_panel = new pgAdmin.Browser.Panel({
|
||||
name: 'sql_panel',
|
||||
|
@ -162,8 +182,12 @@ define('tools.querytool', [
|
|||
widget: '\u2026',
|
||||
},
|
||||
foldGutter: {
|
||||
rangeFinder: CodeMirror.fold.combine(CodeMirror.pgadminBeginRangeFinder, CodeMirror.pgadminIfRangeFinder,
|
||||
CodeMirror.pgadminLoopRangeFinder, CodeMirror.pgadminCaseRangeFinder),
|
||||
rangeFinder: CodeMirror.fold.combine(
|
||||
CodeMirror.pgadminBeginRangeFinder,
|
||||
CodeMirror.pgadminIfRangeFinder,
|
||||
CodeMirror.pgadminLoopRangeFinder,
|
||||
CodeMirror.pgadminCaseRangeFinder
|
||||
),
|
||||
},
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||
extraKeys: pgBrowser.editor_shortcut_keys,
|
||||
|
@ -270,14 +294,47 @@ define('tools.querytool', [
|
|||
|
||||
// Set focus on query tool of active panel
|
||||
p.on(wcDocker.EVENT.GAIN_FOCUS, function() {
|
||||
if (!$(p.$container).hasClass('wcPanelTabContentHidden')) {
|
||||
setTimeout(function() {
|
||||
self.handler.gridView.query_tool_obj.focus();
|
||||
}, 200);
|
||||
var $container = $(this.$container),
|
||||
transId = self.handler.transId;
|
||||
// If transaction id is already set
|
||||
if($container.data('trans-id') != transId) {
|
||||
$container.data('trans-id', transId)
|
||||
}
|
||||
|
||||
if (!$container.hasClass('wcPanelTabContentHidden')) {
|
||||
setTimeout(function () {
|
||||
self.handler.gridView.query_tool_obj.focus();
|
||||
}, 200);
|
||||
// Trigger an event to update connection status flag
|
||||
pgBrowser.Events.trigger(
|
||||
'pgadmin:query_tool:panel:gain_focus:' + transId
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// When any query tool panel lost it focus then
|
||||
p.on(wcDocker.EVENT.LOST_FOCUS, function () {
|
||||
var $container = $(this.$container),
|
||||
transId = $container.data('trans-id');
|
||||
// Trigger an event to update connection status flag
|
||||
if ($container.hasClass('wcPanelTabContentHidden')) {
|
||||
pgBrowser.Events.trigger(
|
||||
'pgadmin:query_tool:panel:lost_focus:' + transId
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Code to update connection status polling flag
|
||||
pgBrowser.Events.on(
|
||||
'pgadmin:query_tool:panel:gain_focus:' + self.handler.transId,
|
||||
self.gain_focus, self
|
||||
);
|
||||
pgBrowser.Events.on(
|
||||
'pgadmin:query_tool:panel:lost_focus:' + self.handler.transId,
|
||||
self.lost_focus, self
|
||||
);
|
||||
}
|
||||
|
||||
// set focus on query tool once loaded
|
||||
|
@ -422,6 +479,34 @@ define('tools.querytool', [
|
|||
});
|
||||
},
|
||||
|
||||
// This function will check the connection status at specific
|
||||
// interval defined by the user in preference
|
||||
checkConnectionStatus: function() {
|
||||
var self = this,
|
||||
preference = window.top.pgAdmin.Browser.get_preference(
|
||||
'sqleditor', 'connection_status_fetch_time'
|
||||
),
|
||||
display_status = window.top.pgAdmin.Browser.get_preference(
|
||||
'sqleditor', 'connection_status'
|
||||
);
|
||||
if(!preference && self.handler.is_new_browser_tab) {
|
||||
preference = window.opener.pgAdmin.Browser.get_preference(
|
||||
'sqleditor', 'connection_status_fetch_time'
|
||||
);
|
||||
display_status = window.opener.pgAdmin.Browser.get_preference(
|
||||
'sqleditor', 'connection_status'
|
||||
);
|
||||
}
|
||||
|
||||
// Only enable pooling if it is enabled
|
||||
if (display_status && display_status.value) {
|
||||
SqlEditorUtils.updateConnectionStatus(
|
||||
url_for('sqleditor.connection_status', {'trans_id': self.transId}),
|
||||
preference.value
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/* To prompt user for unsaved changes */
|
||||
user_confirmation: function(panel, msg) {
|
||||
// If there is anything to save then prompt user
|
||||
|
|
|
@ -268,6 +268,12 @@ module.exports = {
|
|||
}, {
|
||||
test: /\.(eot|svg|ttf|woff|woff2)$/,
|
||||
loader: 'file-loader?name=fonts/[name].[ext]',
|
||||
include: [
|
||||
/node_modules/,
|
||||
path.join(sourceDir, '/css/'),
|
||||
path.join(sourceDir, '/scss/'),
|
||||
path.join(sourceDir, '/fonts/'),
|
||||
],
|
||||
exclude: /vendor/,
|
||||
}, {
|
||||
test: /\.scss$/,
|
||||
|
|
Loading…
Reference in New Issue