Skip to content

Commit

Permalink
Merge branch 'julong/skill-supplement' of https://github.com/microsof…
Browse files Browse the repository at this point in the history
…t/BotFramework-Composer into julong/skill-supplement

* 'julong/skill-supplement' of https://github.com/microsoft/BotFramework-Composer:
  fix: Handle expiration on token used for tenants (#7504)
  fix: update gitignore, detect missing func runtime (#7488)
  fix: enable users to select any non multi bot template during add new skills flow (#7494)
  fix: Add Publish your bot to get started list (#7484)
  fixes notification container blocking interaction (#7429)
  Updates Diagnostic message when a Skill is referenced that is not in the current project (#7481)
  chore: Temporarily removes save as button for R13 (#7482)
  fix: hide recognizers if they don't exist in the app schema (#7469)
  • Loading branch information
alanlong9278 committed Apr 30, 2021
2 parents 64fe3fa + 489be5f commit f2e506e
Show file tree
Hide file tree
Showing 24 changed files with 271 additions and 84 deletions.
5 changes: 4 additions & 1 deletion Composer/cypress/integration/HomePage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ context('Home Page ', () => {
});
});

it('can save as a new bot from an existing bot', () => {
// We are disabling this test since we are temporarily removing
// this feature in R13 since we don't have a clear definition or solution
// for copying parent bots and skills.
xit('can save as a new bot from an existing bot', () => {
cy.createTestBot('EmptySample', ({ id }) => {
cy.visit(`/bot/${id}`);
cy.findByTestId('LeftNav-CommandBarButtonHome').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ interface AddBotModalProps {
onDismiss: () => void;
}

const addExistingKey = 'existing';
const addBlankKey = 'blank';
const addExistingBotKey = 'existing';
const addNewBotKey = 'new';

const addSkillOptions: IChoiceGroupOption[] = [
{ key: addExistingKey, text: 'Add an existing bot' },
{ key: addBlankKey, text: 'Create a new blank bot' },
const getAddSkillOptions = (): IChoiceGroupOption[] => [
{ key: addNewBotKey, text: formatMessage('Create a new bot') },
{ key: addExistingBotKey, text: formatMessage('Add an existing bot') },
];

export const AddBotModal: React.FC<AddBotModalProps> = (props) => {
const { setCreationFlowStatus } = useRecoilValue(dispatcherState);
const [addBotType, setAddBotType] = useState(addExistingKey);
const [addBotType, setAddBotType] = useState(addNewBotKey);

const handleChange = (ev?, option?: IChoiceGroupOption): void => {
if (option) {
Expand All @@ -35,10 +35,10 @@ export const AddBotModal: React.FC<AddBotModalProps> = (props) => {
};

const handleSubmit = () => {
if (addBotType === addExistingKey) {
if (addBotType === addExistingBotKey) {
setCreationFlowStatus(CreationFlowStatus.OPEN);
} else {
setCreationFlowStatus(CreationFlowStatus.NEW_FROM_TEMPLATE);
setCreationFlowStatus(CreationFlowStatus.NEW);
}
};

Expand All @@ -50,7 +50,7 @@ export const AddBotModal: React.FC<AddBotModalProps> = (props) => {
title={formatMessage('Add a bot')}
onDismiss={props.onDismiss}
>
<ChoiceGroup required defaultSelectedKey={addExistingKey} options={addSkillOptions} onChange={handleChange} />
<ChoiceGroup required defaultSelectedKey={addNewBotKey} options={getAddSkillOptions()} onChange={handleChange} />
<DialogFooter>
<DefaultButton text={formatMessage('Cancel')} onClick={props.onDismiss} />
<PrimaryButton data-testid="NextStepButton" text={formatMessage('Next')} onClick={handleSubmit} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,17 +199,22 @@ export function CreateBotV2(props: CreateBotProps) {

useEffect(() => {
const itemKey = selectedProgLang.props.itemKey;
let newTemplates: BotTemplate[] = [];
if (itemKey === csharpFeedKey) {
const newTemplates = templates.filter((template) => {
newTemplates = templates.filter((template) => {
return template.dotnetSupport;
});
setDisplayedTemplates(newTemplates);
} else if (itemKey === nodeFeedKey) {
const newTemplates = templates.filter((template) => {
newTemplates = templates.filter((template) => {
return template.nodeSupport;
});
setDisplayedTemplates(newTemplates);
}
if (creationFlowType === 'Skill') {
newTemplates = newTemplates.filter((template) => {
return !template.isMultiBotTemplate;
});
}
setDisplayedTemplates(newTemplates);
}, [templates, selectedProgLang]);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export const GetStartedNextSteps: React.FC<GetStartedProps> = (props) => {
const linkToPackageManager = `/bot/${rootBotProjectId}/plugin/package-manager/package-manager`;
const linkToConnections = `/bot/${rootBotProjectId}/botProjectsSettings/#connections`;
const linkToPublishProfile = `/bot/${rootBotProjectId}/publish/all#addNewPublishProfile`;
const linkToPublish = `/bot/${rootBotProjectId}/publish/all`;
const linkToCompletePublishProfile = `/bot/${rootBotProjectId}/publish/all#completePublishProfile`;
const linkToLUISSettings = `/bot/${rootBotProjectId}/botProjectsSettings/#luisKey`;
const linktoQNASettings = `/bot/${rootBotProjectId}/botProjectsSettings/#qnaKey`;
Expand Down Expand Up @@ -291,6 +292,21 @@ export const GetStartedNextSteps: React.FC<GetStartedProps> = (props) => {
];

if (hasPublishingProfile) {
if (!hasPartialPublishingProfile) {
optSteps.push({
key: 'publish',
label: formatMessage('Publish your bot'),
description: formatMessage('Once you publish your bot to Azure you will be ready to add connections.'),
learnMore: 'https://aka.ms/composer-getstarted-publishbot',
checked: false,
onClick: () => {
TelemetryClient.track('GettingStartedActionClicked', { taskName: 'publish', priority: 'optional' });
openLink(linkToPublish);
},
hideFeatureStep: isPVABot,
});
}

optSteps.push({
key: 'connections',
label: formatMessage('Add connections'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const cardContainer = (show: boolean, ref?: HTMLDivElement | null) => () => {
animation-timing-function: ${show ? 'cubic-bezier(0.1, 0.9, 0.2, 1)' : 'linear'};
animation-fill-mode: both;
animation-name: ${show ? fadeIn : fadeOut(height)};
pointer-events: auto;
`;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const container = css`
position: absolute;
right: 0px;
padding: 6px;
pointer-events: none;
`;

const layerStyles = { root: { zIndex: zIndices.notificationContainer } };
Expand Down
3 changes: 3 additions & 0 deletions Composer/packages/client/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ export const Text = {
get DOTNETFAILURE() {
return formatMessage('Composer needs .NET Core SDK');
},
get FUNCTIONSFAILURE() {
return formatMessage('Composer needs Azure Functions');
},
get BOTRUNTIMEERROR() {
return formatMessage('Composer Runtime Error');
},
Expand Down
84 changes: 57 additions & 27 deletions Composer/packages/client/src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@ import { useRecoilValue } from 'recoil';
import { Toolbar, IToolbarItem } from '@bfc/ui-shared';

import { CreationFlowStatus } from '../../constants';
import { dispatcherState, botDisplayNameState } from '../../recoilModel';
import { dispatcherState } from '../../recoilModel';
import {
recentProjectsState,
feedState,
templateIdState,
currentProjectIdState,
warnAboutDotNetState,
warnAboutFunctionsState,
} from '../../recoilModel/atoms/appState';
import TelemetryClient from '../../telemetry/TelemetryClient';
import composerDocumentIcon from '../../images/composerDocumentIcon.svg';
import stackoverflowIcon from '../../images/stackoverflowIcon.svg';
import githubIcon from '../../images/githubIcon.svg';
import noRecentBotsCover from '../../images/noRecentBotsCover.svg';
import { InstallDepModal } from '../../components/InstallDepModal';
import { missingDotnetVersionError } from '../../utils/runtimeErrors';
import { missingDotnetVersionError, missingFunctionsError } from '../../utils/runtimeErrors';

import { RecentBotList } from './RecentBotList';
import { WhatsNewsList } from './WhatsNewsList';
Expand Down Expand Up @@ -68,15 +67,26 @@ const resources = [
];

const Home: React.FC<RouteComponentProps> = () => {
const projectId = useRecoilValue<string>(currentProjectIdState);
const botName = useRecoilValue<string>(botDisplayNameState(projectId));
// These variables are used in the save as method which is currently disabled until we
// determine the appropriate save as behavior for parent bots and skills. Since we are
// planning to add the feature back in the next release, I am commenting out this section
// of code instead of removing it. See comment below for more details.
//
// const projectId = useRecoilValue<string>(currentProjectIdState);
// const botName = useRecoilValue<string>(botDisplayNameState(projectId));
// const templateId = useRecoilValue<string>(templateIdState);

const recentProjects = useRecoilValue(recentProjectsState);
const feed = useRecoilValue(feedState);
const templateId = useRecoilValue<string>(templateIdState);
const { openProject, setCreationFlowStatus, setCreationFlowType, setWarnAboutDotNet } = useRecoilValue(
dispatcherState
);
const {
openProject,
setCreationFlowStatus,
setCreationFlowType,
setWarnAboutDotNet,
setWarnAboutFunctions,
} = useRecoilValue(dispatcherState);
const warnAboutDotNet = useRecoilValue(warnAboutDotNetState);
const warnAboutFunctions = useRecoilValue(warnAboutFunctionsState);

const onItemChosen = async (item) => {
if (item?.path) {
Expand Down Expand Up @@ -128,23 +138,30 @@ const Home: React.FC<RouteComponentProps> = () => {
dataTestid: 'homePage-Toolbar-Open',
disabled: false,
},
{
type: 'action',
text: formatMessage('Save as'),
buttonProps: {
iconProps: {
iconName: 'Save',
},
onClick: () => {
setCreationFlowStatus(CreationFlowStatus.SAVEAS);
navigate(`projects/${projectId}/${templateId}/save`);
TelemetryClient.track('ToolbarButtonClicked', { name: 'saveAs' });
},
styles: home.toolbarButtonStyles,
},
align: 'left',
disabled: botName ? false : true,
},
// We are temporarily disabling the save as button until we can
// determine what the appropriate save as behavior should be for both
// parent bots and skills.
//
// Associated issue:
// https://github.com/microsoft/BotFramework-Composer/issues/6808#issuecomment-828758688
//
// {
// type: 'action',
// text: formatMessage('Save as'),
// buttonProps: {
// iconProps: {
// iconName: 'Save',
// },
// onClick: () => {
// setCreationFlowStatus(CreationFlowStatus.SAVEAS);
// navigate(`projects/${projectId}/${templateId}/save`);
// TelemetryClient.track('ToolbarButtonClicked', { name: 'saveAs' });
// },
// styles: home.toolbarButtonStyles,
// },
// align: 'left',
// disabled: botName ? false : true,
// },
];
return (
<div css={home.outline}>
Expand Down Expand Up @@ -250,6 +267,19 @@ const Home: React.FC<RouteComponentProps> = () => {
onDismiss={() => setWarnAboutDotNet(false)}
/>
)}
{warnAboutFunctions && (
<InstallDepModal
downloadLink={missingFunctionsError.link.url}
downloadLinkText={formatMessage('Install Azure Functions')}
learnMore={{
text: formatMessage('Learn more'),
link: missingFunctionsError.linkAfterMessage.url,
}}
text={missingFunctionsError.message}
title={formatMessage('Azure Functions required')}
onDismiss={() => setWarnAboutFunctions(false)}
/>
)}
</div>
);
};
Expand Down
5 changes: 5 additions & 0 deletions Composer/packages/client/src/recoilModel/atoms/appState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,3 +354,8 @@ export const warnAboutDotNetState = atom<boolean>({
key: getFullyQualifiedKey('warnAboutDotNetState'),
default: false,
});

export const warnAboutFunctionsState = atom<boolean>({
key: getFullyQualifiedKey('warnAboutFunctionsState'),
default: false,
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
selectedTemplateReadMeState,
showCreateQnAFromUrlDialogState,
warnAboutDotNetState,
warnAboutFunctionsState,
settingsState,
} from '../atoms';
import { botRuntimeOperationsSelector, rootBotProjectIdSelector } from '../selectors';
Expand Down Expand Up @@ -672,6 +673,10 @@ export const projectDispatcher = () => {
callbackHelpers.set(warnAboutDotNetState, warn);
});

const setWarnAboutFunctions = useRecoilCallback((callbackHelpers: CallbackInterface) => (warn: boolean) => {
callbackHelpers.set(warnAboutFunctionsState, warn);
});

return {
openProject,
createNewBot,
Expand All @@ -696,6 +701,7 @@ export const projectDispatcher = () => {
setCurrentProjectId,
setProjectError,
setWarnAboutDotNet,
setWarnAboutFunctions,
fetchReadMe,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as luUtil from '../../utils/luUtil';
import * as qnaUtil from '../../utils/qnaUtil';
import { ClientStorage } from '../../utils/storage';
import { RuntimeOutputData } from '../types';
import { checkIfFunctionsMissing, missingFunctionsError } from '../../utils/runtimeErrors';

import { BotStatus, Text } from './../../constants';
import httpClient from './../../utils/httpUtil';
Expand Down Expand Up @@ -125,7 +126,14 @@ export const publisherDispatcher = () => {
set(botStatusState(projectId), BotStatus.starting);
} else if (status === PUBLISH_FAILED) {
set(botStatusState(projectId), BotStatus.failed);
set(botBuildTimeErrorState(projectId), { ...data, title: formatMessage('Error occurred building the bot') });
if (checkIfFunctionsMissing(data)) {
set(botBuildTimeErrorState(projectId), {
...missingFunctionsError,
title: formatMessage('Error occurred building the bot'),
});
} else {
set(botBuildTimeErrorState(projectId), { ...data, title: formatMessage('Error occurred building the bot') });
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { CallbackInterface } from 'recoil';
import { v4 as uuid } from 'uuid';
import isEmpty from 'lodash/isEmpty';

import { checkIfDotnetVersionMissing } from '../../../utils/runtimeErrors';
import { checkIfDotnetVersionMissing, checkIfFunctionsMissing } from '../../../utils/runtimeErrors';
import { BASEURL, BotStatus } from '../../../constants';
import settingStorage from '../../../utils/dialogSettingStorage';
import { getUniqueName } from '../../../utils/fileUtil';
Expand Down Expand Up @@ -77,6 +77,7 @@ import {
botEndpointsState,
dispatcherState,
warnAboutDotNetState,
warnAboutFunctionsState,
} from '../../atoms';
import * as botstates from '../../atoms/botState';
import lgWorker from '../../parsers/lgWorker';
Expand Down Expand Up @@ -394,11 +395,17 @@ export const handleProjectFailure = (callbackHelpers: CallbackInterface, error)
const isDotnetError = checkIfDotnetVersionMissing({
message: error.response?.data?.message ?? error.message ?? '',
});
const isFunctionsError = checkIfFunctionsMissing({
message: error.response?.data?.message ?? error.message ?? '',
});

if (isDotnetError) {
callbackHelpers.set(warnAboutDotNetState, true);
} else if (isFunctionsError) {
callbackHelpers.set(warnAboutFunctionsState, true);
} else {
callbackHelpers.set(warnAboutDotNetState, false);
callbackHelpers.set(warnAboutFunctionsState, false);
setError(callbackHelpers, error);
}
};
Expand Down
17 changes: 17 additions & 0 deletions Composer/packages/client/src/utils/runtimeErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ export const missingDotnetVersionError = {
},
};

export const missingFunctionsError = {
message: formatMessage('To run this bot, Composer needs Azure Functions Core Tools.'),
linkAfterMessage: {
text: formatMessage('Learn more.'),
url:
'https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#install-the-azure-functions-core-tools',
},
link: {
text: formatMessage('Install Azure Functions'),
url: 'https://www.npmjs.com/package/azure-functions-core-tools',
},
};

export const checkIfDotnetVersionMissing = (err: { message: string }) => {
return /(Command failed: dotnet user-secrets)|(install[\w\r\s\S\t\n]*\.NET Core SDK)/.test(err.message as string);
};

export const checkIfFunctionsMissing = (err: { message: string }) => {
return /(Azure Functions runtime not installed.)|(spawn func ENOENT)/.test(err.message as string);
};
Loading

0 comments on commit f2e506e

Please sign in to comment.