@@ -54,6 +54,9 @@ import { getBrandingConfig } from "../../redux/selectors/configSelectors";
54
54
import { messageInstance } from "lowcoder-design/src/components/GlobalInstances" ;
55
55
import { EditorContext } from "../../comps/editorState" ;
56
56
import Tooltip from "antd/es/tooltip" ;
57
+ import { LockOutlined } from '@ant-design/icons' ;
58
+ import Avatar from 'antd/es/avatar' ;
59
+
57
60
58
61
const StyledLink = styled . a `
59
62
display: flex;
@@ -234,12 +237,6 @@ const DropdownStyled = styled(Dropdown)`
234
237
}
235
238
` ;
236
239
237
- const DropdownMenuStyled = styled ( DropdownMenu ) `
238
- .ant-dropdown-menu-item:hover {
239
- background: #edf4fa;
240
- }
241
- ` ;
242
-
243
240
const Wrapper = styled . div `
244
241
.taco-edit-text-wrapper {
245
242
width: fit-content;
@@ -262,6 +259,16 @@ const Prefix = styled.div`
262
259
}
263
260
` ;
264
261
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
+
265
272
function HeaderProfile ( props : { user : User } ) {
266
273
const { user } = props ;
267
274
const fetchingUser = useSelector ( isFetchingUser ) ;
@@ -318,6 +325,10 @@ export default function Header(props: HeaderProps) {
318
325
319
326
const isModule = appType === AppTypeEnum . Module ;
320
327
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
+
321
332
const editorModeOptions = [
322
333
{
323
334
label : trans ( "header.editorMode_layout" ) ,
@@ -458,6 +469,16 @@ export default function Header(props: HeaderProps) {
458
469
< HeaderProfile user = { user } />
459
470
) : (
460
471
< >
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
+
461
482
{ applicationId && (
462
483
< AppPermissionDialog
463
484
applicationId = { applicationId }
@@ -472,10 +493,11 @@ export default function Header(props: HeaderProps) {
472
493
{ SHARE_TITLE }
473
494
</ GrayBtn >
474
495
) }
496
+
475
497
< PreviewBtn buttonType = "primary" onClick = { ( ) => preview ( applicationId ) } >
476
498
{ trans ( "header.preview" ) }
477
499
</ PreviewBtn >
478
-
500
+
479
501
< Dropdown
480
502
className = "cypress-header-dropdown"
481
503
placement = "bottomRight"
@@ -484,6 +506,7 @@ export default function Header(props: HeaderProps) {
484
506
< DropdownMenuStyled
485
507
style = { { minWidth : "110px" , borderRadius : "4px" } }
486
508
onClick = { ( e ) => {
509
+ if ( concurrentAppEditingState ) return ; // Prevent clicks if the app is being edited by someone else
487
510
if ( e . key === "deploy" ) {
488
511
dispatch ( publishApplication ( { applicationId } ) ) ;
489
512
} else if ( e . key === "snapshot" ) {
@@ -494,24 +517,36 @@ export default function Header(props: HeaderProps) {
494
517
{
495
518
key : "deploy" ,
496
519
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 >
498
526
) ,
527
+ disabled : concurrentAppEditingState ,
499
528
} ,
500
529
{
501
530
key : "snapshot" ,
502
531
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 >
504
538
) ,
539
+ disabled : concurrentAppEditingState ,
505
540
} ,
506
541
] }
507
542
/>
508
543
) }
509
544
>
510
- < PackUpBtn buttonType = "primary" >
545
+ < PackUpBtn buttonType = "primary" disabled = { concurrentAppEditingState } >
511
546
< PackUpIcon />
512
547
</ PackUpBtn >
513
548
</ Dropdown >
514
-
549
+
515
550
< HeaderProfile user = { user } />
516
551
</ >
517
552
) ;
@@ -520,6 +555,7 @@ export default function Header(props: HeaderProps) {
520
555
showAppSnapshot ,
521
556
applicationId ,
522
557
permissionDialogVisible ,
558
+ concurrentAppEditingState , // Include the state in the dependency array
523
559
] ) ;
524
560
525
561
return (
0 commit comments