diff --git a/package.json b/package.json index 738a550d56f43..59d3aef5b77e5 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "@kbn/config": "link:bazel-bin/packages/kbn-config", "@kbn/config-mocks": "link:bazel-bin/packages/kbn-config-mocks", "@kbn/config-schema": "link:bazel-bin/packages/kbn-config-schema", - "@kbn/content-management-table-list": "link:bazel-bin/packages/kbn-content-management-table-list", + "@kbn/content-management-table-list": "link:bazel-bin/packages/content-management/table_list", "@kbn/core-analytics-browser": "link:bazel-bin/packages/core/analytics/core-analytics-browser", "@kbn/core-analytics-browser-internal": "link:bazel-bin/packages/core/analytics/core-analytics-browser-internal", "@kbn/core-analytics-browser-mocks": "link:bazel-bin/packages/core/analytics/core-analytics-browser-mocks", @@ -801,7 +801,7 @@ "@types/kbn__config": "link:bazel-bin/packages/kbn-config/npm_module_types", "@types/kbn__config-mocks": "link:bazel-bin/packages/kbn-config-mocks/npm_module_types", "@types/kbn__config-schema": "link:bazel-bin/packages/kbn-config-schema/npm_module_types", - "@types/kbn__content-management-table-list": "link:bazel-bin/packages/kbn-content-management-table-list/npm_module_types", + "@types/kbn__content-management-table-list": "link:bazel-bin/packages/content-management/table_list/npm_module_types", "@types/kbn__core-analytics-browser": "link:bazel-bin/packages/core/analytics/core-analytics-browser/npm_module_types", "@types/kbn__core-analytics-browser-internal": "link:bazel-bin/packages/core/analytics/core-analytics-browser-internal/npm_module_types", "@types/kbn__core-analytics-browser-mocks": "link:bazel-bin/packages/core/analytics/core-analytics-browser-mocks/npm_module_types", diff --git a/packages/content-management/table_list/BUILD.bazel b/packages/content-management/table_list/BUILD.bazel index fb2252040b6b4..71827f9b27954 100644 --- a/packages/content-management/table_list/BUILD.bazel +++ b/packages/content-management/table_list/BUILD.bazel @@ -2,17 +2,26 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config") load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") -PKG_DIRNAME = "kbn-content-management-table-list" +PKG_DIRNAME = "table_list" PKG_REQUIRE_NAME = "@kbn/content-management-table-list" SOURCE_FILES = glob( [ - "src/**/*.ts", - "src/**/*.tsx", + "**/*.ts", + "**/*.tsx", ], exclude = [ + "**/*.config.js", + "**/*.mock.*", "**/*.test.*", "**/*.stories.*", + "**/__snapshots__", + "**/integration_tests", + "**/mocks", + "**/scripts", + "**/storybook", + "**/test_fixtures", + "**/test_helpers", ], ) @@ -113,7 +122,7 @@ ts_project( declaration_map = True, emit_declaration_only = True, out_dir = "target_types", - root_dir = "src", + root_dir = ".", tsconfig = ":tsconfig", ) diff --git a/packages/content-management/table_list/index.ts b/packages/content-management/table_list/index.ts new file mode 100644 index 0000000000000..fc9e9cc997bb5 --- /dev/null +++ b/packages/content-management/table_list/index.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export { TableListViewKibanaProvider, TableListViewProvider, TableListView } from './src'; + +export type { UserContentCommonSchema } from './src'; diff --git a/packages/content-management/table_list/src/__jest__/tests.helpers.tsx b/packages/content-management/table_list/src/__jest__/tests.helpers.tsx index 5f2703fa71216..24cbdac0a9279 100644 --- a/packages/content-management/table_list/src/__jest__/tests.helpers.tsx +++ b/packages/content-management/table_list/src/__jest__/tests.helpers.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import React from 'react'; -import type { ComponentType, MemoExoticComponent } from 'react'; +import type { ComponentType } from 'react'; import { TableListViewProvider, Services } from '../table_list_view/services'; export const getMockServices = (overrides?: Partial) => { @@ -20,10 +20,7 @@ export const getMockServices = (overrides?: Partial) => { return services; }; -export function WithServices

( - Comp: MemoExoticComponent>, - overrides: Partial = {} -) { +export function WithServices

(Comp: ComponentType

, overrides: Partial = {}) { return (props: P) => { const services = getMockServices(overrides); return ( diff --git a/packages/content-management/table_list/src/index.ts b/packages/content-management/table_list/src/index.ts index 993ad9240fb52..024531c4578fb 100644 --- a/packages/content-management/table_list/src/index.ts +++ b/packages/content-management/table_list/src/index.ts @@ -6,6 +6,10 @@ * Side Public License, v 1. */ -export { TableListView, TableListViewProvider } from './table_list_view'; +export { + TableListView, + TableListViewProvider, + TableListViewKibanaProvider, +} from './table_list_view'; export type { UserContentCommonSchema } from './table_list_view'; diff --git a/packages/content-management/table_list/src/table_list_view/index.ts b/packages/content-management/table_list/src/table_list_view/index.ts index 0f4b2647dd1ab..df0d1e22bc106 100644 --- a/packages/content-management/table_list/src/table_list_view/index.ts +++ b/packages/content-management/table_list/src/table_list_view/index.ts @@ -14,4 +14,4 @@ export type { UserContentCommonSchema, } from './table_list_view'; -export { TableListViewProvider } from './services'; +export { TableListViewProvider, TableListViewKibanaProvider } from './services'; diff --git a/packages/content-management/table_list/src/table_list_view/mocks.ts b/packages/content-management/table_list/src/table_list_view/mocks.ts index 5b33480623122..11775dc0006ab 100644 --- a/packages/content-management/table_list/src/table_list_view/mocks.ts +++ b/packages/content-management/table_list/src/table_list_view/mocks.ts @@ -20,7 +20,7 @@ export const getStoryServices = (params: Params, action: ActionFn = () => {}) => const services: Services = { canEditAdvancedSettings: true, getListingLimitSettingsUrl: () => 'http://elastic.co', - notifyError: ({ title, text }) => { + notifyError: (title, text) => { action('notifyError')({ title, text }); }, ...params, diff --git a/packages/content-management/table_list/src/table_list_view/services.tsx b/packages/content-management/table_list/src/table_list_view/services.tsx index 470268db9bd56..37bbc224ed761 100644 --- a/packages/content-management/table_list/src/table_list_view/services.tsx +++ b/packages/content-management/table_list/src/table_list_view/services.tsx @@ -8,14 +8,18 @@ import React, { FC, useContext } from 'react'; import type { EuiTableFieldDataColumnType, SearchFilterConfig } from '@elastic/eui'; +import type { Observable } from 'rxjs'; import { UserContentCommonSchema } from './table_list_view'; -type NotifyFn = (notifyArgs: { title: string | JSX.Element; text: string }) => void; +type UnmountCallback = () => void; +type MountPoint = (element: HTMLElement) => UnmountCallback; +type NotifyFn = (title: JSX.Element, text?: string) => void; -interface SavedObjectsReference { - type: string; +export interface SavedObjectsReference { id: string; + name: string; + type: string; } export type DateFormatter = (props: { @@ -30,11 +34,11 @@ export interface Services { canEditAdvancedSettings: boolean; getListingLimitSettingsUrl: () => string; notifyError: NotifyFn; - getTagsColumnDefinition?: () => EuiTableFieldDataColumnType | undefined; searchQueryParser?: (searchQuery: string) => { searchQuery: string; references?: SavedObjectsReference[]; }; + getTagsColumnDefinition?: () => EuiTableFieldDataColumnType | undefined; getSearchBarFilters?: () => SearchFilterConfig[]; DateFormatterComp?: DateFormatter; } @@ -48,6 +52,78 @@ export const TableListViewProvider: FC = ({ children, ...services }) = return {children}; }; +/** + * Kibana-specific service types. + */ + +export interface TableListViewKibanaDependencies { + core: { + application: { + capabilities: { + advancedSettings?: { + save: boolean; + }; + }; + getUrlForApp: (app: string, options: { path: string }) => string; + }; + notifications: { + toasts: { + addDanger: (notifyArgs: { title: MountPoint; text?: string }) => void; + }; + }; + }; + toMountPoint: ( + node: React.ReactNode, + options?: { theme$: Observable<{ readonly darkMode: boolean }> } + ) => MountPoint; + savedObjectTaggingApi?: { + ui: { + getTableColumnDefinition: () => EuiTableFieldDataColumnType; + parseSearchQuery: ( + query: string, + options?: { + useName?: boolean; + tagField?: string; + } + ) => { + searchTerm: string; + tagReferences: SavedObjectsReference[]; + valid: boolean; + }; + getSearchBarFilter: (options?: { + useName?: boolean; + tagField?: string; + }) => SearchFilterConfig; + }; + }; +} + +/** + * Kibana-specific Provider that maps to known dependency types. + */ +export const TableListViewKibanaProvider: FC = ({ + children, + ...services +}) => { + const { core, toMountPoint, savedObjectTaggingApi } = services; + return ( + + core.application.getUrlForApp('management', { + path: `/kibana/settings?query=savedObjects:listingLimit`, + }) + } + notifyError={(title, text) => { + core.notifications.toasts.addDanger({ title: toMountPoint(title), text }); + }} + getTagsColumnDefinition={savedObjectTaggingApi?.ui.getTableColumnDefinition} + > + {children} + + ); +}; + /** * React hook for accessing pre-wired services. */ diff --git a/packages/content-management/table_list/src/table_list_view/table_list_view.stories.tsx b/packages/content-management/table_list/src/table_list_view/table_list_view.stories.tsx index 6429873920ced..388edbd98905a 100644 --- a/packages/content-management/table_list/src/table_list_view/table_list_view.stories.tsx +++ b/packages/content-management/table_list/src/table_list_view/table_list_view.stories.tsx @@ -36,12 +36,12 @@ const createMockItems = (total: number) => { return { id: i.toString(), + type, references: [], updatedAt: moment().subtract(i, 'day').format('YYYY-MM-DDTHH:mm:ss'), attributes: { title: chance.sentence({ words: 5 }), description: `Description of item ${i}`, - type, }, }; }); diff --git a/packages/content-management/table_list/src/table_list_view/table_list_view.test.tsx b/packages/content-management/table_list/src/table_list_view/table_list_view.test.tsx index c222373936a24..50af27d14bbd8 100644 --- a/packages/content-management/table_list/src/table_list_view/table_list_view.test.tsx +++ b/packages/content-management/table_list/src/table_list_view/table_list_view.test.tsx @@ -54,12 +54,13 @@ describe('TableListView', () => { jest.useRealTimers(); }); - type Props = TableListViewProps; - - const setup = registerTestBed(WithServices(TableListView), { - defaultProps: { ...requiredProps }, - memoryRouter: { wrapComponent: false }, - }); + const setup = registerTestBed( + WithServices(TableListView), + { + defaultProps: { ...requiredProps }, + memoryRouter: { wrapComponent: false }, + } + ); test('render default empty prompt', async () => { let testBed: TestBed; diff --git a/packages/content-management/table_list/src/table_list_view/table_list_view.tsx b/packages/content-management/table_list/src/table_list_view/table_list_view.tsx index 3ed8870820507..cc2f8b17e352d 100644 --- a/packages/content-management/table_list/src/table_list_view/table_list_view.tsx +++ b/packages/content-management/table_list/src/table_list_view/table_list_view.tsx @@ -27,14 +27,10 @@ import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { Table, ConfirmDeleteModal, ListingLimitWarning } from './components'; import { useServices } from './services'; +import type { SavedObjectsReference } from './services'; import type { Action } from './actions'; import { reducer } from './reducer'; -interface SavedObjectsReference { - type: string; - id: string; -} - export interface Props { entityName: string; entityNamePlural: string; @@ -83,6 +79,7 @@ export interface UserContentCommonSchema { id: string; updatedAt: string; references: SavedObjectsReference[]; + type: string; attributes: { title: string; description?: string; @@ -278,16 +275,14 @@ function TableListViewComp({ try { await deleteItems!(selectedItems); } catch (error) { - notifyError({ - title: ( - - ), - text: error, - }); + notifyError( + , + error + ); } fetchItems(); @@ -460,7 +455,7 @@ function TableListViewComp({ ); } -const TableListView = React.memo(TableListViewComp); +const TableListView = React.memo(TableListViewComp) as typeof TableListViewComp; export { TableListView }; diff --git a/packages/content-management/table_list/tsconfig.json b/packages/content-management/table_list/tsconfig.json index 5c91fe545126c..ecd4b967ad06a 100644 --- a/packages/content-management/table_list/tsconfig.json +++ b/packages/content-management/table_list/tsconfig.json @@ -5,7 +5,7 @@ "declarationMap": true, "emitDeclarationOnly": true, "outDir": "target_types", - "rootDir": "src", + "rootDir": ".", "stripInternal": false, "types": [ "jest", @@ -16,6 +16,7 @@ ] }, "include": [ - "src/**/*" + "**/*.ts", + "**/*.tsx", ] } diff --git a/src/plugins/dashboard/public/application/dashboard_router.tsx b/src/plugins/dashboard/public/application/dashboard_router.tsx index adafcb3d1f6dd..38f65b44906b0 100644 --- a/src/plugins/dashboard/public/application/dashboard_router.tsx +++ b/src/plugins/dashboard/public/application/dashboard_router.tsx @@ -15,6 +15,8 @@ import { I18nProvider } from '@kbn/i18n-react'; import { parse, ParsedQuery } from 'query-string'; import { render, unmountComponentAtNode } from 'react-dom'; import { Switch, Route, RouteComponentProps, HashRouter, Redirect } from 'react-router-dom'; +import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { TableListViewKibanaProvider } from '@kbn/content-management-table-list'; import { DashboardListing } from './listing'; import { dashboardStateStore } from './state'; @@ -93,6 +95,7 @@ export async function mountApp({ let globalEmbedSettings: DashboardEmbedSettings | undefined; let routerHistory: History; + const savedObjectsTagging = savedObjectsTaggingOss?.getTaggingApi(); const dashboardServices: DashboardAppServices = { navigation, onAppLeave, @@ -116,7 +119,7 @@ export async function mountApp({ savedQueryService: dataStart.query.savedQueries, savedObjectsClient: coreStart.savedObjects.client, savedDashboards: dashboardStart.getSavedDashboardLoader(), - savedObjectsTagging: savedObjectsTaggingOss?.getTaggingApi(), + savedObjectsTagging, allowByValueEmbeddables: initializerContext.config.get().allowByValueEmbeddables, dashboardCapabilities: { @@ -229,26 +232,34 @@ export async function mountApp({ - - - - - - - - - - + + + + + + + + + + + + diff --git a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx index 17433562bcdab..8af80ff85f397 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx +++ b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx @@ -11,17 +11,22 @@ import { EuiLink, EuiButton, EuiEmptyPrompt, - EuiBasicTableColumn, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty, } from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { ApplicationStart, SavedObjectsFindOptionsReference } from '@kbn/core/public'; +import { SavedObjectsFindOptionsReference } from '@kbn/core/public'; import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; import useMount from 'react-use/lib/useMount'; +import { TableListView } from '@kbn/content-management-table-list'; + import { attemptLoadDashboardByTitle } from '../lib'; -import { DashboardAppServices, DashboardRedirect } from '../../types'; +import { + DashboardAppServices, + DashboardRedirect, + DashboardSavedObjectUserContent, +} from '../../types'; import { getDashboardBreadcrumb, dashboardListingTable, @@ -30,9 +35,9 @@ import { getNewDashboardTitle, } from '../../dashboard_strings'; import { syncQueryStateWithUrl } from '../../services/data'; +import { SavedObjectLoader } from '../../services/saved_objects'; import { IKbnUrlStateStorage } from '../../services/kibana_utils'; -import { TableListView, useKibana } from '../../services/kibana_react'; -import { SavedObjectsTaggingApi } from '../../services/saved_objects_tagging_oss'; +import { useKibana } from '../../services/kibana_react'; import { DashboardUnsavedListing } from './dashboard_unsaved_listing'; import { confirmCreateWithUnsaved, confirmDiscardUnsavedChanges } from './confirm_overlays'; import { getDashboardListItemLink } from './get_dashboard_list_item_link'; @@ -42,6 +47,21 @@ import { DashboardAppNoDataPage, isDashboardAppInNoDataState } from '../dashboar const SAVED_OBJECTS_LIMIT_SETTING = 'savedObjects:listingLimit'; const SAVED_OBJECTS_PER_PAGE_SETTING = 'savedObjects:perPage'; +const toTableListViewSavedObject = ( + savedObject: ReturnType +): DashboardSavedObjectUserContent => { + return { + id: savedObject.id, + updatedAt: savedObject.updatedAt!, + references: savedObject.references, + type: savedObject.type, + attributes: { + title: savedObject.title ?? '', + timeRestore: savedObject.timeRestore, + }, + }; +}; + export interface DashboardListingProps { kbnUrlStateStorage: IKbnUrlStateStorage; redirectTo: DashboardRedirect; @@ -62,7 +82,6 @@ export const DashboardListing = ({ dataViews, savedDashboards, savedObjectsClient, - savedObjectsTagging, dashboardCapabilities, dashboardSessionStorage, chrome: { setBreadcrumbs }, @@ -119,17 +138,6 @@ export const DashboardListing = ({ const initialPageSize = core.uiSettings.get(SAVED_OBJECTS_PER_PAGE_SETTING); const defaultFilter = title ? `"${title}"` : ''; - const tableColumns = useMemo( - () => - getTableColumns( - core.application, - kbnUrlStateStorage, - core.uiSettings.get('state:storeInSessionStorage'), - savedObjectsTagging - ), - [core.application, core.uiSettings, kbnUrlStateStorage, savedObjectsTagging] - ); - const createItem = useCallback(() => { if (!dashboardSessionStorage.dashboardHasUnsavedEdits()) { redirectTo({ destination: 'dashboard' }); @@ -250,23 +258,20 @@ export const DashboardListing = ({ ]); const fetchItems = useCallback( - (filter: string) => { - let searchTerm = filter; - let references: SavedObjectsFindOptionsReference[] | undefined; - if (savedObjectsTagging) { - const parsed = savedObjectsTagging.ui.parseSearchQuery(filter, { - useName: true, + (searchTerm: string, references?: SavedObjectsFindOptionsReference[]) => { + return savedDashboards + .find(searchTerm, { + hasReference: references, + size: listingLimit, + }) + .then(({ total, hits }) => { + return { + total, + hits: hits.map(toTableListViewSavedObject), + }; }); - searchTerm = parsed.searchTerm; - references = parsed.tagReferences; - } - - return savedDashboards.find(searchTerm, { - size: listingLimit, - hasReference: references, - }); }, - [listingLimit, savedDashboards, savedObjectsTagging] + [listingLimit, savedDashboards] ); const deleteItems = useCallback( @@ -284,42 +289,35 @@ export const DashboardListing = ({ [redirectTo] ); - const searchFilters = useMemo(() => { - return savedObjectsTagging - ? [savedObjectsTagging.ui.getSearchBarFilter({ useName: true })] - : []; - }, [savedObjectsTagging]); - - const { getEntityName, getTableCaption, getTableListTitle, getEntityNamePlural } = - dashboardListingTable; + const { getEntityName, getTableListTitle, getEntityNamePlural } = dashboardListingTable; return ( <> {showNoDataPage && ( setShowNoDataPage(false)} /> )} {!showNoDataPage && ( - + entityName={getEntityName()} + entityNamePlural={getEntityNamePlural()} + tableListTitle={getTableListTitle()} initialFilter={initialFilter ?? defaultFilter} - toastNotifications={core.notifications.toasts} + initialPageSize={initialPageSize} + emptyPrompt={emptyPrompt} headingId="dashboardListingHeading" findItems={fetchItems} - rowHeader="title" - entityNamePlural={getEntityNamePlural()} - tableListTitle={getTableListTitle()} - tableCaption={getTableCaption()} - entityName={getEntityName()} - {...{ - emptyPrompt, - searchFilters, - listingLimit, - tableColumns, - }} - theme={core.theme} - application={core.application} + getDetailViewLink={({ id, attributes: { timeRestore } }) => + getDashboardListItemLink( + core.application, + kbnUrlStateStorage, + core.uiSettings.get('state:storeInSessionStorage'), // use hash + id, + timeRestore + ) + } + createItem={!showWriteControls ? undefined : createItem} + deleteItems={!showWriteControls ? undefined : deleteItems} + editItem={!showWriteControls ? undefined : editItem} + listingLimit={listingLimit} > ); }; - -const getTableColumns = ( - application: ApplicationStart, - kbnUrlStateStorage: IKbnUrlStateStorage, - useHash: boolean, - savedObjectsTagging?: SavedObjectsTaggingApi -) => { - return [ - { - field: 'title', - name: dashboardListingTable.getTitleColumnName(), - sortable: true, - render: (field: string, record: { id: string; title: string; timeRestore: boolean }) => ( - - {field} - - ), - }, - { - field: 'description', - name: dashboardListingTable.getDescriptionColumnName(), - render: (field: string, record: { description: string }) => {record.description}, - sortable: true, - }, - ...(savedObjectsTagging ? [savedObjectsTagging.ui.getTableColumnDefinition()] : []), - ] as unknown as Array>>; -}; diff --git a/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts b/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts index 5d93cbcfa4f0d..44c5ac175ada1 100644 --- a/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts +++ b/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts @@ -37,6 +37,12 @@ export function makeDefaultServices(): DashboardAppServices { id: `dashboard${i}`, title: `dashboard${i} - ${search} - title`, description: `dashboard${i} desc`, + references: [], + timeRestore: true, + url: '', + updatedAt: '', + panelsJSON: '', + lastSavedTitle: '', }); } return Promise.resolve({ diff --git a/src/plugins/dashboard/public/dashboard_strings.ts b/src/plugins/dashboard/public/dashboard_strings.ts index a158df1013558..30153aa298007 100644 --- a/src/plugins/dashboard/public/dashboard_strings.ts +++ b/src/plugins/dashboard/public/dashboard_strings.ts @@ -437,15 +437,6 @@ export const dashboardListingTable = { defaultMessage: 'dashboards', }), getTableListTitle: () => getDashboardPageTitle(), - getTableCaption: () => getDashboardPageTitle(), - getTitleColumnName: () => - i18n.translate('dashboard.listing.table.titleColumnName', { - defaultMessage: 'Title', - }), - getDescriptionColumnName: () => - i18n.translate('dashboard.listing.table.descriptionColumnName', { - defaultMessage: 'Description', - }), }; export const dashboardUnsavedListingStrings = { diff --git a/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts b/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts index ed3a7fdf4b21f..a8409b88de2ef 100644 --- a/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts +++ b/src/plugins/dashboard/public/saved_dashboards/saved_dashboard.ts @@ -10,7 +10,6 @@ import { assign, cloneDeep } from 'lodash'; import { SavedObjectsClientContract } from '@kbn/core/public'; import type { ResolvedSimpleSavedObject } from '@kbn/core/public'; import { SavedObjectAttributes, SavedObjectReference } from '@kbn/core/types'; -import { RawControlGroupAttributes } from '@kbn/controls-plugin/common'; import { EmbeddableStart } from '../services/embeddable'; import { SavedObject, SavedObjectsStart } from '../services/saved_objects'; import { Filter, ISearchSource, Query, RefreshInterval } from '../services/data'; @@ -20,11 +19,12 @@ import { extractReferences, injectReferences } from '../../common/saved_dashboar import { DashboardOptions } from '../types'; -export interface DashboardSavedObject extends SavedObject { +export interface DashboardAttributes { id?: string; timeRestore: boolean; timeTo?: string; timeFrom?: string; + title: string; description?: string; panelsJSON: string; optionsJSON?: string; @@ -32,15 +32,21 @@ export interface DashboardSavedObject extends SavedObject { uiStateJSON?: string; lastSavedTitle: string; refreshInterval?: RefreshInterval; - searchSource: ISearchSource; - getQuery(): Query; - getFilters(): Filter[]; - getFullEditPath: (editMode?: boolean) => string; outcome?: ResolvedSimpleSavedObject['outcome']; aliasId?: ResolvedSimpleSavedObject['alias_target_id']; aliasPurpose?: ResolvedSimpleSavedObject['alias_purpose']; - controlGroupInput?: Omit; + error?: string; + [key: string]: any; +} + +export interface DashboardSavedObject + extends DashboardAttributes, + SavedObject { + searchSource: ISearchSource; + getQuery(): Query; + getFilters(): Filter[]; + getFullEditPath: (editMode?: boolean) => string; } const defaults = { diff --git a/src/plugins/dashboard/public/services/saved_object_loader.ts b/src/plugins/dashboard/public/services/saved_object_loader.ts index 780daa2939aa4..2d179da10506a 100644 --- a/src/plugins/dashboard/public/services/saved_object_loader.ts +++ b/src/plugins/dashboard/public/services/saved_object_loader.ts @@ -13,6 +13,7 @@ import { SavedObjectReference, } from '@kbn/core/public'; import { SavedObject } from '@kbn/saved-objects-plugin/public'; +import { DashboardAttributes } from '../saved_dashboards'; import { upperFirst } from './string_utils'; /** @@ -96,14 +97,16 @@ export class SavedObjectLoader { * @returns {source} The modified source object, with an id and url field. */ mapHitSource( - source: Record, + attributes: DashboardAttributes, id: string, + type: string, references: SavedObjectReference[] = [], updatedAt?: string - ): Record { + ) { return { - ...source, + ...attributes, id, + type, url: this.urlFor(id), references, updatedAt, @@ -119,15 +122,17 @@ export class SavedObjectLoader { mapSavedObjectApiHits({ attributes, id, + type, references = [], updatedAt, }: { - attributes: Record; + attributes: DashboardAttributes; id: string; + type: string; references?: SavedObjectReference[]; updatedAt?: string; }) { - return this.mapHitSource(attributes, id, references, updatedAt); + return this.mapHitSource(attributes, id, type, references, updatedAt); } /** @@ -144,7 +149,7 @@ export class SavedObjectLoader { { size = 100, fields, hasReference }: SavedObjectLoaderFindOptions ) { return this.savedObjectsClient - .find>({ + .find({ type: this.lowercaseType, search: search ? `${search}*` : undefined, perPage: size, diff --git a/src/plugins/dashboard/public/types.ts b/src/plugins/dashboard/public/types.ts index 8fceca0b27564..a96bb30aaba2a 100644 --- a/src/plugins/dashboard/public/types.ts +++ b/src/plugins/dashboard/public/types.ts @@ -25,6 +25,8 @@ import { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; import { VisualizationsStart } from '@kbn/visualizations-plugin/public'; import { PersistableControlGroupInput } from '@kbn/controls-plugin/common'; import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; +import type { UserContentCommonSchema } from '@kbn/content-management-table-list'; + import { DataView } from './services/data_views'; import { SharePluginStart } from './services/share'; import { EmbeddableStart } from './services/embeddable'; @@ -221,3 +223,13 @@ export interface DashboardAppServices { savedQueryService: DataPublicPluginStart['query']['savedQueries']; spacesService?: SpacesPluginStart; } + +/** Those are the **required** attributes for UserContent and that TableListView depend on */ +export interface DashboardAttributesUserContent { + title: string; + timeRestore: boolean; +} + +export interface DashboardSavedObjectUserContent extends UserContentCommonSchema { + attributes: DashboardAttributesUserContent; +} diff --git a/src/plugins/saved_objects/public/types.ts b/src/plugins/saved_objects/public/types.ts index 1159a02dc0c33..ce3f41e5bb623 100644 --- a/src/plugins/saved_objects/public/types.ts +++ b/src/plugins/saved_objects/public/types.ts @@ -21,10 +21,10 @@ import type { DataView } from '@kbn/data-views-plugin/common'; * @deprecated * @removeBy 8.8.0 */ -export interface SavedObject { +export interface SavedObject { _serialize: () => { attributes: SavedObjectAttributes; references: SavedObjectReference[] }; _source: Record; - applyESResp: (resp: EsResponse) => Promise; + applyESResp: (resp: EsResponse) => Promise>; copyOnSave: boolean; creationOpts: (opts: SavedObjectCreationOpts) => Record; defaults: any; @@ -35,7 +35,7 @@ export interface SavedObject { getFullPath: () => string; hydrateIndexPattern?: (id?: string) => Promise; id?: string; - init?: () => Promise; + init?: () => Promise>; isSaving: boolean; isTitleChanged: () => boolean; lastSavedTitle: string; diff --git a/yarn.lock b/yarn.lock index 0615d21128fb2..32cb8ec4eaeae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3017,7 +3017,7 @@ version "0.0.0" uid "" -"@kbn/content-management-table-list@link:bazel-bin/packages/kbn-content-management-table-list": +"@kbn/content-management-table-list@link:bazel-bin/packages/content-management/table_list": version "0.0.0" uid "" @@ -6975,7 +6975,7 @@ version "0.0.0" uid "" -"@types/kbn__content-management-table-list@link:bazel-bin/packages/kbn-content-management-table-list/npm_module_types": +"@types/kbn__content-management-table-list@link:bazel-bin/packages/content-management/table_list/npm_module_types": version "0.0.0" uid ""