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

Post By Email: add front-end settings for Simple sites #90819

Merged
merged 28 commits into from
May 29, 2024

Conversation

chad1008
Copy link
Contributor

@chad1008 chad1008 commented May 16, 2024

Related to https://github.com/Automattic/dotcom-forge/issues/7210

Proposed Changes

  • moves Post by Email module and settings into their own file
  • implements a Simple Site version of those settings utilizing the endpoints being introduced for 7211-gh-Automattic/dotcom-forge

Why are these changes being made?

Notes

  • This PR took a lot of inspiration from @nightnei's Post by Voice work in PostByVoice: add to Settings Writing #90489. Before I decided to split these settings off into a separate file I actually branched off of that PR so I could more easily keep any changes in sync, so we actually have at least one commit in common at the moment. I'll rebase off of that PR periodically to keep on the same page.
  • Currently in a fairly raw state, it needs a lot of cleanup. I liberally applied the props I needed to silence TypeScript, and will now be going through and trimming them down to what's actually needed
  • The settings are (naturally) not functional as of yet, that'll wait until the new endpoints are in place
  • For the setting toggle, I'm currently rendering either a JetpackModuleToggle as the setting did previously, or just a ToggleControl from @wordpress/components. I'd like to look into whether or not we can use the ToggleControl in both cases and just modify its handlers for Atomic/Jetpack vs Simple sites.

Testing Instructions

  • On your sandbox, apply the patch from 7211-gh-Automattic/dotcom-forge
  • Point public-api.wordpress.com to your sandbox
  • Running Calypso locally off of this branch, visit Settings > Writing for a simple site, and make sure you have the Classic View selected (Calypso, not wp-admin)
  • Confirm that the Post by Email settings appear
  • In a separate tab, open https://dashboard.wordpress.com/
  • Find your simple test site in the dashboard and note the state and/or email address of the current post by email settings
  • Back in Calypso, test the Post by Email toggle, refreshing and checking dashboard.wordpress.com to confirm the settings from Calypso are carrying over.
  • Back in Calypso, test the Regenerate button. Confirm that a new address is generated, and that the new address if reflected when refreshing dashboard.wordpress.com
  • Switch over to Settings > Writing for a WoA site
  • Repeat the same tests, this time comparing them to wp-admin/admin.php?page=jetpack#/writing, making sure the Calypso settings still properly update the Jetpack settings (we didn't make changes here, but the code was moved and refactored so we're making sure nothing got broken in the process)

@matticbot
Copy link
Contributor

matticbot commented May 16, 2024

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

Sections (~213 bytes added 📈 [gzipped])

name              parsed_size           gzip_size
settings-writing       +694 B  (+0.1%)     +213 B  (+0.1%)

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

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.

@chad1008 chad1008 changed the base branch from trunk to nightnei/postByVoiceSettingInCalypso May 17, 2024 19:06
@chad1008 chad1008 force-pushed the post-by-email/simple-site-calypso branch 3 times, most recently from df66af6 to c503407 Compare May 21, 2024 23:41
@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 May 22, 2024
@chad1008
Copy link
Contributor Author

Thanks again for looking this over @nightnei. I've addressed your feedback and also gone through and cleaned things up a bit.

A big part of that was making sure the variables were named it ways that made it clear which path they were a part of (e.g. jetpackRegeneratingPostByEmail instead of simply regeneratingPostByEmail, because for simple sites, the regenerate button goes through a completely separate process with its own variables.

This means the variable names are more verbose than they were before. I think the names I've chosen make the code easier to read, but please let me know if you disagree of if I've overcompensated!

@chad1008 chad1008 requested a review from nightnei May 22, 2024 23:37
Base automatically changed from nightnei/postByVoiceSettingInCalypso to trunk May 23, 2024 09:21
@nightnei
Copy link
Contributor

nightnei commented May 24, 2024

Regarding test instructions - sometimes a reviewer is not in the context of the changes, honestly even for me it's totally not clear what is wp-admin/admin.php?page=jetpack#/writing, how to get to this page (direct link doesn't work for me) 😅

Running Calypso locally off of this branch, visit Settings > Writing for a simple site, and make sure you have the Classic View selected (Calypso, not wp-admin)

Here is typo, right? Classic Default

