mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-12-25 08:21:04 -06:00
Port data filter dialog to React. Fixes #7340
This commit is contained in:
parent
a86a8c6a34
commit
6e2ee9a21f
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 45 KiB |
@ -22,6 +22,7 @@ Housekeeping
|
||||
| `Issue #6131 <https://redmine.postgresql.org/issues/6131>`_ - Port query tool to React.
|
||||
| `Issue #6746 <https://redmine.postgresql.org/issues/6746>`_ - Improve the Kerberos Documentation.
|
||||
| `Issue #7255 <https://redmine.postgresql.org/issues/7255>`_ - Ensure the database and schema restriction controls are not shown as a drop-down.
|
||||
| `Issue #7340 <https://redmine.postgresql.org/issues/7340>`_ - Port data filter dialog to React.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
@ -15,5 +15,3 @@ in the edit grid window:
|
||||
.. image:: images/viewdata_filter_dialog.png
|
||||
:alt: View Data filter dialog window
|
||||
:align: center
|
||||
|
||||
.. note:: Use SHIFT + ENTER keys to apply filter.
|
@ -16,7 +16,9 @@ import SchemaView from 'sources/SchemaView';
|
||||
import 'wcdocker';
|
||||
|
||||
/* The entry point for rendering React based view in properties, called in node.js */
|
||||
export function getUtilityView(schema, treeNodeInfo, actionType, formType, container, containerPanel, onSave, extraData, saveBtnName, urlBase, sqlHelpUrl, helpUrl) {
|
||||
export function getUtilityView(schema, treeNodeInfo, actionType, formType, container, containerPanel,
|
||||
onSave, extraData, saveBtnName, urlBase, sqlHelpUrl, helpUrl, isTabView=true) {
|
||||
|
||||
let serverInfo = treeNodeInfo && ('server' in treeNodeInfo) &&
|
||||
pgAdmin.Browser.serverInfo && pgAdmin.Browser.serverInfo[treeNodeInfo.server._id];
|
||||
let inCatalog = treeNodeInfo && ('catalog' in treeNodeInfo);
|
||||
@ -90,6 +92,7 @@ export function getUtilityView(schema, treeNodeInfo, actionType, formType, conta
|
||||
onDataChange={()=>{/*This is intentional (SonarQube)*/}}
|
||||
confirmOnCloseReset={confirmOnReset}
|
||||
hasSQL={false}
|
||||
isTabView={isTabView}
|
||||
disableSqlHelp={sqlHelpUrl == undefined || sqlHelpUrl == ''}
|
||||
disableDialogHelp={helpUrl == undefined || helpUrl == ''}
|
||||
/>, container);
|
||||
|
@ -594,16 +594,18 @@ def validate_filter(sid, did, obj_id):
|
||||
obj_id: Id of currently selected object
|
||||
"""
|
||||
if request.data:
|
||||
filter_sql = json.loads(request.data, encoding='utf-8')
|
||||
filter_data = json.loads(request.data, encoding='utf-8')
|
||||
else:
|
||||
filter_sql = request.args or request.form
|
||||
filter_data = request.args or request.form
|
||||
|
||||
try:
|
||||
# Create object of SQLFilter class
|
||||
sql_filter_obj = SQLFilter(sid=sid, did=did, obj_id=obj_id)
|
||||
|
||||
# Call validate_filter method to validate the SQL.
|
||||
status, res = sql_filter_obj.validate_filter(filter_sql)
|
||||
status, res = sql_filter_obj.validate_filter(filter_data['filter_sql'])
|
||||
if not status:
|
||||
return internal_server_error(errormsg=str(res))
|
||||
except ObjectGone:
|
||||
raise
|
||||
except Exception as e:
|
||||
|
@ -207,13 +207,13 @@ export default class SQLEditor {
|
||||
// This is a callback function to show data when user click on menu item.
|
||||
showViewData(data, i) {
|
||||
const transId = commonUtils.getRandomInt(1, 9999999);
|
||||
showViewData.showViewData(this, pgBrowser, alertify, data, i, transId);
|
||||
showViewData.showViewData(this, pgBrowser, data, i, transId);
|
||||
}
|
||||
|
||||
// This is a callback function to show filtered data when user click on menu item.
|
||||
showFilteredRow(data, i) {
|
||||
const transId = commonUtils.getRandomInt(1, 9999999);
|
||||
showViewData.showViewData(this, pgBrowser, alertify, data, i, transId, true, this.preferences);
|
||||
showViewData.showViewData(this, pgBrowser, data, i, transId, true);
|
||||
}
|
||||
|
||||
// This is a callback function to show query tool when user click on menu item.
|
||||
|
@ -9,21 +9,51 @@
|
||||
import gettext from '../../../../static/js/gettext';
|
||||
import url_for from '../../../../static/js/url_for';
|
||||
import {getDatabaseLabel, generateTitle} from './sqleditor_title';
|
||||
import CodeMirror from 'bundled_codemirror';
|
||||
import * as SqlEditorUtils from 'sources/sqleditor_utils';
|
||||
import $ from 'jquery';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import _ from 'underscore';
|
||||
import Notify from '../../../../static/js/helpers/Notifier';
|
||||
import { isEmptyString } from 'sources/validators';
|
||||
import { getUtilityView } from '../../../../browser/static/js/utility_view';
|
||||
|
||||
export default class DataFilterSchema extends BaseUISchema {
|
||||
constructor(fieldOptions = {}) {
|
||||
super({
|
||||
filter_sql: ''
|
||||
});
|
||||
|
||||
this.fieldOptions = {
|
||||
...fieldOptions,
|
||||
};
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
return [{
|
||||
id: 'filter_sql',
|
||||
label: gettext('Data Filter'),
|
||||
type: 'sql', isFullTab: true, cell: 'text',
|
||||
}];
|
||||
}
|
||||
|
||||
validate(state, setError) {
|
||||
let errmsg = null;
|
||||
|
||||
if (isEmptyString(state.filter_sql)) {
|
||||
errmsg = gettext('Data filter can not be empty.');
|
||||
setError('filter_sql', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
setError('filter_sql', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function showViewData(
|
||||
queryToolMod,
|
||||
pgBrowser,
|
||||
alertify,
|
||||
connectionData,
|
||||
treeIdentifier,
|
||||
transId,
|
||||
filter=false,
|
||||
preferences=null
|
||||
filter=false
|
||||
) {
|
||||
const node = pgBrowser.tree.findNodeByDomElement(treeIdentifier);
|
||||
if (node === undefined || !node.getData()) {
|
||||
@ -49,27 +79,17 @@ export function showViewData(
|
||||
|
||||
const gridUrl = generateUrl(transId, connectionData, node.getData(), parentData);
|
||||
const queryToolTitle = generateViewDataTitle(pgBrowser, treeIdentifier);
|
||||
|
||||
if(filter) {
|
||||
initFilterDialog(alertify, pgBrowser);
|
||||
|
||||
const validateUrl = generateFilterValidateUrl(node.getData(), parentData);
|
||||
|
||||
let okCallback = function(sql) {
|
||||
queryToolMod.launch(transId, gridUrl, false, queryToolTitle, null, sql);
|
||||
};
|
||||
|
||||
$.get(url_for('sqleditor.filter'),
|
||||
function(data) {
|
||||
alertify.filterDialog(gettext('Data Filter - %s', queryToolTitle), data, validateUrl, preferences, okCallback)
|
||||
.resizeTo(pgBrowser.stdW.sm,pgBrowser.stdH.sm);
|
||||
}
|
||||
);
|
||||
// Show Data Filter Dialog
|
||||
showFilterDialog(pgBrowser, node, queryToolMod, transId, gridUrl,
|
||||
queryToolTitle, validateUrl);
|
||||
} else {
|
||||
queryToolMod.launch(transId, gridUrl, false, queryToolTitle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function retrieveNameSpaceName(parentData) {
|
||||
if(!parentData) {
|
||||
return null;
|
||||
@ -130,170 +150,26 @@ function generateFilterValidateUrl(nodeData, parentData) {
|
||||
return url_for('sqleditor.filter_validate', url_params);
|
||||
}
|
||||
|
||||
function initFilterDialog(alertify, pgBrowser) {
|
||||
// Create filter dialog using alertify
|
||||
let filter_editor = null;
|
||||
if (!alertify.filterDialog) {
|
||||
alertify.dialog('filterDialog', function factory() {
|
||||
return {
|
||||
main: function(title, message, validateUrl, preferences, okCallback) {
|
||||
this.set('title', title);
|
||||
this.message = message;
|
||||
this.validateUrl = validateUrl;
|
||||
this.okCallback = okCallback;
|
||||
this.preferences = preferences;
|
||||
},
|
||||
function showFilterDialog(pgBrowser, treeNodeInfo, queryToolMod, transId,
|
||||
gridUrl, queryToolTitle, validateUrl) {
|
||||
|
||||
setup:function() {
|
||||
return {
|
||||
buttons:[{
|
||||
text: '',
|
||||
key: 112,
|
||||
className: 'btn btn-primary-icon pull-left fa fa-question pg-alertify-icon-button',
|
||||
attrs: {
|
||||
name: 'dialog_help',
|
||||
type: 'button',
|
||||
label: gettext('Data Filter'),
|
||||
'aria-label': gettext('Help'),
|
||||
url: url_for('help.static', {
|
||||
'filename': 'viewdata_filter.html',
|
||||
}),
|
||||
},
|
||||
},{
|
||||
text: gettext('Cancel'),
|
||||
key: 27,
|
||||
className: 'btn btn-secondary fa fa-times pg-alertify-button',
|
||||
},{
|
||||
text: gettext('OK'),
|
||||
key: null,
|
||||
className: 'btn btn-primary fa fa-check pg-alertify-button',
|
||||
}],
|
||||
options: {
|
||||
modal: 0,
|
||||
resizable: true,
|
||||
maximizable: false,
|
||||
pinnable: false,
|
||||
autoReset: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
build: function() {
|
||||
var that = this;
|
||||
alertify.pgDialogBuild.apply(that);
|
||||
let schema = new DataFilterSchema();
|
||||
|
||||
// Set the tooltip of OK
|
||||
$(that.__internal.buttons[2].element).attr('title', gettext('Use SHIFT + ENTER to apply filter...'));
|
||||
// Register dialog panel
|
||||
pgBrowser.Node.registerUtilityPanel();
|
||||
var panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md),
|
||||
j = panel.$container.find('.obj_properties').first();
|
||||
panel.title(gettext('Data Filter - %s', queryToolTitle));
|
||||
panel.focus();
|
||||
|
||||
// For sort/filter dialog we capture the keypress event
|
||||
// and on "shift + enter" we clicked on "OK" button.
|
||||
$(that.elements.body).on('keypress', function(evt) {
|
||||
if (evt.shiftKey && evt.keyCode == 13) {
|
||||
that.__internal.buttons[2].element.click();
|
||||
}
|
||||
});
|
||||
},
|
||||
prepare:function() {
|
||||
var that = this,
|
||||
$content = $(this.message),
|
||||
$sql_filter = $content.find('#sql_filter');
|
||||
var helpUrl = url_for('help.static', {'filename': 'viewdata_filter.html'});
|
||||
|
||||
$(this.elements.header).attr('data-title', this.get('title'));
|
||||
$(this.elements.body.childNodes[0]).addClass(
|
||||
'dataview_filter_dialog'
|
||||
);
|
||||
let okCallback = function() {
|
||||
queryToolMod.launch(transId, gridUrl, false, queryToolTitle, null, schema._sessData.filter_sql);
|
||||
};
|
||||
|
||||
this.setContent($content.get(0));
|
||||
// Disable OK button
|
||||
that.__internal.buttons[2].element.disabled = true;
|
||||
|
||||
// Apply CodeMirror to filter text area.
|
||||
filter_editor = this.filter_obj = CodeMirror.fromTextArea($sql_filter.get(0), {
|
||||
lineNumbers: true,
|
||||
mode: 'text/x-pgsql',
|
||||
extraKeys: pgBrowser.editor_shortcut_keys,
|
||||
indentWithTabs: !that.preferences.use_spaces,
|
||||
indentUnit: that.preferences.tab_size,
|
||||
tabSize: that.preferences.tab_size,
|
||||
lineWrapping: that.preferences.wrap_code,
|
||||
autoCloseBrackets: that.preferences.insert_pair_brackets,
|
||||
matchBrackets: that.preferences.brace_matching,
|
||||
screenReaderLabel: gettext('Filter SQL'),
|
||||
});
|
||||
|
||||
let sql_font_size = SqlEditorUtils.calcFontSize(that.preferences.sql_font_size);
|
||||
$(this.filter_obj.getWrapperElement()).css('font-size', sql_font_size);
|
||||
|
||||
setTimeout(function() {
|
||||
// Set focus on editor
|
||||
that.filter_obj.refresh();
|
||||
that.filter_obj.focus();
|
||||
}, 500);
|
||||
|
||||
that.filter_obj.on('change', function() {
|
||||
if (that.filter_obj.getValue() !== '') {
|
||||
that.__internal.buttons[2].element.disabled = false;
|
||||
} else {
|
||||
that.__internal.buttons[2].element.disabled = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
callback: function(closeEvent) {
|
||||
|
||||
if (closeEvent.button.text == gettext('OK')) {
|
||||
var sql = this.filter_obj.getValue();
|
||||
var that = this;
|
||||
closeEvent.cancel = true; // Do not close dialog
|
||||
|
||||
// Make ajax call to include the filter by selection
|
||||
$.ajax({
|
||||
url: that.validateUrl,
|
||||
method: 'POST',
|
||||
async: false,
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(sql),
|
||||
})
|
||||
.done(function(res) {
|
||||
if (res.data.status) {
|
||||
that.okCallback(sql);
|
||||
that.close(); // Close the dialog
|
||||
}
|
||||
else {
|
||||
Notify.alert(
|
||||
gettext('Validation Error'),
|
||||
gettext(res.data.result),
|
||||
function(){
|
||||
filter_editor.focus();
|
||||
},
|
||||
);
|
||||
}
|
||||
})
|
||||
.fail(function(e) {
|
||||
if (e.status === 410){
|
||||
pgBrowser.report_error(gettext('Error filtering rows - %s.', e.statusText), e.responseJSON.errormsg);
|
||||
|
||||
} else {
|
||||
Notify.alert(
|
||||
gettext('Validation Error'),
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
} else if(closeEvent.index == 0) {
|
||||
/* help Button */
|
||||
closeEvent.cancel = true;
|
||||
pgBrowser.showHelp(
|
||||
closeEvent.button.element.name,
|
||||
closeEvent.button.element.getAttribute('url'),
|
||||
null, null
|
||||
);
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
getUtilityView(schema, treeNodeInfo, 'create', 'dialog', j[0], panel,
|
||||
okCallback, [], 'OK', validateUrl, undefined, helpUrl, false);
|
||||
}
|
||||
|
||||
function hasServerOrDatabaseConfiguration(parentData) {
|
||||
|
@ -217,6 +217,7 @@ module.exports = {
|
||||
'tools': path.join(__dirname, './pgadmin/tools/'),
|
||||
'pgadmin.user_management.current_user': regressionDir + '/javascript/fake_current_user',
|
||||
'pgadmin.browser.constants': regressionDir + '/javascript/fake_constants',
|
||||
'pgadmin.help': path.join(__dirname, './pgadmin/help/static/js/help'),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user