Netlify CMS not saving hidden fields - netlify

Issue
I am using Netlify and Gatsby, actually working with this template to learn these systems. I can see in the pre-made files that there are hidden widgets in the admin/config.yml file for the CMS:
I am attempting create a new page with some widgets in the CMS:
- file: "src/pages/sidebar/index.md"
label: "Sidebar"
name: "sidebar"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "sidebar-page",
}
- { label: Title, name: title, widget: string }
- { label: Subtitle, name: subtitle, widget: string }
- { label: Body, name: body, widget: markdown }
- { label: Sidebar Title, name: sidebartitle, widget: string }
- { label: Sidebar Content, name: sidebarcontent, widget: markdown }
The normal fields all appear in the CMS, and they all get saved to the appropriate .md file in the path that I specified. However, the hidden fields are not being saved. This is resulting in build failures because GraphQL is attempting to build a page that doesn't exist, since the hidden templateKey field is supposed to be directing it to the appropriate Gatsby component. This is only occurring for new pages that I am creating. If I remove the templateKey field from a page that came with the template, it will resave that hidden field when I update the page in the CMS.
I am using the netlify-cms-proxy-server, but even if I send the CMS updates to my remote repo, the hidden fields are not saved.
I only found a couple other references to things tangentially related, and those are from years ago, so I suspect that it's something that I am doing that's preventing these from saving for my new pages.
If I manually add the templateKey field into my sidebar page's .md file, Gatsby will compile and the page will render. I can then edit the page in the CMS, save new content to the .md file, and the templateKey field will remain. Saving a new version does not remove the templateKey field.
I have also created an Issue on the template's github repository to try and get some insight from those involved there.
Here is my gatsby-config, gatsby-node, and config.yml files as well, if those are helpful:
Netlify CMS Config
backend:
name: git-gateway
branch: main
commit_messages:
create: "Create {{collection}} “{{slug}}”"
update: "Update {{collection}} “{{slug}}”"
delete: "Delete {{collection}} “{{slug}}”"
uploadMedia: "[skip ci] Upload “{{path}}”"
deleteMedia: "[skip ci] Delete “{{path}}”"
local_backend: true
media_folder: static/img
public_folder: /img
collections:
- name: "blog"
label: "Blog"
folder: "src/pages/blog"
create: true
slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "blog-post",
}
- { label: "Title", name: "title", widget: "string" }
- { label: "Publish Date", name: "date", widget: "datetime" }
- { label: "Description", name: "description", widget: "text" }
- { label: "Featured Post", name: "featuredpost", widget: "boolean" }
- { label: "Featured Image", name: "featuredimage", widget: image }
- { label: "Body", name: "body", widget: "markdown" }
- { label: "Tags", name: "tags", widget: "list" }
- name: "pages"
label: "Pages"
files:
- file: "src/pages/index.md"
label: "Landing Page"
name: "index"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "index-page",
}
- { label: Title, name: title, widget: string }
- { label: Image, name: image, widget: image }
- { label: Heading, name: heading, widget: string }
- { label: Subheading, name: subheading, widget: string }
- {
label: Mainpitch,
name: mainpitch,
widget: object,
fields:
[
{ label: Title, name: title, widget: string },
{ label: Description, name: description, widget: text },
],
}
- { label: Description, name: description, widget: string }
- {
label: Intro,
name: intro,
widget: object,
fields:
[
{ label: Heading, name: heading, widget: string },
{ label: Description, name: description, widget: text },
{
label: Blurbs,
name: blurbs,
widget: list,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Text, name: text, widget: text },
],
},
],
}
- {
label: Main,
name: main,
widget: object,
fields:
[
{ label: Heading, name: heading, widget: string },
{ label: Description, name: description, widget: text },
{
label: Image1,
name: image1,
widget: object,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Alt, name: alt, widget: string },
],
},
{
label: Image2,
name: image2,
widget: object,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Alt, name: alt, widget: string },
],
},
{
label: Image3,
name: image3,
widget: object,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Alt, name: alt, widget: string },
],
},
],
}
- file: "src/pages/about/index.md"
label: "About"
name: "about"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "about-page",
}
- { label: "Title", name: "title", widget: "string" }
- { label: "Body", name: "body", widget: "markdown" }
- file: "src/pages/products/index.md"
label: "Products Page"
name: "products"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "product-page",
}
- { label: Title, name: title, widget: string }
- { label: Image, name: image, widget: image }
- { label: Heading, name: heading, widget: string }
- { label: Description, name: description, widget: string }
- {
label: Intro,
name: intro,
widget: object,
fields:
[
{ label: Heading, name: heading, widget: string },
{ label: Description, name: description, widget: text },
{
label: Blurbs,
name: blurbs,
widget: list,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Text, name: text, widget: text },
],
},
],
}
- {
label: Main,
name: main,
widget: object,
fields:
[
{ label: Heading, name: heading, widget: string },
{ label: Description, name: description, widget: text },
{
label: Image1,
name: image1,
widget: object,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Alt, name: alt, widget: string },
],
},
{
label: Image2,
name: image2,
widget: object,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Alt, name: alt, widget: string },
],
},
{
label: Image3,
name: image3,
widget: object,
fields:
[
{ label: Image, name: image, widget: image },
{ label: Alt, name: alt, widget: string },
],
},
],
}
- {
label: Testimonials,
name: testimonials,
widget: list,
fields:
[
{ label: Quote, name: quote, widget: string },
{ label: Author, name: author, widget: string },
],
}
- { label: Full_image, name: full_image, widget: image }
- {
label: Pricing,
name: pricing,
widget: object,
fields:
[
{ label: Heading, name: heading, widget: string },
{ label: Description, name: description, widget: string },
{
label: Plans,
name: plans,
widget: list,
fields:
[
{ label: Plan, name: plan, widget: string },
{ label: Price, name: price, widget: string },
{
label: Description,
name: description,
widget: string,
},
{ label: Items, name: items, widget: list },
],
},
],
}
- file: "src/pages/sidebar/index.md"
label: "Sidebar"
name: "sidebar"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "sidebar-page",
}
- { label: Title, name: title, widget: string }
- { label: Subtitle, name: subtitle, widget: string }
- { label: Body, name: body, widget: markdown }
- { label: Sidebar Title, name: sidebartitle, widget: string }
- { label: Sidebar Content, name: sidebarcontent, widget: markdown }
Gatsby Config
module.exports = {
siteMetadata: {
title: "Gatsby + Netlify CMS Starter",
description:
"This repo contains an example business website that is built with Gatsby, and Netlify CMS.It follows the JAMstack architecture by using Git as a single source of truth, and Netlify for continuous deployment, and CDN distribution.",
},
plugins: [
"gatsby-plugin-react-helmet",
{
resolve: "gatsby-plugin-sass",
options: {
sassOptions: {
indentedSyntax: false,
},
},
},
{
// keep as first gatsby-source-filesystem plugin for gatsby image support
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/static/img`,
name: "uploads",
},
},
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/src/pages`,
name: "pages",
},
},
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/src/img`,
name: "images",
},
},
`gatsby-plugin-image`,
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
{
resolve: "gatsby-transformer-remark",
options: {
plugins: [
{
resolve: "gatsby-remark-relative-images",
options: {
name: "uploads",
},
},
{
resolve: "gatsby-remark-images",
options: {
// It's important to specify the maxWidth (in pixels) of
// the content container as this plugin uses this as the
// base for generating different widths of each image.
maxWidth: 2048,
},
},
{
resolve: "gatsby-remark-copy-linked-files",
options: {
destinationDir: "static",
},
},
],
},
},
{
resolve: "gatsby-plugin-netlify-cms",
options: {
modulePath: `${__dirname}/src/cms/cms.js`,
},
},
{
resolve: "gatsby-plugin-purgecss", // purges all unused/unreferenced css rules
options: {
develop: true, // Activates purging in npm run develop
purgeOnly: ["/style.scss"], // applies purging only on the bulma css file
},
}, // must be after other CSS plugins
"gatsby-plugin-netlify", // make sure to keep it last in the array
],
};
Gatsby Node
const _ = require('lodash')
const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem')
const { fmImagesToRelative } = require('gatsby-remark-relative-images')
exports.createPages = ({ actions, graphql }) => {
const { createPage } = actions
return graphql(`
{
allMarkdownRemark(limit: 1000) {
edges {
node {
id
fields {
slug
}
frontmatter {
tags
templateKey
}
}
}
}
}
`).then((result) => {
if (result.errors) {
result.errors.forEach((e) => console.error(e.toString()))
return Promise.reject(result.errors)
}
const posts = result.data.allMarkdownRemark.edges
posts.forEach((edge) => {
const id = edge.node.id
createPage({
path: edge.node.fields.slug,
tags: edge.node.frontmatter.tags,
component: path.resolve(
`src/templates/${String(edge.node.frontmatter.templateKey)}.js`
),
// additional data can be passed via context
context: {
id,
},
})
})
// Tag pages:
let tags = []
// Iterate through each post, putting all found tags into `tags`
posts.forEach((edge) => {
if (_.get(edge, `node.frontmatter.tags`)) {
tags = tags.concat(edge.node.frontmatter.tags)
}
})
// Eliminate duplicate tags
tags = _.uniq(tags)
// Make tag pages
tags.forEach((tag) => {
const tagPath = `/tags/${_.kebabCase(tag)}/`
createPage({
path: tagPath,
component: path.resolve(`src/templates/tags.js`),
context: {
tag,
},
})
})
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
fmImagesToRelative(node) // convert image paths for gatsby images
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}

https://www.netlifycms.org/docs/widgets/hidden/
The hidden widget is not supported for file collections at the moment

Related

Error when loading admin page of netlify cms

Error when loading the admin page on the Netlify CMS.
config must have required property ‘media_folder’
config must have required property ‘media_library’
config must match a schema in anyOf
I have media_folder and I thought that media_library isn’t a required field, or am I wrong.
my config.yml file looks like this
`
backend:
name: git-gateway
branch: main
media_folder: "public/images"
public_folder: "/images"
collections:
- name: "event"
label: "Event"
folder: "src/event"
create: true
slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
fields:
- { label: "Event Title", name: "title", widget: "string" }
- { label: "Event Type", name: "type", widget: "string" }
- { label: "Event Description", name: "description", widget: "markdown" }
- { label: "Event Date", name: "date", widget: "datetime" }
`
Any help is appreciated

Problem with gatsby-node.js trying to create markdown pages hooked to NetlifyCMS

I am trying to solve this issue for days.
I never wrote a gatsby-node.js but used a Gatsby NetlifyCMS starter that came with it.
From what I understand it's probably supposed to create a page from my markdown data automatically.
When I add code to my static/admin/config.yml (the last bit), add content in the admin and pull, i get this error:
I would truly appreciate any help on this.
Your site's "gatsby-node.js" created a page with a component that
doesn't exist.
The path to the missing component is
"/home/hanna/Code/brnhrz-cms/src/templates/null.js"
The page object passed to createPage:
{
"path": "/events/events/",
"tags": null,
"component": "/home/hanna/Code/brnhrz-cms/src/templates/null.js",
"context": {
"id": "331ab6a0-648d-5ed0-9613-09abbdee8c18"
}
}
My config.yml:
backend:
name: git-gateway
branch: master
commit_messages:
create: "Create {{collection}} “{{slug}}”"
update: "Update {{collection}} “{{slug}}”"
delete: "Delete {{collection}} “{{slug}}”"
uploadMedia: "[skip ci] Upload “{{path}}”"
deleteMedia: "[skip ci] Delete “{{path}}”"
local_backend: true
media_folder: static/img
public_folder: /img
collections:
- name: "blog"
label: "Blog"
folder: "src/pages/blog"
create: true
slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "blog-post",
}
- { label: "Title", name: "title", widget: "string" }
- { label: "Publish Date", name: "date", widget: "datetime" }
- { label: "Description", name: "description", widget: "text" }
- { label: "Featured Post", name: "featuredpost", widget: "boolean" }
- { label: "Featured Image", name: "featuredimage", widget: image }
- { label: "Body", name: "body", widget: "markdown" }
- { label: "Tags", name: "tags", widget: "list" }
- name: "pages"
label: "Pages"
files:
- file: "src/pages/events/events.md"
label: "Events"
name: "events"
fields:
- {
label: "Template Key",
name: "templateKey",
widget: "hidden",
default: "events-page",
}
- { label: Title, name: title, widget: markdown }
- { label: Description, name: description, widget: markdown }
(...code for other pages that came already with the starter)
my gatsby-node.js:
const _ = require('lodash')
const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem')
const { fmImagesToRelative } = require('gatsby-remark-relative-images')
exports.createPages = ({ actions, graphql }) => {
const { createPage } = actions
return graphql(`
{
allMarkdownRemark(limit: 1000) {
edges {
node {
id
fields {
slug
}
frontmatter {
tags
templateKey
}
}
}
}
}
`).then((result) => {
if (result.errors) {
result.errors.forEach((e) => console.error(e.toString()))
return Promise.reject(result.errors)
}
const posts = result.data.allMarkdownRemark.edges
posts.forEach((edge) => {
const id = edge.node.id
createPage({
path: edge.node.fields.slug,
tags: edge.node.frontmatter.tags,
component: path.resolve(
`src/templates/${String(edge.node.frontmatter.templateKey)}.js`
),
// additional data can be passed via context
context: {
id,
},
})
})
// Tag pages:
let tags = []
// Iterate through each post, putting all found tags into `tags`
posts.forEach((edge) => {
if (_.get(edge, `node.frontmatter.tags`)) {
tags = tags.concat(edge.node.frontmatter.tags)
}
})
// Eliminate duplicate tags
tags = _.uniq(tags)
// Make tag pages
tags.forEach((tag) => {
const tagPath = `/tags/${_.kebabCase(tag)}/`
createPage({
path: tagPath,
component: path.resolve(`src/templates/tags.js`),
context: {
tag,
},
})
})
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
fmImagesToRelative(node) // convert image paths for gatsby images
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
The fact that is complaining about:
"/home/hanna/Code/brnhrz-cms/src/templates/null.js"
Indicates that your component is null at:
component: path.resolve(
`src/templates/${String(edge.node.frontmatter.templateKey)}.js`
),
So ${String(edge.node.frontmatter.templateKey)} is null.
There are multiple possible sources that cause that issue. First of all, check the query in your GrahiQL environment to check that is returning a valid value in all the events you are creating because if one is null, it will break your code.
Also double-check the created markdown to see if it's properly formatted or it contains all the mandatory fields (specially the templateKey) and add it if it doesn't.

Sort images according to their type and put them in a the corresponding folder

I would like to sort images according to their type (good, medium, bad) and put them in the corresponding folder.
My data is an object with image name + label
export interface data = { image: string, label: 'good' | 'medium' | 'bad' }
export const DATA: data = {
{ image: 'name-of-image-1, label: 'good' }
{ image: 'name-of-image-2, label: 'bad' },
{ image: 'name-of-image-3, label: 'good' },
...,
{ image: 'name-of-image-n, label: 'medium' }
}
Images are on a server, the path is for instance: smb://test/images/
So I find my first image at smb://test/images/name-of-image-1
I would like to map my DATA array and copy images in the corresponding folder depending of the label. For example, put image with label bad in the folder ./bad.
Have you an idea to do that with Node?
Your provided code example has some issues which are solved here:
export interface Data {
image: string,
label: 'good' | 'medium' | 'bad'
}
export const data: Data[] = [
{ image: 'name-of-image-1', label: 'good' },
{ image: 'name-of-image-2', label: 'bad' },
{ image: 'name-of-image-3', label: 'good' },
{ image: 'name-of-image-n', label: 'medium' }
];
To solve your problem you coude use .reduce to group the image label accordingly:
const sorted = data.reduce((prev, current) => ({
...prev,
[current.label]: [
...prev[current.label],
current.image
]
}), { good: [], medium: [], bad: [] });
The response of sorted is then the following
{
"good": [
"name-of-image-1",
"name-of-image-3"
],
"medium": [
"name-of-image-n"
],
"bad": [
"name-of-image-2"
]
}

Mongoose schema infinite nesting

I'm having some trouble creating a model that describes the object that I want to store in mongoDB.
This is the object:
simple: [
{
label: 'Satisfied customers',
children: [
{
label: 'Good food',
children: [
{ label: 'Quality ingredients' },
{ label: 'Good recipe' }
]
},
{
label: 'Good service (disabled node)',
children: [
{ label: 'Prompt attention' },
{ label: 'Professional waiter' }
]
},
{
label: 'Pleasant surroundings',
children: [
{ label: 'Happy atmosphere' },
{ label: 'Good table presentation' },
{ label: 'Pleasing decor' }
]
}
]
}
]
This is data that is input to a QTree: https://quasar.dev/vue-components/tree
I want to model this but this object can in theory expand indefinitely as each child can have children of it's own and so on. Is there a way to do this nicely in a Mongoose Schema? My search so far turned up empty.
Here is what I have now:
simple: [{
_id: false,
label: String,
children: [{
_id: false,
label: String,
}]
}]
I can ofcourse choose to limit the depth to a certain amount (say 5) and put that amount of nesting in my schema, but I'm trying to find a more elegant solution so that I dont have to do that.

JointJS: Inspector doesn't edit link label?

I'm working on a Flowchart editor and I want the ui.inspector to edit labels on links.
I did the following:
function createInspector(cellView) {
if (!inspector || inspector.options.cellView !== cellView) {
if (inspector) {
inspector.remove();
}
inspector = new joint.ui.Inspector({
inputs: {
labels:
attrs: {
text:{
text: { type: 'textarea', group: 'Labels', label: 'Label', index: 2 },
}
}
},
},
},
groups: {
labels:[ { label: 'Labels', index: 1 },
}],
cellView: cellView
});
$('#inspector-holder-create').html(inspector.render().el);
}
}
paper.on('cell:pointerdown', function(cellView) {
createInspector(cellView);
});
However, when I edit a link it shows in the JSON output:
"labels": {
"0": {
"attrs": {
"text": {
"text": "Text I entered"
}
}
}
},
but doesn't actually render on the link in the stencil.
I think the problem is with the { "0": part the inspector adds. I want to remove that and replace with it [ ] so the output will be
labels: [
{ attrs: { text: { text: 'label' } } }
]
What should I do ??
It is possible to define Inspector inputs with paths.
'labels/0/attrs/text/text': {
type: 'text',
group: 'Text',
index: 1,
label: 'Label'
}
Or as a combination of attributes nesting and paths.
'labels/0/attrs': {
text: {
text: {
type: 'text',
group: 'Text',
index: 1,
label: 'Label'
},
fontSize: {
type: 'number',
group: 'Text',
index: 2,
label: 'Font Size'
}
}
}
This is valid for Rappid v2.4.0+.
inspector = new joint.ui.Inspector({
inputs: {
'labels': [
{attrs: {
text: {
text: {
type: 'text',
group: 'someGroup',
index: 1,
label: "Label"
}
}
}}
]
}});

Resources