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

Add/guard installation flow #58493

Merged
merged 17 commits into from
Dec 6, 2021
Merged

Add/guard installation flow #58493

merged 17 commits into from
Dec 6, 2021

Conversation

gcsecsey
Copy link
Contributor

@gcsecsey gcsecsey commented Nov 25, 2021

Changes proposed in this Pull Request

  • prevents the installation if the URL is visited without clicking the Install button on the plugins page
  • if plugin A was installed previously, it still prevents the installation of plugin B from the URL directly

Testing instructions

Marketplace flow

Prevents direct access

  1. choose a site with any plan
  2. visit /marketplace/<pluginname>/install/<siteURL>
  3. verify that the this error message is shown:
    image

Allows install after Install button click

  1. choose a site with any plan
  2. visit /plugins/<pluginname>/<siteURL>
  3. click the Install or Upgrade and Install button
  4. perform the upgrade if needed
  5. verify that the install executes normally

Throws incorrect plan error message correctly

  1. choose a site with a free plan
  2. visit /plugins/<pluginname>/<siteURL>
  3. click the Upgrade and Install button
  4. from the checkout page, click the X button in the upper left corner
  5. verify that the this error message is shown:
    image

Prevents direct access after a successful plugin install

  1. choose a site with any plan
  2. visit /plugins/<pluginname>/<siteURL>
  3. click the Install or Upgrade and Install button
  4. perform the upgrade if needed
  5. verify that the install executes normally
  6. visit /marketplace/<secondpluginname>/install/<siteURL>
  7. verify that the this error message is shown:
    image

Plugin upload flow

Prevents direct access

  1. choose a site with any plan
  2. visit /marketplace/install/<siteURL>
  3. verify that the this error message is shown:
    image

Allows install after plugin upload

  1. choose a site with any plan
  2. visit /plugins/upload/<siteURL>
  3. upload a plugin
  4. verify that the install executes normally

Fixes #58297

@github-actions
Copy link

github-actions bot commented Nov 25, 2021

@gcsecsey
Copy link
Contributor Author

When displaying the error pages, there's a margin-top: 350px rule applied on the container:
image

@cpapazoglou @WBerredo any ideas why it's needed or if we can remove it perhaps?

@matticbot
Copy link
Contributor

matticbot commented Nov 25, 2021

Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

Sections (~2336 bytes added 📈 [gzipped])

name         parsed_size           gzip_size
plugins          +7510 B  (+1.2%)    +1991 B  (+1.1%)
marketplace      +1379 B  (+0.2%)     +345 B  (+0.2%)

Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.

Async-loaded Components (~101 bytes added 📈 [gzipped])

name                                                                           parsed_size           gzip_size
async-load-calypso-my-sites-marketplace-pages-marketplace-plugin-setup-status       +424 B  (+0.8%)     +101 B  (+0.6%)

React components that are loaded lazily, when a certain part of UI is displayed for the first time.

Legend

What is parsed and gzip size?

Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory.
Gzip Size: Compressed size of the JS and CSS files. This much data needs to be downloaded over network.

Generated by performance advisor bot at iscalypsofastyet.com.

@cpapazoglou
Copy link
Contributor

When displaying the error pages, there's a margin-top: 350px rule applied on the container: image

@cpapazoglou @WBerredo any ideas why it's needed or if we can remove it perhaps?

I suppose it was developed that it appears vertically centered? Probably we can make it better by utilizing flex?

SS 2021-11-25 at 13 55 28

@gcsecsey gcsecsey requested a review from a team as a code owner November 25, 2021 19:16
@matticbot matticbot added the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Nov 25, 2021
@gcsecsey
Copy link
Contributor Author

As we're handling multiple types of errors now in this component, I've tried consolidating the error handling with the help of an enum, but ran into some race condition issues down the line.

I see we're checking some conditions in an async way here:

@WBerredo could you help me with why the callback is needed here? Do we have some piece of state that changes on page load? Thanks 🙂

@cpapazoglou cpapazoglou requested review from cpapazoglou and removed request for a team and cpapazoglou November 26, 2021 13:36
@WBerredo
Copy link
Collaborator

