mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[HTTP] Add server/browser side http.staticAssets
service (#171003)
## Summary
Part of https://github.com/elastic/kibana/issues/170421
### 1. Introduce the `http.staticAssets` service
Which can be used to generate hrefs to Kibana's static assets in a
CDN-friendly way (based on the CDN url if defined in the config, and the
Kibana's basePath otherwise)
The service is exposed both on the browser and server-side.
For now a single API is exposed: `getPluginAssetHref`
```ts
// returns "/plugins/{pluginId}/assets/some_folder/asset.png" when CDN isn't configured
core.http.statisAssets.getPluginAssetHref('some_folder/asset.png');
```
### 2. Plug it on some of the `home` plugin assets
Adapt the sample data sets and tutorial schemas to use the service for
links to the associated assets
## How to test
#### 1. Edit`/etc/hosts`
add a line `127.0.0.1 local.cdn`
#### 2. Edit `kibana.yaml`
Add `server.cdn.url: "http://local.cdn:5601"`
#### 3. Boot kibana and navigate to sample data set installation
(if started in dev mode, use `--no-base-path`)
Confirm that the sample data set presentation images are pointing to the
CDN url and properly displayed:
<img width="1565" alt="Screenshot 2023-11-13 at 09 28 51"
src="23a887af
-00cb-400c-9ab1-511ba463495f">
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
82d05036ac
commit
c713b91e66
163 changed files with 673 additions and 287 deletions
|
@ -13,7 +13,7 @@ import { createBrowserHistory, History } from 'history';
|
|||
|
||||
import type { PluginOpaqueId } from '@kbn/core-base-common';
|
||||
import type { ThemeServiceStart } from '@kbn/core-theme-browser';
|
||||
import type { HttpSetup, HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup, InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import type { Capabilities } from '@kbn/core-capabilities-common';
|
||||
import type { MountPoint } from '@kbn/core-mount-utils-browser';
|
||||
import type { OverlayStart } from '@kbn/core-overlays-browser';
|
||||
|
@ -46,7 +46,7 @@ import {
|
|||
import { registerAnalyticsContextProvider } from './register_analytics_context_provider';
|
||||
|
||||
export interface SetupDeps {
|
||||
http: HttpSetup;
|
||||
http: InternalHttpSetup;
|
||||
analytics: AnalyticsServiceSetup;
|
||||
history?: History<any>;
|
||||
/** Used to redirect to external urls */
|
||||
|
@ -54,7 +54,7 @@ export interface SetupDeps {
|
|||
}
|
||||
|
||||
export interface StartDeps {
|
||||
http: HttpStart;
|
||||
http: InternalHttpStart;
|
||||
analytics: AnalyticsServiceStart;
|
||||
theme: ThemeServiceStart;
|
||||
overlays: OverlayStart;
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('parseAppUrl', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
apps = new Map();
|
||||
basePath = new BasePath('/base-path');
|
||||
basePath = new BasePath({ basePath: '/base-path' });
|
||||
|
||||
createApp({
|
||||
id: 'foo',
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { UnregisterCallback } from 'history';
|
|||
import type { CoreContext } from '@kbn/core-base-browser-internal';
|
||||
import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal';
|
||||
import type { DocLinksStart } from '@kbn/core-doc-links-browser';
|
||||
import type { HttpSetup, HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup, InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
|
||||
import type { NotificationsSetup, NotificationsStart } from '@kbn/core-notifications-browser';
|
||||
import { AppNavLinkStatus, type AppMountParameters } from '@kbn/core-application-browser';
|
||||
|
@ -27,7 +27,7 @@ import { renderApp as renderStatusApp } from './status';
|
|||
|
||||
export interface CoreAppsServiceSetupDeps {
|
||||
application: InternalApplicationSetup;
|
||||
http: HttpSetup;
|
||||
http: InternalHttpSetup;
|
||||
injectedMetadata: InternalInjectedMetadataSetup;
|
||||
notifications: NotificationsSetup;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ export interface CoreAppsServiceSetupDeps {
|
|||
export interface CoreAppsServiceStartDeps {
|
||||
application: InternalApplicationStart;
|
||||
docLinks: DocLinksStart;
|
||||
http: HttpStart;
|
||||
http: InternalHttpStart;
|
||||
notifications: NotificationsStart;
|
||||
uiSettings: IUiSettingsClient;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ describe('renderApp', () => {
|
|||
let unmount: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
basePath = new BasePath();
|
||||
basePath = new BasePath({ basePath: '' });
|
||||
element = document.createElement('div');
|
||||
history = createMemoryHistory();
|
||||
unmount = renderApp(
|
||||
|
|
|
@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import type { DocLinksStart } from '@kbn/core-doc-links-browser';
|
||||
import type { HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import type { NotificationsStart } from '@kbn/core-notifications-browser';
|
||||
import { mountReactNode } from '@kbn/core-mount-utils-browser-internal';
|
||||
|
||||
|
@ -21,7 +21,7 @@ export const MISSING_CONFIG_STORAGE_KEY = `core.warnings.publicBaseUrlMissingDis
|
|||
|
||||
interface Deps {
|
||||
docLinks: DocLinksStart;
|
||||
http: HttpStart;
|
||||
http: InternalHttpStart;
|
||||
notifications: NotificationsStart;
|
||||
// Exposed for easier testing
|
||||
storage?: Storage;
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('url overflow detection', () => {
|
|||
let unlisten: any;
|
||||
|
||||
beforeEach(() => {
|
||||
basePath = new BasePath('/test-123');
|
||||
basePath = new BasePath({ basePath: '/test-123' });
|
||||
history = createMemoryHistory();
|
||||
toasts = notificationServiceMock.createStartContract().toasts;
|
||||
uiSettings = uiSettingsServiceMock.createStartContract();
|
||||
|
|
|
@ -189,7 +189,7 @@ export async function loadStatus({
|
|||
http,
|
||||
notifications,
|
||||
}: {
|
||||
http: HttpSetup;
|
||||
http: Pick<HttpSetup, 'get'>;
|
||||
notifications: NotificationsSetup;
|
||||
}) {
|
||||
let response: StatusResponse;
|
||||
|
|
|
@ -10,13 +10,13 @@ import React from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
import { CoreThemeProvider } from '@kbn/core-theme-browser-internal';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
|
||||
import type { NotificationsSetup } from '@kbn/core-notifications-browser';
|
||||
import type { AppMountParameters } from '@kbn/core-application-browser';
|
||||
import { StatusApp } from './status_app';
|
||||
|
||||
interface Deps {
|
||||
http: HttpSetup;
|
||||
http: InternalHttpSetup;
|
||||
notifications: NotificationsSetup;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ import React, { Component } from 'react';
|
|||
import { EuiLoadingSpinner, EuiText, EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
|
||||
import type { NotificationsSetup } from '@kbn/core-notifications-browser';
|
||||
import { loadStatus, type ProcessedServerResponse } from './lib';
|
||||
import { MetricTiles, ServerStatus, StatusSection, VersionHeader } from './components';
|
||||
|
||||
interface StatusAppProps {
|
||||
http: HttpSetup;
|
||||
http: InternalHttpSetup;
|
||||
notifications: NotificationsSetup;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
|
||||
import type { RecursiveReadonly } from '@kbn/utility-types';
|
||||
import { deepFreeze } from '@kbn/std';
|
||||
import type { HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import type { Capabilities } from '@kbn/core-capabilities-common';
|
||||
|
||||
interface StartDeps {
|
||||
appIds: string[];
|
||||
http: HttpStart;
|
||||
http: InternalHttpStart;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
"kbn_references": [
|
||||
"@kbn/utility-types",
|
||||
"@kbn/std",
|
||||
"@kbn/core-http-browser",
|
||||
"@kbn/core-http-browser-mocks",
|
||||
"@kbn/core-capabilities-common"
|
||||
"@kbn/core-capabilities-common",
|
||||
"@kbn/core-http-browser-internal"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -16,7 +16,7 @@ import useObservable from 'react-use/lib/useObservable';
|
|||
import type { InternalInjectedMetadataStart } from '@kbn/core-injected-metadata-browser-internal';
|
||||
import type { AnalyticsServiceSetup } from '@kbn/core-analytics-browser';
|
||||
import { type DocLinksStart } from '@kbn/core-doc-links-browser';
|
||||
import type { HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import { mountReactNode } from '@kbn/core-mount-utils-browser-internal';
|
||||
import type { NotificationsStart } from '@kbn/core-notifications-browser';
|
||||
import type { InternalApplicationStart } from '@kbn/core-application-browser-internal';
|
||||
|
@ -63,7 +63,7 @@ export interface SetupDeps {
|
|||
export interface StartDeps {
|
||||
application: InternalApplicationStart;
|
||||
docLinks: DocLinksStart;
|
||||
http: HttpStart;
|
||||
http: InternalHttpStart;
|
||||
injectedMetadata: InternalInjectedMetadataStart;
|
||||
notifications: NotificationsStart;
|
||||
customBranding: CustomBrandingStart;
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
import { sortBy } from 'lodash';
|
||||
import { BehaviorSubject, ReplaySubject } from 'rxjs';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import type { HttpStart, IBasePath } from '@kbn/core-http-browser';
|
||||
import type { IBasePath } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import type { PublicAppDeepLinkInfo, PublicAppInfo } from '@kbn/core-application-browser';
|
||||
import type { InternalApplicationStart } from '@kbn/core-application-browser-internal';
|
||||
import type { ChromeNavLinks } from '@kbn/core-chrome-browser';
|
||||
|
@ -18,7 +19,7 @@ import { toNavLink } from './to_nav_link';
|
|||
|
||||
interface StartDeps {
|
||||
application: InternalApplicationStart;
|
||||
http: HttpStart;
|
||||
http: InternalHttpStart;
|
||||
}
|
||||
|
||||
export class NavLinksService {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
ChromeSetProjectBreadcrumbsParams,
|
||||
ChromeProjectNavigationNode,
|
||||
} from '@kbn/core-chrome-browser';
|
||||
import type { HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
Observable,
|
||||
|
@ -37,7 +37,7 @@ import { buildBreadcrumbs } from './breadcrumbs';
|
|||
interface StartDeps {
|
||||
application: InternalApplicationStart;
|
||||
navLinks: ChromeNavLinks;
|
||||
http: HttpStart;
|
||||
http: InternalHttpStart;
|
||||
chromeBreadcrumbs$: Observable<ChromeBreadcrumb[]>;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ export class ProjectNavigationService {
|
|||
}>({ breadcrumbs: [], params: { absolute: false } });
|
||||
private readonly stop$ = new ReplaySubject<void>(1);
|
||||
private application?: InternalApplicationStart;
|
||||
private http?: HttpStart;
|
||||
private http?: InternalHttpStart;
|
||||
private unlistenHistory?: () => void;
|
||||
|
||||
public start({ application, navLinks, http, chromeBreadcrumbs$ }: StartDeps) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import type {
|
||||
ChromeRecentlyAccessed,
|
||||
ChromeRecentlyAccessedHistoryItem,
|
||||
|
@ -15,7 +15,7 @@ import { PersistedLog } from './persisted_log';
|
|||
import { createLogKey } from './create_log_key';
|
||||
|
||||
interface StartDeps {
|
||||
http: HttpSetup;
|
||||
http: InternalHttpStart;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
|
|
@ -733,6 +733,7 @@ exports[`CollapsibleNav renders the default nav 1`] = `
|
|||
}
|
||||
basePath={
|
||||
BasePath {
|
||||
"assetsHrefBase": "/test",
|
||||
"basePath": "/test",
|
||||
"get": [Function],
|
||||
"prepend": [Function],
|
||||
|
@ -918,6 +919,7 @@ exports[`CollapsibleNav renders the default nav 2`] = `
|
|||
}
|
||||
basePath={
|
||||
BasePath {
|
||||
"assetsHrefBase": "/test",
|
||||
"basePath": "/test",
|
||||
"get": [Function],
|
||||
"prepend": [Function],
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
"@kbn/core-analytics-browser",
|
||||
"@kbn/shared-ux-router",
|
||||
"@kbn/shared-ux-link-redirect-app",
|
||||
"@kbn/core-http-browser-internal",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
import type { CoreService } from '@kbn/core-base-browser-internal';
|
||||
import type { DeprecationsServiceStart } from '@kbn/core-deprecations-browser';
|
||||
import type { HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import { DeprecationsClient } from './deprecations_client';
|
||||
|
||||
export class DeprecationsService implements CoreService<void, DeprecationsServiceStart> {
|
||||
public setup(): void {}
|
||||
|
||||
public start({ http }: { http: HttpStart }): DeprecationsServiceStart {
|
||||
public start({ http }: { http: InternalHttpStart }): DeprecationsServiceStart {
|
||||
const deprecationsClient = new DeprecationsClient({ http });
|
||||
|
||||
return {
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
"@kbn/core-http-browser",
|
||||
"@kbn/core-http-browser-mocks",
|
||||
"@kbn/core-deprecations-common",
|
||||
"@kbn/core-deprecations-browser"
|
||||
"@kbn/core-deprecations-browser",
|
||||
"@kbn/core-http-browser-internal"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -8,3 +8,4 @@
|
|||
|
||||
export { BasePath } from './src/base_path';
|
||||
export { HttpService } from './src/http_service';
|
||||
export type { InternalHttpSetup, InternalHttpStart } from './src/types';
|
||||
|
|
|
@ -12,13 +12,13 @@ import { BasePath } from './base_path';
|
|||
describe('#setup()', () => {
|
||||
describe('#register', () => {
|
||||
it(`allows paths that don't start with /`, () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('bar');
|
||||
});
|
||||
|
||||
it(`allows paths that end with '/'`, () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar/');
|
||||
});
|
||||
|
@ -26,70 +26,70 @@ describe('#setup()', () => {
|
|||
|
||||
describe('#isAnonymous', () => {
|
||||
it('returns true for registered paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered with a trailing slash, but call "isAnonymous" with no trailing slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar/');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered without a trailing slash, but call "isAnonymous" with a trailing slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar/')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered without a starting slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('when there is no basePath and calling "isAnonymous" without a starting slash, returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('when there is no basePath and calling "isAnonymous" with a starting slash, returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths whose capitalization is different', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/BAR');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for other paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/foo')).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for sub-paths of registered paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const basePath = new BasePath({ basePath: '/foo' });
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar/baz')).toBe(false);
|
||||
|
|
|
@ -10,35 +10,31 @@ import { BasePath } from './base_path';
|
|||
|
||||
describe('BasePath', () => {
|
||||
describe('#get()', () => {
|
||||
it('returns an empty string if no basePath not provided', () => {
|
||||
expect(new BasePath().get()).toBe('');
|
||||
});
|
||||
|
||||
it('returns basePath value if provided', () => {
|
||||
expect(new BasePath('/foo').get()).toBe('/foo');
|
||||
expect(new BasePath({ basePath: '/foo' }).get()).toBe('/foo');
|
||||
});
|
||||
|
||||
describe('#prepend()', () => {
|
||||
it('adds the base path to the path if it is relative and starts with a slash', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.prepend('/a/b')).toBe('/foo/bar/a/b');
|
||||
});
|
||||
|
||||
it('leaves the query string and hash of path unchanged', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.prepend('/a/b?x=y#c/d/e')).toBe('/foo/bar/a/b?x=y#c/d/e');
|
||||
});
|
||||
|
||||
it('returns the path unchanged if it does not start with a slash', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.prepend('a/b')).toBe('a/b');
|
||||
});
|
||||
|
||||
it('returns the path unchanged it it has a hostname', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.prepend('http://localhost:5601/a/b')).toBe('http://localhost:5601/a/b');
|
||||
});
|
||||
|
@ -46,19 +42,19 @@ describe('BasePath', () => {
|
|||
|
||||
describe('#remove()', () => {
|
||||
it('removes the basePath if relative path starts with it', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.remove('/foo/bar/a/b')).toBe('/a/b');
|
||||
});
|
||||
|
||||
it('leaves query string and hash intact', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.remove('/foo/bar/a/b?c=y#1234')).toBe('/a/b?c=y#1234');
|
||||
});
|
||||
|
||||
it('ignores urls with hostnames', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.remove('http://localhost:5601/foo/bar/a/b')).toBe(
|
||||
'http://localhost:5601/foo/bar/a/b'
|
||||
|
@ -66,13 +62,13 @@ describe('BasePath', () => {
|
|||
});
|
||||
|
||||
it('returns slash if path is just basePath', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.remove('/foo/bar')).toBe('/');
|
||||
});
|
||||
|
||||
it('returns full path if basePath is not its own segment', () => {
|
||||
const basePath = new BasePath('/foo/bar');
|
||||
const basePath = new BasePath({ basePath: '/foo/bar' });
|
||||
|
||||
expect(basePath.remove('/foo/barhop')).toBe('/foo/barhop');
|
||||
});
|
||||
|
@ -81,20 +77,39 @@ describe('BasePath', () => {
|
|||
|
||||
describe('serverBasePath', () => {
|
||||
it('defaults to basePath', () => {
|
||||
expect(new BasePath('/foo/bar').serverBasePath).toEqual('/foo/bar');
|
||||
expect(new BasePath({ basePath: '/foo/bar' }).serverBasePath).toEqual('/foo/bar');
|
||||
});
|
||||
|
||||
it('returns value when passed into constructor', () => {
|
||||
expect(new BasePath('/foo/bar', '/foo').serverBasePath).toEqual('/foo');
|
||||
expect(new BasePath({ basePath: '/foo/bar', serverBasePath: '/foo' }).serverBasePath).toEqual(
|
||||
'/foo'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('publicBaseUrl', () => {
|
||||
it('returns value passed into construtor', () => {
|
||||
expect(new BasePath('/foo/bar', '/foo').publicBaseUrl).toEqual(undefined);
|
||||
expect(new BasePath('/foo/bar', '/foo', 'http://myhost.com/foo').publicBaseUrl).toEqual(
|
||||
'http://myhost.com/foo'
|
||||
expect(new BasePath({ basePath: '/foo/bar' }).publicBaseUrl).toEqual(undefined);
|
||||
expect(
|
||||
new BasePath({ basePath: '/foo/bar', publicBaseUrl: 'http://myhost.com/foo' }).publicBaseUrl
|
||||
).toEqual('http://myhost.com/foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('assetsHrefBase', () => {
|
||||
it('default to the serverBasePath if unspecified', () => {
|
||||
expect(new BasePath({ basePath: '/foo/bar', serverBasePath: '/foo' }).assetsHrefBase).toEqual(
|
||||
'/foo'
|
||||
);
|
||||
});
|
||||
it('returns the correct value when explicitly set', () => {
|
||||
expect(
|
||||
new BasePath({
|
||||
basePath: '/foo/bar',
|
||||
serverBasePath: '/foo',
|
||||
assetsHrefBase: 'http://cdn/foo',
|
||||
}).assetsHrefBase
|
||||
).toEqual('http://cdn/foo');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,18 +10,36 @@ import { IBasePath } from '@kbn/core-http-browser';
|
|||
import { modifyUrl } from '@kbn/std';
|
||||
|
||||
export class BasePath implements IBasePath {
|
||||
constructor(
|
||||
private readonly basePath: string = '',
|
||||
public readonly serverBasePath: string = basePath,
|
||||
public readonly publicBaseUrl?: string
|
||||
) {}
|
||||
private readonly basePath: string;
|
||||
public readonly serverBasePath: string;
|
||||
public readonly assetsHrefBase: string;
|
||||
public readonly publicBaseUrl?: string;
|
||||
|
||||
constructor({
|
||||
basePath,
|
||||
serverBasePath,
|
||||
assetsHrefBase,
|
||||
publicBaseUrl,
|
||||
}: {
|
||||
basePath: string;
|
||||
serverBasePath?: string;
|
||||
assetsHrefBase?: string;
|
||||
publicBaseUrl?: string;
|
||||
}) {
|
||||
this.basePath = basePath;
|
||||
this.serverBasePath = serverBasePath ?? this.basePath;
|
||||
this.assetsHrefBase = assetsHrefBase ?? this.serverBasePath;
|
||||
this.publicBaseUrl = publicBaseUrl;
|
||||
}
|
||||
|
||||
public get = () => {
|
||||
return this.basePath;
|
||||
};
|
||||
|
||||
public prepend = (path: string): string => {
|
||||
if (!this.basePath) return path;
|
||||
if (!this.basePath) {
|
||||
return path;
|
||||
}
|
||||
return modifyUrl(path, (parts) => {
|
||||
if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) {
|
||||
parts.pathname = `${this.basePath}${parts.pathname}`;
|
||||
|
|
|
@ -27,7 +27,7 @@ const BASE_PATH = 'http://localhost/myBase';
|
|||
describe('Fetch', () => {
|
||||
const executionContextMock = executionContextServiceMock.createSetupContract();
|
||||
const fetchInstance = new Fetch({
|
||||
basePath: new BasePath(BASE_PATH),
|
||||
basePath: new BasePath({ basePath: BASE_PATH }),
|
||||
kibanaVersion: 'VERSION',
|
||||
buildNumber: 1234,
|
||||
executionContext: executionContextMock,
|
||||
|
|
|
@ -10,8 +10,9 @@ import type { CoreService } from '@kbn/core-base-browser-internal';
|
|||
import type { ExecutionContextSetup } from '@kbn/core-execution-context-browser';
|
||||
import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal';
|
||||
import type { FatalErrorsSetup } from '@kbn/core-fatal-errors-browser';
|
||||
import type { HttpSetup, HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup, InternalHttpStart } from './types';
|
||||
import { BasePath } from './base_path';
|
||||
import { StaticAssets } from './static_assets';
|
||||
import { AnonymousPathsService } from './anonymous_paths_service';
|
||||
import { LoadingCountService } from './loading_count_service';
|
||||
import { Fetch } from './fetch';
|
||||
|
@ -24,19 +25,23 @@ interface HttpDeps {
|
|||
}
|
||||
|
||||
/** @internal */
|
||||
export class HttpService implements CoreService<HttpSetup, HttpStart> {
|
||||
export class HttpService implements CoreService<InternalHttpSetup, InternalHttpStart> {
|
||||
private readonly anonymousPaths = new AnonymousPathsService();
|
||||
private readonly loadingCount = new LoadingCountService();
|
||||
private service?: HttpSetup;
|
||||
private service?: InternalHttpSetup;
|
||||
|
||||
public setup({ injectedMetadata, fatalErrors, executionContext }: HttpDeps): HttpSetup {
|
||||
public setup({ injectedMetadata, fatalErrors, executionContext }: HttpDeps): InternalHttpSetup {
|
||||
const kibanaVersion = injectedMetadata.getKibanaVersion();
|
||||
const buildNumber = injectedMetadata.getKibanaBuildNumber();
|
||||
const basePath = new BasePath(
|
||||
injectedMetadata.getBasePath(),
|
||||
injectedMetadata.getServerBasePath(),
|
||||
injectedMetadata.getPublicBaseUrl()
|
||||
);
|
||||
const basePath = new BasePath({
|
||||
basePath: injectedMetadata.getBasePath(),
|
||||
serverBasePath: injectedMetadata.getServerBasePath(),
|
||||
publicBaseUrl: injectedMetadata.getPublicBaseUrl(),
|
||||
assetsHrefBase: injectedMetadata.getAssetsHrefBase(),
|
||||
});
|
||||
const staticAssets = new StaticAssets({
|
||||
assetsHrefBase: injectedMetadata.getAssetsHrefBase(),
|
||||
});
|
||||
|
||||
const fetchService = new Fetch({ basePath, kibanaVersion, buildNumber, executionContext });
|
||||
const loadingCount = this.loadingCount.setup({ fatalErrors });
|
||||
|
@ -44,6 +49,7 @@ export class HttpService implements CoreService<HttpSetup, HttpStart> {
|
|||
|
||||
this.service = {
|
||||
basePath,
|
||||
staticAssets,
|
||||
anonymousPaths: this.anonymousPaths.setup({ basePath }),
|
||||
externalUrl: new ExternalUrlService().setup({ injectedMetadata, location: window.location }),
|
||||
intercept: fetchService.intercept.bind(fetchService),
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { StaticAssets } from './static_assets';
|
||||
|
||||
describe('StaticAssets', () => {
|
||||
describe('#getPluginAssetHref()', () => {
|
||||
it('returns the expected value when the base is a path', () => {
|
||||
const staticAssets = new StaticAssets({ assetsHrefBase: '/base-path' });
|
||||
expect(staticAssets.getPluginAssetHref('foo', 'path/to/img.gif')).toEqual(
|
||||
'/base-path/plugins/foo/assets/path/to/img.gif'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the expected value when the base is a full url', () => {
|
||||
const staticAssets = new StaticAssets({ assetsHrefBase: 'http://cdn/cdn-base-path' });
|
||||
expect(staticAssets.getPluginAssetHref('bar', 'path/to/img.gif')).toEqual(
|
||||
'http://cdn/cdn-base-path/plugins/bar/assets/path/to/img.gif'
|
||||
);
|
||||
});
|
||||
|
||||
it('removes leading slash from the', () => {
|
||||
const staticAssets = new StaticAssets({ assetsHrefBase: '/base-path' });
|
||||
expect(staticAssets.getPluginAssetHref('dolly', '/path/for/something.svg')).toEqual(
|
||||
'/base-path/plugins/dolly/assets/path/for/something.svg'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { InternalStaticAssets } from './types';
|
||||
|
||||
export class StaticAssets implements InternalStaticAssets {
|
||||
public readonly assetsHrefBase: string;
|
||||
|
||||
constructor({ assetsHrefBase }: { assetsHrefBase: string }) {
|
||||
this.assetsHrefBase = assetsHrefBase.endsWith('/')
|
||||
? assetsHrefBase.slice(0, -1)
|
||||
: assetsHrefBase;
|
||||
}
|
||||
|
||||
getPluginAssetHref(pluginName: string, assetPath: string): string {
|
||||
if (assetPath.startsWith('/')) {
|
||||
assetPath = assetPath.slice(1);
|
||||
}
|
||||
return `${this.assetsHrefBase}/plugins/${pluginName}/assets/${assetPath}`;
|
||||
}
|
||||
}
|
21
packages/core/http/core-http-browser-internal/src/types.ts
Normal file
21
packages/core/http/core-http-browser-internal/src/types.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { HttpSetup, HttpStart } from '@kbn/core-http-browser';
|
||||
|
||||
export type InternalHttpSetup = Omit<HttpSetup, 'staticAssets'> & {
|
||||
staticAssets: InternalStaticAssets;
|
||||
};
|
||||
|
||||
export type InternalHttpStart = Omit<HttpStart, 'staticAssets'> & {
|
||||
staticAssets: InternalStaticAssets;
|
||||
};
|
||||
|
||||
export interface InternalStaticAssets {
|
||||
getPluginAssetHref(pluginId: string, assetPath: string): string;
|
||||
}
|
|
@ -11,13 +11,15 @@ import type { IBasePath } from '@kbn/core-http-browser';
|
|||
const createBasePathMock = ({
|
||||
publicBaseUrl = '/',
|
||||
serverBasePath = '/',
|
||||
}: { publicBaseUrl?: string; serverBasePath?: string } = {}) => {
|
||||
assetsHrefBase = '/',
|
||||
}: { publicBaseUrl?: string; serverBasePath?: string; assetsHrefBase?: string } = {}) => {
|
||||
const mock: jest.Mocked<IBasePath> = {
|
||||
prepend: jest.fn(),
|
||||
get: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
publicBaseUrl,
|
||||
serverBasePath,
|
||||
assetsHrefBase,
|
||||
};
|
||||
|
||||
return mock;
|
||||
|
|
|
@ -29,7 +29,10 @@ const createServiceMock = ({
|
|||
patch: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
options: jest.fn(),
|
||||
basePath: new BasePath(basePath, undefined, publicBaseUrl),
|
||||
basePath: new BasePath({
|
||||
basePath,
|
||||
publicBaseUrl,
|
||||
}),
|
||||
anonymousPaths: {
|
||||
register: jest.fn(),
|
||||
isAnonymous: jest.fn(),
|
||||
|
@ -38,6 +41,9 @@ const createServiceMock = ({
|
|||
isInternalUrl: jest.fn(),
|
||||
validateUrl: jest.fn(),
|
||||
},
|
||||
staticAssets: {
|
||||
getPluginAssetHref: jest.fn(),
|
||||
},
|
||||
addLoadingCountSource: jest.fn(),
|
||||
getLoadingCount$: jest.fn().mockReturnValue(new BehaviorSubject(0)),
|
||||
intercept: jest.fn(),
|
||||
|
|
|
@ -12,6 +12,7 @@ export type {
|
|||
IBasePath,
|
||||
IExternalUrl,
|
||||
IAnonymousPaths,
|
||||
IStaticAssets,
|
||||
HttpHeadersInit,
|
||||
HttpRequestInit,
|
||||
HttpFetchQuery,
|
||||
|
|
|
@ -19,6 +19,12 @@ export interface HttpSetup {
|
|||
*/
|
||||
basePath: IBasePath;
|
||||
|
||||
/**
|
||||
* APIs for creating hrefs to static assets.
|
||||
* See {@link IStaticAssets}
|
||||
*/
|
||||
staticAssets: IStaticAssets;
|
||||
|
||||
/**
|
||||
* APIs for denoting certain paths for not requiring authentication
|
||||
*/
|
||||
|
@ -96,6 +102,12 @@ export interface IBasePath {
|
|||
*/
|
||||
readonly serverBasePath: string;
|
||||
|
||||
/**
|
||||
* Href (hypertext reference) intended to be used as the base for constructing
|
||||
* other hrefs to static assets.
|
||||
*/
|
||||
readonly assetsHrefBase: string;
|
||||
|
||||
/**
|
||||
* The server's publicly exposed base URL, if configured. Includes protocol, host, port (optional) and the
|
||||
* {@link IBasePath.serverBasePath}.
|
||||
|
@ -105,6 +117,7 @@ export interface IBasePath {
|
|||
*/
|
||||
readonly publicBaseUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* APIs for working with external URLs.
|
||||
*
|
||||
|
@ -130,6 +143,25 @@ export interface IExternalUrl {
|
|||
validateUrl(relativeOrAbsoluteUrl: string): URL | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* APIs for creating hrefs to static assets.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IStaticAssets {
|
||||
/**
|
||||
* Gets the full href to the current plugin's asset,
|
||||
* given its path relative to the plugin's `public/assets` folder.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // I want to retrieve the href for the asset stored under `my_plugin/public/assets/some_folder/asset.png`:
|
||||
* const assetHref = core.http.statisAssets.getPluginAssetHref('some_folder/asset.png');
|
||||
* ```
|
||||
*/
|
||||
getPluginAssetHref(assetPath: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* APIs for denoting paths as not requiring authentication
|
||||
*/
|
||||
|
@ -318,10 +350,13 @@ export interface HttpHandler {
|
|||
path: string,
|
||||
options: HttpFetchOptions & { asResponse: true }
|
||||
): Promise<HttpResponse<TResponseBody>>;
|
||||
|
||||
<TResponseBody = unknown>(options: HttpFetchOptionsWithPath & { asResponse: true }): Promise<
|
||||
HttpResponse<TResponseBody>
|
||||
>;
|
||||
|
||||
<TResponseBody = unknown>(path: string, options?: HttpFetchOptions): Promise<TResponseBody>;
|
||||
|
||||
<TResponseBody = unknown>(options: HttpFetchOptionsWithPath): Promise<TResponseBody>;
|
||||
}
|
||||
|
||||
|
@ -368,6 +403,7 @@ export interface HttpInterceptorResponseError extends HttpResponse {
|
|||
request: Readonly<Request>;
|
||||
error: Error | IHttpFetchError;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface HttpInterceptorRequestError {
|
||||
fetchOptions: Readonly<HttpFetchOptionsWithPath>;
|
||||
|
@ -429,6 +465,7 @@ export interface HttpInterceptor {
|
|||
export interface IHttpInterceptController {
|
||||
/** Whether or not this chain has been halted. */
|
||||
halted: boolean;
|
||||
|
||||
/** Halt the request Promise chain and do not process further interceptors or response handlers. */
|
||||
halt(): void;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ beforeEach(() => {
|
|||
cors: {
|
||||
enabled: false,
|
||||
},
|
||||
cdn: {},
|
||||
shutdownTimeout: moment.duration(500, 'ms'),
|
||||
} as any;
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ import { AuthStateStorage } from './auth_state_storage';
|
|||
import { AuthHeadersStorage } from './auth_headers_storage';
|
||||
import { BasePath } from './base_path_service';
|
||||
import { getEcsResponseLog } from './logging';
|
||||
import { StaticAssets, type IStaticAssets } from './static_assets';
|
||||
import { StaticAssets, type InternalStaticAssets } from './static_assets';
|
||||
|
||||
/**
|
||||
* Adds ELU timings for the executed function to the current's context transaction
|
||||
|
@ -136,7 +136,7 @@ export interface HttpServerSetup {
|
|||
* @note Static assets may be served over CDN
|
||||
*/
|
||||
registerStaticDir: (path: string, dirPath: string) => void;
|
||||
staticAssets: IStaticAssets;
|
||||
staticAssets: InternalStaticAssets;
|
||||
basePath: HttpServiceSetup['basePath'];
|
||||
csp: HttpServiceSetup['csp'];
|
||||
createCookieSessionStorageFactory: HttpServiceSetup['createCookieSessionStorageFactory'];
|
||||
|
|
|
@ -199,7 +199,7 @@ export class HttpService
|
|||
// the `plugin` and `legacy` services.
|
||||
public getStartContract(): InternalHttpServiceStart {
|
||||
return {
|
||||
...pick(this.internalSetup!, ['auth', 'basePath', 'getServerInfo']),
|
||||
...pick(this.internalSetup!, ['auth', 'basePath', 'getServerInfo', 'staticAssets']),
|
||||
isListening: () => this.httpServer.isListening(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,18 +14,48 @@ describe('StaticAssets', () => {
|
|||
let basePath: BasePath;
|
||||
let cdnConfig: CdnConfig;
|
||||
let staticAssets: StaticAssets;
|
||||
|
||||
beforeEach(() => {
|
||||
basePath = new BasePath('/test');
|
||||
cdnConfig = CdnConfig.from();
|
||||
staticAssets = new StaticAssets(basePath, cdnConfig);
|
||||
});
|
||||
it('provides fallsback to server base path', () => {
|
||||
expect(staticAssets.getHrefBase()).toEqual('/test');
|
||||
basePath = new BasePath('/base-path');
|
||||
});
|
||||
|
||||
it('provides the correct HREF given a CDN is configured', () => {
|
||||
cdnConfig = CdnConfig.from({ url: 'https://cdn.example.com/test' });
|
||||
staticAssets = new StaticAssets(basePath, cdnConfig);
|
||||
expect(staticAssets.getHrefBase()).toEqual('https://cdn.example.com/test');
|
||||
describe('#getHrefBase()', () => {
|
||||
it('provides fallback to server base path', () => {
|
||||
cdnConfig = CdnConfig.from();
|
||||
staticAssets = new StaticAssets(basePath, cdnConfig);
|
||||
expect(staticAssets.getHrefBase()).toEqual('/base-path');
|
||||
});
|
||||
|
||||
it('provides the correct HREF given a CDN is configured', () => {
|
||||
cdnConfig = CdnConfig.from({ url: 'https://cdn.example.com/test' });
|
||||
staticAssets = new StaticAssets(basePath, cdnConfig);
|
||||
expect(staticAssets.getHrefBase()).toEqual('https://cdn.example.com/test');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPluginAssetHref()', () => {
|
||||
it('returns the expected value when CDN config is not set', () => {
|
||||
cdnConfig = CdnConfig.from();
|
||||
staticAssets = new StaticAssets(basePath, cdnConfig);
|
||||
expect(staticAssets.getPluginAssetHref('foo', 'path/to/img.gif')).toEqual(
|
||||
'/base-path/plugins/foo/assets/path/to/img.gif'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the expected value when CDN config is set', () => {
|
||||
cdnConfig = CdnConfig.from({ url: 'https://cdn.example.com/test' });
|
||||
staticAssets = new StaticAssets(basePath, cdnConfig);
|
||||
expect(staticAssets.getPluginAssetHref('bar', 'path/to/img.gif')).toEqual(
|
||||
'https://cdn.example.com/test/plugins/bar/assets/path/to/img.gif'
|
||||
);
|
||||
});
|
||||
|
||||
it('removes leading slash from the', () => {
|
||||
cdnConfig = CdnConfig.from();
|
||||
staticAssets = new StaticAssets(basePath, cdnConfig);
|
||||
expect(staticAssets.getPluginAssetHref('dolly', '/path/for/something.svg')).toEqual(
|
||||
'/base-path/plugins/dolly/assets/path/for/something.svg'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,20 +9,31 @@
|
|||
import type { BasePath } from './base_path_service';
|
||||
import { CdnConfig } from './cdn';
|
||||
|
||||
export interface IStaticAssets {
|
||||
export interface InternalStaticAssets {
|
||||
getHrefBase(): string;
|
||||
getPluginAssetHref(pluginName: string, assetPath: string): string;
|
||||
}
|
||||
|
||||
export class StaticAssets implements IStaticAssets {
|
||||
constructor(private readonly basePath: BasePath, private readonly cdnConfig: CdnConfig) {}
|
||||
export class StaticAssets implements InternalStaticAssets {
|
||||
private readonly assetsHrefBase: string;
|
||||
|
||||
constructor(basePath: BasePath, cdnConfig: CdnConfig) {
|
||||
const hrefToUse = cdnConfig.baseHref ?? basePath.serverBasePath;
|
||||
this.assetsHrefBase = hrefToUse.endsWith('/') ? hrefToUse.slice(0, -1) : hrefToUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a href (hypertext reference) intended to be used as the base for constructing
|
||||
* other hrefs to static assets.
|
||||
*/
|
||||
getHrefBase(): string {
|
||||
if (this.cdnConfig.baseHref) {
|
||||
return this.cdnConfig.baseHref;
|
||||
return this.assetsHrefBase;
|
||||
}
|
||||
|
||||
getPluginAssetHref(pluginName: string, assetPath: string): string {
|
||||
if (assetPath.startsWith('/')) {
|
||||
assetPath = assetPath.slice(1);
|
||||
}
|
||||
return this.basePath.serverBasePath;
|
||||
return `${this.assetsHrefBase}/plugins/${pluginName}/assets/${assetPath}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ import type {
|
|||
HttpServiceSetup,
|
||||
HttpServiceStart,
|
||||
} from '@kbn/core-http-server';
|
||||
import { HttpServerSetup } from './http_server';
|
||||
import { ExternalUrlConfig } from './external_url';
|
||||
import type { HttpServerSetup } from './http_server';
|
||||
import type { ExternalUrlConfig } from './external_url';
|
||||
import type { InternalStaticAssets } from './static_assets';
|
||||
|
||||
/** @internal */
|
||||
export interface InternalHttpServicePreboot
|
||||
|
@ -43,10 +44,10 @@ export interface InternalHttpServicePreboot
|
|||
|
||||
/** @internal */
|
||||
export interface InternalHttpServiceSetup
|
||||
extends Omit<HttpServiceSetup, 'createRouter' | 'registerRouteHandlerContext'> {
|
||||
extends Omit<HttpServiceSetup, 'createRouter' | 'registerRouteHandlerContext' | 'staticAssets'> {
|
||||
auth: HttpServerSetup['auth'];
|
||||
server: HttpServerSetup['server'];
|
||||
staticAssets: HttpServerSetup['staticAssets'];
|
||||
staticAssets: InternalStaticAssets;
|
||||
externalUrl: ExternalUrlConfig;
|
||||
createRouter: <Context extends RequestHandlerContextBase = RequestHandlerContextBase>(
|
||||
path: string,
|
||||
|
@ -66,7 +67,8 @@ export interface InternalHttpServiceSetup
|
|||
}
|
||||
|
||||
/** @internal */
|
||||
export interface InternalHttpServiceStart extends HttpServiceStart {
|
||||
export interface InternalHttpServiceStart extends Omit<HttpServiceStart, 'staticAssets'> {
|
||||
staticAssets: InternalStaticAssets;
|
||||
/** Indicates if the http server is listening on the configured port */
|
||||
isListening: () => boolean;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import type {
|
|||
HttpServicePreboot,
|
||||
HttpServiceSetup,
|
||||
HttpServiceStart,
|
||||
IStaticAssets,
|
||||
} from '@kbn/core-http-server';
|
||||
import { AuthStatus } from '@kbn/core-http-server';
|
||||
import { mockRouter, RouterMock } from '@kbn/core-http-router-server-mocks';
|
||||
|
@ -34,17 +35,19 @@ import type {
|
|||
import { sessionStorageMock } from './cookie_session_storage.mocks';
|
||||
|
||||
type BasePathMocked = jest.Mocked<InternalHttpServiceSetup['basePath']>;
|
||||
type StaticAssetsMocked = jest.Mocked<InternalHttpServiceSetup['staticAssets']>;
|
||||
type InternalStaticAssetsMocked = jest.Mocked<InternalHttpServiceSetup['staticAssets']>;
|
||||
type StaticAssetsMocked = jest.Mocked<IStaticAssets>;
|
||||
type AuthMocked = jest.Mocked<InternalHttpServiceSetup['auth']>;
|
||||
|
||||
export type HttpServicePrebootMock = jest.Mocked<HttpServicePreboot>;
|
||||
export type InternalHttpServicePrebootMock = jest.Mocked<
|
||||
Omit<InternalHttpServicePreboot, 'basePath' | 'staticAssets'>
|
||||
> & { basePath: BasePathMocked; staticAssets: StaticAssetsMocked };
|
||||
> & { basePath: BasePathMocked; staticAssets: InternalStaticAssetsMocked };
|
||||
export type HttpServiceSetupMock<
|
||||
ContextType extends RequestHandlerContextBase = RequestHandlerContextBase
|
||||
> = jest.Mocked<Omit<HttpServiceSetup<ContextType>, 'basePath' | 'createRouter'>> & {
|
||||
basePath: BasePathMocked;
|
||||
staticAssets: StaticAssetsMocked;
|
||||
createRouter: jest.MockedFunction<() => RouterMock>;
|
||||
};
|
||||
export type InternalHttpServiceSetupMock = jest.Mocked<
|
||||
|
@ -55,15 +58,17 @@ export type InternalHttpServiceSetupMock = jest.Mocked<
|
|||
> & {
|
||||
auth: AuthMocked;
|
||||
basePath: BasePathMocked;
|
||||
staticAssets: StaticAssetsMocked;
|
||||
staticAssets: InternalStaticAssetsMocked;
|
||||
createRouter: jest.MockedFunction<(path: string) => RouterMock>;
|
||||
authRequestHeaders: jest.Mocked<IAuthHeadersStorage>;
|
||||
};
|
||||
export type HttpServiceStartMock = jest.Mocked<HttpServiceStart> & {
|
||||
basePath: BasePathMocked;
|
||||
staticAssets: StaticAssetsMocked;
|
||||
};
|
||||
export type InternalHttpServiceStartMock = jest.Mocked<InternalHttpServiceStart> & {
|
||||
basePath: BasePathMocked;
|
||||
staticAssets: InternalStaticAssetsMocked;
|
||||
};
|
||||
|
||||
const createBasePathMock = (
|
||||
|
@ -78,11 +83,12 @@ const createBasePathMock = (
|
|||
remove: jest.fn(),
|
||||
});
|
||||
|
||||
const createStaticAssetsMock = (
|
||||
const createInternalStaticAssetsMock = (
|
||||
basePath: BasePathMocked,
|
||||
cdnUrl: undefined | string = undefined
|
||||
): StaticAssetsMocked => ({
|
||||
): InternalStaticAssetsMocked => ({
|
||||
getHrefBase: jest.fn(() => cdnUrl ?? basePath.serverBasePath),
|
||||
getPluginAssetHref: jest.fn().mockReturnValue(cdnUrl ?? basePath.serverBasePath),
|
||||
});
|
||||
|
||||
const createAuthMock = () => {
|
||||
|
@ -106,6 +112,7 @@ const createAuthHeaderStorageMock = () => {
|
|||
interface CreateMockArgs {
|
||||
cdnUrl?: string;
|
||||
}
|
||||
|
||||
const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => {
|
||||
const basePath = createBasePathMock();
|
||||
const mock: InternalHttpServicePrebootMock = {
|
||||
|
@ -113,7 +120,7 @@ const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => {
|
|||
registerRouteHandlerContext: jest.fn(),
|
||||
registerStaticDir: jest.fn(),
|
||||
basePath,
|
||||
staticAssets: createStaticAssetsMock(basePath, args.cdnUrl),
|
||||
staticAssets: createInternalStaticAssetsMock(basePath, args.cdnUrl),
|
||||
csp: CspConfig.DEFAULT,
|
||||
externalUrl: ExternalUrlConfig.DEFAULT,
|
||||
auth: createAuthMock(),
|
||||
|
@ -144,6 +151,7 @@ const createPrebootContractMock = () => {
|
|||
};
|
||||
|
||||
const createInternalSetupContractMock = () => {
|
||||
const basePath = createBasePathMock();
|
||||
const mock: InternalHttpServiceSetupMock = {
|
||||
// we can mock other hapi server methods when we need it
|
||||
server: {
|
||||
|
@ -164,9 +172,9 @@ const createInternalSetupContractMock = () => {
|
|||
registerOnPreResponse: jest.fn(),
|
||||
createRouter: jest.fn().mockImplementation(() => mockRouter.create({})),
|
||||
registerStaticDir: jest.fn(),
|
||||
basePath: createBasePathMock(),
|
||||
basePath,
|
||||
csp: CspConfig.DEFAULT,
|
||||
staticAssets: { getHrefBase: jest.fn(() => mock.basePath.serverBasePath) },
|
||||
staticAssets: createInternalStaticAssetsMock(basePath),
|
||||
externalUrl: ExternalUrlConfig.DEFAULT,
|
||||
auth: createAuthMock(),
|
||||
authRequestHeaders: createAuthHeaderStorageMock(),
|
||||
|
@ -202,6 +210,9 @@ const createSetupContractMock = <
|
|||
createRouter: jest.fn(),
|
||||
registerRouteHandlerContext: jest.fn(),
|
||||
getServerInfo: internalMock.getServerInfo,
|
||||
staticAssets: {
|
||||
getPluginAssetHref: jest.fn().mockImplementation((assetPath: string) => assetPath),
|
||||
},
|
||||
};
|
||||
|
||||
mock.createRouter.mockImplementation(() => internalMock.createRouter(''));
|
||||
|
@ -214,14 +225,19 @@ const createStartContractMock = () => {
|
|||
auth: createAuthMock(),
|
||||
basePath: createBasePathMock(),
|
||||
getServerInfo: jest.fn(),
|
||||
staticAssets: {
|
||||
getPluginAssetHref: jest.fn().mockImplementation((assetPath: string) => assetPath),
|
||||
},
|
||||
};
|
||||
|
||||
return mock;
|
||||
};
|
||||
|
||||
const createInternalStartContractMock = () => {
|
||||
const basePath = createBasePathMock();
|
||||
const mock: InternalHttpServiceStartMock = {
|
||||
...createStartContractMock(),
|
||||
staticAssets: createInternalStaticAssetsMock(basePath),
|
||||
isListening: jest.fn(),
|
||||
};
|
||||
|
||||
|
|
|
@ -142,3 +142,5 @@ export type {
|
|||
VersionedRouteRegistrar,
|
||||
VersionedRouter,
|
||||
} from './src/versioning';
|
||||
|
||||
export type { IStaticAssets } from './src/static_assets';
|
||||
|
|
|
@ -20,6 +20,7 @@ import type {
|
|||
OnPreRoutingHandler,
|
||||
} from './lifecycle';
|
||||
import type { IBasePath } from './base_path';
|
||||
import type { IStaticAssets } from './static_assets';
|
||||
import type { ICspConfig } from './csp';
|
||||
import type { GetAuthState, IsAuthenticated } from './auth_state';
|
||||
import type { SessionStorageCookieOptions, SessionStorageFactory } from './session_storage';
|
||||
|
@ -287,6 +288,12 @@ export interface HttpServiceSetup<
|
|||
*/
|
||||
basePath: IBasePath;
|
||||
|
||||
/**
|
||||
* APIs for creating hrefs to static assets.
|
||||
* See {@link IStaticAssets}
|
||||
*/
|
||||
staticAssets: IStaticAssets;
|
||||
|
||||
/**
|
||||
* The CSP config used for Kibana.
|
||||
*/
|
||||
|
@ -361,6 +368,12 @@ export interface HttpServiceStart {
|
|||
*/
|
||||
basePath: IBasePath;
|
||||
|
||||
/**
|
||||
* APIs for creating hrefs to static assets.
|
||||
* See {@link IStaticAssets}
|
||||
*/
|
||||
staticAssets: IStaticAssets;
|
||||
|
||||
/**
|
||||
* Auth status.
|
||||
* See {@link HttpAuth}
|
||||
|
|
26
packages/core/http/core-http-server/src/static_assets.ts
Normal file
26
packages/core/http/core-http-server/src/static_assets.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* APIs for creating hrefs to static assets.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IStaticAssets {
|
||||
/**
|
||||
* Gets the full href to the current plugin's asset,
|
||||
* given its path relative to the plugin's `public/assets` folder.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // I want to retrieve the href for the asset stored under `my_plugin/public/assets/some_folder/asset.png`:
|
||||
* const assetHref = core.http.statisAssets.getPluginAssetHref('some_folder/asset.png');
|
||||
* ```
|
||||
*/
|
||||
getPluginAssetHref(assetPath: string): string;
|
||||
}
|
|
@ -48,6 +48,10 @@ export class InjectedMetadataService {
|
|||
return this.state.publicBaseUrl;
|
||||
},
|
||||
|
||||
getAssetsHrefBase: () => {
|
||||
return this.state.assetsHrefBase;
|
||||
},
|
||||
|
||||
getAnonymousStatusPage: () => {
|
||||
return this.state.anonymousStatusPage;
|
||||
},
|
||||
|
|
|
@ -29,6 +29,7 @@ export interface InternalInjectedMetadataSetup {
|
|||
getBasePath: () => string;
|
||||
getServerBasePath: () => string;
|
||||
getPublicBaseUrl: () => string | undefined;
|
||||
getAssetsHrefBase: () => string;
|
||||
getKibanaBuildNumber: () => number;
|
||||
getKibanaBranch: () => string;
|
||||
getKibanaVersion: () => string;
|
||||
|
|
|
@ -16,6 +16,7 @@ const createSetupContractMock = () => {
|
|||
const setupContract: jest.Mocked<InternalInjectedMetadataSetup> = {
|
||||
getBasePath: jest.fn(),
|
||||
getServerBasePath: jest.fn(),
|
||||
getAssetsHrefBase: jest.fn(),
|
||||
getPublicBaseUrl: jest.fn(),
|
||||
getKibanaVersion: jest.fn(),
|
||||
getKibanaBranch: jest.fn(),
|
||||
|
@ -31,6 +32,9 @@ const createSetupContractMock = () => {
|
|||
getKibanaBuildNumber: jest.fn(),
|
||||
getCustomBranding: jest.fn(),
|
||||
};
|
||||
setupContract.getBasePath.mockReturnValue('/base-path');
|
||||
setupContract.getServerBasePath.mockReturnValue('/server-base-path');
|
||||
setupContract.getAssetsHrefBase.mockReturnValue('/assets-base-path');
|
||||
setupContract.getCspConfig.mockReturnValue({ warnLegacyBrowsers: true });
|
||||
setupContract.getExternalUrlConfig.mockReturnValue({ policy: [] });
|
||||
setupContract.getKibanaVersion.mockReturnValue('kibanaVersion');
|
||||
|
|
|
@ -42,6 +42,7 @@ export interface InjectedMetadata {
|
|||
basePath: string;
|
||||
serverBasePath: string;
|
||||
publicBaseUrl?: string;
|
||||
assetsHrefBase: string;
|
||||
clusterInfo: InjectedMetadataClusterInfo;
|
||||
env: {
|
||||
mode: EnvironmentMode;
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
import type { CoreSetup } from '@kbn/core-lifecycle-browser';
|
||||
import type { InternalApplicationSetup } from '@kbn/core-application-browser-internal';
|
||||
import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal';
|
||||
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
|
||||
|
||||
/** @internal */
|
||||
export interface InternalCoreSetup
|
||||
extends Omit<CoreSetup, 'application' | 'plugins' | 'getStartServices'> {
|
||||
extends Omit<CoreSetup, 'application' | 'plugins' | 'getStartServices' | 'http'> {
|
||||
application: InternalApplicationSetup;
|
||||
injectedMetadata: InternalInjectedMetadataSetup;
|
||||
http: InternalHttpSetup;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
import type { CoreStart } from '@kbn/core-lifecycle-browser';
|
||||
import type { InternalApplicationStart } from '@kbn/core-application-browser-internal';
|
||||
import type { InternalInjectedMetadataStart } from '@kbn/core-injected-metadata-browser-internal';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
|
||||
/** @internal */
|
||||
export interface InternalCoreStart extends Omit<CoreStart, 'application' | 'plugins'> {
|
||||
export interface InternalCoreStart extends Omit<CoreStart, 'application' | 'plugins' | 'http'> {
|
||||
application: InternalApplicationStart;
|
||||
injectedMetadata: InternalInjectedMetadataStart;
|
||||
http: InternalHttpStart;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
"kbn_references": [
|
||||
"@kbn/core-lifecycle-browser",
|
||||
"@kbn/core-application-browser-internal",
|
||||
"@kbn/core-injected-metadata-browser-internal"
|
||||
"@kbn/core-injected-metadata-browser-internal",
|
||||
"@kbn/core-http-browser-internal"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -82,7 +82,13 @@ export function createPluginSetupContext<
|
|||
customBranding: deps.customBranding,
|
||||
fatalErrors: deps.fatalErrors,
|
||||
executionContext: deps.executionContext,
|
||||
http: deps.http,
|
||||
http: {
|
||||
...deps.http,
|
||||
staticAssets: {
|
||||
getPluginAssetHref: (assetPath: string) =>
|
||||
deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath),
|
||||
},
|
||||
},
|
||||
notifications: deps.notifications,
|
||||
uiSettings: deps.uiSettings,
|
||||
settings: deps.settings,
|
||||
|
@ -133,7 +139,13 @@ export function createPluginStartContext<
|
|||
customBranding: deps.customBranding,
|
||||
docLinks: deps.docLinks,
|
||||
executionContext: deps.executionContext,
|
||||
http: deps.http,
|
||||
http: {
|
||||
...deps.http,
|
||||
staticAssets: {
|
||||
getPluginAssetHref: (assetPath: string) =>
|
||||
deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath),
|
||||
},
|
||||
},
|
||||
chrome: omit(deps.chrome, 'getComponent'),
|
||||
i18n: deps.i18n,
|
||||
notifications: deps.notifications,
|
||||
|
|
|
@ -104,6 +104,10 @@ describe('PluginsService', () => {
|
|||
application: expect.any(Object),
|
||||
plugins: expect.any(Object),
|
||||
getStartServices: expect.any(Function),
|
||||
http: {
|
||||
...mockSetupDeps.http,
|
||||
staticAssets: expect.any(Object),
|
||||
},
|
||||
};
|
||||
// @ts-expect-error this file was not being type checked properly in the past, error is legit
|
||||
mockStartDeps = {
|
||||
|
@ -128,6 +132,10 @@ describe('PluginsService', () => {
|
|||
application: expect.any(Object),
|
||||
plugins: expect.any(Object),
|
||||
chrome: omit(mockStartDeps.chrome, 'getComponent'),
|
||||
http: {
|
||||
...mockStartDeps.http,
|
||||
staticAssets: expect.any(Object),
|
||||
},
|
||||
};
|
||||
|
||||
// Reset these for each test.
|
||||
|
|
|
@ -235,6 +235,10 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>({
|
|||
registerOnPostAuth: deps.http.registerOnPostAuth,
|
||||
registerOnPreResponse: deps.http.registerOnPreResponse,
|
||||
basePath: deps.http.basePath,
|
||||
staticAssets: {
|
||||
getPluginAssetHref: (assetPath: string) =>
|
||||
deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath),
|
||||
},
|
||||
csp: deps.http.csp,
|
||||
getServerInfo: deps.http.getServerInfo,
|
||||
},
|
||||
|
@ -324,6 +328,10 @@ export function createPluginStartContext<TPlugin, TPluginDependencies>({
|
|||
auth: deps.http.auth,
|
||||
basePath: deps.http.basePath,
|
||||
getServerInfo: deps.http.getServerInfo,
|
||||
staticAssets: {
|
||||
getPluginAssetHref: (assetPath: string) =>
|
||||
deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath),
|
||||
},
|
||||
},
|
||||
savedObjects: {
|
||||
getScopedClient: deps.savedObjects.getScopedClient,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
exports[`RenderingService preboot() render() renders "core" CDN url injected 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "http://foo.bar:1773",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -70,6 +71,7 @@ Object {
|
|||
exports[`RenderingService preboot() render() renders "core" page 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -133,6 +135,7 @@ Object {
|
|||
exports[`RenderingService preboot() render() renders "core" page driven by settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -200,6 +203,7 @@ Object {
|
|||
exports[`RenderingService preboot() render() renders "core" page for blank basepath 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -263,6 +267,7 @@ Object {
|
|||
exports[`RenderingService preboot() render() renders "core" page for unauthenticated requests 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -326,6 +331,7 @@ Object {
|
|||
exports[`RenderingService preboot() render() renders "core" page with global settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -393,6 +399,7 @@ Object {
|
|||
exports[`RenderingService preboot() render() renders "core" with excluded global user settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -456,6 +463,7 @@ Object {
|
|||
exports[`RenderingService preboot() render() renders "core" with excluded user settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -519,6 +527,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" CDN url injected 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -591,6 +600,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" page 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -654,6 +664,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" page driven by settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -726,6 +737,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" page for blank basepath 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -794,6 +806,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" page for unauthenticated requests 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -857,6 +870,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" page with global settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -929,6 +943,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" with excluded global user settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
@ -997,6 +1012,7 @@ Object {
|
|||
exports[`RenderingService setup() render() renders "core" with excluded user settings 1`] = `
|
||||
Object {
|
||||
"anonymousStatusPage": false,
|
||||
"assetsHrefBase": "/mock-server-basepath",
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
|
|
|
@ -209,6 +209,7 @@ export class RenderingService {
|
|||
basePath,
|
||||
serverBasePath,
|
||||
publicBaseUrl,
|
||||
assetsHrefBase: staticAssetsHrefBase,
|
||||
env,
|
||||
clusterInfo,
|
||||
anonymousStatusPage: status?.isStatusPageAnonymous() ?? false,
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
*/
|
||||
|
||||
import { pick, throttle, cloneDeep } from 'lodash';
|
||||
import type { HttpSetup, HttpFetchOptions } from '@kbn/core-http-browser';
|
||||
import type { HttpFetchOptions } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
|
||||
import type { SavedObject, SavedObjectTypeIdTuple } from '@kbn/core-saved-objects-common';
|
||||
import type {
|
||||
SavedObjectsBulkResolveResponse as SavedObjectsBulkResolveResponseServer,
|
||||
|
@ -106,7 +107,7 @@ const getObjectsToResolve = (queue: BatchResolveQueueEntry[]) => {
|
|||
* @deprecated See https://github.com/elastic/kibana/issues/149098
|
||||
*/
|
||||
export class SavedObjectsClient implements SavedObjectsClientContract {
|
||||
private http: HttpSetup;
|
||||
private http: InternalHttpSetup;
|
||||
private batchGetQueue: BatchGetQueueEntry[];
|
||||
private batchResolveQueue: BatchResolveQueueEntry[];
|
||||
|
||||
|
@ -180,7 +181,7 @@ export class SavedObjectsClient implements SavedObjectsClientContract {
|
|||
);
|
||||
|
||||
/** @internal */
|
||||
constructor(http: HttpSetup) {
|
||||
constructor(http: InternalHttpSetup) {
|
||||
this.http = http;
|
||||
this.batchGetQueue = [];
|
||||
this.batchResolveQueue = [];
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import type { CoreService } from '@kbn/core-base-browser-internal';
|
||||
import type { HttpStart } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpStart } from '@kbn/core-http-browser-internal';
|
||||
import type { SavedObjectsStart } from '@kbn/core-saved-objects-browser';
|
||||
import { SavedObjectsClient } from './saved_objects_client';
|
||||
|
||||
|
@ -17,7 +17,7 @@ import { SavedObjectsClient } from './saved_objects_client';
|
|||
export class SavedObjectsService implements CoreService<void, SavedObjectsStart> {
|
||||
public async setup() {}
|
||||
|
||||
public async start({ http }: { http: HttpStart }): Promise<SavedObjectsStart> {
|
||||
public async start({ http }: { http: InternalHttpStart }): Promise<SavedObjectsStart> {
|
||||
return { client: new SavedObjectsClient(http) };
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"@kbn/core-saved-objects-api-server",
|
||||
"@kbn/core-saved-objects-api-browser",
|
||||
"@kbn/core-http-browser-mocks",
|
||||
"@kbn/core-http-browser-internal",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
import { Subject } from 'rxjs';
|
||||
|
||||
import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
|
||||
import type { SettingsStart, SettingsSetup } from '@kbn/core-ui-settings-browser';
|
||||
import { UiSettingsApi } from './ui_settings_api';
|
||||
import { UiSettingsClient } from './ui_settings_client';
|
||||
import { UiSettingsGlobalClient } from './ui_settings_global_client';
|
||||
|
||||
export interface SettingsServiceDeps {
|
||||
http: HttpSetup;
|
||||
http: InternalHttpSetup;
|
||||
injectedMetadata: InternalInjectedMetadataSetup;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
|
||||
|
||||
import type { UiSettingsState } from '@kbn/core-ui-settings-browser';
|
||||
import { UiSettingsScope } from '@kbn/core-ui-settings-common';
|
||||
|
@ -37,7 +37,7 @@ export class UiSettingsApi {
|
|||
|
||||
private readonly loadingCount$ = new BehaviorSubject(0);
|
||||
|
||||
constructor(private readonly http: HttpSetup) {}
|
||||
constructor(private readonly http: InternalHttpSetup) {}
|
||||
|
||||
/**
|
||||
* Adds a key+value that will be sent to the server ASAP. If a request is
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
import { Subject } from 'rxjs';
|
||||
|
||||
import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { InternalHttpSetup } from '@kbn/core-http-browser-internal';
|
||||
|
||||
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
|
||||
import { UiSettingsApi } from './ui_settings_api';
|
||||
import { UiSettingsClient } from './ui_settings_client';
|
||||
|
||||
export interface UiSettingsServiceDeps {
|
||||
http: HttpSetup;
|
||||
http: InternalHttpSetup;
|
||||
injectedMetadata: InternalInjectedMetadataSetup;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core-test-helpers-http-setup-browser",
|
||||
"@kbn/core-http-browser",
|
||||
"@kbn/core-ui-settings-browser",
|
||||
"@kbn/core-ui-settings-common",
|
||||
"@kbn/core-http-browser-mocks",
|
||||
"@kbn/core-injected-metadata-browser-mocks",
|
||||
"@kbn/core-injected-metadata-browser-internal",
|
||||
"@kbn/core-http-browser-internal",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import { useEuiTheme } from '@elastic/eui';
|
||||
|
||||
import type { SampleDataSet } from '@kbn/home-sample-data-types';
|
||||
import { useServices } from './services';
|
||||
import { SampleDataCard as Component, Props as ComponentProps } from './sample_data_card.component';
|
||||
|
||||
/**
|
||||
|
@ -27,12 +26,10 @@ export interface Props extends Pick<ComponentProps, 'onStatusChange'> {
|
|||
* function.
|
||||
*/
|
||||
export const SampleDataCard = ({ sampleDataSet, onStatusChange }: Props) => {
|
||||
const { addBasePath } = useServices();
|
||||
const { colorMode } = useEuiTheme();
|
||||
const { darkPreviewImagePath, previewImagePath } = sampleDataSet;
|
||||
const path =
|
||||
const imagePath =
|
||||
colorMode === 'DARK' && darkPreviewImagePath ? darkPreviewImagePath : previewImagePath;
|
||||
const imagePath = useMemo(() => addBasePath(path), [addBasePath, path]);
|
||||
|
||||
return <Component {...{ sampleDataSet, imagePath, onStatusChange }} />;
|
||||
};
|
||||
|
|
|
@ -187,6 +187,7 @@ export type {
|
|||
HttpResponse,
|
||||
HttpHandler,
|
||||
IBasePath,
|
||||
IStaticAssets,
|
||||
IAnonymousPaths,
|
||||
IExternalUrl,
|
||||
IHttpInterceptController,
|
||||
|
|
|
@ -184,6 +184,7 @@ export type {
|
|||
ICspConfig,
|
||||
IExternalUrlConfig,
|
||||
IBasePath,
|
||||
IStaticAssets,
|
||||
SessionStorage,
|
||||
SessionStorageCookieOptions,
|
||||
SessionCookieValidationResult,
|
||||
|
|
|
@ -36,6 +36,7 @@ describe('Http server', () => {
|
|||
allowFromAnyIp: true,
|
||||
ipAllowlist: [],
|
||||
},
|
||||
cdn: {},
|
||||
cors: {
|
||||
enabled: false,
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { HttpSetup } from '@kbn/core/public';
|
||||
import { http } from './data_views_api_client.test.mock';
|
||||
import { DataViewsApiClient } from './data_views_api_client';
|
||||
import { FIELDS_FOR_WILDCARD_PATH as expectedPath } from '../../common/constants';
|
||||
|
@ -16,7 +17,7 @@ describe('IndexPatternsApiClient', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
fetchSpy = jest.spyOn(http, 'fetch').mockImplementation(() => Promise.resolve({}));
|
||||
indexPatternsApiClient = new DataViewsApiClient(http);
|
||||
indexPatternsApiClient = new DataViewsApiClient(http as HttpSetup);
|
||||
});
|
||||
|
||||
test('uses the right URI to fetch fields for wildcard', async function () {
|
||||
|
|
|
@ -10,7 +10,7 @@ import path from 'path';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { getSavedObjects } from './saved_objects';
|
||||
import { fieldMappings } from './field_mappings';
|
||||
import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types';
|
||||
import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types';
|
||||
|
||||
const ecommerceName = i18n.translate('home.sampleData.ecommerceSpecTitle', {
|
||||
defaultMessage: 'Sample eCommerce orders',
|
||||
|
@ -19,14 +19,17 @@ const ecommerceDescription = i18n.translate('home.sampleData.ecommerceSpecDescri
|
|||
defaultMessage: 'Sample data, visualizations, and dashboards for tracking eCommerce orders.',
|
||||
});
|
||||
|
||||
export const ecommerceSpecProvider = function (): SampleDatasetSchema {
|
||||
export const ecommerceSpecProvider: SampleDatasetProvider = ({ staticAssets }) => {
|
||||
return {
|
||||
id: 'ecommerce',
|
||||
name: ecommerceName,
|
||||
description: ecommerceDescription,
|
||||
previewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard.webp',
|
||||
darkPreviewImagePath:
|
||||
'/plugins/home/assets/sample_data_resources/ecommerce/dashboard_dark.webp',
|
||||
previewImagePath: staticAssets.getPluginAssetHref(
|
||||
'/sample_data_resources/ecommerce/dashboard.webp'
|
||||
),
|
||||
darkPreviewImagePath: staticAssets.getPluginAssetHref(
|
||||
'/sample_data_resources/ecommerce/dashboard_dark.webp'
|
||||
),
|
||||
overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f',
|
||||
defaultIndex: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f',
|
||||
savedObjects: getSavedObjects(),
|
||||
|
@ -41,6 +44,6 @@ export const ecommerceSpecProvider = function (): SampleDatasetSchema {
|
|||
},
|
||||
],
|
||||
status: 'not_installed',
|
||||
iconPath: '/plugins/home/assets/sample_data_resources/ecommerce/icon.svg',
|
||||
iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/ecommerce/icon.svg'),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import path from 'path';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { getSavedObjects } from './saved_objects';
|
||||
import { fieldMappings } from './field_mappings';
|
||||
import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types';
|
||||
import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types';
|
||||
|
||||
const flightsName = i18n.translate('home.sampleData.flightsSpecTitle', {
|
||||
defaultMessage: 'Sample flight data',
|
||||
|
@ -19,13 +19,17 @@ const flightsDescription = i18n.translate('home.sampleData.flightsSpecDescriptio
|
|||
defaultMessage: 'Sample data, visualizations, and dashboards for monitoring flight routes.',
|
||||
});
|
||||
|
||||
export const flightsSpecProvider = function (): SampleDatasetSchema {
|
||||
export const flightsSpecProvider: SampleDatasetProvider = ({ staticAssets }) => {
|
||||
return {
|
||||
id: 'flights',
|
||||
name: flightsName,
|
||||
description: flightsDescription,
|
||||
previewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard.webp',
|
||||
darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard_dark.webp',
|
||||
previewImagePath: staticAssets.getPluginAssetHref(
|
||||
'/sample_data_resources/flights/dashboard.webp'
|
||||
),
|
||||
darkPreviewImagePath: staticAssets.getPluginAssetHref(
|
||||
'/sample_data_resources/flights/dashboard_dark.webp'
|
||||
),
|
||||
overviewDashboard: '7adfa750-4c81-11e8-b3d7-01146121b73d',
|
||||
defaultIndex: 'd3d7af60-4c81-11e8-b3d7-01146121b73d',
|
||||
savedObjects: getSavedObjects(),
|
||||
|
@ -40,6 +44,6 @@ export const flightsSpecProvider = function (): SampleDatasetSchema {
|
|||
},
|
||||
],
|
||||
status: 'not_installed',
|
||||
iconPath: '/plugins/home/assets/sample_data_resources/flights/icon.svg',
|
||||
iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/flights/icon.svg'),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import path from 'path';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { getSavedObjects } from './saved_objects';
|
||||
import { fieldMappings } from './field_mappings';
|
||||
import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types';
|
||||
import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types';
|
||||
|
||||
const logsName = i18n.translate('home.sampleData.logsSpecTitle', {
|
||||
defaultMessage: 'Sample web logs',
|
||||
|
@ -20,13 +20,15 @@ const logsDescription = i18n.translate('home.sampleData.logsSpecDescription', {
|
|||
});
|
||||
|
||||
export const GLOBE_ICON_PATH = '/plugins/home/assets/sample_data_resources/logs/icon.svg';
|
||||
export const logsSpecProvider = function (): SampleDatasetSchema {
|
||||
export const logsSpecProvider: SampleDatasetProvider = ({ staticAssets }) => {
|
||||
return {
|
||||
id: 'logs',
|
||||
name: logsName,
|
||||
description: logsDescription,
|
||||
previewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard.webp',
|
||||
darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard_dark.webp',
|
||||
previewImagePath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/dashboard.webp'),
|
||||
darkPreviewImagePath: staticAssets.getPluginAssetHref(
|
||||
'/sample_data_resources/logs/dashboard_dark.webp'
|
||||
),
|
||||
overviewDashboard: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b',
|
||||
defaultIndex: '90943e30-9a47-11e8-b64d-95841ca0b247',
|
||||
savedObjects: getSavedObjects(),
|
||||
|
@ -42,6 +44,6 @@ export const logsSpecProvider = function (): SampleDatasetSchema {
|
|||
},
|
||||
],
|
||||
status: 'not_installed',
|
||||
iconPath: GLOBE_ICON_PATH,
|
||||
iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/icon.svg'),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import path from 'path';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { getSavedObjects } from './saved_objects';
|
||||
import { fieldMappings } from './field_mappings';
|
||||
import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types';
|
||||
import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types';
|
||||
|
||||
const logsName = i18n.translate('home.sampleData.logsTsdbSpecTitle', {
|
||||
defaultMessage: 'Sample web logs (TSDB)',
|
||||
|
@ -20,7 +20,7 @@ const logsDescription = i18n.translate('home.sampleData.logsTsdbSpecDescription'
|
|||
});
|
||||
|
||||
export const GLOBE_ICON_PATH = '/plugins/home/assets/sample_data_resources/logs/icon.svg';
|
||||
export const logsTSDBSpecProvider = function (): SampleDatasetSchema {
|
||||
export const logsTSDBSpecProvider: SampleDatasetProvider = ({ staticAssets }) => {
|
||||
const startDate = new Date();
|
||||
const endDate = new Date();
|
||||
startDate.setMonth(startDate.getMonth() - 1);
|
||||
|
@ -29,8 +29,10 @@ export const logsTSDBSpecProvider = function (): SampleDatasetSchema {
|
|||
id: 'logstsdb',
|
||||
name: logsName,
|
||||
description: logsDescription,
|
||||
previewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard.webp',
|
||||
darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard_dark.webp',
|
||||
previewImagePath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/dashboard.webp'),
|
||||
darkPreviewImagePath: staticAssets.getPluginAssetHref(
|
||||
'/sample_data_resources/logs/dashboard_dark.webp'
|
||||
),
|
||||
overviewDashboard: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef8f5b',
|
||||
defaultIndex: '90943e30-9a47-11e8-b64d-95841ca0c247',
|
||||
savedObjects: getSavedObjects(),
|
||||
|
@ -53,6 +55,6 @@ export const logsTSDBSpecProvider = function (): SampleDatasetSchema {
|
|||
},
|
||||
],
|
||||
status: 'not_installed',
|
||||
iconPath: GLOBE_ICON_PATH,
|
||||
iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/icon.svg'),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { IStaticAssets } from '@kbn/core/server';
|
||||
import type { SampleDatasetSchema } from './sample_dataset_schema';
|
||||
export type { SampleDatasetSchema, DataIndexSchema } from './sample_dataset_schema';
|
||||
|
||||
|
@ -27,7 +28,11 @@ export enum EmbeddableTypes {
|
|||
SEARCH_EMBEDDABLE_TYPE = 'search',
|
||||
VISUALIZE_EMBEDDABLE_TYPE = 'visualization',
|
||||
}
|
||||
export type SampleDatasetProvider = () => SampleDatasetSchema;
|
||||
|
||||
export interface SampleDatasetProviderContext {
|
||||
staticAssets: IStaticAssets;
|
||||
}
|
||||
export type SampleDatasetProvider = (context: SampleDatasetProviderContext) => SampleDatasetSchema;
|
||||
|
||||
/** This type is used to identify an object in a sample dataset. */
|
||||
export interface SampleObject {
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
SampleDatasetSchema,
|
||||
SampleDatasetDashboardPanel,
|
||||
AppLinkData,
|
||||
SampleDatasetProviderContext,
|
||||
} from './lib/sample_dataset_registry_types';
|
||||
import { sampleDataSchema } from './lib/sample_dataset_schema';
|
||||
|
||||
|
@ -34,11 +35,15 @@ export class SampleDataRegistry {
|
|||
|
||||
private readonly sampleDatasets: SampleDatasetSchema[] = [];
|
||||
private readonly appLinksMap = new Map<string, AppLinkData[]>();
|
||||
private sampleDataProviderContext?: SampleDatasetProviderContext;
|
||||
|
||||
private registerSampleDataSet(specProvider: SampleDatasetProvider) {
|
||||
if (!this.sampleDataProviderContext) {
|
||||
throw new Error('#registerSampleDataSet called before #setup');
|
||||
}
|
||||
let value: SampleDatasetSchema;
|
||||
try {
|
||||
value = sampleDataSchema.validate(specProvider());
|
||||
value = sampleDataSchema.validate(specProvider(this.sampleDataProviderContext));
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to register sample dataset spec because it's invalid. ${error}`);
|
||||
}
|
||||
|
@ -83,6 +88,10 @@ export class SampleDataRegistry {
|
|||
createInstallRoute(router, this.sampleDatasets, logger, usageTracker, core.analytics);
|
||||
createUninstallRoute(router, this.sampleDatasets, logger, usageTracker, core.analytics);
|
||||
|
||||
this.sampleDataProviderContext = {
|
||||
staticAssets: core.http.staticAssets,
|
||||
};
|
||||
|
||||
this.registerSampleDataSet(flightsSpecProvider);
|
||||
this.registerSampleDataSet(logsSpecProvider);
|
||||
this.registerSampleDataSet(ecommerceSpecProvider);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaRequest } from '@kbn/core/server';
|
||||
import type { KibanaRequest, IStaticAssets } from '@kbn/core/server';
|
||||
import type { TutorialSchema } from './tutorial_schema';
|
||||
export { TutorialsCategory } from '../../../../common/constants';
|
||||
|
||||
|
@ -25,6 +25,7 @@ export type Platform = 'WINDOWS' | 'OSX' | 'DEB' | 'RPM';
|
|||
|
||||
export interface TutorialContext {
|
||||
kibanaBranch: string;
|
||||
staticAssets: IStaticAssets;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
export type TutorialProvider = (context: TutorialContext) => TutorialSchema;
|
||||
|
|
|
@ -166,10 +166,9 @@ describe('TutorialsRegistry', () => {
|
|||
|
||||
describe('start', () => {
|
||||
test('exposes proper contract', () => {
|
||||
const start = new TutorialsRegistry(mockInitContext).start(
|
||||
coreMock.createStart(),
|
||||
mockCustomIntegrationsPluginSetup
|
||||
);
|
||||
const registry = new TutorialsRegistry(mockInitContext);
|
||||
registry.setup(mockCoreSetup, mockCustomIntegrationsPluginSetup);
|
||||
const start = registry.start(coreMock.createStart(), mockCustomIntegrationsPluginSetup);
|
||||
expect(start).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/core/server';
|
||||
import { CoreSetup, CoreStart, PluginInitializerContext, IStaticAssets } from '@kbn/core/server';
|
||||
import { CustomIntegrationsPluginSetup } from '@kbn/custom-integrations-plugin/server';
|
||||
import { IntegrationCategory } from '@kbn/custom-integrations-plugin/common';
|
||||
import {
|
||||
|
@ -71,10 +71,13 @@ function registerBeatsTutorialsWithCustomIntegrations(
|
|||
export class TutorialsRegistry {
|
||||
private tutorialProviders: TutorialProvider[] = []; // pre-register all the tutorials we know we want in here
|
||||
private readonly scopedTutorialContextFactories: TutorialContextFactory[] = [];
|
||||
private staticAssets!: IStaticAssets;
|
||||
|
||||
constructor(private readonly initContext: PluginInitializerContext) {}
|
||||
|
||||
public setup(core: CoreSetup, customIntegrations?: CustomIntegrationsPluginSetup) {
|
||||
this.staticAssets = core.http.staticAssets;
|
||||
|
||||
const router = core.http.createRouter();
|
||||
router.get(
|
||||
{ path: '/api/kibana/home/tutorials', validate: false },
|
||||
|
@ -143,7 +146,10 @@ export class TutorialsRegistry {
|
|||
}
|
||||
|
||||
private get baseTutorialContext(): TutorialContext {
|
||||
return { kibanaBranch: this.initContext.env.packageInfo.branch };
|
||||
return {
|
||||
kibanaBranch: this.initContext.env.packageInfo.branch,
|
||||
staticAssets: this.staticAssets,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ export function activemqLogsSpecProvider(context: TutorialContext): TutorialSche
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-activemq.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/activemq.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/activemq.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ export function activemqLogsSpecProvider(context: TutorialContext): TutorialSche
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/activemq_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/activemq_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -38,7 +38,7 @@ export function activemqMetricsSpecProvider(context: TutorialContext): TutorialS
|
|||
learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-activemq.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/activemq.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/activemq.svg'),
|
||||
isBeta: true,
|
||||
artifacts: {
|
||||
application: {
|
||||
|
|
|
@ -55,7 +55,7 @@ export function apacheLogsSpecProvider(context: TutorialContext): TutorialSchema
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/apache_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/apache_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -54,7 +54,7 @@ export function apacheMetricsSpecProvider(context: TutorialContext): TutorialSch
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/apache_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/apache_metrics/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -54,7 +54,7 @@ processes, users, logins, sockets information, file accesses, and more. \
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/auditbeat/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/auditbeat/screenshot.webp'),
|
||||
onPrem: onPremInstructions(platforms, context),
|
||||
elasticCloud: cloudInstructions(platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(platforms, context),
|
||||
|
|
|
@ -39,7 +39,7 @@ export function auditdLogsSpecProvider(context: TutorialContext): TutorialSchema
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-auditd.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/linux.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/linux.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ export function auditdLogsSpecProvider(context: TutorialContext): TutorialSchema
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/auditd_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/auditd_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -55,7 +55,7 @@ export function awsLogsSpecProvider(context: TutorialContext): TutorialSchema {
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/aws_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/aws_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -56,7 +56,7 @@ export function awsMetricsSpecProvider(context: TutorialContext): TutorialSchema
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/aws_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/aws_metrics/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -56,7 +56,7 @@ export function azureLogsSpecProvider(context: TutorialContext): TutorialSchema
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/azure_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/azure_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -55,7 +55,7 @@ export function azureMetricsSpecProvider(context: TutorialContext): TutorialSche
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/azure_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/azure_metrics/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -40,7 +40,7 @@ export function barracudaLogsSpecProvider(context: TutorialContext): TutorialSch
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-barracuda.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/barracuda.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/barracuda.svg'),
|
||||
artifacts: {
|
||||
dashboards: [],
|
||||
application: {
|
||||
|
|
|
@ -39,7 +39,7 @@ export function checkpointLogsSpecProvider(context: TutorialContext): TutorialSc
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-checkpoint.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/checkpoint.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/checkpoint.svg'),
|
||||
artifacts: {
|
||||
dashboards: [],
|
||||
application: {
|
||||
|
|
|
@ -39,7 +39,7 @@ export function ciscoLogsSpecProvider(context: TutorialContext): TutorialSchema
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-cisco.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/cisco.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/cisco.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ export function ciscoLogsSpecProvider(context: TutorialContext): TutorialSchema
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/cisco_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/cisco_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -38,7 +38,7 @@ export function cockroachdbMetricsSpecProvider(context: TutorialContext): Tutori
|
|||
learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-cockroachdb.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/cockroachdb.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/cockroachdb.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -57,7 +57,9 @@ export function cockroachdbMetricsSpecProvider(context: TutorialContext): Tutori
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/cockroachdb_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref(
|
||||
'/cockroachdb_metrics/screenshot.webp'
|
||||
),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -38,7 +38,7 @@ export function consulMetricsSpecProvider(context: TutorialContext): TutorialSch
|
|||
learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-consul.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/consul.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/consul.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ export function consulMetricsSpecProvider(context: TutorialContext): TutorialSch
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/consul_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/consul_metrics/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -39,7 +39,7 @@ export function corednsLogsSpecProvider(context: TutorialContext): TutorialSchem
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-coredns.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/coredns.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/coredns.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ export function corednsLogsSpecProvider(context: TutorialContext): TutorialSchem
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/coredns_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/coredns_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -38,7 +38,7 @@ export function corednsMetricsSpecProvider(context: TutorialContext): TutorialSc
|
|||
learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-coredns.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/coredns.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/coredns.svg'),
|
||||
artifacts: {
|
||||
application: {
|
||||
label: i18n.translate('home.tutorials.corednsMetrics.artifacts.application.label', {
|
||||
|
@ -52,7 +52,7 @@ export function corednsMetricsSpecProvider(context: TutorialContext): TutorialSc
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/coredns_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/coredns_metrics/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -38,7 +38,7 @@ export function couchdbMetricsSpecProvider(context: TutorialContext): TutorialSc
|
|||
learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-couchdb.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/couchdb.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/couchdb.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ export function couchdbMetricsSpecProvider(context: TutorialContext): TutorialSc
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/couchdb_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/couchdb_metrics/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -43,7 +43,7 @@ export function crowdstrikeLogsSpecProvider(context: TutorialContext): TutorialS
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-crowdstrike.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/crowdstrike.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/crowdstrike.svg'),
|
||||
artifacts: {
|
||||
dashboards: [],
|
||||
application: {
|
||||
|
|
|
@ -39,7 +39,7 @@ export function cylanceLogsSpecProvider(context: TutorialContext): TutorialSchem
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-cylance.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/cylance.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/cylance.svg'),
|
||||
artifacts: {
|
||||
dashboards: [],
|
||||
application: {
|
||||
|
|
|
@ -54,7 +54,7 @@ export function dockerMetricsSpecProvider(context: TutorialContext): TutorialSch
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/docker_metrics/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/docker_metrics/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, context),
|
||||
elasticCloud: cloudInstructions(moduleName, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, context),
|
||||
|
|
|
@ -54,7 +54,9 @@ export function elasticsearchLogsSpecProvider(context: TutorialContext): Tutoria
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/elasticsearch_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref(
|
||||
'/elasticsearch_logs/screenshot.webp'
|
||||
),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -39,7 +39,7 @@ export function envoyproxyLogsSpecProvider(context: TutorialContext): TutorialSc
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-envoyproxy.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/envoyproxy.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/envoyproxy.svg'),
|
||||
artifacts: {
|
||||
dashboards: [
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ export function envoyproxyLogsSpecProvider(context: TutorialContext): TutorialSc
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/envoyproxy_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/envoyproxy_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
|
@ -38,7 +38,7 @@ export function envoyproxyMetricsSpecProvider(context: TutorialContext): Tutoria
|
|||
learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-envoyproxy.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/envoyproxy.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/envoyproxy.svg'),
|
||||
artifacts: {
|
||||
dashboards: [],
|
||||
exportedFields: {
|
||||
|
|
|
@ -39,7 +39,7 @@ export function f5LogsSpecProvider(context: TutorialContext): TutorialSchema {
|
|||
learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-f5.html',
|
||||
},
|
||||
}),
|
||||
euiIconType: '/plugins/home/assets/logos/f5.svg',
|
||||
euiIconType: context.staticAssets.getPluginAssetHref('/logos/f5.svg'),
|
||||
artifacts: {
|
||||
dashboards: [],
|
||||
application: {
|
||||
|
@ -53,7 +53,7 @@ export function f5LogsSpecProvider(context: TutorialContext): TutorialSchema {
|
|||
},
|
||||
},
|
||||
completionTimeMinutes: 10,
|
||||
previewImagePath: '/plugins/home/assets/f5_logs/screenshot.webp',
|
||||
previewImagePath: context.staticAssets.getPluginAssetHref('/f5_logs/screenshot.webp'),
|
||||
onPrem: onPremInstructions(moduleName, platforms, context),
|
||||
elasticCloud: cloudInstructions(moduleName, platforms, context),
|
||||
onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue