blindnet-io / product-management

Repository dedicated for reporting bugs, ideas for improvements, and new features
6 stars 0 forks source link

Configuration for web components #871

Open jboileau99 opened 2 years ago

jboileau99 commented 2 years ago

From working on our web components so far and looking at use cases + stories, it has become clear that each component will have to support several configuration possibilities. For example, the PRCI should allow the client using it on their website to:

I don't believe it's reasonable to pass this many config options through attributes to the component, e.g. <privacy-request-capture-interface allowed-actions="..." auth-options="..." prefilled-demands="..."/>, where attribute is a json string, which can be quite long.

One alternative I thought of was instead we have a single "config" attribute for each component which accepts a filepath to some config.json file that contains a set of options for the component. So for example the the PRCI would be created as <privacy-request-capture-interface config="some/file/path/prci-config.json"/>. The config file would look something like this (but larger):

{
  "allowed-actions": "",
  "action-authentication": {
    "ACCESS": "pre",
    "DELETE": "post",
    "MODIFY": "post"
    ...
  },
  "prefilled-demands": [
    {
      "action": "ACCESS",
      "selected-options": "..."
    }
  ],
  "logo-fp": "my-logo.jpg"
}

@blindnet-io/engineering What do you guys think?

m4rk055 commented 2 years ago

Handling files on the client-side JS is tricky. You can have the configuration object defined in memory an pass it to the component.

jboileau99 commented 2 years ago

@m4rk055 Ok, just pass a json string of the config object to the component, that should work

nweldev commented 2 years ago

+1 on the trickiness of JSON files. @jboileau99, you are right on your last comment about one thing: JSON :arrow_right: JS object literal. It is, indeed, just that: a specific format to record a "plain old" javascript object (to reuse the Java vocabulary), also called an object initialiser.

As this expression indicates, object literals can often be used to "hydrate" a complex object.[^1]

This might indeed be a useful addition to improve the DevX in some cases, as a "hydrate" method or setter (myPrivReqEl.configuration = { ... } here for example) can allow writing a long and complex series of setters for each part of the "configuration".

However, we should always remember Web Components are expected to be used in a declarative way (HTML) more than imperative (JS), for a lot of reasons (ease of use, readability, easy parsing, etc.).

Any custom element's attribute should always be associated with a property/getter/setter[^2] on the associated HTMLElement JS object (like for any standard HTML element) to ensure it works in any programming context.

And it works both ways: we should avoid as much as possible to add properties/getters/setters to a custom element without associating them with a corresponding HTML attribute, except if:

  1. we can be sure it will only be useful in JS
  2. there are alternatives ways to reach the same goal using other HTML arguments

Now, I think it's clear why "pass a json string of the config object to the component", might, from my point of view, be a bad idea. IMHO, it goes against the HTML declarative approach and doesn't provide a very good DevX (in my mind, it screams "this web component is a nightmare to configure, abort, abort" :rofl:).

So instead, I believe we could follow the following approach:

  1. break done the whole required information with a declarative approach in mind (leading to a set of independent, intelligible and unambiguous parameters)
    • I personally like to draw several trees or Venn diagrams to help me better see the possible overlaps, and incrementally improve the API, but this is just me :wink:
  2. make sure each parameter is really appropriate for the front-end side (as it may also be best suited for the Privacy Computation Customization API or even the storage parts)
  3. see if each parameter should be part of the "core" PRCI element, or an additional one (slots can sometimes help, following the idea of "high order components")
  4. find the optimal default value for each parameter (following the convention over configuration paradigm)
  5. As attributes can only be strings, see how complex ones (e.g. action-authentication) should be written.
    • I personally tend to prefer a "style-like" syntax for this and think JS object literals should be avoided in HTML, but I'd still need to give this more thought. I'd love to see your ideas on this.
  6. IF we want to offer a "hydrate" option, we can either:
    1. associate attributes with a computed "configuration" state object that can be get and set in JS
    2. OR provide a "configuration"/"hydration" method which sets each property internally
      • I believe this might be a simpler approach, with a more heavy cost on the JS than the HTML side, but we'd need to investigate this further.

We should also keep in mind that we'll soon provide new approaches and features (other web components, "simple" JS libraries/helpers, Angular/Lit/React/Vue... overlayers, etc.) which could lead us to new ideas but also constraints. For example, several components might need the same parameters (which we'll try to avoid duplicating as much as possible), and a micro-library could rely on a simple JS constructor.

[^1]: Here, I'm using the term "hydrate" in its more generic sense (i.e. to fill an already instantiated object with all the data it needs using a single setter or method), not the more recent sense we see when talking about SSR (see "hydration" on Wikipedia and the really interesting but still experimental @lit-lab/srr package).

[^2]: Here again, the terminology can be a bit confusing when using Lit, as both JS properties and HTML attributes are configured using the same properties getter or @property decorator ... precisely because of such custom element best practices. Lit's documentation still makes a clear distinction between them: « Lit components receive input and store their state as JavaScript class fields or properties. Reactive properties are properties that can trigger the reactive update cycle when changed, re-rendering the component, and optionally be read or written to attributes. » And as always, understanding how this would be done without Lit helps to understand this. MDN made a great doc for that.

jboileau99 commented 2 years ago

@noelmace Thanks for the detailed explanation, this gave me a lot to think about.

Outside of providing the option to set custom prefilled demands, the parameters we want to provide aren't actually so complex. I was thinking the following to start with:

PRCI

Properties

Regarding auth-before and auth-after, I'm still working out how the authentication implementation in the PRCI will work. It will be more clear once we discuss it further here. For now, auth in either case will happen outside of the PRCI so we don't need these parameters

CSS Variables

The following CSS variables (with defaults) will be available:

var(--prci-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
      Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif)
var(--prci-font-color, #000000);

var(--prci-border-light-color, #c4c4c4)
var(--prci-border-medium-color, #5b5b5b)
var(--prci-border-dark-color, #000000)

var(--prci-border-thin, 1px)
var(--prci-border-thick, 2px)

I didn't include a background color variable because the component is currently transparent by default and if developers want, they can set a background-color style on the component. But perhaps it's a better devX to have it as a variable like the others?

Let me know if anyone thinks we should provide some other variables (component properties/attributes or CSS).

nweldev commented 2 years ago

@jboileau99 I'll soon get back to you on this as I need to improve the documentation on blindnet.dev and will do an extensive review doing so

jboileau99 commented 2 years ago

@noelmace Great. For when you do look at this and the PRCI stories, I've added a data-categories parameter and story and made sure the others (custom actions and locale) are working properly.