Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

import { RecognizerSchema, FallbackRecognizerKey, ShellApi, ShellData } from '@bfc/extension-client';
import { checkForPVASchema } from '@bfc/shared';

import { recognizerOrderMap } from './defaultRecognizerOrder';
import { mapRecognizerSchemaToDropdownOption } from './mappers';
Expand All @@ -16,7 +17,15 @@ const getRankScore = (r: RecognizerSchema, shellData: ShellData, shellApi: Shell
return recognizerOrderMap[r.id] ?? Number.MAX_VALUE - 1;
};

export const getDropdownOptions = (recognizerConfigs: RecognizerSchema[], shellData: ShellData, shellApi: ShellApi) => {
export const getDropdownOptions = (configs: RecognizerSchema[], shellData: ShellData, shellApi: ShellApi) => {
const isPVASchema = checkForPVASchema(shellData.schemas?.sdk);
let recognizerConfigs: RecognizerSchema[] = configs;
if (isPVASchema) {
recognizerConfigs = recognizerConfigs.filter((config) => {
return config.id !== FallbackRecognizerKey;
});
}

return recognizerConfigs
.filter((r) => (typeof r.disabled === 'function' && !r.disabled(shellData, shellApi)) || !r.disabled)
.sort((r1, r2) => {
Expand Down
15 changes: 13 additions & 2 deletions Composer/packages/client/src/components/AppComponents/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ import { IconButton } from 'office-ui-fabric-react/lib/Button';
import { FocusZone } from 'office-ui-fabric-react/lib/FocusZone';
import { TooltipHost, DirectionalHint } from 'office-ui-fabric-react/lib/Tooltip';
import { RouteComponentProps } from '@reach/router';
import { useRecoilValue } from 'recoil';

import { resolveToBasePath } from '../../utils/fileUtil';
import { BASEPATH } from '../../constants';
import { NavItem } from '../NavItem';
import TelemetryClient from '../../telemetry/TelemetryClient';
import { PageLink } from '../../utils/pageLinks';
import { DisableFeatureToolTip } from '../DisableFeatureToolTip';
import { currentProjectIdState } from '../../recoilModel';
import { usePVACheck } from '../../hooks/usePVACheck';

import { useLinks } from './../../utils/hooks';

Expand Down Expand Up @@ -66,6 +70,8 @@ const divider = (isExpand: boolean) => css`
// -------------------- SideBar -------------------- //

export const SideBar: React.FC<RouteComponentProps> = () => {
const projectId = useRecoilValue(currentProjectIdState);
const isPVABot = usePVACheck(projectId);
const [sideBarExpand, setSideBarExpand] = useState(false);
const { topLinks, bottomLinks } = useLinks();

Expand All @@ -92,17 +98,22 @@ export const SideBar: React.FC<RouteComponentProps> = () => {
<div css={dividerTop} />{' '}
<FocusZone allowFocusRoot>
{topLinks.map((link, index) => {
return (
const navItem = (
<NavItem
key={'NavLeftBar' + index}
disabled={link.disabled}
disabled={link.disabled || link.isDisabledForPVA}
iconName={link.iconName}
labelName={link.labelName}
match={link.match}
showTooltip={showTooltips(link)}
to={mapNavItemTo(link.to)}
/>
);

if (link.isDisabledForPVA) {
return <DisableFeatureToolTip isPVABot={isPVABot}>{navItem}</DisableFeatureToolTip>;
}
return navItem;
})}
</FocusZone>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { css } from '@emotion/core';
import { NeutralColors, CommunicationColors } from '@uifabric/fluent-theme';
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';

import { DisableFeatureToolTip } from '../DisableFeatureToolTip';
import TelemetryClient from '../../telemetry/TelemetryClient';
import {
buildConfigurationSelector,
Expand All @@ -22,6 +23,7 @@ import {
} from '../../recoilModel';
import { BotStatus } from '../../constants';
import { useClickOutsideOutsideTarget } from '../../utils/hooks';
import { usePVACheck } from '../../hooks/usePVACheck';

import { BotControllerMenu } from './BotControllerMenu';
import { useBotOperations } from './useBotOperations';
Expand Down Expand Up @@ -76,6 +78,7 @@ const BotController: React.FC<BotControllerProps> = ({ onHideController, isContr
const { startAllBots, stopAllBots } = useBotOperations();
const builderEssentials = useRecoilValue(buildConfigurationSelector);
const rootBotId = useRecoilValue(rootBotProjectIdSelector);
const isPVABot = usePVACheck(rootBotId ?? '');

const startPanelTarget = useRef(null);
const botControllerMenuTarget = useRef(null);
Expand Down Expand Up @@ -209,60 +212,64 @@ const BotController: React.FC<BotControllerProps> = ({ onHideController, isContr
return <BotRuntimeStatus key={projectId} projectId={projectId} />;
})}
<div ref={botControllerMenuTarget} css={[startPanelsContainer]}>
<DefaultButton
primary
aria-roledescription={formatMessage('Bot Controller')}
ariaDescription={startPanelButtonText}
data-testid={'startBotButton'}
disabled={disableStartBots || areBotsStarting}
iconProps={{
iconName: statusIconClass,
styles: {
root: {
color: `${NeutralColors.white}`,
},
},
}}
id={'startbot'}
menuAs={() => null}
styles={{
root: {
backgroundColor: CommunicationColors.tint10,
display: 'flex',
alignItems: 'center',
minWidth: '229px',
height: '36px',
flexDirection: 'row',
padding: '0 7px',
border: `1px solid ${CommunicationColors.tint10}`,
width: '100%',
},
rootHovered: {
background: transparentBackground,
},
rootDisabled: {
opacity: 0.6,
backgroundColor: CommunicationColors.tint10,
color: `${NeutralColors.white}`,
border: 'none',
font: '62px',
},
}}
title={startPanelButtonText}
onClick={handleClick}
<DisableFeatureToolTip
content={formatMessage('PVA bots cannot be run at the moment. Publish the bot to PVA and test it there.')}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This could be a constant that gets imported so we only have to change the copy in one place if necessary

isPVABot={isPVABot}
>
{areBotsStarting && (
<Spinner
size={SpinnerSize.small}
styles={{
<DefaultButton
primary
aria-roledescription={formatMessage('Bot Controller')}
ariaDescription={startPanelButtonText}
data-testid={'startBotButton'}
disabled={disableStartBots || areBotsStarting}
iconProps={{
iconName: statusIconClass,
styles: {
root: {
marginRight: '5px',
color: `${NeutralColors.white}`,
},
}}
/>
)}
<span style={{ margin: '0 0 2px 5px' }}>{startPanelButtonText}</span>
</DefaultButton>
},
}}
menuAs={() => null}
styles={{
root: {
backgroundColor: CommunicationColors.tint10,
display: 'flex',
alignItems: 'center',
minWidth: '229px',
height: '36px',
flexDirection: 'row',
padding: '0 7px',
border: `1px solid ${CommunicationColors.tint10}`,
width: '100%',
},
rootHovered: {
background: transparentBackground,
},
rootDisabled: {
opacity: 0.6,
backgroundColor: CommunicationColors.tint10,
color: `${NeutralColors.white}`,
border: 'none',
font: '62px',
},
}}
title={startPanelButtonText}
onClick={handleClick}
>
{areBotsStarting && (
<Spinner
size={SpinnerSize.small}
styles={{
root: {
marginRight: '5px',
},
}}
/>
)}
<span style={{ margin: '0 0 2px 5px' }}>{startPanelButtonText}</span>
</DefaultButton>
</DisableFeatureToolTip>
<div ref={onboardRef} css={[iconSectionContainer, disableStartBots ? disabledStyle : '']}>
<IconButton
ariaDescription={formatMessage('Open start bots panel')}
Expand Down
28 changes: 28 additions & 0 deletions Composer/packages/client/src/components/DisableFeatureToolTip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { useId } from '@uifabric/react-hooks';
import formatMessage from 'format-message';
import { TooltipHost } from 'office-ui-fabric-react/lib/Tooltip';
import React from 'react';

const calloutProps = { gapSpace: 0 };

const genericDisableMessage = () => {
return formatMessage('PVA bots cannot use this functionality at this time.');
};

export const DisableFeatureToolTip: React.FC<{ content?: string; isPVABot: boolean }> = (props) => {
const { isPVABot, content } = props;
const tooltipId = useId('pva-disable-tooltip');

if (!isPVABot) {
return <>{props.children}</>;
}

return (
<TooltipHost calloutProps={calloutProps} content={content ?? genericDisableMessage()} id={tooltipId}>
{props.children}
</TooltipHost>
);
};
5 changes: 1 addition & 4 deletions Composer/packages/client/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { IconButton, IButtonStyles } from 'office-ui-fabric-react/lib/Button';
import { Callout, DirectionalHint } from 'office-ui-fabric-react/lib/Callout';
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { FocusTrapZone } from 'office-ui-fabric-react/lib/FocusTrapZone';
import { checkForPVASchema } from '@bfc/shared';
import { useCallback, useState, Fragment, useMemo, useEffect } from 'react';
import { NeutralColors, SharedColors, FontSizes, CommunicationColors } from '@uifabric/fluent-theme';
import { useRecoilValue } from 'recoil';
Expand All @@ -18,7 +17,6 @@ import { TeachingBubble } from 'office-ui-fabric-react/lib/TeachingBubble';

import { useLocation } from '../utils/hooks';
import { BASEPATH } from '../constants';
import { schemasState } from '../recoilModel/atoms';
import {
dispatcherState,
appUpdateState,
Expand Down Expand Up @@ -162,7 +160,6 @@ export const Header = () => {
const [teachingBubbleVisibility, setTeachingBubbleVisibility] = useState<boolean>();
const [showGetStartedTeachingBubble, setshowGetStartedTeachingBubble] = useState<boolean>(false);
const settings = useRecoilValue(settingsState(projectId));
const schemas = useRecoilValue(schemasState(projectId));
const isWebChatPanelVisible = useRecoilValue(isWebChatPanelVisibleState);
const botProjectSolutionLoaded = useRecoilValue(botProjectSpaceLoadedState);

Expand Down Expand Up @@ -291,7 +288,7 @@ export const Header = () => {
</div>

<div css={rightSection}>
{isShow && !checkForPVASchema(schemas.sdk) && (
{isShow && (
<div
css={css`
margin-right: 12px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BotStatus } from '../../constants';
import { perProjectDiagnosticsSelectorFamily, botStatusState, rootBotProjectIdSelector } from '../../recoilModel';
import TelemetryClient from '../../telemetry/TelemetryClient';
import { createBotSettingUrl, navigateTo } from '../../utils/navigation';
import { usePVACheck } from '../../hooks/usePVACheck';

import { isChildDialogLinkSelected, doesLinkMatch } from './helpers';
import { TreeItem } from './treeItem';
Expand Down Expand Up @@ -69,6 +70,7 @@ export const ProjectHeader = (props: ProjectHeaderProps) => {
const rootProjectId = useRecoilValue(rootBotProjectIdSelector) || '';
const status = useRecoilValue(botStatusState(projectId));
const diagnostics = useRecoilValue(perProjectDiagnosticsSelectorFamily(projectId));
const isPVABot = usePVACheck(projectId);
const isRunning = status === BotStatus.connected;

const displayName = `${name} ${rootProjectId !== projectId ? `(${formatMessage('Skill')})` : ''}`;
Expand All @@ -85,14 +87,15 @@ export const ProjectHeader = (props: ProjectHeaderProps) => {
};

const generateMenuItems = useCallback(() => {
const menuItems = [
let menuItems = [
{
label: formatMessage('Add a dialog'),
icon: 'Add',
onClick: () => {
onBotCreateDialog(projectId);
TelemetryClient.track('AddNewDialogStarted');
},
isDisableForPVA: false,
},
{
label: isRunning ? formatMessage('Stop bot') : formatMessage('Start bot'),
Expand All @@ -105,6 +108,7 @@ export const ProjectHeader = (props: ProjectHeaderProps) => {
isRoot: projectId === rootProjectId,
});
},
isDisableForPVA: true,
},
{
label: '',
Expand All @@ -115,18 +119,21 @@ export const ProjectHeader = (props: ProjectHeaderProps) => {
onClick: () => {
onBotEditManifest(projectId);
},
isDisableForPVA: true,
},
{
label: formatMessage('Export this bot as .zip'),
onClick: () => {
onBotExportZip(projectId);
},
isDisableForPVA: false,
},
{
label: formatMessage('Settings'),
onClick: () => {
navigateTo(createBotSettingUrl(link.projectId, link.skillId));
},
isDisableForPVA: false,
},
];

Expand All @@ -136,13 +143,18 @@ export const ProjectHeader = (props: ProjectHeaderProps) => {
onBotRemoveSkill(projectId);
},
};

if (isRemote || botError) {
return [removeSkillItem];
}

if (!isRootBot) {
menuItems.splice(3, 0, removeSkillItem);
}

if (isPVABot) {
menuItems = menuItems.filter((item) => !item.isDisableForPVA);
}
return menuItems;
}, [projectId, isRunning]);

Expand Down
Loading