Highlight invalid rows when saving data in the edit grid. Fixes #1637

This commit is contained in:
Murtuza Zabuawala 2016-09-02 16:05:00 +01:00 committed by Dave Page
parent e810679592
commit 15df12c924
4 changed files with 149 additions and 43 deletions

View File

@ -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"])

View File

@ -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):

View File

@ -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;
}

View File

@ -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);