Problem/Motivation
Followup to #2779647: Add a workflow component, ui module, and implement it in content moderation.
When a state is deleted an entity continues to use that state causing an error such as Uncaught PHP Exception InvalidArgumentException: "The state 'test' does not exist in workflow 'editorial'" at /home/timmillwood/Code/drupal1/core/modules/workflows/src/Entity/Workflow.php line 205
when trying to edit the entity.
Proposed resolution
- Show an error (and hide the buttons) on the delete confirmation page for states and workflows which are in use.
- Throw an exception if trying to delete a state or workflow via the API methods.
- Set a config validation error if config imports remove states or workflows which are in use.
Remaining tasks
Review.
User interface changes
None
API changes
- It's up to the Workflow plugin to handle what happens.
- The ContentModeration workflow plugin updates the content_moderation_state tables to switch out the moderation state id.
Data model changes
None
Comment | File | Size | Author |
---|---|---|---|
#112 | interdiff.txt | 3.39 KB | amateescu |
#112 | 2830740-112.patch | 17.65 KB | amateescu |
#110 | 2830740-110.patch | 18.03 KB | timmillwood |
#110 | interidff-2830740-110.txt | 1.37 KB | timmillwood |
Comments
Comment #2
alexpottHere's a start. Very pleased with how simple this is.
Comment #3
timmillwoodComment #4
alexpottI think we should do something more generic so that all workflow types have to think about this problem.
Comment #5
alexpottUpdated the issue summary. I've added some decisions to make to it. I'm not sure about adding the same protection to the workflow entity API.
Comment #6
alexpottComment #7
timmillwoodLooks like a good solution to the problem.
I wonder if we need to make use of isWorkflowUsed() anywhere other than checkAcess(), but I guess this can be done in a follow up.
Also another good follow up might be to look at UX. I'm not sure throwing a 403 is that friendly, maybe it'd be better to redirect back and display a warning such as "There are N Nodes and N Blocks using the FOO moderation state."
These should not block this important update though.
Comment #8
alexpott@timmillwood well the user doesn't ever get a delete link. So they don't see the 403 unless they hack together the URL. Late in 8.x cycle we added \Drupal\Core\Access\AccessResultReasonInterface we should leverage that here I guess. But the problem is the
orIf()
not handling merging the reason :(Comment #9
catchDoesn't this need an accessCheck(FALSE) just in case?
Can't imagine any situation where you'd query alter content_moderation_state entities depending on user, but sets a good example at least.
Comment #10
catchWe need this because the database you delete from the UI on dev is not in the same state as the one you deploy the change to via the API on production.
Comment #11
alexpott@catch good point - although that's not an argument for API protection - that's an argument for a config import validator!
Comment #12
alexpottSo whilst writing this code to prevent importing a deleted workflow that is in used i started to ponder if we've got this right. Perhaps what we should be doing is confirming with the user and saying that this will delete the states. And perhaps this means we need to allow the content moderation workflow type to always provide a published and unpublished fallback? So if we delete a state in use we just move them to the fallback state and we never allow the fallback states to be deleted.
Comment #13
catchCould go for that as well yeah.
Comment #14
timmillwood#2817835: When enabling moderation apply a relative state and #2813723: What happens when you enable / disable moderation? both talk about a similar thing to fallback states.
Comment #15
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWhat about doing what the image style system does and implementing a method like \Drupal\image\ImageStyleStorageInterface::setReplacementId? That way the UI asks you which state replaces the one you've deleted?
Comment #16
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedNote, I think closing this issue resolves a @todo in \Drupal\content_moderation\Plugin\Validation\Constraint\ModerationStateConstraintValidator::validate.
Comment #17
alexpott@Sam152 That's a pretty good idea. But we need to maintain a list of replacement IDs - ie. what happens if the replacement gets deleted too?
Comment #18
alexpottAlso I'm not sure how replacement IDs in image styles work with configuration deployment.
Comment #19
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedGood point re: #18, image styles got away with it because they were updating configuration objects that depended on styles that were exported when the style was deleted. Since this updates content, the replacement would have to be stored in config also.
Comment #20
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #22
timmillwoodSo... trying to get this issue back on track as it's a "must-have" in #2843494: WI: Workflows module roadmap.
Is the current thinking that we don't lock changes to a workflow, but if a state is deleted all entities with that state get moved to another state?
In Content Moderation we currently have draft and published as a requires states, so we could use one of them. This also means we'll have to depend on the workflow plugin to do the state changes. Content Moderation could move all "unpublished" entities to draft, and all "published" entities to published?
This then makes this issue heavily related to #2817835: When enabling moderation apply a relative state and #2813723: What happens when you enable / disable moderation? and use very much the same code / batch process.
Comment #23
timmillwoodThis code builds on the suggestion in #12. If a "published" moderation state is deleted we fall back to the published state, if an "unpublished" moderation state is deleted we fall back to the draft state.
The current code results in resaving the ContentModerationState and moderated entity (such as Node), which is going to be slow on big sites. I'm wondering if a better approach would be to just swap out the moderation state string in the content_moderation_state_field_revision and content_moderation_state_field_data tables.
Comment #24
timmillwoodComment #25
timmillwoodThis does the same but doesn't load any entities to improve performance, and also adds to the test to check an unpublished moderation state.
(sorry forgot to generate an interdiff)
Comment #26
timmillwoodHere's the interdiff between #23 and #25.
Comment #27
timmillwoodUpdating issue summary to reflect the new direction.
Comment #28
timmillwoodSwitching to injecting the database.
Comment #29
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedLove it when a plan comes together :)
Review as follows.
nit, {@inheritdoc}
I wonder if this method covers deploying config between environments. I suspect it's not called during a config import, thus we'd probably need to listen to entity_update too.
It kind of sucks we have to do this low level fiddling, we're essentially bypassing entity api rewriting history, but of course when integrity it at stake in the first place, I don't think there is an alternative approach which makes more sense though.
Might be good to get some more input on this though.
Is it relevant to this feature that the content started out as 'draft'? Possibly to just go 'moderation_state' => 'test' in the factory?
Same here? Doesn't 'moderation_state' => 'unpub_test' work?
Comment #30
timmillwoodThis patch addresses 1, 4, and 5, from #29.
2. This doesn't get called when doing a config import, and neither does
\Drupal\workflows\Entity\Workflow::deleteState
so related transitions don't get deleted. Maybe that should be a follow up or dependency for this.3. I've gone back and forth on this. We could call
\Drupal\content_moderation\Entity\ContentModerationState::updateOrCreateFromEntity
which will just save the ContentModerationState entity and not the parent entity, thus firing all entity API things, but it will not recursively go back through all ContentModerationState revisions updating the states, should it? It will also be a performance it. Just updating the database tables seems much nicer, but means there are no entity hooks fired.Comment #31
timmillwoodMoving things to entity_update as suggested in #29.2
Comment #32
timmillwoodShould've removed the use statement.
Comment #33
pauloamgomes CreditAttribution: pauloamgomes as a volunteer and at Appnovation commented@timmillwood, patch seems good, after applying was able to validate both cases:
However I believe that a prompt shall be presented to the user informing about the change, something like "There are X items of content with this state, these will be moved to Y state."
Comment #34
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation commentedI agree with @pauloamgomes - probably a confirmation form should be put in place so the user can see what would be happening before hand. That said, we could do that as a follow up perhaps?
Comment #35
timmillwoodUpdating the message shown on the confirmation page.
Comment #36
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation commentedBrilliant @timmillwood - works for me!
+1 to rtbc
Comment #37
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI wonder if we can test that is is necessary this by using $workflow->set('states', [...]) to simulate a config import, without calling deleteState?
I'm sure someone would think to open a follow up to move this to the more logical (but incorrect) deleteState method.
This will affect all workflows when content_moderation is enabled, not just workflows of type content_moderation.
Would also be good to test this.
Comment #38
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedUpdated patch:
Comment #39
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #40
timmillwoodLooks awesome, thanks @Sam152.
Comment #41
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation commented#37 has been addressed, as well as #33 & #34, looks good to me.
Comment #42
plachI don't think we should be manually fiddling with the database here. This is a bad practice when dealing with content entities. Why can't we just load/edit/save the various state definitions?
Comment #43
timmillwood@plach - My thought was if we're update hundreds or thousands of ContentModerationState entities, a simple database update would be quicker and easier than loading/editing/saving each entity.
Comment #44
plachSorry, I misread the code, I thought this was only updating a few records, now I realized we can have one record per entity. It's unfortunate but I guess there's no way around doing that until we support bulk updates via entity query or something fancy like that. Unless we want to use a batch.
However I guess we need at least to clear entity cache after updating the DB, right?
Comment #45
plachAre we sure it's fine to skip hook invocation when performing this change? Won't it be more correct to prevent state deletion until all entities were moved out of it?
Comment #46
jibranAny reason we are not using batch+entity API? Using the entity API will ensure that all the hooks will fire.
Comment #47
timmillwoodI guess we should really use batch+entity API, I was just worried of the performance hit and as ContentModerationState is kinda an internal entity type that no one should be interacting with, this felt like a good way to get a really good performance boost when deleting a state.
Also, as this is deleting a state, and not like a mandatory upgrade path, I think it's a slightly different use case to to standard bulk updates.
Although, happy to look at a batch entity load/edit/save if that's the better option.
Comment #48
plachFor the record @catch suggested in Slack to block the state deletion altogether if there are entities in the state to be deleted.
Comment #49
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThis is inadequate, because you can delete the state in an environment where there are no corresponding entities and deploy the config to an environment where there is. This approach has been in the works since #2844594: Default workflow states and transitions.
@timmillwood is right here, I feel like we have some liberty with this entity type. If we need to clear the entity cache, lets do that, but we do not need to hold this entity type to the same standards as node in terms of integration and api-completeness. It's a storage mechanism for a computed field, slated to be @internal, that nobody should really have to every think about/interact with directly (see #2876419: Review content_moderation module and mark code with @internal where necessary).
Personally, I think this should only be NW for clearing the entity cache after the update is done.
Comment #50
timmillwoodI guess we should give more reasoning in the code as to why we're doing it this way, core is often used as an example for others, so we want to make it clear this is a special case.
Comment #51
plachYep, adding an inline comment would definitely help. I also think we should mark this stuff as @internal ASAP, ideally before introducing this change.
Comment #52
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedSee #2876419: Review content_moderation module and mark code with @internal where necessary for #51.
Comment #53
timmillwoodAdding a comment and a cache reset.
Comment #54
catchThen config validation would prevent you from deploying the change to production and you'd have to sort it out though. This is the same as other cases where we have the same checks.
Comment #55
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedAh okay, I haven't seen #54 implemented before. Is the only cost that you potentially create config you can't import? We don't have tools for bulk changing states, if we went down the route of making the site administrator update the content.
Comment #56
plachThis is marked as a MUST-HAVE in the roadmap.
Comment #57
catchYes you can end up with config that's deleted on your dev site, which you then can't import into the production site because either new content has been put in the state, or because working with a different db.
That seems like a generally useful feature to me, but shouldn't block this issue - good to open a follow-up to add it though if there isn't one already.
Comment #58
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedIt'd be great to keep all the config importable at all times anyway IMO, even if we add tooks for bulk resolving the issue. The closest thing to that is #2797583: Dynamically provide action plugins for every moderation state change.
The interdiff looks good to me, but will let others comment #53 if we're happy with that solution.
Comment #59
plachWell, according to #48 and #54 the current approach is inconsistent with what happens normally in core, which also forces it to "abuse" the Entity API. It's unfortunate but for that reason I think we need to abandon the current route and implement what @catch is suggesting.
#2797583: Dynamically provide action plugins for every moderation state change can definitely alleviate the problem of not being able to deploy the configuration change, and given that changing the state of many entities has the potential to introduce unexpected and undesirable side-effects, I think in the end it makes more sense to leave that as an explicit choice for administrators rather than doing it automatically.
Comment #60
timmillwoodok, let me get an initial patch done for @catch's suggested direction.
Comment #61
catchFor reference #232327: Deleting node type leaves orphan nodes was the original issue (or close to it) where we introduced the pattern.
Comment #62
timmillwoodThis is a rework of #4 which throws an AccessDenied result if the workflow is being used, or if the state is being used.
Next to implement a config import validator.
As we're going back to the original direction I've changed the issue title back too.
Comment #63
plachI manually tested #62 and it was working as expected, but I discovered this meanwhile:
#2893888: Content moderation state entity field data not removed when the host field data is
Reviews welcome :)
Comment #64
timmillwoodInitial implementation of the config import validation, and a test to go along with it.
Review and feedback really welcome.
Comment #65
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedUnrelated change, but looks correct so +1.
Do we have to cater to the whole workflow being deleted here as well?
Should we mention which workflow here, or do we get that for free?
I wonder if "used" is the right verb. You can probably have states and workflows people would consider being "used" but are completely safe to delete. The fact that a state is in active use and can't be deleted seems kinda content-moderation specific.
Do we need the max age on both access checks?
Comment #66
plachWon't this check only the first deleted state? Shouldn't we iterate over
$diff
?Comment #67
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedMinor nitpick: The entity type manager.
This variable is only used twice and it's not instantiating something expensive to compute, so for better code clarity I would skip this assignment and use the method directly in the two places below.
Also for code clarity, how about renaming these variables to
$original_workflow_config
and$workflow_config
?This seems to handle only the case where one state is deleted in the diff. How about when multiple states are deleted?
As for the question above from @Sam152, how about renaming these to
workflowHasData
andworkflowStateHasData
?It's just a suggestion though, this needs more opinions.
It would be better to use
@covers
than@see
here. Also, for@covers
we need to remove the trailing '()' after the method name.I don't we need to use
sprintf()
here, let's just concatenate the string in thedrupalPostForm()
calls.Missing an empty line here ;)
And this one needs to go.
Comment #68
plachLooks like this needs work :)
Comment #69
timmillwoodI think this addresses #66 and #67.
Re: #65.2 - I think we do need to cover deleting the whole workflow.
Comment #70
timmillwoodNeeds work on #65.2.
Comment #71
timmillwoodWe discussed this issue on a triage call today. @xjm brought up the point that if we use access control to prevent users from deleting Workflows and Workflow states the user will have no idea why they can't delete them. We should show a message to explain, then link to a list of entities which are causing the issue. the problem is there's no list of entities in core per moderation state however we could add this to Content Moderation. #2862041: Provide useful Views filters for Content Moderation State fields would help by providing a filter for this view. Then #2797583: Dynamically provide action plugins for every moderation state change would help to allow users to bulk update the moderation state.
Comment #72
timmillwoodThis patch now handles whole workflows deleted during a config import.
It also, in a slight change of direction, shows the delete button for workflows and workflow states, but then displays a message. Exactly the same as deleting content types which are in use.
This still allows deleting of workflows and workflow states via the API, is this something we want to cover (content types don't cover this yet either)? Do we simply throw an exception in the delete() methods, or use entity validation API, can't entity validation be bypassed too?
Comment #73
plachManually tested this and the UI change makes total sense to me and is fully consistent with what we do with content types, so +1 for that. Code is looking great, I found only the minor things below.
If we already have an issue outlining a clear way forward for this approach for content types, then I'd say to stick to that, otherwise I think it's fine to ignore that case an be consistent with core.
Incomplete PHP docs
Surplus newline(s) :)
Comment #74
timmillwoodFixing #73.
Been thinking about preventing deletion via the API, and not sure entity validation would work, as it's possible to save or delete an entity without running validation. The only option might be littering the Workflow entity with exceptions if the workflow or state is in use. So maybe @plach has the best suggestion, to ignore this case.
Comment #75
plachTo clarify: probably we'll want to address this in the future, however starting from the same state as content types should allow a generic solution to be applied also in this case.
Comment #76
plachTests green
Comment #77
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedAs discussed in the call, let's implement the
preDelete()
method in the Workflow entity and prevent deleting stuff via the API if they are in use :)Comment #78
timmillwoodSwitching to needs work on #77.
Comment #79
timmillwoodAdding API coverage for deleting states and workflows which are in use.
Comment #81
timmillwoodFirst test fail was
\Drupal\Tests\content_moderation\Kernel\EntityStateChangeValidationTest::testInvalidStateWithoutExisting
where we were checking node validation after deleting a moderation state via the API, but now that's not possible, so removed the test.The second was
\Drupal\Tests\workflows\Unit\WorkflowTest::testDeleteState
. This unit test didn't expect workflowStateHaseData to be called. It now does.Comment #82
timmillwoodUnassigned from me as this needs review from others, no work remaining to be done.
Comment #83
martin107 CreditAttribution: martin107 as a volunteer commentedJust fixed a couple of trivial nits found while following along
1) In the new ModerationFormTest::testWorkflowInUse()
Unless explicitly testing translation there is no need to invoke t()
2) Fixed a trivial coding standard nit in ConfigImportSubscriber
Comment #84
timmillwoodThanks @martin107 LGTM.
Comment #85
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #86
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI really wonder if these methods names are describing their behaviour clearly enough. Their functional purpose is checking if a state/workflow can be deleted, which sounds very familiar to the access control handler. Is there a reason instead of creating two new state/workflow methods concerned with "can I delete this thing", that we can't leverage an existing method like \Drupal\workflows\Plugin\WorkflowTypeBase::checkWorkflowAccess?
This will help protect the states/workflow from the UI, then I think content moderation could hook in separately to provide the api level protection in preDelete, much like it does with the config validator.
Possibly related #2896726: Expand the entity access model for workflow states and transitions..
Comment #87
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedCome to think of it, access results even have a "reason" field. We might be able to bubble those up to the UI, so the user gets the same experience of knowing why a state can't be removed.
Comment #88
plachFrom an outsider perspective those names are consistent with what is provided by the Entity API: they have a very specific and well understood meaning and that meaning is useful to determine whether workflow/states can be deleted. The two concepts seem independent to me, although related, I don't think we should merge them.
Comment #89
timmillwoodUpdating the resolution in the Issue Summary.
Comment #90
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI think my primary hesitation is, when you diff the patch in the workflows module, it's mainly adding checks and protection in the UI. Technically REST is another UI which we aren't providing the same nice messages for, we should then probably then duplicate the same workflowHasData() checks in the access controller, which leads me back to, why isn't it just check there in the first place?
Comment #91
plachCorrect if I'm wrong, but if we added an access check we would go back to the situation where the delete drop-button is not displayed in the UI because you dan't have access to the delete route, right? We could definitely add some access checks on top of those methods but they should not be the route access checks for deletion otherwise wouldn't be able to provide the better UX we came up with in the latest iterations.
Comment #92
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWe already have the pattern of denying access to delete states by removing the button, for "required states" of a workflow type (draft and published for content_moderation).
Do you agree this will have to go in the access control handler for proper REST support? After that it'll take extra work to allow users to access the delete confirm route, so unless there is a really good reason we probably shouldn't introduce the pattern in the first place.
If we do decide to do this in the access check instead, I filed #2896881: Workflow type plugins have no chance to act during access checks if a user is an admin to make it possible.
Comment #93
timmillwoodI believe the latest patch is a good solution for a stable release of Workflows module.
Access control would remove the delete button and cause confusion. The latest patch is also consistent with deleting bundles which are in use in core. Maybe we need to review that too, and maybe we need to review what happens when you delete a field which is in use.
The delete button is removed for required states, so maybe we need a follow up to discuss UX for that.
To allow flexibility we should keep the method names related to what they are doing, checking if the workflow or state has data, it's not strictly checking if it can be deleted.
This is only of the remaining blockers for Workflows becoming stable, if we get a good solution in we can always iterate on it.
Comment #94
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedFWIW, if it's only the message on the delete confirm form I've prototyped this (see interdiff.txt). Seems pretty easy and the ContentModeration workflow type can provide a much more specific error message about how to actually resolve the problem.
Based on this, it reduces the changes between workflows in HEAD vs this patch to the contents of interdiff-workflows-8.4.x.txt. Instead of adding 2 methods to the plugin interface, we can actually delete a custom route access controller. On top of this, REST support is now built in. We also use this same mechanism for protecting the deletion of our "required" states (publish/draft) which are also essential for the moderation workflow to work.
As @plach mentioned in #88, if these really are two totally different concepts, happy to drop this and help review/RTBC it, I can see heaps of good work has been put in so far. If anyone can see merit in this approach, I'm happy to work on it until it has full parity with what was proposed in #83.
Not meaning to be a stick in the mud here either, sorry if this is seen as needless bikeshedding, I am just conscious of the amount of methods we're adding to the workflow type plugin interface.
Comment #95
plachI had a look at #94 and it makes sense to me, however it would still be cleaner if the access checks relied on "hasData" methods like the ones implemented in the latest patches.
I think it would be worth moving this back to RTBC and open a related issue to explore your approach. If we can have it ready before this is committed, we can replace the latest patch with yours, otherwise it can be a (non-blocker) follow-up.
Comment #96
timmillwoodWorks for me.
I think the "hasData" method are pretty handy, and we can always deprecate them if we find they're not the best direction.
Comment #97
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWe agreed to remove the api-based delete protection from the latest patch, so lets at least get that done. It's inconsistent with how other critical items of config are handled and also doesn't cover all the ways to delete a state (you could simply use Workflow::set or the config api, deleteState doesn't have to be called).
Other than that, I'm fine with moving this to an access check going in a follow up.
How would you feel about both methods becoming protected in the follow-up? A bit like how \Drupal\entity\EntityAccessControlHandler::checkAccess is used in core. That way we have a single way to check if something can be deleted and you don't have to know about both methods before deciding if a state can be deleted.
Comment #98
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedRemoving the API-based delete protection basically means we want #74 + the interdiff from #83, so here's a patch for that with some cosmetic fixes for the new test as well.
Regarding the debate whether we want/need the new "has data" public methods or not, I'm still mulling on it and I don't have any opinions or suggestion so far. However, I do agree that #94 looks pretty good.
Comment #99
timmillwoodI created a user with just the "Administer workflows" permission, and I can delete a workflow and a workflow which are in use. As the admin user (user/1) I see the "This workflow state is in use. You cannot remove this workflow state until you have removed all content using it." message.
Investigating further.
Comment #100
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI've filed #2897148: Remove @internal from workflowHasData/workflowStateHasData and use those methods for access control and configuration validation. for the access based follow-up. I think once we can get consensus on #97, that will be ready to start.
Comment #101
timmillwoodClearing the cache fixed the issue I saw in #99.
Updating the test to make the permissions more specific just to cover any possible issues like #99.
Comment #102
amateescu CreditAttribution: amateescu for Pfizer, Inc. commented@Sam152, I re-read the entire issue and it seems that @alexpott wanted the generic public methods way back in #4, "so that all workflow types have to think about this problem".
Do you disagree with that part or just with the new method names?
Comment #103
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThe patch in question uses the access system to block states/workflows from being used. The main part of my proposal is not calling workflowHasData/workflowStateHasData() directly to make decisions at the UI level about if a user can delete a workflow or state, this seems like a job for the access controller. While I think it'd be nice to make protected, so it isn't part of the public API, I have no issue with the method names.
Comment #104
plach@Sam152:
I think we all agree that would be a sane goal, but we are running out of time: what do you think about my proposal in #95?
Comment #105
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedMaking these @internal. I think in the follow-up we can either decide to remove the tag, thus making them part of the public API, or they can be safely removed or be made protected if not.
Happy with this approach, lets get this fixed!
Comment #106
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedAfter all these comments, we still need to address #9 :) And we can also improve the performance of the query with a
->range(0, 1)
.Comment #107
plachRTBC +1
Comment #108
timmillwoodWorks for me! +1
Comment #109
larowlannit === can be fixed on commit
looks good
updating issue credit to include @plach and @catch who provided reviews that shaped the patch
Comment #110
timmillwoodAs this has not been committed yet, here's a patch to fix #109.
Comment #112
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedRerolled after #2849827: Move workflow "settings" setters and getters to WorkflowTypeInterface.
Comment #113
plachRTBC +1
Comment #114
larowlanCommitted as 832d769 and pushed to 8.4.x.
Great use of the config import events and api.
Comment #116
webchickCalling out in the release notes, since this feels like pretty important new functionality.