Skip to content

Commit

Permalink
Merge pull request #396 from MeasureAuthoringTool/MAT-7792
Browse files Browse the repository at this point in the history
MAT-7792, MAT-7793: Set up Functions - Expresion Edtior section
  • Loading branch information
mcmcphillips authored Dec 10, 2024
2 parents 50ce7e4 + 81f2e15 commit 0c6b6ed
Show file tree
Hide file tree
Showing 10 changed files with 609 additions and 85 deletions.
2 changes: 1 addition & 1 deletion src/CqlBuilderPanel/CqlBuilderPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,12 @@ export default function CqlBuilderPanel({

{activeTab === "functions" && (
<FunctionsSection
cqlBuilderLookupsTypes={cqlBuilderLookupsTypes}
canEdit={canEdit}
handleApplyFunction={handleApplyFunction}
loading={loading}
cql={measureStoreCql}
isCQLUnchanged={isCQLUnchanged}
cqlBuilderLookupsTypes={cqlBuilderLookupsTypes}
/>
)}
</div>
Expand Down
47 changes: 47 additions & 0 deletions src/CqlBuilderPanel/common/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export const formatExpressionName = (values) => {
return values?.type !== "Timing" && values?.type !== "Pre-Defined Functions"
? values?.type === "Functions" || values?.type === "Fluent Functions"
? values?.name?.replace(/([\w\s]+)\(\)/g, '"$1"()')
: values?.name.includes(".")
? values?.name.replace(/(.*\.)(.*)/, '$1"$2"')
: `"${values?.name}"`
: values?.name;
};

export const getNewExpressionsAndLines = (
values: any,
cursorPosition: any,
expressionEditorValue: any,
autoInsert: boolean
) => {
const formattedExpression = formatExpressionName(values);
let editorExpressionValue = expressionEditorValue;
let newCursorPosition = cursorPosition;

if (cursorPosition && !autoInsert) {
// Insert at cursor position
const { row, column } = cursorPosition;
const lines = expressionEditorValue.split("\n");
const currentLine = lines[row];
lines[row] =
currentLine.slice(0, column) +
formattedExpression +
currentLine.slice(column);
editorExpressionValue = lines.join("\n");
newCursorPosition = {
row,
column: column + formattedExpression.length,
} as unknown;
} else {
// Append to a new line
const lines = editorExpressionValue.split("\n");
const newLineIndex = lines.length;
editorExpressionValue +=
(editorExpressionValue ? "\n" : "") + formattedExpression;
newCursorPosition = {
row: newLineIndex,
column: formattedExpression.length,
};
}
return [editorExpressionValue, newCursorPosition];
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { describe, it } from "@jest/globals";
import "@testing-library/jest-dom";
import { within } from "@testing-library/dom";
import DefinitionBuilder, { formatExpressionName } from "./DefinitionBuilder";
import DefinitionBuilder from "./DefinitionBuilder";
import { formatExpressionName } from "../../common/utils";
import { cqlBuilderLookup } from "../../__mocks__/MockCqlBuilderLookupsTypes";

describe("CQL Definition Builder Tests", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "../Definitions.scss";
import { DefinitionSectionSchemaValidator } from "../../../validations/DefinitionSectionSchemaValidator";
import ExpressionEditor from "../expressionSection/ExpressionEditor";
import { CqlBuilderLookup } from "../../../model/CqlBuilderLookup";
import { getNewExpressionsAndLines } from "../../common/utils";

export interface Definition {
definitionName?: string;
Expand All @@ -29,16 +30,6 @@ export interface DefinitionProps {
onClose?: Function;
}

export const formatExpressionName = (values) => {
return values?.type !== "Timing" && values?.type !== "Pre-Defined Functions"
? values?.type === "Functions" || values?.type === "Fluent Functions"
? values?.name?.replace(/([\w\s]+)\(\)/g, '"$1"()')
: values?.name.includes(".")
? values?.name.replace(/(.*\.)(.*)/, '$1"$2"')
: `"${values?.name}"`
: values?.name;
};

export default function DefinitionBuilder({
canEdit,
handleApplyDefinition,
Expand All @@ -56,58 +47,6 @@ export default function DefinitionBuilder({
);
const [cursorPosition, setCursorPosition] = useState(null);
const [autoInsert, setAutoInsert] = useState(false);

const handleExpressionEditorInsert = (values) => {
const formattedExpression = formatExpressionName(values);
let editorExpressionValue = expressionEditorValue;
let newCursorPosition = cursorPosition;

if (cursorPosition && !autoInsert) {
// Insert at cursor position
const { row, column } = cursorPosition;
const lines = expressionEditorValue.split("\n");
const currentLine = lines[row];
lines[row] =
currentLine.slice(0, column) +
formattedExpression +
currentLine.slice(column);
editorExpressionValue = lines.join("\n");
newCursorPosition = {
row,
column: column + formattedExpression.length,
} as unknown;
} else {
// Append to a new line
const lines = editorExpressionValue.split("\n");
const newLineIndex = lines.length;
editorExpressionValue +=
(editorExpressionValue ? "\n" : "") + formattedExpression;
newCursorPosition = {
row: newLineIndex,
column: formattedExpression.length,
};
}

setExpressionEditorValue(editorExpressionValue);
formik.setFieldValue("type", "");
formik.setFieldValue("name", "");

textAreaRef.current.editor.setValue(editorExpressionValue, 1);

// set the cursor to the end of the inserted text
textAreaRef.current.editor.moveCursorTo(
newCursorPosition.row,
newCursorPosition.column
);
textAreaRef.current.editor.clearSelection();

// set autoInsert to true for next insertion
setAutoInsert(true);

// clear cursor position to allow the next item to auto-insert at the end
setCursorPosition(null);
};

const formik = useFormik({
initialValues: {
definitionName: definition?.definitionName || "",
Expand All @@ -118,9 +57,33 @@ export default function DefinitionBuilder({
validationSchema: DefinitionSectionSchemaValidator,
enableReinitialize: true,
onSubmit: (values) => {
handleExpressionEditorInsert(values);
const newValues = getNewExpressionsAndLines(
values,
cursorPosition,
expressionEditorValue,
autoInsert
);
updateExpressionAndLines(newValues[0], newValues[1]);
},
});

// update formik, and expressionEditor, cursor, lines
const updateExpressionAndLines = (
newEditorExpressionValue,
newCursorPosition
) => {
setExpressionEditorValue(newEditorExpressionValue);
formik.setFieldValue("type", "");
formik.setFieldValue("name", "");
textAreaRef.current.editor.setValue(newEditorExpressionValue, 1);
textAreaRef.current.editor.moveCursorTo(
newCursorPosition.row,
newCursorPosition.column
);
textAreaRef.current.editor.clearSelection();
setAutoInsert(true);
setCursorPosition(null);
};
const { resetForm } = formik;

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ interface ExpressionsProps {
setAutoInsert: Function;
}

export const availableTypes = [
"Parameters",
"Definitions",
"Functions",
"Fluent Functions",
"Timing",
"Pre-Defined Functions",
];

export default function ExpressionEditor(props: ExpressionsProps) {
const {
canEdit,
Expand All @@ -45,14 +54,6 @@ export default function ExpressionEditor(props: ExpressionsProps) {
setAutoInsert,
} = props;
const [namesOptions, setNamesOptions] = useState([]);
const availableTypes = [
"Parameters",
"Definitions",
"Functions",
"Fluent Functions",
"Timing",
"Pre-Defined Functions",
];
const [editorHeight, setEditorHeight] = useState("100px");
const formik: any = useFormikContext();

Expand Down Expand Up @@ -95,7 +96,14 @@ export default function ExpressionEditor(props: ExpressionsProps) {
useEffect(() => {
if (textAreaRef.current) {
const lineCount = textAreaRef.current.editor.session.getLength();
const newHeight = Math.max(lineCount * 20, 100) + "px";
// newNeight should not exceed 180
/*
Text entry control (with line numbers, but only starting with 1 line, expandable as more text is added to it, max height is 11 lines and then it scrolls)
https://jira.cms.gov/browse/MAT-7792
*/
const maxHeight = 180;
const proposedNewHeight = Math.max(lineCount * 20, 100);
const newHeight = Math.min(maxHeight, proposedNewHeight) + "px";
setEditorHeight(newHeight);
}
}, [expressionEditorValue]);
Expand Down
1 change: 1 addition & 0 deletions src/CqlBuilderPanel/functionsSection/FunctionsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export default function FunctionsSection({
<FunctionBuilder
canEdit={canEdit}
handleApplyFunction={handleApplyFunction}
cqlBuilderLookupsTypes={cqlBuilderLookupsTypes}
/>
)}
{activeTab === "saved-functions" && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ export default function ArgumentSection(props: ArgumentsProps) {
<div tw="flex-grow pl-5">
<Select
label="Available DataTypes"
id="type-selector"
id="arg-type-selector"
inputProps={{
"data-testid": "type-selector-input",
"data-testid": "arg-type-selector-input",
}}
data-testid="type-selector"
data-testid="arg-type-selector"
SelectDisplayProps={{
"aria-required": "true",
}}
Expand Down
Loading

0 comments on commit 0c6b6ed

Please sign in to comment.