botbuilder-dialogs
Version:
A dialog stack based conversation manager for Microsoft BotBuilder.
118 lines (108 loc) • 4.62 kB
text/typescript
/**
* @module botbuilder-dialogs
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { BotTelemetryClient, NullTelemetryClient, Severity } from 'botbuilder-core';
import { Dialog, DialogEvent } from './dialog';
import { DialogSet } from './dialogSet';
import { DialogContext } from './dialogContext';
import { DialogEvents } from './dialogEvents';
/**
* A container for a set of Dialogs.
*/
export abstract class DialogContainer<O extends object = {}> extends Dialog<O> {
/**
* The containers dialog set.
*/
readonly dialogs = new DialogSet(undefined);
/**
* Creates an inner dialog context for the containers active child.
*
* @param dc Parents dialog context.
* @returns A new dialog context for the active child or `undefined` if there is no active child.
*/
abstract createChildContext(dc: DialogContext): DialogContext | undefined;
/**
* Finds a child dialog that was previously added to the container.
*
* @param dialogId ID of the dialog to lookup.
* @returns The Dialog if found; otherwise null.
*/
findDialog(dialogId: string): Dialog | undefined {
return this.dialogs.find(dialogId);
}
/**
* Called when an event has been raised, using `DialogContext.emitEvent()`,
* by either the current dialog or a dialog that the current dialog started.
*
* @param dc The dialog context for the current turn of conversation.
* @param e The event being raised.
* @returns True if the event is handled by the current dialog and bubbling should stop.
*/
async onDialogEvent(dc: DialogContext, e: DialogEvent): Promise<boolean> {
const handled = await super.onDialogEvent(dc, e);
if (!handled && e.name === DialogEvents.versionChanged) {
const traceMessage = `Unhandled dialog event: ${e.name}. Active Dialog: ${dc.activeDialog.id}`;
dc.dialogs.telemetryClient.trackTrace({
message: traceMessage,
severityLevel: Severity.Warning,
});
await dc.context.sendTraceActivity(traceMessage);
}
return handled;
}
/**
* Returns internal version identifier for this container.
*
* @remarks
* DialogContainers detect changes of all sub-components in the container and map that to a `versionChanged` event.
* Because they do this, DialogContainers "hide" the internal changes and just have the .id. This isolates changes
* to the container level unless a container doesn't handle it. To support this DialogContainers define a
* protected method getInternalVersion() which computes if this dialog or child dialogs have changed
* which is then examined via calls to checkForVersionChange().
* @returns Version which represents the change of the internals of this container.
*/
protected getInternalVersion(): string {
return this.dialogs.getVersion();
}
/**
* Checks to see if a containers child dialogs have changed since the current dialog instance
* was started.
*
* @remarks
* This should be called at the start of `beginDialog()`, `continueDialog()`, and `resumeDialog()`.
* @param dc Current dialog context.
*/
protected async checkForVersionChange(dc: DialogContext): Promise<void> {
const current = dc.activeDialog.version;
dc.activeDialog.version = this.getInternalVersion();
// Check for change of previously stored hash
if (current && current != dc.activeDialog.version) {
// Give bot an opportunity to handle the change.
// - If bot handles it the changeHash will have been updated as to avoid triggering the
// change again.
await dc.emitEvent(DialogEvents.versionChanged, this.id, true, false);
}
}
/**
* Set the telemetry client, and also apply it to all child dialogs.
* Future dialogs added to the component will also inherit this client.
*/
set telemetryClient(client: BotTelemetryClient) {
this._telemetryClient = client ?? new NullTelemetryClient();
if (this.dialogs.telemetryClient !== this._telemetryClient) {
this.dialogs.telemetryClient = this._telemetryClient;
}
}
/**
* Get the current telemetry client.
*
* @returns The [BotTelemetryClient](xref:botbuilder.BotTelemetryClient) to use for logging.
*/
get telemetryClient(): BotTelemetryClient {
return this._telemetryClient;
}
}