UPDATE:
How I would rewrite your test instructions here (it's just a draft):

Find your simple test site in the dashboard and note the state and/or email address of the current post by email settings
Back in Calypso, test the Post by Email toggle, refreshing and checking dashboard.wordpress.com to confirm the settings from Calypso are carrying over.
Back in Calypso, test the Regenerate button. Confirm that a new address is generated, and that the new address if reflected when refreshing dashboard.wordpress.com

Test steps for Simple website

  1. Open Setting -> Writting in Default (Calypso )
  2. Open the second tab https://dashboard.wordpress.com/ and find your website
  3. Now we will be asserting that all changes applied in Calypso are synced with dashboard:
    3.1) Turn on "Post by Email", assert that email is generated and the same email is rendered in dashboard
    3.2) Regenerate email and assert ...
    3.3) Turn off "Post by Email" and assert ...
  4. Now let's repeat 3.x steps but making changes to dashboard and assert that they are reflected to Calypso

Test steps for Atomic website

Switch over to Settings > Writing for a WoA site
Repeat the same tests, this time comparing them to wp-admin/admin.php?page=jetpack#/writing, making sure the Calypso settings still properly update the Jetpack settings (we didn't make changes here, but the code was moved and refactored so we're making sure nothing got broken in the process)

Offtopic: Newbie question - WoA is WordPress on Atomic, right?

Here I would specify that "now we will be testing Atomic website, so necessary to create another website and make it Atomic", since initially I was confused with short sentense and so quick and dramatic "jump" from Simple to Atomic, w/o explanation that now we will be testing another thing.
And its difficult for me to suggest test instructions here, since I don't remember where is located this configuration for "Classic View(wp-admin)"

Copy link
Contributor

@nightnei nightnei left a comment

Choose a reason for hiding this comment

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

In general everything look cool 👍 And works will (both UI and backend). I haven't only tested the last two steps in your tet instructions, but I tested PbE in Default(Calypso) View and it works well, as previously.
Left a few comments and will be waiting for rebasing with trunk to make a final review.

