Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add runtime settings page and eject #2572

Merged
merged 36 commits into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
22a309f
add new runtime settings page
benbrown Apr 8, 2020
93383a0
add popup modal for pickign runtime
benbrown Apr 10, 2020
68b9952
add ability for plugins to specify a runtime template
benbrown Apr 10, 2020
222d8c7
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 13, 2020
fbac756
add sample runtime to localPublish
benbrown Apr 13, 2020
4b4fb58
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 14, 2020
7cbb723
handle success and failure of runtime injection
benbrown Apr 14, 2020
04bd2bd
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 14, 2020
9b3f89a
respect enableCustomRuntime
benbrown Apr 14, 2020
f9ed942
pull real runtime code
benbrown Apr 15, 2020
4e7437b
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 15, 2020
d921a9a
eject real code
benbrown Apr 15, 2020
fb6ccbb
change the path of the declarative assets relative to the runtime
benbrown Apr 15, 2020
ab9cba4
update code copying to reflect new asset locations
benbrown Apr 15, 2020
6ca6d2f
cleanup
benbrown Apr 15, 2020
6a3861c
allow parameters to be included in start command
benbrown Apr 15, 2020
870bd50
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 15, 2020
13e91fa
update readme with new info about additional plugin APIs
benbrown Apr 15, 2020
b03c870
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 15, 2020
d4cb3f5
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 16, 2020
53038a5
change schema of settings
benbrown Apr 16, 2020
f34164f
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 17, 2020
c1cbee3
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 17, 2020
9280318
little bit more error correction
benbrown Apr 17, 2020
3bbdd6b
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 17, 2020
3e5fd1d
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 17, 2020
1a0eb8e
fix issue with field binding
benbrown Apr 17, 2020
164c946
Merge branch 'master' into benbrown/2470
benbrown Apr 17, 2020
20bef08
Merge branch 'master' into benbrown/2470
benbrown Apr 20, 2020
c78bed0
Merge branch 'master' into benbrown/2470
benbrown Apr 20, 2020
16cf4d9
fix form behaviors
benbrown Apr 20, 2020
f49acfa
Merge branch 'benbrown/2470' of github.com:microsoft/BotFramework-Com…
benbrown Apr 20, 2020
dbcef7c
Merge branch 'master' into benbrown/2470
cwhitten Apr 21, 2020
7b03572
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 23, 2020
078cd1b
address comments from andy
benbrown Apr 23, 2020
7b0581e
Merge branch 'master' of github.com:microsoft/BotFramework-Composer i…
benbrown Apr 23, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions BotProject/Templates/CSharp/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
## Bot Project
## Bot Runtime
Bot project is the launcher project for the bots written in declarative form (JSON), using the Composer, for the Bot Framework SDK.
This same code is used by Composer to start the bot locally for testing.

## Instructions for setting up the Bot Project runtime
The Bot Project is a regular Bot Framework SDK V4 project. Before you can launch it from the emulator, you need to make sure you can run the bot.
## Instructions for using and customizing the bot runtime

Composer can be configured to use a customized copy of this runtime.
A copy of it can be added to your project automatically by using the "runtime settings" page in Composer.

The Bot Project is a regular Bot Framework SDK V4 project. You can modify the code of this project
and continue to use it with Composer.

* Add additional middleware
* Customize the state storage system
* Add custom dialog classes

### Prerequisite:
* Install .Netcore 3.1

### Commands:
### Build:

* from root folder
* cd BotProject
* cd Templates/CSharp
* cd [my bot folder]/runtime
* dotnet user-secrets init // init the user secret id
* dotnet build // build


### Run from Command line:
* cd [my bot folder]/runtime
* dotnet run // start the bot
* It will start a web server and listening at http://localhost:3979.

### Run with Composer

Open your bot project in Composer. Navigate to the runtime settings tab.

Set the path to runtime to the full path to your runtime code. Customize the start command as necessary.

The "Start Bot" button will now use your customized runtime.

Note: the application code must be built and ready to run before Composer can manage it.

### Test bot
* You can set you emulator to connect to http://localhost:3979/api/messages.

