11import { toast } from 'react-toastify' ;
22import Axios from 'axios' ;
33import { actionType as T } from '../../reducer' ;
4- import { EXECUTION_ENGINE_URL } from '../../serverCon/config' ;
4+ import serverConConfig , { EXECUTION_ENGINE_URL } from '../../serverCon/config' ;
55import GraphLoadSave from './5-load-save' ;
66// import {
77// postGraph, updateGraph, forceUpdateGraph, getGraph, getGraphWithHashCheck,
@@ -11,6 +11,86 @@ import {
1111} from '../../serverCon/crud_http' ;
1212
1313class GraphServer extends GraphLoadSave {
14+ static isSyncConflictError ( err ) {
15+ const msg = ( err && err . message ? err . message : '' ) . toLowerCase ( ) ;
16+ return msg . includes ( 'different history' )
17+ || msg . includes ( 'latest changes' )
18+ || msg . includes ( 'can not update' ) ;
19+ }
20+
21+ showSyncConflictModal ( reason ) {
22+ const localHash = this . actionArr . length ? this . actionArr . at ( - 1 ) . hash : 'None' ;
23+ const setModal = ( remoteHash ) => {
24+ const message = [
25+ reason || 'Sync conflict detected.' ,
26+ `Local hash: ${ localHash } ` ,
27+ `Remote hash: ${ remoteHash || 'Remote history is newer/different' } ` ,
28+ 'Choose how to resolve this conflict.' ,
29+ ] . join ( '\n' ) ;
30+ this . dispatcher ( {
31+ type : T . SET_CONFIRM_MODAL ,
32+ payload : {
33+ open : true ,
34+ message,
35+ actions : [
36+ {
37+ label : 'Pull remote' ,
38+ className : 'confirm-btn' ,
39+ onClick : ( ) => this . forcePullFromServer ( ) ,
40+ } ,
41+ {
42+ label : 'Force push local' ,
43+ className : 'confirm-btn' ,
44+ onClick : ( ) => {
45+ if ( this . serverID ) {
46+ forceUpdateGraph ( this . serverID , this . getGraphML ( ) ) . catch ( ( err ) => {
47+ toast . error ( err . response ?. data ?. message || err . message ) ;
48+ } ) ;
49+ } else {
50+ postGraph ( this . getGraphML ( ) ) . then ( ( serverID ) => {
51+ this . set ( { serverID } ) ;
52+ } ) . catch ( ( err ) => {
53+ toast . error ( err . response ?. data ?. message || err . message ) ;
54+ } ) ;
55+ }
56+ } ,
57+ } ,
58+ {
59+ label : 'Open remote in new tab' ,
60+ className : 'cancel-btn' ,
61+ onClick : ( ) => {
62+ if ( ! this . serverID ) return ;
63+ const remotePath = serverConConfig . getGraph ( this . serverID ) ;
64+ const remoteURL = `${ serverConConfig . baseURL } ${ remotePath } ` ;
65+ window . open ( remoteURL , '_blank' , 'noopener,noreferrer' ) ;
66+ } ,
67+ } ,
68+ {
69+ label : 'Cancel' ,
70+ className : 'cancel-btn' ,
71+ onClick : null ,
72+ } ,
73+ ] ,
74+ } ,
75+ } ) ;
76+ } ;
77+ if ( ! this . serverID ) {
78+ setModal ( 'Unknown' ) ;
79+ return ;
80+ }
81+ getGraph ( this . serverID ) . then ( ( graphXML ) => {
82+ try {
83+ const doc = new DOMParser ( ) . parseFromString ( graphXML , 'application/xml' ) ;
84+ const hashes = doc . getElementsByTagName ( 'hash' ) ;
85+ setModal ( hashes . length ? ( hashes [ hashes . length - 1 ] . textContent || '' ) : '' ) ;
86+ } catch {
87+ setModal ( 'Unavailable' ) ;
88+ }
89+ } ) . catch ( ( ) => {
90+ setModal ( 'Unavailable' ) ;
91+ } ) ;
92+ }
93+
1494 set ( config ) {
1595 const { serverID } = config ;
1696 super . set ( config ) ;
@@ -73,6 +153,10 @@ class GraphServer extends GraphLoadSave {
73153 updateGraph ( this . serverID , this . getGraphML ( ) ) . then ( ( ) => {
74154
75155 } ) . catch ( ( err ) => {
156+ if ( GraphServer . isSyncConflictError ( err ) ) {
157+ this . showSyncConflictModal ( 'Cannot push: local and remote histories diverged.' ) ;
158+ return ;
159+ }
76160 toast . error ( err . response ?. data ?. message || err . message ) ;
77161 } ) ;
78162 } else {
@@ -127,8 +211,12 @@ class GraphServer extends GraphLoadSave {
127211 if ( this . serverID ) {
128212 getGraphWithHashCheck ( this . serverID , this . actionArr . at ( - 1 ) . hash ) . then ( ( graphXML ) => {
129213 this . setGraphML ( graphXML ) ;
130- } ) . catch ( ( ) => {
131-
214+ } ) . catch ( ( err ) => {
215+ if ( GraphServer . isSyncConflictError ( err ) ) {
216+ this . showSyncConflictModal ( 'Cannot pull: local and remote histories diverged.' ) ;
217+ return ;
218+ }
219+ toast . error ( err . response ?. data ?. message || err . message ) ;
132220 } ) ;
133221 } else {
134222 toast . success ( 'Not on server' ) ;
0 commit comments