Problem/Motivation

Let's assume you use both diff module and moderation_state on the same page.
Both modules want to expand the revision history page, to show a) the diff form and b) the workflow state of each revision.

Proposed resolution

Integrate diff into views:

Remaining tasks

* Write tests
* Maybe wait on https://www.drupal.org/node/2634212

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner created an issue. See original summary.

dawehner’s picture

Status: Active » Needs review
FileSize
10.44 KB

There we go.

damiankloip’s picture

+++ b/src/Plugin/views/field/DiffFrom.php
@@ -0,0 +1,97 @@
+class DiffFrom extends DiffPluginBase {

Form*

dawehner’s picture

Form*

No.

Its DiffFrom and DiffTo.
Do you have some better naming? DiffFromForm and DiffToForm?

damiankloip’s picture

OHHH AHH AHAHAA

dawehner’s picture

FileSize
10.47 KB
2.06 KB

We need to ensure that all radio entries follow the same name attribute

lhangea’s picture

@dawehner Thanks for your work ! It's really nice that we can use view for this one.
Still, it's not very clear for me yet how are we going to proceed with integration between diff and moderation_state module. Which module is going to provide the view ? Are both modules going to provide their own separate view and when used together the diff view is disabled and the moderation_state one is configured to include the diff form ?

As for waiting on the generic diff controller I think we can work on this first since there are tasks postponed on it and anyway the order doesn't really matter for diff anyway.

dawehner’s picture

Still, it's not very clear for me yet how are we going to proceed with integration between diff and moderation_state module.

This is indeed a good question.

My general idea was to be honest to provide it more as a site builder tool. At least for my custom usecase it was supposed to be customized anyway.
On the other hand, I see where you are coming from. Talked a bit with @berdir on IRC.
One thing we could do is to

a) Ship a view without diff support in moderation_state
b) Have a optional configuration file with diff support included in moderation_state
c) Have a hook_module_installed() hook in moderation_state which disables / removes the first view| enables the second view.

Of course we could do it the other way round as well, but well, its the classical N^2 integration problem.

dawehner’s picture

FileSize
24.26 KB
18.42 KB

Expanded the patch with some test coverage + minor fixes.
In case you wonder about the diff form key. This is basically a copy of what bulk forms do. Its not strictly needed, but its just a good way in case people build crazy views.

Status: Needs review » Needs work

The last submitted patch, 9: 2636406-9.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
24.29 KB
1.59 KB

Fixed the test failures.

Status: Needs review » Needs work

The last submitted patch, 11: 2636406-11.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
18 KB
985 bytes

Meh

Status: Needs review » Needs work

The last submitted patch, 13: 2636406-13.patch, failed testing.

jibran’s picture

