Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 405c8d3

Browse files
liweitianGeoffCoxMSFTbeyackletonyanzianoLouisEugeneMSFT
authored
fix: merge with main (#5048)
* try-catch around trigger grouping expressions (#5017) Co-authored-by: Ben Yackley <[email protected]> * chore: Updated installOneAuth script to target correct version. (#5020) * Updated installOneAuth script to target correct version. * Better refactor * feat: adaptive expression functions menu (#5015) * expressions menu * Fixing aligment of menu * PR comments Co-authored-by: Soroush <[email protected]> * fix: Correct handling of focus for Intellisense fields (#5039) * fix * Improved handling of focus when leveraging an Intellisense suggestion * comments on wrong lines * feat: azure publish with orchestrator (#5011) * refactor the luis build in azure publish * update the orchestrator path * update the cleanup * fix typo * catch the build error * remove qna endpoint * remove console * add qnaconfig Co-authored-by: Geoff Cox (Microsoft) <[email protected]> Co-authored-by: Ben Yackley <[email protected]> Co-authored-by: Tony Anziano <[email protected]> Co-authored-by: LouisEugeneMSFT <[email protected]> Co-authored-by: Soroush <[email protected]> Co-authored-by: leileizhang <[email protected]>
1 parent b5551c9 commit 405c8d3

File tree

26 files changed

+585
-658
lines changed

26 files changed

+585
-658
lines changed

Composer/packages/adaptive-form/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"dependencies": {
4444
"@emotion/core": "^10.0.27",
4545
"lodash": "^4.17.19",
46-
"react-error-boundary": "^1.2.5"
46+
"react-error-boundary": "^1.2.5",
47+
"@bfc/built-in-functions": "*"
4748
}
4849
}

Composer/packages/adaptive-form/src/components/SchemaField.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ export const SchemaField: React.FC<FieldProps> = (props) => {
5151
typeof uiOptions?.serializer?.set === 'function' ? uiOptions.serializer.set(newValue) : newValue;
5252

5353
onChange(serializedValue);
54-
setFieldFocused(true);
5554
};
5655

5756
useEffect(() => {

Composer/packages/adaptive-form/src/components/ExpressionSwitchWindow.tsx renamed to Composer/packages/adaptive-form/src/components/expressions/ExpressionSwitchWindow.tsx

File renamed without changes.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
import { ContextualMenu, DirectionalHint } from 'office-ui-fabric-react/lib/ContextualMenu';
5+
import React, { useCallback, useMemo } from 'react';
6+
import { builtInFunctionsGrouping, getBuiltInFunctionInsertText } from '@bfc/built-in-functions';
7+
8+
import { expressionGroupingsToMenuItems } from './utils/expressionsListMenuUtils';
9+
10+
const componentMaxHeight = 400;
11+
12+
type ExpressionsListMenuProps = {
13+
onExpressionSelected: (expression: string) => void;
14+
onMenuMount: (menuContainerElms: HTMLDivElement[]) => void;
15+
};
16+
export const ExpressionsListMenu = (props: ExpressionsListMenuProps) => {
17+
const { onExpressionSelected, onMenuMount } = props;
18+
19+
const containerRef = React.createRef<HTMLDivElement>();
20+
21+
const onExpressionKeySelected = useCallback(
22+
(key) => {
23+
const insertText = getBuiltInFunctionInsertText(key);
24+
onExpressionSelected('= ' + insertText);
25+
},
26+
[onExpressionSelected]
27+
);
28+
29+
const onLayerMounted = useCallback(() => {
30+
const elms = document.querySelectorAll<HTMLDivElement>('.ms-ContextualMenu-Callout');
31+
onMenuMount(Array.prototype.slice.call(elms));
32+
}, [onMenuMount]);
33+
34+
const menuItems = useMemo(
35+
() =>
36+
expressionGroupingsToMenuItems(
37+
builtInFunctionsGrouping,
38+
onExpressionKeySelected,
39+
onLayerMounted,
40+
componentMaxHeight
41+
),
42+
[onExpressionKeySelected, onLayerMounted]
43+
);
44+
45+
return (
46+
<div ref={containerRef}>
47+
<ContextualMenu
48+
calloutProps={{
49+
onLayerMounted: onLayerMounted,
50+
}}
51+
directionalHint={DirectionalHint.bottomLeftEdge}
52+
hidden={false}
53+
items={menuItems}
54+
shouldFocusOnMount={false}
55+
styles={{
56+
container: { maxHeight: componentMaxHeight },
57+
}}
58+
target={containerRef}
59+
/>
60+
</div>
61+
);
62+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
import { ContextualMenuItemType, IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu';
5+
6+
type ExpressionGroupingType = {
7+
key: string;
8+
name: string;
9+
children: string[];
10+
};
11+
12+
export const expressionGroupingsToMenuItems = (
13+
expressionGroupings: ExpressionGroupingType[],
14+
menuItemSelectedHandler: (key: string) => void,
15+
onLayerMounted: () => void,
16+
maxHeight?: number
17+
): IContextualMenuItem[] => {
18+
const menuItems: IContextualMenuItem[] =
19+
expressionGroupings?.map((grouping: ExpressionGroupingType) => {
20+
return {
21+
key: grouping.key,
22+
text: grouping.name,
23+
target: '_blank',
24+
subMenuProps: {
25+
calloutProps: { onLayerMounted: onLayerMounted },
26+
items: grouping.children.map((key: string) => {
27+
return {
28+
key: key,
29+
text: key,
30+
onClick: () => menuItemSelectedHandler(key),
31+
};
32+
}),
33+
styles: { container: { maxHeight } },
34+
},
35+
};
36+
}) || [];
37+
38+
const header = {
39+
key: 'header',
40+
itemType: ContextualMenuItemType.Header,
41+
text: 'Pre-built functions',
42+
itemProps: { lang: 'en-us' },
43+
};
44+
45+
menuItems.unshift(header);
46+
47+
return menuItems;
48+
};

Composer/packages/adaptive-form/src/components/fields/IntellisenseFields.tsx

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
import { FieldProps } from '@bfc/extension-client';
55
import { Intellisense } from '@bfc/intellisense';
6-
import React, { useRef } from 'react';
6+
import React, { useRef, useState } from 'react';
77

88
import { getIntellisenseUrl } from '../../utils/getIntellisenseUrl';
9-
import { ExpressionSwitchWindow } from '../ExpressionSwitchWindow';
9+
import { ExpressionSwitchWindow } from '../expressions/ExpressionSwitchWindow';
10+
import { ExpressionsListMenu } from '../expressions/ExpressionsListMenu';
1011

1112
import { JsonField } from './JsonField';
1213
import { NumberField } from './NumberField';
@@ -35,9 +36,18 @@ export const IntellisenseTextField: React.FC<FieldProps<string>> = (props) => {
3536
onBlur={props.onBlur}
3637
onChange={onChange}
3738
>
38-
{({ textFieldValue, focused, onValueChanged, onKeyDownTextField, onKeyUpTextField, onClickTextField }) => (
39+
{({
40+
textFieldValue,
41+
focused,
42+
cursorPosition,
43+
onValueChanged,
44+
onKeyDownTextField,
45+
onKeyUpTextField,
46+
onClickTextField,
47+
}) => (
3948
<StringField
4049
{...props}
50+
cursorPosition={cursorPosition}
4151
focused={focused}
4252
id={id}
4353
value={textFieldValue}
@@ -58,8 +68,23 @@ export const IntellisenseExpressionField: React.FC<FieldProps<string>> = (props)
5868
const scopes = ['expressions', 'user-variables'];
5969
const intellisenseServerUrlRef = useRef(getIntellisenseUrl());
6070

71+
const [expressionsListContainerElements, setExpressionsListContainerElements] = useState<HTMLDivElement[]>([]);
72+
73+
const completionListOverrideResolver = (value: string) => {
74+
return value === '=' ? (
75+
<ExpressionsListMenu
76+
onExpressionSelected={(expression: string) => onChange(expression)}
77+
onMenuMount={(refs) => {
78+
setExpressionsListContainerElements(refs);
79+
}}
80+
/>
81+
) : null;
82+
};
83+
6184
return (
6285
<Intellisense
86+
completionListOverrideContainerElements={expressionsListContainerElements}
87+
completionListOverrideResolver={completionListOverrideResolver}
6388
focused={defaultFocused}
6489
id={`intellisense-${id}`}
6590
scopes={scopes}
@@ -68,9 +93,18 @@ export const IntellisenseExpressionField: React.FC<FieldProps<string>> = (props)
6893
onBlur={props.onBlur}
6994
onChange={onChange}
7095
>
71-
{({ textFieldValue, focused, onValueChanged, onKeyDownTextField, onKeyUpTextField, onClickTextField }) => (
96+
{({
97+
textFieldValue,
98+
focused,
99+
cursorPosition,
100+
onValueChanged,
101+
onKeyDownTextField,
102+
onKeyUpTextField,
103+
onClickTextField,
104+
}) => (
72105
<StringField
73106
{...props}
107+
cursorPosition={cursorPosition}
74108
focused={focused}
75109
id={id}
76110
value={textFieldValue}

Composer/packages/adaptive-form/src/components/fields/StringField.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const StringField: React.FC<FieldProps<string>> = function StringField(pr
4141
uiOptions,
4242
required,
4343
focused,
44+
cursorPosition,
4445
} = props;
4546

4647
const textFieldRef = React.createRef<ITextField>();
@@ -49,7 +50,13 @@ export const StringField: React.FC<FieldProps<string>> = function StringField(pr
4950
if (focused && textFieldRef.current) {
5051
textFieldRef.current.focus();
5152
}
52-
}, [focused, textFieldRef.current]);
53+
}, [focused, textFieldRef.current, value]);
54+
55+
useEffect(() => {
56+
if (cursorPosition !== undefined && cursorPosition > -1 && textFieldRef.current) {
57+
textFieldRef.current.setSelectionRange(cursorPosition, cursorPosition);
58+
}
59+
}, [cursorPosition]);
5360

5461
const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
5562
if (typeof onFocus === 'function') {

Composer/packages/client/src/recoilModel/dispatchers/publisher.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ import {
1414
isEjectRuntimeExistState,
1515
filePersistenceState,
1616
settingsState,
17+
luFilesState,
18+
qnaFilesState,
1719
} from '../atoms/botState';
18-
import { botEndpointsState } from '../atoms';
1920
import { openInEmulator } from '../../utils/navigation';
20-
import { rootBotProjectIdSelector } from '../selectors';
21+
import { rootBotProjectIdSelector, dialogsSelectorFamily } from '../selectors';
22+
import { botEndpointsState } from '../atoms';
23+
import * as luUtil from '../../utils/luUtil';
2124

2225
import { BotStatus, Text } from './../../constants';
2326
import httpClient from './../../utils/httpUtil';
@@ -139,10 +142,24 @@ export const publisherDispatcher = () => {
139142
});
140143

141144
const publishToTarget = useRecoilCallback(
142-
(callbackHelpers: CallbackInterface) => async (projectId: string, target: any, metadata, sensitiveSettings) => {
145+
(callbackHelpers: CallbackInterface) => async (
146+
projectId: string,
147+
target: any,
148+
metadata: any,
149+
sensitiveSettings
150+
) => {
143151
try {
152+
const { snapshot } = callbackHelpers;
153+
const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
154+
const luFiles = await snapshot.getPromise(luFilesState(projectId));
155+
const qnaFiles = await snapshot.getPromise(qnaFilesState(projectId));
156+
const referredLuFiles = luUtil.checkLuisBuild(luFiles, dialogs);
144157
const response = await httpClient.post(`/publish/${projectId}/publish/${target.name}`, {
145-
metadata,
158+
metadata: {
159+
...metadata,
160+
luResources: referredLuFiles.map((file) => file.id),
161+
qnaResources: qnaFiles.map((file) => file.id),
162+
},
146163
sensitiveSettings,
147164
});
148165
await publishSuccess(callbackHelpers, projectId, response.data, target);

Composer/packages/electron-server/scripts/installOneAuth.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const { log } = require('./common');
2121
*/
2222

2323
let packageName = null;
24+
const packageVersion = '1.14.0';
2425

2526
switch (process.platform) {
2627
case 'darwin':
@@ -54,7 +55,7 @@ async function downloadPackage() {
5455
log.info('Starting download.');
5556
await ensureDir(outDir);
5657
try {
57-
execSync(`cd ${outDir} && npm pack ${packageName}`, { encoding: 'utf-8' });
58+
execSync(`cd ${outDir} && npm pack ${packageName}@${packageVersion}`, { encoding: 'utf-8' });
5859
} catch (err) {
5960
process.exit(1);
6061
return;

Composer/packages/extension-client/src/types/form.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export interface FieldProps<T = any> {
3636
value?: T;
3737
focused?: boolean;
3838
style?: React.CSSProperties;
39+
cursorPosition?: number;
3940

4041
onChange: ChangeHandler<T>;
4142
onFocus?: (id: string, value?: T) => void;

0 commit comments

Comments
 (0)