@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
239 lines (238 loc) • 12.9 kB
JavaScript
import * as InternalRedux from '../../Redux/ActionsReducers/InternalRedux';
import * as PopupRedux from '../../Redux/ActionsReducers/PopupRedux';
import * as AlertRedux from '../../Redux/ActionsReducers/AlertRedux';
import { ApiBase } from './ApiBase';
import * as ModuleConstants from '../../Utilities/Constants/ModuleConstants';
import ObjectFactory from '../../Utilities/ObjectFactory';
import { isAdaptableCellChangedAlert, isAdaptableRowChangedAlert, } from '../../AdaptableState/Common/AdaptableAlert';
import StringExtensions from '../../Utilities/Extensions/StringExtensions';
import { AlertInternalApi } from '../Internal/AlertInternalApi';
export class AlertApiImpl extends ApiBase {
constructor(_adaptable) {
super(_adaptable);
this.internalApi = new AlertInternalApi(_adaptable);
}
getAlertState() {
return this.getAdaptableState().Alert;
}
getAlertDefinitions(config) {
return (this.handleLayoutAssociatedObjects(this.getAlertState().AlertDefinitions, 'Alert', config) ??
[]);
}
getSuspendedAlertDefinitions(config) {
return this.getAlertDefinitions(config).filter((alertDefinition) => alertDefinition.IsSuspended);
}
getActiveAlertDefinitions(config) {
return this.getAlertDefinitions(config).filter((alertDefinition) => !alertDefinition.IsSuspended);
}
deleteAlertDefinition(alertDefinition) {
this.dispatchAction(AlertRedux.AlertDefinitionDelete(alertDefinition));
}
getAlertDefinitionById(id) {
return this.getAlertDefinitions().find((alert) => alert?.Uuid === id);
}
addAlertDefinition(alertDefinition) {
this.addUidToAdaptableObject(alertDefinition);
this.dispatchAction(AlertRedux.AlertDefinitionAdd(alertDefinition));
return this.getAlertDefinitionById(alertDefinition.Uuid);
}
async displayAdaptableAlert(alertToShow) {
// There are 3 things we always do with an alert:
// 1. Dispatch the Alert (so it appears in the toolbar)
this.addUidToAdaptableObject(alertToShow);
this.dispatchAction(InternalRedux.AdaptableAlertAdd(alertToShow, this.getAlertOptions().maxAlertsInStore));
// 2. Publish the Alert Fired Event
this.getEventApi().internalApi.fireAlertFiredEvent(alertToShow);
// 3. Manage the many different possible Alert behaviours
// Note: alertProperties.PreventEdit is handled separately, in the Adaptable.setupColumnValueSetter() function
if (alertToShow.alertDefinition && alertToShow.alertDefinition.AlertProperties != undefined) {
const alertDefinition = alertToShow.alertDefinition;
const alertProperties = alertDefinition.AlertProperties;
// Show a Toast Popup
if (alertProperties.DisplayNotification) {
this.displayAdaptableAlertNotification(alertToShow);
}
// Log to console
if (alertProperties.LogToConsole) {
this.getAdatableLogger().consoleLogByMessageType(alertToShow.header + ': ' + alertToShow.message, alertDefinition.MessageType);
}
// Show Alert in a Div (if one has been set)
if (alertProperties.ShowInDiv) {
let alertDiv;
let optionsDiv = this.getContainerOptions().alertContainer;
if (optionsDiv) {
alertDiv =
typeof optionsDiv === 'string' ? document.getElementById(optionsDiv) : optionsDiv;
}
if (alertDiv) {
let alertString = alertToShow.header + ': ' + alertToShow.message;
alertDiv.innerHTML = alertString;
}
}
// Jump to the Cell
if (alertProperties.JumpToCell &&
isAdaptableCellChangedAlert(alertToShow) &&
alertToShow.cellDataChangedInfo) {
this.getGridApi().jumpToCell(alertToShow.cellDataChangedInfo.primaryKeyValue, alertToShow.cellDataChangedInfo.column.columnId, alertToShow.cellDataChangedInfo.rowNode);
}
// Jump to the Row
else if (alertProperties.JumpToRow &&
isAdaptableRowChangedAlert(alertToShow) &&
alertToShow.rowDataChangedInfo?.rowTrigger === 'Add') {
const [firstRowNode] = alertToShow.rowDataChangedInfo.rowNodes;
if (firstRowNode) {
this.getGridApi().jumpToRow(firstRowNode);
}
}
// For CellChanged Alerts either Highlight the cell or row
// for former - we just refresh the cells to trigger a re-evaluation of the Adaptable.setupColumn[Style/Class]
if (isAdaptableCellChangedAlert(alertToShow) &&
alertToShow.cellDataChangedInfo &&
(alertProperties.HighlightCell || alertProperties.HighlightRow)) {
let alertNode = alertToShow.cellDataChangedInfo.rowNode;
if (!alertNode) {
alertNode = this.getGridApi().getRowNodeForPrimaryKey(alertToShow.cellDataChangedInfo.primaryKeyValue);
}
if (alertNode) {
if (alertProperties.HighlightRow) {
this.getGridApi().refreshRowNodes([alertNode]);
setTimeout(() => {
this.dispatchAction(InternalRedux.AdaptableAlertRemoveRowHighlight(alertToShow));
}, this.getAlertOptions().rowHighlightDuration);
}
if (alertProperties.HighlightCell) {
this.getGridApi().refreshCell(alertNode, alertToShow.cellDataChangedInfo.column.columnId);
setTimeout(() => {
this.dispatchAction(InternalRedux.AdaptableAlertRemoveCellHighlight(alertToShow));
}, this.getAlertOptions().cellHighlightDuration);
}
}
}
// For RowChange Alerts only Highlight the row - we just refresh the rows to trigger a re-evaluation of the Adaptable.setupColumn[Style/Class]
else if (alertProperties.HighlightRow &&
isAdaptableRowChangedAlert(alertToShow) &&
alertToShow.rowDataChangedInfo?.rowTrigger === 'Add') {
this.getGridApi().refreshRowNodes(alertToShow.rowDataChangedInfo.rowNodes);
setTimeout(() => {
this.dispatchAction(InternalRedux.AdaptableAlertRemoveRowHighlight(alertToShow));
}, this.getAlertOptions().rowHighlightDuration);
}
}
}
displayAdaptableAlertNotification(alert) {
this.dispatchAction(PopupRedux.PopupShowAlert(alert));
}
async showAlert(alertHeader, alertMessage, messageType, alertProperties) {
const alertDefinition = ObjectFactory.CreateInternalAlertDefinitionForMessages(messageType, alertProperties);
let alertToShow = ObjectFactory.CreateGenericAlert(alertHeader, alertMessage, alertDefinition);
await this.displayAdaptableAlert(alertToShow);
}
async showAlertInfo(alertHeader, alertMessage, alertProperties) {
await this.showAlert(alertHeader, alertMessage, 'Info', alertProperties);
}
async showAlertSuccess(alertHeader, alertMessage, alertProperties) {
await this.showAlert(alertHeader, alertMessage, 'Success', alertProperties);
}
async showAlertWarning(alertHeader, alertMessage, alertProperties) {
await this.showAlert(alertHeader, alertMessage, 'Warning', alertProperties);
}
async showAlertError(alertHeader, alertMessage, alertProperties) {
await this.showAlert(alertHeader, alertMessage, 'Error', alertProperties);
}
openAlertSettingsPanel() {
this.showModulePopup(ModuleConstants.AlertModuleId);
}
editAlertDefinition(alertDefinition) {
this.dispatchAction(AlertRedux.AlertDefinitionEdit(alertDefinition));
return this.getAlertDefinitionById(alertDefinition.Uuid);
}
suspendAlertDefinition(alertDefinition) {
this.dispatchAction(AlertRedux.AlertDefinitionSuspend(alertDefinition));
return this.getAlertDefinitionById(alertDefinition.Uuid);
}
suspendAllAlertDefinition() {
this.dispatchAction(AlertRedux.AlertDefinitionSuspendAll());
}
unSuspendAllAlertDefinition() {
this.dispatchAction(AlertRedux.AlertDefinitionUnSuspendAll());
}
unSuspendAlertDefinition(alertDefinition) {
this.dispatchAction(AlertRedux.AlertDefinitionUnSuspend(alertDefinition));
return this.getAlertDefinitionById(alertDefinition.Uuid);
}
evaluateAlertDefinitions(alertDefinitions) {
const filterScopeAllDefinitions = (alertDefinition) => {
if (this.getColumnScopeApi().scopeIsAll(alertDefinition.Scope) &&
!this.getExpressionApi().getAdaptableQueryExpression(alertDefinition.Rule)) {
// we don't support scope ALL without an expression
// the predicates for scope ALL do NOT make any sense for a programmatic evaluation
return false;
}
return true;
};
const relevantAlertDefinitions = alertDefinitions.filter((alertDefinition) => filterScopeAllDefinitions(alertDefinition));
const relevantColumnIds = new Set();
relevantAlertDefinitions.forEach((alertDefinition) => {
this.getRelevantColumnIdsForAlertDefinition(alertDefinition).forEach((relevantColumnId) => relevantColumnIds.add(relevantColumnId));
});
if (!relevantColumnIds.size) {
return;
}
const cellDataChangedInfos = this.createCellDataChangeInfoStubs(Array.from(relevantColumnIds));
cellDataChangedInfos.forEach((cellDataChangedInfo) => {
const alertDefinitions = this.internalApi
.getAlertDefinitionsForCellDataChange(cellDataChangedInfo)
.filter((alertDefinition) => filterScopeAllDefinitions(alertDefinition))
// some alert definitions might NOT be relevant for the given locator
.filter((alertDefinition) => relevantAlertDefinitions.some((relevantAlertDefinition) => relevantAlertDefinition.Uuid === alertDefinition.Uuid));
this.getAlertApi().internalApi.showAlertForDefinitions(cellDataChangedInfo, alertDefinitions);
});
}
findAlertDefinitions(criteria) {
return this.getAdaptableInternalApi().findAdaptableObjectsByLookupCriteria(criteria, this.getAlertDefinitions({
includeLayoutNotAssociatedObjects: true,
}));
}
getRelevantColumnIdsForAlertDefinition(alertDefinition) {
// if there is an Expression defined, extract only the columns from there (in that case the Scope would be 'All' anyway)
// columns referenced in rule expression
const ruleExpression = this.getExpressionApi().getAdaptableQueryExpression(alertDefinition.Rule);
if (this.getColumnScopeApi().scopeIsAll(alertDefinition.Scope) &&
StringExtensions.IsNotNullOrEmpty(ruleExpression)) {
// return only first referenced column (otherwise we would generate multiple alerts for the same row)
const queryColumns = this.getAdaptableInternalApi()
.getQueryLanguageService()
.getColumnsFromExpression(ruleExpression);
return queryColumns.length > 0 ? [queryColumns[0]] : [];
}
else {
// otherwise return all columns for given scope
return this.getColumnScopeApi()
.getColumnsInScope(alertDefinition.Scope)
.map((adaptableColumn) => adaptableColumn.columnId);
}
}
createCellDataChangeInfoStubs(relevantColumnIds) {
const cellDataChangeInfos = [];
//const adaptable: IAdaptable = this.getAdaptableInternalApi().getAdaptableInstance();
const relevantColumns = this.getColumnApi()
.getColumnsWithColumnIds(relevantColumnIds)
.filter(Boolean);
const changedAt = Date.now();
this.getAdaptableInternalApi().forAllRowNodesDo((rowNode) => {
relevantColumns.forEach((column) => {
const cellDataChangeInfoStub = {
changedAt,
rowNode,
column,
rowData: rowNode.data,
oldValue: null,
newValue: this.getGridApi().getRawValueFromRowNode(rowNode, column.columnId),
primaryKeyValue: this.getGridApi().getPrimaryKeyValueForRowNode(rowNode),
};
cellDataChangeInfos.push(cellDataChangeInfoStub);
});
});
return cellDataChangeInfos;
}
}