Replace react-anything-sortable with maintained alternative (#35356)

This commit is contained in:
Alexey Antonov 2019-05-02 13:37:45 +03:00 committed by GitHub
parent 1bf7e4ec66
commit 5b6bc86815
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 412 additions and 552 deletions

View file

@ -206,7 +206,6 @@
"raw-loader": "0.5.1",
"react": "^16.8.0",
"react-addons-shallow-compare": "15.6.2",
"react-anything-sortable": "^1.7.4",
"react-color": "^2.13.8",
"react-dom": "^16.8.0",
"react-grid-layout": "^0.16.2",

View file

@ -0,0 +1,5 @@
.tvbEditor {
overflow-y: auto;
overflow-x: hidden;
}

View file

@ -1,41 +0,0 @@
// react-anything-sortable overrides
// Scoped to just the TSVB editor
.tvbEditor {
.ui-sortable {
display: block;
position: relative;
overflow: visible;
user-select: none;
&:before,
&:after {
content: '';
display: table;
}
&:after {
clear: both;
}
.ui-sortable-item.ui-sortable-dragging {
position: absolute;
z-index: $euiZLevel2;
}
.ui-sortable-placeholder {
display: none;
&.visible {
display: block;
opacity: .5;
z-index: -1;
}
}
}
}

View file

@ -9,11 +9,6 @@
.tvbSeriesEditor {
margin-bottom: $euiSize;
padding: $euiSizeS;
// When dragging a collapsed item, make sure the contents doesn't show
&.ui-sortable-dragging {
overflow: hidden;
}
}
.tvbSeries__body {

View file

@ -20,7 +20,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import aggToComponent from '../lib/agg_to_component';
import { sortable } from 'react-anything-sortable';
import { UnsupportedAgg } from './unsupported_agg';
import { TemporaryUnsupportedAgg } from './temporary_unsupported_agg';
@ -46,8 +45,6 @@ function Agg(props) {
<div
className={props.className}
style={style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
>
<Component
fields={props.fields}
@ -60,6 +57,7 @@ function Agg(props) {
series={props.series}
siblings={props.siblings}
uiRestrictions={props.uiRestrictions}
dragHandleProps={props.dragHandleProps}
/>
</div>
);
@ -72,15 +70,11 @@ Agg.propTypes = {
onAdd: PropTypes.func,
onChange: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
panel: PropTypes.object,
series: PropTypes.object,
siblings: PropTypes.array,
sortData: PropTypes.string,
uiRestrictions: PropTypes.object,
dragHandleProps: PropTypes.object,
};
export default sortable(Agg);
export default Agg;

View file

@ -19,42 +19,23 @@
import PropTypes from 'prop-types';
import React from 'react';
import _ from 'lodash';
import { last } from 'lodash';
import AddDeleteButtons from '../add_delete_buttons';
import { EuiToolTip, EuiButtonIcon, EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { injectI18n } from '@kbn/i18n/react';
import { SeriesDragHandler } from '../series_drag_handler';
function AggRowUi(props) {
let iconType = 'eyeClosed';
let iconColor = 'subdued';
const last = _.last(props.siblings);
const lastSibling = last(props.siblings);
const { intl } = props;
if (last.id === props.model.id) {
if (lastSibling.id === props.model.id) {
iconType = 'eye';
iconColor = 'text';
}
let dragHandle;
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip
content={(<FormattedMessage
id="tsvb.aggRow.dragToSortTooltip"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbAggRow__sortHandle"
aria-label={intl.formatMessage({ id: 'tsvb.aggRow.dragToSortAriaLabel', defaultMessage: 'Drag to sort' })}
iconType="grab"
/>
</EuiToolTip>
</EuiFlexItem>
);
}
return (
<div className="tvbAggRow">
<EuiFlexGroup data-test-subj="aggRow" gutterSize="s" alignItems="flexStart" responsive={false}>
@ -64,7 +45,9 @@ function AggRowUi(props) {
<EuiFlexItem className="tvbAggRow__children">
{props.children}
</EuiFlexItem>
{dragHandle}
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={props.disableDelete} />
<EuiFlexItem grow={false}>
<AddDeleteButtons
testSubj="addMetric"
@ -86,6 +69,7 @@ AggRowUi.propTypes = {
onAdd: PropTypes.func,
onDelete: PropTypes.func,
siblings: PropTypes.array,
dragHandleProps: PropTypes.object,
};
const AggRow = injectI18n(AggRowUi);

View file

@ -0,0 +1,84 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { EuiDraggable, EuiDroppable } from '@elastic/eui';
import Agg from './agg';
import newMetricAggFn from '../lib/new_metric_agg_fn';
import seriesChangeHandler from '../lib/series_change_handler';
import { handleAdd, handleDelete } from '../lib/collection_actions';
const DROPPABLE_ID = 'aggs_dnd';
export class Aggs extends PureComponent {
render() {
const { panel, model, fields, uiRestrictions } = this.props;
const list = model.metrics;
const onChange = seriesChangeHandler(this.props, list);
return (
<EuiDroppable
droppableId={`${DROPPABLE_ID}:${model.id}`}
type="MICRO"
spacing="s"
>
{list.map((row, idx) => (
<EuiDraggable
spacing="s"
key={row.id}
index={idx}
customDragHandle={true}
draggableId={`${DROPPABLE_ID}:${model.id}:${row.id}`}
>
{provided => (
<Agg
key={row.id}
disableDelete={list.length < 2}
fields={fields}
model={row}
onAdd={() => handleAdd(this.props, newMetricAggFn)}
onChange={onChange}
onDelete={() => handleDelete(this.props, row)}
panel={panel}
series={model}
siblings={list}
uiRestrictions={uiRestrictions}
dragHandleProps={provided.dragHandleProps}
/>
)}
</EuiDraggable>
))}
</EuiDroppable>
);
}
}
Aggs.propTypes = {
name: PropTypes.string.isRequired,
fields: PropTypes.object.isRequired,
model: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
panel: PropTypes.object.isRequired,
dragHandleProps: PropTypes.object,
};

View file

@ -69,6 +69,7 @@ class CalculationAgg extends Component {
onAdd={this.props.onAdd}
onDelete={this.props.onDelete}
siblings={this.props.siblings}
dragHandleProps={this.props.dragHandleProps}
>
<EuiFlexGroup direction="column" gutterSize="l">
<EuiFlexItem>

View file

@ -39,6 +39,7 @@ function CumulativeSumAgg(props) {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -54,6 +54,7 @@ export const DerivativeAgg = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -68,6 +68,7 @@ export const FilterRatioAgg = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">

View file

@ -69,6 +69,7 @@ class MathAgg extends Component {
onAdd={this.props.onAdd}
onDelete={this.props.onDelete}
siblings={this.props.siblings}
dragHandleProps={this.props.dragHandleProps}
>
<EuiFlexGroup direction="column" gutterSize="l">
<EuiFlexItem>

View file

@ -94,6 +94,7 @@ const MovingAverageAggUi = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -232,6 +232,7 @@ class PercentileAgg extends Component { // eslint-disable-line react/no-multi-co
onAdd={this.props.onAdd}
onDelete={this.props.onDelete}
siblings={this.props.siblings}
dragHandleProps={this.props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -64,6 +64,7 @@ export const PercentileRankAgg = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -44,6 +44,7 @@ export const PositiveOnlyAgg = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -46,6 +46,7 @@ export const SerialDiffAgg = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -92,6 +92,7 @@ function SeriesAggUi(props) {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiTitle className="tvbAggRow__unavailable" size="xxxs">
<span>
@ -112,6 +113,7 @@ function SeriesAggUi(props) {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -56,6 +56,7 @@ export const Static = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -45,6 +45,7 @@ function StandardAgg(props) {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -83,6 +83,7 @@ const StandardDeviationAggUi = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -114,6 +114,7 @@ const StandardSiblingAggUi = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -30,6 +30,7 @@ export function TemporaryUnsupportedAgg(props) {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiTitle className="tvbAggRow__unavailable" size="xxxs">
<span>

View file

@ -147,6 +147,7 @@ const TopHitAggUi = props => {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>

View file

@ -30,6 +30,7 @@ export function UnsupportedAgg(props) {
onAdd={props.onAdd}
onDelete={props.onDelete}
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiTitle className="tvbAggRow__unavailable" size="xxxs">
<span>

View file

@ -117,12 +117,9 @@ class DataFormatPicker extends Component {
let custom;
if (defaultValue === 'duration') {
const [from, to, decimals] = value.split(',');
const selectedFrom = durationInputOptions.find(option => {
return from === option.value;
});
const selectedTo = durationOutputOptions.find(option => {
return to === option.value;
});
const selectedFrom = durationInputOptions.find(option => from === option.value);
const selectedTo = durationOutputOptions.find(option => to === option.value);
return (
<EuiFlexGroup responsive={false} gutterSize="s">
<EuiFlexItem grow={false}>
@ -232,7 +229,6 @@ class DataFormatPicker extends Component {
</EuiFlexGroup>
);
}
}
DataFormatPicker.defaultProps = {

View file

@ -1,48 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import seriesChangeHandler from './series_change_handler';
import newMetricAggFn from './new_metric_agg_fn';
import { handleAdd, handleDelete } from './collection_actions';
import Agg from '../aggs/agg';
export default function createAggRowRender(props) {
return (row, index, items) => {
const { panel, model, fields, uiRestrictions } = props;
const changeHandler = seriesChangeHandler(props, items);
return (
<Agg
key={row.id}
disableDelete={items.length < 2}
fields={fields}
model={row}
onAdd={handleAdd.bind(null, props, newMetricAggFn)}
onChange={changeHandler}
onDelete={handleDelete.bind(null, props, row)}
panel={panel}
series={model}
siblings={items}
uiRestrictions={uiRestrictions}
sortData={row.id}
/>
);
};
}

View file

@ -16,17 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
export const reorder = (
list,
startIndex,
endIndex,
) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
import { keyCodes } from '@elastic/eui';
export function createUpDownHandler(callback) {
return (ev) => {
if (ev.keyCode === keyCodes.UP) {
ev.preventDefault();
callback('up');
} else if (ev.keyCode === keyCodes.DOWN) {
ev.preventDefault();
callback('down');
}
};
}
return result;
};

View file

@ -27,7 +27,6 @@ import topN from './vis_types/top_n/series';
import table from './vis_types/table/series';
import gauge from './vis_types/gauge/series';
import markdown from './vis_types/markdown/series';
import { sortable } from 'react-anything-sortable';
import { FormattedMessage } from '@kbn/i18n/react';
const lookup = {
@ -76,15 +75,15 @@ class Series extends Component {
e.preventDefault();
this.setState({
visible: !this.state.visible
visible: !this.state.visible,
});
};
componentDidMount() {
if (this.props.visData$) {
this.visDataSubscription = this.props.visData$
.subscribe(visData => this.setState({
uiRestrictions: get(visData, 'uiRestrictions')
.subscribe(visData => this.setState({
uiRestrictions: get(visData, 'uiRestrictions'),
}));
}
}
@ -93,44 +92,35 @@ class Series extends Component {
const { panel } = this.props;
const Component = lookup[panel.type];
if (Component) {
const params = {
className: this.props.className,
disableAdd: this.props.disableAdd,
disableDelete: this.props.disableDelete,
fields: this.props.fields,
name: this.props.name,
onAdd: this.props.onAdd,
onChange: this.handleChange,
onClone: this.props.onClone,
onDelete: this.props.onDelete,
onMouseDown: this.props.onMouseDown,
onTouchStart: this.props.onTouchStart,
onShouldSortItem: this.props.onShouldSortItem,
onSortableItemMount: this.props.onSortableItemMount,
onSortableItemReadyToMove: this.props.onSortableItemReadyToMove,
model: this.props.model,
panel: this.props.panel,
selectedTab: this.state.selectedTab,
sortData: this.props.sortData,
style: this.props.style,
uiRestrictions: this.state.uiRestrictions,
switchTab: this.switchTab,
toggleVisible: this.toggleVisible,
togglePanelActivation: this.togglePanelActivation,
visible: this.state.visible,
};
return (<Component {...params}/>);
}
return (
<div>
<FormattedMessage
id="tsvb.seriesConfig.missingSeriesComponentDescription"
defaultMessage="Missing Series component for panel type: {panelType}"
values={{ panelType: panel.type }}
/>
</div>
);
const params = {
className: this.props.className,
disableAdd: this.props.disableAdd,
disableDelete: this.props.disableDelete,
fields: this.props.fields,
name: this.props.name,
onAdd: this.props.onAdd,
onChange: this.handleChange,
onClone: this.props.onClone,
onDelete: this.props.onDelete,
model: this.props.model,
panel: this.props.panel,
selectedTab: this.state.selectedTab,
style: this.props.style,
uiRestrictions: this.state.uiRestrictions,
switchTab: this.switchTab,
toggleVisible: this.toggleVisible,
togglePanelActivation: this.togglePanelActivation,
visible: this.state.visible,
dragHandleProps: this.props.dragHandleProps,
};
return Boolean(Component) ?
(<Component {...params}/>) :
(<FormattedMessage
id="tsvb.seriesConfig.missingSeriesComponentDescription"
defaultMessage="Missing Series component for panel type: {panelType}"
values={{ panelType: panel.type }}
/>);
}
componentWillUnmount() {
@ -154,15 +144,10 @@ Series.propTypes = {
onChange: PropTypes.func,
onClone: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onShouldSortItem: PropTypes.func.isRequired,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
model: PropTypes.object,
panel: PropTypes.object,
visData$: PropTypes.object,
sortData: PropTypes.string,
dragHandleProps: PropTypes.object,
};
export default sortable(Series);
export default Series;

View file

@ -0,0 +1,60 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { EuiFlexItem, EuiToolTip, EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
export class SeriesDragHandler extends PureComponent {
render() {
const { dragHandleProps, hideDragHandler } = this.props;
return (
<EuiFlexItem grow={false}>
<div {...dragHandleProps}>
{!hideDragHandler && (
<EuiToolTip
content={i18n.translate('tsvb.sort.dragToSortTooltip', {
defaultMessage: 'Drag to sort',
})}
>
<EuiIcon
className="tvbSeries__sortHandle"
aria-label={i18n.translate('tsvb.sort.dragToSortAriaLabel', {
defaultMessage: 'Drag to sort',
})}
type="grab"
/>
</EuiToolTip>
)}
</div>
</EuiFlexItem>
);
}
}
SeriesDragHandler.defaultProps = {
hideDragHandler: true,
};
SeriesDragHandler.propTypes = {
hideDragHandler: PropTypes.bool,
dragHandleProps: PropTypes.object.isRequired,
};

View file

@ -19,95 +19,117 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { find } from 'lodash';
import reIdSeries from './lib/re_id_series';
import Series from './series';
import {
handleAdd,
handleDelete,
handleChange
handleChange,
} from './lib/collection_actions';
import newSeriesFn from './lib/new_series_fn';
import Sortable from 'react-anything-sortable';
import { EuiDragDropContext, EuiDroppable, EuiDraggable } from '@elastic/eui';
import { reorder } from './lib/reorder';
const DROPPABLE_ID = 'series_editor_dnd';
class SeriesEditor extends Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
this.sortSeries = this.sortSeries.bind(this);
}
handleClone(series) {
handleClone = series => {
const newSeries = reIdSeries(series);
handleAdd.call(null, this.props, () => newSeries);
}
};
sortSeries(index, direction, allSeries) {
const newIndex = index + (direction === 'up' ? -1 : 1);
if (newIndex < 0 || newIndex >= allSeries.length) {
// Don't do anything when series is already at the edge
return;
sortHandler = ({ destination, source }) => {
const canSort = destination && source;
if (canSort) {
const sortFunction = this.getSortFunction({ destination, source });
sortFunction({ destination, source });
}
};
const newSeries = allSeries.slice(0);
const changeWithElement = allSeries[newIndex];
newSeries[newIndex] = allSeries[index];
newSeries[index] = changeWithElement;
this.props.onChange({ series: newSeries });
}
renderRow(row, index, allSeries) {
const { props } = this;
const { fields, model, name, limit, colorPicker } = props;
return (
<Series
className="tvbSeriesEditor"
colorPicker={colorPicker}
disableAdd={model[name].length >= limit}
disableDelete={model[name].length < 2}
fields={fields}
key={row.id}
onAdd={handleAdd.bind(null, props, newSeriesFn)}
onChange={handleChange.bind(null, props)}
onClone={() => this.handleClone(row)}
onDelete={handleDelete.bind(null, props, row)}
onShouldSortItem={(direction) => this.sortSeries(index, direction, allSeries)}
visData$={this.props.visData$}
model={row}
panel={model}
sortData={row.id}
/>
getSortFunction = ({ destination, source }) =>
(destination.droppableId === source.droppableId && source.droppableId === DROPPABLE_ID ?
this.sortSeries :
this.sortAggregations
);
}
sortSeries = ({ destination, source }) => {
this.props.onChange({
series: reorder([...this.props.model.series], source.index, destination.index),
});
};
sortAggregations = ({ destination, source }) => {
const extractId = ({ droppableId }) => droppableId.split(':')[1];
const id = extractId(source);
const canSort = id === extractId(destination);
if (canSort) {
const model = [...this.props.model.series];
const series = find(model, { id });
series.metrics = reorder([...series.metrics], source.index, destination.index);
this.props.onChange({
series: model,
});
}
};
render() {
const { limit, model, name } = this.props;
const series = model[name]
.filter((val, index) => index < (limit || Infinity))
.map(this.renderRow);
const handleSort = (data) => {
const series = data.map(id => model[name].find(s => s.id === id));
this.props.onChange({ series });
};
const { limit, model, name, fields, colorPicker } = this.props;
const list = model[name]
.filter((val, index) => index < (limit || Infinity));
return (
<div className="tvbSeriesEditor__container">
<Sortable
dynamic={true}
direction="vertical"
onSort={handleSort}
sortHandle="tvbSeries__sortHandle"
<EuiDragDropContext onDragEnd={this.sortHandler}>
<EuiDroppable
droppableId={DROPPABLE_ID}
spacing="l"
type="MACRO"
>
{ series }
</Sortable>
</div>
{list.map((row, idx) => (
<EuiDraggable
spacing="m"
key={row.id}
index={idx}
customDragHandle={true}
draggableId={`${DROPPABLE_ID}:${row.id}`}
disableInteractiveElementBlocking
>
{provided => (
<Series
className="tvbSeriesEditor"
colorPicker={colorPicker}
disableAdd={model[name].length >= limit}
disableDelete={model[name].length < 2}
fields={fields}
onAdd={() => handleAdd(this.props, newSeriesFn)}
onChange={(doc) => handleChange(this.props, doc)}
onClone={() => this.handleClone(row)}
onDelete={() => handleDelete(this.props, row)}
visData$={this.props.visData$}
model={row}
panel={model}
dragHandleProps={provided.dragHandleProps}
/>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
);
}
}
SeriesEditor.defaultProps = {
name: 'series',
limit: Infinity,
colorPicker: true
colorPicker: true,
};
SeriesEditor.propTypes = {

View file

@ -22,19 +22,19 @@ import React from 'react';
import ColorPicker from '../../color_picker';
import AddDeleteButtons from '../../add_delete_buttons';
import { SeriesConfig } from '../../series_config';
import Sortable from 'react-anything-sortable';
import Split from '../../split';
import { EuiToolTip, EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import createAggRowRender from '../../lib/create_agg_row_render';
import { SeriesDragHandler } from '../../series_drag_handler';
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import createTextHandler from '../../lib/create_text_handler';
import { createUpDownHandler } from '../../lib/sort_keyhandler';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { Aggs } from '../../aggs/aggs';
function GaugeSeriesUi(props) {
const {
panel,
fields,
onAdd,
name,
onChange,
onDelete,
disableDelete,
@ -49,7 +49,6 @@ function GaugeSeriesUi(props) {
const model = { ...defaults, ...props.model };
const handleChange = createTextHandler(onChange);
const aggs = model.metrics.map(createAggRowRender(props));
let caretIcon = 'arrowDown';
if (!visible) caretIcon = 'arrowRight';
@ -58,21 +57,17 @@ function GaugeSeriesUi(props) {
if (visible) {
let seriesBody;
if (selectedTab === 'metrics') {
const handleSort = (data) => {
const metrics = data.map(id => model.metrics.find(m => m.id === id));
props.onChange({ metrics });
};
seriesBody = (
<div>
<Sortable
style={{ cursor: 'default' }}
dynamic={true}
direction="vertical"
onSort={handleSort}
sortHandle="tvbAggRow__sortHandle"
>
{ aggs }
</Sortable>
<Aggs
onChange={props.onChange}
fields={fields}
panel={panel}
model={model}
name={name}
uiRestrictions={uiRestrictions}
dragHandleProps={props.dragHandleProps}
/>
<div className="tvbAggRow tvbAggRow--split">
<Split
onChange={props.onChange}
@ -130,35 +125,11 @@ function GaugeSeriesUi(props) {
/>
);
let dragHandle;
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip
content={(<FormattedMessage
id="tsvb.gauge.sort.dragToSortTooltip"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbSeries__sortHandle"
iconType="grab"
aria-label={intl.formatMessage({ id: 'tsvb.gauge.sort.sortAriaLabel', defaultMessage: 'Sort series by pressing up/down' })}
onKeyDown={createUpDownHandler(props.onShouldSortItem)}
/>
</EuiToolTip>
</EuiFlexItem>
);
}
return (
<div
className={`${props.className}`}
style={props.style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
>
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButtonIcon
@ -183,7 +154,7 @@ function GaugeSeriesUi(props) {
/>
</EuiFlexItem>
{ dragHandle }
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={props.disableDelete} />
<EuiFlexItem grow={false}>
<AddDeleteButtons
@ -199,7 +170,6 @@ function GaugeSeriesUi(props) {
/>
</EuiFlexItem>
</EuiFlexGroup>
{ body }
</div>
);
@ -217,19 +187,15 @@ GaugeSeriesUi.propTypes = {
onChange: PropTypes.func,
onClone: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
model: PropTypes.object,
panel: PropTypes.object,
selectedTab: PropTypes.string,
sortData: PropTypes.string,
style: PropTypes.object,
switchTab: PropTypes.func,
toggleVisible: PropTypes.func,
visible: PropTypes.bool,
uiRestrictions: PropTypes.object,
dragHandleProps: PropTypes.object,
};
const GaugeSeries = injectI18n(GaugeSeriesUi);

View file

@ -21,12 +21,12 @@ import PropTypes from 'prop-types';
import React from 'react';
import AddDeleteButtons from '../../add_delete_buttons';
import { SeriesConfig } from '../../series_config';
import Sortable from 'react-anything-sortable';
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';
import { Aggs } from '../../aggs/aggs';
import { SeriesDragHandler } from '../../series_drag_handler';
function MarkdownSeriesUi(props) {
const {
@ -40,6 +40,7 @@ function MarkdownSeriesUi(props) {
selectedTab,
visible,
intl,
name,
uiRestrictions
} = props;
@ -47,7 +48,6 @@ function MarkdownSeriesUi(props) {
const model = { ...defaults, ...props.model };
const handleChange = createTextHandler(onChange);
const aggs = model.metrics.map(createAggRowRender(props));
let caretIcon = 'arrowDown';
if (!visible) caretIcon = 'arrowRight';
@ -56,21 +56,17 @@ function MarkdownSeriesUi(props) {
if (visible) {
let seriesBody;
if (selectedTab === 'metrics') {
const handleSort = (data) => {
const metrics = data.map(id => model.metrics.find(m => m.id === id));
props.onChange({ metrics });
};
seriesBody = (
<div>
<Sortable
style={{ cursor: 'default' }}
dynamic={true}
direction="vertical"
onSort={handleSort}
sortHandle="tvbAggRow__sortHandle"
>
{ aggs }
</Sortable>
<Aggs
onChange={props.onChange}
fields={fields}
panel={panel}
model={model}
name={name}
uiRestrictions={uiRestrictions}
dragHandleProps={props.dragHandleProps}
/>
<div className="tvbAggRow tvbAggRow--split">
<Split
onChange={props.onChange}
@ -123,8 +119,6 @@ function MarkdownSeriesUi(props) {
<div
className={`${props.className}`}
style={props.style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
>
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
@ -155,6 +149,8 @@ function MarkdownSeriesUi(props) {
/>
</EuiFlexItem>
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={true} />
<EuiFlexItem grow={false}>
<AddDeleteButtons
addTooltip={intl.formatMessage({ id: 'tsvb.markdown.editor.addSeriesTooltip', defaultMessage: 'Add series' })}
@ -169,11 +165,9 @@ function MarkdownSeriesUi(props) {
/>
</EuiFlexItem>
</EuiFlexGroup>
{ body }
</div>
);
}
MarkdownSeriesUi.propTypes = {
@ -187,19 +181,15 @@ MarkdownSeriesUi.propTypes = {
onChange: PropTypes.func,
onClone: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
model: PropTypes.object,
panel: PropTypes.object,
selectedTab: PropTypes.string,
sortData: PropTypes.string,
style: PropTypes.object,
switchTab: PropTypes.func,
toggleVisible: PropTypes.func,
visible: PropTypes.bool,
uiRestrictions: PropTypes.object,
dragHandleProps: PropTypes.object,
};
const MarkdownSeries = injectI18n(MarkdownSeriesUi);

View file

@ -22,18 +22,18 @@ import React from 'react';
import ColorPicker from '../../color_picker';
import AddDeleteButtons from '../../add_delete_buttons';
import { SeriesConfig } from '../../series_config';
import Sortable from 'react-anything-sortable';
import Split from '../../split';
import { EuiToolTip, EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import createAggRowRender from '../../lib/create_agg_row_render';
import { SeriesDragHandler } from '../../series_drag_handler';
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import createTextHandler from '../../lib/create_text_handler';
import { createUpDownHandler } from '../../lib/sort_keyhandler';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { Aggs } from '../../aggs/aggs';
function MetricSeriesUi(props) {
const {
panel,
fields,
name,
onAdd,
onChange,
onDelete,
@ -49,7 +49,6 @@ function MetricSeriesUi(props) {
const model = { ...defaults, ...props.model };
const handleChange = createTextHandler(onChange);
const aggs = model.metrics.map(createAggRowRender(props));
let caretIcon = 'arrowDown';
if (!visible) caretIcon = 'arrowRight';
@ -58,21 +57,17 @@ function MetricSeriesUi(props) {
if (visible) {
let seriesBody;
if (selectedTab === 'metrics') {
const handleSort = (data) => {
const metrics = data.map(id => model.metrics.find(m => m.id === id));
props.onChange({ metrics });
};
seriesBody = (
<div>
<Sortable
style={{ cursor: 'default' }}
dynamic={true}
direction="vertical"
onSort={handleSort}
sortHandle="tvbAggRow__sortHandle"
>
{ aggs }
</Sortable>
<Aggs
onChange={props.onChange}
fields={fields}
panel={panel}
model={model}
name={name}
uiRestrictions={uiRestrictions}
dragHandleProps={props.dragHandleProps}
/>
<div className="tvbAggRow tvbAggRow--split">
<Split
onChange={props.onChange}
@ -135,33 +130,10 @@ function MetricSeriesUi(props) {
);
}
let dragHandle;
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip
content={(<FormattedMessage
id="tsvb.metric.sort.dragToSortTooltip"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbSeries__sortHandle"
iconType="grab"
aria-label={intl.formatMessage({ id: 'tsvb.metric.sort.sortAriaLabel', defaultMessage: 'Sort series by pressing up/down' })}
onKeyDown={createUpDownHandler(props.onShouldSortItem)}
/>
</EuiToolTip>
</EuiFlexItem>
);
}
return (
<div
className={`${props.className}`}
style={props.style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
>
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
@ -185,7 +157,7 @@ function MetricSeriesUi(props) {
/>
</EuiFlexItem>
{ dragHandle }
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={props.disableDelete} />
<EuiFlexItem grow={false}>
<AddDeleteButtons
@ -203,7 +175,6 @@ function MetricSeriesUi(props) {
/>
</EuiFlexItem>
</EuiFlexGroup>
{ body }
</div>
);
@ -221,20 +192,16 @@ MetricSeriesUi.propTypes = {
onChange: PropTypes.func,
onClone: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
model: PropTypes.object,
panel: PropTypes.object,
selectedTab: PropTypes.string,
sortData: PropTypes.string,
style: PropTypes.object,
switchTab: PropTypes.func,
toggleVisible: PropTypes.func,
visible: PropTypes.bool,
togglePanelActivation: PropTypes.func,
uiRestrictions: PropTypes.object,
dragHandleProps: PropTypes.object,
};
const MetricSeries = injectI18n(MetricSeriesUi);

View file

@ -18,6 +18,7 @@
*/
import basicAggs from '../../../../common/basic_aggs';
export function isSortable(metric) {
return basicAggs.includes(metric.type);
}

View file

@ -21,28 +21,30 @@ import React from 'react';
import PropTypes from 'prop-types';
import AddDeleteButtons from '../../add_delete_buttons';
import SeriesConfig from './config';
import Sortable from 'react-anything-sortable';
import { EuiToolTip, EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import { SeriesDragHandler } from '../../series_drag_handler';
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import createTextHandler from '../../lib/create_text_handler';
import createAggRowRender from '../../lib/create_agg_row_render';
import { createUpDownHandler } from '../../lib/sort_keyhandler';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import { Aggs } from '../../aggs/aggs';
function TableSeries(props) {
const {
model,
onAdd,
name,
fields,
panel,
onChange,
onDelete,
disableDelete,
disableAdd,
selectedTab,
visible,
intl
intl,
uiRestrictions,
} = props;
const handleChange = createTextHandler(onChange);
const aggs = model.metrics.map(createAggRowRender(props));
let caretIcon = 'arrowDown';
if (!visible) caretIcon = 'arrowRight';
@ -51,21 +53,17 @@ function TableSeries(props) {
if (visible) {
let seriesBody;
if (selectedTab === 'metrics') {
const handleSort = (data) => {
const metrics = data.map(id => model.metrics.find(m => m.id === id));
props.onChange({ metrics });
};
seriesBody = (
<div>
<Sortable
style={{ cursor: 'default' }}
dynamic={true}
direction="vertical"
onSort={handleSort}
sortHandle="tvbAggRow__sortHandle"
>
{ aggs }
</Sortable>
<Aggs
onChange={props.onChange}
fields={fields}
panel={panel}
model={model}
name={name}
uiRestrictions={uiRestrictions}
dragHandleProps={props.dragHandleProps}
/>
</div>
);
} else {
@ -106,33 +104,10 @@ function TableSeries(props) {
);
}
let dragHandle;
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip
content={(<FormattedMessage
id="tsvb.table.dragToSortTooltip"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbSeries__sortHandle"
iconType="grab"
aria-label={intl.formatMessage({ id: 'tsvb.table.dragToSortAriaLabel', defaultMessage: 'Sort series by pressing up/down' })}
onKeyDown={createUpDownHandler(props.onShouldSortItem)}
/>
</EuiToolTip>
</EuiFlexItem>
);
}
return (
<div
className={`${props.className}`}
style={props.style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
>
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
@ -155,7 +130,7 @@ function TableSeries(props) {
/>
</EuiFlexItem>
{ dragHandle }
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={props.disableDelete} />
<EuiFlexItem grow={false}>
<AddDeleteButtons
@ -189,20 +164,16 @@ TableSeries.propTypes = {
onChange: PropTypes.func,
onClone: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
model: PropTypes.object,
panel: PropTypes.object,
selectedTab: PropTypes.string,
sortData: PropTypes.string,
style: PropTypes.object,
switchTab: PropTypes.func,
toggleVisible: PropTypes.func,
visible: PropTypes.bool,
togglePanelActivation: PropTypes.func,
uiRestrictions: PropTypes.object,
dragHandleProps: PropTypes.object,
};
export default injectI18n(TableSeries);

View file

@ -21,13 +21,12 @@ import PropTypes from 'prop-types';
import React from 'react';
import ColorPicker from '../../color_picker';
import AddDeleteButtons from '../../add_delete_buttons';
import { Aggs } from '../../../components/aggs/aggs';
import SeriesConfig from './config';
import Sortable from 'react-anything-sortable';
import { EuiToolTip, EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import { SeriesDragHandler } from '../../series_drag_handler';
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import Split from '../../split';
import createAggRowRender from '../../lib/create_agg_row_render';
import createTextHandler from '../../lib/create_text_handler';
import { createUpDownHandler } from '../../lib/sort_keyhandler';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
const TimeseriesSeries = injectI18n(function (props) {
@ -42,6 +41,7 @@ const TimeseriesSeries = injectI18n(function (props) {
onChange,
visible,
intl,
name,
uiRestrictions
} = props;
@ -49,7 +49,6 @@ const TimeseriesSeries = injectI18n(function (props) {
const model = { ...defaults, ...props.model };
const handleChange = createTextHandler(onChange);
const aggs = model.metrics.map(createAggRowRender(props));
let caretIcon = 'arrowDown';
if (!visible) caretIcon = 'arrowRight';
@ -57,22 +56,19 @@ const TimeseriesSeries = injectI18n(function (props) {
let body = null;
if (visible) {
let seriesBody;
if (selectedTab === 'metrics') {
const handleSort = (data) => {
const metrics = data.map(id => model.metrics.find(m => m.id === id));
props.onChange({ metrics });
};
seriesBody = (
<div>
<Sortable
style={{ cursor: 'default' }}
dynamic={true}
direction="vertical"
onSort={handleSort}
sortHandle="tvbAggRow__sortHandle"
>
{ aggs }
</Sortable>
<Aggs
onChange={props.onChange}
fields={fields}
panel={panel}
model={model}
name={name}
uiRestrictions={uiRestrictions}
dragHandleProps={props.dragHandleProps}
/>
<div className="tvbAggRow tvbAggRow--split">
<Split
onChange={props.onChange}
@ -130,36 +126,10 @@ const TimeseriesSeries = injectI18n(function (props) {
/>
);
let dragHandle;
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip
content={(<FormattedMessage
id="tsvb.timeSeries.dragToSortLabel"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbSeries__sortHandle"
iconType="grab"
aria-label={intl.formatMessage({
id: 'tsvb.timeSeries.dragToSortAriaLabel',
defaultMessage: 'Sort series by pressing up/down'
})}
onKeyDown={createUpDownHandler(props.onShouldSortItem)}
/>
</EuiToolTip>
</EuiFlexItem>
);
}
return (
<div
className={`${props.className}`}
style={props.style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
>
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
@ -188,7 +158,7 @@ const TimeseriesSeries = injectI18n(function (props) {
/>
</EuiFlexItem>
{ dragHandle }
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={props.disableDelete} />
<EuiFlexItem grow={false}>
<AddDeleteButtons
@ -206,7 +176,6 @@ const TimeseriesSeries = injectI18n(function (props) {
/>
</EuiFlexItem>
</EuiFlexGroup>
{ body }
</div>
);
@ -224,21 +193,16 @@ TimeseriesSeries.propTypes = {
onChange: PropTypes.func,
onClone: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onShouldSortItem: PropTypes.func.isRequired,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
model: PropTypes.object,
panel: PropTypes.object,
selectedTab: PropTypes.string,
sortData: PropTypes.string,
style: PropTypes.object,
switchTab: PropTypes.func,
toggleVisible: PropTypes.func,
visible: PropTypes.bool,
togglePanelActivation: PropTypes.func,
uiRestrictions: PropTypes.object,
dragHandleProps: PropTypes.object,
};
export default injectI18n(TimeseriesSeries);

View file

@ -22,18 +22,18 @@ import React from 'react';
import ColorPicker from '../../color_picker';
import AddDeleteButtons from '../../add_delete_buttons';
import { SeriesConfig } from '../../series_config';
import Sortable from 'react-anything-sortable';
import Split from '../../split';
import { EuiToolTip, EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import { SeriesDragHandler } from '../../series_drag_handler';
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiFieldText, EuiButtonIcon } from '@elastic/eui';
import createTextHandler from '../../lib/create_text_handler';
import createAggRowRender from '../../lib/create_agg_row_render';
import { createUpDownHandler } from '../../lib/sort_keyhandler';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import { Aggs } from '../../aggs/aggs';
const TopNSeries = injectI18n(function (props) {
const {
panel,
model,
name,
fields,
onAdd,
onChange,
@ -47,7 +47,6 @@ const TopNSeries = injectI18n(function (props) {
} = props;
const handleChange = createTextHandler(onChange);
const aggs = model.metrics.map(createAggRowRender(props));
let caretIcon = 'arrowDown';
if (!visible) caretIcon = 'arrowRight';
@ -56,21 +55,17 @@ const TopNSeries = injectI18n(function (props) {
if (visible) {
let seriesBody;
if (selectedTab === 'metrics') {
const handleSort = data => {
const metrics = data.map(id => model.metrics.find(m => m.id === id));
props.onChange({ metrics });
};
seriesBody = (
<div>
<Sortable
style={{ cursor: 'default' }}
dynamic={true}
direction="vertical"
onSort={handleSort}
sortHandle="tvbAggRow__sortHandle"
>
{ aggs }
</Sortable>
<Aggs
onChange={props.onChange}
fields={fields}
panel={panel}
model={model}
name={name}
uiRestrictions={uiRestrictions}
dragHandleProps={props.dragHandleProps}
/>
<div className="tvbAggRow tvbAggRow--split">
<Split
onChange={props.onChange}
@ -128,33 +123,10 @@ const TopNSeries = injectI18n(function (props) {
/>
);
let dragHandle;
if (!props.disableDelete) {
dragHandle = (
<EuiFlexItem grow={false}>
<EuiToolTip
content={(<FormattedMessage
id="tsvb.topN.dragToSortTooltip"
defaultMessage="Drag to sort"
/>)}
>
<EuiButtonIcon
className="tvbSeries__sortHandle"
iconType="grab"
aria-label={intl.formatMessage({ id: 'tsvb.topN.dragToSortAriaLabel', defaultMessage: 'Sort series by pressing up/down' })}
onKeyDown={createUpDownHandler(props.onShouldSortItem)}
/>
</EuiToolTip>
</EuiFlexItem>
);
}
return (
<div
className={`${props.className}`}
style={props.style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
>
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
@ -180,7 +152,7 @@ const TopNSeries = injectI18n(function (props) {
/>
</EuiFlexItem>
{ dragHandle }
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={props.disableDelete} />
<EuiFlexItem grow={false}>
<AddDeleteButtons
@ -215,20 +187,16 @@ TopNSeries.propTypes = {
onChange: PropTypes.func,
onClone: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
model: PropTypes.object,
panel: PropTypes.object,
selectedTab: PropTypes.string,
sortData: PropTypes.string,
style: PropTypes.object,
switchTab: PropTypes.func,
toggleVisible: PropTypes.func,
visible: PropTypes.bool,
togglePanelActivation: PropTypes.func,
uiRestrictions: PropTypes.object,
dragHandleProps: PropTypes.object,
};
export default TopNSeries;

View file

@ -11,7 +11,7 @@
@import './mixins';
// Library overrides
@import './ui_sortable';
@import './tvb_editor';
// Components
@import './components/index';

View file

@ -2706,8 +2706,8 @@
"tsvb.aggLookup.varianceLabel": "方差",
"tsvb.aggRow.addMetricButtonTooltip": "添加指标",
"tsvb.aggRow.deleteMetricButtonTooltip": "删除指标",
"tsvb.aggRow.dragToSortAriaLabel": "拖动以排序",
"tsvb.aggRow.dragToSortTooltip": "拖动以排序",
"tsvb.sort.dragToSortTooltip": "拖动以排序",
"tsvb.sort.dragToSortAriaLabel": "拖动以排序",
"tsvb.aggSelect.aggGroups.metricAggLabel": "指标聚合",
"tsvb.aggSelect.aggGroups.parentPipelineAggLabel": "父级管道聚合",
"tsvb.aggSelect.aggGroups.siblingPipelineAggLabel": "同级管道聚合",
@ -2846,8 +2846,6 @@
"tsvb.gauge.optionsTab.panelFilterLabel": "面板筛选",
"tsvb.gauge.optionsTab.panelOptionsButtonLabel": "面板选项",
"tsvb.gauge.optionsTab.styleLabel": "样式",
"tsvb.gauge.sort.dragToSortTooltip": "拖动以排序",
"tsvb.gauge.sort.sortAriaLabel": "按向上/向下以排序序列",
"tsvb.gauge.styleOptions.circleLabel": "圆",
"tsvb.gauge.styleOptions.halfCircleLabel": "半圆",
"tsvb.horizontalLegend.toggleChartAriaLabel": "切换图例",
@ -2917,8 +2915,6 @@
"tsvb.metric.optionsTab.optionsButtonLabel": "选项",
"tsvb.metric.optionsTab.panelFilterLabel": "面板筛选",
"tsvb.metric.optionsTab.panelOptionsButtonLabel": "面板选项",
"tsvb.metric.sort.dragToSortTooltip": "拖动以排序",
"tsvb.metric.sort.sortAriaLabel": "按向上/向下以排序序列",
"tsvb.metricMissingErrorMessage": "缺少 {field} 的指标",
"tsvb.metricSelect.selectMetricPlaceholder": "选择指标......",
"tsvb.missingPanelConfigDescription": "缺少 “{modelType}” 的面板配置",
@ -3034,8 +3030,6 @@
"tsvb.table.dataTab.groupByFieldLabel": "按字段分组",
"tsvb.table.dataTab.rowsLabel": "行",
"tsvb.table.deleteSeriesTooltip": "删除序列",
"tsvb.table.dragToSortAriaLabel": "按向上/向下以排序序列",
"tsvb.table.dragToSortTooltip": "拖动以排序",
"tsvb.table.fieldLabel": "字段",
"tsvb.table.filterLabel": "筛选",
"tsvb.table.labelAriaLabel": "标签",
@ -3080,8 +3074,6 @@
"tsvb.timeSeries.cloneSeriesTooltip": "克隆序列",
"tsvb.timeseries.dataTab.dataButtonLabel": "数据",
"tsvb.timeSeries.deleteSeriesTooltip": "删除序列",
"tsvb.timeSeries.dragToSortAriaLabel": "按向上/向下以排序序列",
"tsvb.timeSeries.dragToSortLabel": "拖动以排序",
"tsvb.timeSeries.filterLabel": "筛选",
"tsvb.timeSeries.gradientLabel": "渐变",
"tsvb.timeSeries.hideInLegendLabel": "隐藏图例",
@ -3140,8 +3132,6 @@
"tsvb.topN.cloneSeriesTooltip": "克隆序列",
"tsvb.topN.dataTab.dataButtonLabel": "数据",
"tsvb.topN.deleteSeriesTooltip": "删除序列",
"tsvb.topN.dragToSortAriaLabel": "按向上/向下以排序序列",
"tsvb.topN.dragToSortTooltip": "拖动以排序",
"tsvb.topN.labelPlaceholder": "标签",
"tsvb.topN.optionsTab.backgroundColorLabel": "背景色:",
"tsvb.topN.optionsTab.colorRulesLabel": "颜色规则",

View file

@ -21002,14 +21002,6 @@ react-addons-shallow-compare@15.6.2:
fbjs "^0.8.4"
object-assign "^4.1.0"
react-anything-sortable@^1.7.4:
version "1.7.4"
resolved "https://registry.yarnpkg.com/react-anything-sortable/-/react-anything-sortable-1.7.4.tgz#c760cf67d7db226bb3943a7bda21c13614dce0cb"
integrity sha512-xeUrzvgAc5JoSk27Ic0zf86pMeT6z2WpT4tIWpSLLMqwCJOlGwaTRO3Y+eNpK+kRjzE1F0JURcaoxks6lcduqA==
dependencies:
create-react-class "^15.5.2"
prop-types "^15.5.8"
react-apollo@^2.1.4:
version "2.1.8"
resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-2.1.8.tgz#ebac0d9bee0f0906df3ce29207f94df337009887"