Merge remote-tracking branch 'origin/master' into feature/merge-code

This commit is contained in:
Fuyao Zhao 2019-01-24 15:00:11 -08:00
commit 602d39678f
445 changed files with 8565 additions and 8600 deletions

View file

@ -20,9 +20,11 @@
"xpack.apm": "x-pack/plugins/apm",
"xpack.beatsManagement": "x-pack/plugins/beats_management",
"xpack.crossClusterReplication": "x-pack/plugins/cross_cluster_replication",
"xpack.dashboardMode": "x-pack/plugins/dashboard_mode",
"xpack.graph": "x-pack/plugins/graph",
"xpack.grokDebugger": "x-pack/plugins/grokdebugger",
"xpack.idxMgmt": "x-pack/plugins/index_management",
"xpack.indexLifecycleMgmt": "x-pack/plugins/index_lifecycle_management",
"xpack.infra": "x-pack/plugins/infra",
"xpack.licenseMgmt": "x-pack/plugins/license_management",
"xpack.ml": "x-pack/plugins/ml",

View file

@ -80,7 +80,7 @@ POST api/kibana/dashboards/import?exclude=index-pattern
"hits": 0,
"description": "",
"panelsJSON": "[{\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"1\"},\"version\":\"7.0.0-alpha1\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"id\":\"80b956f0-b2cd-11e8-ad8e-85441f0c2e5c\",\"embeddableConfig\":{}}]",
"optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}",
"optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}",
"version": 1,
"timeRestore": false,
"kibanaSavedObjectMeta": {

View file

@ -28,7 +28,7 @@ the shortened URL token for the provided request body.
--------------------------------------------------
POST api/shorten_url
{
"url": "/app/kibana#/dashboard?_g=()&_a=(description:'',filters:!(),fullScreenMode:!f,options:(darkTheme:!f,hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(),gridData:(h:15,i:'1',w:24,x:0,y:0),id:'8f4d0c00-4c86-11e8-b3d7-01146121b73d',panelIndex:'1',type:visualization,version:'7.0.0-alpha1')),query:(language:lucene,query:''),timeRestore:!f,title:'New%20Dashboard',viewMode:edit)",
"url": "/app/kibana#/dashboard?_g=()&_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(),gridData:(h:15,i:'1',w:24,x:0,y:0),id:'8f4d0c00-4c86-11e8-b3d7-01146121b73d',panelIndex:'1',type:visualization,version:'7.0.0-alpha1')),query:(language:lucene,query:''),timeRestore:!f,title:'New%20Dashboard',viewMode:edit)",
}
--------------------------------------------------
// KIBANA

View file

@ -77,7 +77,6 @@ mentioned use "_default_".
`timepicker:timeDefaults`:: The default time filter selection.
`timepicker:refreshIntervalDefaults`:: The time filter's default refresh interval.
`timepicker:quickRanges`:: The list of ranges to show in the Quick section of the time picker. This should be an array of objects, with each object containing `from`, `to` (see {ref}/common-options.html#date-math[accepted formats]), `display` (the title to be displayed), and `section` (which column to put the option in).
`dashboard:defaultDarkTheme`:: Set this property to `true` to make new dashboards use the dark theme by default.
`filters:pinnedByDefault`:: Set this property to `true` to make filters have a global state by default.
`filterEditor:suggestValues`:: Set this property to `false` to prevent the filter editor from suggesting values for fields.
`notifications:banner`:: You can specify a custom banner to display temporary notices to all users. This field supports

View file

@ -5,8 +5,6 @@
<titleabbrev>Collecting monitoring data with {metricbeat}</titleabbrev>
++++
beta[]
In 6.4 and later, you can use {metricbeat} to collect data about {kib}
and ship it to the monitoring cluster, rather than routing it through the
production cluster as described in <<monitoring-kibana>>.

View file

@ -172,3 +172,6 @@ The minimum value is 100.
`status.allowAnonymous:`:: *Default: false* If authentication is enabled, setting this to `true` allows
unauthenticated users to access the Kibana server status API and status page.
`rollup.enabled:`:: *Default: true* Set this value to false to disable the Rollup user interface.
`license_management.enabled`:: *Default: true* Set this value to false to disable the License Management user interface.

View file

@ -190,11 +190,11 @@
"pug": "^2.0.3",
"querystring-browser": "1.0.4",
"raw-loader": "0.5.1",
"react": "^16.3.0",
"react": "^16.6.0",
"react-addons-shallow-compare": "15.6.2",
"react-anything-sortable": "^1.7.4",
"react-color": "^2.13.8",
"react-dom": "^16.3.0",
"react-dom": "^16.6.0",
"react-grid-layout": "^0.16.2",
"react-input-range": "^1.3.0",
"react-markdown": "^3.4.1",
@ -325,9 +325,10 @@
"classnames": "2.2.5",
"dedent": "^0.7.0",
"delete-empty": "^2.0.0",
"enzyme": "3.2.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "3.3.1",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.6.0",
"enzyme-adapter-utils": "^1.8.1",
"enzyme-to-json": "^3.3.4",
"eslint": "^5.6.0",
"eslint-config-prettier": "^3.1.0",
"eslint-plugin-babel": "^5.2.0",

View file

@ -33,6 +33,7 @@ exports.help = (defaults = {}) => {
--version Version of ES to download [default: ${defaults.version}]
--base-path Path containing cache/installations [default: ${basePath}]
--install-path Installation path, defaults to 'source' within base-path
--data-archive Path to zip or tarball containing an ES data directory to seed the cluster with.
--password Sets password for elastic user [default: ${password}]
-E Additional key=value settings to pass to Elasticsearch
--download-only Download the snapshot but don't actually start it
@ -49,6 +50,7 @@ exports.run = async (defaults = {}) => {
alias: {
basePath: 'base-path',
installPath: 'install-path',
dataArchive: 'data-archive',
esArgs: 'E',
},
@ -62,6 +64,11 @@ exports.run = async (defaults = {}) => {
await cluster.downloadSnapshot(options);
} else {
const { installPath } = await cluster.installSnapshot(options);
if (options.dataArchive) {
await cluster.extractDataDirectory(installPath, options.dataArchive);
}
await cluster.run(installPath, { esArgs: options.esArgs });
}
};

View file

@ -33,6 +33,7 @@ exports.help = (defaults = {}) => {
--source-path Path to ES source [default: ${defaults['source-path']}]
--base-path Path containing cache/installations [default: ${basePath}]
--install-path Installation path, defaults to 'source' within base-path
--data-archive Path to zip or tarball containing an ES data directory to seed the cluster with.
--password Sets password for elastic user [default: ${password}]
-E Additional key=value settings to pass to Elasticsearch
@ -49,6 +50,7 @@ exports.run = async (defaults = {}) => {
basePath: 'base-path',
installPath: 'install-path',
sourcePath: 'source-path',
dataArchive: 'data-archive',
esArgs: 'E',
},
@ -57,5 +59,10 @@ exports.run = async (defaults = {}) => {
const cluster = new Cluster();
const { installPath } = await cluster.installSource(options);
if (options.dataArchive) {
await cluster.extractDataDirectory(installPath, options.dataArchive);
}
await cluster.run(installPath, { esArgs: options.esArgs });
};

View file

@ -19,9 +19,10 @@
const execa = require('execa');
const chalk = require('chalk');
const path = require('path');
const { downloadSnapshot, installSnapshot, installSource, installArchive } = require('./install');
const { ES_BIN } = require('./paths');
const { log: defaultLog, parseEsLog, extractConfigFiles } = require('./utils');
const { log: defaultLog, parseEsLog, extractConfigFiles, decompress } = require('./utils');
const { createCliError } = require('./errors');
const { promisify } = require('util');
const treeKillAsync = promisify(require('tree-kill'));
@ -116,6 +117,28 @@ exports.Cluster = class Cluster {
return { installPath };
}
/**
* Unpakcs a tar or zip file containing the data directory for an
* ES cluster.
*
* @param {String} installPath
* @param {String} archivePath
*/
async extractDataDirectory(installPath, archivePath) {
this._log.info(chalk.bold(`Extracting data directory`));
this._log.indent(4);
// decompress excludes the root directory as that is how our archives are
// structured. This works in our favor as we can explicitly extract into the data dir
const extractPath = path.resolve(installPath, 'data');
this._log.info(`Data archive: ${archivePath}`);
this._log.info(`Extract path: ${extractPath}`);
await decompress(archivePath, extractPath);
this._log.indent(-4);
}
/**
* Starts ES and returns resolved promise once started
*

View file

@ -29,7 +29,6 @@ import { render } from './render';
import { shape } from './shape';
import { string } from './string';
import { style } from './style';
import { kibanaTable } from './kibana_table';
import { kibanaContext } from './kibana_context';
export const typeSpecs = [
@ -45,6 +44,5 @@ export const typeSpecs = [
shape,
string,
style,
kibanaTable,
kibanaContext,
];

View file

@ -20,3 +20,4 @@
export { loadBrowserRegistries } from './browser_registries';
export { createSocket } from './socket';
export { initializeInterpreter } from './interpreter';
export { RenderFunctionsRegistry } from './render_functions_registry';

View file

@ -17,20 +17,26 @@
* under the License.
*/
import buildProcessorFunction from '../build_processor_function';
import _ from 'lodash';
import processors from '../response_processors/table';
export function RenderFunction(config) {
// This must match the name of the function that is used to create the `type: render` object
this.name = config.name;
export default function handleResponseBody(panel) {
return resp => {
if (resp.error) {
const err = new Error(resp.error.type);
err.response = JSON.stringify(resp);
throw err;
}
return panel.columns.map(column => {
const processor = buildProcessorFunction(processors, resp, panel, column);
return _.first(processor([]));
});
};
// Use this to set a more friendly name
this.displayName = config.displayName || this.name;
// A sentence or few about what this element does
this.help = config.help;
// used to validate the data before calling the render function
this.validate = config.validate || function validate() {};
// tell the renderer if the dom node should be reused, it's recreated each time by default
this.reuseDomNode = Boolean(config.reuseDomNode);
// the function called to render the data
this.render =
config.render ||
function render(domNode, data, done) {
done();
};
}

View file

@ -17,17 +17,13 @@
* under the License.
*/
import buildRequestBody from './build_request_body';
export default (req, panel, entities) => {
const bodies = [];
entities.forEach(entity => {
bodies.push({
index: panel.index_pattern,
ignoreUnavailable: true,
});
const body = buildRequestBody(req, panel, entity);
body.timeout = '90s';
bodies.push(body);
});
return bodies;
};
import { Registry } from '../common';
import { RenderFunction } from './render_function';
class RenderFunctionsRegistry extends Registry {
wrapper(obj) {
return new RenderFunction(obj);
}
}
export { RenderFunctionsRegistry };

View file

@ -36,6 +36,7 @@ export function createEsTestCluster(options = {}) {
log,
basePath = resolve(KIBANA_ROOT, '.es'),
esFrom = esTestConfig.getBuildFrom(),
dataArchive,
} = options;
const randomHash = Math.random()
@ -74,6 +75,10 @@ export function createEsTestCluster(options = {}) {
throw new Error(`unknown option esFrom "${esFrom}"`);
}
if (dataArchive) {
await cluster.extractDataDirectory(installPath, dataArchive);
}
await cluster.start(installPath, {
esArgs: [
`cluster.name=${clusterName}`,

View file

@ -37,6 +37,7 @@ export async function runElasticsearch({ config, options }) {
log,
basePath: resolve(KIBANA_ROOT, '.es'),
esFrom: esFrom || config.get('esTestCluster.from'),
dataArchive: config.get('esTestCluster.dataArchive'),
});
const esArgs = config.get('esTestCluster.serverArgs');

View file

@ -21,6 +21,7 @@ import chalk from 'chalk';
import { chmod, unlink, writeFile } from 'fs';
import dedent from 'dedent';
import normalizePath from 'normalize-path';
import os from 'os';
import { resolve } from 'path';
import { promisify } from 'util';
import SimpleGit from 'simple-git';
@ -128,7 +129,7 @@ export async function registerPrecommitGitHook(log) {
await getPrecommitGitHookScriptPath(REPO_ROOT),
getKbnPrecommitGitHookScript(
REPO_ROOT,
normalizePath(process.env.HOME.replace(/'/g, '\'')),
normalizePath(os.homedir()),
process.platform
)
);

View file

@ -139,6 +139,7 @@ export const schema = Joi.object().keys({
license: Joi.string().default('oss'),
from: Joi.string().default('snapshot'),
serverArgs: Joi.array(),
dataArchive: Joi.string(),
}).default(),
kbnTestServer: Joi.object().keys({

View file

@ -34,6 +34,7 @@ describe('plugins/elasticsearch', () => {
beforeEach(function () {
server = {
log: sinon.stub(),
logWithMetadata: sinon.stub(),
plugins: {
elasticsearch: {
getCluster: sinon.stub().withArgs('admin').returns({ callWithInternalUser: sinon.stub() }),
@ -120,17 +121,17 @@ describe('plugins/elasticsearch', () => {
it('warns if a node is only off by a patch version', async () => {
setNodes('5.1.1');
await ensureEsVersion(server, KIBANA_VERSION);
sinon.assert.callCount(server.log, 2);
expect(server.log.getCall(0).args[0]).to.contain('debug');
expect(server.log.getCall(1).args[0]).to.contain('warning');
sinon.assert.callCount(server.logWithMetadata, 2);
expect(server.logWithMetadata.getCall(0).args[0]).to.contain('debug');
expect(server.logWithMetadata.getCall(1).args[0]).to.contain('warning');
});
it('warns if a node is off by a patch version and without http publish address', async () => {
setNodeWithoutHTTP('5.1.1');
await ensureEsVersion(server, KIBANA_VERSION);
sinon.assert.callCount(server.log, 2);
expect(server.log.getCall(0).args[0]).to.contain('debug');
expect(server.log.getCall(1).args[0]).to.contain('warning');
sinon.assert.callCount(server.logWithMetadata, 2);
expect(server.logWithMetadata.getCall(0).args[0]).to.contain('debug');
expect(server.logWithMetadata.getCall(1).args[0]).to.contain('warning');
});
it('errors if a node incompatible and without http publish address', async () => {
@ -147,28 +148,28 @@ describe('plugins/elasticsearch', () => {
setNodes('5.1.1');
await ensureEsVersion(server, KIBANA_VERSION);
sinon.assert.callCount(server.log, 2);
expect(server.log.getCall(0).args[0]).to.contain('debug');
expect(server.log.getCall(1).args[0]).to.contain('warning');
sinon.assert.callCount(server.logWithMetadata, 2);
expect(server.logWithMetadata.getCall(0).args[0]).to.contain('debug');
expect(server.logWithMetadata.getCall(1).args[0]).to.contain('warning');
await ensureEsVersion(server, KIBANA_VERSION);
sinon.assert.callCount(server.log, 3);
expect(server.log.getCall(2).args[0]).to.contain('debug');
sinon.assert.callCount(server.logWithMetadata, 3);
expect(server.logWithMetadata.getCall(2).args[0]).to.contain('debug');
});
it('warns again if the node list changes', async () => {
setNodes('5.1.1');
await ensureEsVersion(server, KIBANA_VERSION);
sinon.assert.callCount(server.log, 2);
expect(server.log.getCall(0).args[0]).to.contain('debug');
expect(server.log.getCall(1).args[0]).to.contain('warning');
sinon.assert.callCount(server.logWithMetadata, 2);
expect(server.logWithMetadata.getCall(0).args[0]).to.contain('debug');
expect(server.logWithMetadata.getCall(1).args[0]).to.contain('warning');
setNodes('5.1.2');
await ensureEsVersion(server, KIBANA_VERSION);
sinon.assert.callCount(server.log, 4);
expect(server.log.getCall(2).args[0]).to.contain('debug');
expect(server.log.getCall(3).args[0]).to.contain('warning');
sinon.assert.callCount(server.logWithMetadata, 4);
expect(server.logWithMetadata.getCall(2).args[0]).to.contain('debug');
expect(server.logWithMetadata.getCall(3).args[0]).to.contain('warning');
});
});
});

View file

@ -85,7 +85,7 @@ describe('plugins/elasticsearch', () => {
// Setup the server mock
server = {
log: sinon.stub(),
logWithMetadata: sinon.stub(),
info: { port: 5601 },
config: function () { return { get, set }; },
plugins: {

View file

@ -54,7 +54,7 @@ export function createProxy(server) {
handler(req, h) {
const { query, payload: body } = req;
return callWithRequest(req, 'transport.request', {
path: `/${req.params.index}/_search`,
path: `/${encodeURIComponent(req.params.index)}/_search`,
method: 'POST',
query,
body

View file

@ -40,7 +40,7 @@ export function ensureEsVersion(server, kibanaVersion) {
const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin');
const isProd = server.config().get('env.prod');
server.log(['plugin', 'debug'], 'Checking Elasticsearch version');
server.logWithMetadata(['plugin', 'debug'], 'Checking Elasticsearch version');
return callWithInternalUser('nodes.info', {
filterPath: [
'nodes.*.version',
@ -92,15 +92,14 @@ export function ensureEsVersion(server, kibanaVersion) {
const warningNodeNames = getHumanizedNodeNames(simplifiedNodes).join(', ');
if (lastWarnedNodesForServer.get(server) !== warningNodeNames) {
lastWarnedNodesForServer.set(server, warningNodeNames);
server.log(['warning'], {
tmpl: (
`You're running Kibana ${kibanaVersion} with some different versions of ` +
server.logWithMetadata(['warning'],
`You're running Kibana ${kibanaVersion} with some different versions of ` +
'Elasticsearch. Update Kibana or Elasticsearch to the same ' +
`version to prevent compatibility issues: ${warningNodeNames}`
),
kibanaVersion,
nodes: simplifiedNodes,
});
`version to prevent compatibility issues: ${warningNodeNames}`,
{
kibanaVersion,
nodes: simplifiedNodes,
});
}
}

View file

@ -34,7 +34,7 @@ const courierRequestHandler = courierRequestHandlerProvider().handler;
export const esaggs = () => ({
name: 'esaggs',
type: 'kibana_table',
type: 'datatable',
context: {
types: [
'kibana_context',
@ -90,9 +90,12 @@ export const esaggs = () => ({
});
return {
type: 'kibana_table',
index: args.index,
...response,
type: 'datatable',
rows: response.rows,
columns: response.columns.map(column => ({
id: column.id,
name: column.name,
})),
};
},
});

View file

@ -24,7 +24,7 @@ export const metric = () => ({
type: 'render',
context: {
types: [
'kibana_table'
'datatable'
],
},
help: i18n.translate('interpreter.functions.metric.help', {

View file

@ -26,7 +26,7 @@ export const kibanaPie = () => ({
type: 'render',
context: {
types: [
'kibana_table', 'null'
'datatable'
],
},
help: i18n.translate('interpreter.functions.pie.help', {

View file

@ -24,7 +24,7 @@ export const regionmap = () => ({
type: 'render',
context: {
types: [
'kibana_table'
'datatable'
],
},
help: i18n.translate('interpreter.functions.regionmap.help', {

View file

@ -28,7 +28,7 @@ export const kibanaTable = () => ({
type: 'render',
context: {
types: [
'kibana_table'
'datatable'
],
},
help: i18n.translate('interpreter.functions.table.help', {

View file

@ -24,7 +24,7 @@ export const tagcloud = () => ({
type: 'render',
context: {
types: [
'kibana_table'
'datatable'
],
},
help: i18n.translate('interpreter.functions.tagcloud.help', {

View file

@ -25,7 +25,7 @@ export const tilemap = () => ({
type: 'render',
context: {
types: [
'kibana_table'
'datatable'
],
},
help: i18n.translate('interpreter.functions.tilemap.help', {

View file

@ -26,7 +26,7 @@ export const vislib = () => ({
type: 'render',
context: {
types: [
'kibana_table', 'null'
'datatable'
],
},
help: i18n.translate('interpreter.functions.vislib.help', {

View file

@ -44,9 +44,6 @@ function getHandler(from, type) {
export const visualization = () => ({
name: 'visualization',
type: 'render',
context: {
types: [],
},
help: i18n.translate('interpreter.functions.visualization.help', {
defaultMessage: 'A simple visualization'
}),

View file

@ -23,11 +23,13 @@ import chrome from 'ui/chrome';
import { functions } from './functions';
import { functionsRegistry } from './functions_registry';
import { typesRegistry } from './types_registry';
import { renderFunctionsRegistry } from './render_functions_registry';
const basePath = chrome.getBasePath();
const types = {
browserFunctions: functionsRegistry,
renderers: renderFunctionsRegistry,
types: typesRegistry
};

View file

@ -17,25 +17,6 @@
* under the License.
*/
export const kibanaTable = () => ({
name: 'kibana_table',
serialize: context => {
context.columns.forEach(column => {
column.aggConfig = column.aggConfig.toJSON();
});
return context;
},
validate: tabify => {
if (!tabify.columns) {
throw new Error('tabify must have a columns array, even if it is empty');
}
},
from: {
null: () => {
return {
type: 'kibana_table',
columns: [],
};
},
},
});
import { RenderFunctionsRegistry } from '@kbn/interpreter/public';
export const renderFunctionsRegistry = new RenderFunctionsRegistry();

View file

@ -103,7 +103,7 @@ export const createHeartbeatInstructions = context => ({
defaultMessage: 'Start Heartbeat',
}),
textPre: i18n.translate('kbn.common.tutorials.heartbeatInstructions.start.osxTextPre', {
defaultMessage: 'The `setup` command loads the Kibana dashboards. If the dashboards are already set up, omit this command.',
defaultMessage: 'The `setup` command loads the Kibana index pattern.',
}),
commands: [
'./heartbeat setup',
@ -115,7 +115,7 @@ export const createHeartbeatInstructions = context => ({
defaultMessage: 'Start Heartbeat',
}),
textPre: i18n.translate('kbn.common.tutorials.heartbeatInstructions.start.debTextPre', {
defaultMessage: 'The `setup` command loads the Kibana dashboards. If the dashboards are already set up, omit this command.',
defaultMessage: 'The `setup` command loads the Kibana index pattern.',
}),
commands: [
'sudo heartbeat setup',
@ -127,7 +127,7 @@ export const createHeartbeatInstructions = context => ({
defaultMessage: 'Start Heartbeat',
}),
textPre: i18n.translate('kbn.common.tutorials.heartbeatInstructions.start.rpmTextPre', {
defaultMessage: 'The `setup` command loads the Kibana dashboards. If the dashboards are already set up, omit this command.',
defaultMessage: 'The `setup` command loads the Kibana index pattern.',
}),
commands: [
'sudo heartbeat setup',
@ -139,7 +139,7 @@ export const createHeartbeatInstructions = context => ({
defaultMessage: 'Start Heartbeat',
}),
textPre: i18n.translate('kbn.common.tutorials.heartbeatInstructions.start.windowsTextPre', {
defaultMessage: 'The `setup` command loads the Kibana dashboards. If the dashboards are already set up, omit this command.',
defaultMessage: 'The `setup` command loads the Kibana index pattern.',
}),
commands: [
'.\\heartbeat.exe setup',

View file

@ -110,7 +110,6 @@ State communicated to the embeddable.
// TODO:
filters: FilterObject,
timeRange: TimeRangeObject,
darkTheme: boolean,
}
```

View file

@ -18,191 +18,3 @@ dashboard-listing {
flex: 1;
}
}
// Dark theme bootstrap
// Yes, this is a hack because bootstrap will be removed and everything must move to EUI theming
// Can't reliably remove all/any of these because of embeddables
.theme-dark {
@import '@elastic/eui/src/themes/k6/k6_colors_dark';
// /src/ui/public/styles/bootstrap/scaffolding.less
a {
color: $euiColorPrimary;
&:hover,
&:focus {
color: darken($euiColorPrimary, 10%);
}
}
// /src/ui/public/styles/bootstrap/forms.less
// Updated to match EUI dark theme
.form-control {
color: $euiTextColor;
background-color: tintOrShade($euiColorLightestShade, 60%, 25%);
border-color: transparentize($euiColorFullShade, .9);
&[disabled],
&[readonly],
fieldset[disabled] & {
background-color: darken($euiColorLightestShade, 2%);
}
}
// /src/ui/public/styles/bootstrap/tables.less
// Updated to match EUI dark theme
.table {
// Cells
> thead,
> tbody,
> tfoot {
> tr {
> th,
> td {
border-top-color: $euiColorLightShade;
}
}
}
// Bottom align for column headings
> thead > tr > th {
border-bottom-color: $euiColorLightShade;
}
// Account for multiple tbody instances
> tbody + tbody {
border-top-color: $euiColorLightShade;
}
// Nesting
.table {
background-color: transparent;
}
}
table {
th {
i.fa-sort {
color: $euiColorMediumShade;
}
button.fa-sort-asc,
button.fa-sort-down,
i.fa-sort-asc,
i.fa-sort-down {
color: $euiTextColor;
}
button.fa-sort-desc,
button.fa-sort-up,
i.fa-sort-desc,
i.fa-sort-up {
color: $euiTextColor;
}
}
}
// /src/ui/public/styles/bootstrap/list-group.less
.list-group-item {
background-color: $euiColorLightShade;
border-color: $euiColorDarkShade;
&:nth-child(even) {
background-color: $euiColorMediumShade;
}
}
a.list-group-item,
button.list-group-item {
color: $euiColorMediumShade;
.list-group-item-heading {
color: $euiColorLightShade;
}
// Hover state
&:hover,
&:focus {
color: $euiColorMediumShade;
background-color: $euiColorDarkestShade;
}
}
.panel {
> .panel-body + .table,
> .panel-body + .table-responsive,
> .table + .panel-body,
> .table-responsive + .panel-body {
border-top-color: $euiColorMediumShade;
}
}
.panel-group {
.panel-heading {
+ .panel-collapse > .panel-body,
+ .panel-collapse > .list-group {
border-top-color: $euiColorEmptyShade;
}
}
.panel-footer {
border-top: 0;
+ .panel-collapse .panel-body {
border-bottom-color: $euiColorEmptyShade;
}
}
}
.panel-default {
& > .panel-heading {
color: $euiColorPrimary;
background-color: $euiColorEmptyShade;
border-color: $euiColorLightShade;
+ .panel-collapse > .panel-body {
border-top-color: $euiColorLightShade;
}
.badge {
color: $euiColorEmptyShade;
background-color: $euiColorPrimary;
}
}
& > .panel-footer {
+ .panel-collapse > .panel-body {
border-bottom-color: $euiColorLightShade;
}
}
}
// /src/ui/public/styles/bootstrap/navs.less
.nav {
> li {
> a {
&:hover,
&:focus {
background-color: $euiColorDarkShade;
}
}
}
}
.nav-tabs {
border-bottom-color: $euiColorMediumShade;
> li {
> a {
&:hover {
border-color: $euiColorDarkShade;
}
}
&.active > a {
&,
&:hover,
&:focus {
color: $euiColorFullShade;
background-color: $euiColorMediumShade;
border: 0 none transparent;
}
}
}
}
}

View file

@ -13,35 +13,8 @@
// dshChart__legend--small
// dshChart__legend-isLoading
/**
* 1. Don't duplicate styles in dark mode
*/
.theme-light { /* 1 */
@import 'dashboard_app';
@import 'grid/index';
@import 'panel/index';
@import 'viewport/index';
}
// Imports outside of theme selector don't change between light/dark modes
@import 'dashboard_app';
@import 'grid/index';
@import 'panel/index';
@import 'viewport/index';
@import 'components/index';
// Must be outside of theme selector because it lives in a portal
@import 'panel/panel_header/panel_options_menu_form';
// DARK THEME
// EUI global scope -- dark
@import '@elastic/eui/src/themes/k6/k6_colors_dark';
.theme-dark {
background-color: $euiColorEmptyShade;
@import 'dashboard_app';
@import 'grid/index';
@import 'panel/index';
@import 'viewport/index';
// Vis imports
@import 'src/ui/public/vis/index';
@import 'src/ui/public/vislib/index';
}

View file

@ -22,7 +22,6 @@ import React from 'react';
import angular from 'angular';
import { uiModules } from 'ui/modules';
import chrome from 'ui/chrome';
import { applyTheme } from 'ui/theme';
import { toastNotifications } from 'ui/notify';
import 'ui/query_bar';
@ -230,8 +229,6 @@ app.directive('dashboardApp', function ($injector) {
$scope.refresh();
};
updateTheme();
$scope.indexPatterns = [];
$scope.onPanelRemoved = (panelIndex) => {
@ -433,11 +430,6 @@ app.directive('dashboardApp', function ($injector) {
navActions[TopNavIds.OPTIONS] = (menuItem, navController, anchorElement) => {
showOptionsPopover({
anchorElement,
darkTheme: dashboardStateManager.getDarkTheme(),
onDarkThemeChange: (isChecked) => {
dashboardStateManager.setDarkTheme(isChecked);
updateTheme();
},
useMargins: dashboardStateManager.getUseMargins(),
onUseMarginsChange: (isChecked) => {
dashboardStateManager.setUseMargins(isChecked);
@ -475,27 +467,8 @@ app.directive('dashboardApp', function ($injector) {
$scope.$on('$destroy', () => {
dashboardStateManager.destroy();
// Remove dark theme to keep it from affecting the appearance of other apps.
setLightTheme();
});
function updateTheme() {
dashboardStateManager.getDarkTheme() ? setDarkTheme() : setLightTheme();
}
function setDarkTheme() {
chrome.removeApplicationClass(['theme-light']);
chrome.addApplicationClass('theme-dark');
applyTheme('dark');
}
function setLightTheme() {
chrome.removeApplicationClass(['theme-dark']);
chrome.addApplicationClass('theme-light');
applyTheme('light');
}
if ($route.current.params && $route.current.params[DashboardConstants.NEW_VISUALIZATION_ID_PARAM]) {
dashboardStateManager.addNewPanel($route.current.params[DashboardConstants.NEW_VISUALIZATION_ID_PARAM], 'visualization');

View file

@ -369,15 +369,6 @@ export class DashboardStateManager {
this.saveState();
}
getDarkTheme() {
return this.appState.options.darkTheme;
}
setDarkTheme(darkTheme) {
this.appState.options.darkTheme = darkTheme;
this.saveState();
}
getTimeRestore() {
return this.appState.timeRestore;
}

View file

@ -524,50 +524,48 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = `
<EuiSpacer
size="m"
/>
<React.Fragment>
<EuiCallOut
color="warning"
iconType="help"
size="m"
title={
<FormattedMessage
defaultMessage="Listing limit exceeded"
id="kbn.dashboard.listing.listingLimitExceededTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="You have {totalDashboards} dashboards, but your {listingLimitText} setting prevents the table below from displaying more than {listingLimitValue}. You can change this setting under {advancedSettingsLink}."
id="kbn.dashboard.listing.listingLimitExceededDescription"
values={
Object {
"advancedSettingsLink": <EuiLink
color="primary"
href="#/management/kibana/settings"
type="button"
>
<FormattedMessage
defaultMessage="Advanced Settings"
id="kbn.dashboard.listing.listingLimitExceeded.advancedSettingsLinkText"
values={Object {}}
/>
</EuiLink>,
"listingLimitText": <strong>
listingLimit
</strong>,
"listingLimitValue": 1,
"totalDashboards": 2,
}
<EuiCallOut
color="warning"
iconType="help"
size="m"
title={
<FormattedMessage
defaultMessage="Listing limit exceeded"
id="kbn.dashboard.listing.listingLimitExceededTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="You have {totalDashboards} dashboards, but your {listingLimitText} setting prevents the table below from displaying more than {listingLimitValue}. You can change this setting under {advancedSettingsLink}."
id="kbn.dashboard.listing.listingLimitExceededDescription"
values={
Object {
"advancedSettingsLink": <EuiLink
color="primary"
href="#/management/kibana/settings"
type="button"
>
<FormattedMessage
defaultMessage="Advanced Settings"
id="kbn.dashboard.listing.listingLimitExceeded.advancedSettingsLinkText"
values={Object {}}
/>
</EuiLink>,
"listingLimitText": <strong>
listingLimit
</strong>,
"listingLimitValue": 1,
"totalDashboards": 2,
}
/>
</p>
</EuiCallOut>
<EuiSpacer
size="m"
/>
</React.Fragment>
}
/>
</p>
</EuiCallOut>
<EuiSpacer
size="m"
/>
<EuiFlexGroup
alignItems="stretch"
component="div"

View file

@ -1 +1,2 @@
@import "./dashboard_panel";
@import 'panel_header/panel_options_menu_form';

View file

@ -48,7 +48,6 @@ module.factory('SavedDashboard', function (Private, config, i18n) {
description: '',
panelsJSON: '[]',
optionsJSON: angular.toJson({
darkTheme: config.get('dashboard:defaultDarkTheme'),
// for BWC reasons we can't default dashboards that already exist without this setting to true.
useMargins: id ? false : true,
hidePanelTitles: false,

View file

@ -30,17 +30,10 @@ import {
class OptionsMenuUi extends Component {
state = {
darkTheme: this.props.darkTheme,
useMargins: this.props.useMargins,
hidePanelTitles: this.props.hidePanelTitles,
}
handleDarkThemeChange = (evt) => {
const isChecked = evt.target.checked;
this.props.onDarkThemeChange(isChecked);
this.setState({ darkTheme: isChecked });
}
handleUseMarginsChange = (evt) => {
const isChecked = evt.target.checked;
this.props.onUseMarginsChange(isChecked);
@ -59,18 +52,6 @@ class OptionsMenuUi extends Component {
data-test-subj="dashboardOptionsMenu"
>
<EuiFormRow>
<EuiSwitch
label={this.props.intl.formatMessage({
id: 'kbn.dashboard.topNav.options.useDarkThemeSwitchLabel',
defaultMessage: 'Use dark theme',
})}
checked={this.state.darkTheme}
onChange={this.handleDarkThemeChange}
data-test-subj="dashboardDarkThemeCheckbox"
/>
</EuiFormRow>
<EuiFormRow>
<EuiSwitch
label={this.props.intl.formatMessage({
@ -101,8 +82,6 @@ class OptionsMenuUi extends Component {
}
OptionsMenuUi.propTypes = {
darkTheme: PropTypes.bool.isRequired,
onDarkThemeChange: PropTypes.func.isRequired,
useMargins: PropTypes.bool.isRequired,
onUseMarginsChange: PropTypes.func.isRequired,
hidePanelTitles: PropTypes.bool.isRequired,

View file

@ -38,8 +38,6 @@ const onClose = () => {
export function showOptionsPopover({
anchorElement,
darkTheme,
onDarkThemeChange,
useMargins,
onUseMarginsChange,
hidePanelTitles,
@ -64,8 +62,6 @@ export function showOptionsPopover({
closePopover={onClose}
>
<OptionsMenu
darkTheme={darkTheme}
onDarkThemeChange={onDarkThemeChange}
useMargins={useMargins}
onUseMarginsChange={onUseMarginsChange}
hidePanelTitles={hidePanelTitles}

View file

@ -1012,22 +1012,20 @@ exports[`home should render home component 1`] = `
<EuiPageBody
restrictWidth={false}
>
<React.Fragment>
<RecentlyAccessed
recentlyAccessed={
Array [
Object {
"id": "1",
"label": "my vis",
"link": "link_to_my_vis",
},
]
}
/>
<EuiSpacer
size="l"
/>
</React.Fragment>
<RecentlyAccessed
recentlyAccessed={
Array [
Object {
"id": "1",
"label": "my vis",
"link": "link_to_my_vis",
},
]
}
/>
<EuiSpacer
size="l"
/>
<InjectIntl(AddDataUi)
apmUiEnabled={true}
isNewKibanaInstance={false}

View file

@ -49,82 +49,74 @@ exports[`render 1`] = `
responsive={true}
wrap={false}
>
<React.Fragment
key="0"
>
<EuiFlexItem
className="homRecentlyAccessed__item"
component="div"
grow={false}
style={
Object {
"minWidth": "3.9000000000000004em",
}
<EuiFlexItem
className="homRecentlyAccessed__item"
component="div"
grow={false}
style={
Object {
"minWidth": "3.9000000000000004em",
}
>
<EuiToolTip
anchorClassName="homRecentlyAccessed__anchor"
content="label0"
delay="regular"
position="bottom"
>
<EuiLink
className="homRecentlyAccessed__longLink"
color="primary"
href="link0"
type="button"
>
label0
</EuiLink>
</EuiToolTip>
</EuiFlexItem>
</React.Fragment>
<React.Fragment
key="1"
}
>
<EuiFlexItem
className="homRecentlyAccessed__separator"
component="div"
grow={false}
<EuiToolTip
anchorClassName="homRecentlyAccessed__anchor"
content="label0"
delay="regular"
position="bottom"
>
<EuiText
grow={true}
<EuiLink
className="homRecentlyAccessed__longLink"
color="primary"
href="link0"
type="button"
>
label0
</EuiLink>
</EuiToolTip>
</EuiFlexItem>
<EuiFlexItem
className="homRecentlyAccessed__separator"
component="div"
grow={false}
>
<EuiText
grow={true}
size="m"
>
<EuiIcon
color="subdued"
size="m"
>
<EuiIcon
color="subdued"
size="m"
type="dot"
/>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
className="homRecentlyAccessed__item"
component="div"
grow={false}
style={
Object {
"minWidth": "3.9000000000000004em",
}
type="dot"
/>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
className="homRecentlyAccessed__item"
component="div"
grow={false}
style={
Object {
"minWidth": "3.9000000000000004em",
}
}
>
<EuiToolTip
anchorClassName="homRecentlyAccessed__anchor"
content="label1"
delay="regular"
position="bottom"
>
<EuiToolTip
anchorClassName="homRecentlyAccessed__anchor"
content="label1"
delay="regular"
position="bottom"
<EuiLink
className="homRecentlyAccessed__longLink"
color="primary"
href="link1"
type="button"
>
<EuiLink
className="homRecentlyAccessed__longLink"
color="primary"
href="link1"
type="button"
>
label1
</EuiLink>
</EuiToolTip>
</EuiFlexItem>
</React.Fragment>
label1
</EuiLink>
</EuiToolTip>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem

View file

@ -8,32 +8,30 @@ exports[`isCloudEnabled is false should not render instruction toggle when ON_PR
<EuiPageBody
restrictWidth={false}
>
<React.Fragment>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
</React.Fragment>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
<div>
<InjectIntl(IntroductionUI)
description="tutorial used to drive jest tests"
@ -89,32 +87,30 @@ exports[`isCloudEnabled is false should render ON_PREM instructions with instruc
<EuiPageBody
restrictWidth={false}
>
<React.Fragment>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
</React.Fragment>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
<div>
<InjectIntl(IntroductionUI)
description="tutorial used to drive jest tests"
@ -263,32 +259,30 @@ exports[`should render ELASTIC_CLOUD instructions when isCloudEnabled is true 1`
<EuiPageBody
restrictWidth={false}
>
<React.Fragment>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
</React.Fragment>
<div>
<EuiLink
color="primary"
href="#/home"
type="button"
>
Home
</EuiLink>
/
<EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
Add data
</EuiLink>
/
jest test tutorial
</div>
<EuiSpacer
size="s"
/>
<div>
<InjectIntl(IntroductionUI)
description="tutorial used to drive jest tests"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Before After
Before After

View file

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CreateIndexPatternWizard defaults to the loading state 1`] = `
<React.Fragment>
<Fragment>
<div>
<Header
indexPatternName="name"
@ -17,11 +17,11 @@ exports[`CreateIndexPatternWizard defaults to the loading state 1`] = `
toastLifeTimeMs={6000}
toasts={Array []}
/>
</React.Fragment>
</Fragment>
`;
exports[`CreateIndexPatternWizard renders index pattern step when there are indices 1`] = `
<React.Fragment>
<Fragment>
<div>
<Header
indexPatternName="name"
@ -61,11 +61,11 @@ exports[`CreateIndexPatternWizard renders index pattern step when there are indi
toastLifeTimeMs={6000}
toasts={Array []}
/>
</React.Fragment>
</Fragment>
`;
exports[`CreateIndexPatternWizard renders the empty state when there are no indices 1`] = `
<React.Fragment>
<Fragment>
<div>
<Header
indexPatternName="name"
@ -83,11 +83,11 @@ exports[`CreateIndexPatternWizard renders the empty state when there are no indi
toastLifeTimeMs={6000}
toasts={Array []}
/>
</React.Fragment>
</Fragment>
`;
exports[`CreateIndexPatternWizard renders time field step when step is set to 2 1`] = `
<React.Fragment>
<Fragment>
<div>
<Header
indexPatternName="name"
@ -119,11 +119,11 @@ exports[`CreateIndexPatternWizard renders time field step when step is set to 2
toastLifeTimeMs={6000}
toasts={Array []}
/>
</React.Fragment>
</Fragment>
`;
exports[`CreateIndexPatternWizard renders when there are no indices but there are remote clusters 1`] = `
<React.Fragment>
<Fragment>
<div>
<Header
indexPatternName="name"
@ -157,11 +157,11 @@ exports[`CreateIndexPatternWizard renders when there are no indices but there ar
toastLifeTimeMs={6000}
toasts={Array []}
/>
</React.Fragment>
</Fragment>
`;
exports[`CreateIndexPatternWizard shows system indices even if there are no other indices if the include system indices is toggled 1`] = `
<React.Fragment>
<Fragment>
<div>
<Header
indexPatternName="name"
@ -201,5 +201,5 @@ exports[`CreateIndexPatternWizard shows system indices even if there are no othe
toastLifeTimeMs={6000}
toasts={Array []}
/>
</React.Fragment>
</Fragment>
`;

View file

@ -196,6 +196,6 @@ describe('CreateIndexPatternWizard', () => {
expect(get).toBeCalled();
expect(create).toBeCalled();
expect(clear).toBeCalledWith('id');
expect(changeUrl).toBeCalledWith(`/management/kibana/indices/id`);
expect(changeUrl).toBeCalledWith(`/management/kibana/index_patterns/id`);
});
});

View file

@ -1,5 +1,5 @@
<kbn-management-app section="kibana/indices">
<kbn-management-indices>
<kbn-management-app section="kibana/index_patterns">
<kbn-management-index-patterns>
<div id="createIndexPatternReact"></div>
</kbn-management-indices>
</kbn-management-index-patterns>
</kbn-management-app>

View file

@ -16,13 +16,11 @@ exports[`Header should render a different name, prompt, and beta tag if provided
}
}
/>
<React.Fragment>
<EuiBetaBadge
label="Beta"
tooltipPosition="top"
/>
</React.Fragment>
<EuiBetaBadge
label="Beta"
tooltipPosition="top"
/>
</h1>
</EuiTitle>
<EuiFlexGroup
@ -57,14 +55,12 @@ exports[`Header should render a different name, prompt, and beta tag if provided
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
<React.Fragment>
<EuiSpacer
size="s"
/>
<div>
Test prompt
</div>
</React.Fragment>
<EuiSpacer
size="s"
/>
<div>
Test prompt
</div>
<EuiSpacer
size="m"
/>

View file

@ -2,6 +2,7 @@
exports[`StatusMessage should render with exact matches 1`] = `
<EuiText
data-test-subj="createIndexPatternStatusMessage"
grow={true}
size="s"
>
@ -48,6 +49,7 @@ exports[`StatusMessage should render with exact matches 1`] = `
exports[`StatusMessage should render with no partial matches 1`] = `
<EuiText
data-test-subj="createIndexPatternStatusMessage"
grow={true}
size="s"
>
@ -83,6 +85,7 @@ exports[`StatusMessage should render with no partial matches 1`] = `
exports[`StatusMessage should render with partial matches 1`] = `
<EuiText
data-test-subj="createIndexPatternStatusMessage"
grow={true}
size="s"
>
@ -118,6 +121,7 @@ exports[`StatusMessage should render with partial matches 1`] = `
exports[`StatusMessage should render without a query 1`] = `
<EuiText
data-test-subj="createIndexPatternStatusMessage"
grow={true}
size="s"
>
@ -145,6 +149,7 @@ exports[`StatusMessage should render without a query 1`] = `
exports[`StatusMessage should show that no indices exist 1`] = `
<EuiText
data-test-subj="createIndexPatternStatusMessage"
grow={true}
size="s"
>
@ -165,6 +170,7 @@ exports[`StatusMessage should show that no indices exist 1`] = `
exports[`StatusMessage should show that system indices exist 1`] = `
<EuiText
data-test-subj="createIndexPatternStatusMessage"
grow={true}
size="s"
>

View file

@ -161,7 +161,7 @@ export const StatusMessage = ({
}
return (
<EuiText size="s">
<EuiText size="s" data-test-subj="createIndexPatternStatusMessage">
<EuiTextColor color={statusColor}>
{ statusIcon ? <EuiIcon type={statusIcon}/> : null }
{statusMessage}

View file

@ -136,7 +136,7 @@ export class CreateIndexPatternWizard extends Component {
}
services.indexPatterns.cache.clear(createdId);
services.changeUrl(`/management/kibana/indices/${createdId}`);
services.changeUrl(`/management/kibana/index_patterns/${createdId}`);
}
goToTimeFieldStep = (indexPattern) => {

View file

@ -26,7 +26,7 @@ import { getCreateBreadcrumbs } from '../breadcrumbs';
import { renderCreateIndexPatternWizard, destroyCreateIndexPatternWizard } from './render';
uiRoutes.when('/management/kibana/index', {
uiRoutes.when('/management/kibana/index_pattern', {
template: angularTemplate,
k7Breadcrumbs: getCreateBreadcrumbs,
controller: function ($scope, $injector) {

View file

@ -1,12 +1,12 @@
<kbn-management-app section="kibana/indices">
<kbn-management-indices>
<kbn-management-app section="kibana/index_patterns">
<kbn-management-index-patterns>
<div class="kuiViewContent">
<kbn-management-index-header
<kbn-management-index-patterns-header
index-pattern="fieldSettings.indexPattern"
></kbn-management-index-header>
></kbn-management-index-patterns-header>
</div>
<div id="reactFieldEditor"></div>
</kbn-management-indices>
</kbn-management-index-patterns>
</kbn-management-app>

View file

@ -71,15 +71,15 @@ const destroyFieldEditor = () => {
};
uiRoutes
.when('/management/kibana/indices/:indexPatternId/field/:fieldName*', {
.when('/management/kibana/index_patterns/:indexPatternId/field/:fieldName*', {
mode: 'edit',
k7Breadcrumbs: getEditFieldBreadcrumbs
})
.when('/management/kibana/indices/:indexPatternId/create-field/', {
.when('/management/kibana/index_patterns/:indexPatternId/create-field/', {
mode: 'create',
k7Breadcrumbs: getCreateFieldBreadcrumbs
})
.defaults(/management\/kibana\/indices\/[^\/]+\/(field|create-field)(\/|$)/, {
.defaults(/management\/kibana\/index_patterns\/[^\/]+\/(field|create-field)(\/|$)/, {
template,
mapBreadcrumbs($route, breadcrumbs) {
const { indexPattern } = $route.current.locals;
@ -97,7 +97,7 @@ uiRoutes
resolve: {
indexPattern: function ($route, redirectWhenMissing, indexPatterns) {
return indexPatterns.get($route.current.params.indexPatternId)
.catch(redirectWhenMissing('/management/kibana/indices'));
.catch(redirectWhenMissing('/management/kibana/index_patterns'));
}
},
controllerAs: 'fieldSettings',

View file

@ -1,18 +1,18 @@
<kbn-management-app section="kibana/indices" omit-breadcrumb-pages="['indices']">
<kbn-management-indices>
<kbn-management-app section="kibana/index_patterns" omit-breadcrumb-pages="['index_patterns']">
<kbn-management-index-patterns>
<div
ng-controller="managementIndicesEdit"
ng-controller="managementIndexPatternsEdit"
data-test-subj="editIndexPattern"
role="region"
aria-label="{{::'kbn.management.editIndexPattern.detailsAria' | i18n: { defaultMessage: 'Index pattern details' } }}"
>
<!-- Header -->
<kbn-management-index-header
<kbn-management-index-patterns-header
index-pattern="indexPattern"
set-default="setDefaultPattern()"
refresh-fields="refreshFields()"
delete="removePattern()"
></kbn-management-index-header>
></kbn-management-index-patterns-header>
<div class="euiSpacer euiSpacer--s"></div>
<p ng-if="::(indexPattern.timeFieldName || (indexPattern.tags && indexPattern.tags.length))">
@ -178,5 +178,5 @@
<div id="reactSourceFiltersTable"></div>
</div>
</div>
</kbn-management-indices>
</kbn-management-index-patterns>
</kbn-management-app>

View file

@ -157,32 +157,32 @@ function destroyIndexedFieldsTable() {
}
uiRoutes
.when('/management/kibana/indices/:indexPatternId', {
.when('/management/kibana/index_patterns/:indexPatternId', {
template,
k7Breadcrumbs: getEditBreadcrumbs,
resolve: {
indexPattern: function ($route, redirectWhenMissing, indexPatterns) {
return indexPatterns
.get($route.current.params.indexPatternId)
.catch(redirectWhenMissing('/management/kibana/index'));
.catch(redirectWhenMissing('/management/kibana/index_pattern'));
}
},
});
uiRoutes
.when('/management/kibana/indices', {
.when('/management/kibana/index_patterns', {
redirectTo() {
const defaultIndex = chrome.getUiSettingsClient().get('defaultIndex');
if (defaultIndex) {
return `/management/kibana/indices/${defaultIndex}`;
return `/management/kibana/index_patterns/${defaultIndex}`;
}
return '/management/kibana/index';
return '/management/kibana/index_pattern';
}
});
uiModules.get('apps/management')
.controller('managementIndicesEdit', function (
.controller('managementIndexPatternsEdit', function (
$scope, $location, $route, config, indexPatterns, Private, AppState, docTitle, confirmModal) {
const $state = $scope.state = new AppState();
const { fieldWildcardMatcher } = Private(FieldWildcardProvider);
@ -275,7 +275,7 @@ uiModules.get('apps/management')
indexPatterns.delete($scope.indexPattern)
.then(function () {
$location.url('/management/kibana/index');
$location.url('/management/kibana/index_patterns');
})
.catch(fatalError);
}

View file

@ -21,7 +21,7 @@ import { uiModules } from 'ui/modules';
import template from './index_header.html';
uiModules
.get('apps/management')
.directive('kbnManagementIndexHeader', function (config) {
.directive('kbnManagementIndexPatternsHeader', function (config) {
return {
restrict: 'E',
template,

View file

@ -2,26 +2,24 @@
exports[`Table editing should show a save button 1`] = `
<div>
<React.Fragment>
<EuiButtonIcon
aria-label="Save"
color="primary"
iconSize="m"
iconType="checkInCircleFilled"
onClick={[Function]}
size="s"
type="button"
/>
<EuiButtonIcon
aria-label="Cancel"
color="primary"
iconSize="m"
iconType="cross"
onClick={[Function]}
size="s"
type="button"
/>
</React.Fragment>
<EuiButtonIcon
aria-label="Save"
color="primary"
iconSize="m"
iconType="checkInCircleFilled"
onClick={[Function]}
size="s"
type="button"
/>
<EuiButtonIcon
aria-label="Cancel"
color="primary"
iconSize="m"
iconType="cross"
onClick={[Function]}
size="s"
type="button"
/>
</div>
`;

View file

@ -78,13 +78,13 @@ const indexPatternsResolutions = {
// add a dependency to all of the subsection routes
uiRoutes
.defaults(/management\/kibana\/(indices|index)/, {
.defaults(/management\/kibana\/(index_patterns|index_pattern)/, {
resolve: indexPatternsResolutions
});
// wrapper directive, which sets some global stuff up like the left nav
uiModules.get('apps/management')
.directive('kbnManagementIndices', function ($route, config, kbnUrl, Private) {
.directive('kbnManagementIndexPatterns', function ($route, config, kbnUrl, Private) {
return {
restrict: 'E',
transclude: true,
@ -104,7 +104,7 @@ uiModules.get('apps/management')
return {
id: id,
title: pattern.get('title'),
url: kbnUrl.eval('#/management/kibana/indices/{{id}}', { id: id }),
url: kbnUrl.eval('#/management/kibana/index_patterns/{{id}}', { id: id }),
active: $scope.editingId === id,
default: $scope.defaultIndex === id,
tag: tags && tags.length ? tags[0] : null,
@ -137,10 +137,10 @@ uiModules.get('apps/management')
};
});
management.getSection('kibana').register('indices', {
management.getSection('kibana').register('index_patterns', {
display: i18n.translate('kbn.management.indexPattern.sectionsHeader', { defaultMessage: 'Index Patterns' }),
order: 0,
url: '#/management/kibana/indices/'
url: '#/management/kibana/index_patterns/'
});
FeatureCatalogueRegistryProvider.register(() => {
@ -150,7 +150,7 @@ FeatureCatalogueRegistryProvider.register(() => {
description: i18n.translate('kbn.management.indexPatternLabel',
{ defaultMessage: 'Manage the index patterns that help retrieve your data from Elasticsearch.' }),
icon: 'indexPatternApp',
path: '/app/kibana#/management/kibana/indices',
path: '/app/kibana#/management/kibana/index_patterns',
showOnHomePage: true,
category: FeatureCatalogueCategory.ADMIN
};

View file

@ -24,45 +24,43 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
/>
</h2>
</EuiTitle>
<React.Fragment>
<EuiSpacer
size="s"
/>
<EuiCallOut
color="warning"
iconType="help"
size="m"
title={
<FormattedMessage
defaultMessage="Index Pattern Conflicts"
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
values={
Object {
"indexPatternLink": <EuiLink
color="primary"
href=""
type="button"
>
<FormattedMessage
defaultMessage="create a new index pattern"
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
values={Object {}}
/>
</EuiLink>,
}
<EuiSpacer
size="s"
/>
<EuiCallOut
color="warning"
iconType="help"
size="m"
title={
<FormattedMessage
defaultMessage="Index Pattern Conflicts"
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
values={
Object {
"indexPatternLink": <EuiLink
color="primary"
href=""
type="button"
>
<FormattedMessage
defaultMessage="create a new index pattern"
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
values={Object {}}
/>
</EuiLink>,
}
/>
</p>
</EuiCallOut>
</React.Fragment>
}
/>
</p>
</EuiCallOut>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiInMemoryTable

View file

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Header should render normally 1`] = `
<React.Fragment>
<Fragment>
<EuiFlexGroup
alignItems="baseline"
component="div"
@ -130,5 +130,5 @@ exports[`Header should render normally 1`] = `
<EuiSpacer
size="m"
/>
</React.Fragment>
</Fragment>
`;

View file

@ -40,77 +40,73 @@ exports[`Relationships should render dashboards normally 1`] = `
textStyle="normal"
type="row"
>
<React.Fragment
key="visualizations"
<EuiDescriptionListTitle
style={
Object {
"marginBottom": "1rem",
}
}
>
<EuiDescriptionListTitle
style={
Object {
"marginBottom": "1rem",
}
<EuiCallOut
color="success"
size="m"
title={
<FormattedMessage
defaultMessage="Dashboard"
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutTitle"
values={Object {}}
/>
}
>
<EuiCallOut
color="success"
size="m"
title={
<FormattedMessage
defaultMessage="Dashboard"
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="Here are some visualizations used on this dashboard. You can safely delete this dashboard and the visualizations will still work properly."
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "1",
},
Object {
"id": "2",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
</React.Fragment>
<p>
<FormattedMessage
defaultMessage="Here are some visualizations used on this dashboard. You can safely delete this dashboard and the visualizations will still work properly."
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "1",
},
Object {
"id": "2",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
</EuiDescriptionList>
</EuiFlyoutBody>
</EuiFlyout>
@ -248,142 +244,134 @@ exports[`Relationships should render searches normally 1`] = `
textStyle="normal"
type="row"
>
<React.Fragment
key="indexPatterns"
<EuiDescriptionListTitle
style={
Object {
"marginBottom": "1rem",
}
}
>
<EuiDescriptionListTitle
style={
Object {
"marginBottom": "1rem",
}
<EuiCallOut
color="success"
size="m"
title={
<FormattedMessage
defaultMessage="Saved Search"
id="kbn.management.objects.objectsTable.relationships.search.calloutTitle"
values={Object {}}
/>
}
>
<EuiCallOut
color="success"
size="m"
title={
<FormattedMessage
defaultMessage="Saved Search"
id="kbn.management.objects.objectsTable.relationships.search.calloutTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="Here is the index pattern tied to this saved search."
id="kbn.management.objects.objectsTable.relationships.search.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "1",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
</React.Fragment>
<React.Fragment
key="visualizations"
>
<EuiDescriptionListTitle
style={
<p>
<FormattedMessage
defaultMessage="Here is the index pattern tied to this saved search."
id="kbn.management.objects.objectsTable.relationships.search.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"marginBottom": "1rem",
}
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "1",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
<EuiDescriptionListTitle
style={
Object {
"marginBottom": "1rem",
}
}
>
<EuiCallOut
color="warning"
size="m"
title={
<FormattedMessage
defaultMessage="Warning"
id="kbn.management.objects.objectsTable.relationships.warningTitle"
values={Object {}}
/>
}
>
<EuiCallOut
color="warning"
size="m"
title={
<FormattedMessage
defaultMessage="Warning"
id="kbn.management.objects.objectsTable.relationships.warningTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="Here are some visualizations that use this saved search. If you delete this saved search, these visualizations will not longer work properly."
id="kbn.management.objects.objectsTable.relationships.search.visualizations.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "2",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
</React.Fragment>
<p>
<FormattedMessage
defaultMessage="Here are some visualizations that use this saved search. If you delete this saved search, these visualizations will not longer work properly."
id="kbn.management.objects.objectsTable.relationships.search.visualizations.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "2",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
</EuiDescriptionList>
</EuiFlyoutBody>
</EuiFlyout>
@ -429,77 +417,73 @@ exports[`Relationships should render visualizations normally 1`] = `
textStyle="normal"
type="row"
>
<React.Fragment
key="dashboards"
<EuiDescriptionListTitle
style={
Object {
"marginBottom": "1rem",
}
}
>
<EuiDescriptionListTitle
style={
Object {
"marginBottom": "1rem",
}
<EuiCallOut
color="warning"
size="m"
title={
<FormattedMessage
defaultMessage="Warning"
id="kbn.management.objects.objectsTable.relationships.warningTitle"
values={Object {}}
/>
}
>
<EuiCallOut
color="warning"
size="m"
title={
<FormattedMessage
defaultMessage="Warning"
id="kbn.management.objects.objectsTable.relationships.warningTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="Here are some dashboards which contain this visualization. If you delete this visualization, these dashboards will no longer show them."
id="kbn.management.objects.objectsTable.relationships.visualization.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "1",
},
Object {
"id": "2",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
</React.Fragment>
<p>
<FormattedMessage
defaultMessage="Here are some dashboards which contain this visualization. If you delete this visualization, these dashboards will no longer show them."
id="kbn.management.objects.objectsTable.relationships.visualization.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
<EuiInMemoryTable
columns={
Array [
Object {
"render": [Function],
"width": 24,
},
Object {
"field": "title",
"name": "Title",
"render": [Function],
},
Object {
"actions": Array [
Object {
"description": "View this saved object within Kibana",
"icon": "eye",
"name": "In app",
"onClick": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
items={
Array [
Object {
"id": "1",
},
Object {
"id": "2",
},
]
}
pagination={true}
responsive={true}
sorting={false}
/>
</EuiDescriptionList>
</EuiFlyoutBody>
</EuiFlyout>

View file

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Table should render normally 1`] = `
<React.Fragment>
<Fragment>
<EuiSearchBar
box={
Object {
@ -136,5 +136,5 @@ exports[`Table should render normally 1`] = `
}
/>
</div>
</React.Fragment>
</Fragment>
`;

View file

@ -1,9 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Form should not render no settings message when instructed not to 1`] = `<React.Fragment />`;
exports[`Form should not render no settings message when instructed not to 1`] = `<Fragment />`;
exports[`Form should render no settings message when there are no settings 1`] = `
<React.Fragment>
<Fragment>
<EuiPanel
grow={true}
hasShadow={false}
@ -29,225 +29,213 @@ exports[`Form should render no settings message when there are no settings 1`] =
}
/>
</EuiPanel>
</React.Fragment>
</Fragment>
`;
exports[`Form should render normally 1`] = `
<React.Fragment>
<React.Fragment
key="general"
<Fragment>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<EuiForm>
<EuiText
grow={true}
size="m"
<EuiForm>
<EuiText
grow={true}
size="m"
>
<EuiFlexGroup
alignItems="baseline"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={false}
>
<EuiFlexGroup
alignItems="baseline"
<EuiFlexItem
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={false}
grow={false}
>
<EuiFlexItem
component="div"
grow={false}
>
<h2>
General
</h2>
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>
<EuiSpacer
size="m"
/>
<Field
clear={[Function]}
key="general:test:date"
save={[Function]}
setting={
Object {
"ariaName": "general test date",
"category": Array [
"general",
],
"description": "bar",
"displayName": "Test date",
"name": "general:test:date",
}
<h2>
General
</h2>
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>
<EuiSpacer
size="m"
/>
<Field
clear={[Function]}
key="general:test:date"
save={[Function]}
setting={
Object {
"ariaName": "general test date",
"category": Array [
"general",
],
"description": "bar",
"displayName": "Test date",
"name": "general:test:date",
}
/>
<Field
clear={[Function]}
key="setting:test"
save={[Function]}
setting={
Object {
"ariaName": "setting test",
"category": Array [
"general",
],
"description": "foo",
"displayName": "Test setting",
"name": "setting:test",
}
}
/>
<Field
clear={[Function]}
key="setting:test"
save={[Function]}
setting={
Object {
"ariaName": "setting test",
"category": Array [
"general",
],
"description": "foo",
"displayName": "Test setting",
"name": "setting:test",
}
/>
</EuiForm>
</EuiPanel>
<EuiSpacer
size="l"
/>
</React.Fragment>
<React.Fragment
key="dashboard"
}
/>
</EuiForm>
</EuiPanel>
<EuiSpacer
size="l"
/>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<EuiForm>
<EuiText
grow={true}
size="m"
<EuiForm>
<EuiText
grow={true}
size="m"
>
<EuiFlexGroup
alignItems="baseline"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={false}
>
<EuiFlexGroup
alignItems="baseline"
<EuiFlexItem
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={false}
grow={false}
>
<EuiFlexItem
component="div"
grow={false}
>
<h2>
Dashboard
</h2>
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>
<EuiSpacer
size="m"
/>
<Field
clear={[Function]}
key="dashboard:test:setting"
save={[Function]}
setting={
Object {
"ariaName": "dashboard test setting",
"category": Array [
"dashboard",
],
"displayName": "Dashboard test setting",
"name": "dashboard:test:setting",
}
<h2>
Dashboard
</h2>
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>
<EuiSpacer
size="m"
/>
<Field
clear={[Function]}
key="dashboard:test:setting"
save={[Function]}
setting={
Object {
"ariaName": "dashboard test setting",
"category": Array [
"dashboard",
],
"displayName": "Dashboard test setting",
"name": "dashboard:test:setting",
}
/>
</EuiForm>
</EuiPanel>
<EuiSpacer
size="l"
/>
</React.Fragment>
<React.Fragment
key="x-pack"
}
/>
</EuiForm>
</EuiPanel>
<EuiSpacer
size="l"
/>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<EuiForm>
<EuiText
grow={true}
size="m"
<EuiForm>
<EuiText
grow={true}
size="m"
>
<EuiFlexGroup
alignItems="baseline"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={false}
>
<EuiFlexGroup
alignItems="baseline"
<EuiFlexItem
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={false}
grow={false}
>
<EuiFlexItem
component="div"
grow={false}
>
<h2>
X-pack
</h2>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<em>
<FormattedMessage
defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}"
id="kbn.management.settings.form.searchResultText"
values={
Object {
"clearSearch": <EuiLink
color="primary"
onClick={[Function]}
type="button"
>
<em>
<FormattedMessage
defaultMessage="(clear search)"
id="kbn.management.settings.form.clearSearchResultText"
values={Object {}}
/>
</em>
</EuiLink>,
"settingsCount": 9,
}
<h2>
X-pack
</h2>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<em>
<FormattedMessage
defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}"
id="kbn.management.settings.form.searchResultText"
values={
Object {
"clearSearch": <EuiLink
color="primary"
onClick={[Function]}
type="button"
>
<em>
<FormattedMessage
defaultMessage="(clear search)"
id="kbn.management.settings.form.clearSearchResultText"
values={Object {}}
/>
</em>
</EuiLink>,
"settingsCount": 9,
}
/>
</em>
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>
<EuiSpacer
size="m"
/>
<Field
clear={[Function]}
key="xpack:test:setting"
save={[Function]}
setting={
Object {
"ariaName": "xpack test setting",
"category": Array [
"x-pack",
],
"description": "bar",
"displayName": "X-Pack test setting",
"name": "xpack:test:setting",
}
}
/>
</em>
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>
<EuiSpacer
size="m"
/>
<Field
clear={[Function]}
key="xpack:test:setting"
save={[Function]}
setting={
Object {
"ariaName": "xpack test setting",
"category": Array [
"x-pack",
],
"description": "bar",
"displayName": "X-Pack test setting",
"name": "xpack:test:setting",
}
/>
</EuiForm>
</EuiPanel>
<EuiSpacer
size="l"
/>
</React.Fragment>
</React.Fragment>
}
/>
</EuiForm>
</EuiPanel>
<EuiSpacer
size="l"
/>
</Fragment>
`;

View file

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Search should render normally 1`] = `
<React.Fragment>
<Fragment>
<EuiSearchBar
box={
Object {
@ -57,5 +57,5 @@ exports[`Search should render normally 1`] = `
}
}
/>
</React.Fragment>
</Fragment>
`;

View file

@ -91,7 +91,7 @@ export function onPremInstructions(apmIndexPattern) {
bool: {
filter: {
exists: {
field: 'listening',
field: 'observer.listening',
},
},
},

View file

@ -65,8 +65,8 @@ var apm = require('elastic-apm-node').start({curlyOpen}
defaultMessage: 'See [the documentation]({documentationLink}) for advanced usage, including how to use with \
[Babel/ES Modules]({babelEsModulesLink}).',
values: {
documentationLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/1.x/index.html',
babelEsModulesLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/1.x/advanced-setup.html#es-modules',
documentationLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html',
babelEsModulesLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules',
},
}),
},
@ -128,7 +128,7 @@ MIDDLEWARE = (
)`.split('\n'),
textPost: i18n.translate('kbn.server.tutorials.apm.djangoClient.configure.textPost', {
defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.',
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/python/2.x/django-support.html' },
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html' },
}),
},
];
@ -186,7 +186,7 @@ app.config['ELASTIC_APM'] = {curlyOpen}
apm = ElasticAPM(app)`.split('\n'),
textPost: i18n.translate('kbn.server.tutorials.apm.flaskClient.configure.textPost', {
defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.',
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/python/2.x/flask-support.html' },
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html' },
}),
},
];
@ -222,7 +222,7 @@ export const createRailsAgentInstructions = (apmServerUrl = '', secretToken = ''
# server_url: '${apmServerUrl || 'http://localhost:8200'}'`.split('\n'),
textPost: i18n.translate('kbn.server.tutorials.apm.railsClient.configure.textPost', {
defaultMessage: 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/1.x/index.html' },
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html' },
}),
},
];
@ -296,7 +296,7 @@ export const createRackAgentInstructions = (apmServerUrl = '', secretToken = '')
# server_url: '${apmServerUrl || 'http://localhost:8200'}'`.split('\n'),
textPost: i18n.translate('kbn.server.tutorials.apm.rackClient.createConfig.textPost', {
defaultMessage: 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n',
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/1.x/index.html' },
values: { documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html' },
}),
},
];

View file

@ -17,9 +17,13 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
import { i18n } from '@kbn/i18n';
import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category';
import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/heartbeat_instructions';
import {
onPremInstructions,
cloudInstructions,
onPremCloudInstructions,
} from '../../../common/tutorials/heartbeat_instructions';
export function uptimeMonitorsSpecProvider(server, context) {
return {
@ -32,7 +36,8 @@ export function uptimeMonitorsSpecProvider(server, context) {
defaultMessage: 'Monitor services for their availability',
}),
longDescription: i18n.translate('kbn.server.tutorials.uptimeMonitors.longDescription', {
defaultMessage: 'Monitor services for their availability with active probing. \
defaultMessage:
'Monitor services for their availability with active probing. \
Given a list of URLs, Heartbeat asks the simple question: Are you alive? \
[Learn more]({learnMoreLink}).',
values: {
@ -41,23 +46,24 @@ export function uptimeMonitorsSpecProvider(server, context) {
}),
euiIconType: 'heartbeatApp',
artifacts: {
dashboards: [
{
id: 'f3e771c0-eb19-11e6-be20-559646f8b9ba',
linkLabel: i18n.translate('kbn.server.tutorials.uptimeMonitors.artifacts.dashboards.linkLabel', {
defaultMessage: 'Heartbeat dashboard',
}),
isOverview: true
}
],
dashboards: [],
application: {
path: '/app/uptime',
label: i18n.translate(
'kbn.server.tutorials.uptimeMonitors.artifacts.dashboards.linkLabel',
{
defaultMessage: 'Uptime App',
}
),
},
exportedFields: {
documentationUrl: '{config.docs.beats.heartbeat}/exported-fields.html'
}
documentationUrl: '{config.docs.beats.heartbeat}/exported-fields.html',
},
},
completionTimeMinutes: 10,
previewImagePath: '/plugins/kibana/home/tutorial_resources/uptime_monitors/screenshot.png',
onPrem: onPremInstructions(null, null, null, context),
elasticCloud: cloudInstructions(),
onPremElasticCloud: onPremCloudInstructions()
onPremElasticCloud: onPremCloudInstructions(),
};
}

View file

@ -823,16 +823,6 @@ export function getUiSettingDefaults() {
},
}),
},
'dashboard:defaultDarkTheme': {
name: i18n.translate('kbn.advancedSettings.dashboardDarkThemeTitle', {
defaultMessage: 'Dark theme',
}),
value: false,
description: i18n.translate('kbn.advancedSettings.dashboardDarkThemeText', {
defaultMessage: 'New dashboards use dark theme by default',
}),
category: ['dashboard'],
},
'filters:pinnedByDefault': {
name: i18n.translate('kbn.advancedSettings.pinFiltersTitle', {
defaultMessage: 'Pin filters by default',

View file

@ -26,7 +26,6 @@ import Visualization from './visualization';
import VisPicker from './vis_picker';
import PanelConfig from './panel_config';
import brushHandler from '../lib/create_brush_handler';
import { get } from 'lodash';
import { extractIndexPatterns } from '../lib/extract_index_patterns';
import { fetchFields } from '../lib/fetch_fields';
import chrome from 'ui/chrome';
@ -37,17 +36,14 @@ class VisEditor extends Component {
super(props);
const { vis } = props;
this.appState = vis.API.getAppState();
const reversed = get(this.appState, 'options.darkTheme', false);
this.state = {
model: props.vis.params,
dirty: false,
autoApply: true,
reversed,
visFields: {},
};
this.onBrush = brushHandler(props.vis.API.timeFilter);
this.handleUiState = this.handleUiState.bind(this, props.vis);
this.handleAppStateChange = this.handleAppStateChange.bind(this);
this.getConfig = this.getConfig.bind(this);
this.visDataSubject = new Rx.Subject();
this.visData$ = this.visDataSubject.asObservable().pipe(share());
@ -61,23 +57,6 @@ class VisEditor extends Component {
vis.uiStateVal(...args);
}
componentWillMount() {
if (this.appState) {
this.appState.on('save_with_changes', this.handleAppStateChange);
}
}
handleAppStateChange() {
const reversed = get(this.appState, 'options.darkTheme', false);
this.setState({ reversed });
}
componentWillUnmount() {
if (this.appState) {
this.appState.off('save_with_changes', this.handleAppStateChange);
}
}
fetchIndexPatternFields = async () => {
const { params } = this.props.vis;
const { visFields } = this.state;
@ -134,12 +113,11 @@ class VisEditor extends Component {
if (!this.props.vis.params || !this.props.visData) {
return null;
}
const reversed = this.state.reversed;
return (
<I18nProvider>
<Visualization
dateFormat={this.props.config.get('dateFormat')}
reversed={reversed}
reversed={false}
onBrush={this.onBrush}
onUiState={this.handleUiState}
uiState={this.props.vis.getUiState()}

View file

@ -3,7 +3,6 @@
// depending on dark/light theme and/or background color provided
// An easier way would be to provide if the theme is dark in the JS,
// but it wasn't passed down.
.tab-dashboard.theme-dark .tvbVisMetric--noBackground &,
.tvbVisMetric--reversed & {
@content;
}

View file

@ -1,57 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import getRequestParams from './get_request_params';
import handleResponseBody from './handle_response_body';
import handleErrorResponse from '../handle_error_response';
import getLastValue from '../../../../common/get_last_value';
import _ from 'lodash';
import regression from 'regression';
export function getColumnData(req, panel, entities, client) {
const elasticsearch = _.get(req, 'server.plugins.elasticsearch');
if (elasticsearch) {
const { callWithRequest } = elasticsearch.getCluster('data');
if (!client) {
client = callWithRequest.bind(null, req);
}
}
const params = {
rest_total_hits_as_int: true,
body: getRequestParams(req, panel, entities)
};
return client('msearch', params)
.then(resp => {
const handler = handleResponseBody(panel);
return entities.map((entity, index) => {
entity.data = {};
handler(resp.responses[index]).forEach(row => {
const linearRegression = regression('linear', row.data);
entity.data[row.id] = {
last: getLastValue(row.data),
slope: linearRegression.equation[0],
yIntercept: linearRegression.equation[1],
label: row.label
};
});
return entity;
});
})
.catch(handleErrorResponse(panel));
}

View file

@ -34,10 +34,6 @@
.ngLegendValue {
color: $euiTextColor;
.tab-dashboard.theme-dark & {
color: $euiColorLightShade;
}
&:focus,
&:hover {
text-decoration: underline;
@ -52,10 +48,6 @@
.flot-tick-label {
color: $euiColorDarkShade;
.tab-dashboard.theme-dark & {
color: $euiColorMediumShade;
}
}
}
@ -63,8 +55,4 @@
color: $euiTextColor;
white-space: nowrap;
font-weight: $euiFontWeightBold;
.tab-dashboard.theme-dark & {
color: $euiColorLightShade;
}
}

View file

@ -46,7 +46,7 @@ const STATS_WARNINGS_FILTER = new RegExp([
export default class BaseOptimizer {
constructor(opts) {
this.log = opts.log || (() => null);
this.logWithMetadata = opts.logWithMetadata || (() => null);
this.uiBundles = opts.uiBundles;
this.profile = opts.profile || false;
@ -270,7 +270,7 @@ export default class BaseOptimizer {
new DynamicDllPlugin({
uiBundles: this.uiBundles,
threadLoaderPoolConfig: this.getThreadLoaderPoolConfig(),
log: this.log
logWithMetadata: this.logWithMetadata
}),
new MiniCssExtractPlugin({

View file

@ -51,13 +51,13 @@ export class DllCompiler {
};
}
constructor(uiBundles, threadLoaderPoolConfig, log) {
constructor(uiBundles, threadLoaderPoolConfig, logWithMetadata) {
this.rawDllConfig = DllCompiler.getRawDllConfig(
uiBundles,
uiBundles.getCacheDirectory('babel'),
threadLoaderPoolConfig
);
this.log = log || (() => null);
this.logWithMetadata = logWithMetadata || (() => null);
}
async init() {
@ -182,7 +182,7 @@ export class DllCompiler {
async runWebpack(config) {
return new Promise((resolve, reject) => {
this.log(['info', 'optimize:dynamic_dll_plugin'], 'Client vendors dll compilation started');
this.logWithMetadata(['info', 'optimize:dynamic_dll_plugin'], 'Client vendors dll compilation started');
webpack(config, (err, stats) => {
// If a critical error occurs or we have
@ -197,7 +197,7 @@ export class DllCompiler {
}));
if (webpackErrors) {
this.log(
this.logWithMetadata(
['fatal', 'optimize:dynamic_dll_plugin'],
`Client vendors dll compilation failed`
);
@ -205,7 +205,7 @@ export class DllCompiler {
}
// Otherwise let it proceed
this.log(
this.logWithMetadata(
['info', 'optimize:dynamic_dll_plugin'],
`Client vendors dll compilation finished with success`
);

View file

@ -40,9 +40,9 @@ function inPluginNodeModules(checkPath) {
}
export class DynamicDllPlugin {
constructor({ uiBundles, threadLoaderPoolConfig, log, maxCompilations = 1 }) {
this.log = log || (() => null);
this.dllCompiler = new DllCompiler(uiBundles, threadLoaderPoolConfig, log);
constructor({ uiBundles, threadLoaderPoolConfig, logWithMetadata, maxCompilations = 1 }) {
this.logWithMetadata = logWithMetadata || (() => null);
this.dllCompiler = new DllCompiler(uiBundles, threadLoaderPoolConfig, logWithMetadata);
this.entryPaths = '';
this.afterCompilationEntryPaths = '';
this.maxCompilations = maxCompilations;
@ -92,7 +92,7 @@ export class DynamicDllPlugin {
}
registerTasksHooks(compiler) {
this.log(['info', 'optimize:dynamic_dll_plugin'], 'Started dynamic dll plugin tasks');
this.logWithMetadata(['info', 'optimize:dynamic_dll_plugin'], 'Started dynamic dll plugin tasks');
this.registerBeforeCompileHook(compiler);
this.registerCompilationHook(compiler);
this.registerDoneHook(compiler);
@ -231,7 +231,7 @@ export class DynamicDllPlugin {
// Only run this info log in the first performed dll compilation
// per each execution run
if (this.performedCompilations === 0) {
this.log(
this.logWithMetadata(
['info', 'optimize:dynamic_dll_plugin'],
compilation.needsDLLCompilation
? 'Need to compile the client vendors dll'
@ -269,7 +269,7 @@ export class DynamicDllPlugin {
if (this.forceDLLCreationFlag) {
this.forceDLLCreationFlag = false;
}
this.log(['info', 'optimize:dynamic_dll_plugin'], 'Finished all dynamic dll plugin tasks');
this.logWithMetadata(['info', 'optimize:dynamic_dll_plugin'], 'Finished all dynamic dll plugin tasks');
});
}

View file

@ -62,7 +62,7 @@ export default async (kbnServer, server, config) => {
// only require the FsOptimizer when we need to
const optimizer = new FsOptimizer({
log: (tags, data) => server.log(tags, data),
logWithMetadata: (tags, message, metadata) => server.logWithMetadata(tags, message, metadata),
uiBundles,
profile: config.get('optimize.profile'),
sourceMaps: config.get('optimize.sourceMaps'),

View file

@ -25,16 +25,16 @@ import { DllCompiler } from '../dynamic_dll_plugin';
import { WatchCache } from './watch_cache';
export default async (kbnServer, kibanaHapiServer, config) => {
const log = (tags, data) => kibanaHapiServer.log(tags, data);
const logWithMetadata = (tags, message, metadata) => kibanaHapiServer.logWithMetadata(tags, message, metadata);
const watchOptimizer = new WatchOptimizer({
log,
logWithMetadata,
uiBundles: kbnServer.uiBundles,
profile: config.get('optimize.profile'),
sourceMaps: config.get('optimize.sourceMaps'),
prebuild: config.get('optimize.watchPrebuild'),
watchCache: new WatchCache({
log,
logWithMetadata,
outputPath: config.get('path.data'),
dllsPath: DllCompiler.getRawDllConfig().outputPath,
cachePath: resolve(kbnServer.uiBundles.getCacheDirectory(), '../'),

View file

@ -31,7 +31,7 @@ const readAsync = promisify(readFile);
const writeAsync = promisify(writeFile);
interface Params {
log: (tags: string[], data: string) => void;
logWithMetadata: (tags: string[], message: string, metadata?: { [key: string]: any }) => void;
outputPath: string;
dllsPath: string;
cachePath: string;
@ -43,7 +43,7 @@ interface WatchCacheStateContent {
}
export class WatchCache {
private readonly log: Params['log'];
private readonly logWithMetadata: Params['logWithMetadata'];
private readonly outputPath: Params['outputPath'];
private readonly dllsPath: Params['dllsPath'];
private readonly cachePath: Params['cachePath'];
@ -53,7 +53,7 @@ export class WatchCache {
private isInitialized: boolean;
constructor(params: Params) {
this.log = params.log;
this.logWithMetadata = params.logWithMetadata;
this.outputPath = params.outputPath;
this.dllsPath = params.dllsPath;
this.cachePath = params.cachePath;
@ -87,7 +87,7 @@ export class WatchCache {
}
public async reset() {
this.log(['info', 'optimize:watch_cache'], 'The optimizer watch cache will reset');
this.logWithMetadata(['info', 'optimize:watch_cache'], 'The optimizer watch cache will reset');
// start by deleting the state file to lower the
// amount of time that another process might be able to
@ -116,7 +116,7 @@ export class WatchCache {
// re-write new cache state file
await this.write();
this.log(['info', 'optimize:watch_cache'], 'The optimizer watch cache has reset');
this.logWithMetadata(['info', 'optimize:watch_cache'], 'The optimizer watch cache has reset');
}
private async buildShaWithMultipleFiles(filePaths: string[]) {

View file

@ -156,16 +156,14 @@ export default class WatchOptimizer extends BaseOptimizer {
switch (type) {
case STATUS.RUNNING:
if (!this.initialBuildComplete) {
this.log(['info', 'optimize'], {
tmpl: 'Optimization started',
this.logWithMetadata(['info', 'optimize'], `Optimization started`, {
bundles: this.uiBundles.getIds()
});
}
break;
case STATUS.SUCCESS:
this.log(['info', 'optimize'], {
tmpl: 'Optimization <%= status %> in <%= seconds %> seconds',
this.logWithMetadata(['info', 'optimize'], `Optimization success in ${seconds} seconds`, {
bundles: this.uiBundles.getIds(),
status: 'success',
seconds
@ -176,8 +174,7 @@ export default class WatchOptimizer extends BaseOptimizer {
// errors during initialization to the server, unlike the rest of the
// errors produced here. Lets not muddy the console with extra errors
if (!this.initializing) {
this.log(['fatal', 'optimize'], {
tmpl: 'Optimization <%= status %> in <%= seconds %> seconds<%= err %>',
this.logWithMetadata(['fatal', 'optimize'], `Optimization failed in ${seconds} seconds${error}`, {
bundles: this.uiBundles.getIds(),
status: 'failed',
seconds,
@ -187,7 +184,7 @@ export default class WatchOptimizer extends BaseOptimizer {
break;
case STATUS.FATAL:
this.log('fatal', error);
this.logWithMetadata('fatal', error);
process.exit(1);
break;
}

View file

@ -124,7 +124,10 @@ export class Config {
});
if (results.error) {
throw results.error;
const error = new Error(results.error.message);
error.name = results.error.name;
error.stack = results.error.stack;
throw error;
}
this[vals] = results.value;

View file

@ -174,7 +174,7 @@ describe('lib/config/config', function () {
});
it('should thow an exception when setting a value with the wrong type', function (done) {
expect.assertions(2);
expect.assertions(4);
const run = function () {
config.set('test.enable', 'something');
@ -184,7 +184,11 @@ describe('lib/config/config', function () {
run();
} catch (err) {
expect(err).toHaveProperty('name', 'ValidationError');
expect(err.details[0].message).toBe('"enable" must be a boolean');
expect(err).toHaveProperty('message',
'child \"test\" fails because [child \"enable\" fails because [\"enable\" must be a boolean]]'
);
expect(err).not.toHaveProperty('details');
expect(err).not.toHaveProperty('_object');
}
done();

View file

@ -162,11 +162,6 @@ export default class TransformObjStream extends Stream.Transform {
else if (logWithMetadata.isLogEvent(event.data)) {
_.assign(data, logWithMetadata.getLogEventData(event.data));
}
else if (_.isPlainObject(event.data) && event.data.tmpl) {
_.assign(data, event.data);
data.tmpl = undefined;
data.message = _.template(event.data.tmpl)(event.data);
}
else {
data.message = _.isString(event.data) ? event.data : inspect(event.data);
}

View file

@ -33,24 +33,23 @@ export default Promise.method(function (kbnServer, server, config) {
.catch(function (err) {
if (err.code !== 'EEXIST') throw err;
const log = {
tmpl: 'pid file already exists at <%= path %>',
const message = `pid file already exists at ${path}`;
const metadata = {
path: path,
pid: pid
};
if (config.get('pid.exclusive')) {
throw Boom.internal(_.template(log.tmpl)(log), log);
throw Boom.internal(message, { message, ...metadata });
} else {
server.log(['pid', 'warning'], log);
server.log(['pid', 'warning'], message, metadata);
}
return writeFile(path, pid);
})
.then(function () {
server.log(['pid', 'debug'], {
tmpl: 'wrote pid file to <%= path %>',
server.logWithMetadata(['pid', 'debug'], `wrote pid file to ${path}`, {
path: path,
pid: pid
});

View file

@ -66,8 +66,7 @@ export class Plugin {
this._server = server;
this._options = options;
server.log(['plugins', 'debug'], {
tmpl: 'Initializing plugin <%= plugin.toString() %>',
server.logWithMetadata(['plugins', 'debug'], `Initializing plugin ${this.toString()}`, {
plugin: this
});

View file

@ -38,17 +38,16 @@ export async function scanMixin(kbnServer, server, config) {
const logging$ = Rx.merge(
pack$.pipe(
tap(definition => {
server.log(['plugin', 'debug'], {
tmpl: 'Found plugin at <%= path %>',
path: definition.getPath()
const path = definition.getPath();
server.logWithMetadata(['plugin', 'debug'], `Found plugin at ${path}`, {
path
});
})
),
invalidDirectoryError$.pipe(
tap(error => {
server.log(['plugin', 'warning'], {
tmpl: '<%= err.code %>: Unable to scan directory for plugins "<%= dir %>"',
server.logWithMetadata(['plugin', 'warning'], `${error.code}: Unable to scan directory for plugins "${error.path}"`, {
err: error,
dir: error.path
});
@ -57,8 +56,7 @@ export async function scanMixin(kbnServer, server, config) {
invalidPackError$.pipe(
tap(error => {
server.log(['plugin', 'warning'], {
tmpl: 'Skipping non-plugin directory at <%= path %>',
server.logWithMetadata(['plugin', 'warning'], `Skipping non-plugin directory at ${error.path}`, {
path: error.path
});
})

View file

@ -28,6 +28,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.salesByCategoryTitle', {
defaultMessage: '[eCommerce] Sales by Category',
@ -46,6 +47,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.salesByGenderTitle', {
defaultMessage: '[eCommerce] Sales by Gender',
@ -64,6 +66,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.markdownTitle', {
defaultMessage: '[eCommerce] Markdown',
@ -82,6 +85,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.controlsTitle', {
defaultMessage: '[eCommerce] Controls',
@ -100,6 +104,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:17:30.755Z",
"version": 2,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.promotionTrackingTitle', {
defaultMessage: '[eCommerce] Promotion Tracking',
@ -118,6 +123,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.totalRevenueTitle', {
defaultMessage: '[eCommerce] Total Revenue',
@ -136,6 +142,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.soldProductsPerDayTitle', {
defaultMessage: '[eCommerce] Sold Products per Day',
@ -154,6 +161,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.averageSalesPriceTitle', {
defaultMessage: '[eCommerce] Average Sales Price',
@ -172,6 +180,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.averageSoldQuantityTitle', {
defaultMessage: '[eCommerce] Average Sold Quantity',
@ -190,6 +199,7 @@ export const getSavedObjects = () => [
"type": "search",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.ordersTitle', {
defaultMessage: '[eCommerce] Orders',
@ -217,6 +227,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.averageSalesPerRegionTitle', {
defaultMessage: '[eCommerce] Average Sales Per Region',
@ -235,6 +246,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.topSellingProductsTitle', {
defaultMessage: '[eCommerce] Top Selling Products',
@ -253,6 +265,7 @@ export const getSavedObjects = () => [
"type": "index-pattern",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": "kibana_sample_data_ecommerce",
"timeFieldName": "order_date",
@ -265,6 +278,7 @@ export const getSavedObjects = () => [
"type": "dashboard",
"updated_at": "2018-10-01T15:13:03.270Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.ecommerceSpec.revenueDashboardTitle', {
defaultMessage: '[eCommerce] Revenue Dashboard',
@ -274,7 +288,7 @@ export const getSavedObjects = () => [
defaultMessage: 'Analyze mock eCommerce orders and revenue',
}),
"panelsJSON": "[{\"embeddableConfig\":{\"vis\":{\"colors\":{\"Men's Accessories\":\"#82B5D8\",\"Men's Clothing\":\"#F9BA8F\",\"Men's Shoes\":\"#F29191\",\"Women's Accessories\":\"#F4D598\",\"Women's Clothing\":\"#70DBED\",\"Women's Shoes\":\"#B7DBAB\"}}},\"gridData\":{\"x\":12,\"y\":18,\"w\":36,\"h\":10,\"i\":\"1\"},\"id\":\"37cc8650-b882-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{\"vis\":{\"colors\":{\"FEMALE\":\"#6ED0E0\",\"MALE\":\"#447EBC\"},\"legendOpen\":false}},\"gridData\":{\"x\":12,\"y\":7,\"w\":12,\"h\":11,\"i\":\"2\"},\"id\":\"ed8436b0-b88b-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"2\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":0,\"w\":18,\"h\":7,\"i\":\"3\"},\"id\":\"09ffee60-b88c-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"3\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":18,\"y\":0,\"w\":30,\"h\":7,\"i\":\"4\"},\"id\":\"1c389590-b88d-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"4\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":28,\"w\":48,\"h\":11,\"i\":\"5\"},\"id\":\"45e07720-b890-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"5\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":18,\"w\":12,\"h\":10,\"i\":\"6\"},\"id\":\"10f1a240-b891-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"6\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":7,\"w\":12,\"h\":11,\"i\":\"7\"},\"id\":\"b80e6540-b891-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"7\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{\"vis\":{\"colors\":{\"0 - 50\":\"#E24D42\",\"50 - 75\":\"#EAB839\",\"75 - 100\":\"#7EB26D\"},\"defaultColors\":{\"0 - 50\":\"rgb(165,0,38)\",\"50 - 75\":\"rgb(255,255,190)\",\"75 - 100\":\"rgb(0,104,55)\"},\"legendOpen\":false}},\"gridData\":{\"x\":24,\"y\":7,\"w\":12,\"h\":11,\"i\":\"8\"},\"id\":\"4b3ec120-b892-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"8\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{\"vis\":{\"colors\":{\"0 - 2\":\"#E24D42\",\"2 - 3\":\"#F2C96D\",\"3 - 4\":\"#9AC48A\"},\"defaultColors\":{\"0 - 2\":\"rgb(165,0,38)\",\"2 - 3\":\"rgb(255,255,190)\",\"3 - 4\":\"rgb(0,104,55)\"},\"legendOpen\":false}},\"gridData\":{\"x\":36,\"y\":7,\"w\":12,\"h\":11,\"i\":\"9\"},\"id\":\"9ca7aa90-b892-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"9\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":54,\"w\":48,\"h\":18,\"i\":\"10\"},\"id\":\"3ba638e0-b894-11e8-a6d9-e546fe2bba5f\",\"panelIndex\":\"10\",\"type\":\"search\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{\"mapZoom\":2,\"mapCenter\":[28.304380682962783,-22.148437500000004]},\"gridData\":{\"x\":0,\"y\":39,\"w\":24,\"h\":15,\"i\":\"11\"},\"id\":\"9c6f83f0-bb4d-11e8-9c84-77068524bcab\",\"panelIndex\":\"11\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":24,\"y\":39,\"w\":24,\"h\":15,\"i\":\"12\"},\"id\":\"b72dd430-bb4d-11e8-9c84-77068524bcab\",\"panelIndex\":\"12\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"}]",
"optionsJSON": "{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}",
"optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}",
"version": 1,
"timeRestore": true,
"timeTo": "now",

File diff suppressed because one or more lines are too long

View file

@ -28,6 +28,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.uniqueVisitorsTitle', {
defaultMessage: '[Logs] Unique Visitors vs. Average Bytes',
@ -46,6 +47,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.uniqueVisitorsByCountryTitle', {
defaultMessage: '[Logs] Unique Visitors by Country',
@ -64,6 +66,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.heatmapTitle', {
defaultMessage: '[Logs] Heatmap',
@ -82,6 +85,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:23:20.897Z",
"version": 2,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.hostVisitsBytesTableTitle', {
defaultMessage: '[Logs] Host, Visits and Bytes Table',
@ -100,6 +104,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:24:46.136Z",
"version": 2,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.goalsTitle', {
defaultMessage: '[Logs] Goals',
@ -118,6 +123,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.fileTypeScatterPlotTitle', {
defaultMessage: '[Logs] File Type Scatter Plot',
@ -136,6 +142,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.sourceAndDestinationSankeyChartTitle', {
defaultMessage: '[Logs] Source and Destination Sankey Chart',
@ -154,6 +161,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.responseCodesOverTimeTitle', {
defaultMessage: '[Logs] Response Codes Over Time + Annotations',
@ -172,6 +180,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.inputControlsTitle', {
defaultMessage: '[Logs] Input Controls',
@ -190,6 +199,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.articleTagsTitle', {
defaultMessage: '[Logs] Article Tags',
@ -208,6 +218,7 @@ export const getSavedObjects = () => [
"type": "visualization",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.markdownInstructionsTitle', {
defaultMessage: '[Logs] Markdown Instructions',
@ -226,6 +237,7 @@ export const getSavedObjects = () => [
"type": "index-pattern",
"updated_at": "2018-08-29T13:22:17.617Z",
"version": 1,
"migrationVersion": {},
"attributes": {
"title": "kibana_sample_data_logs",
"timeFieldName": "timestamp",
@ -238,6 +250,7 @@ export const getSavedObjects = () => [
"type": "dashboard",
"updated_at": "2018-08-29T13:26:13.463Z",
"version": 3,
"migrationVersion": {},
"attributes": {
"title": i18n.translate('server.sampleData.logsSpec.webTrafficTitle', {
defaultMessage: '[Logs] Web Traffic',
@ -247,7 +260,7 @@ export const getSavedObjects = () => [
defaultMessage: 'Analyze mock web traffic log data for Elastic\'s website',
}),
"panelsJSON": "[{\"embeddableConfig\":{\"vis\":{\"colors\":{\"Avg. Bytes\":\"#6ED0E0\",\"Unique Visitors\":\"#0A437C\"},\"legendOpen\":false}},\"gridData\":{\"x\":27,\"y\":11,\"w\":21,\"h\":13,\"i\":\"2\"},\"id\":\"e1d0f010-9ee7-11e7-8711-e7a007dcef99\",\"panelIndex\":\"2\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"gridData\":{\"x\":0,\"y\":49,\"w\":24,\"h\":18,\"i\":\"4\"},\"id\":\"06cf9c40-9ee8-11e7-8711-e7a007dcef99\",\"panelIndex\":\"4\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{\"vis\":{\"defaultColors\":{\"0 - 22\":\"rgb(247,251,255)\",\"22 - 44\":\"rgb(208,225,242)\",\"44 - 66\":\"rgb(148,196,223)\",\"66 - 88\":\"rgb(74,152,201)\",\"88 - 110\":\"rgb(23,100,171)\"},\"legendOpen\":false}},\"gridData\":{\"x\":0,\"y\":36,\"w\":24,\"h\":13,\"i\":\"7\"},\"id\":\"935afa20-e0cd-11e7-9d07-1398ccfcefa3\",\"panelIndex\":\"7\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"embeddableConfig\":{\"mapCenter\":[36.8092847020594,-96.94335937500001],\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}},\"gridData\":{\"x\":27,\"y\":24,\"w\":21,\"h\":12,\"i\":\"9\"},\"id\":\"4eb6e500-e1c7-11e7-b6d5-4dc382ef7f5b\",\"panelIndex\":\"9\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"embeddableConfig\":{\"vis\":{\"colors\":{\"0 - 500\":\"#BF1B00\",\"1000 - 1500\":\"#7EB26D\",\"500 - 1000\":\"#F2C96D\"},\"defaultColors\":{\"0 - 500\":\"rgb(165,0,38)\",\"1000 - 1500\":\"rgb(0,104,55)\",\"500 - 1000\":\"rgb(255,255,190)\"},\"legendOpen\":false}},\"gridData\":{\"x\":10,\"y\":0,\"w\":9,\"h\":11,\"i\":\"11\"},\"id\":\"69a34b00-9ee8-11e7-8711-e7a007dcef99\",\"panelIndex\":\"11\",\"title\":\"\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"gridData\":{\"x\":0,\"y\":24,\"w\":27,\"h\":12,\"i\":\"13\"},\"id\":\"42b997f0-0c26-11e8-b0ec-3bb475f6b6ff\",\"panelIndex\":\"13\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"gridData\":{\"x\":24,\"y\":36,\"w\":24,\"h\":31,\"i\":\"14\"},\"id\":\"7cbd2350-2223-11e8-b802-5bcf64c2cfb4\",\"panelIndex\":\"14\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"gridData\":{\"x\":0,\"y\":11,\"w\":27,\"h\":13,\"i\":\"15\"},\"id\":\"314c6f60-2224-11e8-b802-5bcf64c2cfb4\",\"panelIndex\":\"15\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"gridData\":{\"x\":19,\"y\":0,\"w\":15,\"h\":11,\"i\":\"16\"},\"id\":\"24a3e970-4257-11e8-b3aa-73fdaf54bfc9\",\"panelIndex\":\"16\",\"title\":\"\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"embeddableConfig\":{\"vis\":{\"legendOpen\":false}},\"gridData\":{\"x\":34,\"y\":0,\"w\":14,\"h\":11,\"i\":\"17\"},\"id\":\"14e2e710-4258-11e8-b3aa-73fdaf54bfc9\",\"panelIndex\":\"17\",\"type\":\"visualization\",\"version\":\"6.3.0\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":0,\"w\":10,\"h\":11,\"i\":\"18\"},\"id\":\"47f2c680-a6e3-11e8-94b4-c30c0228351b\",\"panelIndex\":\"18\",\"title\":\"\",\"type\":\"visualization\",\"version\":\"7.0.0-alpha1\"}]",
"optionsJSON": "{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}",
"optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}",
"version": 1,
"timeRestore": true,
"timeTo": "now",

View file

@ -49,17 +49,20 @@ export function createSavedObjectsService(server, schema, serializer, migrator)
},
});
} catch (error) {
server.log(['debug', 'savedObjects'], {
tmpl: 'Attempt to write indexTemplate for SavedObjects index failed: <%= err.message %>',
es: {
resp: error.body,
status: error.status,
},
err: {
message: error.message,
stack: error.stack,
},
});
server.logWithMetadata(
['debug', 'savedObjects'],
`Attempt to write indexTemplate for SavedObjects index failed: ${error.message}`,
{
es: {
resp: error.body,
status: error.status,
},
err: {
message: error.message,
stack: error.stack,
},
}
);
// We reject with `es.ServiceUnavailable` because writing an index
// template is a very simple operation so if we get an error here

View file

@ -31,7 +31,7 @@ describe('ServerStatus class', function () {
let serverStatus;
beforeEach(function () {
server = { expose: sinon.stub(), log: sinon.stub() };
server = { expose: sinon.stub(), logWithMetadata: sinon.stub() };
serverStatus = new ServerStatus(server);
});

View file

@ -42,13 +42,15 @@ export default class Status extends EventEmitter {
this.state === 'red' ? 'error' : 'info'
];
server.log(tags, {
tmpl: 'Status changed from <%= prevState %> to <%= state %><%= message ? " - " + message : "" %>',
state: this.state,
message: this.message,
prevState: previous,
prevMsg: previousMsg
});
server.logWithMetadata(tags,
`Status changed from ${ previous } to ${this.state}${ this.message ? ' - ' + this.message : '' }`,
{
state: this.state,
message: this.message,
prevState: previous,
prevMsg: previousMsg
}
);
});
}

View file

@ -27,7 +27,7 @@ describe('Status class', function () {
let serverStatus;
beforeEach(function () {
server = { expose: sinon.stub(), log: sinon.stub() };
server = { expose: sinon.stub(), logWithMetadata: sinon.stub() };
serverStatus = new ServerStatus(server);
});

View file

@ -36,14 +36,3 @@ kbn-agg-table-group {
padding: 0;
}
}
.theme-dark {
@import '@elastic/eui/src/themes/k6/k6_colors_dark';
.kbnAggTable__paginated {
tr:hover td,
.kbnTableCellFilter {
background-color: $euiColorLightestShade;
}
}
}

View file

@ -40,7 +40,11 @@ module.directive('paginatedSelectableList', function () {
disableAutoFocus: '='
},
template: paginatedSelectableListTemplate,
controller: function ($scope) {
controller: function ($scope, $filter) {
function calculateHitsByQuery() {
$scope.hitsByQuery = $filter('filter')($scope.hits, $scope.query);
}
// Should specify either user-make-url or user-on-select
if (!$scope.userMakeUrl && !$scope.userOnSelect) {
throwError('paginatedSelectableList directive expects a makeUrl or onSelect function');
@ -53,6 +57,8 @@ module.directive('paginatedSelectableList', function () {
$scope.perPage = $scope.perPage || 10;
$scope.hits = $scope.list = _.sortBy($scope.list, $scope.accessor);
$scope.$watchGroup(['hits', 'query'], calculateHitsByQuery);
calculateHitsByQuery();
$scope.hitCount = $scope.hits.length;
/**

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