@@ -20,7 +20,7 @@ import { ArrayExt, toArray } from '@lumino/algorithm';
2020import { CommandRegistry } from '@lumino/commands' ;
2121import { PromiseDelegate } from '@lumino/coreutils' ;
2222import { Message } from '@lumino/messaging' ;
23- import { Menu , Panel } from '@lumino/widgets' ;
23+ import { ContextMenu , Menu , Panel } from '@lumino/widgets' ;
2424import * as React from 'react' ;
2525import { DiffModel } from './components/diff/model' ;
2626import { createPlainTextDiff } from './components/diff/PlainTextDiff' ;
@@ -1009,9 +1009,6 @@ export function createGitMenu(
10091009 return menu ;
10101010}
10111011
1012- // matches only non-directory items
1013- const selectorNotDir = '.jp-DirListing-item[data-isdir="false"]' ;
1014-
10151012export function addMenuItems (
10161013 commands : ContextCommandIDs [ ] ,
10171014 contextMenu : Menu ,
@@ -1043,12 +1040,11 @@ export function addMenuItems(
10431040}
10441041
10451042/**
1046- * Add Git context (sub)menu to the file browser context menu .
1043+ * Populate Git context submenu depending on the selected files .
10471044 */
10481045export function addFileBrowserContextMenu (
10491046 model : IGitExtension ,
10501047 tracker : WidgetTracker < FileBrowser > ,
1051- commands : CommandRegistry ,
10521048 contextMenu : ContextMenuSvg
10531049) : void {
10541050 function getSelectedBrowserItems ( ) : Contents . IModel [ ] {
@@ -1059,112 +1055,133 @@ export function addFileBrowserContextMenu(
10591055 return toArray ( widget . selectedItems ( ) ) ;
10601056 }
10611057
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' )
11181115 ) ;
11191116
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 ( ) ;
11241120 }
1121+ _commands = commandsList ;
1122+ _paths = paths ;
1123+ }
1124+ }
11251125
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+ }
11321134
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+ }
11351138
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 ) ;
11471150 }
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+ }
11521159
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+ }
11551171 }
1156- }
11571172
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' } ) ;
11611177
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+ }
11681185}
11691186
11701187/* eslint-disable no-inner-declarations */
0 commit comments