Skip to content

Commit

Permalink
Merge branch 'main' into sorgh/8329
Browse files Browse the repository at this point in the history
  • Loading branch information
hatpick committed Jul 12, 2021
2 parents fa6deba + 267d9ca commit 9f6234e
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 50 deletions.
1 change: 1 addition & 0 deletions Composer/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ module.exports = {
'<rootDir>/packages/lib/code-editor',
'<rootDir>/packages/lib/shared',
'<rootDir>/packages/lib/indexers',
'<rootDir>/packages/lib/ui-shared',
'<rootDir>/packages/server',
'<rootDir>/packages/electron-server',
'<rootDir>/packages/tools/language-servers/language-generation',
Expand Down
21 changes: 17 additions & 4 deletions Composer/packages/client/src/components/Auth/AuthDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { useCallback, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { FontWeights } from 'office-ui-fabric-react/lib/Styling';
import { FontSizes } from '@uifabric/fluent-theme';
import { Stack } from 'office-ui-fabric-react/lib/Stack';
import { CopyableText } from '@bfc/ui-shared';

import { dispatcherState } from '../../recoilModel/atoms';
import { isTokenExpired } from '../../utils/auth';
Expand Down Expand Up @@ -59,6 +61,15 @@ export const AuthDialog: React.FC<AuthDialogProps> = (props) => {
return true;
}, [accessToken, graphToken]);

const renderLabel = (props, defaultRender) => {
return (
<Stack>
{defaultRender(props)}
<CopyableText text={props['data-azcommand']} />
</Stack>
);
};

return (
<Dialog
dialogContentProps={{
Expand All @@ -78,8 +89,9 @@ export const AuthDialog: React.FC<AuthDialogProps> = (props) => {
>
<TextField
multiline
data-azcommand="az account get-access-token"
errorMessage={tokenError}
label={formatMessage('Provide ARM token by running `az account get-access-token`')}
label={formatMessage('Provide ARM token by running:')}
placeholder={formatMessage('Paste token here')}
rows={4}
onChange={(event, newValue) => {
Expand All @@ -90,14 +102,14 @@ export const AuthDialog: React.FC<AuthDialogProps> = (props) => {
setTokenError('');
}
}}
onRenderLabel={renderLabel}
/>
{props.needGraph ? (
<TextField
multiline
data-azcommand="az account get-access-token --resource-type ms-graph"
errorMessage={graphError}
label={formatMessage(
'Provide graph token by running `az account get-access-token --resource-type ms-graph`'
)}
label={formatMessage('Provide graph token by running:')}
placeholder={formatMessage('Paste token here')}
rows={4}
onChange={(event, newValue) => {
Expand All @@ -108,6 +120,7 @@ export const AuthDialog: React.FC<AuthDialogProps> = (props) => {
setGraphError('');
}
}}
onRenderLabel={renderLabel}
/>
) : null}
<DialogFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,30 @@
// Licensed under the MIT License.

/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import React from 'react';
import { CopyableText } from '@bfc/ui-shared';
import { css, jsx } from '@emotion/core';
import { FontSizes } from '@uifabric/fluent-theme';
import { FontWeights } from '@uifabric/styling';
import formatMessage from 'format-message';
import { IconButton, IButtonStyles } from 'office-ui-fabric-react/lib/Button';
import { NeutralColors, FontSizes, FluentTheme } from '@uifabric/fluent-theme';
import { Link } from 'office-ui-fabric-react/lib/Link';
import { FontWeights } from '@uifabric/styling';
import React from 'react';

import { platform, OS } from '../../utils/os';
import { OS, platform } from '../../utils/os';

import { CardProps } from './NotificationCard';

const container = css`
padding: 0 16px 16px 40px;
position: relative;
`;

const commandContainer = css`
display: flex;
flex-flow: row nowrap;
padding: 0 8px 16px 12px;
position: relative;
padding: 4px 28px 4px 8px;
background-color: ${NeutralColors.gray20};
line-height: 22px;
margin: 1rem 0;
`;

const copyContainer = css`
const header = css`
margin: 0;
margin-bottom: 4px;
font-size: ${FontSizes.size16};
font-weight: ${FontWeights.semibold};
`;

const copyIconColor = FluentTheme.palette.themeDark;
const copyIconStyles: IButtonStyles = {
root: { position: 'absolute', right: 0, color: copyIconColor, height: '22px' },
rootHovered: { backgroundColor: 'transparent', color: copyIconColor },
rootPressed: { backgroundColor: 'transparent', color: copyIconColor },
};

const linkContainer = css`
margin: 0;
`;
Expand All @@ -61,18 +44,9 @@ export const TunnelingSetupNotification: React.FC<CardProps> = (props) => {
const port = data?.port;
const command = `${getNgrok()} http ${port} --host-header=localhost`;

const copyLocationToClipboard = async () => {
try {
await window.navigator.clipboard.writeText(command);
} catch (e) {
// eslint-disable-next-line no-console
console.error('Something went wrong when trying to copy the command to clipboard.', e);
}
};

return (
<div css={container}>
<h2 css={copyContainer}>{title}</h2>
<h2 css={header}>{title}</h2>
<p css={linkContainer}>
{formatMessage.rich('<a>Install ngrok</a> and run the following command to continue', {
a: ({ children }) => (
Expand All @@ -82,16 +56,11 @@ export const TunnelingSetupNotification: React.FC<CardProps> = (props) => {
),
})}
</p>
<div css={commandContainer}>
{command}
<IconButton
ariaLabel={formatMessage('Copy command to clipboard')}
iconProps={{ iconName: 'Copy' }}
styles={copyIconStyles}
title={formatMessage('Copy command to clipboard')}
onClick={copyLocationToClipboard}
/>
</div>
<CopyableText
buttonAriaLabel={formatMessage('Copy command to clipboard')}
buttonTitle={formatMessage('Copy command to clipboard')}
text={command}
/>
<p css={linkContainer}>
<Link
href="https://docs.microsoft.com/en-us/composer/how-to-connect-to-a-skill"
Expand Down
5 changes: 4 additions & 1 deletion Composer/packages/client/src/utils/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { authConfig, authUrl } from '../constants';
import storage from './storage';
import httpClient from './httpUtil';
import { isElectron } from './electronUtil';
import { platform, OS } from './os';

export function decodeToken(token: string) {
try {
Expand Down Expand Up @@ -339,7 +340,9 @@ export function getAccessTokenUrl(options: { clientId: string; redirectUrl: stri
}

export function userShouldProvideTokens(): boolean {
if (isElectron()) {
// If it's electron build and not running on Linux use oneAuth, otherwise ask user to manually enter tokens.
const os = platform();
if (isElectron() && os !== OS.Linux) {
return false;
} else return !(authConfig.clientId && authConfig.redirectUrl && authConfig.tenantId);
}
Expand Down
58 changes: 58 additions & 0 deletions Composer/packages/lib/ui-shared/src/components/CopyableText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React from 'react';
import { Stack } from 'office-ui-fabric-react/lib/Stack';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
import { FluentTheme } from '@uifabric/fluent-theme';

const buttonIconProps = { iconName: 'Copy' };
const rootStyles = {
root: { background: 'rgba(0, 0, 0, .08)', margin: '8px 0 4px 0' },
};
const textStyles = { root: { padding: '6px 4px 6px 12px' } };
const preStyles: React.CSSProperties = {
margin: 0,
padding: 0,
fontSize: FluentTheme.fonts.small.fontSize,
whiteSpace: 'pre-line',
wordBreak: 'break-all',
fontFamily: 'Menlo,Consolas,Courier New,monospace',
};

type Props = {
className?: string;
text: string;
buttonAriaLabel?: string;
buttonTitle?: string;
};

export const CopyableText = (props: Props) => {
const { className, text, buttonAriaLabel = 'Copy text to clipboard', buttonTitle = 'Copy text to clipboard' } = props;

const copyToClipboard = React.useCallback(async () => {
try {
await window.navigator.clipboard.writeText(text);
} catch (e) {
// eslint-disable-next-line no-console
console.error('Error: Copy text to clipboard. details: ', e);
}
}, [text]);

return (
<Stack horizontal className={className} styles={rootStyles}>
<Stack.Item grow styles={textStyles}>
<pre style={preStyles}>{text}</pre>
</Stack.Item>
<Stack.Item verticalFill>
<IconButton
ariaLabel={buttonAriaLabel}
data-testid="copy-to-clipboard-button"
iconProps={buttonIconProps}
title={buttonTitle}
onClick={copyToClipboard}
/>
</Stack.Item>
</Stack>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { render, fireEvent } from '@botframework-composer/test-utils';
import React from 'react';

import { CopyableText } from '../CopyableText';

Object.assign(navigator, {
clipboard: {
writeText: () => {},
},
});

describe('<CopyableText />', () => {
it('Should render the given text', async () => {
const textToCopy = 'This is a command';
const { container } = render(<CopyableText text={textToCopy} />);

expect(container).toHaveTextContent(textToCopy);
});

it('Should copy text to clipboard when the copy button ios clicked', async () => {
jest.spyOn(navigator.clipboard, 'writeText');
const textToCopy = 'This is a command';
const { findByTestId } = render(<CopyableText text={textToCopy} />);

const copyButton = await findByTestId('copy-to-clipboard-button');
fireEvent.click(copyButton);

expect(navigator.clipboard.writeText).toHaveBeenCalledWith(textToCopy);
});
});
1 change: 1 addition & 0 deletions Composer/packages/lib/ui-shared/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './ProvisionHandoff/ProvisionHandoff';
export * from './DisplayMarkdownDialog/DisplayMarkdownDialog';
export * from './tags/TagInput';
export * from './IconMenu';
export * from './CopyableText';

0 comments on commit 9f6234e

Please sign in to comment.