2 changes: 1 addition & 1 deletion BotProject/Templates/CSharp/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"microsoftAppId": "",
"bot": "ComposerDialogs",
"bot": "../",
"cosmosDb": {
"authKey": "",
"collectionId": "botstate-collection",
Expand Down
2 changes: 2 additions & 0 deletions Composer/packages/client/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ export enum ActionTypes {
GET_PUBLISH_STATUS_FAILED = 'GET_PUBLISH_STATUS_FAILED',
GET_PUBLISH_HISTORY = 'GET_PUBLISH_HISTORY',
UPDATE_BOTSTATUS = 'UPDATE_BOTSTATUS',
SET_RUNTIME_TEMPLATES = 'SET_RUNTIME_TEMPLATES',
SET_USER_SETTINGS = 'SET_USER_SETTINGS',
ADD_SKILL_DIALOG_BEGIN = 'ADD_SKILL_DIALOG_BEGIN',
ADD_SKILL_DIALOG_END = 'ADD_SKILL_DIALOG_END',
EJECT_SUCCESS = 'EJECT_SUCCESS',
SET_MESSAGE = 'SET_MESSAGE',
SET_APP_UPDATE_ERROR = 'SET_APP_UPDATE_ERROR',
SET_APP_UPDATE_PROGRESS = 'SET_APP_UPDATE_PROGRESS',
Expand Down
3 changes: 3 additions & 0 deletions Composer/packages/client/src/pages/setting/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const SettingPage: React.FC<RouteComponentProps<{ '*': string }>> = props => {
publish: formatMessage('Publish'),
settings: formatMessage('Settings'),
preferences: formatMessage('User Preferences'),
runtime: formatMessage('Runtime Config'),
};

const links: INavLink[] = [
Expand All @@ -44,6 +45,8 @@ const SettingPage: React.FC<RouteComponentProps<{ '*': string }>> = props => {
url: '',
},
{ key: 'preferences', name: settingLabels.preferences, url: '' },
{ key: 'runtime', name: settingLabels.runtime, url: '' },

// { key: '/settings/publish', name: settingLabels.publish, url: '' },

// { key: 'services', name: formatMessage('Services') },
Expand Down
2 changes: 2 additions & 0 deletions Composer/packages/client/src/pages/setting/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DialogSettings } from './dialog-settings';
import { RemotePublish } from './remote-publish';
import { Deployment } from './deployment';
import { UserSettings } from './user-settings';
import { RuntimeSettings } from './runtime-settings';

const Routes = () => {
return (
Expand All @@ -19,6 +20,7 @@ const Routes = () => {
<Deployment path="deployment" />
<RemotePublish path="remote-publish" />
<UserSettings path="preferences" />
<RuntimeSettings path="runtime" />
</Router>
</ErrorBoundary>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/** @jsx jsx */
import { jsx } from '@emotion/core';
import { useEffect, useMemo, useState, useContext } from 'react';
import { Dialog, DialogType } from 'office-ui-fabric-react/lib/Dialog';
import formatMessage from 'format-message';
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import { ChoiceGroup, IChoiceGroupOption } from 'office-ui-fabric-react/lib/ChoiceGroup';

import { StoreContext } from '../../../store';

import { modalControlGroup } from './style';

export interface EjectModalProps {
ejectRuntime: (templateKey: string) => void;
hidden: boolean;
closeModal: () => void;
}

export const EjectModal: React.FC<EjectModalProps> = props => {
const [selectedTemplate, setSelectedTemplate] = useState<string | undefined>();
const { state, actions } = useContext(StoreContext);
const { runtimeTemplates } = state;

useEffect(() => {
actions.getRuntimeTemplates();
}, []);

const availableRuntimeTemplates = useMemo(() => {
return runtimeTemplates.map(t => {
return {
text: t.name,
key: t.key,
};
});
}, [runtimeTemplates]);

const selectTemplate = (ev, item?: IChoiceGroupOption) => {
if (item) {
setSelectedTemplate(item.key);
}
};

const doEject = () => {
if (selectedTemplate) {
props.ejectRuntime(selectedTemplate);
}
};

return (
<Dialog
hidden={props.hidden}
onDismiss={props.closeModal}
dialogContentProps={{
type: DialogType.normal,
title: formatMessage('Add custom runtime'),
subText: formatMessage('Select runtime version to add'),
}}
modalProps={{
isBlocking: false,
}}
>
<div css={modalControlGroup}>
<ChoiceGroup options={availableRuntimeTemplates} onChange={selectTemplate} required={true} />
</div>
<DialogFooter>
<DefaultButton onClick={props.closeModal}>Cancel</DefaultButton>
<PrimaryButton onClick={doEject} disabled={!selectedTemplate}>
{formatMessage('Okay')}
</PrimaryButton>
</DialogFooter>
</Dialog>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/** @jsx jsx */
import { jsx } from '@emotion/core';
import { useState, useContext } from 'react';
import formatMessage from 'format-message';
import { Toggle } from 'office-ui-fabric-react/lib/Toggle';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { Link } from 'office-ui-fabric-react/lib/Link';
import { RouteComponentProps } from '@reach/router';

import { LoadingSpinner } from '../../../components/LoadingSpinner';
import { StoreContext } from '../../../store';

import { EjectModal } from './ejectModal';
import {
breathingSpace,
runtimeSettingsStyle,
runtimeControls,
runtimeControlsTitle,
runtimeToggle,
controlGroup,
} from './style';

export const RuntimeSettings: React.FC<RouteComponentProps> = () => {
const { state, actions } = useContext(StoreContext);
const { botName, settings, projectId } = state;
const [formDataErrors, setFormDataErrors] = useState({ command: '', path: '' });
const [ejectModalVisible, setEjectModalVisible] = useState(false);

const changeEnabled = (_, on) => {
actions.setSettings(projectId, botName, { ...settings, runtime: { ...settings.runtime, customRuntime: on } });
};

const updateSetting = field => (e, newValue) => {
let valid = true;
let error = 'There was an error';
if (newValue === '') {
valid = false;
error = 'This is a required field.';
}

actions.setSettings(projectId, botName, { ...settings, runtime: { ...settings.runtime, [field]: newValue } });

if (valid) {
setFormDataErrors({ ...formDataErrors, [field]: '' });
} else {
setFormDataErrors({ ...formDataErrors, [field]: error });
}
};

const header = () => (
<div css={runtimeControls}>
<h1 css={runtimeControlsTitle}>{formatMessage('Bot runtime settings')}</h1>
<p>{formatMessage('Configure Composer to start your bot using runtime code you can customize and control.')}</p>
</div>
);

const toggle = () => (
<div css={runtimeToggle}>
<Toggle
label={formatMessage('Use custom runtime')}
inlineLabel
onChange={changeEnabled}
checked={settings.runtime && settings.runtime.customRuntime === true}
/>
</div>
);

const showEjectModal = () => {
setEjectModalVisible(true);
};
const closeEjectModal = () => {
setEjectModalVisible(false);
};

const ejectRuntime = async (templateKey: string) => {
await actions.ejectRuntime(projectId, templateKey);
closeEjectModal();
};

return botName ? (
<div css={runtimeSettingsStyle}>
{header()}
{toggle()}
<div css={controlGroup}>
<TextField
label={formatMessage('Runtime code location')}
value={settings.runtime ? settings.runtime.path : ''}
styles={name}
required
onChange={updateSetting('path')}
errorMessage={formDataErrors.path}
data-testid="runtimeCodeLocation"
disabled={!settings.runtime || !settings.runtime.customRuntime}
/>
{formatMessage('Or: ')}
<Link
onClick={showEjectModal}
disabled={!settings.runtime || !settings.runtime.customRuntime}
css={breathingSpace}
>
{formatMessage('Get a new copy of the runtime code')}
</Link>

<TextField
label={formatMessage('Start command')}
value={settings.runtime ? settings.runtime.command : ''}
styles={name}
required
onChange={updateSetting('command')}
errorMessage={formDataErrors.command}
data-testid="runtimeCommand"
disabled={!settings.runtime || !settings.runtime.customRuntime}
/>
</div>
<EjectModal hidden={!ejectModalVisible} closeModal={closeEjectModal} ejectRuntime={ejectRuntime} />
</div>
) : (
<LoadingSpinner />
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { css } from '@emotion/core';
import { FontWeights, FontSizes } from 'office-ui-fabric-react/lib/Styling';
export const runtimeSettingsStyle = css`
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 1rem;
display: flex;
flex-direction: column;
box-sizing: border-box;
`;

export const runtimeControls = css`
margin-bottom: 18px;

& > h1 {
margin-top: 0;
}
`;

export const runtimeToggle = css`
display: flex;

& > * {
margin-right: 2rem;
}
`;

export const controlGroup = css`
border: 1px solid rgb(237, 235, 233);
padding: 0.5rem 1rem 1rem 1rem;
`;

export const modalControlGroup = css`
border: 1px solid rgb(237, 235, 233);
padding: 0.5rem 1rem 1rem 1rem;
`;

export const runtimeControlsTitle = css`
font-size: ${FontSizes.xLarge};
font-weight: ${FontWeights.semibold};
`;

export const breathingSpace = css`
margin-bottom: 1rem;
`;
Loading