This useEffect will run at every render (we don't pass the properties array) and check there is an unsupported plan, if there is, it will check again in 2 seconds and if the problem persists, it shows an error.

useEffect( () => {
if ( ! supportsAtomicUpgrade.current ) {
waitFor( 2 ).then(
() => ! supportsAtomicUpgrade.current && setNonInstallablePlanError( true )
);
}
} );

why the callback is needed here?

On the upgrade and install flow, the plan we receive on the first render is the old/low tier plan, but this plan gets updated on the subsequent renders. That's why we wait 2 seconds before showing the error, and we consider if it didn't get updated in 2 seconds this is the current plan of the user.


Does that makes sense? There is anything that still needs explaining?

@gcsecsey
Copy link
Contributor Author

@WBerredo I thought that we can't use the data that we have on the initial render, but wasn't sure, thanks for clarifying! 🎉

Copy link
Collaborator

@WBerredo WBerredo left a comment

Choose a reason for hiding this comment

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

I was able to test the general path, but I would like to point two things:

  • I didn't get the "upgrade to business plan" error, when following the steps I got the "direct access" error.
  • Shouldn't we store which plugin triggered the install and check it on the state? Otherwise, I would be able to trigger an install and access the direct URL with another plugin installation if done at the same time.

@gcsecsey
Copy link
Contributor Author

Thanks for testing this @WBerredo, it'd be a great idea to add the plugin to the state! I'll check the issue with the errors and add this additional check. 🙂

@gcsecsey
Copy link
Contributor Author

gcsecsey commented Dec 1, 2021

Shouldn't we store which plugin triggered the install and check it on the state? Otherwise, I would be able to trigger an install and access the direct URL with another plugin installation if done at the same time.

We will need to add similar events to the Plugin Upload flow https://wordpress.com/plugins/upload/[DOMAIN] which is now returning an error.

I've added these changes and updated the test instructions with steps for the plugin upload flow. When trying to visit the install page directly on https://wordpress.com/plugins/upload/[DOMAIN], we're now showing a flow-specific error message that helps the user navigate back to the plugin upload page.

I didn't get the "upgrade to business plan" error, when following the steps I got the "direct access" error.

This was a small mistake on my side, I've accidentally copied over the other error message. 😄 I've fixed it now, it should work as per the test instructions. 👍

Copy link
Collaborator

@WBerredo WBerredo left a comment

Choose a reason for hiding this comment

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

I am seeing an error on the upgrade and install flow, if I complete the purchase or not I am always getting the "This URL should not be accessed directly. Please click the Install button on the plugin page." error.

I'm not sure if this is related to the environment it is created on the PR. But I think this worth some research.

@gcsecsey
Copy link
Contributor Author

gcsecsey commented Dec 3, 2021

I am seeing an error on the upgrade and install flow, if I complete the purchase or not I am always getting the "This URL should not be accessed directly. Please click the Install button on the plugin page." error.

I've looked into this, and found that previously, the pluginInstallationStatus state var was written from both actions that were fired, resulting in a race condition when persisting the state:

dispatch( productToBeInstalled( null, slug, selectedSite.slug ) );
dispatch(
pluginInstallationStateChange(
MARKETPLACE_ASYNC_PROCESS_STATUS.IN_PROGRESS,
'preauthorize plugin installation URL'
)
);

case MARKETPLACE_QUEUE_PRODUCT_INSTALL:
return {
...state,
siteTransferStatus: MARKETPLACE_ASYNC_PROCESS_STATUS.UNKNOWN,
pluginInstallationStatus: MARKETPLACE_ASYNC_PROCESS_STATUS.UNKNOWN,

I've updated the installation check to still validate the primaryDomain and productSlug variables, and to check that the plugin installation hasn't been completed yet:

pluginInstallationStatus !== MARKETPLACE_ASYNC_PROCESS_STATUS.COMPLETED &&

pluginInstallationStatus !== MARKETPLACE_ASYNC_PROCESS_STATUS.COMPLETED &&

@gcsecsey
Copy link
Contributor Author

gcsecsey commented Dec 3, 2021

With @WBerredo we've discovered a new edge case.

When the user navigates away from the checkout page by changing the URL in the browser, the IndexedDB state is reset to the defaultState value:
https://d.pr/v/rDDfH9

However, when the user navigates away from the checkout page by clicking the X icon in the upper left corner of the checkout page, the IndexedDB state is persisted as expected:
https://d.pr/v/tqbGqp

It seems that by navigating to a new URL, the Redux init clears the persisted state instead of loading the values from IndexedDB, and hence breaks the purchase flow. When navigating through client routes, the defaultState isn't loaded again and the feature works as expected.

We've tried removing the defaultState so that values in IndexedDB can be read back on a later visit. However, this results in an error, the slice reducer can't be initiated without a default state:
image

It seems that we won't be able to persist state between URL hops by utilizing IndexedDB. For the time being, I've updated the testing steps to clarify that the feature only works when navigating via UI elements.

Copy link
Collaborator

@WBerredo WBerredo left a comment

Choose a reason for hiding this comment

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

Tested the last version and it is all working good 🚀

PS: The only edge case I found is mentioned at this PR but I don't think we can do anything about it.

@gcsecsey gcsecsey merged commit 73b9742 into trunk Dec 6, 2021
@gcsecsey gcsecsey deleted the add/guard-installation-flow branch December 6, 2021 11:13
@github-actions github-actions bot removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Dec 6, 2021
@a8ci18n
Copy link

a8ci18n commented Dec 6, 2021

This Pull Request is now available for translation here: https://translate.wordpress.com/deliverables/7024500

Thank you @gcsecsey for including a screenshot in the description! This is really helpful for our translators.

nelsonec87 pushed a commit that referenced this pull request Dec 9, 2021
* [WIP] add state var when installing plugins from the UI

* [WIP] prevent plugin installation if the URL is visited directly

Still need to clean up local state (nested ternary) and translation

* [WIP] update error handling

* [WIP] fail early when loading the URL directly

* center error message vertically

* update error handling

* unset state var when plugin installation is complete

* fix error handling

* verify plugins slug and domain name when installing plugin from URL

* fix plan upgrade error message

* delete unnecessary whitespace

* guard plugin upload flow too

* add new error message to plugin upload flow

* verify only `primaryDomain` and `productSlug` when installing plugins

`pluginInstallationStatus` could be overwritten by other actions

* evaluate error causes in priority order
@a8ci18n
Copy link

a8ci18n commented Dec 17, 2021

Translation for this Pull Request has now been finished.

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.

Plugin Installation: Better guard the installation flow
5 participants