Skip to content

Commit f6b2416

Browse files
authored
Merge pull request #2775 from devtron-labs/fix/edit-taints-modal
fix: EditTaintsModal - remove empty state, fix not able to save empty taints
2 parents fad5761 + 352947c commit f6b2416

File tree

3 files changed

+88
-105
lines changed

3 files changed

+88
-105
lines changed

src/components/ClusterNodes/NodeActions/EditTaintsModal.tsx

Lines changed: 62 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,13 @@ import {
2424
ComponentSizeType,
2525
Drawer,
2626
DynamicDataTable,
27-
GenericEmptyState,
2827
Icon,
2928
InfoIconTippy,
3029
showError,
3130
ToastManager,
3231
ToastVariantType,
3332
} from '@devtron-labs/devtron-fe-common-lib'
3433

35-
import ImgEmptyChartGroup from '@Images/[email protected]'
36-
3734
import { updateTaints } from '../clusterNodes.service'
3835
import { EDIT_TAINTS_MODAL_MESSAGING, TAINTS_TABLE_HEADERS } from '../constants'
3936
import { EditTaintsModalType, EditTaintsRequest, TaintsTableHeaderKeys, TaintsTableType } from '../types'
@@ -76,9 +73,6 @@ const EditTaintsModal = ({ name, version, kind, taints, closePopup }: EditTaints
7673
// HOOKS
7774
const { clusterId } = useParams<{ clusterId: string }>()
7875

79-
// CONSTANTS
80-
const isTaintListEmpty = taintList.length === 0
81-
8276
// HANDLERS
8377
const onClose = () => {
8478
if (!apiCallInProgress) {
@@ -100,23 +94,29 @@ const EditTaintsModal = ({ name, version, kind, taints, closePopup }: EditTaints
10094
const updatedTaintCellError = structuredClone(taintCellError)
10195
delete updatedTaintCellError[row.id]
10296

97+
if (filteredTaintList.length === 0) {
98+
const newTaintsRow = getTaintsTableRow()
99+
filteredTaintList.push(newTaintsRow)
100+
updatedTaintCellError[newTaintsRow.id] = getTaintsRowCellError()
101+
}
102+
103103
setTaintList(filteredTaintList)
104104
setTaintCellError(updatedTaintCellError)
105105
}
106106

107107
const handleEditTaint: TaintsTableType['onRowEdit'] = (row, headerKey, value) => {
108-
const updatedTaintList = taintList.map((taint) =>
109-
taint.id === row.id
110-
? { ...taint, data: { ...taint.data, [headerKey]: { ...taint.data[headerKey], value } } }
111-
: taint,
112-
)
113-
const updatedTaintCellError = {
114-
...taintCellError,
115-
[row.id]: {
116-
...taintCellError[row.id],
117-
[headerKey]: getTaintsTableCellValidateState(headerKey, value),
118-
},
108+
const indexToUpdateInTaintList = taintList.findIndex((taint) => taint.id === row.id)
109+
if (indexToUpdateInTaintList === -1) {
110+
return
119111
}
112+
113+
const updatedTaintList = taintList
114+
const updatedTaintRow = taintList[indexToUpdateInTaintList]
115+
updatedTaintRow.data[headerKey].value = value
116+
updatedTaintList[indexToUpdateInTaintList] = updatedTaintRow
117+
118+
const updatedTaintCellError = structuredClone(taintCellError)
119+
updatedTaintCellError[row.id][headerKey] = getTaintsTableCellValidateState(headerKey, updatedTaintRow)
120120
validateUniqueTaintKey({ taintCellError: updatedTaintCellError, taintList: updatedTaintList })
121121

122122
setTaintList(updatedTaintList)
@@ -173,77 +173,56 @@ const EditTaintsModal = ({ name, version, kind, taints, closePopup }: EditTaints
173173
/>
174174
</div>
175175
<div className="flex-grow-1 dc__overflow-auto flexbox-col dc__gap-16 p-20">
176-
{isTaintListEmpty ? (
177-
<GenericEmptyState
178-
title={EDIT_TAINTS_MODAL_MESSAGING.emptyState.title}
179-
subTitle={EDIT_TAINTS_MODAL_MESSAGING.emptyState.subTitle}
180-
image={ImgEmptyChartGroup}
181-
isButtonAvailable
182-
renderButton={() => (
183-
<Button
184-
dataTestId="add-taint"
185-
text={EDIT_TAINTS_MODAL_MESSAGING.addTaint}
186-
startIcon={<Icon name="ic-add" color={null} />}
187-
onClick={handleAddTaint}
188-
/>
189-
)}
190-
/>
191-
) : (
192-
<>
193-
<div className="flex dc__content-space">
194-
<div className="flex">
195-
<Icon name="ic-spray-can" color="N900" />
196-
<h3 className="fs-14 lh-20 fw-6 cn-9 mt-0 mb-0 ml-8 mr-4">
197-
{EDIT_TAINTS_MODAL_MESSAGING.infoTitle}
198-
</h3>
199-
<InfoIconTippy
200-
heading="Taints"
201-
documentationLinkText="View documentation"
202-
documentationLink="TAINT"
203-
additionalContent={<AdditionalContent />}
204-
openInNewTab
205-
/>
206-
</div>
207-
<Button
208-
dataTestId="add-taint"
209-
variant={ButtonVariantType.secondary}
210-
startIcon={<Icon name="ic-add" color={null} />}
211-
size={ComponentSizeType.small}
212-
text={EDIT_TAINTS_MODAL_MESSAGING.addTaint}
213-
onClick={handleAddTaint}
214-
/>
215-
</div>
216-
<DynamicDataTable<TaintsTableHeaderKeys>
217-
headers={TAINTS_TABLE_HEADERS}
218-
rows={taintList}
219-
onRowAdd={handleAddTaint}
220-
onRowDelete={handleDeleteTaint}
221-
onRowEdit={handleEditTaint}
222-
cellError={taintCellError}
223-
isAdditionNotAllowed
224-
shouldAutoFocusOnMount
176+
<div className="flex dc__content-space">
177+
<div className="flex">
178+
<Icon name="ic-spray-can" color="N900" />
179+
<h3 className="fs-14 lh-20 fw-6 cn-9 mt-0 mb-0 ml-8 mr-4">
180+
{EDIT_TAINTS_MODAL_MESSAGING.infoTitle}
181+
</h3>
182+
<InfoIconTippy
183+
heading="Taints"
184+
documentationLinkText="View documentation"
185+
documentationLink="TAINT"
186+
additionalContent={<AdditionalContent />}
187+
openInNewTab
225188
/>
226-
</>
227-
)}
228-
</div>
229-
{!isTaintListEmpty && (
230-
<div className="dc__border-top flex right p-16 dc__gap-12">
189+
</div>
231190
<Button
232-
dataTestId="edit-taints-modal-cancel"
191+
dataTestId="add-taint"
233192
variant={ButtonVariantType.secondary}
234-
style={ButtonStyleType.neutral}
235-
disabled={apiCallInProgress}
236-
text={EDIT_TAINTS_MODAL_MESSAGING.Actions.cancel}
237-
onClick={onClose}
238-
/>
239-
<Button
240-
dataTestId="edit-taints-modal-save"
241-
isLoading={apiCallInProgress}
242-
text={EDIT_TAINTS_MODAL_MESSAGING.Actions.save}
243-
onClick={onSave}
193+
startIcon={<Icon name="ic-add" color={null} />}
194+
size={ComponentSizeType.small}
195+
text={EDIT_TAINTS_MODAL_MESSAGING.addTaint}
196+
onClick={handleAddTaint}
244197
/>
245198
</div>
246-
)}
199+
<DynamicDataTable<TaintsTableHeaderKeys>
200+
headers={TAINTS_TABLE_HEADERS}
201+
rows={taintList}
202+
onRowAdd={handleAddTaint}
203+
onRowDelete={handleDeleteTaint}
204+
onRowEdit={handleEditTaint}
205+
cellError={taintCellError}
206+
isAdditionNotAllowed
207+
shouldAutoFocusOnMount
208+
/>
209+
</div>
210+
<div className="dc__border-top flex right p-16 dc__gap-12">
211+
<Button
212+
dataTestId="edit-taints-modal-cancel"
213+
variant={ButtonVariantType.secondary}
214+
style={ButtonStyleType.neutral}
215+
disabled={apiCallInProgress}
216+
text={EDIT_TAINTS_MODAL_MESSAGING.Actions.cancel}
217+
onClick={onClose}
218+
/>
219+
<Button
220+
dataTestId="edit-taints-modal-save"
221+
isLoading={apiCallInProgress}
222+
text={EDIT_TAINTS_MODAL_MESSAGING.Actions.save}
223+
onClick={onSave}
224+
/>
225+
</div>
247226
</div>
248227
</Drawer>
249228
)

src/components/ClusterNodes/NodeActions/utils.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export const getTaintsTableRow = (taint?: TaintType, id?: number): TaintsTableTy
5353
})
5454

5555
export const getTaintsTableRows = (taints: TaintType[]): TaintsTableType['rows'] =>
56-
taints?.length ? taints.map(getTaintsTableRow) : []
56+
taints?.length ? taints.map(getTaintsTableRow) : [getTaintsTableRow()]
5757

5858
export const getTaintsRowCellError = () =>
5959
TAINTS_TABLE_HEADERS.reduce(
@@ -72,22 +72,25 @@ export const getTaintsTableCellError = (taintList: TaintsTableType['rows']): Tai
7272

7373
export const getTaintsTableCellValidateState = (
7474
headerKey: TaintsTableHeaderKeys,
75-
value: string,
75+
row: TaintsTableType['rows'][number],
7676
): DynamicDataTableCellValidationState => {
77-
if (headerKey === TaintsTableHeaderKeys.KEY) {
77+
const keyColumnValue = row.data[TaintsTableHeaderKeys.KEY].value
78+
const valueColumnValue = row.data[TaintsTableHeaderKeys.VALUE].value
79+
80+
if (headerKey === TaintsTableHeaderKeys.KEY && valueColumnValue) {
7881
const keyPrefixRegex = new RegExp(PATTERNS.KUBERNETES_KEY_PREFIX)
7982
const keyNameRegex = new RegExp(PATTERNS.KUBERNETES_KEY_NAME)
8083

81-
if (!value) {
84+
if (!keyColumnValue) {
8285
return { errorMessages: ['Key is required'], isValid: false }
8386
}
8487

85-
if (value.length > 253) {
88+
if (keyColumnValue.length > 253) {
8689
return { errorMessages: ['Maximum 253 chars are allowed'], isValid: false }
8790
}
8891

89-
if (value.indexOf('/') !== -1) {
90-
const keyArr = value.split('/')
92+
if (keyColumnValue.indexOf('/') !== -1) {
93+
const keyArr = keyColumnValue.split('/')
9194

9295
if (keyArr.length > 2 || !keyPrefixRegex.test(keyArr[0])) {
9396
return {
@@ -104,7 +107,7 @@ export const getTaintsTableCellValidateState = (
104107
isValid: false,
105108
}
106109
}
107-
} else if (!keyNameRegex.test(value)) {
110+
} else if (!keyNameRegex.test(keyColumnValue)) {
108111
return {
109112
errorMessages: [
110113
'The key must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores',
@@ -114,13 +117,13 @@ export const getTaintsTableCellValidateState = (
114117
}
115118
}
116119

117-
if (headerKey === TaintsTableHeaderKeys.VALUE && value) {
120+
if (headerKey === TaintsTableHeaderKeys.VALUE && valueColumnValue) {
118121
const valueRegex = new RegExp(PATTERNS.KUBERNETES_VALUE)
119122

120-
if (value.length > 63) {
123+
if (valueColumnValue.length > 63) {
121124
return { errorMessages: ['Maximum 63 chars are allowed'], isValid: false }
122125
}
123-
if (!valueRegex.test(value)) {
126+
if (!valueRegex.test(valueColumnValue)) {
124127
return {
125128
errorMessages: [
126129
'The value must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores',
@@ -195,7 +198,7 @@ export const getTaintTableValidateState = ({ taintList }: { taintList: TaintsTab
195198
acc[curr.id] = TAINTS_TABLE_HEADERS.reduce(
196199
(headerAcc, { key }) => ({
197200
...headerAcc,
198-
[key]: getTaintsTableCellValidateState(key, curr.data[key].value),
201+
[key]: getTaintsTableCellValidateState(key, curr),
199202
}),
200203
{},
201204
)
@@ -212,8 +215,14 @@ export const getTaintTableValidateState = ({ taintList }: { taintList: TaintsTab
212215
}
213216

214217
export const getTaintsPayload = (taintList: TaintsTableType['rows']) =>
215-
taintList.map(({ data }) => ({
216-
key: data.key.value,
217-
value: data.value.value,
218-
effect: data.effect.value as EFFECT_TYPE,
219-
}))
218+
taintList
219+
.map(({ data }) =>
220+
data.key.value
221+
? {
222+
key: data.key.value,
223+
value: data.value.value,
224+
effect: data.effect.value as EFFECT_TYPE,
225+
}
226+
: null,
227+
)
228+
.filter(Boolean)

src/components/ClusterNodes/constants.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,6 @@ export const EDIT_TAINTS_MODAL_MESSAGING = {
115115
'Combination of <key, effect> must be unique',
116116
],
117117
},
118-
emptyState: {
119-
title: 'Manage node taints',
120-
subTitle:
121-
'Add taints to nodes to prevent or discourage pods from being scheduled on them. Use tolerations on pods to let them run on nodes with matching taints.',
122-
},
123118
addTaint: 'Add taint',
124119
Actions: {
125120
cancel: 'Cancel',

0 commit comments

Comments
 (0)