@@ -20,7 +20,7 @@ import { ArrayExt, toArray } from '@lumino/algorithm';
20
20
import { CommandRegistry } from '@lumino/commands' ;
21
21
import { PromiseDelegate } from '@lumino/coreutils' ;
22
22
import { Message } from '@lumino/messaging' ;
23
- import { Menu , Panel } from '@lumino/widgets' ;
23
+ import { ContextMenu , Menu , Panel } from '@lumino/widgets' ;
24
24
import * as React from 'react' ;
25
25
import { DiffModel } from './components/diff/model' ;
26
26
import { createPlainTextDiff } from './components/diff/PlainTextDiff' ;
@@ -1009,9 +1009,6 @@ export function createGitMenu(
1009
1009
return menu ;
1010
1010
}
1011
1011
1012
- // matches only non-directory items
1013
- const selectorNotDir = '.jp-DirListing-item[data-isdir="false"]' ;
1014
-
1015
1012
export function addMenuItems (
1016
1013
commands : ContextCommandIDs [ ] ,
1017
1014
contextMenu : Menu ,
@@ -1043,12 +1040,11 @@ export function addMenuItems(
1043
1040
}
1044
1041
1045
1042
/**
1046
- * Add Git context (sub)menu to the file browser context menu .
1043
+ * Populate Git context submenu depending on the selected files .
1047
1044
*/
1048
1045
export function addFileBrowserContextMenu (
1049
1046
model : IGitExtension ,
1050
1047
tracker : WidgetTracker < FileBrowser > ,
1051
- commands : CommandRegistry ,
1052
1048
contextMenu : ContextMenuSvg
1053
1049
) : void {
1054
1050
function getSelectedBrowserItems ( ) : Contents . IModel [ ] {
@@ -1059,112 +1055,133 @@ export function addFileBrowserContextMenu(
1059
1055
return toArray ( widget . selectedItems ( ) ) ;
1060
1056
}
1061
1057
1062
- class GitMenu extends Menu {
1063
- private _commands : ContextCommandIDs [ ] ;
1064
- private _paths : string [ ] ;
1065
-
1066
- protected onBeforeAttach ( msg : Message ) {
1067
- // Render using the most recent model (even if possibly outdated)
1068
- this . updateItems ( ) ;
1069
- const renderedStatus = model . status ;
1070
-
1071
- // Trigger refresh before the menu is displayed
1072
- model
1073
- . refreshStatus ( )
1074
- . then ( ( ) => {
1075
- if ( model . status !== renderedStatus ) {
1076
- // update items if needed
1077
- this . updateItems ( ) ;
1078
- }
1079
- } )
1080
- . catch ( error => {
1081
- console . error (
1082
- 'Fail to refresh model when displaying git context menu.' ,
1083
- error
1084
- ) ;
1085
- } ) ;
1086
- super . onBeforeAttach ( msg ) ;
1087
- }
1088
-
1089
- protected updateItems ( ) : void {
1090
- const wasShown = this . isVisible ;
1091
- const parent = this . parentMenu ;
1092
-
1093
- const items = getSelectedBrowserItems ( ) ;
1094
- const statuses = new Set < Git . Status > (
1095
- items . map ( item => model . getFile ( item . path ) . status )
1096
- ) ;
1097
-
1098
- // get commands and de-duplicate them
1099
- const allCommands = new Set < ContextCommandIDs > (
1100
- // flatten the list of lists of commands
1101
- [ ]
1102
- . concat ( ...[ ...statuses ] . map ( status => CONTEXT_COMMANDS [ status ] ) )
1103
- // filter out the Open and Delete commands as
1104
- // those are not needed in file browser
1105
- . filter (
1106
- command =>
1107
- command !== ContextCommandIDs . gitFileOpen &&
1108
- command !== ContextCommandIDs . gitFileDelete &&
1109
- typeof command !== 'undefined'
1110
- )
1111
- // replace stage and track with a single "add" operation
1112
- . map ( command =>
1113
- command === ContextCommandIDs . gitFileStage ||
1114
- command === ContextCommandIDs . gitFileTrack
1115
- ? ContextCommandIDs . gitFileAdd
1116
- : command
1117
- )
1058
+ let gitMenu : Menu ;
1059
+ let _commands : ContextCommandIDs [ ] ;
1060
+ let _paths : string [ ] ;
1061
+
1062
+ function updateItems ( menu : Menu ) : void {
1063
+ const wasShown = menu . isVisible ;
1064
+ const parent = menu . parentMenu ;
1065
+
1066
+ const items = getSelectedBrowserItems ( ) ;
1067
+ const statuses = new Set < Git . Status > (
1068
+ items
1069
+ . map ( item => model . getFile ( item . path ) ?. status )
1070
+ . filter ( status => typeof status !== 'undefined' )
1071
+ ) ;
1072
+
1073
+ // get commands and de-duplicate them
1074
+ const allCommands = new Set < ContextCommandIDs > (
1075
+ // flatten the list of lists of commands
1076
+ [ ]
1077
+ . concat ( ...[ ...statuses ] . map ( status => CONTEXT_COMMANDS [ status ] ) )
1078
+ // filter out the Open and Delete commands as
1079
+ // those are not needed in file browser
1080
+ . filter (
1081
+ command =>
1082
+ command !== ContextCommandIDs . gitFileOpen &&
1083
+ command !== ContextCommandIDs . gitFileDelete &&
1084
+ typeof command !== 'undefined'
1085
+ )
1086
+ // replace stage and track with a single "add" operation
1087
+ . map ( command =>
1088
+ command === ContextCommandIDs . gitFileStage ||
1089
+ command === ContextCommandIDs . gitFileTrack
1090
+ ? ContextCommandIDs . gitFileAdd
1091
+ : command
1092
+ )
1093
+ ) ;
1094
+
1095
+ const commandsChanged =
1096
+ ! _commands ||
1097
+ _commands . length !== allCommands . size ||
1098
+ ! _commands . every ( command => allCommands . has ( command ) ) ;
1099
+
1100
+ const paths = items . map ( item => item . path ) ;
1101
+
1102
+ const filesChanged = ! _paths || ! ArrayExt . shallowEqual ( _paths , paths ) ;
1103
+
1104
+ if ( commandsChanged || filesChanged ) {
1105
+ const commandsList = [ ...allCommands ] ;
1106
+ menu . clearItems ( ) ;
1107
+ addMenuItems (
1108
+ commandsList ,
1109
+ menu ,
1110
+ paths
1111
+ . map ( path => model . getFile ( path ) )
1112
+ // if file cannot be resolved (has no action available),
1113
+ // omit the undefined result
1114
+ . filter ( file => typeof file !== 'undefined' )
1118
1115
) ;
1119
1116
1120
- // if looking at a tracked file without any actions available
1121
- // (although `git rm` would be a valid action)
1122
- if ( allCommands . size === 0 ) {
1123
- allCommands . add ( ContextCommandIDs . gitNoAction ) ;
1117
+ if ( wasShown ) {
1118
+ // show the menu again after downtime for refresh
1119
+ parent . triggerActiveItem ( ) ;
1124
1120
}
1121
+ _commands = commandsList ;
1122
+ _paths = paths ;
1123
+ }
1124
+ }
1125
1125
1126
- const commandsChanged =
1127
- ! this . _commands ||
1128
- this . _commands . length !== allCommands . size ||
1129
- ! this . _commands . every ( command => allCommands . has ( command ) ) ;
1130
-
1131
- const paths = items . map ( item => item . path ) ;
1126
+ function updateGitMenu ( contextMenu : ContextMenu ) {
1127
+ if ( ! gitMenu ) {
1128
+ gitMenu =
1129
+ contextMenu . menu . items . find (
1130
+ item =>
1131
+ item . type === 'submenu' && item . submenu ?. id === 'jp-contextmenu-git'
1132
+ ) ?. submenu ?? null ;
1133
+ }
1132
1134
1133
- const filesChanged =
1134
- ! this . _paths || ! ArrayExt . shallowEqual ( this . _paths , paths ) ;
1135
+ if ( ! gitMenu ) {
1136
+ return ; // Bail early if the open with menu is not displayed
1137
+ }
1135
1138
1136
- if ( commandsChanged || filesChanged ) {
1137
- const commandsList = [ ... allCommands ] ;
1138
- this . clearItems ( ) ;
1139
- addMenuItems (
1140
- commandsList ,
1141
- this ,
1142
- paths . map ( path => model . getFile ( path ) )
1143
- ) ;
1144
- if ( wasShown ) {
1145
- // show the menu again after downtime for refresh
1146
- parent . triggerActiveItem ( ) ;
1139
+ // Render using the most recent model (even if possibly outdated)
1140
+ updateItems ( gitMenu ) ;
1141
+ const renderedStatus = model . status ;
1142
+
1143
+ // Trigger refresh before the menu is displayed
1144
+ model
1145
+ . refreshStatus ( )
1146
+ . then ( ( ) => {
1147
+ if ( model . status !== renderedStatus ) {
1148
+ // update items if needed
1149
+ updateItems ( gitMenu ) ;
1147
1150
}
1148
- this . _commands = commandsList ;
1149
- this . _paths = paths ;
1150
- }
1151
- }
1151
+ } )
1152
+ . catch ( error => {
1153
+ console . error (
1154
+ 'Fail to refresh model when displaying git context menu.' ,
1155
+ error
1156
+ ) ;
1157
+ } ) ;
1158
+ }
1152
1159
1153
- onBeforeShow ( msg : Message ) : void {
1154
- super . onBeforeShow ( msg ) ;
1160
+ // as any is to support JLab 3.1 feature
1161
+ if ( ( contextMenu as any ) . opened ) {
1162
+ ( contextMenu as any ) . opened . connect ( updateGitMenu ) ;
1163
+ } else {
1164
+ // matches only non-directory items
1165
+
1166
+ class GitMenu extends Menu {
1167
+ protected onBeforeAttach ( msg : Message ) : void {
1168
+ updateGitMenu ( contextMenu ) ;
1169
+ super . onBeforeAttach ( msg ) ;
1170
+ }
1155
1171
}
1156
- }
1157
1172
1158
- const gitMenu = new GitMenu ( { commands } ) ;
1159
- gitMenu . title . label = 'Git' ;
1160
- gitMenu . title . icon = gitIcon . bindprops ( { stylesheet : 'menuItem' } ) ;
1173
+ const selectorNotDir = '.jp-DirListing-item[data-isdir="false"]' ;
1174
+ gitMenu = new GitMenu ( { commands : contextMenu . menu . commands } ) ;
1175
+ gitMenu . title . label = 'Git' ;
1176
+ gitMenu . title . icon = gitIcon . bindprops ( { stylesheet : 'menuItem' } ) ;
1161
1177
1162
- contextMenu . addItem ( {
1163
- type : 'submenu' ,
1164
- submenu : gitMenu ,
1165
- selector : selectorNotDir ,
1166
- rank : 5
1167
- } ) ;
1178
+ contextMenu . addItem ( {
1179
+ type : 'submenu' ,
1180
+ submenu : gitMenu ,
1181
+ selector : selectorNotDir ,
1182
+ rank : 5
1183
+ } ) ;
1184
+ }
1168
1185
}
1169
1186
1170
1187
/* eslint-disable no-inner-declarations */
0 commit comments