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

fix: introduce ability to pick a free or paid tier of QnA #7184

Merged
merged 39 commits into from
Apr 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
5d62dd6
Refactor LUIS, QNA and Speech to use a single base component
benbrown Apr 13, 2021
a63a732
fix height, sort order
benbrown Apr 14, 2021
4cb0e2a
Merge branch 'main' of https://github.com/microsoft/BotFramework-Comp…
benbrown Apr 14, 2021
2dfede3
fix typing
benbrown Apr 14, 2021
7fddaf5
Merge branch 'main' into benbrown/manageservice
beyackle Apr 14, 2021
e192517
use shared colors
benbrown Apr 14, 2021
162c04e
Merge branch 'benbrown/manageservice' of https://github.com/microsoft…
benbrown Apr 14, 2021
15e9189
refactor handoff instructions to share some text
benbrown Apr 14, 2021
3cbc986
Merge branch 'main' into benbrown/manageservice
benbrown Apr 14, 2021
917e0f9
Merge branch 'main' into benbrown/manageservice
benbrown Apr 14, 2021
b79a55c
Merge branch 'main' into benbrown/manageservice
benbrown Apr 15, 2021
94fa172
Merge branch 'main' into benbrown/manageservice
benbrown Apr 15, 2021
c26b401
Merge branch 'main' into benbrown/manageservice
benbrown Apr 15, 2021
001f1c2
Update BotProjectsSettingsTabView.tsx
benbrown Apr 15, 2021
cfa2ba8
refactor qna maker provisioning into a background process
benbrown Apr 15, 2021
0268660
Merge branch 'benbrown/manageservice' of https://github.com/microsoft…
benbrown Apr 15, 2021
bf3e822
Merge branch 'main' into benbrown/manageservice
benbrown Apr 16, 2021
4ca1b91
fix linter quible:w
benbrown Apr 16, 2021
33af30f
Merge branch 'benbrown/manageservice' of https://github.com/microsoft…
benbrown Apr 16, 2021
7d8d990
remove dep
benbrown Apr 16, 2021
dc359ec
rename setVisible to onToggleVisibility
benbrown Apr 16, 2021
ba97397
Merge branch 'main' into benbrown/manageservice
benbrown Apr 16, 2021
e6c8bd4
Use shared color
benbrown Apr 16, 2021
ca310e3
Merge branch 'benbrown/manageservice' of https://github.com/microsoft…
benbrown Apr 16, 2021
5a8dfd7
add conditional around missing hostname
benbrown Apr 16, 2021
4f40517
add conditional around missing hostname
benbrown Apr 16, 2021
dda8332
Merge branch 'main' into benbrown/manageservice
srinaath Apr 16, 2021
5ca0c64
Merge branch 'main' into benbrown/manageservice
srinaath Apr 16, 2021
46aebc5
Merge branch 'main' into benbrown/manageservice
benbrown Apr 19, 2021
6a1da84
Merge branch 'main' into benbrown/manageservice
benbrown Apr 19, 2021
1ba6fcc
Merge branch 'main' into benbrown/manageservice
benbrown Apr 20, 2021
c125c44
remove duplicate import
benbrown Apr 20, 2021
ceb0ab5
add ability to specify pricing tiers when provisioing a qna
benbrown Apr 20, 2021
5dbf316
merge
benbrown Apr 20, 2021
42e44c9
Merge branch 'main' into benbrown/qnatiers
benbrown Apr 21, 2021
f773989
Merge branch 'main' into benbrown/qnatiers
benbrown Apr 21, 2021
fdbb93b
Merge branch 'main' into benbrown/qnatiers
benbrown Apr 21, 2021
c04bd95
Merge branch 'main' into benbrown/qnatiers
cwhitten Apr 21, 2021
f501c14
Merge branch 'main' into benbrown/qnatiers
benbrown Apr 22, 2021
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
18 changes: 16 additions & 2 deletions Composer/packages/client/src/components/ManageQNA/ManageQNA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import { currentProjectIdState } from '../../recoilModel';
import { rootBotProjectIdSelector } from '../../recoilModel/selectors/project';

const QNA_REGIONS = [{ key: 'westus', text: 'westus' }];
const QNA_TIERS = [
{ key: 'free', text: 'Free' },
{ key: 'paid', text: 'Paid' },
];

type ManageQNAProps = {
hidden: boolean;
Expand All @@ -32,13 +36,22 @@ export const ManageQNA = (props: ManageQNAProps) => {
subscriptionId: string,
resourceGroupName: string,
resourceName: string,
region: string
region: string,
tier?: string
): Promise<string> => {
// hide modal
props.onToggleVisibility(false);

// start background QNA
createQNA(rootBotProjectId, tokenCredentials, subscriptionId, resourceGroupName, resourceName, region);
createQNA(
rootBotProjectId,
tokenCredentials,
subscriptionId,
resourceGroupName,
resourceName,
region,
tier || 'free'
);
return '';
};

Expand All @@ -54,6 +67,7 @@ export const ManageQNA = (props: ManageQNAProps) => {
regions={QNA_REGIONS}
serviceKeyType={'QnAMaker'}
serviceName={'QnA Maker'}
tiers={QNA_TIERS}
onDismiss={props.onDismiss}
onGetKey={props.onGetKey}
onNext={props.onNext}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ type ManageServiceProps = {
subscriptionId: string,
resourceGroupName: string,
resourceName: string,
region: string
region: string,
tier?: string
) => Promise<string>;
createServiceInBackground?: boolean;
handoffInstructions: string;
Expand All @@ -48,6 +49,7 @@ type ManageServiceProps = {
serviceName: string;
regions?: IDropdownOption[];
serviceKeyType: string;
tiers?: IDropdownOption[];
onToggleVisibility: (visible: boolean) => void;
};

Expand All @@ -58,11 +60,12 @@ type KeyRec = {
key: string;
};

const dropdownStyles = { dropdown: { width: '100%', marginBottom: 20 } };
const dropdownStyles = { dropdown: { width: '100%', marginBottom: 10 } };
const inputStyles = { root: { width: '100%', marginBottom: 10 } };
const summaryLabelStyles = { display: 'block', color: '#605E5C', fontSize: 14 };
const summaryStyles = { background: '#F3F2F1', padding: '1px 1rem' };
const mainElementStyle = { marginBottom: 20 };
const dialogBodyStyles = { height: 360 };
const dialogBodyStyles = { height: 480 };
const CREATE_NEW_KEY = 'CREATE_NEW';

export const ManageService = (props: ManageServiceProps) => {
Expand All @@ -76,6 +79,7 @@ export const ManageService = (props: ManageServiceProps) => {
const [newResourceGroupName, setNewResourceGroupName] = useState<string>('');
const [resourceGroupKey, setResourceGroupKey] = useState<string>('');
const [resourceGroup, setResourceGroup] = useState<string>('');
const [tier, setTier] = useState<string>('');

const [showHandoff, setShowHandoff] = useState<boolean>(false);
const [resourceName, setResourceName] = useState<string>('');
Expand Down Expand Up @@ -169,6 +173,14 @@ export const ManageService = (props: ManageServiceProps) => {
}
};

const handleTierOnChange = (e, value: IDropdownOption | undefined) => {
if (value != null) {
setTier(value.key as string);
} else {
setTier('');
}
};

const fetchKeys = async (cognitiveServicesManagementClient, accounts) => {
const keyList: KeyRec[] = [];
for (const account in accounts) {
Expand Down Expand Up @@ -265,14 +277,15 @@ export const ManageService = (props: ManageServiceProps) => {

try {
if (props.createServiceInBackground) {
props.createService(tokenCredentials, subscriptionId, resourceGroupName, resourceName, region);
props.createService(tokenCredentials, subscriptionId, resourceGroupName, resourceName, region, tier);
} else {
const newKey = await props.createService(
tokenCredentials,
subscriptionId,
resourceGroupName,
resourceName,
region
region,
tier
);

TelemetryClient.track('SettingsGetKeysCreateNewResourceCompleted', {
Expand Down Expand Up @@ -542,7 +555,7 @@ export const ManageService = (props: ManageServiceProps) => {
return (
<div>
<div css={dialogBodyStyles}>
<p>
<p css={{ marginTop: 0 }}>
{formatMessage(
'Input your details below to create a new {service} resource. You will be able to manage your new resource in the Azure portal.',
{ service: props.serviceName }
Expand Down Expand Up @@ -588,7 +601,7 @@ export const ManageService = (props: ManageServiceProps) => {
id={'resourceGroupName'}
label={formatMessage('Resource group name')}
placeholder={formatMessage('Enter name for new resource group')}
styles={{ root: { marginTop: 10 } }}
styles={inputStyles}
value={newResourceGroupName}
onChange={(e, val) => {
setNewResourceGroupName(val || '');
Expand Down Expand Up @@ -616,10 +629,25 @@ export const ManageService = (props: ManageServiceProps) => {
id={'resourceName'}
label={formatMessage('Resource name')}
placeholder={formatMessage('Enter name for new resources')}
styles={{ root: { marginTop: 10 } }}
styles={inputStyles}
value={resourceName}
onChange={(e, val) => setResourceName(val || '')}
/>
{props.tiers && (
<Dropdown
required
aria-label={formatMessage('Pricing tier')}
data-testid={'tier'}
disabled={!subscriptionId || loading !== undefined}
GeoffCoxMSFT marked this conversation as resolved.
Show resolved Hide resolved
id={'tier'}
label={formatMessage('Pricing tier')}
options={props.tiers}
placeholder={formatMessage('Select one')}
selectedKey={tier}
styles={dropdownStyles}
onChange={handleTierOnChange}
/>
)}
</div>
</div>
<DialogFooter>
Expand All @@ -635,6 +663,7 @@ export const ManageService = (props: ManageServiceProps) => {
!resourceName ||
!region ||
!resourceGroupKey ||
(props.tiers && !tier) ||
(resourceGroupKey == CREATE_NEW_KEY && !newResourceGroupName)
}
text={formatMessage('Next')}
Expand Down
118 changes: 84 additions & 34 deletions Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CallbackInterface, useRecoilCallback } from 'recoil';
import { CognitiveServicesManagementClient } from '@azure/arm-cognitiveservices';
import { TokenCredentials } from '@azure/ms-rest-js';
import { SearchManagementClient } from '@azure/arm-search';
import { SkuName } from '@azure/arm-search/lib/models';
import { WebSiteManagementClient } from '@azure/arm-appservice';
import { ApplicationInsightsManagementClient } from '@azure/arm-appinsights';

Expand All @@ -20,6 +21,57 @@ import { dispatcherState, settingsState } from '../atoms';
import { setError } from './shared';
import httpClient from './../../utils/httpUtil';
import { createNotification, addNotificationInternal, deleteNotificationInternal } from './notification';

type SkuList = {
search: {
name: SkuName;
};
qna: {
name: string;
};
appservice: {
name: string;
tier: string;
size: string;
family: string;
capacity: number;
};
appinsights?: boolean;
};

const FREE_SKUS: SkuList = {
search: {
name: 'free',
},
appservice: {
name: 'F1',
tier: 'Free',
size: 'F1',
family: 'F',
capacity: 1,
},
qna: {
name: 'F0',
},
};

const PAID_SKUS: SkuList = {
search: {
name: 'standard',
},
appservice: {
name: 'S1',
tier: 'Standard',
size: 'S1',
family: 'S',
capacity: 1,
},
qna: {
name: 'S0',
},
appinsights: true,
};

// poll for the endpoint key til it is available
const fetchEndpointKey = async (projectId: string, subscriptionKey: string): Promise<string> => {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -50,11 +102,12 @@ export const provisionQNADispatcher = () => {
subscriptionId: string,
resourceGroupName: string,
resourceName: string,
region: string
region: string,
tier: string
) => {
const { snapshot } = callbackHelpers;

const startTime = new Date().getTime();
const skus: SkuList = tier === 'free' ? FREE_SKUS : PAID_SKUS;

const notification = createNotification(getPendingQNANotificationCardProps());
// add that notification
Expand All @@ -68,9 +121,7 @@ export const provisionQNADispatcher = () => {
const searchManagementClient = new SearchManagementClient(tokenCredentials as any, subscriptionId);
await searchManagementClient.services.createOrUpdate(resourceGroupName, qnaMakerSearchName, {
location: region,
sku: {
name: 'standard',
},
sku: skus.search,
replicaCount: 1,
partitionCount: 1,
hostingMode: 'default',
Expand All @@ -79,40 +130,41 @@ export const provisionQNADispatcher = () => {
const webSiteManagementClient = new WebSiteManagementClient(tokenCredentials, subscriptionId);
await webSiteManagementClient.appServicePlans.createOrUpdate(resourceGroupName, resourceGroupName, {
location: region,
sku: {
name: 'S1',
tier: 'Standard',
size: 'S1',
family: 'S',
capacity: 1,
},
});
// deploy or update exisiting app insights component
const applicationInsightsManagementClient = new ApplicationInsightsManagementClient(
tokenCredentials,
subscriptionId
);
await applicationInsightsManagementClient.components.createOrUpdate(resourceGroupName, resourceGroupName, {
location: region,
applicationType: 'web',
kind: 'web',
sku: skus.appservice,
});

// add web config for websites
const azureSearchAdminKey = (await searchManagementClient.adminKeys.get(resourceGroupName, qnaMakerSearchName))
.primaryKey;
const appInsightsComponent = await applicationInsightsManagementClient.components.get(
resourceGroupName,
resourceGroupName
);
const userAppInsightsKey = appInsightsComponent.instrumentationKey;
const userAppInsightsName = resourceGroupName;
const userAppInsightsAppId = appInsightsComponent.appId;
const primaryEndpointKey = `${qnaMakerWebAppName}-PrimaryEndpointKey`;
const secondaryEndpointKey = `${qnaMakerWebAppName}-SecondaryEndpointKey`;
const defaultAnswer = 'No good match found in KB.';
const QNAMAKER_EXTENSION_VERSION = 'latest';

const azureSearchAdminKey = (await searchManagementClient.adminKeys.get(resourceGroupName, qnaMakerSearchName))
.primaryKey;

// if app insights is included, set this up too
let userAppInsightsAppId, userAppInsightsKey, userAppInsightsName;
if (skus.appinsights) {
// deploy or update exisiting app insights component
const applicationInsightsManagementClient = new ApplicationInsightsManagementClient(
tokenCredentials,
subscriptionId
);
await applicationInsightsManagementClient.components.createOrUpdate(resourceGroupName, resourceGroupName, {
location: region,
applicationType: 'web',
kind: 'web',
});

const appInsightsComponent = await applicationInsightsManagementClient.components.get(
resourceGroupName,
resourceGroupName
);
userAppInsightsKey = appInsightsComponent.instrumentationKey;
userAppInsightsName = resourceGroupName;
userAppInsightsAppId = appInsightsComponent.appId;
}

// deploy qna host webapp
const webAppResult = await webSiteManagementClient.webApps.createOrUpdate(
resourceGroupName,
Expand Down Expand Up @@ -179,9 +231,7 @@ export const provisionQNADispatcher = () => {
);
await cognitiveServicesManagementClient.accounts.create(resourceGroupName, qnaMakerServiceName, {
kind: 'QnAMaker',
sku: {
name: 'F0',
},
sku: skus.qna,
location: region,
properties: {
apiProperties: {
Expand Down