-
Notifications
You must be signed in to change notification settings - Fork 30
Refactor Studio to depend on CLI for preview site creation #1201
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 Studio to depend on CLI for preview site creation #1201
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really like the progress bar behavior for this scenario.
What happens on all my tests is that the bar progresses quickly until the last step, so it just gets stuck on this state for a while:
In my opinion, we could either use an indeterminate progress indicator (like a continuous progress bar) or display the same information we show on the CLI (Creating archive, Uploading archive, etc...) which seems far more valuable for our users compared to a stuck progress bar.
Code-wise I like this approach, looks clean and it's easy to read.
One minor comment would be to clear up the naming a bit. At least for me, the distinction between previews and snapshots seem confusing. Is there a benefit for keeping the 2, could we pick one?
Another thing on my mind is how we are currently cleaning up operations. Operations that fail, timeout, or are hanging for other reasons could potentially go on existing forever in our state, correct? I don't think this alone will be an issue, but it's something we should be mindful of, if this is going to be our approach for operations in Studio moving forward.
Is it possible to use a feature flag for this during the development?
@@ -0,0 +1,28 @@ | |||
// Store the actions in a separate file to avoid Webpack issues when importing them in the Studio |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some point I believe it would be better for us to start building a common
folder for types and functions that are used in both CLI and Studio. I don't think it will make any difference behavior wise, but will make it more intentional and easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea 👍
This PR touches so many parts of the code, so I was thinking it might be easier to branch off of this PR for the related tasks in https://linear.app/a8c/issue/STU-235 |
@@ -17,12 +17,15 @@ import nodePath from 'path'; | |||
import * as Sentry from '@sentry/electron/main'; | |||
import { __, LocaleData, defaultI18n } from '@wordpress/i18n'; | |||
import archiver from 'archiver'; | |||
import { z } from 'zod'; | |||
import { CreateLoggerAction } from 'cli/commands/preview/logger-actions'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're importing code from the "cli" app, why not import the command and run it as a function instead of a subprocess. I don't have a fully formed opinion at the moment but I think right now we're doing a bit of both which is kind of weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggested this approach of keeping the business logic squarely in the CLI when planning the project. It definitely adds complexity, but the upside is that it lets us avoid double bundling of PHP-WASM dependencies (once we get to moving that functionality from Studio to the CLI), which would increase the bundle size by ~700MB in the short term and ~400MB in the long term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me ;)
That's fair. I guess the current behavior in this PR would easily be perceived as a UX regression. I'll look into improving this.
That's fair. We could probably stick with "snapshots", since that's what we use in the code already.
They could indeed. That's not unique for this architecture, though, even if I realize that I still need to add some error handling to this PR. |
cli/lib/appdata.ts
Outdated
name: z.string().optional(), | ||
name: z.string(), | ||
userId: z.number().optional(), | ||
} ); | ||
|
||
const siteSchema = z | ||
.object( { | ||
id: z.string(), | ||
path: z.string(), | ||
name: z.string().optional(), | ||
name: z.string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe name
props are actually optional for sites or snapshots. I made this change to accommodate the reportKeyValuePair
logging of the snapshot name.
cli/lib/snapshots.ts
Outdated
return; | ||
} | ||
const snapshot: z.infer< typeof snapshotSchema > = { | ||
const site = await getSiteFromFolder( siteFolder ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change means that this function now throws if the site isn't found in the appdata file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
Code and UI are looking great!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was testing and:
- Counter looks broken for me
- Deleting also broken (maybe it's expected for this PR and will be solved in taht separate PR for handling deletion of previews, but wanted to flag in case if it's not expected)
@bcotrim coukd you please test it one more time, to understand is it my local issue or it's indeed exist.
Recording of the issues: https://drive.google.com/file/d/1xd71MGjY8bU0ZFdEcbzrRKjNqounppAp/view?usp=sharing
@nightnei I see that same issue but I assumed it was expected based on Note Snapshot state is now split between the new Redux reducer and the old If you reload the app after creating a preview site, the count is updated as expected. |
It wasn't menthioned in testing instructions, I see only "... works es expected". But it doesn't work as expected. Also, here (p1744904341127939-slack-C04GESRBWKW) he menthioned "I opted for this multi-PR approach to not break the preview site functionality on trunk while still making the PR size relatively manageable.", so looks liek it should work well even after merging just this one PR, w/o other PRs. Let's wait for Fredrik's response to clarify things. UPDATE:
|
if ( value > animatedValue ) { | ||
setAnimatedValue( value ); | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add some description, otherwise anotehr A12N can make mistake with adding it animatedValue
. And it will save time for A12S in the future with debugging to understand teh reason and logic.
src/components/progress-bar.tsx
Outdated
|
||
useEffect( () => { | ||
const maximumAutoIncrementValue = maxValue * 0.95; | ||
|
||
const interval = setInterval( () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems it should be setTimeout, since we run this effect every time when we update animatedValue
.
Theoreticaly, it works even now, since we clear interval every time when we rerun the effect, but a safer and correct way would be to use setTimeout.
Right or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call 👍
.filter( ( operation ) => operation.status === 'pending' ) | ||
.find( ( operation ) => operation.siteId === siteId ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.filter( ( operation ) => operation.status === 'pending' ) | |
.find( ( operation ) => operation.siteId === siteId ), | |
.filter( ( operation ) => operation.status === 'pending' && operation.siteId === siteId ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that you already did it in the follow up PR https://github.com/Automattic/studio/pull/1223/files#diff-e7f3116a80918052c6f2b0b4cc2e22b2f8dc46e44d97249c6d49522bc2bf3b2cR127-R131
}, | ||
selectors: { | ||
selectSnapshots: ( state ) => state.snapshots, | ||
selectSnapshotsCount: ( state ) => state.snapshots.length, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use it only in 1 place.
Also it looks a bit redundant to create extra selector for length if we already have selector for teh list.
Also, it even simlifies using it and readign code:
BEFORE:
const allSnapshots = useRootSelector( snapshotSelectors.selectSnapshots );
const snapshotsCount = useRootSelector( snapshotSelectors.selectSnapshotsCount );
AFTER:
const allSnapshots = useRootSelector( snapshotSelectors.selectSnapshots );
const snapshotsCount = allSnapshots.length; // But actually, I think we can even avoid creating this extra variable and use "allSnapshots.length" directly in code
selectSnapshotsCount: ( state ) => state.snapshots.length, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I actually removed this in #1230.
It's great idea 👍 |
We already merged a change with the initial version of that: #1222 |
} ); | ||
|
||
child.on( 'exit', ( code: number | null ) => { | ||
console.log( 'Preview site creation completed with code', code ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While reviewing #1223 I noticed that we will have a specific execute command for previews. It will likely make sense to remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point 👍 I've removed it in #1230
Good catch. We do actually invalidate the query correctly, but it looks like the deletion hasn't taken effect yet on the back-end when we do that, because the API still returns the old site count. Maybe we should delay the query invalidation to solve this…
Good catch. Looking into this 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
* [WIP] Refactor Studio to depend on CLI for preview site creation * More changes * Fix * Use node's child_process module to fork CLI process * Tests * useGetSnapshotUsage * Build CLI before starting dev version of app * Tweaks * Fixes * preview ➡️ snapshot * Improved progress bar * Display notice when operation completes * Update zod * Remove useArchiveSite hook * Fix test * Modify exitCode in Logger::reportError * Set exit code on error and fix outputFormat parsing * Shorten * Fix outputFormat parsing * Clarify naming * Tweaks
Related issues
Proposed Changes
getSnapshotUsage
query tosrc/stores/wpcom-api.ts
and update the UI to use this hook in the relevant places.useArchiveSite
hook.Note
Snapshot state is now split between the new Redux reducer and the old
SnapshotProvider
. This means updating and deleting snapshots does not update the UI as expected. We will address this in separate PRs (potentially branching off this PR instead of merging this totrunk
first).Testing Instructions
Pre-merge Checklist