Skip to content

Conversation

@h-kataria
Copy link
Contributor

@h-kataria h-kataria commented Apr 11, 2020

Fixes #6977

Screenshot from 2020-04-10 23-38-16

Screenshot from 2020-04-10 23-37-58

@h-kataria
Copy link
Contributor Author

@skateman @himdel my first stab at DDF/REACT/API form, picked a simple one to get started.

@h-kataria h-kataria force-pushed the region_edit_conversion branch from bd579bf to 6e0b692 Compare April 11, 2020 04:14
Copy link
Member

@skateman skateman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather use hooks instead of a class component, all the required stuff for that is available here: https://reactjs.org/docs/hooks-reference.html

@@ -0,0 +1,20 @@
import {validatorTypes} from "@data-driven-forms/react-form-renderer";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces around validatorTypes


RegionForm.propTypes = {
maxDescLen: PropTypes.number.isRequired,
regionFormId: PropTypes.number.isRequired,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is just an id field, why not name it id or regionId if we want to be precise?

import { Grid } from 'patternfly-react';
import createSchema from './region-form.schema';
import MiqFormRenderer from '../../forms/data-driven-form';
import {API} from '../../http_api';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces around API

@@ -0,0 +1,71 @@
import React, {Component, useState} from 'react';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces

};
}

componentDidMount() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the useEffect hook instead componentDidMount, then you can simplify it to a function.

