mavo
mavo copied to clipboard
New special properties for currently logged in user
Potential names: $username
, $name
, $avatar
, and $user
for any misc backend-specific info.
Will update on login/logout.
For multiple reasons:
- Default property values that depend on current user
- UI conditionals
- Storing object creator
- Reduce custom code for Mavo toolbar
- Possibly might help with granular permissions #318
Another option could be an object or functional syntax: $user.username
or userinfo('username')
to avoid polluting the global expression space with too many special variables.
As we know, backends that support authentication provide the user
object to Mavo, and Mavo uses it to add some info about a logged-in user to the Mavo bar.
We also know that this object can have not only expected properties like username
, name
, avatar
(even though there is no guarantee), but also some extra properties that are provided either via the info
property or some other way.
For me, as an author, it is rather easy to find out what properties the $user
special property has via, e.g., log($user)
and then get any of them either via $user.propertyName
or get($user, propertyName)
. For example, I can even do this: get(get($user, info), uid)
.
It seems to me that with functional syntax, there will not be an easy way to know what info provides a backend about a logged-in user. However, I must say that it's rather straightforward to get the same data as above using the functional syntax: get(userinfo('info'), uid)
.
That's why I personally am for an object syntax, i.e., for $user.username
. ☺️
We already have a working prototype of the $user
special property, which @karger and I heavily use in conjunction with the Firebase plugin in our apps. For now, we have to add it via custom JS like so:
(async function () {
await Mavo.ready;
Mavo.DOMExpression.special.event("$user", {
type: "mv-login mv-logout",
update: (evt) => evt.backend.user
});
})();
You can see it in action in this demo app.
LGTM, what's the downside? Why can't we just add this to core?
LGTM, what's the downside? Why can't we just add this to core?
We can. Just needed to resolve it first. ☺️ I’ll send a PR soon.
Actually, the downside of this approach is that the $user
special property is updated on the mv-login
and mv-logout
events firing on any Mavo app on the page so that it returns the user of the backend fired the corresponding event last.
However, we expect it to return every app's (primary backend) user separately.
Another issue is whether an app works with two backends requiring authentication. For example, the author uses GitHub's private repo as the source and a Google spreadsheet as the storage. AFAIC, in that case, the Google Sheets will be the primary backend (the default login button will log the user in with their Google account), and $user
will return info from the user's Google account. Will the app user be able to log in to their GitHub account? It seems to me that without custom JS, no.
Hmm, these are pretty signifiant. We do have special variables scoped to nodes, maybe we can scope them to the root node?
I think @DmitrySharabin urfaced a situation that is independent of the special $user variable. how does a user log in if mv-source and mv-storage have different back-ends? Then there's the separate question of what we should do with $user in that case, since there may be two different sets of user info....
We do have special variables scoped to nodes, maybe we can scope them to the root node?
If you mean $item
, $all
, and other buddies, yes, I’m trying to find a way to make $user
work similarly. Now I know I’m searching in the right direction. ☺️
Then there's the separate question of what we should do with $user in that case, since there may be two different sets of user info.
Exactly. That was the reason why I pointed out (but not fully expressed in words) the second issue.
Maybe someday we need to expose $source
and $storage
special properties so that authors can get not only the info about the logged-in user but also, e.g., the permissions the backends have. And the problem with different sets of user info will be solved automatically. In that case, we’d get something like $storage.user
and $storage.permissions
. Or maybe we’ll come up with the idea that it would be nice for the author to have access to the underlying backends’ methods (actions) like $storage.save()
, $source.load()
, $source.logout()
, etc. 🤔
I think @DmitrySharabin urfaced a situation that is independent of the special $user variable. how does a user log in if mv-source and mv-storage have different back-ends? Then there's the separate question of what we should do with $user in that case, since there may be two different sets of user info....
That's separate and much easier to deal with. E.g. $user
can be defined as user of the primary backend and we could have $storage_user
, $source_user
, $init_user
for more granularity.
I'm not sure "primary back end" is a tractable concept. If the author is creating an app that actually requires the user to have two different logins, it's very unlikely that we can figure out which back-end is primary. Maybe we should just accept that $user will come from the first mavo on the page?
"Primary backend" is an established concept already. Roughly, storage || source || init. It's scoped to a specific Mavo, hence the more pressing problem of scoping.
oh, i thought you were talking about which backend is primary among multiple mavo apps on the same page (which is the problem I was referring to).
I built a prototype of the $user
special property, which is context-aware.
Here is all the code that needs to be added to our code base (from my perspective):
Mavo.DOMExpression.special.event("$user", {
type: "mv-login mv-logout",
target: document
});
Mavo.Data.special["$user"] = function (obj) {
return obj[Mavo.mavo]?.primaryBackend?.user;
};
@LeaVerou Is this legal at all? 😅
I was also examining the option to put $user
into Mavo.Functions
. Unfortunately, I don't know how to make it a context-aware getter. I know how to do the context-aware $user
function:
Mavo.Functions["$user"] = $.extend(function () {
return this[Mavo.mavo]?.primaryBackend?.user;
}, {needsContext: true})
But it doesn't play well with other special properties since they are getters.