-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
PersistenceTransforms for date in datePickerRange and datePickerSingle #1376
Merged
Merged
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
56f0a0e
add logic for checking for persisted prop in propName and propPart
harryturr 4f07812
add persistence checking defining date picker single inside of callback
harryturr 4479682
add persistence test checking defining date picker range inside of ca…
harryturr 6937f1c
lint
harryturr 65938ac
remove comments / sleep
harryturr 94b91c7
rename functions
harryturr 951a767
update circleci config to point to dcc branch
harryturr b180d00
Merge branch 'dev' into persistence-hg
harryturr a5e0874
Merge branch 'dev' into persistence-hg
harryturr 54f6229
Merge branch 'dev' into persistence-hg
harryturr 9b60d4a
update circleci to new dcc branch
harryturr 59bbf30
Update .circleci/config.yml
harryturr 900af6f
Update .circleci/config.yml
harryturr 109ea46
typo
harryturr fe58b2a
functions for interaction with date pickers, rm print statements
harryturr 91c5324
simplify check for PropName
harryturr 5c11477
add dash-generator-test-component-persisted
harryturr 1f04bc5
remove date picker tests
harryturr 424b6dd
rm obsolete imports
harryturr 0cb4d02
update test persisted component
harryturr 9c5e33d
add test components for persisted props and nested persisted props
harryturr 963031b
add persistenceTransforms test for prop and nested prop
harryturr 4c47006
add build for test compenent in package.json
harryturr 95af752
Merge branch 'dev' into persistence-hg
harryturr 738a9ec
simplify test component props and dependencies
harryturr 0b97608
Merge branch 'dev' into persistence-hg
harryturr e541e62
add build for MyPersistedComponentNested
harryturr 3c3efbf
update name
harryturr 1586634
Merge branch 'dev' into persistence-hg
harryturr b063d60
add test persistence components to @plotly/dash-test-components
harryturr e2cab41
update package.json
harryturr 06d77d3
rm old persisted test components
harryturr 2b240e2
update imports for test_persistence
harryturr e4026e6
remove old r builds
harryturr 5601ec3
update component comment description
harryturr 1596d43
Merge branch 'dev' into persistence-hg
harryturr 37d454f
remove unnecessary props from test components
harryturr f7c04fd
remove dcc branch from ci
harryturr 6f2ce30
edit code style with conditional chaining
harryturr b5f78b3
update CHANGELOG.md
harryturr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
166 changes: 166 additions & 0 deletions
166
@plotly/dash-test-components/src/components/MyPersistedComponent.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import React, {PureComponent} from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const isEquivalent = (v1, v2) => v1 === v2 || (isNaN(v1) && isNaN(v2)); | ||
|
||
const omit = (key, obj) => { | ||
const { [key]: omitted, ...rest } = obj; | ||
return rest; | ||
} | ||
|
||
/** | ||
* Adapted dcc input component for persistence tests. | ||
* | ||
* Note that unnecessary props have been removed. | ||
*/ | ||
export default class MyPersistedComponent extends PureComponent { | ||
constructor(props) { | ||
super(props); | ||
this.input = React.createRef(); | ||
this.onChange = this.onChange.bind(this); | ||
this.onEvent = this.onEvent.bind(this); | ||
this.onKeyPress = this.onKeyPress.bind(this); | ||
this.setInputValue = this.setInputValue.bind(this); | ||
this.setPropValue = this.setPropValue.bind(this); | ||
} | ||
|
||
UNSAFE_componentWillReceiveProps(nextProps) { | ||
const {value} = this.input.current; | ||
this.setInputValue( | ||
value, | ||
nextProps.value | ||
); | ||
this.setState({value: nextProps.value}); | ||
} | ||
|
||
componentDidMount() { | ||
const {value} = this.input.current; | ||
this.setInputValue( | ||
value, | ||
this.props.value | ||
); | ||
} | ||
|
||
UNSAFE_componentWillMount() { | ||
this.setState({value: this.props.value}) | ||
} | ||
|
||
render() { | ||
const valprops = {value: this.state.value} | ||
return ( | ||
<input | ||
ref={this.input} | ||
onChange={this.onChange} | ||
onKeyPress={this.onKeyPress} | ||
{...valprops} | ||
{...omit( | ||
[ | ||
'value', | ||
'setProps', | ||
], | ||
this.props | ||
)} | ||
/> | ||
); | ||
} | ||
|
||
setInputValue(base, value) { | ||
base = NaN; | ||
|
||
if (!isEquivalent(base, value)) { | ||
this.input.current.value = value | ||
} | ||
} | ||
|
||
setPropValue(base, value) { | ||
if (!isEquivalent(base, value)) { | ||
this.props.setProps({value}); | ||
} | ||
} | ||
|
||
onEvent() { | ||
const {value} = this.input.current; | ||
this.props.setProps({value}) | ||
} | ||
|
||
onKeyPress(e) { | ||
return this.onEvent(); | ||
} | ||
|
||
onChange() { | ||
this.onEvent() | ||
} | ||
} | ||
|
||
MyPersistedComponent.defaultProps = { | ||
persisted_props: ['value'], | ||
persistence_type: 'local', | ||
}; | ||
|
||
MyPersistedComponent.propTypes = { | ||
/** | ||
* The ID of this component, used to identify dash components | ||
* in callbacks. The ID needs to be unique across all of the | ||
* components in an app. | ||
*/ | ||
id: PropTypes.string, | ||
|
||
/** | ||
* The value of the input | ||
*/ | ||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||
|
||
/** | ||
* The name of the control, which is submitted with the form data. | ||
*/ | ||
name: PropTypes.string, | ||
|
||
/** | ||
* Dash-assigned callback that gets fired when the value changes. | ||
*/ | ||
setProps: PropTypes.func, | ||
|
||
|
||
/** | ||
* Used to allow user interactions in this component to be persisted when | ||
* the component - or the page - is refreshed. If `persisted` is truthy and | ||
* hasn't changed from its previous value, a `value` that the user has | ||
* changed while using the app will keep that change, as long as | ||
* the new `value` also matches what was given originally. | ||
* Used in conjunction with `persistence_type`. | ||
*/ | ||
persistence: PropTypes.oneOfType([ | ||
PropTypes.bool, | ||
PropTypes.string, | ||
PropTypes.number, | ||
]), | ||
|
||
/** | ||
* Properties whose user interactions will persist after refreshing the | ||
* component or the page. Since only `value` is allowed this prop can | ||
* normally be ignored. | ||
*/ | ||
persisted_props: PropTypes.arrayOf(PropTypes.oneOf(['value'])), | ||
|
||
/** | ||
* Where persisted user changes will be stored: | ||
* memory: only kept in memory, reset on page refresh. | ||
* local: window.localStorage, data is kept after the browser quit. | ||
* session: window.sessionStorage, data is cleared once the browser quit. | ||
*/ | ||
persistence_type: PropTypes.oneOf(['local', 'session', 'memory']), | ||
}; | ||
|
||
MyPersistedComponent.persistenceTransforms = { | ||
value: { | ||
|
||
extract: propValue => { | ||
if (!(propValue === null || propValue === undefined)) { | ||
return propValue.toUpperCase(); | ||
} | ||
return propValue; | ||
}, | ||
apply: storedValue => storedValue, | ||
|
||
}, | ||
}; |
169 changes: 169 additions & 0 deletions
169
@plotly/dash-test-components/src/components/MyPersistedComponentNested.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
import React, {PureComponent} from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const isEquivalent = (v1, v2) => v1 === v2 || (isNaN(v1) && isNaN(v2)); | ||
|
||
const omit = (key, obj) => { | ||
const { [key]: omitted, ...rest } = obj; | ||
return rest; | ||
} | ||
|
||
/** | ||
* Adapted dcc input component for persistence tests. | ||
* | ||
* Note that unnecessary props have been removed. | ||
*/ | ||
export default class MyPersistedComponentNested extends PureComponent { | ||
constructor(props) { | ||
super(props); | ||
this.input = React.createRef(); | ||
this.onChange = this.onChange.bind(this); | ||
this.onEvent = this.onEvent.bind(this); | ||
this.onKeyPress = this.onKeyPress.bind(this); | ||
this.setInputValue = this.setInputValue.bind(this); | ||
this.setPropValue = this.setPropValue.bind(this); | ||
} | ||
|
||
UNSAFE_componentWillReceiveProps(nextProps) { | ||
const {value} = this.input.current; | ||
this.setInputValue( | ||
value, | ||
nextProps.value | ||
); | ||
this.setState({value: nextProps.value}); | ||
} | ||
|
||
componentDidMount() { | ||
const {value} = this.input.current; | ||
this.setInputValue( | ||
value, | ||
this.props.value | ||
); | ||
} | ||
|
||
UNSAFE_componentWillMount() { | ||
this.setState({value: this.props.value}) | ||
} | ||
|
||
render() { | ||
const valprops = {value: this.state.value} | ||
return ( | ||
<input | ||
ref={this.input} | ||
onChange={this.onChange} | ||
onKeyPress={this.onKeyPress} | ||
{...valprops} | ||
{...omit( | ||
[ | ||
'value', | ||
'setProps', | ||
], | ||
this.props | ||
)} | ||
/> | ||
); | ||
} | ||
|
||
setInputValue(base, value) { | ||
base = NaN; | ||
|
||
if (!isEquivalent(base, value)) { | ||
this.input.current.value = value | ||
} | ||
} | ||
|
||
setPropValue(base, value) { | ||
if (!isEquivalent(base, value)) { | ||
this.props.setProps({value}); | ||
} | ||
} | ||
|
||
onEvent() { | ||
const {value} = this.input.current; | ||
this.props.setProps({value}) | ||
} | ||
|
||
onKeyPress(e) { | ||
return this.onEvent(); | ||
} | ||
|
||
onChange() { | ||
this.onEvent() | ||
} | ||
} | ||
|
||
MyPersistedComponentNested.defaultProps = { | ||
persisted_props: ['value.nested_value'], | ||
persistence_type: 'local', | ||
}; | ||
|
||
MyPersistedComponentNested.propTypes = { | ||
/** | ||
* The ID of this component, used to identify dash components | ||
* in callbacks. The ID needs to be unique across all of the | ||
* components in an app. | ||
*/ | ||
id: PropTypes.string, | ||
|
||
/** | ||
* The value of the input | ||
*/ | ||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||
|
||
/** | ||
* The name of the control, which is submitted with the form data. | ||
*/ | ||
name: PropTypes.string, | ||
|
||
/** | ||
* Dash-assigned callback that gets fired when the value changes. | ||
*/ | ||
setProps: PropTypes.func, | ||
|
||
|
||
/** | ||
* Used to allow user interactions in this component to be persisted when | ||
* the component - or the page - is refreshed. If `persisted` is truthy and | ||
* hasn't changed from its previous value, a `value` that the user has | ||
* changed while using the app will keep that change, as long as | ||
* the new `value` also matches what was given originally. | ||
* Used in conjunction with `persistence_type`. | ||
*/ | ||
persistence: PropTypes.oneOfType([ | ||
PropTypes.bool, | ||
PropTypes.string, | ||
PropTypes.number, | ||
]), | ||
|
||
/** | ||
* Properties whose user interactions will persist after refreshing the | ||
* component or the page. Since only `value` is allowed this prop can | ||
* normally be ignored. | ||
*/ | ||
persisted_props: PropTypes.arrayOf(PropTypes.oneOf(['value.nested_value'])), | ||
|
||
/** | ||
* Where persisted user changes will be stored: | ||
* memory: only kept in memory, reset on page refresh. | ||
* local: window.localStorage, data is kept after the browser quit. | ||
* session: window.sessionStorage, data is cleared once the browser quit. | ||
*/ | ||
persistence_type: PropTypes.oneOf(['local', 'session', 'memory']), | ||
}; | ||
|
||
MyPersistedComponentNested.persistenceTransforms = { | ||
value: { | ||
|
||
nested_value: { | ||
|
||
extract: propValue => { | ||
if (!(propValue === null || propValue === undefined)) { | ||
return propValue.toUpperCase(); | ||
} | ||
return propValue; | ||
}, | ||
apply: storedValue => storedValue, | ||
|
||
} | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
import StyledComponent from './components/StyledComponent'; | ||
import MyPersistedComponent from './components/MyPersistedComponent'; | ||
import MyPersistedComponentNested from './components/MyPersistedComponentNested'; | ||
|
||
|
||
export { | ||
StyledComponent, | ||
StyledComponent, MyPersistedComponent, MyPersistedComponentNested | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -265,10 +265,18 @@ const noopTransform = { | |
apply: (storedValue, _propValue) => storedValue | ||
}; | ||
|
||
const getTransform = (element, propName, propPart) => | ||
propPart | ||
? element.persistenceTransforms[propName][propPart] | ||
: noopTransform; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Old logic checks for just |
||
const getTransform = (element, propName, propPart) => { | ||
if ( | ||
element.persistenceTransforms && | ||
element.persistenceTransforms[propName] | ||
) { | ||
if (propPart) { | ||
return element.persistenceTransforms[propName][propPart]; | ||
} | ||
return element.persistenceTransforms[propName]; | ||
} | ||
return noopTransform; | ||
}; | ||
|
||
const getValsKey = (id, persistedProp, persistence) => | ||
`${stringifyId(id)}.${persistedProp}.${JSON.stringify(persistence)}`; | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back 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.
As we had discussed, this is copied over from
dcc.Input
. A lot of these props are not really useful for the test either. Try and keep the surface area for this component to the minimum you need to do the tests you need, nothing 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.
37d454f