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: Adding UI for NL2F Expression Assistant and Copilot Service Interface #5107

Merged
merged 31 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c3580b2
improvements to logger service and interface
maturpi Mar 29, 2023
25b026e
updating logger tests
maturpi Mar 29, 2023
a2ae641
making eventData required so that status is always needed for end tra…
maturpi Mar 29, 2023
163579c
Merge branch 'Azure:main' into main
maturpi Apr 3, 2023
01f159c
Merge branch 'Azure:main' into main
maturpi Apr 5, 2023
2deb8c7
Merge branch 'Azure:main' into main
maturpi Apr 17, 2023
57a5f16
Merge branch 'Azure:main' into main
maturpi Apr 21, 2023
cc0d05b
Merge branch 'Azure:main' into main
maturpi May 1, 2023
aa3c9ec
Merge branch 'Azure:main' into main
maturpi May 2, 2023
6cfbd17
Merge branch 'Azure:main' into main
maturpi May 4, 2023
ff7d875
Merge branch 'Azure:main' into main
maturpi May 5, 2023
46d415b
Merge branch 'Azure:main' into main
maturpi May 8, 2023
e071882
Merge branch 'Azure:main' into main
maturpi May 9, 2023
7e0b13b
Merge branch 'Azure:main' into main
maturpi May 10, 2023
f3a22ba
Merge branch 'main' of https://github.com/maturpi/LogicAppsUX
maturpi Apr 25, 2024
d3a7892
fixing merge conflicts
maturpi Apr 25, 2024
a6ddd36
Merge remote-tracking branch 'upstream/main'
maturpi Apr 25, 2024
9ce2f4e
adding nl2f expressions feature and copilot client service
maturpi May 10, 2024
0fc249e
first iteration of NL2F Expression Assistant UI + fixing lint errors
maturpi May 30, 2024
344c555
resolving merge conflict from merging master into fork
maturpi May 30, 2024
3a40526
Merge branch 'main' into main
hartra344 May 31, 2024
702141c
merging upstream repo to forked repo
maturpi Jul 10, 2024
8925745
Merge branch 'main' of https://github.com/maturpi/LogicAppsUX
maturpi Jul 10, 2024
90e87f4
fixing npm problem by removing package-lock
maturpi Jul 11, 2024
46262e5
Merge remote-tracking branch 'upstream/main'
maturpi Jul 11, 2024
85bdffd
adding unit tests
maturpi Jul 23, 2024
6b87ecb
Merge branch 'main' into main
maturpi Jul 23, 2024
bc62f29
Merge remote-tracking branch 'upstream/main'
maturpi Jul 23, 2024
28fea81
Merge branch 'main' of https://github.com/maturpi/LogicAppsUX
maturpi Jul 23, 2024
dafa910
fixing file import syntax
maturpi Jul 23, 2024
b190e73
Merge remote-tracking branch 'upstream/main'
maturpi Jul 23, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
ConsumptionConnectionService,
StandardCustomCodeService,
ResourceIdentityType,
// Uncomment to use dummy version of copilot expression assistant
// BaseCopilotService,
BaseTenantService,
} from '@microsoft/logic-apps-shared';
import type { ContentType } from '@microsoft/logic-apps-shared';
Expand Down Expand Up @@ -58,6 +60,9 @@ const operationManifestServiceStandard = new StandardOperationManifestService({
httpClient,
});

// Uncomment to use dummy version of copilot expression assistant
// const baseCopilotService = new BaseCopilotService({isDev: true});

const operationManifestServiceConsumption = new ConsumptionOperationManifestService({
apiVersion: '2018-11-01',
baseUrl: '/url',
Expand Down Expand Up @@ -183,6 +188,8 @@ export const LocalDesigner = () => {
connectionService: isConsumption ? connectionServiceConsumption : connectionServiceStandard,
operationManifestService: isConsumption ? operationManifestServiceConsumption : operationManifestServiceStandard,
searchService: isConsumption ? searchServiceConsumption : searchServiceStandard,
// Uncomment to use dummy version of copilot expression assistant
// copilotService: baseCopilotService,
oAuthService,
gatewayService,
tenantService,
Expand Down
39 changes: 39 additions & 0 deletions libs/designer-ui/src/lib/tokenpicker/images/copilotLogo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
134 changes: 120 additions & 14 deletions libs/designer-ui/src/lib/tokenpicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
import type { LexicalEditor, NodeKey } from 'lexical';
import { useEffect, useRef, useState } from 'react';
import { useIntl } from 'react-intl';
import { Button } from '@fluentui/react-components';
import copilotLogo from './images/copilotLogo.svg';
import { Nl2fExpressionAssistant } from './nl2fExpressionAssistant';
import { isCopilotServiceEnabled } from '@microsoft/logic-apps-shared';

export const TokenPickerMode = {
TOKEN: 'token',
TOKEN_EXPRESSION: 'tokenExpression',
EXPRESSION: 'expression',
NL2F_EXPRESSION: 'nl2fExpression',
} as const;
export type TokenPickerMode = (typeof TokenPickerMode)[keyof typeof TokenPickerMode];

Expand All @@ -33,6 +38,27 @@ const directionalHint = DirectionalHint.leftTopEdge;
const gapSpace = 10;
const beakWidth = 20;

let calloutStyles: Partial<ICalloutContentStyles> = {
calloutMain: {
overflow: 'visible',
},
};

calloutStyles = isCopilotServiceEnabled()
? {
...calloutStyles,
calloutMain: {
borderRadius: '8px',
},
beakCurtain: {
borderRadius: '8px',
},
root: {
borderRadius: '8px',
},
}
: calloutStyles;

export type SearchTextChangedEventHandler = (e: string) => void;

export interface TokenPickerProps {
Expand Down Expand Up @@ -62,7 +88,7 @@ export function TokenPicker({
const intl = useIntl();
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
const [searchQuery, setSearchQuery] = useState('');
const [selectedKey, setSelectedKey] = useState<TokenPickerMode>(initialMode ?? TokenPickerMode.TOKEN);
const [selectedMode, setSelectedMode] = useState<TokenPickerMode>(initialMode ?? TokenPickerMode.TOKEN);
const [expressionToBeUpdated, setExpressionToBeUpdated] = useState<NodeKey | null>(null);
const [expression, setExpression] = useState<ExpressionEditorEvent>({ value: '', selectionStart: 0, selectionEnd: 0 });
const [fullScreen, setFullScreen] = useState(false);
Expand All @@ -73,7 +99,8 @@ export function TokenPicker({
const containerRef = useRef<HTMLDivElement | null>(null);
const expressionEditorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
const searchBoxRef = useRef<ISearchBox | null>(null);
const isExpression = initialMode === TokenPickerMode.EXPRESSION;
const isExpression = selectedMode === TokenPickerMode.EXPRESSION;
const isNl2fExpression = selectedMode === TokenPickerMode.NL2F_EXPRESSION;

useEffect(() => {
function handleResize() {
Expand All @@ -85,7 +112,7 @@ export function TokenPicker({
}, []);

useEffect(() => {
if (isExpression) {
if (isExpression || isNl2fExpression) {
setTimeout(() => {
expressionEditorRef.current?.focus();
}, 300);
Expand All @@ -94,11 +121,11 @@ export function TokenPicker({
searchBoxRef.current?.focus();
}, 0);
}
}, [isExpression]);
}, [isExpression, isNl2fExpression]);

const handleUpdateExpressionToken = (s: string, n: NodeKey) => {
setExpression({ value: s, selectionStart: 0, selectionEnd: 0 });
setSelectedKey(TokenPickerMode.EXPRESSION);
setSelectedMode(TokenPickerMode.EXPRESSION);
setExpressionToBeUpdated(n);

setTimeout(() => {
Expand All @@ -114,7 +141,7 @@ export function TokenPicker({

const handleSelectKey = (item?: PivotItem) => {
if (item?.props?.itemKey) {
setSelectedKey(item.props.itemKey as TokenPickerMode);
setSelectedMode(item.props.itemKey as TokenPickerMode);
}
};

Expand Down Expand Up @@ -148,11 +175,11 @@ export function TokenPicker({
description: 'Placeholder text to search token picker',
});

const calloutStyles: Partial<ICalloutContentStyles> = {
calloutMain: {
overflow: 'visible',
},
};
const createWithNl2fButtonText = intl.formatMessage({
defaultMessage: 'Create an expression with Copilot',
id: '+Agiub',
description: 'Button text for the create expression with copilot feature',
});

let editor: LexicalEditor | null;
try {
Expand All @@ -161,6 +188,67 @@ export function TokenPicker({
editor = null;
}

const nl2fExpressionPane = (
<Callout
role="dialog"
ariaLabelledBy={labelId}
gapSpace={gapSpace}
target={`#${editorId}`}
beakWidth={beakWidth}
directionalHint={directionalHint}
onMouseMove={handleExpressionEditorMoveDistance}
onMouseUp={() => {
if (isDraggingExpressionEditor) {
setIsDraggingExpressionEditor(false);
}
}}
onDismiss={(e) => {
if (e?.type === 'keydown' && (e as React.KeyboardEvent<HTMLElement>).key === 'Escape') {
editor?.dispatchCommand(CLOSE_TOKENPICKER, { focusEditorAfter: true });
} else {
editor?.dispatchCommand(CLOSE_TOKENPICKER, { focusEditorAfter: false });
}
}}
onRestoreFocus={() => {
return;
}}
styles={calloutStyles}
layerProps={{
hostId: 'msla-layer-host',
}}
>
<div
className="msla-token-picker-container-v3"
style={
fullScreen
? {
height: Math.max(windowDimensions.height - 100, Math.min(windowDimensions.height, 550)),
width: Math.max(
windowDimensions.width - (Number.parseInt(PanelSize.Medium, 10) + 40),
Math.min(windowDimensions.width - 16, 400)
),
}
: { maxHeight: Math.min(windowDimensions.height, 550), width: Math.min(windowDimensions.width - 16, 400) }
}
ref={containerRef}
>
<Nl2fExpressionAssistant
isFullScreen={fullScreen}
expression={expression}
isFixErrorRequest={expressionEditorError !== ''}
setFullScreen={setFullScreen}
setSelectedMode={setSelectedMode}
setExpression={setExpression}
setExpressionEditorError={setExpressionEditorError}
/>
</div>
</Callout>
);

if (isNl2fExpression) {
return nl2fExpressionPane;
}

return (
<>
<Callout
Expand Down Expand Up @@ -211,8 +299,10 @@ export function TokenPicker({
<TokenPickerHeader
fullScreen={fullScreen}
isExpression={isExpression}
isNl2fExpression={false}
setFullScreen={setFullScreen}
pasteLastUsedExpression={pasteLastUsedExpression}
setSelectedMode={setSelectedMode}
/>
) : null}

Expand All @@ -231,7 +321,23 @@ export function TokenPicker({
hideUTFExpressions={hideUTFExpressions}
/>
<div className="msla-token-picker-expression-editor-error">{expressionEditorError}</div>
<TokenPickerPivot selectedKey={selectedKey} selectKey={handleSelectKey} hideExpressions={!!tokenClickedCallback} />
{isCopilotServiceEnabled() ? (
<div className="msla_token_picker_nl2fex_button_container">
<Button
className="msla-token-picker-nl2fex-use-button"
size="medium"
onClick={() => {
setSelectedMode(TokenPickerMode.NL2F_EXPRESSION);
}}
title={createWithNl2fButtonText}
aria-label={createWithNl2fButtonText}
>
<img className="msla_token_picker_nl2fex_button_icon" src={copilotLogo} alt="Copilot" />
<span>{createWithNl2fButtonText}</span>
</Button>
</div>
) : null}
<TokenPickerPivot selectedKey={selectedMode} selectKey={handleSelectKey} hideExpressions={!!tokenClickedCallback} />
</div>
) : null}
<div className="msla-token-picker-search-container">
Expand All @@ -248,10 +354,10 @@ export function TokenPicker({
/>
</div>
<TokenPickerSection
tokenGroup={(selectedKey === TokenPickerMode.TOKEN ? filteredTokenGroup : tokenGroup) ?? []}
tokenGroup={(selectedMode === TokenPickerMode.TOKEN ? filteredTokenGroup : tokenGroup) ?? []}
expressionGroup={expressionGroup ?? []}
expressionEditorRef={expressionEditorRef}
selectedKey={selectedKey}
selectedMode={selectedMode}
searchQuery={searchQuery}
fullScreen={fullScreen}
expression={expression}
Expand Down
Loading
Loading