Openrefine: Access to a JS object on the client side with all the preferences, that would not be updated (frequently)

Created on 14 May 2020  Â·  11Comments  Â·  Source: OpenRefine/OpenRefine

Is your feature request related to a problem or area of OpenRefine? Please describe.
A direct access to the value of the preferences for reading in the interface at the JS level would be most useful. Right now, you have to do an async call to retrieve them.

Those preferences would be, in the context of this issue, only updated when the user changes of page. Other processes could want to modify/update these preferences, but it's not the scope of this issue.

Describe the solution you'd like
Two functions, accessible from anywhere in the UI JS code, that would get and set the user preferences. It could be:

Refine.getPreference(key, defaultValue) => return a string
Refine.setPreference(key, newValue)

enhancement metadata preferences

Most helpful comment

The current code is a little clunky

This is a reference to the existing multiline AJAX code, not any reference to or critique of your code.

So it sounds like you're looking for a convenience function to save you having to write the equivalent of this: https://github.com/OpenRefine/OpenRefine/blob/8414a82df8dac9941ff918f217649020e99487f5/main/webapp/modules/core/scripts/views/data-table/cell-ui.js#L44-L59

That sounds like a useful utility. Although the values aren't guaranteed to be current, they'll get refreshed on project load, so probably close enough for most purposes. If users have multiple tabs open we'll just have to tell them to refresh any stale tabs.

All 11 comments

@wetneb: so I coded it. It's easy and operate at a good time I think (just after metadatas). Since there is no design matter here, maybe it could be merge fast into master? I would need it for another issue.

Regards,
Antoine

This is specifying an implementation rather than stating a problem. What problem are we trying to solve here? Is the concern verbosity / code duplication? Performance? Something else?

Preferences aren't accessed frequently enough that caching them seems worth investing in.

The current code is a little clunky, but that could be easily fixed with the use of Promises and/or a utility function to wrap the AJAX call.

This is specifying an implementation rather than stating a problem.

@tfmorris: This is an enhancement issue, not a bug fix. And my problem was stated, I need an access NOT asynch to preferences.

What problem are we trying to solve here? Is the concern verbosity / code duplication? Performance? Something else?

I'm trying to implement this: « Add a preference to control the choice of row quantity displayed (i.e. other than [5, 10, 25, 50]) #2624 ».

Preferences aren't accessed frequently enough that caching them seems worth investing in.

Right now, because they can't be access fast. But new features could require it.

The current code is a little clunky, but that could be easily fixed with the use of Promises and/or a utility function to wrap the AJAX call.

I don't understand why you do a « low latency prefs read » vs « always current and thru AJAX » competition. Those two things are just different. And for « the code is a little clunky », what do you mean? Because, do you think the code that loads the metadata or the models is clunky? Because I use the exact same technic. And, did you notice I added an error checking on the models loading code?

Now, I see the benefit of the use of Promises and/or a utility function to wrap the AJAX call. Actually, if we had a setPreferenceValue(iKey, iValue), this code could also update thePreferences, which would then be ALWAYS accurate…

Don't you think?

Regards,
Antoine

The current code is a little clunky

This is a reference to the existing multiline AJAX code, not any reference to or critique of your code.

So it sounds like you're looking for a convenience function to save you having to write the equivalent of this: https://github.com/OpenRefine/OpenRefine/blob/8414a82df8dac9941ff918f217649020e99487f5/main/webapp/modules/core/scripts/views/data-table/cell-ui.js#L44-L59

That sounds like a useful utility. Although the values aren't guaranteed to be current, they'll get refreshed on project load, so probably close enough for most purposes. If users have multiple tabs open we'll just have to tell them to refresh any stale tabs.

The current code is a little clunky

This is a reference to the existing multiline AJAX code, not any reference to or critique of your code.

Oh! Now I understand, @tfmorris. I share this opinion.

So it sounds like you're looking for a convenience function to save you having to write the equivalent of this (…)

Yes. And saving the roundtrip that AJAX imposes.

That sounds like a useful utility. Although the values aren't guaranteed to be current, they'll get refreshed on project load, so probably close enough for most purposes. If users have multiple tabs open we'll just have to tell them to refresh any stale tabs.

Exactly. This is an _utility_. It makes NO promesse about acuity/« uptodateness ». Yesterday, I proposed two functions to wetneb, based on his suggestions, and he liked it (see below). How do you feel about that?

https://github.com/OpenRefine/OpenRefine/blob/4f04086b5ad4f594320cf6f8b0531f59462cf8f4/main/webapp/modules/core/scripts/project.js#L230-L252

It's just a step more than my original proposition, in the sense that it will not get update from other tabs, but the preferences would stay updated in each tabs. I know there is a LOT of flaws in this concept, this issue is not about well managing preferences, it’s really a quick and dirty access to prefs.

Thanks for your feedbacks, regards,
Antoine

I think a lot of this older code could be much more simplified.
I'd encourage to investigate looking into using IndexedDB which itself already supports asynchronous database operations.
https://dev.to/rdegges/please-stop-using-local-storage-1i04
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage

Or better yet the newer Cache API (can use for general storage) with or without a service worker.
https://web.dev/cache-api-quick-guide/
https://developer.mozilla.org/en-US/docs/Web/API/Cache
https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker

Reengineering the preference store is pretty far down on my list of priorities, as is performance optimization of fetching preferences. A little light refactoring to reduce redundancy is more along the lines of what I'm thinking of.

@tfmorris yeah, understood and I figured as well. Just wanted to state an option. Although now rethinking it...perhaps it's not the best way always... I recall David and I debating if preferences "go along with" a Project, "or not"... the idea of some preferences being User opinions, and other preferences actually being useful for Project sharing (exporting an OR project for others). Someone could argue that all insecure preferences (no api keys, passwords, etc) should be simplified by storing into a Project itself with JSON, and that way it can always travel with the Project. At the same time, it would not be a nice citizen when we have to force a user to set their row pagination preference on each Project and David and I agreed that User and Project preferences are separate concerns and probably need to be stored differently. That's about as much as I remember of the chat. The end result was that my 50 rows UI preference that I wanted to "stick" always no matter the Project... did finally "stick" always.

Or better yet the newer Cache API (can use for general storage) with or without a service worker.
https://web.dev/cache-api-quick-guide/
https://developer.mozilla.org/en-US/docs/Web/API/Cache
https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker

@thadguidry: Cache is nice, but it does it deal with multi-tabs? I would rather look at « HTML Session Storage »:
http://diveintohtml5.info/storage.html

Regards, A.

@antoine2711 Web Storage sessionStorage is more secure, Yes. For a published App like OR, I would never resort to using localStorage.
localStorage is shared between tabs on the same origin while sessionStorage is not shared.

@lisa761: I'm closing this issue, since #2624 implements the code described in this issue.

Refine.getPreference(key, defaultValue) => return a string
Refine.setPreference(key, newValue)

Regards,
Antoine

Was this page helpful?
0 / 5 - 0 ratings