-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Modular Content Widget #1169
Modular Content Widget #1169
Conversation
Deploy preview for netlify-cms-www ready! Built with commit 3abf66a |
Deploy preview for cms-demo ready! Built with commit 3abf66a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anthonysapp this is awesome work, does just what it says on the tin! This will be extremely useful for a lot of folks.
I have a rather large change request for you: we should refactor this to be a feature on the existing List widget.
Consider that the list widget is already doing exactly what this does, except you can only define one "type". If a types
field is present, we should use that instead of fields
and convert the add
button to a dropdown. Beyond that, the functionality we need is already there in the List widget.
Let me know if any of that doesn't make sense or if you have questions. Excited to see this get in!
@erquhart l will have a look tonight or tomorrow morning, for sure. |
@erquhart What's the use case for your suggestion? Other widgets wrap the |
@Benaiah I think maybe because it is a bit of code duplication? My widget is pretty close to the list widget and can probably be merged pretty easily. |
@erquhart I had a crack at this this morning. I think I've merged all the functionality in the appropriate places. Updated including moving documentation to the list component. The only area I'm not sure if I could make a little cleaner is my modification to the ObjectPreview class. |
@Benaiah I don't think use case and architecture map to one another - the use case is a website that needs flexible content authoring either way. I'm not saying combining this into one widget is the best way to do it, but that it might be the best way to do it at the moment for our codebase. I'm not aware of any widget wrapping the list widget, and I don't believe it's currently possible to do so cleanly. That said, I was thinking that this PR only allowed named field groups to be selected, but it's actually allowing individual fields to be selected by name, which is a big difference, and a noteworthy divergence from the List widget's general role of providing repeatable groups. |
@erquhart I think this is why I decided against merging it into the List widget in the first place. Nevertheless it was a lot of code duplication so I think your reasoning had merit as well. In any case I merged into List and have all the functionality back as of the latest commit to the PR. |
@anthonysapp to help simplify the review, could you do the following?
Let me know if you have questions on that last one. |
@erquhart Not sure I have any changes that only apply to code style? And yeah a pointer on that last one would help for sure. Thanks! |
Ooh, I am very much looking forward to this. I'm pretty sure I'll be able to use it to use Netlify CMS to edit the config.yml file, specifically to make it possible to add new collections via UI. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just blocking to make sure we don't merge with the dist
or package.json
changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a review pointing out the code style changes and a few other things.
Code style changes are changes that only impact how the code looks rather than what it does, like breaking one long line of code down into a few more readable lines. These changes are helpful, but their presence increases the overall risk associated with merging the PR, since the code style changes themselves can break things. Code style changes should be presented in a separate pull request.
package.json
Outdated
@@ -1,6 +1,6 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All changes to this file should be removed.
<div {...props} className={`list-item ${ props.className || '' }`}> | ||
{props.children} | ||
</div> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style change.
const SortableList = SortableContainer(({ items, renderItem }) => { | ||
return <div>{items.map(renderItem)}</div>; | ||
}); | ||
const SortableList = SortableContainer(({ items, renderItem }) => <div>{items.map(renderItem)}</div>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style change.
const listValue = e.target.value | ||
.split(',') | ||
.map(el => el.trim()) | ||
.filter(el => el); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style change.
this.setState({ value: valueToString(listValue) }); | ||
this.props.setInactiveStyle(); | ||
}; | ||
|
||
handleAdd = (e) => { | ||
e.preventDefault(); | ||
const { value, onChange } = this.props; | ||
const parsedValue = (this.valueType === valueTypes.SINGLE) ? null : Map(); | ||
const parsedValue = this.valueType === valueTypes.SINGLE ? null : Map(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is a code style change.
PropTypes.object, | ||
PropTypes.bool, | ||
]), | ||
value: PropTypes.oneOfType([PropTypes.node, PropTypes.object, PropTypes.bool]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style change.
@@ -90,19 +84,27 @@ export default class ObjectControl extends Component { | |||
|
|||
handleCollapseToggle = () => { | |||
this.setState({ collapsed: !this.state.collapsed }); | |||
} | |||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style change.
{ forList ? null : <TopBar collapsed={collapsed} onCollapseToggle={this.handleCollapseToggle} /> } | ||
{ collapsed ? null : multiFields.map((f, idx) => this.controlFor(f, idx)) } | ||
{forList ? null : <TopBar collapsed={collapsed} onCollapseToggle={this.handleCollapseToggle} />} | ||
{collapsed ? null : multiFields.map((f, idx) => this.controlFor(f, idx))} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style change.
let result = value.get('___name') || value.get(value.get('name')); | ||
let valuePreview = null; | ||
|
||
switch (widget) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This switch statement ties this widget to the widgets below in an undesirable way - the object widget shouldn't know about these other widgets.
@@ -8,14 +8,19 @@ type: "widget" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only changes this file should be additions - changes like switching the list item marker from *
to -
are code style changes.
@erquhart I think I've addressed everything in your request. |
Cool, we'll have to get some eyes on that preview component and consider an alternate approach. There are still some points from my review that need to be addressed - if you look at the file changes, there are a number of comments still showing. Let me know if you have questions on any of them. Mostly code style changes still remaining, but also |
@erquhart I had fixed the .gitignore and removed the dist files before the last commit, so not sure why you were still seeing those. Apologies - I think I got to all the code style issues now. |
const { value, onChange } = this.props; | ||
const parsedValue = itemType; | ||
this.setState({ itemsCollapsed: this.state.itemsCollapsed.push(false) }); | ||
onChange((value || List()).push(parsedValue)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one thing I noticed when trying to use this: the whole of the definition from types is written to the output and you end up with widget and label and the other configuration fields in your formatted file.
this is then read in render, and the widget rendering depends on the whole of the type definition being in the the value object.
ideally this would just store the type name and data in the output, and get the type definition from this.props.types based on the stored type name when rendering.
…example modular content settings to config.yml in "Kitchen Sink" post for demo project
Can't wait for this! |
Hey @anthonysapp just checking in - still planning to circle back on the issues raised in the latest comments? |
Hey all this is some great discussion. So sorry to have been unresponsive. I'm quite busy at the moment on another project but I would indeed like to loop back to this in the next week or so, as I'd love to use it for an upcoming project myself :). |
Awesome work on this @anthonysapp - I need this exact feature right now. I've sort of managed to recreate it using This PR/feature would completely solve my problem. I really hope this makes it in soon. |
@erquhart @cjbrooks12 hi guys, I took a look at this last night and I'm just curious if you both think this should still be merged with the List widget, or you think it warrants its own widget with the proposed changes? Also - I'm not 100% sure I understand this comment. What is inherently wrong with using the "name" field to reference each component? I know I'm probably missing something easy :) |
Technically-speaking, I would see the List widget as a special case of the Modular widget where there is only one available type. I think there is still a case for keeping the Modular widget separate for clarity of intent. As for the practical reason for wanting to customize the field used as the key, it is simply that the consumers of these modular blocks may consume them differently than Netlify CMS does. For example, I'm build a SSG with this kind of modularity baked into the framework itself, and Orchid reads these blocks from the Or take Forestry's Blocks, which uses As far as making it happen in the code, it shouldn't be much of a change. Rather than doing
to get the modular type, it would just be one step back with a configuration value to get it instead:
|
@cjbrooks12 I think I'm following now. Thanks for the feedback! |
Just thought I'd say that this is an extremely exciting widget and will really elevate the possibilities (custom layouts on a per page basis). 💯 Looking forward to seeing it shipped. |
I'm monitoring the status of this modular content widget as it is all I'm waiting for to jump into Netlify CMS. |
Closing as stale - if someone wants to pick it up, please comment. |
it would be great if we could use a group of other collections in place of DjangoCMS and EPiServer calls these blocks. And if you have a collection of blocks that are actually layout types with further modular widgets in them, you can do awesome things. Perhaps the widget should be called |
What will it take to get this past the finish line? Are there particular features that still need to be implemented? or tests to pass? I'm willing to help out, but I have zero React experience. |
Hey, our team is currently exploring some ideas that are very similar on our own fork. We'll give an update when we feel more confident in our approach here. |
@criticalmash things are pretty well laid out in the comments above, just a matter of someone putting together a good solution. @loremipson sounds good 🤞 |
I was trying to say this that it can split the |
This sounds awesome. I have been unable to get this pull working at all with current version of netlifycms though. |
This sounds like a must have widget when it comes to customizability and I'm wondering if there has been new updates on this? |
No updates, still needs a sponsor. |
- Summary
The motivation for this pull request is so the CMS can support a front matter property containing a list of modular content or blocks to construct a custom page output.
- Test plan
Add "modular" as widget type in config.yml. This content type accepts a "types" list instead of "fields". Functionality is similar to a list widget with its valueType set to valueTypes.SINGLE. Added the functionality of a dropdown control at the top of the list which chooses the content type to be added to the modular content list. Because it is a variation of the List widget, it retains the ability to re-order child widgets via drag and drop.
Modular content configuration
Modular content widget
- Description for the changelog
Added modular Widget for saving modular content lists to frontmatter.
fixes #1066