Looks ready to me.

  1. +++ b/src/Controller/GenericRevisionController.php
    @@ -0,0 +1,331 @@
    +class GenericRevisionController extends EntityComparisonBase {
    ...
    +  protected function getVids(EntityStorageInterface $storage, $entity_id) {
    

    Doc block missing.

  2. +++ b/src/Controller/GenericRevisionController.php
    @@ -0,0 +1,331 @@
    +  protected function buildMarkdownNavigation(EntityInterface $entity, $left_vid, $right_vid, $active_filter) {
    

    @param part of the doc block is missing.

  3. +++ b/tests/src/Kernel/DiffControllerTest.php
    @@ -0,0 +1,89 @@
    +  public function testController() {
    

    Doc block missing.

dawehner’s picture

dawehner’s picture

Oh wait, this is actually the wrong patch ...

The last submitted patch, 13: 2636406-13.patch, failed testing.

dawehner’s picture

I asked fago to create a DEV release, this should help a bit.

The last submitted patch, 13: 2636406-13.patch, failed testing.

mikemiles86’s picture

phenaproxima’s picture

Status: Needs work » Needs review
FileSize
18.03 KB

Re-rolled.

Status: Needs review » Needs work

The last submitted patch, 22: 2636406-22.patch, failed testing.

The last submitted patch, 22: 2636406-22.patch, failed testing.

dawehner’s picture

Status: Needs work » Postponed
mikemiles86’s picture

juliaschwarz’s picture

FileSize
24.33 KB

This is an improved version of patch #11 (https://www.drupal.org/files/issues/2636406-11.patch) where the path to test files is changed (/modules -> /tests/modules).
I chose #11 as according to @dawehner this is the actual patch for this issue.
As I understand it #13 and #22 belong to https://www.drupal.org/node/2634212.
Please correct me, if I'm wrong!

juliaschwarz’s picture

Status: Postponed » Needs review

Status: Needs review » Needs work

The last submitted patch, 27: 2636406-27.patch, failed testing.

dawehner’s picture

Oh yeah you are absolutely right, these two patches have been the one from the other issue.
Ideally we should get the alpha release out so we can depend on entity module, but this is future ...

@JuliaBayer
Does that patch work fine for you? I'm pretty happy about it, but I might be quite biased.

juliaschwarz’s picture

@dawehner
Yes, it works and helps us very much. Thank you!

josephdpurcell’s picture

juampynr’s picture

  • juampynr committed 2216ce7 on 8.x-1.x
    Issue #2636406 Add dependency on entity module
    
juampynr’s picture

Status: Needs work » Needs review
FileSize
24.33 KB

Re-testing #27.

Status: Needs review » Needs work

The last submitted patch, 35: 2636406-27.patch, failed testing.

juliaschwarz’s picture

I open my view within a modal dialog. By clicking on 'Compare' I want it to stay within the modal, but by default a new page is loaded.

Try 1: Enable ajax for view (within Views API). -> This doesn't seem to work for the Compare button (equal to bulk actions).

Try 2: Use a form_alter hook to add an ajax callback. -> This only works, if I have no exposed filter added to the view. But I need to filter by author. In this case (with exposed filter and added ajax callback for compare button) first the filter form is loaded which then expects an ajax callback too. As I won't define an ajax callback for the filter, nothing happens and i get the following Ajax Error:

ResponseText: {"message":"A fatal error occurred: The specified #ajax callback is empty or not callable."}

Does anybody know this problem?

Alan D.’s picture

Issue tags: +Needs backport to D7

Flagged #641480: Expose diff functionality to views as a duplicate, since there are no patches in that older thread.

shubham_singhal’s picture

Hey, how can I do it on Drupal 7.

I have created a set of pages and I'll update them from time to time. On the home page I want to show the updated things (only updated content) and not the complete page. People shall see what new content is available as form of posts like we do from 'promote to front page'. I have created a view for content revision but can't integrate the diff module with it. Also there is no other way round to solve my problem.

Thanks
Shubham
(Technical Writer)

The last submitted patch, 35: 2636406-27.patch, failed testing.

phenaproxima’s picture

Status: Needs work » Needs review
FileSize
24.34 KB

Rerollèd.

phenaproxima’s picture

Status: Needs review » Needs work
  1. +++ b/diff.views.inc
    @@ -0,0 +1,36 @@
    +  $entity_types = \Drupal::entityTypeManager()->getDefinitions();
    +  $revisionable_entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
    +    return $entity_type->isRevisionable();
    +  });
    

    This can be condensed a bit: array_filter(get_entity_types(), function () { ... })

  2. +++ b/src/Plugin/views/field/DiffFrom.php
    @@ -0,0 +1,98 @@
    +  protected function getToFieldId() {
    

    This is missing a doc comment.

  3. +++ b/src/Plugin/views/field/DiffFrom.php
    @@ -0,0 +1,98 @@
    +    $to_fields = array_filter($this->view->field, function (FieldPluginBase $field) {
    +      return $field instanceof DiffTo;
    +    });
    +    return array_keys($to_fields)[0];
    

    As a micro-optimization, we could just foreach through the fields and return ASAP.

  4. +++ b/src/Plugin/views/field/DiffFrom.php
    @@ -0,0 +1,98 @@
    +      $diff_from = $form_state->getValue($this->options['id']);
    +      $diff_from_entity = $this->loadEntityFromDiffFormKey($diff_from);
    +
    +      $diff_to = $form_state->getValue($this->getToFieldId());
    +      $diff_to_entity = $this->loadEntityFromDiffFormKey($diff_to);
    

    If the entities can't be loaded for any reason, things are going to blow up. Can we add a couple of sanity checks here?

  5. +++ b/src/Plugin/views/field/DiffFrom.php
    @@ -0,0 +1,98 @@
    +      if ($diff_from_entity instanceof NodeInterface) {
    +        $form_state->setRedirect('diff.revisions_diff', [$entity_type_id => $diff_from_entity->id(),'left_vid' => $diff_from_entity->getRevisionId(), 'right_vid' => $diff_to_entity->getRevisionId()], $options);
    +      }
    +      else {
    +        $route_name = 'entity.' . $entity_type_id . '.revisions_diff';
    +        $form_state->setRedirect($route_name, [$entity_type_id => $diff_from_entity->id(), 'left_revision' => $diff_from_entity->getRevisionId(), 'right_revision' => $diff_to_entity->getRevisionId()], $options);
    +      }
    

    Can there be a comment explaining why nodes need different handling from other entity types?

  6. +++ b/src/Plugin/views/field/DiffPluginBase.php
    @@ -0,0 +1,145 @@
    +  public function getCacheMaxAge() {
    

    No doc comment?

  7. +++ b/src/Plugin/views/field/DiffPluginBase.php
    @@ -0,0 +1,145 @@
    +  public function getValue(ResultRow $row, $field = NULL) {
    +    return '<!--form-item-' . $this->options['id'] . '--' . $row->index . '-->';
    +  }
    

    Will getCacheMaxAge() prevent this placeholder from being render-cached? I ask so that we don't run into an issue like the one over in #2758767: [Needs tests] EB views that sort in descending order are broken by render caching.

  8. +++ b/src/Plugin/views/field/DiffPluginBase.php
    @@ -0,0 +1,145 @@
    +    $key = json_encode($key_parts);
    

    Should we use Drupal's JSON serializer here? I think it wraps around json_encode(), but using Drupal's components is probably best practice.

  9. +++ b/src/Plugin/views/field/DiffPluginBase.php
    @@ -0,0 +1,145 @@
    +    $key_parts = json_decode($key);
    

    Ditto about using Drupal's serializer.

  10. +++ b/src/Plugin/views/field/DiffTo.php
    @@ -0,0 +1,48 @@
    +  public function viewsForm(&$form, FormStateInterface $form_state) {
    +    $use_revision = array_key_exists('revision', $this->view->getQuery()->getEntityTableInfo());
    +
    +    if (!empty($this->view->result)) {
    +      $form[$this->options['id']]['#tree'] = TRUE;
    +      foreach ($this->view->result as $row_index => $row) {
    +        $entity = $row->_entity;
    +        $form[$this->options['id']][$row_index] = [
    +          '#type' => 'radio',
    +          '#parents' => [$this->options['id']],
    +          '#title' => $this->t('Compare this item'),
    +          '#title_display' => 'invisible',
    +          '#return_value' => $this->calculateEntityDiffFormKey($entity, $use_revision),
    +        ];
    +      }
    +    }
    

    I haven't done a line-by-line review, but this look awfully similar to what's in the DiffFrom plugin. Can they both inherit this code from their base class? Or better yet, do they even need to be two different plugins? Can't we simply use the same plugin for both the diff__from and diff__to fields?

  11. +++ b/src/Tests/DiffViewsTest.php
    @@ -0,0 +1,65 @@
    +  public function testDiffView() {
    

    Doc comment.

The last submitted patch, 41: 2636406-41.patch, failed testing.

dawehner’s picture

@phenaproxima
Thank you for your response! As said on IRC, its great that people actually care about it.

Feel free to fix whatever you find.

If the entities can't be loaded for any reason, things are going to blow up. Can we add a couple of sanity checks here?

Yes <3

Should we use Drupal's JSON serializer here? I think it wraps around json_encode(), but using Drupal's components is probably best practice.

I couldn't care less. This is some internal PHP variable which will never be returns as HTTP response.

I haven't done a line-by-line review, but this look awfully similar to what's in the DiffFrom plugin. Can they both inherit this code from their base class? Or better yet, do they even need to be two different plugins? Can't we simply use the same plugin for both the diff__from and diff__to fields?

Yeah I haven't put an effort into trying to share code. Feel free to try out!

phenaproxima’s picture

The failing test should still fail, but this addresses some of my comments from #42.

phenaproxima’s picture

Status: Needs work » Needs review
FileSize
24.49 KB
1.33 KB

This oughta fix the failures!

Status: Needs review » Needs work

The last submitted patch, 46: 2636406-46.patch, failed testing.

phenaproxima’s picture

Status: Needs work » Needs review
FileSize
24.52 KB
384 bytes
dawehner’s picture

For me this patch looks kinda great, but well, I'm a bit biased :)

  1. +++ b/src/Plugin/views/field/DiffFrom.php
    @@ -35,28 +35,22 @@
    -    return array_keys($to_fields)[0];
    +    /** @var FieldPluginBase $field */
    +    foreach ($this->view->field as $id => $field) {
    

    Is this actually needed here? $view->field is documented as \Drupal\views\Plugin\views\field\FieldPluginBase[]

  2. +++ b/src/Plugin/views/field/DiffFrom.php
    @@ -78,12 +72,18 @@
    +      // We need both entities, so quietly abort if neither can be loaded for
    +      // any reason.
    +      // TODO: Should we throw an exception instead?
    +      if (empty($diff_from_entity) || empty($diff_to_entity)) {
    +        return;
    +      }
    +
    

    Is that some form of missing form validation or so? I mean ideally we would never get to it.

  3. +++ b/src/Plugin/views/field/DiffPluginBase.php
    @@ -101,11 +128,10 @@
         // safe to use in HTML, and that the key parts can be retrieved.
    -    $key = json_encode($key_parts);
    +    $key = Json::encode($key_parts);
    

    I couldn't care less about it. Its never exposed to the user

phenaproxima’s picture

1. PHPStorm didn't seem to be able to detect it on its own, but it certainly is documented. Will remove.
2. What do you mean by form validation? I agree it's a bit kludgey, but the point is to avoid fatal errors. Happy to take any suggestions on how to improve that bail-out code.
3. If you don't care, then I guess I don't need to change this :)

dawehner’s picture

2. What do you mean by form validation? I agree it's a bit kludgey, but the point is to avoid fatal errors. Happy to take any suggestions on how to improve that bail-out code.

I got that, but do we maybe have to be more defensive before evening reaching this piece of code?

3. If you don't care, then I guess I don't need to change this :)

Yeah, just saying :)

phenaproxima’s picture

How's this?

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Seems reasonable :)
I like this patch, but you know, I'm a bit biased.

The last submitted patch, 45: 2636406-45.patch, failed testing.

miro_dietiker’s picture

Looks pretty fine.
Nit: some comments lack a final ".".

Also..

  1. +++ b/src/Plugin/views/field/DiffPluginBase.php
    @@ -0,0 +1,178 @@
    +    return '<!--form-item-' . $this->options['id'] . '--' . $row->index . '-->';
    

    Is this comment stuff needed? Seems like no real help to me.

  2. +++ b/src/Plugin/views/field/DiffPluginBase.php
    @@ -0,0 +1,178 @@
    +          '#title' => $this->t('Compare this item'),
    

    I thought about accessibility here and if this is enough to cover ARIA requirements...
    First thought if we should offer different title for "from" and "to"...

    Then compared with the default node diff tab to see the radio has no title / alt at all... and that the operations is abused for from and neither to nor the row action button has a table heading. Needs a major revisit there...
    I guess we should create followups to investigate the accessibility situation.

dawehner’s picture

I thought about accessibility here and if this is enough to cover ARIA requirements...
First thought if we should offer different title for "from" and "to"...

Then compared with the default node diff tab to see the radio has no title / alt at all... and that the operations is abused for from and neither to nor the row action button has a table heading. Needs a major revisit there...
I guess we should create followups to investigate the accessibility situation.

Good point!

Is this comment stuff needed? Seems like no real help to me.

Well its how other forms are generated in views. Just to be clear, this is defensive programming of the case that somehow for whatever reason the replacement doesn't work.

dawehner’s picture

But sure we can drop it, when you think it is not worth here.

miro_dietiker’s picture

Status: Reviewed & tested by the community » Fixed

Committed, works nicely.
Also, i added some help text. The emptyness was confusing in the add dialog.
Pity / sorry, not yet in diff alpha3, but we should go beta soon anyway after working through the cleanup issues.

Interesting things happen when you end up creating a view that is not limited to a node.
Comparing two revisions of different nodes results in a 403 link that tries to compare node a in context of node a with a revision id of node b.
No idea if we could somehow avoid this misconfiguration. ;-)

The 7.x branch is not our business. Feel free to mark for backport. :-)

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

ksenzee’s picture

Would a maintainer please reopen this issue and move it to the 7.x queue for backport?