decaporg / decap-cms

A Git-based CMS for Static Site Generators
https://decapcms.org
MIT License
17.83k stars 3.04k forks source link

Allow reusable field group definitions in config file #1342

Open erquhart opened 6 years ago

erquhart commented 6 years ago

- Do you want to request a feature or report a bug?

feature

- What is the current behavior?

Reuse of configuration data, such as a group of fields being defined once and used in multiple collections, is dependent on YAML features. These features are difficult to understand and use, and aren't available in simpler formats like JSON.

- What is the expected behavior?

Netlify CMS should provide means for defining reusable configuration subsets, like field groups, that are easy to understand and use, and format independent.

This is based on the conversation in https://github.com/netlify/netlify-cms/issues/1186#issuecomment-382003132.

erquhart commented 6 years ago

We should first determine if this is even a good idea at all. Can anyone think of reasons not to do this?

zipang commented 6 years ago

Hi @erquhart ! I'm currently trying to use Netlify CMS to edit my personal web site and i really like what you're trying to do as an open source project 👏 😃 , but i'm a bit stucked right now with some important features missing..

However, i was going to post that exact suggestion to start with, when i noticed your post.

Defining groups of fields is exactly what i needed because duplicating the same information in different sections is boring and error prone.

Here is what i was longing for (a new section in config.yaml) :

fieldsets:
  - name: "link"
    label: "Link"
    fields:
      - {label: "URL", name: "url", widget: "string"}
      - {label: "Text", name: "text", widget: "string"}
  - name: "button"
    label: "Button"
    fields:
      - {include: "link"}
      - {label: "Type", name: "type", widget: "select", options: ["primary", "info", "success"]}
  - name: "section_background"
    label: "Section Background"
    fields: # The fields for each document, usually in front matter
      - {label: "Background style", name: "bg_class", widget: "select", required: true, default: "white", options: [{label: "Background image (parallax)", value: "parallax-bg"}, {label: "Background image (fixed)", value: "fixed-bg"}, {label: "Grey background", value: "grey"}, {label: "White background", value: "white"}, {label: "Gradient 1", value: "gradient1"}, {label: "Gradient 2", value: "gradient2"}]}
      - {label: "Background Image", name: "bg_image", widget: "image"}
      - {label: "Photographer", name: "photographer", widget: "string"}
      - {label: "Overlay color", name: "overlay", widget: "color"}
  - name: "hero_section"
    label: "Hero section"
    fields:
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Headline", name: "headline", widget: "text"}
      - {include: "section_background"}
  - name: "call_to_action_section"
    label: "Call to action section"
    fields:
      - {include: ["hero_section", "button"]}

Notice how these fieldsets allow for easy composition between them and allow to follow the rules of atomic design. It's interesting to note also that defining such a fieldset automatically defines a default widget for that group of fields, and that it could allow to declutter the interface by simply replacing the group of fields with a button : "Add link" or "Add Call to Action" when they are empty, and by the rendered widget when these fields have values.

erquhart commented 6 years ago

Yep, this looks like a great approach. I was just noticing today that Contentful does just that - everything in the content model is defined as "Content Types", which are named groups of fields.

@tech4him1 @Benaiah @talves thoughts?

andreasvirkus commented 6 years ago

Would love to see support for this! Our use-case would be once-defined string translations that we can then set under every locale collection.

Any way I could contribute?

erquhart commented 5 years ago

@andreasvirkus sure, a proof-of-concept PR would get the ball rolling.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

chriswthomson commented 4 years ago

This seems like a must have to me. For example, I should be able to define two objects - social (title, description, image) and seo (title, description) to use on all pages, and only have to define them once, instead of defining them for each collection type. Having to define them over and over again seems redundant.

erquhart commented 4 years ago

@chriswthomson this ticket is a nice-to-have for the most part. You can already reuse blocks of yaml (source), and you can write your config in js (source).

Sent with GitHawk

chriswthomson commented 4 years ago

@erquhart - OK thanks!

stephlocke commented 4 years ago

To get aliases working I ended up doing it like this:

aliases:
  - &TITLE {label: 'Title', name: 'title', widget: 'string' }

publish_mode: editorial_workflow
collections:
  - name: 'products'
    label: 'Products'
    folder: 'content/english/products'
    create: true
    fields:
      - << : *TITLE
dafrie commented 4 years ago

And just in case you want to alias a list of keys:

project: &PROJECT
  - { name: title, widget: string }
  - { name: description, widget: string }

collections:
  - name: public
     ... 
     fields: *PROJECT
   - name: private
     ....
     fields: *PROJECT 
duanecilliers commented 4 years ago

Another approach is to use manual initialization. Then you can do something like this.

const titleField = { name: 'title', widget: 'string' }

const projectFields = [
  { ...titleField },
  { name: 'description', widget: 'string' }
]

init({
  config: {
    load_config_file: false,
    collections: [
      {
        name: 'public',
        ...
        fields: [...projectFields]
      },
      {
        name: 'private',
        ...
        fields: [...projectFields]
      }
  }
})
sparkalow commented 3 years ago

Collection summaries do not currently work when using beta manual initialization feature.

flikteoh commented 3 years ago

And just in case you want to alias a list of keys:

project: &PROJECT
  - { name: title, widget: string }
  - { name: description, widget: string }

collections:
  - name: public
     ... 
     fields: *PROJECT
   - name: private
     ....
     fields: *PROJECT 

@dafrie How can we add more keys under the alias?

For example:


project: &PROJECT
   - { name: title, widget: string }
   - { name: description, widget: string }

 collections:
   - name: public
      ... 
      fields: *PROJECT
        - { name: type, widget: hidden, default: page }

Doesn't seem to work.

mosesoak commented 3 years ago

@erquhart For us this feature would improve the "page building" power of variable-type lists. For example, in defining a list of 'atoms' like,

Followed by composed 'molecules' like,

I'm currently looking into whether we can use aliases to accomplish this for now but like seeing that your team is considering a more official feature.

Food for thought:

A different approach (that might touch on the "why not to do this" front) would be to leave the config spec alone and leverage the existing relation feature. I'll explain:

Atomic models can already live at the top level, then be linked by relation into object and variable-type list widgets to compose more complex models. This is actually more like how Contentful does it: when you set up a variable-type list model you can use checkboxes to choose which models are linkable, then when entering data you use a UI similar to Netlify CMS's relation feature where you pick which one you want from a select. The main difference is a "Create new item" option at the top of the dropdown with a circular UX flow that jumps you out of the current page into the component model page, lets you save that and then return to your preserved in-progress page edit.

That flow might be a pretty big UI lift for your team, but would be a way to avoid adding the complexity of field-set lookups in the config file. Devs can just make a variable-type list with relation entries, which surfaces the dropdown of existing entries and could be extended with a new property like create: true. It's also a solid "page builder" UX model proven out for years by Contentful. True, you end up with many more top-level models, but your UI is already built to handle that, so really it's just a way to quickly create new sub-models and keep working in the surrounding context such as a page. I think it's good in that it reinforces content composition which adds flexibility for editors, vs. a more-complex config model aimed only at devs.

Again, I still like the field group idea but wanted to point out how your current UI and powerful variable-type lists and relation features mean you're just one "Create new item" UI feature away from supporting this in your current version! 🌞