Hello all,
With @surli we are currently working on the definition of reusable UI elements. By reusable, I mean that the UI elements are customizable enough to be applicable in other projects than XWiki. The main other project we have in mind is Cristal, but it is conceptually not the only one.
In this context, we are currently studying how to refactor the Live Data (LD) webjar to make it reusable.
I have a PoC of the extraction of the UI elements themselves. Which is relatively straightforward except for the bundling and packaging issues that are not relevant to the current discussion. What I’d like to discuss here is the extraction and generalization of the application logic. Currently, while I have extracted the UI part, the only backend to which LD can connect is XWiki (instead of arbitrary backends).
A note on how LD is working currently
There are two “API” ways to add an LD:
- a wiki macro https://extensions.xwiki.org/xwiki/bin/view/Extension/Live%20Data%20Macro/#HInWikiSyntax
- a velocity script service https://extensions.xwiki.org/xwiki/bin/view/Extension/Live%20Data%20Macro/#HUsingVelocity
Implementation-wise, the two methods share the same parameters and call the same logic that does the following steps:
- Call
jsfxto injectuicomponents/widgets/liveData.js - Generate an HTML div element with the following properties:
-
Two classes:
liveDataandloading -
Optionally an
id -
A
data-configproperty with a serialization of the resolved configuration -
A
data-config-content-trustedset totruewhen the user has enough rights to define sanitation. -
through
uicomponents/widgets/liveData.jsa jQuery initialization script is called. This script observes fordivelements with aliveDataclass and performs a complex series of actions that can be summarized to- Initialize a Vue application with a
XWikiLivedataas its root, and mount it ondiv.liveData - Inject a “logic” instance, which is the component that deals with the business logic.
- Initialize a Vue application with a
Limitations in the context of reuse
The initialization process of LD makes sense in the context of XWiki but isn’t good for reuse.
Assuming LD would be reused inside Vue applications (or inside web apps in general with web components, but that’s another discussion), all the div substitution logic must be avoided.
Instead, we need to aim for a Vue component that can simply be called with the right parameters (or props, as they call them) and then let the library do its usual job.
Discussions
Do we consider the XWikiLivedata component API?
As explained earlier, the two main entry points to add an LD for XWiki developers are currently a wiki macro and a velocity script service.
The XWikiLivedata component itself is currently never publicly exposed and cannot be imported outside the LD webjars.
Therefore, I’d like to confirm that this component is not considered an API and that we can freely change its API to make it more (re)usable.
Note that at the end of this refactoring, XWikiLivedata would become API (and unstable of course).
Do we want to make the logic resolution internal or external?
In the case of an internal resolution, no specific logic is passed when the component is declared.
It’s the job of the component to look up the relevant component based on its context (e.g., an “XWiki” logic in the case of XWiki).
We could imagine having a global configuration for the default logic to look for and an optional component parameter to override it.
In the case of an external resolution, the caller of the LD component is responsible for resolving the logic and for passing the resolved object when declaring the component. The LD component is then only dependent on the LD logic API and does not have to perform lookup.
I tend to prefer the internal resolution logic as it allows for a simpler component encapsulation.
PS: I’ll make a separate proposal for how client side inversion of control can help.
Do we want to declare an abstract API already
The end goal of the LD extraction is to have a backend-agnostic API allowing the declaration of connectors to arbitrary backends by extension.
We could, for instance, have a LiveDataLogic (to keep the existing terminology) “role” and implementations like XWikiLiveDataLogic or FileSystemLiveDataLogic.
But, since we currently have domain knowledge of XWikiLiveDataLogic only, there is a risk of defining LiveDataLogic by relying overly on XWiki, with the risk of having to introduce breaking changes when applying it for another domain.
So I can think of two strategies.
Option 1: Extract the API
Declare an API early and accept the risk and declare the API now. Since we are early in the 18 cycle, the API will be left to be considered stable at the start of the 20 cycle which leaves us almost 2 years.
Option 2: Do not extract an API
Only have an XWiki specific logic (which is basically moving the current logic to its own package), and wait for the need to connect to another connector before extracting a generic API.
This goes well with the internal resolution discussed above since the API would leak in the LD component interface.
I tend to prefer option 2 as it allows us to break the extraction into smaller steps and leaves us a bit of time before exposing APIs.