[Visualizations] Show TSVB and Agg based as "legacy" when users create visualizations from the library (#195966)

## Summary

Fixes https://github.com/elastic/kibana/issues/191489

Redesign of "Create Visualization" Modal

To encourage users to adopt Lens and reduce reliance on Agg-based and
TSVB visualizations, we've redesigned the "Create Visualization" modal.
The new layout now features two distinct tabs: one highlighting
recommended visualizations, and another clearly marking legacy options.
This separation ensures users are well-informed about which
visualization types are preferred moving forward.

<img width="757" alt="Screenshot 2024-10-15 at 13 15 49"
src="https://github.com/user-attachments/assets/fe353504-5511-46ab-aef4-5a340650027b">


![image](https://github.com/user-attachments/assets/86c399fc-e737-453f-84e3-938d85aa22d3)
This commit is contained in:
Marta Bondyra 2024-10-21 18:00:00 +02:00 committed by GitHub
parent ff44bf2770
commit 46eda4c489
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 349 additions and 559 deletions

View file

@ -23,10 +23,10 @@ export const markdownVisDefinition: VisTypeDefinition<MarkdownVisParams> = {
icon: 'visText',
group: VisGroups.TOOLS,
titleInWizard: i18n.translate('visTypeMarkdown.markdownTitleInWizard', {
defaultMessage: 'Text',
defaultMessage: 'Markdown text',
}),
description: i18n.translate('visTypeMarkdown.markdownDescription', {
defaultMessage: 'Add text and images to your dashboard.',
defaultMessage: 'Add custom text or images to dashboards.',
}),
order: 30,
toExpressionAst,

View file

@ -102,7 +102,7 @@ export const metricsVisDefinition: VisTypeDefinition<
name: VIS_TYPE,
title: i18n.translate('visTypeTimeseries.kbnVisTypes.metricsTitle', { defaultMessage: 'TSVB' }),
description: i18n.translate('visTypeTimeseries.kbnVisTypes.metricsDescription', {
defaultMessage: 'Perform advanced analysis of your time series data.',
defaultMessage: 'Create visualizations using time series data.',
}),
icon: 'visVisualBuilder',
group: VisGroups.LEGACY,

View file

@ -32,12 +32,9 @@ export const createVegaTypeDefinition = (): VisTypeDefinition<VisParams> => {
title: 'Vega',
getInfoMessage,
description: i18n.translate('visTypeVega.type.vegaDescription', {
defaultMessage: 'Use Vega to create new types of visualizations.',
defaultMessage: 'Use the Vega syntax to create new types of visualizations.',
description: 'Vega and Vega-Lite are product names and should not be translated',
}),
note: i18n.translate('visTypeVega.type.vegaNote', {
defaultMessage: 'Requires knowledge of Vega syntax.',
}),
icon: 'visVega',
group: VisGroups.PROMOTED,
titleInWizard: i18n.translate('visTypeVega.type.vegaTitleInWizard', {

View file

@ -70,18 +70,18 @@ describe('AggBasedSelection', () => {
jest.clearAllMocks();
});
it('should call the toggleGroups if the user clicks the goBack link', () => {
const toggleGroups = jest.fn();
it('should call the showMainDialog if the user clicks the goBack link', () => {
const showMainDialog = jest.fn();
const wrapper = mountWithIntl(
<AggBasedSelection
visTypesRegistry={visTypes}
toggleGroups={toggleGroups}
showMainDialog={showMainDialog}
onVisTypeSelected={jest.fn()}
/>
);
const aggBasedGroupCard = wrapper.find('[data-test-subj="goBackLink"]').last();
aggBasedGroupCard.simulate('click');
expect(toggleGroups).toHaveBeenCalled();
expect(showMainDialog).toHaveBeenCalled();
});
describe('filter for visualization types', () => {
@ -89,7 +89,7 @@ describe('AggBasedSelection', () => {
const wrapper = mountWithIntl(
<AggBasedSelection
visTypesRegistry={visTypes}
toggleGroups={jest.fn()}
showMainDialog={jest.fn()}
onVisTypeSelected={jest.fn()}
/>
);

View file

@ -39,7 +39,7 @@ interface AggBasedSelectionProps {
openedAsRoot?: boolean;
onVisTypeSelected: (visType: BaseVisType) => void;
visTypesRegistry: TypesStart;
toggleGroups: (flag: boolean) => void;
showMainDialog: (flag: boolean) => void;
}
interface AggBasedSelectionState {
query: string;
@ -67,7 +67,7 @@ class AggBasedSelection extends React.Component<AggBasedSelectionProps, AggBased
</EuiModalHeader>
<EuiModalBody>
{this.props.openedAsRoot ? null : (
<DialogNavigation goBack={() => this.props.toggleGroups(true)} />
<DialogNavigation goBack={() => this.props.showMainDialog(true)} />
)}
<EuiFieldSearch
placeholder="Filter"

View file

@ -1,5 +1,5 @@
$modalWidth: $euiSizeL * 34;
$modalHeight: $euiSizeL * 30;
$modalWidth: $euiSizeS * 100;
$modalHeight: $euiSizeS * 90;
.visNewVisDialog {
max-width: $modalWidth;

View file

@ -8,11 +8,13 @@
*/
import React from 'react';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import userEvent from '@testing-library/user-event';
import { TypesStart, BaseVisType, VisGroups } from '../../vis_types';
import { GroupSelection } from './group_selection';
import { GroupSelection, GroupSelectionProps } from './group_selection';
import { DocLinksStart } from '@kbn/core/public';
import { VisParams } from '../../../common';
import { render, screen } from '@testing-library/react';
import { I18nProvider } from '@kbn/i18n-react';
describe('GroupSelection', () => {
const defaultVisTypeParams = {
@ -99,35 +101,34 @@ describe('GroupSelection', () => {
jest.clearAllMocks();
});
const renderGroupSelectionComponent = (overrideProps?: Partial<GroupSelectionProps>) => {
return render(
<I18nProvider>
<GroupSelection
tab="recommended"
setTab={jest.fn()}
visTypesRegistry={visTypesRegistry(_visTypes)}
docLinks={docLinks as DocLinksStart}
showMainDialog={jest.fn()}
onVisTypeSelected={jest.fn()}
{...overrideProps}
/>
</I18nProvider>
);
};
it('should render the header title', () => {
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry(_visTypes)}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
expect(wrapper.find('[data-test-subj="groupModalHeader"]').at(0).text()).toBe(
'New visualization'
);
renderGroupSelectionComponent();
expect(screen.getByTestId('groupModalHeader')).toHaveTextContent('Create visualization');
});
it('should not render the aggBased group card if no aggBased visualization is registered', () => {
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry(_visTypes)}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
expect(wrapper.find('[data-test-subj="visGroup-aggbased"]').exists()).toBe(false);
it('should not render tabs if no legacy, tools or tsvb visualizations are registered', async () => {
renderGroupSelectionComponent();
expect(screen.queryByRole('tab', { name: /legacy/i })).toBeNull();
expect(screen.queryByRole('tab', { name: /recommended/i })).toBeNull();
});
it('should render the aggBased group card if an aggBased group vis is registered', () => {
it('should render tabs and the aggBased group card if an aggBased group vis is registered', async () => {
const aggBasedVisType = {
name: 'visWithSearch',
title: 'Vis with search',
@ -135,53 +136,18 @@ describe('GroupSelection', () => {
stage: 'production',
...defaultVisTypeParams,
};
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry([..._visTypes, aggBasedVisType] as BaseVisType[])}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
expect(wrapper.find('[data-test-subj="visGroup-aggbased"]').exists()).toBe(true);
renderGroupSelectionComponent({
visTypesRegistry: visTypesRegistry([..._visTypes, aggBasedVisType] as BaseVisType[]),
tab: 'legacy',
});
expect(screen.queryByRole('tab', { name: /legacy/i })).toBeInTheDocument();
expect(screen.queryByRole('tab', { name: /recommended/i })).toBeInTheDocument();
expect(screen.getByTestId('visType-aggbased')).toHaveTextContent('Aggregation-based');
});
it('should not render the tools group card if no tools visualization is registered', () => {
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry(_visTypes)}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
expect(wrapper.find('[data-test-subj="visGroup-tools"]').exists()).toBe(false);
});
it('should render the tools group card if a tools group vis is registered', () => {
const toolsVisType = {
name: 'vis3',
title: 'Vis3',
stage: 'production',
group: VisGroups.TOOLS,
...defaultVisTypeParams,
};
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry([..._visTypes, toolsVisType] as BaseVisType[])}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
expect(wrapper.find('[data-test-subj="visGroup-tools"]').exists()).toBe(true);
});
it('should call the toggleGroups if the aggBased group card is clicked', () => {
const toggleGroups = jest.fn();
it('should call the showMainDialog if the aggBased group card is clicked', async () => {
const showMainDialog = jest.fn();
const aggBasedVisType = {
name: 'visWithSearch',
title: 'Vis with search',
@ -189,82 +155,26 @@ describe('GroupSelection', () => {
stage: 'production',
...defaultVisTypeParams,
};
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry([..._visTypes, aggBasedVisType] as BaseVisType[])}
docLinks={docLinks as DocLinksStart}
toggleGroups={toggleGroups}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
const aggBasedGroupCard = wrapper.find('[data-test-subj="visGroupAggBasedExploreLink"]').last();
aggBasedGroupCard.simulate('click');
expect(toggleGroups).toHaveBeenCalled();
renderGroupSelectionComponent({
showMainDialog,
visTypesRegistry: visTypesRegistry([..._visTypes, aggBasedVisType] as BaseVisType[]),
tab: 'legacy',
});
await userEvent.click(screen.getByRole('button', { name: /Aggregation-based/i }));
expect(showMainDialog).toHaveBeenCalledWith(false);
});
it('should sort promoted visualizations first', () => {
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry(_visTypes as BaseVisType[])}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
it('should only show promoted visualizations in recommended tab', () => {
renderGroupSelectionComponent();
const cards = [
...new Set(
wrapper.find('[data-test-subj^="visType-"]').map((card) => card.prop('data-test-subj'))
),
];
const cards = screen.getAllByRole('button').map((el) => el.textContent);
expect(cards).toEqual([
'visType-visAliasWithPromotion',
'visType-vis1',
'visType-vis2',
'visType-visWithAliasUrl',
'Vis alias with promotion',
'Vis Type 1',
'Vis Type 2',
'Vis with alias Url',
]);
});
it('should not show tools experimental visualizations if showExperimentalis false', () => {
const expVis = {
name: 'visExp',
title: 'Experimental Vis',
group: VisGroups.TOOLS,
stage: 'experimental',
...defaultVisTypeParams,
};
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry([..._visTypes, expVis] as BaseVisType[])}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={false}
/>
);
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(false);
});
it('should show tools experimental visualizations if showExperimental is true', () => {
const expVis = {
name: 'visExp',
title: 'Experimental Vis',
group: VisGroups.TOOLS,
stage: 'experimental',
...defaultVisTypeParams,
};
const wrapper = mountWithIntl(
<GroupSelection
visTypesRegistry={visTypesRegistry([..._visTypes, expVis] as BaseVisType[])}
docLinks={docLinks as DocLinksStart}
toggleGroups={jest.fn()}
onVisTypeSelected={jest.fn()}
showExperimental={true}
/>
);
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(true);
});
});

View file

@ -8,7 +8,7 @@
*/
import { FormattedMessage } from '@kbn/i18n-react';
import React, { useCallback, useMemo } from 'react';
import React, { ReactNode, useCallback, useMemo } from 'react';
import { orderBy } from 'lodash';
import {
EuiFlexGroup,
@ -20,14 +20,13 @@ import {
EuiModalBody,
EuiModalHeaderTitle,
EuiLink,
EuiText,
EuiSpacer,
EuiBetaBadge,
EuiTitle,
EuiDescriptionListTitle,
EuiDescriptionListDescription,
EuiDescriptionList,
EuiBadge,
EuiTabs,
EuiTab,
EuiIconTip,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { DocLinksStart } from '@kbn/core/public';
@ -36,162 +35,210 @@ import { VisGroups } from '../../vis_types/vis_groups_enum';
import type { VisTypeAlias } from '../../vis_types/vis_type_alias_registry';
import './group_selection.scss';
interface GroupSelectionProps {
export interface GroupSelectionProps {
onVisTypeSelected: (visType: BaseVisType | VisTypeAlias) => void;
visTypesRegistry: TypesStart;
docLinks: DocLinksStart;
toggleGroups: (flag: boolean) => void;
showExperimental: boolean;
showMainDialog: (flag: boolean) => void;
tab: 'recommended' | 'legacy';
setTab: (tab: 'recommended' | 'legacy') => void;
}
interface VisCardProps {
onVisTypeSelected: (visType: BaseVisType | VisTypeAlias) => void;
visType: BaseVisType | VisTypeAlias;
showExperimental?: boolean | undefined;
shouldStretch?: boolean;
}
function GroupSelection(props: GroupSelectionProps) {
const tabs: Array<{ id: 'recommended' | 'legacy'; label: ReactNode; dataTestSubj: string }> = [
{
id: 'recommended',
label: i18n.translate('visualizations.newVisWizard.recommendedTab', {
defaultMessage: 'Recommended',
}),
dataTestSubj: 'groupModalRecommendedTab',
},
{
id: 'legacy',
dataTestSubj: 'groupModalLegacyTab',
label: (
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false}>
<EuiFlexItem grow={false}>
{i18n.translate('visualizations.newVisWizard.legacyTab', {
defaultMessage: 'Legacy',
})}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip
content={i18n.translate('visualizations.newVisWizard.legacyTabDescription', {
defaultMessage: 'Legacy visualizations are scheduled for deprecation in the future.',
})}
position="top"
/>
</EuiFlexItem>
</EuiFlexGroup>
),
},
];
const getVisTypesFromGroup = (
visTypesRegistry: TypesStart,
group: VisGroups
): Array<BaseVisType | VisTypeAlias> => {
return visTypesRegistry.getByGroup(group).filter(({ disableCreate }) => !disableCreate);
};
function GroupSelection({
tab = 'recommended',
setTab,
visTypesRegistry,
...props
}: GroupSelectionProps) {
const visualizeGuideLink = props.docLinks.links.dashboard.guide;
const promotedVisGroups = useMemo(
() =>
orderBy(
[
...props.visTypesRegistry.getAliases(),
...props.visTypesRegistry.getByGroup(VisGroups.PROMOTED),
// Include so TSVB still gets displayed
...props.visTypesRegistry.getByGroup(VisGroups.LEGACY),
...visTypesRegistry.getAliases(),
...visTypesRegistry.getByGroup(VisGroups.PROMOTED),
].filter((visDefinition) => {
return !visDefinition.disableCreate;
}),
['promotion', 'title'],
['asc', 'asc']
),
[props.visTypesRegistry]
[visTypesRegistry]
);
const aggBasedTypes = getVisTypesFromGroup(visTypesRegistry, VisGroups.AGGBASED);
const legacyTypes = getVisTypesFromGroup(visTypesRegistry, VisGroups.LEGACY);
const shouldDisplayLegacyTab = legacyTypes.length + aggBasedTypes.length;
const [tsvbProps] = legacyTypes.map((visType) => ({
visType: {
...visType,
icon: visType.name === 'metrics' ? 'visualizeApp' : (visType.icon as string),
},
onVisTypeSelected: props.onVisTypeSelected,
key: visType.name,
}));
return (
<>
<EuiModalHeader>
<EuiModalHeaderTitle data-test-subj="groupModalHeader">
<FormattedMessage
id="visualizations.newVisWizard.title"
defaultMessage="New visualization"
defaultMessage="Create visualization"
/>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody className="visNewVisDialogGroupSelection__body">
{shouldDisplayLegacyTab && (
<div className="visNewVisDialogGroupSelection__visGroups">
<EuiTabs>
{tabs.map((t) => (
<EuiTab
data-test-subj={t.dataTestSubj}
isSelected={tab === t.id}
onClick={() => setTab(t.id)}
key={t.id}
>
{t.label}
</EuiTab>
))}
</EuiTabs>
</div>
)}
<div className="visNewVisDialogGroupSelection__visGroups">
<EuiSpacer size="s" />
<EuiFlexGrid columns={2} data-test-subj="visNewDialogGroups">
{promotedVisGroups.map((visType) => (
<VisGroup
visType={visType}
key={visType.name}
onVisTypeSelected={props.onVisTypeSelected}
/>
))}
</EuiFlexGrid>
<EuiSpacer size="l" />
</div>
<div className="visNewVisDialogGroupSelection__footer">
<EuiSpacer size="l" />
<EuiFlexGrid columns={2}>
{props.visTypesRegistry.getByGroup(VisGroups.AGGBASED).filter((visDefinition) => {
return !visDefinition.disableCreate;
}).length > 0 && (
<EuiFlexItem>
<EuiCard
titleSize="xs"
layout="horizontal"
display="transparent"
onClick={() => props.toggleGroups(false)}
title={
<span data-test-subj="visGroupAggBasedTitle">
{i18n.translate('visualizations.newVisWizard.aggBasedGroupTitle', {
defaultMessage: 'Aggregation based',
})}
</span>
}
data-test-subj="visGroup-aggbased"
description={i18n.translate(
'visualizations.newVisWizard.aggBasedGroupDescription',
{
defaultMessage:
'Use our classic visualize library to create charts based on aggregations.',
}
)}
icon={<EuiIcon type="heatmap" size="xl" color="success" />}
>
<EuiLink
data-test-subj="visGroupAggBasedExploreLink"
onClick={() => props.toggleGroups(false)}
>
<EuiText size="s">
{i18n.translate('visualizations.newVisWizard.exploreOptionLinkText', {
defaultMessage: 'Explore options',
})}{' '}
<EuiIcon type="sortRight" />
</EuiText>
</EuiLink>
</EuiCard>
</EuiFlexItem>
)}
{props.visTypesRegistry.getByGroup(VisGroups.TOOLS).length > 0 && (
<EuiFlexItem className="visNewVisDialog__toolsCard">
<EuiSpacer size="m" />
<EuiTitle size="xs">
<span data-test-subj="visGroup-tools">
{i18n.translate('visualizations.newVisWizard.toolsGroupTitle', {
defaultMessage: 'Tools',
})}
</span>
</EuiTitle>
<EuiSpacer size="s" />
<div className="visNewVisDialog__toolsCardGroupContainer">
{props.visTypesRegistry.getByGroup(VisGroups.TOOLS).map((visType) => (
<ToolsGroup
visType={visType}
key={visType.name}
onVisTypeSelected={props.onVisTypeSelected}
showExperimental={props.showExperimental}
/>
))}
</div>
</EuiFlexItem>
)}
</EuiFlexGrid>
<EuiSpacer size="m" />
<EuiDescriptionList
className="visNewVisDialogGroupSelection__footerDescriptionList"
type="responsiveColumn"
>
<EuiDescriptionListTitle className="visNewVisDialogGroupSelection__footerDescriptionListTitle">
<FormattedMessage
id="visualizations.newVisWizard.learnMoreText"
defaultMessage="Want to learn more?"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription>
<EuiLink href={visualizeGuideLink} target="_blank" external>
<FormattedMessage
id="visualizations.newVisWizard.readDocumentationLink"
defaultMessage="Read documentation"
{tab === 'recommended' ? (
<EuiFlexGrid columns={2} data-test-subj="visNewDialogGroups">
{promotedVisGroups.map((visType) => (
<VisGroup
visType={visType}
key={visType.name}
onVisTypeSelected={props.onVisTypeSelected}
shouldStretch={visType.name === 'lens'}
/>
</EuiLink>
</EuiDescriptionListDescription>
</EuiDescriptionList>
))}
</EuiFlexGrid>
) : (
<EuiFlexGrid columns={2} data-test-subj="visNewDialogGroups">
{tsvbProps ? <VisGroup {...tsvbProps} /> : null}
{
<VisGroup
visType={{
stage: 'production',
name: 'aggbased',
description: i18n.translate(
'visualizations.newVisWizard.aggBasedGroupDescription',
{
defaultMessage: 'Craft charts using basic aggregations.',
}
),
icon: 'indexPatternApp',
title: i18n.translate('visualizations.newVisWizard.aggBasedGroupTitle', {
defaultMessage: 'Aggregation-based',
}),
}}
onVisTypeSelected={() => {
props.showMainDialog(false);
}}
/>
}
</EuiFlexGrid>
)}
<EuiSpacer size="l" />
</div>
<ModalFooter visualizeGuideLink={visualizeGuideLink} />
</EuiModalBody>
</>
);
}
const VisGroup = ({ visType, onVisTypeSelected }: VisCardProps) => {
const ModalFooter = ({ visualizeGuideLink }: { visualizeGuideLink: string }) => {
return (
<div className="visNewVisDialogGroupSelection__footer">
<EuiSpacer size="l" />
<EuiDescriptionList
className="visNewVisDialogGroupSelection__footerDescriptionList"
type="responsiveColumn"
compressed
>
<EuiDescriptionListTitle className="visNewVisDialogGroupSelection__footerDescriptionListTitle">
<FormattedMessage
id="visualizations.newVisWizard.learnMoreText"
defaultMessage="Want to learn more?"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription>
<EuiLink href={visualizeGuideLink} target="_blank" external>
<FormattedMessage
id="visualizations.newVisWizard.viewDocumentationLink"
defaultMessage="View documentation"
/>
</EuiLink>
</EuiDescriptionListDescription>
</EuiDescriptionList>
</div>
);
};
const VisGroup = ({ visType, onVisTypeSelected, shouldStretch = false }: VisCardProps) => {
const onClick = useCallback(() => {
onVisTypeSelected(visType);
}, [onVisTypeSelected, visType]);
return (
<EuiFlexItem className="visNewVisDialog__groupsCardWrapper">
<EuiFlexItem
className="visNewVisDialog__groupsCardWrapper"
css={shouldStretch ? { gridColumn: '1 / -1' } : null}
>
<EuiCard
titleSize="xs"
hasBorder={true}
@ -213,68 +260,10 @@ const VisGroup = ({ visType, onVisTypeSelected }: VisCardProps) => {
</>
}
layout="horizontal"
icon={<EuiIcon type={visType.icon || 'empty'} size="xl" color="success" />}
icon={<EuiIcon type={visType.icon || 'empty'} size="xl" />}
/>
</EuiFlexItem>
);
};
const ToolsGroup = ({ visType, onVisTypeSelected, showExperimental }: VisCardProps) => {
const onClick = useCallback(() => {
onVisTypeSelected(visType);
}, [onVisTypeSelected, visType]);
// hide both the hidden visualizations and, if lab mode is not enabled, the experimental visualizations
// TODO: Remove the showExperimental logic as part of https://github.com/elastic/kibana/issues/152833
if (visType.disableCreate || (!showExperimental && visType.stage === 'experimental')) {
return null;
}
return (
<EuiFlexGroup alignItems="center" gutterSize="m" responsive={false}>
<EuiFlexItem grow={false}>
<EuiIcon type={visType.icon || 'empty'} size="l" />
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
<EuiFlexItem grow={false}>
<EuiLink
data-test-subj={`visType-${visType.name}`}
data-vis-stage={visType.stage}
onClick={onClick}
>
{'titleInWizard' in visType && visType.titleInWizard
? visType.titleInWizard
: visType.title}
</EuiLink>
</EuiFlexItem>
{visType.stage === 'experimental' && !visType.isDeprecated ? (
<EuiFlexItem grow={false}>
<EuiBetaBadge
iconType="beaker"
tooltipContent={i18n.translate('visualizations.newVisWizard.experimentalTooltip', {
defaultMessage:
'This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.',
})}
label={i18n.translate('visualizations.newVisWizard.experimentalTitle', {
defaultMessage: 'Technical preview',
})}
/>
</EuiFlexItem>
) : (
visType.isDeprecated && (
<EuiFlexItem grow={false}>
<EuiBadge color="warning">
<FormattedMessage id="visualizations.deprecatedTag" defaultMessage="Deprecated" />
</EuiBadge>
</EuiFlexItem>
)
)}
</EuiFlexGroup>
<EuiText color="subdued" size="s">
{visType.description}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
);
};
export { GroupSelection };

View file

@ -8,13 +8,15 @@
*/
import React from 'react';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { TypesStart, VisGroups, BaseVisType } from '../vis_types';
import NewVisModal from './new_vis_modal';
import NewVisModal, { TypeSelectionProps } from './new_vis_modal';
import { ApplicationStart, DocLinksStart } from '@kbn/core/public';
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks';
import { VisParams } from '../../common';
import { render, screen } from '@testing-library/react';
import { I18nProvider } from '@kbn/i18n-react';
import userEvent from '@testing-library/user-event';
describe('NewVisModal', () => {
const defaultVisTypeParams = {
@ -96,116 +98,67 @@ describe('NewVisModal', () => {
jest.clearAllMocks();
});
it('should show the aggbased group but not the visualization assigned to this group', () => {
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={() => null}
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{} as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
/>
const renderNewVisModal = (propsOverrides?: Partial<TypeSelectionProps>) => {
return render(
<I18nProvider>
<NewVisModal
isOpen={true}
onClose={() => null}
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{} as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
{...propsOverrides}
/>
</I18nProvider>
);
expect(wrapper.find('[data-test-subj="visGroup-aggbased"]').exists()).toBe(true);
expect(wrapper.find('[data-test-subj="visType-visWithSearch"]').exists()).toBe(false);
});
};
it('should show the tools group', () => {
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={() => null}
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{} as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
/>
);
expect(wrapper.find('[data-test-subj="visGroup-tools"]').exists()).toBe(true);
it('should show the aggbased group but not the visualization assigned to this group', async () => {
renderNewVisModal();
expect(screen.queryByText('Aggregation-based')).not.toBeInTheDocument();
expect(screen.queryByText('Vis with search')).not.toBeInTheDocument();
await userEvent.click(screen.getByRole('tab', { name: /Legacy/i }));
expect(screen.queryByText('Aggregation-based')).toBeInTheDocument();
expect(screen.queryByText('Vis with search')).not.toBeInTheDocument();
});
it('should display the visualizations of the other group', () => {
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={() => null}
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{} as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
/>
);
expect(wrapper.find('[data-test-subj="visType-vis2"]').exists()).toBe(true);
renderNewVisModal();
expect(screen.queryByText('Vis Type 2')).toBeInTheDocument();
});
describe('open editor', () => {
it('should open the editor for visualizations without search', () => {
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={() => null}
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{} as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
/>
);
const visCard = wrapper.find('[data-test-subj="visType-vis"]').last();
visCard.simulate('click');
it('should open the editor for visualizations without search', async () => {
renderNewVisModal();
await userEvent.click(screen.getByText('Vis Type 1'));
expect(window.location.assign).toBeCalledWith('testbasepath/app/visualize#/create?type=vis');
});
it('passes through editor params to the editor URL', () => {
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={() => null}
visTypesRegistry={visTypes}
editorParams={['foo=true', 'bar=42']}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{} as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
/>
);
const visCard = wrapper.find('[data-test-subj="visType-vis"]').last();
visCard.simulate('click');
it('passes through editor params to the editor URL', async () => {
renderNewVisModal({
editorParams: ['foo=true', 'bar=42'],
});
await userEvent.click(screen.getByText('Vis Type 1'));
expect(window.location.assign).toBeCalledWith(
'testbasepath/app/visualize#/create?type=vis&foo=true&bar=42'
);
});
it('closes and redirects properly if visualization with alias.path and originatingApp in props', () => {
it('closes and redirects properly if visualization with alias.path and originatingApp in props', async () => {
const onClose = jest.fn();
const navigateToApp = jest.fn();
const stateTransfer = embeddablePluginMock.createStartContract().getStateTransfer();
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={onClose}
visTypesRegistry={visTypes}
editorParams={['foo=true', 'bar=42']}
originatingApp={'coolJestTestApp'}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{ navigateToApp } as unknown as ApplicationStart}
docLinks={docLinks as DocLinksStart}
stateTransfer={stateTransfer}
contentClient={contentManagement.client}
/>
);
const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last();
visCard.simulate('click');
renderNewVisModal({
editorParams: ['foo=true', 'bar=42'],
onClose,
application: { navigateToApp } as unknown as ApplicationStart,
originatingApp: 'coolJestTestApp',
stateTransfer,
});
await userEvent.click(screen.getByText('Vis with alias Url'));
expect(stateTransfer.navigateToEditor).toBeCalledWith('otherApp', {
path: '#/aliasUrl',
state: { originatingApp: 'coolJestTestApp' },
@ -213,48 +166,28 @@ describe('NewVisModal', () => {
expect(onClose).toHaveBeenCalled();
});
it('closes and redirects properly if visualization with aliasApp and without originatingApp in props', () => {
it('closes and redirects properly if visualization with aliasApp and without originatingApp in props', async () => {
const onClose = jest.fn();
const navigateToApp = jest.fn();
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={onClose}
visTypesRegistry={visTypes}
editorParams={['foo=true', 'bar=42']}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{ navigateToApp } as unknown as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
/>
);
const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last();
visCard.simulate('click');
renderNewVisModal({
editorParams: ['foo=true', 'bar=42'],
onClose,
application: { navigateToApp } as unknown as ApplicationStart,
});
await userEvent.click(screen.getByText('Vis with alias Url'));
expect(navigateToApp).toBeCalledWith('otherApp', { path: '#/aliasUrl' });
expect(onClose).toHaveBeenCalled();
});
});
describe('aggBased visualizations', () => {
it('should render as expected', () => {
const wrapper = mountWithIntl(
<NewVisModal
isOpen={true}
onClose={() => null}
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
application={{} as ApplicationStart}
docLinks={docLinks as DocLinksStart}
contentClient={contentManagement.client}
/>
);
const aggBasedGroupCard = wrapper
.find('[data-test-subj="visGroupAggBasedExploreLink"]')
.last();
aggBasedGroupCard.simulate('click');
expect(wrapper.find('[data-test-subj="visType-visWithSearch"]').exists()).toBe(true);
it('should render as expected', async () => {
renderNewVisModal();
await userEvent.click(screen.getByRole('tab', { name: /Legacy/i }));
expect(screen.queryByText('Aggregation-based')).toBeInTheDocument();
await userEvent.click(screen.getByText('Aggregation-based'));
expect(screen.queryByText('Vis with search')).toBeInTheDocument();
});
});
});

View file

@ -22,7 +22,7 @@ import { AggBasedSelection } from './agg_based_selection';
import type { TypesStart, BaseVisType, VisTypeAlias } from '../vis_types';
import './dialog.scss';
interface TypeSelectionProps {
export interface TypeSelectionProps {
contentClient: ContentClient;
isOpen: boolean;
onClose: () => void;
@ -41,8 +41,9 @@ interface TypeSelectionProps {
interface TypeSelectionState {
showSearchVisModal: boolean;
showGroups: boolean;
isMainDialogShown: boolean;
visType?: BaseVisType;
tab: 'recommended' | 'legacy';
}
// TODO: redirect logic is specific to visualise & dashboard
@ -64,11 +65,16 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
this.state = {
showSearchVisModal: Boolean(this.props.selectedVisType),
showGroups: !this.props.showAggsSelection,
isMainDialogShown: !this.props.showAggsSelection,
visType: this.props.selectedVisType,
tab: 'recommended',
};
}
public setTab = (tab: 'recommended' | 'legacy') => {
this.setState({ tab });
};
public render() {
if (!this.props.isOpen) {
return null;
@ -82,7 +88,7 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
}
);
const WizardComponent = this.state.showGroups ? GroupSelection : AggBasedSelection;
const WizardComponent = this.state.isMainDialogShown ? GroupSelection : AggBasedSelection;
const selectionModal =
this.state.showSearchVisModal && this.state.visType ? (
@ -98,15 +104,21 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
) : (
<EuiModal
onClose={this.onCloseModal}
className={this.state.showGroups ? 'visNewVisDialog' : 'visNewVisDialog--aggbased'}
className={this.state.isMainDialogShown ? 'visNewVisDialog' : 'visNewVisDialog--aggbased'}
aria-label={visNewVisDialogAriaLabel}
>
<WizardComponent
showExperimental={true}
onVisTypeSelected={this.onVisTypeSelected}
visTypesRegistry={this.props.visTypesRegistry}
docLinks={this.props.docLinks}
toggleGroups={(flag: boolean) => this.setState({ showGroups: flag })}
setTab={this.setTab}
tab={this.state.tab}
showMainDialog={(shouldMainBeShown: boolean) => {
this.setState({ isMainDialogShown: shouldMainBeShown });
if (shouldMainBeShown) {
this.setTab('legacy');
}
}}
openedAsRoot={this.props.showAggsSelection && !this.props.selectedVisType}
/>
</EuiModal>

View file

@ -191,7 +191,7 @@ export default function ({ getService, getPageObjects }) {
it('should lose its connection to the dashboard when creating new visualization', async () => {
await visualize.gotoVisualizationLandingPage();
await visualize.clickNewVisualization();
await visualize.clickMarkdownWidget();
await visualize.clickVisualBuilder();
await visualize.notLinkedToOriginatingApp();
// return to origin should not be present in save modal

View file

@ -86,13 +86,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('resolves markdown link', async () => {
await visualize.navigateToNewVisualization();
await visualize.clickMarkdownWidget();
await dashboard.gotoDashboardLandingPage();
await dashboard.clickNewDashboard();
await dashboardAddPanel.clickMarkdownQuickButton();
await visEditor.setMarkdownTxt(`[abc](#/dashboard/${testDashboardId})`);
await visEditor.clickGo();
await visualize.saveVisualizationExpectSuccess('legacy url markdown');
await visualize.saveVisualization('legacy url markdown', { redirectToOrigin: true });
await (await find.byLinkText('abc')).click();
await header.waitUntilLoadingHasFinished();

View file

@ -12,25 +12,26 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const { visualize, visEditor, visChart, header } = getPageObjects([
'visualize',
const { visEditor, visChart, header, dashboard } = getPageObjects([
'dashboard',
'visEditor',
'visChart',
'header',
]);
const find = getService('find');
const inspector = getService('inspector');
const dashboardAddPanel = getService('dashboardAddPanel');
const markdown = `
# Heading 1
<h3>Inline HTML that should not be rendered as html</h3>
`;
describe('markdown app in visualize app', () => {
describe('markdown app', () => {
before(async function () {
await visualize.initTests();
await visualize.navigateToNewVisualization();
await visualize.clickMarkdownWidget();
await dashboard.initTests();
await dashboard.clickNewDashboard();
await dashboardAddPanel.clickMarkdownQuickButton();
await visEditor.setMarkdownTxt(markdown);
await visEditor.clickGo();
});

View file

@ -22,14 +22,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await visualize.navigateToNewVisualization();
});
it('should show the promoted vis types for the first step', async function () {
const expectedChartTypes = ['Custom visualization', 'Lens', 'Maps', 'TSVB'];
it('should show the expected visualizations types for both recommended and legacy tabs', async function () {
const expectedRecommendedChartTypes = ['Custom visualization', 'Lens', 'Maps'];
const expectedLegacyChartTypes = ['Aggregation-based', 'TSVB'];
// find all the chart types and make sure there all there
const chartTypes = (await visualize.getPromotedVisTypes()).sort();
const chartTypes = await visualize.getVisibleVisTypes();
log.debug('returned chart types = ' + chartTypes);
log.debug('expected chart types = ' + expectedChartTypes);
expect(chartTypes).to.eql(expectedChartTypes);
log.debug('expected chart types = ' + expectedRecommendedChartTypes);
expect(chartTypes).to.eql(expectedRecommendedChartTypes);
await visualize.clickLegacyTab();
const legacyChartTypes = await visualize.getVisibleVisTypes();
expect(legacyChartTypes).to.eql(expectedLegacyChartTypes);
});
it('should show the correct agg based chart types', async function () {

View file

@ -10,7 +10,7 @@
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const { visualize, visEditor } = getPageObjects(['visualize', 'visEditor']);
const { visualize, visualBuilder } = getPageObjects(['visualize', 'visualBuilder']);
const listingTable = getService('listingTable');
describe('visualize listing page', function describeIndexTests() {
@ -24,18 +24,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('create new viz', async function () {
// type markdown is used for simplicity
await visualize.createSimpleMarkdownViz(vizName);
// type tsvb is used for simplicity
await visualize.createSimpleTSVBViz(vizName);
await visualize.gotoVisualizationLandingPage();
await listingTable.expectItemsCount('visualize', 1);
});
it('delete all viz', async function () {
await visualize.createSimpleMarkdownViz(vizName + '1');
await visualize.createSimpleTSVBViz(vizName + '1');
await visualize.gotoVisualizationLandingPage();
await listingTable.expectItemsCount('visualize', 2);
await visualize.createSimpleMarkdownViz(vizName + '2');
await visualize.createSimpleTSVBViz(vizName + '2');
await visualize.gotoVisualizationLandingPage();
await listingTable.expectItemsCount('visualize', 3);
@ -48,9 +48,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
before(async function () {
// create one new viz
await visualize.navigateToNewVisualization();
await visualize.clickMarkdownWidget();
await visEditor.setMarkdownTxt('HELLO');
await visEditor.clickGo();
await visualize.clickVisualBuilder();
await visualBuilder.checkVisualBuilderIsPresent();
await visualize.saveVisualization('Hello World');
await visualize.gotoVisualizationLandingPage();
});

View file

@ -41,7 +41,6 @@ export class VisualizePageObject extends FtrService {
private readonly elasticChart = this.ctx.getService('elasticChart');
private readonly common = this.ctx.getPageObject('common');
private readonly header = this.ctx.getPageObject('header');
private readonly visEditor = this.ctx.getPageObject('visEditor');
private readonly visChart = this.ctx.getPageObject('visChart');
private readonly toasts = this.ctx.getService('toasts');
@ -106,7 +105,8 @@ export class VisualizePageObject extends FtrService {
}
public async clickAggBasedVisualizations() {
await this.testSubjects.click('visGroupAggBasedExploreLink');
await this.clickLegacyTab();
await this.testSubjects.click('visType-aggbased');
}
public async goBackToGroups() {
@ -125,7 +125,7 @@ export class VisualizePageObject extends FtrService {
.map((chart) => $(chart).findTestSubject('visTypeTitle').text().trim());
}
public async getPromotedVisTypes() {
public async getVisibleVisTypes() {
const chartTypeField = await this.testSubjects.find('visNewDialogGroups');
const $ = await chartTypeField.parseDomContent();
const promotedVisTypes: string[] = [];
@ -137,7 +137,7 @@ export class VisualizePageObject extends FtrService {
promotedVisTypes.push(title);
}
});
return promotedVisTypes;
return promotedVisTypes.sort();
}
public async waitForVisualizationSelectPage() {
@ -221,8 +221,8 @@ export class VisualizePageObject extends FtrService {
await this.clickVisType('line');
}
public async clickMarkdownWidget() {
await this.clickVisType('markdown');
public async clickLegacyTab() {
await this.testSubjects.click('groupModalLegacyTab');
}
public async clickMetric() {
@ -254,6 +254,7 @@ export class VisualizePageObject extends FtrService {
}
public async clickVisualBuilder() {
await this.clickLegacyTab();
await this.clickVisType('metrics');
}
@ -281,12 +282,10 @@ export class VisualizePageObject extends FtrService {
return await this.hasVisType('maps');
}
public async createSimpleMarkdownViz(vizName: string) {
public async createSimpleTSVBViz(vizName: string) {
await this.gotoVisualizationLandingPage();
await this.navigateToNewVisualization();
await this.clickMarkdownWidget();
await this.visEditor.setMarkdownTxt(vizName);
await this.visEditor.clickGo();
await this.clickVisualBuilder();
await this.saveVisualization(vizName);
}

View file

@ -22,10 +22,7 @@ export const getLensAliasConfig = (): VisTypeAlias => ({
}),
description: i18n.translate('xpack.lens.visTypeAlias.description', {
defaultMessage:
'Create visualizations with our drag and drop editor. Switch between visualization types at any time.',
}),
note: i18n.translate('xpack.lens.visTypeAlias.note', {
defaultMessage: 'Recommended for most users.',
'Create visualizations using an intuitive drag-and-drop interface. Smart suggestions help you follow best practices and find the chart types that best match your data.',
}),
order: 60,
icon: 'lensApp',

View file

@ -8261,8 +8261,6 @@
"visTypeMarkdown.function.help": "Visualisation Markdown",
"visTypeMarkdown.function.markdown.help": "Markdown à rendre",
"visTypeMarkdown.function.openLinksInNewTab.help": "Ouvre les liens dans un nouvel onglet",
"visTypeMarkdown.markdownDescription": "Ajoutez du texte et des images à votre tableau de bord.",
"visTypeMarkdown.markdownTitleInWizard": "Texte",
"visTypeMarkdown.params.fontSizeLabel": "Taille de police de base en points",
"visTypeMarkdown.params.helpLinkLabel": "Aide",
"visTypeMarkdown.params.openLinksLabel": "Ouvrir les liens dans un nouvel onglet",
@ -8591,7 +8589,6 @@
"visTypeTimeseries.indexPatternSelect.switchModePopover.title": "Mode de vue de données",
"visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "Utiliser des vues de données Kibana",
"visTypeTimeseries.indexPatternSelect.updateIndex": "Mettre à jour la visualisation avec la vue de données saisie",
"visTypeTimeseries.kbnVisTypes.metricsDescription": "Réalisez des analyses avancées de vos données temporelles.",
"visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB",
"visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "Compartiment : {lastBucketDate}",
"visTypeTimeseries.lastValueModeIndicator.lastValue": "Dernière valeur",
@ -8969,7 +8966,6 @@
"visTypeVega.mapView.resettingPropertyToMaxValueWarningMessage": "Réinitialisation de {name} sur {max}",
"visTypeVega.mapView.resettingPropertyToMinValueWarningMessage": "Réinitialisation de {name} sur {min}",
"visTypeVega.type.vegaDescription": "Utilisez Vega pour créer de nouveaux types de visualisations.",
"visTypeVega.type.vegaNote": "Requiert une connaissance de la syntaxe Vega.",
"visTypeVega.type.vegaTitleInWizard": "Visualisation personnalisée",
"visTypeVega.urlParser.dataUrlRequiresUrlParameterInFormErrorMessage": "{dataUrlParam} requiert un paramètre {urlParam} sous la forme \"{formLink}\"",
"visTypeVega.urlParser.urlShouldHaveQuerySubObjectWarningMessage": "L'utilisation d'un {urlObject} requiert un sous-objet {subObjectName}",
@ -9154,7 +9150,6 @@
"visualizations.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "Vous devez fournir un indexPattern ou un savedSearchId",
"visualizations.createVisualization.noVisTypeErrorMessage": "Vous devez fournir un type de visualisation valide",
"visualizations.dataView.label": "Vue de données",
"visualizations.deprecatedTag": "Déclassé",
"visualizations.displayName": "visualisation",
"visualizations.editor.createBreadcrumb": "Créer",
"visualizations.editor.defaultEditBreadcrumbText": "Modifier la visualisation",
@ -9206,24 +9201,16 @@
"visualizations.newChart.libraryMode.new": "nouveau",
"visualizations.newChart.libraryMode.old": "âge",
"visualizations.newGaugeChart.notificationMessage": "La nouvelle bibliothèque de graphiques de jauge ne prend pas encore en charge l'agrégation de graphiques fractionnés. {conditionalMessage}",
"visualizations.newVisWizard.aggBasedGroupDescription": "Utilisez notre bibliothèque Visualize classique pour créer des graphiques basés sur des agrégations.",
"visualizations.newVisWizard.aggBasedGroupTitle": "Basé sur une agrégation",
"visualizations.newVisWizard.chooseSourceTitle": "Choisir une source",
"visualizations.newVisWizard.experimentalTitle": "Version d'évaluation technique",
"visualizations.newVisWizard.experimentalTooltip": "Cette fonctionnalité est en version d'évaluation technique et pourra être modifiée ou retirée complètement dans une future version. Elastic s'efforcera de corriger tout problème, mais les fonctionnalités des versions d'évaluation technique ne sont pas soumises aux SLA de support des fonctionnalités officielles en disponibilité générale.",
"visualizations.newVisWizard.exploreOptionLinkText": "Explorer les options",
"visualizations.newVisWizard.filterVisTypeAriaLabel": "Filtrer un type de visualisation",
"visualizations.newVisWizard.goBackLink": "Sélectionner une visualisation différente",
"visualizations.newVisWizard.helpTextAriaLabel": "Commencez à créer votre visualisation en sélectionnant un type pour cette visualisation. Appuyez sur Échap pour fermer ce mode. Appuyez sur Tab pour aller plus loin.",
"visualizations.newVisWizard.learnMoreText": "Envie d'en savoir plus ?",
"visualizations.newVisWizard.newVisTypeTitle": "Nouveau {visTypeName}",
"visualizations.newVisWizard.readDocumentationLink": "Lire la documentation",
"visualizations.newVisWizard.resultsFound": "{resultCount, plural, one {type trouvé} other {types trouvés}}",
"visualizations.newVisWizard.searchSelection.notFoundLabel": "Aucun recherche enregistrée ni aucun index correspondants n'ont été trouvés.",
"visualizations.newVisWizard.searchSelection.savedObjectType.dataView": "Vue de données",
"visualizations.newVisWizard.searchSelection.savedObjectType.search": "Recherche enregistrée",
"visualizations.newVisWizard.title": "Nouvelle visualisation",
"visualizations.newVisWizard.toolsGroupTitle": "Outils",
"visualizations.noDataView.label": "vue de données",
"visualizations.noMatchRoute.bannerText": "L'application Visualize ne reconnaît pas cet itinéraire : {route}.",
"visualizations.noMatchRoute.bannerTitleText": "Page introuvable",
@ -25772,8 +25759,6 @@
"xpack.lens.uniqueLabel": "{label} [{num}]",
"xpack.lens.unknownDatasourceType.shortMessage": "Type de source de données inconnu",
"xpack.lens.unknownVisType.shortMessage": "Type de visualisation inconnu",
"xpack.lens.visTypeAlias.description": "Créez des visualisations avec notre éditeur de glisser-déposer. Basculez entre les différents types de visualisation à tout moment.",
"xpack.lens.visTypeAlias.note": "Recommandé pour la plupart des utilisateurs.",
"xpack.lens.visTypeAlias.title": "Lens",
"xpack.lens.visTypeAlias.type": "Lens",
"xpack.lens.visualizeAggBasedLegend": "Visualiser le graphique basé sur une agrégation",

View file

@ -8015,8 +8015,6 @@
"visTypeMarkdown.function.help": "マークダウンビジュアライゼーション",
"visTypeMarkdown.function.markdown.help": "レンダリングするマークダウン",
"visTypeMarkdown.function.openLinksInNewTab.help": "新規タブでリンクを開きます",
"visTypeMarkdown.markdownDescription": "テキストと画像をダッシュボードに追加します。",
"visTypeMarkdown.markdownTitleInWizard": "Text",
"visTypeMarkdown.params.fontSizeLabel": "ポイント単位のベースフォントサイズです。",
"visTypeMarkdown.params.helpLinkLabel": "ヘルプ",
"visTypeMarkdown.params.openLinksLabel": "新規タブでリンクを開く",
@ -8345,7 +8343,6 @@
"visTypeTimeseries.indexPatternSelect.switchModePopover.title": "データビューモード",
"visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "Kibanaデータビューを使用",
"visTypeTimeseries.indexPatternSelect.updateIndex": "入力したデータビューで可視化を更新",
"visTypeTimeseries.kbnVisTypes.metricsDescription": "時系列データの高度な分析を実行します。",
"visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB",
"visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "バケット:{lastBucketDate}",
"visTypeTimeseries.lastValueModeIndicator.lastValue": "最終値",
@ -8722,7 +8719,6 @@
"visTypeVega.mapView.resettingPropertyToMaxValueWarningMessage": "{name} を {max} にリセットしています",
"visTypeVega.mapView.resettingPropertyToMinValueWarningMessage": "{name} を {min} にリセットしています",
"visTypeVega.type.vegaDescription": "Vega を使用して、新しいタイプのビジュアライゼーションを作成します。",
"visTypeVega.type.vegaNote": "Vega 構文の知識が必要です。",
"visTypeVega.type.vegaTitleInWizard": "カスタムビジュアライゼーション",
"visTypeVega.urlParser.dataUrlRequiresUrlParameterInFormErrorMessage": "{dataUrlParam} には「{formLink}」の形で {urlParam} パラメーターが必要です",
"visTypeVega.urlParser.urlShouldHaveQuerySubObjectWarningMessage": "{urlObject} を使用するには {subObjectName} サブオブジェクトが必要です",
@ -8907,7 +8903,6 @@
"visualizations.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "indexPatternまたはsavedSearchIdが必要です",
"visualizations.createVisualization.noVisTypeErrorMessage": "有効なビジュアライゼーションタイプを指定してください",
"visualizations.dataView.label": "データビュー",
"visualizations.deprecatedTag": "非推奨",
"visualizations.displayName": "ビジュアライゼーション",
"visualizations.editor.createBreadcrumb": "作成",
"visualizations.editor.defaultEditBreadcrumbText": "ビジュアライゼーションを編集",
@ -8959,24 +8954,16 @@
"visualizations.newChart.libraryMode.new": "新規",
"visualizations.newChart.libraryMode.old": "古",
"visualizations.newGaugeChart.notificationMessage": "新しいゲージグラフライブラリはまだ分割グラフアグリゲーションをサポートしていません。{conditionalMessage}",
"visualizations.newVisWizard.aggBasedGroupDescription": "クラシック Visualize ライブラリを使用して、アグリゲーションに基づいてグラフを作成します。",
"visualizations.newVisWizard.aggBasedGroupTitle": "アグリゲーションに基づく",
"visualizations.newVisWizard.chooseSourceTitle": "ソースの選択",
"visualizations.newVisWizard.experimentalTitle": "テクニカルプレビュー",
"visualizations.newVisWizard.experimentalTooltip": "この機能はテクニカルプレビュー中であり、将来のリリースでは変更されたり完全に削除されたりする場合があります。Elasticはすべての問題の修正に努めますが、テクニカルプレビュー中の機能には正式なGA機能のサポートSLAが適用されません。",
"visualizations.newVisWizard.exploreOptionLinkText": "探索オプション",
"visualizations.newVisWizard.filterVisTypeAriaLabel": "ビジュアライゼーションのタイプでフィルタリング",
"visualizations.newVisWizard.goBackLink": "別のビジュアライゼーションを選択",
"visualizations.newVisWizard.helpTextAriaLabel": "タイプを選択してビジュアライゼーションの作成を始めましょう。ESC を押してこのモーダルを閉じます。Tab キーを押して次に進みます。",
"visualizations.newVisWizard.learnMoreText": "詳細について",
"visualizations.newVisWizard.newVisTypeTitle": "新規 {visTypeName}",
"visualizations.newVisWizard.readDocumentationLink": "ドキュメンテーションを表示",
"visualizations.newVisWizard.resultsFound": "{resultCount, plural, other {個のタイプ}} が見つかりました",
"visualizations.newVisWizard.searchSelection.notFoundLabel": "一致インデックスまたは保存した検索が見つかりません。",
"visualizations.newVisWizard.searchSelection.savedObjectType.dataView": "データビュー",
"visualizations.newVisWizard.searchSelection.savedObjectType.search": "保存検索",
"visualizations.newVisWizard.title": "新規ビジュアライゼーション",
"visualizations.newVisWizard.toolsGroupTitle": "ツール",
"visualizations.noDataView.label": "データビュー",
"visualizations.noMatchRoute.bannerText": "Visualizeアプリケーションはこのルートを認識できません。{route}",
"visualizations.noMatchRoute.bannerTitleText": "ページが見つかりません",
@ -25520,8 +25507,6 @@
"xpack.lens.unknownDatasourceType.shortMessage": "不明なデータソースタイプ",
"xpack.lens.unknownVisType.longMessage": "ビジュアライゼーションタイプ{visType}を解決できませんでした。",
"xpack.lens.unknownVisType.shortMessage": "不明なビジュアライゼーションタイプ",
"xpack.lens.visTypeAlias.description": "ドラッグアンドドロップエディターでビジュアライゼーションを作成します。いつでもビジュアライゼーションタイプを切り替えることができます。",
"xpack.lens.visTypeAlias.note": "ほとんどのユーザーに推奨されます。",
"xpack.lens.visTypeAlias.title": "Lens",
"xpack.lens.visTypeAlias.type": "Lens",
"xpack.lens.visualizeAggBasedLegend": "集約に基づくグラフを可視化",

View file

@ -8031,8 +8031,6 @@
"visTypeMarkdown.function.help": "Markdown 可视化",
"visTypeMarkdown.function.markdown.help": "要渲染的 Markdown",
"visTypeMarkdown.function.openLinksInNewTab.help": "在新标签页中打开链接",
"visTypeMarkdown.markdownDescription": "将文本和图像添加到仪表板。",
"visTypeMarkdown.markdownTitleInWizard": "文本",
"visTypeMarkdown.params.fontSizeLabel": "基础字体大小(磅)",
"visTypeMarkdown.params.helpLinkLabel": "帮助",
"visTypeMarkdown.params.openLinksLabel": "在新标签页中打开链接",
@ -8361,7 +8359,6 @@
"visTypeTimeseries.indexPatternSelect.switchModePopover.title": "数据视图模式",
"visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "使用 Kibana 数据视图",
"visTypeTimeseries.indexPatternSelect.updateIndex": "使用输入的数据视图更新可视化",
"visTypeTimeseries.kbnVisTypes.metricsDescription": "对时间序列数据执行高级分析。",
"visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB",
"visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "存储桶:{lastBucketDate}",
"visTypeTimeseries.lastValueModeIndicator.lastValue": "最后值",
@ -8739,7 +8736,6 @@
"visTypeVega.mapView.resettingPropertyToMaxValueWarningMessage": "将 {name} 重置为 {max}",
"visTypeVega.mapView.resettingPropertyToMinValueWarningMessage": "将 {name} 重置为 {min}",
"visTypeVega.type.vegaDescription": "使用 Vega 创建新的可视化类型。",
"visTypeVega.type.vegaNote": "需要有 Vega 语法知识。",
"visTypeVega.type.vegaTitleInWizard": "定制可视化",
"visTypeVega.urlParser.dataUrlRequiresUrlParameterInFormErrorMessage": "{dataUrlParam} 需要“{formLink}”形式的 {urlParam} 参数",
"visTypeVega.urlParser.urlShouldHaveQuerySubObjectWarningMessage": "使用 {urlObject} 应具有 {subObjectName} 子对象",
@ -8924,7 +8920,6 @@
"visualizations.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "必须提供 indexPattern 或 savedSearchId",
"visualizations.createVisualization.noVisTypeErrorMessage": "必须提供有效的可视化类型",
"visualizations.dataView.label": "数据视图",
"visualizations.deprecatedTag": "(已过时)",
"visualizations.displayName": "可视化",
"visualizations.editor.createBreadcrumb": "创建",
"visualizations.editor.defaultEditBreadcrumbText": "编辑可视化",
@ -8976,24 +8971,16 @@
"visualizations.newChart.libraryMode.new": "新",
"visualizations.newChart.libraryMode.old": "以前",
"visualizations.newGaugeChart.notificationMessage": "新的仪表盘图表库尚不支持拆分图表聚合。{conditionalMessage}",
"visualizations.newVisWizard.aggBasedGroupDescription": "使用我们的经典可视化库,基于聚合创建图表。",
"visualizations.newVisWizard.aggBasedGroupTitle": "基于聚合",
"visualizations.newVisWizard.chooseSourceTitle": "选择源",
"visualizations.newVisWizard.experimentalTitle": "技术预览",
"visualizations.newVisWizard.experimentalTooltip": "此功能处于技术预览状态在未来版本中可能会更改或完全移除。Elastic 将努力修复任何问题,但处于技术预览状态的功能不受正式 GA 功能支持 SLA 的约束。",
"visualizations.newVisWizard.exploreOptionLinkText": "浏览选项",
"visualizations.newVisWizard.filterVisTypeAriaLabel": "筛留可视化类型",
"visualizations.newVisWizard.goBackLink": "选择不同的可视化",
"visualizations.newVisWizard.helpTextAriaLabel": "通过为该可视化选择类型,开始创建您的可视化。按 Esc 键关闭此模式。按 Tab 键继续。",
"visualizations.newVisWizard.learnMoreText": "希望了解详情?",
"visualizations.newVisWizard.newVisTypeTitle": "新建{visTypeName}",
"visualizations.newVisWizard.readDocumentationLink": "阅读文档",
"visualizations.newVisWizard.resultsFound": "{resultCount, plural, other {类型}}已找到",
"visualizations.newVisWizard.searchSelection.notFoundLabel": "未找到匹配的索引或已保存搜索。",
"visualizations.newVisWizard.searchSelection.savedObjectType.dataView": "数据视图",
"visualizations.newVisWizard.searchSelection.savedObjectType.search": "已保存搜索",
"visualizations.newVisWizard.title": "新建可视化",
"visualizations.newVisWizard.toolsGroupTitle": "工具",
"visualizations.noDataView.label": "数据视图",
"visualizations.noMatchRoute.bannerText": "Visualize 应用程序无法识别此路由:{route}。",
"visualizations.noMatchRoute.bannerTitleText": "未找到页面",
@ -25555,8 +25542,6 @@
"xpack.lens.unknownDatasourceType.shortMessage": "数据源类型未知",
"xpack.lens.unknownVisType.longMessage": "无法解析可视化类型 {visType}。",
"xpack.lens.unknownVisType.shortMessage": "可视化类型未知",
"xpack.lens.visTypeAlias.description": "使用拖放编辑器创建可视化。随时在可视化类型之间切换。",
"xpack.lens.visTypeAlias.note": "适合绝大多数用户。",
"xpack.lens.visTypeAlias.title": "Lens",
"xpack.lens.visTypeAlias.type": "Lens",
"xpack.lens.visualizeAggBasedLegend": "可视化基于聚合的图表",

View file

@ -32,14 +32,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
}
await testSubjects.click('savedObjectTitle');
};
// creates a simple markdown vis with a tag provided.
// creates a simple tsvb vis with a tag provided.
const createSimpleMarkdownVis = async (opts: Record<string, string>) => {
const { visName, visText, tagName } = opts;
const { visName, tagName } = opts;
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickMarkdownWidget();
await PageObjects.visEditor.setMarkdownTxt(visText);
await PageObjects.visEditor.clickGo();
await PageObjects.visualize.clickVisualBuilder();
await PageObjects.visualize.ensureSavePanelOpen();
await PageObjects.visualize.setSaveModalValues(visName, {
@ -150,10 +148,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickMarkdownWidget();
await PageObjects.visEditor.setMarkdownTxt('Just some markdown');
await PageObjects.visEditor.clickGo();
await PageObjects.visualize.clickVisualBuilder();
await PageObjects.visualize.ensureSavePanelOpen();
await PageObjects.visualize.setSaveModalValues('vis-with-new-tag', {
saveAsNew: false,