#257 | interdiff-257.txt | 988 bytes | amateescu |
#257 | 2862041-257.patch | 63.26 KB | amateescu |
|
#256 | 2862041-256.patch | 63.29 KB | timmillwood |
|
#256 | interdiff-2862041-256.txt | 1.07 KB | timmillwood |
#251 | interdiff-251.txt | 14.68 KB | amateescu |
#251 | 2862041-251.patch | 63.11 KB | amateescu |
|
#251 | 2862041-251-test-only.patch | 63.11 KB | amateescu |
|
#249 | 2862041-249.patch | 55.07 KB | timmillwood |
|
#249 | interdiff-2862041-249.txt | 5.08 KB | timmillwood |
#248 | Screenshot-2018-1-11 Content (Content) drupal 8 5 x(1).png | 157.52 KB | larowlan |
#248 | Screenshot-2018-1-11 Content (Content) drupal 8 5 x.png | 169.02 KB | larowlan |
#245 | interdiff-245.txt | 1.25 KB | amateescu |
#245 | 2862041-245.patch | 54.6 KB | amateescu |
|
#243 | interdiff-243.txt | 1.18 KB | amateescu |
#243 | 2862041-243.patch | 54.26 KB | amateescu |
|
#241 | 2862041-241.patch | 53.92 KB | Manuel Garcia |
|
#236 | Peek 2018-01-02 10-00.gif | 2.77 MB | Manuel Garcia |
#229 | interdiff-229.txt | 849 bytes | amateescu |
#229 | 2862041-229.patch | 53.87 KB | amateescu |
|
#227 | interdiff.txt | 1.1 KB | amateescu |
#227 | 2862041-227.patch | 53.91 KB | amateescu |
|
#222 | Content__Content____Site-Install.png | 107.17 KB | Sam152 |
#220 | interdiff.txt | 10.76 KB | amateescu |
#220 | 2862041-220.patch | 54.06 KB | amateescu |
|
#218 | interdiff.txt | 2.11 KB | amateescu |
#218 | 2862041-218.patch | 47.8 KB | amateescu |
|
#217 | interdiff.txt | 11.53 KB | amateescu |
#217 | 2862041-217.patch | 48.76 KB | amateescu |
|
#211 | interdiff.txt | 6.41 KB | amateescu |
#211 | 2862041-211.patch | 47.96 KB | amateescu |
|
#210 | interdiff.txt | 12.69 KB | amateescu |
#210 | 2862041-210.patch | 43.69 KB | amateescu |
|
#205 | 2862041-205.patch | 46.49 KB | jofitz |
|
#205 | interdiff-203-205.txt | 702 bytes | jofitz |
#203 | actually-2862041-201.patch | 46.49 KB | Sam152 |
|
#201 | 2862041-201.patch | 8.08 KB | Sam152 |
|
#201 | interdiff.txt | 1.23 KB | Sam152 |
#200 | 2862041-200.patch | 45.55 KB | Sam152 |
|
#200 | interdiff.txt | 6.85 KB | Sam152 |
#194 | 2862041-194.patch | 39.23 KB | Sam152 |
|
#194 | 2862041-interdiff.txt | 20.84 KB | Sam152 |
#189 | Screen Shot 2017-09-10 at 4.41.14 pm.png | 79.28 KB | Sam152 |
#189 | Screen Shot 2017-09-10 at 4.34.44 pm.png | 91.46 KB | Sam152 |
#189 | 2862041-189.patch | 43.19 KB | Sam152 |
|
#189 | interdiff.txt | 6.65 KB | Sam152 |
#186 | Screenshot_20170910_054743.png | 35.35 KB | amateescu |
#186 | interdiff.txt | 6.78 KB | amateescu |
#186 | 2862041-186.patch | 42.52 KB | amateescu |
|
#158 | 2862041-158.patch | 39.26 KB | Sam152 |
|
#158 | interdiff.txt | 794 bytes | Sam152 |
#155 | 2862041-155.patch | 39.26 KB | Sam152 |
|
#155 | 2862041-155_TEST_ONLY.patch | 38.82 KB | Sam152 |
|
#155 | interdiff.txt | 4.4 KB | Sam152 |
#152 | 2862041-152.patch | 38.47 KB | Sam152 |
|
#152 | 2862041-152_TEST_ONLY.patch | 38.24 KB | Sam152 |
|
#152 | interdiff.txt | 4.78 KB | Sam152 |
#149 | 2862041-149.patch | 44.41 KB | timmillwood |
|
#149 | 2862041-149.txt | 2.92 KB | timmillwood |
#147 | 2862041-147.patch | 41.41 KB | Sam152 |
|
#147 | interdiff.txt | 788 bytes | Sam152 |
#146 | 2862041-146.patch | 41.49 KB | Sam152 |
|
#146 | interdiff.txt | 7.83 KB | Sam152 |
#143 | three_nodes.png | 101.51 KB | xjm |
#143 | frontpage_empty.png | 39.5 KB | xjm |
#143 | no_valid_values.png | 13.45 KB | xjm |
#143 | filters_unknown.png | 40.14 KB | xjm |
#143 | filter_config_no_relevant_bundles.png | 79.36 KB | xjm |
#135 | 2862041-131.patch | 35.23 KB | amateescu |
|
#133 | interdiff-2862041-132-133.txt | 669 bytes | hamrant |
#133 | 2862041-133.patch | 36.65 KB | hamrant |
|
#132 | 2862041-132.patch | 36.61 KB | hamrant |
|
#132 | interdiff-2862041-131-132.txt | 2.98 KB | hamrant |
#131 | 2862041-131.patch | 35.23 KB | Sam152 |
|
#131 | interdiff.txt | 4.65 KB | Sam152 |
#127 | 2862041-127.patch | 37.07 KB | Sam152 |
|
#123 | 2862041-123.patch | 37.72 KB | timmillwood |
|
#123 | interdiff-2862041-123.txt | 1.12 KB | timmillwood |
#120 | 2862041-120.patch | 37.13 KB | timmillwood |
|
#120 | interdiff-2862041-120.txt | 584 bytes | timmillwood |
#116 | 2862041-116.patch | 37.13 KB | timmillwood |
|
#116 | interdiff-2862041-116.txt | 1.34 KB | timmillwood |
#114 | 2862041-108.patch | 36.58 KB | timmillwood |
|
#109 | 2862041-108-TESTS--64-FILTER_FAIL.patch | 36.14 KB | Sam152 |
|
#109 | interdiff_FAIL.txt | 4.48 KB | Sam152 |
#108 | 2862041-108.patch | 36.58 KB | timmillwood |
|
#108 | interdiff-2862041-108.txt | 2.85 KB | timmillwood |
#106 | 2862041-106.patch | 36.56 KB | timmillwood |
|
#106 | interdiff-2862041-106.txt | 3.61 KB | timmillwood |
#101 | interdiff-2862041.txt | 1.76 KB | dawehner |
#101 | 2862041-101.patch | 35.06 KB | dawehner |
|
#98 | interdiff.txt | 972 bytes | Sam152 |
#98 | 2862041-98.patch | 35.38 KB | Sam152 |
|
#96 | interdiff-2862041.txt | 3.83 KB | dawehner |
#96 | 2862041-96.patch | 34.73 KB | dawehner |
|
#90 | interdiff.txt | 1.98 KB | amateescu |
#90 | 2862041-90.patch | 35.13 KB | amateescu |
|
#81 | 2862041-80.patch | 34.55 KB | timmillwood |
|
#79 | 2862041-79.patch | 74.03 KB | timmillwood |
|
#79 | interdiff-2862041-79.txt | 1.04 KB | timmillwood |
#77 | 2862041-77.patch | 34.44 KB | timmillwood |
|
#77 | interdiff-2862041-77.txt | 1.19 KB | timmillwood |
#68 | Screen Shot 2017-08-14 at 9.23.56 PM.png | 96.34 KB | webchick |
#66 | Screen Shot 2017-08-14 at 12.07.34 PM.png | 72.1 KB | Sam152 |
#66 | Screen Shot 2017-08-14 at 12.07.11 PM.png | 122.36 KB | Sam152 |
#66 | Screen Shot 2017-08-14 at 12.06.50 PM.png | 55.45 KB | Sam152 |
#64 | provide_useful_views-2862041-64.patch | 34.01 KB | jibran |
|
#64 | interdiff-c1296d.txt | 1.55 KB | jibran |
#62 | provide_useful_views-2862041-62.patch | 33.97 KB | jibran |
|
#62 | interdiff-d8f8b7.txt | 2.02 KB | jibran |
#59 | 2862041-59.patch | 33.22 KB | Sam152 |
|
#59 | interdiff.txt | 1.66 KB | Sam152 |
#49 | 2862041-49.patch | 33.02 KB | Sam152 |
|
#49 | interdiff.txt | 2.8 KB | Sam152 |
#46 | 2862041-46.patch | 33.01 KB | amateescu |
|
#36 | 2862041-states-views-filter-36.patch | 33.02 KB | Sam152 |
|
#36 | interdiff.txt | 2.69 KB | Sam152 |
#8 | content_moderation-provide-checklist-workflow-states-views-filter-2862041-8.patch | 2.15 KB | mgalalm |
|
#12 | 2862041-states-views-filter-12.patch | 17.27 KB | Sam152 |
|
#16 | interdiff.txt | 7.75 KB | Sam152 |
#16 | 2862041-states-views-filter-16.patch | 23.9 KB | Sam152 |
|
#17 | 2862041-states-views-filter-17.patch | 23.92 KB | Sam152 |
|
#17 | interdiff.txt | 740 bytes | Sam152 |
#20 | interdiff.txt | 1.03 KB | Sam152 |
#20 | 2862041-states-views-filter-20.patch | 24.08 KB | Sam152 |
|
#24 | interdiff.txt | 13.39 KB | Sam152 |
#24 | 2862041-states-views-filter-24.patch | 32.15 KB | Sam152 |
|
#31 | 2862041-states-views-filter-30.interdiff.txt | 609 bytes | plach |
#31 | 2862041-states-views-filter-30.patch | 32.75 KB | plach |
|
#31 | 2862041-states-views-filter-30.combined.patch | 44.71 KB | plach |
|
Comments
Comment #2
plachThis was defined as MUST-HAVE by @webchik in #2755073-10: WI: Content Moderation module roadmap:
Working on this.
Comment #3
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedIs this a duplicate of #2859384: Provide checklist of workflow states in Views filter?
Comment #4
plachYes, it seems so. I closed that since this is linked in the meta issues, I will summarize any relevant info here.
Comment #5
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI spoke about this briefly in IRC, but I think it would be great to provide good views support for the computed content moderation state field on the entities under moderation, without the need to add a relationship to the ContentModerationState entity.
If we can do that here for filtering, #2852067: Add support for rendering computed fields to the "field" views field handler solves being able to view the state.
After we have filtering and support for viewing the computed field on the moderated entity, I think we should remove the views relationship to the ContentModerationState entirely, honoring it's @internal status by putting it out of sight of users.
Comment #6
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedOpened #2894479: Deprecate the Views relationship from moderated content to the "content_moderation_state" entity to keep this issue focused.
Comment #7
plachI'm not going to get to this one before Monday morning.
Comment #8
mgalalm CreditAttribution: mgalalm at Johnson & Johnson commentedPlease see attached patch for an attempt to add this feature
Comment #9
handkerchiefPlease integrate this "feature" in the next drupal core 8.3.x update. 8.4.x is far away isn't? It's a really basic and required funcionality.
Comment #10
timmillwood@handkerchief - This won't get into 8.3.x, as it is WI critical it should get into 8.4.x. The 8.4.0 alpha release is only 2 weeks away, with the final release early october.
@mgalalm
This shouldn't go in ContentModerationState. It has nothing to do with the ContentModerationState entity.
Also, we need tests for this.
Comment #11
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedGoing to have a look at this. As per #6 going to try and ensure the filter is applied to the computed field on the moderated entity, not the ContentModerationState entity, to ensure no relationship is necessary in the views configuration.
Comment #12
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedPatch attached allows filtering on the computed field, directly on the entity being moderated, no relationships required.
Comment #13
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #14
plachHaving a look at this, however the IS needs some love :)
Comment #15
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commented@plach pointed out this doesn't seem to work with a view of node revisions. NW for fixing that + tests.
Comment #16
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI wasn't able to reproduce the bug, but adding a test case.
Comment #17
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThe field map is required in the assert to make this fail properly.
Comment #18
plachCode is looking great and on manual testing things look very nice too, awesome work!
I was able to find a problem with content revision views and multilingual: apparently this view works perfectly on a monolingual site but adding a language breaks the query.
Aside from that, I have only a few very minor remarks:
We should use a third person verb to start the doc block, what about "Provides a filter..."?
Creates
Views normally uses more verbose aliases, what about replacing
cms
withcontent_moderation_state
for consistency?Tests
"nodes" is a bit misleading, what about "a content type"?
Shouldn't these be
string[]
?Shouldn't this be
\Drupal\node\NodeInterface[]
?Comment #19
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #20
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThanks for the review, will address the feedback. This shows us the failure, but I suspect we'll also need to add another part of the 'extra' section to ensure langcode becomes part of the join criteria, unless that's auto-magically handled.
FWIW, the fail boils down to:
Can't see any obvious fixes for it yet.
Comment #21
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #22
plachI'll try to have a look to that failure during the weekend if you don't beat me to it, tomorrow I'll be AFK.
Comment #23
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI've opened a follow up for what I believe to be the cause #2896381: "TranslationLanguageRenderer" uses the wrong table for the "langcode" column with entity revision views.
Comment #24
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThis patch addresses #18 and adds multilingual support + tests.
It will go green as soon as the blocker is resolved.
Comment #26
tacituseu CreditAttribution: tacituseu commented#20 already has an issue
Comment #27
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThanks, @tacituseu, I've created a test and patch for the blocker. @plach, if have time to look at the progress on it, that'd be great. Looks like you're already familiar with the issue.
Comment #28
plachPostponed on #2446681: Error "Column 'langcode' in field list is ambiguous" thrown due to TranslationLanguageRenderer not rendering a field from a relationship.
Comment #29
plachActually postponed on #2896381: "TranslationLanguageRenderer" uses the wrong table for the "langcode" column with entity revision views.
Comment #30
dawehnerThe test coverage looks great!
Nitpick: let's document the parameters and provide class documentation for them
Let's use string comparison, you never know :)
This information could be fetched from the content moderation state entity key definition, right?
Is there a reason you couldn't get the entity key in the content_moderation_state entity?
Comment #31
plachHere's a patch combined with #2896381-9: "TranslationLanguageRenderer" uses the wrong table for the "langcode" column with entity revision views to check whether we are done here. This includes a one-line fix to a test module to fix a couple failures.
Setting to NR for the bot but this is still postponed.
Comment #32
plachMissed #30, setting to NW then.
Comment #33
plachComment #34
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedLooks like your work in the blocker is going to work for us here. I've +1d the approach in that issue, but having written the test, if it would be great if @dawehner could RTBC.
#30 is good feedback, happy to look at it. Re: #30.3 and #30.4, do we usually get that information from entity definitions when we are working with only a single specific entity type? If those fields ever changed, the tests would inform us right?
Comment #35
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedIf they were ever changed in core, yes, but contrib and custom code are free to rename things to whatever they want, so we should always get the table and field names from the entity definition.
Comment #36
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedAddressing the feedback in #30. Not combined with the fix, so will go read.
Comment #37
plachLooks RTBC to me, I'll move this back to postponed as soon as the bot is done testing.
Comment #39
plachComment #40
AnybodyPerfect, confirming RTBC by my manual tests. As soon as the testbot tests succeed this should become part of the module. It's really essential for building useful moderation views.
Thank you all so much.
Comment #42
timmillwoodThis is a "should have" to get Content Moderation stable, so moving back to 8.4.x
Comment #43
hamrant CreditAttribution: hamrant at FFW, Open Y, Drupal Ukraine Community for Drupal Ukraine Community commented@Sam152 thanks! patch #36 works great!
Comment #44
DuneBLI think it needs a reroll for 8.5 (one FAILED)
Comment #45
DuneBLJust to be clear: I was talking of the patch #36
And, after applying it on 8.5, I got the hideous The handler for this item is broken or missing. The following details are available:
Comment #46
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedRerolled for latest 8.4.x. This will still fail until the dependency gets in (#2896381: "TranslationLanguageRenderer" uses the wrong table for the "langcode" column with entity revision views).
Comment #47
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #49
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedRemoving calls to removed methods.
Comment #50
DuneBLMany thanks for the reroll.
I have applied #49 on 8.5 and it apply more cleanly.
Here is the only problem
Unfortunately, the problem remains (after cache clear): when I tried to add the moderation state field in the view UI, I got the following message:
Comment #51
jeqqThanks @Sam152! Tested #49, it works great with 8.4.x.
Comment #52
jibranJust some minor nits.
Let's store plugin in a local variable and not call the method twice.
This is not needed.
We have seen some nasty bugs related to join configurations and it's so easy to write the views data wrong for joins. Can we please have a
\Drupal\Tests\views\Kernel\Plugin\JoinTest
kind of tests for this, just to make sure that in future whenever someone changes this they have to update the test as well.Comment #53
jibranCan we please also have some screenshots of the filters and resultant queries?
Comment #54
DuneBL@Sam152: At the beginning of this issue, I can read
Is it because my site is multilingual that #49 doesn't solve the issue or is it because it is 8.5?
Comment #55
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedIssue summary just needs an update. The patch works with multilingual.
Comment #56
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedRe: #52.3, I don't know what this would look like, we don't want to retest the abstraction we're using?
Comment #57
jibranI had a quick chat with @dawehner and he agreed with #52.3.
Comment #58
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedLike I said in #56, what does this actually look like? Can you add it to the patch?
Comment #59
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedAddressing #52.(1|2) and filing a follow-up.
Comment #60
amateescu CreditAttribution: amateescu for Pfizer, Inc. commented@jibran, this patch does not add a new views join plugin, so I also don't understand #52.3. Can you open a followup and explain in more detail what you meant?
Otherwise, the patch looks really good!
Comment #61
jibranI'm working on a patch. I'll post soon.
Comment #62
jibranAdded asserts for join config.
Here is resultant query:
Comment #63
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedStill looks good apart from these two nitpicks, which could be fixed on commit :)
Extra new line here.
And here we could have some new lines to delimit these assertions.
Comment #64
jibranHere we go.
Comment #65
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedLooks good. RTBC++
Comment #66
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedAdding screenshots to IS as requested.
Comment #67
jibranThanks, Sam.
Comment #68
webchickI'll try and go back to find it, but the original must-have was that the Content view (or, failing that, a sub-tab) have a moderation state drop-down when Content Moderation module (or Workflow or whatever makes most sense) is installed. Because without that, people within the content approval flow get hard-blocked and can't actually "do" anything, because there's no way (without engaging the services of a Views Master™) to get a list of content in a Draft state:
The preview screenshot at https://www.drupal.org/files/issues/Screen%20Shot%202017-08-14%20at%2012... looks great; we just need to either apply that to the default Content view, or if that's too hard, add a "Moderate" or something sub-tab to that view that exposes the filter.
We can go over this on tomorrow's UX call if you'd like.
Comment #69
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThat would be great, but does it have to block this issue? This patch introduces the technical capability to add the filter. The details of integrating is mostly a UX conversation, whereas this has been a technical one so far.
Comment #70
webchickWe can do it as a follow-up, sure. But either way, it's a must-have and stands in the way of the module being marked stable, so whatever's easiest for you all.
Comment #71
webchickBumping back to needs review to reflect this.
Comment #72
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI'm inclined to go for a follow-up, just based on narrower scoped issues being easier to review and commit.
Comment #73
webchickOk cool, moving this one back to RTBC, will create a new WI critical in a sec w/ the contents of #68.
Comment #74
webchickHere we go: #2902187: Provide a way for users to moderate content
Comment #75
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedBased on the comment you made in #2755073: WI: Content Moderation module roadmap, I should clarify. This issue doesn't add a view or change any existing views configuration. It adds the ability for a site builder to add a views filter based on the "moderation state" field, which wasn't possible previously.
Comment #76
timmillwoodComment #77
timmillwoodThis issue didn't work with "NULL" or "NOT NULL" options, borrowing ideas from InOperator, this patch fixes that.
Comment #78
gambryMissing DocBlocks.
I'm not sure how ensureMyTable() is useful in here if we don't use $this->tableAlias in the addWhere().
It's a shame we are overriding parent method only because 'content_moderation_state.moderation_state' is hardcoded.
This should probably be
===
.Comment #79
timmillwoodThanks for the review, this patch addresses those three items.
I agree with #78.2, it is a shame we just can't use the parent methods, but Content Moderation is pretty special with it's ContentModerationState entity.
Comment #81
timmillwoodI messed up the patch, here's a new one, interdiff was still fine.
Comment #82
plachI think @gambry was actually suggesting to use the table alias returned by
::ensureMyTable()
in the where condition instead of hardcodingcontent_moderation_state
. Unless it's assuming the wrong table obviously :)Comment #83
timmillwood@plach -
::ensureMyTable()
returns a Node table, not a ContentModerationState table.Comment #84
plachOk, then ignore me :)
Comment #85
plachBack to RTBC, actually
Comment #86
timmillwoodBeen talking to @amateescu and he reminded me of #2817835-37: When enabling moderation apply a relative state where he suggested using
COALESCE()
. Here's some initial R&D around how we could use that to handle filtering entities which were created before moderation was enabled, and thus don't have a content_moderation_state entity to query against.We still need to handle entity types that don't have moderation enabled, and non-publishable entity types (such as block content).
Comment #87
timmillwoodEven with #86 I still support the RTBC.
If
COALESCE()
is something we want to do we can add it in #2902187: Provide a way for users to moderate content or another issue.Comment #88
webchickAfter discussing #2902187: Provide a way for users to moderate content with Tim earlier today, I don't think we need to explore the COALESCE option. With the tweaks suggested at #2902187-54: Provide a way for users to moderate content over there, the view makes sense to do what it's currently doing, and only showing things in a "needs moderation" state.
Comment #89
tim.plunkettIf this is a non-associative array, the += will fail. Could result in a pretty nasty bug?
Should use NestedArray::mergeDeep().
IMO this needs test coverage.
array_map(function (StateInterface $state) {
(missing space and typehint){@inheritdoc}
That is quite the punt, but okay
Comment #90
amateescu CreditAttribution: amateescu for Pfizer, Inc. commented@tim.plunkett, thanks for reviewing! :)
Re #89:
\Drupal\workflows\WorkflowTypeInterface::getStates()
always returns an associative array, I expanded its documentation because it wasn't clear in this regard. And that code is pretty well tested in\Drupal\Tests\content_moderation\Kernel\ViewsModerationStateFilterTest::testStateFilterStatesList()
Comment #91
xjmHmmm I don't think we should scope that to a followup. Wrong dependency info == data integrity issues.
We are also missing dedicated test coverage for the new view. There should be test coverage for all the twists and turns this issue has gone down in terms of what to display. This is not the kind of test coverage that should be scoped to followps.
Also let's not mark this issue RTBC with a combined patch with others that haven't landed yet, and please provide the no-test patches so it's easier to read what's part of this issue. Thanks!
Comment #92
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI think #91 was meant to be on #2902187: Provide a way for users to moderate content?
In this instance, when states disappear because of a deleted workflow, views handles this gracefully and the states simply disappear from the list. The impact is some stale state keys in configuration until the filter is resaved. Is there any chance of it being split up like this to keep things moving? Given this is already kinda big, I thought a follow-up would make more sense.
Comment #93
dawehnerIs there a reason we don't assign $this->tableAlias , given that this is what this relationship represents? Once done we could get rid of
opEmpty
andopSimple
Comment #94
larowlanI'm with @tim.plunkett on this - that's a big gamble. I think without that, backporting this to 8.4 would be off the table. So does that reduce the urgency here?
Comment #95
amateescu CreditAttribution: amateescu for Pfizer, Inc. commented@dawehner, that was asked before in #82 and replied to in #83 ;)
Comment #96
dawehner@amateescu
At least #82/#83 is not what I would have intended.
Note: I'm uploading the patch to see whether it fails ...
Comment #98
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedUpdating the
@todo
with a comment as to why we shouldn't actually implementcalculateDependencies
.@see #2901690: Implement ModerationStateFilter::calculateDependencies. for some further discussion on this.
Comment #99
timmillwoodThe condition is if table alias is not set, but then we use table alias for the left_table. Something tells me this is why the test is failing.
Comment #100
timmillwoodThese changes give the same failing tests as #96. In one test the table is missing on
content_moderation_state.langcode = .langcode
and on another the table is missing onrevision_id = content_moderation_state.content_entity_revision_id
.Comment #101
dawehnerHere is a fix for my experiment.
Comment #102
timmillwoodTested locally, much clearer, thanks @dawehner.
That comment makes sense based on #2901690: Implement ModerationStateFilter::calculateDependencies., hope it's ok for @larowlan.
Comment #103
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThe changes from #96 and #101 seem to make sense, there's just one problem though: the patch that fixed "NULL" or "NOT NULL" handling in #77 did not add any tests for the fix, so we don't know if the latest changes from @dawehner have any impact on them..
Comment #104
jibranChanges look good. Thanks @dawehner for jumping in.
Let's change the name to $table_alias. Can be fixed on commit.
Comment #105
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedI think #103 is pretty serious though, we have no idea if "NULL" or "NOT NULL" handling is still working after the latest changes, since they are not tested.
Comment #106
timmillwoodI have been doing a bit of manual testing, and the NULL and NOT NULL look to be pretty stable, here's an initial patch which adds a NOT NULL filter to the main test view, also fixes #104.
Comment #108
timmillwood- Fixing the views config
- Adding a non moderated content type and node to test it isn't listed in any views.
- Adding a test for a view with no options selected in the exposed filters.
Comment #109
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI ran the tests in #108 against the filter in #64, the latest patch before the NULL handling was added. Fail patch attached should prove they work as described.
Comment #110
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #112
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedFail expected, RTBC for #108.
Comment #113
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #114
timmillwoodAwesome, thanks for testing @Sam152!
Reuploading #108 so it's 100% clear this is the patch to be committed.
Comment #115
gambryIs there a reason why the views schema configuration lives in
content_moderation.schema.yml
instead ofcontent_moderation.views.schema.yml
?I can't find any documentation/best practice about it but I can see all core modules have the views config schema definitions inside *.views.schema.yml .
If there isn't any and views schema should be in *.views.schema.yml for consistency, it can be done in a follow-up as there is already a pre-existing
views.filter.latest_revision
to be moved too.Comment #116
timmillwoodGood point @gambry, lets move all views schema to content_moderation.views.schema.yml, tested all content_moderation tests locally, so going straight o RTBC.
Comment #117
xjmCore UI labels should be sentence case rather than title case unless it's a proper noun (like the name of a module).
Hmmm. So I think this is saying that we won't have (e.g.) access bypasses due to a deleted state because no content would be in the state anymore if the filter were no longer functional.
I'm still not entirely sure about this; "mitigating" the impact of potential data integrity issues is still not a reason to introduce them. We also get into trouble a lot when we make assumptions like this for core, but then contrib does something with the data that bypasses core expectations.
At a minimum, we should have thorough functional test coverage for what we expect to happen in different scenarios where relevant workflows, states, provider modules, etc. are not available.
I'd also want to see and review that the view is properly cleaned up (without noisy diffs in config), that it can be re-saved afterward, that it is still functional, etc.
Comment #118
xjmFor others, here's the discussion from the other issue. From @amateescu:
And from @Sam152:
Comment #119
amateescu CreditAttribution: amateescu for Pfizer, Inc. commented@xjm, please see #2901690-7: Implement ModerationStateFilter::calculateDependencies. and #2901690-9: Implement ModerationStateFilter::calculateDependencies. for the reasoning behind that code comment. I'll repeat a short version of it here as well:
Workflow states can not be deleted while there is existing content using them. When that content is gone and the state can be deleted, a views filter that excludes entities with that workflow state will have nothing left to exclude because there are no entities with the given state anymore.
There is no impact to mitigate because there is no impact at all. The code comment shouldn't say anything about mitigation actually :)
Comment #120
timmillwoodAlthough it could be done on commit, here's a patch fixing #117.1.
I agree with there being no need to implement calculateDependencies, and tried, but can't think of a better comment to explain this. We put a lot of work into making sure that states and workflows cannot be deleted via the UI or via config import when there is content uses the workflows or states, so this is a non-issue.
Moving to "Needs review" for another check by @xjm prior to commit.
Comment #121
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI think this part is still outstanding:
But if we can agree in principle it'll be empty, maybe that isn't a blocker.
Comment #122
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThe "where provider modules are not available" part got me thinking that we should do this: #2904101: Do not allow modules that provide a workflow type plugin with existing data to be uninstalled
Comment #123
timmillwoodHere is a patch updating the test to make sure that if a workflow or state is removed the states are removed from the filter. Workflows and States which are in use cannot be deleted therefore testing the entities returned by a view isn't possible.
Comment #124
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI think the testing in #123 is sufficient for to at least unblock this issue and further work on the follow-up view.
The primary concern that was blocking this issue, in my understanding was that a missing implementation of
calculateDependencies
would cause serious problems. If that has now been debunked, in my eyes it'd be best to get this in now with a follow-up (which I'll happily allocate time to) to cover more detailed testing that dives into:My reasoning for addressing this in a follow-up is to unblock folks working on #2902187: Provide a way for users to moderate content quickly. I'm hoping the above doesn't need to block that.
@xjm, if that approach is too much of the cart before the horse, it'd be great if you could chime in so we can prioritise work accordingly.
Comment #125
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #126
hamrant CreditAttribution: hamrant at Open Y, Drupal Ukraine Community for Drupal Ukraine Community commentedIt would be cool to add to the filter settings the ability to select the workflow type. For example, I have 2 workflow types and both is used in different node types. In this case views filter will show all moderation states from both workflow types instead states of workflow type for current entity bundle.
Comment #127
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedRerolling.
Comment #128
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI think this only gets into 8.4.x is the follow-up view gets in, so 8.5 is more correct?
Comment #130
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedSome of the test config needs updating since #2865579: Rewrite the 'Latest revision' views filter and remove the revision_tracker table.
Comment #131
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThis was assumed for views with a relationship, but now that we've removed the relationship seems like we have to put it back manually.
Since #2865579: Rewrite the 'Latest revision' views filter and remove the revision_tracker table we no longer have the latest_revision relationship, so no need to test it here.
Comment #132
hamrant CreditAttribution: hamrant at Open Y, Drupal Ukraine Community for Drupal Ukraine Community commentedAccording to #126 comment I have updated last patch. In this update was provided ability to select workflow types in ExtraOptionsForm and value options now related to this option, if nothing is selected it shows all the options.
Comment #133
hamrant CreditAttribution: hamrant at Open Y, Drupal Ukraine Community for Drupal Ukraine Community commentedMinor fix
Comment #135
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedI fully agree with #124 and the fixes from #131 makes sense, so back to RTBC!
@hamrant, I discussed #126 with @Sam152 and we both think that this extra feature is outside the 80% use case of this filter and that it should be discussed/added in a followup. We need to keep in mind that time is very important here because we still very much want this issue and the one that it blocks to be committed before 8.4.0-beta2.
Re-uploading the patch from #131 to be clear which one we think it's ready to go.
Comment #136
xjmThanks all! Assigning to myself for review both of the work on the issue here since and to test the kinds of edgecase scenarios I'm concerned about.
Comment #137
hamrant CreditAttribution: hamrant at Open Y, Drupal Ukraine Community for Drupal Ukraine Community commented@amateescu, ok, thanks for checking
Comment #138
timmillwood@xjm - How are the edge case tests going? Is there anything we can do to help drive this forward?
Comment #139
xjmOkay, so one thing that came up in the course of my testing.
I was originally expecting that the state filter would be supplied by Workflows rather than by Content Moderation (since Workflows supplies the concepts of workflows, states, and transitions). Is there a reason that the plugin is supplied by Content Moderation instead? I didn't see anything about this when cmd-f "workflows" on the issue, but I haven't read all 130 comments.
Comment #140
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThat's because the filter is using a join on the ContentModerationState entity type, which is an internal implementation of Content Moderation. That's also why the filter is called
content_moderation_state
and notworkflow_state
.Comment #141
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI can echo #140. Workflows has no knowledge of the thing-being-workflowed, implementations may choose to store states and use transitions in any fashion they like, the job of workflows is to allow the creation and configuration of the constraints, not to dictate how a state is stored or used. One interesting use-case I've seen is someone using it to define the submission workflow of a multi-step form, the state "storage" in that instance is the associated
$form_state
.That's why workflows has no knowledge or association with entities at all.
content_moderation
introduces this association.Comment #142
xjmBut a Views filter is exactly a constraint?
Edit: I should clarify that the bit about not having any sort of table to join on with Workflows by itself is a reason, although it's a developer's reason rather than a sitebuilder's reason. However, that didn't necessarily need to be the case. :)
Comment #143
xjmOne weirdness happens when there are no relevant moderation states for whatever entity type is the base table of the view. For example:
Scenario A
/admin/structure/views/view/frontpage
.If I didn't know the underlying reason for this, I would be pretty confused right about now, because there are no options to configure for the filter. Well, that's as a Views maintainer. If I didn't know Views that well, I might not even notice. Since "Select all" isn't something I want, I might just click "Apply (all displays)" again. Since it's a checkbox rather than a radio button, there's no validation to fail, and Views happily adds the filter.
Unknown!
So, okay, this part is a Views bug. Views shouldn't let you submit the form with no options checked when it's a filter and operand that could allow multiple values. However, Views does at least prevent me from saving the View with this handy message:
The above can be a bit confusing, since it's essentially impossible for me to configure the filter correctly until I apply a workflow to some bundle of the entity type of the view's base table (nodes in this case). (And we wouldn't want to have the Views UI to be confusing. Edit: This is a joke with the punchline being that the Views UI is confusing.) However, the risk is minimal because Views does eventually prevent you from saving the View that way.
Scenario B
/node
. You should see nodes 1, 2, and 3.It looks like the filter is defaulting to "Draft" rather than the more logical "- Any -". Okay, that's also a familiar Views configuration problem. If I instead select "- Any -" and click "Apply", my three published articles (which has no moderation state) re-emerge.
If I go back and edit the views configuration to uncheck the selected options, then it still displays all of them but switches to providing sensible defaults. A little-known "feature" here is that if you check some options but do not check the "Limit list" checkbox, the first one as displayed in the Views UI will be the default value.
Note that "Draft" will never show anything here, because the frontpage view, as per the best practice, has the published content filter. (This is kind of a sitebuilder UX gotcha; to truly use this exposed filter, I'd need to remove the "published content" filter. And that in turn is a security gotcha, because if I did that my view would start showing unpublished drafts to the world, so I'd have to replace it with a different access restriction on the view itself, presumably the "view unpublished content" permission. But these are both things that happen with views filters all the time.)
/node
frontpage again. Expected result: the "Future" state shows up in my selector. Actual result: No "Future". Edit:Oh. I think this might be a cache invalidation issue, because it goes away as soon as I create a node.
Aside: I accidentally deleted my Frontpage view about 10 times already while testing this. That's #2773205: Come up with a design for highly destructive operations in confirm forms.
Another aside: Adding a state named "9000" is enough to result in permanent fatal errors. I think I saw an issue for that as well, for any config entity, but did not find it yet because it's late.
Going to bed now, more tomorrow.
Edit: just labeling the two separate scenarios so that I can refer to them in further review.
Comment #144
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commented#2886567: Adding a workflow state or transition with an integer ID results in unrecoverable fatal errors is the ID issue.
Thanks for the really detailed analysis. I think you're correct in saying we might be missing some cache tags to invalidate the filter when the associated workflows are updated.
Comment #145
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWorkin' on it.
Comment #146
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedInitial crack at this. We need to be able to tag things with all workflows of a certain type. Adding a new workflow to an existing entity type with a views filter needs to invalidate it, so it's not enough to add the existing workflows providing states to the filter as dependencies.
As far as why we need to override
::invalidateTagsOnSave
, I'm not sure. It seems in the context of config entities, the::getCacheTagsToInvalidate
method is intentionally ignored. @see\Drupal\block\Entity\Block::postSave
or\Drupal\shortcut\Entity\Shortcut::postSave
for an example and\Drupal\Core\Config\Entity\ConfigEntityBase::invalidateTagsOnSave
for where the behavior is ignored.There was some funkyness where adding a new state to an existing workflow in the test didn't update the filter, but I couldn't reproduce in a real-world environment.
Comment #147
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedRemoving some left over junk.
Comment #149
timmillwoodTrying to fix the failing test.
Comment #150
Wim LeersI attempted to review #146 + #147 + #149, but I kept wondering what it was trying to achieve. It seems the answer can be found in #144:
Okay, so now I roughly know what it's trying to do, I can review it:
Where did this cache tag come from? Is this a new one you're generating here? Because workflow types are plugins, not entities. They don't have per-workflow-type cache tags. There only is the generic
workflow_type_plugins
cache tag, which covers the list of workflow type plugins that are installed.It's strange for the
Workflow
entity type to be defining a cache tag that seems to be associated with@WorkflowType
plugins. If we have a cache tag like this, I think something like'workflows_of_type:' . $this->type
would make more sense? (This reminds me of #2145751: Introduce ENTITY_TYPE_list:BUNDLE cache tag and add it to single bundle listing btw — it's similar, but not the same.)I'm missing documentation for this.
This comment is inaccurate if you read
\Drupal\Core\Config\Entity\ConfigEntityBase::invalidateTagsOnSave()
.You mentioned your reasoning in #146, but note that the docblock of
\Drupal\Core\Config\Entity\ConfigEntityBase::invalidateTagsOnSave()
explicitly explains why it does what it does.So this is really getting at the heart of it (I think).
I think you're trying to make sure that the options presented in the form are always up-to-date, to ensure they reflect any changes in
Workflow
entities that use thecontent_moderation
@WorkflowType
plugin.But then why introduce a new cache tag? Why not just reuse the
Workflow
entity type's list cache tag? You can get that by calling\Drupal\Core\Entity\EntityType::getListCacheTags()
.Yes, that would mean that even changes to
Workflow
entities that use another@WorkflowType
plugin thancontent_moderation
would cause the rendered exposed filter to be invalidated. But changing workflows is a sufficiently rare operation that that should be okay. And you could still optimize it later if the need arises.Finally: I'd think that you'd not override
getValueForm()
, but instead overridegetCacheTags()
. Then it'll also end up in here:So my recommendations:
Workflow
entity type list cache tags, don't introduce a new oneModerationStateFilter::getCacheTags()
, notModerationStateFilter::getValueForm()
Comment #151
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedAll three suggestions sound fantastic, thanks @Wim. I assumed it'd be a deal-breaker to invalidate more often than absolutely necessary, but your reasoning makes perfect sense.
Comment #152
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedInterdiff is from #135 because of the new approach. I've also uploaded a test only patch just for the bug reported in #143 and the test associated with that bug.
Comment #153
Wim LeersGlad you liked my suggestions :)
I like how #152's interdiff looks!
👏
Note: although only the
Node
entity type currently uses it, it's safer to also do the same forgetCacheContexts()
:EntityType::getListCacheContexts()
is also a thing.Note that
getListCacheContexts()
will just return[]
for theWorkflow
entity type, but it's the semantically correct thing to do.Hm, did you re-export this? I expected this to list the
Workflow
entity type's list cache tag.Nit: you can chain these.
And these.
Comment #155
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThanks for the review.
1. Beauty, didn't know entities could do this.
2. Good catch, re-exported.
3. The return value of
addEntityTypeAndBundle
is the@WorkflowType
not the entity.4. Same here, but removed these anyway.
This patch is also a minor test refactor to address some missing coverage I mentioned in #146. Previously I was manipulating the workflow entity in the test thread and visiting the pages in a sub-request. For some reason, the sub-request was loading the old non-updated entity, meaning adding a state wouldn't propagate onto the page. I've had a debugger in there for a few hours now, right into cache-backends, but couldn't figure this out. The rules around manipulating stuff in the test thread during functional testing and the sub-request have always been a bit janky for my liking, so I've simply performed the actions from the UI. I think this is far more widespread practice anyway, so hoping this is alright.
Another test only patch highlighting only the issue picked up in #143. I think this was the only bug with the filter specifically. A lot of issues I suspect would exist when using the
InOperator
with a list of taxonomy terms for example.Hope this addresses all of the critical concerns with the patch so we can get #2902187: Provide a way for users to moderate content done and into 8.4.x. 🤞
Comment #156
Wim LeersIt's good to see things work as expected :)
I'm hereby RTBC'ing the cacheability aspects of this patch. RTBC'ing the entire patch should be done by somebody else.
Comment #158
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #160
Wim LeersPesky semi-colons! 😭 😀
Comment #161
timmillwoodWhen a workflow is not set to any entity types the filter just shows "select all" as shown in the screenshot of #143.5, what can we do to address this?
Comment #162
xjmThanks @Sam152, testing the latest patch now.
Comment #163
xjm@timmillwood, a simple thing I was thinking we could do would be to add help text on that form explaining where the values come from. E.g.: "The Editorial and Marketing workflows apply to content, which has the following states available." or "No workflows are currently available for this content. They can be configured on the workflows administration page." etc.
Comment #164
xjmComment #165
xjmPosted #2906892: Only one workflow can be applied to a given bundle, but there is no indication in the UI (this came up because multiple workflows was one of the edgecases I was going to test; thankfully it appears that's not something we have to worry about).
Comment #166
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedAwesome, thank you for retesting!
Comment #167
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI think this is waiting on xjm for sign-off and RTBC.
Comment #168
xjmA summary of the general problem space I'm testing (which I should have given two weeks ago, sorry for that.) The situation currently is that what's presented as allowed values (for the filter, in an exposed filter, etc.) changes depending on changes to the workflow configuration. You may not be able to delete a state when it has content in it, but you can add or remove which bundles the workflow applies to, etc., and stale/invalid references will sit around in the View until someone edits the filter, at which point they magically disappear.
I was concerned that we might run into fatal data integrity issues for the view with scenarios where we change workflow configuration or remove states. However, I tested lots of permutations of this (more than just what's documented in #143; I fell asleep before writing them all out) and in all cases it was silently updated to the new state list.
One thing that wasn't exactly right was that the state names lingered in config exports. I think that's something that happens elsewhere in Views, though. The closest analogue I can think of is entity references e.g. taxonomy terms, and I tested and confirmed we already have the same problem there. (Filed #2907378: Cached view is not invalidated and dependencies not updated when removing a target entity for an ER filter for that.) Edit: But a more general followup for cleaning up views handler allowed values settings might be in order.
A difference is that taxonomy terms are stored as entities and @timmillwood explained that states are just stored on the given workflow. Tim suggested a filter based on allowed select field values instead.
I confirmed that If you configure a Views filter on an allowed value for a list field, and then remove the allowed value for the list field, the View is not cleaned up. So, that's still an existing problem in Views and can be out of scope here, but we should reference related/followup issues.
However, that scenario isn't entirely parallel: an allowed value can't be removed from a field when the field has that value, and removing the field entirely does disable the view (no longer deleting it since #2468045: When deleting a content type field, users do not realize the related View also is deleted). While you cannot delete a state when it is in use, you can disconnect the workflow from any content type that has it without changing the allowed states.
The above point made me wonder if we should prevent removing workflows from a bundle when a state from that workflow is in use in the same way that deleting the state is disallowed. That would be out of scope for this issue, but it would set expectations for this issue and reduce the need for creative ideas on how to break it.
Some more scenarios I haven't tested yet:
Edit: Fixing goofy list whitespace.
Comment #169
xjmHm, also debating whether we need #2859702: Add a Views filter for access to transition to a given moderation state first to avoid access bypass scenarios. (Thinking of the PSA again here.)
Comment #170
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedMy comment you are referring to (#119) has this explanation:
So I will assume that by 'design behavior', you are referring to that paragraph. A test scenario for this would look like:
- create an "editorial" content moderation workflow with two states, published, draft and archived; assign this workflow to the "article" node type
- create one article node with the "published" state
- create a different article node with the "draft" state
- create a different article node with the "archived" state
- create a view of node revisions, add the moderation_state filter and configure it to display display only nodes with the "published" and "draft" states
- check that the view shows all the three nodes above
- try to delete the 'archived' state -> you can't because there is a node using it (this is already tested in
\Drupal\Tests\content_moderation\Functional\ModerationFormTest::testWorkflowInUse()
)- delete the third node and then delete the 'archived' state
- check that the view does not show the third node anymore
The last step is what this whole discussion is about and I might be missing something, but isn't it obvious that the third node will not be displayed in the view because you just deleted it?
I think this is an entirely different topic. The filter we're adding here is intentionally not tied to the workflows that provide the allowed values (states). Btw, allowing the filter to be tied to specific workflows was actually discussed and decided against, see the second paragraph from #135.
If the user wants to filter the view by some specific bundles in addition to moderation states, there is a dedicated filter for that.
The PSA was about something else: views that do not have a views access plugin configured.
But if we go along with the line of thought, the access restriction expectation from this filter would be "only display entities with the given moderation states", because that's the only thing it can do.. and it does that just fine :)
Comment #171
xjmlol yes, but we should have coverage to ensure that nothing breaks when you remove the state, and for what we expect to happen to the view (that the view is not updated).
I helped write the PSA BTW so I know what is in it. We don't have any such for Content Moderation views to my knowledge. Again, ref. #2859702: Add a Views filter for access to transition to a given moderation state.
Comment #172
xjmMeant to say that I think #119 should further update the inline comment that's already there, but also
But the states' workflows can be removed from the bundles that include the entities, even though that's what supplies the allowed values in the View config, and the allowed values changes when the workflow is enabled or disabled for the bundle, which can happen even while content is in their states. That is what needs additional test coverage.
Comment #173
xjmAlso, some of the access bypass concerns I want to look into are out of scope here (e.g. changing which states are published and the mismatch of expectations between "content in this state is published" vs. the actual "content is published when it gets to this state") but might be blocking. But it was my next action item for me, not actionable yet for anyone else.
Comment #174
xjmBut it is tied to it because the allowed values presented in the Views UI depend which workflows are attached to the entity type for the base table, which you can change. When you change which workflows are attached to which entity types, the allowed values of states presented in the views UI change, but the view has not been updated.
Comment #175
xjmSteps to reproduce:
Comment #176
xjmOkay, there actually is a data integrity issue. If you do #175, it's impossible to ever save your view again without removing and fixing the filter. You'll get the validation error from my scenario A earlier.
So we do need the View to react somehow when a workflow is detached from an entity type entirely (if it's the last bundle), or "heal" the view somehow, or disallow removing it the workflow, or change the validation, or something. (Edit: added possibilities).
Comment #177
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedRe: cleaning up the view when workflows change, I wrote a bunch of test cases kind of in this realm in #2901690: Implement ModerationStateFilter::calculateDependencies.. Turns out it was really complicated with a bunch of edge-cases right below the surface. States being common across workflows made this tricky.
That is getting way too far into edge-cases IMO. If you've removed the archived state from content, this seems like reasonable or even expected behaviour. I'm pretty sure even though it exists in the config, it doesn't show up in the list, so resaving the filter doesn't actually change anything but the stored key.
I'm going to try reproduce and fix the bug of the view not being resavable when a filter is removed, that doesn't seem right. Is anything else in #168 in scope for this issue? I agree that we should look into stopping users from removing moderation from a bundle-in-moderation-with-data.
Comment #178
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedOk, here's an issue for the bug explained in #175: #2907449: Do not allow removing moderation for an entity bundle that has moderated content
Comment #179
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedAnd here's another issue for the access bypass problem hinted at in #173.
Comment #180
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWhat was the validation error in #176? I couldn't reproduce this.
Comment #181
timmillwoodI've been testing #175 and #176. I have been able to replicate the issue, and have also been able to replicate this with a select field, as stated in #168.4. So this is not an issue specific to Workflows.
In #176 this issue was marked "Needs work" because it was not possible to save the view after removing a workflow from an entity type. As the same issue of not being able to save a view also happens when removing an allow value from a list field, I think we can push this back to "needs review" and open a new issue to fix views InOperator filters in general.
Comment #182
timmillwoodOpened #2907573: Views using an InOperator filter cannot be saved if one of the ValueOptions doesn't exist anymore.
Comment #183
xjmThanks @timmillwood, I thought I had tested with the select list version and not encountered the error but I apparently hadn't actually tried to save the view yet (which is also I did not notice it at first with this until #176).
The reason I think this is different the select list case is that with a field's allowed values, you configure the list once in a single screen (and while you can edit it, there's a message on the screen claiming you can't so most people may not even try). If you up and deleted the field that the filter depended on, the view would get disabled.
Re:
Sorry, I wasn't saying you should be able to save it when it did not exist; I was saying that it meant the simple act of editing and re-saving the filter would result in what was stored in configuration changing, even though the user didn't change anything. This results in noise in configuration exports/deployments, a mismatch between the user's actions and the results, etc. I.e. data integrity issues.
I've seen it stated several times that states can be "shared across workflows" and that for this reason we don't want to depend on the workflow, and I've read all the past discussion, but I am still not convinced that's the right choice. There are just so many edgecases that we have to handle that the configuration system would handle for us if we declared a dependency. (Comparing it with the select list case, that's the equivalent of saying that we don't want to add a dependency on the field because the possible values of the field could be found in other select list fields' allowed values.) And really, they're not actually even the same state when they are "shared"; I've just created a state on one workflow called
foo
that's published and becomes the default revision, and a state calledfoo
on another workflow that is neither of those things.Comment #184
xjmSo my proposal would be that the filter be for State in Workflow X. Then, if Workflow X is changed, the view can react.
Comment #185
tacituseu CreditAttribution: tacituseu commented@xjm: The shared states idea was raised in 8.3.x rewrite issue (#2779647-27: Add a workflow component, ui module, and implement it in content moderation) and it was decided against it.
It was sort of the status quo before that, when it was closer to Workbench and there wasn't a support for multiple workflows but you kinda sorta could checkbox out a subset of the states per bundle.
In current implementation there can be multiple workflows that have the same ID/label (key in .yml) for their states, but that doesn't make them common in any meaningful way as they are independent (their settings/properties aren't shared).
If you need to mix and match them in some filter settings the sensible thing would be to prefix each state with the workflow name it belongs to, but then you would have to filter out duplicates if you want to shove them into one select list.
Comment #186
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedSo #183 and #185 finally made me realize that I was so wrong with my "states can be shared across workflows" argument. Sorry, @xjm!
As proposed in #184, we need to differentiate between states across workflows. Also, at this point I think it's actually useful to include the changes from #132.
Here's a starting point for the above, tests will need to be fixed and the logic for updating the view when something changes in a workflow needs to be written, but this should get the ball rolling in the right direction :)
The filter configuration screen looks like this now:
Comment #188
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWhile it's true that the same state ID could possibly have a different meaning across workflows and thus should be filtered different, that doesn't seem like the case for draft and published, which are on all CM workflows and contain settings that cannot be changed.
In any case, the actual likelihood you'd have two different workflows attached to two different bundles of the same entity type and want a view that gracefully created one select list for two workflows, sharing common states etc, seems pretty outside of the 80% as well, so I'm totally fine with the direction in #186.
I don't think we really need this. Surely if the user wanted to limit the workflow/states, they could simply select the relevant values.
I'm just thinking off the top of my head here, but is there any way we could create a new views field for each workflow. That way in the fields list, you'd select Moderation state (editorial) or Moderation state (foobar). It would add complexity in views data, but probably drastically simplify the implementation of the filter and I think it's possibly a clearer in terms of UX? Ie, a user could never start mixing states across different workflows in the same field, which I think given the paradigm of shared labels/IDs, but different semantics/meanings would be a win. Haven't tried this, but just a thought.
Comment #189
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedHere is an interdiff on top of #158 prototyping what I proposed in #188. I'm quite pleased how simple this ended up being, and it could probably be cleaned up a bit further as well.
If we're happy with this approach, happy to fix up and add additional testing as well as implement
calculateDependencies
andonDependencyRemoval
. Both of these method will be trivial if we're dealing with one workflow.Comment #191
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedWhile my patch from #186 was surely fun to write and discover hidden gems in Views, I agree that the approach in #189 is way simpler.
I don't have a preference either way, tbh, so let's ask a product manager if they think that having a single filter able to query across multiple workflows is useful or not :)
Ping @webchick?
Comment #192
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWith the approach in #186 we were treating states across workflows as individual items in the same list right? So this change just shifts the way the user enables additional workflows and splits those workflows into multiple lists. Sounds like the two options are pretty close in terms of outcomes, just a difference in terms of site building and front-end. So my guess would be this is acceptable from the product and technical angle, but would love to hear from @webchick and @xjm.
Comment #193
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #194
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedFixing tests, some clean up and implementing
calculateDependencies
.Looking at #2468045: When deleting a content type field, users do not realize the related View also is deleted, there is a
DependentWithRemovalPluginInterface
, but I'm not sure if that's only for display plugins, not the filter ones. In any case, for the view to gracefully clean-up when the config is updated/deleted, we can hopefully:$view->onDependencyRemoval()
to indicate the dependency it has is not actually a dependency anymore (hence removing it from the view).Still need feedback on the general approach, but if anyone has time to look at the above, my time is a bit stretched this week.
Comment #195
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commented@xjm FWIW, the behaviour is the standard views "broken/missing handler" when the entity type is removed from the workflow. I'm not sure if this is better or worse than the stale state list, but it leaves the config in-tact. It even tells the user what it was and gives them a chance to rectify the situation.
Given I don't think there is much else out there which tries to manually clean-up views config on entity_update (not a dependency being removed), perhaps we can scope that for a follow-up and discuss it there, given the current behaviour seems quite acceptable. I half suspect we'd arrive at the conclusion that it isn't worth doing.
Comment #196
xjmBlah, ugh, gah, I totally misremembered what was in the scope of #2212081: Remove views optional handler handling. The view is still merrily returning results with the broken handler... it should not be. That's (another) major views bug there.
We don't want to do this; in fact, we want to do not-this. Views filters can be used to restrict the data that is shown to the user. There's a reason we disable the view in #2468045: When deleting a content type field, users do not realize the related View also is deleted rather than trying to remove the configuration from the view: doing otherwise could result in access bypasses/information disclosure/etc. because we don't know how the user has used the field in their view.
I'll have a think and chat with some folks about it.
Comment #197
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedGreat, thanks for that additional context.
Comment #198
xjmSo we need to add a test case that does something like this:
This will currently fail in step 6 for @Sam152's version, because views is just ignoring the broken handler rather than disabling the output of the view. I thought that we'd made views with broken handlers return no results back before release. That feels like a views bug to me that would be a separate issue but changing that now would be extremely disruptive (sites that had views with broken handlers would update and then have site content disappear from views that were previously working).
The test will pass step 6 but fail in step 7 for @amateescu's patch, with:
11-Sep-2017 12:24:57 Europe/Berlin] TypeError: Argument 1 passed to Drupal\Core\Form\OptGroup::flattenOptions() must be of the type array, null given, called in /Applications/MAMP/htdocs/d8git/core/modules/views/src/Plugin/views/filter/InOperator.php on line 330 in /Applications/MAMP/htdocs/d8git/core/lib/Drupal/Core/Form/OptGroup.php on line 23
The earlier version of the patch will also pass step 6 and fail step 7.
So let's at least add that test scenario. We'll need to update its default views depending on the approach but I do want to make sure we have coverage for it. (It's basically what I was asking for test coverage for earlier on the issue.) We can hold off on making any one approach work until we get more feedback. I'll also look into it more.
Comment #199
xjmPosted #2907954: Views with broken handlers still return results even if the results might be incorrect to discuss the broken handler thing. Whatever we do here we should make sure that that doesn't happen.
I wonder if our config API should supply an
onDependencyChange()
or something. We can fix this issue in whatever way works without getting into that since it's also out of scope, but it could be a followup where we refactor whatever hotfix we use here to handle it with an added API.Comment #200
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedTotally missed what you were after in terms of testing previously, my bad! Here is the test case you've described in #198.
Not sure what a good solution is yet.
Comment #201
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedHere is a solution.
Comment #203
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedPatch for #201 but for real this time.
Comment #205
jofitz CreditAttribution: jofitz at ComputerMinds commentedCoding standards correction.
Comment #207
webchickOk, I got actually pinged today in #ux on Slack :D, so here's a summary of that conversation.
The use case: a site has two Workflows: Editorial and Translation. Both have a state called "Needs review." But that state means different things depending on context. Let's say for Editorial, it goes to Mary for review. For Translation, it goes to Maria.
We were asked to decide between the approach in #186 (optgroups):
...and #189 (a filter per workflow / state pairing):
My initial impressions:
Additionally, @CatherineOmega chimed in that for the non-technical users in her organization, optgroups would make more sense to them as well, so that's a second data point. (Adding her to the creditors list here, since she helped with the brainstorming.)
So unless @yoroy or @Bojhan or someone with more UX chops than us chimes in differently, that seems like the way to go. Hope that helps.
Comment #208
tim.plunkettArchitecturally both approaches seem reasonable, and have different downsides.
I think deferring to UX is a good choice.
Review of #186:
This has a strange hybrid approach to DI.
Nothing on ETM is being consulted directly, it's still used as a pseudo service locator.
With the one exception (getStorage($this->getEntityType()), every other call is known in advance. I believe it'd would be preferable to inject the needed classes then.
This goes to for the static helper methods like ::loadMultiple
This seems like it deserves dedicated test coverage, and maybe a comment?
Comment #209
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThanks @webchick and @tim.plunkett, I'm going to work on finishing up the approach in #186.
Comment #210
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedFirst, let's fix the tests and the review from #208.
Edit: the interdiff is to #186.
Comment #211
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThis patch implements
onDependencyRemoval()
so that the view is disabled and not deleted when the last workflow dependency is deleted, but I can't figure out why the last assertion doesn't work and the view is not actually disabled.Unassigning because I'm done for today so someone else can pick it up from here.
Comment #212
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedCouple of issues with this. The first one is, a workflow can be removed from an entity type/bundle without being deleted. So we can't really rely on
onDependencyRemoval
to control anything that needs to happen to the view based on a workflow being applicable or not.The second issue is, the test case was around asserting the actual nodes visible in the view before and after moderation is added/removed from a bundle. We need to assert once
$translation_workflow
is disabled, all nodes that were in that workflow (filtered out by a state) still don't appear in the view if they didn't before. I think that's going to be pretty difficult to detect and handle.I don't want to distract from continuing on with this, but I can see this style of filter being a lot harder to complete in a way to meets the feedback so far. So much so, I'd prefer to treat the optgroup as a feature request (given it's probably way out of the 80% use case anyway) and go with the implementation that is easiest to address the access bypass issue.
Maybe the above is wrong and there'll be an implementation that works, but if we're persisting metadata from a previously applied workflow in order to detect and resolve an access bypass, we still have the issue of the noisy config diff that was raised. I can't seem to grok a realistic solution using this approach.
Comment #214
xjm@webchick, did you catch that the version of the patch with the optgroups also has an extra screen when configuring the view?
Comment #215
webchickNope, #207 lays out exactly what we were asked to choose between. In that case, I'd need to try out the patch/see it demoed in UX meeting/see screenshots of the full experience to see if the extra screen is worth the UX benefit of optgroups or not.
Comment #216
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedNote that the extra screen can be removed at any point without affecting the functionality of the filter with the optgroups approach at all, I just thought it might be useful :)
I'll post a more detailed reply to #212 and a new patch tonight I hope.
Comment #217
amateescu CreditAttribution: amateescu for Pfizer, Inc. commented@Sam152, the kernel test that I was trying to write in #211 was strictly meant to check the functionality of
calculateDependencies()
andonDependencyRemoval()
, not the scenario described in #198. I couldn't figure out how to properly update the view storage in a kernel test so I converted it to a browser test instead, which works perfectly.One option for that is to finish #2907449: Do not allow removing moderation for an entity bundle that has moderated content, but I think I have an idea for handling it in the filter itself.
Comment #218
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedBefore that, let's remove the extra screen mentioned by @xjm in #214 because it seems contentious and I don't want it to cause more work for anyone :)
Comment #219
webchickI don't know if it's contentious or not, cos I haven't seen it. :) But I would say in general that the more you can make these filters match the way all of the other filters in Views work/look, the better. :)
Comment #220
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedOk, it took me a while but I got it working. This patch finally adds the scenario from #198 and even goes a bit further than that in order to handle the following case:
I'm pretty sure that no previous patch was passing this scenario.
The implementation works by adding an additional condition on the bundles configured for the workflows that the user can select in the filter. I think it's a reasonable expectation from a filter that lists moderated entities to restrict the results automatically to only those entities whose bundles can actually be moderated (i.e. enabled in a workflow).
I'm done here for now so assigning back to @xjm.
P.S. Keep in mind that if we don't want all this automatic filtering by moderated bundles we can always do #2907449: Do not allow removing moderation for an entity bundle that has moderated content instead.
Comment #221
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedRemoved local debugging leftovers :/
Comment #222
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThat's correct, in a sense this implementation is a little more self-healing instead of the "something doesn't make sense, bail out of all results". Nice job making this work, I couldn't think of a sane way to do it but I think it's entirely reasonable to restrict the set of results to content that is actually moderated when you add a moderation filter.
Found this when manually testing:
This implementation still does suffer from the scenario in #175. That is, you can create the filter and old states will hang around in configuration until the filter is opened and resaved. I believe the position on this was, this is potentially more a views thing than something unique to this patch, but we should cover our expectations around how this works with a test anyway.
Comment #223
jibranThis change makes sense to me. Let's see what @dawehner thinks about it.
Comment #224
phenaproximaNit: You could do $this->workflowStorage->loadByProperties() here, rather than query and load separately.
Comment #225
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedNit of the nit: We also have
\Drupal\workflows\Entity\Workflow::loadMultipleByType
:DComment #226
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedWe're not doing
\Drupal\workflows\Entity\Workflow::loadMultiple
anymore at @tim.plunkett's request, see #208.1. However, we can definitely switch to$this->workflowStorage->loadByProperties()
:)Comment #227
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedLet's do that :)
Comment #228
dawehnerI had no idea about this flag, nice!
What about using
min(count($options, COUNT_RECURSIVE), 8)
here? That' s a bit more readable, IMHO.Comment #229
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThat's a good idea, thanks @dawehner :)
Comment #230
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI opened #2920713: Views InOperator "Select all" option should only be applied when the valueFormType is "checkboxes" for my comment in #222 to not disrupt this issue so much.
From further testing today, I think with the above non-blocking follow-up this is ready for a review by @xjm as @amateescu suggests.
Comment #231
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation for Pfizer, Inc. commentedHad a good read on this issue, looks like everything mentioned has been addressed.
Had a read through the patch and it looks good to go to me, so I'm going to take the leap and RTBC this :-)
Comment #233
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation for Pfizer, Inc. commentedLooks like unrelated failure, retesting and setting back to RTBC
Comment #235
kkus CreditAttribution: kkus as a volunteer commentedIn #222 Sam's screenshot shows selecting multiple moderation states. I'm not sure if this should be a separate issue but I thought this is related enough to ask here: should we also have a field that allows us to see the the states of the nodes?
as of patch 229, I get
When I add moderation state to fields.
Thank you
Comment #236
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation for Pfizer, Inc. commentedThanks @kkus for that, I have just verified that indeed that is the case.
Comment #237
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThe issue described in #235 is fixed in #2859381: Broken/missing handler for Moderation state field and is only blocked behind some additional testing.
Comment #238
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation for Pfizer, Inc. commentedGod I clearly need more coffee!
I was testing the field, and not the filter which is what this issue is providing - apologies!
I have now tested the filter and it is working flawlessly, exposed, with ajax and everything seems to be working great.
Comment #239
kkus CreditAttribution: kkus as a volunteer commentedSorry, I didn't see #2859381. I was able to get this patch working over the weekend on simplytest.me but as of yesterday I get an error:
https://screenshots.firefoxusercontent.com/images/d0db2c7f-faee-4b4a-987...
Steps to reproduce:
1. install drupal core branch 8.5.x and patch https://www.drupal.org/files/issues/2862041-229.patch on simplytest.me (default install)
2. enable workflows and content moderation modules
3. configure editorial workflow to add article to the workflow
4. add moderation state filter and save
5. go to /admin/content and select a moderation state such as draft and select filter
6. check if you get an error
Also got this error locally.
Comment #240
larowlan#2859381: Broken/missing handler for Moderation state field is in, can we get an updated status here as this is blocking CM going stable, which we'd love to see in 8.5
Comment #241
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation for Pfizer, Inc. commentedRerolled #229 for now.
Manually fixed conflicts on
core/modules/content_moderation/src/ViewsData.php
.Comment #242
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI think the postgres fail is genuine:
Need to order the results somewhere?
Comment #243
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedYup, most test views need specific sorting for postgres. This should fix it :)
Comment #245
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedOf course, the test revision view also needs a sort on the revision ID.
Comment #246
timmillwoodNow we have tests passing for all three database types we can RTBC!
Thanks @amateescu!
Comment #247
smazJust given this a brief test too, works very well - thanks!
Comment #248
larowlannit, >80
nit ===
missing test coverage - can we check this attribute in one of the existing web tests?
I did some manual testing of this
Added the 'moderation state' in 'content' category filter to the existing admin/content view - worked as expected.
Added the 'moderation state' in 'content revision' category filter to the existing admin/conten view - tried to filter, received this SQL error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'node_field_revision.nid' in 'on clause': SELECT COUNT(*) AS expression FROM (SELECT 1 AS expression FROM {node_field_data} node_field_data INNER JOIN {users_field_data} users_field_data_node_field_data ON node_field_data.uid = users_field_data_node_field_data.uid INNER JOIN {node_field_data} node_field_data_1 ON node_field_revision.nid = node_field_data_1.nid AND node_field_data_1.langcode = node_field_revision.langcode INNER JOIN {node_field_revision} node_field_revision ON node_field_data.vid = node_field_revision.vid LEFT JOIN {content_moderation_state_field_revision} content_moderation_state ON node_field_revision.vid = content_moderation_state.content_entity_revision_id AND (content_moderation_state.content_entity_type_id = :views_join_condition_1 AND content_moderation_state.langcode = node_field_revision.langcode) WHERE ((node_field_data.status = 1 OR (node_field_data.uid = 1 AND 1 <> 0 AND 1 = 1) OR 1 = 1)) AND (node_field_data_1.type IN (:db_condition_placeholder_0)) AND ((content_moderation_state.workflow = :db_condition_placeholder_1) AND (content_moderation_state.moderation_state = :db_condition_placeholder_2))) subquery; Array ( [:db_condition_placeholder_0] => article [:db_condition_placeholder_1] => editorial [:db_condition_placeholder_2] => draft [:views_join_condition_1] => node )
So I think we either need to limit access to that filter where the base table isn't a revision table, or we need to fix our join logic (most likely the latter)?
Screenshots attached of my configuration and tests.
Comment #249
timmillwoodThis patch fixes 1, 2, and 3 from #248. I didn't get time to fully work out the issue shown in the screenshots. I was able to reproduce the issue and assume something needs to change with the join in
\Drupal\content_moderation\Plugin\views\filter\ModerationStateFilter::opSimple
, but not really sure what.To fix #248.3 I made the test view exposed filter a multi select so the size attribute is added, then provided an assertion in
\Drupal\Tests\content_moderation\Functional\ViewsModerationStateFilterTest::assertFilterStates
to size is the number of states, plus one for the optgroup label, but no more than 8.Comment #250
timmillwoodBumping straight back to needs work to fix our join logic from #248.
Comment #251
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThe fix for the SQL error from #248 is quite simple, we need to call
ensureMyTable()
earlier inModerationStateFilter::opSimple()
. Fixed that and tested with a new view which has the content moderation filter on the revision table.Also improved the test for #248.3.
Comment #253
timmillwoodThanks @amateescu, looks good to me!
Comment #254
RoSk0Comment #255
larowlanminor nit: can we name these cases
it helps debugging fails
i.e. make the array keyed
Tagging for a manual test to repeat the steps in #248
Comment #256
timmillwoodNaming things is the hardest, but here's some names for the test cases.
Comment #257
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThis should describe better what's being tested.
Comment #258
tedbowManual testing for #248
I tried the same for filter but with the 'content revision' category. The filter seem to have no effect but there was not error.
I was going to remove the "Needs Manual testing" tag. But I am not sure if the "content revision" category filter behaviour is what is expected.
Comment #259
amateescu CreditAttribution: amateescu for Pfizer, Inc. commented@tedbow, I just tried that scenario locally and adding the filter from "Content revision" works as expected, meaning that it shows the draft article. This is also very well tested in
\Drupal\Tests\content_moderation\Functional\ViewsModerationStateFilterTest::testWorkflowChanges()
..Comment #260
larowlanAdding review credits
Comment #261
larowlanManually tested this again, confirmed the previous issue is resolved.
Committed as 418e499 and pushed to 8.6.x
Cherry-picked as 58cf759 and pushed to 8.5.x.
Added and published a change record.
Unpostponed #2902187: Provide a way for users to moderate content
:tada:
great work folks!
Comment #265
bramdebacker CreditAttribution: bramdebacker at Dropsolid commentedI've been trying to use the moderation state as a filter for my REST export view, but I get the following SQL error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'node_field_data.type' in 'where clause': SELECT node_field_data_user__field_backpack__tracker_node.nid AS node_field_data_user__field_backpack__tracker_node_nid, user__field_backpack.delta AS user__field_backpack_delta, users_field_data.uid AS uid, node_field_data_user__field_backpack.nid AS node_field_data_user__field_backpack_nid, users_field_data_node__field_author.uid AS users_field_data_node__field_author_uid, node_field_data_node_field_revision.nid AS node_field_data_node_field_revision_nid FROM {users_field_data} users_field_data LEFT JOIN {user__field_backpack} user__field_backpack ON users_field_data.uid = user__field_backpack.entity_id AND user__field_backpack.deleted = :views_join_condition_0 INNER JOIN {node_field_data} node_field_data_user__field_backpack ON user__field_backpack.field_backpack_target_id = node_field_data_user__field_backpack.nid LEFT JOIN {node__field_author} node_field_data_user__field_backpack__node__field_author ON node_field_data_user__field_backpack.nid = node_field_data_user__field_backpack__node__field_author.entity_id AND node_field_data_user__field_backpack__node__field_author.deleted = :views_join_condition_1 LEFT JOIN {users_field_data} users_field_data_node__field_author ON node_field_data_user__field_backpack__node__field_author.field_author_target_id = users_field_data_node__field_author.uid INNER JOIN {node_field_revision} node_field_data_user__field_backpack__node_field_revision ON node_field_data_user__field_backpack.vid = node_field_data_user__field_backpack__node_field_revision.vid LEFT JOIN {node_field_data} node_field_data_node_field_revision ON node_field_data_user__field_backpack__node_field_revision.vid = node_field_data_node_field_revision.vid LEFT JOIN {content_moderation_state_field_revision} content_moderation_state ON node_field_data_user__field_backpack.vid = content_moderation_state.content_entity_revision_id AND (content_moderation_state.content_entity_type_id = :views_join_condition_2 AND content_moderation_state.langcode = node_field_data_user__field_backpack.langcode) INNER JOIN {tracker_node} node_field_data_user__field_backpack__tracker_node ON node_field_data_user__field_backpack.nid = node_field_data_user__field_backpack__tracker_node.nid WHERE ((users_field_data.uid = :users_field_data_uid )) AND ((users_field_data.status = :db_condition_placeholder_4) AND (node_field_data.type IN (:db_condition_placeholder_5)) AND ((content_moderation_state.workflow = :db_condition_placeholder_6) AND (content_moderation_state.moderation_state = :db_condition_placeholder_7))) ORDER BY user__field_backpack_delta DESC; Array ( [:users_field_data_uid] => 1 [:db_condition_placeholder_4] => 1 [:db_condition_placeholder_5] => tip [:db_condition_placeholder_6] => editorial [:db_condition_placeholder_7] => published [:views_join_condition_0] => 0 [:views_join_condition_1] => 0 [:views_join_condition_2] => node )
The view is being used to display content referenced through an entity reference field in user. I'm guessing type is checked in user instead of
the content?
Comment #266
bygeoffthompson CreditAttribution: bygeoffthompson commentedHello everyone. Wanted to stop by this long (and great) thread to report my finding while testing this filter. I am working on a site (8.5.3) with core content_moderation and have discovered what I believe to be a UX issue.
It appears like the Content Moderation filter only works for new, never published nodes. As expected, once published, that node no longer populates in the view. This works perfectly. However, a node which was published, then edited and saved as a draft, will not populate the view with this filter.
Create Node -> Save (Published) -> Edit Node -> Save (Draft)
My website's administrators expect to have a single view page where all drafts can be viewed (regardless if it's a brand new node or a previously published node that has had changes applied). Unfortunately I don't believe this is possible with the Content Moderation filter built.
Has anyone else encountered this issue? Happy to provide more information if necessary.
Thanks!
Comment #267
bygeoffthompson CreditAttribution: bygeoffthompson commentedUpdate on previous note:
I had my view incorrectly set up (listing Content entities instead of Content Revisions). With that squared-away I have a view that satisfies the criteria stated above. For anyone reading this in a similar situation, this post helped point me in the right direction.
Thanks
Comment #268
le72Hi everyone. I see long thread on filtering, but nothing about sort. We really need sorting by Moderation State name and Moderation State wight.
Thanks in advance.
Lev.
Comment #269
amaisano CreditAttribution: amaisano as a volunteer commentedCame here because exposing the Content Moderation State filter and using "Select All" causes a "No valid values found on filter" error, which doesn't make any sense. I can see and select a certain workflow state, like "Draft" and it does show the correct results, but when I default the filter to the "Select All" option, the View breaks.
I found I could work around this by selecting "Limit to selected values" and basically selecting all the values, including the "Select All" option. No more errors. So strange!
Comment #270
apadernoComment #271
xjmRestoring committed branch. Please open a new issue if you're encountering problems.
Comment #272
apadernoI apologize: I confused the issue with an open one.