mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
parent
3294a2ff8e
commit
20c9e3bf30
11 changed files with 200 additions and 14 deletions
|
@ -17,6 +17,42 @@
|
|||
.collapsible-sidebar {
|
||||
.flex-parent(0, 0, auto);
|
||||
margin-right: 10px;
|
||||
flex-direction: row;
|
||||
max-width: 75%;
|
||||
min-width: @vis-editor-sidebar-min-width;
|
||||
width: @vis-editor-sidebar-min-width;
|
||||
}
|
||||
|
||||
.collapsible-sidebar--small {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.collapsible-sidebar--medium {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.collapsible-sidebar--large {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
|
||||
.default-editor__resizer {
|
||||
display: flex;
|
||||
flex: 0 0 13px;
|
||||
cursor: ew-resize;
|
||||
background-color: @globalColorLightestGray;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten(@globalColorBlue, 50%);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: @globalColorBlue;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.visualization-options {
|
||||
|
@ -81,8 +117,6 @@
|
|||
// overrided for tablet and desktop
|
||||
@media (min-width: @screen-md-min) {
|
||||
flex-basis: @vis-editor-sidebar-basis;
|
||||
min-width: @vis-editor-sidebar-min-width;
|
||||
max-width: @vis-editor-sidebar-min-width;
|
||||
}
|
||||
|
||||
.index-pattern,
|
||||
|
|
|
@ -6,6 +6,7 @@ import markdownVisTemplate from 'plugins/markdown_vis/markdown_vis.html';
|
|||
import markdownVisParamsTemplate from 'plugins/markdown_vis/markdown_vis_params.html';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import image from './images/icon-markdown.svg';
|
||||
import { DefaultEditorSize } from 'ui/vis/editor_size';
|
||||
// we need to load the css ourselves
|
||||
|
||||
// we also need to load the controller and used by the template
|
||||
|
@ -32,7 +33,9 @@ function MarkdownVisProvider(Private) {
|
|||
}
|
||||
},
|
||||
editorConfig: {
|
||||
optionsTemplate: markdownVisParamsTemplate
|
||||
optionsTemplate: markdownVisParamsTemplate,
|
||||
enableAutoApply: true,
|
||||
defaultSize: DefaultEditorSize.LARGE,
|
||||
},
|
||||
options: {
|
||||
showTimePicker: false,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { CATEGORY } from 'ui/vis/vis_category';
|
|||
import image from '../images/icon-timelion.svg';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import { TimelionRequestHandlerProvider } from './timelion_request_handler';
|
||||
import { DefaultEditorSize } from 'ui/vis/editor_size';
|
||||
|
||||
// we also need to load the controller and directive used by the template
|
||||
import 'plugins/timelion/vis/timelion_vis_controller';
|
||||
|
@ -38,6 +39,7 @@ export default function TimelionVisProvider(Private) {
|
|||
},
|
||||
editorConfig: {
|
||||
optionsTemplate: editorConfigTemplate,
|
||||
defaultSize: DefaultEditorSize.MEDIUM,
|
||||
},
|
||||
requestHandler: timelionRequestHandler.handler,
|
||||
responseHandler: 'none',
|
||||
|
|
5
src/ui/public/vis/editor_size.js
Normal file
5
src/ui/public/vis/editor_size.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export const DefaultEditorSize = {
|
||||
SMALL: 'small',
|
||||
MEDIUM: 'medium',
|
||||
LARGE: 'large'
|
||||
};
|
|
@ -1,5 +1,11 @@
|
|||
<div class="collapsible-sidebar">
|
||||
<div class="collapsible-sidebar" ng-class="::getSidebarClass()">
|
||||
<vis-editor-sidebar class="vis-editor-sidebar" />
|
||||
<vis-editor-resizer
|
||||
class="default-editor__resizer"
|
||||
tabindex="0"
|
||||
aria-label="Press left/right to resize the editor"
|
||||
data-test-subj="visualizeEditorResizer"
|
||||
>︙</vis-editor-resizer>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import './sidebar';
|
||||
import './vis_options';
|
||||
import './vis_editor_resizer';
|
||||
import $ from 'jquery';
|
||||
|
||||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
import defaultEditorTemplate from './default.html';
|
||||
import { keyCodes } from '@elastic/eui';
|
||||
import { DefaultEditorSize } from 'ui/vis/editor_size';
|
||||
|
||||
import { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
|
||||
|
||||
|
@ -60,6 +63,36 @@ const defaultEditor = function ($rootScope, $compile) {
|
|||
$scope.vis.dirty = false;
|
||||
};
|
||||
|
||||
$scope.autoApplyEnabled = false;
|
||||
if ($scope.vis.type.editorConfig.enableAutoApply) {
|
||||
$scope.toggleAutoApply = () => {
|
||||
$scope.autoApplyEnabled = !$scope.autoApplyEnabled;
|
||||
};
|
||||
|
||||
$scope.$watch('vis.dirty', _.debounce(() => {
|
||||
if (!$scope.autoApplyEnabled || !$scope.vis.dirty) return;
|
||||
$scope.stageEditableVis();
|
||||
}, 800));
|
||||
}
|
||||
|
||||
$scope.submitEditorWithKeyboard = (event) => {
|
||||
if (event.ctrlKey && event.keyCode === keyCodes.ENTER) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$scope.stageEditableVis();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getSidebarClass = () => {
|
||||
if ($scope.vis.type.editorConfig.defaultSize === DefaultEditorSize.SMALL) {
|
||||
return 'collapsible-sidebar--small';
|
||||
} else if ($scope.vis.type.editorConfig.defaultSize === DefaultEditorSize.MEDIUM) {
|
||||
return 'collapsible-sidebar--medium';
|
||||
} else if ($scope.vis.type.editorConfig.defaultSize === DefaultEditorSize.LARGE) {
|
||||
return 'collapsible-sidebar--large';
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$watch(function () {
|
||||
return $scope.vis.getCurrentState(false);
|
||||
}, function (newState) {
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
ng-submit="visualizeEditor.$invalid ? stageEditableVis(false) : stageEditableVis()"
|
||||
name="visualizeEditor"
|
||||
novalidate
|
||||
ng-keydown="submitEditorWithKeyboard($event)"
|
||||
><!-- see http://goo.gl/9kgz5w -->
|
||||
|
||||
<div
|
||||
css-truncate
|
||||
aria-label="{{:: 'Index pattern: ' + vis.indexPattern.title}}"
|
||||
ng-if="vis.type.requiresSearch"
|
||||
ng-if="vis.type.requiresSearch && vis.type.options.showIndexSelection"
|
||||
class="index-pattern"
|
||||
tabindex="0"
|
||||
id="sidebarIndexPatternTitle"
|
||||
|
@ -44,6 +45,7 @@
|
|||
aria-selected="{{sidebar.section === tab.name}}"
|
||||
ng-repeat="tab in vis.type.editorConfig.optionTabs"
|
||||
ng-class="{active: sidebar.section == tab.name}"
|
||||
ng-if="vis.type.editorConfig.optionTabs.length > 1 || sidebar.showData"
|
||||
>
|
||||
<a
|
||||
class="vis-editor-subnav-link"
|
||||
|
@ -75,16 +77,39 @@
|
|||
</div>
|
||||
</li>
|
||||
|
||||
<li
|
||||
tooltip="Auto apply changes"
|
||||
tooltip-placement="bottom"
|
||||
tooltip-popup-delay="400"
|
||||
tooltip-append-to-body="1"
|
||||
ng-if="vis.type.editorConfig.enableAutoApply"
|
||||
>
|
||||
<button
|
||||
data-test-subj="visualizeEditorAutoButton"
|
||||
class="kuiButton kuiButton--basic navbar-btn-link"
|
||||
aria-label="Auto update the visualization on every change"
|
||||
ng-click="toggleAutoApply()"
|
||||
ng-class="{
|
||||
'kuiButton--primary': autoApplyEnabled,
|
||||
'kuiButton--basic': !autoApplyEnabled
|
||||
}"
|
||||
>
|
||||
<span aria-hidden="true" class="kuiIcon fa-repeat"></span>
|
||||
<span ng-show="autoApplyEnabled">Auto Apply</span>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li
|
||||
tooltip="Apply changes"
|
||||
tooltip-placement="bottom"
|
||||
tooltip-popup-delay="400" tooltip-append-to-body="1"
|
||||
ng-hide="autoApplyEnabled"
|
||||
>
|
||||
<button
|
||||
data-test-subj="visualizeEditorRenderButton"
|
||||
class="kuiButton kuiButton--primary navbar-btn-link"
|
||||
type="submit"
|
||||
ng-disabled="!vis.dirty || visualizeEditor.errorCount() > 0"
|
||||
ng-disabled="!vis.dirty || visualizeEditor.errorCount() > 0 || autoApplyEnabled"
|
||||
aria-label="Update the visualization with your changes"
|
||||
>
|
||||
<span aria-hidden="true" class="kuiIcon fa-play"></span>
|
||||
|
@ -96,6 +121,7 @@
|
|||
tooltip-placement="bottom"
|
||||
tooltip-popup-delay="400"
|
||||
tooltip-append-to-body="1"
|
||||
ng-hide="autoApplyEnabled"
|
||||
>
|
||||
<button
|
||||
class="kuiButton kuiButton--basic navbar-btn-link"
|
||||
|
|
45
src/ui/public/vis/editors/default/vis_editor_resizer.js
Normal file
45
src/ui/public/vis/editors/default/vis_editor_resizer.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
import $ from 'jquery';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { keyCodes } from '@elastic/eui';
|
||||
|
||||
uiModules
|
||||
.get('kibana')
|
||||
.directive('visEditorResizer', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function ($scope, $el) {
|
||||
const $left = $el.parent();
|
||||
|
||||
$el.on('mousedown', function (event) {
|
||||
$el.addClass('active');
|
||||
const startWidth = $left.width();
|
||||
const startX = event.pageX;
|
||||
|
||||
function onMove(event) {
|
||||
const newWidth = startWidth + event.pageX - startX;
|
||||
$left.width(newWidth);
|
||||
}
|
||||
|
||||
$(document.body)
|
||||
.on('mousemove', onMove)
|
||||
.one('mouseup', () => {
|
||||
$el.removeClass('active');
|
||||
$(document.body).off('mousemove', onMove);
|
||||
$scope.$broadcast('render');
|
||||
});
|
||||
});
|
||||
|
||||
$el.on('keydown', event => {
|
||||
const { keyCode } = event;
|
||||
|
||||
if (keyCode === keyCodes.LEFT || keyCode === keyCodes.RIGHT) {
|
||||
event.preventDefault();
|
||||
const startWidth = $left.width();
|
||||
const newWidth = startWidth + (keyCode === keyCodes.LEFT ? -15 : 15);
|
||||
$left.width(newWidth);
|
||||
$scope.$broadcast('render');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
|
@ -44,8 +44,8 @@ export default function ({ getService, getPageObjects }) {
|
|||
});
|
||||
});
|
||||
|
||||
it.skip('should show Split Gauges', function () {
|
||||
const expectedTexts = [ 'win 8', 'win xp', 'win 7', 'ios', 'osx' ];
|
||||
it('should show Split Gauges', function () {
|
||||
const expectedTexts = [ 'win 8', 'win xp', 'win 7', 'ios' ];
|
||||
return PageObjects.visualize.clickMetricEditor()
|
||||
.then(function clickBucket() {
|
||||
log.debug('Bucket = Split Group');
|
||||
|
@ -59,6 +59,10 @@ export default function ({ getService, getPageObjects }) {
|
|||
log.debug('Field = machine.os.raw');
|
||||
return PageObjects.visualize.selectField('machine.os.raw');
|
||||
})
|
||||
.then(function setSize() {
|
||||
log.debug('Size = 4');
|
||||
return PageObjects.visualize.setSize('4');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
|
@ -72,8 +76,8 @@ export default function ({ getService, getPageObjects }) {
|
|||
});
|
||||
});
|
||||
|
||||
it.skip('should show correct values for fields with fieldFormatters', async function () {
|
||||
const expectedTexts = [ '2,904\nwin 8: Count', '5.528KB' ];
|
||||
it('should show correct values for fields with fieldFormatters', async function () {
|
||||
const expectedTexts = [ '2,904\nwin 8: Count', '0B\nwin 8: Min bytes' ];
|
||||
|
||||
|
||||
await PageObjects.visualize.clickMetricEditor();
|
||||
|
@ -83,17 +87,18 @@ export default function ({ getService, getPageObjects }) {
|
|||
await PageObjects.visualize.setSize('1');
|
||||
await PageObjects.visualize.clickAddMetric();
|
||||
await PageObjects.visualize.clickBucket('Metric');
|
||||
await PageObjects.visualize.selectAggregation('Average', 'metrics');
|
||||
await PageObjects.visualize.selectAggregation('Min', 'metrics');
|
||||
await PageObjects.visualize.selectField('bytes', 'metrics');
|
||||
await PageObjects.visualize.clickGo();
|
||||
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getGaugeValue()
|
||||
.then(function (metricValue) {
|
||||
.then(async function (metricValue) {
|
||||
expect(expectedTexts).to.eql(metricValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getPageObjects }) {
|
||||
export default function ({ getPageObjects, getService }) {
|
||||
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
|
||||
const find = getService('find');
|
||||
const markdown = `
|
||||
# Heading 1
|
||||
|
||||
|
@ -14,7 +15,6 @@ export default function ({ getPageObjects }) {
|
|||
await PageObjects.visualize.clickMarkdownWidget();
|
||||
await PageObjects.visualize.setMarkdownTxt(markdown);
|
||||
await PageObjects.visualize.clickGo();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
describe('markdown vis', async () => {
|
||||
|
@ -34,6 +34,23 @@ export default function ({ getPageObjects }) {
|
|||
const actual = await PageObjects.visualize.getMarkdownText();
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
it('should auto apply changes if auto mode is turned on', async function () {
|
||||
const markdown2 = '## Heading 2';
|
||||
await PageObjects.visualize.toggleAutoMode();
|
||||
await PageObjects.visualize.setMarkdownTxt(markdown2);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const h1Txt = await PageObjects.visualize.getMarkdownBodyDescendentText('h2');
|
||||
expect(h1Txt).to.equal('Heading 2');
|
||||
});
|
||||
|
||||
it('should resize the editor', async function () {
|
||||
const editorSidebar = await find.byCssSelector('.vis-editor-sidebar');
|
||||
const initialSize = await editorSidebar.getSize();
|
||||
await PageObjects.visualize.sizeUpEditor();
|
||||
const afterSize = await editorSidebar.getSize();
|
||||
expect(afterSize.width).to.be.greaterThan(initialSize.width);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { VisualizeConstants } from '../../../src/core_plugins/kibana/public/visualize/visualize_constants';
|
||||
import Keys from 'leadfoot/keys';
|
||||
|
||||
export function VisualizePageProvider({ getService, getPageObjects }) {
|
||||
const remote = getService('remote');
|
||||
|
@ -389,6 +390,15 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
|
|||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
}
|
||||
|
||||
async toggleAutoMode() {
|
||||
await testSubjects.click('visualizeEditorAutoButton');
|
||||
}
|
||||
|
||||
async sizeUpEditor() {
|
||||
await testSubjects.click('visualizeEditorResizer');
|
||||
await remote.pressKeys(Keys.ARROW_RIGHT);
|
||||
}
|
||||
|
||||
async clickOptions() {
|
||||
await find.clickByPartialLinkText('Options');
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue