Skip to content

Commit

Permalink
API integration and code mirror implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
amalvijayan03 committed Feb 28, 2024
1 parent 5bfa4be commit 409cc34
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 150 deletions.
19 changes: 19 additions & 0 deletions app/controllers/miq_ae_class_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,25 @@ def ae_class_for_instance_or_method(record)
record.id ? record.ae_class : MiqAeClass.find(x_node.split("-").last)
end

def validate_automate_method_data
assert_privileges("miq_ae_method_edit")
@edit[:new][:data] = params[:cls_method_data] if params[:cls_method_data]
@edit[:new][:data] = params[:method_data] if params[:method_data]
res = MiqAeMethod.validate_syntax(@edit[:new][:data])
line = 0
if !res
render :json => {:status => true, :message => _("Data validated successfully")}
else
res.each do |err|
line = err[0] if line.zero?
render :json => {
:status => false,
:message => (_("Error on line %{line_num}: %{err_txt}") % {:line_num => err[0], :err_txt => err[1]})
}
end
end
end

def validate_method_data
assert_privileges("miq_ae_method_edit")
return unless load_edit("aemethod_edit__#{params[:id]}", "replace_cell__explorer")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,66 @@
import React, { useRef, useEffect } from 'react';
import React, { useState, useEffect, useContext } from 'react';
import { Button } from 'carbon-components-react';
import CodeMirror from 'codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/mode/javascript/javascript';
import { Controlled as CodeMirror } from 'react-codemirror2';
import { http } from '../../../http_api';
import NotificationMessage from '../../notification-message';
import AutomateMethodContext from '../automate-method-context';