Comment on lines 147 to 152
disabled={
isFormPending ||
jetpackRegeneratingPostByEmail ||
isSimpleSitePendingRegenerate ||
! isActive ||
!! moduleUnavailable
Copy link
Contributor

Choose a reason for hiding this comment

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

We have different condition for disabled state here and here (https://github.com/Automattic/wp-calypso/pull/90819/files#diff-1a2d2a711ac2389148e7764b72177d565e3e6a88fea709f208906a031a5a64c5R142)

  1. Let's make it the same (I thing we can add isFormPending to the "Copy" button)
  2. Let's create variable for both cases to avoid duplication

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This one was actually a bit of an interesting rabbit hole once I started looking at it more closely.

There are five disabled props in play:

  1. Jetpack toggle
  2. Simple site toggle
  3. Copy button,
  4. Regenerate button
  5. is-disabled classname on the FormLabel.
  6. Across those five items, we actually had four different conditions. Technically only four ever appear at once, but still... that's way too many combinations of conditions!

To clean this up, I've made it so the three items that apply to both flows are the same using a new, single variable to check the relevant conditions. I've also made it so isFormPending is included in all conditions, as that's not flow-specific and checks to see if any settings are being requested for the current site.

One other interesting discovery... for the new Simple site toggle, we disable the toggle itself if the setting is being toggled or if the email is being regenerated. I think that's something I initially included when taking inspiration from earlier versions of your Post by Voice PR.

We don't actually have the same behavior for Jetpack, because:

  1. We don't have a Jetpack version of isSimpleSitePendingToggle (the isUpdatingJetpackSettings selector might suffice, but I'll need to look at it a bit more)
  2. While we do have jetPackRegeneratingPostByEmail, I don't see it actually doing anything. It doesn't apply a disabled state, or change the button text the way the code currently asks it to. It doesn't even log out as true when the regeneration button is pressed. I'm not sure if it just isn't implemented correctly, or if there's some other problem.

When I'm back on tuesday, I'll prioritize looking into jetPackRegeneratingPostByEmail and isUpdatingJetpackSettings to see if they can serve the same roles as our Simple counterparts, or if they should just be excluded entirely for now.

But either way, the disabled logic should be a little simpler now... and might become more so if we decide to go without jetPackRegeneratingPostByEmail.

@chad1008 chad1008 force-pushed the post-by-email/simple-site-calypso branch from 3cb3546 to a14c278 Compare May 24, 2024 19:37
@chad1008
Copy link
Contributor Author

Thank you @nightnei! I appreciate the feedback on the testing instructions, and have made some changes there 🙂

Offtopic: Newbie question - WoA is WordPress on Atomic, right?

Yep! Sorry for throwing the extra acronym around!

--

Thanks for all of the other feedback, I believe I've addressed everything, I'll just need to circle back to the disabled logic question I mentioned above. Will do that first thing when I'm back online!

Copy link
Contributor

@fredrikekelund fredrikekelund left a comment

Choose a reason for hiding this comment

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

Looking good and tests well! 👍

I left a couple of small remarks.

{ renderPostByVoice && this.renderPostByVoiceModule() }
{ renderPostByEmail && this.renderPostByEmailModule() }
{ this.renderPostByEmailModule() }
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should put Post by Email above Post by Voice since it's used much more frequently.

Comment on lines 51 to 49
const moduleUnavailable = siteInDevMode && moduleUnavailableInDevMode;
const { data: simpleSitePostByEmailSettings } = useGetPostByEmail( selectedSiteId );
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const moduleUnavailable = siteInDevMode && moduleUnavailableInDevMode;
const { data: simpleSitePostByEmailSettings } = useGetPostByEmail( selectedSiteId );
const moduleUnavailable = siteInDevMode && moduleUnavailableInDevMode;
const { data: simpleSitePostByEmailSettings } = useGetPostByEmail( selectedSiteId );

Nit, but a newline here would be nice to delineate between Jetpack and Simple stuff.

<ToggleControl
checked={ !! simpleSitePostByEmailSettings?.isEnabled }
disabled={ isFormPending || isSimpleSitePendingToggle || isSimpleSitePendingRegenerate }
label={ translate( 'Post by Email' ) }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
label={ translate( 'Post by Email' ) }
label={ translate( 'Publish posts by sending an email' ) }

It seems logical to reuse the Jetpack control label here.

Comment on lines 39 to 41
const jetpackRegeneratingPostByEmail = useSelector( ( state ) =>
isRegeneratingJetpackPostByEmail( state, selectedSiteId )
);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is outside the scope of this PR, but in my testing, this selector doesn't seem to work properly (it never returns true). The same behavior can be observed in production.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you think it's worth removing from Post by Email for now, so it's not misleading/confusing for devs reading this code in the future? Or leave it to quietly do nothing in case/until it's fixed in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Scratch that question... we were really only trying to use it for one thing that I decided to remove anyway, so that selector is no longer called at all. If it's ever fixed we can bring it back to have parity with Simple sites, but for now we can leave it out, I think.

Comment on lines 109 to 140
const isDisabledForBothFlows =
isFormPending ||
jetpackRegeneratingPostByEmail ||
isSimpleSitePendingRegenerate ||
! isActive ||
!! moduleUnavailable;

return (
<>
<FormFieldset>
<SupportInfo
text={ translate(
'Allows you to publish new posts by sending an email to a special address.'
) }
link={
siteIsAtomic
? localizeUrl( 'https://wordpress.com/support/post-by-email/' )
: 'https://jetpack.com/support/post-by-email/'
}
privacyLink={ ! siteIsAtomic }
/>
{ siteIsJetpack ? (
<JetpackModuleToggle
siteId={ selectedSiteId }
moduleSlug="post-by-email"
label={ translate( 'Publish posts by sending an email' ) }
disabled={ isFormPending || moduleUnavailable }
/>
) : (
<ToggleControl
checked={ !! simpleSitePostByEmailSettings?.isEnabled }
disabled={ isFormPending || isSimpleSitePendingToggle || isSimpleSitePendingRegenerate }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const isDisabledForBothFlows =
isFormPending ||
jetpackRegeneratingPostByEmail ||
isSimpleSitePendingRegenerate ||
! isActive ||
!! moduleUnavailable;
return (
<>
<FormFieldset>
<SupportInfo
text={ translate(
'Allows you to publish new posts by sending an email to a special address.'
) }
link={
siteIsAtomic
? localizeUrl( 'https://wordpress.com/support/post-by-email/' )
: 'https://jetpack.com/support/post-by-email/'
}
privacyLink={ ! siteIsAtomic }
/>
{ siteIsJetpack ? (
<JetpackModuleToggle
siteId={ selectedSiteId }
moduleSlug="post-by-email"
label={ translate( 'Publish posts by sending an email' ) }
disabled={ isFormPending || moduleUnavailable }
/>
) : (
<ToggleControl
checked={ !! simpleSitePostByEmailSettings?.isEnabled }
disabled={ isFormPending || isSimpleSitePendingToggle || isSimpleSitePendingRegenerate }
const isJetpackDisabled = isFormPending || moduleUnavailable;
const isSimpleSiteDisabled =
isFormPending || isSimpleSitePendingToggle || isSimpleSitePendingRegenerate;
const isDisabledControls = ! isActive || isJetpackDisabled || isSimpleSiteDisabled;
return (
<>
<FormFieldset>
<SupportInfo
text={ translate(
'Allows you to publish new posts by sending an email to a special address.'
) }
link={
siteIsAtomic
? localizeUrl( 'https://wordpress.com/support/post-by-email/' )
: 'https://jetpack.com/support/post-by-email/'
}
privacyLink={ ! siteIsAtomic }
/>
{ siteIsJetpack ? (
<JetpackModuleToggle
siteId={ selectedSiteId }
moduleSlug="post-by-email"
label={ translate( 'Publish posts by sending an email' ) }
disabled={ isJetpackDisabled }
/>
) : (
<ToggleControl
checked={ !! simpleSitePostByEmailSettings?.isEnabled }
disabled={ isSimpleSiteDisabled }

It'd be nice to assign the disabled values for the respective controls to separate variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh yes, that's much cleaner, thank you!


export const getPostByEmailPath = ( siteId: number | null ) => `/sites/${ siteId }/post-by-email`;

export const getCachePostByEmailKey = ( siteId: number | null ) => [
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
export const getCachePostByEmailKey = ( siteId: number | null ) => [
export const getPostByEmailKeyQueryKey = ( siteId: number | null ) => [

I overlooked this in #90489, but I think we should mention "query key" rather than "cache key".

Comment on lines 18 to 20
import PressThis from '../press-this';
import { PostByEmailSetting } from './post-by-email';
import { PostByVoiceSetting } from './post-by-voice';
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
import PressThis from '../press-this';
import { PostByEmailSetting } from './post-by-email';
import { PostByVoiceSetting } from './post-by-voice';
import PressThis from 'calypso/my-sites/site-settings/press-this';
import { PostByEmailSetting } from 'calypso/my-sites/site-settings/publishing-tools/post-by-email';
import { PostByVoiceSetting } from 'calypso/my-sites/site-settings/publishing-tools/post-by-voice';

Nit, but let's be consistent with absolute import paths.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Shoot! I made a point of fixing that, because it was mentioned on a previous PR. I must have lost it during a rebase 🤦

@chad1008 chad1008 force-pushed the post-by-email/simple-site-calypso branch from 650f148 to ac575ce Compare May 28, 2024 19:11
value={ email }
/>
<Button onClick={ handleRegenerate } disabled={ isDisabledControls }>
Regenerate address
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There was previously (including on trunk) logic to change this button content to Regenerating... while a new address was being generated for Jetpack sites. I've removed that in favor of consistent button text for the reasons below.

It isn't working for Jetpack (including on trunk) as Fredrik and I noted above, and when I applied it to Simple sites (where it does work) I really didn't like the way it changed the size of the button. The visual jump was king of jarring. Could be fixed with CSS, but it honestly didn't feel like it was worth it.

On Simple, we're also now temporarily disabling the button while the new address is generated, so there's visual feedback in that form, and if/when the isRegeneratingJetpackPostByEmail is working in the future, we can apply the temp disable effect there, too.

tl;dr: from a user perspective, removing this text change doesn't impact Jetpack users at all, and we have something else in place for Simple that I think works better anyway.

@chad1008
Copy link
Contributor Author

Current feedback has been addressed, and I've added one new inline comment regarding a small change when regenerating the email address.

Based on past feedback I think we should be good, or very very close!

@chad1008 chad1008 marked this pull request as ready for review May 28, 2024 19:20
Copy link
Contributor

@fredrikekelund fredrikekelund left a comment

Choose a reason for hiding this comment

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

I made some light tweaks in 09e5011 and then some slightly larger refactorings of the PublishingTools component in 6cf91ac and 2c7e20c. All of the Post by Email-related logic is consolidated in PostByEmailSetting now.

I've tested this with a Simple site, an Atomic site, and an external Jetpack site.

This should be good to land 👍

Comment on lines -201 to -230
export default connect(
( state ) => {
const selectedSiteId = getSelectedSiteId( state );
const siteIsJetpack = isJetpackSite( state, selectedSiteId );
const isAtomic = isSiteAutomatedTransfer( state, selectedSiteId );
const regeneratingPostByEmail = isRegeneratingJetpackPostByEmail( state, selectedSiteId );
const siteInDevMode = isJetpackSiteInDevelopmentMode( state, selectedSiteId );
const moduleUnavailableInDevMode = isJetpackModuleUnavailableInDevelopmentMode(
state,
selectedSiteId,
'post-by-email'
);

return {
siteIsJetpack,
isAtomic,
selectedSiteId,
regeneratingPostByEmail,
postByEmailAddressModuleActive: !! isJetpackModuleActive(
state,
selectedSiteId,
'post-by-email'
),
moduleUnavailable: siteInDevMode && moduleUnavailableInDevMode,
};
},
{
regeneratePostByEmail,
}
)( localize( PublishingTools ) );
Copy link
Contributor

Choose a reason for hiding this comment

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

My goal here wasn't to remove the connect call. However, I discovered that several props were redundant (a lot of logic has been moved to PostByEmailSetting) and that SiteSettingsFormWriting can pass the other props we need.

export const PostByEmailSetting = ( { emailAddress }: PostByEmailSettingProps ) => {
const selectedSiteId = useSelector( getSelectedSiteId ) || 0;
const siteIsJetpack = useSelector( ( state ) => isJetpackSite( state, selectedSiteId ) );
const jetpackRegeneratingPostByEmail = siteIsJetpack && emailAddress === 'regenerate';
Copy link
Contributor

Choose a reason for hiding this comment

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

The isRegeneratingJetpackPostByEmail selector doesn't work, but we can deduce the same thing by determining if emailAddress has the value regenerate. "One weird trick" 🙃

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This almost feels sneaky, and I love it 😆

Comment on lines +118 to +123
link={
! siteIsJetpack
? localizeUrl( 'https://wordpress.com/support/post-by-email/' )
: 'https://jetpack.com/support/post-by-email/'
}
privacyLink={ siteIsJetpack }
Copy link
Contributor

Choose a reason for hiding this comment

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

We used to look at siteIsAtomic here and the logic was flipped (Simple sites linked to jetpack.com and Atomic sites to wordpress.com).

The flipped logic was obviously wrong, but I also don't see a reason to look at siteIsAtomic instead of siteIsJetpack.

Comment on lines -32 to -62
componentDidUpdate() {
const {
fields,
moduleUnavailable,
postByEmailAddressModuleActive,
regeneratingPostByEmail,
selectedSiteId,
} = this.props;

if ( ! moduleUnavailable ) {
return;
}

if (
postByEmailAddressModuleActive &&
regeneratingPostByEmail === null &&
! fields.post_by_email_address
) {
this.props.regeneratePostByEmail( selectedSiteId );
}
}

onRegenerateButtonClick = () => {
this.props.regeneratePostByEmail( this.props.selectedSiteId );
};

isFormPending() {
const { isRequestingSettings, isSavingSettings } = this.props;

return isRequestingSettings || isSavingSettings;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Initially, I thought we could remove this altogether, but I realized that the componentDidUpdate logic is still required. What it does is regenerate the email address immediately after the Jetpack Post by Email module is enabled for the first time. Without it, the feature can be enabled, but there's no email address to send to.

I moved this functionality to PostByEmailSetting in 2c7e20c

@@ -8,15 +8,15 @@ import type {

export const getPostByVoicePath = ( siteId: number | null ) => `/sites/${ siteId }/post-by-voice`;

export const getCachePostByVoiceKey = ( siteId: number | null ) => [
export const getPostByVoiceQueryKey = ( siteId: number | null ) => [
Copy link
Contributor

Choose a reason for hiding this comment

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

For consistency, I took the opportunity to rename this.

@chad1008
Copy link
Contributor Author

Thanks for sharing those updates @fredrikekelund. Testing well on my end, too!

@chad1008 chad1008 merged commit 374aace into trunk May 29, 2024
11 checks passed
@chad1008 chad1008 deleted the post-by-email/simple-site-calypso branch May 29, 2024 19:27
@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 May 29, 2024
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.

None yet

4 participants