[i18n] Translate Visual Builder(part_2) (#25800)

* Translate visual_builder(part_2)

* Replace namespace metrics to tsvb

* Fix issues
This commit is contained in:
Nox911 2018-11-26 11:44:47 +03:00 committed by GitHub
parent 6efd51e44a
commit 28556bf605
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 721 additions and 187 deletions

View file

@ -13,6 +13,7 @@
"statusPage": "src/core_plugins/status_page",
"tileMap": "src/core_plugins/tile_map",
"timelion": "src/core_plugins/timelion",
"tsvb": "src/core_plugins/metrics",
"tagCloud": "src/core_plugins/tagcloud",
"xpack.graph": "x-pack/plugins/graph",
"xpack.grokDebugger": "x-pack/plugins/grokdebugger",

View file

@ -17,21 +17,55 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
export const durationOutputOptions = [
{ label: 'milliseconds', value: 'ms' },
{ label: 'seconds', value: 's' },
{ label: 'minutes', value: 'm' },
{ label: 'hours', value: 'h' },
{ label: 'days', value: 'd' },
{ label: 'weeks', value: 'w' },
{ label: 'months', value: 'M' },
{ label: 'years', value: 'Y' }
{
label: i18n.translate('tsvb.durationOptions.millisecondsLabel', { defaultMessage: 'milliseconds' }),
value: 'ms'
},
{
label: i18n.translate('tsvb.durationOptions.secondsLabel', { defaultMessage: 'seconds' }),
value: 's'
},
{
label: i18n.translate('tsvb.durationOptions.minutesLabel', { defaultMessage: 'minutes' }),
value: 'm'
},
{
label: i18n.translate('tsvb.durationOptions.hoursLabel', { defaultMessage: 'hours' }),
value: 'h'
},
{
label: i18n.translate('tsvb.durationOptions.daysLabel', { defaultMessage: 'days' }),
value: 'd'
},
{
label: i18n.translate('tsvb.durationOptions.weeksLabel', { defaultMessage: 'weeks' }),
value: 'w'
},
{
label: i18n.translate('tsvb.durationOptions.monthsLabel', { defaultMessage: 'months' }),
value: 'M'
},
{
label: i18n.translate('tsvb.durationOptions.yearsLabel', { defaultMessage: 'years' }),
value: 'Y'
}
];
export const durationInputOptions = [
{ label: 'picoseconds', value: 'ps' },
{ label: 'nanoseconds', value: 'ns' },
{ label: 'microseconds', value: 'us' },
{
label: i18n.translate('tsvb.durationOptions.picosecondsLabel', { defaultMessage: 'picoseconds' }),
value: 'ps'
},
{
label: i18n.translate('tsvb.durationOptions.nanosecondsLabel', { defaultMessage: 'nanoseconds' }),
value: 'ns'
},
{
label: i18n.translate('tsvb.durationOptions.microsecondsLabel', { defaultMessage: 'microseconds' }),
value: 'us' },
...durationOutputOptions
];

View file

@ -20,14 +20,16 @@
import { relativeOptions } from '../../../../../ui/public/timepicker/relative_options';
import _ from 'lodash';
import moment from 'moment';
import { i18n } from '@kbn/i18n';
const unitLookup = {
s: 'seconds',
m: 'minutes',
h: 'hours',
d: 'days',
w: 'weeks',
M: 'months',
y: 'years'
s: i18n.translate('tsvb.axisLabelOptions.secondsLabel', { defaultMessage: 'seconds' }),
m: i18n.translate('tsvb.axisLabelOptions.minutesLabel', { defaultMessage: 'minutes' }),
h: i18n.translate('tsvb.axisLabelOptions.hoursLabel', { defaultMessage: 'hours' }),
d: i18n.translate('tsvb.axisLabelOptions.daysLabel', { defaultMessage: 'days' }),
w: i18n.translate('tsvb.axisLabelOptions.weeksLabel', { defaultMessage: 'weeks' }),
M: i18n.translate('tsvb.axisLabelOptions.monthsLabel', { defaultMessage: 'months' }),
y: i18n.translate('tsvb.axisLabelOptions.yearsLabel', { defaultMessage: 'years' })
};
export function getAxisLabelString(interval) {
const units = _.pluck(_.clone(relativeOptions).reverse(), 'value')
@ -38,7 +40,8 @@ export function getAxisLabelString(interval) {
if (Math.abs(as) > 1) {
const unitValue = Math.round(Math.abs(as));
const unitString = unitLookup[units[i]];
return `per ${unitValue} ${unitString}`;
return i18n.translate('tsvb.axisLabelOptions.axisLabel',
{ defaultMessage: 'per {unitValue} {unitString}', values: { unitValue, unitString } });
}
}
}

View file

@ -19,6 +19,8 @@
import _ from 'lodash';
import handlebars from 'handlebars/dist/handlebars';
import { i18n } from '@kbn/i18n';
export default function replaceVars(str, args = {}, vars = {}) {
try {
const template = handlebars.compile(str, { strict: true });
@ -36,15 +38,17 @@ export default function replaceVars(str, args = {}, vars = {}) {
const badVar = e.message.split(/"/)[1];
e.error = {
caused_by: {
reason: `{{${badVar}}} is an unknown variable`,
title: 'Error processing your markdown'
reason: i18n.translate('tsvb.replaceVars.errors.unknownVarDescription',
{ defaultMessage: '{badVar} is an unknown variable', values: { badVar: '{{' + badVar + '}}' } }),
title: i18n.translate('tsvb.replaceVars.errors.unknownVarTitle', { defaultMessage: 'Error processing your markdown' })
}
};
} else {
e.error = {
caused_by: {
reason: 'Please verify you are only using markdown, known variables, and built-in Handlebars expressions',
title: 'Error processing your markdown'
reason: i18n.translate('tsvb.replaceVars.errors.markdownErrorDescription', {
defaultMessage: 'Please verify you are only using markdown, known variables, and built-in Handlebars expressions' }),
title: i18n.translate('tsvb.replaceVars.errors.markdownErrorTitle', { defaultMessage: 'Error processing your markdown' })
}
};
}

View file

@ -43,8 +43,9 @@ import {
EuiTitle,
EuiHorizontalRule,
} from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
class GaugePanelConfig extends Component {
class GaugePanelConfigUi extends Component {
constructor(props) {
super(props);
@ -70,6 +71,7 @@ class GaugePanelConfig extends Component {
render() {
const { selectedTab } = this.state;
const { intl } = this.props;
const defaults = {
gauge_max: '',
filter: '',
@ -81,8 +83,16 @@ class GaugePanelConfig extends Component {
const handleSelectChange = createSelectHandler(this.props.onChange);
const handleTextChange = createTextHandler(this.props.onChange);
const styleOptions = [
{ label: 'Circle', value: 'circle' },
{ label: 'Half Circle', value: 'half' }
{
label: intl.formatMessage({
id: 'tsvb.gauge.styleOptions.circleLabel', defaultMessage: 'Circle' }),
value: 'circle'
},
{
label: intl.formatMessage({
id: 'tsvb.gauge.styleOptions.halfCircleLabel', defaultMessage: 'Half Circle' }),
value: 'half'
}
];
const htmlId = htmlIdGenerator();
const selectedGaugeStyleOption = styleOptions.find(option => {
@ -104,7 +114,14 @@ class GaugePanelConfig extends Component {
view = (
<div className="tvbPanelConfig__container">
<EuiPanel>
<EuiTitle size="s"><span>Data</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.gauge.optionsTab.dataLabel"
defaultMessage="Data"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<IndexPattern
@ -119,7 +136,10 @@ class GaugePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label="Panel filter"
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
fullWidth
>
<EuiFieldText
@ -130,7 +150,12 @@ class GaugePanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel>Ignore global filter?</EuiFormLabel>
<EuiFormLabel>
<FormattedMessage
id="tsvb.gauge.optionsTab.ignoreGlobalFilterLabel"
defaultMessage="Ignore global filter?"
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo
value={model.ignore_global_filter}
@ -144,14 +169,24 @@ class GaugePanelConfig extends Component {
<EuiSpacer />
<EuiPanel>
<EuiTitle size="s"><span>Style</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.gauge.optionsTab.styleLabel"
defaultMessage="Style"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFlexGroup responsive={false} wrap={true}>
<EuiFlexItem>
<EuiFormRow
id={htmlId('gaugeMax')}
label="Gauge max (empty for auto)"
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeMaxLabel"
defaultMessage="Gauge max (empty for auto)"
/>)}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.
@ -169,7 +204,10 @@ class GaugePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('gaugeStyle')}
label="Gauge style"
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeStyleLabel"
defaultMessage="Gauge style"
/>)}
>
<EuiComboBox
isClearable={false}
@ -183,7 +221,10 @@ class GaugePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('innerLine')}
label="Inner line width"
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.innerLineWidthLabel"
defaultMessage="Inner line width"
/>)}
>
<EuiFieldNumber
onChange={handleTextChange('gauge_inner_width')}
@ -194,7 +235,10 @@ class GaugePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('gaugeLine')}
label="Gauge line width"
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeLineWidthLabel"
defaultMessage="Gauge line width"
/>)}
>
<EuiFieldNumber
onChange={handleTextChange('gauge_width')}
@ -208,7 +252,12 @@ class GaugePanelConfig extends Component {
<EuiFlexGroup responsive={false} wrap={true} alignItems="center">
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Background color:</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.gauge.optionsTab.backgroundColorLabel"
defaultMessage="Background color:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ColorPicker
@ -218,7 +267,12 @@ class GaugePanelConfig extends Component {
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Inner color:</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.gauge.optionsTab.innerColorLabel"
defaultMessage="Inner color:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ColorPicker
@ -231,7 +285,14 @@ class GaugePanelConfig extends Component {
<EuiHorizontalRule />
<EuiTitle size="xxs"><span>Color rules</span></EuiTitle>
<EuiTitle size="xxs">
<span>
<FormattedMessage
id="tsvb.gauge.optionsTab.colorRulesLabel"
defaultMessage="Color rules"
/>
</span>
</EuiTitle>
<EuiSpacer size="s" />
<ColorRules
primaryName="gauge color"
@ -253,13 +314,19 @@ class GaugePanelConfig extends Component {
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
Data
<FormattedMessage
id="tsvb.gauge.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
Panel options
<FormattedMessage
id="tsvb.gauge.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
/>
</EuiTab>
</EuiTabs>
{view}
@ -269,10 +336,11 @@ class GaugePanelConfig extends Component {
}
GaugePanelConfig.propTypes = {
GaugePanelConfigUi.propTypes = {
fields: PropTypes.object,
model: PropTypes.object,
onChange: PropTypes.func,
};
const GaugePanelConfig = injectI18n(GaugePanelConfigUi);
export default GaugePanelConfig;

View file

@ -45,8 +45,9 @@ import {
EuiHorizontalRule,
} from '@elastic/eui';
const lessC = less(window, { env: 'production' });
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
class MarkdownPanelConfig extends Component {
class MarkdownPanelConfigUi extends Component {
constructor(props) {
super(props);
@ -78,13 +79,23 @@ class MarkdownPanelConfig extends Component {
const { selectedTab } = this.state;
const handleSelectChange = createSelectHandler(this.props.onChange);
const handleTextChange = createTextHandler(this.props.onChange);
const { intl } = this.props;
const htmlId = htmlIdGenerator();
const alignOptions = [
{ label: 'Top', value: 'top' },
{ label: 'Middle', value: 'middle' },
{ label: 'Bottom', value: 'bottom' }
{
label: intl.formatMessage({ id: 'tsvb.markdown.alignOptions.topLabel', defaultMessage: 'Top' }),
value: 'top'
},
{
label: intl.formatMessage({ id: 'tsvb.markdown.alignOptions.middleLabel', defaultMessage: 'Middle' }),
value: 'middle'
},
{
label: intl.formatMessage({ id: 'tsvb.markdown.alignOptions.bottomLabel', defaultMessage: 'Bottom' }),
value: 'bottom'
}
];
const selectedAlignOption = alignOptions.find(option => {
return model.markdown_vertical_align === option.value;
@ -106,7 +117,14 @@ class MarkdownPanelConfig extends Component {
view = (
<div className="tvbPanelConfig__container">
<EuiPanel>
<EuiTitle size="s"><span>Data</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.markdown.optionsTab.dataLabel"
defaultMessage="Data"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<IndexPattern
@ -121,7 +139,10 @@ class MarkdownPanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label="Panel filter"
label={(<FormattedMessage
id="tsvb.markdown.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
fullWidth
>
<EuiFieldText
@ -132,7 +153,12 @@ class MarkdownPanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel>Ignore global filter?</EuiFormLabel>
<EuiFormLabel>
<FormattedMessage
id="tsvb.markdown.optionsTab.ignoreGlobalFilterLabel"
defaultMessage="Ignore global filter?"
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo
value={model.ignore_global_filter}
@ -146,12 +172,24 @@ class MarkdownPanelConfig extends Component {
<EuiSpacer />
<EuiPanel>
<EuiTitle size="s"><span>Style</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.markdown.optionsTab.styleLabel"
defaultMessage="Style"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFlexGroup responsive={false} wrap={true} alignItems="center">
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Background color:</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.markdown.optionsTab.backgroundColorLabel"
defaultMessage="Background color:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<ColorPicker
@ -161,7 +199,12 @@ class MarkdownPanelConfig extends Component {
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Show scrollbars?</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.markdown.optionsTab.showScrollbarsLabel"
defaultMessage="Show scrollbars?"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<YesNo
@ -171,7 +214,12 @@ class MarkdownPanelConfig extends Component {
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }} htmlFor={htmlId('valign')}>Vertical alignment:</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }} htmlFor={htmlId('valign')}>
<FormattedMessage
id="tsvb.markdown.optionsTab.verticalAlignmentLabel"
defaultMessage="Vertical alignment:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<EuiComboBox
@ -187,7 +235,14 @@ class MarkdownPanelConfig extends Component {
<EuiHorizontalRule />
<EuiTitle size="xxs"><span>Custom CSS (supports Less)</span></EuiTitle>
<EuiTitle size="xxs">
<span>
<FormattedMessage
id="tsvb.markdown.optionsTab.customCSSLabel"
defaultMessage="Custom CSS (supports Less)"
/>
</span>
</EuiTitle>
<EuiSpacer size="s" />
<KuiCodeEditor
mode="less"
@ -209,20 +264,29 @@ class MarkdownPanelConfig extends Component {
isSelected={selectedTab === 'markdown'}
onClick={() => this.switchTab('markdown')}
>
Markdown
<FormattedMessage
id="tsvb.markdown.markdownTab.markdownButtonLabel"
defaultMessage="Markdown"
/>
</EuiTab>
<EuiTab
data-test-subj="markdownDataBtn"
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
Data
<FormattedMessage
id="tsvb.markdown.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
Panel options
<FormattedMessage
id="tsvb.markdown.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
/>
</EuiTab>
</EuiTabs>
{view}
@ -231,11 +295,12 @@ class MarkdownPanelConfig extends Component {
}
}
MarkdownPanelConfig.propTypes = {
MarkdownPanelConfigUi.propTypes = {
fields: PropTypes.object,
model: PropTypes.object,
onChange: PropTypes.func,
dateFormat: PropTypes.string
};
const MarkdownPanelConfig = injectI18n(MarkdownPanelConfigUi);
export default MarkdownPanelConfig;

View file

@ -39,6 +39,7 @@ import {
EuiTitle,
EuiHorizontalRule,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
class MetricPanelConfig extends Component {
@ -82,7 +83,14 @@ class MetricPanelConfig extends Component {
view = (
<div className="tvbPanelConfig__container">
<EuiPanel>
<EuiTitle size="s"><span>Data</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.metric.optionsTab.dataLabel"
defaultMessage="Data"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<IndexPattern
@ -97,7 +105,10 @@ class MetricPanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label="Panel filter"
label={(<FormattedMessage
id="tsvb.metric.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
fullWidth
>
<EuiFieldText
@ -108,7 +119,12 @@ class MetricPanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel>Ignore global filter?</EuiFormLabel>
<EuiFormLabel>
<FormattedMessage
id="tsvb.metric.optionsTab.ignoreGlobalFilterLabel"
defaultMessage="Ignore global filter?"
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo
value={model.ignore_global_filter}
@ -122,7 +138,14 @@ class MetricPanelConfig extends Component {
<EuiSpacer />
<EuiPanel>
<EuiTitle size="s"><span>Color rules</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.metric.optionsTab.colorRulesLabel"
defaultMessage="Color rules"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<ColorRules
@ -141,14 +164,20 @@ class MetricPanelConfig extends Component {
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
Data
<FormattedMessage
id="tsvb.metric.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
data-test-subj="metricEditorPanelOptionsBtn"
>
Panel options
<FormattedMessage
id="tsvb.metric.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
/>
</EuiTab>
</EuiTabs>
{view}

View file

@ -42,6 +42,7 @@ import {
EuiCode,
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
class TablePanelConfig extends Component {
@ -78,15 +79,23 @@ class TablePanelConfig extends Component {
<EuiPanel>
<EuiText>
<p>
For the table visualization you need to define a field to
group by using a terms aggregation.
<FormattedMessage
id="tsvb.table.dataTab.defineFieldDescription"
defaultMessage="For the table visualization you need to define a field to group by using a terms aggregation."
/>
</p>
</EuiText>
<EuiSpacer size="m" />
<EuiFlexGroup responsive={false} wrap={true}>
<EuiFlexItem data-test-subj="groupByField">
<EuiFormRow id={htmlId('field')} label="Group by field">
<EuiFormRow
id={htmlId('field')}
label={(<FormattedMessage
id="tsvb.table.dataTab.groupByFieldLabel"
defaultMessage="Group by field"
/>)}
>
<FieldSelect
fields={this.props.fields}
value={model.pivot_id}
@ -99,7 +108,10 @@ class TablePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('pivotLabelInput')}
label="Column label"
label={(<FormattedMessage
id="tsvb.table.dataTab.columnLabel"
defaultMessage="Column label"
/>)}
fullWidth
>
<EuiFieldText
@ -113,7 +125,10 @@ class TablePanelConfig extends Component {
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('pivotRowsInput')}
label="Rows"
label={(<FormattedMessage
id="tsvb.table.dataTab.rowsLabel"
defaultMessage="Rows"
/>)}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.
@ -143,15 +158,28 @@ class TablePanelConfig extends Component {
view = (
<div className="tvbPanelConfig__container">
<EuiPanel>
<EuiTitle size="s"><span>Data</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.table.optionsTab.dataLabel"
defaultMessage="Data"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFormRow
id={htmlId('drilldownInput')}
label="Item url"
label={(<FormattedMessage
id="tsvb.table.optionsTab.itemUrlLabel"
defaultMessage="Item url"
/>)}
helpText={
<span>
This supports mustache templating.
<EuiCode>{'{{key}}'}</EuiCode> is set to the term.
<FormattedMessage
id="tsvb.table.optionsTab.itemUrlHelpText"
defaultMessage="This supports mustache templating. {key} is set to the term."
values={{ key: (<EuiCode>{'{{key}}'}</EuiCode>) }}
/>
</span>
}
>
@ -175,7 +203,10 @@ class TablePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilterInput')}
label="Panel filter"
label={(<FormattedMessage
id="tsvb.table.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
fullWidth
>
<EuiFieldText
@ -186,7 +217,12 @@ class TablePanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel htmlFor={htmlId('globalFilterOption')}>Ignore global filter?</EuiFormLabel>
<EuiFormLabel htmlFor={htmlId('globalFilterOption')}>
<FormattedMessage
id="tsvb.table.optionsTab.ignoreGlobalFilterLabel"
defaultMessage="Ignore global filter?"
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo
id={htmlId('globalFilterOption')}
@ -207,13 +243,19 @@ class TablePanelConfig extends Component {
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
Columns
<FormattedMessage
id="tsvb.table.dataTab.columnsButtonLabel"
defaultMessage="Columns"
/>
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
Panel options
<FormattedMessage
id="tsvb.table.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
/>
</EuiTab>
</EuiTabs>
{view}

View file

@ -41,8 +41,9 @@ import {
EuiTitle,
EuiHorizontalRule,
} from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
class TimeseriesPanelConfig extends Component {
class TimeseriesPanelConfigUi extends Component {
constructor(props) {
super(props);
@ -66,24 +67,46 @@ class TimeseriesPanelConfig extends Component {
const handleSelectChange = createSelectHandler(this.props.onChange);
const handleTextChange = createTextHandler(this.props.onChange);
const htmlId = htmlIdGenerator();
const { intl } = this.props;
const positionOptions = [
{ label: 'Right', value: 'right' },
{ label: 'Left', value: 'left' }
{
label: intl.formatMessage({ id: 'tsvb.timeseries.positionOptions.rightLabel', defaultMessage: 'Right' }),
value: 'right'
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.positionOptions.leftLabel', defaultMessage: 'Left' }),
value: 'left'
}
];
const selectedPositionOption = positionOptions.find(option => {
return model.axis_position === option.value;
});
const scaleOptions = [
{ label: 'Normal', value: 'normal' },
{ label: 'Log', value: 'log' }
{
label: intl.formatMessage({ id: 'tsvb.timeseries.scaleOptions.normalLabel', defaultMessage: 'Normal' }),
value: 'normal'
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.scaleOptions.logLabel', defaultMessage: 'Log' }),
value: 'log' }
];
const selectedAxisScaleOption = scaleOptions.find(option => {
return model.axis_scale === option.value;
});
const legendPositionOptions = [
{ label: 'Right', value: 'right' },
{ label: 'Left', value: 'left' },
{ label: 'Bottom', value: 'bottom' }
{
label: intl.formatMessage({ id: 'tsvb.timeseries.legendPositionOptions.rightLabel', defaultMessage: 'Right' }),
value: 'right'
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.legendPositionOptions.leftLabel', defaultMessage: 'Left' }),
value: 'left'
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.legendPositionOptions.bottomLabel', defaultMessage: 'Bottom' }),
value: 'bottom'
}
];
const selectedLegendPosOption = legendPositionOptions.find(option => {
return model.legend_position === option.value;
@ -112,7 +135,14 @@ class TimeseriesPanelConfig extends Component {
view = (
<div className="tvbPanelConfig__container">
<EuiPanel>
<EuiTitle size="s"><span>Data</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.timeseries.optionsTab.dataLabel"
defaultMessage="Data"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<IndexPattern
@ -127,7 +157,10 @@ class TimeseriesPanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label="Panel filter"
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
fullWidth
>
<EuiFieldText
@ -138,7 +171,12 @@ class TimeseriesPanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel>Ignore global filter?</EuiFormLabel>
<EuiFormLabel>
<FormattedMessage
id="tsvb.timeseries.optionsTab.ignoreGlobalFilterLabel"
defaultMessage="Ignore global filter?"
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo
value={model.ignore_global_filter}
@ -152,12 +190,25 @@ class TimeseriesPanelConfig extends Component {
<EuiSpacer />
<EuiPanel>
<EuiTitle size="s"><span>Style</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.timeseries.optionsTab.styleLabel"
defaultMessage="Style"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFlexGroup responsive={false} wrap={true} alignItems="center">
<EuiFlexItem>
<EuiFormRow id={htmlId('axisMin')} label="Axis min">
<EuiFormRow
id={htmlId('axisMin')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisMinLabel"
defaultMessage="Axis min"
/>)}
>
<EuiFieldText
onChange={handleTextChange('axis_min')}
value={model.axis_min}
@ -165,7 +216,13 @@ class TimeseriesPanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow id={htmlId('axisMax')} label="Axis max">
<EuiFormRow
id={htmlId('axisMax')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisMaxLabel"
defaultMessage="Axis max"
/>)}
>
<EuiFieldText
onChange={handleTextChange('axis_max')}
value={model.axis_max}
@ -173,7 +230,13 @@ class TimeseriesPanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow id={htmlId('axisPos')} label="Axis position">
<EuiFormRow
id={htmlId('axisPos')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisPositionLabel"
defaultMessage="Axis position"
/>)}
>
<EuiComboBox
isClearable={false}
options={positionOptions}
@ -184,7 +247,13 @@ class TimeseriesPanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow id={htmlId('axisScale')} label="Axis scale">
<EuiFormRow
id={htmlId('axisScale')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisScaleLabel"
defaultMessage="Axis scale"
/>)}
>
<EuiComboBox
isClearable={false}
options={scaleOptions}
@ -200,7 +269,12 @@ class TimeseriesPanelConfig extends Component {
<EuiFlexGroup responsive={false} wrap={true} alignItems="center">
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Background color:</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.timeseries.optionsTab.backgroundColorLabel"
defaultMessage="Background color:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<ColorPicker
@ -210,7 +284,12 @@ class TimeseriesPanelConfig extends Component {
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Show legend?</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.timeseries.optionsTab.showLegendLabel"
defaultMessage="Show legend?"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<YesNo
@ -220,7 +299,12 @@ class TimeseriesPanelConfig extends Component {
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }} htmlFor={htmlId('legendPos')}>Legend position</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }} htmlFor={htmlId('legendPos')}>
<FormattedMessage
id="tsvb.timeseries.optionsTab.legendPositionLabel"
defaultMessage="Legend position"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<EuiComboBox
@ -233,7 +317,12 @@ class TimeseriesPanelConfig extends Component {
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Display grid</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.timeseries.optionsTab.displayGridLabel"
defaultMessage="Display grid"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<YesNo
@ -254,19 +343,28 @@ class TimeseriesPanelConfig extends Component {
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
Data
<FormattedMessage
id="tsvb.timeseries.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
Panel options
<FormattedMessage
id="tsvb.timeseries.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
/>
</EuiTab>
<EuiTab
isSelected={selectedTab === 'annotations'}
onClick={() => this.switchTab('annotations')}
>
Annotations
<FormattedMessage
id="tsvb.timeseries.annotationsTab.annotationsButtonLabel"
defaultMessage="Annotations"
/>
</EuiTab>
</EuiTabs>
{view}
@ -277,10 +375,11 @@ class TimeseriesPanelConfig extends Component {
}
TimeseriesPanelConfig.propTypes = {
TimeseriesPanelConfigUi.propTypes = {
fields: PropTypes.object,
model: PropTypes.object,
onChange: PropTypes.func,
};
const TimeseriesPanelConfig = injectI18n(TimeseriesPanelConfigUi);
export default TimeseriesPanelConfig;

View file

@ -41,6 +41,7 @@ import {
EuiHorizontalRule,
EuiCode,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
class TopNPanelConfig extends Component {
@ -83,15 +84,28 @@ class TopNPanelConfig extends Component {
view = (
<div className="tvbPanelConfig__container">
<EuiPanel>
<EuiTitle size="s"><span>Data</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.topN.optionsTab.dataLabel"
defaultMessage="Data"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFormRow
id={htmlId('itemUrl')}
label="Item url"
label={(<FormattedMessage
id="tsvb.topN.optionsTab.itemUrlLabel"
defaultMessage="Item url"
/>)}
helpText={
<span>
This supports mustache templating.
<EuiCode>{'{{key}}'}</EuiCode> is set to the term.
<FormattedMessage
id="tsvb.topN.optionsTab.itemUrlDescription"
defaultMessage="This supports mustache templating. {key} is set to the term."
values={{ key: (<EuiCode>{'{{key}}'}</EuiCode>) }}
/>
</span>
}
>
@ -115,7 +129,10 @@ class TopNPanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label="Panel filter"
label={(<FormattedMessage
id="tsvb.topN.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
fullWidth
>
<EuiFieldText
@ -126,7 +143,12 @@ class TopNPanelConfig extends Component {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel>Ignore global filter?</EuiFormLabel>
<EuiFormLabel>
<FormattedMessage
id="tsvb.topN.optionsTab.ignoreGlobalFilterLabel"
defaultMessage="Ignore global filter?"
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo
value={model.ignore_global_filter}
@ -140,12 +162,24 @@ class TopNPanelConfig extends Component {
<EuiSpacer />
<EuiPanel>
<EuiTitle size="s"><span>Style</span></EuiTitle>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.topN.optionsTab.styleLabel"
defaultMessage="Style"
/>
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFlexGroup responsive={false} wrap={true} alignItems="center">
<EuiFlexItem grow={false}>
<EuiFormLabel style={{ marginBottom: 0 }}>Background color:</EuiFormLabel>
<EuiFormLabel style={{ marginBottom: 0 }}>
<FormattedMessage
id="tsvb.topN.optionsTab.backgroundColorLabel"
defaultMessage="Background color:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ColorPicker
@ -158,7 +192,14 @@ class TopNPanelConfig extends Component {
<EuiHorizontalRule />
<EuiTitle size="xxs"><span>Color rules</span></EuiTitle>
<EuiTitle size="xxs">
<span>
<FormattedMessage
id="tsvb.topN.optionsTab.colorRulesLabel"
defaultMessage="Color rules"
/>
</span>
</EuiTitle>
<EuiSpacer size="s" />
<ColorRules
model={model}
@ -179,13 +220,19 @@ class TopNPanelConfig extends Component {
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
Data
<FormattedMessage
id="tsvb.topN.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
Panel options
<FormattedMessage
id="tsvb.topN.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
/>
</EuiTab>
</EuiTabs>
{view}

View file

@ -22,6 +22,7 @@ import GroupBySelect from './group_by_select';
import PropTypes from 'prop-types';
import React from 'react';
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
function SplitByEverything(props) {
const { onChange, model } = props;
@ -30,7 +31,13 @@ function SplitByEverything(props) {
return (
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiFormRow id={htmlId('group')} label="Group by">
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.everything.groupByLabel"
defaultMessage="Group by"
/>)}
>
<GroupBySelect
value={model.split_mode}
onChange={handleSelectChange('split_mode')}

View file

@ -23,6 +23,7 @@ import GroupBySelect from './group_by_select';
import PropTypes from 'prop-types';
import React from 'react';
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiFieldText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const SplitByFilter = props => {
const { onChange } = props;
@ -34,7 +35,13 @@ export const SplitByFilter = props => {
return (
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiFormRow id={htmlId('group')} label="Group by">
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.filter.groupByLabel"
defaultMessage="Group by"
/>)}
>
<GroupBySelect
value={model.split_mode}
onChange={handleSelectChange('split_mode')}
@ -42,7 +49,13 @@ export const SplitByFilter = props => {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow id={htmlId('query')} label="Query string">
<EuiFormRow
id={htmlId('query')}
label={(<FormattedMessage
id="tsvb.splits.filter.queryStringLabel"
defaultMessage="Query string"
/>)}
>
<EuiFieldText
value={model.filter}
onChange={handleTextChange('filter')}

View file

@ -25,7 +25,8 @@ import AddDeleteButtons from '../add_delete_buttons';
import ColorPicker from '../color_picker';
import uuid from 'uuid';
import { EuiFieldText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
class FilterItems extends Component {
import { injectI18n } from '@kbn/i18n/react';
class FilterItemsUi extends Component {
constructor(props) {
super(props);
@ -53,6 +54,8 @@ class FilterItems extends Component {
.bind(null, this.props, newFilter);
const handleDelete = collectionActions.handleDelete
.bind(null, this.props, model);
const { intl } = this.props;
return (
<EuiFlexGroup gutterSize="s" className="tvbAggRow" alignItems="center" key={model.id}>
<EuiFlexItem grow={false}>
@ -65,8 +68,8 @@ class FilterItems extends Component {
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldText
placeholder="Filter"
aria-label="Filter"
placeholder={intl.formatMessage({ id: 'tsvb.splits.filterItems.filterPlaceholder', defaultMessage: 'Filter' })}
aria-label={intl.formatMessage({ id: 'tsvb.splits.filterItems.filterAriaLabel', defaultMessage: 'Filter' })}
onChange={this.handleChange(model, 'filter')}
value={model.filter}
fullWidth
@ -74,8 +77,8 @@ class FilterItems extends Component {
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldText
placeholder="Label"
aria-label="Label"
placeholder={intl.formatMessage({ id: 'tsvb.splits.filterItems.labelPlaceholder', defaultMessage: 'Label' })}
aria-label={intl.formatMessage({ id: 'tsvb.splits.filterItems.labelAriaLabel', defaultMessage: 'Label' })}
onChange={this.handleChange(model, 'label')}
value={model.label}
fullWidth
@ -106,10 +109,11 @@ class FilterItems extends Component {
}
FilterItems.propTypes = {
FilterItemsUi.propTypes = {
name: PropTypes.string,
model: PropTypes.object,
onChange: PropTypes.func
};
const FilterItems = injectI18n(FilterItemsUi);
export default FilterItems;

View file

@ -23,6 +23,7 @@ import FilterItems from './filter_items';
import PropTypes from 'prop-types';
import React from 'react';
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
function SplitByFilters(props) {
const { onChange, model } = props;
@ -32,7 +33,13 @@ function SplitByFilters(props) {
<div>
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiFormRow id={htmlId('group')} label="Group by">
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.filters.groupByLabel"
defaultMessage="Group by"
/>)}
>
<GroupBySelect
value={model.split_mode}
onChange={handleSelectChange('split_mode')}

View file

@ -22,12 +22,27 @@ import React from 'react';
import {
EuiComboBox,
} from '@elastic/eui';
function GroupBySelect(props) {
import { injectI18n } from '@kbn/i18n/react';
function GroupBySelectUi(props) {
const { intl } = props;
const modeOptions = [
{ label: 'Everything', value: 'everything' },
{ label: 'Filter', value: 'filter' },
{ label: 'Filters', value: 'filters' },
{ label: 'Terms', value: 'terms' }
{
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.everythingLabel', defaultMessage: 'Everything' }),
value: 'everything'
},
{
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.filterLabel', defaultMessage: 'Filter' }),
value: 'filter'
},
{
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.filtersLabel', defaultMessage: 'Filters' }),
value: 'filters'
},
{
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.termsLabel', defaultMessage: 'Terms' }),
value: 'terms'
}
];
const selectedValue = props.value || 'everything';
const selectedOption = modeOptions.find(option => {
@ -46,9 +61,10 @@ function GroupBySelect(props) {
}
GroupBySelect.propTypes = {
GroupBySelectUi.propTypes = {
onChange: PropTypes.func,
value: PropTypes.string
};
const GroupBySelect = injectI18n(GroupBySelectUi);
export default GroupBySelect;

View file

@ -25,21 +25,34 @@ import createSelectHandler from '../lib/create_select_handler';
import FieldSelect from '../aggs/field_select';
import MetricSelect from '../aggs/metric_select';
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiFieldNumber, EuiComboBox, EuiSpacer } from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
export const SplitByTerms = props => {
const SplitByTermsUi = props => {
const htmlId = htmlIdGenerator();
const handleTextChange = createTextHandler(props.onChange);
const handleSelectChange = createSelectHandler(props.onChange);
const { indexPattern } = props;
const { indexPattern, intl } = props;
const defaults = { terms_direction: 'desc', terms_size: 10, terms_order_by: '_count' };
const model = { ...defaults, ...props.model };
const { metrics } = model;
const defaultCount = { value: '_count', label: 'Doc Count (default)' };
const terms = { value: '_term', label: 'Terms' };
const defaultCount = {
value: '_count',
label: intl.formatMessage({ id: 'tsvb.splits.terms.defaultCountLabel', defaultMessage: 'Doc Count (default)' })
};
const terms = {
value: '_term',
label: intl.formatMessage({ id: 'tsvb.splits.terms.termsLabel', defaultMessage: 'Terms' })
};
const dirOptions = [
{ value: 'desc', label: 'Descending' },
{ value: 'asc', label: 'Ascending' },
{
value: 'desc',
label: intl.formatMessage({ id: 'tsvb.splits.terms.dirOptions.descendingLabel', defaultMessage: 'Descending' })
},
{
value: 'asc',
label: intl.formatMessage({ id: 'tsvb.splits.terms.dirOptions.ascendingLabel', defaultMessage: 'Ascending' })
},
];
const selectedDirectionOption = dirOptions.find(option => {
return model.terms_direction === option.value;
@ -49,7 +62,13 @@ export const SplitByTerms = props => {
<div>
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiFormRow id={htmlId('group')} label="Group by">
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.terms.groupByLabel"
defaultMessage="Group by"
/>)}
>
<GroupBySelect
value={model.split_mode}
onChange={handleSelectChange('split_mode')}
@ -57,7 +76,13 @@ export const SplitByTerms = props => {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow id={htmlId('by')} label="By">
<EuiFormRow
id={htmlId('by')}
label={(<FormattedMessage
id="tsvb.splits.terms.byLabel"
defaultMessage="By"
/>)}
>
<FieldSelect
indexPattern={indexPattern}
onChange={handleSelectChange('terms_field')}
@ -72,16 +97,28 @@ export const SplitByTerms = props => {
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiFormRow id={htmlId('top')} label="Top">
<EuiFormRow
id={htmlId('top')}
label={(<FormattedMessage
id="tsvb.splits.terms.topLabel"
defaultMessage="Top"
/>)}
>
<EuiFieldNumber
placeholder="Size"
placeholder={intl.formatMessage({ id: 'tsvb.splits.terms.sizePlaceholder', defaultMessage: 'Size' })}
value={Number(model.terms_size)}
onChange={handleTextChange('terms_size')}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow id={htmlId('order')} label="Order by">
<EuiFormRow
id={htmlId('order')}
label={(<FormattedMessage
id="tsvb.splits.terms.orderByLabel"
defaultMessage="Order by"
/>)}
>
<MetricSelect
metrics={metrics}
clearable={false}
@ -93,7 +130,13 @@ export const SplitByTerms = props => {
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow id={htmlId('direction')} label="Direction">
<EuiFormRow
id={htmlId('direction')}
label={(<FormattedMessage
id="tsvb.splits.terms.directionLabel"
defaultMessage="Direction"
/>)}
>
<EuiComboBox
isClearable={false}
options={dirOptions}
@ -108,9 +151,11 @@ export const SplitByTerms = props => {
);
};
SplitByTerms.propTypes = {
SplitByTermsUi.propTypes = {
model: PropTypes.object,
onChange: PropTypes.func,
indexPattern: PropTypes.string,
fields: PropTypes.object
};
export const SplitByTerms = injectI18n(SplitByTermsUi);

View file

@ -28,8 +28,9 @@ import { EuiToolTip, EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, E
import createAggRowRender from '../../lib/create_agg_row_render';
import createTextHandler from '../../lib/create_text_handler';
import { createUpDownHandler } from '../../lib/sort_keyhandler';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
function GaugeSeries(props) {
function GaugeSeriesUi(props) {
const {
panel,
fields,
@ -39,7 +40,8 @@ function GaugeSeries(props) {
disableDelete,
disableAdd,
selectedTab,
visible
visible,
intl
} = props;
const defaults = { label: '' };
@ -96,14 +98,20 @@ function GaugeSeries(props) {
isSelected={selectedTab === 'metrics'}
onClick={() => props.switchTab('metrics')}
>
Metrics
<FormattedMessage
id="tsvb.gauge.dataTab.metricsButtonLabel"
defaultMessage="Metrics"
/>
</EuiTab>
<EuiTab
data-test-subj="seriesOptions"
isSelected={selectedTab === 'options'}
onClick={() => props.switchTab('options')}
>
Options
<FormattedMessage
id="tsvb.gauge.optionsTab.optionsButtonLabel"
defaultMessage="Options"
/>
</EuiTab>
</EuiTabs>
{seriesBody}
@ -124,11 +132,16 @@ function GaugeSeries(props) {
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip content="Drag to sort">
<EuiToolTip
content={(<FormattedMessage
id="tsvb.gauge.sort.dragToSortTooltip"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbSeries__sortHandle"
iconType="grab"
aria-label="Sort series by pressing up/down"
aria-label={intl.formatMessage({ id: 'tsvb.gauge.sort.sortAriaLabel', defaultMessage: 'Sort series by pressing up/down' })}
onKeyDown={createUpDownHandler(props.onShouldSortItem)}
/>
</EuiToolTip>
@ -150,7 +163,7 @@ function GaugeSeries(props) {
iconType={caretIcon}
color="text"
onClick={props.toggleVisible}
aria-label="Toggle series editor"
aria-label={intl.formatMessage({ id: 'tsvb.gauge.editor.toggleEditorAriaLabel', defaultMessage: 'Toggle series editor' })}
aria-expanded={props.visible}
/>
</EuiFlexItem>
@ -163,7 +176,7 @@ function GaugeSeries(props) {
<EuiFieldText
fullWidth
onChange={handleChange('label')}
placeholder="Label"
placeholder={intl.formatMessage({ id: 'tsvb.gauge.editor.labelPlaceholder', defaultMessage: 'Label' })}
value={model.label}
/>
</EuiFlexItem>
@ -172,9 +185,9 @@ function GaugeSeries(props) {
<EuiFlexItem grow={false}>
<AddDeleteButtons
addTooltip="Add Series"
deleteTooltip="Delete Series"
cloneTooltip="Clone Series"
addTooltip={intl.formatMessage({ id: 'tsvb.gauge.editor.addSeriesTooltip', defaultMessage: 'Add Series' })}
deleteTooltip={intl.formatMessage({ id: 'tsvb.gauge.editor.deleteSeriesTooltip', defaultMessage: 'Delete Series' })}
cloneTooltip={intl.formatMessage({ id: 'tsvb.gauge.editor.cloneSeriesTooltip', defaultMessage: 'Clone Series' })}
onDelete={onDelete}
onClone={props.onClone}
onAdd={onAdd}
@ -191,7 +204,7 @@ function GaugeSeries(props) {
}
GaugeSeries.propTypes = {
GaugeSeriesUi.propTypes = {
className: PropTypes.string,
colorPicker: PropTypes.bool,
disableAdd: PropTypes.bool,
@ -216,4 +229,5 @@ GaugeSeries.propTypes = {
visible: PropTypes.bool
};
const GaugeSeries = injectI18n(GaugeSeriesUi);
export default GaugeSeries;

View file

@ -26,8 +26,9 @@ import Split from '../../split';
import createAggRowRender from '../../lib/create_agg_row_render';
import createTextHandler from '../../lib/create_text_handler';
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
function MarkdownSeries(props) {
function MarkdownSeriesUi(props) {
const {
panel,
fields,
@ -37,7 +38,8 @@ function MarkdownSeries(props) {
disableDelete,
disableAdd,
selectedTab,
visible
visible,
intl
} = props;
const defaults = { label: '', var_name: '' };
@ -94,14 +96,20 @@ function MarkdownSeries(props) {
isSelected={selectedTab === 'metrics'}
onClick={() => props.switchTab('metrics')}
>
Metrics
<FormattedMessage
id="tsvb.markdown.dataTab.metricsButtonLabel"
defaultMessage="Metrics"
/>
</EuiTab>
<EuiTab
data-test-subj="seriesOptions"
isSelected={selectedTab === 'options'}
onClick={() => props.switchTab('options')}
>
Options
<FormattedMessage
id="tsvb.markdown.optionsTab.optionsButtonLabel"
defaultMessage="Options"
/>
</EuiTab>
</EuiTabs>
{seriesBody}
@ -122,7 +130,7 @@ function MarkdownSeries(props) {
iconType={caretIcon}
color="text"
onClick={props.toggleVisible}
aria-label="Toggle series editor"
aria-label={intl.formatMessage({ id: 'tsvb.markdown.editor.toggleEditorAriaLabel', defaultMessage: 'Toggle series editor' })}
aria-expanded={props.visible}
/>
</EuiFlexItem>
@ -131,7 +139,7 @@ function MarkdownSeries(props) {
<EuiFieldText
fullWidth
onChange={handleChange('label')}
placeholder="Label"
placeholder={intl.formatMessage({ id: 'tsvb.markdown.editor.labelPlaceholder', defaultMessage: 'Label' })}
value={model.label}
/>
</EuiFlexItem>
@ -140,16 +148,16 @@ function MarkdownSeries(props) {
<EuiFieldText
fullWidth
onChange={handleChange('var_name')}
placeholder="Variable name"
placeholder={intl.formatMessage({ id: 'tsvb.markdown.editor.variableNamePlaceholder', defaultMessage: 'Variable name' })}
value={model.var_name}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<AddDeleteButtons
addTooltip="Add series"
deleteTooltip="Delete series"
cloneTooltip="Clone series"
addTooltip={intl.formatMessage({ id: 'tsvb.markdown.editor.addSeriesTooltip', defaultMessage: 'Add series' })}
deleteTooltip={intl.formatMessage({ id: 'tsvb.markdown.editor.deleteSeriesTooltip', defaultMessage: 'Delete series' })}
cloneTooltip={intl.formatMessage({ id: 'tsvb.markdown.editor.cloneSeriesTooltip', defaultMessage: 'Clone series' })}
onDelete={onDelete}
onClone={props.onClone}
onAdd={onAdd}
@ -166,7 +174,7 @@ function MarkdownSeries(props) {
}
MarkdownSeries.propTypes = {
MarkdownSeriesUi.propTypes = {
className: PropTypes.string,
colorPicker: PropTypes.bool,
disableAdd: PropTypes.bool,
@ -191,4 +199,5 @@ MarkdownSeries.propTypes = {
visible: PropTypes.bool
};
const MarkdownSeries = injectI18n(MarkdownSeriesUi);
export default MarkdownSeries;

View file

@ -28,8 +28,9 @@ import { EuiToolTip, EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, E
import createAggRowRender from '../../lib/create_agg_row_render';
import createTextHandler from '../../lib/create_text_handler';
import { createUpDownHandler } from '../../lib/sort_keyhandler';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
function MetricSeries(props) {
function MetricSeriesUi(props) {
const {
panel,
fields,
@ -39,7 +40,8 @@ function MetricSeries(props) {
disableDelete,
disableAdd,
selectedTab,
visible
visible,
intl
} = props;
const defaults = { label: '' };
@ -96,14 +98,20 @@ function MetricSeries(props) {
isSelected={selectedTab === 'metrics'}
onClick={() => props.switchTab('metrics')}
>
Metrics
<FormattedMessage
id="tsvb.metric.dataTab.metricsButtonLabel"
defaultMessage="Metrics"
/>
</EuiTab>
<EuiTab
data-test-subj="seriesOptions"
isSelected={selectedTab === 'options'}
onClick={() => props.switchTab('options')}
>
Options
<FormattedMessage
id="tsvb.metric.optionsTab.optionsButtonLabel"
defaultMessage="Options"
/>
</EuiTab>
</EuiTabs>
{seriesBody}
@ -129,11 +137,16 @@ function MetricSeries(props) {
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip content="Drag to sort">
<EuiToolTip
content={(<FormattedMessage
id="tsvb.metric.sort.dragToSortTooltip"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbSeries__sortHandle"
iconType="grab"
aria-label="Sort series by pressing up/down"
aria-label={intl.formatMessage({ id: 'tsvb.metric.sort.sortAriaLabel', defaultMessage: 'Sort series by pressing up/down' })}
onKeyDown={createUpDownHandler(props.onShouldSortItem)}
/>
</EuiToolTip>
@ -154,7 +167,7 @@ function MetricSeries(props) {
iconType={caretIcon}
color="text"
onClick={props.toggleVisible}
aria-label="Toggle series editor"
aria-label={intl.formatMessage({ id: 'tsvb.metric.editor.toggleEditorAriaLabel', defaultMessage: 'Toggle series editor' })}
aria-expanded={props.visible}
/>
</EuiFlexItem>
@ -165,7 +178,7 @@ function MetricSeries(props) {
<EuiFieldText
fullWidth
onChange={handleChange('label')}
placeholder="Label"
placeholder={intl.formatMessage({ id: 'tsvb.metric.editor.labelPlaceholder', defaultMessage: 'Label' })}
value={model.label}
/>
</EuiFlexItem>
@ -174,9 +187,9 @@ function MetricSeries(props) {
<EuiFlexItem grow={false}>
<AddDeleteButtons
addTooltip="Add Series"
deleteTooltip="Delete Series"
cloneTooltip="Clone Series"
addTooltip={intl.formatMessage({ id: 'tsvb.metric.editor.addSeriesTooltip', defaultMessage: 'Add Series' })}
deleteTooltip={intl.formatMessage({ id: 'tsvb.metric.editor.deleteSeriesTooltip', defaultMessage: 'Delete Series' })}
cloneTooltip={intl.formatMessage({ id: 'tsvb.metric.editor.cloneSeriesTooltip', defaultMessage: 'Clone Series' })}
onDelete={onDelete}
onClone={props.onClone}
onAdd={onAdd}
@ -193,7 +206,7 @@ function MetricSeries(props) {
}
MetricSeries.propTypes = {
MetricSeriesUi.propTypes = {
className: PropTypes.string,
colorPicker: PropTypes.bool,
disableAdd: PropTypes.bool,
@ -218,4 +231,5 @@ MetricSeries.propTypes = {
visible: PropTypes.bool
};
const MetricSeries = injectI18n(MetricSeriesUi);
export default MetricSeries;

View file

@ -19,6 +19,7 @@
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { I18nProvider } from '@kbn/i18n/react';
function ReactEditorControllerProvider(Private, config) {
class ReactEditorController {
@ -30,15 +31,19 @@ function ReactEditorControllerProvider(Private, config) {
async render(params) {
const Component = this.vis.type.editorConfig.component;
render(<Component
config={config}
vis={this.vis}
savedObj={this.savedObj}
timeRange={params.timeRange}
renderComplete={() => {}}
isEditorMode={true}
appState={params.appState}
/>, this.el);
render(
<I18nProvider>
<Component
config={config}
vis={this.vis}
savedObj={this.savedObj}
timeRange={params.timeRange}
renderComplete={() => {}}
isEditorMode={true}
appState={params.appState}
/>
</I18nProvider>,
this.el);
}
resize() {

View file

@ -22,8 +22,8 @@ import { timezoneProvider } from 'ui/vis/lib/timezone';
import { timefilter } from 'ui/timefilter';
import { BuildESQueryProvider } from '@kbn/es-query';
const MetricsRequestHandlerProvider = function (Private, Notifier, config, $http) {
const notify = new Notifier({ location: 'Metrics' });
const MetricsRequestHandlerProvider = function (Private, Notifier, config, $http, i18n) {
const notify = new Notifier({ location: i18n('tsvb.requestHandler.notifier.locationNameTitle', { defaultMessage: 'Metrics' }) });
const buildEsQuery = Private(BuildESQueryProvider);
return {

View file

@ -18,6 +18,7 @@
*/
import { kfetch } from 'ui/kfetch';
import { toastNotifications } from 'ui/notify';
import { i18n } from '@kbn/i18n';
async function fetchFields(indexPatterns = ['*']) {
const patterns = Array.isArray(indexPatterns) ? indexPatterns : [indexPatterns];
@ -40,7 +41,9 @@ async function fetchFields(indexPatterns = ['*']) {
return fields;
} catch(error) {
toastNotifications.addDanger({
title: 'Unable to load index_pattern fields',
title: i18n.translate('tsvb.fetchFields.loadIndexPatternFieldsErrorMessage', {
defaultMessage: 'Unable to load index_pattern fields'
}),
text: error.message,
});
}

View file

@ -19,6 +19,8 @@
import { parseInterval } from 'ui/utils/parse_interval';
import { GTE_INTERVAL_RE } from '../../common/interval_regexp';
import { i18n } from '@kbn/i18n';
export function validateInterval(bounds, panel, maxBuckets) {
const { interval } = panel;
const { min, max } = bounds;
@ -32,7 +34,10 @@ export function validateInterval(bounds, panel, maxBuckets) {
const span = max.valueOf() - min.valueOf();
const buckets = Math.floor(span / duration.asMilliseconds());
if (buckets > maxBuckets) {
throw new Error(`Max buckets exceeded: ${buckets} is greater than ${maxBuckets}, try a larger time interval in the panel options.`);
throw new Error(i18n.translate('tsvb.validateInterval.notifier.maxBucketsExceededErrorMessage', {
defaultMessage: 'Max buckets exceeded: {buckets} is greater than {maxBuckets}, try a larger time interval in the panel options.',
values: { buckets, maxBuckets }
}));
}
}
}