Allow queries to be cancelled from the dashboard, and display additional info in the subnode control. Fixes #2597

This commit is contained in:
Murtuza Zabuawala 2017-08-25 16:57:33 +01:00 committed by Dave Page
parent 46c5df4e7b
commit 74db837417
5 changed files with 200 additions and 7 deletions

View File

@ -88,3 +88,83 @@
margin-top: 13px;
display: block;
}
/* CSS to make subnode control look preety in backgrid - START */
.dashboard-tab-container .subnode-dialog .form-control {
font-size: inherit;
}
#server_activity .CodeMirror,
#database_activity .CodeMirror,
#server_activity .CodeMirror-scroll,
#database_activity .CodeMirror-scroll {
height: auto;
max-height:100px;
}
.dashboard-tab-container .sub-node-form > ul.tab-content {
padding-left: 0px;
left: 0px;
}
.dashboard-tab-container .sub-node-form > ul.pg-el-sm-12,
.dashboard-tab-container .sub-node-form > ul.pg-el-md-12,
.dashboard-tab-container .sub-node-form > ul.pg-el-lg-12,
.dashboard-tab-container .sub-node-form > ul.pg-el-xs-12 {
padding: 0px;
}
.dashboard-tab-container .subnode-dialog {
background-color: white;
border: 0px solid #e8e8e8;
}
.dashboard-tab-container .subnode-dialog .control-label {
font-weight: inherit;
}
.dashboard-tab-container .sub-node-form {
padding: 0px 0px 0px 1px;
background-color: #f8f8f8;
}
.dashboard-tab-container .subnode-body {
background-color: #f8f8f8;
}
.dashboard-tab-container .sub-node-form > .nav-tabs {
background-color: #f8f8f8 !important;
}
.dashboard-tab-container .subnode-dialog .nav > li > a {
font-weight: bold;
border-color: #f8f8f8;
}
.dashboard-tab-container .subnode-dialog .nav-tabs > li.active > a,
.dashboard-tab-container .subnode-dialog .nav-tabs > li.active > a:hover {
border-top: 1px solid #cccccc;
border-left: 1px solid #cccccc;
border-right: 1px solid #cccccc;
margin-bottom: -1px;
z-index: 10;
}
.dashboard-tab-container .backgrid .editor {
background-color: #f8f8f8 !important;
border-bottom-color: #f8f8f8;
}
.dashboard-tab-container .backgrid.presentation td.editable:not(.edit-cell) {
padding-right: 25px
}
.dashboard-tab-container .subnode-dialog .pgadmin-control-group {
padding: 5px;
}
.dashboard-tab-container .subnode-dialog .tab-pane {
border: 1px solid #cccccc;
}
/* CSS to make subnode control look preety in backgrid - END */

View File

