2019-01-02 04:24:12 -06:00
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// pgAdmin 4 - PostgreSQL Tools
|
|
|
|
//
|
2021-01-04 04:04:45 -06:00
|
|
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
2019-01-02 04:24:12 -06:00
|
|
|
// This software is released under the PostgreSQL Licence
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
2021-06-29 04:03:36 -05:00
|
|
|
import {removeNodeView} from './node_view';
|
|
|
|
|
2017-06-07 05:23:02 -05:00
|
|
|
define([
|
2019-10-10 01:35:28 -05:00
|
|
|
'sources/gettext', 'jquery', 'underscore', 'sources/pgadmin',
|
2018-10-31 05:30:36 -05:00
|
|
|
'backbone', 'alertify', 'backform', 'backgrid', 'sources/browser/generate_url',
|
|
|
|
'pgadmin.backform', 'pgadmin.backgrid',
|
|
|
|
'pgadmin.browser.node', 'backgrid.select.all',
|
2019-10-10 01:35:28 -05:00
|
|
|
], function(gettext, $, _, pgAdmin, Backbone, Alertify, Backform, Backgrid, generateUrl) {
|
2015-11-17 00:21:09 -06:00
|
|
|
|
|
|
|
var pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
|
|
|
|
|
|
|
|
// It has already been defined.
|
|
|
|
// Avoid running this script again.
|
|
|
|
if (pgBrowser.Collection)
|
|
|
|
return pgBrowser.Collection;
|
|
|
|
|
2016-04-14 06:15:32 -05:00
|
|
|
pgBrowser.Collection = function() {};
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
_.extend(
|
|
|
|
pgBrowser.Collection,
|
|
|
|
_.clone(pgBrowser.Node), {
|
|
|
|
///////
|
|
|
|
// Initialization function
|
|
|
|
// Generally - used to register the menus for this type of node.
|
|
|
|
//
|
|
|
|
// Also, look at pgAdmin.Browser.add_menus(...) function.
|
|
|
|
//
|
|
|
|
// Collection will not have 'Properties' menu.
|
|
|
|
//
|
|
|
|
// NOTE: Override this for each node for initialization purpose
|
|
|
|
Init: function() {
|
|
|
|
if (this.node_initialized)
|
|
|
|
return;
|
|
|
|
this.node_initialized = true;
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
pgAdmin.Browser.add_menus([{
|
|
|
|
name: 'refresh', node: this.type, module: this,
|
|
|
|
applies: ['object', 'context'], callback: 'refresh',
|
|
|
|
priority: 1, label: gettext('Refresh...'),
|
2020-08-13 01:34:00 -05:00
|
|
|
icon: 'fa fa-sync-alt',
|
2018-01-12 01:29:51 -06:00
|
|
|
}]);
|
2016-06-08 07:18:59 -05:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
// show query tool only in context menu of supported nodes.
|
2020-04-06 07:03:07 -05:00
|
|
|
if (pgAdmin.unsupported_nodes && _.indexOf(pgAdmin.unsupported_nodes, this.type) == -1) {
|
|
|
|
if ((this.type == 'database' && this.allowConn) || this.type != 'database') {
|
2018-01-12 01:29:51 -06:00
|
|
|
pgAdmin.Browser.add_menus([{
|
2020-04-20 08:20:20 -05:00
|
|
|
name: 'show_query_tool', node: this.type, module: this,
|
2018-01-12 01:29:51 -06:00
|
|
|
applies: ['context'], callback: 'show_query_tool',
|
2021-01-20 09:52:34 -06:00
|
|
|
priority: 998, label: gettext('Query Tool'),
|
2021-02-10 01:17:52 -06:00
|
|
|
icon: 'pg-font-icon icon-query_tool',
|
2018-01-12 01:29:51 -06:00
|
|
|
}]);
|
2020-04-06 07:03:07 -05:00
|
|
|
|
|
|
|
// show search objects same as query tool
|
|
|
|
pgAdmin.Browser.add_menus([{
|
2020-04-20 08:20:20 -05:00
|
|
|
name: 'search_objects', node: this.type, module: this,
|
2020-04-06 07:03:07 -05:00
|
|
|
applies: ['context'], callback: 'show_search_objects',
|
|
|
|
priority: 997, label: gettext('Search Objects...'),
|
|
|
|
icon: 'fa fa-search',
|
|
|
|
}]);
|
2021-05-25 09:42:57 -05:00
|
|
|
|
|
|
|
// show psql tool same as query tool.
|
2021-06-08 04:28:43 -05:00
|
|
|
if(pgAdmin['enable_psql']) {
|
2021-06-01 09:34:43 -05:00
|
|
|
pgAdmin.Browser.add_menus([{
|
|
|
|
name: 'show_psql_tool', node: this.type, module: this,
|
|
|
|
applies: ['context'], callback: 'show_psql_tool',
|
|
|
|
priority: 998, label: gettext('PSQL Tool (Beta)'),
|
|
|
|
icon: 'fas fa-terminal',
|
|
|
|
}]);
|
|
|
|
}
|
2018-01-12 01:29:51 -06:00
|
|
|
}
|
2016-06-08 07:18:59 -05:00
|
|
|
}
|
2018-01-12 01:29:51 -06:00
|
|
|
},
|
2018-10-31 05:30:36 -05:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
hasId: false,
|
|
|
|
is_collection: true,
|
|
|
|
collection_node: true,
|
|
|
|
// A collection will always have a collection of statistics, when the node
|
|
|
|
// it represent will have some statistics.
|
|
|
|
hasCollectiveStatistics: true,
|
2018-10-31 05:30:36 -05:00
|
|
|
canDrop: true,
|
|
|
|
canDropCascade: true,
|
2021-08-25 06:31:48 -05:00
|
|
|
selectParentNodeOnDelete: false,
|
2018-01-12 01:29:51 -06:00
|
|
|
showProperties: function(item, data, panel) {
|
|
|
|
var that = this,
|
|
|
|
j = panel.$container.find('.obj_properties').first(),
|
|
|
|
view = j.data('obj-view'),
|
|
|
|
content = $('<div></div>')
|
2019-03-14 10:11:16 -05:00
|
|
|
.addClass('pg-prop-content col-12 has-pg-prop-btn-group'),
|
2018-01-12 01:29:51 -06:00
|
|
|
node = pgBrowser.Nodes[that.node],
|
2019-02-14 05:15:01 -06:00
|
|
|
$msgContainer = '',
|
2018-01-12 01:29:51 -06:00
|
|
|
// This will be the URL, used for object manipulation.
|
|
|
|
urlBase = this.generate_url(item, 'properties', data),
|
|
|
|
info = this.getTreeNodeHierarchy.apply(this, [item]),
|
|
|
|
gridSchema = Backform.generateGridColumnsFromModel(
|
2015-12-23 06:41:27 -06:00
|
|
|
info, node.model, 'properties', that.columns
|
2015-11-17 00:21:09 -06:00
|
|
|
),
|
2020-06-17 06:38:23 -05:00
|
|
|
createButtons = function(buttonsList, location, extraClasses) {
|
2018-10-31 05:30:36 -05:00
|
|
|
// Arguments must be non-zero length array of type
|
|
|
|
// object, which contains following attributes:
|
|
|
|
// label, type, extraClasses, register
|
2020-06-17 06:38:23 -05:00
|
|
|
if (buttonsList && _.isArray(buttonsList) && buttonsList.length > 0) {
|
2018-10-31 05:30:36 -05:00
|
|
|
// All buttons will be created within a single
|
|
|
|
// div area.
|
|
|
|
var btnGroup =
|
2019-05-15 06:07:06 -05:00
|
|
|
$('<div class="pg-prop-btn-group"></div>'),
|
2018-10-31 05:30:36 -05:00
|
|
|
// Template used for creating a button
|
|
|
|
tmpl = _.template([
|
2019-05-15 06:07:06 -05:00
|
|
|
'<button tabindex="0" type="<%= type %>" ',
|
2018-10-31 05:30:36 -05:00
|
|
|
'class="btn <%=extraClasses.join(\' \')%>"',
|
|
|
|
'<% if (disabled) { %> disabled="disabled"<% } %> title="<%-tooltip%>">',
|
2020-01-31 02:51:35 -06:00
|
|
|
'<span class="<%= icon %>" role="img"></span><% if (label != "") { %> <%-label%><% } %><span class="sr-only"><%-tooltip%></span></button>',
|
2018-10-31 05:30:36 -05:00
|
|
|
].join(' '));
|
|
|
|
if (location == 'header') {
|
|
|
|
btnGroup.appendTo(that.header);
|
|
|
|
} else {
|
|
|
|
btnGroup.appendTo(that.footer);
|
|
|
|
}
|
|
|
|
if (extraClasses) {
|
|
|
|
btnGroup.addClass(extraClasses);
|
|
|
|
}
|
2020-06-17 06:38:23 -05:00
|
|
|
_.each(buttonsList, function(btn) {
|
2018-10-31 05:30:36 -05:00
|
|
|
// Create the actual button, and append to
|
|
|
|
// the group div
|
|
|
|
|
|
|
|
// icon may not present for this button
|
|
|
|
if (!btn.icon) {
|
|
|
|
btn.icon = '';
|
2018-01-12 01:29:51 -06:00
|
|
|
}
|
2018-10-31 05:30:36 -05:00
|
|
|
var b = $(tmpl(btn));
|
|
|
|
btnGroup.append(b);
|
|
|
|
// Register is a callback to set callback
|
|
|
|
// for certain operation for this button.
|
|
|
|
btn.register(b);
|
|
|
|
});
|
|
|
|
return btnGroup;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}.bind(panel);
|
|
|
|
|
2019-02-14 05:15:01 -06:00
|
|
|
that.collection = new (node.Collection.extend({
|
|
|
|
url: urlBase,
|
|
|
|
model: node.model,
|
|
|
|
}))();
|
2018-10-31 05:30:36 -05:00
|
|
|
// Add the new column for the multi-select menus
|
2018-12-13 05:03:30 -06:00
|
|
|
if((_.isFunction(that.canDrop) ?
|
2019-03-14 10:11:16 -05:00
|
|
|
that.canDrop.apply(that, [data, item]) : that.canDrop) ||
|
2018-12-13 05:03:30 -06:00
|
|
|
(_.isFunction(that.canDropCascade) ?
|
2019-03-14 10:11:16 -05:00
|
|
|
that.canDropCascade.apply(that, [data, item]) : that.canDropCascade)) {
|
2018-10-31 05:30:36 -05:00
|
|
|
gridSchema.columns.unshift({
|
|
|
|
name: 'oid',
|
|
|
|
cell: Backgrid.Extension.SelectRowCell.extend({
|
|
|
|
initialize: function (options) {
|
|
|
|
this.column = options.column;
|
|
|
|
if (!(this.column instanceof Backgrid.Column)) {
|
|
|
|
this.column = new Backgrid.Column(this.column);
|
|
|
|
}
|
|
|
|
|
|
|
|
var column = this.column, model = this.model, $el = this.$el;
|
2020-06-17 06:38:23 -05:00
|
|
|
this.listenTo(column, 'change:renderable', function (col, renderable) {
|
2018-10-31 05:30:36 -05:00
|
|
|
$el.toggleClass('renderable', renderable);
|
|
|
|
});
|
|
|
|
|
2019-02-13 03:25:52 -06:00
|
|
|
if (Backgrid.callByNeed(column.renderable(), column, model)) $el.addClass('renderable width_percent_3');
|
2018-10-31 05:30:36 -05:00
|
|
|
|
|
|
|
this.listenTo(model, 'backgrid:select', this.toggleCheckbox);
|
|
|
|
},
|
|
|
|
toggleCheckbox: function(model, selected) {
|
|
|
|
if (this.checkbox().prop('disabled') === false) {
|
|
|
|
this.checkbox().prop('checked', selected).change();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
render: function() {
|
|
|
|
let model = this.model.toJSON();
|
|
|
|
// canDrop can be set to false for individual row from the server side to disable the checkbox
|
2020-02-24 02:41:00 -06:00
|
|
|
let disabled = ('canDrop' in model && model.canDrop === false);
|
|
|
|
let id = `row-${_.uniqueId(model.oid || model.name)}`;
|
|
|
|
|
|
|
|
this.$el.empty().append(`
|
|
|
|
<div class="custom-control custom-checkbox custom-checkbox-no-label">
|
|
|
|
<input tabindex="-1" type="checkbox" class="custom-control-input" id="${id}" ${disabled?'disabled':''}/>
|
|
|
|
<label class="custom-control-label" for="${id}">
|
2020-04-10 04:22:41 -05:00
|
|
|
<span class="sr-only">` + gettext('Select') + `<span>
|
2020-02-24 02:41:00 -06:00
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
`);
|
2018-10-31 05:30:36 -05:00
|
|
|
this.delegateEvents();
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
headerCell: Backgrid.Extension.SelectAllHeaderCell,
|
|
|
|
});
|
|
|
|
}
|
2020-07-02 05:36:16 -05:00
|
|
|
/* Columns should be always non-editable */
|
|
|
|
gridSchema.columns.forEach((col)=>{
|
|
|
|
col.disabled = true;
|
|
|
|
});
|
2021-02-26 01:15:06 -06:00
|
|
|
|
|
|
|
// Get the list of selected models, before initializing the grid
|
|
|
|
// again.
|
|
|
|
var selectedModels = [];
|
|
|
|
if(!_.isUndefined(that.grid) && 'collection' in that.grid){
|
|
|
|
selectedModels = that.grid.getSelectedModels();
|
|
|
|
}
|
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
// Initialize a new Grid instance
|
2018-10-31 05:30:36 -05:00
|
|
|
that.grid = new Backgrid.Grid({
|
2020-03-24 00:44:05 -05:00
|
|
|
emptyText: gettext('No data found'),
|
2018-10-31 05:30:36 -05:00
|
|
|
columns: gridSchema.columns,
|
2019-02-14 05:15:01 -06:00
|
|
|
collection: that.collection,
|
Improvement in the look and feel of the whole application
Changed the SCSS/CSS for the below third party libraries to adopt the
new look 'n' feel:
- wcDocker
- Alertify dialogs, and notifications
- AciTree
- Bootstrap Navbar
- Bootstrap Tabs
- Bootstrap Drop-Down menu
- Backgrid
- Select2
Adopated the new the look 'n' feel for the dialogs, wizard, properties,
tab panels, tabs, fieldset, subnode control, spinner control, HTML
table, and other form controls.
- Font is changed to Roboto
- Using SCSS variables to define the look 'n' feel
- Designer background images for the Login, and Forget password pages in
'web' mode
- Improved the look 'n' feel for the key selection in the preferences
dialog
- Table classes consistency changes across the application
- File Open and Save dialog list view changes
Author(s): Aditya Toshniwal & Khushboo Vashi
2018-12-21 05:44:55 -06:00
|
|
|
className: 'backgrid table presentation table-bordered table-noouter-border table-hover',
|
2018-10-31 05:30:36 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
var gridView = {
|
|
|
|
'remove': function() {
|
|
|
|
if (this.grid) {
|
|
|
|
if (this.grid.collection) {
|
2019-11-05 03:17:07 -06:00
|
|
|
this.grid.collection.reset([], {silent: true});
|
2018-10-31 05:30:36 -05:00
|
|
|
delete (this.grid.collection);
|
2016-04-15 05:44:01 -05:00
|
|
|
}
|
2018-10-31 05:30:36 -05:00
|
|
|
delete (this.grid);
|
|
|
|
this.grid = null;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
grid: that.grid,
|
|
|
|
};
|
2015-11-17 00:21:09 -06:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
if (view) {
|
|
|
|
// Cache the current IDs for next time
|
|
|
|
$(panel).data('node-prop', urlBase);
|
2016-06-29 06:16:02 -05:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
// Reset the data object
|
|
|
|
j.data('obj-view', null);
|
|
|
|
}
|
2015-11-17 00:21:09 -06:00
|
|
|
|
2021-06-29 04:03:36 -05:00
|
|
|
/* Remove any dom rendered by getNodeView */
|
|
|
|
removeNodeView(j[0]);
|
2018-01-12 01:29:51 -06:00
|
|
|
// Make sure the HTML element is empty.
|
|
|
|
j.empty();
|
|
|
|
j.data('obj-view', gridView);
|
2015-11-17 00:21:09 -06:00
|
|
|
|
2020-02-24 02:41:00 -06:00
|
|
|
$msgContainer = '<div role="status" class="pg-panel-message pg-panel-properties-message">' +
|
2019-02-14 05:15:01 -06:00
|
|
|
gettext('Retrieving data from the server...') + '</div>';
|
|
|
|
|
|
|
|
$msgContainer = $($msgContainer).appendTo(j);
|
|
|
|
|
2018-10-31 05:30:36 -05:00
|
|
|
that.header = $('<div></div>').addClass(
|
2019-03-14 10:11:16 -05:00
|
|
|
'pg-prop-header'
|
2019-02-14 05:15:01 -06:00
|
|
|
);
|
2018-10-31 05:30:36 -05:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
// Render the buttons
|
2018-10-31 05:30:36 -05:00
|
|
|
var buttons = [];
|
|
|
|
|
|
|
|
buttons.push({
|
|
|
|
label: '',
|
|
|
|
type: 'delete',
|
|
|
|
tooltip: gettext('Delete/Drop'),
|
2020-07-20 01:21:21 -05:00
|
|
|
extraClasses: ['btn-primary-icon m-1', 'delete_multiple'],
|
2020-08-13 07:18:04 -05:00
|
|
|
icon: 'fa fa-trash-alt',
|
2018-12-18 03:45:06 -06:00
|
|
|
disabled: (_.isFunction(that.canDrop)) ? !(that.canDrop.apply(self, [data, item])) : (!that.canDrop),
|
2018-10-31 05:30:36 -05:00
|
|
|
register: function(btn) {
|
|
|
|
btn.on('click',() => {
|
|
|
|
onDrop('drop');
|
|
|
|
});
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
buttons.push({
|
|
|
|
label: '',
|
|
|
|
type: 'delete',
|
|
|
|
tooltip: gettext('Drop Cascade'),
|
2020-07-20 01:21:21 -05:00
|
|
|
extraClasses: ['btn-primary-icon m-1', 'delete_multiple_cascade'],
|
2021-02-10 01:17:52 -06:00
|
|
|
icon: 'pg-font-icon icon-drop_cascade',
|
2018-12-18 03:45:06 -06:00
|
|
|
disabled: (_.isFunction(that.canDropCascade)) ? !(that.canDropCascade.apply(self, [data, item])) : (!that.canDropCascade),
|
2018-10-31 05:30:36 -05:00
|
|
|
register: function(btn) {
|
|
|
|
btn.on('click',() => {
|
|
|
|
onDrop('dropCascade');
|
|
|
|
});
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
Improvement in the look and feel of the whole application
Changed the SCSS/CSS for the below third party libraries to adopt the
new look 'n' feel:
- wcDocker
- Alertify dialogs, and notifications
- AciTree
- Bootstrap Navbar
- Bootstrap Tabs
- Bootstrap Drop-Down menu
- Backgrid
- Select2
Adopated the new the look 'n' feel for the dialogs, wizard, properties,
tab panels, tabs, fieldset, subnode control, spinner control, HTML
table, and other form controls.
- Font is changed to Roboto
- Using SCSS variables to define the look 'n' feel
- Designer background images for the Login, and Forget password pages in
'web' mode
- Improved the look 'n' feel for the key selection in the preferences
dialog
- Table classes consistency changes across the application
- File Open and Save dialog list view changes
Author(s): Aditya Toshniwal & Khushboo Vashi
2018-12-21 05:44:55 -06:00
|
|
|
createButtons(buttons, 'header', 'pg-prop-btn-group-above');
|
2018-10-31 05:30:36 -05:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
// Render subNode grid
|
Improvement in the look and feel of the whole application
Changed the SCSS/CSS for the below third party libraries to adopt the
new look 'n' feel:
- wcDocker
- Alertify dialogs, and notifications
- AciTree
- Bootstrap Navbar
- Bootstrap Tabs
- Bootstrap Drop-Down menu
- Backgrid
- Select2
Adopated the new the look 'n' feel for the dialogs, wizard, properties,
tab panels, tabs, fieldset, subnode control, spinner control, HTML
table, and other form controls.
- Font is changed to Roboto
- Using SCSS variables to define the look 'n' feel
- Designer background images for the Login, and Forget password pages in
'web' mode
- Improved the look 'n' feel for the key selection in the preferences
dialog
- Table classes consistency changes across the application
- File Open and Save dialog list view changes
Author(s): Aditya Toshniwal & Khushboo Vashi
2018-12-21 05:44:55 -06:00
|
|
|
content.append('<div class="pg-prop-coll-container"></div>');
|
|
|
|
content.find('.pg-prop-coll-container').append(that.grid.render().$el);
|
2019-02-14 05:15:01 -06:00
|
|
|
|
|
|
|
var timer;
|
2019-05-28 01:30:18 -05:00
|
|
|
var getAjaxHook = function() {
|
|
|
|
$.ajax({
|
|
|
|
url: urlBase,
|
|
|
|
type: 'GET',
|
|
|
|
beforeSend: function(xhr) {
|
|
|
|
xhr.setRequestHeader(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
|
|
|
|
// Generate a timer for the request
|
|
|
|
timer = setTimeout(function() {
|
|
|
|
// notify user if request is taking longer than 1 second
|
|
|
|
|
2021-03-01 00:38:33 -06:00
|
|
|
if (!$msgContainer.text()== 'Failed to retrieve data from the server.')
|
|
|
|
$msgContainer.text(gettext('Retrieving data from the server...'));
|
2019-05-28 01:30:18 -05:00
|
|
|
$msgContainer.removeClass('d-none');
|
|
|
|
if (self.grid) {
|
|
|
|
self.grid.remove();
|
|
|
|
}
|
|
|
|
}, 1000);
|
|
|
|
},
|
|
|
|
}).done(function(res) {
|
2019-03-14 10:11:16 -05:00
|
|
|
clearTimeout(timer);
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
if (_.isUndefined(that.grid) || _.isNull(that.grid)) return;
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
that.data = res;
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
if (that.data.length > 0) {
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
if (!$msgContainer.hasClass('d-none')) {
|
|
|
|
$msgContainer.addClass('d-none');
|
|
|
|
}
|
|
|
|
that.header.appendTo(j);
|
|
|
|
j.append(content);
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
// Listen scroll event to load more rows
|
|
|
|
$('.pg-prop-content').on('scroll', that.__loadMoreRows.bind(that));
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
that.collection.reset(that.data.splice(0, 50));
|
2020-06-16 00:35:10 -05:00
|
|
|
|
|
|
|
// Listen to select all checkbox event
|
|
|
|
that.collection.on('backgrid:select-all', that.__loadAllRows.bind(that));
|
2021-02-26 01:15:06 -06:00
|
|
|
|
|
|
|
// Trigger the backgrid:select event for already selected items
|
|
|
|
// as we have created a new grid instance.
|
|
|
|
if(selectedModels.length > 0) {
|
|
|
|
that.collection.each(function (model) {
|
|
|
|
for(var inx=0; inx < selectedModels.length; inx++){
|
|
|
|
if (selectedModels[inx].id == model.id){
|
|
|
|
model.trigger('backgrid:select', model, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-03-14 10:11:16 -05:00
|
|
|
} else {
|
2019-02-14 05:15:01 -06:00
|
|
|
// Do not listen the scroll event
|
2019-03-14 10:11:16 -05:00
|
|
|
$('.pg-prop-content').off('scroll', that.__loadMoreRows);
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
$msgContainer.text(gettext('No properties are available for the selected object.'));
|
2019-02-14 05:15:01 -06:00
|
|
|
|
2019-03-14 10:11:16 -05:00
|
|
|
}
|
2021-02-26 01:15:06 -06:00
|
|
|
selectedModels = [];
|
2019-05-28 01:30:18 -05:00
|
|
|
}).fail(function(xhr, error) {
|
2019-03-14 10:11:16 -05:00
|
|
|
pgBrowser.Events.trigger(
|
|
|
|
'pgadmin:node:retrieval:error', 'properties', xhr, error.message, item, that
|
|
|
|
);
|
|
|
|
if (!Alertify.pgHandleItemError(xhr, error.message, {
|
|
|
|
item: item,
|
|
|
|
info: info,
|
|
|
|
})) {
|
|
|
|
Alertify.pgNotifier(
|
2019-10-10 01:35:28 -05:00
|
|
|
error, xhr, gettext('Error retrieving properties - %s', error.message || that.label),
|
2019-05-28 01:30:18 -05:00
|
|
|
function(msg) {
|
|
|
|
if(msg === 'CRYPTKEY_SET') {
|
|
|
|
getAjaxHook();
|
|
|
|
} else {
|
|
|
|
console.warn(arguments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2019-03-14 10:11:16 -05:00
|
|
|
}
|
|
|
|
// show failed message.
|
|
|
|
$msgContainer.text(gettext('Failed to retrieve data from the server.'));
|
|
|
|
});
|
2019-05-28 01:30:18 -05:00
|
|
|
};
|
|
|
|
getAjaxHook();
|
2018-10-31 05:30:36 -05:00
|
|
|
|
2019-05-28 01:30:18 -05:00
|
|
|
var onDrop = function(type, confirm=true) {
|
2018-10-31 05:30:36 -05:00
|
|
|
let sel_row_models = this.grid.getSelectedModels(),
|
|
|
|
sel_rows = [],
|
2020-06-17 06:38:23 -05:00
|
|
|
sel_item = pgBrowser.tree.selected(),
|
|
|
|
d = sel_item ? pgBrowser.tree.itemData(sel_item) : null,
|
|
|
|
sel_node = d && pgBrowser.Nodes[d._type],
|
2018-10-31 05:30:36 -05:00
|
|
|
url = undefined,
|
|
|
|
msg = undefined,
|
|
|
|
title = undefined;
|
|
|
|
|
2020-06-17 09:00:56 -05:00
|
|
|
if (sel_node && sel_node.type && sel_node.type == 'coll-constraints') {
|
2020-04-22 05:15:48 -05:00
|
|
|
// In order to identify the constraint type, the type should be passed to the server
|
|
|
|
sel_rows = sel_row_models.map(row => ({id: row.get('oid'), _type: row.get('_type')}));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sel_rows = sel_row_models.map(row => row.id);
|
|
|
|
}
|
2018-10-31 05:30:36 -05:00
|
|
|
|
|
|
|
if (sel_rows.length === 0) {
|
|
|
|
Alertify.alert(gettext('Drop Multiple'),
|
|
|
|
gettext('Please select at least one object to delete.')
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-17 09:00:56 -05:00
|
|
|
if (!sel_node)
|
|
|
|
return;
|
|
|
|
|
2018-10-31 05:30:36 -05:00
|
|
|
if (type === 'dropCascade') {
|
2020-06-17 06:38:23 -05:00
|
|
|
url = sel_node.generate_url(sel_item, 'delete');
|
|
|
|
msg = gettext('Are you sure you want to drop all the selected objects and all the objects that depend on them?');
|
2018-10-31 05:30:36 -05:00
|
|
|
title = gettext('DROP CASCADE multiple objects?');
|
|
|
|
} else {
|
2020-06-17 06:38:23 -05:00
|
|
|
url = sel_node.generate_url(sel_item, 'drop');
|
2018-10-31 05:30:36 -05:00
|
|
|
msg = gettext('Are you sure you want to drop all the selected objects?');
|
|
|
|
title = gettext('DROP multiple objects?');
|
|
|
|
}
|
|
|
|
|
2019-05-28 01:30:18 -05:00
|
|
|
let dropAjaxHook = function() {
|
|
|
|
$.ajax({
|
|
|
|
url: url,
|
|
|
|
type: 'DELETE',
|
|
|
|
data: JSON.stringify({'ids': sel_rows}),
|
|
|
|
contentType: 'application/json; charset=utf-8',
|
|
|
|
}).done(function(res) {
|
|
|
|
if (res.success == 0) {
|
|
|
|
pgBrowser.report_error(res.errormsg, res.info);
|
|
|
|
} else {
|
|
|
|
$(pgBrowser.panels['properties'].panel).removeData('node-prop');
|
|
|
|
pgBrowser.Events.trigger(
|
2020-06-17 06:38:23 -05:00
|
|
|
'pgadmin:browser:tree:refresh', sel_item || pgBrowser.tree.selected(), {
|
2019-05-28 01:30:18 -05:00
|
|
|
success: function() {
|
2020-06-17 06:38:23 -05:00
|
|
|
sel_node.callbacks.selected.apply(sel_node, [sel_item]);
|
2019-05-28 01:30:18 -05:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}).fail(function(xhr, error) {
|
|
|
|
Alertify.pgNotifier(
|
|
|
|
error, xhr,
|
2019-10-10 01:35:28 -05:00
|
|
|
gettext('Error dropping %s', d._label.toLowerCase()),
|
2020-06-17 06:38:23 -05:00
|
|
|
function(alertMsg) {
|
|
|
|
if (alertMsg == 'CRYPTKEY_SET') {
|
2019-05-28 01:30:18 -05:00
|
|
|
onDrop(type, false);
|
2019-03-14 10:11:16 -05:00
|
|
|
} else {
|
|
|
|
$(pgBrowser.panels['properties'].panel).removeData('node-prop');
|
|
|
|
pgBrowser.Events.trigger(
|
2020-06-17 06:38:23 -05:00
|
|
|
'pgadmin:browser:tree:refresh', sel_item || pgBrowser.tree.selected(), {
|
2019-03-14 10:11:16 -05:00
|
|
|
success: function() {
|
2020-06-17 06:38:23 -05:00
|
|
|
sel_node.callbacks.selected.apply(sel_node, [sel_item]);
|
2019-03-14 10:11:16 -05:00
|
|
|
},
|
2019-05-28 01:30:18 -05:00
|
|
|
}
|
|
|
|
);
|
2018-10-31 05:30:36 -05:00
|
|
|
}
|
2019-05-28 01:30:18 -05:00
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
if(confirm) {
|
|
|
|
Alertify.confirm(title, msg, dropAjaxHook, null).show();
|
|
|
|
} else {
|
|
|
|
dropAjaxHook();
|
|
|
|
}
|
2018-10-31 05:30:36 -05:00
|
|
|
return;
|
|
|
|
}.bind(that);
|
2018-01-12 01:29:51 -06:00
|
|
|
},
|
2019-02-14 05:15:01 -06:00
|
|
|
__loadMoreRows: function(e) {
|
|
|
|
let elem = e.currentTarget;
|
|
|
|
if ((elem.scrollHeight - 10) < elem.scrollTop + elem.offsetHeight) {
|
|
|
|
if (this.data.length > 0) {
|
|
|
|
this.collection.add(this.data.splice(0, 50));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-06-16 00:35:10 -05:00
|
|
|
__loadAllRows: function(tmp, checked) {
|
|
|
|
if (this.data.length > 0) {
|
|
|
|
this.collection.add(this.data);
|
|
|
|
this.collection.each(function (model) {
|
|
|
|
model.trigger('backgrid:select', model, checked);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
2018-01-12 01:29:51 -06:00
|
|
|
generate_url: function(item, type) {
|
|
|
|
/*
|
|
|
|
* Using list, and collection functions of a node to get the nodes
|
|
|
|
* under the collection, and properties of the collection respectively.
|
|
|
|
*/
|
|
|
|
var opURL = {
|
2018-10-31 05:30:36 -05:00
|
|
|
'properties': 'obj',
|
|
|
|
'children': 'nodes',
|
|
|
|
'drop': 'obj',
|
2018-01-12 01:29:51 -06:00
|
|
|
},
|
|
|
|
self = this;
|
|
|
|
var collectionPickFunction = function (treeInfoValue, treeInfoKey) {
|
|
|
|
return (treeInfoKey != self.type);
|
|
|
|
};
|
|
|
|
var treeInfo = this.getTreeNodeHierarchy(item);
|
|
|
|
var actionType = type in opURL ? opURL[type] : type;
|
|
|
|
return generateUrl.generate_url(
|
|
|
|
pgAdmin.Browser.URL, treeInfo, actionType, self.node,
|
|
|
|
collectionPickFunction
|
|
|
|
);
|
|
|
|
},
|
2020-04-20 08:20:20 -05:00
|
|
|
show_query_tool: function() {
|
|
|
|
if(pgAdmin.DataGrid) {
|
|
|
|
pgAdmin.DataGrid.show_query_tool('', pgAdmin.Browser.tree.selected());
|
|
|
|
}
|
|
|
|
},
|
|
|
|
show_search_objects: function() {
|
|
|
|
if(pgAdmin.SearchObjects) {
|
|
|
|
pgAdmin.SearchObjects.show_search_objects('', pgAdmin.Browser.tree.selected());
|
|
|
|
}
|
|
|
|
},
|
2021-05-25 09:42:57 -05:00
|
|
|
show_psql_tool: function(args) {
|
|
|
|
var input = args || {},
|
|
|
|
t = pgBrowser.tree,
|
|
|
|
i = input.item || t.selected(),
|
|
|
|
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
|
|
|
pgBrowser.psql.psql_tool(d, i, true);
|
|
|
|
},
|
2018-01-12 01:29:51 -06:00
|
|
|
});
|
2015-11-17 00:21:09 -06:00
|
|
|
|
2016-04-14 06:15:32 -05:00
|
|
|
return pgBrowser.Collection;
|
2015-11-17 00:21:09 -06:00
|
|
|
});
|