Skip to content

Commit

Permalink
fix: correct the usage of pods preview (chaos-mesh#785)
Browse files Browse the repository at this point in the history
* fix: correct the usage of pods preview

Signed-off-by: Yue Yang <[email protected]>

* chore: add comment

Signed-off-by: Yue Yang <[email protected]>

* fix: typo

Signed-off-by: Yue Yang <[email protected]>

Co-authored-by: ti-srebot <[email protected]>
  • Loading branch information
g1eny0ung and ti-srebot authored Aug 6, 2020
1 parent 65eff1a commit 645db62
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 23 deletions.
7 changes: 6 additions & 1 deletion ui/src/components/FormField/AutocompleteMultipleField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const AutocompleteMultipleField: React.FC<AutocompleteMultipleFieldProps & TextF
}) => {
const { values, setFieldValue } = useFormikContext<Experiment>()

const firstRenderRef = useRef(false) // This ref prevents to exec the callback function when labels are empty in the first render
const labelsRef = useRef(getIn(values, props.name!))
const [labels, _setLabels] = useState<string[]>(labelsRef.current)
const setLabels = (newVal: string[]) => {
Expand Down Expand Up @@ -44,8 +45,12 @@ const AutocompleteMultipleField: React.FC<AutocompleteMultipleFieldProps & TextF
}

useEffect(() => {
if (typeof onChangeCallback === 'function') {
if (typeof onChangeCallback === 'function' && (labels.length > 0 || firstRenderRef.current)) {
onChangeCallback(labels)

if (!firstRenderRef.current) {
firstRenderRef.current = true
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [labels])
Expand Down
28 changes: 24 additions & 4 deletions ui/src/components/NewExperiment/Stepper/Scope.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { AutocompleteMultipleField, SelectField, TextField } from 'components/Fo
import { Box, Divider, InputAdornment, MenuItem, Typography } from '@material-ui/core'
import React, { useMemo } from 'react'
import { RootState, useStoreDispatch } from 'store'
import { arrToObjBySep, joinObjKVs, toTitleCase } from 'lib/utils'
import { getAnnotations, getLabels, getPodsByNamespaces } from 'slices/experiments'
import { getIn, useFormikContext } from 'formik'
import { joinObjKVs, toTitleCase } from 'lib/utils'

import AdvancedOptions from 'components/AdvancedOptions'
import { Experiment } from '../types'
Expand Down Expand Up @@ -39,6 +39,24 @@ const ScopeStep: React.FC<ScopeStepProps> = ({ namespaces, scope = 'scope' }) =>
storeDispatch(getPodsByNamespaces({ namespace_selectors: _labels }))
}

const handleLabelSelectorsChangeCallback = (labels: string[]) =>
storeDispatch(
getPodsByNamespaces({
namespace_selectors: namespaces,
label_selectors: arrToObjBySep(labels, ': '),
annotation_selectors: annotations,
})
)

const handleAnnotationSelectorsChangeCallback = (labels: string[]) =>
storeDispatch(
getPodsByNamespaces({
namespace_selectors: namespaces,
label_selectors: labels,
annotation_selectors: arrToObjBySep(labels, ': '),
})
)

const handleChangeIncludeAll = (id: string) => (e: React.ChangeEvent<HTMLInputElement>) => {
const lastValues = id.split('.').reduce((acc, cur) => acc[cur], values as any)
const currentValues = (e.target.value as unknown) as string[]
Expand Down Expand Up @@ -71,6 +89,7 @@ const ScopeStep: React.FC<ScopeStepProps> = ({ namespaces, scope = 'scope' }) =>
label="Label Selectors"
helperText="Multiple options"
options={labelKVs}
onChangeCallback={handleLabelSelectorsChangeCallback}
/>

<SelectField id={`${scope}.mode`} name={`${scope}.mode`} label="Mode" helperText="Select the experiment mode">
Expand Down Expand Up @@ -108,6 +127,7 @@ const ScopeStep: React.FC<ScopeStepProps> = ({ namespaces, scope = 'scope' }) =>
label="Annotation Selectors"
helperText="Multiple options"
options={annotationKVs}
onChangeCallback={handleAnnotationSelectorsChangeCallback}
/>

<SelectField
Expand All @@ -132,9 +152,9 @@ const ScopeStep: React.FC<ScopeStepProps> = ({ namespaces, scope = 'scope' }) =>
<Divider />
</Box>
<Box mb={6}>
<Typography>Pods</Typography>
<Typography variant="body2" color="textSecondary">
This will overide Label Selectors and Annotation Selectors
<Typography>Affected Pods Preview</Typography>
<Typography variant="subtitle2" color="textSecondary">
You can further limit the scope of the experiment by checking pods
</Typography>
</Box>
<ScopePodsTable scope={scope} pods={pods} />
Expand Down
54 changes: 37 additions & 17 deletions ui/src/components/NewExperiment/Stepper/ScopePodsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Checkbox, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@material-ui/core'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { getIn, useFormikContext } from 'formik'
import { setAlert, setAlertOpen } from 'slices/globalStatus'

import { Experiment } from 'components/NewExperiment/types'
import { useFormikContext } from 'formik'
import { useStoreDispatch } from 'store'

const PaperOutlined: React.FC = ({ children }) => <Paper variant="outlined">{children}</Paper>

Expand All @@ -12,31 +14,36 @@ interface ScopePodsTableProps {
}

const ScopePodsTable: React.FC<ScopePodsTableProps> = ({ scope = 'scope', pods }) => {
const { values, setFieldValue } = useFormikContext<Experiment>()

const podsCount = pods.length

const originFormPods = getIn(values, `${scope}.pods`)
const formPods = useMemo(
() =>
originFormPods
? Object.entries<string[]>(originFormPods)
.map((d) => d[1])
.reduce((acc, d) => acc.concat(d), [])
: [],
[originFormPods]
)
const { setFieldValue } = useFormikContext<Experiment>()

const dispatch = useStoreDispatch()

const formPods = useMemo(() => pods.map((d) => d.name).reduce((acc, d) => acc.concat(d), []), [pods])
const podsCount = formPods.length
const podsCountRef = useRef(podsCount)

const selectedRef = useRef(formPods)
const [selected, _setSelected] = useState<string[]>(selectedRef.current)
const setSelected = (newVal: string[]) => {
selectedRef.current = newVal
_setSelected(selectedRef.current)
}

const numSelected = selected.length
const isSelected = (name: string) => selected.indexOf(name) !== -1

useEffect(() => {
setSelected(formPods)
podsCountRef.current = formPods.length
}, [formPods])

useEffect(
() => () =>
() => () => {
// If all pods are checked, then only need to pass selectors
if (selectedRef.current.length === podsCountRef.current) {
return
}

setFieldValue(
`${scope}.pods`,
pods
Expand All @@ -50,7 +57,8 @@ const ScopePodsTable: React.FC<ScopePodsTableProps> = ({ scope = 'scope', pods }

return acc
}, {})
),
)
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
)
Expand Down Expand Up @@ -81,6 +89,18 @@ const ScopePodsTable: React.FC<ScopePodsTableProps> = ({ scope = 'scope', pods }
newSelected = [...selected.slice(0, selectedIndex), ...selected.slice(selectedIndex + 1)]
}

if (newSelected.length === 0) {
dispatch(
setAlert({
type: 'warning',
message: 'Please select at least one pod.',
})
)
dispatch(setAlertOpen(true))

return
}

setSelected(newSelected)
}

Expand Down
12 changes: 12 additions & 0 deletions ui/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,15 @@ export function joinObjKVs(obj: { [key: string]: string[] }, separator: string,
.filter((d) => !filters?.includes(d[0]))
.reduce((acc: string[], [key, val]) => acc.concat(val.map((d) => `${key}${separator}${d}`)), [])
}

export function arrToObjBySep(arr: string[], sep: string) {
const result: any = {}

arr.forEach((d) => {
const splited = d.split(sep)

result[splited[0]] = splited[1]
})

return result as object
}
2 changes: 1 addition & 1 deletion ui/src/slices/experiments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const getAnnotations = createAsyncThunk(
)
export const getPodsByNamespaces = createAsyncThunk(
'common/pods',
async (data: Pick<ExperimentScope, 'namespace_selectors'>) => (await api.common.pods(data)).data
async (data: Partial<ExperimentScope>) => (await api.common.pods(data)).data
)

const initialState: {
Expand Down

0 comments on commit 645db62

Please sign in to comment.