Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Update relations mapping to support dynamic zones #158

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ShipleyC95
Copy link
Collaborator

Fixes #132

Using a recursive function, iterates through all the dynamic zones on a model and finds the components that are relations then, builds up the connections using the new and existing data for each component.

The change to server/register.js was to enable draft pages to have their references updated without publishing. Something that I believe @omikulcik was investigating

@ShipleyC95 ShipleyC95 marked this pull request as ready for review December 18, 2023 10:37
@omikulcik
Copy link
Collaborator

I went through the code and it looks good. Great job. Will play around with it tomorrow

@ShipleyC95
Copy link
Collaborator Author

ShipleyC95 commented Dec 19, 2023

I have just discussed this fix with a colleague and while it works for Dynamic Zones, it does not detect relations on components. I'm looking into this now.

e.g. A dynamic zone that has a component that had a relation within it does not save correctly

@omikulcik
Copy link
Collaborator

Yes, I have just discovered the same issue

const relations = getUpdatableRelations(model);
relations && result.push({ [key]: relations });
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ShipleyC95

I also added this here

if (attributes[key].type === "component") { const model = strapi.getModel(attributes[key].component); const relations = getUpdatableRelations(model); relations && result.push({ [key]: relations }); }

But then i also need to update the generation of populate statement.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, looking at refactoring the generate statement now to account for nested objects, will hopefully be able to post soon

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spent the past hour trying to refactor it but could not figure it out. I will try tomorrow if you are not faster to do it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, keep the branch updated if you can :)

const prevRel = previous[relation] ?? undefined;

if (prevRel) {
const newDataRel = parent
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm struggling with how to correct this and attach the new data for if the value is more than one level down. e.g. the relation, from the top level would be, contentType -> dynamicZone -> component -> relation and therefore setting newData[parent][relation] results in an error because it skips a level

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I was on to something with these functions:

const setDeepValue = (obj, value, path) => {
  let index = 0;
  for (index; index < path.length; index++) {
    obj = obj[path[index]];
  }
  obj[path[index]] = value;
};

const getDeepValue = (obj, path) => {
  for (const index of path) {
    obj = obj[path[index]];
    return obj;
  }
};

But haven't managed to get it working for all circumstances with an implementation like

const newDataRel = getDeepValue(newData, [...path, relation]);

And don't want to push a half working commit

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. So did you manage to fix the getUpdateStatement fnc? It would be great for me to have that part so I could debug this one.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I did not get to you quicker. I had to finish work on other project before Christmas + fixed another bug on this plugin. I should be free to deep into this one tomorrow.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. So did you manage to fix the getUpdateStatement fnc? It would be great for me to have that part so I could debug this one.

Sadly not yet, I just hard-coded a data structure that fit with my use case

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, glad to be back after the holiday. I think I adjusted the populate statement generator. It works for my data structure. I think I will now encouter the problem you have described and will try to fix it.

`const generatePopulateStatement = (relations) => {
const result = {};

relations.forEach((item) => {
if (typeof item === "object" && !Array.isArray(item)) {
const key = Object.keys(item)[0];
const innerObj = {};

  item[key].forEach((innerItem) => {
    if (typeof innerItem === "object") {
      const key = Object.keys(innerItem)[0];
      innerObj[key] = {
        populate: {},
      };
      innerItem[key].forEach((element) => {
        innerObj[key]["populate"][element] = true;
      });
    } else {
      innerObj[innerItem] = true;
    }
  });

  result[key] = { populate: innerObj };
} else if (Array.isArray(item)) {
  const key = Object.keys(item)[0];
  const innerObj = {};

  item[key].forEach((innerItem) => {
    innerObj[innerItem] = true;
  });

  result[key] = { populate: innerObj };
} else {
  result[item] = true;
}

});

return result;
};`

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ShipleyC95 So I tried implementing it and I think I got close. However it still does not work :/ Morover, when there are multiple types of components in the dz it sometimes deletes one of them.

You can check what I have tried in https://github.com/notum-cz/strapi-plugin-content-versioning/tree/feature/dz-relations-om

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update @omikulcik. Unfortunately, your generate method doesn't work for me, I end up with one of the keys being "[Object object]" but I will look into it and that branch you've posted there

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for testing it @ShipleyC95. Working with this polymorphic data structure seems quite complex to me but hopefully we can somehow solve this. I will get into working on this again during this week.

Fixed the generate populate statement
if (!connects[parent]) {
connects[parent] = [
{
...newData[parent][i],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be ...newData[parent] instead of ...newData[parent][i], all my other dynamiczone elements are deleted and only the relation one is left if its ...newData[parent][i], using ...newData[parent] fixes this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Relations support in components/dynamic zones
4 participants