mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Migrate graph server and licensing handling (#52279)
This commit is contained in:
parent
28e81f2b49
commit
c73f984e7f
34 changed files with 419 additions and 503 deletions
|
@ -69,6 +69,7 @@ export interface LegacyPluginOptions {
|
|||
noParse: string[];
|
||||
home: string[];
|
||||
mappings: any;
|
||||
migrations: any;
|
||||
savedObjectSchemas: SavedObjectsSchemaDefinition;
|
||||
savedObjectsManagement: SavedObjectsManagementDefinition;
|
||||
visTypes: string[];
|
||||
|
|
|
@ -32,6 +32,7 @@ import { DevToolsSetup, DevToolsStart } from '../../../../plugins/dev_tools/publ
|
|||
import { KibanaLegacySetup, KibanaLegacyStart } from '../../../../plugins/kibana_legacy/public';
|
||||
import { HomePublicPluginSetup, HomePublicPluginStart } from '../../../../plugins/home/public';
|
||||
import { SharePluginSetup, SharePluginStart } from '../../../../plugins/share/public';
|
||||
import { LicensingPluginSetup } from '../../../../../x-pack/plugins/licensing/common/types';
|
||||
|
||||
export interface PluginsSetup {
|
||||
data: ReturnType<DataPlugin['setup']>;
|
||||
|
@ -43,6 +44,7 @@ export interface PluginsSetup {
|
|||
dev_tools: DevToolsSetup;
|
||||
kibana_legacy: KibanaLegacySetup;
|
||||
share: SharePluginSetup;
|
||||
licensing: LicensingPluginSetup;
|
||||
}
|
||||
|
||||
export interface PluginsStart {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"xpack.endpoint": "plugins/endpoint",
|
||||
"xpack.features": "plugins/features",
|
||||
"xpack.fileUpload": "legacy/plugins/file_upload",
|
||||
"xpack.graph": "legacy/plugins/graph",
|
||||
"xpack.graph": ["legacy/plugins/graph", "plugins/graph"],
|
||||
"xpack.grokDebugger": "legacy/plugins/grokdebugger",
|
||||
"xpack.idxMgmt": "legacy/plugins/index_management",
|
||||
"xpack.indexLifecycleMgmt": "legacy/plugins/index_lifecycle_management",
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
import { resolve } from 'path';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
// @ts-ignore
|
||||
import migrations from './migrations';
|
||||
import { initServer } from './server';
|
||||
import mappings from './mappings.json';
|
||||
import { LegacyPluginInitializer } from '../../../../src/legacy/plugin_discovery/types';
|
||||
|
||||
export function graph(kibana) {
|
||||
export const graph: LegacyPluginInitializer = kibana => {
|
||||
return new kibana.Plugin({
|
||||
id: 'graph',
|
||||
configPrefix: 'xpack.graph',
|
||||
|
@ -26,17 +27,17 @@ export function graph(kibana) {
|
|||
main: 'plugins/graph/index',
|
||||
},
|
||||
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
||||
hacks: ['plugins/graph/hacks/toggle_app_link_in_nav'],
|
||||
home: ['plugins/graph/register_feature'],
|
||||
mappings,
|
||||
migrations,
|
||||
},
|
||||
|
||||
config(Joi) {
|
||||
config(Joi: any) {
|
||||
return Joi.object({
|
||||
enabled: Joi.boolean().default(true),
|
||||
canEditDrillDownUrls: Joi.boolean().default(true),
|
||||
savePolicy: Joi.string().valid(['config', 'configAndDataWithConsent', 'configAndData', 'none']).default('configAndData'),
|
||||
savePolicy: Joi.string()
|
||||
.valid(['config', 'configAndDataWithConsent', 'configAndData', 'none'])
|
||||
.default('configAndData'),
|
||||
}).default();
|
||||
},
|
||||
|
||||
|
@ -45,7 +46,7 @@ export function graph(kibana) {
|
|||
const config = server.config();
|
||||
return {
|
||||
graphSavePolicy: config.get('xpack.graph.savePolicy'),
|
||||
canEditDrillDownUrls: config.get('xpack.graph.canEditDrillDownUrls')
|
||||
canEditDrillDownUrls: config.get('xpack.graph.canEditDrillDownUrls'),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -72,11 +73,9 @@ export function graph(kibana) {
|
|||
read: ['index-pattern', 'graph-workspace'],
|
||||
},
|
||||
ui: [],
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
initServer(server);
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
|
@ -13,7 +13,6 @@ import { isColorDark, hexToRgb } from '@elastic/eui';
|
|||
|
||||
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
|
||||
import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
|
||||
import { addAppRedirectMessageToUrl } from 'ui/notify';
|
||||
|
||||
import appTemplate from './angular/templates/index.html';
|
||||
import listingTemplate from './angular/templates/listing_ng_wrapper.html';
|
||||
|
@ -39,10 +38,10 @@ import {
|
|||
hasFieldsSelector
|
||||
} from './state_management';
|
||||
import { formatHttpError } from './helpers/format_http_error';
|
||||
import { checkLicense } from '../../../../plugins/graph/common/check_license';
|
||||
|
||||
export function initGraphApp(angularModule, deps) {
|
||||
const {
|
||||
xpackInfo,
|
||||
chrome,
|
||||
savedGraphWorkspaces,
|
||||
toastNotifications,
|
||||
|
@ -63,17 +62,6 @@ export function initGraphApp(angularModule, deps) {
|
|||
|
||||
const app = angularModule;
|
||||
|
||||
function checkLicense(kbnBaseUrl) {
|
||||
const licenseAllowsToShowThisPage = xpackInfo.get('features.graph.showAppLink') &&
|
||||
xpackInfo.get('features.graph.enableAppLink');
|
||||
if (!licenseAllowsToShowThisPage) {
|
||||
const message = xpackInfo.get('features.graph.message');
|
||||
const newUrl = addAppRedirectMessageToUrl(addBasePath(kbnBaseUrl), message);
|
||||
window.location.href = newUrl;
|
||||
throw new Error('Graph license error');
|
||||
}
|
||||
}
|
||||
|
||||
app.directive('vennDiagram', function (reactDirective) {
|
||||
return reactDirective(VennDiagram);
|
||||
});
|
||||
|
@ -123,7 +111,6 @@ export function initGraphApp(angularModule, deps) {
|
|||
template: listingTemplate,
|
||||
badge: getReadonlyBadge,
|
||||
controller($location, $scope) {
|
||||
checkLicense(kbnBaseUrl);
|
||||
const services = savedObjectRegistry.byLoaderPropertiesName;
|
||||
const graphService = services['Graph workspace'];
|
||||
|
||||
|
@ -164,7 +151,6 @@ export function initGraphApp(angularModule, deps) {
|
|||
) : savedGraphWorkspaces.get();
|
||||
|
||||
},
|
||||
//Copied from example found in wizard.js ( Kibana TODO - can't
|
||||
indexPatterns: function () {
|
||||
return savedObjectsClient.find({
|
||||
type: 'index-pattern',
|
||||
|
@ -185,10 +171,8 @@ export function initGraphApp(angularModule, deps) {
|
|||
|
||||
//======== Controller for basic UI ==================
|
||||
app.controller('graphuiPlugin', function ($scope, $route, $location, confirmModal) {
|
||||
checkLicense(kbnBaseUrl);
|
||||
|
||||
function handleError(err) {
|
||||
checkLicense(kbnBaseUrl);
|
||||
const toastTitle = i18n.translate('xpack.graph.errorToastTitle', {
|
||||
defaultMessage: 'Graph Error',
|
||||
description: '"Graph" is a product name and should not be translated.',
|
||||
|
@ -206,7 +190,6 @@ export function initGraphApp(angularModule, deps) {
|
|||
}
|
||||
|
||||
async function handleHttpError(error) {
|
||||
checkLicense(kbnBaseUrl);
|
||||
toastNotifications.addDanger(formatHttpError(error));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
|
||||
|
||||
const navLinkUpdates = {};
|
||||
navLinkUpdates.hidden = true;
|
||||
const showAppLink = xpackInfo.get('features.graph.showAppLink', false);
|
||||
navLinkUpdates.hidden = !showAppLink;
|
||||
if (showAppLink) {
|
||||
navLinkUpdates.disabled = !xpackInfo.get('features.graph.enableAppLink', false);
|
||||
navLinkUpdates.tooltip = xpackInfo.get('features.graph.message');
|
||||
}
|
||||
|
||||
npStart.core.chrome.navLinks.update('graph', navLinkUpdates);
|
|
@ -12,8 +12,6 @@ import 'ui/autoload/all';
|
|||
import chrome from 'ui/chrome';
|
||||
import { IPrivate } from 'ui/private';
|
||||
// @ts-ignore
|
||||
import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
|
||||
// @ts-ignore
|
||||
import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
|
||||
|
||||
import { npSetup, npStart } from 'ui/new_platform';
|
||||
|
@ -45,9 +43,9 @@ async function getAngularInjectedDependencies(): Promise<LegacyAngularInjectedDe
|
|||
const instance = new GraphPlugin();
|
||||
instance.setup(npSetup.core, {
|
||||
__LEGACY: {
|
||||
xpackInfo,
|
||||
Storage,
|
||||
},
|
||||
...npSetup.plugins,
|
||||
});
|
||||
instance.start(npStart.core, {
|
||||
npData: npStart.plugins.data,
|
||||
|
|
|
@ -9,6 +9,7 @@ import { CoreSetup, CoreStart, Plugin, SavedObjectsClientContract } from 'src/co
|
|||
import { Plugin as DataPlugin } from 'src/plugins/data/public';
|
||||
import { LegacyAngularInjectedDependencies } from './render_app';
|
||||
import { NavigationStart } from '../../../../../src/legacy/core_plugins/navigation/public';
|
||||
import { LicensingPluginSetup } from '../../../../plugins/licensing/common/types';
|
||||
|
||||
export interface GraphPluginStartDependencies {
|
||||
npData: ReturnType<DataPlugin['start']>;
|
||||
|
@ -18,8 +19,8 @@ export interface GraphPluginStartDependencies {
|
|||
export interface GraphPluginSetupDependencies {
|
||||
__LEGACY: {
|
||||
Storage: any;
|
||||
xpackInfo: any;
|
||||
};
|
||||
licensing: LicensingPluginSetup;
|
||||
}
|
||||
|
||||
export interface GraphPluginStartDependencies {
|
||||
|
@ -34,7 +35,7 @@ export class GraphPlugin implements Plugin {
|
|||
private savedObjectsClient: SavedObjectsClientContract | null = null;
|
||||
private angularDependencies: LegacyAngularInjectedDependencies | null = null;
|
||||
|
||||
setup(core: CoreSetup, { __LEGACY: { xpackInfo, Storage } }: GraphPluginSetupDependencies) {
|
||||
setup(core: CoreSetup, { __LEGACY: { Storage }, licensing }: GraphPluginSetupDependencies) {
|
||||
core.application.register({
|
||||
id: 'graph',
|
||||
title: 'Graph',
|
||||
|
@ -42,10 +43,10 @@ export class GraphPlugin implements Plugin {
|
|||
const { renderApp } = await import('./render_app');
|
||||
return renderApp({
|
||||
...params,
|
||||
licensing,
|
||||
navigation: this.navigationStart!,
|
||||
npData: this.npDataStart!,
|
||||
savedObjectsClient: this.savedObjectsClient!,
|
||||
xpackInfo,
|
||||
addBasePath: core.http.basePath.prepend,
|
||||
getBasePath: core.http.basePath.get,
|
||||
canEditDrillDownUrls: core.injectedMetadata.getInjectedVar(
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
FeatureCatalogueRegistryProvider.register(() => {
|
||||
return {
|
||||
id: 'graph',
|
||||
title: 'Graph',
|
||||
description: i18n.translate('xpack.graph.pluginDescription', {
|
||||
defaultMessage: 'Surface and analyze relevant relationships in your Elasticsearch data.',
|
||||
}),
|
||||
icon: 'graphApp',
|
||||
path: '/app/graph',
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.DATA
|
||||
};
|
||||
});
|
|
@ -19,6 +19,8 @@ import { configureAppAngularModule } from 'ui/legacy_compat';
|
|||
import { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav';
|
||||
// @ts-ignore
|
||||
import { confirmModalFactory } from 'ui/modals/confirm_modal';
|
||||
// @ts-ignore
|
||||
import { addAppRedirectMessageToUrl } from 'ui/notify';
|
||||
|
||||
// type imports
|
||||
import {
|
||||
|
@ -36,6 +38,8 @@ import {
|
|||
IndexPatternsContract,
|
||||
} from '../../../../../src/plugins/data/public';
|
||||
import { NavigationStart } from '../../../../../src/legacy/core_plugins/navigation/public';
|
||||
import { LicensingPluginSetup } from '../../../../plugins/licensing/common/types';
|
||||
import { checkLicense } from '../../../../plugins/graph/common/check_license';
|
||||
|
||||
/**
|
||||
* These are dependencies of the Graph app besides the base dependencies
|
||||
|
@ -49,13 +53,13 @@ export interface GraphDependencies extends LegacyAngularInjectedDependencies {
|
|||
capabilities: Record<string, boolean | Record<string, boolean>>;
|
||||
coreStart: AppMountContext['core'];
|
||||
navigation: NavigationStart;
|
||||
licensing: LicensingPluginSetup;
|
||||
chrome: ChromeStart;
|
||||
config: IUiSettingsClient;
|
||||
toastNotifications: ToastsStart;
|
||||
indexPatterns: IndexPatternsContract;
|
||||
npData: ReturnType<DataPlugin['start']>;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
xpackInfo: { get(path: string): unknown };
|
||||
addBasePath: (url: string) => string;
|
||||
getBasePath: () => string;
|
||||
Storage: any;
|
||||
|
@ -82,9 +86,23 @@ export interface LegacyAngularInjectedDependencies {
|
|||
export const renderApp = ({ appBasePath, element, ...deps }: GraphDependencies) => {
|
||||
const graphAngularModule = createLocalAngularModule(deps.navigation);
|
||||
configureAppAngularModule(graphAngularModule, deps.coreStart as LegacyCoreStart, true);
|
||||
|
||||
const licenseSubscription = deps.licensing.license$.subscribe(license => {
|
||||
const info = checkLicense(license);
|
||||
const licenseAllowsToShowThisPage = info.showAppLink && info.enableAppLink;
|
||||
|
||||
if (!licenseAllowsToShowThisPage) {
|
||||
const newUrl = addAppRedirectMessageToUrl(deps.addBasePath(deps.kbnBaseUrl), info.message);
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
});
|
||||
|
||||
initGraphApp(graphAngularModule, deps);
|
||||
const $injector = mountGraphApp(appBasePath, element);
|
||||
return () => $injector.get('$rootScope').$destroy();
|
||||
return () => {
|
||||
licenseSubscription.unsubscribe();
|
||||
$injector.get('$rootScope').$destroy();
|
||||
};
|
||||
};
|
||||
|
||||
const mainTemplate = (basePath: string) => `<div style="height: 100%">
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Boom from 'boom';
|
||||
|
||||
import { mirrorPluginStatus } from '../../../server/lib/mirror_plugin_status';
|
||||
import { checkLicense } from './lib';
|
||||
import { graphExploreRoute, searchProxyRoute } from './routes';
|
||||
|
||||
export function initServer(server) {
|
||||
const graphPlugin = server.plugins.graph;
|
||||
const xpackMainPlugin = server.plugins.xpack_main;
|
||||
|
||||
mirrorPluginStatus(xpackMainPlugin, graphPlugin);
|
||||
xpackMainPlugin.status.once('green', () => {
|
||||
// Register a function that is called whenever the xpack info changes,
|
||||
// to re-compute the license check results
|
||||
xpackMainPlugin.info.feature('graph').registerLicenseCheckResultsGenerator(checkLicense);
|
||||
});
|
||||
|
||||
server.route(graphExploreRoute);
|
||||
server.route(searchProxyRoute);
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { set } from 'lodash';
|
||||
import sinon from 'sinon';
|
||||
import { checkLicense } from '../check_license';
|
||||
|
||||
describe('check_license: ', function () {
|
||||
|
||||
let mockLicenseInfo;
|
||||
let licenseCheckResult;
|
||||
|
||||
beforeEach(() => {
|
||||
mockLicenseInfo = {
|
||||
isAvailable: () => true
|
||||
};
|
||||
});
|
||||
|
||||
describe('mockLicenseInfo is not set', () => {
|
||||
beforeEach(() => {
|
||||
mockLicenseInfo = null;
|
||||
licenseCheckResult = checkLicense(mockLicenseInfo);
|
||||
});
|
||||
|
||||
it ('should set showAppLink to true', () => {
|
||||
expect(licenseCheckResult.showAppLink).to.be(true);
|
||||
});
|
||||
|
||||
it ('should set enableAppLink to false', () => {
|
||||
expect(licenseCheckResult.enableAppLink).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mockLicenseInfo is set but not available', () => {
|
||||
beforeEach(() => {
|
||||
mockLicenseInfo = { isAvailable: () => false };
|
||||
licenseCheckResult = checkLicense(mockLicenseInfo);
|
||||
});
|
||||
|
||||
it ('should set showAppLink to true', () => {
|
||||
expect(licenseCheckResult.showAppLink).to.be(true);
|
||||
});
|
||||
|
||||
it ('should set enableAppLink to false', () => {
|
||||
expect(licenseCheckResult.enableAppLink).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('graph is disabled in Elasticsearch', () => {
|
||||
beforeEach(() => {
|
||||
set(mockLicenseInfo, 'feature', sinon.stub().withArgs('graph').returns({ isEnabled: () => false }));
|
||||
licenseCheckResult = checkLicense(mockLicenseInfo);
|
||||
});
|
||||
|
||||
it ('should set showAppLink to false', () => {
|
||||
expect(licenseCheckResult.showAppLink).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('graph is enabled in Elasticsearch', () => {
|
||||
beforeEach(() => {
|
||||
set(mockLicenseInfo, 'feature', sinon.stub().withArgs('graph').returns({ isEnabled: () => true }));
|
||||
});
|
||||
|
||||
describe('& license is trial or platinum', () => {
|
||||
beforeEach(() => {
|
||||
set(mockLicenseInfo, 'license.isOneOf', sinon.stub().withArgs([ 'trial', 'platinum' ]).returns(true));
|
||||
set(mockLicenseInfo, 'license.getType', () => 'trial');
|
||||
});
|
||||
|
||||
describe('& license is active', () => {
|
||||
beforeEach(() => {
|
||||
set(mockLicenseInfo, 'license.isActive', () => true);
|
||||
licenseCheckResult = checkLicense(mockLicenseInfo);
|
||||
});
|
||||
|
||||
it ('should set showAppLink to true', () => {
|
||||
expect(licenseCheckResult.showAppLink).to.be(true);
|
||||
});
|
||||
|
||||
it ('should set enableAppLink to true', () => {
|
||||
expect(licenseCheckResult.enableAppLink).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('& license is expired', () => {
|
||||
beforeEach(() => {
|
||||
set(mockLicenseInfo, 'license.isActive', () => false);
|
||||
licenseCheckResult = checkLicense(mockLicenseInfo);
|
||||
});
|
||||
|
||||
it ('should set showAppLink to true', () => {
|
||||
expect(licenseCheckResult.showAppLink).to.be(true);
|
||||
});
|
||||
|
||||
it ('should set enableAppLink to false', () => {
|
||||
expect(licenseCheckResult.enableAppLink).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('& license is neither trial nor platinum', () => {
|
||||
beforeEach(() => {
|
||||
set(mockLicenseInfo, 'license.isOneOf', () => false);
|
||||
set(mockLicenseInfo, 'license.getType', () => 'basic');
|
||||
set(mockLicenseInfo, 'license.isActive', () => true);
|
||||
licenseCheckResult = checkLicense(mockLicenseInfo);
|
||||
});
|
||||
|
||||
it ('should set showAppLink to false', () => {
|
||||
expect(licenseCheckResult.showAppLink).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function checkLicense(xpackLicenseInfo) {
|
||||
|
||||
if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) {
|
||||
return {
|
||||
showAppLink: true,
|
||||
enableAppLink: false,
|
||||
message: i18n.translate('xpack.graph.serverSideErrors.unavailableLicenseInformationErrorMessage', {
|
||||
defaultMessage: 'Graph is unavailable - license information is not available at this time.',
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
const graphFeature = xpackLicenseInfo.feature('graph');
|
||||
if (!graphFeature.isEnabled()) {
|
||||
return {
|
||||
showAppLink: false,
|
||||
enableAppLink: false,
|
||||
message: i18n.translate('xpack.graph.serverSideErrors.unavailableGraphErrorMessage', {
|
||||
defaultMessage: 'Graph is unavailable',
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
const isLicenseActive = xpackLicenseInfo.license.isActive();
|
||||
let message;
|
||||
if (!isLicenseActive) {
|
||||
message = i18n.translate('xpack.graph.serverSideErrors.expiredLicenseErrorMessage', {
|
||||
defaultMessage: 'Graph is unavailable - license has expired.',
|
||||
});
|
||||
}
|
||||
|
||||
if (xpackLicenseInfo.license.isOneOf([ 'trial', 'platinum' ])) {
|
||||
return {
|
||||
showAppLink: true,
|
||||
enableAppLink: isLicenseActive,
|
||||
message
|
||||
};
|
||||
}
|
||||
|
||||
message = i18n.translate('xpack.graph.serverSideErrors.wrongLicenseTypeErrorMessage', {
|
||||
defaultMessage: 'Graph is unavailable for the current {licenseType} license. Please upgrade your license.',
|
||||
values: {
|
||||
licenseType: xpackLicenseInfo.license.getType(),
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
showAppLink: false,
|
||||
enableAppLink: false,
|
||||
message
|
||||
};
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Boom from 'boom';
|
||||
import { get } from 'lodash';
|
||||
|
||||
export async function callEsGraphExploreApi({ callCluster, index, query }) {
|
||||
try {
|
||||
return {
|
||||
ok: true,
|
||||
resp: await callCluster('transport.request', {
|
||||
'path': '/' + encodeURIComponent(index) + '/_graph/explore',
|
||||
body: query,
|
||||
method: 'POST',
|
||||
query: {}
|
||||
})
|
||||
};
|
||||
} catch (error) {
|
||||
// Extract known reasons for bad choice of field
|
||||
const relevantCause = [].concat(get(error, 'body.error.root_cause', []) || [])
|
||||
.find(cause => {
|
||||
return (
|
||||
cause.reason.includes('Fielddata is disabled on text fields') ||
|
||||
cause.reason.includes('No support for examining floating point') ||
|
||||
cause.reason.includes('Sample diversifying key must be a single valued-field') ||
|
||||
cause.reason.includes('Failed to parse query') ||
|
||||
cause.type == 'parsing_exception'
|
||||
);
|
||||
});
|
||||
|
||||
if (relevantCause) {
|
||||
throw Boom.badRequest(relevantCause.reason);
|
||||
}
|
||||
|
||||
throw Boom.boomify(error);
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Boom from 'boom';
|
||||
|
||||
export async function callEsSearchApi({ callCluster, index, body, queryParams }) {
|
||||
try {
|
||||
return {
|
||||
ok: true,
|
||||
resp: await callCluster('search', {
|
||||
...queryParams,
|
||||
index,
|
||||
body
|
||||
})
|
||||
};
|
||||
} catch (error) {
|
||||
throw Boom.boomify(error, { statusCode: error.statusCode || 500 });
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { callEsSearchApi } from './call_es_search_api';
|
||||
export { callEsGraphExploreApi } from './call_es_graph_explore_api';
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { checkLicense } from './check_license';
|
||||
|
||||
export {
|
||||
callEsGraphExploreApi,
|
||||
callEsSearchApi,
|
||||
} from './es';
|
||||
|
||||
export {
|
||||
getCallClusterPre,
|
||||
verifyApiAccessPre,
|
||||
} from './pre';
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const getCallClusterPre = {
|
||||
assign: 'callCluster',
|
||||
method(request) {
|
||||
const cluster = request.server.plugins.elasticsearch.getCluster('data');
|
||||
return (...args) => cluster.callWithRequest(request, ...args);
|
||||
}
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { getCallClusterPre } from './get_call_cluster_pre';
|
||||
export { verifyApiAccessPre } from './verify_api_access_pre';
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Boom from 'boom';
|
||||
|
||||
export function verifyApiAccessPre(request, h) {
|
||||
const xpackInfo = request.server.plugins.xpack_main.info;
|
||||
const graph = xpackInfo.feature('graph');
|
||||
const licenseCheckResults = graph.getLicenseCheckResults();
|
||||
|
||||
if (licenseCheckResults.showAppLink && licenseCheckResults.enableAppLink) {
|
||||
return null;
|
||||
} else {
|
||||
throw Boom.forbidden(licenseCheckResults.message);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
|
||||
import {
|
||||
verifyApiAccessPre,
|
||||
getCallClusterPre,
|
||||
callEsGraphExploreApi,
|
||||
} from '../lib';
|
||||
|
||||
export const graphExploreRoute = {
|
||||
path: '/api/graph/graphExplore',
|
||||
method: 'POST',
|
||||
config: {
|
||||
pre: [
|
||||
verifyApiAccessPre,
|
||||
getCallClusterPre,
|
||||
],
|
||||
validate: {
|
||||
payload: Joi.object().keys({
|
||||
index: Joi.string().required(),
|
||||
query: Joi.object().required().unknown(true)
|
||||
}).default()
|
||||
},
|
||||
handler(request) {
|
||||
return callEsGraphExploreApi({
|
||||
callCluster: request.pre.callCluster,
|
||||
index: request.payload.index,
|
||||
query: request.payload.query,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import Boom from 'boom';
|
||||
|
||||
import {
|
||||
verifyApiAccessPre,
|
||||
getCallClusterPre,
|
||||
callEsSearchApi,
|
||||
} from '../lib';
|
||||
|
||||
export const searchProxyRoute = {
|
||||
path: '/api/graph/searchProxy',
|
||||
method: 'POST',
|
||||
config: {
|
||||
pre: [
|
||||
getCallClusterPre,
|
||||
verifyApiAccessPre,
|
||||
],
|
||||
validate: {
|
||||
payload: Joi.object().keys({
|
||||
index: Joi.string().required(),
|
||||
body: Joi.object().unknown(true).default()
|
||||
}).default()
|
||||
},
|
||||
async handler(request) {
|
||||
const includeFrozen = await request.getUiSettingsService().get('search:includeFrozen');
|
||||
return await callEsSearchApi({
|
||||
callCluster: request.pre.callCluster,
|
||||
index: request.payload.index,
|
||||
body: request.payload.body,
|
||||
queryParams: {
|
||||
rest_total_hits_as_int: true,
|
||||
ignore_throttled: !includeFrozen,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
68
x-pack/plugins/graph/common/check_license.ts
Normal file
68
x-pack/plugins/graph/common/check_license.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ILicense, LICENSE_CHECK_STATE } from '../../licensing/common/types';
|
||||
import { assertNever } from '../../../../src/core/utils';
|
||||
|
||||
export interface GraphLicenseInformation {
|
||||
showAppLink: boolean;
|
||||
enableAppLink: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export function checkLicense(license: ILicense | undefined): GraphLicenseInformation {
|
||||
if (!license || !license.isAvailable) {
|
||||
return {
|
||||
showAppLink: true,
|
||||
enableAppLink: false,
|
||||
message: i18n.translate(
|
||||
'xpack.graph.serverSideErrors.unavailableLicenseInformationErrorMessage',
|
||||
{
|
||||
defaultMessage:
|
||||
'Graph is unavailable - license information is not available at this time.',
|
||||
}
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const graphFeature = license.getFeature('graph');
|
||||
if (!graphFeature.isEnabled) {
|
||||
return {
|
||||
showAppLink: false,
|
||||
enableAppLink: false,
|
||||
message: i18n.translate('xpack.graph.serverSideErrors.unavailableGraphErrorMessage', {
|
||||
defaultMessage: 'Graph is unavailable',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
const check = license.check('graph', 'platinum');
|
||||
|
||||
switch (check.state) {
|
||||
case LICENSE_CHECK_STATE.Expired:
|
||||
return {
|
||||
showAppLink: true,
|
||||
enableAppLink: false,
|
||||
message: check.message || '',
|
||||
};
|
||||
case LICENSE_CHECK_STATE.Invalid:
|
||||
case LICENSE_CHECK_STATE.Unavailable:
|
||||
return {
|
||||
showAppLink: false,
|
||||
enableAppLink: false,
|
||||
message: check.message || '',
|
||||
};
|
||||
case LICENSE_CHECK_STATE.Valid:
|
||||
return {
|
||||
showAppLink: true,
|
||||
enableAppLink: true,
|
||||
message: '',
|
||||
};
|
||||
default:
|
||||
return assertNever(check.state);
|
||||
}
|
||||
}
|
9
x-pack/plugins/graph/kibana.json
Normal file
9
x-pack/plugins/graph/kibana.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "graph",
|
||||
"version": "8.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["licensing"],
|
||||
"optionalPlugins": ["home"]
|
||||
}
|
|
@ -4,4 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { initServer } from './init_server';
|
||||
import { GraphPlugin } from './plugin';
|
||||
|
||||
export const plugin = () => new GraphPlugin();
|
54
x-pack/plugins/graph/public/plugin.ts
Normal file
54
x-pack/plugins/graph/public/plugin.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { CoreSetup, CoreStart } from 'kibana/public';
|
||||
import { Plugin } from 'src/core/public';
|
||||
import { toggleNavLink } from './services/toggle_nav_link';
|
||||
import { LicensingPluginSetup } from '../../licensing/common/types';
|
||||
import { checkLicense } from '../common/check_license';
|
||||
import {
|
||||
FeatureCatalogueCategory,
|
||||
HomePublicPluginSetup,
|
||||
} from '../../../../src/plugins/home/public';
|
||||
|
||||
export interface GraphPluginSetupDependencies {
|
||||
licensing: LicensingPluginSetup;
|
||||
home?: HomePublicPluginSetup;
|
||||
}
|
||||
|
||||
export class GraphPlugin implements Plugin {
|
||||
private licensing: LicensingPluginSetup | null = null;
|
||||
|
||||
setup(core: CoreSetup, { licensing, home }: GraphPluginSetupDependencies) {
|
||||
this.licensing = licensing;
|
||||
|
||||
if (home) {
|
||||
home.featureCatalogue.register({
|
||||
id: 'graph',
|
||||
title: 'Graph',
|
||||
description: i18n.translate('xpack.graph.pluginDescription', {
|
||||
defaultMessage: 'Surface and analyze relevant relationships in your Elasticsearch data.',
|
||||
}),
|
||||
icon: 'graphApp',
|
||||
path: '/app/graph',
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.DATA,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
start(core: CoreStart) {
|
||||
if (this.licensing === null) {
|
||||
throw new Error('Start called before setup');
|
||||
}
|
||||
this.licensing.license$.subscribe(license => {
|
||||
toggleNavLink(checkLicense(license), core.chrome.navLinks);
|
||||
});
|
||||
}
|
||||
|
||||
stop() {}
|
||||
}
|
26
x-pack/plugins/graph/public/services/toggle_nav_link.ts
Normal file
26
x-pack/plugins/graph/public/services/toggle_nav_link.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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ChromeNavLink, ChromeNavLinks } from 'kibana/public';
|
||||
import { GraphLicenseInformation } from '../../common/check_license';
|
||||
|
||||
type Mutable<T> = { -readonly [P in keyof T]: T[P] };
|
||||
type ChromeNavLinkUpdate = Mutable<Partial<ChromeNavLink>>;
|
||||
|
||||
export function toggleNavLink(
|
||||
licenseInformation: GraphLicenseInformation,
|
||||
navLinks: ChromeNavLinks
|
||||
) {
|
||||
const navLinkUpdates: ChromeNavLinkUpdate = {
|
||||
hidden: !licenseInformation.showAppLink,
|
||||
};
|
||||
if (licenseInformation.showAppLink) {
|
||||
navLinkUpdates.disabled = !licenseInformation.enableAppLink;
|
||||
navLinkUpdates.tooltip = licenseInformation.message;
|
||||
}
|
||||
|
||||
navLinks.update('graph', navLinkUpdates);
|
||||
}
|
|
@ -4,5 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { graphExploreRoute } from './graph_explore';
|
||||
export { searchProxyRoute } from './search_proxy';
|
||||
import { GraphPlugin } from './plugin';
|
||||
|
||||
export const plugin = () => new GraphPlugin();
|
43
x-pack/plugins/graph/server/lib/license_state.ts
Normal file
43
x-pack/plugins/graph/server/lib/license_state.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Boom from 'boom';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { ILicense } from '../../../licensing/common/types';
|
||||
import { checkLicense, GraphLicenseInformation } from '../../common/check_license';
|
||||
|
||||
export class LicenseState {
|
||||
private licenseInformation: GraphLicenseInformation = checkLicense(undefined);
|
||||
private subscription: Subscription | null = null;
|
||||
|
||||
private updateInformation(license: ILicense | undefined) {
|
||||
this.licenseInformation = checkLicense(license);
|
||||
}
|
||||
|
||||
public start(license$: Observable<ILicense>) {
|
||||
this.subscription = license$.subscribe(this.updateInformation.bind(this));
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
public getLicenseInformation() {
|
||||
return this.licenseInformation;
|
||||
}
|
||||
}
|
||||
|
||||
export function verifyApiAccess(licenseState: LicenseState) {
|
||||
const licenseCheckResults = licenseState.getLicenseInformation();
|
||||
|
||||
if (licenseCheckResults.showAppLink && licenseCheckResults.enableAppLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw Boom.forbidden(licenseCheckResults.message);
|
||||
}
|
32
x-pack/plugins/graph/server/plugin.ts
Normal file
32
x-pack/plugins/graph/server/plugin.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup } from 'src/core/server';
|
||||
import { LicensingPluginSetup } from '../../licensing/common/types';
|
||||
import { LicenseState } from './lib/license_state';
|
||||
import { registerSearchRoute } from './routes/search';
|
||||
import { registerExploreRoute } from './routes/explore';
|
||||
|
||||
export class GraphPlugin implements Plugin {
|
||||
private licenseState: LicenseState | null = null;
|
||||
|
||||
public async setup(core: CoreSetup, { licensing }: { licensing: LicensingPluginSetup }) {
|
||||
const licenseState = new LicenseState();
|
||||
licenseState.start(licensing.license$);
|
||||
this.licenseState = licenseState;
|
||||
|
||||
const router = core.http.createRouter();
|
||||
registerSearchRoute({ licenseState, router });
|
||||
registerExploreRoute({ licenseState, router });
|
||||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {
|
||||
if (this.licenseState) {
|
||||
this.licenseState.stop();
|
||||
}
|
||||
}
|
||||
}
|
79
x-pack/plugins/graph/server/routes/explore.ts
Normal file
79
x-pack/plugins/graph/server/routes/explore.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { IRouter } from 'kibana/server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import Boom from 'boom';
|
||||
import { get } from 'lodash';
|
||||
import { LicenseState, verifyApiAccess } from '../lib/license_state';
|
||||
|
||||
export function registerExploreRoute({
|
||||
router,
|
||||
licenseState,
|
||||
}: {
|
||||
router: IRouter;
|
||||
licenseState: LicenseState;
|
||||
}) {
|
||||
router.post(
|
||||
{
|
||||
path: '/api/graph/graphExplore',
|
||||
validate: {
|
||||
body: schema.object({
|
||||
index: schema.string(),
|
||||
query: schema.object({}, { allowUnknowns: true }),
|
||||
}),
|
||||
},
|
||||
},
|
||||
router.handleLegacyErrors(
|
||||
async (
|
||||
{
|
||||
core: {
|
||||
elasticsearch: {
|
||||
dataClient: { callAsCurrentUser: callCluster },
|
||||
},
|
||||
},
|
||||
},
|
||||
request,
|
||||
response
|
||||
) => {
|
||||
verifyApiAccess(licenseState);
|
||||
try {
|
||||
return response.ok({
|
||||
body: {
|
||||
resp: await callCluster('transport.request', {
|
||||
path: '/' + encodeURIComponent(request.body.index) + '/_graph/explore',
|
||||
body: request.body.query,
|
||||
method: 'POST',
|
||||
query: {},
|
||||
}),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// Extract known reasons for bad choice of field
|
||||
const relevantCause = get(
|
||||
error,
|
||||
'body.error.root_cause',
|
||||
[] as Array<{ type: string; reason: string }>
|
||||
).find(cause => {
|
||||
return (
|
||||
cause.reason.includes('Fielddata is disabled on text fields') ||
|
||||
cause.reason.includes('No support for examining floating point') ||
|
||||
cause.reason.includes('Sample diversifying key must be a single valued-field') ||
|
||||
cause.reason.includes('Failed to parse query') ||
|
||||
cause.type === 'parsing_exception'
|
||||
);
|
||||
});
|
||||
|
||||
if (relevantCause) {
|
||||
throw Boom.badRequest(relevantCause.reason);
|
||||
}
|
||||
|
||||
throw Boom.boomify(error);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
61
x-pack/plugins/graph/server/routes/search.ts
Normal file
61
x-pack/plugins/graph/server/routes/search.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { IRouter } from 'kibana/server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import Boom from 'boom';
|
||||
import { LicenseState, verifyApiAccess } from '../lib/license_state';
|
||||
|
||||
export function registerSearchRoute({
|
||||
router,
|
||||
licenseState,
|
||||
}: {
|
||||
router: IRouter;
|
||||
licenseState: LicenseState;
|
||||
}) {
|
||||
router.post(
|
||||
{
|
||||
path: '/api/graph/searchProxy',
|
||||
validate: {
|
||||
body: schema.object({
|
||||
index: schema.string(),
|
||||
body: schema.object({}, { allowUnknowns: true }),
|
||||
}),
|
||||
},
|
||||
},
|
||||
router.handleLegacyErrors(
|
||||
async (
|
||||
{
|
||||
core: {
|
||||
uiSettings: { client: uiSettings },
|
||||
elasticsearch: {
|
||||
dataClient: { callAsCurrentUser: callCluster },
|
||||
},
|
||||
},
|
||||
},
|
||||
request,
|
||||
response
|
||||
) => {
|
||||
verifyApiAccess(licenseState);
|
||||
const includeFrozen = await uiSettings.get<boolean>('search:includeFrozen');
|
||||
try {
|
||||
return response.ok({
|
||||
body: {
|
||||
resp: await callCluster('search', {
|
||||
index: request.body.index,
|
||||
body: request.body.body,
|
||||
rest_total_hits_as_int: true,
|
||||
ignore_throttled: !includeFrozen,
|
||||
}),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw Boom.boomify(error, { statusCode: error.statusCode || 500 });
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
|
@ -5170,10 +5170,8 @@
|
|||
"xpack.graph.savedWorkspaces.graphWorkspacesLabel": "グラフワークスペース",
|
||||
"xpack.graph.saveWorkspace.successNotification.noDataSavedText": "構成が保存されましたが、データは保存されませんでした",
|
||||
"xpack.graph.saveWorkspace.successNotificationTitle": "「{workspaceTitle}」が保存されました",
|
||||
"xpack.graph.serverSideErrors.expiredLicenseErrorMessage": "グラフを利用できません。ライセンスが期限切れです。",
|
||||
"xpack.graph.serverSideErrors.unavailableGraphErrorMessage": "グラフを利用できません",
|
||||
"xpack.graph.serverSideErrors.unavailableLicenseInformationErrorMessage": "グラフを利用できません。現在ライセンス情報が利用できません。",
|
||||
"xpack.graph.serverSideErrors.wrongLicenseTypeErrorMessage": "現在の {licenseType} ライセンスではグラフを利用できません。ライセンスをアップグレードしてください。",
|
||||
"xpack.graph.settings.advancedSettings.certaintyInputHelpText": "関連用語が登録される前に証拠として必要なドキュメントの最低数です",
|
||||
"xpack.graph.settings.advancedSettings.certaintyInputLabel": "確実性",
|
||||
"xpack.graph.settings.advancedSettings.diversityFieldInputHelpText1": "ドキュメントのサンプルが 1 種類に偏らないように、バイアスの原因の認識に役立つフィールドを選択してください。",
|
||||
|
|
|
@ -5172,10 +5172,8 @@
|
|||
"xpack.graph.savedWorkspaces.graphWorkspacesLabel": "Graph 工作空间",
|
||||
"xpack.graph.saveWorkspace.successNotification.noDataSavedText": "配置会被保存,但不保存数据",
|
||||
"xpack.graph.saveWorkspace.successNotificationTitle": "已保存“{workspaceTitle}”",
|
||||
"xpack.graph.serverSideErrors.expiredLicenseErrorMessage": "Graph 不可用 - 许可已过期。",
|
||||
"xpack.graph.serverSideErrors.unavailableGraphErrorMessage": "Graph 不可用",
|
||||
"xpack.graph.serverSideErrors.unavailableLicenseInformationErrorMessage": "Graph 不可用 - 许可信息当前不可用。",
|
||||
"xpack.graph.serverSideErrors.wrongLicenseTypeErrorMessage": "当前{licenseType}许可的 Graph 不可用。请升级您的许可。",
|
||||
"xpack.graph.settings.advancedSettings.certaintyInputHelpText": "在引入相关字词之前作为证据所需的最小文档数量。",
|
||||
"xpack.graph.settings.advancedSettings.certaintyInputLabel": "确定性",
|
||||
"xpack.graph.settings.advancedSettings.diversityFieldInputHelpText1": "为避免文档示例过于雷同,请选取有助于识别偏差来源的字段。",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue