"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useModelActions = useModelActions; var _i18n = require("@kbn/i18n"); var _mlIsPopulatedObject = require("@kbn/ml-is-populated-object"); var _eui = require("@elastic/eui"); var _react = _interopRequireWildcard(require("react")); var _mlTrainedModelsUtils = require("@kbn/ml-trained-models-utils"); var _trained_models = require("@kbn/ml-trained-models-utils/src/constants/trained_models"); var _mlDataFrameAnalyticsUtils = require("@kbn/ml-data-frame-analytics-utils"); var _trained_models2 = require("../services/ml_api_service/trained_models"); var _force_stop_dialog = require("./force_stop_dialog"); var _toast_notification_service = require("../services/toast_notification_service"); var _deployment_setup = require("./deployment_setup"); var _kibana = require("../contexts/kibana"); var _locator = require("../../../common/constants/locator"); var _test_models = require("./test_models"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /* * 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; you may not use this file except in compliance with the Elastic License * 2.0. */ function useModelActions({ onTestAction, onModelsDeleteRequest, onModelDeployRequest, onLoading, isLoading, fetchModels, modelAndDeploymentIds }) { const { services: { application: { navigateToUrl, capabilities }, overlays, theme, i18n: i18nStart, docLinks, mlServices: { mlApiServices } } } = (0, _kibana.useMlKibana)(); const [canManageIngestPipelines, setCanManageIngestPipelines] = (0, _react.useState)(false); const startModelDeploymentDocUrl = docLinks.links.ml.startTrainedModelsDeployment; const navigateToPath = (0, _kibana.useNavigateToPath)(); const { displayErrorToast, displaySuccessToast } = (0, _toast_notification_service.useToastNotificationService)(); const urlLocator = (0, _kibana.useMlLocator)(); const trainedModelsApiService = (0, _trained_models2.useTrainedModelsApiService)(); const canStartStopTrainedModels = capabilities.ml.canStartStopTrainedModels; const canTestTrainedModels = capabilities.ml.canTestTrainedModels; const canDeleteTrainedModels = capabilities.ml.canDeleteTrainedModels; (0, _react.useEffect)(() => { let isMounted = true; mlApiServices.hasPrivileges({ cluster: ['manage_ingest_pipelines'] }).then(result => { var _result$cluster; const canManagePipelines = (_result$cluster = result.cluster) === null || _result$cluster === void 0 ? void 0 : _result$cluster.manage_ingest_pipelines; if (isMounted) { setCanManageIngestPipelines(canManagePipelines); } }); return () => { isMounted = false; }; }, [mlApiServices]); const getUserConfirmation = (0, _react.useMemo)(() => (0, _force_stop_dialog.getUserConfirmationProvider)(overlays, theme, i18nStart), [i18nStart, overlays, theme]); const getUserInputModelDeploymentParams = (0, _react.useMemo)(() => (0, _deployment_setup.getUserInputModelDeploymentParamsProvider)(overlays, theme, i18nStart, startModelDeploymentDocUrl), [overlays, theme, i18nStart, startModelDeploymentDocUrl]); const isBuiltInModel = (0, _react.useCallback)(item => item.tags.includes(_mlTrainedModelsUtils.BUILT_IN_MODEL_TAG), []); return (0, _react.useMemo)(() => [{ name: _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.viewTrainingDataActionLabel', { defaultMessage: 'View training data' }), description: _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.viewTrainingDataActionLabel', { defaultMessage: 'View training data' }), icon: 'visTable', type: 'icon', available: item => { var _item$metadata, _item$metadata$analyt; return !!((_item$metadata = item.metadata) !== null && _item$metadata !== void 0 && (_item$metadata$analyt = _item$metadata.analytics_config) !== null && _item$metadata$analyt !== void 0 && _item$metadata$analyt.id); }, onClick: async item => { var _item$metadata2, _item$metadata3, _item$metadata4, _item$metadata5; if (((_item$metadata2 = item.metadata) === null || _item$metadata2 === void 0 ? void 0 : _item$metadata2.analytics_config) === undefined) return; const analysisType = (0, _mlDataFrameAnalyticsUtils.getAnalysisType)((_item$metadata3 = item.metadata) === null || _item$metadata3 === void 0 ? void 0 : _item$metadata3.analytics_config.analysis); const url = await urlLocator.getUrl({ page: _locator.ML_PAGES.DATA_FRAME_ANALYTICS_EXPLORATION, pageState: { jobId: (_item$metadata4 = item.metadata) === null || _item$metadata4 === void 0 ? void 0 : _item$metadata4.analytics_config.id, analysisType, ...(analysisType === 'classification' || analysisType === 'regression' ? { queryText: `${(_item$metadata5 = item.metadata) === null || _item$metadata5 === void 0 ? void 0 : _item$metadata5.analytics_config.dest.results_field}.is_training : true` } : {}) } }); await navigateToUrl(url); }, isPrimary: true }, { name: _i18n.i18n.translate('xpack.ml.inference.modelsList.analyticsMapActionLabel', { defaultMessage: 'Analytics map' }), description: _i18n.i18n.translate('xpack.ml.inference.modelsList.analyticsMapActionLabel', { defaultMessage: 'Analytics map' }), icon: 'graphApp', type: 'icon', isPrimary: true, available: item => { var _item$metadata6, _item$metadata6$analy; return !!((_item$metadata6 = item.metadata) !== null && _item$metadata6 !== void 0 && (_item$metadata6$analy = _item$metadata6.analytics_config) !== null && _item$metadata6$analy !== void 0 && _item$metadata6$analy.id); }, onClick: async item => { const path = await urlLocator.getUrl({ page: _locator.ML_PAGES.DATA_FRAME_ANALYTICS_MAP, pageState: { modelId: item.model_id } }); await navigateToPath(path, false); } }, { name: _i18n.i18n.translate('xpack.ml.inference.modelsList.startModelDeploymentActionLabel', { defaultMessage: 'Start deployment' }), description: _i18n.i18n.translate('xpack.ml.inference.modelsList.startModelDeploymentActionLabel', { defaultMessage: 'Start deployment' }), 'data-test-subj': 'mlModelsTableRowStartDeploymentAction', icon: 'play', type: 'icon', isPrimary: true, enabled: item => { return canStartStopTrainedModels && !isLoading && item.state !== _trained_models.MODEL_STATE.DOWNLOADING; }, available: item => item.model_type === _mlTrainedModelsUtils.TRAINED_MODEL_TYPE.PYTORCH, onClick: async item => { const modelDeploymentParams = await getUserInputModelDeploymentParams(item, undefined, modelAndDeploymentIds); if (!modelDeploymentParams) return; try { onLoading(true); await trainedModelsApiService.startModelAllocation(item.model_id, { number_of_allocations: modelDeploymentParams.numOfAllocations, threads_per_allocation: modelDeploymentParams.threadsPerAllocations, priority: modelDeploymentParams.priority, deployment_id: !!modelDeploymentParams.deploymentId ? modelDeploymentParams.deploymentId : item.model_id }); displaySuccessToast(_i18n.i18n.translate('xpack.ml.trainedModels.modelsList.startSuccess', { defaultMessage: 'Deployment for "{modelId}" has been started successfully.', values: { modelId: item.model_id } })); await fetchModels(); } catch (e) { displayErrorToast(e, _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.startFailed', { defaultMessage: 'Failed to start "{modelId}"', values: { modelId: item.model_id } })); onLoading(false); } } }, { name: _i18n.i18n.translate('xpack.ml.inference.modelsList.updateModelDeploymentActionLabel', { defaultMessage: 'Update deployment' }), description: _i18n.i18n.translate('xpack.ml.inference.modelsList.updateModelDeploymentActionLabel', { defaultMessage: 'Update deployment' }), 'data-test-subj': 'mlModelsTableRowUpdateDeploymentAction', icon: 'documentEdit', type: 'icon', isPrimary: false, available: item => { var _item$stats, _item$stats$deploymen; return item.model_type === _mlTrainedModelsUtils.TRAINED_MODEL_TYPE.PYTORCH && canStartStopTrainedModels && !isLoading && !!((_item$stats = item.stats) !== null && _item$stats !== void 0 && (_item$stats$deploymen = _item$stats.deployment_stats) !== null && _item$stats$deploymen !== void 0 && _item$stats$deploymen.some(v => v.state === _mlTrainedModelsUtils.DEPLOYMENT_STATE.STARTED)); }, onClick: async item => { const deploymentToUpdate = item.deployment_ids[0]; const deploymentParams = await getUserInputModelDeploymentParams(item, { deploymentId: deploymentToUpdate, numOfAllocations: item.stats.deployment_stats.find(v => v.deployment_id === deploymentToUpdate).number_of_allocations }); if (!deploymentParams) return; try { onLoading(true); await trainedModelsApiService.updateModelDeployment(item.model_id, deploymentParams.deploymentId, { number_of_allocations: deploymentParams.numOfAllocations }); displaySuccessToast(_i18n.i18n.translate('xpack.ml.trainedModels.modelsList.updateSuccess', { defaultMessage: 'Deployment for "{modelId}" has been updated successfully.', values: { modelId: item.model_id } })); await fetchModels(); } catch (e) { displayErrorToast(e, _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.updateFailed', { defaultMessage: 'Failed to update "{modelId}"', values: { modelId: item.model_id } })); onLoading(false); } } }, { name: _i18n.i18n.translate('xpack.ml.inference.modelsList.stopModelDeploymentActionLabel', { defaultMessage: 'Stop deployment' }), description: _i18n.i18n.translate('xpack.ml.inference.modelsList.stopModelDeploymentActionLabel', { defaultMessage: 'Stop deployment' }), 'data-test-subj': 'mlModelsTableRowStopDeploymentAction', icon: 'stop', type: 'icon', isPrimary: true, available: item => item.model_type === _mlTrainedModelsUtils.TRAINED_MODEL_TYPE.PYTORCH, enabled: item => canStartStopTrainedModels && !isLoading && item.deployment_ids.length > 0, onClick: async item => { const requireForceStop = (0, _mlIsPopulatedObject.isPopulatedObject)(item.pipelines); const hasMultipleDeployments = item.deployment_ids.length > 1; let deploymentIds = item.deployment_ids; if (requireForceStop || hasMultipleDeployments) { try { deploymentIds = await getUserConfirmation(item); } catch (error) { return; } } try { onLoading(true); const results = await trainedModelsApiService.stopModelAllocation(item.model_id, deploymentIds, { force: requireForceStop }); displaySuccessToast(_i18n.i18n.translate('xpack.ml.trainedModels.modelsList.stopSuccess', { defaultMessage: '{numberOfDeployments, plural, one {Deployment} other {Deployments}} for "{modelId}" has been stopped successfully.', values: { modelId: item.model_id, numberOfDeployments: deploymentIds.length } })); if (Object.values(results).some(r => r.error !== undefined)) { Object.entries(results).forEach(([id, r]) => { if (r.error !== undefined) { displayErrorToast(r.error, _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.stopDeploymentWarning', { defaultMessage: 'Failed to stop "{deploymentId}"', values: { deploymentId: id } })); } }); } } catch (e) { displayErrorToast(e, _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.stopFailed', { defaultMessage: 'Failed to stop "{modelId}"', values: { modelId: item.model_id } })); onLoading(false); } // Need to fetch model state updates await fetchModels(); } }, { name: _i18n.i18n.translate('xpack.ml.inference.modelsList.downloadModelActionLabel', { defaultMessage: 'Download model' }), description: _i18n.i18n.translate('xpack.ml.inference.modelsList.downloadModelActionLabel', { defaultMessage: 'Download model' }), 'data-test-subj': 'mlModelsTableRowDownloadModelAction', icon: 'download', type: 'icon', isPrimary: true, available: item => item.tags.includes(_trained_models.ELASTIC_MODEL_TAG), enabled: item => !item.state && !isLoading, onClick: async item => { try { onLoading(true); await trainedModelsApiService.putTrainedModelConfig(item.model_id, item.putModelConfig); displaySuccessToast(_i18n.i18n.translate('xpack.ml.trainedModels.modelsList.downloadSuccess', { defaultMessage: '"{modelId}" model download has been started successfully.', values: { modelId: item.model_id } })); // Need to fetch model state updates await fetchModels(); } catch (e) { displayErrorToast(e, _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.downloadFailed', { defaultMessage: 'Failed to download "{modelId}"', values: { modelId: item.model_id } })); onLoading(false); } } }, { name: model => { const hasDeployments = model.state === _trained_models.MODEL_STATE.STARTED; return /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { position: "left", content: hasDeployments ? _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.deleteDisabledWithDeploymentsTooltip', { defaultMessage: 'Model has started deployments' }) : null }, /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.deployModelActionLabel', { defaultMessage: 'Deploy model' }))); }, description: _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.deployModelActionLabel', { defaultMessage: 'Deploy model' }), 'data-test-subj': 'mlModelsTableRowDeployAction', icon: 'continuityAbove', type: 'icon', isPrimary: false, onClick: model => { onModelDeployRequest(model); }, available: item => { var _item$metadata7; const isDfaTrainedModel = ((_item$metadata7 = item.metadata) === null || _item$metadata7 === void 0 ? void 0 : _item$metadata7.analytics_config) !== undefined; return isDfaTrainedModel && !isBuiltInModel(item) && !item.putModelConfig && canManageIngestPipelines; }, enabled: item => { return item.state !== _trained_models.MODEL_STATE.STARTED; } }, { name: model => { const hasDeployments = model.state === _trained_models.MODEL_STATE.STARTED; return /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { position: "left", content: hasDeployments ? _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.deleteDisabledWithDeploymentsTooltip', { defaultMessage: 'Model has started deployments' }) : null }, /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { defaultMessage: 'Delete model' }))); }, description: _i18n.i18n.translate('xpack.ml.trainedModels.modelsList.deleteModelActionLabel', { defaultMessage: 'Delete model' }), 'data-test-subj': 'mlModelsTableRowDeleteAction', icon: 'trash', type: 'icon', color: 'danger', isPrimary: false, onClick: model => { onModelsDeleteRequest([model]); }, available: item => { var _item$pipelines; const hasZeroPipelines = Object.keys((_item$pipelines = item.pipelines) !== null && _item$pipelines !== void 0 ? _item$pipelines : {}).length === 0; return canDeleteTrainedModels && !isBuiltInModel(item) && !item.putModelConfig && (hasZeroPipelines || canManageIngestPipelines); }, enabled: item => { return item.state !== _trained_models.MODEL_STATE.STARTED; } }, { name: _i18n.i18n.translate('xpack.ml.inference.modelsList.testModelActionLabel', { defaultMessage: 'Test model' }), description: _i18n.i18n.translate('xpack.ml.inference.modelsList.testModelActionLabel', { defaultMessage: 'Test model' }), 'data-test-subj': 'mlModelsTableRowTestAction', icon: 'inputOutput', type: 'icon', isPrimary: true, available: _test_models.isTestable, onClick: item => onTestAction(item), enabled: item => canTestTrainedModels && (0, _test_models.isTestable)(item, true) && !isLoading }], [urlLocator, navigateToUrl, navigateToPath, canStartStopTrainedModels, isLoading, getUserInputModelDeploymentParams, modelAndDeploymentIds, onLoading, trainedModelsApiService, displaySuccessToast, fetchModels, displayErrorToast, getUserConfirmation, onModelsDeleteRequest, onModelDeployRequest, canDeleteTrainedModels, isBuiltInModel, onTestAction, canTestTrainedModels, canManageIngestPipelines]); }