Skip to content

Commit

Permalink
fix: Fixed various onboarding issues and updated content (microsoft#2900
Browse files Browse the repository at this point in the history
)

* fix: Fixed various onboarding issues and updated content

* fixed integration tests
  • Loading branch information
tdurnford authored May 6, 2020
1 parent cc86f30 commit 9948307
Show file tree
Hide file tree
Showing 17 changed files with 121 additions and 155 deletions.
1 change: 0 additions & 1 deletion Composer/cypress/integration/Onboarding.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

context('Onboarding', () => {
beforeEach(() => {
window.localStorage.setItem('composer:OnboardingState', JSON.stringify({ complete: false }));
cy.visit(Cypress.env('COMPOSER_URL'));
cy.createBot('TodoSample', 'Onboarding');

Expand Down
2 changes: 1 addition & 1 deletion Composer/cypress/integration/ToDoBot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

context('ToDo Bot', () => {
before(() => {
beforeEach(() => {
cy.visit(Cypress.env('COMPOSER_URL'));
cy.createBot('TodoSample');
});
Expand Down
10 changes: 8 additions & 2 deletions Composer/packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/** @jsx jsx */
import { jsx } from '@emotion/core';
import React, { forwardRef, useContext, useState, Fragment, Suspense } from 'react';
import React, { forwardRef, useContext, useEffect, useState, Fragment, Suspense } from 'react';
import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
import { FocusZone } from 'office-ui-fabric-react/lib/FocusZone';
Expand All @@ -19,6 +19,7 @@ import { resolveToBasePath } from './utils/fileUtil';
import { ErrorBoundary } from './components/ErrorBoundary';
import { RequireAuth } from './components/RequireAuth';
import { AppUpdater } from './components/AppUpdater';
import onboardingState from './utils/onboardingStorage';

initializeIcons(undefined, { disableWarnings: true });

Expand Down Expand Up @@ -127,11 +128,16 @@ const bottomLinks = [
];

export const App: React.FC = () => {
const { state } = useContext(StoreContext);
const { actions, state } = useContext(StoreContext);
const [sideBarExpand, setSideBarExpand] = useState(false);

const { onboardingSetComplete } = actions;
const { botName, projectId, dialogs, locale, designPageLocation, announcement } = state;

useEffect(() => {
onboardingSetComplete(onboardingState.getComplete());
}, []);

const mapNavItemTo = x => resolveToBasePath(BASEPATH, x);

const openedDialogId = designPageLocation.dialogId || dialogs.find(({ isRoot }) => isRoot === true)?.id || 'Main';
Expand Down
28 changes: 4 additions & 24 deletions Composer/packages/client/src/Onboarding/TeachingBubbles/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ const TeachingBubbles = () => {
state: { currentSet, currentStep, teachingBubble },
} = useContext(OnboardingContext);

// Since some of the teaching bubbles are positioned with (x, y) coordinates relative
// to the extension they exist in and we get the (left, top) position of the extension
// to position the bubble relative to the app, we need to re-render the teaching bubble
// when the screen is resized.
const [, forceRender] = useState();
const rerender = useRef(debounce(() => forceRender({}), 200)).current;

Expand All @@ -46,29 +42,13 @@ const TeachingBubbles = () => {
return () => window.removeEventListener('resize', rerender);
}, [forceRender]);

const { id, location, setLength = 0, targetId = '' } = teachingBubble || {};
const { id, setLength = 0, targetId = '' } = teachingBubble || {};
const target = coachMarkRefs[targetId];

if (!target) {
return null;
}

// The teaching bubbles attach themselves to elements in Composer with component refs.
// However, the `actions` teaching bubble attaches itself to an element in the Visual
// Editor, and we can't access the component ref in the iFrame from the app. As a
// workaround, the extension adds an (x, y) coordinate to the `coachMarkRefs` map where
// the teaching bubble should be positioned relative to the extension. We can then
// add the `top` and `left` position of the extension to position the teaching bubble
// relative to the app.
let position;
const { x, y } = target;

if (typeof x !== 'undefined' && typeof y !== 'undefined' && location) {
const extension = coachMarkRefs[location];
const { left = 0, top = 0 } = (extension && extension.getBoundingClientRect()) || {};
position = { x: left + x, y: top + y };
}

const teachingBubbleProps = getTeachingBubble(id);

teachingBubbleProps.primaryButtonProps = {
Expand All @@ -93,14 +73,14 @@ const TeachingBubbles = () => {
teachingBubbleProps.onDismiss = nextStep;
}

return target ? (
return (
<TeachingBubble
styles={teachingBubbleStyles}
target={position || target}
target={target}
theme={teachingBubbleTheme}
{...teachingBubbleProps}
/>
) : null;
);
};

export default TeachingBubbles;
46 changes: 19 additions & 27 deletions Composer/packages/client/src/Onboarding/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { navigate } from '@reach/router';
import formatMessage from 'format-message';

Expand Down Expand Up @@ -30,7 +30,22 @@ const Onboarding: React.FC = () => {

const rootDialogId = dialogs.find(({ isRoot }) => isRoot === true)?.id || 'Main';

const [stepSets, setStepSets] = useState<IStepSet[]>(defaultStepSets(projectId, rootDialogId));
const stepSets = useMemo<IStepSet[]>(() => {
return defaultStepSets(projectId, rootDialogId)
.map(stepSet => ({
...stepSet,
steps: stepSet.steps.filter(({ targetId }) => {
if (!dialogs.length) {
return !(targetId === 'mainDialog' || targetId === 'newTrigger' || targetId === 'action');
} else if (!dialogs[0].triggers.length) {
return targetId !== 'action';
}
return true;
}),
}))
.filter(({ steps }) => steps.length);
}, [projectId, rootDialogId]);

const [currentSet, setCurrentSet] = useState<number>(getCurrentSet(stepSets));
const [currentStep, setCurrentStep] = useState<number>(0);
const [hideModal, setHideModal] = useState(true);
Expand All @@ -41,10 +56,6 @@ const Onboarding: React.FC = () => {
location: { pathname },
} = useLocation();

useEffect(() => {
onboardingSetComplete(onboardingState.getComplete());
}, []);

useEffect(() => {
if (didMount.current && complete) {
setCurrentSet(0);
Expand All @@ -58,34 +69,15 @@ const Onboarding: React.FC = () => {
const { steps } = stepSets[currentSet] || { steps: [] };
const coachMark = steps[currentStep] || {};
const { id, location, navigateTo, targetId } = coachMark;
!complete && navigateTo && navigate(navigateTo);

!complete && projectId && navigateTo && navigate(navigateTo);
setTeachingBubble({ currentStep, id, location, setLength: steps.length, targetId });

setMinimized(!!~currentStep);

if (currentSet > -1 && currentSet < stepSets.length) {
onboardingState.setCurrentSet(stepSets[currentSet].id);
}
}, [currentSet, currentStep, setTeachingBubble]);

useEffect(() => {
const sets = defaultStepSets(projectId, rootDialogId)
.map(stepSet => ({
...stepSet,
steps: stepSet.steps.filter(({ targetId }) => {
if (!dialogs.length) {
return !(targetId === 'mainDialog' || targetId === 'newTrigger' || targetId === 'action');
} else if (!dialogs[0].triggers.length) {
return targetId !== 'action';
}
return true;
}),
}))
.filter(({ steps }) => steps.length);

setStepSets(sets);
}, [dialogs, rootDialogId]);
}, [currentSet, currentStep, setTeachingBubble, projectId]);

useEffect(() => {
setHideModal(pathname !== `/bot/${projectId}/dialogs/${rootDialogId}`);
Expand Down
125 changes: 64 additions & 61 deletions Composer/packages/client/src/Onboarding/onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import React from 'react';
import formatMessage from 'format-message';
import { ITeachingBubbleProps } from 'office-ui-fabric-react/lib/TeachingBubble';
import { generateUniqueId } from '@bfc/shared';

export interface IComposerTeachingBubble extends ITeachingBubbleProps {
children?: any;
Expand Down Expand Up @@ -99,75 +100,59 @@ export const stepSets = (projectId: string, rootDialogId: string): IStepSet[] =>
},
];

const Bold = ({ children }) => <b key={generateUniqueId()}>{children}</b>;
const Italics = ({ children }) => <i key={generateUniqueId()}>{children}</i>;

export const getTeachingBubble = (id: string | undefined): IComposerTeachingBubble => {
switch (id) {
case 'setUpYourBot':
return {
children: (
<div>
{formatMessage(
'We have created a sample bot to help you get started with Composer. Click here to open the bot.'
)}
</div>
children: formatMessage(
'We have created a sample bot to help you get started with Composer. Click here to open the bot.'
),
headline: formatMessage('Get started!'),
};

case 'mainDialog':
return {
children: (
<div>{formatMessage('Main dialog is named after your bot. It is the root and entry point of a bot.')}</div>
),
children: formatMessage('The main dialog is named after your bot. It is the root and entry point of a bot.'),
headline: formatMessage('Main dialog'),
};

case 'trigger':
return {
children: (
<div>
{formatMessage(
'Triggers connect intents with bot responses. Think of a trigger as one capability of your bot. So your bot is a collection of triggers.'
)}
</div>
children: formatMessage.rich(
'Triggers connect intents with bot responses. Think of a trigger as one capability of your bot. So your bot is a collection of triggers. To add a new trigger, click the <b>Add</b> button in the toolbar, and then select the <b>Add a new trigger</b> option from the dropdown menu.',
{
b: Bold,
}
),
headline: formatMessage('Trigger'),
headline: formatMessage('Add a new trigger'),
};

case 'userInput':
return {
children: (
<div>
{formatMessage('You can define and manage ')}
<b>{formatMessage('intents ')}</b>
{formatMessage(
'here. Each intent describes a particular user intention through utterances (i.e. user says). '
)}
<b>{formatMessage('Intents are often triggers of your bot.')}</b>
</div>
children: formatMessage.rich(
'You can define and manage <b>intents</b> here. Each intent describes a particular user intention through utterances (i.e. user says). <b>Intents are often triggers of your bot.</b>',
{
b: Bold,
}
),
headline: formatMessage('User input'),
};

case 'actions':
return {
children: (
<div>
{formatMessage('Actions define ')}
<b>{formatMessage('how the bot responds ')}</b>
{formatMessage('to a certain trigger.')}
</div>
),
children: formatMessage.rich('Actions define <b>how the bot responds</b> to a certain trigger.', {
b: Bold,
}),
headline: formatMessage('Actions'),
};

case 'botResponses':
return {
children: (
<div>
{formatMessage(
'You can manage all bot responses here. Make good use of the templates to create sophisticated response logic based on your own needs.'
)}
</div>
children: formatMessage(
'You can manage all bot responses here. Make good use of the templates to create sophisticated response logic based on your own needs.'
),
headline: formatMessage('Bot responses'),
};
Expand All @@ -176,45 +161,63 @@ export const getTeachingBubble = (id: string | undefined): IComposerTeachingBubb
return {
children: (
<div>
<div>
{formatMessage('The welcome message is triggered by the ')}
<i>{formatMessage('ConversationUpdate ')}</i>
{formatMessage('event. You may customize or add a new one. To do this:')}
</div>
{formatMessage.rich(
'The welcome message is triggered by the <i>ConversationUpdate</i> event. To add a new <i>ConversationUpdate</i> trigger:',
{
i: Italics,
}
)}
<ol>
<li>
{formatMessage('Create a new or go to the trigger: ')}
<i>{formatMessage('ConversationUpdate')}</i>
{formatMessage.rich(
'Click the <b>Add</b> button in the toolbar, and select <b>Add a new trigger</b> from the dropdown menu.',
{
b: Bold,
}
)}
</li>
<li>
{formatMessage.rich(
'In the <b>Create a trigger</b> wizard, set the trigger type to <i>Activities</i> in the dropdown. Then set the <b>Activity Type</b> to <i>Greeting (ConversationUpdate activity)</i>, and click the <b>Submit</b> button.',
{ b: Bold, i: Italics }
)}
</li>
<li>
{formatMessage.rich(
"To customize the welcome message, select the <i>Send a response</i> action in the Visual Editor. Then in the Form Editor on the right, you can edit the bot's welcome message in the <b>Language Generation</b> field.",
{ b: Bold, i: Italics }
)}
</li>
<li>{formatMessage('Select/add action: send an Activity')}</li>
<li>{formatMessage('Edit the message in the right pane')}</li>
</ol>
</div>
),
headline: formatMessage('Add welcome message'),
headline: formatMessage('Add a welcome message'),
};

case 'intentTrigger':
return {
children: (
<div>
{formatMessage(
'Click on the + and select intent as the trigger type. Follow the wizard to define the intent and other trigger settings. Then add actions in the visual editor.'
)}
</div>
children: formatMessage.rich(
'Click on the <b>Add</b> button in the toolbar, and select <b>Add a new trigger</b>. In the <b>Create a trigger</b> wizard, set the <b>Trigger Type</b> to <i>Intent recognized</i> and configure the <b>Trigger Name</b> and <b>Trigger Phrases</b>. Then add actions in the Visual Editor.',
{ b: Bold, i: Italics }
),
headline: formatMessage('Add an intent trigger'),
};

case 'startBot':
return {
children: (
<div>
{formatMessage(
"This will open your Emulator application. If you don't yet have the Bot Framework Emulator installed, you can download it "
)}
<a href="https://github.com/microsoft/BotFramework-Emulator/releases/latest">{formatMessage('here.')}</a>
</div>
children: formatMessage.rich(
"This will open your Emulator application. If you don't yet have the Bot Framework Emulator installed, you can download it <a>here</a>.",
{
a: ({ children }) => (
<a
href="https://github.com/microsoft/BotFramework-Emulator/releases/latest"
target="_blank"
rel="noopener noreferrer"
>
{children}
</a>
),
}
),
headline: formatMessage('Test your bot'),
};
Expand Down
Loading

0 comments on commit 9948307

Please sign in to comment.