Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Discover] Enable tags for saved searches #136162

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
7a3f383
[Discover] Add initial support for tags to saved search modal
davismcphee Jul 11, 2022
b9da6c0
[Discover] Add tags to savedSearch types
davismcphee Jul 12, 2022
cfba008
[Discover] Finish initial support for adding tags to saved searches
davismcphee Jul 12, 2022
ed5e84b
[Discover] Start to convert saved object finder to a table in order t…
davismcphee Jul 14, 2022
087c12e
[Discover] Add support for displaying saved search tags in open searc…
davismcphee Jul 14, 2022
36f8724
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Jul 14, 2022
c3c1a93
[Discover] Continue support for tags in saved object finder
davismcphee Jul 18, 2022
5ca6f1f
[Discover] Clean up saved object finder
davismcphee Jul 18, 2022
6d04555
[Discover] Finish initial support for tags in saved object finder
davismcphee Jul 18, 2022
4617afc
[Discover] Update SimpleSavedObject constructor to SimpleSavedObjectImpl
davismcphee Aug 2, 2022
15c41fc
[Discover] Remove orig files
davismcphee Aug 2, 2022
69437a4
[Discover] Saved search tag type registration and telemetry
davismcphee Aug 2, 2022
84cc0fc
[Discover] Create new saved_objects_finder plugin
davismcphee Aug 3, 2022
813c3d1
[Discover] Continue work creating saved_objects_finder plugin
davismcphee Aug 3, 2022
9783970
[Discover] Revert some changes in saved_objects
davismcphee Aug 3, 2022
743d072
[Discover] Revert some changes in saved_objects again
davismcphee Aug 3, 2022
68b59b9
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Aug 3, 2022
878cd0d
[Discover] Update saved_objects_finder i18n keys
davismcphee Aug 3, 2022
5f2bda3
[Discover] Update docs
davismcphee Aug 3, 2022
fa1617e
[Discover] Add plugins to saved_object_finder and fix broken types
davismcphee Aug 3, 2022
efa5eb4
[Discover] Finish creating saved_objects_finder plugin and use it in …
davismcphee Aug 3, 2022
4cff26a
[Discover] Update SavedObjectFinderProps type export, and update x-pa…
davismcphee Aug 3, 2022
8b0ffd3
[Discover] Fix broken jest tests
davismcphee Aug 3, 2022
b68d6f8
[Discover] Update saved_objects_finder API
davismcphee Aug 4, 2022
78f2930
[Discover] Remove unused translations
davismcphee Aug 4, 2022
68aa25a
[Discover] Fix issue with initial saved object finder fetch
davismcphee Aug 5, 2022
f834bc3
[Discover] Fix some of the saved object finder jest tests
davismcphee Aug 5, 2022
6590a5f
[Discover] Clean up finder after merge
davismcphee Aug 11, 2022
7f0dd2e
[Discover] Fixing saved_object_finder.tsx
davismcphee Aug 12, 2022
65412a9
[Discover] Add savedObjectsTaggingOss reference to saved_search plugin
davismcphee Aug 12, 2022
90060c6
[Discover] Fix broken open_search_panel test
davismcphee Aug 12, 2022
8acfb54
[Discover] Removed allowed types from saved object finder
davismcphee Aug 15, 2022
cdab767
[Discover] Removing type column when there's only one saved object ty…
davismcphee Aug 15, 2022
866ecfd
[Discover] Fix issue where visible types were entirely removed, fixed…
davismcphee Aug 15, 2022
4bf1a41
[Discover] Add showFilter to open_search_panel's saved_objects_finder…
davismcphee Aug 15, 2022
35bb65b
[Discover] Fix remaining saved_object_finder Jest tests
davismcphee Aug 15, 2022
de53a5f
[Discover] Update snapshot
davismcphee Aug 15, 2022
ad2e4aa
[Discover] Fix failing functional tests
davismcphee Aug 16, 2022
4839040
[Discover] Add tagging Jest tests for saved_objects_finder
davismcphee Aug 17, 2022
0b284cf
[Discover] Fix small bugs in saved_object_finder, update Jest tests, …
davismcphee Aug 18, 2022
107f796
[Discover] Removed unused variable in functional test
davismcphee Aug 18, 2022
9bd3531
[Discover] Update Discover Jest tests with tagging tests
davismcphee Aug 22, 2022
8c4c937
[Discover] Remove translations
davismcphee Aug 22, 2022
a99080d
[Discover] Updating saved_objects_finder to use static export vs prec…
davismcphee Aug 22, 2022
7bbf3ea
[Discover] Move saved_object_finder service deps to a 'services' prop…
davismcphee Aug 22, 2022
a978d38
[Discover] Fix broken Jest test
davismcphee Aug 22, 2022
83d2c27
[Discover] Fix broken Jest test from merge
davismcphee Aug 24, 2022
d236898
[Discover] Fix discover tags integration test description
davismcphee Aug 24, 2022
2b49c72
Merge branch 'main' into discover-feature-saved-search-tags
kibanamachine Aug 29, 2022
a1bad58
- Updated tags prop to be `string | undefined`
davismcphee Aug 30, 2022
5425a68
[Discover] Fixed LISTING_LIMIT_SETTING import
davismcphee Aug 30, 2022
16fbee2
[Discover] Revert tags saving change that introduced a bug
davismcphee Aug 30, 2022
7394aea
Merge branch 'main' into discover-feature-saved-search-tags
davismcphee Aug 30, 2022
9325807
[CI] Auto-commit changed files from 'node scripts/build_plugin_list_d…
kibanamachine Aug 30, 2022
6df2a96
[Discover] Try again to fix LISTING_LIMIT_SETTINGS import
davismcphee Aug 30, 2022
c11454d
Merge branch 'discover-feature-saved-search-tags' of https://github.c…
davismcphee Aug 30, 2022
a196963
[Discover] Fix failing snapshot
davismcphee Aug 31, 2022
16d3266
Merge branch 'main' into discover-feature-saved-search-tags
davismcphee Aug 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
/x-pack/plugins/graph/ @elastic/kibana-data-discovery
/x-pack/test/functional/apps/graph @elastic/kibana-data-discovery
/src/plugins/unified_field_list/ @elastic/kibana-data-discovery
/src/plugins/saved_objects_finder/ @elastic/kibana-data-discovery

