Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -26,6 +26,7 @@ import { MarkdownPreview } from "../controls/MarkdownPreview";
import { transformExpressionToMarkdown } from "../utils/transformToMarkdown";
import { useFormContext } from "../../../../context/form";
import { ErrorBanner } from "@wso2/ui-toolkit";
import { RawTemplateEditorConfig } from "../../MultiModeExpressionEditor/Configurations";

const ExpressionContainer = styled.div`
width: 100%;
Expand Down Expand Up @@ -150,6 +151,7 @@ export const TemplateMode: React.FC<EditorModeExpressionProps> = ({
onEditorViewReady={setEditorView}
toolbarRef={toolbarRef}
enableListContinuation={true}
configuration={new RawTemplateEditorConfig()}
/>
</ExpressionContainer>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,9 @@ export const ExpressionEditor = (props: ExpressionEditorProps) => {
const inputModeRef = useRef<InputMode>(inputMode);
const [isExpressionEditorHovered, setIsExpressionEditorHovered] = useState<boolean>(false);
const [showModeSwitchWarning, setShowModeSwitchWarning] = useState(false);
const [targetInputMode, setTargetInputMode] = useState<InputMode | null>(null);
const [formDiagnostics, setFormDiagnostics] = useState(field.diagnostics);
const [isExpandedModalOpen, setIsExpandedModalOpen] = useState(false);
const targetInputModeRef = useRef<InputMode>(null);

// Update formDiagnostics when field.diagnostics changes
useEffect(() => {
Expand Down Expand Up @@ -441,34 +441,22 @@ export const ExpressionEditor = (props: ExpressionEditorProps) => {
}

let newInputMode = getInputModeFromTypes(field.valueTypeConstraint)
if (isModeSwitcherRestricted()) {
if (!newInputMode) {
setInputMode(InputMode.EXP);
return;
}
if (!newInputMode) {
if (isModeSwitcherRestricted()) {
setInputMode(InputMode.EXP);
return;
}
if (newInputMode === InputMode.TEXT
&& typeof initialFieldValue.current === 'string'
&& initialFieldValue.current.trim() !== ''
&& !(initialFieldValue.current.trim().startsWith("\"")
&& initialFieldValue.current.trim().endsWith("\"")
)
) {
setInputMode(InputMode.EXP)
} else if (newInputMode === InputMode.TEMPLATE) {
if (sanitizedExpression && rawExpression) {
const sanitized = sanitizedExpression(initialFieldValue.current as string);
if (sanitized !== initialFieldValue.current || !initialFieldValue.current || initialFieldValue.current.trim() === '') {
setInputMode(InputMode.TEMPLATE);
} else {
switch (newInputMode) {
case (InputMode.BOOLEAN):
if (!isExpToBooleanSafe(field?.value as string)) {
setInputMode(InputMode.EXP);
return;
}
}
} else {
setInputMode(newInputMode);
}
setInputMode(newInputMode)
}, [field?.valueTypeConstraint, recordTypeField]);

const handleFocus = async (controllerOnChange?: (value: string) => void) => {
Expand Down Expand Up @@ -548,63 +536,37 @@ export const ExpressionEditor = (props: ExpressionEditorProps) => {
return await extractArgsFromFunction(value, getPropertyFromFormField(field), cursorPosition);
};

const isExpToBooleanSafe = (expValue: string) => {
return ["true", "false"].includes(expValue.trim().toLowerCase())
}

const handleModeChange = (value: InputMode) => {
const raw = watch(key);
const currentValue = typeof raw === "string" ? raw.trim() : "";

// Warn when switching from EXP to TEXT if value doesn't have quotes
if (
inputMode === InputMode.EXP
&& value === InputMode.TEXT
&& (!currentValue.trim().startsWith("\"") || !currentValue.trim().endsWith("\""))
&& currentValue.trim() !== ''
) {
setTargetInputMode(value);
setShowModeSwitchWarning(true);
return;
}

// Warn when switching from EXP to TEMPLATE if sanitization would hide parts of the expression
if (
inputMode === InputMode.EXP
&& value === InputMode.TEMPLATE
&& sanitizedExpression
&& currentValue
&& currentValue.trim() !== ''
) {
setTargetInputMode(value);
if (currentValue === sanitizedExpression(currentValue)) {
setShowModeSwitchWarning(true);
} else {
setInputMode(value);
}
if (inputMode !== InputMode.EXP) {
setInputMode(value);
return;
}

// Auto-add quotes when switching from TEXT to EXP if not present
if (inputMode === InputMode.TEXT && value === InputMode.EXP) {
if (currentValue && typeof currentValue === 'string' &&
!currentValue.startsWith('"') && !currentValue.endsWith('"')) {
setValue(key, `"${currentValue}"`);
}
const primaryInputMode = getInputModeFromTypes(field.valueTypeConstraint);
switch (primaryInputMode) {
case (InputMode.BOOLEAN):
if (!isExpToBooleanSafe(currentValue)) {
targetInputModeRef.current = value;
setShowModeSwitchWarning(true)
return;
}
break;
}

setInputMode(value);
};

const handleModeSwitchWarningContinue = () => {
if (targetInputMode !== null) {
setInputMode(targetInputMode);
setTargetInputMode(null);
if (targetInputMode === InputMode.TEMPLATE && inputMode === InputMode.EXP && rawExpression) {
setValue(key, rawExpression(""));
}
}
setInputMode(targetInputModeRef.current);
setShowModeSwitchWarning(false);
};

const handleModeSwitchWarningCancel = () => {
setTargetInputMode(null);
targetInputModeRef.current = null;
setShowModeSwitchWarning(false);
};

Expand Down Expand Up @@ -697,15 +659,15 @@ export const ExpressionEditor = (props: ExpressionEditorProps) => {
render={({ field: { name, value, onChange }, fieldState: { error } }) => (
<div>
<ExpressionField
field={field}
inputMode={inputMode}
primaryMode={getInputModeFromTypes(field.valueTypeConstraint)}
name={name}
value={value}
completions={completions}
fileName={effectiveFileName}
targetLineRange={effectiveTargetLineRange}
autoFocus={recordTypeField ? false : autoFocus}
sanitizedExpression={inputMode === InputMode.TEMPLATE ? sanitizedExpression : undefined}
rawExpression={inputMode === InputMode.TEMPLATE ? rawExpression : undefined}
ariaLabel={field.label}
placeholder={placeholder}
onChange={async (updatedValue: string, updatedCursorPosition: number) => {
Expand All @@ -714,13 +676,12 @@ export const ExpressionEditor = (props: ExpressionEditorProps) => {
setFormDiagnostics([]);
// Use ref to get current mode (not stale closure value)
const currentMode = inputModeRef.current;
const rawValue = currentMode === InputMode.TEMPLATE && rawExpression ? rawExpression(updatedValue) : updatedValue;

onChange(rawValue);
onChange(updatedValue);
if (getExpressionEditorDiagnostics && (currentMode === InputMode.EXP || currentMode === InputMode.TEMPLATE)) {
getExpressionEditorDiagnostics(
(required ?? !field.optional) || rawValue !== '',
rawValue,
(required ?? !field.optional) || updatedValue !== '',
updatedValue,
key,
getPropertyFromFormField(field)
);
Expand All @@ -729,18 +690,18 @@ export const ExpressionEditor = (props: ExpressionEditorProps) => {
// Check if the current character is a trigger character
const triggerCharacter =
updatedCursorPosition > 0
? triggerCharacters.find((char) => rawValue[updatedCursorPosition - 1] === char)
? triggerCharacters.find((char) => updatedValue[updatedCursorPosition - 1] === char)
: undefined;
if (triggerCharacter) {
await retrieveCompletions(
rawValue,
updatedValue,
getPropertyFromFormField(field),
updatedCursorPosition,
triggerCharacter
);
} else {
await retrieveCompletions(
rawValue,
updatedValue,
getPropertyFromFormField(field),
updatedCursorPosition
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,19 @@ import {
} from '@wso2/ui-toolkit';
import { S } from './ExpressionEditor';
import TextModeEditor from './MultiModeExpressionEditor/TextExpressionEditor/TextModeEditor';
import { InputMode } from './MultiModeExpressionEditor/ChipExpressionEditor/types';
import { InputMode, TokenType } from './MultiModeExpressionEditor/ChipExpressionEditor/types';
import { LineRange } from '@wso2/ballerina-core/lib/interfaces/common';
import { HelperpaneOnChangeOptions } from '../Form/types';
import { FormField, HelperpaneOnChangeOptions } from '../Form/types';
import { ChipExpressionEditorComponent } from './MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor';
import RecordConfigPreviewEditor from './MultiModeExpressionEditor/RecordConfigPreviewEditor/RecordConfigPreviewEditor';
import { RawTemplateEditorConfig, StringTemplateEditorConfig, PrimaryModeChipExpressionEditorConfig } from './MultiModeExpressionEditor/Configurations';
import NumberExpressionEditor from './MultiModeExpressionEditor/NumberExpressionEditor/NumberEditor';
import BooleanEditor from './MultiModeExpressionEditor/BooleanEditor/BooleanEditor';

export interface ExpressionField {
field: FormField;
inputMode: InputMode;
primaryMode: InputMode;
name: string;
value: string;
fileName?: string;
Expand Down Expand Up @@ -96,6 +102,8 @@ const EditorRibbon = ({ onClick }: { onClick: () => void }) => {

export const ExpressionField: React.FC<ExpressionField> = ({
inputMode,
field,
primaryMode,
name,
value,
completions,
Expand Down Expand Up @@ -127,9 +135,18 @@ export const ExpressionField: React.FC<ExpressionField> = ({
onOpenExpandedMode,
isInExpandedMode
}) => {
if (inputMode === InputMode.TEXT || inputMode === InputMode.RECORD) {
if (inputMode === InputMode.BOOLEAN) {
return (
<TextModeEditor
<BooleanEditor
field={field}
value={value}
onChange={onChange}
/>
);
}
if (inputMode === InputMode.RECORD) {
return (
<RecordConfigPreviewEditor
exprRef={exprRef}
anchorRef={anchorRef}
name={name}
Expand All @@ -147,6 +164,67 @@ export const ExpressionField: React.FC<ExpressionField> = ({
onOpenExpandedMode={onOpenExpandedMode}
isInExpandedMode={isInExpandedMode}
/>
);
}
if (inputMode === InputMode.TEXT) {
return (
<TextModeEditor
getHelperPane={getHelperPane}
isExpandedVersion={false}
completions={completions}
onChange={onChange}
value={value}
sanitizedExpression={sanitizedExpression}
rawExpression={rawExpression}
fileName={fileName}
targetLineRange={targetLineRange}
extractArgsFromFunction={extractArgsFromFunction}
onOpenExpandedMode={onOpenExpandedMode}
onRemove={onRemove}
isInExpandedMode={isInExpandedMode}
configuration={new StringTemplateEditorConfig()}
/>

);
}
if (inputMode === InputMode.TEMPLATE) {
return (
<TextModeEditor
getHelperPane={getHelperPane}
isExpandedVersion={false}
completions={completions}
onChange={onChange}
value={value}
sanitizedExpression={sanitizedExpression}
rawExpression={rawExpression}
fileName={fileName}
targetLineRange={targetLineRange}
extractArgsFromFunction={extractArgsFromFunction}
onOpenExpandedMode={onOpenExpandedMode}
onRemove={onRemove}
isInExpandedMode={isInExpandedMode}
configuration={new RawTemplateEditorConfig()}
/>

);
}
if (inputMode === InputMode.NUMBER) {
return (
<NumberExpressionEditor
getHelperPane={getHelperPane}
isExpandedVersion={false}
completions={completions}
onChange={onChange}
value={value}
sanitizedExpression={sanitizedExpression}
rawExpression={rawExpression}
fileName={fileName}
targetLineRange={targetLineRange}
extractArgsFromFunction={extractArgsFromFunction}
onOpenExpandedMode={onOpenExpandedMode}
onRemove={onRemove}
isInExpandedMode={isInExpandedMode}
/>

);
}
Expand All @@ -166,6 +244,7 @@ export const ExpressionField: React.FC<ExpressionField> = ({
onOpenExpandedMode={onOpenExpandedMode}
onRemove={onRemove}
isInExpandedMode={isInExpandedMode}
configuration={new PrimaryModeChipExpressionEditorConfig(primaryMode)}
/>
);
};
Loading
Loading