Open papandreou opened 6 years ago
I've been thinking about this recently - we'd need a way to do it for fields in the config.yml, too.
@papandreou check out my proposal in #1409, you brought up a good case here that helped. The caveat is that we need to get rid of widget: hidden
, and instead allow some sort of visible: false
property for any widget. That way the dynamic default value function that will ship with widgets can be used automatically.
@erquhart, cool. That approach looks good to me!
we'd need a way to do it for fields in the config.yml, too
I don't know if it's a standard thing, but I noticed that the yaml parser I use mentions a funky !<tag:yaml.org,2002:js/function>
syntax for declaring functions: https://github.com/nodeca/js-yaml#load-string---options-
Might be too weird, though :)
Yeah, I'm aware of js-in-yaml, and agree that it's weird. Extensions shipping functions feels pretty sane.
A possible implementation for editor components (not config.yml
), was created in #1511.
Hello,
I don't know if what I'm trying to reach is already possible or it could be related to this request. I have a hugo site deployed on netlify through github, using netlify cms. I would like to set the netlify cms config.yml to return automatically a default field for the post collection. The field is the weight and I want it to count how many posts are published and return a negative number bigger than that, With hugo I use -{{ len (where .Site.Pages "Section" "post") }} in the archetypes but I can't figure out if I can do something similar with netlify cms
Thanks!
Managed to hack around this by creating a custom uuid
widget:
CMS.registerWidget(
'uuid',
class extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
forID: PropTypes.string,
value: PropTypes.node,
classNameWrapper: PropTypes.string.isRequired
};
static defaultProps = {
value: ''
};
componentDidMount() {
const { value, onChange } = this.props;
if (!value) {
onChange(generateUuid());
}
}
render() {
const { value, classNameWrapper, forID } = this.props;
return (
<span id={forID} className={classNameWrapper}>
{value}
</span>
);
}
}
);
Makes sense - a dedicated id widget might be a good idea to include with the cms, too.
I guess -- if it's the only use case we can come up with for the dynamic default value feature 😆
Lol exactly, I still haven't thought of another one
Sent with GitHawk
@erquhart Would it be worth thinking about this from a different perspective? Could you add a 'uid' field that supported interpolation in the same way that 'slug' does? They are very similar - both are used once on creation. If this was supported you could do:
uid: '{{year}}-{{month}}-{{day}}-{{hour}}-{{minute}}-{{second}}-{{collection}}-{{slug}}'
You could simplify this by adding a {{dateTime}}
interpolation. Another option would be for Netlify CMs to provide its own {{uuid}}
interpolation (using uuid):
uid: '{{uuid}}-{{collection}}-{{slug}}'
If you think this is worthwhile I'll happily put together a PR.
The issue there is consistency and avoiding privileged entities. Frontmatter values are currently always generated by a widget, how do you see your solution working within that context?
Sent with GitHawk
I suppose it depends on how you look at the uuid
field. It is a field that should never change after creation, so the idea that it needs a widget doesn't really make sense because it's very reason for being is that it should never be edited, and the creation of uuids is pretty standard, so I see no problem with Netlify CMS handling the creation in the same way it handles the creation of the filename, once at creation.
I can see your concerns about this field having unique behaviour, but a uuid field is by definition unique: it should never change. It has to be stored as a field because there is nowhere else to store it, but I don't think that means it has to be treated like other fields. It is a special case. I think there's a good argument for a uuid being generated for everything by default and used for tracking relations.
Anyhow, I think a robust solution is needed, as this is currently quite a big weakness in the library: the fact that relations are based on fields that are not protected from user editing makes the use of relations deeply unstable.
Definitely agree on the need for it. I think the ideal approach is probably a combination of our suggestions: supporting placeholders in the default
field for widgets, and adding a built in uuid
placeholder. Then you could do:
{ name: id, widget: hidden, default: "{{uuid}}" }
Sent with GitHawk
That sounds like a good solution to me.
I guess the other thing to consider is whether all items that are created should have a uuid field: is this something that should happen by default? This would definitely be a great help when the need for a relation emerges later on.
An additional consideration. Because of how a hidden
widget is treated it doesn't seem to be possible to use a widget to set a default value, but not show that value within the CMS. For any widget other than 'hidden', an Editor component will be rendered to the UI. In the case of a uuid widget. In short, using a Widget to provide a uuid is far from ideal because it must display that value (or an empty widget) to the user, despite a uuid
being an internal fields. I think this is another good reason to pursue #1975.
I just came across the same issue, and I agree width @Undistraction that It will better to approach it differently, as the uuid is an internal value that has no meaning for the cms user. As the project I'm working on does not include React, I create an uuid widget like @papandreou but with createClass
and no external dependencies ment to be used in script tag. The uuid function is from the nanoid package.
<!-- Include the script that builds the page and powers Netlify CMS -->
<script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script>
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
<script>
CMS.registerWidget(
'uuid',
createClass({
getDefaultProps: function() {
return {
value: ''
}
},
uuid: function(options) {
options = options || {};
var size = options.size || 21;
var url = options.url || "Uint8ArdomValuesObj012345679BCDEFGHIJKLMNPQRSTWXYZ_cfghkpqvwxyz-";
var id = "";
if (typeof self === "undefined" || (!self.crypto && !self.msCrypto)) {
while (0 < size--) {
id += url[(Math.random() * 64) | 0];
}
return id;
}
// else
var crypto = self.crypto || self.msCrypto;
var bytes = crypto.getRandomValues(new Uint8Array(size));
while (0 < size--) {
id += url[bytes[size] & 63];
}
return id;
},
componentDidMount: function() {
var value = this.props.value;
var onChange = this.props.onChange;
var uuid = this.uuid;
if (!value) {
onChange(uuid());
}
},
render: function() {
var value = this.props.value;
var classNameWrapper = this.props.classNameWrapper;
var forID = this.props.forID;
return h('span', { id: forID, className: classNameWrapper }, value);
}
})
);
</script>
I think the bigger issue here is that widgets need to set their own default values, the CMS has no way of doing that correctly.
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.
- Do you want to request a feature or report a bug?
feature
- What is the current behavior?
The default value of a field has to be a fixed string/number/boolean (depending on the field type).
- What is the expected behavior?
It would be great to be able specify a function that would return the desired value (maybe even allow it to return a promise for it, for even greater flexibility).
My use case is that I would like to generate
uuid
s for my collection entries and editor components, and store them in a field withwidget: 'hidden'
.Would be great to be able to do something like: