Skip to content

Commit

Permalink
navigator: handle empty multi-root workspace
Browse files Browse the repository at this point in the history
When a multi-root workspace is opened, the navigator will try to draw
the file tree because `model.root` is a `WorkspaceRootNode` with no
children.

This commit handles this case by adding a bit of ui to help the user add
folders to his workspace, instead of displaying a blank view.

Signed-off-by: Paul Maréchal <paul.marechal@ericsson.com>
  • Loading branch information
paul-marechal committed Oct 14, 2020
1 parent d262753 commit 3098982
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
11 changes: 11 additions & 0 deletions packages/navigator/src/browser/navigator-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,24 @@ export class FileNavigatorTree extends FileTree {
}
}

/**
* File tree root node for multi-root workspaces.
*/
export interface WorkspaceNode extends CompositeTreeNode, SelectableTreeNode {
children: WorkspaceRootNode[];
}
export namespace WorkspaceNode {

export const id = 'WorkspaceNodeId';
export const name = 'WorkspaceNode';

export function is(node: TreeNode | undefined): node is WorkspaceNode {
return CompositeTreeNode.is(node) && node.id === WorkspaceNode.id;
}

/**
* Create a `WorkspaceNode` that can be used as a `Tree` root.
*/
export function createRoot(multiRootName?: string): WorkspaceNode {
return {
id: WorkspaceNode.id,
Expand All @@ -82,10 +89,14 @@ export namespace WorkspaceNode {
}
}

/**
* A node representing a folder from a multi-root workspace.
*/
export interface WorkspaceRootNode extends DirNode {
parent: WorkspaceNode;
}
export namespace WorkspaceRootNode {

export function is(node: Object | undefined): node is WorkspaceRootNode {
return DirNode.is(node) && WorkspaceNode.is(node.parent);
}
Expand Down
36 changes: 34 additions & 2 deletions packages/navigator/src/browser/navigator-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ export class FileNavigatorWidget extends FileTreeWidget {
}

protected renderTree(model: TreeModel): React.ReactNode {
return super.renderTree(model) || this.renderOpenWorkspaceDiv();
return this.model.root === undefined
? this.renderOpenWorkspaceDiv()
: this.isEmptyMultiRootWorkspace(model)
? this.renderEmptyMultiRootWorkspace()
: super.renderTree(model);
}

protected onAfterAttach(msg: Message): void {
Expand Down Expand Up @@ -181,11 +185,17 @@ export class FileNavigatorWidget extends FileTreeWidget {
this.commandService.executeCommand(WorkspaceCommands.OPEN_FOLDER.id);
}

protected readonly addFolder = () => this.doAddFolder();
protected doAddFolder(): void {
this.commandService.executeCommand(WorkspaceCommands.ADD_FOLDER.id);
}

protected readonly keyUpHandler = (e: React.KeyboardEvent) => {
if (Key.ENTER.keyCode === e.keyCode) {
(e.target as HTMLElement).click();
}
};

/**
* Instead of rendering the file resources from the workspace, we render a placeholder
* button when the workspace root is not yet set.
Expand All @@ -199,7 +209,8 @@ export class FileNavigatorWidget extends FileTreeWidget {
Open Workspace
</button>;
} else {
openButton = <button className='theia-button open-workspace-button' title='Select a folder as your workspace root' onClick={this.openFolder}
openButton = <button className='theia-button open-workspace-button' title='Select a folder as your workspace root'
onClick={this.openFolder}
onKeyUp={this.keyUpHandler}>
Open Folder
</button>;
Expand All @@ -213,6 +224,27 @@ export class FileNavigatorWidget extends FileTreeWidget {
</div>;
}

/**
* When a multi-root workspace is opened, a user can remove all the folders from it.
* Instead of displaying an empty navigator tree, this will show a button to add more folders.
*/
protected renderEmptyMultiRootWorkspace(): React.ReactNode {
return <div className='theia-navigator-container'>
<div className='center'>You have not yet added a folder to the workspace.</div>
<div className='open-workspace-button-container'>
<button className='theia-button open-workspace-button' title='Add a folder to your workspace'
onClick={this.addFolder}
onKeyUp={this.keyUpHandler}>
Add Folder
</button>
</div>
</div>;
}

protected isEmptyMultiRootWorkspace(model: TreeModel): boolean {
return WorkspaceNode.is(model.root) && model.root.children.length === 0;
}

protected handleClickEvent(node: TreeNode | undefined, event: React.MouseEvent<HTMLElement>): void {
const modifierKeyCombined: boolean = isOSX ? (event.shiftKey || event.metaKey) : (event.shiftKey || event.ctrlKey);
if (!modifierKeyCombined && node && this.corePreferences['workbench.list.openMode'] === 'singleClick') {
Expand Down

0 comments on commit 3098982

Please sign in to comment.