Skip to content

Issue 19058 - Sort user-mentions suggestions by prefix first, then alphabetically#19218

Merged
hassaanelgarem merged 25 commits intowordpress-mobile:trunkfrom
igoriols:feature/19058-sort-users-suggestions-by-prefix
Sep 6, 2022
Merged

Issue 19058 - Sort user-mentions suggestions by prefix first, then alphabetically#19218
hassaanelgarem merged 25 commits intowordpress-mobile:trunkfrom
igoriols:feature/19058-sort-users-suggestions-by-prefix

Conversation

@igoriols
Copy link
Contributor

@igoriols igoriols commented Aug 22, 2022

Closes #19058

Description

In this PR, I'm addressing the sorting change requested. I'm displaying first the users whose names begin with a prefix provided by the user, then alphabetically. The first criteria are to sort alphabetically by users whose usernames or display names begin with the provided prefix. If both username and display name begin with the prefix, the display name will be prioritized in the sorting.

Details

  • I’m using localizedCaseInsensitiveCompare to compare displayNames, because the user can have the displayName in different languages. The comparison is localizable and case-insensitive.

  • I’m using < to compare usernames because they are very restricted, and the lexicographical comparison should work for them.

  • I'm looping through the UserSuggestions array to create two sub-arrays. The first one has the users whose display names begin with a prefix provided by the user. The second one has the users whose display names don't begin with the prefix provided by the user.

  • I'm sorting both arrays alphabetically, then I combine the sorted arrays.

  • I updated the tests to conform with the new sorting criteria.

Preview

Testing Instructions

N.B: The user-mentions suggestions feature is not enabled in self-hosted sites ( wordpress.org ).

  1. Tap the "My Site" tab.
  2. Tap on "Menu"
  3. Tap on "Comments" row.
  4. Tap any comment.
  5. Tap "Reply" button.
  6. Type "@" and you should see the user-mentions suggestions list.
  7. Type a prefix and check if the list is sorted first by users whose usernames or display names begin with the prefix, then alphabetically.

There are other scenarios to display the user-mentions suggestions list described in #18979.

Regression Notes

  1. Potential unintended areas of impact
    N/A

  2. What I did to test those areas of impact (or what existing automated tests I relied on)
    N/A

  3. What automated tests I added (or what prevented me from doing so)
    I updated the existing tests related to the user-mentions suggestions list.

PR submission checklist:

  • I have completed the Regression Notes.
  • I have considered adding unit tests for my changes.
  • I have considered adding accessibility improvements for my changes.
  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

@igoriols igoriols changed the title Issue 19058 - Sort user-mentions suggestions by prefix first then alphabetically Issue 19058 - Sort user-mentions suggestions by prefix first, then alphabetically Aug 22, 2022
@igoriols igoriols force-pushed the feature/19058-sort-users-suggestions-by-prefix branch from 516c39d to 3f8c2ce Compare August 22, 2022 01:00
Copy link
Contributor

@hassaanelgarem hassaanelgarem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can do two things differently:

  • Doing a case insensitive search instead of case-sensitive
  • Look for the prefix in both the username and the display name

@igoriols What do you think?

@@ -0,0 +1,7 @@
extension UserSuggestion: Comparable {
public static func < (lus: UserSuggestion, rus: UserSuggestion) -> Bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Nit]

Suggested change
public static func < (lus: UserSuggestion, rus: UserSuggestion) -> Bool {
public static func < (lhs: UserSuggestion, rhs: UserSuggestion) -> Bool {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious, what do lus and ldn stand for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lus: left user suggestion
rus: right user suggestion
ldn: left display name
rdn: right display name
I thought it would be better than the standard lhs (left-hand side) and rhs (right-hand side), but I can change to use lhs and rhs. I can apply more meaningful names to the unwrapped display names, also.

var otherUserSuggestions = [UserSuggestion]()

userSuggestions.forEach { suggestion in
guard let displayName = suggestion.displayName else { return }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a corner case, but if the user doesn't have a display name for some reason, they will be filtered out completely. I think we should add them to otherUserSuggestions in that case. Wdyt?

Copy link
Contributor Author

@igoriols igoriols Aug 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is a good idea. I'm going to apply it.

}
}

private static func sort(userSuggestions: [UserSuggestion], by searchQuery: String) -> [UserSuggestion] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a brief documentation of what's happening here? 🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. It's done. Thank you for reminding me.

@igoriols
Copy link
Contributor Author

igoriols commented Aug 23, 2022

I think we can do two things differently:

* Doing a case insensitive search instead of case-sensitive

* Look for the prefix in both the username and the display name

@igoriols What do you think?

Hi @hassaanelgarem. Just to make sure I understand.

  1. About case insensitive search, do you mean remove the [c] from here?

  2. If the user has the prefix in username and displayName, should we sort by displayName first?
    I'm asking because, in my opinion, the displayName is more relevant.

@hassaanelgarem
Copy link
Contributor

About case insensitive search, do you mean remove the [c] from here?

@igoriols No, I mean changing the hasPrefix() check here to be case insensitive.

Comment on lines +151 to +153
if let displayName = suggestion.displayName,
(username.beginsWith(prefix: prefix) || displayName.beginsWith(prefix: prefix)) {
prefixedUserSuggestions.append(suggestion)
Copy link
Contributor

@AliSoftware AliSoftware Aug 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will skip users with a nil displayName… even if they have a username that begins with the prefix.

So {"ID":102,"user_login":"carlosdiaz","display_name":null} will not be found even if prefix is carl here, because let displayName = suggestion.displayName will be false and exit the condition already.

Is that intentional? Do we want to prioritize only the users who have a non-nil display name?

If not, this condition will need to be adjusted accordingly 🙂 (and it would be nice to use the occasion to add a test case for this while we're at it 😉 )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch. The idea was to have users with a username or a displayName beginning with the prefix first. I think your dictionary approach suggestion will cover that. I will add a new entry to test this scenario, also.

@igoriols igoriols requested a review from AliSoftware August 25, 2022 00:02
@igoriols igoriols requested review from hassaanelgarem and removed request for AliSoftware August 26, 2022 03:11
@igoriols igoriols requested review from AliSoftware and hassaanelgarem and removed request for AliSoftware and hassaanelgarem August 26, 2022 04:18
Copy link
Contributor

@hassaanelgarem hassaanelgarem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works as expected 🚀

@igoriols igoriols requested a review from AliSoftware August 31, 2022 06:00
Copy link
Contributor

@AliSoftware AliSoftware left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall good, nice job!

Left a couple of nitpick suggestions (up to you to apply or not), and also a suggestion for additional test cases. But other than that this LGTM 👍

@@ -119,7 +119,7 @@ class SuggestionsListViewModelTests: CoreDataTestCase {
func testSearchSuggestionsWithPartialMatch() throws {
// Given
let word = "@ca"
Copy link
Contributor

@AliSoftware AliSoftware Aug 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 I notice that you don't have tests that contains diacritics or uppercase letters as prefix. Which means we don't cover the cases of things like @Ca, or ensure that e.g. @Caa would match user with display name "Caárla Diaz".

Could be nice to add some coverage for that, especially given you were thoughtful in the implementation to implement case-insensitive and diacritics-insensitive comparison for display Name (but not for user name), so would be nice to test for it to ensure there won't be an accidental regression for that aspect in the future.

Copy link
Contributor Author

@igoriols igoriols Aug 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch. I added more tests to cover more scenarios. Thank you!

@AliSoftware
Copy link
Contributor

AliSoftware commented Aug 31, 2022

Just thought of some edge cases (though that one should probably be for a separate PR rather than this one): how does this whole thing behaves with RTL and non-Latin languages?

  • I'd assume that thanks to the localizedCaseInsensitiveCompare the comparison will be locale-aware, so we should be good on that front with using the sort order according to the user's locale 👍
  • But is that also true for our hasPrefix, especially for RTL text? Or using Latin transcription prefix of simplified Chinese characters? 🤔 Not sure that .caseInsensitive, .diacriticsInsensitive covers locale insensitive or awareness 🤔
  • And how does both the sorting and the filtering fares when the list of suggested users contains a mix of users with Latin displayName and other users with eg Japanese or Chinese characters in their display name? I think it should turn out OK (because Foundation is smart enough to deal with those on our behalf in the localizedCaseInsensitiveCompare and range implementations, but would be nice to confirm 😛
  • And is the logic of "The user types @ then C then a in the textField and expect the filtering to be by prefix Ca (and not aC or \u{200F}Ca) (U200F being the RTL marker in Unicode, though I doubt it would be present in the String, since the Bidi algorithm would take care of switching the text direction between @ and the text as needed automatically… but worth checking)
  • If the user types @Cá with the acute accent explicitly typed, should we list suggestions actually having the accent first, then the ones matching in diacritics-insensitive way next, then the rest? This would probably be taking it a bit too far and not worth the effort tho 😅

To be clear, all of those cases/open questions are (1) likely out of scope for this PR (2) might not all be worth actually fixing or even investigating, even in a separate PR — as I'm probably overthinking some of those cases. Still, I just thought I'd braindump those here to raise the question and see if it's worth checking/ investigating those cases or not. 🙃

Copy link
Contributor

@AliSoftware AliSoftware left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from the small 💄 typo in the test comments, this looks ready to merge to me now. Nice work 👍

@hassaanelgarem hassaanelgarem modified the milestones: 20.7, 20.8 Sep 4, 2022
@hassaanelgarem
Copy link
Contributor

@igoriols I updated the milestone to 20.8 since we won't catch the code freeze. Please update the release note accordingly 🙏

@hassaanelgarem hassaanelgarem merged commit 0a65c53 into wordpress-mobile:trunk Sep 6, 2022
@mokagio
Copy link
Contributor

mokagio commented Oct 2, 2022

@igoriols just wanted to let you know that WordPress 20.8, the first version with your changes from this PR, just started rolling out to users.

Thank you so much for your contribution! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mentions: Suggestions ordered by prefix instead of alphabetically.

4 participants