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

#9242: migrate unsaved standalone mod components in the Page Editor #9246

Merged
merged 5 commits into from
Oct 8, 2024

Conversation

twschiller
Copy link
Contributor

@twschiller twschiller commented Oct 7, 2024

What does this PR do?

Reviewer Notes

Future Work

  • Migrate ModComponent type to require _recipe/modMetadata

For more information on our expectations for the PR process, see the
code review principles doc

@twschiller twschiller self-assigned this Oct 7, 2024
@twschiller twschiller changed the title #9242: migrate unsaved standalone mod components in the Page Editor #9242: [WIP] migrate unsaved standalone mod components in the Page Editor Oct 7, 2024
@twschiller twschiller requested review from grahamlangford and removed request for grahamlangford and mnholtz October 7, 2024 01:20
);
for (const formState of modComponentFormStates) {
formState.modMetadata = modMetadata;
}
},
addModComponentFormStateToMod(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Drop unused action

@@ -670,53 +628,6 @@ export const editorSlice = createSlice({
state.visibleModalKey = ModalKey.MOVE_COPY_TO_MOD;
state.keepLocalCopyOnCreateMod = moveOrCopy === "copy";
},
removeModComponentFormStateFromMod(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Drop unused action

* The mod metadata for the mod component
* @see createNewUnsavedModMetadata
*/
modMetadata: ModMetadata;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Main type change: require modMetadata

Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of Except, would SetRequired be better here?

Copy link
Contributor Author

@twschiller twschiller Oct 7, 2024

Choose a reason for hiding this comment

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

Sure - I'll make the change. I think the end result is the same? I agree SetRequired is probably more readable

Copy link
Contributor Author

@twschiller twschiller Oct 8, 2024

Choose a reason for hiding this comment

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

Looks like we can't use it since SetRequired seems to operate on "?" and not types where the prop exists but the value might be set to undefined

Copy link
Collaborator

Choose a reason for hiding this comment

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

That makes sense now that I think about it. I need to poll with the team whether we want to start differentiating between ? and | undefined, since we've run into at least one bug due to the difference. There's a TS setting to enforce similar to strictNullChecks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IIRC, historically when adding a new prop, we've used foo: X | undefined so that the type checker forces us to think about where to provide a default value, etc. vs. accidentally leaving the property off

Agree that we might choose to revisit that decision, e.g., now that we have strict null checks enabled

export function migrateEditorStateV8(
state: EditorStateV8 & PersistedState,
): EditorStateV9 & PersistedState {
return produce(state, (draft) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Slice migration code

@twschiller twschiller added this to the 2.1.4 milestone Oct 7, 2024
@twschiller twschiller added the do not merge Merging of this PR is blocked by another one label Oct 7, 2024
@grahamlangford
Copy link
Collaborator

grahamlangford commented Oct 7, 2024

@grahamlangford I don't think I understand the sketch here: https://www.notion.so/pixiebrix/Re-Slicing-Eliminate-Standalone-mods-from-UI-694e4c85e61441809e14aec18f6b6109?pvs=4#10a43b21a253801a93e5e7e0cabb0b4d. UnsavedModDefinition is not how the Page Editor tracks mods/components. So there isn't really a way to convert standalone mod components to UnsavedModDefinition

If the user has any unsaved standalone mod components in their Page Editor, then we need to change them (structurally and visually) to match the new behavior when you create a new mod but don't save it via the dropdown (pushing metadata down with the @inner id, etc.

This is so we can get rid of the UI affordances for standalone mod components entirely

@grahamlangford do you remember the context behind why the sketch indicated we have to keep useMigrateStandaloneComponentsToMods? https://www.notion.so/pixiebrix/Re-Slicing-Eliminate-Standalone-mods-from-UI-694e4c85e61441809e14aec18f6b6109?pvs=4#10a43b21a25380e4974ae924d03f3fc5?. That hook loops over standalone mod component form states. So, if the Page Editor migrates those, the set of those would always be empty by the time it hits the hook

Sure, the idea is to be defensive:

  1. I am on an older version of the Extension (either before useMigrateStandaloneComponentsToMods was added or if it's more recent, I haven't opened the Page Editor since before)
  2. I have saved standalone mods that have been converted on the backend but not in the Extension. (because my previous version was too old or because I haven't opened the Page Editor in several versions
  3. I update my Extension to 2.1.4
  4. I open my Page Editor
  5. I need my persisted standalone mod components to be converted or I will probably experience UI errors (depending on how we handle removing the affordances for standalone mod components)

@twschiller twschiller force-pushed the feature/9244-move-copy-mod-component branch from 99f9601 to 9c49084 Compare October 7, 2024 18:27
Comment on lines 57 to 59
modComponentActions.UNSAFE_setModComponents(
array(activatedModComponentFactory, 3)(),
),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I forgot about that helper. There are so many places that would be useful

Comment on lines 27 to 28
// FIXME: why is this hook still required?
// See comment: https://www.notion.so/pixiebrix/Re-Slicing-Eliminate-Standalone-mods-from-UI-694e4c85e61441809e14aec18f6b6109?pvs=4#10a43b21a25380e4974ae924d03f3fc5
Copy link
Collaborator

@grahamlangford grahamlangford Oct 7, 2024

Choose a reason for hiding this comment

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

As noted on the PR comment, it's purely for backwards compatibility in case the user skipped multiple versions or didn't open the Page Editor in the time since the hook was added. We could consider other options as well (have redux-persist migrations delete any still-existing standalone mod components from both the options and editor stores?)

Copy link
Contributor Author

@twschiller twschiller Oct 7, 2024

Choose a reason for hiding this comment

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

I think the hook is a NOP though given the migration in this PR. Given the migration, standaloneComponentFormStates will always be an empty array

I agree there's a corner case for someone on 1/ a version of PixieBrix without the mod component slice migration, 2/ an unsaved standalone mod form state. They could get into a case where a different mod id is assigned to the form state vs. the mod component, but the mod id component will be the same

Personally, I don't think we need to account for people with unsaved standalone mod component who haven't opened the Page Editor in 2+ releases. They can recover just by saving deleting the unsaved mod from the Page Editor and recreating it

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's a good point. Though in that case we could end up in a situation where the App converted a persisted standalone mod component into a mod definition and the Extension converted the same persisted standalone mod component into an UnsavedMod.

I'll leave it to you to determine how defensive we want to be. It might be that the correct thing to do in that case is to update the hook to find mod components that have a temporary registry id instead of nullish metadata instead of removing it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a good point. Though in that case we could end up in a situation where the App converted a persisted standalone mod component into a mod definition and the Extension converted the same persisted standalone mod component into an UnsavedMod.

Yep - that's the corner case.

I'll leave it to you to determine how defensive we want to be

My strong preference is to just drop the code given that it's over a month/2+ releases away, outside our enterprise support window, and a recoverable issue

url,
modMetadata,
starterBrickMetadata,
element,
Copy link
Collaborator

Choose a reason for hiding this comment

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

NIT: I agree that button is the wrong name for this, but perhaps selectionResult would read better?

Copy link
Contributor Author

@twschiller twschiller Oct 7, 2024

Choose a reason for hiding this comment

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

It's using "element" because of the method name fromNativeElement. That's the "element" it's being created from. So if we wanted to use selectionResult, we'd probably want to rename the whole method in the adapter protocol

Leaving off of this PR

const modComponentFormState =
action.payload as Draft<ModComponentFormState>;
// Ensure the form state is writeable for normalization
const modComponentFormState = cloneDeep(action.payload);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm curious if we should consider switching to structuredClone

Copy link
Contributor Author

@twschiller twschiller Oct 8, 2024

Choose a reason for hiding this comment

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

🤷 Not sure. Initial Google search/chatter indicates structuredClone might be slower?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It might be. I haven't looked into any tests. I do know that structuredClone makes a copy of the prototype, whereas lodash cloneDeep apparently copies a reference to it. That's unlikely to ever be a problem for us though

@twschiller twschiller force-pushed the feature/9242-migrate-unsaved-standalone branch from 1040c91 to 666f093 Compare October 7, 2024 21:13
Base automatically changed from feature/9244-move-copy-mod-component to main October 7, 2024 21:20
@twschiller twschiller removed the do not merge Merging of this PR is blocked by another one label Oct 7, 2024
Fixup for _recipe/modMetadata

Revert cross-cutting refactoring

Revert cross-cutting refactoring
Copy link

github-actions bot commented Oct 7, 2024

Playwright test results

passed  135 passed
flaky  3 flaky
skipped  4 skipped

Details

report  Open report ↗︎
stats  142 tests across 46 suites
duration  13 minutes, 28 seconds
commit  bbeb17e
info  For more information on how to debug and view this report, see our readme

Flaky tests

chrome › tests/pageEditor/addStarterBrick.spec.ts › Add starter brick to mod
msedge › tests/pageEditor/addStarterBrick.spec.ts › Add starter brick to mod
msedge › tests/regressions/welcomeStarterBricks.spec.ts › #8740: can view the starter mods on the pixiebrix.com/welcome page

Skipped tests

chrome › tests/regressions/doNotCloseSidebarOnPageEditorSave.spec.ts › #8104: Do not automatically close the sidebar when saving in the Page Editor
msedge › tests/regressions/doNotCloseSidebarOnPageEditorSave.spec.ts › #8104: Do not automatically close the sidebar when saving in the Page Editor
chrome › tests/runtime/googleSheetsIntegration.spec.ts › can activate a google spreadsheet mod with config options
msedge › tests/runtime/googleSheetsIntegration.spec.ts › can activate a google spreadsheet mod with config options

@twschiller twschiller changed the title #9242: [WIP] migrate unsaved standalone mod components in the Page Editor #9242: migrate unsaved standalone mod components in the Page Editor Oct 8, 2024
@twschiller twschiller marked this pull request as ready for review October 8, 2024 01:16
Copy link

codecov bot commented Oct 8, 2024

Codecov Report

Attention: Patch coverage is 78.48101% with 17 lines in your changes missing coverage. Please review.

Project coverage is 75.10%. Comparing base (8318d74) to head (bbeb17e).
Report is 347 commits behind head on main.

Files with missing lines Patch % Lines
...itor/modListingPanel/DraftModComponentListItem.tsx 60.00% 4 Missing ⚠️
src/pageEditor/hooks/useAddNewModComponent.ts 0.00% 3 Missing ⚠️
src/pageEditor/starterBricks/base.ts 71.42% 2 Missing ⚠️
src/pageEditor/starterBricks/dynamicQuickBar.ts 0.00% 2 Missing ⚠️
src/pageEditor/hooks/useClearModChanges.ts 0.00% 1 Missing ⚠️
...geEditor/modListingPanel/modals/CreateModModal.tsx 0.00% 1 Missing ⚠️
src/pageEditor/store/analysisManager.ts 50.00% 1 Missing ⚠️
src/pageEditor/store/editor/editorSlice.ts 66.66% 1 Missing ⚠️
src/pageEditor/utils.ts 0.00% 1 Missing ⚠️
src/store/editorMigrations.ts 85.71% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9246      +/-   ##
==========================================
+ Coverage   74.24%   75.10%   +0.85%     
==========================================
  Files        1332     1370      +38     
  Lines       40817    42306    +1489     
  Branches     7634     7891     +257     
==========================================
+ Hits        30306    31773    +1467     
- Misses      10511    10533      +22     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment on lines +248 to +255
// Can't use SetRequired because the property is required (it does not use ?), but it can be set to undefined
Except<BaseFormStateV5<TModComponent, TStarterBrick>, "modMetadata"> & {
/**
* The mod metadata for the mod component
* @see createNewUnsavedModMetadata
*/
modMetadata: ModMetadata;
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

Copy link

github-actions bot commented Oct 8, 2024

No loom links were found in the first post. Please add one there if you'd like to it to appear on Slack.

Do not edit this comment manually.

@twschiller twschiller enabled auto-merge (squash) October 8, 2024 13:45
@twschiller twschiller added the user experience Improve the user experience (UX) label Oct 8, 2024
@twschiller twschiller merged commit 91ceceb into main Oct 8, 2024
32 checks passed
@twschiller twschiller deleted the feature/9242-migrate-unsaved-standalone branch October 8, 2024 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 participants