@@ -54,6 +54,9 @@ import { getBrandingConfig } from "../../redux/selectors/configSelectors";
5454import { messageInstance } from "lowcoder-design/src/components/GlobalInstances" ;
5555import { EditorContext } from "../../comps/editorState" ;
5656import Tooltip from "antd/es/tooltip" ;
57+ import { LockOutlined } from '@ant-design/icons' ;
58+ import Avatar from 'antd/es/avatar' ;
59+
5760
5861const StyledLink = styled . a `
5962 display: flex;
@@ -234,12 +237,6 @@ const DropdownStyled = styled(Dropdown)`
234237 }
235238` ;
236239
237- const DropdownMenuStyled = styled ( DropdownMenu ) `
238- .ant-dropdown-menu-item:hover {
239- background: #edf4fa;
240- }
241- ` ;
242-
243240const Wrapper = styled . div `
244241 .taco-edit-text-wrapper {
245242 width: fit-content;
@@ -262,6 +259,16 @@ const Prefix = styled.div`
262259 }
263260` ;
264261
262+ // Add the lock icon logic for disabled options
263+ const DropdownMenuStyled = styled ( DropdownMenu ) `
264+ .ant-dropdown-menu-item:hover {
265+ background: ${ ( props ) =>
266+ props . disabled ? 'inherit' : '#edf4fa' } ;
267+ cursor: ${ ( props ) =>
268+ props . disabled ? 'not-allowed' : 'pointer' } ;
269+ }
270+ ` ;
271+
265272function HeaderProfile ( props : { user : User } ) {
266273 const { user } = props ;
267274 const fetchingUser = useSelector ( isFetchingUser ) ;
@@ -318,6 +325,10 @@ export default function Header(props: HeaderProps) {
318325
319326 const isModule = appType === AppTypeEnum . Module ;
320327
328+ // Raheel: Todo - get concurrent editing state by API
329+ // maybe via editorState.getConcurrentAppEditingState(); as a new function?
330+ const [ concurrentAppEditingState , setConcurrentAppEditingState ] = useState ( true ) ;
331+
321332 const editorModeOptions = [
322333 {
323334 label : trans ( "header.editorMode_layout" ) ,
@@ -458,6 +469,16 @@ export default function Header(props: HeaderProps) {
458469 < HeaderProfile user = { user } />
459470 ) : (
460471 < >
472+ { /* Display a hint about who is editing the app */ }
473+ { concurrentAppEditingState && (
474+ < div style = { { display : 'flex' , alignItems : 'center' , marginRight : '8px' } } >
475+ < Avatar size = "small" src = { user . avatarUrl } />
476+ < span style = { { marginLeft : '8px' , fontSize : '12px' , color : '#b8b9bf' } } >
477+ { `${ user . username } is currently editing this app.` }
478+ </ span >
479+ </ div >
480+ ) }
481+
461482 { applicationId && (
462483 < AppPermissionDialog
463484 applicationId = { applicationId }
@@ -472,10 +493,11 @@ export default function Header(props: HeaderProps) {
472493 { SHARE_TITLE }
473494 </ GrayBtn >
474495 ) }
496+
475497 < PreviewBtn buttonType = "primary" onClick = { ( ) => preview ( applicationId ) } >
476498 { trans ( "header.preview" ) }
477499 </ PreviewBtn >
478-
500+
479501 < Dropdown
480502 className = "cypress-header-dropdown"
481503 placement = "bottomRight"
@@ -484,6 +506,7 @@ export default function Header(props: HeaderProps) {
484506 < DropdownMenuStyled
485507 style = { { minWidth : "110px" , borderRadius : "4px" } }
486508 onClick = { ( e ) => {
509+ if ( concurrentAppEditingState ) return ; // Prevent clicks if the app is being edited by someone else
487510 if ( e . key === "deploy" ) {
488511 dispatch ( publishApplication ( { applicationId } ) ) ;
489512 } else if ( e . key === "snapshot" ) {
@@ -494,24 +517,36 @@ export default function Header(props: HeaderProps) {
494517 {
495518 key : "deploy" ,
496519 label : (
497- < CommonTextLabel > { trans ( "header.deploy" ) } </ CommonTextLabel >
520+ < div style = { { display : 'flex' , alignItems : 'center' } } >
521+ { concurrentAppEditingState && < LockOutlined style = { { marginRight : '8px' } } /> }
522+ < CommonTextLabel style = { { color : concurrentAppEditingState ? "#ccc" : "#222" } } >
523+ { trans ( "header.deploy" ) }
524+ </ CommonTextLabel >
525+ </ div >
498526 ) ,
527+ disabled : concurrentAppEditingState ,
499528 } ,
500529 {
501530 key : "snapshot" ,
502531 label : (
503- < CommonTextLabel > { trans ( "header.snapshot" ) } </ CommonTextLabel >
532+ < div style = { { display : 'flex' , alignItems : 'center' } } >
533+ { concurrentAppEditingState && < LockOutlined style = { { marginRight : '8px' } } /> }
534+ < CommonTextLabel style = { { color : concurrentAppEditingState ? "#ccc" : "#222" } } >
535+ { trans ( "header.snapshot" ) }
536+ </ CommonTextLabel >
537+ </ div >
504538 ) ,
539+ disabled : concurrentAppEditingState ,
505540 } ,
506541 ] }
507542 />
508543 ) }
509544 >
510- < PackUpBtn buttonType = "primary" >
545+ < PackUpBtn buttonType = "primary" disabled = { concurrentAppEditingState } >
511546 < PackUpIcon />
512547 </ PackUpBtn >
513548 </ Dropdown >
514-
549+
515550 < HeaderProfile user = { user } />
516551 </ >
517552 ) ;
@@ -520,6 +555,7 @@ export default function Header(props: HeaderProps) {
520555 showAppSnapshot ,
521556 applicationId ,
522557 permissionDialogVisible ,
558+ concurrentAppEditingState , // Include the state in the dependency array
523559 ] ) ;
524560
525561 return (
0 commit comments