Skip to content

Commit 41759a7

Browse files
RI-7186 validate job name separately
1 parent 9ad8f32 commit 41759a7

File tree

6 files changed

+86
-12
lines changed

6 files changed

+86
-12
lines changed

redisinsight/ui/src/components/yaml-validator/validatePipeline.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import { get } from 'lodash'
2-
import { validateYamlSchema } from './validateYamlSchema'
2+
import { Nullable } from 'uiSrc/utils'
3+
import { validateSchema, validateYamlSchema } from './validateYamlSchema'
34

45
interface PipelineValidationProps {
56
config: string
67
schema: any
8+
monacoJobsSchema: Nullable<object>
9+
jobNameSchema: Nullable<object>
710
jobs: { name: string; value: string }[]
811
}
912

1013
export const validatePipeline = ({
1114
config,
1215
schema,
16+
monacoJobsSchema,
17+
jobNameSchema,
1318
jobs,
1419
}: PipelineValidationProps) => {
1520
const { valid: isConfigValid, errors: configErrors } = validateYamlSchema(
@@ -22,7 +27,11 @@ export const validatePipeline = ({
2227
jobsErrors: Record<string, Set<string>>
2328
}>(
2429
(acc, j) => {
25-
const validation = validateYamlSchema(j.value, get(schema, 'jobs', null))
30+
const validation = validateYamlSchema(j.value, monacoJobsSchema)
31+
const jobNameValidation = validateSchema(j.name, jobNameSchema, {
32+
errorMessagePrefix: 'Job name',
33+
includePathIntoErrorMessage: false,
34+
})
2635

2736
if (!acc.jobsErrors[j.name]) {
2837
acc.jobsErrors[j.name] = new Set()
@@ -32,7 +41,14 @@ export const validatePipeline = ({
3241
validation.errors.forEach((error) => acc.jobsErrors[j.name].add(error))
3342
}
3443

35-
acc.areJobsValid = acc.areJobsValid && validation.valid
44+
if (!jobNameValidation.valid) {
45+
jobNameValidation.errors.forEach((error) =>
46+
acc.jobsErrors[j.name].add(error),
47+
)
48+
}
49+
50+
acc.areJobsValid =
51+
acc.areJobsValid && validation.valid && jobNameValidation.valid
3652
return acc
3753
},
3854
{ areJobsValid: true, jobsErrors: {} },

redisinsight/ui/src/components/yaml-validator/validateYamlSchema.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import yaml, { YAMLException } from 'js-yaml'
22
import Ajv from 'ajv'
33

4-
export const validateYamlSchema = (
5-
content: string,
4+
type ValidationConfig = {
5+
errorMessagePrefix?: string
6+
includePathIntoErrorMessage?: boolean
7+
}
8+
9+
export const validateSchema = (
10+
parsed: any,
611
schema: any,
12+
config: ValidationConfig = {},
713
): { valid: boolean; errors: string[] } => {
14+
const errorMessagePrefix = config.errorMessagePrefix ?? 'Error:'
15+
const includePathIntoErrorMessage = config.includePathIntoErrorMessage ?? true
16+
817
try {
9-
const parsed = yaml.load(content)
1018
const ajv = new Ajv({
1119
strict: false,
1220
unicodeRegExp: false,
@@ -18,12 +26,28 @@ export const validateYamlSchema = (
1826

1927
if (!valid) {
2028
const errors = validate.errors?.map(
21-
(err) => `Error: ${err.message} (at ${err.instancePath || 'root'})`,
29+
(err) => {
30+
const pathMessage = includePathIntoErrorMessage ? ` (at ${err.instancePath || 'root'})` : ''
31+
return `${[errorMessagePrefix]} ${err.message}${pathMessage}`
32+
}
2233
)
2334
return { valid: false, errors: errors || [] }
2435
}
2536

2637
return { valid: true, errors: [] }
38+
} catch (e) {
39+
return { valid: false, errors: [`${errorMessagePrefix} unknown error`] }
40+
}
41+
}
42+
43+
export const validateYamlSchema = (
44+
content: string,
45+
schema: any,
46+
): { valid: boolean; errors: string[] } => {
47+
try {
48+
const parsed = yaml.load(content) as object
49+
50+
return validateSchema(parsed, schema)
2751
} catch (e) {
2852
if (e instanceof YAMLException) {
2953
return { valid: false, errors: [`Error: ${e.reason}`] }

redisinsight/ui/src/pages/rdi/instance/components/header/components/pipeline-actions/PipelineActions.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const PipelineActions = ({ collectorStatus, pipelineStatus }: Props) => {
3838
const {
3939
loading: deployLoading,
4040
schema,
41+
monacoJobsSchema,
42+
jobNameSchema,
4143
config,
4244
jobs,
4345
} = useSelector(rdiPipelineSelector)
@@ -56,7 +58,13 @@ const PipelineActions = ({ collectorStatus, pipelineStatus }: Props) => {
5658
}
5759

5860
const { result, configValidationErrors, jobsValidationErrors } =
59-
validatePipeline({ schema, config, jobs })
61+
validatePipeline({
62+
schema,
63+
monacoJobsSchema,
64+
jobNameSchema,
65+
config,
66+
jobs,
67+
})
6068

6169
dispatch(setConfigValidationErrors(configValidationErrors))
6270
dispatch(setJobsValidationErrors(jobsValidationErrors))

redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/Job.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useEffect, useRef, useCallback } from 'react'
22
import { useDispatch, useSelector } from 'react-redux'
3-
import { get, throttle } from 'lodash'
3+
import { throttle } from 'lodash'
44
import cx from 'classnames'
55
import { monaco as monacoEditor } from 'react-monaco-editor'
66

@@ -59,7 +59,7 @@ const Job = (props: Props) => {
5959
const deployedJobValueRef = useRef<Maybe<string>>(deployedJobValue)
6060
const jobNameRef = useRef<string>(name)
6161

62-
const { loading, schema, jobFunctions, jobs } =
62+
const { loading, monacoJobsSchema, jobFunctions, jobs } =
6363
useSelector(rdiPipelineSelector)
6464

6565
useEffect(() => {
@@ -243,7 +243,7 @@ const Job = (props: Props) => {
243243
</div>
244244
) : (
245245
<MonacoYaml
246-
schema={get(schema, 'jobs', null)}
246+
schema={monacoJobsSchema}
247247
value={value}
248248
onChange={handleChange}
249249
disabled={loading}

redisinsight/ui/src/slices/interfaces/rdi.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ export interface IStateRdiPipeline {
185185
jobsValidationErrors: Record<string, string[]>
186186
resetChecked: boolean
187187
schema: Nullable<object>
188+
jobNameSchema: Nullable<object>
189+
monacoJobsSchema: Nullable<object>
188190
strategies: IRdiPipelineStrategies
189191
changes: Record<string, FileChangeType>
190192
jobFunctions: monacoEditor.languages.CompletionItem[]

redisinsight/ui/src/slices/rdi/pipeline.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
22
import { AxiosError } from 'axios'
3+
import { get, omit } from 'lodash'
34
import { apiService } from 'uiSrc/services'
45
import {
56
addErrorNotification,
@@ -45,6 +46,8 @@ export const initialState: IStateRdiPipeline = {
4546
jobsValidationErrors: {},
4647
resetChecked: false,
4748
schema: null,
49+
jobNameSchema: null,
50+
monacoJobsSchema: null,
4851
strategies: {
4952
loading: false,
5053
error: '',
@@ -128,6 +131,18 @@ const rdiPipelineSlice = createSlice({
128131
) => {
129132
state.schema = payload
130133
},
134+
setMonacoJobsSchema: (
135+
state,
136+
{ payload }: PayloadAction<Nullable<object>>,
137+
) => {
138+
state.monacoJobsSchema = payload
139+
},
140+
setJobNameSchema: (
141+
state,
142+
{ payload }: PayloadAction<Nullable<object>>,
143+
) => {
144+
state.jobNameSchema = payload
145+
},
131146
getPipelineStrategies: (state) => {
132147
state.strategies.loading = true
133148
},
@@ -224,6 +239,8 @@ export const {
224239
deployPipelineSuccess,
225240
deployPipelineFailure,
226241
setPipelineSchema,
242+
setMonacoJobsSchema,
243+
setJobNameSchema,
227244
getPipelineStrategies,
228245
getPipelineStrategiesSuccess,
229246
getPipelineStrategiesFailure,
@@ -399,12 +416,19 @@ export function fetchRdiPipelineSchema(
399416
) {
400417
return async (dispatch: AppDispatch) => {
401418
try {
402-
const { data, status } = await apiService.get<IPipeline>(
419+
const { data, status } = await apiService.get<Nullable<object>>(
403420
getRdiUrl(rdiInstanceId, ApiEndpoints.RDI_PIPELINE_SCHEMA),
404421
)
405422

406423
if (isStatusSuccessful(status)) {
407424
dispatch(setPipelineSchema(data))
425+
dispatch(setMonacoJobsSchema({
426+
...omit(get(data, ['jobs'], {}), ['properties.name']),
427+
required: get(data, ['jobs', 'required'], []).filter(
428+
(val: string) => val !== 'name',
429+
),
430+
}))
431+
dispatch(setJobNameSchema(get(data, ['jobs', 'properties', 'name'], '^aaa&')))
408432
onSuccessAction?.(data)
409433
}
410434
} catch (_err) {

0 commit comments

Comments
 (0)