New visualization search selection (#30196) (#31476)

* EUIfication of Wizard Step 2

* Update snapshot

* Remove unnecessarily function bind

* Ignor ts untill file is converted to ts

* Apply styles

* Make button filled

* Update labels

* Update types

* Unfilled button

* Update styles

* Remove unused translations

* Add "manage index patterns" button

* Remove buttons and hide per page options; get rid of injectI18n

* Add back button

* Update header

* Remove back button

* Update data test subject

* Add data-test-subj for tabs

* Fix test

* Make test subj consistent with initial data test subj

* Move SavedObject initializing to render function

* Update propTypes
This commit is contained in:
Maryia Lapata 2019-02-20 11:34:39 +03:00 committed by GitHub
parent f968ebf8f8
commit d0c6aebf39
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 258 additions and 195 deletions

View file

@ -49,7 +49,7 @@ exports[`render 1`] = `
<EuiSpacer
size="s"
/>
<InjectIntl(SavedObjectFinderUI)
<SavedObjectFinder
callToActionButton={
<EuiButton
color="primary"

View file

@ -26,7 +26,7 @@ exports[`render 1`] = `
<EuiSpacer
size="m"
/>
<InjectIntl(SavedObjectFinderUI)
<SavedObjectFinder
callToActionButton={
<EuiButton
color="primary"

View file

@ -18,7 +18,6 @@
*/
import './editor/editor';
import './wizard/wizard';
import 'ui/draggable/draggable_container';
import 'ui/draggable/draggable_item';
import 'ui/draggable/draggable_handle';

View file

@ -150,8 +150,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
>
<div>
<div
class="euiModal visNewVisDialog"
style="max-width: 100vw;"
class="euiModal euiModal--maxWidth-default visNewVisDialog"
tabindex="0"
>
<button
@ -361,7 +360,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
>
<EuiModal
className="visNewVisDialog"
maxWidth="100vw"
maxWidth={true}
onClose={[Function]}
>
<FocusTrap
@ -378,13 +377,8 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
>
<div>
<div
className="euiModal visNewVisDialog"
className="euiModal euiModal--maxWidth-default visNewVisDialog"
onKeyDown={[Function]}
style={
Object {
"maxWidth": "100vw",
}
}
tabIndex={0}
>
<EuiI18n
@ -1096,8 +1090,7 @@ exports[`NewVisModal should render as expected 1`] = `
>
<div>
<div
class="euiModal visNewVisDialog"
style="max-width: 100vw;"
class="euiModal euiModal--maxWidth-default visNewVisDialog"
tabindex="0"
>
<button
@ -1304,7 +1297,7 @@ exports[`NewVisModal should render as expected 1`] = `
>
<EuiModal
className="visNewVisDialog"
maxWidth="100vw"
maxWidth={true}
onClose={[Function]}
>
<FocusTrap
@ -1321,13 +1314,8 @@ exports[`NewVisModal should render as expected 1`] = `
>
<div>
<div
className="euiModal visNewVisDialog"
className="euiModal euiModal--maxWidth-default visNewVisDialog"
onKeyDown={[Function]}
style={
Object {
"maxWidth": "100vw",
}
}
tabIndex={0}
>
<EuiI18n

View file

@ -1,10 +1,15 @@
.visNewVisDialog {
max-width: 100vw;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='166' height='157' viewBox='0 0 166 157'%3E%3Cdefs%3E%3ClinearGradient id='untitled-2-a' x1='0%25' y1='0%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%23FFF' stop-opacity='.2'/%3E%3Cstop offset='100%25' stop-opacity='0'/%3E%3C/linearGradient%3E%3CradialGradient id='untitled-2-b' cx='0%25' cy='0%25' r='127.787%25' fx='0%25' fy='0%25' gradientTransform='matrix(.681 .68098 -.63326 .7323 0 0)'%3E%3Cstop offset='0%25' stop-color='%23BBB' stop-opacity='.1'/%3E%3Cstop offset='100%25' stop-opacity='.5'/%3E%3C/radialGradient%3E%3ClinearGradient id='untitled-2-c' x1='0%25' y1='0%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%23FFF' stop-opacity='.4'/%3E%3Cstop offset='100%25' stop-opacity='0'/%3E%3C/linearGradient%3E%3CradialGradient id='untitled-2-d' cx='0%25' cy='0%25' r='148.851%25' fx='0%25' fy='0%25' gradientTransform='matrix(.6718 .67182 -.74072 .60932 0 0)'%3E%3Cstop offset='0%25' stop-color='%23FFF' stop-opacity='.101'/%3E%3Cstop offset='100%25' stop-opacity='.15'/%3E%3C/radialGradient%3E%3CradialGradient id='untitled-2-e' cx='0%25' cy='0%25' r='127.349%25' fx='0%25' fy='0%25' gradientTransform='matrix(.68331 .68332 -.73013 .63951 0 0)'%3E%3Cstop offset='0%25' stop-color='%23BBB' stop-opacity='.1'/%3E%3Cstop offset='100%25' stop-opacity='.5'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cg opacity='.5' fill='none' fill-rule='evenodd' transform='matrix(-1 0 0 1 166 0)'%3E%3Cg opacity='.65' transform='matrix(0 -1 -1 0 146 157)'%3E%3Cpolygon fill='%23DD0A73' points='0 0 157 146 0 146' opacity='.418'/%3E%3Cpolygon fill='url(%23untitled-2-a)' points='0 0 157 146 0 146' style='mix-blend-mode:overlay'/%3E%3Cpolygon fill='url(%23untitled-2-b)' points='0 0 157 146 0 146' opacity='.618' style='mix-blend-mode:overlay'/%3E%3C/g%3E%3Cg opacity='.65' transform='translate(88 71)'%3E%3Cpath fill='%23017F75' d='M0,86 L78,86 C74.2038079,48.730962 43.6293886,16.7871605 0,0 L0,86 Z' opacity='.409'/%3E%3Cpath fill='url(%23untitled-2-c)' d='M0,86 L78,86 C74.2038079,48.730962 43.6293886,16.7871605 0,0 L0,86 Z' style='mix-blend-mode:overlay'/%3E%3Cpath fill='url(%23untitled-2-d)' d='M0,86 L78,86 C74.2038079,48.730962 43.6293886,16.7871605 0,0 L0,86 Z' opacity='.663' style='mix-blend-mode:overlay'/%3E%3C/g%3E%3Cg opacity='.15' transform='translate(73 79)'%3E%3Cpolygon fill='%23353535' points='0 0 73 78 0 78' opacity='.38'/%3E%3Cpolygon fill='url(%23untitled-2-a)' points='0 0 73 78 0 78' style='mix-blend-mode:overlay'/%3E%3Cpolygon fill='url(%23untitled-2-e)' points='0 0 73 78 0 78' style='mix-blend-mode:overlay'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A");
background-repeat: no-repeat;
background-position: calc(100% + 1px) calc(100% + 1px);
background-size: 37%;
}
.visNewVisSearchDialog {
min-height: $euiSizeL * 20;
}
.visNewVisDialog__body {
display: flex;
padding: $euiSizeM $euiSizeL 0;

View file

@ -23,6 +23,7 @@ import { EuiModal, EuiOverlayMask } from '@elastic/eui';
import { VisualizeConstants } from '../visualize_constants';
import { SearchSelection } from './search_selection';
import { TypeSelection } from './type_selection';
import chrome from 'ui/chrome';
@ -35,7 +36,14 @@ interface TypeSelectionProps {
editorParams?: string[];
}
class NewVisModal extends React.Component<TypeSelectionProps> {
interface TypeSelectionState {
showSearchVisModal: boolean;
visType?: VisType;
}
const baseUrl = `#${VisualizeConstants.CREATE_PATH}?`;
class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState> {
public static defaultProps = {
editorParams: [],
};
@ -45,6 +53,10 @@ class NewVisModal extends React.Component<TypeSelectionProps> {
constructor(props: TypeSelectionProps) {
super(props);
this.isLabsEnabled = chrome.getUiSettingsClient().get('visualize:enableLabs');
this.state = {
showSearchVisModal: false,
};
}
public render() {
@ -52,26 +64,50 @@ class NewVisModal extends React.Component<TypeSelectionProps> {
return null;
}
return (
<EuiOverlayMask>
<EuiModal onClose={this.props.onClose} maxWidth={'100vw'} className="visNewVisDialog">
const selectionModal =
this.state.showSearchVisModal && this.state.visType ? (
<EuiModal onClose={this.onCloseModal} className="visNewVisSearchDialog">
<SearchSelection onSearchSelected={this.onSearchSelected} visType={this.state.visType} />
</EuiModal>
) : (
<EuiModal onClose={this.onCloseModal} className="visNewVisDialog">
<TypeSelection
showExperimental={this.isLabsEnabled}
onVisTypeSelected={this.onVisTypeSelected}
visTypesRegistry={this.props.visTypesRegistry}
/>
</EuiModal>
</EuiOverlayMask>
);
);
return <EuiOverlayMask>{selectionModal}</EuiOverlayMask>;
}
private onVisTypeSelected = (visType: VisType) => {
const baseUrl =
visType.requiresSearch && visType.options.showIndexSelection
? `#${VisualizeConstants.WIZARD_STEP_2_PAGE_PATH}?`
: `#${VisualizeConstants.CREATE_PATH}?`;
const params = [`type=${encodeURIComponent(visType.name)}`, ...this.props.editorParams!];
private onCloseModal = () => {
this.setState({ showSearchVisModal: false });
this.props.onClose();
};
private onVisTypeSelected = (visType: VisType) => {
if (visType.requiresSearch && visType.options.showIndexSelection) {
this.setState({
showSearchVisModal: true,
visType,
});
} else {
const params = [`type=${encodeURIComponent(visType.name)}`, ...this.props.editorParams!];
this.props.onClose();
location.assign(`${baseUrl}${params.join('&')}`);
}
};
private onSearchSelected = (searchId: string, searchType: string) => {
this.props.onClose();
const params = [
`type=${encodeURIComponent(this.state.visType!.name)}`,
`${searchType === 'search' ? 'savedSearchId' : 'indexPattern'}=${searchId}`,
...this.props.editorParams!,
];
location.assign(`${baseUrl}${params.join('&')}`);
};
}

View file

@ -0,0 +1,20 @@
/*
* 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.
*/
export { SearchSelection } from './search_selection';

View file

@ -0,0 +1,150 @@
/*
* 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 {
EuiModalBody,
EuiModalHeader,
EuiModalHeaderTitle,
EuiSpacer,
EuiTab,
EuiTabs,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { VisType } from 'ui/vis';
import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
interface SearchSelectionProps {
onSearchSelected: (searchId: string, searchType: string) => void;
visType: VisType;
}
interface SearchSelectionState {
selectedTabId: string;
}
interface TabProps {
id: string;
name: string;
}
const INDEX_PATTERNS_TAB_ID = 'indexPatterns';
const SAVED_SEARCHES_TAB_ID = 'savedSearches';
export class SearchSelection extends React.Component<SearchSelectionProps, SearchSelectionState> {
public state = {
selectedTabId: INDEX_PATTERNS_TAB_ID,
};
private fixedPageSize: number = 8;
public render() {
return (
<React.Fragment>
<EuiModalHeader>
<EuiModalHeaderTitle>
<FormattedMessage
id="kbn.visualize.newVisWizard.newVisTypeTitle"
defaultMessage="New {visTypeName}"
values={{ visTypeName: this.props.visType.title }}
/>{' '}
/{' '}
<FormattedMessage
id="kbn.visualize.newVisWizard.chooseSourceTitle"
defaultMessage="Choose a source"
/>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiTabs size="m">{this.renderTabs()}</EuiTabs>
<EuiSpacer size="m" />
{this.renderTab()}
</EuiModalBody>
</React.Fragment>
);
}
private onSelectedTabChanged = (tab: TabProps) => {
this.setState({
selectedTabId: tab.id,
});
};
private renderTabs() {
const tabs = [
{
id: INDEX_PATTERNS_TAB_ID,
name: i18n.translate('kbn.visualize.newVisWizard.indexPatternTabLabel', {
defaultMessage: 'Index pattern',
}),
},
{
id: SAVED_SEARCHES_TAB_ID,
name: i18n.translate('kbn.visualize.newVisWizard.savedSearchTabLabel', {
defaultMessage: 'Saved search',
}),
},
];
const { selectedTabId } = this.state;
return tabs.map(tab => (
<EuiTab
onClick={() => this.onSelectedTabChanged(tab)}
isSelected={tab.id === selectedTabId}
key={tab.id}
data-test-subj={`${tab.id}Tab`}
>
{tab.name}
</EuiTab>
));
}
private renderTab() {
if (this.state.selectedTabId === SAVED_SEARCHES_TAB_ID) {
return (
<SavedObjectFinder
key="searchSavedObjectFinder"
onChoose={this.props.onSearchSelected}
noItemsMessage={i18n.translate(
'kbn.visualize.newVisWizard.savedSearchTab.notFoundLabel',
{ defaultMessage: 'No matching saved searches found.' }
)}
savedObjectType="search"
fixedPageSize={this.fixedPageSize}
/>
);
}
return (
<SavedObjectFinder
key="visSavedObjectFinder"
onChoose={this.props.onSearchSelected}
noItemsMessage={i18n.translate('kbn.visualize.newVisWizard.indexPatternTab.notFoundLabel', {
defaultMessage: 'No matching index patterns found.',
})}
savedObjectType="index-pattern"
fixedPageSize={this.fixedPageSize}
/>
);
}
}

View file

@ -1,36 +0,0 @@
<div class="kuiViewContent kuiViewContent--constrainedWidth kuiViewContentItem" data-test-subj="visualizeSelectSearch">
<div class="visWizard kuiViewContentItem">
<div class="visWizard__column visWizard__column--small">
<h2
class="kuiTitle kuiVerticalRhythm"
i18n-id="kbn.visualize.newVisWizard.createFromNewSearchTitle"
i18n-default-message="From a New Search, Select Index"
></h2>
<paginated-selectable-list
per-page="20"
list="indexPattern.list"
list-property="attributes.title"
user-make-url="makeUrl"
class="visWizard__row visWizard__list--paginated--selectable kuiVerticalRhythm"
disable-auto-focus="true"
></paginated-selectable-list>
</div>
<div class="visWizard__column visWizard__column--large">
<h2
class="kuiTitle kuiVerticalRhythm"
i18n-id="kbn.visualize.newVisWizard.createFromSavedSearchTitle"
i18n-default-message="Or, From a Saved Search"
></h2>
<!-- Saved searches -->
<saved-object-finder
type="searches"
class="visWizard__row visWizard__savedObjectFinder kuiVerticalRhythm"
make-url="step2WithSearchUrl"
disable-auto-focus="true"
></saved-object-finder>
</div>
</div>
</div>

View file

@ -1,104 +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 '../saved_visualizations/saved_visualizations';
import 'ui/directives/saved_object_finder';
import 'ui/directives/paginated_selectable_list';
import '../../discover/saved_searches/saved_searches';
import { DashboardConstants } from '../../dashboard/dashboard_constants';
import { VisualizeConstants } from '../visualize_constants';
import routes from 'ui/routes';
import { uiModules } from 'ui/modules';
import visualizeWizardStep2Template from './step_2.html';
import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { timefilter } from 'ui/timefilter';
import { getWizardStep2Breadcrumbs } from '../breadcrumbs';
const module = uiModules.get('app/visualize', ['kibana/courier']);
/********
/** Wizard Step 2
/********/
// Redirect old route to new route.
// NOTE: Accessing this route directly means the user has entered into the wizard UX without
// selecting a Visualization type in step 1. So we want to redirect them to step 1, not step 2.
routes.when('/visualize/step/2', {
redirectTo: VisualizeConstants.WIZARD_STEP_1_PAGE_PATH,
});
routes.when(VisualizeConstants.WIZARD_STEP_2_PAGE_PATH, {
template: visualizeWizardStep2Template,
k7Breadcrumbs: getWizardStep2Breadcrumbs,
controller: 'VisualizeWizardStep2',
resolve: {
indexPatterns: function (Private) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
return savedObjectsClient.find({
type: 'index-pattern',
fields: ['title'],
perPage: 10000
}).then(response => response.savedObjects);
}
}
});
module.controller('VisualizeWizardStep2', function ($route, $scope, kbnUrl) {
const type = $route.current.params.type;
const addToDashMode = $route.current.params[DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM];
kbnUrl.removeParam(DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM);
$scope.step2WithSearchUrl = function (hit) {
if (addToDashMode) {
return kbnUrl.eval(
`#${VisualizeConstants.CREATE_PATH}` +
`?type={{type}}&savedSearchId={{id}}` +
`&${DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM}`,
{ type: type, id: hit.id }
);
}
return kbnUrl.eval(
`#${VisualizeConstants.CREATE_PATH}?type={{type}}&savedSearchId={{id}}`,
{ type: type, id: hit.id }
);
};
timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector();
$scope.indexPattern = {
selection: null,
list: $route.current.locals.indexPatterns
};
$scope.makeUrl = function (pattern) {
if (!pattern) return;
if (addToDashMode) {
return `#${VisualizeConstants.CREATE_PATH}` +
`?${DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM}` +
`&type=${type}&indexPattern=${pattern.id}`;
}
return `#${VisualizeConstants.CREATE_PATH}?type=${type}&indexPattern=${pattern.id}`;
};
});

View file

@ -20,7 +20,6 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import { InjectedIntlProps } from 'react-intl';
import chrome from 'ui/chrome';
import {
@ -32,7 +31,7 @@ import {
EuiTableCriteria,
} from '@elastic/eui';
import { Direction } from '@elastic/eui/src/services/sort/sort_direction';
import { injectI18n } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { SavedObjectAttributes } from '../../../../server/saved_objects';
import { VisTypesRegistryProvider } from '../../registry/vis_types';
@ -52,7 +51,7 @@ interface SavedObjectFinderUIState {
sortDirection?: Direction;
}
interface SavedObjectFinderUIProps extends InjectedIntlProps {
interface BaseSavedObjectFinder {
callToActionButton?: React.ReactNode;
onChoose?: (
id: SavedObject<SavedObjectAttributes>['id'],
@ -60,23 +59,31 @@ interface SavedObjectFinderUIProps extends InjectedIntlProps {
) => void;
makeUrl?: (id: SavedObject<SavedObjectAttributes>['id']) => void;
noItemsMessage?: React.ReactNode;
savedObjectType: 'visualization' | 'search';
savedObjectType: 'visualization' | 'search' | 'index-pattern';
visTypes?: VisTypesRegistryProvider;
initialPageSize?: 5 | 10 | 15;
}
class SavedObjectFinderUI extends React.Component<
SavedObjectFinderUIProps,
SavedObjectFinderUIState
> {
interface SavedObjectFinderFixedPage extends BaseSavedObjectFinder {
initialPageSize?: undefined;
fixedPageSize: number;
}
interface SavedObjectFinderInitialPageSize extends BaseSavedObjectFinder {
initialPageSize?: 5 | 10 | 15;
fixedPageSize?: undefined;
}
type SavedObjectFinderProps = SavedObjectFinderFixedPage | SavedObjectFinderInitialPageSize;
class SavedObjectFinder extends React.Component<SavedObjectFinderProps, SavedObjectFinderUIState> {
public static propTypes = {
callToActionButton: PropTypes.node,
onChoose: PropTypes.func,
makeUrl: PropTypes.func,
noItemsMessage: PropTypes.node,
savedObjectType: PropTypes.oneOf(['visualization', 'search']).isRequired,
savedObjectType: PropTypes.oneOf(['visualization', 'search', 'index-pattern']).isRequired,
visTypes: PropTypes.object,
initialPageSize: PropTypes.number,
initialPageSize: PropTypes.oneOf([5, 10, 15]),
fixedPageSize: PropTypes.number,
};
private isComponentMounted: boolean = false;
@ -128,14 +135,14 @@ class SavedObjectFinderUI extends React.Component<
}
}, 300);
constructor(props: SavedObjectFinderUIProps) {
constructor(props: SavedObjectFinderProps) {
super(props);
this.state = {
items: [],
isFetchingItems: false,
page: 0,
perPage: props.initialPageSize || 15,
perPage: props.initialPageSize || props.fixedPageSize || 15,
filter: '',
};
}
@ -225,8 +232,7 @@ class SavedObjectFinderUI extends React.Component<
<EuiFlexGroup>
<EuiFlexItem grow={true}>
<EuiFieldSearch
placeholder={this.props.intl.formatMessage({
id: 'common.ui.savedObjects.finder.searchPlaceholder',
placeholder={i18n.translate('common.ui.savedObjects.finder.searchPlaceholder', {
defaultMessage: 'Search…',
})}
fullWidth
@ -255,6 +261,7 @@ class SavedObjectFinderUI extends React.Component<
pageIndex: this.state.page,
pageSize: this.state.perPage,
totalItemCount: this.state.items.length,
hidePerPageOptions: Boolean(this.props.fixedPageSize),
pageSizeOptions: [5, 10, 15],
};
// TODO there should be a Type in EUI for that, replace if it exists
@ -268,8 +275,7 @@ class SavedObjectFinderUI extends React.Component<
const tableColumns = [
{
field: 'title',
name: this.props.intl.formatMessage({
id: 'common.ui.savedObjects.finder.titleLabel',
name: i18n.translate('common.ui.savedObjects.finder.titleLabel', {
defaultMessage: 'Title',
}),
sortable: true,
@ -313,4 +319,4 @@ class SavedObjectFinderUI extends React.Component<
}
}
export const SavedObjectFinder = injectI18n(SavedObjectFinderUI);
export { SavedObjectFinder };

View file

@ -307,12 +307,13 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
}
async clickNewSearch(indexPattern = this.index.LOGSTASH_TIME_BASED) {
await testSubjects.click(`paginatedListItem-${indexPattern}`);
await testSubjects.click(`savedObjectTitle${indexPattern.split(' ').join('-')}`);
await PageObjects.header.waitUntilLoadingHasFinished();
}
async clickSavedSearch(savedSearchName) {
await find.clickByPartialLinkText(savedSearchName);
await testSubjects.click('savedSearchesTab');
await testSubjects.click(`savedObjectTitle${savedSearchName.split(' ').join('-')}`);
await PageObjects.header.waitUntilLoadingHasFinished();
}

View file

@ -2064,8 +2064,6 @@
"kbn.visualize.listing.listingLimitHelpText": "您有 {totalItems} 个可视化但“listingLimit”设置使得下表最多只能显示 {listingLimit} 个。此设置可在以下选项下更改:",
"kbn.visualize.listing.noVisualizations.createVisualizationButtonLabel": "创建可视化",
"kbn.visualize.listing.noVisualizationsText": "看起来您还没有任何可视化。开始创建一些吧!",
"kbn.visualize.newVisWizard.createFromNewSearchTitle": "基于“新搜索”,选择“索引”",
"kbn.visualize.newVisWizard.createFromSavedSearchTitle": "或者,基于“已保存的搜索”",
"kbn.visualize.newVisWizard.experimentalDescription": "这是实验性可视化。与稳定的可视化相比,其设计和实现均不够成熟,可能会随时发生更改。",
"kbn.visualize.newVisWizard.experimentalTitle": "实验性",
"kbn.visualize.newVisWizard.experimentalTooltip": "这是实验性可视化。",