sanity-io / sanity

Sanity Studio – Rapidly configure content workspaces powered by structured content
https://www.sanity.io
MIT License
5.24k stars 426 forks source link

Cannot mix references and non-references #3357

Open struct78 opened 2 years ago

struct78 commented 2 years ago

Describe the bug

I am attempting to update one of our flexible content components to support inserting inline documents, as well as document references so authors can create content components once, and use them on multiple pages/in multiple contexts.

To Reproduce

For simplicity's sake, I've not included all of the different document types we are using, but save to say they all follow the same kind of structure:

export default {
  title: "Accordion",
  name: "sectionAccordion",
  type: "document",
  fields: [...],
  preview: {
    select: {
      subtitle: "title",
    },
    prepare: selection => {
      const { subtitle } = selection
      return {
        title: "Accordion",
        subtitle,
      }
    },
  },
}

This is how the file used to look - this deploys perfectly fine!

const types = [{
  title: "Accordion",
  type: "sectionAccordion",
},
{
  title: "Banner",
  type: "sectionBanner",
},
{
  title: "Hero",
  type: "sectionHero",
},
{
  title: "Image",
  type: "sectionImage",
},
{
  title: "Rich Text",
  type: "sectionRichtext",
},
{
  title: "Title",
  type: "sectionTitle",
},
{
  title: "Video",
  type: "sectionVideo",
}]

export default {
  title: "Content Sections",
  name: "sections",
  type: "array",
  of: types,
}

When I update this to include references to those types:

const types = [{
  title: "Accordion",
  type: "sectionAccordion",
},
{
  title: "Banner",
  type: "sectionBanner",
},
{
  title: "Hero",
  type: "sectionHero",
},
{
  title: "Image",
  type: "sectionImage",
},
{
  title: "Rich Text",
  type: "sectionRichtext",
},
{
  title: "Title",
  type: "sectionTitle",
},
{
  title: "Video",
  type: "sectionVideo",
}]

export default {
  title: "Content Sections",
  name: "sections",
  type: "array",
  of: [...types, { type: "reference", title: "Component Library...", to: types }],
}

I get the following error message:

Error: All members of union type "SectionAccordionOrSectionBannerOrSectionHeroOrSectionImageOrSectionRichtextOrSectionTitleOrSectionVideoOr" must be strings

The trailing or at the end of the type grabbed my attention.

After dumping out the schema that is being posted to Sanity's API, I noticed that there are a number of references (i.e. in fields) to the union type SectionAccordionOrSectionBannerOrSectionHeroOrSectionImageOrSectionRichtextOrSectionTitleOrSectionVideo in the schema, which is correct, however the union type created under the "types" node is called SectionAccordionOrSectionBannerOrSectionHeroOrSectionImageOrSectionRichtextOrSectionTitleOrSectionVideoOr

This is what the type looks like in the schema:

{
      "kind": "Union",
      "name": "SectionAccordionOrSectionBannerOrSectionHeroOrSectionImageOrSectionRichtextOrSectionTitleOrSectionVideoOr",
      "types": [
        "SectionAccordion",
        "SectionBanner",
        "SectionHero",
        "SectionImage",
        "SectionRichtext",
        "SectionTitle",
        "SectionVideo",
        null
      ]
    }

It seems like it's ignoring the references altogether? If I switch the order and put the references first:

export default {
  title: "Content Sections",
  name: "sections",
  type: "array",
  of: [{ type: "reference", title: "Component Library...", to: types }, ...types],
}

The schema isn't even generated, and I get the following error:

TypeError: Cannot read property 'name' of undefined
    at ~/Github/bared-footwear-website/admin/node_modules/@sanity/core/lib/actions/graphql/extractFromSanitySchema.js:357:74
    at Array.find (<anonymous>)
    at ~/Github/bared-footwear-website/admin/node_modules/@sanity/core/lib/actions/graphql/extractFromSanitySchema.js:357:37
    at Array.every (<anonymous>)
    at getUnionDefinition (~/Github/bared-footwear-website/admin/node_modules/@sanity/core/lib/actions/graphql/extractFromSanitySchema.js:356:51)
    at getArrayDefinition (~/Github/bared-footwear-website/admin/node_modules/@sanity/core/lib/actions/graphql/extractFromSanitySchema.js:281:17)
    at _convertType (~/Github/bared-footwear-website/admin/node_modules/@sanity/core/lib/actions/graphql/extractFromSanitySchema.js:163:16)
    at convertType (~/Github/bared-footwear-website/admin/node_modules/@sanity/core/lib/actions/graphql/extractFromSanitySchema.js:174:20)
    at ~/Github/bared-footwear-website/admin/node_modules/@sanity/core/lib/actions/graphql/extractFromSanitySchema.js:215:89
    at Array.map (<anonymous>)

Is there something I'm missing? The setup works fine in Sanity Studio, and I can add documents and document references, and it works on the front end preview locally.

References:

Screen Shot 2022-06-17 at 11 20 18 am

Mixing documents and references:

Screen Shot 2022-06-17 at 11 20 42 am

Which versions of Sanity are you using?

@sanity/cli                 2.30.0 (up to date)
@sanity/base                2.30.1 (up to date)
@sanity/cli                 2.30.0 (up to date)
@sanity/code-input          2.30.1 (up to date)
@sanity/color-input         2.30.1 (up to date)
@sanity/components          2.14.0 (up to date)
@sanity/core                2.30.1 (up to date)
@sanity/dashboard           2.30.1 (up to date)
@sanity/default-layout      2.30.1 (up to date)
@sanity/default-login       2.30.1 (up to date)
@sanity/desk-tool           2.30.1 (up to date)
@sanity/google-maps-input   2.30.1 (up to date)
@sanity/production-preview  2.29.3 (up to date)
@sanity/vision              2.30.1 (up to date)

What operating system are you using?

MacOS 11.6.4

Which versions of Node.js / npm are you running?

NPM 6.14.16
Node v14.19.1
struct78 commented 1 year ago

Managed to fix it by patching a couple of functions in @sanity/core/lib/actions/graphql/extractFromSanitySchema.js

Just needs null checks on the type.

function isBaseType(type) { return type != null && type.name !== null && type.name !== type.jsonType && allowedJsonTypes.includes(type.jsonType) && !skipTypes.includes(type.name) && !isReference(type) && !isCrossDatasetReference(type); }

and

const flattened = converted.reduce((acc, candidate) => { const union = unionTypes.find(item => item.name === candidate.type); return union ? acc.concat(union.types.map(type => ({ type, isReference: candidate.isReference }))) : acc.concat(candidate); }, []).filter(def => def != null && def.type != null);

pascalwengerter commented 1 year ago

Managed to fix it by patching a couple of functions in @sanity/core/lib/actions/graphql/extractFromSanitySchema.js

Just needs null checks on the type.

function isBaseType(type) { return type != null && type.name !== null && type.name !== type.jsonType && allowedJsonTypes.includes(type.jsonType) && !skipTypes.includes(type.name) && !isReference(type) && !isCrossDatasetReference(type); }

and

const flattened = converted.reduce((acc, candidate) => { const union = unionTypes.find(item => item.name === candidate.type); return union ? acc.concat(union.types.map(type => ({ type, isReference: candidate.isReference }))) : acc.concat(candidate); }, []).filter(def => def != null && def.type != null);

Do you think making a PR for this is worth it? I see myself running into the same issue sometime soon 😬