Skip to content

Commit 1ca6918

Browse files
Merge pull request #1511 from devtron-labs/feat(pod-manifest)/hide-managed-fields
feat: hide managed fields from cluster terminal manifest
2 parents b880ad1 + 0085f9c commit 1ca6918

File tree

8 files changed

+124
-36
lines changed

8 files changed

+124
-36
lines changed

src/components/ClusterNodes/ClusterManifest.tsx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ReactComponent as WarningIcon } from '../../assets/icons/ic-warning.svg
1111
import { ReactComponent as Close } from '../../assets/icons/ic-cross.svg'
1212
import { defaultManifestErrorText, manifestCommentsRegex } from './constants'
1313
import { EditModeType } from '../v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/terminal/constants'
14+
import { getTrimmedManifestData } from '../v2/appDetails/k8Resource/nodeDetail/nodeDetail.util'
1415

1516
export default function ClusterManifest({
1617
terminalAccessId,
@@ -19,8 +20,12 @@ export default function ClusterManifest({
1920
setManifestData,
2021
errorMessage,
2122
setManifestAvailable,
22-
selectTerminalTab
23+
selectTerminalTab,
24+
hideManagedFields,
2325
}: ClusterManifestType) {
26+
// Manifest data with managed fields
27+
const [originalManifest, setOriginalManifest] = useState('')
28+
// Manifest data that we would be comparing with the edited manifest
2429
const [defaultManifest, setDefaultManifest] = useState('')
2530
const [manifestValue, setManifest] = useState('')
2631
const [loading, setLoading] = useState<boolean>(true)
@@ -32,8 +37,16 @@ export default function ClusterManifest({
3237
getClusterManifest(terminalAccessId)
3338
.then((response) => {
3439
const _manifest = YAML.stringify(response.result?.manifest)
35-
setDefaultManifest(_manifest)
36-
setManifest(_manifest)
40+
setOriginalManifest(_manifest)
41+
const trimmedManifest = YAML.stringify(getTrimmedManifestData(response.result?.manifest))
42+
setDefaultManifest(trimmedManifest)
43+
// Ideally should have been setManifest(trimmedManifest).
44+
if (hideManagedFields) {
45+
setManifest(trimmedManifest)
46+
}
47+
else {
48+
setManifest(_manifest)
49+
}
3750
setLoading(false)
3851
setManifestAvailable(true)
3952
})
@@ -51,10 +64,14 @@ export default function ClusterManifest({
5164
}
5265
}, [terminalAccessId])
5366

67+
// NOTE: Need to remove this useEffect since manifestMode changes on events only.
68+
// Since there can be alot of ways this useEffect interferes with other handlers, causing bugs.
69+
// Plus it might be a case when this useEffect will run before we have manifest, which will cause issues.
5470
useEffect(() => {
5571
const regex = manifestCommentsRegex
5672
if (manifestMode === EditModeType.NON_EDIT) {
57-
setManifest(defaultManifest)
73+
const _manifest = hideManagedFields ? defaultManifest : originalManifest
74+
setManifest(_manifest)
5875
} else if (manifestMode === EditModeType.APPLY) {
5976
const _manifestValue = manifestValue.replace(regex, 'apiVersion:')
6077
if (_manifestValue !== defaultManifest) {
@@ -63,21 +80,35 @@ export default function ClusterManifest({
6380
setManifestData(JSON.stringify(YAML.parse(_manifestValue)))
6481
} else {
6582
setManifest(defaultManifestErrorText)
83+
setManifestMode(EditModeType.EDIT)
6684
}
6785
} catch (error) {
68-
setManifest(defaultManifestErrorText + '# ' + error + '\n#\n' + _manifestValue)
86+
// Since we check error in edit as well, we can ignore this error and somehow infinite loop is created if we setManifest here.
6987
setManifestMode(EditModeType.EDIT)
7088
}
7189
} else {
7290
selectTerminalTab()
7391
setManifestMode(EditModeType.NON_EDIT)
7492
}
7593
} else if (manifestMode === EditModeType.EDIT) {
76-
if (errorMessage?.length) {
77-
setManifest(defaultManifestErrorText + '# ' + errorMessage + '\n#\n' + manifestValue)
94+
try {
95+
// Parsing will remove earlier comments, which will fix internal issues of code, currently the errorMessage is not getting cleared due to line 83.
96+
const parsedManifest = YAML.parse(manifestValue)
97+
if (parsedManifest) {
98+
const trimmedManifest = YAML.stringify(getTrimmedManifestData(parsedManifest))
99+
const errorDetails = errorMessage?.length ? defaultManifestErrorText + '# ' + errorMessage + '\n#\n' : ''
100+
setManifest(errorDetails + trimmedManifest)
101+
}
102+
else {
103+
setManifest(defaultManifestErrorText)
104+
}
105+
}
106+
catch (error) {
107+
// Should we directly use error object here?
108+
setManifest(defaultManifestErrorText + '# ' + error + '\n#\n' + manifestValue)
78109
}
79110
}
80-
}, [manifestMode])
111+
}, [manifestMode, hideManagedFields])
81112

82113
const switchToEditMode = (): void => {
83114
setManifestMode(EditModeType.EDIT)

src/components/ClusterNodes/ClusterTerminal.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from './clusterNodes.service'
1212
import { GroupHeading, menuComponentForImage, Option } from '../../components/v2/common/ReactSelect.utils'
1313
import { clusterImageDescription, convertToOptionsList } from '../common'
14-
import { get, ServerErrors, showError } from '@devtron-labs/devtron-fe-common-lib'
14+
import { Checkbox, CHECKBOX_VALUE, get, ServerErrors, showError } from '@devtron-labs/devtron-fe-common-lib'
1515
import ClusterManifest, { ManifestPopupMenu } from './ClusterManifest'
1616
import ClusterEvents from './ClusterEvents'
1717
import { ClusterTerminalType, NodeTaintType } from './types'
@@ -99,6 +99,7 @@ export default function ClusterTerminal({
9999
const [manifestErrors, setManifestErrors] = useState<string[]>()
100100
const [debugMode, setDebugMode] = useState<boolean>(false)
101101
const [isManifestAvailable, setManifestAvailable] = useState<boolean>()
102+
const [hideManagedFields, setHideManagedFields] = useState<boolean>(true)
102103
const isShellSwitched = useRef<boolean>(false)
103104
const autoSelectNodeRef = useRef(null)
104105
const terminalRef = useRef(null)
@@ -179,6 +180,7 @@ export default function ClusterTerminal({
179180
}
180181
const namespace = result.namespace
181182
setNamespace(namespace ? { label: namespace, value: namespace } : defaultNameSpace)
183+
setHideManagedFields(true)
182184
setManifestButtonState(EditModeType.NON_EDIT)
183185
terminalAccessIdRef.current = result.terminalAccessId
184186
socketConnecting()
@@ -337,6 +339,7 @@ export default function ClusterTerminal({
337339
function getNewSession() {
338340
if (!terminalAccessIdRef.current) return
339341
setSocketConnection(SocketConnectionType.CONNECTING)
342+
// It might be that we dont have resourceData.
340343
getClusterData(
341344
`user/terminal/get?namespace=${selectedNamespace.value}&shellName=${
342345
selectedTerminalType.value
@@ -627,6 +630,10 @@ export default function ClusterTerminal({
627630
setTerminalCleared(!terminalCleared)
628631
}
629632

633+
const handleToggleManagedFields = () => {
634+
setHideManagedFields(!hideManagedFields)
635+
}
636+
630637
const renderRegisterLinkMatcher = (terminal) => {
631638
const linkMatcherRegex = new RegExp(`${POD_LINKS.POD_MANIFEST}|${POD_LINKS.POD_EVENTS}`)
632639
terminal.registerLinkMatcher(linkMatcherRegex, (_event, text) => {
@@ -704,6 +711,7 @@ export default function ClusterTerminal({
704711
errorMessage={manifestErrors}
705712
setManifestAvailable={setManifestAvailable}
706713
selectTerminalTab={selectTerminalTab}
714+
hideManagedFields={hideManagedFields}
707715
/>
708716
</div>
709717
)}
@@ -815,13 +823,30 @@ export default function ClusterTerminal({
815823
}
816824
}
817825

826+
const renderHideManagedFields = () => (
827+
<div className="pt-6 pb-6 pl-12 pr-8 top">
828+
<Checkbox
829+
rootClassName="mb-0-imp h-18"
830+
isChecked={hideManagedFields}
831+
value={CHECKBOX_VALUE.CHECKED}
832+
onChange={handleToggleManagedFields}
833+
>
834+
<span className="mr-5 cn-9 fs-12 lh-18" data-testid="hide-pods-managed-fields">
835+
Hide Managed Fields
836+
</span>
837+
</Checkbox>
838+
</div>
839+
)
840+
818841
const closeManifetsPopup = (isClose: boolean): void => {
819842
setManifestButtonState(EditModeType.REVIEW)
820843
setManifestData('')
821844
setShowPodExistPopup(isClose)
822845
}
823846

824847
const hideShell: boolean = !(connectTerminal && isPodCreated && !selectedTabIndex)
848+
const showManagedFieldsCheckbox: boolean =
849+
selectedTabIndex === 2 && isManifestAvailable && manifestButtonState === EditModeType.NON_EDIT
825850

826851
const fullScreenClassWrapper = isFullScreen ? 'cluster-full_screen' : 'cluster-terminal-view-container'
827852
const nodeDetailsPageClassWrapper = isNodeDetailsPage || isClusterDetailsPage ? '' : 'node-terminal'
@@ -951,6 +976,14 @@ export default function ClusterTerminal({
951976
buttonSelectionState: manifestButtonState,
952977
setManifestButtonState: setManifestButtonState,
953978
},
979+
...(showManagedFieldsCheckbox
980+
? [
981+
{
982+
type: TerminalWrapperType.CUSTOM_COMPONENT,
983+
customComponent: renderHideManagedFields,
984+
},
985+
]
986+
: []),
954987
],
955988
tabSwitcher: {
956989
terminalTabWrapper: terminalTabWrapper,

src/components/ClusterNodes/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ export interface ClusterManifestType {
351351
errorMessage?: string[]
352352
setManifestAvailable: (isManifestAvailable: boolean) => void
353353
selectTerminalTab: () => void
354+
hideManagedFields: boolean
354355
}
355356

356357
export interface ClusterEditManifestType {

src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetail.component.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ function NodeDetailComponent({
262262
}
263263

264264
return (
265-
<React.Fragment>
265+
<>
266266
<div className="w-100 pr-20 pl-20 bcn-0 flex dc__border-bottom dc__content-space">
267267
<div className="flex left">
268268
<div data-testid="app-resource-containor-header" className="flex left">
@@ -423,7 +423,7 @@ function NodeDetailComponent({
423423
removeTabByIdentifier={removeTabByIdentifier}
424424
/>
425425
)}
426-
</React.Fragment>
426+
</>
427427
)
428428
}
429429

src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/Manifest.component.tsx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ import {
2323
EA_MANIFEST_SECRET_EDIT_MODE_INFO_TEXT,
2424
EA_MANIFEST_SECRET_INFO_TEXT,
2525
} from '../../../../../../config/constantMessaging'
26-
import { MANIFEST_KEY_FIELDS } from '../../../../../../config/constants'
2726
import { MODES } from '../../../../../../config'
2827
import { EMPTY_YAML_ERROR, SAVE_DATA_VALIDATION_ERROR_MSG } from '../../../../values/chartValuesDiff/ChartValuesView.constants'
28+
import { getTrimmedManifestData } from '../nodeDetail.util'
2929

3030
function ManifestComponent({
3131
selectedTab,
@@ -138,7 +138,7 @@ function ManifestComponent({
138138
toggleManagedFields(false)
139139
const jsonManifestData = YAML.parse(activeManifestEditorData)
140140
if (jsonManifestData?.metadata?.managedFields) {
141-
setTrimedManifestEditorData(trimManifestData(jsonManifestData))
141+
setTrimedManifestEditorData(getTrimmedManifestData(jsonManifestData, true) as string)
142142
}
143143
}
144144
}, [isEditmode])
@@ -152,27 +152,16 @@ function ManifestComponent({
152152
useEffect(() => {
153153
setTrimedManifestEditorData(activeManifestEditorData)
154154
if (activeTab === 'Live manifest') {
155-
let jsonManifestData = YAML.parse(activeManifestEditorData)
155+
const jsonManifestData = YAML.parse(activeManifestEditorData)
156156
if (jsonManifestData?.metadata?.managedFields) {
157157
toggleManagedFields(true)
158158
if (hideManagedFields) {
159-
setTrimedManifestEditorData(trimManifestData(jsonManifestData))
159+
setTrimedManifestEditorData(getTrimmedManifestData(jsonManifestData, true) as string)
160160
}
161161
}
162162
}
163163
}, [activeManifestEditorData, hideManagedFields, activeTab])
164164

165-
//For External
166-
const trimManifestData = (jsonManifestData: object): string => {
167-
const _trimedManifestData = JSON.stringify(jsonManifestData, (key, value) => {
168-
if (key === MANIFEST_KEY_FIELDS.METADATA) {
169-
value[MANIFEST_KEY_FIELDS.MANAGED_FIELDS] = undefined
170-
}
171-
return value
172-
})
173-
return _trimedManifestData
174-
}
175-
176165
const handleEditorValueChange = (codeEditorData: string) => {
177166
if (activeTab === 'Live manifest' && isEditmode) {
178167
setModifiedManifest(codeEditorData)

src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/Terminal.component.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,12 @@ function TerminalComponent({
307307
return (
308308
<div className={`${showTerminal ? '' : 'pod-terminal-hidden'}`}>
309309
<TerminalWrapper
310-
dataTestId="terminal-editor-header"
311-
selectionListData={selectionListData}
312-
socketConnection={socketConnection}
313-
setSocketConnection={setSocketConnection}
314-
className={isResourceBrowserView ? 'k8s-resource-view-container' : 'terminal-view-container'}
315-
/>
310+
dataTestId="terminal-editor-header"
311+
selectionListData={selectionListData}
312+
socketConnection={socketConnection}
313+
setSocketConnection={setSocketConnection}
314+
className={isResourceBrowserView ? 'k8s-resource-view-container' : 'terminal-view-container'}
315+
/>
316316
</div>
317317
)
318318
}

src/components/v2/appDetails/k8Resource/nodeDetail/nodeDetail.type.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { OptionType } from '@devtron-labs/devtron-fe-common-lib';
1+
import { OptionType } from '@devtron-labs/devtron-fe-common-lib'
22
import React from 'react'
3-
import {Options, OptionsBase } from "../../appDetails.type";
3+
import {Options, OptionsBase } from '../../appDetails.type'
4+
import { MANIFEST_KEY_FIELDS } from '../../../../../config'
45

56
export enum NodeDetailTab {
67
EVENTS = 'EVENTS',
@@ -68,3 +69,18 @@ export interface ResponsePayload {
6869
manifest: string
6970
}
7071
}
72+
73+
74+
interface ManagedFields {
75+
[key: string]: any
76+
}
77+
78+
interface ManifestMetadata {
79+
[MANIFEST_KEY_FIELDS.MANAGED_FIELDS]?: ManagedFields[]
80+
[key: string]: any
81+
}
82+
83+
export interface ManifestData {
84+
[MANIFEST_KEY_FIELDS.METADATA]?: ManifestMetadata
85+
[key: string]: any
86+
}

src/components/v2/appDetails/k8Resource/nodeDetail/nodeDetail.util.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import {
99
SelectedResourceType,
1010
} from '../../appDetails.type'
1111
import IndexStore from '../../index.store'
12-
import { NodeDetailTab } from './nodeDetail.type'
12+
import { ManifestData, NodeDetailTab } from './nodeDetail.type'
1313
import { multiSelectStyles } from '../../../common/ReactSelectCustomization'
1414
import { sortOptionsByLabel } from '../../../../common'
15+
import { MANIFEST_KEY_FIELDS } from '../../../../../config'
1516

1617
export const getNodeDetailTabs = (nodeType: NodeType, isResourceBrowserTab?: boolean) => {
1718
if (nodeType.toLowerCase() === NodeType.Pod.toLowerCase()) {
@@ -386,4 +387,21 @@ export const selectStyles = {
386387
...base,
387388
padding: '0 8px',
388389
}),
389-
}
390+
}
391+
392+
/**
393+
* @description This function is used to trim the manifest data by removing the managed fields from the manifest data
394+
*/
395+
export const getTrimmedManifestData = (
396+
manifestData: ManifestData,
397+
returnAsString: boolean = false,
398+
): ManifestData | string => {
399+
if (manifestData[MANIFEST_KEY_FIELDS.METADATA]) {
400+
const { [MANIFEST_KEY_FIELDS.MANAGED_FIELDS]: _, ...metadata } = manifestData[MANIFEST_KEY_FIELDS.METADATA]
401+
const trimmedManifestData = {...manifestData, [MANIFEST_KEY_FIELDS.METADATA]: metadata}
402+
403+
return returnAsString ? JSON.stringify(trimmedManifestData) : trimmedManifestData
404+
}
405+
406+
return returnAsString ? JSON.stringify(manifestData) : manifestData
407+
}

0 commit comments

Comments
 (0)