@ -88,6 +88,68 @@ function(url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid, Flotr,
}
});
// Subnode Cell, which will display subnode control
var SessionDetailsCell = Backgrid.Extension.ObjectCell.extend({
enterEditMode: function () {
// Notify that we are about to enter in edit mode for current cell.
this.model.trigger("enteringEditMode", [this]);
Backgrid.Cell.prototype.enterEditMode.apply(this, arguments);
/* Make sure - we listen to the click event */
this.delegateEvents();
var editable = Backgrid.callByNeed(this.column.editable(), this.column, this.model);
if (editable) {
this.$el.html(
"<i class='fa fa-caret-down subnode-edit-in-process'></i>"
);
this.model.trigger(
"pg-sub-node:opened", this.model, this
);
}
},
render: function(){
this.$el.empty();
this.$el.html(
"<i class='fa fa-caret-right' data-toggle='tooltip' " +
"title='" + gettext('View the active session details') +
"'></i>"
);
this.delegateEvents();
if (this.grabFocus)
this.$el.focus();
return this;
}
});
// Subnode Model
var ActiveQueryDetailsModel = Backbone.Model.extend({
defaults: {
version: null /* Postgres version */
},
schema: [{
id: 'backend_type', label: gettext('Backend type'),
type: 'text', editable: true, disabled: true,
group: gettext('Details'),
visible: function(m) {
return m.get('version') >= 100000;
}
},{
id: 'query_start', label: gettext('Query started at'),
type: 'text', editable: false, disabled: true,
group: gettext('Details')
},{
id: 'state_change', label: gettext('Last state changed at'),
type: 'text', editable: true, disabled: true,
group: gettext('Details')
},{
id: 'query', label: gettext('SQL'),
type: 'text', editable: true, disabled: true,
control: Backform.SqlFieldControl,
group: gettext('Details')
}]
});
pgAdmin.Dashboard = {
init: function() {
if (this.initialized)
@ -582,6 +644,23 @@ function(url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid, Flotr,
}]);
}
var newActiveQueryDetailsModel = new ActiveQueryDetailsModel(
{'version': version}
);
var subNodeFieldsModel = Backform.generateViewSchema(
null, newActiveQueryDetailsModel, 'create', null, null, true
);
// Add cancel active query button
server_activity_columns.unshift({
name: "pg-backform-expand", label: "",
cell: SessionDetailsCell,
cell_priority: -1,
postgres_version: version,
schema: subNodeFieldsModel
});
// Add cancel active query button
server_activity_columns.unshift({
name: "pg-backform-delete", label: "",
@ -739,6 +818,10 @@ function(url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid, Flotr,
bio_stats_refresh
);
// To align subnode controls properly
$(div_server_activity).addClass('pg-el-container');
$(div_server_activity).attr('el', 'sm');
// Render the tabs, but only get data for the activity tab for now
pgAdmin.Dashboard.render_grid(
div_server_activity, sid, did,
@ -895,6 +978,23 @@ function(url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid, Flotr,
}]);
}
var newActiveQueryDetailsModel = new ActiveQueryDetailsModel(
{'version': version}
);
var subNodeFieldsModel = Backform.generateViewSchema(
null, newActiveQueryDetailsModel, 'create', null, null, true
);
// Add cancel active query button
database_activity_columns.unshift({
name: "pg-backform-expand", label: "",
cell: SessionDetailsCell,
cell_priority: -1,
postgres_version: version,
schema: subNodeFieldsModel
});
database_activity_columns.unshift({
name: "pg-backform-delete", label: "",
cell: cancelQueryCell,
@ -1014,6 +1114,10 @@ function(url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid, Flotr,
bio_stats_refresh
);
// To align subnode controls properly
$(div_database_activity).addClass('pg-el-container');
$(div_database_activity).attr('el', 'sm');
// Render the tabs, but only get data for the activity tab for now
pgAdmin.Dashboard.render_grid(
div_database_activity, sid, did, url_for('dashboard.activity'),

View File

@ -7,9 +7,13 @@ SELECT
to_char(backend_start, 'YYYY-MM-DD HH24:MI:SS TZ') AS backend_start,
state,
wait_event_type || ': ' || wait_event AS wait_event,
pg_blocking_pids(pid) AS blocking_pids
pg_blocking_pids(pid) AS blocking_pids,
query,
to_char(state_change, 'YYYY-MM-DD HH24:MI:SS TZ') AS state_change,
to_char(query_start, 'YYYY-MM-DD HH24:MI:SS TZ') AS query_start,
backend_type
FROM
pg_stat_activity
{% if did %}WHERE
datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}
ORDER BY pid
ORDER BY pid

View File

@ -6,9 +6,12 @@ SELECT
client_addr,
to_char(backend_start, 'YYYY-MM-DD HH24:MI:SS TZ') AS backend_start,
state,
CASE WHEN waiting THEN '{{ _('yes') }}' ELSE '{{ _('no') }}' END AS waiting
CASE WHEN waiting THEN '{{ _('yes') }}' ELSE '{{ _('no') }}' END AS waiting,
query,
to_char(state_change, 'YYYY-MM-DD HH24:MI:SS TZ') AS state_change,
to_char(query_start, 'YYYY-MM-DD HH24:MI:SS TZ') AS query_start
FROM
pg_stat_activity
{% if did %}WHERE
datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}
ORDER BY pid
ORDER BY pid

View File

@ -217,12 +217,14 @@
postRender: function(model, column) {
var editor = this,
el = this.el,
columns_length = this.columns_length;
columns_length = this.columns_length,
// To render schema directly from Backgrid cell we use columns schema attribute
schema = this.schema.length ? this.schema : this.column.get('schema');
if (column != null && column.get("name") != this.column.get("name"))
return false;
if (!_.isArray(this.schema)) throw new TypeError("schema must be an array");
if (!_.isArray(schema)) throw new TypeError("schema must be an array");
// Create a Backbone model from our object if it does not exist
var $dialog = this.createDialog(columns_length);
@ -235,7 +237,7 @@
var back_el = $dialog.find('form.form-dialog');
this.objectView = new Backform.Dialog({
el: back_el, model: this.model, schema: this.schema,
el: back_el, model: this.model, schema: schema,
tabPanelClassName: function() {
return 'sub-node-form col-sm-12';
}