Implement autostart for VNet in Connect#40900
Merged
Conversation
Those tests explicitly set the entire WorkspacesService state and would have to be modified each time we added something to the state. There's no reason for them to know about WorkspacesService state, so this commit refactors them out of that knowledge.
The unsubscribe function will be needed in order to comply with useSyncExternalStore API in the next commit.
gzdunek
approved these changes
Apr 25, 2024
Contributor
gzdunek
left a comment
There was a problem hiding this comment.
Awesome, these new hooks make working with non-react services much nicer 👏
I only left a comment about naming.
| * ); | ||
| * } | ||
| */ | ||
| export function useAppState< |
Contributor
There was a problem hiding this comment.
I have a feeling that this name could be more specific, for example, usePersistedState or useAppPersistedState.
Without checking the docs it is quite hard to guess what kind of state it updates (maybe it's a runtime state that lives in AppContext services?).
Member
Author
There was a problem hiding this comment.
Renamed to usePersistedState after a short discussion in DMs.
Member
Author
There was a problem hiding this comment.
…and renamed useImmutableStore to useStoreSelector, because as Grzegorz pointed out to me, the "immutable" part is just an implementation details.
avatus
approved these changes
Apr 26, 2024
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Colleagues, comrades, fellow developers, engineering directors, Mr. president. I have a very exciting PR to share with you today.
On the surface, it merely implements autostart for VNet, which is similar to how autostart works in Connect My Computer: it's turned on when VNet starts, turned off when VNet is manually stopped. The exciting part is two new hooks introduced in this PR. I believe those hooks will make future work on Connect easier and more idiomatic in the context of React.
usePersistedState
The state of autostart needs to be stored on disk. Historically this has been done by adding a new field to
StatePersistenceState, and then adding both a getter and a setter. That's a lot of boilerplate and worst of all, it doesn't quite follow React's state model. Most of the time your component gets a fresh value fromStatePersistenceStateonly because some other part of the component has caused an update, but changing the state on disk doesn't update anything.usePersistedStateis supposed to be a first attempt at curbing that.Unlike
useState,usePersistedStatedoesn't let you define arbitrary state and still requires you to add any new fields toStatePersistanceState. That gives us more control over what exactly gets stored inapp_state.jsonand it help with avoiding typos (e.g. I cannot dousePersistedState('vnet')in one place andusePersistedState('VNet')in another).One big caveat is that at the moment it doesn't propagate updates across multiple
usePersistedStatecallsites, see the comment aboveusePersistedStatedefinition. At the moment it's not a problem since the app state is consumed at a single callsite anyway (VnetContext).useStoreSelector
Accessing resources through VNet might require Connect to show some modals and some other UI interactions (i.e. showing recent connections in the future). As such, we cannot autostart VNet the moment the context gets mounted. We have to wait for
ClustersServiceandWorkspacesServicestates to be initialized.To achieve that, I added
isInitializedto the state ofWorkspacesService. But how does a React component get "notified" aboutisInitializedchanging fromfalsetotrue?Historically, we used
useStatemethod of each service which underneath calleduseStore. This hook updates the component whenever the state of a service changes. ForisInitializedin particular, this would be very wasteful –isInitializedchanges only once, but the rest of the workspace state changes all the time when you open new tabs.useStoreSelectorfixes that. It uses React'suseSyncExternalStoretogether withsubscribeWithSelectorthat I added toImmutableStorea while ago. This means you can write the following code and it'll cause the component to update only when the selected part of the state gets updated:In the future, it can be used to optimize some of our other hooks. For example,
useLoggedInUseranduseWorkspaceLoggedInUsertoday calluseStateonclustersServiceandworkspacesService. WithuseStoreSelector, they could provide selectors that trigger updates only when the relevant part of the state changes.For services which need to be consumed outside of React code, it's probably a good idea to keep their
ImmutableStoreimplementations and don't migrate completely to React. But for everything else, we should probably use React built-ins such as contexts anduseStateover custom solutions.