VulcanJS / Vulcan

🌋 A toolkit to quickly build apps with React, GraphQL & Meteor
http://vulcanjs.org
MIT License
7.98k stars 1.89k forks source link

Add tags to post #1677

Open mulikaminker opened 7 years ago

mulikaminker commented 7 years ago

Hey, I'm trying to add tags to the post. I followed these instructions but I get an error.

my code:

`import Posts from "meteor/vulcan:posts";
import Tags from 'meteor/vulcan:forms-tags';
import React from 'react';

Posts.addField(
  {
    fieldName: 'description',
    fieldSchema: {
      type: String,
      optional: true,
      max: 3000,
      viewableBy: ['guests'],
      insertableBy: ['members'],
      editableBy: ['members'],
      control: "textarea",
      order: 5
    }
  }
);

Posts.addField({
  fieldName: 'tags',
  fieldSchema: {
    type: Array,
    control: Tags,
    insertableBy: ['members'],
    afterComponent: <a target="_blank" className="suggest-category-link" href="https://github.com/SachaG/SidebarFeedback/issues/1">Suggest new categories</a>
  }
});`

the error:

Error: Type "null" not found in document.

SachaG commented 7 years ago

You also need to add a tags.$ field. For example:

Posts.addField([
  {
    fieldName: 'categories',
    fieldSchema: {
      type: Array,
      control: "checkboxgroup",
      optional: true,
      insertableBy: ['members'],
      editableBy: ['members'],
      viewableBy: ['guests'],
      form: {
        noselect: true,
        type: "bootstrap-category",
        order: 50,
        options: formProps => getCategoriesAsOptions(formProps.client),
      },
      resolveAs: {
        fieldName: 'categories',
        type: '[Category]',
        resolver: async (post, args, {currentUser, Users, Categories}) => {
          if (!post.categories) return [];
          const categories = _.compact(await Categories.loader.loadMany(post.categories));
          return Users.restrictViewableFields(currentUser, Categories, categories);
        }
      }
    }
  },
  {
    fieldName: 'categories.$',
    fieldSchema: {
      type: String,
      optional: true
    }
  }
]);
mulikaminker commented 7 years ago

@SachaG, Thanks. My intention was to add tags instead of categories, but together. I want to allow adding a tag to friends too. Currently it allows you to select an existing tag / category only

eric-burel commented 6 years ago

Edit : there seems to be working example in the movie example, so I'll check this out. Though error messages are not quite clear in my case, see below.

Hi, adding a schema with a '$' in the name throws an error when generating the GraphQL schema:

"Syntax Error GraphQL request (9:18) Cannot parse the unexpected character ".".

 8: vendingMachineIds{_id}
 9: vendingMachineIds.$
                     ^
10:       }
"

This prevents me from either adding objects or array in the schema whether I use addField or put it directly in the schema.

The tested schema (mostly copied from the example in this issue):

Tours.addField([

  {
    fieldName: 'vendingMachineIds',
    fieldSchema: {
      type: Array,
      label: 'Id des distributeur',
      control: "checkboxgroup",
      editableBy:['admins', 'managers', 'runners'],
      insertableBy:['admins', 'managers', 'runners'],
      viewableBy:['admins', 'managers', 'runners'],
      form: {
        noselect: true,
        type: "bootstrap-category",
        order: 50,
        options: formProps => []
       ,
      },
      resolveAs: {
        fieldName: 'vendingMachine',
        type: 'VendingMachine',
        resolver: (tour, args, context) => {
          if (tour.vendingMachineIds) return []
          const vendingMachines = context.VendingMachines.loader.loadMany(tour.vendingMachineIds)
          return Users.restrictViewableFields(context.currentUser, context.VendingMachines, vendingMachines)
        },
        addOriginalField: true
      }
    }
  },
  {
    fieldName: 'vendingMachineIds.$',
    fieldSchema: {
      type: String,
      optional: true,
      editableBy:['admins'],
      insertableBy:['admins'],
      viewableBy:['admins'],
    }
  },
])
SachaG commented 6 years ago

That's weird, because field whose names contains $ should be excluded from the GraphQL schema generation process:

https://github.com/VulcanJS/Vulcan/blob/master/packages/vulcan-lib/lib/modules/graphql.js#L134

eric-burel commented 6 years ago

Hm thats weird, maybe that's related to the point, e.g there is some split somewhere and only the first part of the fieldName, or the fieldName is never tested ? Would need to test with breakpoints

My guess is that you somehow hop over your check when the schema is an array, or there is an error in my schema which in turn have other things to fail. But it also happens with Object so I don't know...

SachaG commented 6 years ago

I think at this point the easiest thing is for you to just share your repo and specify some reproduction steps so I can try directly. It's hard to know the source of the issue otherwise.

eric-burel commented 6 years ago

Yep I'll try to repro if I can't fix the schema

eric-burel commented 6 years ago

Edit: see next comment instead Hi, I could not build a repro but here is more feedback.

The schema below does work, I used one field only instead of one field for the Array, as you do in the example-forum for comments in the Posts schema. However, to get it working I had to do two things:

So I guess that when viewableBy is undefined, trying to get the field lead to an error, which is reasonnable. My other guess is that when editableBy or insertableBy is set, the automated graphql mutation builder (or the defaultMutations or whatever makes the Vulcan gql magic happen) try to create a mutation and fails.

That could explain why it is unhappy about the foobar.$ when I try the 2-fields approach.

vendingMachineIds: {
        type: Array,
        optional: true,
        resolveAs: {
            fieldName: 'vendingMachines',
            type: '[VendingMachine]',
            resolver: (refill, args, context) => {

                const machines = refill.vendingMachineIds && refill.vendingMachineIds.length
                    ? context.VendingMachines.find(
                        { _id: { '$in': refill.vendingMachineIds } },
                        {
                            fields: context.VendingMachines.getViewableFields(context.currentUser, context.VendingMachines)
                        }).fetch()
                    : [];

                console.log(machines)
                return machines
            },
            addOriginalField: true,
        }
    },

I am still investigating this right now

eric-burel commented 6 years ago

God I think I finally got it! When you don't provide fields to the SmartForm, it will create inputs for ALL fields, including the foobar.$. It also creates the corresponding gql mutation (however I provided both a mutationFragment and a queryFragment so I am not sure why).

This explains those weird issues I encountered, everything seems to work well now I specified the fields.

So the solution would be to add a small condition on the SmartForm (I can't tell exactly which underlying component is responsible for this yet) that scraps out invalid field names. Seems to be related to this function https://github.com/VulcanJS/Vulcan/blob/master/packages/vulcan-forms/lib/components/Form.jsx#L255

SachaG commented 6 years ago

If you'd like me to look into this, could you provide the following?

SachaG commented 6 years ago

Also if you'd like to open a more general discussion about how nested fields should be handled, feel free to open a new issue.

stale[bot] commented 5 years ago

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.