Closed (fixed)
Project:
Entity Share
Version:
8.x-3.x-dev
Component:
User interface
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
28 Feb 2017 at 17:19 UTC
Updated:
19 Feb 2021 at 14:04 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
grimreaperBefore making a nice diff feature.
Indicating on the pull form if the content is a new content or will be updated.
Comment #4
grimreaperBack to minor has a basic diff has been implemented.
Comment #5
grimreaperComment #7
grimreaperUsing the diff module https://www.drupal.org/project/diff. Maybe it will be possible to use:
diff/src/Controller/NodeRevisionController.php, compareNodeRevisions:
But the problem is the route_match parameter that we may don't want.
Discussed with @friera, @richardrodriguez21, and others at Werfen.
Comment #8
grimreaperComment #9
grimreaperComment #10
grimreaperComment #13
grimreaperCrediting people at Werfen to not forget.
Comment #14
grimreaperHere is a POC I made.
It requires to have patch on diff module: #3088227-2: Use diff in another context
And a discussion with diff's maintainers to have something maintainable.
Comment #15
grimreaperI am removing the options to only get the split_fields layout.
So a lot less modifications in the diff module will be required.
Comment #16
grimreaperAfter simplifying the diff, I had been able to obtain a default implementation that requires only the following patch in diff module:
#3088274-2: Prevent fatal error if the revision has no author
jsonapiHelper and stateInformation services are more complex, and will be required to be rethought as part of #3060694: Rework service and tests.
I am waiting for feedbacks before merging.
Comment #17
grimreaperComment #18
grimreaperComment #19
quicksketchI'm having a few issues testing this so far.
First, for some reason the Diff links do not respect the config override settings on the Remote URLs. In our settings.php files, we override the URL based on the environment. For example for localhost testing on Lando:
But the Diff links do not respect these. instead they use the original URLs when attempting to fetch information about the remote, and Guzzle throws a 500 error because the original URLs are inaccessible.
Oddly every other place in Entity Share uses the config overrides, I'm not sure what's happening here.
Another small issue so far is that the "Diff" link shows up even when entities are 100% in sync.
For improving the UI, I think it would be better if the entire "Diff" column were removed so it doesn't show up unnecessarily. Where it says "Entities not synchronized" it added a link for "(Diff)" after it within the same column
Comment #20
quicksketchDoing the following I was able to get a diff:
I synced one piece of content and then modified a single field on it (adding a "Subheading"). The diff result is close, but I'm seeing completely different rows instead of each comparison being made against the same field. And I'm not sure why "Language", "Authored by", and "Title" show up as modified at all, when they're all the same values.
Comment #21
grimreaperI found that when a config entity is created with parameter upcasting, the overrides are not applied. I found some issues in search_api about that but not core (I admit that I searched only two minutes).
I will upload a quick fix.
I have allowed to have a diff link even when the entity is marked has synchronized, because currently only the changed timestamp is used to check if there is a diff and also in DiffLayoutInterface, there is only one method "build".
So to avoid relying only on the changed timestamp, the diff should be calculated on each row and then parse the renderable array to see if there is a diff. That adds too many calculation in my opinion, and so in case, the change timestamp is the same but there is a change it allows to see if there is a diff.
If after a lot of usage, this case can be removed easily I think.
Also I will apply your suggestion on removing diff column.
Patch incoming.
Comment #22
grimreaperI forgot: Thanks @quicksketch for the tests and feedbacks!
Here is the patch.
Also I am not able to reproduce the screenshot from comment 20. I attached a screenshot to show my results.
I use the default diff settings, maybe you have some different config?
If you can give me more steps to reproduce the behavior.
Comment #23
quicksketchThanks @GrimReaper! The table looks better:
However, note that there is still a "Diff" link even when two items are already synchronized. Clicking on the Diff link yields the predictable result, "No visible changes." We should remove that link if it's always an empty Diff.
I'm still seeing the problem where diffing changed entities results in a complete set of subtractions and replaced with all additions.
Digging into Diff module, it appears that this is due to the Node (or whatever entity) IDs differing. On my remote site, the NID is 1, but on my local it's NID 5. When Diff assembles the keys for comparison, it includes the Entity ID:
From \Drupal\diff\DiffEntityParser::parseEntity():
So if the entity IDs differ, you end up with this display where the entire contents are removed/added like my screenshot above.
Here's a partial dump of the Diff
$buildas dumped in\Drupal\entity_share_client\Controller\DiffController::compareEntityRevisions():So looks like either we need to make Diff module learn how to compare two entities with different IDs, or we need to modify the entities to have the same IDs before asking them to be compared.
Comment #24
grimreaperThanks @Quicksketch for testing.
Great to find out it was mismatching entity ids!
Here is a patch that will resolve this case too.
Also for the diff appearing on "synchronized" entities it was still there so normal that you still saw the link. It is removed now.
Is the last patch ok for you?
Comment #25
quicksketchThe diff is now working properly and the unnecessary link to the empty diff is removed.
This looks really good and works great! Seems like it's ready to me.
Comment #27
grimreaperThanks!
This is merged now.
Comment #28
quicksketchHi @Grimreaper, on further testing we found there is an issue with reference fields, in particular when dealing with Paragraphs.
Because paragraphs are also entities, and also have entity IDs, it seems that just forcing the top-level entity to have the same ID is not sufficient.
To test:
- Have a paragraph type with a single text field in it.
- Add a paragraph field to a sync-able content type.
- Create and delete a paragraph on one site to increment the paragraph ID on one site only.
- Create a piece of content containing a paragraph.
- Sync it to the other site.
- Make a change on the original site to the paragraph content.
- View the diff via Entity Share. See the following problem:
The diff ends up any paragraph fields showing as only existing on one site but not the other, even though values are specified (but different) on each site's copy of the content.
Comment #29
grimreaperComment #30
grimreaperHere are the results of my investigations.
I reproduced the problem.
There is also the problem in the case of taxonomy term for example.
Seeing the options on admin/config/content/diff/fields and on https://git.drupalcode.org/project/diff/blob/8.x-1.x/src/Plugin/diff/Fie..., for entity reference field, there is only the option of a diff on the entity id or on the label.
For entity reference revisions, there is a dedicated plugin https://git.drupalcode.org/project/entity_reference_revisions/blob/8.x-1... which compare the entities:
The problem is that the workaround of injecting the entity ID:
can't be done for referenced entities because the Diff module is thought to be used on one website and so in diff/src/Controller/NodeRevisionController.php:
$right_revision has values loaded and for the entity reference fields there are values, they are populated. So when loading a referenced it is ok, the entity exists on the website.
But in the Entity share implementation, entity_share/modules/entity_share_client/src/Controller/DiffController.php, when extracting JSON data to create $right_revision, the entity has the fields, but there is no value for the entity referenced fields.
So I don't know how to go further with Diff. And I am thinking that it will require to have a custom diff implementation in Entity share.
Maybe getting JSON:API and/or Diff maintainers will be helpful.
Comment #31
quicksketchI think you're right this needs to be fixed in Diff. I haven't been able to produce a working result, but I think it should be possible to fix this if instead of using the entity ID, it used a combination of the field name plus the field value delta in the keys. Then it wouldn't matter if the paragraph or file IDs were mismatched, they'd be keyed by their value position, not ID. That might have benefits for Diff itself, as there could be situations where a replacement reference is used where most of the values within the reference are the same.
Comment #32
grimreaperThanks @quickstketch for the feedback.
Yes that could be interesting, but that will require Diff maintainers help.
And there is still the second problem.
When doing diff, the way it has been intended, on one website, you have access to all the entities.
When extracting an entity in Entity Share, the entity reference fields are empty. I will take a look into the tests of JSON:API if there is a case of inclusion allowing to get those entities when extracting.
Comment #33
grimreaperI have searched in JSON:API tests and asked on Slack if it is possible to extract an entity with entity reference values set.
In JSON:API tests, core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php, there are only tests for normalization involving the inclusion feature https://www.drupal.org/docs/8/modules/jsonapi/includes.
I also put a comment on #3088227-4: Use diff in another context.
Comment #34
grimreaperBefore forgetting.
Maybe a light custom solution using https://www.previousnext.com.au/blog/using-drupal-diff-component-custom-... can be tested.
Comment #35
harpreet16 commentedComment #36
harpreet16 commentedMaybe before using the custom solution for diff we need to get the correct "right revision entity"(remote entity) loaded for further comparison as entity reference fields are not available in the right revision. Something similar to the "public function updateRelationships(ContentEntityInterface $entity, array $data)" present in "entity_share/modules/entity_share_client/src/Service/JsonapiHelper.php" could be implemented here that will just return the data set and not import it. I have started writing a piece of code for the same but need to switch to some other work on priority. I Will update the issue as soon as I find a solution.
In my opinion loading the correct right revision needs to be taken on priority. @grimreaper should we create a new issue for addressing this?
Comment #37
grimreaperHello,
@harpreet16: first, thanks a lot for the article https://www.srijan.net/blog/entity-share-a-cost-effective-solution-to-ma....
Second, thanks for your dedication on this issue. The custom solution of comment 34 is only a proposition in case fixing "right revision entity" would be impossible. So yes, if it will be possible to fix "right revision entity", let's go for it for sure.
I think we can stay in this issue, as it has been reopened on comment 28.
: no problem, I understand completly being staffed on something else. No pressure.
Comment #38
harpreet16 commentedThanks, @grimreaper for reading the article.
Comment #39
harpreet16 commentedComment #40
harpreet16 commentedComment #41
harpreet16 commentedHello @Grimreaper,
Hope you're doing well. First of all sorry for taking so much time in getting some sort of solution for the issue we are facing here.
Secondly, thanks for your suggestion of a light custom solution in #34.
I have written down some code quickly using your suggestion after going through the details of how the diff module works. Please note that I might have missed a certain edge case here. But the main motive is to get started with at least an idea as to finalize an approach.
Changes to be noted:
1. Diff won't work in our case as it has no means to load entities(referenced) from a remote site. Hence I have created Diff Plugins in the entity_share_client module that does not use target_id for comparison and builds a list of comparable attributes from the data provided.
2. In the case of remote entities, the idea is to pass the UUID of the entity (that is not there on client site) that can be used further to load attributes from its JSON endpoint. This is done as target_id for the newly created entity will not be the same as a remote one. This module works on UUID matching, hence the logic.
3. I have also made changes to few functions like- Converting one named "relationshipHandleable"(modules/entity_share_client/src/Service/JsonapiHelper.php) from "protected to public" and created getURL function in /modules/entity_share_client/src/Entity/Remote.php.
4. With new Diff plugins in place meant specifically to be used with entity_share; there is no need for enabling diff at all. Hence dependencies have been removed as well.
Please let me know if this works. The visibility of difference is not as convenient as provided by diff.
Comment #42
grimreaperHello @harpreet16,
Thanks! Thanks a lot for your patch. And no problem for the delay. I know it is hard to get time to contribute.
Thanks for the detailed explainations, I will give a look to the patch.
Comment #43
grimreaperHere is my review.
Why don't you request the related entity to be able to provide a complete diff?
Infinite loop? Or maybe too many requests?
I would have named the headers as before, to be clear of what represents the remote entity and what represents the local entity.
Plugin/EntityShareClient/diff to be sure to not interfere with the diff module.
I would have named it DiffParserBase.
Same as #3139150-3: Get the remote Entity ID, I think you don't need this method.
Beyond the review, great work, but...
I think we can, by making a GET on
$value['links']['related']['href'], and then JsonapiHelper::extractEntity, we can have an entity object that can be injected in the entity we wan't to see the diff.This would be the approach I would try.
And/Or, changing diff on referenced entities into a link to a new custom controller page, where the diff of this new entity will be done, etc.
Is it ok for you?
Regards,
Comment #44
grimreaperComment #45
harpreet16 commentedThanks a lot @grimreaper for your valuable feedback. I will work on your feedback and come back with a separate module.
Also look forward to feedbacks/suggestions from @quicksketch.
Comment #46
ivan.vujovicComment #47
ivan.vujovicHello,
I added the patch which should solve the issue of referenced entities (and some other issues).
Referenced entity can now be either embedded into Diff (paragraphs, media) or just its UUID can be listed (all other cases - nodes, terms...).
I couldn't provide the interdiff to the patch of @harpreet16 because of conflicts I had rebasing (in the meantime two big features have been merged).
What may still be needed to do:
DiffManagerBasefor example)parseEntity()andparseField()etc.) and it would be nice if they could be actually visibleComment #48
grimreaperHello,
@ivan.vujovic, Thanks a lot for the patch!
Here is a summary of our discussion.
I will test with recursive paragraphs to see the real effect of the patch. And I will test with the approach I mentioned in my comment 43:
And post the screenshots of the results.
Because the suggestion I made on comment 37 which led to using core diff system was only in a first time for experiment.
And even if this not much code, if we can avoid reinventing what the Diff module does that would be nice.
So I am testing what I have in mind and then, we will be able to compare and take a decision.
For Dynamic Entity Reference fields, it is "normal" that sharing is not working, there is a dedicated issue #3056102: Support dynamic entity reference fields.
Cheers :)
Comment #49
grimreaperI have tested the custom diff with subparagraphs and it works. Nice @Ivan.vujovic!
The screenshots are from the Diff module on a revision comparaison on the same site, native Diff usage, and it also works recursively with paragraphs.
I have tested the approach I wanted to test on comment 37, and now I know why it won't work. When unserializing the referenced content, and injecting it into the $right_revision, the problem is that it does not work. the values in the entity reference fields are target_id which changes between the local and remote entities. So impossible to use Diff module properly on Entity Share when dealing with Entity Reference fields.
Except if someone else has an idea on that?
I agree now that the approach with custom diff plugin is the only one remaining.
In addition (may be redundant) to what @ivan.vujovic wrote in comment 47, this is what I think needs to be done:
Any opinion on that?
I wonder if this can be refactored, or it is worth refactoring.
Need to refactor with modules/entity_share_client/src/Plugin/EntityShareClient/Processor/EntityReference.php::isUserOrConfigEntity()
Comment #50
ivan.vujovicHello @grimreaper,
The new patch contains the fixes for the most of the issues that you and I raised for the patch of #47.
What I didn't do:
What I did, among other things:
getPublicFieldName(string $field_name, array $entity_json_data)instead of not-so-usefulgetResourceType(ContentEntityInterface $entity); I also think that this new helper can be used in several other cases.As for the look-and-feel of the Diff output: currently it depends on website configuration - when you do
drush cset system.diff context.lines_trailing 100it looks good, but if the number of context lines is too small, it might not be possible to see the name of the embedded field.I think we should manipulate this config for our needs, but without affecting the other cases where core Diff is used, such as at /admin/config/development/configuration.
Comment #51
ivan.vujovic@grimraper I forgot to update README.txt and section "RECOMMENDED MODULES" where Diff module is mentioned.
Comment #52
grimreaperHello,
@ivan.vujovic, really good work! Thanks a lot for your patch!
Before going further, I would like to get some feedbacks from @harpreet16 and @quicksketch.
So do not take my review points into account please. Especially the coding standards/unused variables, I can handle it when merging if no other patch has to be provided.
Now that we depend of a sub-module of our own and not a contrib module, would it be possible to do like in entity_share_async, with a hook_form_FORM_ID_alter?
If yes, we can remove the moduleHandler service because it is no more used.
(Also, maybe we will have to think on an approach to not have entity_share_async removing the diff link)
I really like this idea!
Can we introduce an interface for that service please?
Same as for the PullForm, if possible, move that in hook_form_FORM_ID_alter into entity_share_diff.
If you want to override the diff.formatter service. You can avoid to have ro redeclare the arguments (and so if diff.formatter will change it will be automatically taken into account) by adding "parent: diff.formatter".
See modules/entity_share_client/tests/modules/entity_share_client_remote_manager_test/entity_share_client_remote_manager_test.services.yml
Missing "declare(strict_types = 1);". I will do a check when commiting.
I think this line can be removed.
Unused variable.
I think you can just do "return $this->..."
Unused variable.
PHPDoc to complete.
Is "if (!$this->htmlOutput) {" ok? Because htmlOutput is a boolean
Unused variable.
?
Unused variable.
And some small code duplication.
Can we put this list into a constant in the class please? so if someone wants to override it he/she, only have to override the service and replace the constant.
This would be a compromise between having a config form and the availability to override it.
Or this can stay as it is and people overriding the service only have to override this method. As for the getFieldsIrrelevantForDiff it is impossible to put the list into a constant.
Forget my comment.
Unused variable.
Absolutely no problem with that. This is already a very big patch and feature. If people want to push further they will have to open a new issue. No need to over-engineer the stuff.
About the dependence on the diff configuration:
As of the introduction of a new sub-module for something inside the "main" module. I wonder if we should add a hook_update to enable it.
PS: ok about Readme.
Thanks again @ivan.vujovic! I think we are really near the end of this issue.
Regards,
Comment #53
ivan.vujovicHello @grimreaper, thank you for your review and the feedback!
Some answers:
- The timestamp problem: actually we need the separate plugin for datetime fields, but the issue is the same as in CoreFieldDiffParser:
- A hook_update to enable the new submodule: absolutely! I failed to see that diff functionality exists in 8.x-3.x :)
- Using
hook_form_FORM_ID_alter()of the PullForm: yes, that was my idea as well. However I was hesitating to do so, because of the wayFormHelper::addOptionFromJson()was done - it would mean we would have to repeat a lot of code to get variables needed to generate the Diff URL. So my idea is to add a new helper service which would treat a single row of the import table, and which could cache the needed variables as class properties.-
EntityReferenceHelperInterface.php- sure, let's add it!- Configuration of the number of Diff context lines: maybe some cache needs to be cleared, but this setting definitely has effect on the diff. Also it affects other Diff core usages, so I suggest a flag in our decorated service: we can either introduce a new Setting to use just with diff, or simply hardcode these values in our service - but only if this flag is on (similar to what I did with
if (empty($this->htmlOutput))...)Comment #54
ivan.vujovicComment #55
ivan.vujovicHello @grimreaper,
I am adding the fixes for your feedback in comment #52.
I only didn't do anything about your
hook_form_FORM_ID_altersuggestion, we still have the not-so-good condition$this->moduleHandler->moduleExists('diff').Comment #57
grimreaperAout the review points from comment 52:
1: ok, postponed
2: ok
3: ok, postponed
4: ok
5: ok
6: ok
7: ok
8: ok
9: ok
10: ok
11: ok
12: ok
13: ko
14: ok
15: ok
16: ok
I will fix 13
Will do a new code review and manual testing.
I have created a PR for easier code review.
Thanks a lot @ivan.vujovic!!!
Comment #58
grimreaperI will fix the small adjustments then manual testing.
Comment #60
grimreaperManual test ok. I manually re-do the commits for proper credit attribution.
Thanks everyone!