UNPKG

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