Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Convert Service Reconfigure Form Page to React #8951

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions app/controllers/catalog_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,9 @@ def svc_catalog_provision
ra, st, svc_catalog_provision_finish_submit_endpoint
)
@in_a_form = true
@dialog_locals = options[:dialog_locals]
# require 'byebug'
# byebug
replace_right_cell(:action => "dialog_provision", :dialog_locals => options[:dialog_locals])
else
# if catalog item has no dialog and provision button was pressed from list view
Expand Down
23 changes: 15 additions & 8 deletions app/controllers/service_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def button
service_retire
when 'service_retire_now'
service_retire_now
when 'service_reconfigure'
javascript_redirect(:action => 'service_reconfigure', :id => params[:id])
end
end

Expand All @@ -56,20 +58,25 @@ def show_generic_object

def edit
assert_privileges("service_edit")

$log.warn("testing edit")

checked = find_checked_items
checked[0] = params[:id] if checked.blank? && params[:id]
@service = find_record_with_rbac(Service, checked[0])
@in_a_form = true
drop_breadcrumb(:name => _("Edit Service\"%{name}\"") % {:name => @service.name}, :url => "/service/edit/#{@service.id}")
drop_breadcrumb(:name => _("Edit Service \"%{name}\"") % {:name => @service.name}, :url => "/service/edit/#{@service.id}")
end

def service_reconfigure
service = Service.find_by(:id => params[:id])
service_template = service.service_template
resource_action = service_template.resource_actions.find_by(:action => 'Reconfigure') if service_template
assert_privileges('service_reconfigure')

@right_cell_text = _("Reconfigure Service \"%{name}\"") % {:name => service.name}
dialog_locals = {:resource_action_id => resource_action.id, :target_id => service.id}
@service = find_record_with_rbac(Service, params[:id])
service_template = @service.service_template
resource_action = service_template.resource_actions.find_by(:action => 'Reconfigure') if service_template
@dialog_locals = {:resource_action_id => resource_action.id, :target_id => @service.id}
@in_a_form = true
drop_breadcrumb(:name => _("Reconfigure Service \"%{name}\"") % {:name => @service.name}, :url => "/service/service_reconfigure/#{@service.id}")
end

def service_form_fields
Expand Down Expand Up @@ -211,8 +218,8 @@ def set_right_cell_vars(action)
action = "retire"
when "reconfigure_dialog"
partial = "shared/dialogs/reconfigure_dialog"
header = @right_cell_text
action = nil
header = _("Reconfigure Service \"%{name}\"") % {:name => @service.name}
action = "reconfigure_dialog"
when "service_edit"
partial = "service_form"
header = _("Editing Service \"%{name}\"") % {:name => @service.name}
Expand Down
1 change: 1 addition & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module ApplicationHelper
include Title
include ReactjsHelper
include Webpack
include OrderServiceHelper

VALID_PERF_PARENTS = {
"EmsCluster" => :ems_cluster,
Expand Down
1 change: 1 addition & 0 deletions app/helpers/miq_request_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module MiqRequestHelper
include RequestInfoHelper
include RequestDetailsHelper
include RequestDialogOptionsHelper

def row_data(label, value)
{:cells => {:label => label, :value => value}}
Expand Down
17 changes: 17 additions & 0 deletions app/helpers/order_service_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module OrderServiceHelper
def order_service_data(dialog)
{

:apiSubmitEndpoint => dialog[:api_submit_endpoint],
:apiAction => dialog[:api_action],
:cancelEndPoint => dialog[:cancel_endpoint],
:dialogId => dialog[:dialog_id],
:finishSubmitEndpoint => dialog[:finish_submit_endpoint],
:openUrl => dialog[:open_url],
:resourceActionId => dialog[:resource_action_id],
:realTargetType => dialog[:real_target_type],
:targetId => dialog[:target_id],
:targetType => dialog[:target_type],
}
end
end
66 changes: 66 additions & 0 deletions app/helpers/request_dialog_options_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
module RequestDialogOptionsHelper
def request_dialog_options(workflow)
data = workflow.dialog.dialog_tabs.map do |tab, _tab_index|
{
:label => _(tab.label),
:content => request_dialog_options_groups(tab.dialog_groups, workflow)
}
end
react('RequestDialogOptions', {:data => data})
end

private

def request_dialog_options_groups(dialog_groups, workflow)
dialog_groups.map do |group|
{
:title => _(group.label),
:rows => request_dialog_options_fields(group.dialog_fields, workflow),
:mode => "miq_summary request_dialog_options"
}
end
end

def request_dialog_options_fields(dialog_fields, workflow)
dialog_fields.map do |field|
row_data(_(field.label), request_dialog_options_field_content(field, workflow))
end
end

def request_dialog_options_field_content(field, workflow)
case field.type
when 'DialogFieldTextBox', 'DialogFieldTextAreaBox'
if field.protected?
"********"
else
field.value
end

when 'DialogFieldCheckBox'
{:input => "checkbox", :name => field.name, :checked => field.checked?, :disabled => true, :label => ''}

when 'DialogFieldDateControl'
field.value

when 'DialogFieldDateTimeControl'
date_val, time_val = field.value.split
hour_val, minute_val = time_val.split(":")
"#{date_val} at #{hour_val.rjust(2, '0')}:#{minute_val.rjust(2, '0')} #{session[:user_tz]}"

when "DialogFieldRadioButton"
field.values.detect { |k, _v| k == workflow.value(field.name) }.try(:last) || workflow.value(field.name)

when "DialogFieldDropDownList"
field.value.blank? ? _("<None>") : field.value.to_s.gsub("\x1F", ", ")

when 'DialogFieldTagControl'
value = workflow.value(field.name) || '' # it returns in format Clasification::id
classifications = value.split(',').map { |c| Classification.find_by(:id => c.split('::').second).description }
if classifications.empty?
''
else
classifications.join(', ')
end
end
end
end
173 changes: 173 additions & 0 deletions app/javascript/components/order-service-form/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import MiqFormRenderer, { useFormApi } from '@@ddf';
import { Button, Loading } from 'carbon-components-react';
import { FormSpy } from '@data-driven-forms/react-form-renderer';
import createSchema from '../service-dialog-builder/service-dialog-builder.schema';
import { API } from '../../http_api';
import miqRedirectBack from '../../helpers/miq-redirect-back';
import { buildFields, prepareSubmitData } from '../service-dialog-builder/helper';
import ServiceDialogRefreshButton from '../service-dialog-builder/service-dialog-refresh-button';
import mapper from '../../forms/mappers/componentMapper';
import NotificationMessage from '../notification-message';

const OrderServiceForm = ({ initialData }) => {
const {
dialogId, resourceActionId, targetId, targetType, apiSubmitEndpoint, apiAction, openUrl, realTargetType, finishSubmitEndpoint,
} = initialData;

const [data, setData] = useState({
isLoading: true,
fields: [],
hasTime: false,
showPastDates: [],
showPastDatesFieldErrors: [],
dateErrorFields: [],
checkBoxes: [],
dates: [],
refreshDialogFields: {},
notification: undefined,
});
const [showDateError, setShowDateError] = useState([]);

useEffect(() => {
const url = `/api/service_dialogs/${dialogId}?resource_action_id=${resourceActionId}&target_id=${targetId}&target_type=${targetType}`;
API.get(url, { skipErrors: [500] })
.then((response) => {
buildFields(response, data, setData, initialData);
})
.catch((errorData) => {
setData({
...data,
notification: { type: 'error', message: errorData.data.error },
});
});
}, []);

const onSubmit = (values) => {
let submitData = prepareSubmitData('order', values, setShowDateError);

if (submitData !== false) {
if (apiSubmitEndpoint.includes('/generic_objects/')) {
submitData = { action: apiAction, parameters: _.omit(submitData, 'action') };
} else if (apiAction === 'reconfigure') {
submitData = { action: apiAction, resource: _.omit(submitData, 'action') };
}
return API.post(apiSubmitEndpoint, submitData, { skipErrors: [400] })
.then((response) => {
if (openUrl === 'true') {
return API.wait_for_task(response)
.then(() =>
// eslint-disable-next-line no-undef
$http.post('open_url_after_dialog', { targetId, realTargetType }))
.then((taskResponse) => {
if (taskResponse.data.open_url) {
window.open(response.data.open_url);
miqRedirectBack(__('Order Request was Submitted'), 'success', finishSubmitEndpoint);
} else {
add_flash(__('Automate failed to obtain URL.'), 'error');
miqSparkleOff();
}
});
}
miqRedirectBack(__('Order Request was Submitted'), 'success', finishSubmitEndpoint);
return null;
});
}
return null;
};

const onCancel = () => miqRedirectBack(__('Dialog Cancelled'), 'warning', '/catalog');

const componentMapper = {
...mapper,
'refresh-button': ServiceDialogRefreshButton,
};

return (
<>
{
data.notification && <NotificationMessage type={data.notification.type} message={data.notification.message} />
}
{
data.isLoading && (
<div className="loadingSpinner">
<Loading active small withOverlay={false} className="loading" />
</div>
)
}
{
!data.isLoading && (
<MiqFormRenderer
FormTemplate={(props) => <FormTemplate {...props} fields={data.fields} />}
componentMapper={componentMapper}
schema={createSchema(data.fields, showDateError)}
initialValues={data.initialValues}
onSubmit={onSubmit}
onCancel={onCancel}
/>
)
}
</>
);
};

const verifyIsDisabled = (valid) => {
let isDisabled = true;
if (valid) {
isDisabled = false;
}
return isDisabled;
};

const FormTemplate = ({ formFields }) => {
const {
handleSubmit, onCancel, getState,
} = useFormApi();
const { values, valid } = getState();
return (
<form id="order-service-form" onSubmit={handleSubmit}>
{formFields}
<FormSpy>
{() => (
<div className="custom-button-wrapper">
<Button
disabled={verifyIsDisabled(valid)}
kind="primary"
className="btnRight"
type="submit"
id="submit"
variant="contained"
>
{__('Submit')}
</Button>
<Button variant="contained" type="button" onClick={onCancel} kind="secondary">
{ __('Cancel')}
</Button>
</div>
)}
</FormSpy>
</form>
);
};

FormTemplate.propTypes = {
formFields: PropTypes.arrayOf(PropTypes.any).isRequired,
};

OrderServiceForm.propTypes = {
initialData: PropTypes.shape({
apiSubmitEndpoint: PropTypes.string.isRequired,
apiAction: PropTypes.string.isRequired,
cancelEndPoint: PropTypes.string.isRequired,
dialogId: PropTypes.number.isRequired,
finishSubmitEndpoint: PropTypes.string.isRequired,
openUrl: PropTypes.bool.isRequired,
resourceActionId: PropTypes.number.isRequired,
realTargetType: PropTypes.string.isRequired,
targetId: PropTypes.number.isRequired,
targetType: PropTypes.string.isRequired,
}).isRequired,
};

export default OrderServiceForm;
33 changes: 33 additions & 0 deletions app/javascript/components/request-dialog-options/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Tabs, Tab } from 'carbon-components-react';
import MiqStructuredList from '../miq-structured-list';

/** Component to render the dialog options in Request/show page. */
const RequestDialogOptions = ({ data }) => {
/** Function to render the tabs from the tabLabels props */
const renderTabs = () => data.map(({ label, content }, tabIndex) => (
<Tab className="dialog-option-tab" key={`${tabIndex.toString()}-tabKey`} label={label}>
{content.map((item, contentIndex) => (
<MiqStructuredList
key={`${contentIndex.toString()}-contentKey`}
title={item.title}
rows={item.rows}
mode={item.mode}
/>
))}
</Tab>
));

return (
<Tabs className="miq_custom_tabs">
{renderTabs()}
</Tabs>
);
};

export default RequestDialogOptions;

RequestDialogOptions.propTypes = {
data: PropTypes.arrayOf(PropTypes.any).isRequired,
};
1 change: 1 addition & 0 deletions app/javascript/components/retirement-form/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const RetirementForm = ({
retirementTime = moment().startOf('D')._d;
setShowTimeField(false);
}
console.log(retires_on);
setState({
isLoading: false,
initialValues: retires_on ? {
Expand Down
Loading
Loading