Skip to content
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
3c35b23
Add icons for AI document types
dan-niles Nov 12, 2025
cc155c0
Fix border bars in helper pane in dark mode
dan-niles Nov 12, 2025
eb0e87d
Add support for adding documents through helper pane
dan-niles Nov 12, 2025
bd89661
Add support for adding documents using hardcoded URLs through helper …
dan-niles Nov 13, 2025
2f33cf6
Update `shouldShowNavigationArrow` in helper pane to show arrow only …
dan-niles Nov 13, 2025
a82b758
Display record types in documents view in helper pane
dan-niles Nov 13, 2025
0c0d329
Update document insert in helper pane to wrap AI document type variab…
dan-niles Nov 13, 2025
22cefb8
Add document chip support to expression editor
dan-niles Nov 13, 2025
5e4739c
Update helper pane to conditionally display the Documents section bas…
dan-niles Nov 13, 2025
4830015
Update raw template expression editor to display chips properly
dan-niles Nov 13, 2025
439e548
Refactor token metadata handling to unify document and variable token…
dan-niles Nov 13, 2025
a556ff5
Fix the issue where record types are automatically added when selecti…
dan-niles Nov 14, 2025
92edcc8
Enhance token management to handle merged tokens in expression model,…
dan-niles Nov 14, 2025
91f211b
Fix AutoExpandingEditableDiv height in expanded mode
dan-niles Nov 14, 2025
1822148
Remove old chip editor files
dan-niles Nov 15, 2025
ac533c4
Add rawExpression prop to editor components
dan-niles Nov 17, 2025
4594b56
Refactor ContextAwareRawExpressionEditor to include template configur…
dan-niles Nov 17, 2025
af404d5
Remove redundant value checks in getSanitizedExp and getRawExp functions
dan-niles Nov 17, 2025
135e88b
Add support for rendering document tokens in chip expression editor
dan-niles Nov 17, 2025
1885a2d
Add support to switch between template mode and expression mode for t…
dan-niles Nov 17, 2025
b567f12
Revert "Remove redundant value checks in getSanitizedExp and getRawEx…
dan-niles Nov 17, 2025
0d36e30
Pass input mode as a prop to helper pane
dan-niles Nov 17, 2025
54b34c5
Remove inputMode prop from HelperPaneNewEl component
dan-niles Nov 17, 2025
421a1b4
Add template mode to expanded editor with markdown preview support
dan-niles Nov 17, 2025
2f9545d
Remove unused helper pane toggle and console log from MarkdownToolbar…
dan-niles Nov 18, 2025
4f9cf3c
Fix chip expression editor height in expanded mode
dan-niles Nov 18, 2025
c658409
Display error diagnostics in expanded editor for expression and templ…
dan-niles Nov 18, 2025
fb20726
Add option to disable auto-opening of helper pane in ChipExpressionEd…
dan-niles Nov 18, 2025
1844d60
Add Markdown preview styling and integrate with ReactMarkdown component
dan-niles Nov 18, 2025
518aa0b
Update template mode styles
dan-niles Nov 18, 2025
c2cf9b1
Fix bug where document token created from hardcoded URL gets inserted…
dan-niles Nov 19, 2025
f21d364
Update chip styles
dan-niles Nov 19, 2025
5928bcf
Refactor ChipComponent to use TokenType enum and update MarkdownPrevi…
dan-niles Nov 19, 2025
95e3e6e
Update ErrorBanner component to accept custom styles and apply max he…
dan-niles Nov 19, 2025
15cf507
Wrap variables in interpolations when adding through helper pane in t…
dan-niles Nov 19, 2025
7aca0ad
Refactor document type handling to use AIDocumentType in helper pane
dan-niles Nov 19, 2025
e11876e
Refactor getCurrentNavigationPath to use getCurrentPath in useHelperP…
dan-niles Nov 19, 2025
6e81502
Refactor ChipComponent styles to use styled components
dan-niles Nov 19, 2025
851676c
Remove disableAutoOpenHelperPane prop from ChipExpressionEditor
dan-niles Nov 19, 2025
3fe5315
Refactor chip styling in chip expression editor
dan-niles Nov 19, 2025
f794550
Refactor template mode markdown toolbar
dan-niles Nov 19, 2025
31ff8ae
Refactor MarkdownToolbar and CodeUtils for improved token processing
dan-niles Nov 19, 2025
33982b5
Refactor token processing in transformToMarkdown and CodeUtils for im…
dan-niles Nov 19, 2025
58938a6
Add support for inserting functions with interpolations in template mode
dan-niles Nov 19, 2025
49a6cb1
Address PR comments
dan-niles Nov 19, 2025
458b5b3
Set template mode as default for new template based form fields
dan-niles Nov 19, 2025
e080371
Fix condition to wrap value with template config in ContextAwareRawEx…
dan-niles Nov 20, 2025
78c8ce0
Swap priority values for token patterns in TOKEN_PATTERNS to correct …
dan-niles Nov 20, 2025
af669a2
Add a null check before passing start line to getExpressionTokens API
dan-niles Nov 20, 2025
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
6 changes: 6 additions & 0 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Copy link
Contributor

