路由、导航和 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>

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

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 状态。来自 Analyze 组应用程序的常见示例:时间范围、刷新间隔、已固定的过滤器。
  • _a应用程序)- 范围限定为当前应用程序的 UI 状态。

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

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

何时应考虑使用状态同步实用程序

  • 您希望以类似于 Analyze 组应用程序的方式使用 URL 同步您的应用程序状态。
  • 您希望开箱即用地遵循平台的使用浏览器历史记录和位置的最佳实践
  • 您希望开箱即用地支持用于 URL 溢出的 state:storeInSessionStore 逃生舱口。
  • 如果您希望将状态序列化为不同的(非 rison)格式,您还应该考虑使用它们。实用程序是可组合的,您可以实现自己的 storage
  • 如果您想使用 URL 同步部分状态,但使用浏览器存储同步另一部分状态。

何时不应使用状态同步实用程序

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

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

在导航之间保留状态

编辑

考虑以下场景

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

您会注意到您已使用您离开时相同的状态导航到 Dashboard 应用程序,只是时间过滤器已更改为您在 Discover 应用程序上应用的过滤器。

历史上,Kibana Analyze 组应用程序通过依赖 URL 中的状态来实现这种行为。如果您仔细查看导航中的链接,您会注意到状态存储在该链接内部,并且只要发生相关的状态更改,它也会更新

State is stored inside the navigation link

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

在迁移到 KP 之后,导航在无需页面重新加载的情况下工作,并且所有插件都同时加载。因此,除非您想通过 URL 进行操作,否则很可能存在更简单的方法来保留您的应用程序状态。