-
Notifications
You must be signed in to change notification settings - Fork 8.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
[Dashboard] [Controls] Allow control changes to be discarded #147482
[Dashboard] [Controls] Allow control changes to be discarded #147482
Conversation
} | ||
this.syncWithTimeRange(); |
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.
The timeslider control wasn't actually discarding the changes to the selected time range value on input change because it was only syncing with the time range when the global time range changed. Moving this syncwithTimeRange
call outside of the if
statement fixed this 👍
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.syncWithTimeRange() should stay in the if statement so syncWithTimeRange is not called every time input changes.
I could not reproduce the problem you mentioned and was able to do the following
- edit code, moving syncwithTimeRange back into if statement
- create dashboard with timeslider control
- save dashboard
- switch to view mode
- switch back to edit mode
- change time range - verified time slider control updated to new time range
- Click "Switch to view mode" and select discard changes in modal
- verified time slider control updated to previous time range.
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.
Oh... hrm. Very odd.
Here is me replicating the behaviour when I move the syncwithTimeRange
back into the if
:
BadTimeSlider.mov
I will try with a freshly bootstrapped Kibana to see if something funky is happening....
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.
Yup, tried it with a fresh install (updated my branch, pulled the changes, and built Kibana with yarn cache clean && yarn kbn clean && yarn kbn bootstrap
) and I can still replicate that the changes to the time slider are not being discarded when I move syncwithTimeRange
back into the if
. I'm not sure why you aren't able to replicate it? Very odd....
Here it is being replicated in Firefox (the previous video was taken in Chrome) after the fresh install:
BadTimeSlider2.mov
Can you try replicating it after a fresh install on your end @nreese?
Agreed that calling syncWithTimeRange
may not be the best way to do it but, from my digging into this bug, the componentState
and explicitInput
became out of sync when discarding changes. Basically, discarding changes resets the explicitInput
to the old value directly - so, while the getInput$()
subscription is fired appropriately when changes are discarded, because this.onInputChanged()
is all contained within the if
, the component state is not updated as it should be. Hence, the changes appearing to not be discarded.
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.
Thank you for the video, that helped. I was changing the time range in the global time picker, not changing the selected timeslice in the time slider. I can see the problem now.
Calling syncWithTimeRange on any input change is a problem. syncWithTimeRange publishes timeslice and updates a bunch of redux state that does not need to be updated.
How about wrapping syncWithTimeRange in an if statement to only call when this case happens. See 97887a5 as an example.
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.
Good idea! :) I added something along those lines in 62f2f0d
It's definitely a bit messy - not sure if there is a better way to go about it. Because componentState
stores the value but explicitInput
stores the percentage, there isn't a super easy way to reset the component state back to its previous value when the explicitInput
is changed.... Interested in your thoughts on how this might be cleaned up!
Pinging @elastic/kibana-presentation (Team:Presentation) |
@@ -617,8 +617,11 @@ export class DashboardPageControls extends FtrService { | |||
} | |||
|
|||
// Time slider functions | |||
public async gotoNextTimeSlice() { | |||
public async gotoNextTimeSlice(closePopover: boolean = 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.
I would not recommend adding closePopover parameter to gotoNextTimeSlice. It takes away from the readability of the functional tests. For example
- gotoNextTimeSlice(false) means goto next time slice
- gotoNextTimeSlice() means goto next time slice and close popover.
When you come back to look at these tests in a few months, you will not remember what passing false and not passing false actually do.
I think this does not really save a lot and showing explicit steps in functional tests really helps with readability.
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.
Ignore my previous comment :) Cleaned this up in cfdb008
@@ -50,6 +50,12 @@ export class TimeSliderControlEmbeddable extends Embeddable< | |||
private getTimezone: ControlsSettingsService['getTimezone']; | |||
private timefilter: ControlsDataService['timefilter']; | |||
private prevTimeRange: TimeRange | undefined; | |||
private prevTimesliceAsPercentage: |
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.
prevTimesliceAsPercentage needs to be set either in constructor or syncWithTimeRange (which is called by constructor)
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.
Good catch! Done in 3297a73 👍
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.
prevTimesliceAsPercentage is always set and can be typed as just
private prevTimesliceAsPercentage:
{
timesliceStartAsPercentageOfTimeRange?: number;
timesliceEndAsPercentageOfTimeRange?: number;
};
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.
Right WOOP sorry :) Done in 23c0da7
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.
LGTM
code review, tested in chrome
💚 Build Succeeded
Metrics [docs]Async chunks
Unknown metric groupsESLint disabled in files
ESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: cc @Heenawter |
💔 All backports failed
Manual backportTo create the backport manually run:
Questions ?Please refer to the Backport tool documentation |
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
…#147482) Closes elastic#147293 ## Summary Before this change, the Redux state `explicitInput` was getting out of sync with the embeddable `explicitInput` in scenarios where the new `explicitInput` was missing a key that the old `explicitInput` had - therefore, because they were out of sync, the changes that **should** have been discarded kept getting injected back into the embeddable `explicitInput`, which made it impossible to actually discard anything unless the key existed in both the before and after state. This PR fixes this by replacing the entire Redux state `explicitInput` with the embeddable `explicitInput` rather than spreading the new value. It also fixes a bug with the time slider control where changes to the embeddable's input were not reflected properly in the control's state, so nothing could be discarded even after the initial bug was fixed. #### Further Explanation When a control is first created, all the optional properties of the explicit input do not yet exist - for example, when creating an options list control, the `selections` key does not exist in the `explicitInput` until a selection is made. Therefore, imagine the following scenario: 1. You create an options list control (where the `selections` key does not exist) and save the dashboard 2. You make some selections, which causes `unsaved changes` because the `selections` key now exists and is equal to an array 3. You switch to view mode and choose to discard your changes, thus (supposedly) removing the `selections` key from the `explicitInput` object once again Unfortunately, the Redux embeddable state for each control was **not** accurately removing the `selections` key as expected - this was because, when trying to update the `explicitInput` via the old `updateEmbeddableReduxInput`, the new value was **spread** on top of the older value rather than replacing it. In a simplified scenario, this resulted in something like this: ```typescript const oldExplicitInput = { id: 'test_id', selections: ['test selection'] }; const newExplicitInput = { id: 'test_id' } const result = { ...oldExplicitInput, ...newExplicitInput }; ``` In this code, because `newExplicitInput` does not have the `selections` key, `result` will equal `{ id: 'test_id', selections: ['test selection'] }` - this is not the behaviour we want! Instead, we wanted to replace the entire old `explicitInput` with the new `explicitInput`. Effectively, that is what this PR does. Thanks to @ThomThomson for helping out with finding the root cause of this after I got lost :) ### How to Test For both options list and range slider controls, 1. Create a control of the desired type 2. Save the dashboard 3. Make some sort of change that causes unsaved changes - for example, make a selection or, if an options list control, set `exclude` to `true` 4. Switch to view mode, discarding the changes 5. Ensure that the changes made in step 3 are no longer applied ✅ 6. Switch back to edit mode 7. Ensure that there are no `unsaved changes` ✅ #### Flaky Test Runner <a href="https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/1649"><img src="https://user-images.githubusercontent.com/8698078/207701101-69cdfada-77c6-4510-b254-1fd1fa13af5c.png"/></a> ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) (cherry picked from commit 7a6eac8) # Conflicts: # src/plugins/controls/public/time_slider/embeddable/time_slider_embeddable.tsx
…147482) (#147819) # Backport This will backport the following commits from `main` to `8.6`: - [[Dashboard] [Controls] Allow control changes to be discarded (#147482)](#147482) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Hannah Mudge","email":"Heenawter@users.noreply.github.com"},"sourceCommit":{"committedDate":"2022-12-19T21:55:31Z","message":"[Dashboard] [Controls] Allow control changes to be discarded (#147482)\n\nCloses https://github.com/elastic/kibana/issues/147293\r\n\r\n## Summary\r\n\r\nBefore this change, the Redux state `explicitInput` was getting out of\r\nsync with the embeddable `explicitInput` in scenarios where the new\r\n`explicitInput` was missing a key that the old `explicitInput` had -\r\ntherefore, because they were out of sync, the changes that **should**\r\nhave been discarded kept getting injected back into the embeddable\r\n`explicitInput`, which made it impossible to actually discard anything\r\nunless the key existed in both the before and after state.\r\n\r\nThis PR fixes this by replacing the entire Redux state `explicitInput`\r\nwith the embeddable `explicitInput` rather than spreading the new value.\r\nIt also fixes a bug with the time slider control where changes to the\r\nembeddable's input were not reflected properly in the control's state,\r\nso nothing could be discarded even after the initial bug was fixed.\r\n\r\n#### Further Explanation \r\n\r\nWhen a control is first created, all the optional properties of the\r\nexplicit input do not yet exist - for example, when creating an options\r\nlist control, the `selections` key does not exist in the `explicitInput`\r\nuntil a selection is made. Therefore, imagine the following scenario:\r\n\r\n1. You create an options list control (where the `selections` key does\r\nnot exist) and save the dashboard\r\n2. You make some selections, which causes `unsaved changes` because the\r\n`selections` key now exists and is equal to an array\r\n3. You switch to view mode and choose to discard your changes, thus\r\n(supposedly) removing the `selections` key from the `explicitInput`\r\nobject once again\r\n\r\nUnfortunately, the Redux embeddable state for each control was **not**\r\naccurately removing the `selections` key as expected - this was because,\r\nwhen trying to update the `explicitInput` via the old\r\n`updateEmbeddableReduxInput`, the new value was **spread** on top of the\r\nolder value rather than replacing it. In a simplified scenario, this\r\nresulted in something like this:\r\n\r\n```typescript\r\nconst oldExplicitInput = { id: 'test_id', selections: ['test selection'] };\r\nconst newExplicitInput = { id: 'test_id' }\r\nconst result = { ...oldExplicitInput, ...newExplicitInput };\r\n```\r\n\r\nIn this code, because `newExplicitInput` does not have the `selections`\r\nkey, `result` will equal `{ id: 'test_id', selections: ['test\r\nselection'] }` - this is not the behaviour we want! Instead, we wanted\r\nto replace the entire old `explicitInput` with the new `explicitInput`.\r\nEffectively, that is what this PR does.\r\n\r\nThanks to @ThomThomson for helping out with finding the root cause of\r\nthis after I got lost :)\r\n\r\n### How to Test\r\nFor both options list and range slider controls, \r\n1. Create a control of the desired type\r\n2. Save the dashboard \r\n3. Make some sort of change that causes unsaved changes - for example,\r\nmake a selection or, if an options list control, set `exclude` to `true`\r\n4. Switch to view mode, discarding the changes\r\n5. Ensure that the changes made in step 3 are no longer applied ✅ \r\n6. Switch back to edit mode\r\n7. Ensure that there are no `unsaved changes` ✅ \r\n\r\n#### Flaky Test Runner\r\n\r\n<a\r\nhref=\"https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/1649\"><img\r\nsrc=\"https://user-images.githubusercontent.com/8698078/207701101-69cdfada-77c6-4510-b254-1fd1fa13af5c.png\"/></a>\r\n\r\n### Checklist\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n### For maintainers\r\n\r\n- [ ] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"7a6eac8d1bfe492b8dce83c7a0f47dc26706e388","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Dashboard","release_note:fix","Feature:Input Control","Team:Presentation","loe:days","impact:high","Project:Controls","backport:prev-minor","v8.7.0"],"number":147482,"url":"https://github.com/elastic/kibana/pull/147482","mergeCommit":{"message":"[Dashboard] [Controls] Allow control changes to be discarded (#147482)\n\nCloses https://github.com/elastic/kibana/issues/147293\r\n\r\n## Summary\r\n\r\nBefore this change, the Redux state `explicitInput` was getting out of\r\nsync with the embeddable `explicitInput` in scenarios where the new\r\n`explicitInput` was missing a key that the old `explicitInput` had -\r\ntherefore, because they were out of sync, the changes that **should**\r\nhave been discarded kept getting injected back into the embeddable\r\n`explicitInput`, which made it impossible to actually discard anything\r\nunless the key existed in both the before and after state.\r\n\r\nThis PR fixes this by replacing the entire Redux state `explicitInput`\r\nwith the embeddable `explicitInput` rather than spreading the new value.\r\nIt also fixes a bug with the time slider control where changes to the\r\nembeddable's input were not reflected properly in the control's state,\r\nso nothing could be discarded even after the initial bug was fixed.\r\n\r\n#### Further Explanation \r\n\r\nWhen a control is first created, all the optional properties of the\r\nexplicit input do not yet exist - for example, when creating an options\r\nlist control, the `selections` key does not exist in the `explicitInput`\r\nuntil a selection is made. Therefore, imagine the following scenario:\r\n\r\n1. You create an options list control (where the `selections` key does\r\nnot exist) and save the dashboard\r\n2. You make some selections, which causes `unsaved changes` because the\r\n`selections` key now exists and is equal to an array\r\n3. You switch to view mode and choose to discard your changes, thus\r\n(supposedly) removing the `selections` key from the `explicitInput`\r\nobject once again\r\n\r\nUnfortunately, the Redux embeddable state for each control was **not**\r\naccurately removing the `selections` key as expected - this was because,\r\nwhen trying to update the `explicitInput` via the old\r\n`updateEmbeddableReduxInput`, the new value was **spread** on top of the\r\nolder value rather than replacing it. In a simplified scenario, this\r\nresulted in something like this:\r\n\r\n```typescript\r\nconst oldExplicitInput = { id: 'test_id', selections: ['test selection'] };\r\nconst newExplicitInput = { id: 'test_id' }\r\nconst result = { ...oldExplicitInput, ...newExplicitInput };\r\n```\r\n\r\nIn this code, because `newExplicitInput` does not have the `selections`\r\nkey, `result` will equal `{ id: 'test_id', selections: ['test\r\nselection'] }` - this is not the behaviour we want! Instead, we wanted\r\nto replace the entire old `explicitInput` with the new `explicitInput`.\r\nEffectively, that is what this PR does.\r\n\r\nThanks to @ThomThomson for helping out with finding the root cause of\r\nthis after I got lost :)\r\n\r\n### How to Test\r\nFor both options list and range slider controls, \r\n1. Create a control of the desired type\r\n2. Save the dashboard \r\n3. Make some sort of change that causes unsaved changes - for example,\r\nmake a selection or, if an options list control, set `exclude` to `true`\r\n4. Switch to view mode, discarding the changes\r\n5. Ensure that the changes made in step 3 are no longer applied ✅ \r\n6. Switch back to edit mode\r\n7. Ensure that there are no `unsaved changes` ✅ \r\n\r\n#### Flaky Test Runner\r\n\r\n<a\r\nhref=\"https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/1649\"><img\r\nsrc=\"https://user-images.githubusercontent.com/8698078/207701101-69cdfada-77c6-4510-b254-1fd1fa13af5c.png\"/></a>\r\n\r\n### Checklist\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n### For maintainers\r\n\r\n- [ ] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"7a6eac8d1bfe492b8dce83c7a0f47dc26706e388"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/147482","number":147482,"mergeCommit":{"message":"[Dashboard] [Controls] Allow control changes to be discarded (#147482)\n\nCloses https://github.com/elastic/kibana/issues/147293\r\n\r\n## Summary\r\n\r\nBefore this change, the Redux state `explicitInput` was getting out of\r\nsync with the embeddable `explicitInput` in scenarios where the new\r\n`explicitInput` was missing a key that the old `explicitInput` had -\r\ntherefore, because they were out of sync, the changes that **should**\r\nhave been discarded kept getting injected back into the embeddable\r\n`explicitInput`, which made it impossible to actually discard anything\r\nunless the key existed in both the before and after state.\r\n\r\nThis PR fixes this by replacing the entire Redux state `explicitInput`\r\nwith the embeddable `explicitInput` rather than spreading the new value.\r\nIt also fixes a bug with the time slider control where changes to the\r\nembeddable's input were not reflected properly in the control's state,\r\nso nothing could be discarded even after the initial bug was fixed.\r\n\r\n#### Further Explanation \r\n\r\nWhen a control is first created, all the optional properties of the\r\nexplicit input do not yet exist - for example, when creating an options\r\nlist control, the `selections` key does not exist in the `explicitInput`\r\nuntil a selection is made. Therefore, imagine the following scenario:\r\n\r\n1. You create an options list control (where the `selections` key does\r\nnot exist) and save the dashboard\r\n2. You make some selections, which causes `unsaved changes` because the\r\n`selections` key now exists and is equal to an array\r\n3. You switch to view mode and choose to discard your changes, thus\r\n(supposedly) removing the `selections` key from the `explicitInput`\r\nobject once again\r\n\r\nUnfortunately, the Redux embeddable state for each control was **not**\r\naccurately removing the `selections` key as expected - this was because,\r\nwhen trying to update the `explicitInput` via the old\r\n`updateEmbeddableReduxInput`, the new value was **spread** on top of the\r\nolder value rather than replacing it. In a simplified scenario, this\r\nresulted in something like this:\r\n\r\n```typescript\r\nconst oldExplicitInput = { id: 'test_id', selections: ['test selection'] };\r\nconst newExplicitInput = { id: 'test_id' }\r\nconst result = { ...oldExplicitInput, ...newExplicitInput };\r\n```\r\n\r\nIn this code, because `newExplicitInput` does not have the `selections`\r\nkey, `result` will equal `{ id: 'test_id', selections: ['test\r\nselection'] }` - this is not the behaviour we want! Instead, we wanted\r\nto replace the entire old `explicitInput` with the new `explicitInput`.\r\nEffectively, that is what this PR does.\r\n\r\nThanks to @ThomThomson for helping out with finding the root cause of\r\nthis after I got lost :)\r\n\r\n### How to Test\r\nFor both options list and range slider controls, \r\n1. Create a control of the desired type\r\n2. Save the dashboard \r\n3. Make some sort of change that causes unsaved changes - for example,\r\nmake a selection or, if an options list control, set `exclude` to `true`\r\n4. Switch to view mode, discarding the changes\r\n5. Ensure that the changes made in step 3 are no longer applied ✅ \r\n6. Switch back to edit mode\r\n7. Ensure that there are no `unsaved changes` ✅ \r\n\r\n#### Flaky Test Runner\r\n\r\n<a\r\nhref=\"https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/1649\"><img\r\nsrc=\"https://user-images.githubusercontent.com/8698078/207701101-69cdfada-77c6-4510-b254-1fd1fa13af5c.png\"/></a>\r\n\r\n### Checklist\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n### For maintainers\r\n\r\n- [ ] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"7a6eac8d1bfe492b8dce83c7a0f47dc26706e388"}}]}] BACKPORT-->
…#147482) Closes elastic#147293 ## Summary Before this change, the Redux state `explicitInput` was getting out of sync with the embeddable `explicitInput` in scenarios where the new `explicitInput` was missing a key that the old `explicitInput` had - therefore, because they were out of sync, the changes that **should** have been discarded kept getting injected back into the embeddable `explicitInput`, which made it impossible to actually discard anything unless the key existed in both the before and after state. This PR fixes this by replacing the entire Redux state `explicitInput` with the embeddable `explicitInput` rather than spreading the new value. It also fixes a bug with the time slider control where changes to the embeddable's input were not reflected properly in the control's state, so nothing could be discarded even after the initial bug was fixed. #### Further Explanation When a control is first created, all the optional properties of the explicit input do not yet exist - for example, when creating an options list control, the `selections` key does not exist in the `explicitInput` until a selection is made. Therefore, imagine the following scenario: 1. You create an options list control (where the `selections` key does not exist) and save the dashboard 2. You make some selections, which causes `unsaved changes` because the `selections` key now exists and is equal to an array 3. You switch to view mode and choose to discard your changes, thus (supposedly) removing the `selections` key from the `explicitInput` object once again Unfortunately, the Redux embeddable state for each control was **not** accurately removing the `selections` key as expected - this was because, when trying to update the `explicitInput` via the old `updateEmbeddableReduxInput`, the new value was **spread** on top of the older value rather than replacing it. In a simplified scenario, this resulted in something like this: ```typescript const oldExplicitInput = { id: 'test_id', selections: ['test selection'] }; const newExplicitInput = { id: 'test_id' } const result = { ...oldExplicitInput, ...newExplicitInput }; ``` In this code, because `newExplicitInput` does not have the `selections` key, `result` will equal `{ id: 'test_id', selections: ['test selection'] }` - this is not the behaviour we want! Instead, we wanted to replace the entire old `explicitInput` with the new `explicitInput`. Effectively, that is what this PR does. Thanks to @ThomThomson for helping out with finding the root cause of this after I got lost :) ### How to Test For both options list and range slider controls, 1. Create a control of the desired type 2. Save the dashboard 3. Make some sort of change that causes unsaved changes - for example, make a selection or, if an options list control, set `exclude` to `true` 4. Switch to view mode, discarding the changes 5. Ensure that the changes made in step 3 are no longer applied ✅ 6. Switch back to edit mode 7. Ensure that there are no `unsaved changes` ✅ #### Flaky Test Runner <a href="https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/1649"><img src="https://user-images.githubusercontent.com/8698078/207701101-69cdfada-77c6-4510-b254-1fd1fa13af5c.png"/></a> ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
Closes #147293
Summary
Before this change, the Redux state
explicitInput
was getting out of sync with the embeddableexplicitInput
in scenarios where the newexplicitInput
was missing a key that the oldexplicitInput
had - therefore, because they were out of sync, the changes that should have been discarded kept getting injected back into the embeddableexplicitInput
, which made it impossible to actually discard anything unless the key existed in both the before and after state.This PR fixes this by replacing the entire Redux state
explicitInput
with the embeddableexplicitInput
rather than spreading the new value. It also fixes a bug with the time slider control where changes to the embeddable's input were not reflected properly in the control's state, so nothing could be discarded even after the initial bug was fixed.Further Explanation
When a control is first created, all the optional properties of the explicit input do not yet exist - for example, when creating an options list control, the
selections
key does not exist in theexplicitInput
until a selection is made. Therefore, imagine the following scenario:selections
key does not exist) and save the dashboardunsaved changes
because theselections
key now exists and is equal to an arrayselections
key from theexplicitInput
object once againUnfortunately, the Redux embeddable state for each control was not accurately removing the
selections
key as expected - this was because, when trying to update theexplicitInput
via the oldupdateEmbeddableReduxInput
, the new value was spread on top of the older value rather than replacing it. In a simplified scenario, this resulted in something like this:In this code, because
newExplicitInput
does not have theselections
key,result
will equal{ id: 'test_id', selections: ['test selection'] }
- this is not the behaviour we want! Instead, we wanted to replace the entire oldexplicitInput
with the newexplicitInput
. Effectively, that is what this PR does.Thanks to @ThomThomson for helping out with finding the root cause of this after I got lost :)
How to Test
For both options list and range slider controls,
exclude
totrue
unsaved changes
✅Flaky Test Runner
Checklist
For maintainers