Skip to content

Commit

Permalink
Merge pull request #1 from compulim/feat-pending-upload
Browse files Browse the repository at this point in the history
Incorporate PR changes
  • Loading branch information
ms-jb authored Apr 3, 2024
2 parents 3909c6f + decd63b commit c91cfbb
Show file tree
Hide file tree
Showing 38 changed files with 2,258 additions and 2,143 deletions.
3,598 changes: 1,800 additions & 1,798 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion __tests__/html/attachment.combineAttachmentsAndText.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
Expand Down
16 changes: 14 additions & 2 deletions docs/HOOKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Following is the list of hooks supported by Web Chat API.
- [`useScrollUp`](#usescrollup)
- [`useSendBoxValue`](#usesendboxvalue)
- [`useSendEvent`](#usesendevent)
- [`useSendFiles`](#usesendfiles)
- [`useSendFiles`](#usesendfiles) (Deprecated)
- [`useSendMessage`](#usesendmessage)
- [`useSendMessageBack`](#usesendmessageback)
- [`useSendPostBack`](#usesendpostback)
Expand Down Expand Up @@ -999,6 +999,8 @@ When called, this function will send an event activity to the bot.
## `useSendFiles`
> This function is deprecated. Developers should migrate to [`useSendMessage`](#usesendmessage).
<!-- prettier-ignore-start -->
```js
useSendFiles(): (files: (Blob | File)[]) => void
Expand All @@ -1016,14 +1018,24 @@ If you are using an `ArrayBuffer`, you can use `FileReader` to convert it into a
<!-- prettier-ignore-start -->
```js
useSendMessage(): (text: string, method: string) => void
useSendMessage(): (
text?: string,
method: string,
{
files?: Iterable<Blob | File> | undefined
}
) => void
```
<!-- prettier-ignore-end -->
When called, this function will send a text message activity to the bot.
You can optionally include the input method how the text message was collected. Currently, if specified, only `speech` is supported.
For media attachments, thumbnail can be optionally provided and should be a data URL.
Either `text` or `files` must be defined. If none of them are defined, the function will be no-op.
## `useSendMessageBack`
<!-- prettier-ignore-start -->
Expand Down
7 changes: 5 additions & 2 deletions packages/api/src/StyleOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,13 @@ type StyleOptions = {
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple
*/
uploadMultiple?: boolean;

/**
* Send the attachments and message text together as a single activity
* If set to `send` (default), attachment will be sent when the send button is clicked, or when the message is being sent.
*
* Otherwise, if set to `upload`, attachment will be sent immediately after upload.
*/
combineAttachmentsAndText?: boolean;
sendAttachmentOn?: 'upload' | 'send';

/** Send box button: Icon color, defaults to subtle */
sendBoxButtonColor?: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/defaultStyleOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const DEFAULT_OPTIONS: Required<StyleOptions> = {
sendBoxBackground: 'White',
uploadAccept: undefined,
uploadMultiple: true,
combineAttachmentsAndText: undefined,
sendAttachmentOn: 'send',

// Send box buttons
sendBoxButtonColor: undefined,
Expand Down
62 changes: 29 additions & 33 deletions packages/api/src/hooks/Composer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import updateIn from 'simple-update-in';
import {
clearSuggestedActions,
connect as createConnectAction,
Expand All @@ -21,6 +17,7 @@ import {
setLanguage,
setNotification,
setSendBox,
setSendBoxAttachments,
setSendTimeout,
setSendTypingIndicator,
singleToArray,
Expand All @@ -30,42 +27,46 @@ import {
stopSpeakingActivity,
submitSendBox
} from 'botframework-webchat-core';
import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Provider } from 'react-redux';
import updateIn from 'simple-update-in';

import { default as WebChatAPIContext } from './internal/WebChatAPIContext';
import StyleOptions from '../StyleOptions';
import usePonyfill from '../hooks/usePonyfill';
import getAllLocalizedStrings from '../localization/getAllLocalizedStrings';
import normalizeStyleOptions from '../normalizeStyleOptions';
import patchStyleOptionsFromDeprecatedProps from '../patchStyleOptionsFromDeprecatedProps';
import ActivityAcknowledgementComposer from '../providers/ActivityAcknowledgement/ActivityAcknowledgementComposer';
import ActivityKeyerComposer from '../providers/ActivityKeyer/ActivityKeyerComposer';
import ActivityMiddleware from '../types/ActivityMiddleware';
import ActivitySendStatusComposer from '../providers/ActivitySendStatus/ActivitySendStatusComposer';
import ActivitySendStatusTelemetryComposer from '../providers/ActivitySendStatusTelemetry/ActivitySendStatusTelemetryComposer';
import PonyfillComposer from '../providers/Ponyfill/PonyfillComposer';
import ActivityMiddleware from '../types/ActivityMiddleware';
import AttachmentForScreenReaderMiddleware from '../types/AttachmentForScreenReaderMiddleware';
import AttachmentMiddleware from '../types/AttachmentMiddleware';
import AvatarMiddleware from '../types/AvatarMiddleware';
import CardActionMiddleware from '../types/CardActionMiddleware';
import createCustomEvent from '../utils/createCustomEvent';
import createDefaultCardActionMiddleware from './middleware/createDefaultCardActionMiddleware';
import createDefaultGroupActivitiesMiddleware from './middleware/createDefaultGroupActivitiesMiddleware';
import defaultSelectVoice from './internal/defaultSelectVoice';
import ErrorBoundary from './utils/ErrorBoundary';
import getAllLocalizedStrings from '../localization/getAllLocalizedStrings';
import GroupActivitiesMiddleware from '../types/GroupActivitiesMiddleware';
import isObject from '../utils/isObject';
import LocalizedStrings from '../types/LocalizedStrings';
import mapMap from '../utils/mapMap';
import normalizeLanguage from '../utils/normalizeLanguage';
import normalizeStyleOptions from '../normalizeStyleOptions';
import observableToPromise from './utils/observableToPromise';
import patchStyleOptionsFromDeprecatedProps from '../patchStyleOptionsFromDeprecatedProps';
import PonyfillComposer from '../providers/Ponyfill/PonyfillComposer';
import PrecompiledGlobalizeType from '../types/PrecompiledGlobalize';
import ScrollToEndButtonMiddleware, { ScrollToEndButtonComponentFactory } from '../types/ScrollToEndButtonMiddleware';
import StyleOptions from '../StyleOptions';
import TelemetryMeasurementEvent, { TelemetryExceptionMeasurementEvent } from '../types/TelemetryMeasurementEvent';
import ToastMiddleware from '../types/ToastMiddleware';
import Tracker from './internal/Tracker';
import TypingIndicatorMiddleware from '../types/TypingIndicatorMiddleware';
import useMarkAllAsAcknowledged from './useMarkAllAsAcknowledged';
import usePonyfill from '../hooks/usePonyfill';
import createCustomEvent from '../utils/createCustomEvent';
import isObject from '../utils/isObject';
import mapMap from '../utils/mapMap';
import normalizeLanguage from '../utils/normalizeLanguage';
import Tracker from './internal/Tracker';
import { default as WebChatAPIContext } from './internal/WebChatAPIContext';
import WebChatReduxContext, { useDispatch } from './internal/WebChatReduxContext';
import defaultSelectVoice from './internal/defaultSelectVoice';
import createDefaultCardActionMiddleware from './middleware/createDefaultCardActionMiddleware';
import createDefaultGroupActivitiesMiddleware from './middleware/createDefaultGroupActivitiesMiddleware';
import useMarkAllAsAcknowledged from './useMarkAllAsAcknowledged';
import ErrorBoundary from './utils/ErrorBoundary';
import observableToPromise from './utils/observableToPromise';

import applyMiddleware, {
forLegacyRenderer as applyMiddlewareForLegacyRenderer,
Expand All @@ -76,15 +77,15 @@ import applyMiddleware, {
// @ts-ignore
import PrecompiledGlobalize from '../external/PrecompiledGlobalize';

import type { ActivityStatusMiddleware, RenderActivityStatus } from '../types/ActivityStatusMiddleware';
import type { ContextOf } from '../types/internal/ContextOf';
import type {
DirectLineJSBotConnection,
OneOrMany,
GlobalScopePonyfill,
OneOrMany,
WebChatActivity
} from 'botframework-webchat-core';
import type { ReactNode } from 'react';
import type { ActivityStatusMiddleware, RenderActivityStatus } from '../types/ActivityStatusMiddleware';
import type { ContextOf } from '../types/internal/ContextOf';

// List of Redux actions factory we are hoisting as Web Chat functions
const DISPATCHERS = {
Expand All @@ -102,6 +103,7 @@ const DISPATCHERS = {
setDictateState,
setNotification,
setSendBox,
setSendBoxAttachments,
setSendTimeout,
startDictate,
startSpeakingActivity,
Expand Down Expand Up @@ -540,9 +542,6 @@ const ComposerCore = ({
[scrollToEndButtonMiddleware]
);

// For useFiles hook
const [files, setFiles] = useState<File[]>([]);

// For useUploadButtonRef
const uploadButtonRef = useRef<HTMLInputElement>();

Expand Down Expand Up @@ -571,7 +570,6 @@ const ComposerCore = ({
directLine,
disabled,
downscaleImageToDataURL,
files,
grammars: patchedGrammars,
internalErrorBoxClass,
language: locale,
Expand All @@ -582,7 +580,6 @@ const ComposerCore = ({
scrollToEndButtonRenderer,
selectVoice: patchedSelectVoice,
sendTypingIndicator,
setFiles,
styleOptions: patchedStyleOptions,
telemetryDimensionsRef,
toastRenderer: patchedToastRenderer,
Expand All @@ -597,7 +594,6 @@ const ComposerCore = ({
directLine,
disabled,
downscaleImageToDataURL,
files,
groupActivitiesContext,
hoistedDispatchers,
internalErrorBoxClass,
Expand All @@ -619,7 +615,7 @@ const ComposerCore = ({
renderMarkdown,
scrollToEndButtonRenderer,
sendTypingIndicator,
setFiles,
telemetryDimensionsRef,
trackDimension,
userID,
username
Expand Down
6 changes: 2 additions & 4 deletions packages/api/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import useDirection from './useDirection';
import useDisabled from './useDisabled';
import useDismissNotification from './useDismissNotification';
import useEmitTypingIndicator from './useEmitTypingIndicator';
import useFiles from './useFiles';
import useGetActivityByKey from './useGetActivityByKey';
import useGetHasAcknowledgedByActivityKey from './useGetHasAcknowledgedByActivityKey';
import useGetKeyByActivity from './useGetKeyByActivity';
Expand All @@ -46,6 +45,7 @@ import useRenderAttachment from './useRenderAttachment';
import useRenderAvatar from './useRenderAvatar';
import useRenderToast from './useRenderToast';
import useRenderTypingIndicator from './useRenderTypingIndicator';
import useSendBoxAttachments from './useSendBoxAttachments';
import useSendBoxValue from './useSendBoxValue';
import useSendEvent from './useSendEvent';
import useSendFiles from './useSendFiles';
Expand All @@ -67,7 +67,6 @@ import useTrackDimension from './useTrackDimension';
import useTrackEvent from './useTrackEvent';
import useTrackException from './useTrackException';
import useTrackTiming from './useTrackTiming';
import useUploadButtonRef from './useUploadButtonRef';
import useUserID from './useUserID';
import useUsername from './useUsername';
import useVoiceSelector from './useVoiceSelector';
Expand All @@ -94,7 +93,6 @@ export {
useDisabled,
useDismissNotification,
useEmitTypingIndicator,
useFiles,
useGetActivityByKey,
useGetHasAcknowledgedByActivityKey,
useGetKeyByActivity,
Expand All @@ -121,6 +119,7 @@ export {
useRenderAvatar,
useRenderToast,
useRenderTypingIndicator,
useSendBoxAttachments,
useSendBoxValue,
useSendEvent,
useSendFiles,
Expand All @@ -142,7 +141,6 @@ export {
useTrackEvent,
useTrackException,
useTrackTiming,
useUploadButtonRef,
useUserID,
useUsername,
useVoiceSelector
Expand Down
39 changes: 25 additions & 14 deletions packages/api/src/hooks/internal/WebChatAPIContext.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
import { createContext } from 'react';
import { createContext, type Dispatch, type SetStateAction } from 'react';

import { AttachmentForScreenReaderComponentFactory } from '../../types/AttachmentForScreenReaderMiddleware';
import { AvatarComponentFactory } from '../../types/AvatarMiddleware';
import { GroupActivities } from '../../types/GroupActivitiesMiddleware';
import { StrictStyleOptions } from '../../StyleOptions';
import { LegacyActivityRenderer } from '../../types/ActivityMiddleware';
import { PerformCardAction } from '../../types/CardActionMiddleware';
import { RenderActivityStatus } from '../../types/ActivityStatusMiddleware';
import { AttachmentForScreenReaderComponentFactory } from '../../types/AttachmentForScreenReaderMiddleware';
import { RenderAttachment } from '../../types/AttachmentMiddleware';
import { RenderToast } from '../../types/ToastMiddleware';
import { ScrollToEndButtonComponentFactory } from '../../types/ScrollToEndButtonMiddleware';
import { StrictStyleOptions } from '../../StyleOptions';
import { AvatarComponentFactory } from '../../types/AvatarMiddleware';
import { PerformCardAction } from '../../types/CardActionMiddleware';
import { GroupActivities } from '../../types/GroupActivitiesMiddleware';
import LocalizedStrings from '../../types/LocalizedStrings';
import Notification from '../../types/Notification';
import PrecompiledGlobalize from '../../types/PrecompiledGlobalize';
import { ScrollToEndButtonComponentFactory } from '../../types/ScrollToEndButtonMiddleware';
import TelemetryMeasurementEvent from '../../types/TelemetryMeasurementEvent';
import { RenderToast } from '../../types/ToastMiddleware';

import type { DirectLineJSBotConnection, Observable, WebChatActivity } from 'botframework-webchat-core';
import type {
DirectLineJSBotConnection,
Observable,
sendFiles,
sendMessage,
WebChatActivity,
WebChatPostActivityAttachment
} from 'botframework-webchat-core';

type WebChatAPIContext = {
activityRenderer?: LegacyActivityRenderer;
activityStatusRenderer: RenderActivityStatus;
attachmentForScreenReaderRenderer?: AttachmentForScreenReaderComponentFactory;
attachmentRenderer?: RenderAttachment;
avatarRenderer?: AvatarComponentFactory;
avatarRenderer: AvatarComponentFactory;
clearSuggestedActions?: () => void;
dir?: string;
directLine?: DirectLineJSBotConnection;
disabled?: boolean;
dismissNotification?: (id: string) => void;
downscaleImageToDataURL?: (blob: Blob, maxWidth: number, maxHeight: number, type: string, quality: number) => string;
emitTypingIndicator?: () => void;
files?: File[];
grammars?: any;
groupActivities?: GroupActivities;
internalErrorBoxClass?: React.Component | Function;
Expand All @@ -46,17 +53,21 @@ type WebChatAPIContext = {
linkOptions: { externalLinkAlt: string }
) => string;
scrollToEndButtonRenderer?: ScrollToEndButtonComponentFactory;
selectVoice?: (voices: (typeof window.SpeechSynthesisVoice)[], activity: WebChatActivity) => void;
selectVoice?: (
voices: (typeof window.SpeechSynthesisVoice)[],
activity: WebChatActivity
) => typeof window.SpeechSynthesisVoice;
sendEvent?: (name: string, value: any) => void;
sendFiles?: (files: File[], text?: string) => void;
sendMessage?: (text: string, method?: string, { channelData }?: { channelData?: any }) => void;
sendFiles?: typeof sendFiles;
sendMessage?: typeof sendMessage;
sendMessageBack?: (value: any, text?: string, displayText?: string) => void;
sendPostBack?: (value?: any) => void;
sendTypingIndicator?: boolean;
setDictateInterims?: (interims: string[]) => void;
setDictateState?: (dictateState: number) => void;
setNotification?: (notification: Notification) => void;
setSendBox?: (value: string) => void;
setSendBoxAttachments?: Dispatch<SetStateAction<readonly WebChatPostActivityAttachment[]>>;
setSendTimeout?: (timeout: number) => void;
startDictate?: () => void;
startSpeakingActivity?: () => void;
Expand Down
10 changes: 0 additions & 10 deletions packages/api/src/hooks/useFiles.ts

This file was deleted.

19 changes: 19 additions & 0 deletions packages/api/src/hooks/useSendBoxAttachments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { WebChatPostActivityAttachment } from 'botframework-webchat-core';
import { useMemo, type Dispatch, type SetStateAction } from 'react';

import { useSelector } from './internal/WebChatReduxContext';
import useWebChatAPIContext from './internal/useWebChatAPIContext';

export default function useSendBoxAttachments(): readonly [
readonly WebChatPostActivityAttachment[],
Dispatch<SetStateAction<readonly WebChatPostActivityAttachment[]>>
] {
// TODO: We should use the selector from "core" package.
const sendBoxAttachments = useSelector(({ sendBoxAttachments }) => sendBoxAttachments);
const { setSendBoxAttachments } = useWebChatAPIContext();

return useMemo(
() => Object.freeze([sendBoxAttachments, setSendBoxAttachments]),
[sendBoxAttachments, setSendBoxAttachments]
);
}
Loading

0 comments on commit c91cfbb

Please sign in to comment.