-
Notifications
You must be signed in to change notification settings - Fork 178
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
Overhaul HTML syntax to specify backends #1019
Comments
Does this mean there would be no way to have a fallback, or that all errors are handled in the component?
Without a fallback, their data is just lost? |
@joyously Not sure what you're referring to? That’s describing how Mavo currently works, that data reading has fallbacks (if the source backend has no data) but writing doesn't (because it doesn't matter if the write backend has no data). It has nothing to do with these error conditions, which will continue to be handled the same. If anything, with the new syntax, the idea is that eventually you can provide multiple backends for writing, so that you can have redundancy. |
Thank you. I couldn't determine that it described the current functionality. When I was trying to write my storage backend, I really couldn't tell what it was supposed to handle and what the base class handled. (perhaps lack of docs) |
Before diving into engineering, I'd prefer to back up and think about what kind of functionality, and what kind of conceptual model to support it, is the right one for mavo applications. In particular, I think it's worth thinking about whether a model that has worked well for decades---a file system---is the right one for these web applications, or whether web applications in general need an entirely different model. For starters let's look at the argument for a filesystem approach. People have a very strong understanding of its conceptual model, and the fact that our "files" would usually live on the web instead of the device is not a big deal in this era of google drive and dropbox (perhaps webdav just came too early). People would have no difficulty with ideas like "to edit my own data with this app, I open this file, but to look at my friend's data that they are sharing with me, I open that file." If I launch an app for the first time with no configuration, there's a customary workflow of opening a new blank "file" in such circumstances. We can continue to use our current heuristics for specifying the default "filename" for that new file. This would also simplify things for a user who for example wanted to have two distinct data files and switch between them. If we pursued this approach we would probably want to develop a "file manager" component that would allow the user to list, open, delete, and move files. But all of this maps quite naturally to many of our back ends. We would also, for convenience, want to remember which was the last opened file so we could open it on the next visit, but this could easily be recorded in localstorage. Some complication comes from the fact that certain functionalities that an app requires might only be available on certain back-ends. For example if I am relying on firebase realtime updates I can't switch my back end to github and expect that to keep working (though I could make it work with dropbox https://developers.dropbox.com/detecting-changes-guide ). I think this points towards an author specifying which capabilities are required of their app, which would cause the set of available back-ends to be filtered to meet that specification. |
@karger I don't understand how your message relates to the first post at all, did you mean to post it somewhere else? |
Yes, lack of docs, especially for plugin development, is sadly a very pervasive problem :( Hopefully once we move to ESM we can just use typedoc. |
Do I understand correctly that we can go either the “HTML way” or “CSS way“? By “HTML way” I mean “plain ids” similar to how ids are used to link to The HTML way feels more natural and more aligned with the rest of the native elements we have in HTML. However, the CSS way feels more powerful, especially if we plan to support linking to multiple backends—the author can simply provide a (valid) CSS selector, and they are done. I wonder, is there an attribute in HTML whose value is a CSS selector? 🤔 |
My concern was about investing substantial effort in updating our HTML syntax (which also probably means refining the current conceptual model of storage) if it turns out that the current conceptual model is not a good one. |
Reading your initial post, I wonder just how much of what you are doing needs to be specialized to "back ends". From the perspective of a mavo app that wants to access the data of the custom element, all mavo needs is that custom element to have a standard api for (i) getting the data blob from that component and (ii) giving the data blob to the component. So long as the custom element has that contract, it could be (i) something whose data is implicit, computed when queried, (ii) an interface to some smart-home hardware, (iii) a chart or other data visualization, etc. |
Please open a separate issue to brainstorm changes to the conceptual model. It is off-topic here.
"Backend" is the general term we use for any data provider. Elements like what you are describing are already a type of backend we support. If you have better ideas about what the concept could be called, feel free to suggest them (that would actually be on-topic, since we're also discussing naming of that element). |
Thinking of this a bit more, I try to imagine how the new syntax would work. Suppose we decided to go with <mv-backend
id="github"
src="https://github.com"
username="mavoweb"
repo="test"
branch="js-first-tests"
filepath="data"
filename="countries.json">
</mv-backend> Considering that custom elements must have the closing tag, we might end up with an empty element with a bunch of attributes inside its opening tag. In simple cases, it's acceptable from my perspective. However, what if we go with an alternative approach for more complex cases like the one above? (Can we have both? Can we mix them?) Since all storage attributes are the backend options, what if we re-use the existing <mv-backend id="github" src="https://github.com">
<option id="username" value="mavoweb"></option>
<option id="repo" value="test"></option>
<option id="branch" value="js-first-tests"></option>
<option id="filepath" value="data"></option>
<option id="filename" value="countries.json"></option>
</mv-backend> Or simply (If the <mv-backend id="github" src="https://github.com">
<option id="username">mavoweb</option>
<option id="repo">test</option>
<option id="branch">js-first-tests</option>
<option id="filepath">data</option>
<option id="filename">countries.json</option>
</mv-backend> Or we can follow the approach we already use when localizing UI and text in Mavo: we use the <mv-backend id="github" src="https://github.com">
<option value="username">mavoweb</option>
<option value="repo">test</option>
<option value="branch">js-first-tests</option>
<option value="filepath">data</option>
<option value="filename">countries.json</option>
</mv-backend> It would also be nice if With the proposed syntax, we might allow authors to:
<mv-backend id="github" src="https://github.com" mv-list mv-value="options">
<option mv-list-item value="[id]" mv-group>[value]</option>
</mv-backend> Where {
...
"options": [
{
"id": "username",
"value": "mavoweb"
},
{
"id": "repo",
"value": "test"
},
{
"id": "branch",
"value": "js-first-tests"
},
{
"id": "filepath",
"value": "data"
},
{
"id": "filename",
"value": "countries.json"
}
]
...
}
<option id="...:" value="[expression]">fallback/initial value</option> It will also allow the opening tag not to be polluted with many attributes but to contain only the essential (and global) ones. However, this approach might have another downside (amongst the others, I can't see yet 😅). What if we decide to provide the backend initial/fallback data as By providing initial/fallback data, I imagine something like this: <mv-backend id="github" src="https://github.com/...">
<!-- Initial (fallback) data -->
{
"country": [
{
"name": "Online"
},
{
"code": "us",
"name": "United States"
},
{
"code": "gb",
"name": "United Kingdom"
}
]
}
</mv-backend> |
Furthermore, it's unclear what benefit the additional structure provides: I proposed making backends an element because they already have their own metadata, but backend properties don't have their own metadata, they are just key-value pairs. Another reason to make something an element is to provide formatting, which you cannot do in an attribute, but that also doesn't apply here. Authors can already provide expressions for these, even if they are attributes. In terms of implementation, making the params elements currently makes the API more technically challenging to implement, since web components have And not to forget that more verbose syntax can degrade DX if the verbosity is not justified, so it needs to be a balance. |
Fair! Thank you for your explanation. 🙏 Let’s ignore my proposal, then. 😄 |
Problem
It just occurred to me that we have a bit of an API smell: we have three different attributes doing similar but slightly different things:
mv-storage
handles saving, and also loading iff there is nomv-source
mv-source
overridesmv-storage
for reading datamv-init
defines a fallback data source to load, ifmv-storage
/mv-source
is emptymv-uploads
overridesmv-storage
for uploadsBecause each of these can take metadata of its own, we also have a ton of
mv-storage-*
,mv-source-*
,mv-init-*
attributes as well. And yet, not all use cases are covered anyway, e.g.Plus there is a lot of ad-hoc-ness:
mv-autosave
currently applies tomv-storage
, but it's notmv-storage-autosave
Ideation
Decomposing
mv-storage
/mv-source
/mv-init
/mv-uploads
and the use cases above:Solution
Custom element for backends
In Madata, we introduced a
<ma-data>
component and a<madata-auth>
component. While these would probably not be appropriate to adopt as-is (unless we evolve them significantly), I do think custom elements are the way to go here: using an element per backend, and having the Mavo app reference them to declare what they’re for (the association would happen implicitly if only one backend is specified).Custom elements allow a lot of flexibility, and encapsulate a lot of complexity. For example, we could even do things like:
It may even be easier to introduce this and migrate to Madata in one go as it abstracts a lot of stuff that now lives scattered around the Mavo codebase. It also means we don't need to use an IIFE build of Madata, since we'll be using the component, which can use ESM just fine.
I’m hoping the Mavo version could simply be a subclass of a generic component, rather than a whole parallel implementation.
<mv-backend>
,<mv-data>
,<mv-storage>
src
attribute for the locationobservedAttributes
is designed to take a static array, but perhaps we could simply add all backend properties there. This will require backends declaring their settings declaratively, but that's probably a good thing anyway.Syntax for linking to backends
Possibly the most challenging part of this is what is the best way for the Mavo app to reference these.
For now, we can continue using the same set of attributes, but instead of URLs they will use ids (unsure whether to use plain ids or #-prefixed).
To keep things simple, the MVP would only support one id, but the plan is to support multiple in the future.
Migration plan
The
mv-storage
/mv-source
/mv-init
/mv-uploads
attributes would be shortcuts to this and would generate the appropriate attribute and element behind the scenes. Same withmv-storage-*
,mv-source-*
,mv-init-*
but these would also print a deprecation warning (users would be advised to use the element to specify metadata on their backends).mv-autosave
would be moved to the respective backend element. If the element was specified by the user (and not automatically generated), we should also print a deprecation warning.The text was updated successfully, but these errors were encountered: