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

Refactor modifications in upgrade and deployment forms #1283

Merged
merged 4 commits into from
Nov 14, 2019

Conversation

andresmgot
Copy link
Contributor

Follow up of #1278

This refactor:

  • Adds a new property to the IChartState: deployed. Instead of using selected and taking advantage that the first version selected is the one deployed, now we explicitly store that chart version in a different variable. This requires changes in the Redux store but allows us to pre-select the latest version in the upgrade form (not included in this PR)
  • Move the logic to manage modifications outside the BasicDeploymentFormBody. This procedure is specific to the upgrade flow so it's now in the UpgradeForm component.
  • Since the process of changing the appValues when changing the version is different between the deployment and the upgrade form, that's been extracted from the BasicDeploymentFormBody as well. In the case of the deployment, we simply apply the default values of the new version while in the upgrade scenario we also apply modifications if they exist.

Copy link
Contributor

@absoludity absoludity left a comment

Choose a reason for hiding this comment

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

Some small points and one big one: Can we please update past react 16.2 before doing this PR, so that we can use getDerivedStateFromProps and stop adding componentWillReceiveProps methods (which will need to be removed with effort very soon) or at least have to prefix them with UNSAFE_ and consider how we can avoid them.

@@ -25,6 +25,13 @@ export const selectChartVersion = createAction("SELECT_CHART_VERSION", resolve =
resolve({ chartVersion, values, schema });
});

export const requestedDeployedChartversion = createAction("SELECTED_DEPLOYED_CHART_VERSION");
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the different name from the string value here? (ie. why not selectedDeployedChartVersion, matching the string action value, or updating the string value to "REQUESTED_..." to match)

Also, we really should have some standard here... I see requestCharts/receiveCharts (which makes sense as a pattern), while for another action it is selectChartVersions / receiveChartVersions (select doesn't really make sense here, I think it's request?). Anyway, for this new one, can we do requestDeployedChartVersion (ie. no ed) and receiveDeployedChartVersion (ie. matching requestCharts/receiveCharts) and possibly update the other action here (unless I'm missing why select is being used).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you are right, I didn't properly read these

expect(wrapper.state("repo")).toEqual(repo);
});

it("should request the deployed chart when teh app and repo are populated", () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Tiny typo - s/teh/the/


export function getDeployedChartVersion(
id: string,
version: string,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there some confusion here about a chart version vs a chart revision, or are we defining a function called getDeployedChartVersion which takes the chart version as input? confused

Copy link
Contributor Author

@andresmgot andresmgot Nov 13, 2019

Choose a reason for hiding this comment

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

yeah, it's a bit confusing but it's the name pattern chosen here. The function needs a version as a string and returns a IChartVersion which is all the information about that version. The difference with a IChart is that IChart contains a reference to the latest version instead of a specific version.

public componentDidMount() {
const { releaseName, getAppWithUpdateInfo, namespace, fetchRepositories } = this.props;
getAppWithUpdateInfo(releaseName, namespace);
fetchRepositories();
}

public componentWillReceiveProps(nextProps: IAppUpgradeProps) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We seem to keep adding more componentWillReceiveProps when we should be removing them as we go, not adding?

See https://reactjs.org/docs/react-component.html#updating

The issue here is that we're adding more code that is dependent on detecting a change in the prop values, rather than working towards the functional getDerivedStateFromProps. Even if we can't use that here (it's added in 16.3), let's not add code which we're going to have to remove/update in the future? We should be considering the reasons why react is removing componentWillReceiveProps (ie. so that people won't be deriving state based on existing state or old prop values).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I completely forgot that componentWillReceiveProps was the one being deprecated. In this case, I think it's okay to use componentDidUpdate. I am reluctant to use getDerivedStateFromProps since it's a bit complex (and we need to use componentDidUpdate anyway for the second part of this function)

if (nextProps.selected.version !== this.props.selected.version && !this.state.valuesModified) {
this.setState({ appValues: nextProps.selected.values || "" });
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, this looks like we're adding more code which calculates state by detecting changes in props, rather than simply a function of the state... I worry we're going to pay for this later when componentWillReceiveProps is no longer supported (it'll be removed in 1.17).

Can we first update to React 16.3 (at least, but possibly latest - 16.11), before we add more code like this? At least then we'll be able to use getDerivedStateFromProps and will be forced to add UNSAFE_ to these unsafe methods we're adding?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the same here, it's true that we should not be using componentWillReceiveProps but I prefer using componentDidUpdate because the way to use it is more similar

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good.

@@ -41,6 +46,28 @@ class UpgradeForm extends React.Component<IUpgradeFormProps, IUpgradeFormState>
valuesModified: false,
};

public componentWillReceiveProps(nextProps: IUpgradeFormProps) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto for getDerivedStateFromProps

Copy link
Contributor Author

@andresmgot andresmgot left a comment

Choose a reason for hiding this comment

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

Hi @absoludity, thanks for the review. It's true that we should not be using componentWillReceiveProps but I'd rather use componentDidUpdate which is the closest one. Let me know what you think.

@@ -25,6 +25,13 @@ export const selectChartVersion = createAction("SELECT_CHART_VERSION", resolve =
resolve({ chartVersion, values, schema });
});

export const requestedDeployedChartversion = createAction("SELECTED_DEPLOYED_CHART_VERSION");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

you are right, I didn't properly read these


export function getDeployedChartVersion(
id: string,
version: string,
Copy link
Contributor Author

@andresmgot andresmgot Nov 13, 2019

Choose a reason for hiding this comment

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

yeah, it's a bit confusing but it's the name pattern chosen here. The function needs a version as a string and returns a IChartVersion which is all the information about that version. The difference with a IChart is that IChart contains a reference to the latest version instead of a specific version.

public componentDidMount() {
const { releaseName, getAppWithUpdateInfo, namespace, fetchRepositories } = this.props;
getAppWithUpdateInfo(releaseName, namespace);
fetchRepositories();
}

public componentWillReceiveProps(nextProps: IAppUpgradeProps) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I completely forgot that componentWillReceiveProps was the one being deprecated. In this case, I think it's okay to use componentDidUpdate. I am reluctant to use getDerivedStateFromProps since it's a bit complex (and we need to use componentDidUpdate anyway for the second part of this function)

if (nextProps.selected.version !== this.props.selected.version && !this.state.valuesModified) {
this.setState({ appValues: nextProps.selected.values || "" });
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the same here, it's true that we should not be using componentWillReceiveProps but I prefer using componentDidUpdate because the way to use it is more similar

Copy link
Contributor

@absoludity absoludity left a comment

Choose a reason for hiding this comment

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

Great, thanks for the update Andres.

repo = this.props.repo;
if (repo && repo.metadata) {
// If the repository comes from the properties, use it
this.setState({ repo });
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we storing props in the state like this? There should be no need if it's available in the props? Ah - I see below because it may not be in the props and may need to be fetched... so the state is guaranteed to have the repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly, the repo will be only available in the props when using the SelectRepoForm if not, it's obtained from the app info. For simplicity, I stored it in the state.

Comment on lines 79 to 81
this.setState({ repo: repoWithLatest });
repo = repoWithLatest;
this.setState({ repo });
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like 2 of these lines are redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops, yes

if (nextProps.selected.version !== this.props.selected.version && !this.state.valuesModified) {
this.setState({ appValues: nextProps.selected.values || "" });
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good.

@andresmgot andresmgot merged commit a10f05c into vmware-tanzu:master Nov 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants