-
Notifications
You must be signed in to change notification settings - Fork 10
Remove the requirement to pre-format JSON data before it is passed into jsonInput #3937
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
base: develop
Are you sure you want to change the base?
Conversation
- prevents need for each use of jsonInput to manually format the value
…on pool monitor - will be formatted in the JSONinput component itself
desktop/cmp/input/JsonInput.ts
Outdated
@@ -21,11 +21,18 @@ export const [JsonInput, jsonInput] = hoistCmp.withFactory<JsonInputProps>({ | |||
displayName: 'JsonInput', | |||
className: 'xh-json-input', | |||
render(props, ref) { | |||
let {value, ...jsonInputProps} = props; | |||
|
|||
if (typeof value !== 'string') { |
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.
Originally was checking if value was an object, but null
seems to be a valid value to be passed in, and is an object in JS.
Per request, now using lodash for this check.
- use lodash for data type checks (rather than typeof) - rename spread props to reference that they are going INTO codeInput, rather than OUT OF jsonInput
desktop/cmp/input/JsonInput.ts
Outdated
let {value, ...codeInputProps} = props; | ||
|
||
if (isPlainObject(value)) { | ||
value = JSON.stringify(value, null, 2); |
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.
Any processing of the value should be done in the input model, in this case that would be CodeInputModel
since this input control is just a wrapper on the codeInput
component, might make sense to introduce a JsonInputModel
class here for special json handling. HoistInputModel
is the base class for all input component models and has methods for converting between the external and internal values, which is where code like this needs to live. It is important to use those methods as our input components support both the controlled mode (providing value
and onChange
in props) as well as binding to a property of a provided model.
DateInput
is probably a good example to follow here, where it has a valueType
prop to tell it whether it should be dealing with a LocalDate
or a Date
.
I'm personally in favor of this change overall, others might feel differently as it does open the door for potentially confusing behavior as the object will be stringified and then parsed when written back, though any usages currently would effectively be doing the same thing, just that they'd just be needing to do the stringifying and parsing themselves.
@amcclain / @lbwexler any thoughts on supporting both strings and objects in JsonInput?
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's a good question - I had not considered it.
My concern was that it could muddy the waters a bit in terms of what value types this component supports. Was thinking we could use a type to represent valid JSON values - typefest has JsonValue
which I believe would be it.
However for that to be a valid concern at all, we'd need to actually spec the type of values that inputs support, and as David points out above, HoistInputProps.value
is stuck on any
. Can we add a generic to support setting the value type on that props interface?
That would be a very different change from pretty-printing - I think that still need to be addressed, see comment on the linked issue, but adding proper value typing seems like a good idea. My only concern is that if we did so we would create work for devs who were unwittingly benefitting from looser typing with any
, but that's kinda the idea...
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.
If we did support auto-conversion, believe then the type would be Jsonifiable
from typefest.
CHANGELOG.md
Outdated
* Updated the `jsonInput` component to auto-format its provided value for display. | ||
It can accept JSON, stringified JSON or plain objects and output proper pretty-printed JSON in the | ||
UI - without the need for manual formatting in the call. | ||
|
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.
We had a release underneath this PR, sorry :) - will need to move this up
…n showing readonly values - specific use case here is pretty printing JSON data without manual fromatting of provided values - codeInput does all the heavy lifting, so change is there (possible use cases for other formats) - update to admin activity details use of jsonInput to test change
- no longer attempts to format the JSON for display manually - rename an observed prop to represent that it is not auto-formatted
- includes an update to a component which was passing a raw object into jsonInput - objects will still need to be stringified to use in jsonInput / codeInput - also includes doc update to the codeInput interface
import {action, computed, makeObservable, observable} from '@xh/hoist/mobx'; | ||
import {ActivityTrackingModel} from '../ActivityTrackingModel'; | ||
|
||
export class ActivityDetailModel extends HoistModel { | ||
@lookup(ActivityTrackingModel) activityTrackingModel: ActivityTrackingModel; | ||
@managed gridModel: GridModel; | ||
@managed formModel: FormModel; | ||
@observable formattedData; | ||
@observable displayData; |
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 model is no longer doing the formatting. Update the name to reflect. See https://github.com/xh/hoist-react/pull/3937/files#diff-2a82d78cc59aadd90860fcd0383be76d3b7491d7b19736a18857b6b93d30cd66L117-L125
@@ -326,22 +334,33 @@ class CodeInputModel extends HoistInputModel { | |||
if (this.cursor) this.clearSearchResults(); | |||
}; | |||
|
|||
onAutoFormat = () => { | |||
if (!isFunction(this.componentProps.formatter)) return; | |||
override toInternal(val: any) { |
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.
Override fo the toInternal used by the HoistInputModel
. Now will run the formatter if requested and properly configured.
…ter describe the functionality occuring
width: '100%', | ||
height: '100%', | ||
showCopyButton: true, | ||
value: model.formattedData | ||
value: model.displayData |
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.
} | ||
} | ||
|
||
private formatAndSetEditorValue() { |
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.
@amcclain had some naming / formatting updates he wanted done here.
onAutoFormat -> formatValue was the first pass at the name. We are choosing to use autoFormat as the new prop (on interface) to format readonly data when loading into the UI. Anselm felt onAutoFormat was not the best name of the reaction happening here (to a user requesting the use of the formatter to update their UI)
tryPrettyPrint was use only once, in this method, to run the formatter. Inlining that call to the method itself.
However, we subsequently added safeFormatValue, which is much leaner - it just takes a val, tries to format it, and returns it one way or the other. This existing method was already safe (try/catch block), so to a future developer it may be configuring why the similar names. So I opted to update this method to denote that it would be sending the value to the editor (code mirror) instead of returning said value.
linter: linter, | ||
formatter: fmtJson, | ||
linter, | ||
formatter: safeFmtJson, |
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.
Unsure if we want this? We create a "safe" version of fmtJson
(https://github.com/xh/hoist-react/pull/3937/files#diff-1bd2a34b6889e1254a813e22f3fecee2169724007549f9c6d2396658c54ebc7bR76). I made this update to use that for jsonInput, but that may create issues I am not thinking of?
Had a meeting this morning with @amcclain, and in that we reviewed this issue broadly. Updates done in that meeting applied to this PR. CC:// @haynesjm42 |
@@ -43,6 +43,14 @@ export interface CodeInputProps extends HoistProps, HoistInputProps, LayoutProps | |||
/** True to focus the control on render. */ |
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 is a desktop
component. I did not see a mobile version, but let me know if I just overlooked something.
Linked issue: #1923
This change attempts to handle the use case of formatting provided JSON values to the jsonInput component, so each use does not need to manually format the value. It does this under narrow criteria here for safety - readonly inputs only being the main requirement, to avoid possible formatting conflicts while a user was editing a value.
Optional discussion
value
fromHoistInputProps
. It is set asvalue?: any;
which not quite right here - I would assume jsonInput would want a more limited set of accepted options? However, I am not yet sure of the full set of XH provided types we would want to limit this to. I seePlainObject
, but I am likely missing (or just forgetting) other valid options. So optionally:[Object object]
.Hoist P/R Checklist
develop
branch as of last change.breaking-change
label + CHANGELOG if so.