Skip to content

Commit

Permalink
4.8 blockers (#2098)
Browse files Browse the repository at this point in the history
* 4.8 blockers

Copy to clipboard fixed
Making sure restart conversation does not show up in Transcript or Debug mode

Signed-off-by: Srinaath Ravichandran <srravich@microsoft.com>

* Changelog updated

Signed-off-by: Srinaath Ravichandran <srravich@microsoft.com>

Co-authored-by: Srinaath Ravichandran <srravich@microsoft.com>
  • Loading branch information
srinaath and Srinaath Ravichandran committed Mar 12, 2020
1 parent 47c8349 commit 4ab4d87
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 30 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [client] Upload and download attachments bubble texts and background in webchat were hidden. The adjustments have been made to override FileContent class in PR [2088](https://github.com/microsoft/BotFramework-Emulator/pull/2088)
- [client] Fixed an issue that was causing adaptive card focus to be blurred when clicking on an activity in PR [2090](https://github.com/microsoft/BotFramework-Emulator/pull/2090)
- [client] Fixed an accessibility issue with the recent bots list remove button in PR [2091](https://github.com/microsoft/BotFramework-Emulator/pull/2091)

- [client] Copy secret key button now copies the secret key to the clipboar when creating a new bot file in PR [2098](https://github.com/microsoft/BotFramework-Emulator/pull/2098)

## Removed
- [client/main] Removed legacy payments code in PR [2058](https://github.com/microsoft/BotFramework-Emulator/pull/2058)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ import { ariaAlertService } from '../../a11y';
import { BotCreationDialog, BotCreationDialogState } from './botCreationDialog';
import { BotCreationDialogContainer } from './botCreationDialogContainer';

const mockCopyToClipboard = jest.fn(args => true);
jest.mock('../index', () => null);
jest.mock('../../../utils', () => ({
debounce: (func: () => any) => func,
generateBotSecret: () => {
return Math.random() + '';
},
copyTextToClipboard: args => mockCopyToClipboard(args),
}));

jest.mock('electron', () => ({
Expand Down Expand Up @@ -140,26 +142,13 @@ describe('BotCreationDialog tests', () => {

it('should execute a window copy command when copy is clicked', () => {
testWrapper.instance().setState({ encryptKey: true });
// mock window functions
const backupExec = window.document.execCommand;
const mockExec = jest.fn((_command: string) => null);
const backupGetElementById = window.document.getElementById;
const mockGetElementById = _selector => ({
removeAttribute: () => null,
select: () => null,
setAttribute: () => null,
});
(window.document.getElementById as any) = mockGetElementById;
window.document.execCommand = mockExec;
const alertServiceSpy = jest.spyOn(ariaAlertService, 'alert').mockReturnValueOnce(undefined);

(testWrapper.instance() as any).onCopyClick();
expect(mockExec).toHaveBeenCalledWith('copy');
expect(alertServiceSpy).toHaveBeenCalledWith('Secret copied to clipboard.');

// restore window functions
window.document.execCommand = backupExec;
window.document.getElementById = backupGetElementById;
mockCopyToClipboard.mockReturnValueOnce(false);
(testWrapper.instance() as any).onCopyClick();
expect(alertServiceSpy).toHaveBeenCalledWith('Failed to copy secret to clipboard.');
});

it('should set state via input change handlers', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import * as React from 'react';
import { CommandServiceImpl, CommandServiceInstance } from '@bfemulator/sdk-shared';

import { store } from '../../../state/store';
import { generateBotSecret, debounce } from '../../../utils';
import { generateBotSecret, debounce, copyTextToClipboard } from '../../../utils';
import { ActiveBotHelper } from '../../helpers/activeBotHelper';
import { DialogService } from '../service';
import { ariaAlertService } from '../../a11y';
Expand Down Expand Up @@ -295,13 +295,14 @@ export class BotCreationDialog extends React.Component<BotCreationDialogProps, B
if (!this.state.encryptKey) {
return null;
}
const { secretInputRef } = this;
const { type } = secretInputRef;
secretInputRef.type = 'text';
secretInputRef.select();
window.document.execCommand('copy');
secretInputRef.type = type;
ariaAlertService.alert('Secret copied to clipboard.');
if (copyTextToClipboard(this.secretInputRef.value)) {
ariaAlertService.alert('Secret copied to clipboard.');
} else {
const err = 'Failed to copy secret to clipboard.';
ariaAlertService.alert(err);
// eslint-disable-next-line no-console
console.error(err);
}
};

// TODO: Re-enable ability to re-generate secret after 4.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ interface ActivityWrapperProps extends HTMLAttributes<HTMLDivElement> {
activity: Activity;
children: ReactNode;
isSelected: boolean;
isUserActivity: boolean;
onRestartConversationFromActivityClick: () => void;
showRestartBubble: boolean;
}

// Returns false if the event target is normally an interactive element.
Expand All @@ -65,10 +65,10 @@ function shouldSelectActivity(e: React.SyntheticEvent): boolean {

export class ActivityWrapper extends Component<ActivityWrapperProps> {
render() {
const { activity: _, children, isSelected, isUserActivity, ...divProps } = this.props;
const { activity: _, children, isSelected, showRestartBubble, ...divProps } = this.props;
let classes = styles.chatActivity;
const restartConversationBubble = (
<div className={[styles.replayBubble, isUserActivity && isSelected ? '' : styles.hidden].join(' ')}>
<div className={[styles.replayBubble, showRestartBubble ? '' : styles.hidden].join(' ')}>
<LinkButton ariaLabel="Restart from activity." linkRole={false} onClick={this.replayConversation}>
Restart conversation from here
</LinkButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ export class Chat extends PureComponent<ChatProps, ChatState> {
}

private activityWrapper(next, card, children): ReactNode {
const { mode, restartStatus } = this.props;
const isWebChatDisabled =
mode === 'transcript' || mode === 'debug' || restartStatus === RestartConversationStatus.Started;
return (
<OuterActivityWrapperContainer
card={card}
Expand All @@ -147,6 +150,7 @@ export class Chat extends PureComponent<ChatProps, ChatState> {
onItemRendererClick={this.onItemRendererClick}
onItemRendererKeyDown={this.onItemRendererKeyDown}
restartStatusForActivity={this.props.restartStatus}
isWebChatDisabled={isWebChatDisabled}
>
{next(card)(children)}
</OuterActivityWrapperContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,16 @@ export interface OuterActivityWrapperProps {
restartOption: RestartConversationOptions
) => void;
currentRestartConversationOption: RestartConversationOptions;
isWebChatDisabled: boolean;
}

export class OuterActivityWrapper extends React.Component<OuterActivityWrapperProps, {}> {
public render() {
const { card, children, onContextMenu, onItemRendererClick, onItemRendererKeyDown } = this.props;
const { card, children, onContextMenu, onItemRendererClick, onItemRendererKeyDown, isWebChatDisabled } = this.props;

const isSelected = this.shouldBeSelected(card.activity);
const isUserActivity = this.isUserActivity(card.activity);
const showRestartBubble = isUserActivity && isSelected && !isWebChatDisabled;

return (
<ActivityWrapper
Expand All @@ -71,8 +73,8 @@ export class OuterActivityWrapper extends React.Component<OuterActivityWrapperPr
onKeyDown={onItemRendererKeyDown}
onContextMenu={onContextMenu}
isSelected={isSelected}
isUserActivity={isUserActivity}
onRestartConversationFromActivityClick={this.onRestartConversationFromActivityClick}
showRestartBubble={showRestartBubble}
>
{children}
</ActivityWrapper>
Expand Down
59 changes: 59 additions & 0 deletions packages/app/client/src/utils/copyToClipBord.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

import { copyTextToClipboard } from './copyToClipboard';

const mockWrite = jest.fn(args => true);

jest.mock('electron', () => ({
clipboard: {
writeText: args => {
mockWrite(args);
},
},
}));

describe('Copy To Clipboard', () => {
beforeEach(() => {
mockWrite.mockReset();
});

it('should copy text to clipboard', async () => {
let expected = 'Hello';
copyTextToClipboard(expected);
expect(mockWrite).toHaveBeenCalledWith(expected);
expected = 'Hello Check Again';
copyTextToClipboard(expected);
expect(mockWrite).toHaveBeenCalledWith(expected);
});
});
41 changes: 41 additions & 0 deletions packages/app/client/src/utils/copyToClipboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import { clipboard } from 'electron';

export const copyTextToClipboard = (textValue: string): boolean => {
try {
clipboard.writeText(textValue, 'selection');
return true;
} catch (ex) {
return false;
}
};
1 change: 1 addition & 0 deletions packages/app/client/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ export * from './getGlobal';
export * from './getSettingsDelta';
export * from './generateBotSecret';
export * from './chatUtils';
export * from './copyToClipboard';

0 comments on commit 4ab4d87

Please sign in to comment.