mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
* Fix success message to show correct language based on timeline type
* Fix translation problems
Co-authored-by: Kristof-Pierre Cummings <kristofpierre.cummings@elastic.co>
(cherry picked from commit 91a35c20ce
)
Co-authored-by: Kristof C <kpac.ja@gmail.com>
This commit is contained in:
parent
1939432623
commit
d551f02ca4
10 changed files with 75 additions and 18 deletions
|
@ -180,9 +180,9 @@ const FlyoutHeaderPanelComponent: React.FC<FlyoutHeaderPanelProps> = ({ timeline
|
|||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip content={i18n.CLOSE_TIMELINE}>
|
||||
<EuiToolTip content={i18n.CLOSE_TIMELINE_OR_TEMPLATE(timelineType === 'default')}>
|
||||
<EuiButtonIcon
|
||||
aria-label={i18n.CLOSE_TIMELINE}
|
||||
aria-label={i18n.CLOSE_TIMELINE_OR_TEMPLATE(timelineType === 'default')}
|
||||
data-test-subj="close-timeline"
|
||||
iconType="cross"
|
||||
onClick={handleClose}
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const CLOSE_TIMELINE = i18n.translate(
|
||||
'xpack.securitySolution.timeline.flyout.header.closeTimelineButtonLabel',
|
||||
{
|
||||
defaultMessage: 'Close timeline',
|
||||
}
|
||||
);
|
||||
export const CLOSE_TIMELINE_OR_TEMPLATE = (isTimeline: boolean) =>
|
||||
i18n.translate('xpack.securitySolution.timeline.flyout.header.closeTimelineButtonLabel', {
|
||||
defaultMessage: 'Close {isTimeline, select, true {timeline} false {template}}',
|
||||
values: {
|
||||
isTimeline,
|
||||
},
|
||||
});
|
||||
|
||||
export const UNSAVED = i18n.translate('xpack.securitySolution.timeline.properties.unsavedLabel', {
|
||||
defaultMessage: 'Unsaved',
|
||||
|
|
|
@ -11,9 +11,19 @@ import React from 'react';
|
|||
|
||||
import AddToTimelineButton, { ADD_TO_TIMELINE_KEYBOARD_SHORTCUT } from './add_to_timeline';
|
||||
import { DataProvider, IS_OPERATOR } from '../../../../common/types';
|
||||
import { useDeepEqualSelector } from '../../../hooks/use_selector';
|
||||
import { TestProviders } from '../../../mock';
|
||||
import * as i18n from './translations';
|
||||
|
||||
const mockAddSuccess = jest.fn();
|
||||
jest.mock('../../../hooks/use_app_toasts', () => ({
|
||||
useAppToasts: () => ({
|
||||
addSuccess: mockAddSuccess,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('../../../hooks/use_selector');
|
||||
|
||||
const mockDispatch = jest.fn();
|
||||
jest.mock('react-redux', () => {
|
||||
const originalModule = jest.requireActual('react-redux');
|
||||
|
@ -72,6 +82,7 @@ const providerB: DataProvider = {
|
|||
describe('add to timeline', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ timelineType: 'default' });
|
||||
});
|
||||
|
||||
const field = 'user.name';
|
||||
|
@ -369,4 +380,32 @@ describe('add to timeline', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('it shows the appropriate text based on timeline type', () => {
|
||||
test('Add success is called with "timeline" if timeline type is timeline', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<AddToTimelineButton dataProvider={providerA} field={field} ownFocus={false} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
|
||||
expect(mockAddSuccess).toBeCalledWith('Added a to timeline');
|
||||
});
|
||||
|
||||
test('Add success is called with "template" if timeline type is template', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ timelineType: 'template' });
|
||||
|
||||
render(
|
||||
<TestProviders>
|
||||
<AddToTimelineButton dataProvider={providerA} field={field} ownFocus={false} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
|
||||
expect(mockAddSuccess).toBeCalledWith('Added a to template');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,10 +9,12 @@ import React, { useCallback, useEffect, useMemo } from 'react';
|
|||
import { EuiContextMenuItem, EuiButtonEmpty, EuiButtonIcon, EuiToolTip } from '@elastic/eui';
|
||||
import { DraggableId } from 'react-beautiful-dnd';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import { stopPropagationAndPreventDefault } from '../../../../common/utils/accessibility';
|
||||
import { DataProvider, TimelineId } from '../../../../common/types';
|
||||
import { useDeepEqualSelector } from '../../../hooks/use_selector';
|
||||
import { tGridSelectors } from '../../../types';
|
||||
import { TooltipWithKeyboardShortcut } from '../../tooltip_with_keyboard_shortcut';
|
||||
import { getAdditionalScreenReaderOnlyContext } from '../utils';
|
||||
import { useAddToTimeline } from '../../../hooks/use_add_to_timeline';
|
||||
|
@ -67,6 +69,12 @@ const AddToTimelineButton: React.FC<AddToTimelineButtonProps> = React.memo(
|
|||
const dispatch = useDispatch();
|
||||
const { addSuccess } = useAppToasts();
|
||||
const startDragToTimeline = useGetHandleStartDragToTimeline({ draggableId, field });
|
||||
const getTGrid = tGridSelectors.getTGridByIdSelector();
|
||||
|
||||
const { timelineType } = useDeepEqualSelector((state) => {
|
||||
return getTGrid(state, TimelineId.active);
|
||||
});
|
||||
|
||||
const handleStartDragToTimeline = useCallback(() => {
|
||||
if (draggableId != null) {
|
||||
startDragToTimeline();
|
||||
|
@ -80,7 +88,9 @@ const AddToTimelineButton: React.FC<AddToTimelineButtonProps> = React.memo(
|
|||
dataProvider: provider,
|
||||
})
|
||||
);
|
||||
addSuccess(i18n.ADDED_TO_TIMELINE_MESSAGE(provider.name));
|
||||
addSuccess(
|
||||
i18n.ADDED_TO_TIMELINE_OR_TEMPLATE_MESSAGE(provider.name, timelineType === 'default')
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -88,7 +98,15 @@ const AddToTimelineButton: React.FC<AddToTimelineButtonProps> = React.memo(
|
|||
if (onClick != null) {
|
||||
onClick();
|
||||
}
|
||||
}, [addSuccess, onClick, dataProvider, dispatch, draggableId, startDragToTimeline]);
|
||||
}, [
|
||||
addSuccess,
|
||||
dataProvider,
|
||||
dispatch,
|
||||
draggableId,
|
||||
onClick,
|
||||
startDragToTimeline,
|
||||
timelineType,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ownFocus) {
|
||||
|
|
|
@ -11,8 +11,8 @@ export const ADD_TO_TIMELINE = i18n.translate('xpack.timelines.hoverActions.addT
|
|||
defaultMessage: 'Add to timeline investigation',
|
||||
});
|
||||
|
||||
export const ADDED_TO_TIMELINE_MESSAGE = (fieldOrValue: string) =>
|
||||
export const ADDED_TO_TIMELINE_OR_TEMPLATE_MESSAGE = (fieldOrValue: string, isTimeline: boolean) =>
|
||||
i18n.translate('xpack.timelines.hoverActions.addToTimeline.addedFieldMessage', {
|
||||
values: { fieldOrValue },
|
||||
defaultMessage: `Added {fieldOrValue} to timeline`,
|
||||
values: { fieldOrValue, isTimeline },
|
||||
defaultMessage: `Added {fieldOrValue} to {isTimeline, select, true {timeline} false {template}}`,
|
||||
});
|
||||
|
|
|
@ -53,6 +53,7 @@ export const mockGlobalState: TimelineState = {
|
|||
queryFields: [],
|
||||
selectAll: false,
|
||||
title: 'Events',
|
||||
timelineType: 'default',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1588,4 +1588,5 @@ export const mockTgridModel: TGridModel = {
|
|||
],
|
||||
title: 'Test rule',
|
||||
version: '1',
|
||||
timelineType: 'default',
|
||||
};
|
||||
|
|
|
@ -84,6 +84,7 @@ export interface TGridModel extends TGridModelSettings {
|
|||
/** Events selected on this timeline -- eventId to TimelineNonEcsData[] mapping of data required for bulk actions **/
|
||||
selectedEventIds: Record<string, TimelineNonEcsData[]>;
|
||||
savedObjectId: string | null;
|
||||
timelineType: 'default' | 'template';
|
||||
version: string | null;
|
||||
initialized?: boolean;
|
||||
}
|
||||
|
|
|
@ -23844,7 +23844,6 @@
|
|||
"xpack.securitySolution.timeline.failSearchDescription": "検索を実行できませんでした",
|
||||
"xpack.securitySolution.timeline.fieldTooltip": "フィールド",
|
||||
"xpack.securitySolution.timeline.file.fromOriginalPathDescription": "元のパスから",
|
||||
"xpack.securitySolution.timeline.flyout.header.closeTimelineButtonLabel": "タイムラインを閉じる",
|
||||
"xpack.securitySolution.timeline.flyout.pane.removeColumnButtonLabel": "列を削除",
|
||||
"xpack.securitySolution.timeline.flyout.pane.timelinePropertiesAriaLabel": "タイムラインのプロパティ",
|
||||
"xpack.securitySolution.timeline.flyoutTimelineTemplateLabel": "タイムラインテンプレート",
|
||||
|
@ -25228,7 +25227,6 @@
|
|||
"xpack.timelines.footer.rowsPerPageLabel": "ページごとの行:{rowsPerPage}",
|
||||
"xpack.timelines.footer.totalCountOfEvents": "イベント",
|
||||
"xpack.timelines.hoverActions.addToTimeline": "タイムライン調査に追加",
|
||||
"xpack.timelines.hoverActions.addToTimeline.addedFieldMessage": "{fieldOrValue}をタイムラインに追加しました",
|
||||
"xpack.timelines.hoverActions.columnToggleLabel": "表の{field}列を切り替える",
|
||||
"xpack.timelines.hoverActions.fieldLabel": "フィールド",
|
||||
"xpack.timelines.hoverActions.filterIn": "フィルタリング",
|
||||
|
|
|
@ -24241,7 +24241,6 @@
|
|||
"xpack.securitySolution.timeline.failSearchDescription": "无法运行搜索",
|
||||
"xpack.securitySolution.timeline.fieldTooltip": "字段",
|
||||
"xpack.securitySolution.timeline.file.fromOriginalPathDescription": "从其原始路径",
|
||||
"xpack.securitySolution.timeline.flyout.header.closeTimelineButtonLabel": "关闭时间线",
|
||||
"xpack.securitySolution.timeline.flyout.pane.removeColumnButtonLabel": "移除列",
|
||||
"xpack.securitySolution.timeline.flyout.pane.timelinePropertiesAriaLabel": "时间线属性",
|
||||
"xpack.securitySolution.timeline.flyoutTimelineTemplateLabel": "时间线模板",
|
||||
|
@ -25661,7 +25660,6 @@
|
|||
"xpack.timelines.footer.rowsPerPageLabel": "每页行数:{rowsPerPage}",
|
||||
"xpack.timelines.footer.totalCountOfEvents": "事件",
|
||||
"xpack.timelines.hoverActions.addToTimeline": "添加到时间线调查",
|
||||
"xpack.timelines.hoverActions.addToTimeline.addedFieldMessage": "已将 {fieldOrValue} 添加到时间线",
|
||||
"xpack.timelines.hoverActions.columnToggleLabel": "在表中切换 {field} 列",
|
||||
"xpack.timelines.hoverActions.fieldLabel": "字段",
|
||||
"xpack.timelines.hoverActions.filterIn": "筛选",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue