diff --git a/src/core_plugins/kbn_vislib_vis_types/public/area.js b/src/core_plugins/kbn_vislib_vis_types/public/area.js index 6e6b47055f7c0..868c3a9d1179f 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/area.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/area.js @@ -1,19 +1,20 @@ +import VisVisTypeProvider from 'ui/vis/vis_type'; import VislibVisTypeVislibVisTypeProvider from 'ui/vislib_vis_type/vislib_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html'; +import image from './images/icon-area.svg'; export default function PointSeriesVisType(Private) { + const VisType = Private(VisVisTypeProvider); const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider); const Schemas = Private(VisSchemasProvider); return new VislibVisType({ name: 'area', - title: 'Area chart', - icon: 'fa-area-chart', - description: 'Great for stacked timelines in which the total of all series is more important ' + - 'than comparing any two or more series. Less useful for assessing the relative change of ' + - 'unrelated data points as changes in a series lower down the stack will have a difficult to gauge ' + - 'effect on the series above it.', + title: 'Area', + image, + description: 'Emphasize the quantity beneath a line chart', + category: VisType.CATEGORY.BASIC, params: { defaults: { grid: { diff --git a/src/core_plugins/kbn_vislib_vis_types/public/heatmap.js b/src/core_plugins/kbn_vislib_vis_types/public/heatmap.js index 53316d79529c2..265d2ed141cc5 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/heatmap.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/heatmap.js @@ -1,18 +1,21 @@ +import VisVisTypeProvider from 'ui/vis/vis_type'; import VislibVisTypeVislibVisTypeProvider from 'ui/vislib_vis_type/vislib_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import heatmapTemplate from 'plugins/kbn_vislib_vis_types/editors/heatmap.html'; import heatmapColors from 'ui/vislib/components/color/colormaps'; +import image from './images/icon-heatmap.svg'; export default function HeatmapVisType(Private) { + const VisType = Private(VisVisTypeProvider); const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider); const Schemas = Private(VisSchemasProvider); return new VislibVisType({ name: 'heatmap', - title: 'Heatmap chart', - icon: 'fa-barcode', - description: 'A heat map is a graphical representation of data' + - ' where the individual values contained in a matrix are represented as colors. ', + title: 'Heat Map', + image, + description: 'Shade cells within a matrix', + category: VisType.CATEGORY.BASIC, params: { defaults: { addTooltip: true, diff --git a/src/core_plugins/kbn_vislib_vis_types/public/histogram.js b/src/core_plugins/kbn_vislib_vis_types/public/histogram.js index 04b87c41593f0..ee4217ed69ec1 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/histogram.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/histogram.js @@ -1,17 +1,20 @@ +import VisVisTypeProvider from 'ui/vis/vis_type'; import VislibVisTypeVislibVisTypeProvider from 'ui/vislib_vis_type/vislib_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html'; +import image from './images/icon-vertical.svg'; export default function PointSeriesVisType(Private) { + const VisType = Private(VisVisTypeProvider); const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider); const Schemas = Private(VisSchemasProvider); return new VislibVisType({ name: 'histogram', - title: 'Vertical bar chart', - icon: 'fa-bar-chart', - description: 'The goto chart for oh-so-many needs. Great for time and non-time data. Stacked or grouped, ' + - 'exact numbers or percentages. If you are not sure which chart you need, you could do worse than to start here.', + title: 'Vertical Bar', + image, + description: 'Assign a continuous variable to each axis', + category: VisType.CATEGORY.BASIC, params: { defaults: { grid: { diff --git a/src/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js b/src/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js index ed5af51626a10..9de565200b945 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js @@ -1,16 +1,20 @@ +import VisVisTypeProvider from 'ui/vis/vis_type'; import VislibVisTypeVislibVisTypeProvider from 'ui/vislib_vis_type/vislib_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html'; +import image from './images/icon-horizontal.svg'; export default function PointSeriesVisType(Private) { + const VisType = Private(VisVisTypeProvider); const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider); const Schemas = Private(VisSchemasProvider); return new VislibVisType({ name: 'horizontal_bar', - title: 'Horizontal bar chart', - icon: 'fa-bars', - description: 'Like histogram chart but with horizontal bars.', + title: 'Horizontal Bar', + image, + description: 'Assign a continuous variable to each axis', + category: VisType.CATEGORY.BASIC, params: { defaults: { grid: { diff --git a/src/core_plugins/kbn_vislib_vis_types/public/images/icon-area.svg b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-area.svg new file mode 100644 index 0000000000000..b7469195dae17 --- /dev/null +++ b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-area.svg @@ -0,0 +1,19 @@ + + + + icon-area + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kbn_vislib_vis_types/public/images/icon-heatmap.svg b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-heatmap.svg new file mode 100644 index 0000000000000..a480d4435f8b6 --- /dev/null +++ b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-heatmap.svg @@ -0,0 +1,27 @@ + + + + Group 2 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kbn_vislib_vis_types/public/images/icon-horizontal.svg b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-horizontal.svg new file mode 100644 index 0000000000000..bc779f9ab0c73 --- /dev/null +++ b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-horizontal.svg @@ -0,0 +1,23 @@ + + + + icon-horizontal + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kbn_vislib_vis_types/public/images/icon-line.svg b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-line.svg new file mode 100644 index 0000000000000..c46e5f56e88c2 --- /dev/null +++ b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-line.svg @@ -0,0 +1,19 @@ + + + + icon-line + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kbn_vislib_vis_types/public/images/icon-pie.svg b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-pie.svg new file mode 100644 index 0000000000000..a2ddb72d7a6bd --- /dev/null +++ b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-pie.svg @@ -0,0 +1,16 @@ + + + + icon-pie + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kbn_vislib_vis_types/public/images/icon-tilemap.svg b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-tilemap.svg new file mode 100644 index 0000000000000..0888ce38f05a2 --- /dev/null +++ b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-tilemap.svg @@ -0,0 +1,16 @@ + + + + icon-tilemap + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kbn_vislib_vis_types/public/images/icon-vertical.svg b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-vertical.svg new file mode 100644 index 0000000000000..78bf5661942f5 --- /dev/null +++ b/src/core_plugins/kbn_vislib_vis_types/public/images/icon-vertical.svg @@ -0,0 +1,19 @@ + + + + icon-vertical + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kbn_vislib_vis_types/public/line.js b/src/core_plugins/kbn_vislib_vis_types/public/line.js index 896e5163ab296..1c3330dced3aa 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/line.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/line.js @@ -1,17 +1,20 @@ +import VisVisTypeProvider from 'ui/vis/vis_type'; import VislibVisTypeVislibVisTypeProvider from 'ui/vislib_vis_type/vislib_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html'; +import image from './images/icon-line.svg'; export default function PointSeriesVisType(Private) { + const VisType = Private(VisVisTypeProvider); const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider); const Schemas = Private(VisSchemasProvider); return new VislibVisType({ name: 'line', - title: 'Line chart', - icon: 'fa-line-chart', - description: 'Often the best chart for high density time series. Great for comparing one series to another. ' + - 'Be careful with sparse sets as the connection between points can be misleading.', + title: 'Line', + image, + description: 'Emphasize trends', + category: VisType.CATEGORY.BASIC, params: { defaults: { grid: { diff --git a/src/core_plugins/kbn_vislib_vis_types/public/pie.js b/src/core_plugins/kbn_vislib_vis_types/public/pie.js index 6ec170695fdc9..c25c3d76cfb3b 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/pie.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/pie.js @@ -1,17 +1,20 @@ +import VisVisTypeProvider from 'ui/vis/vis_type'; import VislibVisTypeVislibVisTypeProvider from 'ui/vislib_vis_type/vislib_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import pieTemplate from 'plugins/kbn_vislib_vis_types/editors/pie.html'; +import image from './images/icon-pie.svg'; export default function HistogramVisType(Private) { + const VisType = Private(VisVisTypeProvider); const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider); const Schemas = Private(VisSchemasProvider); return new VislibVisType({ name: 'pie', - title: 'Pie chart', - icon: 'fa-pie-chart', - description: 'Pie charts are ideal for displaying the parts of some whole. For example, sales percentages by department.' + - 'Pro Tip: Pie charts are best used sparingly, and with no more than 7 slices per pie.', + title: 'Pie', + image, + description: 'Compare parts of a whole', + category: VisType.CATEGORY.BASIC, params: { defaults: { addTooltip: true, diff --git a/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js b/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js index 5859d2d532112..f0b0449b59808 100644 --- a/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js +++ b/src/core_plugins/kbn_vislib_vis_types/public/tile_map.js @@ -1,20 +1,23 @@ import supports from 'ui/utils/supports'; +import VisVisTypeProvider from 'ui/vis/vis_type'; import MapsVisTypeVislibVisTypeProvider from 'ui/vis_maps/maps_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import AggResponseGeoJsonGeoJsonProvider from 'ui/agg_response/geo_json/geo_json'; import tileMapTemplate from 'plugins/kbn_vislib_vis_types/editors/tile_map.html'; +import image from './images/icon-tilemap.svg'; export default function TileMapVisType(Private, getAppState, courier, config) { + const VisType = Private(VisVisTypeProvider); const MapsVisType = Private(MapsVisTypeVislibVisTypeProvider); const Schemas = Private(VisSchemasProvider); const geoJsonConverter = Private(AggResponseGeoJsonGeoJsonProvider); return new MapsVisType({ name: 'tile_map', - title: 'Tile map', - icon: 'fa-map-marker', - description: 'Your source for geographic maps. Requires an elasticsearch geo_point field. More specifically, a field ' + - 'that is mapped as type:geo_point with latitude and longitude coordinates.', + title: 'Tile Map', + image, + description: 'Plot latitude and longitude coordinates on a map', + category: VisType.CATEGORY.MAP, params: { defaults: { mapType: 'Scaled Circle Markers', diff --git a/src/core_plugins/kibana/public/visualize/editor/editor.html b/src/core_plugins/kibana/public/visualize/editor/editor.html index 667551edbfb2c..557550337d911 100644 --- a/src/core_plugins/kibana/public/visualize/editor/editor.html +++ b/src/core_plugins/kibana/public/visualize/editor/editor.html @@ -71,13 +71,15 @@
- +
diff --git a/src/core_plugins/kibana/public/visualize/wizard/step_1.html b/src/core_plugins/kibana/public/visualize/wizard/step_1.html index ebc04c4218792..5a89273afd368 100644 --- a/src/core_plugins/kibana/public/visualize/wizard/step_1.html +++ b/src/core_plugins/kibana/public/visualize/wizard/step_1.html @@ -13,35 +13,71 @@
diff --git a/src/core_plugins/kibana/public/visualize/wizard/wizard.js b/src/core_plugins/kibana/public/visualize/wizard/wizard.js index 55b7e2c5fc7ec..94936799c0426 100644 --- a/src/core_plugins/kibana/public/visualize/wizard/wizard.js +++ b/src/core_plugins/kibana/public/visualize/wizard/wizard.js @@ -2,6 +2,10 @@ import 'plugins/kibana/visualize/saved_visualizations/saved_visualizations'; import 'ui/directives/saved_object_finder'; import 'ui/directives/paginated_selectable_list'; import 'plugins/kibana/discover/saved_searches/saved_searches'; +import './wizard.less'; + +import _ from 'lodash'; +import VisVisTypeProvider from 'ui/vis/vis_type'; import { DashboardConstants } from 'plugins/kibana/dashboard/dashboard_constants'; import { VisualizeConstants } from '../visualize_constants'; import routes from 'ui/routes'; @@ -29,12 +33,109 @@ routes.when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, { module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, timefilter, Private) { timefilter.enabled = false; + const VisType = Private(VisVisTypeProvider); + + const visTypeCategoryToHumanReadableMap = { + [VisType.CATEGORY.BASIC]: 'Basic Charts', + [VisType.CATEGORY.DATA]: 'Data', + [VisType.CATEGORY.GRAPHIC]: 'Graphic', + [VisType.CATEGORY.MAP]: 'Maps', + [VisType.CATEGORY.OTHER]: 'Other', + [VisType.CATEGORY.TIME]: 'Time Series', + }; + const addToDashMode = $route.current.params[DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM]; kbnUrl.removeParam(DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM); - $scope.visTypes = Private(RegistryVisTypesProvider); + const visTypes = Private(RegistryVisTypesProvider); + + const categoryToVisTypesMap = {}; + + visTypes.forEach(visType => { + const categoryName = visType.category; + + // Create category object if it doesn't exist yet. + if (!categoryToVisTypesMap[categoryName]) { + categoryToVisTypesMap[categoryName] = { + label: visTypeCategoryToHumanReadableMap[categoryName], + list: [], + }; + } + + const categoryVisTypes = categoryToVisTypesMap[categoryName]; + + // Add the visType to the list and sort them by their title. + // categoryVisTypes.list.push(visType); + categoryVisTypes.list = _.sortBy( + categoryVisTypes.list.concat(visType), + type => type.title + ); + }); + + // Sort the categories alphabetically. + const sortedVisTypeCategories = Object.values(categoryToVisTypesMap).sort((a, b) => { + const other = VisType.CATEGORY.OTHER.toLowerCase(); + + // Put "other" category at the end of the list. + const labelA = a.label.toLowerCase(); + if (labelA === other) return 1; + + const labelB = b.label.toLowerCase(); + if (labelB === other) return -1; + + if (labelA < labelB) return -1; + if (labelA > labelB) return 1; + return 0; + }); + + $scope.searchTerm = ''; + + $scope.filteredVisTypeCategories = []; + + $scope.$watch('searchTerm', () => { + function getVisTypeCategories() { + const normalizedSearchTerm = $scope.searchTerm.toLowerCase().trim(); + + const filteredVisTypeCategories = sortedVisTypeCategories.map(category => { + // Include entire category if the category matches the search term. + if (category.label.toLowerCase().includes(normalizedSearchTerm)) { + return category; + } + + // Otherwise, return just the vis types in the category which match. + const filteredVisTypes = category.list.filter(visType => { + return visType.title.toLowerCase().includes(normalizedSearchTerm); + }); + + return { + label: category.label, + list: filteredVisTypes, + }; + }); + + return filteredVisTypeCategories.filter(category => category.list.length); + } + + $scope.filteredVisTypeCategories = getVisTypeCategories(); + }); + + $scope.getVisTypeTooltip = type => { + const prefix = type.isExperimental ? '(Experimental)' : ''; + return `${prefix} ${type.description}`; + }; + + $scope.getVisTypeTooltipPosition = index => { + // Tooltips should appear on the bottom by default, unless they're on the last row. This is a + // cheap workaround to automatically positioning the tooltip so that it won't disappear off + // the edge of the screen. + if (index === $scope.filteredVisTypeCategories.length - 1) { + return 'top'; + } + + return 'bottom'; + }; - $scope.visTypeUrl = function (visType) { + $scope.getVisTypeUrl = function (visType) { const baseUrl = visType.requiresSearch ? `#${VisualizeConstants.WIZARD_STEP_2_PAGE_PATH}?` diff --git a/src/core_plugins/kibana/public/visualize/wizard/wizard.less b/src/core_plugins/kibana/public/visualize/wizard/wizard.less new file mode 100644 index 0000000000000..82e99646898bf --- /dev/null +++ b/src/core_plugins/kibana/public/visualize/wizard/wizard.less @@ -0,0 +1,10 @@ +/** + * This preserves backwards-compatibility with any plugins that are still specifying an `icon` + * class. + * + * 1. Size icon correctly. + */ +.visualizeWizardVisTypeIcon { + color: #000000; + font-size: 50px; /* 1 */ +} diff --git a/src/core_plugins/markdown_vis/public/images/icon-markdown.svg b/src/core_plugins/markdown_vis/public/images/icon-markdown.svg new file mode 100644 index 0000000000000..3678082403ed4 --- /dev/null +++ b/src/core_plugins/markdown_vis/public/images/icon-markdown.svg @@ -0,0 +1,19 @@ + + + + icon-markdown + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/markdown_vis/public/markdown_vis.js b/src/core_plugins/markdown_vis/public/markdown_vis.js index f79a205aac503..ea137cefa3160 100644 --- a/src/core_plugins/markdown_vis/public/markdown_vis.js +++ b/src/core_plugins/markdown_vis/public/markdown_vis.js @@ -1,9 +1,11 @@ import 'plugins/markdown_vis/markdown_vis.less'; import 'plugins/markdown_vis/markdown_vis_controller'; +import VisVisTypeProvider from 'ui/vis/vis_type'; import TemplateVisTypeTemplateVisTypeProvider from 'ui/template_vis_type/template_vis_type'; import markdownVisTemplate from 'plugins/markdown_vis/markdown_vis.html'; import markdownVisParamsTemplate from 'plugins/markdown_vis/markdown_vis_params.html'; import visTypesRegistry from 'ui/registry/vis_types'; +import image from './images/icon-markdown.svg'; // we need to load the css ourselves // we also need to load the controller and used by the template @@ -12,15 +14,17 @@ import visTypesRegistry from 'ui/registry/vis_types'; visTypesRegistry.register(MarkdownVisProvider); function MarkdownVisProvider(Private) { + const VisType = Private(VisVisTypeProvider); const TemplateVisType = Private(TemplateVisTypeTemplateVisTypeProvider); // return the visType object, which kibana will use to display and configure new // Vis object of this type. return new TemplateVisType({ name: 'markdown', - title: 'Markdown widget', - icon: 'fa-code', - description: 'Useful for displaying explanations or instructions for dashboards.', + title: 'Markdown', + image, + description: 'Create a document using markdown syntax', + category: VisType.CATEGORY.OTHER, template: markdownVisTemplate, params: { editor: markdownVisParamsTemplate diff --git a/src/core_plugins/metric_vis/public/images/icon-number.svg b/src/core_plugins/metric_vis/public/images/icon-number.svg new file mode 100644 index 0000000000000..2d503bc2fe07a --- /dev/null +++ b/src/core_plugins/metric_vis/public/images/icon-number.svg @@ -0,0 +1,16 @@ + + + + icon-number + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/metric_vis/public/metric_vis.js b/src/core_plugins/metric_vis/public/metric_vis.js index 7b71836dfbb53..c6d67478c9aa0 100644 --- a/src/core_plugins/metric_vis/public/metric_vis.js +++ b/src/core_plugins/metric_vis/public/metric_vis.js @@ -1,10 +1,12 @@ import 'plugins/metric_vis/metric_vis.less'; import 'plugins/metric_vis/metric_vis_controller'; +import VisVisTypeProvider from 'ui/vis/vis_type'; import TemplateVisTypeTemplateVisTypeProvider from 'ui/template_vis_type/template_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import metricVisTemplate from 'plugins/metric_vis/metric_vis.html'; import metricVisParamsTemplate from 'plugins/metric_vis/metric_vis_params.html'; import visTypesRegistry from 'ui/registry/vis_types'; +import image from './images/icon-number.svg'; // we need to load the css ourselves // we also need to load the controller and used by the template @@ -13,6 +15,7 @@ import visTypesRegistry from 'ui/registry/vis_types'; visTypesRegistry.register(MetricVisProvider); function MetricVisProvider(Private) { + const VisType = Private(VisVisTypeProvider); const TemplateVisType = Private(TemplateVisTypeTemplateVisTypeProvider); const Schemas = Private(VisSchemasProvider); @@ -21,9 +24,9 @@ function MetricVisProvider(Private) { return new TemplateVisType({ name: 'metric', title: 'Metric', - description: 'One big number for all of your one big number needs. Perfect for showing ' + - 'a count of hits, or the exact average of a numeric field.', - icon: 'fa-calculator', + image, + description: 'Display a calculation as a single number', + category: VisType.CATEGORY.DATA, template: metricVisTemplate, params: { defaults: { diff --git a/src/core_plugins/metrics/public/images/icon-visualbuilder.svg b/src/core_plugins/metrics/public/images/icon-visualbuilder.svg new file mode 100644 index 0000000000000..5c1f0f5d1eb8c --- /dev/null +++ b/src/core_plugins/metrics/public/images/icon-visualbuilder.svg @@ -0,0 +1,23 @@ + + + + Group 2 + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/metrics/public/kbn_vis_types/index.js b/src/core_plugins/metrics/public/kbn_vis_types/index.js index cf2f478ea6a2e..36fdfdd2bff04 100644 --- a/src/core_plugins/metrics/public/kbn_vis_types/index.js +++ b/src/core_plugins/metrics/public/kbn_vis_types/index.js @@ -3,23 +3,26 @@ import './editor_controller'; import '../visualizations/less/main.less'; import 'react-select/dist/react-select.css'; import '../less/main.less'; +import image from '../images/icon-visualbuilder.svg'; - // register the provider with the visTypes registry so that other know it exists +import VisVisTypeProvider from 'ui/vis/vis_type'; +// register the provider with the visTypes registry so that other know it exists import visTypes from 'ui/registry/vis_types'; visTypes.register(MetricsVisProvider); export default function MetricsVisProvider(Private) { + const VisType = Private(VisVisTypeProvider); const TemplateVisType = Private(require('ui/template_vis_type')); // return the visType object, which kibana will use to display and configure new // Vis object of this type. return new TemplateVisType({ name: 'metrics', - title: 'Time Series Visual Builder', - icon: 'fa-area-chart', - description: `Experimental Feature: Create a time series based visualization for metrics. Perfect - for creating visualizations for time series based metrics using the - powerful pipeline aggs Elasticsearch feature`, + title: 'Visual Builder', + image, + description: 'Build time-series using a visual pipeline interface', + category: VisType.CATEGORY.TIME, + isExperimental: true, template: require('./vis.html'), fullEditor: true, params: { diff --git a/src/core_plugins/table_vis/public/images/icon-table.svg b/src/core_plugins/table_vis/public/images/icon-table.svg new file mode 100644 index 0000000000000..bc903cb561f50 --- /dev/null +++ b/src/core_plugins/table_vis/public/images/icon-table.svg @@ -0,0 +1,16 @@ + + + + icon-table + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/table_vis/public/table_vis.js b/src/core_plugins/table_vis/public/table_vis.js index cde17e9458e9d..ec8d504ace5e5 100644 --- a/src/core_plugins/table_vis/public/table_vis.js +++ b/src/core_plugins/table_vis/public/table_vis.js @@ -3,10 +3,12 @@ import 'plugins/table_vis/table_vis_controller'; import 'plugins/table_vis/table_vis_params'; import 'ui/agg_table'; import 'ui/agg_table/agg_table_group'; +import VisVisTypeProvider from 'ui/vis/vis_type'; import TemplateVisTypeTemplateVisTypeProvider from 'ui/template_vis_type/template_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import tableVisTemplate from 'plugins/table_vis/table_vis.html'; import visTypesRegistry from 'ui/registry/vis_types'; +import image from './images/icon-table.svg'; // we need to load the css ourselves // we also need to load the controller and used by the template @@ -20,6 +22,7 @@ visTypesRegistry.register(TableVisTypeProvider); // define the TableVisType function TableVisTypeProvider(Private) { + const VisType = Private(VisVisTypeProvider); const TemplateVisType = Private(TemplateVisTypeTemplateVisTypeProvider); const Schemas = Private(VisSchemasProvider); @@ -30,10 +33,10 @@ function TableVisTypeProvider(Private) { // Vis object of this type. return new TemplateVisType({ name: 'table', - title: 'Data table', - icon: 'fa-table', - description: 'The data table provides a detailed breakdown, in tabular format, of the results of a composed ' + - 'aggregation. Tip, a data table is available from many other charts by clicking the grey bar at the bottom of the chart.', + title: 'Data Table', + image, + description: 'Display values in a table', + category: VisType.CATEGORY.DATA, template: tableVisTemplate, params: { defaults: { diff --git a/src/core_plugins/tagcloud/public/images/icon-tagcloud.svg b/src/core_plugins/tagcloud/public/images/icon-tagcloud.svg new file mode 100644 index 0000000000000..4b8a7f90495b2 --- /dev/null +++ b/src/core_plugins/tagcloud/public/images/icon-tagcloud.svg @@ -0,0 +1,21 @@ + + + + icon-tagcloud + Created with Sketch. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/tagcloud/public/tag_cloud_vis.js b/src/core_plugins/tagcloud/public/tag_cloud_vis.js index a36ea8645654e..dd960a83cb099 100644 --- a/src/core_plugins/tagcloud/public/tag_cloud_vis.js +++ b/src/core_plugins/tagcloud/public/tag_cloud_vis.js @@ -1,23 +1,25 @@ import 'plugins/tagcloud/tag_cloud.less'; import 'plugins/tagcloud/tag_cloud_controller'; import 'plugins/tagcloud/tag_cloud_vis_params'; +import VisVisTypeProvider from 'ui/vis/vis_type'; import TemplateVisTypeTemplateVisTypeProvider from 'ui/template_vis_type/template_vis_type'; import VisSchemasProvider from 'ui/vis/schemas'; import tagCloudTemplate from 'plugins/tagcloud/tag_cloud_controller.html'; import visTypes from 'ui/registry/vis_types'; +import image from './images/icon-tagcloud.svg'; visTypes.register(function TagCloudProvider(Private) { + const VisType = Private(VisVisTypeProvider); const TemplateVisType = Private(TemplateVisTypeTemplateVisTypeProvider); const Schemas = Private(VisSchemasProvider); return new TemplateVisType({ name: 'tagcloud', - title: 'Tag cloud', + title: 'Tag Cloud', + image, implementsRenderComplete: true, - description: 'A tag cloud visualization is a visual representation of text data, ' + - 'typically used to visualize individual words. The font size of a word corresponds ' + - 'with its importance.', - icon: 'fa-cloud', + description: 'A group of words, sized according to their importance', + category: VisType.CATEGORY.OTHER, template: tagCloudTemplate, params: { defaults: { diff --git a/src/core_plugins/timelion/public/images/icon-timelion.svg b/src/core_plugins/timelion/public/images/icon-timelion.svg new file mode 100644 index 0000000000000..3d67b6924de02 --- /dev/null +++ b/src/core_plugins/timelion/public/images/icon-timelion.svg @@ -0,0 +1,16 @@ + + + + Timelion + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/timelion/public/vis/index.js b/src/core_plugins/timelion/public/vis/index.js index 3ea9b78377e47..f47fc6458cba7 100644 --- a/src/core_plugins/timelion/public/vis/index.js +++ b/src/core_plugins/timelion/public/vis/index.js @@ -1,3 +1,6 @@ +import VisVisTypeProvider from 'ui/vis/vis_type'; +import image from '../images/icon-timelion.svg'; + define(function (require) { // we also need to load the controller and used by the template require('plugins/timelion/vis/timelion_vis_controller'); @@ -10,6 +13,7 @@ define(function (require) { require('ui/registry/vis_types').register(TimelionVisProvider); function TimelionVisProvider(Private) { + const VisType = Private(VisVisTypeProvider); const TemplateVisType = Private(require('ui/template_vis_type')); // return the visType object, which kibana will use to display and configure new @@ -17,9 +21,9 @@ define(function (require) { return new TemplateVisType({ name: 'timelion', title: 'Timelion', - icon: 'fa-clock-o', - description: 'Create timeseries charts using the timelion expression language. ' + - 'Perfect for computing and combining timeseries sets with functions such as derivatives and moving averages', + image, + description: 'Build time-series using functional expressions', + category: VisType.CATEGORY.TIME, template: require('plugins/timelion/vis/timelion_vis.html'), params: { editor: require('plugins/timelion/vis/timelion_vis_params.html') diff --git a/src/ui/public/vis/vis_type.js b/src/ui/public/vis/vis_type.js index b127430101e7f..ef8420f95917c 100644 --- a/src/ui/public/vis/vis_type.js +++ b/src/ui/public/vis/vis_type.js @@ -3,30 +3,43 @@ import VisSchemasProvider from './schemas'; export default function VisTypeFactory(Private) { const VisTypeSchemas = Private(VisSchemasProvider); - function VisType(opts) { - opts = opts || {}; + class VisType { + constructor(opts) { + opts = opts || {}; - this.name = opts.name; - this.title = opts.title; - this.responseConverter = opts.responseConverter; - this.hierarchicalData = opts.hierarchicalData || false; - this.icon = opts.icon; - this.description = opts.description; - this.schemas = opts.schemas || new VisTypeSchemas(); - this.params = opts.params || {}; - this.requiresSearch = opts.requiresSearch == null ? true : opts.requiresSearch; // Default to true unless otherwise specified - this.fullEditor = opts.fullEditor == null ? false : opts.fullEditor; - this.implementsRenderComplete = opts.implementsRenderComplete || false; + this.name = opts.name; + this.title = opts.title; + this.responseConverter = opts.responseConverter; + this.hierarchicalData = opts.hierarchicalData || false; + this.icon = opts.icon; + this.image = opts.image; + this.description = opts.description; + this.category = opts.category || VisType.CATEGORY.OTHER; + this.isExperimental = opts.isExperimental; + this.schemas = opts.schemas || new VisTypeSchemas(); + this.params = opts.params || {}; + this.requiresSearch = opts.requiresSearch == null ? true : opts.requiresSearch; // Default to true unless otherwise specified + this.fullEditor = opts.fullEditor == null ? false : opts.fullEditor; + this.implementsRenderComplete = opts.implementsRenderComplete || false; - if (!this.params.optionTabs) { - this.params.optionTabs = [ - { name: 'options', title: 'Options', editor: this.params.editor } - ]; + if (!this.params.optionTabs) { + this.params.optionTabs = [ + { name: 'options', title: 'Options', editor: this.params.editor } + ]; + } + } + + createRenderbot() { + throw new Error('not implemented'); } } - VisType.prototype.createRenderbot = function () { - throw new Error('not implemented'); + VisType.CATEGORY = { + BASIC: 'basic', + DATA: 'data', + MAP: 'map', + OTHER: 'other', + TIME: 'time', }; return VisType; diff --git a/test/functional/apps/visualize/_chart_types.js b/test/functional/apps/visualize/_chart_types.js index 170364ad3ff9c..273e5552dbc4a 100644 --- a/test/functional/apps/visualize/_chart_types.js +++ b/test/functional/apps/visualize/_chart_types.js @@ -16,9 +16,21 @@ bdd.describe('visualize app', function describeIndexTests() { bdd.describe('chart types', function indexPatternCreation() { bdd.it('should show the correct chart types', function () { const expectedChartTypes = [ - 'Area chart', 'Data table', 'Heatmap chart', 'Horizontal bar chart', 'Line chart', 'Markdown widget', - 'Metric', 'Pie chart', 'Tag cloud', 'Tile map', 'Time Series Visual Builder', 'Timelion', 'Vertical bar chart' + 'Area', + 'Heat Map', + 'Horizontal Bar', + 'Line', + 'Pie', + 'Vertical Bar', + 'Data Table', + 'Metric', + 'Tile Map', + 'Timelion', + 'Visual Builder', + 'Markdown', + 'Tag Cloud', ]; + // find all the chart types and make sure there all there return PageObjects.visualize.getChartTypes() .then(function testChartTypes(chartTypes) { diff --git a/test/support/page_objects/visualize_page.js b/test/support/page_objects/visualize_page.js index b0cef9e768ad0..9f9ce67bfdc1c 100644 --- a/test/support/page_objects/visualize_page.js +++ b/test/support/page_objects/visualize_page.js @@ -16,28 +16,28 @@ export default class VisualizePage { clickAreaChart() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Area chart') + .findByPartialLinkText('Area') .click(); } clickDataTable() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Data table') + .findByPartialLinkText('Data Table') .click(); } clickLineChart() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Line chart') + .findByPartialLinkText('Line') .click(); } clickMarkdownWidget() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Markdown widget') + .findByPartialLinkText('Markdown') .click(); } @@ -58,28 +58,28 @@ export default class VisualizePage { clickPieChart() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Pie chart') + .findByPartialLinkText('Pie') .click(); } clickTileMap() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Tile map') + .findByPartialLinkText('Tile Map') .click(); } clickVerticalBarChart() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Vertical bar chart') + .findByPartialLinkText('Vertical Bar') .click(); } clickHeatmapChart() { return this.remote .setFindTimeout(defaultFindTimeout) - .findByPartialLinkText('Heatmap chart') + .findByPartialLinkText('Heat Map') .click(); } diff --git a/ui_framework/components/gallery/_gallery.scss b/ui_framework/components/gallery/_gallery.scss new file mode 100644 index 0000000000000..d1bedfe06f396 --- /dev/null +++ b/ui_framework/components/gallery/_gallery.scss @@ -0,0 +1,4 @@ +.kuiGallery { + display: flex; + flex-wrap: wrap; +} diff --git a/ui_framework/components/gallery/_gallery_button.scss b/ui_framework/components/gallery/_gallery_button.scss new file mode 100644 index 0000000000000..5dc7fd90ff6af --- /dev/null +++ b/ui_framework/components/gallery/_gallery_button.scss @@ -0,0 +1,54 @@ +$galleryButtonSize: 140px; +$galleryButtonRhythm: 20px; +$galleryButtonIconSize: 50px; + +.kuiGalleryButton { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: $galleryButtonSize; + height: $galleryButtonSize; + margin: 0 $galleryButtonRhythm $galleryButtonRhythm 0; + padding: 25px 10px 10px; + line-height: $lineHeight; + background-color: #F6F6F6; + border: 1px solid #CED5DA; + border-radius: $buttonBorderRadius; + text-decoration: none; + + &:hover { + background-color: #FFFFFF; + border-color: #00A6FF; + } +} + + .kuiGalleryButton__image { + display: flex; + align-items: center; + justify-content: center; + width: $galleryButtonIconSize; + height: $galleryButtonIconSize; + margin-bottom: 20px; + } + + /** + * 1. Truncate overflowing text. + */ + .kuiGalleryButton__label { + font-size: $fontSize; + color: $fontColor; + text-align: center; + max-width: 100%; /* 1 */ + white-space: nowrap; /* 1 */ + overflow: hidden; /* 1 */ + text-overflow: ellipsis; /* 1 */ + } + + .kuiGalleryButton__icon { + position: absolute; + top: 5px; + right: 5px; + color: $subduedFontColor; + } diff --git a/ui_framework/components/gallery/_index.scss b/ui_framework/components/gallery/_index.scss new file mode 100644 index 0000000000000..fa363e3a7a7f0 --- /dev/null +++ b/ui_framework/components/gallery/_index.scss @@ -0,0 +1,2 @@ +@import "gallery"; +@import "gallery_button"; diff --git a/ui_framework/components/index.scss b/ui_framework/components/index.scss index 8a167d42bf6d0..899f1b714d4e2 100644 --- a/ui_framework/components/index.scss +++ b/ui_framework/components/index.scss @@ -249,6 +249,7 @@ body { @import "event/index"; @import "form/index"; @import "form_layout/index"; +@import "gallery/index"; @import "header_bar/index"; @import "icon/index"; @import "info_panel/index"; diff --git a/ui_framework/dist/ui_framework.css b/ui_framework/dist/ui_framework.css index 0fc10e6382915..f2ecd3e48b270 100644 --- a/ui_framework/dist/ui_framework.css +++ b/ui_framework/dist/ui_framework.css @@ -820,6 +820,86 @@ body { .kuiFieldGroupSection--wide > * { width: 100%; } +.kuiGallery { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; } + +.kuiGalleryButton { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + position: relative; + width: 140px; + height: 140px; + margin: 0 20px 20px 0; + padding: 25px 10px 10px; + line-height: 1.5; + background-color: #F6F6F6; + border: 1px solid #CED5DA; + border-radius: 4px; + text-decoration: none; } + .kuiGalleryButton:hover { + background-color: #FFFFFF; + border-color: #00A6FF; } + +.kuiGalleryButton__image { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + width: 50px; + height: 50px; + margin-bottom: 20px; } + +/** + * 1. Truncate overflowing text. + */ +.kuiGalleryButton__label { + font-size: 14px; + color: #191E23; + text-align: center; + max-width: 100%; + /* 1 */ + white-space: nowrap; + /* 1 */ + overflow: hidden; + /* 1 */ + text-overflow: ellipsis; + /* 1 */ } + +.kuiGalleryButton__icon { + position: absolute; + top: 5px; + right: 5px; + color: #9fa3a7; } + .kuiHeaderBar { display: -webkit-box; display: -webkit-flex; diff --git a/ui_framework/doc_site/src/services/routes/routes.js b/ui_framework/doc_site/src/services/routes/routes.js index 919e118162878..db059c1fef9b0 100644 --- a/ui_framework/doc_site/src/services/routes/routes.js +++ b/ui_framework/doc_site/src/services/routes/routes.js @@ -30,6 +30,9 @@ import FormExample import FormLayoutExample from '../../views/form_layout/form_layout_example'; +import GalleryExample + from '../../views/gallery/gallery_example'; + import HeaderBarExample from '../../views/header_bar/header_bar_example'; @@ -118,6 +121,9 @@ const components = [{ }, { name: 'FormLayout', component: FormLayoutExample, +}, { + name: 'Gallery', + component: GalleryExample, }, { name: 'HeaderBar', component: HeaderBarExample, diff --git a/ui_framework/doc_site/src/views/gallery/gallery.html b/ui_framework/doc_site/src/views/gallery/gallery.html new file mode 100644 index 0000000000000..05aea95026e5b --- /dev/null +++ b/ui_framework/doc_site/src/views/gallery/gallery.html @@ -0,0 +1,81 @@ +
+
+ Some items +
+ + +
+ +
+
+ Some more items +
+ + +
diff --git a/ui_framework/doc_site/src/views/gallery/gallery_example.js b/ui_framework/doc_site/src/views/gallery/gallery_example.js new file mode 100644 index 0000000000000..43cd7f110eb05 --- /dev/null +++ b/ui_framework/doc_site/src/views/gallery/gallery_example.js @@ -0,0 +1,26 @@ +import React from 'react'; + +import { + GuideDemo, + GuidePage, + GuideSection, + GuideSectionTypes, +} from '../../components'; + +const galleryHtml = require('./gallery.html'); + +export default props => ( + + + + + +);