Page MenuHomePhabricator

[web] Fix `ThreadSettingsGeneralTab` save button `disabled` prop
ClosedPublic

Authored by abosh on May 9 2022, 9:50 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Nov 23, 10:44 PM
Unknown Object (File)
Sat, Nov 23, 10:03 PM
Unknown Object (File)
Sat, Nov 23, 9:40 PM
Unknown Object (File)
Sat, Nov 23, 7:43 PM
Unknown Object (File)
Wed, Nov 13, 3:14 AM
Unknown Object (File)
Sat, Nov 9, 3:49 PM
Unknown Object (File)
Sat, Nov 9, 3:49 PM
Unknown Object (File)
Sat, Nov 9, 3:33 PM

Details

Summary

Fixed the save button in ThreadSettingsGeneralTab which was previously not staying disabled if the user had selected another color and then changed their selection back to the current thread color (making no other changes in the thread settings) (see before/after video in Test Plan).

Related Linear issue with full context here.

Test Plan

Tested on Chrome/Safari and works as expected.

Before:

After:

Diff Detail

Repository
rCOMM Comm
Branch
master
Lint
No Lint Coverage
Unit
No Test Coverage

Event Timeline

abosh edited the test plan for this revision. (Show Details)
abosh added 1 blocking reviewer(s): atul.
web/modals/threads/thread-settings-general-tab.react.js
56 ↗(On Diff #12459)

Not sure about the usage of the !! coercion operator to test if a value is truthy (couldn't find anything in Notion about this, but it is used elsewhere in the codebase). The original code explicitly wrote v !== null && v !== undefined (which also missed the case if v === '') but this was in a call to the some method, whereas the new code explicitly checks each field, so checking against each field against each value (undefined, null, and '') might be too verbose.

58 ↗(On Diff #12459)

This covers the case when the ThreadSettingsGeneralTab is first opened. In that case, queuedChanges.color is not defined, but once a new color is selected queuedChanges.color is always defined, which is why the equals() check to make sure the "selected" color is not the current thread color is included on the next line.

web/modals/threads/thread-settings-general-tab.react.js
56 ↗(On Diff #12459)

OK, just realized why the v === '' case was not included in the original code. The user might want to clear the current thread name or description! Updating right now.

Removed case when queuedChanges.name and queuedChanges.description are '' (if the
user wants to clear the name/description, this is stil a change!).

This logic is pretty verbose and will only grow in size with the addition of new settings.

I think it'd be cleaner to handle the issue with the color setting in onChangeColor. What do you think?

atul requested changes to this revision.May 10 2022, 6:38 AM
This revision now requires changes to proceed.May 10 2022, 6:38 AM

Handled issue in onChangeColor, per feedback.

Ok, so the previous issue was that something like #ffffff was being compared with something like ffffff and so changes were always queued? And using tinycolor, which handles either way of representing hex string, gets around that issue?

Should we instead be consistent about using hex colors that start with # vs without? Or maybe we should use always run the strings through tinycolor to figure things out for us?

Either way, looks like this resolves the issue.

(Adding @ashoat/@palys-swm as reviewers to see if they have thoughts)

This revision is now accepted and ready to land.May 19 2022, 6:23 AM
This revision now requires review to proceed.May 19 2022, 6:23 AM

I think relying on us being consistent with hex values is a great idea, but we should still run the strings through tinycolor for the guarantee that color equality is handled the same way each time. For example, someone could easily forget to add or remove a # from the string but not know it, introducing a bug like this one. Using tinycolor.equals() removes this aspect of human error.

ashoat requested changes to this revision.May 19 2022, 10:01 PM

Should we instead be consistent about using hex colors that start with # vs without?

Yes, I think so. Can you clarify where the mismatch is? In some places we use #${color} to convert between... maybe we need to do that here too?

Not opposed to using tinycolor but would like more context on what's causing the issue to determine if a simple string concatenation somewhere would be a more appropriate solution.

This revision now requires changes to proceed.May 19 2022, 10:01 PM
In D3980#115398, @yayabosh wrote:

I think relying on us being consistent with hex values is a great idea, but we should still run the strings through tinycolor for the guarantee that color equality is handled the same way each time. For example, someone could easily forget to add or remove a # from the string but not know it, introducing a bug like this one. Using tinycolor.equals() removes this aspect of human error.

Would this be a programmer forgetting to remove a #, or a user? I assume it's the former since I don't think we let the user input hex codes anywhere... as for the programmer, I wonder if there would be a way to enforce this with Flow.

Here's the exact issue, it's actually not related to the #:

The color of the thread (threadInfo.color) is stored as a lowercase hex string (screenshot is from Redux DevTools, which I used to confirm this):

image.png (230×364 px, 30 KB)

However, when the user selects another color (updating queuedChanges), queuedChanges.color is stored as an uppercase hex string (screenshot is from React Developer Tools):

image.png (210×516 px, 59 KB)

Now, let's say the user switches their selection back to the original thread color. So now queuedChanges.color is the uppercase version of threadInfo.color, when really it should be undefined since no "change" was made! But in the original code, queuedChanges.color is the uppercase version of threadInfo.color, which doesn't disable the Save button since there was some change queued.

This is all because the original equality check will return false since it's checking for string equality, which means checking two strings against each other, case-sensitively. However, hex strings should be compared case-insensitively, and moreover, any strings representing colors should probably have their own special form of equality checking to ensure they're the same color (like converting to an RGB string or something). In this case, though, if we're all only using hex strings for colors this isn't necessary.

The usage of tinycolor just ensures this color equality in a standardized way.

Thanks for the detailed explanation, @yayabosh!

Can we also make sure to lowercase the strings going into queuedChanges.color? Separate note: I'm not sure where else we do string comparisons of hex codes, but I suspect we have other places in the app where we do string comparisons without tinycolor.

This revision is now accepted and ready to land.May 20 2022, 7:01 AM

Can we also make sure to lowercase the strings going into queuedChanges.color?

Done!

I'm not sure where else we do string comparisons of hex codes, but I suspect we have other places in the app where we do string comparisons without tinycolor.

I'll make a Linear issue to track this and try and get this fixed. There are other places in the codebase where we compare color strings without tinycolor.