diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a78ec2bd5..4b9cb64f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,18 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/ - `styleOptions.bubbleImageHeight` is being deprecated in favor of `styleOptions.bubbleImageMaxHeight` and `styleOptions.bubbleImageMinHeight`. The option will be removed on or after 2026-07-05 +### Added + +- (Experimental) Added pre-chat message with starter prompts, in PR [#5255](https://github.com/microsoft/BotFramework-WebChat/issues/5255), by [@compulim](https://github.com/compulim) + +### Changed + +- Updated `useSuggestedActions` to return the activity the suggested actions originated from, in PR [#5255](https://github.com/microsoft/BotFramework-WebChat/issues/5255), by [@compulim](https://github.com/compulim) + +### Fixed + +- Fixed [#5256](https://github.com/microsoft/BotFramework-WebChat/issues/5256). `styleOptions.maxMessageLength` should support any JavaScript number value including `Infinity`, by [@compulim](https://github.com/compulim), in PR [#5255](https://github.com/microsoft/BotFramework-WebChat/issues/pull/5255) + ## [4.18.0] - 2024-07-10 ### Added diff --git a/__tests__/__image_snapshots__/html/max-message-length-infinity-js-fluent-theme-applied-handles-max-message-length-of-infinity-1-snap.png b/__tests__/__image_snapshots__/html/max-message-length-infinity-js-fluent-theme-applied-handles-max-message-length-of-infinity-1-snap.png new file mode 100644 index 0000000000..a1d58ee284 Binary files /dev/null and b/__tests__/__image_snapshots__/html/max-message-length-infinity-js-fluent-theme-applied-handles-max-message-length-of-infinity-1-snap.png differ diff --git a/__tests__/__image_snapshots__/html/pre-chat-message-activity-js-fluent-theme-applied-should-display-pre-chat-message-1-snap.png b/__tests__/__image_snapshots__/html/pre-chat-message-activity-js-fluent-theme-applied-should-display-pre-chat-message-1-snap.png new file mode 100644 index 0000000000..17d4729d57 Binary files /dev/null and b/__tests__/__image_snapshots__/html/pre-chat-message-activity-js-fluent-theme-applied-should-display-pre-chat-message-1-snap.png differ diff --git a/__tests__/__image_snapshots__/html/pre-chat-message-activity-wide-js-fluent-theme-applied-should-display-pre-chat-message-in-wide-format-1-snap.png b/__tests__/__image_snapshots__/html/pre-chat-message-activity-wide-js-fluent-theme-applied-should-display-pre-chat-message-in-wide-format-1-snap.png new file mode 100644 index 0000000000..98507c0480 Binary files /dev/null and b/__tests__/__image_snapshots__/html/pre-chat-message-activity-wide-js-fluent-theme-applied-should-display-pre-chat-message-in-wide-format-1-snap.png differ diff --git a/__tests__/html/fluentTheme/maxMessageLength.infinity.html b/__tests__/html/fluentTheme/maxMessageLength.infinity.html new file mode 100644 index 0000000000..7c5679dc6a --- /dev/null +++ b/__tests__/html/fluentTheme/maxMessageLength.infinity.html @@ -0,0 +1,46 @@ + + +
+ + + + + + + + + + + + + + diff --git a/__tests__/html/fluentTheme/maxMessageLength.infinity.js b/__tests__/html/fluentTheme/maxMessageLength.infinity.js new file mode 100644 index 0000000000..fb15dfd18a --- /dev/null +++ b/__tests__/html/fluentTheme/maxMessageLength.infinity.js @@ -0,0 +1,5 @@ +/** @jest-environment ./packages/test/harness/src/host/jest/WebDriverEnvironment.js */ + +describe('Fluent theme applied', () => { + test('handles max message length of Infinity', () => runHTML('fluentTheme/maxMessageLength.infinity')); +}); diff --git a/__tests__/html/fluentTheme/preChatMessageActivity.html b/__tests__/html/fluentTheme/preChatMessageActivity.html new file mode 100644 index 0000000000..62a285c59d --- /dev/null +++ b/__tests__/html/fluentTheme/preChatMessageActivity.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + diff --git a/__tests__/html/fluentTheme/preChatMessageActivity.js b/__tests__/html/fluentTheme/preChatMessageActivity.js new file mode 100644 index 0000000000..df16d5cd33 --- /dev/null +++ b/__tests__/html/fluentTheme/preChatMessageActivity.js @@ -0,0 +1,5 @@ +/** @jest-environment ./packages/test/harness/src/host/jest/WebDriverEnvironment.js */ + +describe('Fluent theme applied', () => { + test('should display pre-chat message', () => runHTML('fluentTheme/preChatMessageActivity')); +}); diff --git a/__tests__/html/fluentTheme/preChatMessageActivity.wide.html b/__tests__/html/fluentTheme/preChatMessageActivity.wide.html new file mode 100644 index 0000000000..98bc868e19 --- /dev/null +++ b/__tests__/html/fluentTheme/preChatMessageActivity.wide.html @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + diff --git a/__tests__/html/fluentTheme/preChatMessageActivity.wide.js b/__tests__/html/fluentTheme/preChatMessageActivity.wide.js new file mode 100644 index 0000000000..dd0f21e7d9 --- /dev/null +++ b/__tests__/html/fluentTheme/preChatMessageActivity.wide.js @@ -0,0 +1,5 @@ +/** @jest-environment ./packages/test/harness/src/host/jest/WebDriverEnvironment.js */ + +describe('Fluent theme applied', () => { + test('should display pre-chat message in wide format', () => runHTML('fluentTheme/preChatMessageActivity.wide')); +}); diff --git a/docs/HOOKS.md b/docs/HOOKS.md index 884bc104de..2740de0f9c 100644 --- a/docs/HOOKS.md +++ b/docs/HOOKS.md @@ -1355,16 +1355,19 @@ This function will send the text in the send box to the bot and clear the send b ## `useSuggestedActions` +> New in 4.18.1: Will return the activity which the suggested actions are originated from. + ```js -useSuggestedActions(): [CardAction[], (CardAction[]) => void] +useSuggestedActions(): [CardAction[], (CardAction[]) => void, { activity: WebChatActivity }] ``` -This hook will return an array and a setter function. +This hook will return an array, a setter function, and a property bag. 1. array: a list of suggested actions that should be shown to the user 1. function: a setter function to clear suggested actions. The setter function can only be used to clear suggested actions, and it will accept empty array or falsy value only. +1. `activity`: the activity which the suggested actions are originated from The suggested actions are computed from the last message activity sent from the bot. If the user posts an activity, the suggested actions will be cleared. diff --git a/packages/api/src/hooks/useSuggestedActions.ts b/packages/api/src/hooks/useSuggestedActions.ts index 880adeb185..9402baca17 100644 --- a/packages/api/src/hooks/useSuggestedActions.ts +++ b/packages/api/src/hooks/useSuggestedActions.ts @@ -1,11 +1,23 @@ +import type { DirectLineCardAction, WebChatActivity } from 'botframework-webchat-core'; import { useCallback } from 'react'; -import type { DirectLineCardAction } from 'botframework-webchat-core'; import { useSelector } from './internal/WebChatReduxContext'; import useWebChatAPIContext from './internal/useWebChatAPIContext'; -export default function useSuggestedActions(): [DirectLineCardAction[], (suggestedActions: never[]) => void] { - const value = useSelector(({ suggestedActions }) => suggestedActions); +export default function useSuggestedActions(): [ + DirectLineCardAction[], + (suggestedActions: never[]) => void, + extras: { activity: WebChatActivity } +] { + const [value, activity] = useSelector( + ({ + suggestedActions, + suggestedActionsOriginActivity: { activity } + }: { + suggestedActions: readonly DirectLineCardAction[]; + suggestedActionsOriginActivity: { activity: undefined | WebChatActivity }; + }) => [suggestedActions, activity] + ); const { clearSuggestedActions } = useWebChatAPIContext(); return [ @@ -19,6 +31,7 @@ export default function useSuggestedActions(): [DirectLineCardAction[], (suggest clearSuggestedActions(); }, [clearSuggestedActions] - ) + ), + { activity } ]; } diff --git a/packages/core/src/actions/clearSuggestedActions.js b/packages/core/src/actions/clearSuggestedActions.ts similarity index 94% rename from packages/core/src/actions/clearSuggestedActions.js rename to packages/core/src/actions/clearSuggestedActions.ts index c37dd7a291..47782d11e7 100644 --- a/packages/core/src/actions/clearSuggestedActions.js +++ b/packages/core/src/actions/clearSuggestedActions.ts @@ -1,4 +1,4 @@ -const CLEAR_SUGGESTED_ACTIONS = 'WEB_CHAT/CLEAR_SUGGESTED_ACTIONS'; +const CLEAR_SUGGESTED_ACTIONS = 'WEB_CHAT/CLEAR_SUGGESTED_ACTIONS' as const; export default function clearSuggestedActions() { return { diff --git a/packages/core/src/actions/setSuggestedActions.js b/packages/core/src/actions/setSuggestedActions.js deleted file mode 100644 index a1b854d63c..0000000000 --- a/packages/core/src/actions/setSuggestedActions.js +++ /dev/null @@ -1,12 +0,0 @@ -const EMPTY_ARRAY = []; - -const SET_SUGGESTED_ACTIONS = 'WEB_CHAT/SET_SUGGESTED_ACTIONS'; - -export default function setSuggestedActions(suggestedActions = EMPTY_ARRAY) { - return { - type: SET_SUGGESTED_ACTIONS, - payload: { suggestedActions } - }; -} - -export { SET_SUGGESTED_ACTIONS }; diff --git a/packages/core/src/actions/setSuggestedActions.ts b/packages/core/src/actions/setSuggestedActions.ts new file mode 100644 index 0000000000..e9e55ff194 --- /dev/null +++ b/packages/core/src/actions/setSuggestedActions.ts @@ -0,0 +1,18 @@ +import type { DirectLineCardAction } from '../types/external/DirectLineCardAction'; +import type { WebChatActivity } from '../types/WebChatActivity'; + +const EMPTY_ARRAY: readonly DirectLineCardAction[] = Object.freeze([]); + +const SET_SUGGESTED_ACTIONS = 'WEB_CHAT/SET_SUGGESTED_ACTIONS' as const; + +export default function setSuggestedActions( + suggestedActions: readonly DirectLineCardAction[] = EMPTY_ARRAY, + originActivity: undefined | WebChatActivity = undefined +) { + return { + type: SET_SUGGESTED_ACTIONS, + payload: { originActivity, suggestedActions } + }; +} + +export { SET_SUGGESTED_ACTIONS }; diff --git a/packages/core/src/createReducer.ts b/packages/core/src/createReducer.ts index bca68d263d..3e9c9894b1 100644 --- a/packages/core/src/createReducer.ts +++ b/packages/core/src/createReducer.ts @@ -16,6 +16,7 @@ import sendTimeout from './reducers/sendTimeout'; import sendTypingIndicator from './reducers/sendTypingIndicator'; import shouldSpeakIncomingActivity from './reducers/shouldSpeakIncomingActivity'; import suggestedActions from './reducers/suggestedActions'; +import suggestedActionsOriginActivity from './reducers/suggestedActionsOriginActivity'; import type { GlobalScopePonyfill } from './types/GlobalScopePonyfill'; @@ -36,6 +37,7 @@ export default function createReducer(ponyfill: GlobalScopePonyfill) { sendTypingIndicator, shouldSpeakIncomingActivity, suggestedActions, + suggestedActionsOriginActivity, typing: createTypingReducer(ponyfill) }); } diff --git a/packages/core/src/reducers/suggestedActions.js b/packages/core/src/reducers/suggestedActions.js index 706b308684..93bae8d9c4 100644 --- a/packages/core/src/reducers/suggestedActions.js +++ b/packages/core/src/reducers/suggestedActions.js @@ -1,7 +1,7 @@ import { CLEAR_SUGGESTED_ACTIONS } from '../actions/clearSuggestedActions'; import { SET_SUGGESTED_ACTIONS } from '../actions/setSuggestedActions'; -const DEFAULT_STATE = []; +const DEFAULT_STATE = Object.freeze([]); export default function suggestedActions(state = DEFAULT_STATE, { payload = {}, type }) { switch (type) { diff --git a/packages/core/src/reducers/suggestedActionsOriginActivity.ts b/packages/core/src/reducers/suggestedActionsOriginActivity.ts new file mode 100644 index 0000000000..8b2d06cd10 --- /dev/null +++ b/packages/core/src/reducers/suggestedActionsOriginActivity.ts @@ -0,0 +1,33 @@ +import type clearSuggestedActions from '../actions/clearSuggestedActions'; +import { CLEAR_SUGGESTED_ACTIONS } from '../actions/clearSuggestedActions'; +import type setSuggestedActions from '../actions/setSuggestedActions'; +import { SET_SUGGESTED_ACTIONS } from '../actions/setSuggestedActions'; +import type { WebChatActivity } from '../types/WebChatActivity'; + +type ClearSuggestedActions = ReturnType