-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enables on hold for user #9888
enables on hold for user #9888
Conversation
…ment-of-veterans-affairs/caseflow into amprokop-add-hold-ability
…fairs/caseflow into amprokop-add-hold-ability
…ment-of-veterans-affairs/caseflow into amprokop-add-hold-ability
Did we explore creating a new Quoting from a slack thread about one of the issues with the current implementation of the on hold ability:
In addition to not distinguishing from the different types of holds we don't currently respect the |
@@ -34,6 +34,7 @@ def available_actions(user) | |||
Constants.TASK_ACTIONS.ASSIGN_TO_TEAM.to_h, | |||
Constants.TASK_ACTIONS.REASSIGN_TO_PERSON.to_h, | |||
Constants.TASK_ACTIONS.MARK_COMPLETE.to_h, | |||
Constants.TASK_ACTIONS.PLACE_HOLD.to_h, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We override available_actions
for a handful of classes that inherit from GenericTask
so we'll need to add this option to those classes as well if we want them to be able to be placed on hold.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR that added the ability to cancel tasks might be a good reference for how we could go about accomplishing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I'll update the available actions for those tasks.
It may be that creating a new task class and migrating everything over to that is the best approach — or we could directly fix the bugs you mentioned with how we currently use the I'm happy to not merge this and start exploring either approach — but I'm not confident that I'll have time to complete either of the alternative approaches this sprint, my shallow read is that both are much more of a lift. You and/or @laurjpeterson should make that call, is it better to merge this now with some known issues, or wait for a more perfect solution? |
I'd prefer to merge this now so users can have the ability to place tasks on hold, which is "generic queue" functionality we trained them on, but haven't had. I know refactoring before merging might be the desired way forward, but if we don't have bandwidth now to do it, I worry about delaying this feature for another few months. |
I am strongly opposed to merging this as is until we do more exploration about the approach I suggested above. I think 2 hours of exploration with a quick summary of findings if it won't pan out would be well worth that time. I believe we will spend a significant amount of time supporting this approach, and if we eventually move over to a more robust approach that time spent will be negatively productive in getting the refactor in because it would be time spent on things other than developing the robust approach. |
@lowellrex — cool, I'm happy to commit 2 hours to this this sprint — I am confident that the approach you proposed will work, but my guess is that implementation and any subsequent fixes will take significantly more than 2 hours, and I can't commit to having it done before next Friday. Does that work for you? |
Yup! That works! I think as long as we can get this out the door before the end of the sprint (Fri 22 March) then we'll be good to go! |
@lowellrex — hmm I'm not sure I'm going to be able to do that, it will depend on how big of a task it winds up being (when I said next Friday, i meant 22 March). I'll give it a shot — is there some deadline for fixing this bug? |
…fairs/caseflow into amprokop-add-hold-ability
…ment-of-veterans-affairs/caseflow into amprokop-add-hold-ability
app/models/appeal.rb
Outdated
@@ -705,6 +705,10 @@ def bgs | |||
BGSService.new | |||
end | |||
|
|||
def tasks_for_frontend |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this method should probably be in the task model itself. Will move it. But the general idea is that we'll save the frontend from having to walk the task tree to match up on hold tasks with their parents to get those details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make sense to follow this pattern, where we hide tasks from various views with methods that return booleans. So we have hide_from_case_timeline
and hide_from_task_snapshot
; you could add something like hide_from_task_list
and then filter on that value (whether it's here in the Appeal model, on the Task model, or on the frontend).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh wait — i think what i actually want is to return true for hide_from_case_timeline
and hide_from_task_snapshot
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
Code Climate has analyzed commit 85a15e8 and detected 3 issues on this pull request. Here's the issue category breakdown:
View more on Code Climate. |
# rubocop:enable Metrics/MethodLength | ||
# rubocop:enable Metrics/AbcSize | ||
|
||
def placed_on_hold_at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we're overriding the methods that would automatically be accessing DB fields (see the task schema) in GenericTask for now — eventually, I'd favor getting rid of the placed_on_hold_at
and on_hold_duration
columns entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can move this into the base Task
class and override these methods only in ColocatedTask
since that is the only task class that uses timed holds? Either way, can we write up a ticket that includes a migration plan for abandoning the old (ColocatedTask
) way of doing timed holds in favor of this new strategy?
app/models/tasks/generic_task.rb
Outdated
def place_on_hold(parent, current_user, params) | ||
transaction do | ||
# Remove any other hold tasks so we don't wind up with more than one | ||
if parent.timed_hold_task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess is that we should only permit one hold on a task at a time, and any new hold should blow away the old one. Open to other suggestions though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overall approach looks good to me!
app/models/appeal.rb
Outdated
@@ -705,6 +705,10 @@ def bgs | |||
BGSService.new | |||
end | |||
|
|||
def tasks_for_frontend |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make sense to follow this pattern, where we hide tasks from various views with methods that return booleans. So we have hide_from_case_timeline
and hide_from_task_snapshot
; you could add something like hide_from_task_list
and then filter on that value (whether it's here in the Appeal model, on the Task model, or on the frontend).
on_hold_duration: params[:on_hold_duration] | ||
) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this approach is right. I have some syntactical/implementation feedback which you may've been considering already, so I'll be brief.
- the task parameter should be named
task
instead ofparent
- this (plus the
timed_hold_task
getter) will only get the most recent activeTimedHoldTask
child. I know it shouldn't be possible to have more than one activeTimedHoldTask
as a child of aGenericTask
, but maybe we can get all active tasks and destroy them all to be sure? - can we cascade destruction of the
TaskTimer
when theTimedHoldTask
is destroyed (or vice versa)? - I don't think you need to explicitly set the parent
on_hold
, this hook should do it for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, do we want to destroy
tasks or should we cancel
them so there's a record?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this to cancel them.
class TimedHoldTask < GenericTask | ||
include TimeableTask | ||
|
||
validates :on_hold_duration, presence: true, inclusion: { in: 1..100 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we pick an upper limit of 100 days?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the UI goes up to 90 days. Open to changing it to whatever you like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me!
end | ||
|
||
def timer_ends_at | ||
Time.zone.today + on_hold_duration.days |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we update this function to use a static date (maybe the task's creation date?) instead of the current date? It looks like we only call this function when we create the TaskTimer
, but we may forget about that convention in the future and I think it would make sense to have this function always return the same value regardless of whether we call this function the day the task was created or 3 days later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that sounds like a good tweak. Thanks!
# A nightly job queries for and expires | ||
|
||
class TimedHoldTask < GenericTask | ||
include TimeableTask |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might we need an available_actions
item that ends the hold early?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This work should probably be completed in another PR, along with the front-end work to add the modal to place tasks on hold.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, do we currently have an option in the UI to cancel holds on tasks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't currently cancel holds so this definitely makes sense to be part of a different PR if we want to do it.
GenericTask.place_on_hold(task, update_params) | ||
else | ||
task.update_from_params(update_params, current_user) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the only field of the parent task we're updating here is the "status" field by way of the after_create
hook perhaps it would be more precise to have this be a create
action since we are creating a new instance of the TimedHoldTask
?
If we use that approach we would have to move the logic to cancel existing task timers associated with the task to the TimedHoldTask
class, but it would allow us to not change TasksController
at all.
Closing this out in favor of other PRs (linked in #9207) that will continue this work. |
#9207
This code is not yet fully tested nor does it have enough automated tests, just surfacing for feedback on the general approach.
Creates a new TimedHoldTask class that imports TimeableTask. To put a GenericTask on hold, we will now call GenericTask.place_on_hold(parent, current_user, params).
Colocated tasks are not changed for now, but I suggest we plan to migrate them when convenient.
I considered sending the TimedHoldTask to the frontend and then just updating the Case Timeline and all the frontend logic to handle this new TimedHoldTask correctly, but decided against it for the moment, out of a sense that the frontend shouldn't need to know about all tasks necessarily, and shouldn't be responsible for sorting through backend implementation details.
So, the smoothest past forward seemed to be to redefine the
placed_on_hold_at
andon_hold_duration
methods on GenericTask, so we wouldn't have to change anything from the serializer or the frontend (theoretically). This has the effect that we need to filter out TimedHoldTasks from the list of tasks we return to the frontend.Suggested path forward for future PRs if we continue with this approach:
Open questions:
Test plan (not ran yet):
when_timer_ends
on the on hold task