@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
99 lines (98 loc) • 4.72 kB
JavaScript
import Emitter from '../../Utilities/Emitter';
import { Subject } from 'rxjs';
import Helper from '../Helpers/Helper';
// ~ 8 hours
const MAX_TIMEFRAME_SIZE = 86400000;
export class DataService {
constructor(adaptable) {
this.adaptable = adaptable;
this.on = (eventName, callback) => this.emitter.on(eventName, callback);
this.emit = (eventName, data) => this.emitter.emit(eventName, data);
this.adaptable = adaptable;
this.emitter = new Emitter();
this.cellDataChangeLogSubject$ = new Subject();
this.cellDataChangeLog$ = this.cellDataChangeLogSubject$.asObservable();
this.rowDataChangeLogSubject$ = new Subject();
this.rowDataChangeLog$ = this.rowDataChangeLogSubject$.asObservable();
this.undoChangeLog = new Map();
this.undoChangeTimers = new Map();
}
destroy() {
this.emitter.destroy();
this.emitter = null;
this.cellDataChangeLogSubject$.complete();
this.cellDataChangeLogSubject$ = null;
this.cellDataChangeLog$ = null;
this.rowDataChangeLogSubject$.complete();
this.rowDataChangeLogSubject$ = null;
this.rowDataChangeLog$ = null;
this.undoChangeLog.clear();
this.undoChangeLog = null;
this.undoChangeTimers.clear();
this.undoChangeTimers = null;
}
CreateCellDataChangedEvent(cellDataChangedInfo) {
if (cellDataChangedInfo.newValue != cellDataChangedInfo.oldValue) {
this.emitter.emitSync('CellDataChanged', cellDataChangedInfo);
this.adaptable.api.eventApi.internalApi.fireCellChangedEvent(cellDataChangedInfo);
const dataChangeLogEntry = this.extractDataChangeLogEntry(cellDataChangedInfo);
this.cellDataChangeLogSubject$.next(dataChangeLogEntry);
}
}
CreateRowDataChangedEvent(rowDataChangedInfo) {
this.emitter.emitSync('RowDataChanged', rowDataChangedInfo);
this.adaptable.api.eventApi.internalApi.fireRowChangedEvent(rowDataChangedInfo);
this.rowDataChangeLogSubject$.next(rowDataChangedInfo);
}
// we need this temporary "shared memory" because the value change and the AG Grid cellChanged event are asynchronous
// in the first phase we keep the undone change
logUndoChange(change) {
const { primaryKeyValue, column, oldValue, newValue } = change;
const undoChangeKey = this.getUndoChangeKey(primaryKeyValue, column.columnId, oldValue, newValue);
this.undoChangeLog.set(undoChangeKey, change);
// normally the extractUndoChange() should be executed right after this method
// just to be sure that no 'zombie' undo change remains here (if something goes wrong with the undo value change)
// we manually extract the change after a 2 seconds
// why 2 and not 3 or 1? no good reason, only seems like a reasonable waiting time :)
const UNDO_WAIT = 2000;
const timeoutId = setTimeout(() => {
this.adaptable.logger.warn(`Undo change was NOT handled, this should NOT happen: PK(${change.primaryKeyValue}) Col(${change.column}) RevertedValue(${change.newValue}) NewValue(${change.oldValue})`);
this.extractUndoChange(change);
}, UNDO_WAIT);
this.undoChangeTimers.set(undoChangeKey, timeoutId);
}
// in the second phase, when AG-Grid triggers the cellChange event, we check if it corresponds to an undone change
extractUndoChange(change) {
const { primaryKeyValue, column, oldValue, newValue } = change;
// this is post-undo, so we have to swap the new & old values
const undoChangeKey = this.getUndoChangeKey(primaryKeyValue, column.columnId, newValue, oldValue);
const result = this.undoChangeLog.get(undoChangeKey);
this.undoChangeLog.delete(undoChangeKey);
const timeoutId = this.undoChangeTimers.get(undoChangeKey);
if (timeoutId) {
clearTimeout(timeoutId);
}
return result;
}
getUndoChangeKey(primaryKeyValue, columnId, previousValue, newValue) {
return JSON.stringify({
primaryKeyValue,
columnId,
previousValue,
newValue,
});
}
extractDataChangeLogEntry(cellDataChangedInfo) {
// create rowData snapshot
const rowData = cellDataChangedInfo.rowData
? Helper.cloneObject(cellDataChangedInfo.rowData)
: null;
// strip down rowNode properties as it is pretty "heavy" on the memory
const rowNode = rowData ? { data: rowData } : null;
return {
...cellDataChangedInfo,
rowNode,
rowData,
};
}
}