public inbox for [email protected]
help / color / mirror / Atom feedFrom: Murtuza Zabuawala <[email protected]>
To: pgadmin-hackers <[email protected]>
Subject: PATCH: Highlight a row at fault (pgAdmin4)
Date: Fri, 2 Sep 2016 20:06:21 +0530
Message-ID: <CAKKotZTD_V9tqdgeLYEyKCKSwQ1KaaTTi1DREShxxTzPJ2656Q@mail.gmail.com> (raw)
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgadmin-hackers>
Hi,
PFA patch to highlight a row at fault when user try to save invalid value
in the grid.
Please review.
--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers
Attachments:
[application/octet-stream] slickgrid_highlight_row.patch (16.1K, 3-slickgrid_highlight_row.patch)
download | inline diff:
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index 1ddcdeb..607d0ec 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -584,13 +584,18 @@ def save(trans_id):
'result': gettext('No primary key found for this object, so unable to save records.')}
)
- status, res, query_res = trans_obj.save(changed_data)
+ status, res, query_res, _rowid = trans_obj.save(changed_data)
else:
status = False
res = error_msg
query_res = None
- return make_json_response(data={'status': status, 'result': res, 'query_result': query_res})
+ return make_json_response(
+ data={ 'status': status,
+ 'result': res,
+ 'query_result': query_res,
+ '_rowid': _rowid }
+ )
@blueprint.route('/filter/get/<int:trans_id>', methods=["GET"])
diff --git a/web/pgadmin/tools/sqleditor/command.py b/web/pgadmin/tools/sqleditor/command.py
index 0421e98..4b8db6e 100644
--- a/web/pgadmin/tools/sqleditor/command.py
+++ b/web/pgadmin/tools/sqleditor/command.py
@@ -416,7 +416,9 @@ class TableCommand(GridCommand):
res = None
query_res = dict()
count = 0
+ list_of_rowid = []
list_of_sql = []
+ _rowid = None
if conn.connected():
@@ -435,6 +437,7 @@ class TableCommand(GridCommand):
for each_row in changed_data[of_type]:
data = changed_data[of_type][each_row]['data']
data_type = changed_data[of_type][each_row]['data_type']
+ list_of_rowid.append(data.get('__temp_PK'))
# Remove our unique tracking key
data.pop('__temp_PK', None)
sql = render_template("/".join([self.sql_path, 'insert.sql']),
@@ -458,6 +461,7 @@ class TableCommand(GridCommand):
nsp_name=self.nsp_name,
data_type=data_type)
list_of_sql.append(sql)
+ list_of_rowid.append(data)
# For deleted rows
elif of_type == 'deleted':
@@ -468,8 +472,9 @@ class TableCommand(GridCommand):
object_name=self.object_name,
nsp_name=self.nsp_name)
list_of_sql.append(sql)
+ list_of_rowid.append(data)
- for sql in list_of_sql:
+ for i, sql in enumerate(list_of_sql):
if sql:
status, res = conn.execute_void(sql)
rows_affected = conn.rows_affected()
@@ -486,13 +491,14 @@ class TableCommand(GridCommand):
for val in query_res:
if query_res[val]['status']:
query_res[val]['result'] = 'Transaction ROLLBACK'
+ _rowid = list_of_rowid[i]
- return status, res, query_res
+ return status, res, query_res, _rowid
# Commit the transaction if there is no error found
conn.execute_void('COMMIT;')
- return status, res, query_res
+ return status, res, query_res, _rowid
class ViewCommand(GridCommand):
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index e6788f9..64833bd 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -392,3 +392,18 @@ input.editor-checkbox {
.slick-cell.selected {
background-color: #eeeeee !important;
}
+
+/* To highlight all newly inserted rows */
+.grid-canvas .new_row {
+ background: #f3f2d8;
+}
+
+/* To highlight all the updated rows */
+.grid-canvas .updated_row {
+ background: #c1c1c1;
+}
+
+/* To highlight row at fault */
+.grid-canvas .new_row.error, .grid-canvas .updated_row.error {
+ background: #e46b6b;
+}
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
index da45b76..c22fdd6 100644
--- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
@@ -431,6 +431,17 @@ define(
render_grid: function(collection, columns, is_editable) {
var self = this;
+ // This will work as data store and holds all the
+ // inserted/updated/deleted data from grid
+ self.handler.data_store = {
+ updated: {},
+ added: {},
+ staged_rows: {},
+ deleted: {},
+ updated_index: {},
+ added_index: {}
+ };
+
// To store primary keys before they gets changed
self.handler.primary_keys_data = {};
@@ -451,6 +462,7 @@ define(
checkboxSelector = new Slick.CheckboxSelectColumn({
cssClass: "slick-cell-checkboxsel"
});
+
grid_columns.push(checkboxSelector.getColumnDefinition());
_.each(columns, function(c) {
@@ -461,18 +473,15 @@ define(
name: c.label
};
- // If gird is editable then add editor
+ // If grid is editable then add editor
if(is_editable) {
if(c.cell == 'Json') {
options['editor'] = Slick.Editors.JsonText;
- }
- else if(c.cell == 'number') {
+ } else if(c.cell == 'number') {
options['editor'] = Slick.Editors.Text;
- }
- else if(c.cell == 'boolean') {
+ } else if(c.cell == 'boolean') {
options['editor'] = Slick.Editors.Checkbox;
- }
- else {
+ } else {
options['editor'] = Slick.Editors.pgText;
}
}
@@ -483,7 +492,6 @@ define(
} else if(c.cell == 'boolean') {
options['formatter'] = Slick.Formatters.Checkmark;
}
-
grid_columns.push(options)
});
@@ -506,6 +514,26 @@ define(
row['__temp_PK'] = epicRandomString(15);
});
+ // Add-on function which allow us to identify the faulty row after insert/update
+ // and apply css accordingly
+ collection.getItemMetadata = function(i) {
+ var res = {}, cssClass = 'normal_row';
+ if (_.has(self.handler, 'data_store')) {
+ if (i in self.handler.data_store.added_index) {
+ cssClass = 'new_row';
+ if (self.handler.data_store.added[self.handler.data_store.added_index[i]].err) {
+ cssClass += ' error';
+ }
+ } else if (i in self.handler.data_store.updated_index) {
+ cssClass = 'updated_row';
+ if (self.handler.data_store.updated[self.handler.data_store.updated_index[i]].err) {
+ cssClass += ' error';
+ }
+ }
+ }
+ return {'cssClasses': cssClass};
+ }
+
var grid = new Slick.Grid($data_grid, collection, grid_columns, grid_options);
grid.registerPlugin( new Slick.AutoTooltips({ enableForHeaderCells: false }) );
grid.setSelectionModel(new Slick.RowSelectionModel({selectActiveRow: false}));
@@ -522,15 +550,6 @@ define(
self.handler.slickgrid = grid;
- // This will work as data store and holds all the
- // inserted/updated/deleted data from grid
- self.handler.data_store = {
- updated: {},
- added: {},
- staged_rows: {},
- deleted: {}
- };
-
// Listener function to watch selected rows from grid
if (editor_data.selection) {
editor_data.selection.onSelectedRangesChanged.subscribe(function(e, args) {
@@ -634,27 +653,37 @@ define(
var changed_column = args.grid.getColumns()[args.cell].field, // Current filed name
updated_data = args.item[changed_column], // New value for current field
_pk = args.item.__temp_PK || null, // Unique key to identify row
- col_val = {},
+ column_data = {},
_type;
- col_val[changed_column] = updated_data;
+ column_data[changed_column] = updated_data;
if(_pk) {
// Check if it is in newly added row by user?
if(_pk in self.handler.data_store.added) {
- _.extend(self.handler.data_store.added[_pk]['data'], col_val);
+ _.extend(
+ self.handler.data_store.added[_pk]['data'],
+ column_data);
//Find type for current column
+ self.handler.data_store.added[_pk]['err'] = false
self.handler.data_store.added[_pk]['data_type'][changed_column] = _.where(this.columns, {name: changed_column})[0]['type'];
// Check if it is updated data from existing rows?
} else if(_pk in self.handler.data_store.updated) {
- _.extend(self.handler.data_store.updated[_pk]['data'], col_val);
+ _.extend(
+ self.handler.data_store.updated[_pk], {
+ 'data': column_data,
+ 'err': false
+ }
+ );
//Find type for current column
self.handler.data_store.updated[_pk]['data_type'][changed_column] = _.where(this.columns, {name: changed_column})[0]['type'];
} else {
// First updated data for this primary key
- self.handler.data_store.updated[_pk] = {};
- self.handler.data_store.updated[_pk]['data'] = col_val;
- self.handler.data_store.updated[_pk]['primary_keys'] = self.handler.primary_keys_data[_pk];
+ self.handler.data_store.updated[_pk] = {
+ 'err': false, 'data': column_data,
+ 'primary_keys': self.handler.primary_keys_data[_pk]
+ };
+ self.handler.data_store.updated_index[args.row] = _pk;
// Find & add column data type for current changed column
var temp = {};
temp[changed_column] = _.where(this.columns, {name: changed_column})[0]['type'];
@@ -670,14 +699,14 @@ define(
// self.handler.data_store.added will holds all the newly added rows/data
var _key = epicRandomString(10),
column = args.column,
- item = args.item;
+ item = args.item, data_length = this.grid.getDataLength();
if(item) {
item.__temp_PK = _key;
}
collection.push(item);
- self.handler.data_store.added[_key] = {};
- self.handler.data_store.added[_key]['data'] = item;
+ self.handler.data_store.added[_key] = {'err': false, 'data': item};
+ self.handler.data_store.added_index[data_length] = _key;
// Fetch data type & add it for the column
var temp = {};
temp[column.field] = _.where(this.columns, {name: column.field})[0]['type'];
@@ -1861,8 +1890,7 @@ define(
grid.resetActiveCell();
grid.setData(data, true);
grid.setSelectedRows([]);
- grid.invalidateAllRows();
- grid.render();
+ grid.invalidate();
// Nothing to copy or delete here
$("#btn-delete-row").prop('disabled', true);
$("#btn-copy-row").prop('disabled', true);
@@ -1951,12 +1979,12 @@ define(
contentType: "application/json",
data: JSON.stringify(self.data_store),
success: function(res) {
+ var grid = self.slickgrid,
+ data = grid.getData();;
if (res.data.status) {
// Remove deleted rows from client as well
if(is_deleted) {
- var grid = self.slickgrid,
- data = grid.getData(),
- rows = grid.getSelectedRows();
+ var rows = grid.getSelectedRows();
// Reverse the deletion from array
// so that when we remove it does not affect index
rows = rows.sort().reverse();
@@ -1965,23 +1993,41 @@ define(
});
grid.setData(data, true);
grid.setSelectedRows([]);
- grid.invalidateAllRows();
- grid.render();
}
// Reset data store
- self.data_store.updated = {};
- self.data_store.added = {};
- self.data_store.deleted = {};
+ self.data_store = {
+ 'added': {},
+ 'updated': {},
+ 'deleted': {},
+ 'added_index': {},
+ 'updated_index': {}
+ }
+
// Reset old primary key data now
self.primary_keys_data = {};
+
// Clear msgs after successful save
$('.sql-editor-message').html('');
} else {
+ // Something went wrong while saving data on the db server
self.trigger('pgadmin-sqleditor:loading-icon:hide');
$("#btn-flash").prop('disabled', false);
$('.sql-editor-message').text(res.data.result);
- self.gridView.messages_panel.focus();
+ var err_msg = S('{{ _('%s.') }}').sprintf(res.data.result).value();
+ alertify.notify(err_msg, 'error', 20);
+
+ // To highlight the row at fault
+ if(_.has(res.data, '_rowid') &&
+ (!_.isUndefined(res.data._rowid)|| !_.isNull(res.data._rowid))) {
+ var _row_index = self._find_rowindex(res.data._rowid);
+ if(_row_index in self.data_store.added_index) {
+ self.data_store.added[self.data_store.added_index[_row_index]].err = true
+ } else if (_row_index in self.data_store.updated_index) {
+ self.data_store.updated[self.data_store.updated_index[_row_index]].err = true
+ }
+ }
+ grid.gotoCell(_row_index, 1);
}
// Update the sql results in history tab
@@ -1992,6 +2038,8 @@ define(
'total_time': self.total_time, 'message': r.result
});
});
+
+ grid.invalidate();
},
error: function(e) {
if (e.readyState == 0) {
@@ -2012,6 +2060,38 @@ define(
}
},
+ // Find index of row at fault from grid data
+ _find_rowindex: function(rowid) {
+ var self = this;
+ var grid = self.slickgrid,
+ data = grid.getData(), _rowid, count = 0, _idx = -1;
+ // If _rowid is object then it's update/delete operation
+ if(_.isObject(rowid)) {
+ _rowid = rowid;
+ } else if (_.isString(rowid)) { // Insert opration
+ _rowid = { '__temp_PK': rowid };
+ } else {
+ // Something is wrong with unique id
+ return _idx;
+ }
+
+ _.find(data, function(d) {
+ // search for unique id in row data if found than its the row
+ // which error out on server side
+ var tmp = []; //_.findWhere needs array of object to work
+ tmp.push(d);
+ if(_.findWhere(tmp, _rowid)) {
+ _idx = count;
+ // Now exit the loop by returning true
+ return true;
+ }
+ count++;
+ });
+
+ // Not able to find in grid Data
+ return _idx;
+ },
+
// Save as
_save_as: function() {
return this._save(true);
view thread (2+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: PATCH: Highlight a row at fault (pgAdmin4)
In-Reply-To: <CAKKotZTD_V9tqdgeLYEyKCKSwQ1KaaTTi1DREShxxTzPJ2656Q@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox