nuvoleweb / ui_patterns

[NOTE] Development has moved to https://drupal.org/project/ui_patterns
https://drupal.org/project/ui_patterns
GNU General Public License v2.0
85 stars 56 forks source link

Advanced field type schema #306

Open donquixote opened 4 years ago

donquixote commented 4 years ago

Quick summary

Define how a structured field type can be defined in a *.ui_patterns.yml file, so that other modules can use this information.

Background

When defining a pattern in a *.ui_patterns.yml file, there is an entry 'fields', where in each field there is an entry 'type'.

In the docs, the following is said about 'type':

Field type, can be text, numeric, etc. at the moment only used for documentation purposes. Optional.

This means currently the value does not have any effect.

There is no clear definition how a field type should be described.

There is no way to describe "structured" types, e.g. "array of items, where each item has the following fields". Some patterns I have seen use value objects, but I don't think there is an agreed-upon format to describe this in the yml file.

Problems

Developers don't know what to put in the type definition in a *.ui_patterns.yml file.

Consuming modules cannot reliably use the information, because it could be anything. E.g. a module that renders a list of items (e.g. field items) cannot filter the available patterns to only show those which have a "list" field.

Modules with dynamic data mapping, if a user chose the wrong pattern, send data to a pattern field that expects a different data format. This can cause errors or misbehavior. E.g. a render element is sent to a pattern that expects a list of items, and then it would attempt to render the properties...

Desired behavior

A well-defined format to describe structured fields in pattern definitions.

Then other modules can pick this up and send make sure that the data sent to the pattern has the correct format.

Examples:

Proposed change

Field type format

A well-defined format to describe structured fields.

Possible formats:

Built-in plugins

Change the DsFieldTemplate plugin to only accept list-like patterns.

Create a views style plugin that uses list-like ui patterns.

nedjo commented 4 years ago

The Component Schema project is an option here; see #296. It's based on core's configuration schema API, itself modeled on Kwalify. I've just updated #296 with further details on how Component Schema works.

If there's interest I'd be happy to contribute to integrating Component Schema and UI Patterns.

donquixote commented 4 years ago

@nedjo Interesting!

I am looking at the schema here: https://git.drupalcode.org/project/bulma_components/-/blob/1.0.x/components/columns/columns.variables.yml

One thing I notice is that fields/variables that expect html or render element are just marked as "string". I would prefer if there was a dedicated type for html. Or perhaps even more, to distinguish different types of strings:

Another question would be if or how patterns and components could be used together, or if one should be seen as a replacement of the other.

nedjo commented 4 years ago

Or perhaps even more, to distinguish different types of strings:

Yes. So far, the custom schema types are mainly focused on the task of processing values to reduce the need for logic at the template level. For example, there's a component_string type that supports three keys beyond the standard set for schema variables:

It's relatively easy to extend the existing schema types as needed, either directly in Component Schema or in another module. They work just like core's configuration API schemas.

Another question would be if or how patterns and components could be used together, or if one should be seen as a replacement of the other.

I think that we could use just the variables schema directly in UI Patterns. That is, define the variables as fields in UI Patterns. This wouldn't create a dependency on the components as defined by Component Schema but would just reuse the schema definition. To get access to the processing done by Component Schema's process_component() Twig extension we'd have to do some integration since currently that method requires a component type. One potential approach would be to alter the component type definitions to define a component type per UI pattern (if one doesn't already exist).

That might open two potential paths:

  1. Define UI patterns. After this proposed refactoring, pattern fields use the component schema definitions.
  2. Define components per Component Schema. Then write an integration module that includes a UiPatterns/Pattern plugin type that uses a deriver to add a UI Pattern per component, parallel to what's done for example with layouts in https://www.drupal.org/project/ui_patterns_from_layouts.
donquixote commented 4 years ago

Thanks @nedjo !

It's relatively easy to extend the existing schema types as needed, either directly in Component Schema or in another module. They work just like core's configuration API schemas.

Ok, seems like something we could figure out and improve over time.

Another question would be if or how patterns and components could be used together, or if one should be seen as a replacement of the other.

I could be mistaken, but I think one difference is that every ui pattern is registered as a theme hook, whereas components are just templates. So it might be a good idea to only declare ui patterns that actually need to be ui patterns, and leave the rest as pure components, so not to pollute the theme registry. I am not sure about the exact performance or memory impact.

Another difference is that ui_patterns are exposed to the site-building UI, e.g. as ds field templates or as views plugins. (This is not ideal, and I think one limitation is the unspecific field types.) On the other hand, components are not exposed in the UI anywhere, or are they?

That might open two potential paths:

Going to make sure I understand correctly..

Define UI patterns. After this proposed refactoring, pattern fields use the component schema definitions.

So a front-end developer would create a ui pattern with a *.ui_patterns.yml file, but the 'fields' part would use the schema from components. No actual "components!" would be defined. To mitigate backwards compatibility problems, perhaps we could introduce a new key "variables" as an alternative to "fields", which would use the advanced schema.

Currently the "fields" keys also contain "preview" values. I wonder if the component variables schema also supports this, or if we would need to find a different solution for this. The "preview" feature is limited anyway, because it allows only one set of values per pattern. Perhaps instead we should have separate yml files with different preview scenarios.

Define components per Component Schema. Then write an integration module that includes a UiPatterns/Pattern plugin type that uses a deriver to add a UI Pattern per component, parallel to what's done for example with layouts in https://www.drupal.org/project/ui_patterns_from_layouts.

(I would call this an "adapter layer") So the front-end developer would create "components!", which would then be implicitly registered as UI patterns? Does a component have all the info we need for a UI pattern? Is it wise to register all components as UI patterns, or should we only do it for some of them?

donquixote commented 4 years ago

I am interested in this for multiple reasons:

donquixote commented 4 years ago

If there's interest I'd be happy to contribute to integrating Component Schema and UI Patterns.

So I would clearly be interested :) But the first step should be to define the desired behavior and how this would be used.

nedjo commented 4 years ago

it might be a good idea to only declare ui patterns that actually need to be ui patterns, and leave the rest as pure components, so not to pollute the theme registry

I suspect you're right.

components are not exposed in the UI anywhere

Correct. Before starting work I evaluated UI Patterns as a potential base but wasn't able to work with its limited fields definition. I've deliberately left that out so Component Schema could be focused just on schema functionality and be complimentary to UI Patterns (or other similar efforts).

perhaps we could introduce a new key "variables" as an alternative to "fields", which would use the advanced schema.

That sounds doable. It might open the option of doing integration in a separate module project rather than directly in ui_patterns.

Currently the "fields" keys also contain "preview" values. I wonder if the component variables schema also supports this, or if we would need to find a different solution for this.

There isn't currently a preview. There is something partially analogous: the styleguide integration, which allows defining a template to be displayed in a styleguide.

So the front-end developer would create "components!", which would then be implicitly registered as UI patterns?

Yes.

Does a component have all the info we need for a UI pattern?

Probably not, at least not without further development. A main issue is the relative complexity of variables in Component Schema vs. the single-level list of fields currently supported in UI Patterns. Like the configuration schema API they're based on, Component Schema variables can be nested through mappings and sequences. This means:

  1. Converting the schema programmatically into form elements is non-trivial.
  2. It's also non-trivial to decide how a particular (often, flat) element like an entity view mode maps to component variables.

Also, some of the Component Schema variables aren't necessarily intended to map to incoming data like entity fields but instead are more like settings. This gets into territory partially mapped out in the UI Patterns Settings module.

Also, I haven't yet looked at registering libraries per component. One option would be to follow exactly the model used in UI Patterns, so that part at least would be directly parallel in the two data structures (component, UI pattern).

Is it wise to register all components as UI patterns, or should we only do it for some of them?

Probably only some. That might be as simple as adding a boolean key to the component definition such as provide_ui_pattern or similar. There's already integration for the styleguide module so adding integration for ui_patterns would be in keeping.

nedjo commented 4 years ago

Converting the schema programmatically into form elements is non-trivial.

These couple of Drupal core issues (both long since stalled out) are related:

donquixote commented 4 years ago

Converting the schema programmatically into form elements is non-trivial.

I imagine something different: Instead of producing a form for an arbitrary pattern, we would filter patterns that match a given schema requirement. E.g.

The field names / keys can be arbitrary, there would be some adapter logic to map fields. E.g. it could be "title" in the pattern, but "label" in the subsystem that wants to use the pattern.

If I were to plan this from scratch, perhaps I would instead start with these common types, and then the patterns should follow that: E.g. "labeled elements", "labeled element", "list"..

A pattern that goes beyond these basic types should probably be split up..

Also, some of the Component Schema variables aren't necessarily intended to map to incoming data like entity fields but instead are more like settings. This gets into territory partially mapped out in the UI Patterns Settings module.

I think it can be useful to distinguish "data input" vs "settings" when defining the schema. Although in some cases the ambiguity could in fact be useful, so that the same variable could be fed from data or from settings.

nedjo commented 4 years ago

I imagine something different: Instead of producing a form for an arbitrary pattern, we would filter patterns that match a given schema requirement.

Wow, I like this idea.

The most straightforward way to integrate may be to start in Component Schema. I've opened an issue there and tried to sketch in some potential steps: [meta] Integrate with UI Patterns module. I probably haven't quite captured everything you were suggesting. Please wade in and clarify.

I would prefer if there was a dedicated type for html.

At least tangentially related: I've been mulling over how to handle the need that comes up in multiple components for a flexible container for content. I opened a related issue on Component Schema: Provide a standard way of handling arbitrary content.

donquixote commented 4 years ago

At least tangentially related: I've been mulling over how to handle the need that comes up in multiple components for a flexible container for content.

I already commented in the linked issue. A "container for content" should be the simplest thing ever: A component that receives a single variable with type = html. Where this html is coming from should not be the responsibility of the component, but of the calling template or some adapter layer that can handle render elements.

nedjo commented 3 years ago

Basic integration of Component Schema and UI Patterns is largely complete, see [meta] Integrate with UI Patterns module. While that doesn't in itself accomplish everything discussed in this issue, it does open up new possibilities.

OProf77 commented 3 years ago

I don't know if this is the place to ask. I don't know how to check the contents of a variable in my pattern file.

I think that's the discussion, right?