From 05fcaee75c7ab5957ae596ebcd730dcee3b26c29 Mon Sep 17 00:00:00 2001 From: illia prokopchuk Date: Mon, 6 Nov 2023 16:41:49 +0200 Subject: [PATCH 1/3] Impl [Batch Run] Model Training --- src/actions/functions.js | 4 +- src/common/TargetPath/targetPath.util.js | 2 +- src/components/Datasets/Datasets.js | 8 ++-- src/components/Datasets/datasets.util.js | 27 +++++++++++++- src/components/JobWizard/JobWizard.js | 23 +++++++++++- src/components/JobWizard/JobWizard.util.js | 26 +++++++++++-- .../JobWizardFunctionSelection.js | 37 ++++++++++++------- .../jobWizardFunctionSelection.util.js | 18 +++++++++ .../ProjectOverview/ProjectOverview.util.js | 3 +- src/utils/generateTemplatesCategories.js | 15 +++++--- src/utils/panelPathScheme.js | 2 +- 11 files changed, 128 insertions(+), 37 deletions(-) diff --git a/src/actions/functions.js b/src/actions/functions.js index 42cbe89cd4..726ddb2b0f 100644 --- a/src/actions/functions.js +++ b/src/actions/functions.js @@ -287,13 +287,13 @@ const functionsActions = { type: FETCH_HUB_FUNCTION_TEMPLATE_FAILURE, payload: err }), - fetchHubFunctions: () => dispatch => { + fetchHubFunctions: isTrainModel => dispatch => { dispatch(functionsActions.fetchHubFunctionsBegin()) return functionsApi .getHubFunctions() .then(({ data: functionTemplates }) => { - const templatesData = generateHubCategories(functionTemplates.catalog) + const templatesData = generateHubCategories(functionTemplates.catalog, isTrainModel) dispatch(functionsActions.setHubFunctions(templatesData)) diff --git a/src/common/TargetPath/targetPath.util.js b/src/common/TargetPath/targetPath.util.js index b21f46d96b..16def23a2f 100644 --- a/src/common/TargetPath/targetPath.util.js +++ b/src/common/TargetPath/targetPath.util.js @@ -275,7 +275,7 @@ export const generateComboboxMatchesList = ( export const generateArtifactsList = artifacts => { const generatedArtifacts = artifacts .map(artifact => { - const key = artifact.link_iteration ? artifact.link_iteration.db_key : artifact.key ?? '' + const key = artifact.link_iteration?.db_key || artifact.db_key || artifact.key || '' return { label: key, id: key diff --git a/src/components/Datasets/Datasets.js b/src/components/Datasets/Datasets.js index 9371724f5b..08c02dff33 100644 --- a/src/components/Datasets/Datasets.js +++ b/src/components/Datasets/Datasets.js @@ -83,10 +83,6 @@ const Datasets = () => { const filtersStore = useSelector(store => store.filtersStore) const datasetsRef = useRef(null) const viewMode = getViewMode(window.location.search) - const pageData = useMemo( - () => generatePageData(selectedDataset, viewMode), - [selectedDataset, viewMode] - ) const params = useParams() const navigate = useNavigate() const location = useLocation() @@ -96,6 +92,10 @@ const Datasets = () => { () => filtersStore[FILTER_MENU_MODAL][DATASETS_FILTERS].values, [filtersStore] ) + const pageData = useMemo( + () => generatePageData(selectedDataset, viewMode, params), + [selectedDataset, viewMode, params] + ) const detailsFormInitialValues = useMemo( () => ({ diff --git a/src/components/Datasets/datasets.util.js b/src/components/Datasets/datasets.util.js index 3d00719a61..7022447430 100644 --- a/src/components/Datasets/datasets.util.js +++ b/src/components/Datasets/datasets.util.js @@ -18,6 +18,8 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import JobWizard from '../JobWizard/JobWizard' +import { openPopUp } from 'igz-controls/utils/common.util' import { applyTagChanges } from '../../utils/artifacts.util' import { getArtifactIdentifier } from '../../utils/getUniqueIdentifier' import { @@ -34,6 +36,8 @@ import { searchArtifactItem } from '../../utils/searchArtifactItem' import { sortListByDate } from '../../utils' import { fetchDataSet } from '../../reducers/artifactsReducer' +import { PRIMARY_BUTTON } from 'igz-controls/constants' + export const infoHeaders = [ { label: 'Hash', @@ -85,17 +89,36 @@ export const generateDataSetsDetailsMenu = selectedItem => [ } ] -export const generatePageData = (selectedItem, viewMode) => ({ +export const generatePageData = (selectedItem, viewMode, params) => ({ page: DATASETS_PAGE, details: { menu: generateDataSetsDetailsMenu(selectedItem), infoHeaders, type: DATASETS, hideBackBtn: viewMode === FULL_VIEW_MODE, - withToggleViewBtn: true + withToggleViewBtn: true, + actionButton: { + label: 'Train', + variant: PRIMARY_BUTTON, + onClick: () => handleTrainDataset(selectedItem, params) + } } }) +const handleTrainDataset = (selectedItem, params) => { + const defaultDataInput = { + name: selectedItem.db_key || selectedItem.key || 'dataset', + path: selectedItem.URI + } + + openPopUp(JobWizard, { + params, + isTrainModel: true, + wizardTitle: 'Train model', + defaultDataInput + }) +} + export const fetchDataSetRowData = async ( dispatch, dataSet, diff --git a/src/components/JobWizard/JobWizard.js b/src/components/JobWizard/JobWizard.js index ade3ce45fd..e1d4865839 100644 --- a/src/components/JobWizard/JobWizard.js +++ b/src/components/JobWizard/JobWizard.js @@ -77,6 +77,7 @@ import './jobWizard.scss' const JobWizard = ({ defaultData, + defaultDataInput, editJob, fetchFunctionTemplate, fetchHubFunction, @@ -84,6 +85,7 @@ const JobWizard = ({ functionsStore, isBatchInference, isOpen, + isTrainModel, jobsStore, mode, onResolve, @@ -286,7 +288,11 @@ const JobWizard = ({ return [ { - label: isBatchInference ? 'Schedule Infer' : 'Schedule for later', + label: isBatchInference + ? 'Schedule Infer' + : isTrainModel + ? 'Schedule training job' + : 'Schedule for later', onClick: () => { formState.handleSubmit() @@ -301,7 +307,14 @@ const JobWizard = ({ ref: scheduleButtonRef }, { - label: mode === PANEL_EDIT_MODE ? 'Save' : isBatchInference ? 'Infer now' : 'Run', + label: + mode === PANEL_EDIT_MODE + ? 'Save' + : isBatchInference + ? 'Infer now' + : isTrainModel + ? 'Run training now' + : 'Run', onClick: () => { formState.handleSubmit() @@ -429,12 +442,14 @@ const JobWizard = ({ {}, onWizardClose: () => {}, @@ -513,8 +530,10 @@ JobWizard.defaultProps = { JobWizard.propTypes = { defaultData: PropTypes.shape({}), + defaultDataInput: PropTypes.shape({}), isBatchInference: PropTypes.bool, isOpen: PropTypes.bool.isRequired, + isTrainModel: PropTypes.bool, mode: JOB_WIZARD_MODE, onResolve: PropTypes.func.isRequired, onSuccessRequest: PropTypes.func, diff --git a/src/components/JobWizard/JobWizard.util.js b/src/components/JobWizard/JobWizard.util.js index 1a309711fb..e67ba39976 100644 --- a/src/components/JobWizard/JobWizard.util.js +++ b/src/components/JobWizard/JobWizard.util.js @@ -102,7 +102,8 @@ export const generateJobWizardData = ( selectedFunctionData, defaultData, currentProjectName, - isEditMode + isEditMode, + defaultDataInput ) => { const functions = selectedFunctionData.functions const functionInfo = getFunctionInfo(selectedFunctionData) @@ -181,12 +182,18 @@ export const generateJobWizardData = ( jobFormData[RESOURCES_STEP].jobPriorityClassName = jobPriorityClassName } + if (!isEmpty(functionParameters) || !isEmpty(defaultDataInput)) { + jobFormData[DATA_INPUTS_STEP].dataInputsTable = parseDataInputs( + functionParameters, + defaultDataInput + ) + } + if (!isEmpty(functionParameters)) { jobFormData[PARAMETERS_STEP].parametersTable = { predefined: parsePredefinedParameters(functionParameters), custom: [] } - jobFormData[DATA_INPUTS_STEP].dataInputsTable = parseDataInputs(functionParameters) } return [jobFormData, jobAdditionalData] @@ -611,8 +618,8 @@ const getDataInputData = (dataInputName, dataInputValue, dataInputIsChecked) => const sortParameters = (parameter, nextParameter) => nextParameter.isRequired - parameter.isRequired -export const parseDataInputs = functionParameters => { - return functionParameters +export const parseDataInputs = (functionParameters = [], defaultDataInput) => { + const generatedDataInputs = functionParameters .filter(dataInputs => dataInputs.type?.includes('DataItem')) .map(dataInput => { return { @@ -624,6 +631,17 @@ export const parseDataInputs = functionParameters => { } }) .sort(sortParameters) + + if (!isEmpty(defaultDataInput)) { + generatedDataInputs.unshift({ + data: getDataInputData(defaultDataInput.name, defaultDataInput.path, true), + isRequired: true, + isDefault: true, + isPredefined: true + }) + } + + return generatedDataInputs } export const parseDefaultDataInputs = (funcParams, runDataInputs = {}) => { diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js index 6c043f9523..0f9425099c 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js @@ -45,6 +45,7 @@ import { generateProjectsList } from '../../../../utils/projects' import { functionRunKinds } from '../../../Jobs/jobs.util' import { openConfirmPopUp } from 'igz-controls/utils/common.util' import { + filterSelectedFunctionMethods, FUNCTIONS_SELECTION_FUNCTIONS_TAB, FUNCTIONS_SELECTION_HUB_TAB, functionsSelectionTabs, @@ -57,12 +58,14 @@ import './jobWizardFunctionSelection.scss' const JobWizardFunctionSelection = ({ activeTab, defaultData, + defaultDataInput, filteredFunctions, filteredTemplates, formState, frontendSpec, functions, isEditMode, + isTrainModel, params, selectedFunctionData, selectedFunctionTab, @@ -215,7 +218,8 @@ const JobWizardFunctionSelection = ({ functionData, defaultData, params.projectName, - isEditMode + isEditMode, + defaultDataInput ) const newInitial = { @@ -272,7 +276,7 @@ const JobWizardFunctionSelection = ({ activeTab === FUNCTIONS_SELECTION_HUB_TAB && (isEmpty(hubFunctions) || isEmpty(hubFunctionsCatalog)) ) { - dispatch(functionsActions.fetchHubFunctions()).then(templatesObject => { + dispatch(functionsActions.fetchHubFunctions(isTrainModel)).then(templatesObject => { if (templatesObject) { setTemplatesCategories(templatesObject.hubFunctionsCategories) setTemplates(templatesObject.hubFunctions) @@ -298,6 +302,7 @@ const JobWizardFunctionSelection = ({ formState.initialValues, hubFunctions, hubFunctionsCatalog, + isTrainModel, setTemplates, setTemplatesCategories ]) @@ -327,8 +332,10 @@ const JobWizardFunctionSelection = ({ const functionTemplatePath = `${functionData.spec.item_uri}${functionData.spec.assets.function}` dispatch(functionsActions.fetchFunctionTemplate(functionTemplatePath)).then(result => { - setSelectedFunctionData(result) - generateData(result) + const filteredResult = filterSelectedFunctionMethods(result) + + setSelectedFunctionData(filteredResult) + generateData(filteredResult) setSelectedFunctionTab(FUNCTIONS_SELECTION_HUB_TAB) setShowSchedule(false) }) @@ -416,15 +423,17 @@ const JobWizardFunctionSelection = ({ placeholder="Search functions..." setMatches={setFilterMatches} /> - - - + {!isTrainModel && ( + + + + )} {(filterByName.length > 0 && (filterMatches.length === 0 || isEmpty(filteredTemplates))) || @@ -470,12 +479,14 @@ const JobWizardFunctionSelection = ({ JobWizardFunctionSelection.propTypes = { activeTab: PropTypes.string.isRequired, defaultData: PropTypes.shape({}).isRequired, + defaultDataInput: PropTypes.shape({}).isRequired, filteredFunctions: PropTypes.arrayOf(PropTypes.shape({})).isRequired, filteredTemplates: PropTypes.arrayOf(PropTypes.shape({})).isRequired, formState: PropTypes.shape({}).isRequired, frontendSpec: PropTypes.shape({}).isRequired, functions: PropTypes.arrayOf(PropTypes.shape({})).isRequired, isEditMode: PropTypes.bool.isRequired, + isTrainModel: PropTypes.bool.isRequired, params: PropTypes.shape({}).isRequired, selectedFunctionData: PropTypes.shape({}).isRequired, selectedFunctionTab: PropTypes.string.isRequired, diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.util.js b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.util.js index 5eb5e69261..1cd414269f 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.util.js +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.util.js @@ -24,6 +24,11 @@ import { FUNCTION_SELECTION_STEP } from '../../../../constants' export const FUNCTIONS_SELECTION_FUNCTIONS_TAB = 'functions' export const FUNCTIONS_SELECTION_HUB_TAB = 'hub' +export const trainModelAllowedHubFunctions = { + 'auto-trainer': ['train'], + 'azureml-utils': ['submit_training_job', 'train'] +} + export const functionsSelectionTabs = [ { id: FUNCTIONS_SELECTION_FUNCTIONS_TAB, @@ -63,3 +68,16 @@ export const generateFunctionTemplateCardData = templateData => { return functionTemplateCardData } + +export const filterSelectedFunctionMethods = result => { + const allowedMethods = trainModelAllowedHubFunctions[result.name] + const { entry_points } = result.functions[0].spec + + if (entry_points) { + result.functions[0].spec.entry_points = Object.fromEntries( + Object.entries(entry_points).filter(([key]) => allowedMethods.includes(key)) + ) + } + + return result +} diff --git a/src/components/Project/ProjectOverview/ProjectOverview.util.js b/src/components/Project/ProjectOverview/ProjectOverview.util.js index ae39511bb1..23dd060aeb 100644 --- a/src/components/Project/ProjectOverview/ProjectOverview.util.js +++ b/src/components/Project/ProjectOverview/ProjectOverview.util.js @@ -326,8 +326,7 @@ export const getInitialCards = (params, navigate, isDemoMode) => { }, label: 'Train model', tooltip: - 'Train a new model based on an input dataset. You can also define hyperparameters to execute and compare multiple models.', - hidden: !isDemoMode + 'Train a new model based on an input dataset. You can also define hyperparameters to execute and compare multiple models.' }, { id: 'createWorkflow', diff --git a/src/utils/generateTemplatesCategories.js b/src/utils/generateTemplatesCategories.js index 73c3b9e75c..38574d8248 100644 --- a/src/utils/generateTemplatesCategories.js +++ b/src/utils/generateTemplatesCategories.js @@ -19,6 +19,7 @@ such restriction. */ import { functionRunKinds } from '../components/Jobs/jobs.util' +import { trainModelAllowedHubFunctions } from '../components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.util' const excludedFunctionNames = ['batch-inference'] @@ -77,8 +78,15 @@ export const generateCategories = functionTemplates => { return { templates, templatesCategories } } -export const generateHubCategories = functionTemplates => { +export const generateHubCategories = (functionTemplates, isTrainModel) => { const hubFunctions = functionTemplates + .filter( + template => + functionRunKinds.includes(template.spec.kind) && + !excludedFunctionNames.includes(template.metadata.name) && + (!isTrainModel || + Object.keys(trainModelAllowedHubFunctions).includes(template.metadata.name)) + ) .map(template => ({ ...template, ui: { @@ -90,11 +98,6 @@ export const generateHubCategories = functionTemplates => { .map(funcTemplate => funcTemplate.metadata.version) } })) - .filter( - template => - functionRunKinds.includes(template.spec.kind) && - !excludedFunctionNames.includes(template.metadata.name) - ) const hubFunctionsCategories = [] diff --git a/src/utils/panelPathScheme.js b/src/utils/panelPathScheme.js index b424e22373..7c55686251 100644 --- a/src/utils/panelPathScheme.js +++ b/src/utils/panelPathScheme.js @@ -44,7 +44,7 @@ export const generateProjectsList = (projectsList, currentProject) => export const generateArtifactsList = artifacts => { const generatedArtifacts = artifacts .map(artifact => { - const key = artifact.link_iteration ? artifact.link_iteration.db_key : artifact.key ?? '' + const key = artifact.link_iteration?.db_key || artifact.db_key || artifact.key || '' return { label: key, id: key From bf6cd7c74a9f042661d961b47e5228417b5952ea Mon Sep 17 00:00:00 2001 From: illia prokopchuk Date: Mon, 6 Nov 2023 18:34:45 +0200 Subject: [PATCH 2/3] Comments fixed --- src/actions/functions.js | 4 +-- src/components/Datasets/datasets.util.js | 10 ++++--- src/components/JobWizard/JobWizard.js | 21 +++++++------- src/components/JobWizard/JobWizard.util.js | 26 +++++++++-------- .../JobWizardFunctionSelection.js | 29 ++++++++++--------- .../jobWizardFunctionSelection.util.js | 2 +- .../JobWizardRunDetails.js | 4 ++- .../ProjectOverview/ProjectOverview.util.js | 2 +- src/utils/generateTemplatesCategories.js | 9 +++--- 9 files changed, 59 insertions(+), 48 deletions(-) diff --git a/src/actions/functions.js b/src/actions/functions.js index 726ddb2b0f..01ccb07ee8 100644 --- a/src/actions/functions.js +++ b/src/actions/functions.js @@ -287,13 +287,13 @@ const functionsActions = { type: FETCH_HUB_FUNCTION_TEMPLATE_FAILURE, payload: err }), - fetchHubFunctions: isTrainModel => dispatch => { + fetchHubFunctions: allowedHubFunctions => dispatch => { dispatch(functionsActions.fetchHubFunctionsBegin()) return functionsApi .getHubFunctions() .then(({ data: functionTemplates }) => { - const templatesData = generateHubCategories(functionTemplates.catalog, isTrainModel) + const templatesData = generateHubCategories(functionTemplates.catalog, allowedHubFunctions) dispatch(functionsActions.setHubFunctions(templatesData)) diff --git a/src/components/Datasets/datasets.util.js b/src/components/Datasets/datasets.util.js index 7022447430..8c1f2b5144 100644 --- a/src/components/Datasets/datasets.util.js +++ b/src/components/Datasets/datasets.util.js @@ -106,16 +106,18 @@ export const generatePageData = (selectedItem, viewMode, params) => ({ }) const handleTrainDataset = (selectedItem, params) => { - const defaultDataInput = { + const prePopulatedDataInputs = [{ name: selectedItem.db_key || selectedItem.key || 'dataset', path: selectedItem.URI - } + }] openPopUp(JobWizard, { params, - isTrainModel: true, + isTrain: true, wizardTitle: 'Train model', - defaultDataInput + prePopulatedData: { + dataInputs: prePopulatedDataInputs + } }) } diff --git a/src/components/JobWizard/JobWizard.js b/src/components/JobWizard/JobWizard.js index e1d4865839..a72ff50f9b 100644 --- a/src/components/JobWizard/JobWizard.js +++ b/src/components/JobWizard/JobWizard.js @@ -77,7 +77,6 @@ import './jobWizard.scss' const JobWizard = ({ defaultData, - defaultDataInput, editJob, fetchFunctionTemplate, fetchHubFunction, @@ -85,13 +84,14 @@ const JobWizard = ({ functionsStore, isBatchInference, isOpen, - isTrainModel, + isTrain, jobsStore, mode, onResolve, onSuccessRequest, onWizardClose, params, + prePopulatedData, removeJobFunction, removeHubFunctions, runNewJob, @@ -290,7 +290,7 @@ const JobWizard = ({ { label: isBatchInference ? 'Schedule Infer' - : isTrainModel + : isTrain ? 'Schedule training job' : 'Schedule for later', onClick: () => { @@ -312,7 +312,7 @@ const JobWizard = ({ ? 'Save' : isBatchInference ? 'Infer now' - : isTrainModel + : isTrain ? 'Run training now' : 'Run', onClick: () => { @@ -442,15 +442,15 @@ const JobWizard = ({ @@ -519,26 +520,26 @@ const JobWizard = ({ JobWizard.defaultProps = { defaultData: {}, - defaultDataInput: {}, isBatchInference: false, - isTrainModel: false, + isTrain: false, mode: PANEL_CREATE_MODE, onSuccessRequest: () => {}, onWizardClose: () => {}, + prePopulatedData: {}, wizardTitle: 'Batch run' } JobWizard.propTypes = { defaultData: PropTypes.shape({}), - defaultDataInput: PropTypes.shape({}), isBatchInference: PropTypes.bool, isOpen: PropTypes.bool.isRequired, - isTrainModel: PropTypes.bool, + isTrain: PropTypes.bool, mode: JOB_WIZARD_MODE, onResolve: PropTypes.func.isRequired, onSuccessRequest: PropTypes.func, onWizardClose: PropTypes.func, params: PropTypes.shape({}).isRequired, + prePopulatedData: PropTypes.shape({}), wizardTitle: PropTypes.string } diff --git a/src/components/JobWizard/JobWizard.util.js b/src/components/JobWizard/JobWizard.util.js index e67ba39976..d9f671e7f0 100644 --- a/src/components/JobWizard/JobWizard.util.js +++ b/src/components/JobWizard/JobWizard.util.js @@ -103,7 +103,7 @@ export const generateJobWizardData = ( defaultData, currentProjectName, isEditMode, - defaultDataInput + prePopulatedData ) => { const functions = selectedFunctionData.functions const functionInfo = getFunctionInfo(selectedFunctionData) @@ -182,10 +182,10 @@ export const generateJobWizardData = ( jobFormData[RESOURCES_STEP].jobPriorityClassName = jobPriorityClassName } - if (!isEmpty(functionParameters) || !isEmpty(defaultDataInput)) { + if (!isEmpty(functionParameters) || !isEmpty(prePopulatedData.dataInputs)) { jobFormData[DATA_INPUTS_STEP].dataInputsTable = parseDataInputs( functionParameters, - defaultDataInput + prePopulatedData.dataInputs ) } @@ -618,8 +618,8 @@ const getDataInputData = (dataInputName, dataInputValue, dataInputIsChecked) => const sortParameters = (parameter, nextParameter) => nextParameter.isRequired - parameter.isRequired -export const parseDataInputs = (functionParameters = [], defaultDataInput) => { - const generatedDataInputs = functionParameters +export const parseDataInputs = (functionParameters = [], prePopulatedDataInputs) => { + const parsedDataInputs = functionParameters .filter(dataInputs => dataInputs.type?.includes('DataItem')) .map(dataInput => { return { @@ -632,16 +632,18 @@ export const parseDataInputs = (functionParameters = [], defaultDataInput) => { }) .sort(sortParameters) - if (!isEmpty(defaultDataInput)) { - generatedDataInputs.unshift({ - data: getDataInputData(defaultDataInput.name, defaultDataInput.path, true), - isRequired: true, - isDefault: true, - isPredefined: true + if (!isEmpty(prePopulatedDataInputs)) { + prePopulatedDataInputs.forEach(dataInput => { + parsedDataInputs.unshift({ + data: getDataInputData(dataInput.name, dataInput.path, true), + isRequired: true, + isDefault: true, + isPredefined: true + }) }) } - return generatedDataInputs + return parsedDataInputs } export const parseDefaultDataInputs = (funcParams, runDataInputs = {}) => { diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js index 0f9425099c..e670d9e99f 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js @@ -45,12 +45,13 @@ import { generateProjectsList } from '../../../../utils/projects' import { functionRunKinds } from '../../../Jobs/jobs.util' import { openConfirmPopUp } from 'igz-controls/utils/common.util' import { - filterSelectedFunctionMethods, + filterTrainFunctionMethods, FUNCTIONS_SELECTION_FUNCTIONS_TAB, FUNCTIONS_SELECTION_HUB_TAB, functionsSelectionTabs, generateFunctionCardData, - generateFunctionTemplateCardData + generateFunctionTemplateCardData, + trainModelAllowedHubFunctions } from './jobWizardFunctionSelection.util' import './jobWizardFunctionSelection.scss' @@ -58,15 +59,15 @@ import './jobWizardFunctionSelection.scss' const JobWizardFunctionSelection = ({ activeTab, defaultData, - defaultDataInput, filteredFunctions, filteredTemplates, formState, frontendSpec, functions, isEditMode, - isTrainModel, + isTrain, params, + prePopulatedData, selectedFunctionData, selectedFunctionTab, setActiveTab, @@ -219,7 +220,7 @@ const JobWizardFunctionSelection = ({ defaultData, params.projectName, isEditMode, - defaultDataInput + prePopulatedData ) const newInitial = { @@ -276,7 +277,9 @@ const JobWizardFunctionSelection = ({ activeTab === FUNCTIONS_SELECTION_HUB_TAB && (isEmpty(hubFunctions) || isEmpty(hubFunctionsCatalog)) ) { - dispatch(functionsActions.fetchHubFunctions(isTrainModel)).then(templatesObject => { + dispatch( + functionsActions.fetchHubFunctions(isTrain ? trainModelAllowedHubFunctions : {}) + ).then(templatesObject => { if (templatesObject) { setTemplatesCategories(templatesObject.hubFunctionsCategories) setTemplates(templatesObject.hubFunctions) @@ -302,7 +305,7 @@ const JobWizardFunctionSelection = ({ formState.initialValues, hubFunctions, hubFunctionsCatalog, - isTrainModel, + isTrain, setTemplates, setTemplatesCategories ]) @@ -332,10 +335,10 @@ const JobWizardFunctionSelection = ({ const functionTemplatePath = `${functionData.spec.item_uri}${functionData.spec.assets.function}` dispatch(functionsActions.fetchFunctionTemplate(functionTemplatePath)).then(result => { - const filteredResult = filterSelectedFunctionMethods(result) + const resultData = isTrain ? filterTrainFunctionMethods(result) : result - setSelectedFunctionData(filteredResult) - generateData(filteredResult) + setSelectedFunctionData(resultData) + generateData(resultData) setSelectedFunctionTab(FUNCTIONS_SELECTION_HUB_TAB) setShowSchedule(false) }) @@ -423,7 +426,7 @@ const JobWizardFunctionSelection = ({ placeholder="Search functions..." setMatches={setFilterMatches} /> - {!isTrainModel && ( + {!isTrain && ( { return functionTemplateCardData } -export const filterSelectedFunctionMethods = result => { +export const filterTrainFunctionMethods = result => { const allowedMethods = trainModelAllowedHubFunctions[result.name] const { entry_points } = result.functions[0].spec diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.js b/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.js index c88ab9a28b..747278ef77 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.js +++ b/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.js @@ -59,6 +59,7 @@ const JobWizardRunDetails = ({ isBatchInference, isEditMode, jobAdditionalData, + prePopulatedData, selectedFunctionData, stepIsActive }) => { @@ -82,7 +83,7 @@ const JobWizardRunDetails = ({ setSpyOnMethodChange(true) const functionParameters = getFunctionParameters(selectedFunctionData.functions, method) - const dataInputs = parseDataInputs(functionParameters) + const dataInputs = parseDataInputs(functionParameters, prePopulatedData.dataInputs) const predefinedParameters = parsePredefinedParameters(functionParameters) const methodData = getMethodData(selectedFunctionData, method) @@ -317,6 +318,7 @@ JobWizardRunDetails.propTypes = { isBatchInference: PropTypes.bool.isRequired, isEditMode: PropTypes.bool.isRequired, jobAdditionalData: PropTypes.shape({}).isRequired, + prePopulatedData: PropTypes.shape({}).isRequired, selectedFunctionData: PropTypes.shape({}).isRequired } diff --git a/src/components/Project/ProjectOverview/ProjectOverview.util.js b/src/components/Project/ProjectOverview/ProjectOverview.util.js index 23dd060aeb..7f5a5c28e0 100644 --- a/src/components/Project/ProjectOverview/ProjectOverview.util.js +++ b/src/components/Project/ProjectOverview/ProjectOverview.util.js @@ -317,7 +317,7 @@ export const getInitialCards = (params, navigate, isDemoMode) => { component: JobWizard, props: { params, - isTrainModel: true, + isTrain: true, wizardTitle: 'Train model', isOverview: true }, diff --git a/src/utils/generateTemplatesCategories.js b/src/utils/generateTemplatesCategories.js index 38574d8248..77ef3f1880 100644 --- a/src/utils/generateTemplatesCategories.js +++ b/src/utils/generateTemplatesCategories.js @@ -18,8 +18,9 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import { isEmpty } from 'lodash' + import { functionRunKinds } from '../components/Jobs/jobs.util' -import { trainModelAllowedHubFunctions } from '../components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.util' const excludedFunctionNames = ['batch-inference'] @@ -78,14 +79,14 @@ export const generateCategories = functionTemplates => { return { templates, templatesCategories } } -export const generateHubCategories = (functionTemplates, isTrainModel) => { +export const generateHubCategories = (functionTemplates, allowedHubFunctions = {}) => { const hubFunctions = functionTemplates .filter( template => functionRunKinds.includes(template.spec.kind) && !excludedFunctionNames.includes(template.metadata.name) && - (!isTrainModel || - Object.keys(trainModelAllowedHubFunctions).includes(template.metadata.name)) + (isEmpty(allowedHubFunctions) || + Object.keys(allowedHubFunctions).includes(template.metadata.name)) ) .map(template => ({ ...template, From d9937d3585f1959a131bbeac83c184bb08b045f1 Mon Sep 17 00:00:00 2001 From: illia prokopchuk Date: Tue, 7 Nov 2023 11:46:37 +0200 Subject: [PATCH 3/3] Added "Train model" button in Models page --- src/common/NameFilter/nameFilter.scss | 2 + .../ArtifactsActionBar/ArtifactsActionBar.js | 39 +++++++++++-------- src/components/Datasets/DatasetsView.js | 14 ++++--- src/components/Files/FilesView.js | 14 ++++--- src/components/ModelsPage/Models/Models.js | 10 +++++ .../ModelsPage/Models/ModelsView.js | 28 ++++++++----- src/scss/main.scss | 6 ++- 7 files changed, 75 insertions(+), 38 deletions(-) diff --git a/src/common/NameFilter/nameFilter.scss b/src/common/NameFilter/nameFilter.scss index 54382f0c99..fe294be763 100644 --- a/src/common/NameFilter/nameFilter.scss +++ b/src/common/NameFilter/nameFilter.scss @@ -16,6 +16,8 @@ such restriction. */ .name-filter { + min-width: 180px; + &__icon { cursor: pointer; } diff --git a/src/components/ArtifactsActionBar/ArtifactsActionBar.js b/src/components/ArtifactsActionBar/ArtifactsActionBar.js index da408556ce..894298281a 100644 --- a/src/components/ArtifactsActionBar/ArtifactsActionBar.js +++ b/src/components/ArtifactsActionBar/ArtifactsActionBar.js @@ -40,7 +40,7 @@ import detailsActions from '../../actions/details' import { ReactComponent as RefreshIcon } from 'igz-controls/images/refresh.svg' function ArtifactsActionBar({ - actionButton, + actionButtons, cancelRequest, filterMenuName, handleRefresh, @@ -154,13 +154,18 @@ function ArtifactsActionBar({
- {actionButton && !actionButton.hidden && ( -