路由、导航和 URL编辑

Kibana 平台提供了一组工具来帮助开发者围绕路由和浏览器导航构建一致的体验。其中一些工具位于 core 内,而另一些工具则作为各种插件的一部分提供。

本指南的目的是对可用工具进行高层次的概述,并解释处理路由和浏览器导航的常用方法。

本指南涵盖以下主题

深度链接到 Kibana 应用编辑

假设您想从您的应用链接到 Discover。在构建此类 URL 时,需要考虑两件事

  1. 添加适当的 basePath 前缀。
  2. 指定 Discover 状态。

添加适当的 basePath 前缀编辑

要添加 Kibana 的 basePath 前缀,请使用 core.http.basePath.prepend 帮助程序

const discoverUrl = core.http.basePath.prepend(`/discover`);

console.log(discoverUrl); // https://127.0.0.1:5601/bpr/s/space/app/discover

指定状态编辑

将 Kibana 应用 URL 视为应用插件契约的一部分

  1. 避免在您的应用代码中硬编码其他应用的 URL。
  2. 避免生成其他应用的状态并将其序列化为 URL 查询参数。
// Avoid relying on other app's state structure in your app's code:
const discoverUrlWithSomeState = core.http.basePath.prepend(`/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'2020-09-10T11:39:50.203Z',to:'2020-09-10T11:40:20.249Z'))&_a=(columns:!(_source),filters:!(),index:'90943e30-9a47-11e8-b64d-95841ca0b247',interval:auto,query:(language:kuery,query:''),sort:!())`);

相反,每个应用都应该公开 一个定位器。其他应用应该使用这些定位器进行导航或 URL 创建。

// Properly generated URL to *Discover* app. Locator code is owned by *Discover* app and available on *Discover*'s plugin contract.
const discoverUrl = await plugins.discover.locator.getUrl({filters, timeRange});
// or directly execute navigation
await plugins.discover.locator.navigate({filters, timeRange});

为了更好地理解,请查看 Discover 定位器 实现。它允许指定各种 Discover 应用状态部分,例如:索引模式、过滤器、查询、时间范围等等。

有两种方法可以访问其他应用的定位器

  1. 从目标应用的插件契约中 (首选)
  2. 使用 share 插件中的定位器客户端(在无法明确依赖插件的情况下)。

如果您希望其他应用链接到您的应用,那么您应该创建一个定位器并将其公开在您的插件契约上。

在 Kibana 应用之间导航编辑

Kibana 是一个单页应用,开发者应遵循一组简单的规则,以确保在从 Kibana 中的一个位置导航到另一个位置时不会重新加载页面。

例如,使用原生浏览器 API 进行导航会导致页面完全重新加载。

const urlToADashboard = core.http.basePath.prepend(`/dashboard/my-dashboard`);

// this would cause a full page reload:
window.location.href = urlToADashboard;

要在不同的 Kibana 应用之间导航而无需重新加载页面(默认情况下),可以使用 core 中的 API

这两种方法都提供自定义选项,例如使用 options 参数在新页面中打开目标。所有选项默认都是可选的。

渲染指向另一个 Kibana 应用的链接本身也会导致页面完全重新加载

const myLink = () =>
  <a href={urlToADashboard}>Go to Dashboard</a>;

一种解决方法是处理点击事件,阻止浏览器导航,并使用 core.application.navigateToApp API

const MySPALink = () =>
  <a
    href={urlToADashboard}
    onClick={(e) => {
      e.preventDefault();
      core.application.navigateToApp('dashboard', { path: '/my-dashboard' });
    }}
  >
    Go to Dashboard
  </a>;

由于为应用中的每个 Kibana 链接都这样做会产生过多的样板代码,因此有一个方便的包装器可以帮助您:RedirectAppLinks

const MyApp = () =>
  <RedirectAppLinks coreStart={{application: core.application}}>
    {/*...*/}
    {/* navigations using this link will happen in SPA friendly way */}
      <a href={urlToADashboard}>Go to Dashboard</a>
    {/*...*/}
  </RedirectAppLinks>

在某些情况下,您可能需要完全重新加载页面。虽然这种情况很少发生,应该尽量避免,但您可以使用 navigateToUrlforceRedirect 选项,而不是实现您自己的导航。