Choose a reason for hiding this comment

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

@dan-niles did you change this or is it from a merge commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it came from rebasing. Previously I sent the PR to bi-1.5.x branch and switched it to main.

2 changes: 2 additions & 0 deletions workspaces/ballerina/ballerina-side-panel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"lodash": "~4.17.21",
"react-hook-form": "7.56.4",
"react-markdown": "~10.1.0",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.1",
"@github/markdown-toolbar-element": "^2.2.3",
"@codemirror/commands": "~6.10.0",
"@codemirror/state": "~6.5.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { RefObject } from "react";
import { DiagnosticMessage, FormDiagnostics, TextEdit, PropertyModel, LinePosition, LineRange, ExpressionProperty, Metadata, RecordTypeField, Imports, ConfigProperties } from "@wso2/ballerina-core";
import { ParamConfig } from "../ParamManager/ParamManager";
import { CompletionItem, FormExpressionEditorRef, HelperPaneHeight, HelperPaneOrigin, OptionProps } from "@wso2/ui-toolkit";
import { InputMode } from "../editors/MultiModeExpressionEditor/ChipExpressionEditor/types";

export type FormValues = {
[key: string]: any;
Expand Down Expand Up @@ -184,7 +185,8 @@ type FormHelperPaneConditionalProps = {
helperPaneHeight: HelperPaneHeight,
recordTypeField?: RecordTypeField,
isAssignIdentifier?: boolean,
valueTypeConstraint?: string | string[]
valueTypeConstraint?: string | string[],
inputMode?: InputMode
) => JSX.Element;
helperPaneOrigin?: HelperPaneOrigin;
helperPaneHeight: HelperPaneHeight;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ export const SwitchWrapper = styled.div`
position: relative;
display: inline-flex;
align-items: center;
width: 112px;
min-width: 112px;
width: max-content;
height: 24px;
margin-top: 2px;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,9 @@ export const EditorFactory = (props: FormFieldEditorProps) => {

/>
);
} else if (!field.items && (field.type === "EXPRESSION" || field.type === "LV_EXPRESSION" || field.type == "ACTION_OR_EXPRESSION") && field.editable) {
// Expression field is a inline expression editor
} else if (!field.items && (field.type === "RAW_TEMPLATE" || field.valueTypeConstraint === "ai:Prompt") && field.editable) {
return (
<ContextAwareExpressionEditor
<ContextAwareRawExpressionEditor
field={field}
openSubPanel={openSubPanel}
subPanelView={subPanelView}
Expand All @@ -168,11 +167,17 @@ export const EditorFactory = (props: FormFieldEditorProps) => {
recordTypeField={recordTypeFields?.find(recordField => recordField.key === field.key)}
/>
);
} else if (!field.items && field.type === "RAW_TEMPLATE" && field.editable) {
} else if (!field.items && (field.type === "EXPRESSION" || field.type === "LV_EXPRESSION" || field.type == "ACTION_OR_EXPRESSION") && field.editable) {
// Expression field is a inline expression editor
return (
<ContextAwareRawExpressionEditor
<ContextAwareExpressionEditor
field={field}
openSubPanel={openSubPanel}
subPanelView={subPanelView}
handleOnFieldFocus={handleOnFieldFocus}
onBlur={onBlur}
autoFocus={autoFocus}
recordTypeField={recordTypeFields?.find(recordField => recordField.key === field.key)}
/>
);
} else if (field.type === "VIEW") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ import { EditorMode } from "./modes/types";
import { TextMode } from "./modes/TextMode";
import { PromptMode } from "./modes/PromptMode";
import { ExpressionMode } from "./modes/ExpressionMode";
import { TemplateMode } from "./modes/TemplateMode";
import { MinimizeIcon } from "../MultiModeExpressionEditor/ChipExpressionEditor/components/FloatingButtonIcons";
import { LineRange } from "@wso2/ballerina-core/lib/interfaces/common";
import { DiagnosticMessage } from "@wso2/ballerina-core";
import { InputMode } from "../MultiModeExpressionEditor/ChipExpressionEditor/types";
import { FieldError } from "react-hook-form";

interface ExpandedPromptEditorProps {
isOpen: boolean;
Expand All @@ -41,6 +45,8 @@ interface ExpandedPromptEditorProps {
completions?: CompletionItem[];
fileName?: string;
targetLineRange?: LineRange;
sanitizedExpression?: (value: string) => string;
rawExpression?: (value: string) => string;
extractArgsFromFunction?: (value: string, cursorPosition: number) => Promise<{
label: string;
args: string[];
Expand All @@ -52,6 +58,9 @@ interface ExpandedPromptEditorProps {
onChange: (value: string, options?: HelperpaneOnChangeOptions) => void,
helperPaneHeight: HelperPaneHeight
) => React.ReactNode;
// Error diagnostics props
error?: FieldError;
formDiagnostics?: DiagnosticMessage[];
}

const ModalContainer = styled.div`
Expand Down Expand Up @@ -97,7 +106,7 @@ const ModalHeaderSection = styled.header`

const ModalContent = styled.div`
flex: 1;
overflow-y: auto;
overflow-y: hidden;
padding: 8px 18px 16px;
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -139,7 +148,8 @@ const TitleWrapper = styled.div`
const MODE_COMPONENTS: Record<EditorMode, React.ComponentType<any>> = {
text: TextMode,
prompt: PromptMode,
expression: ExpressionMode
expression: ExpressionMode,
template: TemplateMode
};

export const ExpandedEditor: React.FC<ExpandedPromptEditorProps> = ({
Expand All @@ -153,8 +163,12 @@ export const ExpandedEditor: React.FC<ExpandedPromptEditorProps> = ({
completions,
fileName,
targetLineRange,
sanitizedExpression,
rawExpression,
extractArgsFromFunction,
getHelperPane
getHelperPane,
error,
formDiagnostics
}) => {
const promptFields = ["query", "instructions", "role"];

Expand All @@ -163,10 +177,14 @@ export const ExpandedEditor: React.FC<ExpandedPromptEditorProps> = ({
promptFields.includes(field.key) ? "prompt" : "text"
);

const [mode] = useState<EditorMode>(defaultMode);
const [mode, setMode] = useState<EditorMode>(defaultMode);
const [showPreview, setShowPreview] = useState(false);
const [mouseDownTarget, setMouseDownTarget] = useState<EventTarget | null>(null);

useEffect(() => {
setMode(defaultMode);
}, [defaultMode]);

useEffect(() => {
if (mode === "text") {
setShowPreview(false);
Expand Down Expand Up @@ -202,15 +220,33 @@ export const ExpandedEditor: React.FC<ExpandedPromptEditorProps> = ({
// Props for modes with preview support
...(mode === "prompt" && {
isPreviewMode: showPreview,
onTogglePreview: () => setShowPreview(!showPreview)
onTogglePreview: (enabled: boolean) => setShowPreview(enabled)
}),
// Props for expression mode
...(mode === "expression" && {
completions,
fileName,
targetLineRange,
sanitizedExpression,
rawExpression,
extractArgsFromFunction,
getHelperPane,
error,
formDiagnostics
}),
// Props for template mode
...(mode === "template" && {
completions,
fileName,
targetLineRange,
sanitizedExpression,
rawExpression,
extractArgsFromFunction,
getHelperPane
getHelperPane,
isPreviewMode: showPreview,
onTogglePreview: (enabled: boolean) => setShowPreview(enabled),
error,
formDiagnostics
})
};
// HACK: Must find a proper central way to manager popups
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com) All Rights Reserved.
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from "react";

import { DocumentType, TokenType } from "../../MultiModeExpressionEditor/ChipExpressionEditor/types";
import {
getChipDisplayContent,
StandardChip,
ChipText,
getTokenIconClass,
StandardIcon
} from "../../MultiModeExpressionEditor/ChipExpressionEditor/chipStyles";

export interface ChipComponentProps {
type: TokenType;
content: string;
documentType?: DocumentType;
}

export const ChipComponent: React.FC<ChipComponentProps> = ({ type, content, documentType }) => {
let iconClass = getTokenIconClass(type, documentType);
return (
<StandardChip chipType={type}>
<StandardIcon chipType={type} className={iconClass} />
<ChipText>{getChipDisplayContent(type, content)}</ChipText>
</StandardChip>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,28 @@ import React from "react";
import styled from "@emotion/styled";
import { ThemeColors } from "@wso2/ui-toolkit";
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import remarkGfm from "remark-gfm";
import { ChipComponent } from "./ChipComponent";
import { DocumentType, TokenType } from "../../MultiModeExpressionEditor/ChipExpressionEditor/types";
import "../styles/markdown-preview.css";

const PreviewContainer = styled.div`
width: 100%;
height: 100%;
padding: 12px;
fontSize: 14px;
font-family: var(--vscode-editor-font-family);
padding: 16px;
background: var(--input-background);
color: ${ThemeColors.ON_SURFACE};
border: 1px solid ${ThemeColors.OUTLINE_VARIANT};
border-top: none;
border-radius: 0 0 4px 4px;
overflow-y: auto;
overflow-x: auto;
box-sizing: border-box;

word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-word;

p, li, td, th, blockquote {
word-wrap: break-word;
overflow-wrap: break-word;
}

pre {
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}

code {
white-space: pre-wrap;
word-wrap: break-word;
.markdown-body {
background: transparent;
font-size: 14px;
color: ${ThemeColors.ON_SURFACE};
}
`;

Expand All @@ -68,17 +56,31 @@ interface MarkdownPreviewProps {
export const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({ content }) => {
return (
<PreviewContainer>
<ReactMarkdown
components={{
// Prevent rendering of potentially dangerous elements
script: () => null,
iframe: () => null,
}}
disallowedElements={['script', 'iframe', 'object', 'embed']}
unwrapDisallowed={true}
>
{content}
</ReactMarkdown>
<div className="markdown-body">
<ReactMarkdown
rehypePlugins={[rehypeRaw, remarkGfm]}
components={{
// Prevent rendering of potentially dangerous elements
script: () => null,
iframe: () => null,
// Custom chip component for rendering tokens
chip: ({ node }: any) => {
const props = node?.properties || {};
return (
<ChipComponent
type={props.type || TokenType.VARIABLE}
content={props.dataContent || ''}
documentType={props.dataDocType as DocumentType}
/>
);
}
}}
disallowedElements={['script', 'iframe', 'object', 'embed']}
unwrapDisallowed={true}
>
{content}
</ReactMarkdown>
</div>
</PreviewContainer>
);
};
Loading
Loading