diff --git a/src/platform/plugins/shared/dashboard/kibana.jsonc b/src/platform/plugins/shared/dashboard/kibana.jsonc index 9d47ab95c8872..d5ba75b11db10 100644 --- a/src/platform/plugins/shared/dashboard/kibana.jsonc +++ b/src/platform/plugins/shared/dashboard/kibana.jsonc @@ -35,6 +35,7 @@ "home", "spaces", "savedObjectsTaggingOss", + "savedObjectsTagging", "screenshotMode", "usageCollection", "taskManager", @@ -51,4 +52,4 @@ "savedObjects" ] } -} \ No newline at end of file +} diff --git a/x-pack/platform/plugins/shared/fleet/server/services/epm/kibana/assets/saved_object.test.ts b/x-pack/platform/plugins/shared/fleet/server/services/epm/kibana/assets/saved_object.test.ts index 8ac5703265075..3a018819e2b19 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/epm/kibana/assets/saved_object.test.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/epm/kibana/assets/saved_object.test.ts @@ -19,6 +19,9 @@ describe('getSpaceAwareSaveobjectsClients', () => { const mockedSavedObjectTagging = { createInternalAssignmentService: jest.fn(), createTagClient: jest.fn(), + getTagsFromReferences: jest.fn(), + convertTagNameToId: jest.fn(), + replaceTagReferences: jest.fn(), }; const scoppedSoClient = savedObjectsClientMock.create(); diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/common/index.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/common/index.ts index d883ac78c7c05..12cd30e69fd7f 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/common/index.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/common/index.ts @@ -17,3 +17,12 @@ export { tagNameMaxLength, tagDescriptionMaxLength, } from './validation'; +export { + convertTagNameToId, + getObjectTags, + getTag, + getTagIdsFromReferences, + getTagsFromReferences, + replaceTagReferences, + tagIdToReference, +} from './references'; diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.test.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.test.ts index cc8093a5cebb2..d5e9d6c7b9f09 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.test.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.test.ts @@ -5,8 +5,16 @@ * 2.0. */ -import { SavedObjectReference } from '@kbn/core/types'; -import { tagIdToReference, replaceTagReferences, updateTagReferences } from './references'; +import type { SavedObject, SavedObjectReference } from '@kbn/core/server'; +import { + convertTagNameToId, + getObjectTags, + getTag, + getTagIdsFromReferences, + replaceTagReferences, + tagIdToReference, + updateTagReferences, +} from './references'; const ref = (type: string, id: string): SavedObjectReference => ({ id, @@ -16,6 +24,80 @@ const ref = (type: string, id: string): SavedObjectReference => ({ const tagRef = (id: string) => ref('tag', id); +const createObject = (refs: SavedObjectReference[]): SavedObject => { + return { + type: 'unkown', + id: 'irrelevant', + references: refs, + } as SavedObject; +}; + +const createTag = (id: string, name: string = id) => ({ + id, + name, + description: `desc ${id}`, + color: '#FFCC00', + managed: false, +}); + +const tag1 = createTag('id-1', 'name-1'); +const tag2 = createTag('id-2', 'name-2'); +const tag3 = createTag('id-3', 'name-3'); + +const allTags = [tag1, tag2, tag3]; + +describe('convertTagNameToId', () => { + it('returns the id for the given tag name', () => { + expect(convertTagNameToId('name-2', allTags)).toBe('id-2'); + }); + + it('returns undefined if no tag was found', () => { + expect(convertTagNameToId('name-4', allTags)).toBeUndefined(); + }); +}); + +describe('getObjectTags', () => { + it('returns the tags for the tag references of the object', () => { + const { tags } = getObjectTags( + createObject([tagRef('id-1'), ref('dashboard', 'dash-1'), tagRef('id-3')]), + allTags + ); + + expect(tags).toEqual([tag1, tag3]); + }); + + it('returns the missing references for tags that were not found', () => { + const missingRef = tagRef('missing-tag'); + const refs = [tagRef('id-1'), ref('dashboard', 'dash-1'), missingRef]; + const { tags, missingRefs } = getObjectTags(createObject(refs), allTags); + + expect(tags).toEqual([tag1]); + expect(missingRefs).toEqual([missingRef]); + }); +}); + +describe('getTag', () => { + it('returns the tag for the given id', () => { + expect(getTag('id-2', allTags)).toEqual(tag2); + }); + it('returns undefined if no tag was found', () => { + expect(getTag('id-4', allTags)).toBeUndefined(); + }); +}); + +describe('getTagIdsFromReferences', () => { + it('returns the tag ids from the given references', () => { + expect( + getTagIdsFromReferences([ + tagRef('tag-1'), + ref('dashboard', 'dash-1'), + tagRef('tag-2'), + ref('lens', 'lens-1'), + ]) + ).toEqual(['tag-1', 'tag-2']); + }); +}); + describe('tagIdToReference', () => { it('returns a reference for given tag id', () => { expect(tagIdToReference('some-tag-id')).toEqual({ diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.ts index 4328f006307a7..ec53584881d07 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/common/references.ts @@ -6,8 +6,15 @@ */ import { uniq, intersection } from 'lodash'; -import { SavedObjectReference } from '@kbn/core/types'; +import type { + SavedObject, + SavedObjectReference, + SavedObjectsFindOptionsReference, +} from '@kbn/core/server'; import { tagSavedObjectTypeName } from './constants'; +import { Tag } from './types'; + +type SavedObjectReferenceLike = SavedObjectReference | SavedObjectsFindOptionsReference; /** * Create a {@link SavedObjectReference | reference} for given tag id. @@ -64,3 +71,43 @@ export const updateTagReferences = ({ return [...nonTagReferences, ...newTagIds.map(tagIdToReference)]; }; + +export const getTagsFromReferences = (references: SavedObjectReference[], allTags: Tag[]) => { + const tagReferences = references.filter((ref) => ref.type === tagSavedObjectTypeName); + + const foundTags: Tag[] = []; + const missingRefs: SavedObjectReference[] = []; + + tagReferences.forEach((ref) => { + const found = allTags.find((tag) => tag.id === ref.id); + if (found) { + foundTags.push(found); + } else { + missingRefs.push(ref); + } + }); + + return { + tags: foundTags, + missingRefs, + }; +}; + +export const convertTagNameToId = (tagName: string, allTags: Tag[]): string | undefined => { + const found = allTags.find((tag) => tag.name.toLowerCase() === tagName.toLowerCase()); + return found?.id; +}; + +export const getObjectTags = ( + object: { references: SavedObject['references'] }, + allTags: Tag[] +) => { + return getTagsFromReferences(object.references, allTags); +}; + +export const getTag = (tagId: string, allTags: Tag[]): Tag | undefined => { + return allTags.find(({ id }) => id === tagId); +}; +export const getTagIdsFromReferences = (references: SavedObjectReferenceLike[]): string[] => { + return references.filter((ref) => ref.type === tagSavedObjectTypeName).map(({ id }) => id); +}; diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/public/components/connected/tag_list.tsx b/x-pack/platform/plugins/shared/saved_objects_tagging/public/components/connected/tag_list.tsx index d3c65926fa00f..4ef099b3effd7 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/public/components/connected/tag_list.tsx +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/public/components/connected/tag_list.tsx @@ -10,10 +10,10 @@ import useObservable from 'react-use/lib/useObservable'; import type { SavedObjectReference } from '@kbn/core/types'; import type { TagListComponentProps } from '@kbn/saved-objects-tagging-oss-plugin/public'; import type { Tag, TagWithOptionalId } from '../../../common/types'; -import { getObjectTags } from '../../utils'; import { TagList } from '../base'; import type { ITagsCache } from '../../services'; import { byNameTagSorter } from '../../utils'; +import { getObjectTags } from '../../../common'; interface SavedObjectTagListProps { object: { references: SavedObjectReference[] }; diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/convert_name_to_reference.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/convert_name_to_reference.ts index 034005791d757..be6ab2cef1f1a 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/convert_name_to_reference.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/convert_name_to_reference.ts @@ -6,8 +6,8 @@ */ import { SavedObjectsTaggingApiUi } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import { convertTagNameToId } from '../../common'; import { ITagsCache } from '../services'; -import { convertTagNameToId } from '../utils'; export interface BuildConvertNameToReferenceOptions { cache: ITagsCache; diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/get_table_column_definition.tsx b/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/get_table_column_definition.tsx index ae9e96625eaa9..1f3a7769f44b3 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/get_table_column_definition.tsx +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/get_table_column_definition.tsx @@ -14,7 +14,8 @@ import { GetTableColumnDefinitionOptions, } from '@kbn/saved-objects-tagging-oss-plugin/public'; import { ITagsCache } from '../services'; -import { getTagsFromReferences, byNameTagSorter } from '../utils'; +import { byNameTagSorter } from '../utils'; +import { getTagsFromReferences } from '../../common'; export interface BuildGetTableColumnDefinitionOptions { components: SavedObjectsTaggingApiUiComponent; diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/index.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/index.ts index 635e2e5af0440..c8e6284b1023b 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/index.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/public/ui_api/index.ts @@ -11,10 +11,10 @@ import { ITagsCache, ITagInternalClient } from '../services'; import { StartServices } from '../types'; import { getTagIdsFromReferences, - updateTagsReferences, + replaceTagReferences, convertTagNameToId, getTag, -} from '../utils'; +} from '../../common'; import { getComponents } from './components'; import { buildGetTableColumnDefinition } from './get_table_column_definition'; import { buildGetSearchBarFilter } from './get_search_bar_filter'; @@ -51,7 +51,7 @@ export const getUiApi = ({ convertNameToReference: buildConvertNameToReference({ cache }), getTagIdsFromReferences, getTagIdFromName: (tagName: string) => convertTagNameToId(tagName, cache.getState()), - updateTagsReferences, + updateTagsReferences: replaceTagReferences, getTag: (tagId: string) => getTag(tagId, cache.getState()), getTagList, }; diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.test.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.test.ts index c076b615bdda3..7a5f3fce12972 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.test.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.test.ts @@ -5,14 +5,7 @@ * 2.0. */ -import { SavedObject, SavedObjectReference } from '@kbn/core/types'; -import { - getObjectTags, - convertTagNameToId, - byNameTagSorter, - getTagIdsFromReferences, - getTag, -} from './utils'; +import { byNameTagSorter } from './utils'; const createTag = (id: string, name: string = id) => ({ id, @@ -22,67 +15,6 @@ const createTag = (id: string, name: string = id) => ({ managed: false, }); -const ref = (type: string, id: string): SavedObjectReference => ({ - id, - type, - name: `${type}-ref-${id}`, -}); - -const tagRef = (id: string) => ref('tag', id); - -const createObject = (refs: SavedObjectReference[]): SavedObject => { - return { - type: 'unkown', - id: 'irrelevant', - references: refs, - } as SavedObject; -}; - -const tag1 = createTag('id-1', 'name-1'); -const tag2 = createTag('id-2', 'name-2'); -const tag3 = createTag('id-3', 'name-3'); - -const allTags = [tag1, tag2, tag3]; - -describe('getObjectTags', () => { - it('returns the tags for the tag references of the object', () => { - const { tags } = getObjectTags( - createObject([tagRef('id-1'), ref('dashboard', 'dash-1'), tagRef('id-3')]), - allTags - ); - - expect(tags).toEqual([tag1, tag3]); - }); - - it('returns the missing references for tags that were not found', () => { - const missingRef = tagRef('missing-tag'); - const refs = [tagRef('id-1'), ref('dashboard', 'dash-1'), missingRef]; - const { tags, missingRefs } = getObjectTags(createObject(refs), allTags); - - expect(tags).toEqual([tag1]); - expect(missingRefs).toEqual([missingRef]); - }); -}); - -describe('convertTagNameToId', () => { - it('returns the id for the given tag name', () => { - expect(convertTagNameToId('name-2', allTags)).toBe('id-2'); - }); - - it('returns undefined if no tag was found', () => { - expect(convertTagNameToId('name-4', allTags)).toBeUndefined(); - }); -}); - -describe('getTag', () => { - it('returns the tag for the given id', () => { - expect(getTag('id-2', allTags)).toEqual(tag2); - }); - it('returns undefined if no tag was found', () => { - expect(getTag('id-4', allTags)).toBeUndefined(); - }); -}); - describe('byNameTagSorter', () => { it('sorts tags by name', () => { const tags = [ @@ -97,16 +29,3 @@ describe('byNameTagSorter', () => { expect(tags.map(({ id }) => id)).toEqual(['id-2', 'id-1', 'id-4', 'id-3']); }); }); - -describe('getTagIdsFromReferences', () => { - it('returns the tag ids from the given references', () => { - expect( - getTagIdsFromReferences([ - tagRef('tag-1'), - ref('dashboard', 'dash-1'), - tagRef('tag-2'), - ref('lens', 'lens-1'), - ]) - ).toEqual(['tag-1', 'tag-2']); - }); -}); diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.ts index 14b47bfd8b815..971c404a1f8af 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/public/utils.ts @@ -5,63 +5,12 @@ * 2.0. */ -import type { SavedObject, SavedObjectReference } from '@kbn/core/types'; -import type { SavedObjectsFindOptionsReference } from '@kbn/core/public'; import type { Tag } from '../common/types'; -import { tagSavedObjectTypeName } from '../common'; - -type SavedObjectReferenceLike = SavedObjectReference | SavedObjectsFindOptionsReference; - -export { - tagIdToReference, - replaceTagReferences as updateTagsReferences, -} from '../common/references'; - -export const getObjectTags = ( - object: { references: SavedObject['references'] }, - allTags: Tag[] -) => { - return getTagsFromReferences(object.references, allTags); -}; - -export const getTagsFromReferences = (references: SavedObjectReference[], allTags: Tag[]) => { - const tagReferences = references.filter((ref) => ref.type === tagSavedObjectTypeName); - - const foundTags: Tag[] = []; - const missingRefs: SavedObjectReference[] = []; - - tagReferences.forEach((ref) => { - const found = allTags.find((tag) => tag.id === ref.id); - if (found) { - foundTags.push(found); - } else { - missingRefs.push(ref); - } - }); - - return { - tags: foundTags, - missingRefs, - }; -}; - -export const convertTagNameToId = (tagName: string, allTags: Tag[]): string | undefined => { - const found = allTags.find((tag) => tag.name.toLowerCase() === tagName.toLowerCase()); - return found?.id; -}; export const byNameTagSorter = (tagA: Tag, tagB: Tag): number => { return tagA.name.localeCompare(tagB.name); }; -export const getTag = (tagId: string, allTags: Tag[]): Tag | undefined => { - return allTags.find(({ id }) => id === tagId); -}; - export const testSubjFriendly = (name: string) => { return name.replace(' ', '_'); }; - -export const getTagIdsFromReferences = (references: SavedObjectReferenceLike[]): string[] => { - return references.filter((ref) => ref.type === tagSavedObjectTypeName).map(({ id }) => id); -}; diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/server/mocks.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/server/mocks.ts index 6e1b456090dd4..daa7e441ebe69 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/server/mocks.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/server/mocks.ts @@ -13,6 +13,9 @@ const createStartMock = () => { const start: jest.Mocked = { createTagClient: jest.fn(), createInternalAssignmentService: jest.fn(), + getTagsFromReferences: jest.fn(), + convertTagNameToId: jest.fn(), + replaceTagReferences: jest.fn(), }; start.createTagClient.mockImplementation(() => tagsClientMock.create()); diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.test.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.test.ts index 78cd2cd1f1f95..cf38d3bd66c96 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.test.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.test.ts @@ -79,6 +79,9 @@ describe('SavedObjectTaggingPlugin', () => { expect(contract).toEqual({ createTagClient: expect.any(Function), createInternalAssignmentService: expect.any(Function), + convertTagNameToId: expect.any(Function), + getTagsFromReferences: expect.any(Function), + replaceTagReferences: expect.any(Function), }); }); }); diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.ts index e0e65c522b5eb..414ccbee7146b 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/server/plugin.ts @@ -21,6 +21,7 @@ import { TagsRequestHandlerContext } from './request_handler_context'; import { registerRoutes } from './routes'; import { createTagUsageCollector } from './usage'; import { TagsClient, AssignmentService } from './services'; +import { convertTagNameToId, getTagsFromReferences, replaceTagReferences } from '../common'; interface SetupDeps { features: FeaturesPluginSetup; @@ -36,7 +37,7 @@ export class SavedObjectTaggingPlugin implements Plugin<{}, SavedObjectTaggingStart, SetupDeps, StartDeps> { public setup( - { savedObjects, http, getStartServices }: CoreSetup, + { savedObjects, http, getStartServices }: CoreSetup, { features, usageCollection, security }: SetupDeps ) { savedObjects.registerType(tagType); @@ -69,7 +70,7 @@ export class SavedObjectTaggingPlugin return {}; } - public start(core: CoreStart, { security }: StartDeps) { + public start(core: CoreStart, { security }: StartDeps): SavedObjectTaggingStart { return { createTagClient: ({ client }: CreateTagClientOptions) => { return new TagsClient({ client }); @@ -82,6 +83,9 @@ export class SavedObjectTaggingPlugin internal: true, }); }, + convertTagNameToId, + getTagsFromReferences, + replaceTagReferences, }; } } diff --git a/x-pack/platform/plugins/shared/saved_objects_tagging/server/types.ts b/x-pack/platform/plugins/shared/saved_objects_tagging/server/types.ts index 156be38e79a0d..d2441d8e12282 100644 --- a/x-pack/platform/plugins/shared/saved_objects_tagging/server/types.ts +++ b/x-pack/platform/plugins/shared/saved_objects_tagging/server/types.ts @@ -9,8 +9,9 @@ import type { IRouter, CustomRequestHandlerContext, SavedObjectsClientContract, + SavedObjectReference, } from '@kbn/core/server'; -import type { ITagsClient } from '../common/types'; +import type { ITagsClient, Tag } from '../common/types'; import type { IAssignmentService } from './services'; export interface ITagsRequestHandlerContext { @@ -47,6 +48,15 @@ export interface SavedObjectTaggingStart { createInternalAssignmentService: ( options: CreateTagAssignmentServiceOptions ) => IAssignmentService; + convertTagNameToId: (tagName: string, allTags: Tag[]) => string | undefined; + getTagsFromReferences: ( + references: SavedObjectReference[], + allTags: Tag[] + ) => { tags: Tag[]; missingRefs: SavedObjectReference[] }; + replaceTagReferences: ( + references: SavedObjectReference[], + newTagIds: string[] + ) => SavedObjectReference[]; } /**