UNPKG

@adaptabletools/adaptable

Version:

Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

281 lines (280 loc) 14.8 kB
import * as FlashingCellRedux from '../Redux/ActionsReducers/FlashingCellRedux'; import * as ModuleConstants from '../Utilities/Constants/ModuleConstants'; import { ArrayExtensions } from '../Utilities/Extensions/ArrayExtensions'; import { AdaptableModuleBase } from './AdaptableModuleBase'; import { isReactiveQuery } from '../AdaptableState/Common/AdaptableQuery'; import { getFlashingTargetViewItems } from './Utilities/FlashingCell/getFlashingTargetViewItems'; import { getFlashingCellStyleViewItems } from './Utilities/FlashingCell/getFlashingCellStyleViewItems'; import { getObjectTagsViewItems } from '../Utilities/getObjectTagsViewItems'; import { getRuleViewItems } from '../Utilities/getRuleViewItems'; import { getScopeViewItems } from '../Utilities/getScopeViewItems'; import { FlashingCellWizard } from '../View/FlashingCell/Wizard/FlashingCellWizard'; import { getFlashingCellDurationViewItems } from './Utilities/FlashingCell/getFlashingCellDurationViewItems'; import { errorOnce } from '../agGrid/AdaptableLogger'; export class FlashingCellModule extends AdaptableModuleBase { constructor(api) { super(ModuleConstants.FlashingCellModuleId, ModuleConstants.FlashingCellFriendlyName, 'lightning', 'FlashingAlert', 'Flash cells when they change', api); this.isListeningToCellDataChanges = false; } onAdaptableReady() { this.checkListenToCellDataChanged(); } shouldListenToDataChanges() { return ArrayExtensions.IsNotNullOrEmpty(this.api.flashingCellApi.getActiveFlashingCellDefinitions()); } checkListenToCellDataChanged() { if (!this.isListeningToCellDataChanges) { if (this.shouldListenToDataChanges()) { this.setupCellDataChangeListener(); this.isListeningToCellDataChanges = true; } } } setupCellDataChangeListener() { this.api.internalApi .getDataService() .on('CellDataChanged', (cellDataChangedInfo) => { if (cellDataChangedInfo.trigger === 'undo') { // do NOT handle reverted changes return; } const activeFlashingCellDefinitions = this.api.flashingCellApi.getActiveFlashingCellDefinitions(); if (ArrayExtensions.IsNotNullOrEmpty(activeFlashingCellDefinitions)) { // TODO: think about flashing row value only // - flash for the underlying small data changes, but the visual does not if (this.api.optionsApi.getAlertOptions().dataChangeDetectionPolicy === 'formattedValue') { const { oldValue, newValue, rowNode } = cellDataChangedInfo; const columnId = cellDataChangedInfo.column.columnId; const oldFormattedValue = this.api.gridApi.getDisplayValueFromRawValue(rowNode, columnId, oldValue); const newFormattedValue = this.api.gridApi.getDisplayValueFromRawValue(rowNode, columnId, newValue); if (oldFormattedValue === newFormattedValue) { // if the formattedValues are identical, then no alert is fired return; } } const relevantFlashingCellDefinitions = this.getFlashingCellDefinitionsForDataChange(activeFlashingCellDefinitions, cellDataChangedInfo); if (ArrayExtensions.IsNotNullOrEmpty(relevantFlashingCellDefinitions)) { this.showFlashingCellsForDefinitions(cellDataChangedInfo, relevantFlashingCellDefinitions); } } }); } getFlashingCellDefinitionsForDataChange(activeFlashingCellDefinitions, cellDataChangedInfo) { const defaultNoPredicateReturn = false; let relatedFlashingCellsDefinitions = activeFlashingCellDefinitions .filter((v) => this.api.columnScopeApi.isColumnInScope(cellDataChangedInfo.column, v.Scope)) .filter((flashingCellDefinition) => !isReactiveQuery(flashingCellDefinition.Rule)); let triggeredFlashingCells = []; if (ArrayExtensions.IsNotNullOrEmpty(relatedFlashingCellsDefinitions)) { relatedFlashingCellsDefinitions.forEach((flashingCellDefinition) => { // for aggregation the data-change needs to be aggChange if (cellDataChangedInfo.trigger !== 'aggChange' && this.isFlashingTargetOnlyAggChange(flashingCellDefinition)) { return; } if (flashingCellDefinition.Rule.BooleanExpression) { let expression = flashingCellDefinition.Rule.BooleanExpression; let rowNode = cellDataChangedInfo.rowNode; if (!rowNode) { rowNode = this.api.gridApi.getRowNodeForPrimaryKey(cellDataChangedInfo.primaryKeyValue); } const isValidExpression = this.api.expressionApi.isValidBooleanExpression(expression, this.moduleInfo.ModuleName, `Invalid Alert boolean expression '${expression}'`); let isSatisfiedExpression = false; try { isSatisfiedExpression = isValidExpression && this.api.internalApi .getQueryLanguageService() .evaluateBooleanExpression(expression, this.moduleInfo.ModuleName, rowNode, cellDataChangedInfo); } catch (error) { isSatisfiedExpression = false; errorOnce(error.message); } if (isSatisfiedExpression) { triggeredFlashingCells.push(flashingCellDefinition); } } else if (this.isAlertPredicateTriggered(flashingCellDefinition, cellDataChangedInfo, defaultNoPredicateReturn)) { triggeredFlashingCells.push(flashingCellDefinition); } }); } return triggeredFlashingCells; } showFlashingCellsForDefinitions(cellDataChangedInfo, flashingCellDefinitions = []) { const allColumnIds = this.api.columnApi.getUIAvailableColumns().map((c) => c.columnId); const columnDataType = cellDataChangedInfo.column.dataType; const numeric = columnDataType === 'number'; const isComparableType = numeric || columnDataType === 'date'; let up = false; let down = false; let direction = 'neutral'; if (isComparableType) { const newValue = numeric ? Number(cellDataChangedInfo.newValue) : cellDataChangedInfo.newValue; const oldValue = numeric ? Number(cellDataChangedInfo.oldValue) : cellDataChangedInfo.oldValue; up = newValue > oldValue; down = newValue < oldValue; direction = up ? 'up' : down ? 'down' : 'neutral'; } flashingCellDefinitions.forEach((flashingCellDefinition) => { let flashTarget = this.api.flashingCellApi.getFlashingCellFlashTarget(flashingCellDefinition); const flashColumnIds = { [cellDataChangedInfo.column.columnId]: true }; /** * When flashing a row, all columns in that row are marked to flash. */ if (flashTarget === 'row' || flashTarget?.includes?.('row')) { allColumnIds.forEach((colId) => { flashColumnIds[colId] = true; }); } const rowPrimaryKey = cellDataChangedInfo.primaryKeyValue; this.api.flashingCellApi.showFlashingCell({ rowPrimaryKey, flashingCellDefinition: flashingCellDefinition, cellDataChangedInfo: cellDataChangedInfo, direction, flashTarget, flashColumnIds, }); }); } getModuleAdaptableObjects(config) { return this.api.flashingCellApi.getFlashingCellDefinitions(config); } getExplicitlyReferencedColumnIds(alertDefinition) { const queryExpression = this.api.expressionApi.getAdaptableQueryExpression(alertDefinition.Rule); if (queryExpression) { return this.api.expressionApi.getColumnsFromExpression(queryExpression); } else if (this.api.columnScopeApi.scopeHasColumns(alertDefinition.Scope)) { return this.api.columnScopeApi .getColumnsInScope(alertDefinition.Scope) .map((adaptableColumn) => adaptableColumn.columnId); } return []; } getReferencedNamedQueryNames(alertDefinition) { const queryExpression = this.api.expressionApi.getAdaptableQueryExpression(alertDefinition.Rule); if (!queryExpression) { return []; } return this.api.namedQueryApi.internalApi.getReferencedNamedQueryNames(queryExpression); } createColumnMenuItems(column) { if (column && this.isModuleEditable()) { if (!column.isCalculatedColumn && !column.isTreeColumn) { const flashingCellDefinitions = this.api.flashingCellApi.getFlashingCellDefinitions(); const flashingCellForCurrentColumn = flashingCellDefinitions.find((flashingCellDefinition) => { return this.api.columnScopeApi.isColumnInScope(column, flashingCellDefinition.Scope); }); if (flashingCellForCurrentColumn) { return [ this.createMenuItemReduxAction('flashing-cell-delete', 'Delete Flashing Cell', this.moduleInfo.Glyph, FlashingCellRedux.FlashingCellDefinitionDelete(flashingCellForCurrentColumn)), ]; } return [ this.createMenuItemReduxAction('flashing-cell-add', 'Add Flashing Cell', this.moduleInfo.Glyph, FlashingCellRedux.FlashingCellDefinitionAdd({ Scope: { ColumnIds: [column.columnId], }, Rule: { Predicates: [{ PredicateId: 'AnyChange' }], }, })), ]; } } } createContextMenuItems(menuContext) { const items = []; if (!menuContext.isRowGroupColumn && this.isModuleAvailable()) { if (menuContext.adaptableColumn && menuContext.rowNode) { const flashingCellForRow = this.api.flashingCellApi.internalApi.getAdaptableFlashingCellFor(menuContext.primaryKeyValue); const flashingCellForCell = this.api.flashingCellApi.internalApi.getAdaptableFlashingCellFor(menuContext.primaryKeyValue, menuContext.adaptableColumn.columnId); if (flashingCellForRow) { if (flashingCellForRow.flashTarget === 'row' || (Array.isArray(flashingCellForRow?.flashTarget) && flashingCellForRow.flashTarget.includes('row'))) { items.push(this.createMenuItemClickFunction('flashing-row-clear', 'Clear Flashing Row', this.moduleInfo.Glyph, () => this.api.internalApi .getFlashingCellService() .clearGridCellFlash(flashingCellForRow))); } } else if (flashingCellForCell && flashingCellForCell.flashTarget === 'cell') { items.push(this.createMenuItemClickFunction('flashing-cell-clear', 'Clear Flashing Cell', this.moduleInfo.Glyph, () => this.api.internalApi .getFlashingCellService() .clearGridCellFlash(flashingCellForCell))); } } } return items; } isFlashingTargetOnlyAggChange(flashingCellDefinition) { if (flashingCellDefinition.FlashTarget === 'aggFuncCell') { return true; } return (Array.isArray(flashingCellDefinition.FlashTarget) && flashingCellDefinition.FlashTarget.length === 1 && flashingCellDefinition.FlashTarget.includes('aggFuncCell')); } isAlertPredicateTriggered(alert, dataChangedEvent, defaultNoPredicateReturn = false) { const predicateDefHandlerContext = { value: dataChangedEvent.newValue, oldValue: dataChangedEvent.oldValue, // TODO send real display value displayValue: null, node: dataChangedEvent.rowNode, column: dataChangedEvent.column, ...this.api.internalApi.buildBaseContext(), }; return this.api.predicateApi.handleColumnPredicates(alert.Rule?.Predicates, predicateDefHandlerContext, defaultNoPredicateReturn); } getTeamSharingAction() { return { ModuleEntities: this.api.flashingCellApi.getFlashingCellDefinitions(), AddAction: FlashingCellRedux.FlashingCellDefinitionAdd, EditAction: FlashingCellRedux.FlashingCellDefinitionEdit, }; } toView(flashingCell) { return { items: [ { ...getScopeViewItems(flashingCell.Scope, this.api), label: 'Trigger' }, { ...getRuleViewItems(flashingCell.Rule, this.api), label: 'Rule', name: 'Rule', }, getFlashingCellDurationViewItems(flashingCell), getFlashingTargetViewItems(flashingCell), getFlashingCellStyleViewItems(), getObjectTagsViewItems(flashingCell, this.api), ], abObject: flashingCell, }; } toViewAll() { return this.getModuleAdaptableObjects({ includeLayoutNotAssociatedObjects: this.showLayoutNotAssociatedObjects(), }).map((flashingCell) => this.toView(flashingCell)); } getViewProperties() { return { getEditAction: FlashingCellRedux.FlashingCellDefinitionEdit, getSuspendAction: FlashingCellRedux.FlashingCellDefinitionSuspend, getUnSuspendAction: FlashingCellRedux.FlashingCellDefinitionUnSuspend, getSuspendAllAction: FlashingCellRedux.FlashingCellDefinitionSuspendAll, getUnSuspendAllAction: FlashingCellRedux.FlashingCellDefinitionUnSuspendAll, getDeleteAction: FlashingCellRedux.FlashingCellDefinitionDelete, getEditWizard: () => FlashingCellWizard, }; } canBeAssociatedWithLayouts() { return true; } }