Skip to content

Commit

Permalink
Merge branch 'main' into zhixzhan/file-api-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
cwhitten committed May 4, 2021
2 parents 0a23cc7 + 7b94964 commit 8b6af64
Show file tree
Hide file tree
Showing 22 changed files with 242 additions and 176 deletions.
2 changes: 1 addition & 1 deletion Composer/cypress/integration/HomePage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ context('Home Page ', () => {
cy.visit('/home');
cy.findByTestId('LeftNav-CommandBarButtonHome').click();
cy.findByTestId('homePage-Toolbar-New').within(() => {
cy.findByText('New').click();
cy.findByText('Create new').click();
});
cy.wait(3000);
cy.findByTestId('@microsoft/generator-bot-empty').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ const BotController: React.FC<BotControllerProps> = ({ onHideController, isContr
},
},
}}
id={'startBotPanelElement'}
menuAs={() => null}
styles={{
root: {
Expand Down
2 changes: 1 addition & 1 deletion Composer/packages/client/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ export const Header = () => {
hasCondensedHeadline
calloutProps={{ directionalHint: DirectionalHint.bottomAutoEdge }}
headline={formatMessage('You’re ready to go!')}
target="#startbot"
target="#startBotPanelElement"
onDismiss={hideTeachingBubble}
>
{formatMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ProvisionHandoff } from '@bfc/ui-shared';
import sortBy from 'lodash/sortBy';
import { NeutralColors } from '@uifabric/fluent-theme';
import { AzureTenant } from '@botframework-composer/types';
import jwtDecode from 'jwt-decode';

import TelemetryClient from '../../telemetry/TelemetryClient';
import { AuthClient } from '../../utils/authClient';
Expand Down Expand Up @@ -95,7 +96,7 @@ export const ManageService = (props: ManageServiceProps) => {
const [availableSubscriptions, setAvailableSubscriptions] = useState<Subscription[]>([]);
const [subscriptionsErrorMessage, setSubscriptionsErrorMessage] = useState<string>();
const [keys, setKeys] = useState<KeyRec[]>([]);

const [userProvidedTokens, setUserProvidedTokens] = useState<boolean>(false);
const [currentStep, setCurrentStep] = useState<Step>('intro');
const [outcomeDescription, setOutcomeDescription] = useState<string>('');
const [outcomeSummary, setOutcomeSummary] = useState<any>();
Expand Down Expand Up @@ -137,15 +138,23 @@ export const ManageService = (props: ManageServiceProps) => {
return [];
}
};
const decodeToken = (token: string) => {
try {
return jwtDecode<any>(token);
} catch (err) {
console.error('decode token error in ', err);
return null;
}
};

useEffect(() => {
if (!userShouldProvideTokens()) {
if (currentStep === 'subscription' && !userShouldProvideTokens()) {
AuthClient.getTenants()
.then((tenants) => {
setAllTenants(tenants);
if (tenants.length === 0) {
setTenantsErrorMessage(formatMessage('No Azure Directories were found.'));
} else if (tenants.length === 1) {
} else if (tenants.length >= 1) {
setTenantId(tenants[0].tenantId);
} else {
setTenantsErrorMessage(undefined);
Expand All @@ -159,7 +168,7 @@ export const ManageService = (props: ManageServiceProps) => {
);
});
}
}, []);
}, [currentStep]);

useEffect(() => {
if (tenantId) {
Expand Down Expand Up @@ -210,9 +219,21 @@ export const ManageService = (props: ManageServiceProps) => {
setShowAuthDialog(true);
}
newtoken = getTokenFromCache('accessToken');
}
if (newtoken) {
setToken(newtoken);
if (newtoken) {
const decoded = decodeToken(newtoken);
if (decoded) {
setToken(newtoken);
setUserProvidedTokens(true);
} else {
setTenantsErrorMessage(
formatMessage(
'There was a problem with the authentication access token. Close this dialog and try again. To be prompted to provide the access token again, clear it from application local storage.'
)
);
}
}
} else {
setUserProvidedTokens(false);
}
setCurrentStep('subscription');
};
Expand Down Expand Up @@ -619,7 +640,7 @@ export const ManageService = (props: ManageServiceProps) => {
);
};

const renderResourseCreatorStep = () => {
const renderResourceCreatorStep = () => {
return (
<div>
<div css={dialogBodyStyles}>
Expand Down Expand Up @@ -754,7 +775,7 @@ export const ManageService = (props: ManageServiceProps) => {
<div css={dialogBodyStyles}>
<p css={{ marginTop: 0 }}>
{formatMessage(
'Select your Azure directory, then choose the subscription where you’d like your new {service} resource.',
'Select your Azure directory, then choose the subscription where you’d like your new {service} resource. ',
{ service: props.serviceName }
)}
{props.learnMore ? (
Expand Down Expand Up @@ -799,7 +820,7 @@ export const ManageService = (props: ManageServiceProps) => {
{loading && <Spinner label={loading} labelPosition="right" styles={{ root: { float: 'left' } }} />}
<DefaultButton disabled={!!loading} text={formatMessage('Back')} onClick={() => setCurrentStep('intro')} />
<PrimaryButton
disabled={!!loading || !tenantId || !subscriptionId}
disabled={!!loading || (!userProvidedTokens && !tenantId) || !subscriptionId}
text={formatMessage('Next')}
onClick={() => setCurrentStep('resourceCreation')}
/>
Expand All @@ -820,7 +841,7 @@ export const ManageService = (props: ManageServiceProps) => {
return renderSubscriptionSelectionStep();
}
case 'resourceCreation':
return renderResourseCreatorStep();
return renderResourceCreatorStep();
case 'outcome':
return renderOutcomeStep();
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ import { navigateTo } from '../../../utils/navigation';
import { botDisplayNameState, settingsState } from '../../../recoilModel';
import { AuthClient } from '../../../utils/authClient';
import { AuthDialog } from '../../../components/Auth/AuthDialog';
import { armScopes } from '../../../constants';
import { getTokenFromCache, isShowAuthDialog, userShouldProvideTokens } from '../../../utils/auth';
import {
getTokenFromCache,
getTenantIdFromCache,
isShowAuthDialog,
userShouldProvideTokens,
} from '../../../utils/auth';
import httpClient from '../../../utils/httpUtil';
import { dispatcherState } from '../../../recoilModel';
import { armScopes } from '../../../constants';
import {
tableHeaderRow,
tableRow,
Expand Down Expand Up @@ -63,6 +68,7 @@ type AzureResourcePointer = {
resourceName: string;
resourceGroupName: string;
microsoftAppId: string;
tenantId: string;
};

type AzureChannelStatus = {
Expand Down Expand Up @@ -117,32 +123,65 @@ export const ABSChannels: React.FC<RuntimeSettingsProps> = (props) => {
}
};

const onSelectProfile = async (_, opt) => {
if (opt.key === 'manageProfiles') {
TelemetryClient.track('ConnectionsAddNewProfile');
navigateTo(`/bot/${projectId}/publish/all/#addNewPublishProfile`);
} else {
let newtoken = '';
if (userShouldProvideTokens()) {
if (isShowAuthDialog(false)) {
setShowAuthDialog(true);
const getTokenInteractively = async (tenantId: string) => {
let newtoken = '';
try {
// if tenantId is present, use this to retrieve the arm token.
// absence of a tenantId indicates this was a legacy (pre-tenant support) provisioning profile
if (!tenantId) {
const tenants = await AuthClient.getTenants();
const cachedTenantId = getTenantIdFromCache();

if (tenants.length === 0) {
throw new Error('No Azure Directories were found.');
} else if (cachedTenantId && tenants.map((t) => t.tenantId).includes(cachedTenantId)) {
tenantId = cachedTenantId;
} else {
tenantId = tenants[0].tenantId;
}
newtoken = getTokenFromCache('accessToken');
}
if (tenantId) {
newtoken = await AuthClient.getARMTokenForTenant(tenantId);
} else {
newtoken = await AuthClient.getAccessToken(armScopes);
}
setToken(newtoken);
} catch (error) {
setErrorMessage(error.message || error.toString());
setCurrentResource(undefined);
}
return newtoken;
};

const onSelectProfile = async (_, opt) => {
if (opt.key === 'manageProfiles') {
TelemetryClient.track('ConnectionsAddNewProfile');
navigateTo(`/bot/${projectId}/publish/all/#addNewPublishProfile`);
} else {
// identify the publishing profile in the list
const profile = publishTargets?.find((p) => p.name === opt.key);
if (profile) {
const config = JSON.parse(profile.configuration);
setCurrentResource({
microsoftAppId: config?.settings?.MicrosoftAppId,
resourceName: config.botName || config.name,
resourceGroupName: config.resourceGroup || config.botName || config.name,
subscriptionId: config.subscriptionId,
});

let newtoken = '';
if (userShouldProvideTokens()) {
if (isShowAuthDialog(false)) {
setShowAuthDialog(true);
}
newtoken = getTokenFromCache('accessToken');
} else {
newtoken = await getTokenInteractively(config.tenantId);
}
setToken(newtoken);

if (newtoken) {
setCurrentResource({
microsoftAppId: config?.settings?.MicrosoftAppId,
resourceName: config.botName || config.name,
resourceGroupName: config.resourceGroup || config.botName || config.name,
tenantId: config.tenantId,
subscriptionId: config.subscriptionId,
});
}
}
}
};
Expand Down Expand Up @@ -321,16 +360,18 @@ export const ABSChannels: React.FC<RuntimeSettingsProps> = (props) => {
};

const hasAuth = async () => {
let newtoken = '';
if (userShouldProvideTokens()) {
if (isShowAuthDialog(false)) {
setShowAuthDialog(true);
if (currentResource) {
let newtoken = '';
if (userShouldProvideTokens()) {
if (isShowAuthDialog(false)) {
setShowAuthDialog(true);
}
newtoken = getTokenFromCache('accessToken');
} else {
newtoken = await getTokenInteractively(currentResource.tenantId);
}
newtoken = getTokenFromCache('accessToken');
} else {
newtoken = await AuthClient.getAccessToken(armScopes);
setToken(newtoken);
}
setToken(newtoken);
};

const toggleService = (channel) => {
Expand Down
51 changes: 27 additions & 24 deletions Composer/packages/client/src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,29 @@ import * as home from './styles';
const resources = [
{
imageCover: composerDocumentIcon,
title: formatMessage('Composer documentation'),
description: formatMessage('Find tutorials, step-by-step guides. Discover what you can build with Composer.'),
moreText: formatMessage('Read documentation'),
title: formatMessage('Documentation'),
description: formatMessage('Everything you need to build sophisticated conversational experiences'),
moreText: formatMessage('Learn more'),
url: 'https://docs.microsoft.com/en-us/composer/',
},
{
imageCover: githubIcon,
title: formatMessage('Composer on GitHub'),
description: formatMessage('Check out the resources on GitHub.'),
moreText: formatMessage('Go to Composer repository'),
title: formatMessage('GitHub'),
description: formatMessage('View documentation, samples, and extensions'),
moreText: formatMessage('Open GitHub'),
url: 'https://github.com/microsoft/BotFramework-Composer',
},
{
imageCover: githubIcon,
title: formatMessage('Bot Framework Emulator'),
description: formatMessage('Test and debug bots built using the Bot Framework SDK. Available on GitHub.'),
description: formatMessage('Test and debug your bots in Bot Framework Emulator'),
moreText: formatMessage('Download Emulator'),
url: 'https://github.com/microsoft/BotFramework-Emulator/releases',
},
{
imageCover: stackoverflowIcon,
title: formatMessage('Stack Overflow'),
description: formatMessage('Engage with other bot builders. Ask and answer questions.'),
description: formatMessage('Connect with the community to ask and answer questions about Composer'),
moreText: formatMessage('Go to Stack Overflow'),
url: 'https://stackoverflow.com/questions/tagged/botframework',
},
Expand Down Expand Up @@ -105,7 +105,7 @@ const Home: React.FC<RouteComponentProps> = () => {
const toolbarItems: IToolbarItem[] = [
{
type: 'action',
text: formatMessage('New'),
text: formatMessage('Create new'),
buttonProps: {
iconProps: {
iconName: 'Add',
Expand Down Expand Up @@ -166,10 +166,10 @@ const Home: React.FC<RouteComponentProps> = () => {
return (
<div css={home.outline}>
<div css={home.page}>
<h1 css={home.title}>{formatMessage(`Bot Framework Composer`)}</h1>
<h1 css={home.title}>{formatMessage(`Welcome to Bot Framework Composer`)}</h1>
<div css={home.leftPage} role="main">
<div css={home.recentBotsContainer}>
<h2 css={home.subtitle}>{formatMessage(`Recent Bots`)}</h2>
<h2 css={home.subtitle}>{formatMessage(`Recent`)}</h2>
<Toolbar css={home.toolbar} toolbarItems={toolbarItems} />
{recentProjects.length > 0 ? (
<RecentBotList
Expand All @@ -188,19 +188,22 @@ const Home: React.FC<RouteComponentProps> = () => {
src={noRecentBotsCover}
/>
<div css={home.noRecentBotsDescription}>
{formatMessage.rich('You don’t have any bot yet. Start to <Link>create a new bot</Link>', {
Link: ({ children }) => (
<Link
key="create-new-bot-link"
onClick={() => {
onClickNewBot();
TelemetryClient.track('ToolbarButtonClicked', { name: 'new' });
}}
>
{children}
</Link>
),
})}
{formatMessage.rich(
'Open the product tour to learn about Bot Framework Composer or <Link>create a new bot</Link>',
{
Link: ({ children }) => (
<Link
key="create-new-bot-link"
onClick={() => {
onClickNewBot();
TelemetryClient.track('ToolbarButtonClicked', { name: 'new' });
}}
>
{children}
</Link>
),
}
)}
</div>
</div>
)}
Expand Down
8 changes: 3 additions & 5 deletions Composer/packages/client/src/shell/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { LgMetaData, LgTemplateRef, LgType } from '@bfc/shared';
import { LgMetaData, LgTemplateRef, LgType, extractTemplateNameFromExpression } from '@bfc/shared';
import { LgTemplate, MicrosoftIDialog, ShellApi } from '@botframework-composer/types';

type SerializableLg = {
Expand Down Expand Up @@ -30,7 +30,6 @@ export const serializeLgTemplate = (
return '';
}

const exprRegex = /^\${(.*)\(\)}$/;
const serializableLg: SerializableLg = {
originalId: fromId,
mainTemplateBody: lgTemplate?.body,
Expand All @@ -44,9 +43,8 @@ export const serializeLgTemplate = (
? (lgTemplate.properties[responseType] as string[])
: ([lgTemplate.properties[responseType]] as string[]);
for (const subTemplateItem of subTemplateItems) {
const matched = subTemplateItem.trim().match(exprRegex);
if (matched && matched.length > 1) {
const subTemplateId = matched[1];
const subTemplateId = extractTemplateNameFromExpression(subTemplateItem.trim());
if (subTemplateId) {
const subTemplate = lgTemplates.find((x) => x.name === subTemplateId);
if (subTemplate) {
if (!serializableLg.relatedLgTemplateBodies) {
Expand Down
Loading

0 comments on commit 8b6af64

Please sign in to comment.