-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Kibana app migration: Local application service #48898
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
Kibana app migration: Local application service #48898
Conversation
💚 Build Succeeded |
|
Pinging @elastic/kibana-app (Team:KibanaApp) |
|
@elasticmachine merge upstream |
💚 Build Succeeded |
|
|
||
| this.forwards.forEach(({ legacyAppId, newAppId, keepPrefix }) => { | ||
| angularRouteManager.when(matchAllWithPrefix(legacyAppId), { | ||
| redirectTo: (_params: unknown, path: string, search: 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.
A quick note while testing, when search is an object, this produces links like:
http://localhost:5601/tmz/app/kibana#/discover/doc/indexPattern/index?%5Bobject%20Object%5D&_g=()
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.
Ah, good catch, thanks. I will look into 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.
OK, this should be fixed by using a resolveRedirectTo constructing the redirect by using $location.url.
…pplication-service
…h1293/kibana into flash1293/local-application-service
💚 Build Succeeded |
src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| const matchAllWithPrefix = (prefixOrApp: string | App) => | ||
| `/${typeof prefixOrApp === 'string' ? prefixOrApp : prefixOrApp.id}:tail*?`; |
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.
Shouldn't there be a / before the :tail*??
| controller($scope: IScope) { | ||
| const element = document.getElementById(wrapperElementId)!; | ||
| (async () => { | ||
| const onUnmount = await app.mount({ core: npStart.core }, { element, appBasePath: '' }); |
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 function looks like it would break if we're navigating away while we're still mounting the app, since we're attaching a listener on a then destroyed scope? We could potentially use the private scope.$$destroyed to check if it actually is already destroyed once app mount has finished?
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 believe the appBasePath here shouldn't be empty. It probably should be the id of the current legacy app + the id of the app being mounted. For example, if I registered a app with id dashboard, I'd expect the appBasePath to be something like: chrome.basePath.prepend('/kibana#dashboard')
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.
Is this really helpful? AFAI understand the appBasePath is passed in so the application can make sure it's prefixing all links and routes correctly, right? So the contract is basically "if something changes after this prefix, it's up to you to handle it". If the base path switches technologies going from a path to a hash, this will require really weird code within the app to handle both cases (checking whether there is a hash in there and switching from history router to hash router or something like that).
I'm also not sure whether we can provide a meaningful "base path" here yet. Currently all consumers of the local application service have to use hash routing and make sure they handle the app/kibana part as well as the #/dashboard part of the url, so we have to do changes to the routing in this regard anyway when switching to the new platform and the real application router. The compat layer for legacy platform seems to follow the same principle: src/legacy/ui/public/new_platform/new_platform.ts (it also has the same problem Tim is mentioning above).
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.
@joshdover I'm going to merge this PR because it's blocking several other PRs to become reviewable and it's not actively used anywhere for now. If you still have concerns we can continue the discussion and adjust things in a separate PR.
💚 Build Succeeded |
| redirectTo: (_params: unknown, path: string, search: string) => { | ||
| const newPath = `/${newAppId}${keepPrefix ? path : path.replace(legacyAppId, '')}`; | ||
| return `${newPath}?${search}`; | ||
| resolveRedirectTo: ($location: 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.
ng.ILocationService
| import { localApplicationService } from './local_application_service'; | ||
|
|
||
| localApplicationService.apply(routes); | ||
| localApplicationService.forwardApp('foo', 'discover'); |
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.
Don't forget to remove that debug forward before merging :-)
💚 Build Succeeded |
kertal
left a comment
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.
Code LGTM, tested forwarding in my Discover shim with doc and context, works 👍
Introducing a local application service simulating the core application service within the kibana app LP plugin to make routing without reload possible.
The individual apps register themselves to the local application service and can do their own routing within
#/${appId}/...- the local application service just listens for changes in the first path segment and unmounts/mounts the correct app. For now this is realized with the global angular router but once everything in the kibana app plugin is using the local application service, it can be retired in favor of something super lightweight like awindow.onhashchangelistener. While the global angular routing is used, it is important to make sure that triggered listeners won't interfere with the loaded app (e.g. resetting badges or help texts). Because of this the handlers look for a special flag marking the "wrapper routes" and exit early if they are encountered.As it is using the global angular router for now, it is possible to do a step-wise migration, e.g. moving the home app to a pure react app while the other parts of the Kibana plugin are still using the global angular router (#48715).
Because discover will need this for the shimming, it also introduces a
forwardmethod that can be used to forward all URLs matching a certain prefix to another prefix. For now this feature will only migrate URLs within the kibana app route (everything after the hash), but when the individual plugins are actually moved to the new platform, the local application service will be the only thing left in the kibana plugin making sure all old URLs are forwarded correctly to their NP counterparts.When moving the responsibility for the routing into the individual sub-apps, it's important to make sure unknown urls are redirected to the correct place because the catch-all redirect on kibana plugin level doesn't trigger anymore. The flow works like this:
#/discover/this/is/not/a/real/path, the app router should redirect to#/{chrome.getInjected('kbnDefaultAppId')}(because this is the current behavior, if you go to an unknown route within let's say visualize, you get redirected to home - we can discuss to change this and have an app-specific behavior which might make more sense)In case of react router the config might look like this:
In case of local angular in might look like this:
This PR can be tested by adding a small demo app, registering it in the local application service and check whether handles are called in the correct places.