const MyForcedPageReloadLink = () =>
  <a
    href={urlToSomeSpecialApp}
    onClick={(e) => {
      e.preventDefault();
      core.application.navigateToUrl('someSpecialApp', { forceRedirect: true });
    }}
  >
    Go to Some Special App
  </a>;

如果您还需要绕过默认的 onAppLeave 行为,可以将 skipUnload 选项设置为 true。此选项在 navigateToApp 中也可用。

设置内部应用路由编辑

Kibana 应用通常使用 React 和 React Router。在这种情况下,应遵循以下通用规则

  • 设置 BrowserRouter 而不是 HashRouter
  • 使用 core 提供的 history 实例初始化您的路由器。

这是必需的,以确保 core 知道您的应用内部触发的导航,以便它在需要时可以采取相应的行动。

相对链接将相对于您的应用路由(例如:https://127.0.0.15601/app/{your-app-id})进行解析,在您的应用中以 SPA 友好的方式设置内部链接如下所示

import {Link} from 'react-router-dom';

const MyInternalLink = () => <Link to="/my-other-page"></Link>

使用历史记录和浏览器位置编辑

尽量避免直接使用 window.locationwindow.history
相反,请考虑使用 core 提供的 ScopedHistory 实例。

  • 这样,core 就会知道您的应用内部触发的地址更改,并会采取相应的行动。
  • 一些插件会监听地址更改。手动触发地址更改可能会导致不可预测且难以捕捉的错误。

直接使用 coreScopedHistory 的常见用例

  • 读取/写入查询参数或哈希值。
  • 在您的应用内部强制触发内部导航。
  • 监听浏览器地址更改。

将状态与 URL 同步编辑

过去,Kibana 应用在 URL 中存储了*大量*的应用状态。如今,Kibana 应用最常用的模式是将状态以 rison 格式存储在 _a_g 查询参数中。

这些查询参数遵循以下约定

  • _g (全局) - 应该在多个应用之间共享和同步的全局 UI 状态。分析组应用中的常见示例:时间范围、刷新间隔、固定 过滤器。
  • _a (应用) - 限制在当前应用范围内的 UI 状态。

迁移到 KP 平台后,我们实现了无需重新加载页面的导航。因此,不再需要遵循 _g_a 的分离。您可以决定是否要遵循此模式,或者是否更喜欢使用单个查询参数或其他方式。在 在导航之间保留状态 中解释了之前需要进行这种分离的原因。

有一些实用程序可以帮助您实现这种状态同步。

您应该在以下情况下考虑使用状态同步实用程序

  • 您希望以类似于分析组应用的方式将应用状态与 URL 同步。
  • 您希望遵循平台的 使用浏览器历史记录和位置的最佳实践
  • 您希望支持 state:storeInSessionStore 应急机制,以防止 URL 超出长度限制。
  • 如果您希望将状态序列化为不同的格式(不是 rison),也应该考虑使用它们。这些实用程序是可组合的,您可以实现自己的 storage
  • 如果您希望将部分状态与 URL 同步,而将其他部分状态与浏览器存储同步。

您不应该在以下情况下使用状态同步实用程序

  • 向 URL 添加查询参数标志或简单的键/值对。

请遵循 这些 文档了解更多信息。

在导航之间保留状态编辑

考虑以下场景

  1. 您在 Dashboard 应用中查看应用了一些过滤器的仪表板;
  2. 使用应用内导航导航到 Discover
  3. 更改时间过滤器'
  4. 使用应用内导航导航到 Dashboard

您会注意到您导航回了 Dashboard 应用,并且应用的状态与您离开时相同,只是时间过滤器已更改为您在 Discover 应用中应用的过滤器。

过去,Kibana 分析组应用依靠 URL 中的状态来实现这种行为。如果您仔细查看导航中的链接,您会注意到状态存储在该链接中,并且每当相关状态发生更改时,该链接也会更新

State is stored inside the navigation link

这就是 分离_a_g 查询参数的意义所在。被视为 全局 状态的内容会在这些导航链接中不断更新。在上面的示例中,它是一个时间过滤器。这是由 KbnUrlTracker 实用程序支持的。您可以使用它来实现类似的行为。

迁移到 KP 后,导航无需重新加载页面,并且所有插件都同时加载。因此,除非您想通过 URL 来实现,否则可能会有更简单的方法来保留应用的状态。