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

Refactor LocalStorage and associated hooks #11625

Open
wants to merge 28 commits into
base: develop
Choose a base branch
from

Conversation

somebody1234
Copy link
Contributor

@somebody1234 somebody1234 commented Nov 22, 2024

Pull Request Description

  • Close https://github.com/enso-org/cloud-v2/issues/1586
    • Refactor localStorage to use functionality returned by a single function, rather than registering keys plugin-style when modules are loaded.
      • This avoids errors when a module tries to read a key when the module defining the key has not yet been imported.

Important Notes

None

Testing Instructions

  • Make sure local storage keys are loaded and saved as appropriate:
    • ToS and Privacy Policy modal should not reappear on reload
    • Displayed columns
    • Sidebar open state
    • Local root directory
    • Extra local root directories

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • The documentation has been updated, if necessary.
  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    TypeScript,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • Unit tests have been written where possible.
  • If meaningful changes were made to logic or tests affecting Enso Cloud integration in the libraries,
    or the Snowflake database integration, a run of the Extra Tests has been scheduled.
    • If applicable, it is suggested to paste a link to a successful run of the Extra Tests.

@somebody1234 somebody1234 added CI: No changelog needed Do not require a changelog entry for this PR. g-dashboard x-refactor Changes that should not be visible to the end-user labels Nov 22, 2024
@somebody1234
Copy link
Contributor Author

@MrFlashAccount for CR

@somebody1234
Copy link
Contributor Author

and i guess @indiv0 (or @MrFlashAccount) for QA

Copy link

github-actions bot commented Nov 22, 2024

🧪 Storybook is successfully deployed!

📊 Dashboard:

const { localStorage } = useLocalStorage()

useEffect(() => {
if ('error' in schema.safeParse(localStorage.get(key))) {
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 this won't notify subscribers about removing the item from localstorage.

Also I'm not a fan of doing this stuff on the hook level, I though the defineLocalStorageKey is just a wrapper that removes the need to write boilerplate stuff, and the whole logic is still in the LocalStorage component

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this won't notify subscribers

notifying logic should still be in the LocalStorage class right now

not a fan of doing this stuff on the hook level

true. but now the schema stuff no longer exists in the LocalStorage class, i guess not strongly opinionated on it though. is there a reason schema stuff should be in LocalStorage?

(previously it was there mostly because all the registry stuff was more or less global - so it wasn't an option at all for the schema to be not in the core class)

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought we're stil into keeping it global? And this is supposed to be a solution for import order

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, but global doesn't mean all the functionality needs to be in one file, right? is there a reason the schema stuff should be in the LocalStorage class? like, i guess imo the best solution to kinda enforce this is to avoid exposing an alternative way with the same API that uses just the class

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, if we want developers to fall into the pit of success by forcing them to use defineLocalStorageItem, we need to put these api into the same folder and expose only the function, but not the LocalStoage class. But I still think that the LocalStorage should keep the schema, as it used to be, because we could have different wrappers around the class in the future and coping this logic might be a bad idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

btw not sure to have it in a separate module (so the class needs to be exported) but also hide it from auto import

return [value, setValue]
return [value, setValue]
}
return { get, set, delete: deleteKey, useGet, useSet, useDelete, useState: useLocalStorageState }
Copy link
Contributor

Choose a reason for hiding this comment

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

can we unify the stuff here, like:

// use array to make it easier to rename
return [
  item: {
    get,set,clear
  },
  useItem: useLocalStorageState(): [value, setValue, clearValue]
]

Hook might be less performant but more convinient to use.
For perf reasons we might expose setter as third item:

...
useSetItem(): [setValue, clearValue]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

use array to make it easier to rename

not sure about this one, especially since you don't always need both non-reactive and reactive parts.

i think unifying the values as you suggested should be enough

Copy link
Contributor

Choose a reason for hiding this comment

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

Same as for useState. We can flip items in the array btw. Also we can declare names for the array items aswell

Copy link
Contributor Author

@somebody1234 somebody1234 Nov 25, 2024

Choose a reason for hiding this comment

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

Same as for useState

i know useState does it but IMO that's because a getter/setter pair is a very common pattern for reactive state - and because you almost always want to rename the accessors anyway, and because you usually want all (all two) members of the tuple

Copy link
Contributor

Choose a reason for hiding this comment

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

And we dont want to rename the result of 'defineLocalStorageItem'?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you do have a point! still not 100% sure as we don't always want all the members and it's a lot less obvious what each returned value is (it's not a popular pattern unlike get/set), but if you think it's better than the current option then we can absolutely do that

} = defineLocalStorageKey('localRootDirectories', {
schema: (z) => z.string().array().readonly(),
})
export const { use: useLocalRootDirectories, useState: useLocalRootDirectoriesState } =
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it still use? Is it a hook?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup. it uses localStorage from the context, not sure if it's necessary tbh but i think removing the LocalStorageProvider is out of scope for this PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

Nowadays LocalStorage is a Singleton class, we can avoid using it from the context to make it possible to manipulate the storage state outside of the components, I think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: No changelog needed Do not require a changelog entry for this PR. g-dashboard x-refactor Changes that should not be visible to the end-user
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants