▣🔗 Asset Link - Use-case Drive

This is great, I’m glad to see some more complex use-cases coming together!

Just a few bits of feedback.

fetchAssetLink

I’m curious where this pattern came from? I don’t think you should ever need to do this…

// Create a function to fetch assetLink and store it in the ref
const fetchAssetLink = async () => {
  assetLink.value = await getAssetLink(); // Replace getAssetLink with your code to retrieve assetLink
};

// Fetch the assetLink on component mount
onMounted(fetchAssetLink);

The recommended ways to get an AssetLink instance are:

In a setup method/block;

const assetLink = inject('assetLink');

Otherwise, assetLink should be already available - such as in a plugin’s onLoad method.

findUnitTerm

I don’t think you should need to do this “double-lookup-else-create” pattern;

    const findUnitTerm = async entitySource => {
      const results = await entitySource.query(q => q
          .findRecords('taxonomy_term--unit')
          .filter({ attribute: 'name', op: 'equal', value: UNIT_NAME }));
      return results.flatMap(l => l).find(a => a);
    };

    let seedUnitTerm = await findUnitTerm(assetLink.entitySource.cache);

    if (!seedUnitTerm) {
      seedUnitTerm = await findUnitTerm(assetLink.entitySource);
    }

    if (!seedUnitTerm) {
      const unitTermToCreate = {
          type: 'taxonomy_term--unit',
          id: uuidv4(),
          attributes: {
            name: UNIT_NAME,
          },
      };

      seedUnitTerm = await assetLink.entitySource.update(
          (t) => t.addRecord(unitTermToCreate),
          {label: `Add '${UNIT_NAME}' unit`});
    }

See my feedback on the other thread about the " $relateByName directive". (Actually, it looks like maybe you’re already doing that and just need to delete the above code?)

Retrieving Entity Lists

Looking at the code like this;

  const results = await entitySource.query((q) =>
    q.findRecords('taxonomy_term--plant_type')
  );

  const plant_types = results.flatMap((l) => l);

I’m skeptical that this has been tested… I didn’t try running it, but I’m pretty sure that if you define a single query (instead of a list of them) in the entitySource.query lambda, then it will return a single list of entity results, not a list of lists. Thus the flatMap wouldn’t be necessary and would probably fail.

It’s also worth noting that entitySource.query doesn’t handle pagination automagically, so it could be surprising to users of your plugin to find that only some of the plant types show up (or are filterable) via the drop-down.

It might be better to use the EntitySelect component that Asset Link already provides as part of its plugin API: Asset Link docs EntitySelect (If we examine its code, we find that it doesn’t do pagination since showing a huge list isn’t very helpful, but instead it searches the entity source again if the user types in filter criteria.)

Getting Seeds by Name

It’s probably obvious, but code like the following would only work if your use-case has a very strong convention of seeds having unique names.

const seed = await assetLink.entitySource.query((q) =>
  q.findRecords('asset--seed').filter({ attribute: 'name', op: 'equal', value: seedAsset })
);
console.log('Seed object', seed)

It might also be better to pass the whole seed object through and use the object that your form already had access to instead of looking it up again.

Namespacing

In your other plugin here, I notice you’ve used the id net.symbioquine.farmos_asset_link.actions.v0.harvestPlant.

While it doesn’t hurt anything to put any text you want into that id, it is preferable to base the id on a domain that you control. This is a pattern that I established so that in the future Asset Link can be smarter about showing where functionality comes from and allowing plugins to be gracefully upgraded.

1 Like