14
14
* limitations under the License.
15
15
*/
16
16
17
- import { useEffect , useMemo , useState } from 'react'
18
- import { useHistory , useLocation , useParams , useRouteMatch } from 'react-router-dom'
17
+ import { useEffect , useMemo , useRef , useState } from 'react'
18
+ import { Prompt , useHistory , useLocation , useParams , useRouteMatch } from 'react-router-dom'
19
19
import Tippy from '@tippyjs/react'
20
20
import YAML from 'yaml'
21
21
@@ -24,6 +24,7 @@ import {
24
24
Checkbox ,
25
25
CHECKBOX_VALUE ,
26
26
CodeEditor ,
27
+ CodeEditorProps ,
27
28
ConditionalWrap ,
28
29
ConfigurationType ,
29
30
DeploymentAppTypes ,
@@ -36,8 +37,10 @@ import {
36
37
TOAST_ACCESS_DENIED ,
37
38
ToastManager ,
38
39
ToastVariantType ,
40
+ UNSAVED_CHANGES_PROMPT_MESSAGE ,
39
41
useEffectAfterMount ,
40
42
useMainContext ,
43
+ usePrompt ,
41
44
YAMLStringify ,
42
45
} from '@devtron-labs/devtron-fe-common-lib'
43
46
@@ -140,9 +143,12 @@ const ManifestComponent = ({
140
143
const [ lockedKeys , setLockedKeys ] = useState < string [ ] > ( null )
141
144
const [ showLockedDiffModal , setShowLockedDiffModal ] = useState ( false )
142
145
146
+ const previousEditorState = useRef ( '' )
147
+
143
148
const { isSuperAdmin } = useMainContext ( ) // to show the cluster meta data at the bottom
144
149
// Cancel is an intermediate state wherein edit is true
145
150
const isEditMode =
151
+ manifestCodeEditorMode === ManifestCodeEditorMode . REVIEW ||
146
152
manifestCodeEditorMode === ManifestCodeEditorMode . EDIT ||
147
153
manifestCodeEditorMode === ManifestCodeEditorMode . CANCEL
148
154
@@ -683,6 +689,41 @@ const ManifestComponent = ({
683
689
handleStickDynamicTabsToTop ?.( )
684
690
}
685
691
692
+ const hasUnsavedChanges = previousEditorState . current !== getCodeEditorValue ( )
693
+
694
+ usePrompt ( { shouldPrompt : hasUnsavedChanges } )
695
+
696
+ const getCodeEditorProps = ( ) => {
697
+ if ( ! previousEditorState . current ) {
698
+ previousEditorState . current = getCodeEditorValue ( )
699
+ }
700
+
701
+ if ( showManifestCompareView ) {
702
+ return {
703
+ diffView : true ,
704
+ originalValue : desiredManifest ,
705
+ modifiedValue : getCodeEditorValue ( ) ,
706
+ onModifiedValueChange : handleEditorValueChange ,
707
+ } as CodeEditorProps < true >
708
+ }
709
+
710
+ if ( manifestCodeEditorMode === ManifestCodeEditorMode . REVIEW ) {
711
+ return {
712
+ diffView : true ,
713
+ originalValue : previousEditorState . current ,
714
+ modifiedValue : getCodeEditorValue ( ) ,
715
+ onModifiedValueChange : handleEditorValueChange ,
716
+ } as CodeEditorProps < true >
717
+ }
718
+
719
+ return {
720
+ diffView : false ,
721
+ value : getCodeEditorValue ( ) ,
722
+ onChange : handleEditorValueChange ,
723
+ autoFocus : isEditMode ,
724
+ } as CodeEditorProps < false >
725
+ }
726
+
686
727
const renderContent = ( ) => {
687
728
if ( showGUIView ) {
688
729
return (
@@ -714,19 +755,7 @@ const ManifestComponent = ({
714
755
height = { isResourceBrowserView || isDynamicTabsStuck ? 'fitToParent' : '100%' }
715
756
onSearchPanelOpen = { handleStickDynamicTabsToTopWrapper }
716
757
onSearchBarAction = { handleStickDynamicTabsToTopWrapper }
717
- { ...( showManifestCompareView
718
- ? {
719
- diffView : true ,
720
- originalValue : desiredManifest ,
721
- modifiedValue : getCodeEditorValue ( ) ,
722
- onModifiedValueChange : handleEditorValueChange ,
723
- }
724
- : {
725
- diffView : false ,
726
- value : getCodeEditorValue ( ) ,
727
- onChange : handleEditorValueChange ,
728
- autoFocus : isEditMode ,
729
- } ) }
758
+ { ...getCodeEditorProps ( ) }
730
759
>
731
760
{ renderEditorInfo ( true ) }
732
761
@@ -761,50 +790,55 @@ const ManifestComponent = ({
761
790
)
762
791
}
763
792
764
- return isDeleted ? (
765
- < div className = "h-100 flex-grow-1" >
766
- < MessageUI msg = "This resource no longer exists" size = { 32 } />
767
- </ div >
768
- ) : (
769
- < div
770
- className = { `flexbox-col flex-grow-1 ${ isResourceBrowserView ? 'dc__overflow-auto' : '' } ` }
771
- data-testid = "app-manifest-container"
772
- style = { {
773
- background : 'var(--terminal-bg)' ,
774
- } }
775
- >
776
- { error && ! loading && < MessageUI msg = "Manifest not available" size = { 24 } /> }
777
- { ! error && (
793
+ return (
794
+ < >
795
+ < Prompt when = { hasUnsavedChanges } message = { UNSAVED_CHANGES_PROMPT_MESSAGE } />
796
+ { isDeleted ? (
797
+ < div className = "h-100 flex-grow-1" >
798
+ < MessageUI msg = "This resource no longer exists" size = { 32 } />
799
+ </ div >
800
+ ) : (
778
801
< div
779
- className = { `${
780
- manifestFormConfigurationType === ConfigurationType . GUI ? 'bg__primary' : ''
781
- } flexbox-col flex-grow-1 ${ isResourceBrowserView ? 'dc__overflow-hidden' : '' } `}
802
+ className = { `flexbox-col flex-grow-1 ${ isResourceBrowserView ? 'dc__overflow-auto' : '' } ` }
803
+ data-testid = "app-manifest-container"
804
+ style = { {
805
+ background : 'var(--terminal-bg)' ,
806
+ } }
782
807
>
783
- { isResourceMissing && ! loading && ! showManifestCompareView ? (
784
- < MessageUI
785
- msg = "Manifest not available"
786
- size = { 24 }
787
- isShowActionButton = { showDesiredAndCompareManifest }
788
- actionButtonText = "Recreate this resource"
789
- onActionButtonClick = { recreateResource }
808
+ { error && ! loading && < MessageUI msg = "Manifest not available" size = { 24 } /> }
809
+ { ! error && (
810
+ < div
811
+ className = { `${
812
+ manifestFormConfigurationType === ConfigurationType . GUI ? 'bg__primary' : ''
813
+ } flexbox-col flex-grow-1 ${ isResourceBrowserView ? 'dc__overflow-hidden' : '' } `}
814
+ >
815
+ { isResourceMissing && ! loading && ! showManifestCompareView ? (
816
+ < MessageUI
817
+ msg = "Manifest not available"
818
+ size = { 24 }
819
+ isShowActionButton = { showDesiredAndCompareManifest }
820
+ actionButtonText = "Recreate this resource"
821
+ onActionButtonClick = { recreateResource }
822
+ />
823
+ ) : (
824
+ renderContent ( )
825
+ ) }
826
+ </ div >
827
+ ) }
828
+
829
+ { showLockedDiffModal && ShowIneligibleChangesModal && (
830
+ < ShowIneligibleChangesModal
831
+ handleCallApplyChangesAPI = { handleCallApplyChangesAPI }
832
+ uneditedManifest = { uneditedManifest }
833
+ // NOTE: a check on modifiedManifest is made before this component is rendered
834
+ editedManifest = { YAML . parse ( modifiedManifest ) }
835
+ handleModalClose = { handleCloseShowLockedDiffModal }
836
+ lockedKeys = { lockedKeys }
790
837
/>
791
- ) : (
792
- renderContent ( )
793
838
) }
794
839
</ div >
795
840
) }
796
-
797
- { showLockedDiffModal && ShowIneligibleChangesModal && (
798
- < ShowIneligibleChangesModal
799
- handleCallApplyChangesAPI = { handleCallApplyChangesAPI }
800
- uneditedManifest = { uneditedManifest }
801
- // NOTE: a check on modifiedManifest is made before this component is rendered
802
- editedManifest = { YAML . parse ( modifiedManifest ) }
803
- handleModalClose = { handleCloseShowLockedDiffModal }
804
- lockedKeys = { lockedKeys }
805
- />
806
- ) }
807
- </ div >
841
+ </ >
808
842
)
809
843
}
810
844
0 commit comments