Removed canvas function reference docs generator component (#136955)

This commit is contained in:
Catherine Liu 2022-07-22 16:15:59 -07:00 committed by GitHub
parent 03f1a218c5
commit cf359703a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 4 additions and 842 deletions

View file

@ -36,7 +36,6 @@ import {
services,
LegacyServicesProvider,
CanvasPluginServices,
pluginServices as canvasServices,
} from './services';
import { initFunctions } from './functions';
// @ts-expect-error untyped local
@ -154,11 +153,7 @@ export const initializeCanvas = async (
ReactDOM.render(
<KibanaThemeProvider theme$={coreStart.theme.theme$}>
<Provider store={canvasStore}>
<HelpMenu
functionRegistry={expressions.getFunctions()}
notifyService={canvasServices.getServices().notify}
hideHelpMenu={hideHelpMenu}
/>
<HelpMenu hideHelpMenu={hideHelpMenu} />
</Provider>
</KibanaThemeProvider>,
domNode

View file

@ -1,473 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export interface FunctionExample {
syntax: string;
usage: {
expression: string;
help?: string;
};
}
interface FunctionExampleDict {
[key: string]: FunctionExample;
}
export const getFunctionExamples = (): FunctionExampleDict => ({
all: {
syntax: `all {neq "foo"} {neq "bar"} {neq "fizz"}
all condition={gt 10} condition={lt 20}`,
usage: {
expression: `kibana
| selectFilter
| demodata
| math "mean(percent_uptime)"
| formatnumber "0.0%"
| metric "Average uptime"
metricFont={
font size=48 family="'Open Sans', Helvetica, Arial, sans-serif"
color={
if {all {gte 0} {lt 0.8}} then="red" else="green"
}
align="center" lHeight=48
}
| render`,
help: 'This sets the color of the metric text to `"red"` if the context passed into `metric` is greater than or equal to 0 and less than 0.8. Otherwise, the color is set to `"green"`.',
},
},
alterColumn: {
syntax: `alterColumn "cost" type="string"
alterColumn column="@timestamp" name="foo"`,
usage: {
expression: `kibana
| selectFilter
| demodata
| alterColumn "time" name="time_in_ms" type="number"
| table
| render`,
help: 'This renames the `time` column to `time_in_ms` and converts the type of the columns values from `date` to `number`.',
},
},
any: {
syntax: `any {eq "foo"} {eq "bar"} {eq "fizz"}
any condition={lte 10} condition={gt 30}`,
usage: {
expression: `kibana
| selectFilter
| demodata
| filterrows {
getCell "project" | any {eq "elasticsearch"} {eq "kibana"} {eq "x-pack"}
}
| pointseries color="project" size="max(price)"
| pie
| render`,
help: 'This filters out any rows that dont contain `"elasticsearch"`, `"kibana"` or `"x-pack"` in the `project` field.',
},
},
as: {
syntax: `as
as "foo"
as name="bar"`,
usage: {
expression: `kibana
| selectFilter
| demodata
| ply by="project" fn={math "count(username)" | as "num_users"} fn={math "mean(price)" | as "price"}
| pointseries x="project" y="num_users" size="price" color="project"
| plot
| render`,
help: `\`as\` casts any primitive value (\`string\`, \`number\`, \`date\`, \`null\`) into a \`datatable\` with a single row and a single column with the given name (or defaults to \`"value"\` if no name is provided). This is useful when piping a primitive value into a function that only takes \`datatable\` as an input.
In the example, \`ply\` expects each \`fn\` subexpression to return a \`datatable\` in order to merge the results of each \`fn\` back into a \`datatable\`, but using a \`math\` aggregation in the subexpressions returns a single \`math\` value, which is then cast into a \`datatable\` using \`as\`.`,
},
},
asset: {
syntax: `asset "asset-52f14f2b-fee6-4072-92e8-cd2642665d02"
asset id="asset-498f7429-4d56-42a2-a7e4-8bf08d98d114"`,
usage: {
expression: `image dataurl={asset "asset-c661a7cc-11be-45a1-a401-d7592ea7917a"} mode="contain"
| render`,
help: 'The image asset stored with the ID `"asset-c661a7cc-11be-45a1-a401-d7592ea7917a"` is passed into the `dataurl` argument of the `image` function to display the stored asset.',
},
},
axisConfig: {
syntax: `axisConfig show=false
axisConfig position="right" min=0 max=10 tickSize=1`,
usage: {
expression: `kibana
| selectFilter
| demodata
| pointseries x="size(cost)" y="project" color="project"
| plot defaultStyle={seriesStyle bars=0.75 horizontalBars=true}
legend=false
xaxis={axisConfig position="top" min=0 max=400 tickSize=100}
yaxis={axisConfig position="right"}
| render`,
help: 'This sets the `x-axis` to display on the top of the chart and sets the range of values to `0-400` with ticks displayed at `100` intervals. The `y-axis` is configured to display on the `right`.',
},
},
case: {
syntax: `case 0 then="red"
case when=5 then="yellow"
case if={lte 50} then="green"`,
usage: {
expression: `math "random()"
| progress shape="gauge" label={formatnumber "0%"}
font={
font size=24 family="'Open Sans', Helvetica, Arial, sans-serif" align="center"
color={
switch {case if={lte 0.5} then="green"}
{case if={all {gt 0.5} {lte 0.75}} then="orange"}
default="red"
}
}
valueColor={
switch {case if={lte 0.5} then="green"}
{case if={all {gt 0.5} {lte 0.75}} then="orange"}
default="red"
}
| render`,
help: 'This sets the color of the progress indicator and the color of the label to `"green"` if the value is less than or equal to `0.5`, `"orange"` if the value is greater than `0.5` and less than or equal to `0.75`, and `"red"` if `none` of the case conditions are met.',
},
},
clog: {
syntax: `clog`,
usage: {
expression: `kibana
| demodata
| clog
| filterrows fn={getCell "age" | gt 70}
| clog
| pointseries x="time" y="mean(price)"
| plot defaultStyle={seriesStyle lines=1 fill=1}
| render`,
help: 'This prints the `datatable` objects in the browser console before and after the `filterrows` function.',
},
},
columns: {
syntax: `columns include="@timestamp, projects, cost"
columns exclude="username, country, age"`,
usage: {
expression: `kibana
| selectFilter
| demodata
| columns include="price, cost, state, project"
| table
| render`,
help: 'This only keeps the `price`, `cost`, `state`, and `project` columns from the `demodata` data source and removes all other columns.',
},
},
compare: {
syntax: `compare "neq" to="elasticsearch"
compare op="lte" to=100`,
usage: {
expression: `kibana
| selectFilter
| demodata
| mapColumn project
fn={getCell project |
switch
{case if={compare eq to=kibana} then=kibana}
{case if={compare eq to=elasticsearch} then=elasticsearch}
default="other"
}
| pointseries size="size(cost)" color="project"
| pie
| render`,
help: 'This maps all `project` values that arent `"kibana"` and `"elasticsearch"` to `"other"`. Alternatively, you can use the individual comparator functions instead of compare.',
},
},
containerStyle: {
syntax: `containerStyle backgroundColor="red"
containerStyle borderRadius="50px"
containerStyle border="1px solid black"
containerStyle padding="5px"
containerStyle opacity="0.5"
containerStyle overflow="hidden"
containerStyle backgroundImage={asset id=asset-f40d2292-cf9e-4f2c-8c6f-a504a25e949c}
backgroundRepeat="no-repeat"
backgroundSize="cover"`,
usage: {
expression: `shape "star" fill="#E61D35" maintainAspect=true
| render containerStyle={
containerStyle backgroundColor="#F8D546"
borderRadius="200px"
border="4px solid #05509F"
padding="0px"
opacity="0.9"
overflow="hidden"
}`,
},
},
context: {
syntax: `context`,
usage: {
expression: `date
| formatdate "LLLL"
| markdown "Last updated: " {context}
| render`,
help: 'Using the `context` function allows us to pass the output, or _context_, of the previous function as a value to an argument in the next function. Here we get the formatted date string from the previous function and pass it as `content` for the markdown element.',
},
},
createTable: {
syntax: `createTable id="a" id="b"
createTable id="a" name="A" id="b" name="B" rowCount=5`,
usage: {
expression: `var_set
name="logs" value={essql "select count(*) as a from kibana_sample_data_logs"}
name="commerce" value={essql "select count(*) as b from kibana_sample_data_ecommerce"}
| createTable ids="totalA" ids="totalB"
| staticColumn name="totalA" value={var "logs" | getCell "a"}
| alterColumn column="totalA" type="number"
| staticColumn name="totalB" value={var "commerce" | getCell "b"}
| alterColumn column="totalB" type="number"
| mathColumn id="percent" name="percent" expression="totalA / totalB"
| render`,
help: 'This creates a table based on the results of two `essql` queries, joined into one table.',
},
},
csv: {
syntax: `csv "fruit, stock
kiwi, 10
Banana, 5"`,
usage: {
expression: `csv "fruit,stock
kiwi,10
banana,5"
| pointseries color=fruit size=stock
| pie
| render`,
help: 'This creates a `datatable` with `fruit` and `stock` columns with two rows. This is useful for quickly mocking data.',
},
},
date: {
syntax: `date
date value=1558735195
date "2019-05-24T21:59:55+0000"
date "01/31/2019" format="MM/DD/YYYY"`,
usage: {
expression: `date
| formatdate "LLL"
| markdown {context}
font={font family="Arial, sans-serif" size=30 align="left"
color="#000000"
weight="normal"
underline=false
italic=false}
| render`,
help: 'Using `date` without passing any arguments will return the current date and time.',
},
},
demodata: {
syntax: `demodata
demodata "ci"
demodata type="shirts"`,
usage: {
expression: `kibana
| selectFilter
| demodata
| table
| render`,
help: '`demodata` is a mock data set that you can use to start playing around in Canvas.',
},
},
dropdownControl: {
syntax: `dropdownControl valueColumn=project filterColumn=project
dropdownControl valueColumn=agent filterColumn=agent.keyword filterGroup=group1`,
usage: {
expression: `demodata
| dropdownControl valueColumn=project filterColumn=project
| render`,
help: 'This creates a dropdown filter element. It requires a data source and uses the unique values from the given `valueColumn` (i.e. `project`) and applies the filter to the `project` column. Note: `filterColumn` should point to a keyword type field for Elasticsearch data sources.',
},
},
eq: {
syntax: `eq true
eq null
eq 10
eq "foo"`,
usage: {
expression: `kibana
| selectFilter
| demodata
| mapColumn project
fn={getCell project |
switch
{case if={eq kibana} then=kibana}
{case if={eq elasticsearch} then=elasticsearch}
default="other"
}
| pointseries size="size(cost)" color="project"
| pie
| render`,
help: 'This changes all values in the project column that dont equal `"kibana"` or `"elasticsearch"` to `"other"`.',
},
},
escount: {
syntax: `escount index="logstash-*"
escount "currency:\"EUR\"" index="kibana_sample_data_ecommerce"
escount query="response:404" index="kibana_sample_data_logs"`,
usage: {
expression: `kibana
| selectFilter
| escount "Cancelled:true" index="kibana_sample_data_flights"
| math "value"
| progress shape="semicircle"
label={formatnumber 0,0}
font={font size=24 family="'Open Sans', Helvetica, Arial, sans-serif" color="#000000" align=center}
max={filters | escount index="kibana_sample_data_flights"}
| render`,
help: 'The first `escount` expression retrieves the number of flights that were cancelled. The second `escount` expression retrieves the total number of flights.',
},
},
esdocs: {
syntax: `esdocs index="logstash-*"
esdocs "currency:\"EUR\"" index="kibana_sample_data_ecommerce"
esdocs query="response:404" index="kibana_sample_data_logs"
esdocs index="kibana_sample_data_flights" count=100
esdocs index="kibana_sample_data_flights" sort="AvgTicketPrice, asc"`,
usage: {
expression: `kibana
| selectFilter
| esdocs index="kibana_sample_data_ecommerce"
fields="customer_gender, taxful_total_price, order_date"
sort="order_date, asc"
count=10000
| mapColumn "order_date"
fn={getCell "order_date" | date {context} | rounddate "YYYY-MM-DD"}
| alterColumn "order_date" type="date"
| pointseries x="order_date" y="sum(taxful_total_price)" color="customer_gender"
| plot defaultStyle={seriesStyle lines=3}
palette={palette "#7ECAE3" "#003A4D" gradient=true}
| render`,
help: 'This retrieves the first 10000 documents data from the `kibana_sample_data_ecommerce` index sorted by `order_date` in ascending order, and only requests the `customer_gender`, `taxful_total_price`, and `order_date` fields.',
},
},
essql: {
syntax: `essql query="SELECT * FROM \"logstash*\""
essql "SELECT * FROM \"apm*\"" count=10000`,
usage: {
expression: `kibana
| selectFilter
| essql query="SELECT Carrier, FlightDelayMin, AvgTicketPrice FROM \"kibana_sample_data_flights\""
| table
| render`,
help: 'This retrieves the `Carrier`, `FlightDelayMin`, and `AvgTicketPrice` fields from the "kibana_sample_data_flights" index.',
},
},
exactly: {
syntax: `exactly "state" value="running"
exactly "age" value=50 filterGroup="group2"
exactly column="project" value="beats"`,
usage: {
expression: `kibana
| selectFilter
| exactly column=project value=elasticsearch
| demodata
| pointseries x=project y="mean(age)"
| plot defaultStyle={seriesStyle bars=1}
| render`,
help: 'The `exactly` filter here is added to existing filters retrieved by the `filters` function and further filters down the data to only have `"elasticsearch"` data. The `exactly` filter only applies to this one specific element and will not affect other elements in the workpad.',
},
},
filterrows: {
syntax: `filterrows {getCell "project" | eq "kibana"}
filterrows fn={getCell "age" | gt 50}`,
usage: {
expression: `kibana
| selectFilter
| demodata
| filterrows {getCell "country" | any {eq "IN"} {eq "US"} {eq "CN"}}
| mapColumn "@timestamp"
fn={getCell "@timestamp" | rounddate "YYYY-MM"}
| alterColumn "@timestamp" type="date"
| pointseries x="@timestamp" y="mean(cost)" color="country"
| plot defaultStyle={seriesStyle points="2" lines="1"}
palette={palette "#01A4A4" "#CC6666" "#D0D102" "#616161" "#00A1CB" "#32742C" "#F18D05" "#113F8C" "#61AE24" "#D70060" gradient=false}
| render`,
help: 'This uses `filterrows` to only keep data from India (`IN`), the United States (`US`), and China (`CN`).',
},
},
filters: {
syntax: `filters
filters group="timefilter1"
filters group="timefilter2" group="dropdownfilter1" ungrouped=true`,
usage: {
expression: `filters group=group2 ungrouped=true
| demodata
| pointseries x="project" y="size(cost)" color="project"
| plot defaultStyle={seriesStyle bars=0.75} legend=false
font={
font size=14
family="'Open Sans', Helvetica, Arial, sans-serif"
align="left"
color="#FFFFFF"
weight="lighter"
underline=true
italic=true
}
| render`,
help: '`filters` sets the existing filters as context and accepts a `group` parameter to opt into specific filter groups. Setting `ungrouped` to `true` opts out of using global filters.',
},
},
font: {
syntax: `font size=12
font family=Arial
font align=middle
font color=pink
font weight=lighter
font underline=true
font italic=false
font lHeight=32`,
usage: {
expression: `kibana
| selectFilter
| demodata
| pointseries x="project" y="size(cost)" color="project"
| plot defaultStyle={seriesStyle bars=0.75} legend=false
font={
font size=14
family="'Open Sans', Helvetica, Arial, sans-serif"
align="left"
color="#FFFFFF"
weight="lighter"
underline=true
italic=true
}
| render`,
},
},
formatdate: {
syntax: `formatdate format="YYYY-MM-DD"
formatdate "MM/DD/YYYY"`,
usage: {
expression: `kibana
| selectFilter
| demodata
| mapColumn "time" fn={getCell time | formatdate "MMM 'YY"}
| pointseries x="time" y="sum(price)" color="state"
| plot defaultStyle={seriesStyle points=5}
| render`,
help: 'This transforms the dates in the `time` field into strings that look like `"Jan 19"`, `"Feb 19"`, etc. using a MomentJS format.',
},
},
formatnumber: {
syntax: `formatnumber format="$0,0.00"
formatnumber "0.0a"`,
usage: {
expression: `kibana
| selectFilter
| demodata
| math "mean(percent_uptime)"
| progress shape="gauge"
label={formatnumber "0%"}
font={font size=24 family="'Open Sans', Helvetica, Arial, sans-serif" color="#000000" align="center"}
| render`,
help: 'The `formatnumber` subexpression receives the same `context` as the `progress` function, which is the output of the `math` function. It formats the value into a percentage.',
},
},
});

View file

@ -1,38 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { FC } from 'react';
import { ExpressionFunction } from '@kbn/expressions-plugin';
import { EuiButtonEmpty } from '@elastic/eui';
import copy from 'copy-to-clipboard';
import { CanvasPluginServices } from '../../services';
import { generateFunctionReference } from './generate_function_reference';
interface Props {
functionRegistry: Record<string, ExpressionFunction>;
notifyService: CanvasPluginServices['notify'];
}
export const FunctionReferenceGenerator: FC<Props> = ({ functionRegistry, notifyService }) => {
const functionDefinitions = Object.values(functionRegistry);
const copyDocs = () => {
const functionRefs = generateFunctionReference(functionDefinitions);
copy(functionRefs);
notifyService.success(
`Please paste updated docs into '/kibana/docs/canvas/canvas-function-reference.asciidoc' and commit your changes.`,
{ title: 'Copied function docs to clipboard' }
);
};
return (
<EuiButtonEmpty color="danger" flush="left" size="s" iconType="beaker" onClick={copyDocs}>
Generate function reference
</EuiButtonEmpty>
);
};

View file

@ -1,281 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
// @ts-expect-error untyped lib
import pluralize from 'pluralize';
import { ExpressionFunction, ExpressionFunctionParameter } from '@kbn/expressions-plugin';
import { isValidDataUrl } from '@kbn/presentation-util-plugin/public';
import { functions as browserFunctions } from '../../../canvas_plugin_src/functions/browser';
import { functions as serverFunctions } from '../../../canvas_plugin_src/functions/server';
import { DATATABLE_COLUMN_TYPES } from '../../../common/lib';
import { getFunctionExamples, FunctionExample } from './function_examples';
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'.split('');
const REQUIRED_ARG_ANNOTATION = '***';
const MULTI_ARG_ANNOTATION = '†';
const UNNAMED_ARG = '_Unnamed_';
const ANY_TYPE = '`any`';
const examplesDict = getFunctionExamples();
const fnList = [
...browserFunctions.map((fn) => fn().name),
...serverFunctions.map((fn) => fn().name),
'asset',
'clog',
'createTable',
'embeddable',
'filters',
'font',
'image',
'kibana',
'mapColumn',
'math',
'mathColumn',
'metric',
'palette',
'pie',
'plot',
'progress',
'removeFilter',
'repeatImage',
'revealImage',
'selectFilter',
'shape',
'timelion',
'to',
'uiSetting',
'var',
'var_set',
// ignore unsupported embeddables functions for now
].filter((fn) => !['savedSearch'].includes(fn));
interface FunctionDictionary {
[key: string]: ExpressionFunction[];
}
const wrapInBackTicks = (str: string) => `\`${str}\``;
const wrapInDoubleQuotes = (str: string) => (str.includes('"') ? str : `"${str}"`);
const stringSorter = (a: string, b: string) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
};
// Converts reference to another function in a function's help text into an Asciidoc link
const addFunctionLinks = (help: string, options?: { ignoreList?: string[] }) => {
const { ignoreList = [] } = options || {};
fnList.forEach((name: string) => {
const nameWithBackTicks = wrapInBackTicks(name);
// ignore functions with the same name as data types, i.e. string, date
if (
!ignoreList.includes(name) &&
!DATATABLE_COLUMN_TYPES.includes(name) &&
help.includes(nameWithBackTicks)
) {
help = help.replace(nameWithBackTicks, `<<${name}_fn>>`);
}
});
return help;
};
export const generateFunctionReference = (functionDefinitions: ExpressionFunction[]) => {
const functionDefs = functionDefinitions.filter((fn: ExpressionFunction) =>
fnList.includes(fn.name)
);
const functionDictionary: FunctionDictionary = {};
functionDefs.forEach((fn: ExpressionFunction) => {
const firstLetter = fn.name[0];
if (!functionDictionary[firstLetter]) {
functionDictionary[firstLetter] = [];
}
functionDictionary[firstLetter].push(fn);
});
return `[role="xpack"]
[[canvas-function-reference]]
== Canvas function reference
Behind the scenes, Canvas is driven by a powerful expression language,
with dozens of functions and other capabilities, including table transforms,
type casting, and sub-expressions.
The Canvas expression language also supports <<canvas-tinymath-functions>>, which
perform complex math calculations.
A ${REQUIRED_ARG_ANNOTATION} denotes a required argument.
A ${MULTI_ARG_ANNOTATION} denotes an argument can be passed multiple times.
${createAlphabetLinks(functionDictionary)}
${createFunctionDocs(functionDictionary)}`;
};
const createAlphabetLinks = (functionDictionary: FunctionDictionary) => {
return ALPHABET.map((letter: string) =>
functionDictionary[letter] ? `<<${letter}_fns>>` : letter.toUpperCase()
).join(' | ');
};
const createFunctionDocs = (functionDictionary: FunctionDictionary) => {
return Object.keys(functionDictionary)
.sort()
.map(
(letter: string) => `[float]
[[${letter}_fns]]
== ${letter.toUpperCase()}
${functionDictionary[letter]
.sort((a, b) => stringSorter(a.name, b.name))
.map(getDocBlock)
.join('\n')}`
)
.join('');
};
const getDocBlock = (fn: ExpressionFunction) => {
const header = `[float]
[[${fn.name}_fn]]
=== \`${fn.name}\``;
const input = fn.inputTypes;
const output = fn.type;
const args = fn.args;
const examples = examplesDict[fn.name];
const help = addFunctionLinks(fn.help);
const argBlock =
!args || Object.keys(args).length === 0
? ''
: `\n[cols="3*^<"]
|===
|Argument |Type |Description
${getArgsTable(args)}
|===\n`;
const examplesBlock = !examples ? `` : `${getExamplesBlock(examples)}`;
return `${header}\n
${help}
${examplesBlock}
*Accepts:* ${input ? input.map(wrapInBackTicks).join(', ') : ANY_TYPE}\n${argBlock}
*Returns:* ${output ? wrapInBackTicks(output) : 'Depends on your input and arguments'}\n\n`;
};
const getArgsTable = (args: { [key: string]: ExpressionFunctionParameter<any> }) => {
if (!args || Object.keys(args).length === 0) {
return 'None';
}
const argNames = Object.keys(args);
return argNames
.sort((a: string, b: string) => {
const argA = args[a];
const argB = args[b];
// sorts unnamed arg to the front
if (a === '_' || (argA.aliases && argA.aliases.includes('_'))) {
return -1;
}
if (b === '_' || (argB.aliases && argB.aliases.includes('_'))) {
return 1;
}
return stringSorter(a, b);
})
.map((argName: string) => {
const arg = args[argName];
const types = arg.types;
const aliases = arg.aliases ? [...arg.aliases] : [];
let defaultValue = arg.default;
const requiredAnnotation = arg.required === true ? ` ${REQUIRED_ARG_ANNOTATION}` : '';
const multiAnnotation = arg.multi === true ? ` ${MULTI_ARG_ANNOTATION}` : '';
if (typeof defaultValue === 'string') {
defaultValue = defaultValue.replace('{', '${').replace(/[\r\n/]+/g, '');
if (types && types.includes('string')) {
defaultValue = wrapInDoubleQuotes(defaultValue);
}
}
let displayName = '';
if (argName === '_') {
displayName = UNNAMED_ARG;
} else if (aliases && aliases.includes('_')) {
displayName = UNNAMED_ARG;
aliases[aliases.indexOf('_')] = argName;
} else {
displayName = wrapInBackTicks(argName);
}
const aliasList =
aliases && aliases.length
? `\n\n${pluralize('Alias', aliases.length)}: ${aliases
.sort()
.map(wrapInBackTicks)
.join(', ')}`
: '';
let defaultBlock = '';
if (isValidDataUrl(arg.default)) {
defaultBlock = getDataUrlExampleBlock(displayName, arg.default);
} else {
defaultBlock =
typeof defaultValue !== 'undefined' ? `\n\nDefault: \`${defaultValue}\`` : '';
}
return `|${displayName}${requiredAnnotation}${multiAnnotation}${aliasList}
|${types && types.length ? types.map(wrapInBackTicks).join(', ') : ANY_TYPE}
|${arg.help ? addFunctionLinks(arg.help, { ignoreList: argNames }) : ''}${defaultBlock}`;
})
.join('\n\n');
};
const getDataUrlExampleBlock = (
argName: string,
value: string
) => `\n\nExample value for the ${argName} argument, formatted as a \`base64\` data URL:
[source, url]
------------
${value}
------------`;
const getExamplesBlock = (examples: FunctionExample) => {
const { syntax, usage } = examples;
const { expression, help } = usage || {};
const syntaxBlock = syntax
? `\n*Expression syntax*
[source,js]
----
${syntax}
----\n`
: '';
const codeBlock = expression
? `\n*Code example*
[source,text]
----
${expression}
----\n`
: '';
const codeHelp = help ? `${help}\n` : '';
return `${syntaxBlock}${codeBlock}${codeHelp}`;
};

View file

@ -1,8 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { FunctionReferenceGenerator } from './function_reference_generator';

View file

@ -5,22 +5,10 @@
* 2.0.
*/
import React, { FC, lazy, Suspense, useCallback } from 'react';
import { EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
import React, { FC, useCallback } from 'react';
import { EuiButtonEmpty } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ChromeHelpMenuActions } from '@kbn/core/public';
import { ExpressionFunction } from '@kbn/expressions-plugin';
import { CanvasPluginServices } from '../../services';
let FunctionReferenceGenerator: null | React.LazyExoticComponent<any> = null;
if (process.env.NODE_ENV === 'development') {
FunctionReferenceGenerator = lazy(() =>
import('../function_reference_generator').then((module) => ({
default: module.FunctionReferenceGenerator,
}))
);
}
const strings = {
getKeyboardShortcutsLinkLabel: () =>
@ -30,18 +18,11 @@ const strings = {
};
interface Props {
functionRegistry: Record<string, ExpressionFunction>;
notifyService: CanvasPluginServices['notify'];
showKeyboardShortcutsDocFlyout: () => void;
hideHelpMenu: ChromeHelpMenuActions['hideHelpMenu'];
}
export const HelpMenu: FC<Props> = ({
functionRegistry,
notifyService,
hideHelpMenu,
showKeyboardShortcutsDocFlyout,
}) => {
export const HelpMenu: FC<Props> = ({ hideHelpMenu, showKeyboardShortcutsDocFlyout }) => {
const onKeyboardShortcutButtonClick = useCallback(() => {
hideHelpMenu();
showKeyboardShortcutsDocFlyout();
@ -57,16 +38,6 @@ export const HelpMenu: FC<Props> = ({
>
{strings.getKeyboardShortcutsLinkLabel()}
</EuiButtonEmpty>
{FunctionReferenceGenerator ? (
<Suspense fallback={null}>
<EuiSpacer size="xs" />
<FunctionReferenceGenerator
functionRegistry={functionRegistry}
notifyService={notifyService}
/>
</Suspense>
) : null}
</>
);
};

View file

@ -6,16 +6,12 @@
*/
import React, { FC, useCallback } from 'react';
import { ExpressionFunction } from '@kbn/expressions-plugin';
import { ChromeHelpMenuActions } from '@kbn/core/public';
import { useDispatch } from 'react-redux';
import { HelpMenu as Component } from './help_menu.component';
import { CanvasPluginServices } from '../../services';
import { setKeyboardShortcutsDocVisibility } from '../../state/actions/flyouts';
interface Props {
functionRegistry: Record<string, ExpressionFunction>;
notifyService: CanvasPluginServices['notify'];
hideHelpMenu: ChromeHelpMenuActions['hideHelpMenu'];
}