Skip to content
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

Remove the need to pass state and parentUiState to dashboard_panel directive #9769

Merged
merged 5 commits into from
Jan 19, 2017

Conversation

stacey-gammon
Copy link
Contributor

This improves isolation of the panel and makes state changes clearer.

Along the way I simplified the logic for loading the saved object and once simplified, I didn't think it required a separate file so brought the logic inside the directive.

Also made note of where #9523 is creeping in. I was originally going to fix it in this PR but since how to fix it isn't clear yet, this PR remains a non-functional change.

@stacey-gammon stacey-gammon added Feature:Dashboard Dashboard related features review labels Jan 6, 2017
@stacey-gammon stacey-gammon requested review from kobelb and removed request for cjcenizal January 6, 2017 19:29
@stacey-gammon stacey-gammon force-pushed the saved-search-refresh-bug branch from 2390122 to 2fdc280 Compare January 9, 2017 14:43
@stacey-gammon stacey-gammon force-pushed the saved-search-refresh-bug branch from 2fdc280 to 7b9eb00 Compare January 10, 2017 15:28
Copy link
Member

@weltenwort weltenwort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the way you create the child ui state a lot better. 👍 🎉 The saveState property also looks quite elegant.

But I have to say that I'm not in favor of inlining the loader that way. Since the closure environment is a lot bigger that way it is hard for me to keep it all in working memory when reading through dashboard_panel.js. I thought the previous loaders were a lot easier to understand (and probably to test as well). loadPanelProvider seemed to have been a misnomer though, with loadSavedObjectProvider being more accurate.

Moving the two $watchCollection calls out of the searchLoaderProvider on the other hand makes sense.

Maybe there is a middle-ground to be had where we can move maintain your sensible sequence of "loadSavedObject", "initializeSavedObject" and "initializePanel" while not relying on a huge closure. I feel I need to dwell on this a bit and will post a follow-up later today. 🤔

*/
let postLoadInit;

if ($scope.panel.type === 'search') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem I have with this explicit conditional is that it does not scale well to new panel types:

  • Previously, when adding a new panel type, a new loader would just have to be created and added to the declarative panelTypes mapping in loadPanelProvider. The panel code itself would not have to be changed.
  • This conditional though would grow with each new panel type and probably become a lot harder to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got rid of the conditional. New types just need to register a loader in getObjectLoadersForDashboard. No good place right now for custom post initialization code, but ideally there wouldn't need to be any.

@stacey-gammon
Copy link
Contributor Author

What do you think about this new version @weltenwort? I extracted the load_saved_object code and removed the need for scope by pushing the "postInit" function stuff into initializePanel which is probably a better spot for it anyhow, since that is "postInit" code.

I created a new service for the loaders, so to add a new type all you have to do is add one to that service. Any custom initialization of the saved object must, for now, go in the directive.

I'd like to improve that latter requirement, but I think this PR is sufficient and that can be a Step 3. Plus I don't have a clear idea right now how to improve the initialization code.

Copy link
Contributor

@kobelb kobelb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome job separating the dashboard_panel directive out from requiring the parent uiState, I really like this improvement.

export function loadSavedObject(loaders, panel) {
const loader = loaders.find((loader) => loader.type === panel.type);
if (!loader) {
throw `No loader for object of type ${panel.type}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though Javascript lets us throw whatever we want, it's good practice to throw a new Error('error message') as opposed to a string.

@@ -1,15 +1,19 @@
import _ from 'lodash';
import 'ui/visualize';
import 'ui/doc_table';
import { loadPanelProvider } from 'plugins/kibana/dashboard/components/panel/lib/load_panel';
import 'plugins/kibana/dashboard/services/get_object_loaders_for_dashboard.factory';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dunno how I feel about the .factory part of the filename. Was it your intention for us to do this for all of the different angular 'types'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was motivated by some conversations with @w33ble and a new style pattern the Management team has been experimenting with. This morning I decided I'm on the fence with whether or not I should be incorporating this new pattern, read more here: #9859 (comment)

Once I hear back from @w33ble and @cjcenizal on that comment I'll decide whether to revert the .factory naming scheme.

FWIW I do like the pattern a lot but since it's not fully adopted by the team, it does seem a bit premature, especially with the last email that went around about consistency trumping new patterns until a certain # of criteria is hit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too, reverting this change to avoid introducing new patterns that aren't yet embraced by the team as a whole.

.directive('dashboardPanel', function (savedVisualizations, savedSearches, Notifier, Private, $injector) {
const loadPanel = Private(loadPanelProvider);
.directive('dashboardPanel', function ($injector) {
const Private = $injector.get('Private');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What made you switch to using the $injector service directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another new style suggestion from the Management team. Once you are only using the injector, you don't need to wrap the class in Private, so it'll make getting rid of Private easier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, FilterManagerProvider is still wrapped below. Isn't the only reason you get around using Private on getObjectLoadersForDashboard the fact that it has been globally registered under that name? That is still tightly coupled to Angular's DI, then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I think the idea is to stop using nameless functions that require Private, and explicitly register them in angular. The more I think about this specific change though, the more I am unsure.

I was originally under the assumption that if I got rid of the parameters and only passed $Injector, I could avoid wrapping dashboardPanel with Private but that doesn't make sense because dashboardPanel is a directive, first off, and second off, is registered with angular, and no class registered with angular would require Private.

After going back to the original discussion with @w33ble I think the idea is to use $injector only for nameless functions, not for things already registered with angular. Does that sound right, @w33ble? So this should go back to it's previous version?

Copy link
Contributor

@w33ble w33ble Jan 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is still tightly coupled to Angular's DI

Everything will be, you can't use Angular without the DI 😢 .

There's actually 2 things going on here though. First is the removal of Private, which I think is a universal desire.

The second is the use of $injector to make it clear this is Angular stuff, to allow the code to be minified without duplicating all the dependencies, and I guess tangentially to make the code still look like the Private code. This change is very much up for debate, and was just an idea that was thrown out when discussing the Angular styleguide (which is also kind of in flux). Sounds like folks aren't too keen on this idea, so maybe it's best to remove it for now and discuss it outside this PR.

I think the idea is to use $injector only for nameless functions, not for things already registered with angular.

Actually, $injector only works for named, registered Angular code. It doesn't work the same way the Private does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay folks, I reverted to the old variation. Discussed with @cjcenizal and @w33ble and decided to move the debate around the new $injector style to a separate issue and pull out of here, in order to stay consistent with the current code, until the new pattern is embraced as a whole by the team.

// This causes changes to a saved search to be hidden, but also allows
// the user to locally modify and save changes to a saved search only in a dashboard.
// See https://github.com/elastic/kibana/issues/9523 for more details.
$scope.panel.columns = $scope.panel.columns || $scope.savedObj.columns;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to only happen for saved searches. Are $scope.panel.columns and $scope.panel.sort only being set so that we can watch them and know when to call saveState?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, maybe a if ($scope.savedObj.type === 'search') { ... } would be appropriate? And then line 97 could also read if ($scope.savedObj.type === 'visualization') for symmetry.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I figured it was just a noop for visualizations, but I can wrap in an if as well.

Copy link
Member

@weltenwort weltenwort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there was a if ($scope.savedObj.vis) in initializePanel anyway, moving the handler registration there makes sense. Now it's all in one place, at least.

And nice job reusing loader.type! 👍

// This causes changes to a saved search to be hidden, but also allows
// the user to locally modify and save changes to a saved search only in a dashboard.
// See https://github.com/elastic/kibana/issues/9523 for more details.
$scope.panel.columns = $scope.panel.columns || $scope.savedObj.columns;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, maybe a if ($scope.savedObj.type === 'search') { ... } would be appropriate? And then line 97 could also read if ($scope.savedObj.type === 'visualization') for symmetry.

@stacey-gammon stacey-gammon force-pushed the saved-search-refresh-bug branch 2 times, most recently from b726936 to 67e102f Compare January 17, 2017 15:26
@stacey-gammon
Copy link
Contributor Author

@weltenwort and @kobelb should be all good to go for a final look, thanks!

@stacey-gammon stacey-gammon force-pushed the saved-search-refresh-bug branch from 3b7fec3 to 65131d0 Compare January 19, 2017 15:18
Copy link
Contributor

@kobelb kobelb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@weltenwort weltenwort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM too

@stacey-gammon stacey-gammon merged commit 2fccac6 into elastic:master Jan 19, 2017
elastic-jasper added a commit that referenced this pull request Jan 19, 2017
…rective

Backports PR #9769

**Commit 1:**
- Remove need for passing state to dashboard_panel directive.

get rid of parentUiState

* Original sha: e97cb33
* Authored by Stacey Gammon <[email protected]> on 2017-01-05T21:05:40Z

**Commit 2:**
Address code review comments

* Original sha: 4c7f0be
* Authored by Stacey Gammon <[email protected]> on 2017-01-13T20:29:45Z

**Commit 3:**
Only do savedSearch specific init stuff for searches

* Original sha: 76149ed
* Authored by Stacey Gammon <[email protected]> on 2017-01-16T15:21:42Z

**Commit 4:**
Throw Error object, not string

* Original sha: 31713b0
* Authored by Stacey Gammon <[email protected]> on 2017-01-17T15:25:47Z

**Commit 5:**
Remove new patterns from this PR

Removing the new patterns from this PR to preserve consistency.

* Original sha: 65131d0
* Authored by Stacey Gammon <[email protected]> on 2017-01-17T20:15:07Z
stacey-gammon added a commit to stacey-gammon/kibana that referenced this pull request Jan 20, 2017
…rective (elastic#9769)

* - Remove need for passing state to dashboard_panel directive.

get rid of parentUiState

* Address code review comments

* Only do savedSearch specific init stuff for searches

* Throw Error object, not string

* Remove new patterns from this PR

Removing the new patterns from this PR to preserve consistency.
stacey-gammon added a commit that referenced this pull request Jan 20, 2017
…rective (#9769) (#9980)

* - Remove need for passing state to dashboard_panel directive.

get rid of parentUiState

* Address code review comments

* Only do savedSearch specific init stuff for searches

* Throw Error object, not string

* Remove new patterns from this PR

Removing the new patterns from this PR to preserve consistency.
@stacey-gammon stacey-gammon deleted the saved-search-refresh-bug branch January 20, 2017 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Dashboard Dashboard related features review v5.3.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants