From f8d8e5af5c6de19fb43d14759271feb896c52c08 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 8 Oct 2019 11:23:12 +0200 Subject: [PATCH 01/51] Split angular templates into React components --- .../kibana/public/discover/_discover.scss | 5 - .../field_chooser/discover_field.html | 26 ---- .../field_chooser/discover_field.js | 138 ------------------ .../field_chooser/discover_field.tsx | 98 +++++++++++++ .../field_chooser/discover_field_bucket.tsx | 90 ++++++++++++ .../field_chooser/discover_field_details.tsx | 119 +++++++++++++++ .../field_chooser/discover_field_directive.ts | 32 ++++ .../components/field_chooser/field_chooser.js | 10 +- .../lib/detail_views/string.html | 106 -------------- .../lib/get_bucket_aria_label.ts | 32 ++++ .../field_chooser/lib/get_warnings.ts | 43 ++++++ .../field_chooser/lib/text_truncate.tsx | 45 ++++++ ...rogress_bar.js => string_progress_bar.tsx} | 37 ++--- 13 files changed, 475 insertions(+), 306 deletions(-) delete mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.html delete mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.js create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.tsx create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_bucket.tsx create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_details.tsx create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_directive.ts delete mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/lib/detail_views/string.html create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/lib/get_bucket_aria_label.ts create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/lib/get_warnings.ts create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/field_chooser/lib/text_truncate.tsx rename src/legacy/core_plugins/kibana/public/discover/components/field_chooser/{string_progress_bar.js => string_progress_bar.tsx} (68%) diff --git a/src/legacy/core_plugins/kibana/public/discover/_discover.scss b/src/legacy/core_plugins/kibana/public/discover/_discover.scss index 12cac1c89275b..06b3177ab58fc 100644 --- a/src/legacy/core_plugins/kibana/public/discover/_discover.scss +++ b/src/legacy/core_plugins/kibana/public/discover/_discover.scss @@ -115,13 +115,8 @@ discover-app { * 1. Override sidebar-item-title styles. */ .dscSidebarItem { - position: relative; - display: flex; - align-items: center; - justify-content: space-between; padding-top: 0 !important; /* 1 */ padding-bottom: 0 !important; /* 1 */ - height: $euiSizeXL; &:hover, &:focus { diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.html b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.html deleted file mode 100644 index 06e7cc5075411..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.html +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.js b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.js deleted file mode 100644 index f7469d0142d57..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.js +++ /dev/null @@ -1,138 +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 $ from 'jquery'; -import { i18n } from '@kbn/i18n'; -import html from './discover_field.html'; -import _ from 'lodash'; -import 'ui/directives/css_truncate'; -import 'ui/directives/field_name'; -import './string_progress_bar'; -import detailsHtml from './lib/detail_views/string.html'; -import { capabilities } from 'ui/capabilities'; -import { uiModules } from 'ui/modules'; -const app = uiModules.get('apps/discover'); - -app.directive('discoverField', function ($compile) { - return { - restrict: 'E', - template: html, - replace: true, - scope: { - field: '=', - onAddField: '=', - onAddFilter: '=', - onRemoveField: '=', - onShowDetails: '=', - }, - link: function ($scope, $elem) { - let detailsElem; - let detailScope; - - const init = function () { - if ($scope.field.details) { - $scope.toggleDetails($scope.field, true); - } - - $scope.addRemoveButtonLabel = $scope.field.display - ? i18n.translate('kbn.discover.fieldChooser.discoverField.removeButtonLabel', { - defaultMessage: 'remove', - }) - : i18n.translate('kbn.discover.fieldChooser.discoverField.addButtonLabel', { - defaultMessage: 'add', - }); - }; - - const getWarnings = function (field) { - let warnings = []; - - if (field.scripted) { - warnings.push(i18n.translate('kbn.discover.fieldChooser.discoverField.scriptedFieldsTakeLongExecuteDescription', { - defaultMessage: 'Scripted fields can take a long time to execute.', - })); - } - - if (warnings.length > 1) { - warnings = warnings.map(function (warning, i) { - return (i > 0 ? '\n' : '') + (i + 1) + ' - ' + warning; - }); - } - - return warnings; - - }; - - $scope.canVisualize = capabilities.get().visualize.show; - - $scope.toggleDisplay = function (field) { - if (field.display) { - $scope.onRemoveField(field.name); - } else { - $scope.onAddField(field.name); - } - - if (field.details) { - $scope.toggleDetails(field); - } - }; - - $scope.onClickToggleDetails = function onClickToggleDetails($event, field) { - // Do nothing if the event originated from a child. - if ($event.currentTarget !== $event.target) { - $event.preventDefault(); - } - - $scope.toggleDetails(field); - }; - - $scope.toggleDetails = function (field, recompute) { - if (_.isUndefined(field.details) || recompute) { - $scope.onShowDetails(field, recompute); - detailScope = $scope.$new(); - detailScope.warnings = getWarnings(field); - detailScope.getBucketAriaLabel = (bucket) => { - return i18n.translate('kbn.discover.fieldChooser.discoverField.bucketAriaLabel', { - defaultMessage: 'Value: {value}', - values: { - value: bucket.display === '' - ? i18n.translate('kbn.discover.fieldChooser.discoverField.emptyStringText', { - defaultMessage: 'Empty string', - }) - : bucket.display, - }, - }); - }; - - detailsElem = $(detailsHtml); - $compile(detailsElem)(detailScope); - $elem.append(detailsElem).addClass('active'); - $elem.find('.dscSidebarItem').addClass('dscSidebarItem--active'); - } else { - delete field.details; - detailScope.$destroy(); - detailsElem.remove(); - $elem.removeClass('active'); - $elem.find('.dscSidebarItem').removeClass('dscSidebarItem--active'); - } - }; - - init(); - } - }; -}); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.tsx new file mode 100644 index 0000000000000..c9efac42aecaa --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field.tsx @@ -0,0 +1,98 @@ +/* + * 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, { useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FieldNameIcon } from 'ui/directives/field_name/field_name_icon'; +import { DiscoverFieldDetails, Field } from './discover_field_details'; + +export interface Props { + field: Field; + onAddField: any; + onAddFilter: any; + onRemoveField: any; +} +export function DiscoverField({ field, onAddField, onRemoveField, onAddFilter }: Props) { + const [showDetails, setShowDetails] = useState(false); + + const toggleDisplay = (f: Field) => { + if (f.display) { + onRemoveField(f.name); + } else { + onAddField(f.name); + } + }; + + return ( + <> +
+ + +
+ setShowDetails(!showDetails)} + flush="left" + style={{ textAlign: 'left' }} + > + + {field.name} + +
+
+ + + {field.name !== '_source' && !field.display && ( + toggleDisplay(field)} + data-test-subj={`fieldToggle-${field.name}`} + aria-label={i18n.translate( + 'kbn.discover.fieldChooser.discoverField.addButtonLabel', + { + defaultMessage: 'add', + } + )} + /> + )} + {field.name !== '_source' && field.display && ( + toggleDisplay(field)} + data-test-subj={`fieldToggle-${field.name}`} + aria-label={i18n.translate( + 'kbn.discover.fieldChooser.discoverField.removeButtonLabel', + { + defaultMessage: 'remove', + } + )} + /> + )} + +
+
+ {showDetails && field.details && ( + + )} + + ); +} diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_bucket.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_bucket.tsx new file mode 100644 index 0000000000000..ca8b77f05de94 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_bucket.tsx @@ -0,0 +1,90 @@ +/* + * 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 { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { StringFieldProgressBar } from './string_progress_bar'; +import { TextTruncate } from './lib/text_truncate'; +import { getBucketAriaLabel } from './lib/get_bucket_aria_label'; +import { Field } from './discover_field_details'; + +interface Bucket { + display: string; + value: any; + percent: any; + count: any; +} + +interface Props { + bucket: Bucket; + field: Field; + onAddFilter: any; +} + +export function DiscoverFieldBucket({ field, bucket, onAddFilter }: Props) { + const emptyTxt = i18n.translate('kbn.discover.fieldChooser.detailViews.emptyStringText', { + defaultMessage: 'Empty string', + }); + return ( + <> + + +
+ + {bucket.display === '' ? emptyTxt : bucket.display} + +
+
+ {field.filterable && ( + +
+ onAddFilter(field, bucket.value, '+')} + aria-label="{{::'kbn.discover.fieldChooser.detailViews.filterValueButtonAriaLabel' | i18n: {defaultMessage: 'Filter for this value'} }}" + data-test-subj={`plus-${field.name}-${bucket.display}`} + style={{ + minHeight: 'auto', + minWidth: 'auto', + paddingTop: 0, + paddingBottom: 0, + }} + /> + onAddFilter(field, bucket.value, '-')} + aria-label="{{::'kbn.discover.fieldChooser.detailViews.filterOutValueButtonAriaLabel' | i18n: {defaultMessage: 'Filter out this value'} }}" + data-test-subj={`minus-${field.name}-${bucket.display}`} + style={{ + minHeight: 'auto', + minWidth: 'auto', + paddingTop: 0, + paddingBottom: 0, + }} + /> +
+
+ )} +
+ + + ); +} diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_details.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_details.tsx new file mode 100644 index 0000000000000..94565c594201d --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_details.tsx @@ -0,0 +1,119 @@ +/* + * 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 { EuiLink, EuiToolTip } from '@elastic/eui'; +import { capabilities } from 'ui/capabilities'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { DiscoverFieldBucket } from './discover_field_bucket'; +import { getWarnings } from './lib/get_warnings'; + +export interface Field { + details: { + error: string; + exists: number; + total: boolean; + buckets: any; + visualizeUrl: string; + }; + indexPattern: { + metaFields: string[]; + }; + scripted: boolean; + name: string; + filterable: boolean; + visualizable: boolean; + type: string; + /** + * determins if a field is selected and displayed in the doc table + */ + display: boolean; +} + +interface Props { + field: Field; + onAddFilter: (field: Field | string, value: string, type: '+' | '-') => void; +} + +export function DiscoverFieldDetails({ field, onAddFilter }: Props) { + const warnings = getWarnings(field); + + return ( +
+ {!field.details.error && ( +

+ {' '} + {field.indexPattern.metaFields.includes(field.name) && !field.scripted && ( + onAddFilter('_exists_', field.name, '+')}> + {field.details.exists} + + )}{' '} + {field.indexPattern.metaFields.includes(field.name) && field.scripted && ( + {field.details.exists} + )} + / {field.details.total}{' '} + +

+ )} + {field.details.error && ( +
+ {field.details.error} +
+ )} + {!field.details.error && ( +
+ {field.details.buckets.map((bucket: any) => ( + + ))} +
+ )} + + {field.visualizable && capabilities.get().visualize.show && ( + + + {warnings.length > 0 && ( + + + ({' '} + {' '} +