-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Color Schemes: Add Color Scheme Picker to Account Settings #17259
Conversation
Design wise it's good. In the future we'll have a separate section for this, but as a first PR this is good: 👍 |
7d5578b
to
25c9550
Compare
Adding the [Status] Blocked / Hold label until #17200 is merged to master :) |
client/lib/user-settings/index.js
Outdated
@@ -1,16 +1,9 @@ | |||
/** | |||
* External dependencies | |||
*/ | |||
import { assign, isEmpty, keys, merge, has, get, set, unset } from 'lodash'; |
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.
❤️
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.
Before I comment on the other comments below:
Thanks for your review, highly appreciated! 💯
unset( settings, settingName ); | ||
|
||
const settingKeys = settingName.split( '.' ); | ||
if ( settingKeys.length > 1 ) { |
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.
What do you think to using ! isEmpty( settingKeys )
here? I feel that would be in keeping with the rest of the checks in this function.
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.
Hmm, ! isEmpty( settingKeys )
would be true though even if there is only one setting key. We only want to continue if there is more than one key e.g. ["calypso_settings", "colorScheme"]
.
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.
Ahh my bad! For some reason I was reading/treating this as settingKeys.length >= 1
!
const parentKey = settingKeys.join( '.' ); | ||
//if parent is empty, call function again | ||
if ( parentKey && isEmpty( get( settings, parentKey ) ) ) { | ||
deleteUnsavedSetting( settings, parentKey, true ); |
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 be because it's late, but I think I'm missing the need to recurse here - is this to cover strings that represent nested settings, similar to _.get
s usage?
So something like the following would work?:
deleteUnsavedSetting( userSettings, 'preferences.colorTheme' )
console.log( userSettings.preferences.colorTheme );
// undefined
Or something else?
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.
Yes, the idea behind the update to user settings is to support nested settings like 'preferences.colorTheme'
. The current way of deletion only deleted the key but resulted in an empty parent key in this.unsavedSettings
. As hasUnsavedUserSettings
only checks for isEmpty
, it would return true despite no settings being unsaved. Therefore we have to ensure to remove potentially empty parent keys.
e.g. {calypso_preferences: { colorScheme: "dark" }
=> {calypso_preferences: { } }
=> { }
client/lib/user-settings/index.js
Outdated
@@ -156,8 +173,8 @@ UserSettings.prototype.cancelPendingEmailChange = function( callback ) { | |||
*/ | |||
UserSettings.prototype.getOriginalSetting = function( settingName ) { | |||
var setting = null; | |||
if ( this.settings && this.settings[ settingName ] ) { | |||
setting = this.settings[ settingName ]; | |||
if ( this.settings && get( this.settings, settingName ) ) { |
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 may be outside the scope of this PR but I believe theres an issue here (before & after the change).
I think we could quite easily fix that here though, if you don't mind?
Here's a quick demo showing the issue... basically any falsey value would be replaced with null
:
https://runkit.com/spen/599cd633888c48001253cc1d
I think something like so should do the trick:
getOriginalSetting = settingName =>
has( this.settings, settingName )
? get( this.settings, settingName )
: null;
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.
Commenting for continuity: As per our discussion in Slack, we'll address this one outside the scope of this PR in order to isolate any potential side effects.
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.
Just a note on the code example I gave above - that can be squished down further:
getOriginalSetting = settingName => get( this.settings, settingName, null );
client/lib/user-settings/index.js
Outdated
setting = ( 'undefined' !== typeof this.unsavedSettings[ settingName ] ) | ||
? this.unsavedSettings[ settingName ] | ||
: this.settings[ settingName ]; | ||
if ( this.settings && 'undefined' !== typeof get( this.settings, settingName ) ) { |
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.
Just a suggestion here, FFTI as it's not necessarily in scope for this PR...
_.isUndefined
could be useful here, but I think _.has
would be even more useful.
If IIRC we could squish these checks down like so:
if ( this.settings && 'undefined' !== typeof get( this.settings, settingName ) ) {
// >>
if ( ! has( this.settings, settingName ) ) {
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.
Yes, that should work. 👍
Just without the !
, as it's checking for not undefined:
if ( has( this.settings, settingName ) ) {
'user_login' !== settingName | ||
) { | ||
debug( 'Removing ' + settingName + ' from changed settings.' ); | ||
delete this.unsavedSettings[ settingName ]; | ||
deleteUnsavedSetting( this.unsavedSettings, settingName ); |
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 a fan of the functional
-izing here 🙂 👍
client/lib/user-settings/index.js
Outdated
if ( settingName in this.unsavedSettings ) { | ||
delete this.unsavedSettings[ settingName ]; | ||
|
||
if ( has( this.unsavedSettings, settingName ) ) { |
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 check might also be a candidate for this.isSettingUnsaved
.
client/lib/user-settings/index.js
Outdated
: this.settings[ settingName ]; | ||
if ( this.settings && 'undefined' !== typeof get( this.settings, settingName ) ) { | ||
setting = | ||
'undefined' !== typeof get( this.unsavedSettings, settingName ) |
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 could be wrong here, but we may be able to use this.isSettingUnsaved
here - if so that might help with readability :)
@@ -529,6 +534,14 @@ const Account = React.createClass( { | |||
|
|||
{ this.communityTranslator() } | |||
|
|||
{ config.isEnabled( 'me/account/color-scheme-picker' ) && |
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 see that we're only enabling in development in this PR, so this is not a huge issue but to err on the side of caution what do you think to merging #17310 first and including the check in this PR? (See: #17310 (review))
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.
Commenting for continuity: As per our discussion in Slack just now, we're going to leave the PR order as is to ensure we have a good test case for the feature detection in #17310. We're aiming to merge the PRs in quick succession.
@frontdevde This PR needs a rebase |
0608b5a
to
c2fa9e4
Compare
@frontdevde This PR needs a rebase |
3ec9837
to
abcd2df
Compare
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.
Looking great :D
client/me/account/main.jsx
Outdated
this.updateUserSetting( 'calypso_preferences.colorScheme', colorScheme ); | ||
const settingName = 'calypso_preferences.colorScheme'; | ||
|
||
// set a fallback color scheme if no default value is provided by the API |
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'd be tempted to mention that this is a bit of a hack, allowing us to use this.props.userSettings.updateSetting
without an existing value and mention the behaviour we see without forcing this default.
In the TODO, it may also be worth explicitly mentioning that the intention is to remove this line.
What do you think?
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.
Done 👍
client/me/account/main.jsx
Outdated
|
||
// set a fallback color scheme if no default value is provided by the API | ||
// TODO: ideally the default value should be provided on the API side | ||
update( this.props.userSettings.settings, settingName, value => value || 'default' ); |
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 seems to do the trick! I'm seeing the button become active when making selections, then the option saved is persisted :)
abcd2df
to
29c0814
Compare
updateColorScheme( colorScheme ) { | ||
const settingName = 'calypso_preferences.colorScheme'; | ||
|
||
// Set a fallback color scheme if no default value is provided by the API. |
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.
👍 👍 👍 :)
@frontdevde This PR needs a rebase |
29c0814
to
05a43d9
Compare
This PR is part of a series of PRs aiming to provide support for Color Schemes in Calypso.
This PR focuses on integrating the Color Scheme Picker (PR #17200) in the Account Settings.
Notable additions in this PR:
UserSettings
(/lib/user-settings
).'me/account/color-scheme-picker'
is introduced.ColorSchemePicker
component is added to theme/account/
page.Considerations
The
ColorSchemePicker
by default connects to/viastate/preferences/
. I initially contemplated using the same approach for the integration onme/account/
but during development realized how deeply integrated with/lib/user-settings
the whole page is (viaform-base
). In order to not having to duplicate all the functionality on that page, I then decided to add support for nested settings to/lib/user-settings
instead. This way there's hardly any overhead involved in integrating theColorSchemePicker
on the Account Settings page.How to test
Visit https://calypso.live/?branch=add/color-schemes/account-me-integration or test locally.
Navigate to the
Accounts Settings
page and scroll down to theAdmin Color Scheme
section.Suggestions as to what to test
/lib/user-settings
).Note
This PR currently compares its changes to PR #17200 which in turn compares to PR #17157. This is so the changes can be easily identified. This PR will be pointed at
master
once PR #17200 and #17157 have been merged.For a more detailed description of the feature, the chosen approach and its advantages feel free to check out my post on the subject: p4TIVU-75d-p2 (internal reference).