diff --git a/x-pack/plugins/transform/kibana.json b/x-pack/plugins/transform/kibana.json index e0d549b634a21..6045d50ea26b9 100644 --- a/x-pack/plugins/transform/kibana.json +++ b/x-pack/plugins/transform/kibana.json @@ -5,6 +5,7 @@ "ui": true, "requiredPlugins": [ "data", + "dataViews", "home", "licensing", "management", diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 42708f2a3f2e2..f90faf53e87b5 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -23,7 +23,7 @@ import { indexService } from '../services/es_index_service'; export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const { http, - savedObjects, + data: { dataViews: dataViewsContract }, ml: { extractErrorMessage }, application: { capabilities }, } = useAppDependencies(); @@ -46,9 +46,8 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const checkDataViewExists = useCallback( async (indexName: string) => { try { - if (await indexService.dataViewExists(savedObjects.client, indexName)) { - setDataViewExists(true); - } + const dvExists = await indexService.dataViewExists(dataViewsContract, indexName); + setDataViewExists(dvExists); } catch (e) { const error = extractErrorMessage(e); @@ -63,7 +62,7 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { ); } }, - [savedObjects.client, toastNotifications, extractErrorMessage] + [dataViewsContract, toastNotifications, extractErrorMessage] ); const checkUserIndexPermission = useCallback(async () => { diff --git a/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts b/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts index 07c0a9ae9bcbe..60b2a080bba29 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts @@ -6,9 +6,9 @@ */ import { buildEsQuery } from '@kbn/es-query'; -import { SavedObjectsClientContract, SimpleSavedObject, IUiSettingsClient } from '@kbn/core/public'; +import type { IUiSettingsClient } from '@kbn/core/public'; import { getEsQueryConfig } from '@kbn/data-plugin/public'; -import { DataView, DataViewAttributes, DataViewsContract } from '@kbn/data-views-plugin/public'; +import type { DataView, DataViewsContract } from '@kbn/data-views-plugin/public'; import { matchAllQuery } from '../../common'; @@ -16,58 +16,21 @@ import { isDataView } from '../../../../common/types/data_view'; export type SavedSearchQuery = object; -type DataViewId = string; - -let dataViewCache: Array>> = []; -let fullDataViews; -let currentDataView = null; +let dataViewCache: DataView[] = []; export let refreshDataViews: () => Promise; -export function loadDataViews( - savedObjectsClient: SavedObjectsClientContract, - dataViews: DataViewsContract -) { - fullDataViews = dataViews; - return savedObjectsClient - .find({ - type: 'index-pattern', - fields: ['id', 'title', 'type', 'fields'], - perPage: 10000, - }) - .then((response) => { - dataViewCache = response.savedObjects; - - if (refreshDataViews === null) { - refreshDataViews = () => { - return new Promise((resolve, reject) => { - loadDataViews(savedObjectsClient, dataViews) - .then((resp) => { - resolve(resp); - }) - .catch((error) => { - reject(error); - }); - }); - }; - } - - return dataViewCache; - }); +export async function loadDataViews(dataViewsContract: DataViewsContract) { + dataViewCache = await dataViewsContract.find('*', 10000); + return dataViewCache; } export function getDataViewIdByTitle(dataViewTitle: string): string | undefined { - return dataViewCache.find((d) => d?.attributes?.title === dataViewTitle)?.id; + return dataViewCache.find(({ title }) => title === dataViewTitle)?.id; } type CombinedQuery = Record<'bool', any> | object; -export function loadCurrentDataView(dataViews: DataViewsContract, dataViewId: DataViewId) { - fullDataViews = dataViews; - currentDataView = fullDataViews.get(dataViewId); - return currentDataView; -} - export interface SearchItems { dataView: DataView; savedSearch: any; diff --git a/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts b/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts index 76fdc77c523e4..cd24d092f754c 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts @@ -15,33 +15,24 @@ import { getSavedSearch, getSavedSearchUrlConflictMessage } from '../../../share import { useAppDependencies } from '../../app_dependencies'; -import { - createSearchItems, - getDataViewIdByTitle, - loadCurrentDataView, - loadDataViews, - SearchItems, -} from './common'; +import { createSearchItems, getDataViewIdByTitle, loadDataViews, SearchItems } from './common'; export const useSearchItems = (defaultSavedObjectId: string | undefined) => { const [savedObjectId, setSavedObjectId] = useState(defaultSavedObjectId); const [error, setError] = useState(); const appDeps = useAppDependencies(); - const dataViews = appDeps.data.dataViews; + const dataViewsContract = appDeps.data.dataViews; const uiSettings = appDeps.uiSettings; - const savedObjectsClient = appDeps.savedObjects.client; const [searchItems, setSearchItems] = useState(undefined); async function fetchSavedObject(id: string) { - await loadDataViews(savedObjectsClient, dataViews); - let fetchedDataView; let fetchedSavedSearch; try { - fetchedDataView = await loadCurrentDataView(dataViews, id); + fetchedDataView = await dataViewsContract.get(id); } catch (e) { // Just let fetchedDataView stay undefined in case it doesn't exist. } diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx index f6c700aef67cc..61fd9afdbee14 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx @@ -21,8 +21,7 @@ export type CloneAction = ReturnType; export const useCloneAction = (forceDisable: boolean, transformNodes: number) => { const history = useHistory(); const appDeps = useAppDependencies(); - const savedObjectsClient = appDeps.savedObjects.client; - const dataViews = appDeps.data.dataViews; + const dataViewsContract = appDeps.data.dataViews; const toastNotifications = useToastNotifications(); const { getDataViewIdByTitle, loadDataViews } = useSearchItems(undefined); @@ -32,7 +31,7 @@ export const useCloneAction = (forceDisable: boolean, transformNodes: number) => const clickHandler = useCallback( async (item: TransformListRow) => { try { - await loadDataViews(savedObjectsClient, dataViews); + await loadDataViews(dataViewsContract); const dataViewTitle = Array.isArray(item.config.source.index) ? item.config.source.index.join(',') : item.config.source.index; @@ -57,14 +56,7 @@ export const useCloneAction = (forceDisable: boolean, transformNodes: number) => }); } }, - [ - history, - savedObjectsClient, - dataViews, - toastNotifications, - loadDataViews, - getDataViewIdByTitle, - ] + [history, dataViewsContract, toastNotifications, loadDataViews, getDataViewIdByTitle] ); const action: TransformListAction = useMemo( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/use_action_discover.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/use_action_discover.tsx index 9194d9f63045e..aeb5c3e2d09a3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/use_action_discover.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/use_action_discover.tsx @@ -25,11 +25,12 @@ const getDataViewTitleFromTargetIndex = (item: TransformListRow) => export type DiscoverAction = ReturnType; export const useDiscoverAction = (forceDisable: boolean) => { - const appDeps = useAppDependencies(); - const { share } = appDeps; - const savedObjectsClient = appDeps.savedObjects.client; - const dataViews = appDeps.data.dataViews; - const isDiscoverAvailable = !!appDeps.application.capabilities.discover?.show; + const { + share, + data: { dataViews: dataViewsContract }, + application: { capabilities }, + } = useAppDependencies(); + const isDiscoverAvailable = !!capabilities.discover?.show; const { getDataViewIdByTitle, loadDataViews } = useSearchItems(undefined); @@ -37,12 +38,12 @@ export const useDiscoverAction = (forceDisable: boolean) => { useEffect(() => { async function checkDataViewAvailability() { - await loadDataViews(savedObjectsClient, dataViews); + await loadDataViews(dataViewsContract); setDataViewsLoaded(true); } checkDataViewAvailability(); - }, [dataViews, loadDataViews, savedObjectsClient]); + }, [loadDataViews, dataViewsContract]); const clickHandler = useCallback( (item: TransformListRow) => { diff --git a/x-pack/plugins/transform/public/app/services/es_index_service.ts b/x-pack/plugins/transform/public/app/services/es_index_service.ts index 5a0f907b78e22..609018c30b226 100644 --- a/x-pack/plugins/transform/public/app/services/es_index_service.ts +++ b/x-pack/plugins/transform/public/app/services/es_index_service.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { HttpSetup, SavedObjectsClientContract } from '@kbn/core/public'; -import { DataView } from '@kbn/data-views-plugin/public'; +import type { HttpSetup } from '@kbn/core/public'; +import type { DataViewsContract } from '@kbn/data-views-plugin/public'; import { API_BASE_PATH } from '../../../common/constants'; export class IndexService { @@ -18,16 +18,8 @@ export class IndexService { return privilege.hasAllPrivileges; } - async dataViewExists(savedObjectsClient: SavedObjectsClientContract, indexName: string) { - const response = await savedObjectsClient.find({ - type: 'index-pattern', - perPage: 1, - search: `"${indexName}"`, - searchFields: ['title'], - fields: ['title'], - }); - const ip = response.savedObjects.find((obj) => obj.attributes.title === indexName); - return ip !== undefined; + async dataViewExists(dataViewsContract: DataViewsContract, indexName: string) { + return (await dataViewsContract.find(indexName)).some(({ title }) => title === indexName); } } diff --git a/x-pack/plugins/transform/public/plugin.ts b/x-pack/plugins/transform/public/plugin.ts index 74cd845dd49da..762dfd2bcaab8 100644 --- a/x-pack/plugins/transform/public/plugin.ts +++ b/x-pack/plugins/transform/public/plugin.ts @@ -9,6 +9,7 @@ import { i18n as kbnI18n } from '@kbn/i18n'; import type { CoreSetup } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; import type { SavedObjectsStart } from '@kbn/saved-objects-plugin/public'; import type { ManagementSetup } from '@kbn/management-plugin/public'; @@ -21,6 +22,7 @@ import { getTransformHealthRuleType } from './alerting'; export interface PluginsDependencies { data: DataPublicPluginStart; + dataViews: DataViewsPublicPluginStart; management: ManagementSetup; home: HomePublicPluginSetup; savedObjects: SavedObjectsStart; diff --git a/x-pack/plugins/transform/server/plugin.ts b/x-pack/plugins/transform/server/plugin.ts index c803785de2c4b..3eab84ca0b5fc 100644 --- a/x-pack/plugins/transform/server/plugin.ts +++ b/x-pack/plugins/transform/server/plugin.ts @@ -6,11 +6,11 @@ */ import { i18n } from '@kbn/i18n'; -import { CoreSetup, Plugin, Logger, PluginInitializerContext } from '@kbn/core/server'; +import { CoreSetup, CoreStart, Plugin, Logger, PluginInitializerContext } from '@kbn/core/server'; import { LicenseType } from '@kbn/licensing-plugin/common/types'; -import { Dependencies } from './types'; +import { PluginSetupDependencies, PluginStartDependencies } from './types'; import { ApiRoutes } from './routes'; import { License } from './services'; import { registerTransformHealthRuleType } from './lib/alerting'; @@ -38,8 +38,8 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> { } setup( - { http, getStartServices, elasticsearch }: CoreSetup, - { licensing, features, alerting }: Dependencies + { http, getStartServices, elasticsearch }: CoreSetup, + { licensing, features, alerting }: PluginSetupDependencies ): {} { const router = http.createRouter(); @@ -74,6 +74,7 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> { this.apiRoutes.setup({ router, license: this.license, + getStartServices, }); if (alerting) { @@ -83,7 +84,7 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> { return {}; } - start() {} + start(core: CoreStart, plugins: PluginStartDependencies) {} stop() {} } diff --git a/x-pack/plugins/transform/server/routes/api/transforms.ts b/x-pack/plugins/transform/server/routes/api/transforms.ts index f1c5e74056a94..7c4df878456ba 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms.ts @@ -13,10 +13,9 @@ import { KibanaResponseFactory, RequestHandler, RequestHandlerContext, - SavedObjectsClientContract, } from '@kbn/core/server'; -import { DataView } from '@kbn/data-views-plugin/common'; +import { DataViewsService } from '@kbn/data-views-plugin/common'; import { TRANSFORM_STATE } from '../../../common/constants'; import { transformIdParamSchema, @@ -74,7 +73,7 @@ enum TRANSFORM_ACTIONS { } export function registerTransformsRoutes(routeDependencies: RouteDependencies) { - const { router, license } = routeDependencies; + const { router, license, getStartServices } = routeDependencies; /** * @apiGroup Transforms * @@ -303,7 +302,16 @@ export function registerTransformsRoutes(routeDependencies: RouteDependencies) { license.guardApiRoute( async (ctx, req, res) => { try { - const body = await deleteTransforms(req.body, ctx, res); + const [{ savedObjects, elasticsearch }, { dataViews }] = await getStartServices(); + const savedObjectsClient = savedObjects.getScopedClient(req); + const esClient = elasticsearch.client.asScoped(req).asCurrentUser; + + const dataViewsService = await dataViews.dataViewsServiceFactory( + savedObjectsClient, + esClient, + req + ); + const body = await deleteTransforms(req.body, ctx, res, dataViewsService); if (body && body.status) { if (body.status === 404) { @@ -456,29 +464,20 @@ export function registerTransformsRoutes(routeDependencies: RouteDependencies) { registerTransformNodesRoutes(routeDependencies); } -async function getDataViewId(indexName: string, savedObjectsClient: SavedObjectsClientContract) { - const response = await savedObjectsClient.find({ - type: 'index-pattern', - perPage: 1, - search: `"${indexName}"`, - searchFields: ['title'], - fields: ['title'], - }); - const ip = response.saved_objects.find((obj) => obj.attributes.title === indexName); - return ip?.id; +async function getDataViewId(indexName: string, dataViewsService: DataViewsService) { + const dv = (await dataViewsService.find(indexName)).find(({ title }) => title === indexName); + return dv?.id; } -async function deleteDestDataViewById( - dataViewId: string, - savedObjectsClient: SavedObjectsClientContract -) { - return await savedObjectsClient.delete('index-pattern', dataViewId); +async function deleteDestDataViewById(dataViewId: string, dataViewsService: DataViewsService) { + return await dataViewsService.delete(dataViewId); } async function deleteTransforms( reqBody: DeleteTransformsRequestSchema, ctx: RequestHandlerContext, - response: KibanaResponseFactory + response: KibanaResponseFactory, + dataViewsService: DataViewsService ) { const { transformsInfo } = reqBody; @@ -491,7 +490,6 @@ async function deleteTransforms( const coreContext = await ctx.core; const esClient = coreContext.elasticsearch.client; - const soClient = coreContext.savedObjects.client; for (const transformInfo of transformsInfo) { let destinationIndex: string | undefined; @@ -548,9 +546,9 @@ async function deleteTransforms( // Delete the data view if there's a data view that matches the name of dest index if (destinationIndex && deleteDestDataView) { try { - const dataViewId = await getDataViewId(destinationIndex, soClient); + const dataViewId = await getDataViewId(destinationIndex, dataViewsService); if (dataViewId) { - await deleteDestDataViewById(dataViewId, soClient); + await deleteDestDataViewById(dataViewId, dataViewsService); destDataViewDeleted.success = true; } } catch (deleteDestDataViewError) { diff --git a/x-pack/plugins/transform/server/types.ts b/x-pack/plugins/transform/server/types.ts index f9be90a1a20da..26bdf02acb5c0 100644 --- a/x-pack/plugins/transform/server/types.ts +++ b/x-pack/plugins/transform/server/types.ts @@ -5,19 +5,25 @@ * 2.0. */ -import { IRouter } from '@kbn/core/server'; +import { IRouter, CoreSetup } from '@kbn/core/server'; +import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { AlertingPlugin } from '@kbn/alerting-plugin/server'; import { License } from './services'; -export interface Dependencies { +export interface PluginSetupDependencies { licensing: LicensingPluginSetup; features: FeaturesPluginSetup; alerting?: AlertingPlugin['setup']; } +export interface PluginStartDependencies { + dataViews: DataViewsServerPluginStart; +} + export interface RouteDependencies { router: IRouter; license: License; + getStartServices: CoreSetup['getStartServices']; }