const AutomateMethodCodeMirror = () => {
const codeMirrorRef = useRef(null);
const { updateCodeEditor } = useContext(AutomateMethodContext);

const defaultEditorContents = `#\n# Description: <Method description here>\n#\n`;

const [data, setData] = useState({
editorContents: defaultEditorContents,
enableValidationButton: false,
validation: undefined,
});

useEffect(() => {
const editor = CodeMirror.fromTextArea(codeMirrorRef.current, {
mode: 'javascript',
theme: 'material',
lineNumbers: true,
});
updateCodeEditor(data.editorContents);
}, [data.validation]);

editor.on('change', (instance) => {
console.log(instance);
const validate = () => {
const formData = { cls_method_data: data.editorContents };
http.post('/miq_ae_class/validate_automate_method_data/new?button=validate', formData).then((response) => {
setData({
...data,
validation: response,
});
});
};

editor.setValue('test');

return () => {
editor.toTextArea();
};
}, []);
const renderValidateButton = () => (
<div className="custom-form-buttons">
<Button kind="primary" size="sm" onClick={validate}>Validate</Button>
</div>
);

return (
<div>
<CodeMirror
className="miq-codemirror miq-automate-method-code-mirror"
options={{
mode: 'ruby',
lineNumbers: true,
matchBrackets: true,
theme: 'eclipse',
readOnly: 'nocursor',
viewportMargin: Infinity,
}}
value="asdasd"
/>
<Button kind="primary">Validate</Button>
<div className="automate-code-mirror custom-form-wrapper">
<div className="custom-form-title-wrapper">
<div className="custom-form-title">{__('Data')}</div>
</div>
<div className="custom-form-component-wrapper">
{
data.validation && <NotificationMessage type={data.validation.status ? 'success' : 'error'} message={data.validation.message} />
}
<CodeMirror
className="miq-codemirror miq-structured-list-code-mirror"
options={{
mode: 'ruby',
lineNumbers: true,
matchBrackets: true,
theme: 'eclipse',
viewportMargin: Infinity,
readOnly: false,
}}
onBeforeChange={(_editor, _data, value) => setData({ ...data, validation: undefined, editorContents: value })}
value={data.editorContents}
/>
{renderValidateButton()}
</div>

</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const AutomateMethodInputParameterForm = ({ modalStatus }) => {
passiveModal
>
<MiqFormRenderer
schema={inputParameterSchema(formData.ansibleJobTemplate)}
schema={inputParameterSchema(formData.apiResponse)}
initialValues={data.initialValues}
onSubmit={(values) => addOrUpdateInputParameter(values)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,39 @@ const AutomateMethodInputParameter = () => {
};

const renderAddButton = () => (
<Button onClick={() => updateInputParameter('openModal', undefined)} kind="primary">
{__('Add Input Parameters')}
</Button>
<div className="custom-form-buttons">
<Button onClick={() => updateInputParameter('openModal', undefined)} kind="primary" size="sm">
{__('Add Input Parameters')}
</Button>
</div>

);

return (
<div className="input-parameter-form-table">
<div className="form-section-title">
<h3>{__('Input Parameters')}</h3>
<div className="automate-custom-form custom-form-wrapper">
<div className="custom-form-title-wrapper">
<div className="custom-form-title">{__('Input Parameters')}</div>
</div>
<div className="custom-form-component-wrapper">
{renderAddButton()}
{
formData.inputParameter.items.length > 0
? (
<MiqDataTable
headers={headers}
rows={reformatList(formData.inputParameter.items)}
onCellClick={(selectedRow) => onSelect(selectedRow)}
mode="button-group-list"
/>
)
: (
<>
<br />
<NotificationMessage type="info" message={__('Input parameters are not available.')} />
</>
)
}
</div>
{
formData.inputParameter.items.length > 0
? (
<MiqDataTable
headers={headers}
rows={reformatList(formData.inputParameter.items)}
onCellClick={(selectedRow) => onSelect(selectedRow)}
mode="button-group-list"
/>
)
: (
<>
<br />
<NotificationMessage type="info" message={__('Input parameters are not available.')} />
</>
)
}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
/* eslint-disable camelcase */
import { componentTypes, validatorTypes } from '@@ddf';

// const options = [
// { label: 'Option 1', value: 'option1' },
// { label: 'Option 2', value: 'option2' },
// { label: 'Option 3', value: 'option3' },
// ];

/** Schema for input parameter form */
export const inputParameterSchema = ({ available_datatypes }) => ({
fields: [
Expand Down
76 changes: 56 additions & 20 deletions app/javascript/components/automate-method-form/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,23 @@ import AutomateMethodCodeMirror from './automate-method-code-mirror';
import AutomateMethodInputParameterForm from './automate-method-input-parameter/automate-method-input-parameter-form';
import AutomateMethodContext from './automate-method-context';
import { http } from '../../http_api';
import './style.scss';

const AutomateMethodForm = ({ availableLocations }) => {
const options = availableLocations.map((item) => ({ id: item[1], label: item[0] }));
const AutomateMethodForm = ({ availableLocations, levels }) => {
const mapper = {
...componentMapper,
'automate-method-code-mirror': AutomateMethodCodeMirror,
'automate-method-input-parameter': AutomateMethodInputParameter,
};

const [formData, setFormData] = useState({
loading: true,
ansibleJobTemplate: undefined,
loading: false,
apiResponse: undefined,
selectedType: undefined,
providerId: undefined,
workflowTemplates: undefined,
levels,
codeEditor: undefined,
inputParameter: {
modal: false,
selectedId: undefined,
Expand All @@ -26,14 +35,38 @@ const AutomateMethodForm = ({ availableLocations }) => {
});

useEffect(() => {
http.get('/miq_ae_class/method_form_fields/new?location=ansible_job_template').then((ansibleJobTemplateResponse) => {
if (formData.selectedType && formData.selectedType.id) {
http.get(`/miq_ae_class/method_form_fields/new?location=${formData.selectedType.id}`).then((apiResponse) => {
setFormData({
...formData,
loading: false,
apiResponse,
});
});
}
}, [formData.selectedType]);

useEffect(() => {
if (formData.providerId) {
const collectionClass = 'collection_class=ManageIQ::Providers::AnsibleTower::AutomationManager::ConfigurationScript';
const filter = `filter[]=manager_id=${formData.providerId}`;
const sort = `sort_by=name&sort_order=asc`;
const url = `/api/configuration_scripts?expand=resources&${collectionClass}&${filter}&${sort}`;
API.get(url).then((response) => {
miqSparkleOn();
setFormData({
...formData,
workflowTemplates: response,
});
miqSparkleOff();
});
} else {
setFormData({
...formData,
loading: false,
ansibleJobTemplate: ansibleJobTemplateResponse,
workflowTemplates: undefined,
});
});
}, []);
}
}, [formData.providerId]);

const updateInputParameter = (actionType, data) => {
setFormData({
Expand All @@ -42,22 +75,24 @@ const AutomateMethodForm = ({ availableLocations }) => {
});
};

const mapper = {
...componentMapper,
'automate-method-inline': AutomateMethodCodeMirror,
'automate-method-input-parameter': AutomateMethodInputParameter,
const updateCodeEditor = (data) => {
setFormData({
...formData,
codeEditor: data,
});
};

const chooseAutomateType = () => (
const renderAutomateTypes = () => (
<div className="mainClass">
<h3>{__('Main Info')}</h3>
<Dropdown
id="choose"
label="Choose"
items={options}
items={availableLocations.map((item) => ({ id: item[1], label: item[0] }))}
itemToString={(item) => (item ? item.label : '')}
onChange={({ selectedItem }) => setFormData({
...formData,
loading: true,
selectedType: selectedItem,
})}
titleText={formData.selectedType ? formData.selectedType.label : ''}
Expand All @@ -80,14 +115,11 @@ const AutomateMethodForm = ({ availableLocations }) => {

const renderFormContents = () => (
<>
{
chooseAutomateType()
}
{
formData.selectedType && (
<AutomateMethodContext.Provider value={{ formData, updateInputParameter }}>
<AutomateMethodContext.Provider value={{ formData, updateInputParameter, updateCodeEditor }}>
<MiqFormRenderer
schema={createSchema(formData.selectedType)}
schema={createSchema(formData, setFormData)}
componentMapper={mapper}
/>
{
Expand All @@ -101,6 +133,9 @@ const AutomateMethodForm = ({ availableLocations }) => {

return (
<div className="automate-method-form">
{
renderAutomateTypes()
}
{
formData.loading
? renderLoader()
Expand All @@ -114,4 +149,5 @@ export default AutomateMethodForm;

AutomateMethodForm.propTypes = {
availableLocations: PropTypes.arrayOf(PropTypes.any).isRequired,
levels: PropTypes.shape({}).isRequired,
};
Loading

0 comments on commit 409cc34

Please sign in to comment.