[NP] Graph migration (#59409) (#60225)

* Move graph to NP

* Styles

* Clean up

* Fix eslint

* Fix ESlint

* Fix path

* Fix container height

* Clean up

* Update index.ts

* Update graph_client_workspace.js

* Refactoring

* Remove unused methods

* Update graph_client_workspace.test.js

* Rename npData to data

* Move Readme

* Inline parsing discover url

* Remove import of legacy styles

* Update README

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Maryia Lapata 2020-03-16 12:34:18 +03:00 committed by GitHub
parent a6f2b2e4f2
commit d78150da17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
121 changed files with 339 additions and 451 deletions

View file

@ -4,31 +4,19 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { resolve } from 'path';
import { i18n } from '@kbn/i18n';
// @ts-ignore
import migrations from './migrations';
import mappings from './mappings.json';
import { LegacyPluginInitializer } from '../../../../src/legacy/plugin_discovery/types';
import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils';
export const graph: LegacyPluginInitializer = kibana => {
return new kibana.Plugin({
id: 'graph',
configPrefix: 'xpack.graph',
publicDir: resolve(__dirname, 'public'),
require: ['kibana', 'elasticsearch', 'xpack_main'],
uiExports: {
app: {
title: 'Graph',
order: 9000,
icon: 'plugins/graph/icon.png',
euiIconType: 'graphApp',
main: 'plugins/graph/index',
category: DEFAULT_APP_CATEGORIES.analyze,
},
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
mappings,
migrations,
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -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 { npSetup, npStart } from 'ui/new_platform';
import { LicensingPluginSetup } from '../../../../plugins/licensing/public';
import { GraphPlugin } from './plugin';
import { GraphSetup } from '../../../../plugins/graph/public';
type XpackNpSetupDeps = typeof npSetup.plugins & {
licensing: LicensingPluginSetup;
graph: GraphSetup;
};
(async () => {
const instance = new GraphPlugin();
instance.setup(npSetup.core, {
...(npSetup.plugins as XpackNpSetupDeps),
});
instance.start(npStart.core, {
npData: npStart.plugins.data,
navigation: npStart.plugins.navigation,
});
})();

View file

@ -1,9 +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 'ace';
export { configureAppAngularModule } from '../../../../../src/plugins/kibana_legacy/public';

View file

@ -1,75 +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.
*/
// NP type imports
import {
AppMountParameters,
CoreSetup,
CoreStart,
Plugin,
SavedObjectsClientContract,
} from 'src/core/public';
import { Plugin as DataPlugin } from 'src/plugins/data/public';
import { Storage } from '../../../../../src/plugins/kibana_utils/public';
import { LicensingPluginSetup } from '../../../../plugins/licensing/public';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../../src/plugins/navigation/public';
import { initAngularBootstrap } from '../../../../../src/plugins/kibana_legacy/public';
import { GraphSetup } from '../../../../plugins/graph/public';
export interface GraphPluginStartDependencies {
npData: ReturnType<DataPlugin['start']>;
navigation: NavigationStart;
}
export interface GraphPluginSetupDependencies {
licensing: LicensingPluginSetup;
graph: GraphSetup;
}
export class GraphPlugin implements Plugin {
private navigationStart: NavigationStart | null = null;
private npDataStart: ReturnType<DataPlugin['start']> | null = null;
private savedObjectsClient: SavedObjectsClientContract | null = null;
setup(core: CoreSetup, { licensing, graph }: GraphPluginSetupDependencies) {
initAngularBootstrap();
core.application.register({
id: 'graph',
title: 'Graph',
mount: async (params: AppMountParameters) => {
const [coreStart] = await core.getStartServices();
const { renderApp } = await import('./application');
return renderApp({
...params,
licensing,
navigation: this.navigationStart!,
npData: this.npDataStart!,
savedObjectsClient: this.savedObjectsClient!,
addBasePath: core.http.basePath.prepend,
getBasePath: core.http.basePath.get,
canEditDrillDownUrls: graph.config.canEditDrillDownUrls,
graphSavePolicy: graph.config.savePolicy,
storage: new Storage(window.localStorage),
capabilities: coreStart.application.capabilities.graph,
coreStart,
chrome: coreStart.chrome,
config: coreStart.uiSettings,
toastNotifications: coreStart.notifications.toasts,
indexPatterns: this.npDataStart!.indexPatterns,
overlays: coreStart.overlays,
});
},
});
}
start(core: CoreStart, { npData, navigation }: GraphPluginStartDependencies) {
this.navigationStart = navigation;
this.npDataStart = npData;
this.savedObjectsClient = core.savedObjects.client;
}
stop() {}
}

View file

@ -8,7 +8,7 @@ Graph shows only up in the side bar if your server is running on a platinum or t
* Run tests `node x-pack/scripts/jest.js --watch plugins/graph`
* Run type check `node scripts/type_check.js --project=x-pack/tsconfig.json`
* Run linter `node scripts/eslint.js x-pack/legacy/plugins/graph`
* Run linter `node scripts/eslint.js x-pack/plugins/graph`
* Run functional tests (make sure to stop dev server)
* Server `cd x-pack && node ./scripts/functional_tests_server.js`
* Tests `cd x-pack && node ../scripts/functional_test_runner.js --config ./test/functional/config.js --grep=graph`
@ -21,7 +21,6 @@ Currently most of the state handling is done by a central angular controller. Th
* `angular/` contains all code using javascript and angular. Rewriting this code in typescript and react is currently ongoing. When the migration is finished, this folder will go away
* `components/` contains react components for various parts of the interface. Components can hold local UI state (e.g. current form data), everything else should be passed in from the caller. Styles should reside in a component-specific stylesheet
* `hacks/` contains files that need to run before the actual app is started. When moving to the new platform, this folder will go away.
* `services/` contains functions that encapsule other parts of Kibana. Stateful dependencies are passed in from the outside. Components should not rely on services directly but have callbacks passed in. Once the migration to redux/saga is complete, only sagas will use services.
* `helpers/` contains side effect free helper functions that can be imported and used from components and services
* `state_management/` contains reducers, action creators, selectors and sagas. It also exports the central store creator

View file

@ -4,7 +4,7 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["licensing"],
"requiredPlugins": ["licensing", "data", "navigation"],
"optionalPlugins": ["home"],
"configPath": ["xpack", "graph"]
}

View file

@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import $ from 'jquery';
// Kibana wrapper
const d3 = require('d3');
@ -79,7 +81,7 @@ module.exports = (function() {
self.redo = reverseOperation.undo;
}
function GroupOperation(receiver, orphan, vm) {
function GroupOperation(receiver, orphan) {
const self = this;
self.receiver = receiver;
self.orphan = orphan;
@ -91,7 +93,7 @@ module.exports = (function() {
};
}
function UnGroupOperation(parent, child, vm) {
function UnGroupOperation(parent, child) {
const self = this;
self.parent = parent;
self.child = child;
@ -152,9 +154,7 @@ module.exports = (function() {
if (lastOps) {
this.stopLayout();
this.redoLog.push(lastOps);
for (const i in lastOps) {
lastOps[i].undo();
}
lastOps.forEach(ops => ops.undo());
this.runLayout();
}
};
@ -163,29 +163,22 @@ module.exports = (function() {
if (lastOps) {
this.stopLayout();
this.undoLog.push(lastOps);
for (const i in lastOps) {
lastOps[i].redo();
}
lastOps.forEach(ops => ops.redo());
this.runLayout();
}
};
//Determines if 2 nodes are connected via an edge
this.areLinked = function(a, b) {
if (a == b) return true;
const allEdges = this.edges;
for (const e in allEdges) {
if (e.source == a) {
if (e.target == b) {
return true;
}
if (a === b) return true;
this.edges.forEach(e => {
if (e.source === a && e.target === b) {
return true;
}
if (e.source == b) {
if (e.target == a) {
return true;
}
if (e.source === b && e.target === a) {
return true;
}
}
});
return false;
};
@ -193,47 +186,43 @@ module.exports = (function() {
this.selectAll = function() {
self.selectedNodes = [];
for (const n in self.nodes) {
const node = self.nodes[n];
if (node.parent == undefined) {
self.nodes.forEach(node => {
if (node.parent === undefined) {
node.isSelected = true;
self.selectedNodes.push(node);
} else {
node.isSelected = false;
}
}
});
};
this.selectNone = function() {
self.selectedNodes = [];
for (const n in self.nodes) {
const node = self.nodes[n];
self.nodes.forEach(node => {
node.isSelected = false;
}
});
};
this.selectInvert = function() {
self.selectedNodes = [];
for (const n in self.nodes) {
const node = self.nodes[n];
if (node.parent != undefined) {
continue;
self.nodes.forEach(node => {
if (node.parent !== undefined) {
return;
}
node.isSelected = !node.isSelected;
if (node.isSelected) {
self.selectedNodes.push(node);
}
}
});
};
this.selectNodes = function(nodes) {
for (const n in nodes) {
const node = nodes[n];
nodes.forEach(node => {
node.isSelected = true;
if (self.selectedNodes.indexOf(node) < 0) {
self.selectedNodes.push(node);
}
}
});
};
this.selectNode = function(node) {
@ -247,29 +236,27 @@ module.exports = (function() {
let allAndGrouped = self.returnUnpackedGroupeds(self.selectedNodes);
// Nothing selected so process all nodes
if (allAndGrouped.length == 0) {
if (allAndGrouped.length === 0) {
allAndGrouped = self.nodes.slice(0);
}
const undoOperations = [];
for (const i in allAndGrouped) {
const node = allAndGrouped[i];
allAndGrouped.forEach(node => {
//We set selected to false because despite being deleted, node objects sit in an undo log
node.isSelected = false;
delete self.nodesMap[node.id];
undoOperations.push(new ReverseOperation(new AddNodeOperation(node, self)));
}
});
self.arrRemoveAll(self.nodes, allAndGrouped);
self.arrRemoveAll(self.selectedNodes, allAndGrouped);
const danglingEdges = self.edges.filter(function(edge) {
return self.nodes.indexOf(edge.source) < 0 || self.nodes.indexOf(edge.target) < 0;
});
for (const i in danglingEdges) {
const edge = danglingEdges[i];
danglingEdges.forEach(edge => {
delete self.edgesMap[edge.id];
undoOperations.push(new ReverseOperation(new AddEdgeOperation(edge, self)));
}
});
self.addUndoLogEntry(undoOperations);
self.arrRemoveAll(self.edges, danglingEdges);
self.runLayout();
@ -277,8 +264,7 @@ module.exports = (function() {
this.selectNeighbours = function() {
const newSelections = [];
for (const n in self.edges) {
const edge = self.edges[n];
self.edges.forEach(edge => {
if (!edge.topSrc.isSelected) {
if (self.selectedNodes.indexOf(edge.topTarget) >= 0) {
if (newSelections.indexOf(edge.topSrc) < 0) {
@ -293,18 +279,17 @@ module.exports = (function() {
}
}
}
}
for (const i in newSelections) {
const newlySelectedNode = newSelections[i];
});
newSelections.forEach(newlySelectedNode => {
self.selectedNodes.push(newlySelectedNode);
newlySelectedNode.isSelected = true;
}
});
};
this.selectNone = function() {
for (const n in self.selectedNodes) {
self.selectedNodes[n].isSelected = false;
}
self.selectedNodes.forEach(node => {
node.isSelected = false;
});
self.selectedNodes = [];
};
@ -318,30 +303,25 @@ module.exports = (function() {
};
this.colorSelected = function(colorNum) {
const selections = self.getAllSelectedNodes();
for (const i in selections) {
selections[i].color = colorNum;
}
self.getAllSelectedNodes().forEach(node => {
node.color = colorNum;
});
};
this.getSelectionsThatAreGrouped = function() {
const result = [];
const selections = self.selectedNodes;
for (const i in selections) {
const node = selections[i];
self.selectedNodes.forEach(node => {
if (node.numChildren > 0) {
result.push(node);
}
}
});
return result;
};
this.ungroupSelection = function() {
const selections = self.getSelectionsThatAreGrouped();
for (const i in selections) {
const node = selections[i];
self.getSelectionsThatAreGrouped().forEach(node => {
self.ungroup(node);
}
});
};
this.toggleNodeSelection = function(node) {
@ -371,7 +351,7 @@ module.exports = (function() {
if (result.indexOf(topLevelTarget) >= 0) {
//visible top-level node is selected - add all nesteds starting from bottom up
let target = edge.target;
while (target.parent != undefined) {
while (target.parent !== undefined) {
if (result.indexOf(target) < 0) {
result.push(target);
}
@ -382,7 +362,7 @@ module.exports = (function() {
if (result.indexOf(topLevelSource) >= 0) {
//visible top-level node is selected - add all nesteds starting from bottom up
let source = edge.source;
while (source.parent != undefined) {
while (source.parent !== undefined) {
if (result.indexOf(source) < 0) {
result.push(source);
}
@ -425,22 +405,21 @@ module.exports = (function() {
this.getNeighbours = function(node) {
const neighbourNodes = [];
for (const e in self.edges) {
const edge = self.edges[e];
if (edge.topSrc == edge.topTarget) {
continue;
self.edges.forEach(edge => {
if (edge.topSrc === edge.topTarget) {
return;
}
if (edge.topSrc == node) {
if (edge.topSrc === node) {
if (neighbourNodes.indexOf(edge.topTarget) < 0) {
neighbourNodes.push(edge.topTarget);
}
}
if (edge.topTarget == node) {
if (edge.topTarget === node) {
if (neighbourNodes.indexOf(edge.topSrc) < 0) {
neighbourNodes.push(edge.topSrc);
}
}
}
});
return neighbourNodes;
};
@ -448,7 +427,7 @@ module.exports = (function() {
this.buildNodeQuery = function(topLevelNode) {
let containedNodes = [topLevelNode];
containedNodes = self.returnUnpackedGroupeds(containedNodes);
if (containedNodes.length == 1) {
if (containedNodes.length === 1) {
//Simple case - return a single-term query
const tq = {};
tq[topLevelNode.data.field] = topLevelNode.data.term;
@ -457,17 +436,16 @@ module.exports = (function() {
};
}
const termsByField = {};
for (const i in containedNodes) {
const node = containedNodes[i];
containedNodes.forEach(node => {
let termsList = termsByField[node.data.field];
if (!termsList) {
termsList = [];
termsByField[node.data.field] = termsList;
}
termsList.push(node.data.term);
}
});
//Single field case
if (Object.keys(termsByField).length == 1) {
if (Object.keys(termsByField).length === 1) {
return {
terms: termsByField,
};
@ -479,11 +457,13 @@ module.exports = (function() {
},
};
for (const field in termsByField) {
const tq = {};
tq[field] = termsByField[field];
q.bool.should.push({
terms: tq,
});
if (termsByField.hasOwnProperty(field)) {
const tq = {};
tq[field] = termsByField[field];
q.bool.should.push({
terms: tq,
});
}
}
return q;
};
@ -503,39 +483,40 @@ module.exports = (function() {
// is potentially a reduced set of nodes if the client has used any
// grouping of nodes into parent nodes.
const effectiveEdges = [];
const edges = self.edges;
for (const e in edges) {
const edge = edges[e];
self.edges.forEach(edge => {
let topSrc = edge.source;
let topTarget = edge.target;
while (topSrc.parent != undefined) {
while (topSrc.parent !== undefined) {
topSrc = topSrc.parent;
}
while (topTarget.parent != undefined) {
while (topTarget.parent !== undefined) {
topTarget = topTarget.parent;
}
edge.topSrc = topSrc;
edge.topTarget = topTarget;
if (topSrc != topTarget) {
if (topSrc !== topTarget) {
effectiveEdges.push({
source: topSrc,
target: topTarget,
});
}
}
});
const visibleNodes = self.nodes.filter(function(n) {
return n.parent == undefined;
return n.parent === undefined;
});
//reset then roll-up all the counts
const allNodes = self.nodes;
for (const n in allNodes) {
const node = allNodes[n];
allNodes.forEach(node => {
node.numChildren = 0;
}
});
for (const n in allNodes) {
if (!allNodes.hasOwnProperty(n)) {
continue;
}
let node = allNodes[n];
while (node.parent != undefined) {
while (node.parent !== undefined) {
node = node.parent;
node.numChildren = node.numChildren + 1;
}
@ -551,36 +532,34 @@ module.exports = (function() {
.theta(0.99)
.alpha(0.5)
.size([800, 600])
.on('tick', function(e) {
.on('tick', function() {
const nodeArray = self.nodes;
let hasRollups = false;
//Update the position of all "top level nodes"
for (const i in nodeArray) {
const n = nodeArray[i];
nodeArray.forEach(n => {
//Code to support roll-ups
if (n.parent == undefined) {
if (n.parent === undefined) {
n.kx = n.x;
n.ky = n.y;
} else {
hasRollups = true;
}
}
});
if (hasRollups) {
for (const i in nodeArray) {
const n = nodeArray[i];
nodeArray.forEach(n => {
//Code to support roll-ups
if (n.parent != undefined) {
if (n.parent !== undefined) {
// Is a grouped node - inherit parent's position so edges point into parent
// d3 thinks it has moved it to x and y but we have final say using kx and ky.
let topLevelNode = n.parent;
while (topLevelNode.parent != undefined) {
while (topLevelNode.parent !== undefined) {
topLevelNode = topLevelNode.parent;
}
n.kx = topLevelNode.x;
n.ky = topLevelNode.y;
}
}
});
}
if (self.changeHandler) {
// Hook to allow any client to respond to position changes
@ -597,11 +576,11 @@ module.exports = (function() {
this.groupSelections = function(node) {
const ops = [];
self.nodes.forEach(function(otherNode) {
if (otherNode != node && otherNode.isSelected && otherNode.parent == undefined) {
if (otherNode !== node && otherNode.isSelected && otherNode.parent === undefined) {
otherNode.parent = node;
otherNode.isSelected = false;
self.arrRemove(self.selectedNodes, otherNode);
ops.push(new GroupOperation(node, otherNode, self));
ops.push(new GroupOperation(node, otherNode));
}
});
self.selectNone();
@ -614,11 +593,11 @@ module.exports = (function() {
const neighbours = self.getNeighbours(node);
const ops = [];
neighbours.forEach(function(otherNode) {
if (otherNode != node && otherNode.parent == undefined) {
if (otherNode !== node && otherNode.parent === undefined) {
otherNode.parent = node;
otherNode.isSelected = false;
self.arrRemove(self.selectedNodes, otherNode);
ops.push(new GroupOperation(node, otherNode, self));
ops.push(new GroupOperation(node, otherNode));
}
});
self.addUndoLogEntry(ops);
@ -633,11 +612,11 @@ module.exports = (function() {
const selClone = self.selectedNodes.slice();
const ops = [];
selClone.forEach(function(otherNode) {
if (otherNode != targetNode && otherNode.parent == undefined) {
if (otherNode !== targetNode && otherNode.parent === undefined) {
otherNode.parent = targetNode;
otherNode.isSelected = false;
self.arrRemove(self.selectedNodes, otherNode);
ops.push(new GroupOperation(targetNode, otherNode, self));
ops.push(new GroupOperation(targetNode, otherNode));
}
});
self.addUndoLogEntry(ops);
@ -647,9 +626,9 @@ module.exports = (function() {
this.ungroup = function(node) {
const ops = [];
self.nodes.forEach(function(other) {
if (other.parent == node) {
if (other.parent === node) {
other.parent = undefined;
ops.push(new UnGroupOperation(node, other, self));
ops.push(new UnGroupOperation(node, other));
}
});
self.addUndoLogEntry(ops);
@ -669,12 +648,11 @@ module.exports = (function() {
danglingEdges.push(edge);
}
});
for (const n in selection) {
const node = selection[n];
selection.forEach(node => {
delete self.nodesMap[node.id];
self.blacklistedNodes.push(node);
node.isSelected = false;
}
});
self.arrRemoveAll(self.nodes, selection);
self.arrRemoveAll(self.edges, danglingEdges);
self.selectedNodes = [];
@ -722,9 +700,7 @@ module.exports = (function() {
for (let hopNum = 0; hopNum < numHops; hopNum++) {
const arr = [];
for (const f in fieldsChoice) {
const field = fieldsChoice[f].name;
const hopSize = fieldsChoice[f].hopSize;
fieldsChoice.forEach(({ name: field, hopSize }) => {
const excludes = excludeNodesByField[field];
const stepField = {
field: field,
@ -735,7 +711,7 @@ module.exports = (function() {
stepField.exclude = excludes;
}
arr.push(stepField);
}
});
step.vertices = arr;
if (hopNum < numHops - 1) {
// if (s < (stepSizes.length - 1)) {
@ -814,8 +790,7 @@ module.exports = (function() {
//Remove nodes we already have
const dedupedNodes = [];
for (const o in newData.nodes) {
const node = newData.nodes[o];
newData.nodes.forEach(node => {
//Assign an ID
node.id = self.makeNodeId(node.field, node.term);
if (!this.nodesMap[node.id]) {
@ -825,14 +800,13 @@ module.exports = (function() {
}
dedupedNodes.push(node);
}
}
});
if (dedupedNodes.length > 0 && this.options.nodeLabeller) {
// A hook for client code to attach labels etc to newly introduced nodes.
this.options.nodeLabeller(dedupedNodes);
}
for (const o in dedupedNodes) {
const dedupedNode = dedupedNodes[o];
dedupedNodes.forEach(dedupedNode => {
let label = dedupedNode.term;
if (dedupedNode.label) {
label = dedupedNode.label;
@ -856,10 +830,9 @@ module.exports = (function() {
this.nodes.push(node);
lastOps.push(new AddNodeOperation(node, self));
this.nodesMap[node.id] = node;
}
});
for (const o in newData.edges) {
const edge = newData.edges[o];
newData.edges.forEach(edge => {
const src = newData.nodes[edge.source];
const target = newData.nodes[edge.target];
edge.id = this.makeEdgeId(src.id, target.id);
@ -873,7 +846,7 @@ module.exports = (function() {
existingEdge.weight = Math.max(existingEdge.weight, edge.weight);
//TODO update width too?
existingEdge.doc_count = Math.max(existingEdge.doc_count, edge.doc_count);
continue;
return;
}
const newEdge = {
source: srcWrapperObj,
@ -890,7 +863,7 @@ module.exports = (function() {
this.edgesMap[newEdge.id] = newEdge;
this.edges.push(newEdge);
lastOps.push(new AddEdgeOperation(newEdge, self));
}
});
if (lastOps.length > 0) {
self.addUndoLogEntry(lastOps);
@ -907,7 +880,7 @@ module.exports = (function() {
self.arrRemove(self.selectedNodes, child);
}
child.parent = parent;
self.addUndoLogEntry([new GroupOperation(parent, child, self)]);
self.addUndoLogEntry([new GroupOperation(parent, child)]);
self.runLayout();
};
@ -922,7 +895,7 @@ module.exports = (function() {
this.expandSelecteds = function(targetOptions = {}) {
let startNodes = self.getAllSelectedNodes();
if (startNodes.length == 0) {
if (startNodes.length === 0) {
startNodes = self.nodes;
}
const clone = startNodes.slice();
@ -1000,11 +973,13 @@ module.exports = (function() {
const primaryVertices = [];
const secondaryVertices = [];
for (const fieldName in nodesByField) {
primaryVertices.push({
field: fieldName,
include: nodesByField[fieldName],
min_doc_count: parseInt(self.options.exploreControls.minDocCount),
});
if (nodesByField.hasOwnProperty(fieldName)) {
primaryVertices.push({
field: fieldName,
include: nodesByField[fieldName],
min_doc_count: parseInt(self.options.exploreControls.minDocCount),
});
}
}
let targetFields = this.options.vertex_fields;
@ -1013,11 +988,11 @@ module.exports = (function() {
}
//Identify target fields
for (const f in targetFields) {
const fieldName = targetFields[f].name;
targetFields.forEach(targetField => {
const fieldName = targetField.name;
// Sometimes the target field is disabled from loading new hops so we need to use the last valid figure
const hopSize =
targetFields[f].hopSize > 0 ? targetFields[f].hopSize : targetFields[f].lastValidHopSize;
targetField.hopSize > 0 ? targetField.hopSize : targetField.lastValidHopSize;
const fieldHop = {
field: fieldName,
@ -1026,7 +1001,7 @@ module.exports = (function() {
};
fieldHop.exclude = excludeNodesByField[fieldName];
secondaryVertices.push(fieldHop);
}
});
const request = {
controls: self.buildControls(),
@ -1038,33 +1013,27 @@ module.exports = (function() {
self.lastRequest = JSON.stringify(request, null, '\t');
graphExplorer(self.options.indexName, request, function(data) {
self.lastResponse = JSON.stringify(data, null, '\t');
const nodes = [];
const edges = [];
//Label fields with a field number for CSS styling
for (const n in data.vertices) {
const node = data.vertices[n];
for (const f in targetFields) {
const fieldDef = targetFields[f];
if (node.field == fieldDef.name) {
data.vertices.forEach(node => {
targetFields.some(fieldDef => {
if (node.field === fieldDef.name) {
node.color = fieldDef.color;
node.icon = fieldDef.icon;
node.fieldDef = fieldDef;
break;
return true;
}
}
}
return false;
});
});
// Size the edges based on the maximum weight
const minLineSize = 2;
const maxLineSize = 10;
let maxEdgeWeight = 0.00000001;
for (const e in data.connections) {
const edge = data.connections[e];
data.connections.forEach(edge => {
maxEdgeWeight = Math.max(maxEdgeWeight, edge.weight);
}
for (const e in data.connections) {
const edge = data.connections[e];
edges.push({
source: edge.source,
target: edge.target,
@ -1072,7 +1041,7 @@ module.exports = (function() {
weight: edge.weight,
width: Math.max(minLineSize, (edge.weight / maxEdgeWeight) * maxLineSize),
});
}
});
// Add the new nodes and edges into the existing workspace's graph
self.mergeGraph({
@ -1087,8 +1056,7 @@ module.exports = (function() {
let trimmedEdges = [];
const maxNumEdgesToReturn = 5;
//Trim here to just the new edges that are most interesting.
for (const o in newEdges) {
const edge = newEdges[o];
newEdges.forEach(edge => {
const src = newNodes[edge.source];
const target = newNodes[edge.target];
const srcId = src.field + '..' + src.term;
@ -1097,25 +1065,25 @@ module.exports = (function() {
const existingSrcNode = self.nodesMap[srcId];
const existingTargetNode = self.nodesMap[targetId];
if (existingSrcNode != null && existingTargetNode != null) {
if (existingSrcNode.parent != undefined && existingTargetNode.parent != undefined) {
if (existingSrcNode.parent !== undefined && existingTargetNode.parent !== undefined) {
// both nodes are rolled-up and grouped so this edge would not be a visible
// change to the graph - lose it in favour of any other visible ones.
continue;
return;
}
} else {
console.log('Error? Missing nodes ' + srcId + ' or ' + targetId, self.nodesMap);
continue;
return;
}
const existingEdge = self.edgesMap[id];
if (existingEdge) {
existingEdge.weight = Math.max(existingEdge.weight, edge.weight);
existingEdge.doc_count = Math.max(existingEdge.doc_count, edge.doc_count);
continue;
return;
} else {
trimmedEdges.push(edge);
}
}
});
if (trimmedEdges.length > maxNumEdgesToReturn) {
//trim to only the most interesting ones
trimmedEdges.sort(function(a, b) {
@ -1132,12 +1100,11 @@ module.exports = (function() {
if (!startNodes) {
nodes = self.nodes;
}
for (const bs in nodes) {
const node = nodes[bs];
if (node.parent == undefined) {
nodes.forEach(node => {
if (node.parent === undefined) {
shoulds.push(self.buildNodeQuery(node));
}
}
});
return {
bool: {
should: shoulds,
@ -1256,7 +1223,7 @@ module.exports = (function() {
const t2 = keyedBuckets[ids[1]].doc_count;
const t1AndT2 = bucket.doc_count;
// Calc the significant_terms score to prioritize selection of interesting links
bucket.weight = self.JLHScore(
bucket.weight = self.jLHScore(
t1AndT2,
Math.max(t1, t2),
Math.min(t1, t2),
@ -1276,7 +1243,7 @@ module.exports = (function() {
return;
}
const ids = bucket.key.split('|');
if (ids.length == 2) {
if (ids.length === 2) {
// Bucket represents an edge
const srcNode = nodesForLinking[ids[0]];
const targetNode = nodesForLinking[ids[1]];
@ -1340,16 +1307,18 @@ module.exports = (function() {
txtsByFieldType[node.data.field] = txt;
});
for (const field in txtsByFieldType) {
likeQueries.push({
more_like_this: {
like: txtsByFieldType[field],
min_term_freq: 1,
minimum_should_match: '20%',
min_doc_freq: 1,
boost_terms: 2,
max_query_terms: 25,
},
});
if (txtsByFieldType.hasOwnProperty(field)) {
likeQueries.push({
more_like_this: {
like: txtsByFieldType[field],
min_term_freq: 1,
minimum_should_match: '20%',
min_doc_freq: 1,
boost_terms: 2,
max_query_terms: 25,
},
});
}
}
const excludeNodesByField = {};
@ -1397,10 +1366,10 @@ module.exports = (function() {
};
this.getSelectedIntersections = function(callback) {
if (self.selectedNodes.length == 0) {
if (self.selectedNodes.length === 0) {
return self.getAllIntersections(callback, self.nodes);
}
if (self.selectedNodes.length == 1) {
if (self.selectedNodes.length === 1) {
const selectedNode = self.selectedNodes[0];
const neighbourNodes = self.getNeighbours(selectedNode);
neighbourNodes.push(selectedNode);
@ -1409,7 +1378,7 @@ module.exports = (function() {
return self.getAllIntersections(callback, self.getAllSelectedNodes());
};
this.JLHScore = function(subsetFreq, subsetSize, supersetFreq, supersetSize) {
this.jLHScore = function(subsetFreq, subsetSize, supersetFreq, supersetSize) {
const subsetProbability = subsetFreq / subsetSize;
const supersetProbability = supersetFreq / supersetSize;
@ -1432,7 +1401,7 @@ module.exports = (function() {
this.getAllIntersections = function(callback, nodes) {
//Ensure these are all top-level nodes only
nodes = nodes.filter(function(n) {
return n.parent == undefined;
return n.parent === undefined;
});
const allQueries = nodes.map(function(node) {
@ -1468,44 +1437,42 @@ module.exports = (function() {
},
},
};
for (const n in allQueries) {
allQueries.forEach((query, n) => {
// Add aggs to get intersection stats with root node.
request.aggs.sources.filters.filters['bg' + n] = allQueries[n];
request.aggs.sources.aggs.targets.filters.filters['fg' + n] = allQueries[n];
}
const dataForServer = JSON.stringify(request);
request.aggs.sources.filters.filters['bg' + n] = query;
request.aggs.sources.aggs.targets.filters.filters['fg' + n] = query;
});
searcher(self.options.indexName, request, function(data) {
const termIntersects = [];
const fullDocCounts = [];
const allDocCount = data.aggregations.all.doc_count;
// Gather the background stats for all nodes.
for (const n in nodes) {
nodes.forEach((rootNode, n) => {
fullDocCounts.push(data.aggregations.sources.buckets['bg' + n].doc_count);
}
for (const n in nodes) {
const rootNode = nodes[n];
});
nodes.forEach((rootNode, n) => {
const t1 = fullDocCounts[n];
const baseAgg = data.aggregations.sources.buckets['bg' + n].targets.buckets;
for (const l in nodes) {
nodes.forEach((leafNode, l) => {
const t2 = fullDocCounts[l];
const leafNode = nodes[l];
if (l == n) {
continue;
if (l === n) {
return;
}
if (t1 > t2) {
// We should get the same stats for t2->t1 from the t1->t2 bucket path
continue;
return;
}
if (t1 == t2) {
if (t1 === t2) {
if (rootNode.id > leafNode.id) {
// We should get the same stats for t2->t1 from the t1->t2 bucket path
continue;
return;
}
}
const t1AndT2 = baseAgg['fg' + l].doc_count;
if (t1AndT2 == 0) {
continue;
if (t1AndT2 === 0) {
return;
}
const neighbourNode = nodes[l];
let t1Label = rootNode.data.label;
@ -1521,7 +1488,7 @@ module.exports = (function() {
// var mergeConfidence=t1AndT2/t1;
// So using Significance heuristic instead
const mergeConfidence = self.JLHScore(t1AndT2, t2, t1, allDocCount);
const mergeConfidence = self.jLHScore(t1AndT2, t2, t1, allDocCount);
const termIntersect = {
id1: rootNode.id,
@ -1536,16 +1503,16 @@ module.exports = (function() {
overlap: t1AndT2,
};
termIntersects.push(termIntersect);
}
}
});
});
termIntersects.sort(function(a, b) {
if (b.mergeConfidence != a.mergeConfidence) {
if (b.mergeConfidence !== a.mergeConfidence) {
return b.mergeConfidence - a.mergeConfidence;
}
// If of equal similarity use the size of the overlap as
// a measure of magnitude/significance for tie-breaker.
if (b.overlap != a.overlap) {
if (b.overlap !== a.overlap) {
return b.overlap - a.overlap;
}
//All other things being equal we now favour where t2 NOT t1 is small.
@ -1563,32 +1530,28 @@ module.exports = (function() {
self.lastRequest = JSON.stringify(request, null, '\t');
graphExplorer(self.options.indexName, request, function(data) {
self.lastResponse = JSON.stringify(data, null, '\t');
const nodes = [];
const edges = [];
//Label the nodes with field number for CSS styling
for (const n in data.vertices) {
const node = data.vertices[n];
for (const f in self.options.vertex_fields) {
const fieldDef = self.options.vertex_fields[f];
if (node.field == fieldDef.name) {
data.vertices.forEach(node => {
self.options.vertex_fields.some(fieldDef => {
if (node.field === fieldDef.name) {
node.color = fieldDef.color;
node.icon = fieldDef.icon;
node.fieldDef = fieldDef;
break;
return true;
}
}
}
return false;
});
});
//Size the edges depending on weight
const minLineSize = 2;
const maxLineSize = 10;
let maxEdgeWeight = 0.00000001;
for (const e in data.connections) {
const edge = data.connections[e];
data.connections.forEach(edge => {
maxEdgeWeight = Math.max(maxEdgeWeight, edge.weight);
}
for (const e in data.connections) {
const edge = data.connections[e];
});
data.connections.forEach(edge => {
edges.push({
source: edge.source,
target: edge.target,
@ -1596,7 +1559,7 @@ module.exports = (function() {
weight: edge.weight,
width: Math.max(minLineSize, (edge.weight / maxEdgeWeight) * maxLineSize),
});
}
});
self.mergeGraph(
{

View file

@ -77,7 +77,7 @@ describe('graphui-workspace', function() {
},
],
};
workspace.simpleSearch('myquery', {}, 2);
workspace.simpleSearch('myquery', undefined, 2);
expect(workspace.nodes.length).toEqual(2);
expect(workspace.edges.length).toEqual(1);
@ -119,7 +119,7 @@ describe('graphui-workspace', function() {
},
],
};
workspace.simpleSearch('myquery', {}, 2);
workspace.simpleSearch('myquery', undefined, 2);
expect(workspace.nodes.length).toEqual(2);
expect(workspace.edges.length).toEqual(1);
@ -201,7 +201,7 @@ describe('graphui-workspace', function() {
},
],
};
workspace.simpleSearch('myquery', {}, 2);
workspace.simpleSearch('myquery', undefined, 2);
expect(workspace.selectedNodes.length).toEqual(0);
@ -264,7 +264,7 @@ describe('graphui-workspace', function() {
},
],
};
workspace.simpleSearch('myquery', {}, 2);
workspace.simpleSearch('myquery', undefined, 2);
expect(workspace.nodes.length).toEqual(2);
@ -320,7 +320,7 @@ describe('graphui-workspace', function() {
},
],
};
workspace.simpleSearch('myquery', {}, 2);
workspace.simpleSearch('myquery', undefined, 2);
expect(workspace.nodes.length).toEqual(2);

View file

@ -6,13 +6,12 @@
import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import 'ace';
import React from 'react';
import { Provider } from 'react-redux';
import { isColorDark, hexToRgb } from '@elastic/eui';
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
import { showSaveModal } from '../../../../../src/plugins/saved_objects/public';
import { toMountPoint } from '../../../../src/plugins/kibana_react/public';
import { showSaveModal } from '../../../../src/plugins/saved_objects/public';
import appTemplate from './angular/templates/index.html';
import listingTemplate from './angular/templates/listing_ng_wrapper.html';
@ -41,7 +40,7 @@ export function initGraphApp(angularModule, deps) {
indexPatterns,
addBasePath,
getBasePath,
npData,
data,
config,
savedWorkspaceLoader,
capabilities,
@ -107,7 +106,7 @@ export function initGraphApp(angularModule, deps) {
.when('/home', {
template: listingTemplate,
badge: getReadonlyBadge,
controller($location, $scope) {
controller: function($location, $scope) {
$scope.listingLimit = config.get('savedObjects:listingLimit');
$scope.create = () => {
$location.url(getNewPath());
@ -249,6 +248,7 @@ export function initGraphApp(angularModule, deps) {
const store = createGraphStore({
basePath: getBasePath(),
addBasePath,
indexPatternProvider: $scope.indexPatternProvider,
indexPatterns: $route.current.locals.indexPatterns,
createWorkspace: (indexPattern, exploreControls) => {
@ -301,7 +301,7 @@ export function initGraphApp(angularModule, deps) {
});
// register things on scope passed down to react components
$scope.pluginDataStart = npData;
$scope.pluginDataStart = data;
$scope.storage = storage;
$scope.coreStart = coreStart;
$scope.loading = false;
@ -420,11 +420,13 @@ export function initGraphApp(angularModule, deps) {
while (found) {
found = false;
for (const i in $scope.detail.mergeCandidates) {
const mc = $scope.detail.mergeCandidates[i];
if (mc.id1 === childId || mc.id2 === childId) {
$scope.detail.mergeCandidates.splice(i, 1);
found = true;
break;
if ($scope.detail.mergeCandidates.hasOwnProperty(i)) {
const mc = $scope.detail.mergeCandidates[i];
if (mc.id1 === childId || mc.id2 === childId) {
$scope.detail.mergeCandidates.splice(i, 1);
found = true;
break;
}
}
}
}
@ -434,8 +436,7 @@ export function initGraphApp(angularModule, deps) {
$scope.handleMergeCandidatesCallback = function(termIntersects) {
const mergeCandidates = [];
for (const i in termIntersects) {
const ti = termIntersects[i];
termIntersects.forEach(ti => {
mergeCandidates.push({
id1: ti.id1,
id2: ti.id2,
@ -445,7 +446,7 @@ export function initGraphApp(angularModule, deps) {
v2: ti.v2,
overlap: ti.overlap,
});
}
});
$scope.detail = { mergeCandidates };
};

View file

@ -9,34 +9,36 @@
// They can stay even after NP cutover
import angular from 'angular';
import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular';
import '../../../../webpackShims/ace';
// required for i18nIdDirective
import 'angular-sanitize';
// type imports
import {
AppMountContext,
ChromeStart,
LegacyCoreStart,
CoreStart,
PluginInitializerContext,
SavedObjectsClientContract,
ToastsStart,
IUiSettingsClient,
OverlayStart,
} from 'kibana/public';
import { configureAppAngularModule } from './legacy_imports';
// @ts-ignore
import { initGraphApp } from './app';
import {
Plugin as DataPlugin,
IndexPatternsContract,
} from '../../../../../src/plugins/data/public';
import { LicensingPluginSetup } from '../../../../plugins/licensing/public';
import { checkLicense } from '../../../../plugins/graph/common/check_license';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../../src/plugins/navigation/public';
import { Plugin as DataPlugin, IndexPatternsContract } from '../../../../src/plugins/data/public';
import { LicensingPluginSetup } from '../../licensing/public';
import { checkLicense } from '../common/check_license';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../src/plugins/navigation/public';
import { createSavedWorkspacesLoader } from './services/persistence/saved_workspace_loader';
import { Storage } from '../../../../../src/plugins/kibana_utils/public';
import { Storage } from '../../../../src/plugins/kibana_utils/public';
import {
addAppRedirectMessageToUrl,
configureAppAngularModule,
createTopNavDirective,
createTopNavHelper,
} from '../../../../../src/plugins/kibana_legacy/public';
import { addAppRedirectMessageToUrl } from '../../../../../src/plugins/kibana_legacy/public';
} from '../../../../src/plugins/kibana_legacy/public';
import './index.scss';
/**
* These are dependencies of the Graph app besides the base dependencies
@ -45,6 +47,8 @@ import { addAppRedirectMessageToUrl } from '../../../../../src/plugins/kibana_le
* itself changes
*/
export interface GraphDependencies {
pluginInitializerContext: PluginInitializerContext;
core: CoreStart;
element: HTMLElement;
appBasePath: string;
capabilities: Record<string, boolean | Record<string, boolean>>;
@ -55,7 +59,7 @@ export interface GraphDependencies {
config: IUiSettingsClient;
toastNotifications: ToastsStart;
indexPatterns: IndexPatternsContract;
npData: ReturnType<DataPlugin['start']>;
data: ReturnType<DataPlugin['start']>;
savedObjectsClient: SavedObjectsClientContract;
addBasePath: (url: string) => string;
getBasePath: () => string;
@ -67,7 +71,11 @@ export interface GraphDependencies {
export const renderApp = ({ appBasePath, element, ...deps }: GraphDependencies) => {
const graphAngularModule = createLocalAngularModule(deps.navigation);
configureAppAngularModule(graphAngularModule, deps.coreStart as LegacyCoreStart, true);
configureAppAngularModule(
graphAngularModule,
{ core: deps.core, env: deps.pluginInitializerContext.env },
true
);
const licenseSubscription = deps.licensing.license$.subscribe(license => {
const info = checkLicense(license);
@ -81,7 +89,7 @@ export const renderApp = ({ appBasePath, element, ...deps }: GraphDependencies)
const savedWorkspaceLoader = createSavedWorkspacesLoader({
chrome: deps.coreStart.chrome,
indexPatterns: deps.npData.indexPatterns,
indexPatterns: deps.data.indexPatterns,
overlays: deps.coreStart.overlays,
savedObjectsClient: deps.coreStart.savedObjects.client,
basePath: deps.coreStart.http.basePath,
@ -113,6 +121,7 @@ function mountGraphApp(appBasePath: string, element: HTMLElement) {
// make angular-within-angular possible
const $injector = angular.bootstrap(mountpoint, [moduleName]);
element.appendChild(mountpoint);
element.setAttribute('class', 'kbnLocalApplicationWrapper');
return $injector;
}

View file

@ -18,7 +18,7 @@ import { GraphStore } from '../state_management';
import { GuidancePanel } from './guidance_panel';
import { GraphTitle } from './graph_title';
import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
export interface GraphAppProps extends SearchBarProps {
coreStart: CoreStart;

View file

@ -29,7 +29,7 @@ import classNames from 'classnames';
import { WorkspaceField } from '../../types';
import { iconChoices } from '../../helpers/style_choices';
import { LegacyIcon } from '../legacy_icon';
import { FieldIcon } from '../../../../../../../src/plugins/kibana_react/public';
import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public';
import { UpdateableFieldProperties } from './field_manager';
import { isEqual } from '../helpers';

View file

@ -9,7 +9,7 @@ import { EuiPopover, EuiSelectable, EuiBadge } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import classNames from 'classnames';
import { WorkspaceField } from '../../types';
import { FieldIcon } from '../../../../../../../src/plugins/kibana_react/public';
import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public';
export interface FieldPickerProps {
fieldMap: Record<string, WorkspaceField>;

View file

@ -30,7 +30,7 @@ import {
import { IndexPatternSavedObject } from '../../types';
import { openSourceModal } from '../../services/source_modal';
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
export interface GuidancePanelProps {
onFillWorkspace: () => void;

View file

@ -10,7 +10,7 @@ import React, { Fragment } from 'react';
import { EuiEmptyPrompt, EuiLink, EuiButton } from '@elastic/eui';
import { CoreStart, ApplicationStart } from 'kibana/public';
import { TableListView } from '../../../../../../src/plugins/kibana_react/public';
import { TableListView } from '../../../../../src/plugins/kibana_react/public';
import { GraphWorkspaceSavedObject } from '../types';
export interface ListingProps {

View file

@ -7,10 +7,7 @@
import React, { useState } from 'react';
import { EuiFormRow, EuiTextArea, EuiCallOut, EuiSpacer, EuiSwitch } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
SavedObjectSaveModal,
OnSaveProps,
} from '../../../../../../src/plugins/saved_objects/public';
import { SavedObjectSaveModal, OnSaveProps } from '../../../../../src/plugins/saved_objects/public';
import { GraphSavePolicy } from '../types/config';

View file

@ -9,9 +9,9 @@ import { SearchBar, OuterSearchBarProps } from './search_bar';
import React, { ReactElement } from 'react';
import { CoreStart } from 'src/core/public';
import { act } from 'react-dom/test-utils';
import { IndexPattern, QueryStringInput } from '../../../../../../src/plugins/data/public';
import { IndexPattern, QueryStringInput } from '../../../../../src/plugins/data/public';
import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
import { I18nProvider } from '@kbn/i18n/react';
import { openSourceModal } from '../services/source_modal';

View file

@ -18,14 +18,14 @@ import {
IndexpatternDatasource,
} from '../state_management';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
import {
IndexPattern,
QueryStringInput,
IDataPluginServices,
Query,
esKuery,
} from '../../../../../../src/plugins/data/public';
} from '../../../../../src/plugins/data/public';
export interface OuterSearchBarProps {
isLoading: boolean;

View file

@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
import React from 'react';
import { CoreStart } from 'src/core/public';
import { SavedObjectFinderUi } from '../../../../../../src/plugins/saved_objects/public';
import { SavedObjectFinderUi } from '../../../../../src/plugins/saved_objects/public';
import { IndexPatternSavedObject } from '../types';
export interface SourcePickerProps {

View file

@ -1,6 +1,3 @@
// Import the EUI global scope so we can use EUI constants
@import 'src/legacy/ui/public/styles/_styling_constants';
/* Graph plugin styles */
// Prefix all styles with "gph" to avoid conflicts.

View file

@ -10,5 +10,3 @@ import { ConfigSchema } from '../config';
export const plugin = (initializerContext: PluginInitializerContext<ConfigSchema>) =>
new GraphPlugin(initializerContext);
export { GraphSetup } from './plugin';

View file

@ -6,8 +6,14 @@
import { i18n } from '@kbn/i18n';
import { CoreSetup, CoreStart } from 'kibana/public';
import { Plugin } from 'src/core/public';
import { AppMountParameters, Plugin } from 'src/core/public';
import { PluginInitializerContext } from 'kibana/public';
import { Storage } from '../../../../src/plugins/kibana_utils/public';
import { initAngularBootstrap } from '../../../../src/plugins/kibana_legacy/public';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../src/plugins/navigation/public';
import { DataPublicPluginStart } from '../../../../src/plugins/data/public';
import { toggleNavLink } from './services/toggle_nav_link';
import { LicensingPluginSetup } from '../../licensing/public';
import { checkLicense } from '../common/check_license';
@ -15,6 +21,7 @@ import {
FeatureCatalogueCategory,
HomePublicPluginSetup,
} from '../../../../src/plugins/home/public';
import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils';
import { ConfigSchema } from '../config';
export interface GraphPluginSetupDependencies {
@ -22,12 +29,21 @@ export interface GraphPluginSetupDependencies {
home?: HomePublicPluginSetup;
}
export class GraphPlugin implements Plugin<{ config: Readonly<ConfigSchema> }, void> {
export interface GraphPluginStartDependencies {
navigation: NavigationStart;
data: DataPublicPluginStart;
}
export class GraphPlugin
implements Plugin<void, void, GraphPluginSetupDependencies, GraphPluginStartDependencies> {
private licensing: LicensingPluginSetup | null = null;
constructor(private initializerContext: PluginInitializerContext<ConfigSchema>) {}
setup(core: CoreSetup, { licensing, home }: GraphPluginSetupDependencies) {
setup(
core: CoreSetup<GraphPluginStartDependencies>,
{ licensing, home }: GraphPluginSetupDependencies
) {
this.licensing = licensing;
if (home) {
@ -44,15 +60,42 @@ export class GraphPlugin implements Plugin<{ config: Readonly<ConfigSchema> }, v
});
}
return {
/**
* The configuration is temporarily exposed to allow the legacy graph plugin to consume
* the setting. Once the graph plugin is migrated completely, this will become an implementation
* detail.
* @deprecated
*/
config: this.initializerContext.config.get(),
};
const config = this.initializerContext.config.get();
initAngularBootstrap();
core.application.register({
id: 'graph',
title: 'Graph',
order: 9000,
appRoute: '/app/graph',
euiIconType: 'graphApp',
category: DEFAULT_APP_CATEGORIES.analyze,
mount: async (params: AppMountParameters) => {
const [coreStart, pluginsStart] = await core.getStartServices();
const { renderApp } = await import('./application');
return renderApp({
...params,
pluginInitializerContext: this.initializerContext,
licensing,
core: coreStart,
navigation: pluginsStart.navigation,
data: pluginsStart.data,
savedObjectsClient: coreStart.savedObjects.client,
addBasePath: core.http.basePath.prepend,
getBasePath: core.http.basePath.get,
canEditDrillDownUrls: config.canEditDrillDownUrls,
graphSavePolicy: config.savePolicy,
storage: new Storage(window.localStorage),
capabilities: coreStart.application.capabilities.graph,
coreStart,
chrome: coreStart.chrome,
config: coreStart.uiSettings,
toastNotifications: coreStart.notifications.toasts,
indexPatterns: pluginsStart.data!.indexPatterns,
overlays: coreStart.overlays,
});
},
});
}
start(core: CoreStart) {
@ -66,5 +109,3 @@ export class GraphPlugin implements Plugin<{ config: Readonly<ConfigSchema> }, v
stop() {}
}
export type GraphSetup = ReturnType<GraphPlugin['setup']>;

View file

@ -5,7 +5,7 @@
*/
import { IndexPatternProvider } from '../types';
import { IndexPattern } from '../../../../../../src/plugins/data/public';
import { IndexPattern } from '../../../../../src/plugins/data/public';
export function createCachedIndexPatternProvider(
indexPatternGetter: (id: string) => Promise<IndexPattern>

View file

@ -8,7 +8,7 @@ import { GraphWorkspaceSavedObject, Workspace } from '../../types';
import { savedWorkspaceToAppState } from './deserialize';
import { createWorkspace } from '../../angular/graph_client_workspace';
import { outlinkEncoders } from '../../helpers/outlink_encoders';
import { IndexPattern } from '../../../../../../../src/plugins/data/public';
import { IndexPattern } from '../../../../../../src/plugins/data/public';
describe('deserialize', () => {
let savedWorkspace: GraphWorkspaceSavedObject;

View file

@ -27,7 +27,7 @@ import {
import {
IndexPattern,
indexPatterns as indexPatternsUtils,
} from '../../../../../../../src/plugins/data/public';
} from '../../../../../../src/plugins/data/public';
const defaultAdvancedSettings: AdvancedSettings = {
useSignificance: true,

View file

@ -9,7 +9,7 @@ import {
SavedObject,
createSavedObjectClass,
SavedObjectKibanaServices,
} from '../../../../../../../src/plugins/saved_objects/public';
} from '../../../../../../src/plugins/saved_objects/public';
export interface SavedWorkspace extends SavedObject {
wsState?: string;

View file

@ -7,7 +7,7 @@
import { IBasePath } from 'kibana/public';
import { i18n } from '@kbn/i18n';
import { SavedObjectKibanaServices } from '../../../../../../../src/plugins/saved_objects/public';
import { SavedObjectKibanaServices } from '../../../../../../src/plugins/saved_objects/public';
import { createSavedWorkspaceClass } from './saved_workspace';
export function createSavedWorkspacesLoader(

View file

@ -17,7 +17,7 @@ import {
setDatasource,
requestDatasource,
} from './datasource';
import { IndexPattern } from '../../../../../../src/plugins/data/public';
import { IndexPattern } from '../../../../../src/plugins/data/public';
/**
* Saga loading field information when the datasource is switched. This will overwrite current settings

Some files were not shown because too many files have changed in this diff Show more