feat: Trigger automations on call answered, rejected and hung up (#2591)
This commit is contained in:
@@ -1,9 +1,24 @@
|
||||
import { CallConditionEvaluator } from '../../conditions/conditions/call';
|
||||
import type { ConditionState } from '../../conditions/types';
|
||||
import { ConditionStateTriggerBase } from './condition-state-base';
|
||||
import {
|
||||
ConditionStateTriggerBase,
|
||||
type TransitionEvaluators,
|
||||
} from './condition-state-base';
|
||||
import type { TriggerOfType } from './types';
|
||||
|
||||
export class CallTrigger extends ConditionStateTriggerBase<TriggerOfType<'call'>> {
|
||||
protected _getValue(state: ConditionState): unknown {
|
||||
return state.call ?? false;
|
||||
return state.call ?? 'idle';
|
||||
}
|
||||
|
||||
// `from` and `to` are matched with the call condition's own evaluator, so the
|
||||
// trigger and the condition share one definition of what a phase means.
|
||||
protected _createTransitionEvaluators(): TransitionEvaluators {
|
||||
const from = this._trigger.from;
|
||||
const to = this._trigger.to;
|
||||
return {
|
||||
...(from !== undefined && { from: new CallConditionEvaluator({ call: from }) }),
|
||||
...(to !== undefined && { to: new CallConditionEvaluator({ call: to }) }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,25 @@ import type {
|
||||
TriggerEvaluatorContext,
|
||||
} from './types';
|
||||
|
||||
// Evaluators a state change must satisfy: `from` is checked against the state
|
||||
// before the change, `to` against the state after it. Either may be omitted, in
|
||||
// which case that check is skipped.
|
||||
export interface TransitionEvaluators {
|
||||
from?: ConditionEvaluator;
|
||||
to?: ConditionEvaluator;
|
||||
}
|
||||
|
||||
// A trigger driven by `ConditionState` changes: subscribe to the state manager,
|
||||
// fire when the watched value (`_getValue`) changes and the new state passes
|
||||
// the trigger's condition, and emit the `acc` payload. The condition is the
|
||||
// matching condition reused as a point-in-time predicate -- so a trigger and
|
||||
// its condition share one definition of meaning. A trigger with no value (any
|
||||
// change), or no matching condition (`config`), has no condition to pass.
|
||||
//
|
||||
// A trigger type may additionally match the change itself rather than only its
|
||||
// result, by supplying `_createTransitionEvaluators()`. The same condition
|
||||
// evaluator is then read twice: against the state before the change and the
|
||||
// state after it.
|
||||
export abstract class ConditionStateTriggerBase<T extends Trigger>
|
||||
implements TriggerEvaluator
|
||||
{
|
||||
@@ -24,18 +37,23 @@ export abstract class ConditionStateTriggerBase<T extends Trigger>
|
||||
protected _context: TriggerEvaluatorContext;
|
||||
|
||||
private _callback: TriggerCallback | null = null;
|
||||
private _condition: ConditionEvaluator | null;
|
||||
private _condition: ConditionEvaluator | null = null;
|
||||
private _transition: TransitionEvaluators | null = null;
|
||||
|
||||
constructor(trigger: T, context: TriggerEvaluatorContext) {
|
||||
this._trigger = trigger;
|
||||
this._context = context;
|
||||
|
||||
// The condition the trigger checks each change against.
|
||||
this._condition = createConditionEvaluatorForTrigger(trigger);
|
||||
}
|
||||
|
||||
public subscribe(callback: TriggerCallback): void {
|
||||
this._callback = callback;
|
||||
|
||||
// Both are built here rather than in the constructor, which runs before a
|
||||
// subclass has initialized its own fields -- and so before an overridden
|
||||
// `_createTransitionEvaluators()` could read them.
|
||||
this._condition = createConditionEvaluatorForTrigger(this._trigger);
|
||||
this._transition = this._createTransitionEvaluators();
|
||||
|
||||
this._context.stateManager.addListener(this._handler);
|
||||
}
|
||||
|
||||
@@ -51,9 +69,23 @@ export abstract class ConditionStateTriggerBase<T extends Trigger>
|
||||
if (this._condition && !this._condition.evaluate(change.new).result) {
|
||||
return;
|
||||
}
|
||||
const transition = this._transition;
|
||||
if (transition?.from && !transition.from.evaluate(change.old).result) {
|
||||
return;
|
||||
}
|
||||
if (transition?.to && !transition.to.evaluate(change.new).result) {
|
||||
return;
|
||||
}
|
||||
this._callback?.(buildCardTriggerData(this._trigger.trigger, change));
|
||||
};
|
||||
|
||||
// The slice of state this trigger watches; it fires only when this changes.
|
||||
protected abstract _getValue(state: ConditionState): unknown;
|
||||
|
||||
// What the states before and after a change must satisfy, for a trigger type
|
||||
// that matches transitions. `null` (the default) matches on the new state
|
||||
// alone.
|
||||
protected _createTransitionEvaluators(): TransitionEvaluators | null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user