This repository was archived by the owner on Jul 9, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 374
feat: Add skill configuration to bot project settings #6522
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
7cacc16
feat: Add skill configuration to bot project settings
tdurnford d50526a
hide remove button
tdurnford 215f796
Merge branch 'main' into durnford/feat/allowed-callers
tdurnford 8939e71
Move IsSkill.tsx to SkillToggle.tsx
tdurnford 30dcccc
Merge branch 'main' into durnford/feat/allowed-callers
hatpick a127d1a
requested chagnes
tdurnford 3788c60
Merge branch 'durnford/feat/allowed-callers' of github.com:microsoft/…
tdurnford 9692439
Merge branch 'main' into durnford/feat/allowed-callers
cwhitten 913c2f2
Merge branch 'main' into durnford/feat/allowed-callers
tdurnford f58f6d6
Merge branch 'main' into durnford/feat/allowed-callers
hatpick 8194ddb
Merge branch 'main' into durnford/feat/allowed-callers
cwhitten 33b76e6
lint
tdurnford File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
159 changes: 159 additions & 0 deletions
159
Composer/packages/client/src/pages/botProject/skill-configuration/AllowedCallers.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| /** @jsx jsx */ | ||
| import { jsx } from '@emotion/core'; | ||
| import React from 'react'; | ||
| import styled from '@emotion/styled'; | ||
| import { useRecoilValue } from 'recoil'; | ||
| import { ActionButton, IconButton } from 'office-ui-fabric-react/lib/components/Button'; | ||
| import { FluentTheme } from '@uifabric/fluent-theme'; | ||
| import { Stack } from 'office-ui-fabric-react/lib/components/Stack'; | ||
| import { ITextField, TextField } from 'office-ui-fabric-react/lib/components/TextField'; | ||
| import cloneDeep from 'lodash/cloneDeep'; | ||
| import formatMessage from 'format-message'; | ||
|
|
||
| import { dispatcherState, rootBotProjectIdSelector, settingsState } from '../../../recoilModel'; | ||
| import { mergePropertiesManagedByRootBot } from '../../../recoilModel/dispatchers/utils/project'; | ||
| import { addNewButton, tableColumnHeader } from '../styles'; | ||
|
|
||
| const Input = styled(TextField)({ | ||
| width: '100%', | ||
| position: 'relative', | ||
| '& .ms-TextField-fieldGroup:focus::after': { | ||
| content: '""', | ||
| position: 'absolute', | ||
| left: -1, | ||
| top: -1, | ||
| right: -1, | ||
| bottom: -1, | ||
| pointerEvents: 'none', | ||
| borderRadius: 2, | ||
| border: `2px solid ${FluentTheme.palette.themePrimary}`, | ||
| zIndex: 1, | ||
| }, | ||
| }); | ||
|
|
||
| const textFieldStyles = { | ||
| fieldGroup: { | ||
| borderColor: 'transparent', | ||
| transition: 'border-color 0.1s linear', | ||
| selectors: { | ||
| ':hover': { | ||
| borderColor: FluentTheme.palette.neutralLight, | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| const ItemContainer = styled.div({ | ||
| borderTop: `1px solid ${FluentTheme.palette.neutralLight}`, | ||
| marginTop: '4px', | ||
| }); | ||
|
|
||
| const Row = styled(Stack)({ | ||
| borderBottom: `1px solid ${FluentTheme.palette.neutralLight}`, | ||
| padding: '8px 0 8px 4px', | ||
| '& .ms-Button:not(:focus) i': { | ||
| visibility: 'hidden', | ||
| }, | ||
| '&:hover .ms-Button i': { | ||
| visibility: 'visible', | ||
| }, | ||
| }); | ||
|
|
||
| type ItemProps = { | ||
| value: string; | ||
| onBlur: () => void; | ||
| onChange: (event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => void; | ||
| onRemove: () => void; | ||
| }; | ||
|
|
||
| const Item = React.memo(({ value, onBlur, onChange, onRemove }: ItemProps) => { | ||
| const itemRef = React.useRef<ITextField | null>(null); | ||
| const didMount = React.useRef<boolean>(false); | ||
|
|
||
| React.useEffect(() => { | ||
| if (!value && !didMount.current) { | ||
| itemRef.current?.focus(); | ||
| } | ||
| didMount.current = true; | ||
| }, []); | ||
|
|
||
| return ( | ||
| <Row horizontal> | ||
tdurnford marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| <Input | ||
| componentRef={(ref) => (itemRef.current = ref)} | ||
| styles={textFieldStyles} | ||
| value={value} | ||
| onBlur={onBlur} | ||
| onChange={onChange} | ||
| /> | ||
| <IconButton aria-label={formatMessage('Remove item')} iconProps={{ iconName: 'Trash' }} onClick={onRemove} /> | ||
| </Row> | ||
| ); | ||
| }); | ||
|
|
||
| type Props = { | ||
| projectId: string; | ||
| }; | ||
|
|
||
| export const AllowedCallers: React.FC<Props> = ({ projectId }) => { | ||
| const { setSettings } = useRecoilValue(dispatcherState); | ||
| const rootBotProjectId = useRecoilValue(rootBotProjectIdSelector) || ''; | ||
| const settings = useRecoilValue(settingsState(projectId)); | ||
| const mergedSettings = mergePropertiesManagedByRootBot(projectId, rootBotProjectId, settings); | ||
| const { skillConfiguration } = mergedSettings; | ||
|
|
||
| const updateAllowedCallers = React.useCallback( | ||
| (allowedCallers: string[] = []) => { | ||
| const updatedSetting = { | ||
| ...cloneDeep(mergedSettings), | ||
| skillConfiguration: { ...skillConfiguration, allowedCallers }, | ||
| }; | ||
| setSettings(projectId, updatedSetting); | ||
| }, | ||
| [mergedSettings, projectId, skillConfiguration] | ||
| ); | ||
|
|
||
| const onBlur = React.useCallback(() => { | ||
| updateAllowedCallers(skillConfiguration?.allowedCallers?.filter(Boolean)); | ||
| }, [skillConfiguration?.allowedCallers, updateAllowedCallers]); | ||
|
|
||
| const onChange = React.useCallback( | ||
| (index: number) => (_: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue = '') => { | ||
| const updatedAllowedCallers = [...(skillConfiguration?.allowedCallers || [])]; | ||
| updatedAllowedCallers[index] = newValue; | ||
| updateAllowedCallers(updatedAllowedCallers); | ||
| }, | ||
| [skillConfiguration?.allowedCallers, updateAllowedCallers] | ||
| ); | ||
|
|
||
| const onRemove = React.useCallback( | ||
| (index: number) => () => { | ||
| const updatedAllowedCallers = skillConfiguration?.allowedCallers?.filter((_, itemIndex) => itemIndex !== index); | ||
| updateAllowedCallers(updatedAllowedCallers); | ||
| }, | ||
| [skillConfiguration?.allowedCallers, updateAllowedCallers] | ||
| ); | ||
|
|
||
| const onAddNewAllowedCaller = React.useCallback(() => { | ||
| updateAllowedCallers([...skillConfiguration?.allowedCallers, '']); | ||
| }, [skillConfiguration?.allowedCallers, updateAllowedCallers]); | ||
|
|
||
| return ( | ||
| <React.Fragment> | ||
| <div css={tableColumnHeader()}>{formatMessage('Allowed callers')} </div> | ||
| <ItemContainer> | ||
| {skillConfiguration?.allowedCallers?.map((caller, index) => { | ||
| return ( | ||
| <Item key={index} value={caller} onBlur={onBlur} onChange={onChange(index)} onRemove={onRemove(index)} /> | ||
tdurnford marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ); | ||
| })} | ||
| </ItemContainer> | ||
| <ActionButton data-testid={'addNewAllowedCaller'} styles={addNewButton} onClick={onAddNewAllowedCaller}> | ||
| {formatMessage('Add new')} | ||
| </ActionButton> | ||
| </React.Fragment> | ||
| ); | ||
| }; | ||
60 changes: 60 additions & 0 deletions
60
Composer/packages/client/src/pages/botProject/skill-configuration/SkillToggle.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| /** @jsx jsx */ | ||
| import { css, jsx } from '@emotion/core'; | ||
| import React from 'react'; | ||
| import { useRecoilValue } from 'recoil'; | ||
| import { Toggle } from 'office-ui-fabric-react/lib/components/Toggle'; | ||
| import cloneDeep from 'lodash/cloneDeep'; | ||
| import formatMessage from 'format-message'; | ||
|
|
||
| import { dispatcherState, rootBotProjectIdSelector, settingsState } from '../../../recoilModel'; | ||
| import { mergePropertiesManagedByRootBot } from '../../../recoilModel/dispatchers/utils/project'; | ||
|
|
||
| const toggle = css` | ||
| display: flex; | ||
| flex-direction: column; | ||
| box-sizing: border-box; | ||
| `; | ||
|
|
||
| type Props = { | ||
| projectId: string; | ||
| }; | ||
|
|
||
| export const SkillToggle: React.FC<Props> = ({ projectId }) => { | ||
| const { setSettings } = useRecoilValue(dispatcherState); | ||
| const rootBotProjectId = useRecoilValue(rootBotProjectIdSelector) || ''; | ||
| const settings = useRecoilValue(settingsState(projectId)); | ||
| const mergedSettings = mergePropertiesManagedByRootBot(projectId, rootBotProjectId, settings); | ||
| const { skillConfiguration } = mergedSettings; | ||
|
|
||
| const updateIsSkill = React.useCallback( | ||
| (isSkill: boolean) => { | ||
| const updatedSetting = { | ||
| ...cloneDeep(mergedSettings), | ||
| skillConfiguration: { ...skillConfiguration, isSkill }, | ||
| }; | ||
| setSettings(projectId, updatedSetting); | ||
| }, | ||
| [mergedSettings, projectId, skillConfiguration] | ||
| ); | ||
|
|
||
| const toggleIsSKill = React.useCallback( | ||
| (event, checked?: boolean) => { | ||
| updateIsSkill(!!checked); | ||
| }, | ||
| [updateIsSkill] | ||
| ); | ||
|
|
||
| return ( | ||
| <div css={toggle}> | ||
| <Toggle | ||
| inlineLabel | ||
| checked={!!skillConfiguration?.isSkill} | ||
| label={formatMessage('Allow bot to be called as skill')} | ||
| onChange={toggleIsSKill} | ||
| /> | ||
| </div> | ||
| ); | ||
| }; |
24 changes: 24 additions & 0 deletions
24
Composer/packages/client/src/pages/botProject/skill-configuration/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| import React from 'react'; | ||
| import formatMessage from 'format-message'; | ||
|
|
||
| import { CollapsableWrapper } from '../../../components/CollapsableWrapper'; | ||
| import { title } from '../styles'; | ||
|
|
||
| import { AllowedCallers } from './AllowedCallers'; | ||
| import { SkillToggle } from './SkillToggle'; | ||
|
|
||
| type Props = { | ||
| projectId: string; | ||
| }; | ||
|
|
||
| export const SkillConfiguration: React.FC<Props> = ({ projectId }) => { | ||
| return ( | ||
| <CollapsableWrapper title={formatMessage('Skill configuration')} titleStyle={title}> | ||
| <SkillToggle projectId={projectId} /> | ||
| <AllowedCallers projectId={projectId} /> | ||
| </CollapsableWrapper> | ||
| ); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.