# Vis Editors
/x-pack/plugins/lens/ @elastic/kibana-vis-editors
Expand Down
1 change: 1 addition & 0 deletions .i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"newsfeed": "src/plugins/newsfeed",
"presentationUtil": "src/plugins/presentation_util",
"savedObjects": "src/plugins/saved_objects",
"savedObjectsFinder": "src/plugins/saved_objects_finder",
"savedObjectsManagement": "src/plugins/saved_objects_management",
"server": "src/legacy/server",
"share": "src/plugins/share",
Expand Down
4 changes: 4 additions & 0 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ Content is fetched from the remote (https://feeds.elastic.co) once a day, with p
|NOTE: This plugin is deprecated and will be removed in 8.0. See https://github.com/elastic/kibana/issues/46435 for more information.


|{kib-repo}blob/{branch}/src/plugins/saved_objects_finder/README.md[savedObjectsFinder]
|The savedObjectsFinder plugin exposes a UI for finding saved objects on the client side.


|{kib-repo}blob/{branch}/src/plugins/saved_objects_management/README.md[savedObjectsManagement]
|The savedObjectsManagement plugin manages the Saved Objects management section.

Expand Down
1 change: 1 addition & 0 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,4 @@ pageLoadAssetSize:
kubernetesSecurity: 77234
threatIntelligence: 29195
files: 22673
savedObjectsFinder: 21691
11 changes: 10 additions & 1 deletion src/plugins/discover/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,20 @@
"navigation",
"uiActions",
"savedObjects",
"savedObjectsFinder",
"savedObjectsManagement",
"dataViewFieldEditor",
"dataViewEditor",
"expressions"
],
"optionalPlugins": ["home", "share", "usageCollection", "spaces", "triggersActionsUi"],
"optionalPlugins": [
"home",
"share",
"usageCollection",
"spaces",
"triggersActionsUi",
"savedObjectsTaggingOss"
],
"requiredBundles": ["kibanaUtils", "kibanaReact", "dataViews", "unifiedSearch", "savedSearch"],
"extraPublicDirs": ["common"],
"owner": {
Expand Down
1 change: 1 addition & 0 deletions src/plugins/discover/public/__mocks__/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,5 @@ export const discoverServiceMock = {
addWarning: jest.fn(),
},
expressions: expressionsPlugin,
savedObjectsTagging: {},
} as unknown as DiscoverServices;

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,160 @@
* Side Public License, v 1.
*/

import { showSaveModal } from '@kbn/saved-objects-plugin/public';
import * as savedObjectsPlugin from '@kbn/saved-objects-plugin/public';
jest.mock('@kbn/saved-objects-plugin/public');

