Skip to content

Commit

Permalink
Fix [Artifacts] Change uniqueness validation and update messages (#2186)
Browse files Browse the repository at this point in the history
  • Loading branch information
mavdryk authored Jan 12, 2024
1 parent 774191c commit a2fe665
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 88 deletions.
12 changes: 10 additions & 2 deletions src/api/artifacts-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,16 @@ const artifactsApi = {
category
}
}),
getArtifact: (project, artifact) => {
return mainHttpClientV2.get(`/projects/${project}/artifacts?name=${artifact}`)
getArtifact: (project, artifactName, artifactTag) => {
const params = {
name: artifactName
}

if (artifactTag) {
params.tag = artifactTag
}

return mainHttpClientV2.get(`/projects/${project}/artifacts`, { params })
},
getArtifacts: (project, filters, config) => {
return fetchArtifacts(project, filters, config)
Expand Down
43 changes: 30 additions & 13 deletions src/components/RegisterArtifactModal/RegisterArtifactModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
import React from 'react'
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { connect, useDispatch } from 'react-redux'
import { useLocation } from 'react-router-dom'
import { v4 as uuidv4 } from 'uuid'
import { Form } from 'react-final-form'
import { createForm } from 'final-form'
import arrayMutators from 'final-form-arrays'
import { isEmpty } from 'lodash'

import RegisterArtifactModalForm from '../../elements/RegisterArtifactModalForm/RegisterArtifactModalForm'
import { Button, Modal } from 'igz-controls/components'
Expand All @@ -38,7 +39,7 @@ import {
import artifactApi from '../../api/artifacts-api'
import { ARTIFACT_TYPE } from '../../constants'
import { convertChipsData } from '../../utils/convertChipsData'
import { messagesByKind } from './messagesByKind'
import { createArtifactMessages } from '../../utils/createArtifact.util'
import { setFieldState } from 'igz-controls/utils/form.util'
import { setNotification } from '../../reducers/notificationReducer'
import { showErrorNotification } from '../../utils/notifications.util'
Expand Down Expand Up @@ -70,6 +71,7 @@ const RegisterArtifactModal = ({
}
}
}
const [uniquenessErrorIsShown, setUniquenessErrorIsShown] = useState(false)
const formRef = React.useRef(
createForm({
initialValues,
Expand Down Expand Up @@ -104,17 +106,29 @@ const RegisterArtifactModal = ({
}

return artifactApi
.registerArtifact(params.projectName, data)
.getArtifact(params.projectName, values.metadata.key, values.metadata.tag)
.then(response => {
resolveModal()
refresh(filtersStore)
dispatch(
setNotification({
status: response.status,
id: Math.random(),
message: `${title} initiated successfully`
})
)
if (response?.data) {
if (!isEmpty(response.data.artifacts)) {
setUniquenessErrorIsShown(true)
} else {
setUniquenessErrorIsShown(false)

return artifactApi
.registerArtifact(params.projectName, data)
.then(response => {
resolveModal()
refresh(filtersStore)
dispatch(
setNotification({
status: response.status,
id: Math.random(),
message: `${title} initiated successfully`
})
)
})
}
}
})
.catch(error => {
const customErrorMsg =
Expand All @@ -124,6 +138,7 @@ const RegisterArtifactModal = ({

showErrorNotification(dispatch, error, '', customErrorMsg, () => registerArtifact(values))

setUniquenessErrorIsShown(false)
resolveModal()
})
}
Expand Down Expand Up @@ -164,10 +179,12 @@ const RegisterArtifactModal = ({
<RegisterArtifactModalForm
formState={formState}
initialValues={initialValues}
messagesByKind={messagesByKind[artifactKind.toLowerCase()]}
messagesByKind={createArtifactMessages[artifactKind.toLowerCase()]}
params={params}
setFieldState={formState.form.mutators.setFieldState}
setUniquenessErrorIsShown={setUniquenessErrorIsShown}
showType={artifactKind === ARTIFACT_TYPE}
uniquenessErrorIsShown={uniquenessErrorIsShown}
/>
</Modal>
)
Expand Down
31 changes: 0 additions & 31 deletions src/components/RegisterArtifactModal/messagesByKind.js

This file was deleted.

30 changes: 18 additions & 12 deletions src/elements/RegisterArtifactModalForm/RegisterArtifactModalForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@ such restriction.
import React, { useMemo } from 'react'
import PropTypes from 'prop-types'

import ErrorMessage from '../../common/ErrorMessage/ErrorMessage'
import TargetPath from '../../common/TargetPath/TargetPath'
import { FormInput, FormSelect, FormTextarea, FormChipCell } from 'igz-controls/components'
import { ARTIFACT_TYPE, MLRUN_STORAGE_INPUT_PATH_SCHEME } from '../../constants'

import { getValidationRules } from 'igz-controls/utils/validation.util'
import { isArtifactNameUnique } from '../../utils/artifacts.util'
import { ARTIFACT_TYPE, MLRUN_STORAGE_INPUT_PATH_SCHEME } from '../../constants'
import { getChipOptions } from '../../utils/getChipOptions'
import { getValidationRules } from 'igz-controls/utils/validation.util'

const RegisterArtifactModalForm = ({
formState,
initialValues,
messagesByKind,
params,
setFieldState,
showType
setUniquenessErrorIsShown,
showType,
uniquenessErrorIsShown
}) => {
const kindOptions = useMemo(
() => [
Expand Down Expand Up @@ -78,20 +80,22 @@ const RegisterArtifactModalForm = ({
</div>
)}
</div>
{uniquenessErrorIsShown && (
<div className="form-row">
<ErrorMessage
closeError={() => setUniquenessErrorIsShown(false)}
message={messagesByKind.uniquenessError}
/>
</div>
)}
<div className="form-row">
<div className="form-col-2">
<FormInput
async
label="Name"
name="metadata.key"
required
tip={messagesByKind?.nameTip}
validationRules={getValidationRules('artifact.name', {
name: 'ArtifactExists',
label: 'Artifact name must be unique',
pattern: isArtifactNameUnique(params.projectName),
async: true
})}
validationRules={getValidationRules('artifact.name')}
/>
</div>
<div className="form-col-1">
Expand Down Expand Up @@ -150,7 +154,9 @@ RegisterArtifactModalForm.propTypes = {
messagesByKind: PropTypes.object,
params: PropTypes.shape({}).isRequired,
setFieldState: PropTypes.func.isRequired,
showType: PropTypes.bool
setUniquenessErrorIsShown: PropTypes.func.isRequired,
showType: PropTypes.bool,
uniquenessError: PropTypes.string.isRequired
}

export default RegisterArtifactModalForm
56 changes: 36 additions & 20 deletions src/elements/RegisterModelModal/RegisterModelModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,27 @@ illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your` compliance with
such restriction.
*/
import React from 'react'
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { useDispatch, useSelector } from 'react-redux'
import { useLocation } from 'react-router-dom'
import { createForm } from 'final-form'
import { Form } from 'react-final-form'
import arrayMutators from 'final-form-arrays'
import { v4 as uuidv4 } from 'uuid'
import { isEmpty } from 'lodash'

import { Button, Modal, FormChipCell, FormInput, FormTextarea } from 'igz-controls/components'
import ErrorMessage from '../../common/ErrorMessage/ErrorMessage'
import TargetPath from '../../common/TargetPath/TargetPath'
import { Button, Modal, FormChipCell, FormInput, FormTextarea } from 'igz-controls/components'

import artifactApi from '../../api/artifacts-api'
import { MLRUN_STORAGE_INPUT_PATH_SCHEME } from '../../constants'
import { MODAL_SM, SECONDARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants'
import { convertChipsData } from '../../utils/convertChipsData'
import { getChipOptions } from '../../utils/getChipOptions'
import { getValidationRules } from 'igz-controls/utils/validation.util'
import { isArtifactNameUnique } from '../../utils/artifacts.util'
import { modelUniquenessError } from '../../utils/createArtifact.util'
import { setFieldState } from 'igz-controls/utils/form.util'
import { setNotification } from '../../reducers/notificationReducer'
import { showErrorNotification } from '../../utils/notifications.util'
Expand All @@ -59,6 +61,7 @@ function RegisterModelModal({ actions, isOpen, onResolve, params, refresh }) {
}
}
}
const [uniquenessErrorIsShown, setUniquenessErrorIsShown] = useState(false)
const formRef = React.useRef(
createForm({
initialValues,
Expand Down Expand Up @@ -99,22 +102,33 @@ function RegisterModelModal({ actions, isOpen, onResolve, params, refresh }) {
}

return artifactApi
.registerArtifact(params.projectName, data)
.getArtifact(params.projectName, values.metadata.key, values.metadata.tag)
.then(response => {
resolveModal()
refresh(filtersStore)
dispatch(
setNotification({
status: response.status,
id: Math.random(),
message: 'Model initiated successfully'
})
)
if (response?.data) {
if (!isEmpty(response.data.artifacts)) {
setUniquenessErrorIsShown(true)
} else {
setUniquenessErrorIsShown(false)

return artifactApi.registerArtifact(params.projectName, data).then(response => {
resolveModal()
refresh(filtersStore)
dispatch(
setNotification({
status: response.status,
id: Math.random(),
message: 'Model initiated successfully'
})
)
})
}
}
})
.catch(error => {
showErrorNotification(dispatch, error, '', 'Model failed to initiate', () =>
registerModel(values)
)
setUniquenessErrorIsShown(false)
resolveModal()
})
}
Expand Down Expand Up @@ -151,20 +165,22 @@ function RegisterModelModal({ actions, isOpen, onResolve, params, refresh }) {
size={MODAL_SM}
title="Register model"
>
{uniquenessErrorIsShown && (
<div className="form-row">
<ErrorMessage
closeError={() => setUniquenessErrorIsShown(false)}
message={modelUniquenessError}
/>
</div>
)}
<div className="form-row">
<div className="form-col-2">
<FormInput
async
label="Name"
name="metadata.key"
required
tip="Artifacts names in the same project must be unique."
validationRules={getValidationRules('artifact.name', {
name: 'ArtifactExists',
label: 'Artifact name must be unique',
pattern: isArtifactNameUnique(params.projectName),
async: true
})}
validationRules={getValidationRules('artifact.name')}
/>
</div>
<div className="form-col-1">
Expand Down
10 changes: 0 additions & 10 deletions src/utils/artifacts.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,6 @@ export const applyTagChanges = (changes, artifactItem, projectName, dispatch, se
}
}

export const isArtifactNameUnique = projectName => async value => {
if (!value) return

const {
data: { artifacts }
} = await artifactApi.getArtifact(projectName, value)

return artifacts.length === 0
}

export const isArtifactTagUnique = (projectName, category, artifact) => async value => {
const artifactCategory = {
MODELS_TAB: MODEL_TYPE,
Expand Down
35 changes: 35 additions & 0 deletions src/utils/createArtifact.util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Copyright 2019 Iguazio Systems Ltd.
Licensed under the Apache License, Version 2.0 (the "License") with
an addition restriction as set forth herein. You may not use this
file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
In addition, you may not use the software for any purposes that are
illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
export const modelUniquenessError = 'That combination of model name and model tag is already in use. Assign a unique combination of model name and model tag.'
const artifactSubTitle = 'Assign it a unique combination of name and tag, and specify its path (for example, s3://mybucket/path).'

export const createArtifactMessages = {
artifact: {
title: 'Register an artifact in MLRun so it can be used, for example, by functions, jobs, and pipelines.',
subTitle: artifactSubTitle,
uniquenessError: 'That combination of artifact name and artifact tag is already in use. Assign a unique combination of artifact name and artifact tag.'
},
dataset: {
title:
'Register a dataset as an artifact in MLRun so it can be used, for example, by functions, jobs, and pipelines.',
subTitle: artifactSubTitle,
uniquenessError: 'That combination of dataset name and dataset tag is already in use. Assign a unique combination of dataset name and dataset tag.'
}
}

0 comments on commit a2fe665

Please sign in to comment.