From 35f2199d995565c822a7742b3f37e503a120d898 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 1 Nov 2023 16:16:50 -0400 Subject: [PATCH 01/19] Add Spaces column to TableListViewTable component See MSearch developer example under Content Management --- .../content_management_examples/kibana.jsonc | 3 + .../public/examples/index.tsx | 3 +- .../public/examples/msearch/msearch_app.tsx | 41 +++++++---- .../public/types.ts | 2 + .../content_management_examples/tsconfig.json | 1 + .../src/components/spaces_list.tsx | 71 +++++++++++++++++++ .../table_list_view_table/src/services.tsx | 6 +- .../src/table_list_view_table.tsx | 34 +++++++++ 8 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 packages/content-management/table_list_view_table/src/components/spaces_list.tsx diff --git a/examples/content_management_examples/kibana.jsonc b/examples/content_management_examples/kibana.jsonc index 0d4a9b39dc0ef..caa71594d7760 100644 --- a/examples/content_management_examples/kibana.jsonc +++ b/examples/content_management_examples/kibana.jsonc @@ -13,6 +13,9 @@ "kibanaReact", "savedObjectsTaggingOss" ], + "optionalPlugins": [ + "spaces" + ], "requiredBundles": ["savedObjectsFinder"] } } diff --git a/examples/content_management_examples/public/examples/index.tsx b/examples/content_management_examples/public/examples/index.tsx index 3b92da0ba025e..bd83f3f93417e 100644 --- a/examples/content_management_examples/public/examples/index.tsx +++ b/examples/content_management_examples/public/examples/index.tsx @@ -20,7 +20,7 @@ import { FinderApp } from './finder'; export const renderApp = ( core: CoreStart, - { contentManagement, savedObjectsTaggingOss }: StartDeps, + { contentManagement, savedObjectsTaggingOss, spaces }: StartDeps, { element, history }: AppMountParameters ) => { ReactDOM.render( @@ -69,6 +69,7 @@ export const renderApp = ( contentClient={contentManagement.client} core={core} savedObjectsTagging={savedObjectsTaggingOss} + spaces={spaces} /> diff --git a/examples/content_management_examples/public/examples/msearch/msearch_app.tsx b/examples/content_management_examples/public/examples/msearch/msearch_app.tsx index 2bb4ab1bf6fb9..34ea97d92f1b1 100644 --- a/examples/content_management_examples/public/examples/msearch/msearch_app.tsx +++ b/examples/content_management_examples/public/examples/msearch/msearch_app.tsx @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { FC, useMemo } from 'react'; +import { SpacesContextProps, SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { ContentClientProvider, type ContentClient } from '@kbn/content-management-plugin/public'; import { TableListViewKibanaProvider } from '@kbn/content-management-table-list-view-table'; import type { CoreStart } from '@kbn/core/public'; @@ -15,23 +16,37 @@ import { FormattedRelative, I18nProvider } from '@kbn/i18n-react'; import { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; import { MSearchTable } from './msearch_table'; +const getEmptyFunctionComponent: FC = ({ children }) => <>{children}; + export const MSearchApp = (props: { contentClient: ContentClient; core: CoreStart; savedObjectsTagging: SavedObjectTaggingOssPluginStart; + spaces?: SpacesPluginStart; }) => { + const SpacesContextWrapper = useMemo( + () => + props.spaces + ? props.spaces.ui.components.getSpacesContextProvider + : getEmptyFunctionComponent, + [props.spaces] + ); + return ( - - - - - - - + + + + + + + + + ); }; diff --git a/examples/content_management_examples/public/types.ts b/examples/content_management_examples/public/types.ts index 747bfd961c434..3dca87717e791 100644 --- a/examples/content_management_examples/public/types.ts +++ b/examples/content_management_examples/public/types.ts @@ -10,6 +10,7 @@ import { ContentManagementPublicSetup, ContentManagementPublicStart, } from '@kbn/content-management-plugin/public'; +import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; import { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; @@ -21,4 +22,5 @@ export interface SetupDeps { export interface StartDeps { contentManagement: ContentManagementPublicStart; savedObjectsTaggingOss: SavedObjectTaggingOssPluginStart; + spaces?: SpacesPluginStart; } diff --git a/examples/content_management_examples/tsconfig.json b/examples/content_management_examples/tsconfig.json index 33d00ec0ee82d..154ab455a88b8 100644 --- a/examples/content_management_examples/tsconfig.json +++ b/examples/content_management_examples/tsconfig.json @@ -30,5 +30,6 @@ "@kbn/content-management-table-list-view", "@kbn/shared-ux-router", "@kbn/saved-objects-finder-plugin", + "@kbn/spaces-plugin", ] } diff --git a/packages/content-management/table_list_view_table/src/components/spaces_list.tsx b/packages/content-management/table_list_view_table/src/components/spaces_list.tsx new file mode 100644 index 0000000000000..61423df5dd27f --- /dev/null +++ b/packages/content-management/table_list_view_table/src/components/spaces_list.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { FC, useState } from 'react'; + +import type { Capabilities } from '@kbn/core/public'; +import type { SpacesPluginStart, ShareToSpaceFlyoutProps } from '@kbn/spaces-plugin/public'; + +interface Props { + spacesApi: SpacesPluginStart; + capabilities: Capabilities | undefined; + spaceIds: string[]; + type: string; + noun: string; + id: string; + title: string; + refresh(): void; +} + +export const SpacesList: FC = ({ + spacesApi, + capabilities, + type, + noun, + spaceIds, + id, + title, + refresh, +}) => { + const [showFlyout, setShowFlyout] = useState(false); + + function onClose() { + setShowFlyout(false); + } + + const LazySpaceList = spacesApi.ui.components.getSpaceList; + const LazyShareToSpaceFlyout = spacesApi.ui.components.getShareToSpaceFlyout; + + const shareToSpaceFlyoutProps: ShareToSpaceFlyoutProps = { + savedObjectTarget: { + type, + namespaces: spaceIds, + id, + title, + noun, + }, + onUpdate: refresh, + onClose, + }; + + const canAssignSpaces = !capabilities || !!capabilities.savedObjectsManagement.shareIntoSpace; + const clickProperties = canAssignSpaces + ? { cursorStyle: 'pointer', listOnClick: () => setShowFlyout(true) } + : { cursorStyle: 'not-allowed' }; + return ( + <> + + {showFlyout && } + + ); +}; diff --git a/packages/content-management/table_list_view_table/src/services.tsx b/packages/content-management/table_list_view_table/src/services.tsx index 5ee9f9d4b32bd..19a36c258446e 100644 --- a/packages/content-management/table_list_view_table/src/services.tsx +++ b/packages/content-management/table_list_view_table/src/services.tsx @@ -9,6 +9,7 @@ import React, { FC, useContext, useMemo, useCallback } from 'react'; import type { Observable } from 'rxjs'; import type { FormattedRelative } from '@kbn/i18n-react'; +import type { SpacesApi } from '@kbn/spaces-plugin/public'; import type { MountPoint, OverlayRef } from '@kbn/core-mount-utils-browser'; import type { OverlayFlyoutOpenOptions } from '@kbn/core-overlays-browser'; import { RedirectAppLinksKibanaProvider } from '@kbn/shared-ux-link-redirect-app'; @@ -56,6 +57,7 @@ export interface Services { /** Handler to retrieve the list of available tags */ getTagList: () => Tag[]; TagList: FC; + spacesApi?: SpacesApi; /** Predicate function to indicate if some of the saved object references are tags */ itemHasTags: (references: SavedObjectsReference[]) => boolean; /** Handler to return the url to navigate to the kibana tags management */ @@ -155,6 +157,7 @@ export interface TableListViewKibanaDependencies { getTagIdsFromReferences: (references: SavedObjectsReference[]) => string[]; }; }; + spacesApi?: SpacesApi; /** The component from the @kbn/i18n-react package */ FormattedRelative: typeof FormattedRelative; } @@ -166,7 +169,7 @@ export const TableListViewKibanaProvider: FC = children, ...services }) => { - const { core, toMountPoint, savedObjectsTagging, FormattedRelative } = services; + const { core, toMountPoint, savedObjectsTagging, spacesApi, FormattedRelative } = services; const searchQueryParser = useMemo(() => { if (savedObjectsTagging) { @@ -245,6 +248,7 @@ export const TableListViewKibanaProvider: FC = itemHasTags={itemHasTags} getTagIdsFromReferences={getTagIdsFromReferences} getTagManagementUrl={() => core.http.basePath.prepend(TAG_MANAGEMENT_APP_URL)} + spacesApi={spacesApi} > {children} diff --git a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx index f7de8935ea949..7aafc32294686 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx @@ -43,6 +43,7 @@ import type { SortColumnField } from './components'; import { useTags } from './use_tags'; import { useInRouterContext, useUrlState } from './use_url_state'; import { RowActions, TableItemsRowActions } from './types'; +import { SpacesList } from './components/spaces_list'; interface ContentEditorConfig extends Pick { @@ -147,6 +148,7 @@ export interface UserContentCommonSchema { id: string; updatedAt: string; managed?: boolean; + namespaces: string[]; references: SavedObjectsReference[]; type: string; attributes: { @@ -246,6 +248,10 @@ const tableColumnMetadata = { field: 'attributes.title', name: 'Name, description, tags', }, + spaces: { + field: 'namespaces', + name: 'Spaces', + }, updatedAt: { field: 'updatedAt', name: 'Last updated', @@ -316,6 +322,7 @@ function TableListViewTableComp({ notifyError, DateFormatterComp, getTagList, + spacesApi, } = useServices(); const openContentEditor = useOpenContentEditor(); @@ -521,6 +528,31 @@ function TableListViewTableComp({ columns.push(customTableColumn); } + if (spacesApi) { + columns.push({ + field: tableColumnMetadata.spaces.field, + name: i18n.translate('contentManagement.tableList.spacesColumnTitle', { + defaultMessage: 'Spaces', + }), + width: '20%', + render: ( + field: string, + record: { id: string; attributes: { title: string }; type: string; namespaces: string[] } + ) => ( + fetchItems()} + /> + ), + }); + } + if (hasUpdatedAtMetadata) { columns.push({ field: tableColumnMetadata.updatedAt.field, @@ -603,6 +635,7 @@ function TableListViewTableComp({ }, [ titleColumnName, customTableColumn, + spacesApi, hasUpdatedAtMetadata, editItem, contentEditor.enabled, @@ -612,6 +645,7 @@ function TableListViewTableComp({ searchQuery.text, addOrRemoveExcludeTagFilter, addOrRemoveIncludeTagFilter, + fetchItems, DateFormatterComp, isEditable, inspectItem, From a8fb8ed08dc79b508f5790b516176f5480b811c9 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Mon, 27 Nov 2023 17:09:26 -0500 Subject: [PATCH 02/19] Only show Spaces component for shareable objects --- .../public/examples/msearch/msearch_table.tsx | 6 +++ .../table_list_view/src/table_list_view.tsx | 3 ++ .../src/components/spaces_list.tsx | 9 ++-- .../table_list_view_table/src/services.tsx | 4 ++ .../src/table_list_view_table.tsx | 41 +++++++++++-------- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/examples/content_management_examples/public/examples/msearch/msearch_table.tsx b/examples/content_management_examples/public/examples/msearch/msearch_table.tsx index 84c5d58b86558..05b3e5f26f130 100644 --- a/examples/content_management_examples/public/examples/msearch/msearch_table.tsx +++ b/examples/content_management_examples/public/examples/msearch/msearch_table.tsx @@ -13,6 +13,11 @@ import { SavedObjectsFindOptionsReference } from '@kbn/core-saved-objects-api-br const LISTING_LIMIT = 1000; +// TODO Currently each consumer of TableListView needs to pass an itemIsShareable handler to the TableListView. +// Ideally, the contentClient would use the ISavedObjectTypeRegistry.isShareable method to tell us if the saved +// object type is shareable. For this demo we are hard-coding the shareable object types. +const shareableSavedObjects = ['index-pattern']; + export const MSearchTable = () => { const contentClient = useContentClient(); @@ -59,6 +64,7 @@ export const MSearchTable = () => { entityNamePlural={`ContentItems`} title={`MSearch Demo`} urlStateEnabled={false} + itemIsShareable={({ type }) => shareableSavedObjects.includes(type)} emptyPrompt={<>No data found. Try to install some sample data first.} onClickTitle={(item) => { alert(`Clicked item ${item.attributes.title} (${item.id})`); diff --git a/packages/content-management/table_list_view/src/table_list_view.tsx b/packages/content-management/table_list_view/src/table_list_view.tsx index f5d1a9bc596b9..0b773e8caa177 100644 --- a/packages/content-management/table_list_view/src/table_list_view.tsx +++ b/packages/content-management/table_list_view/src/table_list_view.tsx @@ -37,6 +37,7 @@ export type TableListViewProps & { title: string; description?: string; @@ -74,6 +75,7 @@ export const TableListView = ({ additionalRightSideActions, withoutPageTemplateWrapper, itemIsEditable, + itemIsShareable, }: TableListViewProps) => { const PageTemplate = withoutPageTemplateWrapper ? (React.Fragment as unknown as typeof KibanaPageTemplate) @@ -120,6 +122,7 @@ export const TableListView = ({ contentEditor={contentEditor} titleColumnName={titleColumnName} itemIsEditable={itemIsEditable} + itemIsShareable={itemIsShareable} withoutPageTemplateWrapper={withoutPageTemplateWrapper} onFetchSuccess={onFetchSuccess} setPageDataTestSubject={setPageDataTestSubject} diff --git a/packages/content-management/table_list_view_table/src/components/spaces_list.tsx b/packages/content-management/table_list_view_table/src/components/spaces_list.tsx index 61423df5dd27f..99ab75e77ee8e 100644 --- a/packages/content-management/table_list_view_table/src/components/spaces_list.tsx +++ b/packages/content-management/table_list_view_table/src/components/spaces_list.tsx @@ -7,13 +7,11 @@ */ import React, { FC, useState } from 'react'; - -import type { Capabilities } from '@kbn/core/public'; import type { SpacesPluginStart, ShareToSpaceFlyoutProps } from '@kbn/spaces-plugin/public'; interface Props { spacesApi: SpacesPluginStart; - capabilities: Capabilities | undefined; + canShareToSpaces?: boolean; spaceIds: string[]; type: string; noun: string; @@ -24,7 +22,7 @@ interface Props { export const SpacesList: FC = ({ spacesApi, - capabilities, + canShareToSpaces, type, noun, spaceIds, @@ -53,8 +51,7 @@ export const SpacesList: FC = ({ onClose, }; - const canAssignSpaces = !capabilities || !!capabilities.savedObjectsManagement.shareIntoSpace; - const clickProperties = canAssignSpaces + const clickProperties = canShareToSpaces ? { cursorStyle: 'pointer', listOnClick: () => setShowFlyout(true) } : { cursorStyle: 'not-allowed' }; return ( diff --git a/packages/content-management/table_list_view_table/src/services.tsx b/packages/content-management/table_list_view_table/src/services.tsx index 19a36c258446e..7c2cfaee1ef4c 100644 --- a/packages/content-management/table_list_view_table/src/services.tsx +++ b/packages/content-management/table_list_view_table/src/services.tsx @@ -44,6 +44,7 @@ export interface TagListProps { */ export interface Services { canEditAdvancedSettings: boolean; + canShareToSpaces?: boolean; getListingLimitSettingsUrl: () => string; notifyError: NotifyFn; currentAppId$: Observable; @@ -231,6 +232,9 @@ export const TableListViewKibanaProvider: FC = > core.application.getUrlForApp('management', { path: `/kibana/settings?query=savedObjects:listingLimit`, diff --git a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx index 7aafc32294686..e6871b6d95c3a 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx @@ -97,6 +97,11 @@ export interface TableListViewTableProps< */ itemIsEditable?(item: T): boolean; + /** + * Handler to set whether item can be shared into other Spaces. + */ + itemIsShareable?(item: T): boolean; + /** * Name for the column containing the "title" value. */ @@ -274,6 +279,7 @@ function TableListViewTableComp({ createItem, editItem, itemIsEditable, + itemIsShareable, deleteItems, getDetailViewLink, onClickTitle, @@ -316,6 +322,7 @@ function TableListViewTableComp({ const { canEditAdvancedSettings, + canShareToSpaces, getListingLimitSettingsUrl, getTagIdsFromReferences, searchQueryParser, @@ -528,28 +535,28 @@ function TableListViewTableComp({ columns.push(customTableColumn); } - if (spacesApi) { + if (spacesApi && !spacesApi.hasOnlyDefaultSpace) { columns.push({ field: tableColumnMetadata.spaces.field, name: i18n.translate('contentManagement.tableList.spacesColumnTitle', { defaultMessage: 'Spaces', }), width: '20%', - render: ( - field: string, - record: { id: string; attributes: { title: string }; type: string; namespaces: string[] } - ) => ( - fetchItems()} - /> - ), + render: (field: string, record: T) => + !itemIsShareable || !itemIsShareable(record) ? ( + <> + ) : ( + fetchItems()} + /> + ), }); } @@ -645,6 +652,8 @@ function TableListViewTableComp({ searchQuery.text, addOrRemoveExcludeTagFilter, addOrRemoveIncludeTagFilter, + itemIsShareable, + canShareToSpaces, fetchItems, DateFormatterComp, isEditable, From d62272dbb9b351771ec7d89fa18c350c81eb3d0c Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Mon, 27 Nov 2023 17:10:37 -0500 Subject: [PATCH 03/19] Add namespaces property to saved objects --- .../dashboard_listing/hooks/use_dashboard_listing_table.tsx | 1 + .../event_annotation/public/event_annotation_service/service.tsx | 1 + .../public/visualize_app/components/visualize_listing.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx index 80b39ff0e9d62..5ebe48d0d8752 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx @@ -42,6 +42,7 @@ const toTableListViewSavedObject = (hit: DashboardItem): DashboardSavedObjectUse type: 'dashboard', id: hit.id, updatedAt: hit.updatedAt!, + namespaces: hit.namespaces ?? [], references: hit.references, managed: hit.managed, attributes: { diff --git a/src/plugins/event_annotation/public/event_annotation_service/service.tsx b/src/plugins/event_annotation/public/event_annotation_service/service.tsx index 4003ea524b291..c63dc874457fd 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/service.tsx +++ b/src/plugins/event_annotation/public/event_annotation_service/service.tsx @@ -82,6 +82,7 @@ export function getEventAnnotationService( return { id: savedObject.id, references: savedObject.references, + namespaces: savedObject.namespaces ?? [], type: savedObject.type, updatedAt: savedObject.updatedAt ? savedObject.updatedAt : '', attributes: { diff --git a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx index d1de28ac73795..bf13ea14d457b 100644 --- a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx +++ b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx @@ -66,6 +66,7 @@ const toTableListViewSavedObject = (savedObject: Record): Visua return { id: savedObject.id as string, updatedAt: savedObject.updatedAt as string, + namespaces: savedObject.namespaces as string[], references: savedObject.references as Array<{ id: string; type: string; name: string }>, type: savedObject.savedObjectType as string, icon: savedObject.icon as string, From 36835877c00aa435ccc29cae48e5926018fb0f75 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Mon, 27 Nov 2023 17:11:01 -0500 Subject: [PATCH 04/19] Add namespaces to file saved object --- packages/shared-ux/file/types/index.ts | 4 ++++ src/plugins/files/server/file/file.ts | 3 ++- src/plugins/files/server/file/to_json.ts | 7 ++++++- .../files/server/file_client/file_client.ts | 17 +++++++++++------ .../adapters/saved_objects.ts | 3 +++ .../file_metadata_client.ts | 1 + .../file_service/internal_file_service.ts | 2 +- src/plugins/files_management/public/app.tsx | 1 + 8 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/shared-ux/file/types/index.ts b/packages/shared-ux/file/types/index.ts index 32dda0bd933a7..053bda5b2d73c 100644 --- a/packages/shared-ux/file/types/index.ts +++ b/packages/shared-ux/file/types/index.ts @@ -230,6 +230,10 @@ export interface FileJSON { * File hash information */ hash?: BaseFileMetadata['hash']; + /** + * The Spaces to which this saved object is shared + */ + namespaces?: string[]; } export interface FileKindBase { diff --git a/src/plugins/files/server/file/file.ts b/src/plugins/files/server/file/file.ts index 495d233fd421b..0c332774bba34 100644 --- a/src/plugins/files/server/file/file.ts +++ b/src/plugins/files/server/file/file.ts @@ -42,7 +42,8 @@ export class File implements IFile { public readonly id: string, private metadata: FileJSON, private readonly fileClient: FileClientImpl, - private readonly logger: Logger + private readonly logger: Logger, + public readonly namespaces?: string[] ) {} private async updateFileState(action: Action): Promise { diff --git a/src/plugins/files/server/file/to_json.ts b/src/plugins/files/server/file/to_json.ts index 68870e94ee67c..c59ab53fda8a5 100644 --- a/src/plugins/files/server/file/to_json.ts +++ b/src/plugins/files/server/file/to_json.ts @@ -43,7 +43,11 @@ export function serializeJSON(attrs: Partial): Partial(id: string, attrs: FileMetadata): FileJSON { +export function toJSON( + id: string, + attrs: FileMetadata, + namespaces?: string[] +): FileJSON { const { name, mime_type: mimeType, @@ -61,6 +65,7 @@ export function toJSON(id: string, attrs: FileMetadata): FileJSO return pickBy>( { id, + namespaces, user, name, mimeType, diff --git a/src/plugins/files/server/file_client/file_client.ts b/src/plugins/files/server/file_client/file_client.ts index 26dbc90a44b90..c17dc854f15ea 100644 --- a/src/plugins/files/server/file_client/file_client.ts +++ b/src/plugins/files/server/file_client/file_client.ts @@ -110,7 +110,11 @@ export class FileClientImpl implements FileClient { FileClientImpl.usageCounter?.incrementCounter({ counterName: this.getCounters()[counter] }); } - private instantiateFile(id: string, metadata: FileMetadata): File { + private instantiateFile( + id: string, + metadata: FileMetadata, + namespaces?: string[] + ): File { return new FileImpl( id, toJSON(id, { @@ -118,7 +122,8 @@ export class FileClientImpl implements FileClient { ...metadata, }), this, - this.logger + this.logger, + namespaces ); } @@ -153,8 +158,8 @@ export class FileClientImpl implements FileClient { } public async get(arg: P1): Promise> { - const { id, metadata } = await this.metadataClient.get(arg); - return this.instantiateFile(id, metadata as FileMetadata); + const { id, namespaces, metadata } = await this.metadataClient.get(arg); + return this.instantiateFile(id, metadata as FileMetadata, namespaces); } public async internalUpdate(id: string, metadata: Partial): Promise { @@ -173,8 +178,8 @@ export class FileClientImpl implements FileClient { const result = await this.metadataClient.find(arg); return { total: result.total, - files: result.files.map(({ id, metadata }) => - this.instantiateFile(id, metadata as FileMetadata) + files: result.files.map(({ id, namespaces, metadata }) => + this.instantiateFile(id, metadata as FileMetadata, namespaces) ), }; } diff --git a/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts b/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts index 84274d695d292..f507ee781cdb2 100644 --- a/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts +++ b/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts @@ -61,6 +61,7 @@ export class SavedObjectsFileMetadataClient implements FileMetadataClient { const result = await this.soClient.get(this.soType, id); return { id: result.id, + namespaces: result.namespaces, metadata: result.attributes as FileDescriptor['metadata'], }; } @@ -78,6 +79,7 @@ export class SavedObjectsFileMetadataClient implements FileMetadataClient { return { id: so.id, + namespaces: so.namespaces, metadata: so.attributes as FileDescriptor['metadata'], }; }); @@ -98,6 +100,7 @@ export class SavedObjectsFileMetadataClient implements FileMetadataClient { return { files: result.saved_objects.map((so) => ({ id: so.id, + namespaces: so.namespaces, metadata: so.attributes as FileMetadata, })), total: result.total, diff --git a/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts b/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts index 33117ad842afc..3a9adf383e13e 100644 --- a/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts +++ b/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts @@ -37,6 +37,7 @@ export interface FileDescriptor { * The file's metadata. */ metadata: FileMetadata; + namespaces?: string[]; } /** diff --git a/src/plugins/files/server/file_service/internal_file_service.ts b/src/plugins/files/server/file_service/internal_file_service.ts index b224a28313a70..04c09f079f4cd 100644 --- a/src/plugins/files/server/file_service/internal_file_service.ts +++ b/src/plugins/files/server/file_service/internal_file_service.ts @@ -167,7 +167,7 @@ export class InternalFileService { const { total, files } = await this.metadataClient.find(args); return { total, - files: files.map(({ id, metadata }) => toJSON(id, metadata)), + files: files.map(({ id, metadata, namespaces }) => toJSON(id, metadata, namespaces)), }; } diff --git a/src/plugins/files_management/public/app.tsx b/src/plugins/files_management/public/app.tsx index 08f942c644789..a82ec7f81dd8f 100644 --- a/src/plugins/files_management/public/app.tsx +++ b/src/plugins/files_management/public/app.tsx @@ -58,6 +58,7 @@ export const App: FunctionComponent = () => { hits: files.map((file) => ({ id: file.id, updatedAt: file.updated, + namespaces: file.namespaces ?? [], references: [], type: 'file', attributes: { From edbc37636d791ed1429596110323bd9997832c3b Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 27 Nov 2023 22:19:57 +0000 Subject: [PATCH 05/19] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- packages/content-management/table_list_view_table/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/content-management/table_list_view_table/tsconfig.json b/packages/content-management/table_list_view_table/tsconfig.json index 16a8a6b1a6de1..5649881e54fa9 100644 --- a/packages/content-management/table_list_view_table/tsconfig.json +++ b/packages/content-management/table_list_view_table/tsconfig.json @@ -25,6 +25,7 @@ "@kbn/shared-ux-page-kibana-template", "@kbn/shared-ux-link-redirect-app", "@kbn/test-jest-helpers", + "@kbn/spaces-plugin", ], "exclude": [ "target/**/*", From 53b984e993579773417a3253822bf1ccce3b7548 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 8 Nov 2023 12:18:58 -0500 Subject: [PATCH 06/19] Fix types on test --- .../src/table_list_view.test.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/content-management/table_list_view_table/src/table_list_view.test.tsx b/packages/content-management/table_list_view_table/src/table_list_view.test.tsx index 277748b44b883..a1d15bec35655 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view.test.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view.test.tsx @@ -141,6 +141,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: 'item-1', + namespaces: ['default'], type: 'dashboard', updatedAt: '2020-01-01T00:00:00Z', attributes: { @@ -188,6 +189,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: '123', + namespaces: ['default'], updatedAt: twoDaysAgo.toISOString(), type: 'dashboard', attributes: { @@ -198,6 +200,7 @@ describe('TableListView', () => { }, { id: '456', + namespaces: ['default'], // This is the latest updated and should come first in the table updatedAt: yesterday.toISOString(), type: 'dashboard', @@ -330,6 +333,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [...Array(totalItems)].map((_, i) => ({ id: `item${i}`, + namespaces: ['default'], type: 'dashboard', updatedAt, attributes: { @@ -438,6 +442,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: '123', + namespaces: ['default'], updatedAt: twoDaysAgo.toISOString(), // first asc, last desc type: 'dashboard', attributes: { @@ -447,6 +452,7 @@ describe('TableListView', () => { }, { id: '456', + namespaces: ['default'], updatedAt: yesterday.toISOString(), // first desc, last asc type: 'dashboard', attributes: { @@ -639,6 +645,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: '123', + namespaces: ['default'], updatedAt: new Date(new Date().setDate(new Date().getDate() - 1)).toISOString(), attributes: { title: 'Item 1', @@ -649,6 +656,7 @@ describe('TableListView', () => { }, { id: '456', + namespaces: ['default'], updatedAt: new Date(new Date().setDate(new Date().getDate() - 2)).toISOString(), attributes: { title: 'Item 2', @@ -697,6 +705,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: '123', + namespaces: ['default'], updatedAt: new Date(new Date().setDate(new Date().getDate() - 1)).toISOString(), type: 'dashboard', attributes: { @@ -710,6 +719,7 @@ describe('TableListView', () => { }, { id: '456', + namespaces: ['default'], updatedAt: new Date(new Date().setDate(new Date().getDate() - 2)).toISOString(), type: 'dashboard', attributes: { @@ -890,6 +900,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: 'item-1', + namespaces: ['default'], type: 'dashboard', updatedAt, attributes: { @@ -899,6 +910,7 @@ describe('TableListView', () => { }, { id: 'item-2', + namespaces: ['default'], type: 'dashboard', updatedAt, attributes: { @@ -1075,6 +1087,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: '123', + namespaces: ['default'], updatedAt: yesterday.toISOString(), type: 'dashboard', attributes: { @@ -1085,6 +1098,7 @@ describe('TableListView', () => { }, { id: '456', + namespaces: ['default'], updatedAt: twoDaysAgo.toISOString(), type: 'dashboard', attributes: { @@ -1344,6 +1358,7 @@ describe('TableListView', () => { const hits: UserContentCommonSchema[] = [ { id: '123', + namespaces: ['default'], updatedAt: twoDaysAgo.toISOString(), type: 'dashboard', attributes: { @@ -1354,6 +1369,7 @@ describe('TableListView', () => { }, { id: '456', + namespaces: ['default'], updatedAt: yesterday.toISOString(), type: 'dashboard', attributes: { @@ -1467,6 +1483,7 @@ describe('TableList', () => { const originalHits: UserContentCommonSchema[] = [ { id: `item`, + namespaces: ['default'], type: 'dashboard', updatedAt: 'original timestamp', attributes: { @@ -1491,6 +1508,7 @@ describe('TableList', () => { const hits: UserContentCommonSchema[] = [ { id: `item`, + namespaces: ['default'], type: 'dashboard', updatedAt: 'updated timestamp', attributes: { From b69c8b80b76b29031d34ffb38bcd2ab05e03e8d2 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 28 Nov 2023 08:24:12 -0500 Subject: [PATCH 07/19] Add savedObjectsManagement to DashboardApplicationService --- .../public/dashboard_actions/add_to_library_action.test.tsx | 1 + .../dashboard/public/services/application/application.stub.ts | 1 + .../public/services/application/application_service.ts | 3 ++- src/plugins/dashboard/public/services/application/types.ts | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.test.tsx b/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.test.tsx index 417795dee9334..91a83998911fe 100644 --- a/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.test.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.test.tsx @@ -40,6 +40,7 @@ const defaultCapabilities = { visualize: { save: true }, maps: { save: true }, navLinks: {}, + savedObjectsManagement: {}, }; Object.defineProperty(pluginServices.getServices().application, 'capabilities', { diff --git a/src/plugins/dashboard/public/services/application/application.stub.ts b/src/plugins/dashboard/public/services/application/application.stub.ts index 9717e75ea7bc8..b2e8111b6cec6 100644 --- a/src/plugins/dashboard/public/services/application/application.stub.ts +++ b/src/plugins/dashboard/public/services/application/application.stub.ts @@ -25,6 +25,7 @@ export const applicationServiceFactory: ApplicationServiceFactory = () => { maps: pluginMock.capabilities.maps, navLinks: pluginMock.capabilities.navLinks, visualize: pluginMock.capabilities.visualize, + savedObjectsManagement: pluginMock.capabilities.savedObjectsManagement, }, }; }; diff --git a/src/plugins/dashboard/public/services/application/application_service.ts b/src/plugins/dashboard/public/services/application/application_service.ts index adc6d23f48461..2518d68b723c6 100644 --- a/src/plugins/dashboard/public/services/application/application_service.ts +++ b/src/plugins/dashboard/public/services/application/application_service.ts @@ -22,7 +22,7 @@ export const applicationServiceFactory: ApplicationServiceFactory = ({ coreStart navigateToApp, navigateToUrl, getUrlForApp, - capabilities: { advancedSettings, maps, navLinks, visualize }, + capabilities: { advancedSettings, maps, navLinks, visualize, savedObjectsManagement }, }, } = coreStart; @@ -36,6 +36,7 @@ export const applicationServiceFactory: ApplicationServiceFactory = ({ coreStart maps, navLinks, visualize, + savedObjectsManagement, }, }; }; diff --git a/src/plugins/dashboard/public/services/application/types.ts b/src/plugins/dashboard/public/services/application/types.ts index 66ef934e44bb3..97b21dddbd4b3 100644 --- a/src/plugins/dashboard/public/services/application/types.ts +++ b/src/plugins/dashboard/public/services/application/types.ts @@ -18,5 +18,6 @@ export interface DashboardApplicationService { maps: CoreStart['application']['capabilities']['maps']; // only used in `add_to_library_action` navLinks: CoreStart['application']['capabilities']['navLinks']; visualize: CoreStart['application']['capabilities']['visualize']; // only used in `add_to_library_action` + savedObjectsManagement: CoreStart['application']['capabilities']['savedObjectsManagement']; }; } From b96864f5ed79f20b75b050cf23c0722c2d54e951 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 28 Nov 2023 14:28:56 -0500 Subject: [PATCH 08/19] Add unit test for spaces column --- .../table_list_view_table/src/services.tsx | 4 + .../src/table_list_view.test.tsx | 76 ++++++++++++++++++- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/content-management/table_list_view_table/src/services.tsx b/packages/content-management/table_list_view_table/src/services.tsx index 7c2cfaee1ef4c..b319fbfc21a6d 100644 --- a/packages/content-management/table_list_view_table/src/services.tsx +++ b/packages/content-management/table_list_view_table/src/services.tsx @@ -158,6 +158,10 @@ export interface TableListViewKibanaDependencies { getTagIdsFromReferences: (references: SavedObjectsReference[]) => string[]; }; }; + /** + * The public API from the Spaces plugin. Provide the `spacesApi` to show the Spaces + * column in the table. + */ spacesApi?: SpacesApi; /** The component from the @kbn/i18n-react package */ FormattedRelative: typeof FormattedRelative; diff --git a/packages/content-management/table_list_view_table/src/table_list_view.test.tsx b/packages/content-management/table_list_view_table/src/table_list_view.test.tsx index a1d15bec35655..71958e691c893 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view.test.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view.test.tsx @@ -8,6 +8,7 @@ import { EuiEmptyPrompt } from '@elastic/eui'; import { registerTestBed, TestBed } from '@kbn/test-jest-helpers'; +import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; import React, { useEffect } from 'react'; import queryString from 'query-string'; import moment, { Moment } from 'moment'; @@ -428,17 +429,86 @@ describe('TableListView', () => { }); }); - describe('column sorting', () => { - const setupColumnSorting = registerTestBed( + describe('spaces column', () => { + const spacesApi = spacesPluginMock.createStartContract(); + jest + .spyOn(spacesApi.ui.components, 'getSpaceList') + .mockImplementation(({ namespaces }) => <>{namespaces.toString()}); + const setupSpacesColumn = registerTestBed( WithServices(TableListViewTable, { + spacesApi, TagList: getTagList({ references: [] }), }), { - defaultProps: { ...requiredProps }, + defaultProps: { ...requiredProps, itemIsShareable: ({ id }) => id !== '789' }, memoryRouter: { wrapComponent: true }, } ); + const hits: UserContentCommonSchema[] = [ + { + id: '123', + namespaces: ['default', 'engineering', 'product-management'], + updatedAt: twoDaysAgo.toISOString(), // first asc, last desc + type: 'dashboard', + attributes: { + title: 'z-foo', // first desc, last asc + }, + references: [{ id: 'id-tag-1', name: 'tag-1', type: 'tag' }], + }, + { + id: '456', + namespaces: ['*'], + updatedAt: yesterday.toISOString(), // first desc, last asc + type: 'dashboard', + attributes: { + title: 'a-foo', // first asc, last desc + }, + references: [], + }, + { + id: '789', + namespaces: ['default'], + updatedAt: yesterday.toISOString(), + type: 'lens', + attributes: { + title: 'not-shareable', + }, + references: [], + }, + ]; + + test('should display on shareable items when spaces is provided', async () => { + let testBed: TestBed; + + await act(async () => { + testBed = await setupSpacesColumn({ + findItems: jest.fn().mockResolvedValue({ total: hits.length, hits }), + }); + }); + + const { component, table } = testBed!; + component.update(); + + const { tableCellsValues } = table.getMetaData('itemsInMemTable'); + + expect(tableCellsValues).toEqual([ + ['a-foo', '*', yesterdayToString], + ['not-shareable', '', yesterdayToString], + ['z-foo', 'default,engineering,product-management', twoDaysAgoToString], + ]); + }); + }); + + describe('column sorting', () => { + const tagList = WithServices(TableListViewTable, { + TagList: getTagList({ references: [] }), + }); + const setupColumnSorting = registerTestBed(tagList, { + defaultProps: { ...requiredProps }, + memoryRouter: { wrapComponent: true }, + }); + const hits: UserContentCommonSchema[] = [ { id: '123', From affb1b8fec512f046b3711c19445f3e4ce0d579d Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 28 Nov 2023 14:53:16 -0500 Subject: [PATCH 09/19] Add namespaces to event annotation tests --- .../__snapshots__/service.test.ts.snap | 12 ++++++++++++ .../public/event_annotation_service/service.test.ts | 4 ++++ .../public/components/table_list.test.tsx | 2 ++ 3 files changed, 18 insertions(+) diff --git a/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap b/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap index 0bd643095dcdc..ad113cc376690 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap +++ b/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap @@ -11,6 +11,9 @@ Object { "title": undefined, }, "id": "nonExistingGroup", + "namespaces": Array [ + "default", + ], "references": Array [], "type": undefined, "updatedAt": "", @@ -23,6 +26,9 @@ Object { "title": "groupTitle", }, "id": undefined, + "namespaces": Array [ + "default", + ], "references": Array [ Object { "id": "ipid", @@ -46,6 +52,9 @@ Object { "title": "groupTitle", }, "id": "multiAnnotations", + "namespaces": Array [ + "default", + ], "references": Array [ Object { "id": "ipid", @@ -66,6 +75,9 @@ Object { "title": "groupTitle", }, "id": "multiAnnotations", + "namespaces": Array [ + "default", + ], "references": Array [], "type": "event-annotation-group", "updatedAt": "", diff --git a/src/plugins/event_annotation/public/event_annotation_service/service.test.ts b/src/plugins/event_annotation/public/event_annotation_service/service.test.ts index 7a0f00e7a4de2..b80219694b161 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/service.test.ts +++ b/src/plugins/event_annotation/public/event_annotation_service/service.test.ts @@ -24,6 +24,7 @@ const annotationGroupResolveMocks: Record = attributes: {} as EventAnnotationGroupSavedObjectAttributes, references: [], id: 'nonExistingGroup', + namespaces: ['default'], error: { error: 'Saved object not found', statusCode: 404, @@ -40,6 +41,7 @@ const annotationGroupResolveMocks: Record = dataViewSpec: null, }, type: 'event-annotation-group', + namespaces: ['default'], references: [ { id: 'ipid', @@ -59,6 +61,7 @@ const annotationGroupResolveMocks: Record = }, id: 'multiAnnotations', type: 'event-annotation-group', + namespaces: ['default'], references: [ { id: 'ipid', @@ -76,6 +79,7 @@ const annotationGroupResolveMocks: Record = } as Partial, id: 'multiAnnotations', type: 'event-annotation-group', + namespaces: ['default'], references: [], } as Partial as AnnotationGroupSavedObject, }; diff --git a/src/plugins/event_annotation_listing/public/components/table_list.test.tsx b/src/plugins/event_annotation_listing/public/components/table_list.test.tsx index 65970aeca3c7d..aef902fad6e84 100644 --- a/src/plugins/event_annotation_listing/public/components/table_list.test.tsx +++ b/src/plugins/event_annotation_listing/public/components/table_list.test.tsx @@ -135,6 +135,7 @@ describe('annotation list view', () => { wrapper.find(TableListViewTable).prop('deleteItems')!([ { id: 'some-id-1', + namespaces: ['default'], references: [ { type: 'index-pattern', @@ -150,6 +151,7 @@ describe('annotation list view', () => { }, { id: 'some-id-2', + namespaces: ['default'], references: [], type: EVENT_ANNOTATION_GROUP_TYPE, updatedAt: '', From d8f62549af9a09689308ad8e0e0503035c7407c7 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 28 Nov 2023 14:53:48 -0500 Subject: [PATCH 10/19] Add namespaces to graph saved object type --- x-pack/plugins/graph/public/apps/listing_route.tsx | 1 + x-pack/plugins/graph/public/types/persistence.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/x-pack/plugins/graph/public/apps/listing_route.tsx b/x-pack/plugins/graph/public/apps/listing_route.tsx index d5e7d2be00967..058f2899017e9 100644 --- a/x-pack/plugins/graph/public/apps/listing_route.tsx +++ b/x-pack/plugins/graph/public/apps/listing_route.tsx @@ -26,6 +26,7 @@ type GraphUserContent = UserContentCommonSchema; const toTableListViewSavedObject = (savedObject: GraphWorkspaceSavedObject): GraphUserContent => { return { id: savedObject.id!, + namespaces: savedObject.namespaces!, updatedAt: savedObject.updatedAt!, references: savedObject.references ?? [], type: savedObject.type, diff --git a/x-pack/plugins/graph/public/types/persistence.ts b/x-pack/plugins/graph/public/types/persistence.ts index f5c1366ff8661..3eeb070092e5c 100644 --- a/x-pack/plugins/graph/public/types/persistence.ts +++ b/x-pack/plugins/graph/public/types/persistence.ts @@ -34,6 +34,7 @@ export interface GraphWorkspaceSavedObject { legacyIndexPatternRef?: string; _source: Record; updatedAt?: string; + namespaces?: string[]; references: SavedObjectReference[]; } From c8be79414c140922061214215503cf49f908c001 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 28 Nov 2023 14:54:43 -0500 Subject: [PATCH 11/19] Add namespaces to maps listing saved object --- x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx index 8c982a2853708..fccd46fb325a8 100644 --- a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx @@ -46,6 +46,7 @@ function navigateToNewMap() { const toTableListViewSavedObject = (mapItem: MapItem): MapUserContent => { return { ...mapItem, + namespaces: mapItem.namespaces!, updatedAt: mapItem.updatedAt!, attributes: { ...mapItem.attributes, From 22bebc8746f78bfa372d6ca693421d5859cf377e Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 28 Nov 2023 15:03:15 -0500 Subject: [PATCH 12/19] Assert namespaces on dashboard saved object --- .../dashboard_listing/hooks/use_dashboard_listing_table.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx index 5ebe48d0d8752..597bdbdfef97e 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx @@ -42,7 +42,7 @@ const toTableListViewSavedObject = (hit: DashboardItem): DashboardSavedObjectUse type: 'dashboard', id: hit.id, updatedAt: hit.updatedAt!, - namespaces: hit.namespaces ?? [], + namespaces: hit.namespaces!, references: hit.references, managed: hit.managed, attributes: { From 8b6c3067fbec900c3ee7fb37eec7226e0e430973 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 29 Nov 2023 09:05:29 -0500 Subject: [PATCH 13/19] Coalesce undefined namespaces to empty array Alternatively, we could probably use an assertion operator as I think all saved objects will have the namespaces property. --- .../dashboard_listing/hooks/use_dashboard_listing_table.tsx | 2 +- x-pack/plugins/graph/public/apps/listing_route.tsx | 2 +- x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx index 597bdbdfef97e..5ebe48d0d8752 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx @@ -42,7 +42,7 @@ const toTableListViewSavedObject = (hit: DashboardItem): DashboardSavedObjectUse type: 'dashboard', id: hit.id, updatedAt: hit.updatedAt!, - namespaces: hit.namespaces!, + namespaces: hit.namespaces ?? [], references: hit.references, managed: hit.managed, attributes: { diff --git a/x-pack/plugins/graph/public/apps/listing_route.tsx b/x-pack/plugins/graph/public/apps/listing_route.tsx index 058f2899017e9..45d05d0d204ca 100644 --- a/x-pack/plugins/graph/public/apps/listing_route.tsx +++ b/x-pack/plugins/graph/public/apps/listing_route.tsx @@ -26,7 +26,7 @@ type GraphUserContent = UserContentCommonSchema; const toTableListViewSavedObject = (savedObject: GraphWorkspaceSavedObject): GraphUserContent => { return { id: savedObject.id!, - namespaces: savedObject.namespaces!, + namespaces: savedObject.namespaces ?? [], updatedAt: savedObject.updatedAt!, references: savedObject.references ?? [], type: savedObject.type, diff --git a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx index fccd46fb325a8..d881dc7541c0e 100644 --- a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx @@ -46,7 +46,7 @@ function navigateToNewMap() { const toTableListViewSavedObject = (mapItem: MapItem): MapUserContent => { return { ...mapItem, - namespaces: mapItem.namespaces!, + namespaces: mapItem.namespaces ?? [], updatedAt: mapItem.updatedAt!, attributes: { ...mapItem.attributes, From 19992767e6bc60d4b6e89034aaf632486ca2b0b5 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 29 Nov 2023 14:56:13 -0500 Subject: [PATCH 14/19] Revert "Add namespaces property to saved objects" This reverts commit d62272dbb9b351771ec7d89fa18c350c81eb3d0c. --- .../dashboard_listing/hooks/use_dashboard_listing_table.tsx | 1 - .../event_annotation/public/event_annotation_service/service.tsx | 1 - .../public/visualize_app/components/visualize_listing.tsx | 1 - 3 files changed, 3 deletions(-) diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx index 5ebe48d0d8752..80b39ff0e9d62 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx @@ -42,7 +42,6 @@ const toTableListViewSavedObject = (hit: DashboardItem): DashboardSavedObjectUse type: 'dashboard', id: hit.id, updatedAt: hit.updatedAt!, - namespaces: hit.namespaces ?? [], references: hit.references, managed: hit.managed, attributes: { diff --git a/src/plugins/event_annotation/public/event_annotation_service/service.tsx b/src/plugins/event_annotation/public/event_annotation_service/service.tsx index c63dc874457fd..4003ea524b291 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/service.tsx +++ b/src/plugins/event_annotation/public/event_annotation_service/service.tsx @@ -82,7 +82,6 @@ export function getEventAnnotationService( return { id: savedObject.id, references: savedObject.references, - namespaces: savedObject.namespaces ?? [], type: savedObject.type, updatedAt: savedObject.updatedAt ? savedObject.updatedAt : '', attributes: { diff --git a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx index bf13ea14d457b..d1de28ac73795 100644 --- a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx +++ b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx @@ -66,7 +66,6 @@ const toTableListViewSavedObject = (savedObject: Record): Visua return { id: savedObject.id as string, updatedAt: savedObject.updatedAt as string, - namespaces: savedObject.namespaces as string[], references: savedObject.references as Array<{ id: string; type: string; name: string }>, type: savedObject.savedObjectType as string, icon: savedObject.icon as string, From 3bafc9b45bc5d441bf48407e0ef7c621264a4d13 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 29 Nov 2023 14:57:03 -0500 Subject: [PATCH 15/19] Revert "Add namespaces to file saved object" This reverts commit 36835877c00aa435ccc29cae48e5926018fb0f75. --- packages/shared-ux/file/types/index.ts | 4 ---- src/plugins/files/server/file/file.ts | 3 +-- src/plugins/files/server/file/to_json.ts | 7 +------ .../files/server/file_client/file_client.ts | 17 ++++++----------- .../adapters/saved_objects.ts | 3 --- .../file_metadata_client.ts | 1 - .../file_service/internal_file_service.ts | 2 +- src/plugins/files_management/public/app.tsx | 1 - 8 files changed, 9 insertions(+), 29 deletions(-) diff --git a/packages/shared-ux/file/types/index.ts b/packages/shared-ux/file/types/index.ts index 053bda5b2d73c..32dda0bd933a7 100644 --- a/packages/shared-ux/file/types/index.ts +++ b/packages/shared-ux/file/types/index.ts @@ -230,10 +230,6 @@ export interface FileJSON { * File hash information */ hash?: BaseFileMetadata['hash']; - /** - * The Spaces to which this saved object is shared - */ - namespaces?: string[]; } export interface FileKindBase { diff --git a/src/plugins/files/server/file/file.ts b/src/plugins/files/server/file/file.ts index 0c332774bba34..495d233fd421b 100644 --- a/src/plugins/files/server/file/file.ts +++ b/src/plugins/files/server/file/file.ts @@ -42,8 +42,7 @@ export class File implements IFile { public readonly id: string, private metadata: FileJSON, private readonly fileClient: FileClientImpl, - private readonly logger: Logger, - public readonly namespaces?: string[] + private readonly logger: Logger ) {} private async updateFileState(action: Action): Promise { diff --git a/src/plugins/files/server/file/to_json.ts b/src/plugins/files/server/file/to_json.ts index c59ab53fda8a5..68870e94ee67c 100644 --- a/src/plugins/files/server/file/to_json.ts +++ b/src/plugins/files/server/file/to_json.ts @@ -43,11 +43,7 @@ export function serializeJSON(attrs: Partial): Partial( - id: string, - attrs: FileMetadata, - namespaces?: string[] -): FileJSON { +export function toJSON(id: string, attrs: FileMetadata): FileJSON { const { name, mime_type: mimeType, @@ -65,7 +61,6 @@ export function toJSON( return pickBy>( { id, - namespaces, user, name, mimeType, diff --git a/src/plugins/files/server/file_client/file_client.ts b/src/plugins/files/server/file_client/file_client.ts index c17dc854f15ea..26dbc90a44b90 100644 --- a/src/plugins/files/server/file_client/file_client.ts +++ b/src/plugins/files/server/file_client/file_client.ts @@ -110,11 +110,7 @@ export class FileClientImpl implements FileClient { FileClientImpl.usageCounter?.incrementCounter({ counterName: this.getCounters()[counter] }); } - private instantiateFile( - id: string, - metadata: FileMetadata, - namespaces?: string[] - ): File { + private instantiateFile(id: string, metadata: FileMetadata): File { return new FileImpl( id, toJSON(id, { @@ -122,8 +118,7 @@ export class FileClientImpl implements FileClient { ...metadata, }), this, - this.logger, - namespaces + this.logger ); } @@ -158,8 +153,8 @@ export class FileClientImpl implements FileClient { } public async get(arg: P1): Promise> { - const { id, namespaces, metadata } = await this.metadataClient.get(arg); - return this.instantiateFile(id, metadata as FileMetadata, namespaces); + const { id, metadata } = await this.metadataClient.get(arg); + return this.instantiateFile(id, metadata as FileMetadata); } public async internalUpdate(id: string, metadata: Partial): Promise { @@ -178,8 +173,8 @@ export class FileClientImpl implements FileClient { const result = await this.metadataClient.find(arg); return { total: result.total, - files: result.files.map(({ id, namespaces, metadata }) => - this.instantiateFile(id, metadata as FileMetadata, namespaces) + files: result.files.map(({ id, metadata }) => + this.instantiateFile(id, metadata as FileMetadata) ), }; } diff --git a/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts b/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts index f507ee781cdb2..84274d695d292 100644 --- a/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts +++ b/src/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts @@ -61,7 +61,6 @@ export class SavedObjectsFileMetadataClient implements FileMetadataClient { const result = await this.soClient.get(this.soType, id); return { id: result.id, - namespaces: result.namespaces, metadata: result.attributes as FileDescriptor['metadata'], }; } @@ -79,7 +78,6 @@ export class SavedObjectsFileMetadataClient implements FileMetadataClient { return { id: so.id, - namespaces: so.namespaces, metadata: so.attributes as FileDescriptor['metadata'], }; }); @@ -100,7 +98,6 @@ export class SavedObjectsFileMetadataClient implements FileMetadataClient { return { files: result.saved_objects.map((so) => ({ id: so.id, - namespaces: so.namespaces, metadata: so.attributes as FileMetadata, })), total: result.total, diff --git a/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts b/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts index 3a9adf383e13e..33117ad842afc 100644 --- a/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts +++ b/src/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts @@ -37,7 +37,6 @@ export interface FileDescriptor { * The file's metadata. */ metadata: FileMetadata; - namespaces?: string[]; } /** diff --git a/src/plugins/files/server/file_service/internal_file_service.ts b/src/plugins/files/server/file_service/internal_file_service.ts index 04c09f079f4cd..b224a28313a70 100644 --- a/src/plugins/files/server/file_service/internal_file_service.ts +++ b/src/plugins/files/server/file_service/internal_file_service.ts @@ -167,7 +167,7 @@ export class InternalFileService { const { total, files } = await this.metadataClient.find(args); return { total, - files: files.map(({ id, metadata, namespaces }) => toJSON(id, metadata, namespaces)), + files: files.map(({ id, metadata }) => toJSON(id, metadata)), }; } diff --git a/src/plugins/files_management/public/app.tsx b/src/plugins/files_management/public/app.tsx index a82ec7f81dd8f..08f942c644789 100644 --- a/src/plugins/files_management/public/app.tsx +++ b/src/plugins/files_management/public/app.tsx @@ -58,7 +58,6 @@ export const App: FunctionComponent = () => { hits: files.map((file) => ({ id: file.id, updatedAt: file.updated, - namespaces: file.namespaces ?? [], references: [], type: 'file', attributes: { From 9166573fbf6eb231bf1c92f4e698ececfd637b13 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 29 Nov 2023 14:57:29 -0500 Subject: [PATCH 16/19] Revert "Add namespaces to event annotation tests" This reverts commit affb1b8fec512f046b3711c19445f3e4ce0d579d. --- .../__snapshots__/service.test.ts.snap | 12 ------------ .../public/event_annotation_service/service.test.ts | 4 ---- .../public/components/table_list.test.tsx | 2 -- 3 files changed, 18 deletions(-) diff --git a/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap b/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap index ad113cc376690..0bd643095dcdc 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap +++ b/src/plugins/event_annotation/public/event_annotation_service/__snapshots__/service.test.ts.snap @@ -11,9 +11,6 @@ Object { "title": undefined, }, "id": "nonExistingGroup", - "namespaces": Array [ - "default", - ], "references": Array [], "type": undefined, "updatedAt": "", @@ -26,9 +23,6 @@ Object { "title": "groupTitle", }, "id": undefined, - "namespaces": Array [ - "default", - ], "references": Array [ Object { "id": "ipid", @@ -52,9 +46,6 @@ Object { "title": "groupTitle", }, "id": "multiAnnotations", - "namespaces": Array [ - "default", - ], "references": Array [ Object { "id": "ipid", @@ -75,9 +66,6 @@ Object { "title": "groupTitle", }, "id": "multiAnnotations", - "namespaces": Array [ - "default", - ], "references": Array [], "type": "event-annotation-group", "updatedAt": "", diff --git a/src/plugins/event_annotation/public/event_annotation_service/service.test.ts b/src/plugins/event_annotation/public/event_annotation_service/service.test.ts index b80219694b161..7a0f00e7a4de2 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/service.test.ts +++ b/src/plugins/event_annotation/public/event_annotation_service/service.test.ts @@ -24,7 +24,6 @@ const annotationGroupResolveMocks: Record = attributes: {} as EventAnnotationGroupSavedObjectAttributes, references: [], id: 'nonExistingGroup', - namespaces: ['default'], error: { error: 'Saved object not found', statusCode: 404, @@ -41,7 +40,6 @@ const annotationGroupResolveMocks: Record = dataViewSpec: null, }, type: 'event-annotation-group', - namespaces: ['default'], references: [ { id: 'ipid', @@ -61,7 +59,6 @@ const annotationGroupResolveMocks: Record = }, id: 'multiAnnotations', type: 'event-annotation-group', - namespaces: ['default'], references: [ { id: 'ipid', @@ -79,7 +76,6 @@ const annotationGroupResolveMocks: Record = } as Partial, id: 'multiAnnotations', type: 'event-annotation-group', - namespaces: ['default'], references: [], } as Partial as AnnotationGroupSavedObject, }; diff --git a/src/plugins/event_annotation_listing/public/components/table_list.test.tsx b/src/plugins/event_annotation_listing/public/components/table_list.test.tsx index aef902fad6e84..65970aeca3c7d 100644 --- a/src/plugins/event_annotation_listing/public/components/table_list.test.tsx +++ b/src/plugins/event_annotation_listing/public/components/table_list.test.tsx @@ -135,7 +135,6 @@ describe('annotation list view', () => { wrapper.find(TableListViewTable).prop('deleteItems')!([ { id: 'some-id-1', - namespaces: ['default'], references: [ { type: 'index-pattern', @@ -151,7 +150,6 @@ describe('annotation list view', () => { }, { id: 'some-id-2', - namespaces: ['default'], references: [], type: EVENT_ANNOTATION_GROUP_TYPE, updatedAt: '', From 892beab6209c63104cde9c786f0a76ed9230d546 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 29 Nov 2023 14:58:26 -0500 Subject: [PATCH 17/19] Revert "Add namespaces to graph saved object type" This reverts commit d8f62549af9a09689308ad8e0e0503035c7407c7. --- x-pack/plugins/graph/public/apps/listing_route.tsx | 1 - x-pack/plugins/graph/public/types/persistence.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/x-pack/plugins/graph/public/apps/listing_route.tsx b/x-pack/plugins/graph/public/apps/listing_route.tsx index 45d05d0d204ca..d5e7d2be00967 100644 --- a/x-pack/plugins/graph/public/apps/listing_route.tsx +++ b/x-pack/plugins/graph/public/apps/listing_route.tsx @@ -26,7 +26,6 @@ type GraphUserContent = UserContentCommonSchema; const toTableListViewSavedObject = (savedObject: GraphWorkspaceSavedObject): GraphUserContent => { return { id: savedObject.id!, - namespaces: savedObject.namespaces ?? [], updatedAt: savedObject.updatedAt!, references: savedObject.references ?? [], type: savedObject.type, diff --git a/x-pack/plugins/graph/public/types/persistence.ts b/x-pack/plugins/graph/public/types/persistence.ts index 3eeb070092e5c..f5c1366ff8661 100644 --- a/x-pack/plugins/graph/public/types/persistence.ts +++ b/x-pack/plugins/graph/public/types/persistence.ts @@ -34,7 +34,6 @@ export interface GraphWorkspaceSavedObject { legacyIndexPatternRef?: string; _source: Record; updatedAt?: string; - namespaces?: string[]; references: SavedObjectReference[]; } From b4c87d73761c8dea5cd7c52b13344db9bbddc68d Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 29 Nov 2023 14:59:01 -0500 Subject: [PATCH 18/19] Revert "Add namespaces to maps listing saved object" This reverts commit c8be79414c140922061214215503cf49f908c001. --- x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx index d881dc7541c0e..8c982a2853708 100644 --- a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx @@ -46,7 +46,6 @@ function navigateToNewMap() { const toTableListViewSavedObject = (mapItem: MapItem): MapUserContent => { return { ...mapItem, - namespaces: mapItem.namespaces ?? [], updatedAt: mapItem.updatedAt!, attributes: { ...mapItem.attributes, From 0b0c9904d4b0fe08f54deadcfb8fd6d765c6d274 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 29 Nov 2023 15:50:10 -0500 Subject: [PATCH 19/19] Make namespaces optional in UserContentCommonSchema --- .../table_list_view_table/src/table_list_view_table.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx index e6871b6d95c3a..ab13843021563 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx @@ -153,7 +153,7 @@ export interface UserContentCommonSchema { id: string; updatedAt: string; managed?: boolean; - namespaces: string[]; + namespaces?: string[]; references: SavedObjectsReference[]; type: string; attributes: { @@ -549,7 +549,7 @@ function TableListViewTableComp({