jest.mock('../../utils/persist_saved_search', () => ({
persistSavedSearch: jest.fn(() => ({ id: 'the-saved-search-id' })),
}));
import { onSaveSearch } from './on_save_search';
import { dataViewMock } from '../../../../__mocks__/data_view';
import { savedSearchMock } from '../../../../__mocks__/saved_search';
import { DiscoverServices } from '../../../../build_services';
import { GetStateReturn } from '../../services/discover_state';
import { i18nServiceMock } from '@kbn/core/public/mocks';
import { ReactElement } from 'react';
import { discoverServiceMock } from '../../../../__mocks__/services';
import * as persistSavedSearchUtils from '../../utils/persist_saved_search';
import { SavedSearch } from '@kbn/saved-search-plugin/public';

describe('onSaveSearch', () => {
it('should call showSaveModal', async () => {
const serviceMock = {
core: {
i18n: i18nServiceMock.create(),
},
} as unknown as DiscoverServices;
const stateMock = {
appStateContainer: {
getState: () => ({
rowsPerPage: 250,
}),
},
} as unknown as GetStateReturn;

test('onSaveSearch', async () => {
const serviceMock = {
core: {
i18n: i18nServiceMock.create(),
},
} as unknown as DiscoverServices;
const stateMock = {
appStateContainer: {
getState: () => ({
rowsPerPage: 250,
}),
},
} as unknown as GetStateReturn;
await onSaveSearch({
dataView: dataViewMock,
navigateTo: jest.fn(),
savedSearch: savedSearchMock,
services: serviceMock,
state: stateMock,
});

expect(savedObjectsPlugin.showSaveModal).toHaveBeenCalled();
});

await onSaveSearch({
dataView: dataViewMock,
navigateTo: jest.fn(),
savedSearch: savedSearchMock,
services: serviceMock,
state: stateMock,
it('should pass tags to the save modal', async () => {
const serviceMock = discoverServiceMock;
const stateMock = {
appStateContainer: {
getState: () => ({
rowsPerPage: 250,
}),
},
} as unknown as GetStateReturn;
let saveModal: ReactElement | undefined;
jest.spyOn(savedObjectsPlugin, 'showSaveModal').mockImplementationOnce((modal) => {
saveModal = modal;
});
await onSaveSearch({
dataView: dataViewMock,
navigateTo: jest.fn(),
savedSearch: {
...savedSearchMock,
tags: ['tag1', 'tag2'],
},
services: serviceMock,
state: stateMock,
});
expect(saveModal?.props.tags).toEqual(['tag1', 'tag2']);
});

expect(showSaveModal).toHaveBeenCalled();
it('should update the saved search tags', async () => {
const serviceMock = discoverServiceMock;
const stateMock = {
appStateContainer: {
getState: () => ({
rowsPerPage: 250,
}),
},
resetInitialAppState: jest.fn(),
} as unknown as GetStateReturn;
let saveModal: ReactElement | undefined;
jest.spyOn(savedObjectsPlugin, 'showSaveModal').mockImplementationOnce((modal) => {
saveModal = modal;
});
let savedSearch: SavedSearch = {
...savedSearchMock,
tags: ['tag1', 'tag2'],
};
await onSaveSearch({
dataView: dataViewMock,
navigateTo: jest.fn(),
savedSearch,
services: serviceMock,
state: stateMock,
});
expect(savedSearch.tags).toEqual(['tag1', 'tag2']);
jest
.spyOn(persistSavedSearchUtils, 'persistSavedSearch')
.mockImplementationOnce((newSavedSearch, _) => {
savedSearch = newSavedSearch;
return Promise.resolve({ id: newSavedSearch.id });
});
saveModal?.props.onSave({
newTitle: savedSearch.title,
newCopyOnSave: false,
newDescription: savedSearch.description,
newTags: ['tag3', 'tag4'],
isTitleDuplicateConfirmed: false,
onTitleDuplicate: jest.fn(),
});
expect(savedSearch.tags).toEqual(['tag3', 'tag4']);
});

it('should not update tags if savedObjectsTagging is undefined', async () => {
const serviceMock = discoverServiceMock;
const stateMock = {
appStateContainer: {
getState: () => ({
rowsPerPage: 250,
}),
},
resetInitialAppState: jest.fn(),
} as unknown as GetStateReturn;
let saveModal: ReactElement | undefined;
jest.spyOn(savedObjectsPlugin, 'showSaveModal').mockImplementationOnce((modal) => {
saveModal = modal;
});
let savedSearch: SavedSearch = {
...savedSearchMock,
tags: ['tag1', 'tag2'],
};
await onSaveSearch({
dataView: dataViewMock,
navigateTo: jest.fn(),
savedSearch,
services: {
...serviceMock,
savedObjectsTagging: undefined,
},
state: stateMock,
});
expect(savedSearch.tags).toEqual(['tag1', 'tag2']);
jest
.spyOn(persistSavedSearchUtils, 'persistSavedSearch')
.mockImplementationOnce((newSavedSearch, _) => {
savedSearch = newSavedSearch;
return Promise.resolve({ id: newSavedSearch.id });
});
saveModal?.props.onSave({
newTitle: savedSearch.title,
newCopyOnSave: false,
newDescription: savedSearch.description,
newTags: ['tag3', 'tag4'],
isTitleDuplicateConfirmed: false,
onTitleDuplicate: jest.fn(),
});
expect(savedSearch.tags).toEqual(['tag1', 'tag2']);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -106,31 +106,38 @@ export async function onSaveSearch({
onClose?: () => void;
onSaveCb?: () => void;
}) {
const { uiSettings } = services;
const { uiSettings, savedObjectsTagging } = services;
const onSave = async ({
newTitle,
newCopyOnSave,
newTimeRestore,
newDescription,
newTags,
isTitleDuplicateConfirmed,
onTitleDuplicate,
}: {
newTitle: string;
newTimeRestore: boolean;
newCopyOnSave: boolean;
newDescription: string;
newTags: string[];
isTitleDuplicateConfirmed: boolean;
onTitleDuplicate: () => void;
}) => {
const currentTitle = savedSearch.title;
const currentTimeRestore = savedSearch.timeRestore;
const currentRowsPerPage = savedSearch.rowsPerPage;
const currentDescription = savedSearch.description;
davismcphee marked this conversation as resolved.
Show resolved Hide resolved
const currentTags = savedSearch.tags;
savedSearch.title = newTitle;
savedSearch.description = newDescription;
savedSearch.timeRestore = newTimeRestore;
savedSearch.rowsPerPage = uiSettings.get(DOC_TABLE_LEGACY)
? currentRowsPerPage
: state.appStateContainer.getState().rowsPerPage;
if (savedObjectsTagging) {
savedSearch.tags = newTags;
}
const saveOptions: SaveSavedSearchOptions = {
onTitleDuplicate,
copyOnSave: newCopyOnSave,
Expand All @@ -151,6 +158,10 @@ export async function onSaveSearch({
savedSearch.title = currentTitle;
savedSearch.timeRestore = currentTimeRestore;
savedSearch.rowsPerPage = currentRowsPerPage;
savedSearch.description = currentDescription;
if (savedObjectsTagging) {
savedSearch.tags = currentTags;
}
} else {
state.resetInitialAppState();
}
Expand All @@ -160,10 +171,12 @@ export async function onSaveSearch({

const saveModal = (
<SaveSearchObjectModal
services={services}
title={savedSearch.title ?? ''}
showCopyOnSave={!!savedSearch.id}
description={savedSearch.description}
timeRestore={savedSearch.timeRestore}
tags={savedSearch.tags ?? []}
onSave={onSave}
onClose={onClose ?? (() => {})}
/>
Expand All @@ -172,23 +185,46 @@ export async function onSaveSearch({
}

const SaveSearchObjectModal: React.FC<{
services: DiscoverServices;
title: string;
showCopyOnSave: boolean;
description?: string;
timeRestore?: boolean;
onSave: (props: OnSaveProps & { newTimeRestore: boolean }) => void;
tags: string[];
onSave: (props: OnSaveProps & { newTimeRestore: boolean; newTags: string[] }) => void;
onClose: () => void;
}> = ({ title, description, showCopyOnSave, timeRestore: savedTimeRestore, onSave, onClose }) => {
}> = ({
services,
title,
description,
tags,
showCopyOnSave,
timeRestore: savedTimeRestore,
onSave,
onClose,
}) => {
const { savedObjectsTagging } = services;
const [timeRestore, setTimeRestore] = useState<boolean>(savedTimeRestore || false);
const [currentTags, setCurrentTags] = useState(tags);

const onModalSave = (params: OnSaveProps) => {
onSave({
...params,
newTimeRestore: timeRestore,
newTags: currentTags,
});
};

const options = (
const tagSelector = savedObjectsTagging ? (
<savedObjectsTagging.ui.components.SavedObjectSaveModalTagSelector
initialSelection={currentTags}
onTagsSelected={(newTags) => {
setCurrentTags(newTags);
}}
/>
) : undefined;

const timeSwitch = (
<EuiFormRow
helpText={
<FormattedMessage
Expand All @@ -211,6 +247,15 @@ const SaveSearchObjectModal: React.FC<{
</EuiFormRow>
);

const options = tagSelector ? (
<>
{tagSelector}
{timeSwitch}
</>
) : (
timeSwitch
);

return (
<SavedObjectSaveModal
title={title}
Expand Down
Loading