-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Implementation/59721 add setedit reminder buttondialog to workpackage page #17341
Implementation/59721 add setedit reminder buttondialog to workpackage page #17341
Conversation
…tondialog-to-workpackage-page
...tures/work-packages/components/wp-buttons/wp-reminder-button/wp-reminder-button.component.ts
Fixed
Show fixed
Hide fixed
...tures/work-packages/components/wp-buttons/wp-reminder-button/wp-reminder-button.component.ts
Fixed
Show fixed
Hide fixed
...tures/work-packages/components/wp-buttons/wp-reminder-button/wp-reminder-button.component.ts
Fixed
Show fixed
Hide fixed
frontend/src/app/features/work-packages/components/wp-reminder-modal/wp-reminder.modal.ts
Fixed
Show fixed
Hide fixed
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.
Quite the feat, nicely done! 👏🏾 I've noted a few general issues
- Missing unit test coverage for model, contract and API changes - annotated in the code
- Missing API specification & tests
- Several eslint and rubocop issues
UI Wise
- Missing modal cancel button as per the design
- Separately, it would be good to check with UX/Product if we can adopt "Remove reminder" instead of "Delete reminder" and "Schedule" instead of "Save" - from previous mention people seemed in favour of the idea
- On hover of the "Set reminder icon" no label is displayed
- The reminders clock icon is off-centered to the left
- Content loader skeleton does not match the reminders UI
- Duplicate form error messages
- Unhandled 404 when reminder edit modal is open, and the reminder notification is created whilst it's still open (you can test this by creating a reminder in the next minute, open the edit modal and wait for the reminder notification to be created then attempt to edit it)
- icon is smaller than counter
# At the form level, we split the date and time into two form fields. | ||
# In order to be a bit more informative of which field is causing | ||
# the remind_at attribute to be in the past/invalid, we need to | ||
# remap the error attribute to the appropriate field. | ||
def prepare_errors_from_result(service_result) | ||
# We set the reminder here for "create" case | ||
# as the record comes from the service. | ||
@reminder = service_result.result | ||
@errors = service_result.errors | ||
|
||
case @errors.find { |error| error.attribute == :remind_at }&.type | ||
when :blank | ||
handle_blank_error | ||
when :datetime_must_be_in_future | ||
handle_future_error | ||
end | ||
|
||
@errors.delete(:remind_at) | ||
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 method and related calls would do well as an extracted simple PORO that can be unit tested- also reduce the perceived complexity on the controller
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.
app/models/reminder.rb
Outdated
# Currently, reminders are personal, meaning | ||
# they are only visible to the user who created them. | ||
def self.visible(user) | ||
where(creator: user) | ||
end | ||
|
||
def self.upcoming_and_visible_to(user) | ||
visible_reminders = visible(user) | ||
reminder_notifications_for_reminders = ReminderNotification.where(reminder: visible_reminders) | ||
|
||
visible_reminders | ||
.where(completed_at: nil) | ||
.where.not(id: reminder_notifications_for_reminders.select(:reminder_id)) | ||
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.
Nice one covering these- 🟠 it would be worth add the corresponding model unit specs in https://github.com/opf/openproject/blob/dev/spec/models/reminder_spec.rb
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.
🟠 Once the tests are added. I think the method to exclude reminders that have associated reminder notifications can be simplified via where.missing
Performance seems about the same faster - as the later results in no sub-queries and reads easier IMO
# Currently, reminders are personal, meaning | |
# they are only visible to the user who created them. | |
def self.visible(user) | |
where(creator: user) | |
end | |
def self.upcoming_and_visible_to(user) | |
visible_reminders = visible(user) | |
reminder_notifications_for_reminders = ReminderNotification.where(reminder: visible_reminders) | |
visible_reminders | |
.where(completed_at: nil) | |
.where.not(id: reminder_notifications_for_reminders.select(:reminder_id)) | |
end | |
# Currently, reminders are personal, meaning | |
# they are only visible to the user who created them. | |
def self.visible(user) | |
where(creator: user) | |
end | |
def self.upcoming_and_visible_to(user) | |
visible(user) | |
.where(completed_at: nil) | |
.where.missing(:reminder_notifications) | |
end |
<svg:rect height="10" rx="2" ry="2" width="110" x="0" y="0"/> | ||
<svg:rect height="10" rx="2" ry="2" width="25" x="120" y="0"/> | ||
<svg:rect height="10" rx="2" ry="2" width="25" x="155" y="0"/> | ||
<svg:rect height="25%" rx="2" ry="2" width="180" x="0" y="16"/> |
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 noticed this content loader skeleton comes from the shares modal- could we ask design for one that matches the reminders modal?
map((collection:CollectionResource) => { return collection.total; }), | ||
); | ||
} | ||
} |
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.
🧹 Several eslint issues that need fixing
this.reminderCount$ = merge( | ||
this | ||
.actions$ | ||
.ofType(reminderModalUpdated) | ||
.pipe( | ||
map((action) => action.workPackageId), | ||
filter((id) => id === this.workPackage.id?.toString()), | ||
startWith(null), | ||
switchMap(() => this.countReminders()), | ||
), | ||
this.storeService.unread$ | ||
.pipe( | ||
startWith(0), | ||
switchMap(() => this.countReminders()), | ||
), | ||
); |
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.
Q: Why do we need to reference unread notifications? 🤔
<turbo-frame | ||
#frameElement |
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.
Nice one 👍🏾
|
||
describe "validations" do | ||
it "renders errors on the date field or time field when the reminder is in the past" do | ||
two_am = "02:00".to_time |
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.
work_package_page.expect_no_reminder_button | ||
end | ||
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.
Nice work on the feature specs! 👍🏾
…tondialog-to-workpackage-page
Thank you @akabiru for the comprehensive and detailed review! I'm on it! :) |
…tondialog-to-workpackage-page
@jjabari-op updating against dev as there were several recent CI stabalisation fixes that would be nice to have in |
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.
🥇
# At the form level, we split the date and time into two form fields. | ||
# In order to be a bit more informative of which field is causing | ||
# the remind_at attribute to be in the past/invalid, we need to | ||
# remap the error attribute to the appropriate field. | ||
def prepare_errors_from_result(service_result) | ||
# We set the reminder here for "create" case | ||
# as the record comes from the service. | ||
@reminder = service_result.result | ||
@errors = service_result.errors | ||
|
||
case @errors.find { |error| error.attribute == :remind_at }&.type | ||
when :blank | ||
handle_blank_error | ||
when :datetime_must_be_in_future | ||
handle_future_error | ||
end | ||
|
||
@errors.delete(:remind_at) | ||
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.
Ticket