-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Plugin URLs should be part of the plugin's contract #66682
Comments
Pinging @elastic/kibana-platform (Team:Platform) |
I'm guessing that by 'plugin' you mean Imho:
However, the example you linked is an issue about a plugin changing some of their routes, which is different than changing the app's basePath. This is not something we can properly detect from core, as we are only aware of an application's basePath, not their route mapping. I.E if the However, in these cases:
I.E props.application.navigateToApp(
'kibana#/management/elasticsearch/license_management'
); could be changed for something like props.managementStart.navigateToSection('elasticsearch', 'licensing_management') to let the dependency plugin handles the action-to-navigation logic. |
Tests are a great point, but FTR tests are particularly slow and difficult to develop. As I result I think people tend to avoid them if possible. Would there also be an added cost for disabling the dependency plugin as part of the test? I haven't looked into this, but I imagine it would require a Kibana server restart. If we could solve this problem more cheaply (e.g. via TS checks), I'd prefer that.
Right! This is exactly what I had in mind. Except in your example, I don't think the Management plugin could expose this helper, since it's not aware of License Management. License Management should expose this helper and any plugin that contains an app that wants to link to it should declare it as a dependency. |
After thinking about it a little more I think this will quickly cause cyclic dependency issues: I.E: dashboard app can link to discover, discover can link to dashboard, but including both as a dependency to the other is not possible. Not sure what our best option is then |
Ouch, you're right. What if the platform introduced a new type of dependency, e.g. |
Basically that yea. I wouldn't want to recode spring multi-step DI just for this specific need :D |
Voicing support for @cjcenizal 's thoughts. I fully agree with what he's proposing and why - it seems like the primary argument against it is that we need to find an acceptable way to implement it. Do optional dependencies do anything to fix the cyclical dependency issue? I assume not but have to ask. Still, there's a clear solution to the problem - rely on core or another plugin to provide the interface to register and look up app URLs. You'd need to specify the type when retrieving but that extra step would provide everything else we want. This would help solve the problem of having internally consistent urls. Yes, we should maintain backward compatibility with urls stored externally but I think that needs to be solved in routing. I should mention that the URL Generator exists - #25247 - but I'm really not crazy about registering one url at a time. Slightly different usage and api. |
Unfortunatly it doesn't. Both kind of dependencies are used the same way when generating the dependency graph, that cannot be cyclic for multiple reasons. |
How it's solved right now? |
I didn't have a specific example in mind for the But technically, nothing blocks an app to use |
Everything what CJ describes here is the way we want to go. No application should build any kind of URL in some kind of string for any other application. You should only consume URLs via APIs of that specific plugin so the ownership of creating those URLs is clearly within that plugin. As pointed out we'll run into the cyclic dependency problems with it, since apps can pretty cross link between each other. We have that case in a couple of places in Kibana (e.g. the whole observability apps). The above linked was afaik meant to target that problem (I haven't followed it's development closely though). If it now has become something different, or different APIs are needed to be used, we should make this clear. This is one of those topics we imho need a very clear guidance on how plugins should do that. @stacey-gammon can hopefully clearify on the "how should this be done" part. |
URL generators aren't meant to solve this. Pulling specific implementations off a generic registry should not be used as a way to circumvent circular dependencies - it'll still be an issue, just not as obvious. The only way I can see to get around this is to build separate plugins. One with the application contents, one with the linkers. Then the chain is: Dashboard App -> Discover Link It would encourage many small plugins though, and it's still weird because shouldn't Dashboard Link have a dependency on Dashboard App? How else could you test it? What good is a dashboard link plugin without a dashboard app plugin? I brought my concern up with circular dependencies in #47065. The sentiment was:
I don't think we considered inter app linking then, and it's a great example of a circular dependency that doesn't seem to me like a code smell. tl;dr; I don't have a recommended answer for "how this should be done" but agree it's something we need to figure out. |
+1 on that |
Yeah I don't think we were considering linking between apps as an example of circular dependencies in that original discussion -- IMHO having a bunch of separate "linking" plugins is just moving our code smell from one place to another 😄 That said, I'm not sure I can conceive of a way to link between apps without either:
My gut reaction: Since you can have circular dependencies at the plugin level if they are type-only imports, I wonder if the least-worst option would be a combination of 1 and 2: You use a registry to get your URL (either URL generators or persistable states + This is at least somewhat more explicit due to the type imports, though certainly not as ideal as the original proposal of exposing these methods from each plugin. This needs more thought though -- would be interested to hear others' ideas on this. |
I don't think this will solve the root problem, and is going against our current recommendations of not going through a generic registry when you have concrete information at compile time. It feels like a hacky solution that could start causing flaky ci errors that are hard to debug. For instance. Hey, this works! class FooPlugin {
setup(core) {
core.registerApp(() => {
// Post start lifecycle so this works without an explicit dependency
const [coreStart, { urlGenerators } ] = core.getStartServices();
renderApp(linkToDiscover: urlGenerators.get(DISCOVER).createUrl());
})
}
} Hm, but this randomly breaks ci: class FooPlugin {
setup(core) {
core.registerApp(() => {
// Post start lifecycle so this works without an explicit dependency
const [coreStart, { urlGenerators } ] = core.getStartServices();
const linkToDiscover = urlGenerators.get(DISCOVER).createUrl();
renderApp(linkToDiscover);
}
}
start(core, { urlGenerators }) {
// This will cause random ci failures without an explicit dependency on the discover plugin.
const linkToDiscover = urlGenerators.get(DISCOVER).createUrl();
return {
DashboardEmbeddable: () => <DashboardEmbeddable linkToDiscover={linkToDiscover} />
}
} What about service level dependencies? |
We took on this issue in today's Repo Review sync. Summary We recommend creating separate plugins if circular dependencies is an issue due to inter app linking. Note the platform team is doing work to support plugins nested inside folders, which will help avoid a too flat plugin folder structure going this route. Notes
Options we have:
Work through how navigation should work if the app is disabled. Should users be able to create links? Server side? Dashboard app plugin could turn off dashboard navigation plugin if disabled.
We are recommending option 4 as a work around. Some next steps to make this experience better:
We should still come up with a recommendation for "who's enhancing who". For example, OSS apps shouldn't be registering themselves into x-pack plugins. X-pack plugins are the enhancers, that enhance OSS plugins. Opt for one way direction when possible. |
FYI We are adding a high-level guide on routing, navigation and URL: #76888 In case something new and important pops up from this discussion, then |
For an example of the problem see 68c0eb4. This PR changed the paths of several plugins, which required manually finding and updating the points of entry into these plugins from other plugins.
Changing a plugin's URL should be considered a breaking change from the perspective of dependent plugins. It's easy to miss a plugin's dependency upon another plugin's URL, but by requiring plugins to publish entry points into their apps we can force dependent plugins to identify and declare this dependency via
kibana.json
(and properly handle the case in which the dependency is missing).The text was updated successfully, but these errors were encountered: