diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.displayname.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.displayname.md
new file mode 100644
index 0000000000000..71325318a68e6
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.displayname.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsTypeManagementDefinition](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.md) > [displayName](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.displayname.md)
+
+## SavedObjectsTypeManagementDefinition.displayName property
+
+When specified, will be used instead of the type's name in SO management section's labels.
+
+Signature:
+
+```typescript
+displayName?: string;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md
index 2c3dd9f3f8434..057eb6284bf9e 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md
@@ -17,6 +17,7 @@ export interface SavedObjectsTypeManagementDefinition
| Property | Type | Description |
| --- | --- | --- |
| [defaultSearchField](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.defaultsearchfield.md) | string | The default search field to use for this type. Defaults to id. |
+| [displayName](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.displayname.md) | string | When specified, will be used instead of the type's name in SO management section's labels. |
| [getEditUrl](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.getediturl.md) | (savedObject: SavedObject<Attributes>) => string | Function returning the url to use to redirect to the editing page of this object. If not defined, editing will not be allowed. |
| [getInAppUrl](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.getinappurl.md) | (savedObject: SavedObject<Attributes>) => {
path: string;
uiCapabilitiesPath: string;
} | Function returning the url to use to redirect to this object from the management section. If not defined, redirecting to the object will not be allowed. |
| [getTitle](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.gettitle.md) | (savedObject: SavedObject<Attributes>) => string | Function returning the title to display in the management table. If not defined, will use the object's type and id to generate a label. |
diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts
index b2a6be38bb526..7e38a52bee0ca 100644
--- a/src/core/server/saved_objects/types.ts
+++ b/src/core/server/saved_objects/types.ts
@@ -356,6 +356,10 @@ export interface SavedObjectsTypeManagementDefinition {
* Is the type importable or exportable. Defaults to `false`.
*/
importableAndExportable?: boolean;
+ /**
+ * When specified, will be used instead of the type's name in SO management section's labels.
+ */
+ displayName?: string;
/**
* When set to false, the type will not be listed or searchable in the SO management section.
* Main usage of setting this property to false for a type is when objects from the type should
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index 3c7aa8b992688..1ef845730e1f3 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -2739,6 +2739,7 @@ export interface SavedObjectsType {
// @public
export interface SavedObjectsTypeManagementDefinition {
defaultSearchField?: string;
+ displayName?: string;
getEditUrl?: (savedObject: SavedObject) => string;
getInAppUrl?: (savedObject: SavedObject) => {
path: string;
diff --git a/src/plugins/saved_objects_management/common/index.ts b/src/plugins/saved_objects_management/common/index.ts
index efabdace329c3..bc4631d2c8e61 100644
--- a/src/plugins/saved_objects_management/common/index.ts
+++ b/src/plugins/saved_objects_management/common/index.ts
@@ -13,4 +13,5 @@ export type {
SavedObjectRelationKind,
SavedObjectInvalidRelation,
SavedObjectGetRelationshipsResponse,
+ SavedObjectManagementTypeInfo,
} from './types';
diff --git a/src/plugins/saved_objects_management/common/types.ts b/src/plugins/saved_objects_management/common/types.ts
index 7899cd0938ad3..cb771a2aa0ab6 100644
--- a/src/plugins/saved_objects_management/common/types.ts
+++ b/src/plugins/saved_objects_management/common/types.ts
@@ -6,8 +6,8 @@
* Side Public License, v 1.
*/
-import { SavedObject } from 'src/core/types';
-import { SavedObjectsNamespaceType } from 'src/core/public';
+import type { SavedObject } from 'src/core/types';
+import type { SavedObjectsNamespaceType } from 'src/core/public';
/**
* The metadata injected into a {@link SavedObject | saved object} when returning
@@ -52,3 +52,10 @@ export interface SavedObjectGetRelationshipsResponse {
relations: SavedObjectRelation[];
invalidRelations: SavedObjectInvalidRelation[];
}
+
+export interface SavedObjectManagementTypeInfo {
+ name: string;
+ namespaceType: SavedObjectsNamespaceType;
+ hidden: boolean;
+ displayName: string;
+}
diff --git a/src/plugins/saved_objects_management/public/lib/get_allowed_types.ts b/src/plugins/saved_objects_management/public/lib/get_allowed_types.ts
index e2cf7518c54e9..b2465e09a3888 100644
--- a/src/plugins/saved_objects_management/public/lib/get_allowed_types.ts
+++ b/src/plugins/saved_objects_management/public/lib/get_allowed_types.ts
@@ -6,13 +6,14 @@
* Side Public License, v 1.
*/
-import { HttpStart } from 'src/core/public';
+import type { HttpStart } from 'src/core/public';
+import type { SavedObjectManagementTypeInfo } from '../../common/types';
interface GetAllowedTypesResponse {
- types: string[];
+ types: SavedObjectManagementTypeInfo[];
}
-export async function getAllowedTypes(http: HttpStart) {
+export async function getAllowedTypes(http: HttpStart): Promise {
const response = await http.get(
'/api/kibana/management/saved_objects/_allowed_types'
);
diff --git a/src/plugins/saved_objects_management/public/lib/get_saved_object_label.test.ts b/src/plugins/saved_objects_management/public/lib/get_saved_object_label.test.ts
new file mode 100644
index 0000000000000..d8f4f09c2bfa4
--- /dev/null
+++ b/src/plugins/saved_objects_management/public/lib/get_saved_object_label.test.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 type { SavedObjectManagementTypeInfo } from '../../common/types';
+import { getSavedObjectLabel } from './get_saved_object_label';
+
+const toTypeInfo = (name: string, displayName?: string): SavedObjectManagementTypeInfo => ({
+ name,
+ displayName: displayName ?? name,
+ hidden: false,
+ namespaceType: 'single',
+});
+
+describe('getSavedObjectLabel', () => {
+ it('returns the type name if no types are provided', () => {
+ expect(getSavedObjectLabel('foo', [])).toEqual('foo');
+ });
+
+ it('returns the type name if type does not specify a display name', () => {
+ expect(getSavedObjectLabel('foo', [toTypeInfo('foo')])).toEqual('foo');
+ });
+
+ it('returns the type display name if type does specify a display name', () => {
+ expect(getSavedObjectLabel('foo', [toTypeInfo('foo', 'fooDisplay')])).toEqual('fooDisplay');
+ });
+});
diff --git a/src/plugins/saved_objects_management/public/lib/get_saved_object_label.ts b/src/plugins/saved_objects_management/public/lib/get_saved_object_label.ts
index e86c200fb4fcc..753ffe9af6ce0 100644
--- a/src/plugins/saved_objects_management/public/lib/get_saved_object_label.ts
+++ b/src/plugins/saved_objects_management/public/lib/get_saved_object_label.ts
@@ -6,13 +6,12 @@
* Side Public License, v 1.
*/
-export function getSavedObjectLabel(type: string) {
- switch (type) {
- case 'index-pattern':
- case 'index-patterns':
- case 'indexPatterns':
- return 'index patterns';
- default:
- return type;
- }
+import type { SavedObjectManagementTypeInfo } from '../../common/types';
+
+/**
+ * Returns the label to be used for given saved object type.
+ */
+export function getSavedObjectLabel(type: string, types: SavedObjectManagementTypeInfo[]) {
+ const typeInfo = types.find((t) => t.name === type);
+ return typeInfo?.displayName ?? type;
}
diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx
index 45170ad14f92c..cbebc72b20c5a 100644
--- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx
@@ -14,6 +14,7 @@ import { i18n } from '@kbn/i18n';
import { EuiLoadingSpinner } from '@elastic/eui';
import { CoreSetup } from 'src/core/public';
import { ManagementAppMountParams } from '../../../management/public';
+import type { SavedObjectManagementTypeInfo } from '../../common/types';
import { StartDependencies, SavedObjectsManagementPluginStart } from '../plugin';
import { getAllowedTypes } from './../lib';
@@ -22,7 +23,7 @@ interface MountParams {
mountParams: ManagementAppMountParams;
}
-let allowedObjectTypes: string[] | undefined;
+let allowedObjectTypes: SavedObjectManagementTypeInfo[] | undefined;
const title = i18n.translate('savedObjectsManagement.objects.savedObjectsTitle', {
defaultMessage: 'Saved Objects',
@@ -33,15 +34,15 @@ const SavedObjectsTablePage = lazy(() => import('./saved_objects_table_page'));
export const mountManagementSection = async ({ core, mountParams }: MountParams) => {
const [coreStart, { data, savedObjectsTaggingOss, spaces: spacesApi }, pluginStart] =
await core.getStartServices();
+ const { capabilities } = coreStart.application;
const { element, history, setBreadcrumbs } = mountParams;
- if (allowedObjectTypes === undefined) {
+
+ if (!allowedObjectTypes) {
allowedObjectTypes = await getAllowedTypes(coreStart.http);
}
coreStart.chrome.docTitle.change(title);
- const capabilities = coreStart.application.capabilities;
-
const RedirectToHomeIfUnauthorized: React.FunctionComponent = ({ children }) => {
const allowed = capabilities?.management?.kibana?.objects ?? false;
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
index 327a9635462cc..f4325b277faba 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
@@ -2,6 +2,34 @@
exports[`SavedObjectsTable delete should show a confirm modal 1`] = `
@@ -374,13 +374,13 @@ exports[`Relationships should render invalid relations 1`] = `
>
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.test.tsx
index 76e85c9603cc0..396ef209cc396 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.test.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.test.tsx
@@ -9,7 +9,7 @@
import React from 'react';
import { findTestSubject } from '@elastic/eui/lib/test';
import { mountWithIntl } from '@kbn/test/jest';
-import { SavedObjectWithMetadata } from '../../../../common';
+import type { SavedObjectWithMetadata, SavedObjectManagementTypeInfo } from '../../../../common';
import { DeleteConfirmModal } from './delete_confirm_modal';
interface CreateObjectOptions {
@@ -32,6 +32,7 @@ const createObject = ({
});
describe('DeleteConfirmModal', () => {
+ const allowedTypes: SavedObjectManagementTypeInfo[] = [];
let onConfirm: jest.Mock;
let onCancel: jest.Mock;
@@ -47,6 +48,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={[]}
+ allowedTypes={allowedTypes}
/>
);
expect(wrapper.find('EuiLoadingElastic')).toHaveLength(1);
@@ -61,6 +63,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
+ allowedTypes={allowedTypes}
/>
);
expect(wrapper.find('.euiTableRow')).toHaveLength(3);
@@ -73,6 +76,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={[]}
+ allowedTypes={allowedTypes}
/>
);
wrapper.find('EuiButtonEmpty').simulate('click');
@@ -88,6 +92,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={[createObject()]}
+ allowedTypes={allowedTypes}
/>
);
wrapper.find('EuiButton').simulate('click');
@@ -109,6 +114,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
+ allowedTypes={allowedTypes}
/>
);
expect(wrapper.find('.euiTableRow')).toHaveLength(1);
@@ -126,6 +132,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
+ allowedTypes={allowedTypes}
/>
);
@@ -145,6 +152,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
+ allowedTypes={allowedTypes}
/>
);
@@ -164,6 +172,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
+ allowedTypes={allowedTypes}
/>
);
@@ -184,6 +193,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
+ allowedTypes={allowedTypes}
/>
);
const callout = findTestSubject(wrapper, 'sharedObjectsWarning');
@@ -202,6 +212,7 @@ describe('DeleteConfirmModal', () => {
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
+ allowedTypes={allowedTypes}
/>
);
const callout = findTestSubject(wrapper, 'sharedObjectsWarning');
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx
index e3ffc6d52a3ab..2ac3730da5142 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/delete_confirm_modal.tsx
@@ -27,7 +27,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import { SavedObjectWithMetadata } from '../../../../common';
+import type { SavedObjectWithMetadata, SavedObjectManagementTypeInfo } from '../../../../common';
import { getSavedObjectLabel } from '../../../lib';
export interface DeleteConfirmModalProps {
@@ -35,6 +35,7 @@ export interface DeleteConfirmModalProps {
onConfirm: () => void;
onCancel: () => void;
selectedObjects: SavedObjectWithMetadata[];
+ allowedTypes: SavedObjectManagementTypeInfo[];
}
export const DeleteConfirmModal: FC = ({
@@ -42,6 +43,7 @@ export const DeleteConfirmModal: FC = ({
onConfirm,
onCancel,
selectedObjects,
+ allowedTypes,
}) => {
const undeletableObjects = useMemo(() => {
return selectedObjects.filter((obj) => obj.meta.hiddenType);
@@ -145,7 +147,7 @@ export const DeleteConfirmModal: FC = ({
),
width: '50px',
render: (type, { icon }) => (
-
+
),
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx
index acdab1db40370..4cdacd30e83d1 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx
@@ -47,9 +47,9 @@ describe('Flyout', () => {
]),
} as any,
http,
- allowedTypes: ['search', 'index-pattern', 'visualization'],
search,
basePath,
+ allowedTypes: [],
};
});
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx
index 607b3aeeac275..92dbba2d23023 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx
@@ -37,6 +37,7 @@ import {
IndexPattern,
DataPublicPluginStart,
} from '../../../../../data/public';
+import type { SavedObjectManagementTypeInfo } from '../../../../common/types';
import {
importFile,
resolveImportErrors,
@@ -52,7 +53,6 @@ const CREATE_NEW_COPIES_DEFAULT = false;
const OVERWRITE_ALL_DEFAULT = true;
export interface FlyoutProps {
- allowedTypes: string[];
close: () => void;
done: () => void;
newIndexPatternUrl: string;
@@ -60,6 +60,7 @@ export interface FlyoutProps {
http: HttpStart;
basePath: IBasePath;
search: DataPublicPluginStart['search'];
+ allowedTypes: SavedObjectManagementTypeInfo[];
}
export interface FlyoutState {
@@ -408,6 +409,7 @@ export class Flyout extends Component {
}
renderBody() {
+ const { allowedTypes } = this.props;
const {
status,
loadingMessage,
@@ -439,6 +441,7 @@ export class Flyout extends Component {
failedImports={failedImports}
successfulImports={successfulImports}
importWarnings={importWarnings ?? []}
+ allowedTypes={allowedTypes}
/>
);
}
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx
index 5ac428b3e6ba3..4cbfcb06b3595 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx
@@ -24,6 +24,7 @@ describe('ImportSummary', () => {
failedImports: [],
successfulImports: [],
importWarnings: [],
+ allowedTypes: [],
...parts,
});
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx
index c24faf4e12687..18f49407cdec1 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx
@@ -28,6 +28,7 @@ import type {
SavedObjectsImportWarning,
IBasePath,
} from 'kibana/public';
+import type { SavedObjectManagementTypeInfo } from '../../../../common/types';
import { getDefaultTitle, getSavedObjectLabel, FailedImport } from '../../../lib';
import './import_summary.scss';
@@ -38,6 +39,7 @@ export interface ImportSummaryProps {
successfulImports: SavedObjectsImportSuccess[];
importWarnings: SavedObjectsImportWarning[];
basePath: IBasePath;
+ allowedTypes: SavedObjectManagementTypeInfo[];
}
interface ImportItem {
@@ -244,6 +246,7 @@ export const ImportSummary: FC = ({
successfulImports,
importWarnings,
basePath,
+ allowedTypes,
}) => {
const importItems: ImportItem[] = useMemo(
() =>
@@ -279,6 +282,7 @@ export const ImportSummary: FC = ({
{importItems.map((item, index) => {
const { type, title, icon } = item;
+ const typeLabel = getSavedObjectLabel(type, allowedTypes);
return (
= ({
className="savedObjectsManagementImportSummary__row"
>
-
-
+
+
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx
index b31c8ebbc4e9e..8f859cd594f92 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx
@@ -9,6 +9,7 @@
import React from 'react';
import { shallowWithI18nProvider } from '@kbn/test/jest';
import { httpServiceMock } from '../../../../../../core/public/mocks';
+import type { SavedObjectManagementTypeInfo } from '../../../../common/types';
import { Relationships, RelationshipsProps } from './relationships';
jest.mock('../../../lib/fetch_export_by_type_and_search', () => ({
@@ -19,6 +20,15 @@ jest.mock('../../../lib/fetch_export_objects', () => ({
fetchExportObjects: jest.fn(),
}));
+const allowedTypes: SavedObjectManagementTypeInfo[] = [
+ {
+ name: 'index-pattern',
+ displayName: 'index-pattern',
+ namespaceType: 'single',
+ hidden: false,
+ },
+];
+
describe('Relationships', () => {
it('should render index patterns normally', async () => {
const props: RelationshipsProps = {
@@ -71,6 +81,7 @@ describe('Relationships', () => {
},
},
},
+ allowedTypes,
close: jest.fn(),
};
@@ -139,6 +150,7 @@ describe('Relationships', () => {
},
},
},
+ allowedTypes,
close: jest.fn(),
};
@@ -206,6 +218,7 @@ describe('Relationships', () => {
},
},
},
+ allowedTypes,
close: jest.fn(),
};
@@ -273,6 +286,7 @@ describe('Relationships', () => {
},
},
},
+ allowedTypes,
close: jest.fn(),
};
@@ -312,6 +326,7 @@ describe('Relationships', () => {
},
},
},
+ allowedTypes,
close: jest.fn(),
};
@@ -357,6 +372,7 @@ describe('Relationships', () => {
},
},
},
+ allowedTypes,
close: jest.fn(),
};
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx
index 8eb48ac91da66..3c518296e5ccd 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx
@@ -25,6 +25,7 @@ import { SearchFilterConfig } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { IBasePath } from 'src/core/public';
+import type { SavedObjectManagementTypeInfo } from '../../../../common/types';
import { getDefaultTitle, getSavedObjectLabel } from '../../../lib';
import {
SavedObjectWithMetadata,
@@ -41,6 +42,7 @@ export interface RelationshipsProps {
close: () => void;
goInspectObject: (obj: SavedObjectWithMetadata) => void;
canGoInApp: (obj: SavedObjectWithMetadata) => boolean;
+ allowedTypes: SavedObjectManagementTypeInfo[];
}
export interface RelationshipsState {
@@ -213,7 +215,7 @@ export class Relationships extends Component {
+ const typeLabel = getSavedObjectLabel(type, allowedTypes);
return (
-
+
-
-
+
+
{savedObject.meta.title || getDefaultTitle(savedObject)}
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx
index 98aa29a92856e..a736c7a8a7c5e 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx
@@ -36,6 +36,9 @@ const defaultProps: TableProps = {
},
},
],
+ allowedTypes: [
+ { name: 'index-pattern', displayName: 'index-pattern', hidden: false, namespaceType: 'single' },
+ ],
selectionConfig: {
onSelectionChange: () => {},
},
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
index 0645c0955f7ac..75f36e20eb084 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
@@ -28,6 +28,7 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { SavedObjectsTaggingApi } from '../../../../../saved_objects_tagging_oss/public';
+import type { SavedObjectManagementTypeInfo } from '../../../../common/types';
import { getDefaultTitle, getSavedObjectLabel } from '../../../lib';
import { SavedObjectWithMetadata } from '../../../types';
import {
@@ -39,6 +40,7 @@ import {
export interface TableProps {
taggingApi?: SavedObjectsTaggingApi;
basePath: IBasePath;
+ allowedTypes: SavedObjectManagementTypeInfo[];
actionRegistry: SavedObjectsManagementActionServiceStart;
columnRegistry: SavedObjectsManagementColumnServiceStart;
selectedSavedObjects: SavedObjectWithMetadata[];
@@ -145,6 +147,7 @@ export class Table extends PureComponent {
actionRegistry,
columnRegistry,
taggingApi,
+ allowedTypes,
} = this.props;
const pagination = {
@@ -182,10 +185,11 @@ export class Table extends PureComponent {
sortable: false,
'data-test-subj': 'savedObjectsTableRowType',
render: (type: string, object: SavedObjectWithMetadata) => {
+ const typeLabel = getSavedObjectLabel(type, allowedTypes);
return (
-
+
({
+ name: type,
+ displayName: type,
+ hidden: false,
+ namespaceType: 'single',
+});
+
+const allowedTypes = ['index-pattern', 'visualization', 'dashboard', 'search'].map(convertType);
const allSavedObjects = [
{
@@ -377,7 +385,7 @@ describe('SavedObjectsTable', () => {
expect(fetchExportByTypeAndSearchMock).toHaveBeenCalledWith({
http,
- types: allowedTypes,
+ types: allowedTypes.map((type) => type.name),
includeReferencesDeep: true,
});
expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
@@ -406,7 +414,7 @@ describe('SavedObjectsTable', () => {
expect(fetchExportByTypeAndSearchMock).toHaveBeenCalledWith({
http,
- types: allowedTypes,
+ types: allowedTypes.map((type) => type.name),
search: 'test*',
includeReferencesDeep: true,
});
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
index 5001b52e819c2..15db82d06d09b 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
@@ -23,6 +23,7 @@ import {
import { RedirectAppLinks } from '../../../../kibana_react/public';
import { SavedObjectsTaggingApi } from '../../../../saved_objects_tagging_oss/public';
import { IndexPatternsContract } from '../../../../data/public';
+import type { SavedObjectManagementTypeInfo } from '../../../common/types';
import {
parseQuery,
getSavedObjectCounts,
@@ -56,7 +57,7 @@ interface ExportAllOption {
}
export interface SavedObjectsTableProps {
- allowedTypes: string[];
+ allowedTypes: SavedObjectManagementTypeInfo[];
actionRegistry: SavedObjectsManagementActionServiceStart;
columnRegistry: SavedObjectsManagementColumnServiceStart;
savedObjectsClient: SavedObjectsClientContract;
@@ -102,6 +103,7 @@ const unableFindSavedObjectNotificationMessage = i18n.translate(
'savedObjectsManagement.objectsTable.unableFindSavedObjectNotificationMessage',
{ defaultMessage: 'Unable to find saved object' }
);
+
export class SavedObjectsTable extends Component {
private _isMounted = false;
@@ -114,7 +116,7 @@ export class SavedObjectsTable extends Component {
- typeToCountMap[type] = 0;
+ typeToCountMap[type.name] = 0;
return typeToCountMap;
}, {} as Record),
activeQuery: props.initialQuery ?? Query.parse(''),
@@ -146,9 +148,11 @@ export class SavedObjectsTable extends Component {
- const { allowedTypes, taggingApi } = this.props;
+ const { taggingApi } = this.props;
const { queryText, visibleTypes, selectedTags } = parseQuery(this.state.activeQuery);
+ const allowedTypes = this.props.allowedTypes.map((type) => type.name);
+
const selectedTypes = allowedTypes.filter(
(type) => !visibleTypes || visibleTypes.includes(type)
);
@@ -207,6 +211,11 @@ export class SavedObjectsTable extends Component type.name)
+ .filter((type) => !visibleTypes || visibleTypes.includes(type));
+
// "searchFields" is missing from the "findOptions" but gets injected via the API.
// The API extracts the fields from each uiExports.savedObjectsManagement "defaultSearchField" attribute
const findOptions: SavedObjectsFindOptions = {
@@ -214,7 +223,7 @@ export class SavedObjectsTable extends Component !visibleTypes || visibleTypes.includes(type)),
+ type: searchTypes,
};
if (findOptions.type.length > 1) {
findOptions.sortField = 'type';
@@ -520,8 +529,9 @@ export class SavedObjectsTable extends Component {
- const { allowedTypes, http } = this.props;
- return await getRelationships(http, type, id, allowedTypes);
+ const { http } = this.props;
+ const allowedTypeNames = this.props.allowedTypes.map((t) => t.name);
+ return await getRelationships(http, type, id, allowedTypeNames);
};
renderFlyout() {
@@ -540,9 +550,9 @@ export class SavedObjectsTable extends Component
);
}
@@ -560,12 +570,15 @@ export class SavedObjectsTable extends Component
);
}
renderDeleteConfirmModal() {
const { isShowingDeleteConfirmModal, isDeleting, selectedSavedObjects } = this.state;
+ const { allowedTypes } = this.props;
+
if (!isShowingDeleteConfirmModal) {
return null;
}
@@ -580,6 +593,7 @@ export class SavedObjectsTable extends Component
);
}
@@ -638,9 +652,9 @@ export class SavedObjectsTable extends Component ({
- value: type,
- name: type,
- view: `${type} (${savedObjectCounts[type] || 0})`,
+ value: type.name,
+ name: type.name,
+ view: `${type.displayName} (${savedObjectCounts[type.name] || 0})`,
}));
return (
@@ -661,6 +675,7 @@ export class SavedObjectsTable extends Component void;
diff --git a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts
index ce371ea590230..65465fbfa67d8 100644
--- a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts
+++ b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts
@@ -6,7 +6,17 @@
* Side Public License, v 1.
*/
-import { IRouter } from 'src/core/server';
+import { IRouter, SavedObjectsType } from 'src/core/server';
+import { SavedObjectManagementTypeInfo } from '../../common';
+
+const convertType = (sot: SavedObjectsType): SavedObjectManagementTypeInfo => {
+ return {
+ name: sot.name,
+ namespaceType: sot.namespaceType,
+ hidden: sot.hidden,
+ displayName: sot.management?.displayName ?? sot.name,
+ };
+};
export const registerGetAllowedTypesRoute = (router: IRouter) => {
router.get(
@@ -18,7 +28,7 @@ export const registerGetAllowedTypesRoute = (router: IRouter) => {
const allowedTypes = context.core.savedObjects.typeRegistry
.getImportableAndExportableTypes()
.filter((type) => type.management!.visibleInManagement ?? true)
- .map((type) => type.name);
+ .map(convertType);
return res.ok({
body: {
diff --git a/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts b/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts
index 0cb6a5ba8eb5d..0fd5c467d081b 100644
--- a/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts
+++ b/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts
@@ -212,6 +212,24 @@ export class SavedObjectExportTransformsPlugin implements Plugin {
visibleInManagement: true,
},
});
+
+ // example of a SO type specifying a display name
+ savedObjects.registerType<{ enabled: boolean; title: string }>({
+ name: 'test-with-display-name',
+ hidden: false,
+ namespaceType: 'single',
+ mappings: {
+ properties: {
+ title: { type: 'text' },
+ enabled: { type: 'boolean' },
+ },
+ },
+ management: {
+ defaultSearchField: 'title',
+ importableAndExportable: true,
+ displayName: 'my display name',
+ },
+ });
}
public start() {}
diff --git a/test/plugin_functional/test_suites/saved_objects_management/visible_in_management.ts b/test/plugin_functional/test_suites/saved_objects_management/visible_in_management.ts
index dd43ba80a8e8e..e6d8aa4189f28 100644
--- a/test/plugin_functional/test_suites/saved_objects_management/visible_in_management.ts
+++ b/test/plugin_functional/test_suites/saved_objects_management/visible_in_management.ts
@@ -11,6 +11,7 @@ import expect from '@kbn/expect';
import type { Response } from 'supertest';
import type { PluginFunctionalProviderContext } from '../../services';
import { SavedObject } from '../../../../src/core/types';
+import type { SavedObjectManagementTypeInfo } from '../../../../src/plugins/saved_objects_management/common/types';
function parseNdJson(input: string): Array> {
return input.split('\n').map((str) => JSON.parse(str));
@@ -97,17 +98,39 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
});
describe('savedObjects management APIS', () => {
- it('GET /api/kibana/management/saved_objects/_allowed_types should only return types that are `visibleInManagement: true`', async () =>
- await supertest
- .get('/api/kibana/management/saved_objects/_allowed_types')
- .set('kbn-xsrf', 'true')
- .expect(200)
- .then((response: Response) => {
- const { types } = response.body;
- expect(types.includes('test-is-exportable')).to.eql(true);
- expect(types.includes('test-visible-in-management')).to.eql(true);
- expect(types.includes('test-not-visible-in-management')).to.eql(false);
- }));
+ describe('GET /api/kibana/management/saved_objects/_allowed_types', () => {
+ let types: SavedObjectManagementTypeInfo[];
+
+ before(async () => {
+ await supertest
+ .get('/api/kibana/management/saved_objects/_allowed_types')
+ .set('kbn-xsrf', 'true')
+ .expect(200)
+ .then((response: Response) => {
+ types = response.body.types as SavedObjectManagementTypeInfo[];
+ });
+ });
+
+ it('should only return types that are `visibleInManagement: true`', () => {
+ const typeNames = types.map((type) => type.name);
+
+ expect(typeNames.includes('test-is-exportable')).to.eql(true);
+ expect(typeNames.includes('test-visible-in-management')).to.eql(true);
+ expect(typeNames.includes('test-not-visible-in-management')).to.eql(false);
+ });
+
+ it('should return displayName for types specifying it', () => {
+ const typeWithDisplayName = types.find((type) => type.name === 'test-with-display-name');
+ expect(typeWithDisplayName !== undefined).to.eql(true);
+ expect(typeWithDisplayName!.displayName).to.eql('my display name');
+
+ const typeWithoutDisplayName = types.find(
+ (type) => type.name === 'test-visible-in-management'
+ );
+ expect(typeWithoutDisplayName !== undefined).to.eql(true);
+ expect(typeWithoutDisplayName!.displayName).to.eql('test-visible-in-management');
+ });
+ });
});
});
}