Skip to content

Commit

Permalink
Fix typing for usePerformCardAction hook (microsoft#3969)
Browse files Browse the repository at this point in the history
* Fix typing for usePerformCardAction

* Update entry

* Fix ESLint
  • Loading branch information
compulim committed Sep 9, 2021
1 parent 694ee4b commit 852c898
Show file tree
Hide file tree
Showing 19 changed files with 237 additions and 64 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Fixed

- Fixes [#3968](https://github.com/microsoft/BotFramework-WebChat/issues/3968). Fix typing for `usePerformCardAction` hook, by [@compulim](https://github.com/compulim), in PR [#3969](https://github.com/microsoft/BotFramework-WebChat/pull/3969)
- Fixes [#4018](https://github.com/microsoft/BotFramework-WebChat/issues/4018). When using <kbd>TAB</kbd> or <kbd>SHIFT</kbd> + <kbd>TAB</kbd> key to focus on the transcript, it should select the last activity, by [@compulim](https://github.com/compulim), in PR [#4035](https://github.com/microsoft/BotFramework-WebChat/pull/4035)

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ export default function createDefaultCardActionMiddleware(): CardActionMiddlewar
return ({ dispatch }) => next => (...args) => {
const [
{
cardAction: { displayText, text, type, value }
cardAction,
cardAction: { value }
}
] = args;

switch (type) {
// We cannot use destructured "type" here because TypeScript don't recognize "messageBack" is "MessageBackCardAction".
switch (cardAction.type) {
case 'imBack':
if (typeof value === 'string') {
// TODO: [P4] Instead of calling dispatch, we should move to dispatchers instead for completeness
Expand All @@ -22,7 +24,7 @@ export default function createDefaultCardActionMiddleware(): CardActionMiddlewar
break;

case 'messageBack':
dispatch(sendMessageBack(value, text, displayText));
dispatch(sendMessageBack(value, cardAction.text, cardAction.displayText));

break;

Expand Down
5 changes: 3 additions & 2 deletions packages/api/src/hooks/usePerformCardAction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PerformCardAction } from '../types/CardActionMiddleware';
import { DirectLineCardAction } from 'botframework-webchat-core';

import useWebChatAPIContext from './internal/useWebChatAPIContext';

export default function usePerformCardAction(): PerformCardAction {
export default function usePerformCardAction(): (cardAction: DirectLineCardAction) => void {
return useWebChatAPIContext().onCardAction;
}
26 changes: 13 additions & 13 deletions packages/api/src/types/CardActionMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { DirectLineCardAction } from 'botframework-webchat-core';

import FunctionMiddleware, { CallFunction } from './FunctionMiddleware';
import FunctionMiddleware from './FunctionMiddleware';

type PerformCardActionParameter = {
cardAction?: DirectLineCardAction;
displayText?: string;
getSignInUrl?: () => string;
target?: any;
text?: string;
type?: string;
value?: any;
};
type PerformCardAction = (cardAction: DirectLineCardAction) => void;

type PerformCardAction = CallFunction<[PerformCardActionParameter], void>;

type CardActionMiddleware = FunctionMiddleware<[{ dispatch: (action: any) => void }], [PerformCardActionParameter], {}>;
type CardActionMiddleware = FunctionMiddleware<
[{ dispatch: (action: any) => void }],
[
{
cardAction: DirectLineCardAction;
getSignInUrl?: () => string;
target: any;
}
],
{}
>;

export default CardActionMiddleware;

Expand Down
20 changes: 10 additions & 10 deletions packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ import {
TextWeight
} from 'adaptivecards';

import { CardAction } from 'botframework-directlinejs';
import { DirectLineCardAction } from 'botframework-webchat-core';
import AdaptiveCardsPackage from '../../types/AdaptiveCardsPackage';
import AdaptiveCardsStyleOptions from '../AdaptiveCardsStyleOptions';

export interface BotFrameworkCardAction {
__isBotFrameworkCardAction: boolean;
cardAction: CardAction;
__isBotFrameworkCardAction: true;
cardAction: DirectLineCardAction;
}

function addCardAction(cardAction: CardAction, includesOAuthButtons?: boolean) {
function addCardAction(cardAction: DirectLineCardAction, includesOAuthButtons?: boolean) {
const { type } = cardAction;
let action;

Expand All @@ -42,11 +42,11 @@ function addCardAction(cardAction: CardAction, includesOAuthButtons?: boolean) {
cardAction
};

action.title = cardAction.title;
action.title = (cardAction as { title: string }).title;
} else {
action = new OpenUrlAction();

action.title = cardAction.title;
action.title = (cardAction as { title: string }).title;
action.url = cardAction.type === 'call' ? `tel:${cardAction.value}` : cardAction.value;
}

Expand All @@ -71,7 +71,7 @@ export default class AdaptiveCardBuilder {
this.card.addItem(this.container);
}

addColumnSet(sizes: number[], container: Container = this.container, selectAction?: CardAction) {
addColumnSet(sizes: number[], container: Container = this.container, selectAction?: DirectLineCardAction) {
const columnSet = new ColumnSet();

columnSet.selectAction = selectAction && addCardAction(selectAction);
Expand Down Expand Up @@ -107,7 +107,7 @@ export default class AdaptiveCardBuilder {
}
}

addButtons(cardActions: CardAction[], includesOAuthButtons?: boolean) {
addButtons(cardActions: DirectLineCardAction[], includesOAuthButtons?: boolean) {
cardActions &&
cardActions.forEach(cardAction => {
this.card.addAction(addCardAction(cardAction, includesOAuthButtons));
Expand All @@ -131,7 +131,7 @@ export default class AdaptiveCardBuilder {
this.addButtons(content.buttons);
}

addImage(url: string, container?: Container, selectAction?: CardAction, altText?: string) {
addImage(url: string, container?: Container, selectAction?: DirectLineCardAction, altText?: string) {
container = container || this.container;

const image = new Image();
Expand All @@ -146,7 +146,7 @@ export default class AdaptiveCardBuilder {
}

export interface ICommonContent {
buttons?: CardAction[];
buttons?: DirectLineCardAction[];
subtitle?: string;
text?: string;
title?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
SubmitAction
} from 'adaptivecards';
import { Components, getTabIndex, hooks } from 'botframework-webchat-component';
import { DirectLineCardAction } from 'botframework-webchat-core';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, {
Expand All @@ -21,6 +22,7 @@ import React, {
VFC
} from 'react';

import { BotFrameworkCardAction } from './AdaptiveCardBuilder';
import { PerformCardAction } from '../../../../api/lib';
import useAdaptiveCardsHostConfig from '../hooks/useAdaptiveCardsHostConfig';
import useAdaptiveCardsPackage from '../hooks/useAdaptiveCardsPackage';
Expand Down Expand Up @@ -482,7 +484,7 @@ type AdaptiveCardRendererProps = {
actionPerformedClassName?: string;
adaptiveCard: AdaptiveCard;
disabled?: boolean;
tapAction?: Parameters<PerformCardAction>[0];
tapAction?: DirectLineCardAction;
};

const AdaptiveCardRenderer: VFC<AdaptiveCardRendererProps> = ({
Expand Down Expand Up @@ -573,29 +575,40 @@ const AdaptiveCardRenderer: VFC<AdaptiveCardRendererProps> = ({
addActionsPerformed(action);

const actionTypeName = action.getJsonTypeName();
const { iconUrl: image, title } = action;

// We cannot use "instanceof" check here, because web devs may bring their own version of Adaptive Cards package.
// We need to check using "getJsonTypeName()" instead.
if (actionTypeName === 'Action.OpenUrl') {
const { url: value } = action as OpenUrlAction;

performCardAction({
image,
title,
type: 'openUrl',
value: (action as OpenUrlAction).url
value
});
} else if (actionTypeName === 'Action.Submit') {
const submitAction = action as SubmitAction;

if (typeof submitAction.data !== 'undefined') {
const { data: actionData } = submitAction;

// "__isBotFrameworkCardAction" does not exists on the AdaptiveCardAction type.
// eslint-disable-next-line dot-notation
if (actionData && actionData['__isBotFrameworkCardAction']) {
const { cardAction } = actionData as any;
const { displayText, text, type, value } = cardAction;
const { data } = action as SubmitAction as {
data: string | BotFrameworkCardAction;
};

performCardAction({ displayText, text, type, value });
if (typeof data !== 'undefined') {
if (typeof data === 'string') {
performCardAction({
image,
title,
type: 'imBack',
value: data
});
} else if (data.__isBotFrameworkCardAction) {
performCardAction(data.cardAction);
} else {
performCardAction({
type: typeof actionData === 'string' ? 'imBack' : 'postBack',
value: actionData
image,
title,
type: 'postBack',
value: data
});
}
}
Expand Down Expand Up @@ -743,7 +756,13 @@ AdaptiveCardRenderer.propTypes = {
actionPerformedClassName: PropTypes.string,
adaptiveCard: PropTypes.any.isRequired,
disabled: PropTypes.bool,

// TypeScript class is not mappable to PropTypes.func
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
tapAction: PropTypes.shape({
image: PropTypes.string,
title: PropTypes.string,
type: PropTypes.string.isRequired,
value: PropTypes.string
})
Expand Down
54 changes: 35 additions & 19 deletions packages/component/src/SendBox/SuggestedActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ SuggestedActionStackedContainer.propTypes = {

type SuggestedActionsProps = {
className?: string;
suggestedActions?: DirectLineCardAction;
suggestedActions?: DirectLineCardAction[];
};

const SuggestedActions: FC<SuggestedActionsProps> = ({ className, suggestedActions = [] }) => {
Expand All @@ -227,24 +227,36 @@ const SuggestedActions: FC<SuggestedActionsProps> = ({ className, suggestedActio
: localize('SUGGESTED_ACTIONS_ALT_NO_CONTENT')
);

const children = suggestedActions.map(({ displayText, image, imageAltText, text, title, type, value }, index) => (
<SuggestedAction
buttonText={suggestedActionText({ displayText, title, type, value })}
className="webchat__suggested-actions__button"
displayText={displayText}
image={image}
imageAlt={imageAltText}
key={index}
text={text}
textClassName={
suggestedActionLayout === 'stacked' && suggestedActionsStackedLayoutButtonTextWrap
? 'webchat__suggested-actions__button-text-stacked-text-wrap'
: 'webchat__suggested-actions__button-text'
}
type={type}
value={value}
/>
));
const children = suggestedActions.map((cardAction, index) => {
const { displayText, image, imageAltText, text, title, type, value } = cardAction as {
displayText?: string;
image?: string;
imageAltText?: string;
text?: string;
title?: string;
type: string;
value?: { [key: string]: any } | string;
};

return (
<SuggestedAction
buttonText={suggestedActionText({ displayText, title, type, value })}
className="webchat__suggested-actions__button"
displayText={displayText}
image={image}
imageAlt={imageAltText}
key={index}
text={text}
textClassName={
suggestedActionLayout === 'stacked' && suggestedActionsStackedLayoutButtonTextWrap
? 'webchat__suggested-actions__button-text-stacked-text-wrap'
: 'webchat__suggested-actions__button-text'
}
type={type}
value={value}
/>
);
});

if (suggestedActionLayout === 'flow') {
return (
Expand Down Expand Up @@ -273,6 +285,10 @@ SuggestedActions.defaultProps = {

SuggestedActions.propTypes = {
className: PropTypes.string,

// TypeScript class is not mappable to PropTypes.func
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
suggestedActions: PropTypes.arrayOf(
PropTypes.shape({
displayText: PropTypes.string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// TODO: [P1] #3953 We should fully type it out.

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type DirectLineAnimationCard = any;

export default DirectLineAnimationCard;
1 change: 1 addition & 0 deletions packages/core/src/types/external/DirectLineAttachment.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// TODO: [P1] #3953 We should fully type it out.

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type DirectLineAttachment = any;

export default DirectLineAttachment;
1 change: 1 addition & 0 deletions packages/core/src/types/external/DirectLineAudioCard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// TODO: [P1] #3953 We should fully type it out.

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type DirectLineAudioCard = any;

export default DirectLineAudioCard;
Loading

0 comments on commit 852c898

Please sign in to comment.