mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
[Expressions] Create expressions function to get UI settings (#101317)
This commit is contained in:
parent
49ea272240
commit
bde81c2090
26 changed files with 560 additions and 54 deletions
|
@ -2893,6 +2893,33 @@ Alias: `type`
|
||||||
[[u_fns]]
|
[[u_fns]]
|
||||||
== U
|
== U
|
||||||
|
|
||||||
|
[float]
|
||||||
|
[[uiSetting_fn]]
|
||||||
|
=== `uiSetting`
|
||||||
|
|
||||||
|
Returns a UI settings parameter value.
|
||||||
|
|
||||||
|
*Accepts:* `null`
|
||||||
|
|
||||||
|
[cols="3*^<"]
|
||||||
|
|===
|
||||||
|
|Argument |Type |Description
|
||||||
|
|
||||||
|
|_Unnamed_ ***
|
||||||
|
|
||||||
|
Aliases: `parameter`
|
||||||
|
|`string`
|
||||||
|
|The parameter name.
|
||||||
|
|
||||||
|
|`default`
|
||||||
|
|`any`
|
||||||
|
|A default value in case of the parameter is not set.
|
||||||
|
|
||||||
|
Default: `null`
|
||||||
|
|===
|
||||||
|
|
||||||
|
*Returns:* `ui_setting`
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
[[urlparam_fn]]
|
[[urlparam_fn]]
|
||||||
=== `urlparam`
|
=== `urlparam`
|
||||||
|
|
|
@ -70,7 +70,7 @@ The actual function is defined in the <code>fn</code> key. The function can be \
|
||||||
|
|
||||||
| Method | Modifiers | Description |
|
| Method | Modifiers | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [setup()](./kibana-plugin-plugins-expressions-public.expressionsservice.setup.md) | | Returns Kibana Platform \*setup\* life-cycle contract. Useful to return the same contract on server-side and browser-side. |
|
| [setup(args)](./kibana-plugin-plugins-expressions-public.expressionsservice.setup.md) | | Returns Kibana Platform \*setup\* life-cycle contract. Useful to return the same contract on server-side and browser-side. |
|
||||||
| [start()](./kibana-plugin-plugins-expressions-public.expressionsservice.start.md) | | Returns Kibana Platform \*start\* life-cycle contract. Useful to return the same contract on server-side and browser-side. |
|
| [start(args)](./kibana-plugin-plugins-expressions-public.expressionsservice.start.md) | | Returns Kibana Platform \*start\* life-cycle contract. Useful to return the same contract on server-side and browser-side. |
|
||||||
| [stop()](./kibana-plugin-plugins-expressions-public.expressionsservice.stop.md) | | |
|
| [stop()](./kibana-plugin-plugins-expressions-public.expressionsservice.stop.md) | | |
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,15 @@ Returns Kibana Platform \*setup\* life-cycle contract. Useful to return the same
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
setup(): ExpressionsServiceSetup;
|
setup(...args: unknown[]): ExpressionsServiceSetup;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| args | <code>unknown[]</code> | |
|
||||||
|
|
||||||
<b>Returns:</b>
|
<b>Returns:</b>
|
||||||
|
|
||||||
`ExpressionsServiceSetup`
|
`ExpressionsServiceSetup`
|
||||||
|
|
|
@ -9,8 +9,15 @@ Returns Kibana Platform \*start\* life-cycle contract. Useful to return the same
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
start(): ExpressionsServiceStart;
|
start(...args: unknown[]): ExpressionsServiceStart;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| args | <code>unknown[]</code> | |
|
||||||
|
|
||||||
<b>Returns:</b>
|
<b>Returns:</b>
|
||||||
|
|
||||||
`ExpressionsServiceStart`
|
`ExpressionsServiceStart`
|
||||||
|
|
|
@ -52,12 +52,6 @@ describe('Executor', () => {
|
||||||
executor.registerFunction(expressionFunctions.clog);
|
executor.registerFunction(expressionFunctions.clog);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can register all functions', () => {
|
|
||||||
const executor = new Executor();
|
|
||||||
for (const functionDefinition of expressionFunctions.functionSpecs)
|
|
||||||
executor.registerFunction(functionDefinition);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('can retrieve all functions', () => {
|
test('can retrieve all functions', () => {
|
||||||
const executor = new Executor();
|
const executor = new Executor();
|
||||||
executor.registerFunction(expressionFunctions.clog);
|
executor.registerFunction(expressionFunctions.clog);
|
||||||
|
@ -67,12 +61,24 @@ describe('Executor', () => {
|
||||||
|
|
||||||
test('can retrieve all functions - 2', () => {
|
test('can retrieve all functions - 2', () => {
|
||||||
const executor = new Executor();
|
const executor = new Executor();
|
||||||
for (const functionDefinition of expressionFunctions.functionSpecs)
|
const functionSpecs = [
|
||||||
|
expressionFunctions.clog,
|
||||||
|
expressionFunctions.font,
|
||||||
|
expressionFunctions.variableSet,
|
||||||
|
expressionFunctions.variable,
|
||||||
|
expressionFunctions.theme,
|
||||||
|
expressionFunctions.cumulativeSum,
|
||||||
|
expressionFunctions.derivative,
|
||||||
|
expressionFunctions.movingAverage,
|
||||||
|
expressionFunctions.mapColumn,
|
||||||
|
expressionFunctions.math,
|
||||||
|
];
|
||||||
|
for (const functionDefinition of functionSpecs) {
|
||||||
executor.registerFunction(functionDefinition);
|
executor.registerFunction(functionDefinition);
|
||||||
|
}
|
||||||
const functions = executor.getFunctions();
|
const functions = executor.getFunctions();
|
||||||
expect(Object.keys(functions).sort()).toEqual(
|
|
||||||
expressionFunctions.functionSpecs.map((spec) => spec.name).sort()
|
expect(Object.keys(functions).sort()).toEqual(functionSpecs.map((spec) => spec.name).sort());
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import { ExpressionType } from '../expression_types/expression_type';
|
||||||
import { AnyExpressionTypeDefinition } from '../expression_types/types';
|
import { AnyExpressionTypeDefinition } from '../expression_types/types';
|
||||||
import { ExpressionAstExpression, ExpressionAstFunction } from '../ast';
|
import { ExpressionAstExpression, ExpressionAstFunction } from '../ast';
|
||||||
import { ExpressionValueError, typeSpecs } from '../expression_types/specs';
|
import { ExpressionValueError, typeSpecs } from '../expression_types/specs';
|
||||||
import { functionSpecs } from '../expression_functions/specs';
|
|
||||||
import { getByAlias } from '../util';
|
import { getByAlias } from '../util';
|
||||||
import { SavedObjectReference } from '../../../../core/types';
|
import { SavedObjectReference } from '../../../../core/types';
|
||||||
import { PersistableStateService, SerializableState } from '../../../kibana_utils/common';
|
import { PersistableStateService, SerializableState } from '../../../kibana_utils/common';
|
||||||
|
@ -85,7 +84,7 @@ export class Executor<Context extends Record<string, unknown> = Record<string, u
|
||||||
): Executor<Ctx> {
|
): Executor<Ctx> {
|
||||||
const executor = new Executor<Ctx>(state);
|
const executor = new Executor<Ctx>(state);
|
||||||
for (const type of typeSpecs) executor.registerType(type);
|
for (const type of typeSpecs) executor.registerType(type);
|
||||||
for (const func of functionSpecs) executor.registerFunction(func);
|
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,31 +6,6 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { clog } from './clog';
|
|
||||||
import { font } from './font';
|
|
||||||
import { variableSet } from './var_set';
|
|
||||||
import { variable } from './var';
|
|
||||||
import { AnyExpressionFunctionDefinition } from '../types';
|
|
||||||
import { theme } from './theme';
|
|
||||||
import { cumulativeSum } from './cumulative_sum';
|
|
||||||
import { derivative } from './derivative';
|
|
||||||
import { movingAverage } from './moving_average';
|
|
||||||
import { mapColumn } from './map_column';
|
|
||||||
import { math } from './math';
|
|
||||||
|
|
||||||
export const functionSpecs: AnyExpressionFunctionDefinition[] = [
|
|
||||||
clog,
|
|
||||||
font,
|
|
||||||
variableSet,
|
|
||||||
variable,
|
|
||||||
theme,
|
|
||||||
cumulativeSum,
|
|
||||||
derivative,
|
|
||||||
movingAverage,
|
|
||||||
mapColumn,
|
|
||||||
math,
|
|
||||||
];
|
|
||||||
|
|
||||||
export * from './clog';
|
export * from './clog';
|
||||||
export * from './font';
|
export * from './font';
|
||||||
export * from './var_set';
|
export * from './var_set';
|
||||||
|
@ -39,5 +14,6 @@ export * from './theme';
|
||||||
export * from './cumulative_sum';
|
export * from './cumulative_sum';
|
||||||
export * from './derivative';
|
export * from './derivative';
|
||||||
export * from './moving_average';
|
export * from './moving_average';
|
||||||
|
export * from './ui_setting';
|
||||||
export { mapColumn, MapColumnArguments } from './map_column';
|
export { mapColumn, MapColumnArguments } from './map_column';
|
||||||
export { math, MathArguments, MathInput } from './math';
|
export { math, MathArguments, MathInput } from './math';
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
jest.mock('../../../../common');
|
||||||
|
|
||||||
|
import { IUiSettingsClient } from 'src/core/public';
|
||||||
|
import { getUiSettingFn } from '../ui_setting';
|
||||||
|
|
||||||
|
describe('uiSetting', () => {
|
||||||
|
describe('fn', () => {
|
||||||
|
let getStartDependencies: jest.MockedFunction<
|
||||||
|
Parameters<typeof getUiSettingFn>[0]['getStartDependencies']
|
||||||
|
>;
|
||||||
|
let uiSetting: ReturnType<typeof getUiSettingFn>;
|
||||||
|
let uiSettings: jest.Mocked<IUiSettingsClient>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
uiSettings = ({
|
||||||
|
get: jest.fn(),
|
||||||
|
} as unknown) as jest.Mocked<IUiSettingsClient>;
|
||||||
|
getStartDependencies = (jest.fn(async () => ({
|
||||||
|
uiSettings,
|
||||||
|
})) as unknown) as typeof getStartDependencies;
|
||||||
|
|
||||||
|
uiSetting = getUiSettingFn({ getStartDependencies });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a value', () => {
|
||||||
|
uiSettings.get.mockReturnValueOnce('value');
|
||||||
|
|
||||||
|
expect(uiSetting.fn(null, { parameter: 'something' }, {} as any)).resolves.toEqual({
|
||||||
|
type: 'ui_setting',
|
||||||
|
key: 'something',
|
||||||
|
value: 'value',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass a default value', async () => {
|
||||||
|
await uiSetting.fn(null, { parameter: 'something', default: 'default' }, {} as any);
|
||||||
|
|
||||||
|
expect(uiSettings.get).toHaveBeenCalledWith('something', 'default');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when parameter does not exist', () => {
|
||||||
|
uiSettings.get.mockImplementationOnce(() => {
|
||||||
|
throw new Error();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(uiSetting.fn(null, { parameter: 'something' }, {} as any)).rejects.toEqual(
|
||||||
|
new Error('Invalid parameter "something".')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get a request instance on the server-side', async () => {
|
||||||
|
const request = {};
|
||||||
|
await uiSetting.fn(null, { parameter: 'something' }, {
|
||||||
|
getKibanaRequest: () => request,
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
const [[getKibanaRequest]] = getStartDependencies.mock.calls;
|
||||||
|
|
||||||
|
expect(getKibanaRequest()).toBe(request);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if request is not provided on the server-side', async () => {
|
||||||
|
await uiSetting.fn(null, { parameter: 'something' }, {} as any);
|
||||||
|
|
||||||
|
const [[getKibanaRequest]] = getStartDependencies.mock.calls;
|
||||||
|
|
||||||
|
expect(getKibanaRequest).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||||
|
import type { KibanaRequest } from 'src/core/server';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
|
||||||
|
import { UiSetting } from '../../expression_types/specs/ui_setting';
|
||||||
|
|
||||||
|
interface UiSettingsClient {
|
||||||
|
get<T>(key: string, defaultValue?: T): T | Promise<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UiSettingStartDependencies {
|
||||||
|
uiSettings: UiSettingsClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UiSettingFnArguments {
|
||||||
|
getStartDependencies(getKibanaRequest: () => KibanaRequest): Promise<UiSettingStartDependencies>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UiSettingArguments {
|
||||||
|
default?: unknown;
|
||||||
|
parameter: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ExpressionFunctionUiSetting = ExpressionFunctionDefinition<
|
||||||
|
'uiSetting',
|
||||||
|
unknown,
|
||||||
|
UiSettingArguments,
|
||||||
|
Promise<UiSetting>
|
||||||
|
>;
|
||||||
|
|
||||||
|
export function getUiSettingFn({
|
||||||
|
getStartDependencies,
|
||||||
|
}: UiSettingFnArguments): ExpressionFunctionUiSetting {
|
||||||
|
return {
|
||||||
|
name: 'uiSetting',
|
||||||
|
help: i18n.translate('expressions.functions.uiSetting.help', {
|
||||||
|
defaultMessage: 'Returns a UI settings parameter value.',
|
||||||
|
}),
|
||||||
|
args: {
|
||||||
|
default: {
|
||||||
|
help: i18n.translate('expressions.functions.uiSetting.args.default', {
|
||||||
|
defaultMessage: 'A default value in case of the parameter is not set.',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
parameter: {
|
||||||
|
aliases: ['_'],
|
||||||
|
help: i18n.translate('expressions.functions.uiSetting.args.parameter', {
|
||||||
|
defaultMessage: 'The parameter name.',
|
||||||
|
}),
|
||||||
|
required: true,
|
||||||
|
types: ['string'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async fn(input, { default: defaultValue, parameter }, { getKibanaRequest }) {
|
||||||
|
const { uiSettings } = await getStartDependencies(() => {
|
||||||
|
const request = getKibanaRequest?.();
|
||||||
|
if (!request) {
|
||||||
|
throw new Error(
|
||||||
|
i18n.translate('expressions.functions.uiSetting.error.kibanaRequest', {
|
||||||
|
defaultMessage:
|
||||||
|
'A KibanaRequest is required to get UI settings on the server. ' +
|
||||||
|
'Please provide a request object to the expression execution params.',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
type: 'ui_setting',
|
||||||
|
key: parameter,
|
||||||
|
value: await uiSettings.get(parameter, defaultValue),
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
throw new Error(
|
||||||
|
i18n.translate('expressions.functions.uiSetting.error.parameter', {
|
||||||
|
defaultMessage: 'Invalid parameter "{parameter}".',
|
||||||
|
values: { parameter },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ import { shape } from './shape';
|
||||||
import { string } from './string';
|
import { string } from './string';
|
||||||
import { style } from './style';
|
import { style } from './style';
|
||||||
import { AnyExpressionTypeDefinition } from '../types';
|
import { AnyExpressionTypeDefinition } from '../types';
|
||||||
|
import { uiSetting } from './ui_setting';
|
||||||
|
|
||||||
export const typeSpecs: AnyExpressionTypeDefinition[] = [
|
export const typeSpecs: AnyExpressionTypeDefinition[] = [
|
||||||
boolean,
|
boolean,
|
||||||
|
@ -37,6 +38,7 @@ export const typeSpecs: AnyExpressionTypeDefinition[] = [
|
||||||
shape,
|
shape,
|
||||||
string,
|
string,
|
||||||
style,
|
style,
|
||||||
|
uiSetting,
|
||||||
];
|
];
|
||||||
|
|
||||||
export * from './boolean';
|
export * from './boolean';
|
||||||
|
@ -53,3 +55,4 @@ export * from './render';
|
||||||
export * from './shape';
|
export * from './shape';
|
||||||
export * from './string';
|
export * from './string';
|
||||||
export * from './style';
|
export * from './style';
|
||||||
|
export * from './ui_setting';
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { UiSetting, uiSetting } from '../ui_setting';
|
||||||
|
|
||||||
|
function createUiSetting(value: unknown, key = 'something'): UiSetting {
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
type: 'ui_setting',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('uiSetting', () => {
|
||||||
|
describe('to', () => {
|
||||||
|
describe('render', () => {
|
||||||
|
it.each`
|
||||||
|
value | expected
|
||||||
|
${{ a: 'b' }} | ${JSON.stringify({ a: 'b' })}
|
||||||
|
${null} | ${''}
|
||||||
|
${'something'} | ${'something'}
|
||||||
|
`('should render "$value" as "$expected"', ({ expected, value }) => {
|
||||||
|
expect(uiSetting.to?.render(createUiSetting(value), {})).toHaveProperty(
|
||||||
|
'value.text',
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('datatable', () => {
|
||||||
|
it('should use parameter name as a datatable column', () => {
|
||||||
|
expect(uiSetting.to?.datatable(createUiSetting('value', 'column'), {})).toHaveProperty(
|
||||||
|
'columns.0',
|
||||||
|
expect.objectContaining({ id: 'column', name: 'column' })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
value | type
|
||||||
|
${null} | ${'null'}
|
||||||
|
${undefined} | ${'null'}
|
||||||
|
${'something'} | ${'string'}
|
||||||
|
${['123']} | ${'string'}
|
||||||
|
${123} | ${'number'}
|
||||||
|
${[123]} | ${'number'}
|
||||||
|
${true} | ${'boolean'}
|
||||||
|
${{ a: 'b' }} | ${'object'}
|
||||||
|
${[]} | ${'unknown'}
|
||||||
|
`('should determine $type type', ({ value, type }) => {
|
||||||
|
expect(uiSetting.to?.datatable(createUiSetting(value, 'column'), {})).toHaveProperty(
|
||||||
|
'columns.0.meta.type',
|
||||||
|
type
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should put a value into a row', () => {
|
||||||
|
expect(uiSetting.to?.datatable(createUiSetting('value'), {})).toHaveProperty(
|
||||||
|
'rows.0.something',
|
||||||
|
'value'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should put an array value into multiple rows', () => {
|
||||||
|
expect(uiSetting.to?.datatable(createUiSetting(['a', 'b']), {})).toHaveProperty(
|
||||||
|
'rows',
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ something: 'a' }),
|
||||||
|
expect.objectContaining({ something: 'b' }),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Datatable, DatatableColumnType } from './datatable';
|
||||||
|
import { ExpressionTypeDefinition, ExpressionValueBoxed } from '../types';
|
||||||
|
import { ExpressionValueRender } from './render';
|
||||||
|
|
||||||
|
const name = 'ui_setting';
|
||||||
|
|
||||||
|
function getType(value: unknown): DatatableColumnType {
|
||||||
|
if (value == null) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.length ? getType(value[0]) : 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['boolean', 'number', 'object', 'string'].includes(typeof value)) {
|
||||||
|
return typeof value as DatatableColumnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UiSetting = ExpressionValueBoxed<'ui_setting', { key: string; value: unknown }>;
|
||||||
|
|
||||||
|
export const uiSetting: ExpressionTypeDefinition<'ui_setting', UiSetting> = {
|
||||||
|
name,
|
||||||
|
to: {
|
||||||
|
boolean({ value }) {
|
||||||
|
return Boolean(value);
|
||||||
|
},
|
||||||
|
number({ value }) {
|
||||||
|
return Number(value);
|
||||||
|
},
|
||||||
|
string({ value }) {
|
||||||
|
return String(value ?? '');
|
||||||
|
},
|
||||||
|
render({ value }): ExpressionValueRender<{ text: string }> {
|
||||||
|
return {
|
||||||
|
type: 'render',
|
||||||
|
as: 'text',
|
||||||
|
value: {
|
||||||
|
text:
|
||||||
|
typeof value === 'object' && value !== null
|
||||||
|
? JSON.stringify(value)
|
||||||
|
: String(value ?? ''),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
datatable({ key, value }): Datatable {
|
||||||
|
return {
|
||||||
|
type: 'datatable',
|
||||||
|
columns: [{ id: key, name: key, meta: { type: getType(value) } }],
|
||||||
|
rows: (Array.isArray(value) ? value : [value]).map((cell) => ({ [key]: cell })),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -19,6 +19,18 @@ import { AnyExpressionFunctionDefinition } from '../expression_functions';
|
||||||
import { SavedObjectReference } from '../../../../core/types';
|
import { SavedObjectReference } from '../../../../core/types';
|
||||||
import { PersistableStateService, SerializableState } from '../../../kibana_utils/common';
|
import { PersistableStateService, SerializableState } from '../../../kibana_utils/common';
|
||||||
import { Adapters } from '../../../inspector/common/adapters';
|
import { Adapters } from '../../../inspector/common/adapters';
|
||||||
|
import {
|
||||||
|
clog,
|
||||||
|
font,
|
||||||
|
variableSet,
|
||||||
|
variable,
|
||||||
|
theme,
|
||||||
|
cumulativeSum,
|
||||||
|
derivative,
|
||||||
|
movingAverage,
|
||||||
|
mapColumn,
|
||||||
|
math,
|
||||||
|
} from '../expression_functions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The public contract that `ExpressionsService` provides to other plugins
|
* The public contract that `ExpressionsService` provides to other plugins
|
||||||
|
@ -269,7 +281,7 @@ export class ExpressionsService implements PersistableStateService<ExpressionAst
|
||||||
public readonly fork = () => {
|
public readonly fork = () => {
|
||||||
const executor = this.executor.fork();
|
const executor = this.executor.fork();
|
||||||
const renderers = this.renderers;
|
const renderers = this.renderers;
|
||||||
const fork = new ExpressionsService({ executor, renderers });
|
const fork = new (this.constructor as typeof ExpressionsService)({ executor, renderers });
|
||||||
|
|
||||||
return fork;
|
return fork;
|
||||||
};
|
};
|
||||||
|
@ -318,7 +330,22 @@ export class ExpressionsService implements PersistableStateService<ExpressionAst
|
||||||
* Returns Kibana Platform *setup* life-cycle contract. Useful to return the
|
* Returns Kibana Platform *setup* life-cycle contract. Useful to return the
|
||||||
* same contract on server-side and browser-side.
|
* same contract on server-side and browser-side.
|
||||||
*/
|
*/
|
||||||
public setup(): ExpressionsServiceSetup {
|
public setup(...args: unknown[]): ExpressionsServiceSetup {
|
||||||
|
for (const fn of [
|
||||||
|
clog,
|
||||||
|
font,
|
||||||
|
variableSet,
|
||||||
|
variable,
|
||||||
|
theme,
|
||||||
|
cumulativeSum,
|
||||||
|
derivative,
|
||||||
|
movingAverage,
|
||||||
|
mapColumn,
|
||||||
|
math,
|
||||||
|
]) {
|
||||||
|
this.registerFunction(fn);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +353,7 @@ export class ExpressionsService implements PersistableStateService<ExpressionAst
|
||||||
* Returns Kibana Platform *start* life-cycle contract. Useful to return the
|
* Returns Kibana Platform *start* life-cycle contract. Useful to return the
|
||||||
* same contract on server-side and browser-side.
|
* same contract on server-side and browser-side.
|
||||||
*/
|
*/
|
||||||
public start(): ExpressionsServiceStart {
|
public start(...args: unknown[]): ExpressionsServiceStart {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,19 @@ import { introspectContext } from './introspect_context';
|
||||||
import { mult } from './mult';
|
import { mult } from './mult';
|
||||||
import { sleep } from './sleep';
|
import { sleep } from './sleep';
|
||||||
import { sum } from './sum';
|
import { sum } from './sum';
|
||||||
import { AnyExpressionFunctionDefinition } from '../../expression_functions';
|
import {
|
||||||
|
AnyExpressionFunctionDefinition,
|
||||||
|
clog,
|
||||||
|
font,
|
||||||
|
variableSet,
|
||||||
|
variable,
|
||||||
|
theme,
|
||||||
|
cumulativeSum,
|
||||||
|
derivative,
|
||||||
|
movingAverage,
|
||||||
|
mapColumn,
|
||||||
|
math,
|
||||||
|
} from '../../expression_functions';
|
||||||
|
|
||||||
export const functionTestSpecs: AnyExpressionFunctionDefinition[] = [
|
export const functionTestSpecs: AnyExpressionFunctionDefinition[] = [
|
||||||
access,
|
access,
|
||||||
|
@ -23,4 +35,14 @@ export const functionTestSpecs: AnyExpressionFunctionDefinition[] = [
|
||||||
mult,
|
mult,
|
||||||
sleep,
|
sleep,
|
||||||
sum,
|
sum,
|
||||||
|
clog,
|
||||||
|
font,
|
||||||
|
variableSet,
|
||||||
|
variable,
|
||||||
|
theme,
|
||||||
|
cumulativeSum,
|
||||||
|
derivative,
|
||||||
|
movingAverage,
|
||||||
|
mapColumn,
|
||||||
|
math,
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './ui_setting';
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { CoreSetup } from 'src/core/public';
|
||||||
|
import { getUiSettingFn as getCommonUiSettingFn } from '../../common';
|
||||||
|
|
||||||
|
export function getUiSettingFn({ getStartServices }: Pick<CoreSetup, 'getStartServices'>) {
|
||||||
|
return getCommonUiSettingFn({
|
||||||
|
async getStartDependencies() {
|
||||||
|
const [{ uiSettings }] = await getStartServices();
|
||||||
|
|
||||||
|
return { uiSettings };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import { expressionsPluginMock } from './mocks';
|
import { expressionsPluginMock } from './mocks';
|
||||||
import { add } from '../common/test_helpers/expression_functions/add';
|
import { add } from '../common/test_helpers/expression_functions/add';
|
||||||
import { ExpressionsService } from '../common';
|
import { ExpressionsService } from './services';
|
||||||
|
|
||||||
describe('ExpressionsPublicPlugin', () => {
|
describe('ExpressionsPublicPlugin', () => {
|
||||||
test('can instantiate from mocks', async () => {
|
test('can instantiate from mocks', async () => {
|
||||||
|
|
|
@ -6,9 +6,15 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { pick } from 'lodash';
|
||||||
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public';
|
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public';
|
||||||
import { ExpressionsService, ExpressionsServiceSetup, ExpressionsServiceStart } from '../common';
|
import { ExpressionsServiceSetup, ExpressionsServiceStart } from '../common';
|
||||||
import { setRenderersRegistry, setNotifications, setExpressionsService } from './services';
|
import {
|
||||||
|
ExpressionsService,
|
||||||
|
setRenderersRegistry,
|
||||||
|
setNotifications,
|
||||||
|
setExpressionsService,
|
||||||
|
} from './services';
|
||||||
import { ReactExpressionRenderer } from './react_expression_renderer';
|
import { ReactExpressionRenderer } from './react_expression_renderer';
|
||||||
import { ExpressionLoader, IExpressionLoader, loader } from './loader';
|
import { ExpressionLoader, IExpressionLoader, loader } from './loader';
|
||||||
import { render, ExpressionRenderHandler } from './render';
|
import { render, ExpressionRenderHandler } from './render';
|
||||||
|
@ -51,7 +57,7 @@ export class ExpressionsPublicPlugin implements Plugin<ExpressionsSetup, Express
|
||||||
setRenderersRegistry(renderers);
|
setRenderersRegistry(renderers);
|
||||||
setExpressionsService(expressions);
|
setExpressionsService(expressions);
|
||||||
|
|
||||||
const setup = expressions.setup();
|
const setup = expressions.setup(pick(core, 'getStartServices'));
|
||||||
|
|
||||||
return Object.freeze(setup);
|
return Object.freeze(setup);
|
||||||
}
|
}
|
||||||
|
|
|
@ -612,8 +612,8 @@ export class ExpressionsService implements PersistableStateService<ExpressionAst
|
||||||
readonly renderers: ExpressionRendererRegistry;
|
readonly renderers: ExpressionRendererRegistry;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
readonly run: ExpressionsServiceStart['run'];
|
readonly run: ExpressionsServiceStart['run'];
|
||||||
setup(): ExpressionsServiceSetup;
|
setup(...args: unknown[]): ExpressionsServiceSetup;
|
||||||
start(): ExpressionsServiceStart;
|
start(...args: unknown[]): ExpressionsServiceStart;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
stop(): void;
|
stop(): void;
|
||||||
readonly telemetry: (state: ExpressionAstExpression, telemetryData?: Record<string, any>) => Record<string, any>;
|
readonly telemetry: (state: ExpressionAstExpression, telemetryData?: Record<string, any>) => Record<string, any>;
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { CoreSetup } from 'src/core/public';
|
||||||
|
import { ExpressionsService as CommonExpressionsService } from '../../common';
|
||||||
|
import { getUiSettingFn } from '../expression_functions';
|
||||||
|
|
||||||
|
export class ExpressionsService extends CommonExpressionsService {
|
||||||
|
setup({ getStartServices }: Pick<CoreSetup, 'getStartServices'>) {
|
||||||
|
this.registerFunction(getUiSettingFn({ getStartServices }));
|
||||||
|
|
||||||
|
return super.setup();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,8 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { NotificationsStart } from 'kibana/public';
|
import { NotificationsStart } from 'kibana/public';
|
||||||
import { createGetterSetter } from '../../kibana_utils/public';
|
import { createGetterSetter } from '../../../kibana_utils/public';
|
||||||
import { ExpressionsService, ExpressionRendererRegistry } from '../common';
|
import { ExpressionsService, ExpressionRendererRegistry } from '../../common';
|
||||||
|
|
||||||
export const [getNotifications, setNotifications] = createGetterSetter<NotificationsStart>(
|
export const [getNotifications, setNotifications] = createGetterSetter<NotificationsStart>(
|
||||||
'Notifications'
|
'Notifications'
|
||||||
|
@ -23,3 +23,5 @@ export const [
|
||||||
getExpressionsService,
|
getExpressionsService,
|
||||||
setExpressionsService,
|
setExpressionsService,
|
||||||
] = createGetterSetter<ExpressionsService>('ExpressionsService');
|
] = createGetterSetter<ExpressionsService>('ExpressionsService');
|
||||||
|
|
||||||
|
export * from './expressions_services';
|
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './ui_setting';
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { CoreSetup } from 'src/core/server';
|
||||||
|
import { getUiSettingFn as getCommonUiSettingFn } from '../../common';
|
||||||
|
|
||||||
|
export function getUiSettingFn({ getStartServices }: Pick<CoreSetup, 'getStartServices'>) {
|
||||||
|
return getCommonUiSettingFn({
|
||||||
|
async getStartDependencies(getKibanaRequest) {
|
||||||
|
const [{ savedObjects, uiSettings }] = await getStartServices();
|
||||||
|
const savedObjectsClient = savedObjects.getScopedClient(getKibanaRequest());
|
||||||
|
const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient);
|
||||||
|
|
||||||
|
return { uiSettings: uiSettingsClient };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { pick } from 'lodash';
|
||||||
import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from 'src/core/server';
|
import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from 'src/core/server';
|
||||||
import { ExpressionsService, ExpressionsServiceSetup, ExpressionsServiceStart } from '../common';
|
import { ExpressionsService, ExpressionsServiceSetup, ExpressionsServiceStart } from '../common';
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ export class ExpressionsServerPlugin
|
||||||
environment: 'server',
|
environment: 'server',
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup = this.expressions.setup();
|
const setup = this.expressions.setup(pick(core, 'getStartServices'));
|
||||||
|
|
||||||
return Object.freeze(setup);
|
return Object.freeze(setup);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { CoreSetup } from 'src/core/server';
|
||||||
|
import { ExpressionsService as CommonExpressionsService } from '../../common';
|
||||||
|
import { getUiSettingFn } from '../expression_functions';
|
||||||
|
|
||||||
|
export class ExpressionsService extends CommonExpressionsService {
|
||||||
|
setup({ getStartServices }: Pick<CoreSetup, 'getStartServices'>) {
|
||||||
|
this.registerFunction(getUiSettingFn({ getStartServices }));
|
||||||
|
|
||||||
|
return super.setup();
|
||||||
|
}
|
||||||
|
}
|
9
src/plugins/expressions/server/services/index.ts
Normal file
9
src/plugins/expressions/server/services/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './expressions_services';
|
Loading…
Add table
Add a link
Reference in a new issue