menu
announcement

Spectrum is now read-only. Learn more about the decision in our official announcement.

Theia

Eclipse Theia - Cloud & Desktop IDE

Channels
Team

Menu contributions depending on the backend

May 31, 2020 at 9:46am

Menu contributions depending on the backend

May 31, 2020 at 9:46am
Hello there. I need to create menu elements based on the backend's directory content, so that after a quick directory scan backend could tell the frontend how many menu contributions should be there and what are they exactly. I guess some specific binding type might help, but I can't figure out how to achieve this just yet. Could you help me with this, please?

June 1, 2020 at 8:09am
You could create a JSON RPC service in the backend that provides the data which would then be used by the frontend in a MenuContribution.

June 1, 2020 at 7:41pm
thank you for the response. This is exactly what I'm trying to do. However, I face the following problem: the backend service returns a Promise, but it seems like in order to bind MenuContribution to my contribution (and to do so for an exact number of instances that backend tells me) I need to know the values, not their Promises. Not sure about the get around.
Here is a working example:
@injectable()
export class AsyncMenuContribution implements MenuContribution {
@inject(FileSystem)
private fileSystem: FileSystem;
@inject(CommandRegistry)
private commands: CommandRegistry;
async registerMenus(menus: MenuModelRegistry): Promise<void> {
const menuPath = ["navigator-context-menu", "dynamic-sub-menu"];
// get test directory
const fileStat = await this.fileSystem.getFileStat("file:/Users/vivienjovet/Desktop/test");
// register sub menu to show our dynamic menu actions
menus.registerSubmenu(menuPath, "Dynamic Sub Menu");
// register a menu action for each child directory
fileStat?.children
?.filter(stat => stat.isDirectory)
.forEach(dir => {
const uri = new URI(dir.uri);
// register a command for that directory
this.commands.registerCommand(
{
id: uri.displayName,
label: uri.displayName
},
{
execute: () => alert(uri.displayName)
}
);
// register a menu for the command
menus.registerMenuAction(menuPath, {
commandId: uri.displayName
});
});
}
}
like-fill
2
And in the frontend module: bind(MenuContribution).to(AsyncMenuContribution).inSingletonScope();
Since it's dynamic it only works for context menus (or anything that's not created only on startup)
Edited
Another limitation is that you have to create a command for each dynamic entry, it would have been better to use one command which accepts an argument from the menu action. Is there any way to achieve that ?
It would be also nice to be able to register menu actions without a corresponding command and just an execute function, I can see that being used for sub menus like "Open Recent".

June 3, 2020 at 4:48pm
thank you so much for an example with a detailed explanation, that helped me a lot!
like-fill
1