UNPKG

botbuilder-dialogs

Version:

A dialog stack based conversation manager for Microsoft BotBuilder.

118 lines (108 loc) 4.62 kB
/** * @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; } }