From 94ca76ddc2ecb72dfb4ba062eedf97b018a68521 Mon Sep 17 00:00:00 2001 From: Amal-Vijayan Date: Wed, 25 Oct 2023 15:06:17 +0530 Subject: [PATCH] Expression editor conversion from HAML to React --- .../expression-editor-style.css | 48 ++++ .../expression-editor/helpers/constants.js | 96 +++++++ .../expression-editor/index.jsx | 253 ++++++++++++++++++ .../components/visual-settings-form/index.jsx | 16 +- 4 files changed, 407 insertions(+), 6 deletions(-) create mode 100644 app/javascript/components/visual-settings-form/expression-editor/expression-editor-style.css create mode 100644 app/javascript/components/visual-settings-form/expression-editor/helpers/constants.js create mode 100644 app/javascript/components/visual-settings-form/expression-editor/index.jsx diff --git a/app/javascript/components/visual-settings-form/expression-editor/expression-editor-style.css b/app/javascript/components/visual-settings-form/expression-editor/expression-editor-style.css new file mode 100644 index 00000000000..db29ab28dd7 --- /dev/null +++ b/app/javascript/components/visual-settings-form/expression-editor/expression-editor-style.css @@ -0,0 +1,48 @@ +.edit-expression-container { + border: 1px solid #ccc; + padding: 20px; + margin: 10px; + border-radius: 4px; + background-color: #f5f5f5; +} + +.edit-expression-title { + font-size: 24px; + font-weight: bold; + margin-bottom: 10px; +} + +.edit-expression-button { + margin-right: 10px; + padding: 10px 20px; + background-color: #0073e6; + color: #fff; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.edit-expression-button:hover { + background-color: #0057b3; +} + +.edit-expression-textarea { + padding: 10px; + color: blue; +} + +.edit-expression-button-secondary { + margin-right: 10px; + padding: 10px 20px; + background-color: #eee; + color: #333; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.edit-expression-button-secondary:hover { + background-color: #ddd; +} diff --git a/app/javascript/components/visual-settings-form/expression-editor/helpers/constants.js b/app/javascript/components/visual-settings-form/expression-editor/helpers/constants.js new file mode 100644 index 00000000000..019b13798e0 --- /dev/null +++ b/app/javascript/components/visual-settings-form/expression-editor/helpers/constants.js @@ -0,0 +1,96 @@ +export const ExprCondition = [ + { id: 'expr', label: 'Expression' }, +]; + +export const FieldItems = [ + { id: 'field', label: 'field' }, +]; + +export const EventItems = [ + { id: '1', label: 'EVM Audit Event:Date Created' }, + { id: '2', label: 'EVM Audit Event:Event' }, + { id: '3', label: 'EVM Audit Event:Href Slug' }, + { id: '4', label: 'EVM Audit Event:Id' }, + { id: '5', label: 'EVM Audit Event:Message' }, + { id: '6', label: 'EVM Audit Event:Region Description' }, + { id: '7', label: 'EVM Audit Event:Region Number' }, + { id: '8', label: 'EVM Audit Event:Severity' }, + { id: '9', label: 'EVM Audit Event:Source' }, +]; + +export const ConstraintTexts = [ + { id: 'is', label: 'IS' }, + { id: 'before', label: 'BEFORE' }, + { id: 'after', label: 'AFTER' }, + { id: 'from', label: 'FROM' }, + { id: 'isempty', label: 'IS EMPTY' }, + { id: 'isnotempty', label: 'IS NOT EMPTY' }, +]; + +export const DateParameters = [ + { id: 'choose', label: '' }, + { id: 'thishour', label: 'This Hour' }, + { id: 'lasthour', label: 'Last Hour' }, + { id: '2hoursago', label: '2 Hours Ago' }, + { id: '3hoursago', label: '3 Hours Ago' }, + { id: '4hoursago', label: '4 Hours Ago' }, + { id: '5hoursago', label: '5 Hours Ago' }, + { id: '6hoursago', label: '6 Hours Ago' }, + { id: '7hoursago', label: '7 Hours Ago' }, + { id: '8hoursago', label: '8 Hours Ago' }, + { id: '9hoursago', label: '9 Hours Ago' }, + { id: '10hoursago', label: '10 Hours Ago' }, + { id: '11hoursago', label: '11 Hours Ago' }, + { id: '12hoursago', label: '12 Hours Ago' }, + { id: '13hoursago', label: '13 Hours Ago' }, + { id: '14hoursago', label: '14 Hours Ago' }, + { id: '15hoursago', label: '15 Hours Ago' }, + { id: '16hoursago', label: '16 Hours Ago' }, + { id: '17hoursago', label: '17 Hours Ago' }, + { id: '18hoursago', label: '18 Hours Ago' }, + { id: '19hoursago', label: '19 Hours Ago' }, + { id: '20hoursago', label: '20 Hours Ago' }, + { id: '21hoursago', label: '21 Hours Ago' }, + { id: '22hoursago', label: '22 Hours Ago' }, + { id: '23hoursago', label: '23 Hours Ago' }, + { id: 'today', label: 'Today' }, + { id: 'yesterday', label: 'Yesterday' }, + { id: '2dayssgo', label: '2 Days Ago' }, + { id: '3dayssgo', label: '3 Days Ago' }, + { id: '5dayssgo', label: '4 Days Ago' }, + { id: '6dayssgo', label: '5 Days Ago' }, + { id: '7dayssgo', label: '6 Days Ago' }, + { id: '14dayssgo', label: '7 Days Ago' }, + { id: 'thisweek', label: 'This Week' }, + { id: 'lastweek', label: 'Last Week' }, + { id: '2weeksago', label: 'Two Weeks Ago' }, + { id: '3weeksago', label: 'Three Weeks Ago' }, + { id: '4weeksago', label: 'Four Weeks Ago' }, + { id: 'thismonth', label: 'This Month' }, + { id: 'lastmonth', label: 'Last Month' }, + { id: '2monthsago', label: '2 Months Ago' }, + { id: '3monthsago', label: '3 Months Ago' }, + { id: '4monthsago', label: '4 Months Ago' }, + { id: '6monthsago', label: '6 Months Ago' }, + { id: 'thisquarter', label: 'This Quarter' }, + { id: 'lastquarter', label: 'Last Quarter' }, + { id: 'thisyear', label: 'This Year' }, + { id: 'lastyear', label: 'Last Year' }, + { id: '2yearago', label: 'Two Year Ago' }, + { id: '3yearago', label: 'Three Year Ago' }, + { id: '4yearago', label: 'Four Year Ago' }, +]; + +export const InputParameters = [ + { id: 'choose', label: '' }, + { id: 'equal', label: '=' }, + { id: 'startswith', label: 'STARTS WITH' }, + { id: 'endswith', label: 'ENDS WITH' }, + { id: 'include', label: 'INCLUDE' }, + { id: 'isnull', label: 'IS NULL' }, + { id: 'isnotnull', label: 'IS NOT NULL' }, + { id: 'isempty', label: 'IS EMPTY' }, + { id: 'isnotempty', label: 'IS NOT EMPTY' }, + { id: 'regexmatches', label: 'REGULAR EXPRESSION MATCHES' }, + { id: 'regexdoesnotmatches', label: 'REGULAR EXPRESSION DOES NOT MATCH' }, +] diff --git a/app/javascript/components/visual-settings-form/expression-editor/index.jsx b/app/javascript/components/visual-settings-form/expression-editor/index.jsx new file mode 100644 index 00000000000..ad8e331b41b --- /dev/null +++ b/app/javascript/components/visual-settings-form/expression-editor/index.jsx @@ -0,0 +1,253 @@ +import React, { useState } from 'react'; +import { + Dropdown, + Button, + Checkbox, + Form, +} from 'carbon-components-react'; +import { + ExprCondition, + FieldItems, + EventItems, + ConstraintTexts, + DateParameters, + InputParameters, +} from './helpers/constants.js'; +import './expression-editor-style.css'; + +const ExpressionLabels = { + newElement: "", +} + +const ExpressionEditor = () => { + const [data, setData] = useState({ + selectedCondition: undefined, + isComponentVisible: false, + isEditSelectedComponentVisible: true, + isEventVisible: false, + selectedField: undefined, + selectedEvent: undefined, + selectedConstraint: undefined, + selectedDateParam: undefined, + selectedInputParam: undefined, + buttonsEnabled: false, + textFieldButtonCount: 1, + combinedString: ExpressionLabels.newElement, + labelStack: [ExpressionLabels.newElement], + labelStackIndex: 0, + conditionalButtonsDisabled:true, + }); + + const DropDownLabels = { + expression: 'expression', + field: 'field', + event: 'event', + constraint: 'constraint', + date: 'date', + input: 'input', + } + + // Function to reset the form and clear state variables + const resetForm = () => { + setData({ + ...data, + selectedCondition: undefined, + isEventVisible: false, + selectedField: undefined, + selectedEvent: undefined, + selectedDateParam: undefined, + selectedConstraint: undefined, + selectedInputParam: undefined, + }) + }; + + // Update labelStack and reset combinedString + const updateLabelStack = (newLabelStack, enableConditionalButtons) => { + setData({ + ...data, + labelStack: newLabelStack, + combinedString: ExpressionLabels.newElement, // Reset combinedString + conditionalButtonsDisabled: false, // Enable conditional buttons + }); + }; + + /** Function to render the buttons in toolbar */ + const renderToolBarButtons = () => (<> +   +   + + ); + + /** Function to render the conditional buttons in the editor. */ + const renderConditionalButtons = () => (<> +   +   + + ); + + /** Function to handle the drop down button change events. */ + const handleDropDownChange = (name, {selectedItem}) => { + const value = selectedItem; + console.log('value=', value); + const {expression, field, event, constraint, date, input} = DropDownLabels; + switch(name){ + case expression: + return { selectedCondition: value, isComponentVisible: true, }; + case field: + return { selectedField: value, isEventVisible: true }; + case event: + return { selectedEvent: value }; + case constraint: + return { selectedConstraint: value }; + case date: + return { selectedDateParam: value }; + case input: + return { selectedInputParam: value }; + default: + return {}; + } + } + + // Handle label click to display a new label + const handleLabelClick = (index) => { + const newLabelStack = data.labelStack.slice(0, index + 1); + console.log('label clicked') + console.log('newLabelStack=',newLabelStack) + setData({ + ...data, + labelStack: newLabelStack, + conditionalButtonsDisabled:false, + }); + }; + + const dropDownOnChange = (name, value) => { + const newData = handleDropDownChange(name, value); + setData({ + ...data, + ...newData, + }) + } + + const renderDropDown = (name, items, selectedItem) => { + return ( + dropDownOnChange(name, value)} + /> + ); + } + + const renderActionButtons = () => (<> +   + + ) + + const isSelectedFieldValid = (data) => { + return data.selectedField && data.selectedField.label === 'field'; + } + const isSelectedEventValid = (data) => { + return data.isEventVisible && data.selectedEvent && data.selectedEvent.label === 'EVM Audit Event:Date Created' + } + + // Handle commit button click + const handleCommitClick = () => { + const { + selectedEvent, + selectedConstraint, + selectedDateParam, + selectedInputParam, + } = data; + + const combinedString = ` ${selectedEvent ? selectedEvent.label : ''} ${selectedConstraint ? selectedConstraint.label : ''} "${selectedDateParam ? selectedDateParam.label : ''}" ${selectedInputParam ? selectedInputParam.label : ''}`; + console.log('Combined Selected Items=', combinedString); + const newLabelStack = [...data.labelStack, combinedString]; + console.log(newLabelStack,"newLabelStack") + setData({ + ...data, + combinedString, + label:combinedString, + labelStack:newLabelStack, + }); + }; + + // Render labels conditionally + const renderLabels = () => { + if (data.combinedString === ExpressionLabels.newElement) { + return ( + + ); + } else { + return data.labelStack.map((label, index) => ( + + )); + } + }; + + return ( +
+
+ { renderDropDown(DropDownLabels.expression, ExprCondition, data.selectedCondition) } +
+ {data.isComponentVisible && ( +
+
+

Edit Expression

+
+
+ { renderToolBarButtons() } +
+
+   + {renderLabels()} +
+
+ +
+
+
{ renderConditionalButtons() } +
+
+ { data.isEditSelectedComponentVisible &&( + <> +
+

Edit Selected Element

+
+ { renderDropDown('field', FieldItems, data.selectedField) } + +
+ { isSelectedFieldValid(data) && (renderDropDown(DropDownLabels.event, EventItems, data.selectedEvent)) } + { isSelectedEventValid(data) && ( + <> + {renderDropDown(DropDownLabels.constraint, ConstraintTexts, data.selectedConstraint)} + {renderDropDown(DropDownLabels.date, DateParameters, data.selectedDateParam)} + + )} + {data.isEventVisible && data.selectedEvent && data.selectedEvent.label !== 'EVM Audit Event:Date Created' && ( + renderDropDown(DropDownLabels.input, InputParameters, data.selectedInputParam) + )} + { renderActionButtons() } + +
+ + )} +
+ )} +
+
{/* TBD Input parameters section */}
+
+ ); +}; + +export default ExpressionEditor; diff --git a/app/javascript/components/visual-settings-form/index.jsx b/app/javascript/components/visual-settings-form/index.jsx index cc2f3e3c67c..f628ce731fd 100644 --- a/app/javascript/components/visual-settings-form/index.jsx +++ b/app/javascript/components/visual-settings-form/index.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import MiqFormRenderer from '@@ddf'; import createSchema from './visual-settings-form.schema'; +import ExpressionEditor from './expression-editor'; const VisualSettingsForm = ({ recordId }) => { const [{ initialValues, timezoneOptions, isLoading }, setState] = useState({ isLoading: true }); @@ -34,12 +35,15 @@ const VisualSettingsForm = ({ recordId }) => { }; return !isLoading && ( - +
+ + +
); };