constructor(props) {
super(props);
this.state = {
schema: createSchema(props.maxDescLen),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need the schema in the state?

import handleFailure from "../../helpers/handle-failure";
import miqRedirectBack from "../../helpers/miq-redirect-back";

class RegionForm extends Component {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a class component could you make a function component? Then you can eliminate the constructor function and have just useState below.

}

onCancel = () => {
const message = sprintf(__('Edit of Region was cancelled by the user'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need the sprintf here?

return request().then(() => miqRedirectBack(message, 'success', submitUrl)).catch(miqSparkleOff);
}

render() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're using a function component, you don't need this render(), just simply return with the markup from the function.

@h-kataria h-kataria force-pushed the region_edit_conversion branch from 6e0b692 to 3d9f9f8 Compare April 11, 2020 16:24
@h-kataria
Copy link
Contributor Author

@skateman please re-review, made suggested changes

@h-kataria h-kataria force-pushed the region_edit_conversion branch from 3d9f9f8 to 6354207 Compare April 11, 2020 16:32

const RegionForm = ({ id, maxDescLen }) => {
const [initialValues, setInitialValues] = useState({});
const [isLoading, setIsLoading] = useState(!!id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't really need this second one, you can just test against the initialValues in the rendering.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if you can always use a single state object like this:

const [{ description, isLoading }, setState] = useState({});

But in this case you don't really need it.

const [isLoading, setIsLoading] = useState(!!id);

useEffect(() => {
if (id) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need this? Can the id be not set?

}) => setInitialValues({
...data,
}))
.then(() => setIsLoading(false))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can skip this step

miqSparkleOn();
API.get(`/api/regions/${id}?attributes=description`)
.then(({
...data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just simply use data without the {...}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking this through, maybe you just need the description field and nothing more, so you don't even need the whole initialValues, just a { description }

.then(({
...data
}) => setInitialValues({
...data,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably here too, no need for copying, especially twice.

.then(() => setIsLoading(false))
.then(miqSparkleOff);
}
}, []);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}, []);
}, [id]);

return request().then(() => miqRedirectBack(message, 'success', submitUrl)).catch(miqSparkleOff);
};

if (isLoading) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (isLoading) {
if (!initialValues) {

miqSparkleOn();
const message = __('Region was saved');
const submitUrl = `/ops/explorer/${id}?button=save`;
const request = () => API.post(`/api/regions/${id}`, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the request variable allocation here, you can chain like:

return API.post().then().catch()

as you're not really using the request afterwards.

@h-kataria h-kataria force-pushed the region_edit_conversion branch from 6354207 to 3356c02 Compare April 12, 2020 14:03
@h-kataria
Copy link
Contributor Author

@skateman made suggested changes.

Copy link
Member

@skateman skateman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's Easter, we shouldn't be working today :trollface:

import miqRedirectBack from "../../helpers/miq-redirect-back";

const RegionForm = ({ id, maxDescLen }) => {
const [description, setInitialValues] = useState({});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const [description, setInitialValues] = useState({});
const [description, setDescription] = useState();

useEffect(() => {
miqSparkleOn();
API.get(`/api/regions/${id}?attributes=description`)
.then(({ description }) => setInitialValues({ description }))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.then(({ description }) => setInitialValues({ description }))
.then(({ description }) => setDescription(description))

const message = __('Region was saved');
const submitUrl = `/ops/explorer/${id}?button=save`;

return API.post(`/api/regions/${id}`, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to return here at all

return (
<Grid fluid style={{ paddingTop: 20 }}>
<MiqFormRenderer
initialValues={description}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
initialValues={description}
initialValues={{ description }}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why we need those extra curlies here, those populate text field with value [object Object] instead of an actual value of the description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's about semantics, the initialValues should contain the description not be it. The extra curly here basically does:

initialValues = { description: description }

MAX_NAME_LEN = 255
MAX_DESC_LEN = 255
MAX_HOSTNAME_LEN = 255
MAX_DESC_LEN_SHORT = 50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this name descriptive enough? Out of context I wouldn't really understand what this is 😕

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well to me that made sense, but if we are nitpicking all variable names here, i would go with MAX_LEN_SMALL_TEXT_FIELD makes sense that is the length of a small text field in the form

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just thought that you'd want to use this constant on this single form, but now I understand. It can be either way I guess.

@h-kataria h-kataria force-pushed the region_edit_conversion branch from 3356c02 to 8cbb2ff Compare April 12, 2020 22:30
return (
<Grid fluid style={{ paddingTop: 20 }}>
<MiqFormRenderer
initialValues={description}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's about semantics, the initialValues should contain the description not be it. The extra curly here basically does:

initialValues = { description: description }

useEffect(() => {
miqSparkleOn();
API.get(`/api/regions/${id}?attributes=description`)
.then(({ description }) => setDescription({ description }))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

description = description instead of description = { description: description }

Suggested change
.then(({ description }) => setDescription({ description }))
.then(({ description }) => setDescription(description))

import miqRedirectBack from "../../helpers/miq-redirect-back";

const RegionForm = ({ id, maxDescLen }) => {
const [description, setDescription] = useState({});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description should be undefined and not an empty object when mounting the component:

Suggested change
const [description, setDescription] = useState({});
const [description, setDescription] = useState();

@h-kataria h-kataria force-pushed the region_edit_conversion branch 2 times, most recently from d135cdf to d56d19c Compare April 13, 2020 20:29
@skateman
Copy link
Member

Code looks good now, I'll test it tomorrow 👍

Copy link
Member

@skateman skateman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Seal of Approval


RegionForm.propTypes = {
maxDescLen: PropTypes.number.isRequired,
id: PropTypes.number.isRequired,
Copy link
Contributor

@himdel himdel Apr 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ids must be strings in js (only database ids, because of the high region precision issue)

const flashLaterSpy = jest.spyOn(window, 'miqFlashLater');
beforeEach(() => {
initialProps = {
id: 123,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(and here)

:force_cancel_button => true,
:ajax_buttons => true})

= react('RegionForm', :maxDescLen => ViewHelper::MAX_LEN_SMALL_TEXT_FIELD, :id => region.id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

region.id.to_s

@himdel
Copy link
Contributor

himdel commented Apr 14, 2020

Looks great :)

The id thing is the only thing I'd change :)

@h-kataria h-kataria force-pushed the region_edit_conversion branch from d56d19c to a916e3f Compare April 14, 2020 13:03
@miq-bot
Copy link
Member

miq-bot commented Apr 14, 2020

Checked commits h-kataria/manageiq-ui-classic@479e749~...a916e3f with ruby 2.5.7, rubocop 0.69.0, haml-lint 0.28.0, and yamllint
3 files checked, 0 offenses detected
Everything looks fine. 👍

@himdel himdel merged commit f829ace into ManageIQ:master Apr 14, 2020
@h-kataria h-kataria deleted the region_edit_conversion branch April 14, 2020 14:22
@asirvadAbrahamVarghese asirvadAbrahamVarghese mentioned this pull request Aug 4, 2025
84 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Form conversion: Configuration/Settings/Region: Region edit

4 participants