Skip to content
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

Feature: edit data files with a list/array at root level #531

Open
rriemann opened this issue Aug 16, 2017 · 24 comments
Open

Feature: edit data files with a list/array at root level #531

rriemann opened this issue Aug 16, 2017 · 24 comments

Comments

@rriemann
Copy link
Contributor

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

Feature

- What is the current behavior?

it seems to be impossible to create data files with a list at root level:

- nav_object_1
- nav_object_2

The current work-around is to use

navigation:
  - nav_object_1
  - nav_object_2

However, this may require a change of the template that may be part of libraries (jekyll theme gems).

- What is the expected behavior?

I can just create lists also on root level.

@erquhart
Copy link
Contributor

erquhart commented Aug 17, 2017

Thanks for opening this - it's definitely something folks have needed.

I think the most straightforward approach would be to accept a boolean root config value on the list widget (this doesn't make much sense for any other widget type). If root is true, the resulting data is a list rather than an object. We would need validation to ensure that no other fields are defined if a "root" field is provided, and we would need to start handling frontmatter and data that are lists and not just objects as we do currently.

This probably conflicts with #468 as well, where I believe we're outmoding the list widget in favor of a "repeatable" flag for all fields, in which case any "repeatable" field could have a "root" field (but still only one field defined if there's a root).

Would you be up for taking a swing at this?

@rriemann
Copy link
Contributor Author

Would you be up for taking a swing at this?

Unfortunately I'm super busy with university. :(

@erquhart
Copy link
Contributor

No problem! I'm sure someone will take it on.

@r1b
Copy link

r1b commented Sep 22, 2017

I would be happy to implement this - currently it is not possible to use gatsby-transformer-yaml with netlify since the transformer only supports lists.

Any pointers on where to look in the code to get started? I'm pretty new to netlify.

@r1b
Copy link

r1b commented Sep 28, 2017

I have solved this on the gatsby side with a custom yaml transformer. I would still like to support it here for maximum flexibility :)

@erquhart
Copy link
Contributor

erquhart commented Feb 5, 2019

Forget the boolean thing I said before, we should apply the field/fields approach from the list widget to the collection config.

fields vs. field

Here's the list widget using fields:

# list field config using `fields`
- name: my-list
  label: My List
  widget: list
  fields: [{ name: title, label: title, widget: string }]

# output:
# list: [{ title: 'a title' }, { title: 'another title' }]

Here's the same widget config using field:

# list field config using `field`
- name: my-list
  label: My List
  widget: list
  field: [{ name: title, label: title, widget: string }]

# output
# list: ['a title', 'another title']

field on collections

Note: this is a proposal, doesn't actually work!

- name: posts
  label: Posts
  file: data/list.json # this only makes sense for file collections
  field: [{ name: name, label: Name, widget: string }]

# output
['item', 'another item']

The UI and certain config options (like allowAdd) from the list widget would be reused for at the collection level for this.

I can't think of any downsides or issues with this approach, personally. Thoughts?

@erquhart erquhart closed this as completed Feb 5, 2019
@erquhart erquhart reopened this Feb 5, 2019
@kripod
Copy link

kripod commented May 2, 2019

Are there any updates regarding the proposals mentioned above? This is a deal-breaker for Gatsby users, please see #1282.

@talves
Copy link
Collaborator

talves commented May 2, 2019

@kripod I believe this is a feature the CMS should support, Until then, it is NOT a deal-breaker for Gatsby users when it is still able to map to a structure the CMS does support at the moment.

@stale
Copy link

stale bot commented Oct 29, 2019

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.

@erquhart
Copy link
Contributor

erquhart commented Nov 4, 2019

This is still happening.

@stale stale bot removed the status: stale label Nov 4, 2019
@erquhart erquhart added the pinned label Nov 4, 2019
@erquhart erquhart changed the title Feature: edit data files with a list at root level Feature: edit data files with a list/array at root level Nov 8, 2019
@bharrisau
Copy link
Contributor

I've just patched this locally in netlify-cms-core/src/backend.ts functions entryToRaw and entryWithFormat. Around the calls to either format.toFile or format.fromFile I'm just doing a wrap/unwrap with a special key rootArray.

  entryWithFormat(collectionOrEntity: unknown) {
    return (entry: EntryValue): EntryValue => {
      const format = resolveFormat(collectionOrEntity, entry);
      if (entry && entry.raw !== undefined) {
        let data = (format && attempt(format.fromFile.bind(format, entry.raw))) || {};
        let data = Array.isArray(data) ? { rootArray: data } : data; //Added wrapper for root arrays
        if (isError(data)) console.error(data);
        return Object.assign(entry, { data: isError(data) ? {} : data });
      }
      let data = format.fromFile(entry);
      return Array.isArray(data) ? { rootArray: data } : data; //Added wrapper for root arrays
    };
  }

  entryToRaw(collection: Collection, entry: EntryMap): string {
    const format = resolveFormat(collection, entry.toJS());
    const fieldsOrder = this.fieldsOrder(collection, entry);
    let data = entry.get('data').toJS();
    let data = data.rootArray || data; // Unwrap root array (this should probably check the fields.length == 1 too)
    return format && format.toFile(data, fieldsOrder);
  }

Not as clever as the approach mentioned above - but if you think of it as normalising files to always be a map instead of sometimes passing arrays around then it feels a bit less hacky.

@cyonder
Copy link

cyonder commented May 6, 2020

No fix on this since 2017? )=

@erezrokah
Copy link
Contributor

Hi @cyonder, we try to get to the most up voted features first. You can see the sorted list here https://github.com/netlify/netlify-cms/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc.
Regardless, we would love a contribution for this.

@reimertz
Copy link

I just tried to see if I could get the ball rolling on this issue.

  1. Parse the single entry file to get array of content
  2. Based on that content, generate new "real" entries
  3. Populate the collection with previously generated entries

Doing edits / adding new content would be similar to above but in reversed order.

But the assumptions of content being in separate files made it very complicated straight away but maybe my idea was overly complicated?

Would love to get some help / discussion with main contributors to the project. <3

@erezrokah
Copy link
Contributor

Hi @reimertz, thanks for pushing this forward.
What do you think about putting a draft PR for it? We can use it for the discussion.

Another option is our #contributing channel on Slack https://www.netlifycms.org/chat.

@vnourdin
Copy link
Contributor

Hi everyone, any update on this ?
This seems blocking for Eleventy global data files too, if anyone has a workaround for this I'm interested 😅

@erezrokah
Copy link
Contributor

Hi @vnourdin this would make a great contribution to the CMS if anyone would like to pick it up

@ManUtopiK
Copy link

Just to said this is also an issue for @nuxt/content with array at the root level of a json. Like here.

@hayden2114
Copy link

+1 would love to see support for .json files with array at root level to mimic a MongoDB collection

@astrawnuts
Copy link

would love to see support for this

@izanagi1995
Copy link

Still needed :)

@TheReyzer
Copy link

NEEEEED

@CKLFish
Copy link

CKLFish commented Feb 24, 2023

Need it....

@reteps
Copy link

reteps commented Oct 22, 2024

Here is a workaround:

            CMS.registerCustomFormat('flat-json', 'json', {
                fromFile: text => {
                    const body = JSON.parse(text) as Record<string, Record<string, string>>;
                    // Now we want to transform this object into a flat object with a 'key' field
                    const value = { items: Object.entries(body).reduce((acc, [key, value] : [
                        string,
                        Record<string, string>
                    ]) => {
                        acc.push({ key, ...value });
                        return acc;
                    }, [] as Record<string, string>[]) };
                    return value;
                },
                toFile: (value : { items: Record<string, string>[] }) => {
                    const body = value.items.reduce((acc, { key, ...rest }) => {
                        acc[key] = rest;
                        return acc;
                    }, {} as Record<string, Record<string, string>>);
                    return JSON.stringify(body, null, 2);
                }
            });
  - name: 'redirects-collection'
   label: 'Redirects'
   format: 'flat-json'
   files:
   - label: 'All Redirects'
     file: 'sigpwny.com/src/redirects.json'
     name: 'redirects'
     fields:
       - {label: 'Links', name: 'items', widget: 'list', fields: [
           # must be named 'key' for our custom formatter to work
           {label: 'From', name: 'key', widget: 'string', hint: 'Example: "/qrcode"'},
           {label: 'To', name: 'destination', widget: 'string', hint: 'Example: "myurl.com/foo"'},
           {label: 'Status Code', name: 'status', widget: 'hidden', default: 302}
         ]}

If you have a folder collection, you need a title field, and then your fromFile should add one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests