Skip to content

Commit fa331f0

Browse files
authored
Merge pull request #1966 from devtron-labs/chore/revamp-manifest-component-header
feat: update manifest component header UI
2 parents a53c4c8 + 4a70284 commit fa331f0

File tree

5 files changed

+218
-196
lines changed

5 files changed

+218
-196
lines changed

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import { ExternalLink, OptionTypeWithIcon } from '../../externalLinks/ExternalLi
2626
import { iLink } from '../utils/tabUtils/link.type'
2727
import { EphemeralForm, EphemeralFormAdvancedType } from './k8Resource/nodeDetail/nodeDetail.type'
2828
import { useTabs } from '../../common/DynamicTabs/useTabs'
29-
import { ManifestTabJSON } from '../utils/tabUtils/tab.json'
3029

3130
export interface ApplicationObject extends iLink {
3231
selectedNode: string
@@ -470,18 +469,27 @@ export interface ManifestViewRefType {
470469
manifest: string
471470
activeManifestEditorData: string
472471
modifiedManifest: string
473-
isEditmode: boolean
474-
activeTab: (typeof ManifestTabJSON)[number]['name']
475472
}
476473
id: string
477474
}
478475

476+
export enum ManifestCodeEditorMode {
477+
READ = 'read',
478+
EDIT = 'edit',
479+
APPLY_CHANGES = 'applyChanges',
480+
CANCEL = 'cancel',
481+
}
482+
483+
479484
export interface ManifestActionPropsType extends ResourceInfoActionPropsType {
480485
hideManagedFields: boolean
481486
toggleManagedFields: (managedFieldsExist: boolean) => void
482487
manifestViewRef: MutableRefObject<ManifestViewRefType>
483488
getComponentKey: () => string
484-
isExternalApp: boolean
489+
showManifestCompareView: boolean
490+
setShowManifestCompareView: Dispatch<SetStateAction<boolean>>
491+
manifestCodeEditorMode: ManifestCodeEditorMode
492+
setManifestCodeEditorMode: Dispatch<SetStateAction<ManifestCodeEditorMode>>
485493
}
486494

487495
export interface NodeTreeDetailTabProps {

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

Lines changed: 112 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,31 @@
1616

1717
import React, { useEffect, useRef, useState, useMemo } from 'react'
1818
import { NavLink, Redirect, Route, Switch, useParams, useRouteMatch, useLocation } from 'react-router-dom'
19-
import { showError, Checkbox, CHECKBOX_VALUE, OptionType } from '@devtron-labs/devtron-fe-common-lib'
19+
import {
20+
showError,
21+
Checkbox,
22+
CHECKBOX_VALUE,
23+
OptionType,
24+
DeploymentAppTypes,
25+
} from '@devtron-labs/devtron-fe-common-lib'
26+
import { ReactComponent as ICArrowsLeftRight } from '@Icons/ic-arrows-left-right.svg'
27+
import { ReactComponent as ICPencil } from '@Icons/ic-pencil.svg'
28+
import { ReactComponent as ICCheck } from '@Icons/ic-check.svg'
2029
import EventsComponent from './NodeDetailTabs/Events.component'
2130
import LogsComponent from './NodeDetailTabs/Logs.component'
2231
import ManifestComponent from './NodeDetailTabs/Manifest.component'
2332
import TerminalComponent from './NodeDetailTabs/Terminal.component'
2433
import SummaryComponent from './NodeDetailTabs/Summary.component'
2534
import { NodeDetailTab, ParamsType } from './nodeDetail.type'
26-
import { ManifestViewRefType, NodeDetailPropsType, NodeType, Options, OptionsBase } from '../../appDetails.type'
35+
import {
36+
AppType,
37+
ManifestCodeEditorMode,
38+
ManifestViewRefType,
39+
NodeDetailPropsType,
40+
NodeType,
41+
Options,
42+
OptionsBase,
43+
} from '../../appDetails.type'
2744
import AppDetailsStore from '../../appDetails.store'
2845
import { useSharedState } from '../../../utils/useSharedState'
2946
import IndexStore from '../../index.store'
@@ -74,6 +91,8 @@ const NodeDetailComponent = ({
7491
const podMetaData = !isResourceBrowserView && IndexStore.getMetaDataForPod(params.podName)
7592
const { path, url } = useRouteMatch()
7693
const [showDeleteDialog, setShowDeleteDialog] = useState(false)
94+
const [showManifestCompareView, setShowManifestCompareView] = useState(false)
95+
const [manifestCodeEditorMode, setManifestCodeEditorMode] = useState<ManifestCodeEditorMode>(null)
7796

7897
const toggleManagedFields = (managedFieldsExist: boolean) => {
7998
if (selectedTabName === NodeDetailTab.MANIFEST && managedFieldsExist) {
@@ -98,6 +117,20 @@ const NodeDetailComponent = ({
98117
containers: [],
99118
}
100119

120+
const currentResource = isResourceBrowserView
121+
? selectedResource
122+
: appDetails.resourceTree.nodes.filter(
123+
(data) => data.name === params.podName && data.kind.toLowerCase() === params.nodeType,
124+
)[0]
125+
126+
const showDesiredAndCompareManifest =
127+
!isResourceBrowserView &&
128+
appDetails.appType === AppType.EXTERNAL_HELM_CHART &&
129+
!currentResource?.['parentRefs']?.length
130+
131+
const isResourceMissing =
132+
appDetails.appType === AppType.EXTERNAL_HELM_CHART && currentResource?.['health']?.status === 'Missing'
133+
101134
const [containers, setContainers] = useState<Options[]>(
102135
(isResourceBrowserView ? selectedResource?.containers ?? [] : getContainersData(podMetaData)) as Options[],
103136
)
@@ -117,13 +150,12 @@ const NodeDetailComponent = ({
117150
manifest: '',
118151
activeManifestEditorData: '',
119152
modifiedManifest: '',
120-
isEditmode: false,
121-
activeTab: 'Live manifest', // NOTE: default activeTab
122153
},
123154
id: '',
124155
})
125156

126157
useEffect(() => setManagedFields((prev) => prev && selectedTabName === NodeDetailTab.MANIFEST), [selectedTabName])
158+
127159
useEffect(() => {
128160
if (location.pathname.endsWith('/terminal') && params.nodeType === Nodes.Pod.toLowerCase()) {
129161
setStartTerminal(true)
@@ -301,6 +333,14 @@ const NodeDetailComponent = ({
301333
return Object.values(params).join('/')
302334
}
303335

336+
const handleManifestApplyChanges = () => setManifestCodeEditorMode(ManifestCodeEditorMode.APPLY_CHANGES)
337+
338+
const handleManifestCancel = () => setManifestCodeEditorMode(ManifestCodeEditorMode.CANCEL)
339+
340+
const handleManifestEdit = () => setManifestCodeEditorMode(ManifestCodeEditorMode.EDIT)
341+
342+
const handleManifestCompareWithDesired = () => setShowManifestCompareView(true)
343+
304344
const renderPodTerminal = (): JSX.Element => {
305345
if (!startTerminal) {
306346
return null
@@ -324,6 +364,69 @@ const NodeDetailComponent = ({
324364
)
325365
}
326366

367+
const renderManifestTabHeader = () => (
368+
<>
369+
{(isExternalApp ||
370+
isResourceBrowserView ||
371+
(appDetails.deploymentAppType === DeploymentAppTypes.GITOPS &&
372+
appDetails.deploymentAppDeleteRequest)) &&
373+
manifestCodeEditorMode &&
374+
!showManifestCompareView &&
375+
!isResourceMissing && (
376+
<>
377+
<div className="ml-4 mr-12 tab-cell-border" />
378+
{manifestCodeEditorMode === ManifestCodeEditorMode.EDIT ? (
379+
<div className="flex dc__gap-12">
380+
<button
381+
type="button"
382+
className="dc__unset-button-styles cb-5 fs-12 lh-1-5 fw-6 flex dc__gap-4"
383+
onClick={handleManifestApplyChanges}
384+
>
385+
<>
386+
<ICCheck className="icon-dim-16 scb-5" />
387+
<span>Apply changes</span>
388+
</>
389+
</button>
390+
<button
391+
type="button"
392+
className="dc__unset-button-styles fs-12 lh-1-5 fw-6 flex cn-6"
393+
onClick={handleManifestCancel}
394+
>
395+
Cancel
396+
</button>
397+
</div>
398+
) : (
399+
<button
400+
type="button"
401+
className="dc__unset-button-styles cb-5 fs-12 lh-1-5 fw-6 flex dc__gap-4"
402+
onClick={handleManifestEdit}
403+
>
404+
<>
405+
<ICPencil className="icon-dim-16 scb-5" />
406+
<span>Edit live manifest</span>
407+
</>
408+
</button>
409+
)}
410+
</>
411+
)}
412+
{manifestCodeEditorMode === ManifestCodeEditorMode.READ &&
413+
!showManifestCompareView &&
414+
(showDesiredAndCompareManifest || isResourceMissing) && (
415+
<>
416+
<div className="ml-12 mr-12 tab-cell-border" />
417+
<button
418+
type="button"
419+
className="dc__unset-button-styles cb-5 fs-12 lh-1-5 fw-6 flex dc__gap-4"
420+
onClick={handleManifestCompareWithDesired}
421+
>
422+
<ICArrowsLeftRight className="icon-dim-16 scb-5" />
423+
<span>Compare with desired</span>
424+
</button>
425+
</>
426+
)}
427+
</>
428+
)
429+
327430
return (
328431
<>
329432
<div
@@ -388,6 +491,7 @@ const NodeDetailComponent = ({
388491
</div>
389492
</>
390493
)}
494+
{selectedTabName === NodeDetailTab.MANIFEST && renderManifestTabHeader()}
391495
</div>
392496
{isResourceBrowserView &&
393497
!hideDeleteButton && ( // hide delete button if resource is deleted or user is not authorized
@@ -414,7 +518,10 @@ const NodeDetailComponent = ({
414518
selectedResource={selectedResource}
415519
manifestViewRef={manifestViewRef}
416520
getComponentKey={getComponentKeyFromParams}
417-
isExternalApp={isExternalApp}
521+
showManifestCompareView={showManifestCompareView}
522+
setShowManifestCompareView={setShowManifestCompareView}
523+
manifestCodeEditorMode={manifestCodeEditorMode}
524+
setManifestCodeEditorMode={setManifestCodeEditorMode}
418525
/>
419526
</Route>
420527
<Route path={`${path}/${NodeDetailTab.EVENTS}`}>

0 commit comments

Comments
 (0)