mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[input controls] Horizontal layout (#14918)
* input controls horizontal layout * fix controlWidth calculation * add functional test to ensure panel resizing changes layout * use all caps for consts, add more comments about where values came from * replace sleeps in functional tests with retry * use KuiFlexGroup with wrap option instead of manually calculating widths * remove no longer used min width constants
This commit is contained in:
parent
cd92cff665
commit
c579677bf9
11 changed files with 269 additions and 136 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
exports[`renders ListControl 1`] = `
|
||||
<Component
|
||||
controlIndex={0}
|
||||
id="mock-list-control"
|
||||
label="list control"
|
||||
>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
exports[`renders RangeControl 1`] = `
|
||||
<Component
|
||||
controlIndex={0}
|
||||
id="mock-range-control"
|
||||
label="range control"
|
||||
>
|
||||
|
|
|
@ -4,37 +4,49 @@ exports[`Apply and Cancel change btns enabled when there are changes 1`] = `
|
|||
<div
|
||||
className="inputControlVis"
|
||||
>
|
||||
<div
|
||||
data-test-subj="inputControl0"
|
||||
<KuiFlexGroup
|
||||
alignItems="stretch"
|
||||
gutterSize="large"
|
||||
justifyContent="flexStart"
|
||||
wrap={true}
|
||||
>
|
||||
<ListControl
|
||||
control={
|
||||
<KuiFlexItem
|
||||
grow={true}
|
||||
style={
|
||||
Object {
|
||||
"getMultiSelectDelimiter": [Function],
|
||||
"id": "mock-list-control",
|
||||
"label": "list control",
|
||||
"options": Object {
|
||||
"multiselect": true,
|
||||
"type": "terms",
|
||||
},
|
||||
"selectOptions": Array [
|
||||
Object {
|
||||
"label": "choice1",
|
||||
"value": "choice1",
|
||||
},
|
||||
Object {
|
||||
"label": "choice2",
|
||||
"value": "choice2",
|
||||
},
|
||||
],
|
||||
"type": "list",
|
||||
"value": "",
|
||||
"minWidth": "250px",
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</div>
|
||||
>
|
||||
<ListControl
|
||||
control={
|
||||
Object {
|
||||
"getMultiSelectDelimiter": [Function],
|
||||
"id": "mock-list-control",
|
||||
"label": "list control",
|
||||
"options": Object {
|
||||
"multiselect": true,
|
||||
"type": "terms",
|
||||
},
|
||||
"selectOptions": Array [
|
||||
Object {
|
||||
"label": "choice1",
|
||||
"value": "choice1",
|
||||
},
|
||||
Object {
|
||||
"label": "choice2",
|
||||
"value": "choice2",
|
||||
},
|
||||
],
|
||||
"type": "list",
|
||||
"value": "",
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</KuiFlexItem>
|
||||
</KuiFlexGroup>
|
||||
<KuiFieldGroup
|
||||
className="actions"
|
||||
isAlignedTop={false}
|
||||
|
@ -86,37 +98,49 @@ exports[`Clear btns enabled when there are values 1`] = `
|
|||
<div
|
||||
className="inputControlVis"
|
||||
>
|
||||
<div
|
||||
data-test-subj="inputControl0"
|
||||
<KuiFlexGroup
|
||||
alignItems="stretch"
|
||||
gutterSize="large"
|
||||
justifyContent="flexStart"
|
||||
wrap={true}
|
||||
>
|
||||
<ListControl
|
||||
control={
|
||||
<KuiFlexItem
|
||||
grow={true}
|
||||
style={
|
||||
Object {
|
||||
"getMultiSelectDelimiter": [Function],
|
||||
"id": "mock-list-control",
|
||||
"label": "list control",
|
||||
"options": Object {
|
||||
"multiselect": true,
|
||||
"type": "terms",
|
||||
},
|
||||
"selectOptions": Array [
|
||||
Object {
|
||||
"label": "choice1",
|
||||
"value": "choice1",
|
||||
},
|
||||
Object {
|
||||
"label": "choice2",
|
||||
"value": "choice2",
|
||||
},
|
||||
],
|
||||
"type": "list",
|
||||
"value": "",
|
||||
"minWidth": "250px",
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</div>
|
||||
>
|
||||
<ListControl
|
||||
control={
|
||||
Object {
|
||||
"getMultiSelectDelimiter": [Function],
|
||||
"id": "mock-list-control",
|
||||
"label": "list control",
|
||||
"options": Object {
|
||||
"multiselect": true,
|
||||
"type": "terms",
|
||||
},
|
||||
"selectOptions": Array [
|
||||
Object {
|
||||
"label": "choice1",
|
||||
"value": "choice1",
|
||||
},
|
||||
Object {
|
||||
"label": "choice2",
|
||||
"value": "choice2",
|
||||
},
|
||||
],
|
||||
"type": "list",
|
||||
"value": "",
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</KuiFlexItem>
|
||||
</KuiFlexGroup>
|
||||
<KuiFieldGroup
|
||||
className="actions"
|
||||
isAlignedTop={false}
|
||||
|
@ -168,37 +192,49 @@ exports[`Renders list control 1`] = `
|
|||
<div
|
||||
className="inputControlVis"
|
||||
>
|
||||
<div
|
||||
data-test-subj="inputControl0"
|
||||
<KuiFlexGroup
|
||||
alignItems="stretch"
|
||||
gutterSize="large"
|
||||
justifyContent="flexStart"
|
||||
wrap={true}
|
||||
>
|
||||
<ListControl
|
||||
control={
|
||||
<KuiFlexItem
|
||||
grow={true}
|
||||
style={
|
||||
Object {
|
||||
"getMultiSelectDelimiter": [Function],
|
||||
"id": "mock-list-control",
|
||||
"label": "list control",
|
||||
"options": Object {
|
||||
"multiselect": true,
|
||||
"type": "terms",
|
||||
},
|
||||
"selectOptions": Array [
|
||||
Object {
|
||||
"label": "choice1",
|
||||
"value": "choice1",
|
||||
},
|
||||
Object {
|
||||
"label": "choice2",
|
||||
"value": "choice2",
|
||||
},
|
||||
],
|
||||
"type": "list",
|
||||
"value": "",
|
||||
"minWidth": "250px",
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</div>
|
||||
>
|
||||
<ListControl
|
||||
control={
|
||||
Object {
|
||||
"getMultiSelectDelimiter": [Function],
|
||||
"id": "mock-list-control",
|
||||
"label": "list control",
|
||||
"options": Object {
|
||||
"multiselect": true,
|
||||
"type": "terms",
|
||||
},
|
||||
"selectOptions": Array [
|
||||
Object {
|
||||
"label": "choice1",
|
||||
"value": "choice1",
|
||||
},
|
||||
Object {
|
||||
"label": "choice2",
|
||||
"value": "choice2",
|
||||
},
|
||||
],
|
||||
"type": "list",
|
||||
"value": "",
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</KuiFlexItem>
|
||||
</KuiFlexGroup>
|
||||
<KuiFieldGroup
|
||||
className="actions"
|
||||
isAlignedTop={false}
|
||||
|
@ -250,31 +286,43 @@ exports[`Renders range control 1`] = `
|
|||
<div
|
||||
className="inputControlVis"
|
||||
>
|
||||
<div
|
||||
data-test-subj="inputControl0"
|
||||
<KuiFlexGroup
|
||||
alignItems="stretch"
|
||||
gutterSize="large"
|
||||
justifyContent="flexStart"
|
||||
wrap={true}
|
||||
>
|
||||
<RangeControl
|
||||
control={
|
||||
<KuiFlexItem
|
||||
grow={true}
|
||||
style={
|
||||
Object {
|
||||
"id": "mock-range-control",
|
||||
"label": "ragne control",
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"options": Object {
|
||||
"decimalPlaces": 0,
|
||||
"step": 1,
|
||||
},
|
||||
"type": "range",
|
||||
"value": Object {
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
},
|
||||
"minWidth": "250px",
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</div>
|
||||
>
|
||||
<RangeControl
|
||||
control={
|
||||
Object {
|
||||
"id": "mock-range-control",
|
||||
"label": "ragne control",
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"options": Object {
|
||||
"decimalPlaces": 0,
|
||||
"step": 1,
|
||||
},
|
||||
"type": "range",
|
||||
"value": Object {
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
controlIndex={0}
|
||||
stageFilter={[Function]}
|
||||
/>
|
||||
</KuiFlexItem>
|
||||
</KuiFlexGroup>
|
||||
<KuiFieldGroup
|
||||
className="actions"
|
||||
isAlignedTop={false}
|
||||
|
|
|
@ -2,7 +2,10 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
|
||||
export const FormRow = (props) => (
|
||||
<div className="kuiVerticalRhythm">
|
||||
<div
|
||||
className="kuiVerticalRhythm"
|
||||
data-test-subj={'inputControl' + props.controlIndex}
|
||||
>
|
||||
<label className="kuiLabel kuiVerticalRhythmSmall" htmlFor={props.id}>
|
||||
{props.label}
|
||||
</label>
|
||||
|
@ -15,5 +18,6 @@ export const FormRow = (props) => (
|
|||
FormRow.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
children: PropTypes.node.isRequired
|
||||
children: PropTypes.node.isRequired,
|
||||
controlIndex: PropTypes.number.isRequired
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ export class ListControl extends Component {
|
|||
<FormRow
|
||||
id={this.props.control.id}
|
||||
label={this.props.control.label}
|
||||
controlIndex={this.props.controlIndex}
|
||||
>
|
||||
<Select
|
||||
className="list-control-react-select"
|
||||
|
|
|
@ -84,6 +84,7 @@ export class RangeControl extends Component {
|
|||
<FormRow
|
||||
id={this.props.control.id}
|
||||
label={this.props.control.label}
|
||||
controlIndex={this.props.controlIndex}
|
||||
>
|
||||
<input
|
||||
id={`${this.props.control.id}_min`}
|
||||
|
|
|
@ -2,7 +2,13 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import { RangeControl } from './range_control';
|
||||
import { ListControl } from './list_control';
|
||||
import { KuiFieldGroup, KuiFieldGroupSection, KuiButton } from 'ui_framework/components';
|
||||
import {
|
||||
KuiFieldGroup,
|
||||
KuiFieldGroupSection,
|
||||
KuiButton,
|
||||
KuiFlexGroup,
|
||||
KuiFlexItem
|
||||
} from 'ui_framework/components';
|
||||
|
||||
export class InputControlVis extends Component {
|
||||
constructor(props) {
|
||||
|
@ -26,6 +32,7 @@ export class InputControlVis extends Component {
|
|||
}
|
||||
|
||||
renderControls() {
|
||||
|
||||
return this.props.controls.map((control, index) => {
|
||||
let controlComponent = null;
|
||||
switch (control.type) {
|
||||
|
@ -51,12 +58,9 @@ export class InputControlVis extends Component {
|
|||
throw new Error(`Unhandled control type ${control.type}`);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key={control.id}
|
||||
data-test-subj={'inputControl' + index}
|
||||
>
|
||||
<KuiFlexItem key={control.id} style={{ minWidth: '250px' }}>
|
||||
{controlComponent}
|
||||
</div>
|
||||
</KuiFlexItem>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -109,7 +113,9 @@ export class InputControlVis extends Component {
|
|||
|
||||
return (
|
||||
<div className="inputControlVis">
|
||||
{this.renderControls()}
|
||||
<KuiFlexGroup wrap>
|
||||
{this.renderControls()}
|
||||
</KuiFlexGroup>
|
||||
{stagingButtons}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -45,4 +45,3 @@ visualization.input_control_vis {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
data-title="{{sharedItemTitle}}"
|
||||
data-description="{{savedObj.description}}"
|
||||
render-counter
|
||||
class="panel-content">
|
||||
class="panel-content {{savedObj.vis.type.name}}">
|
||||
</visualize>
|
||||
|
|
|
@ -1,45 +1,117 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getService, getPageObjects }) {
|
||||
const retry = getService('retry');
|
||||
const find = getService('find');
|
||||
const remote = getService('remote');
|
||||
const PageObjects = getPageObjects(['dashboard', 'header']);
|
||||
const PageObjects = getPageObjects(['dashboard', 'header', 'common']);
|
||||
|
||||
describe('dashboard grid', function describeIndexTests() {
|
||||
before(async function () {
|
||||
describe('dashboard grid', () => {
|
||||
|
||||
before(async () => {
|
||||
return PageObjects.dashboard.initTests();
|
||||
});
|
||||
|
||||
after(async function () {
|
||||
after(async () => {
|
||||
// avoids any 'Object with id x not found' errors when switching tests.
|
||||
await PageObjects.header.clickDashboard();
|
||||
await PageObjects.dashboard.gotoDashboardLandingPage();
|
||||
});
|
||||
|
||||
// Specific test after https://github.com/elastic/kibana/issues/14764 fix
|
||||
it('Can move panel from bottom to top row', async function addVisualizations() {
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.dashboard.addVisualizations([
|
||||
PageObjects.dashboard.getTestVisualizationNames()[0],
|
||||
PageObjects.dashboard.getTestVisualizationNames()[1],
|
||||
PageObjects.dashboard.getTestVisualizationNames()[2],
|
||||
]);
|
||||
describe('move panel', () => {
|
||||
// Specific test after https://github.com/elastic/kibana/issues/14764 fix
|
||||
it('Can move panel from bottom to top row', async () => {
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.dashboard.addVisualizations([
|
||||
PageObjects.dashboard.getTestVisualizationNames()[0],
|
||||
PageObjects.dashboard.getTestVisualizationNames()[1],
|
||||
PageObjects.dashboard.getTestVisualizationNames()[2],
|
||||
]);
|
||||
|
||||
const panels = await find.allByCssSelector('.panel-title');
|
||||
const panels = await find.allByCssSelector('.panel-title');
|
||||
|
||||
const thirdPanel = panels[2];
|
||||
const position1 = await thirdPanel.getPosition();
|
||||
const thirdPanel = panels[2];
|
||||
const position1 = await thirdPanel.getPosition();
|
||||
|
||||
remote
|
||||
.moveMouseTo(thirdPanel)
|
||||
.pressMouseButton()
|
||||
.moveMouseTo(null, -20, -400)
|
||||
.releaseMouseButton();
|
||||
remote
|
||||
.moveMouseTo(thirdPanel)
|
||||
.pressMouseButton()
|
||||
.moveMouseTo(null, -20, -400)
|
||||
.releaseMouseButton();
|
||||
|
||||
const panelsMoved = await find.allByCssSelector('.panel-title');
|
||||
const position2 = await panelsMoved[2].getPosition();
|
||||
const panelsMoved = await find.allByCssSelector('.panel-title');
|
||||
const position2 = await panelsMoved[2].getPosition();
|
||||
|
||||
expect(position1.y).to.be.greaterThan(position2.y);
|
||||
expect(position1.y).to.be.greaterThan(position2.y);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resize panel', () => {
|
||||
|
||||
describe('input control panel', () => {
|
||||
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.dashboard.addVisualizations(['Visualization InputControl']);
|
||||
});
|
||||
|
||||
it('Should position controls in horizontal layout when panel is short and long', async () => {
|
||||
const resizeIcons = await find.allByCssSelector('.react-resizable-handle');
|
||||
expect(resizeIcons.length).to.equal(1);
|
||||
remote
|
||||
.moveMouseTo(resizeIcons[0])
|
||||
.pressMouseButton()
|
||||
.moveMouseTo(null, 300, 0)
|
||||
.releaseMouseButton();
|
||||
|
||||
await retry.try(async () => {
|
||||
const controls = await find.allByCssSelector('.inputControlVis .kuiFlexItem');
|
||||
expect(controls.length).to.equal(3);
|
||||
const control0Position = await controls[0].getPosition();
|
||||
const control1Position = await controls[1].getPosition();
|
||||
const control2Position = await controls[2].getPosition();
|
||||
expect(control0Position.y).to.equal(control1Position.y);
|
||||
expect(control1Position.y).to.equal(control2Position.y);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should position controls in vertical layout when panel is tall and skinny', async () => {
|
||||
const resizeIcons = await find.allByCssSelector('.react-resizable-handle');
|
||||
expect(resizeIcons.length).to.equal(1);
|
||||
remote
|
||||
.moveMouseTo(resizeIcons[0])
|
||||
.pressMouseButton()
|
||||
.moveMouseTo(null, -400, 200)
|
||||
.releaseMouseButton();
|
||||
|
||||
await retry.try(async () => {
|
||||
const controls = await find.allByCssSelector('.inputControlVis .kuiFlexItem');
|
||||
expect(controls.length).to.equal(3);
|
||||
const control0Position = await controls[0].getPosition();
|
||||
const control1Position = await controls[1].getPosition();
|
||||
const control2Position = await controls[2].getPosition();
|
||||
expect(control2Position.y).to.be.greaterThan(control1Position.y);
|
||||
expect(control1Position.y).to.be.greaterThan(control0Position.y);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('Should position controls inside panel', async () => {
|
||||
const controls = await find.allByCssSelector('.inputControlVis .kuiFlexItem');
|
||||
expect(controls.length).to.equal(3);
|
||||
const control0Size = await controls[0].getSize();
|
||||
const control1Size = await controls[1].getSize();
|
||||
const control2Size = await controls[2].getSize();
|
||||
|
||||
const panels = await find.allByCssSelector('.dashboard-panel');
|
||||
expect(panels.length).to.equal(1);
|
||||
const panelSize = await panels[0].getSize();
|
||||
expect(control0Size.width).to.be.lessThan(panelSize.width);
|
||||
expect(control1Size.width).to.be.lessThan(panelSize.width);
|
||||
expect(control2Size.width).to.be.lessThan(panelSize.width);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue