Problem/Motivation
Diff now provides a revision tab. But it is very hard to display feasible data to represent a revision, specifically to understand what the difference between revisions is.
Nodes have a revision comment field to allow editors to enter a comment. In most cases though, revision comments are empty and forcing a user to enter a revision comment leads to bad usability with quick edits...
The original idea came up when discussing
#2462053: Provide a container revision summary
8.2 core introduced an interface to deal with revisions: RevisionLogInterface
Node implements it and sure returns empty strings if no log message is stored.
Still the Revision tab can not be altered easily but we override it anyway.
Proposed resolution
Add the fallback logic into our override tab controller and check for RevisionLogInterface and if inexisting or not available, fall back to some generated summary. I think that helps most for fast iteration and doesn't add new assumptions or APIs to maintain.
We can then bring in our extensibility requirements to Entity module or Core when we are well progressed.
Entity has RevisionOverviewController with getRevisionDescription for a revision.
For the specific case of Collect, Diff won't be able to offer a reasonable default.
We will create a follow-up to switch away from the own Controller for revisionOverview to the generic Entity revision tab and then implement the interface to offer a generated summary.
A revision summary could be to loop over all fields and compare each of the values and mention which field changed.
That however would require the summary of each revision to load the previous revision too.
But it seems that will always be needed for a generated change summary.
Remaining tasks
Decide about approach, implement.
User interface changes
API changes
Comment | File | Size | Author |
---|---|---|---|
#47 | interdiff-2462731-45-47.txt | 1.06 KB | johnchque |
#47 | check-2462731-47.patch | 9.38 KB | johnchque |
#45 | interdiff-2462731-43-45.txt | 3.64 KB | johnchque |
#45 | check-2462731-45.patch | 9.3 KB | johnchque |
#43 | interdiff-2462731-41-43.txt | 2.32 KB | johnchque |
Comments
Comment #1
BerdirNot just the summary, everything that could possibly be different based on the entity type could be moved there, with default implementations when possible.. routes, local tasks, revision date, author, getting a list of revisions...
Comment #2
lhangea CreditAttribution: lhangea commentedJust to make sure I understand correctly: you are basically saying that we need to display some sort of a revision summary in the revision overview table and as an example, with that we should be able to override the revision log message which is displayed by default for node revisions.
Comment #3
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedThis issue is blocked by
#2452523: [Meta] Offer a revisions tab for all entities
Comment #4
miro_dietiker@lhangea the revision comment field only exists on node revisions. All other entities don't have a similar comment. As a result, the revision tab could only display the revision id and date. Also the revision author is optional data.
You can see an example revision tab in collect module: #2446011: Show container revisions
To show more than just the date, the image outputs the content with a cutoff at 255 chars. This is still not satisfying. The general revisions tab needs to provide extensibility for a nice revision summary.
We want to decouple the general revisions tab from a pluggable revision handler. As berdir pointed out, the summary is just one thing.
This would be a healthy pattern to adopt by core once in future.
Comment #5
lhangea CreditAttribution: lhangea commentedOk, got it, thanks
Comment #6
miro_dietikerUnpostponing. The generic controller has landed.
Revision summary still easily sucks.
Comment #7
miro_dietikerIMHO if the revision summary is not provided by the user, the system could add a revision change / summary statement. Not just if the revision comment field is technically not existing.
Comment #8
johnchqueComment #9
miro_dietikerSoo... I just checked the issue queue.
Most issues are cleanups and small bugs. After the most recent bugfix.
This is the only remaining major feature we are eager to see.
It's not a release blocker though. We are also fine to add it on a 1.1+ release as it's also not introducing any incompatibility.
In any case, a diff release is near. :-)
Comment #10
phenaproximaNow that Diff has Views integration, is there any real reason not to provide a view to replace the core /node/%/revisions route? This would grant the user a lot of power and configurability, and be easy to implement. We've already done it in a feature branch of Lightning, and I'd be happy to extract that as a patch if it would be helpful.
If we went with that approach, we could provide a Views field handler that would display the revision comment if one was available, or otherwise summarize it if not.
Comment #11
BerdirNot sure if it the diff integration is not specific or not, but even if it is generic, it would have to generate views dynamically for other entity types.
We could do it just for node as a start but we should probably keep the code and routes anyway, as it can be tricky to have code rely on views-provided routes, in case that view is deleted or changed.
Comment #12
phenaproximaThat's a good point. I'm thinking about the out-of-the-box use case -- Diff already specifically provides a route subscriber whose only purpose is to override core's node revision controller. It seems to be pretty un-opinionated (again, OOTB) about other versionable entities. I merely propose taking that node-specific functionality and making it a view. I agree about not having code depend on it -- what are you specifically thinking of?
Comment #13
miro_dietikerThis whole discussion about the view is more related to #2452523: [Meta] Offer a revisions tab for all entities
In code there is a reference to the core issue that wants to convert the revision tab to a view... You might want to create a separate issue about this subject?
Comment #14
miro_dietikerSo after the progress, discussions and the direction about diff pluggability, i think it's clear:
This handler will provide revision (summary) information and not really anything diff specific.
Comment #15
johnchqueEarly patch uploaded. Not really sure if this is the right approach.
Comment #16
miro_dietikerYeah a valid first step.
Checkout Node.php. It has a list_builder in the annotation or 'translation' for a TranslationHandler.
What we want is to introduce a new key here for the revision handler.
We could alter entity definitions and bring the key in for all entities.
Or we could fall back to our code when no specific one is declared. I guess that's more minimalistic.
Comment #17
johnchqueMade some small changes, this should allow to add our handler.
Comment #18
miro_dietikerAlso do the fallback if the RevisionLogMessage is empty.
Almost. ;-)
I think our name doesn't differentiate yet and can be easily confused with RevisionableInterface. Interestingly this skips "Entity" completely.
Are we only handling the summary or are we going to add other revision related methods too?
Comment #19
miro_dietikerWe had some general discussions and change directions.
It turns out that 8.2 core introduced an interface to deal with revisions: RevisionLogInterface
Node implements it and sure returns empty strings if no log message is stored.
Still the Revision tab can not be altered easily but we override it anyway.
We only need pluggability if we stop overriding and the revision tab is provided by Entity.
To stay simple, let's stay within our straight scope:
Add the fallback logic into our override tab controller and check for RevisionLogInterface and if inexisting or not available, fall back to some generated summary. I think that helps most for fast iteration and doesn't add new assumptions or APIs to maintain.
We can then bring in our extensibility requirements to Entity module or Core when we are well progressed.
Entity has RevisionOverviewController with getRevisionDescription for a revision.
For the specific case of Collect, Diff won't be able to offer a reasonable default.
We will create a follow-up to switch away from the own Controller for revisionOverview to the generic Entity revision tab and then implement the interface to offer a generated summary.
Comment #20
johnchqueThen we should add it in the current PluginRevisionController? Or create a new controller for it?
Comment #21
BerdirYeah, and also use there :)
Comment #22
miro_dietikerA revision summary could be to loop over all fields and compare each of the values and mention which field changed.
That however would require the summary of each revision to load the previous revision too.
But it seems that will always be needed for a generated change summary.
Comment #23
johnchqueDid some code to load the previous revision and get the fields that have changed. For now it lists the fields that have changed.
Looking like this now. Not sure yet where to use it in the current controller.
Comment #24
miro_dietikergetRevisionIds is node specific. Also some things are this line seem wild. ;-)
Berdir proposes to use an entity query.
This method should get the current and the previews revision, or at least call another method that gets both params.
Comment #25
johnchquegetRevisionIds doesn't seem to be Node specific, its a function present in the controller.
Comment #26
BerdirSorry my fault. Still, that would mean you need to get all the revision ids again for every revision, that's extremely inefficient.
You already have a list of revision ids, work for example with an index based on the current revision and access the next/previous in your list or invert the order and always start with the first revision, then you can easily store the previous revision ID in a variable. Then pass that to your method as an additional argument.
Comment #27
johnchqueShouldn't be easier to use the left revision and right revision that are used in the controller itself?
Comment #28
BerdirYes if we have that already, sure, use those.
Comment #29
johnchqueGreat, then would this make sense? Not really sure where to place that summary.
Comment #30
BerdirI think I see why you are confused now :)
This is about the revision list, not the diff. Which is not generic yet I think but node specific.
Comment #32
johnchqueOhhhhh I see, so I have to place the summary in the revisionOverview right? OK, will try :) Thank you! So instead of using the method in the controller itself I have to use it in the revision form, I see!
Comment #33
johnchqueMoved the functions to a service. Working nicely. Still need to get rid of those fields that are not useful for the user.
Comment #35
miro_dietikerNice. I think we should make it more compact and implode by "," so it fits better the text format of a revision log.
As an idea to better indicate change:
Git displays on the terminal repeatingly + or - varying the amount of changes. Or sometimes % change. And a summary on a merge.
Example:
So the challenge would be that we need to trigger the diff engine to know how many characters / words / lines have been removed and added.
Title +3/-15, Body +1k/-3.1k
Or even more simplified, we could output the change in length?
But i guess those are lots of ideas for follow-ups... But not yet sure what we need to boost UX.
Comment #36
johnchqueFor now imploding with ",". Looks nice.
Comment #38
miro_dietikerHa, funny, the first field i get listed as changed is "Revision ID", so we should definitively only list fields that are subject for diff like we filter the fields in our field settings UI.
As much as at a first glance this looks nice:
"Revision ID, Changed, Revision timestamp, Revision log message, Body"
Only the "Body" part of it is real information. The other ones are all garbage.
BTW how are we determining field sequence?
I'm not 100% sure if we can only list the fields or if we need to prepend the message with "Changed: " or "Changes on ".
Comment #39
johnchqueActually this changes filter those useless lines, for now it checks if there is a plugin for that field, in that case it is added to the summary.
Comment #41
johnchquehmmm this should fix the tests.
Comment #42
miro_dietikerGreat stuff.
Hey tests, where are you hiding? :-)
Comment #43
johnchqueWhen no changes. Added "No changes." summary, tests added.
Comment #44
miro_dietikerI don't like these crypto lines.
i'd just build an array of items, after the loop check for count() and implode conditionally with prepending the text with else "No changes".
Any what is this crapto line all about?
Comment #45
johnchqueThis is more readable. :)
Comment #47
johnchqueAdded a check if the element in array is set.
Comment #49
miro_dietikerHa! Funny how simple this code can be!
Plus really awesome to have this in now!
Committed and updated summary a bit from comments.
Comment #50
miro_dietikerCreated Follow-up.