From 5948db5f763c53c511495643ec8e0f8c93b3bcbe Mon Sep 17 00:00:00 2001 From: wenytang-ms Date: Wed, 2 Sep 2026 11:52:15 +0800 Subject: [PATCH 1/3] fix: hide non-Java workspace roots when resources are hidden --- README.md | 2 +- package.nls.json | 2 +- package.nls.zh-cn.json | 2 +- package.nls.zh-tw.json | 1 + src/views/dependencyDataProvider.ts | 19 ++++++--- test/e2e-plans/java-dep-project-explorer.yaml | 39 ++++++++++++++++++- test/multiple-suite/projectView.test.ts | 39 ++++++++++++++++++- 7 files changed, 94 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6fc1881c..58de3e35 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ You can turn these reminders on or off at any time with the `java.dependency.ena | `java.dependency.packagePresentation` | Specify how to display the package. Supported values are: `flat`, `hierarchical`.| `flat` | | `java.dependency.enableDependencyCheckup` | Show reminders when your Java runtimes or dependencies need an upgrade. | `true` | | `java.project.exportJar.targetPath` | The output path of export jar. When this setting is **empty** , a file explorer will pop up to let the user select the output location.| `${workspaceFolder}/${workspaceFolderBasename}.jar` | -| `java.project.explorer.showNonJavaResources` | When enabled, the explorer shows non-Java resources. | `true` | +| `java.project.explorer.showNonJavaResources` | When enabled, the explorer shows non-Java resources. When disabled, workspace folders without Java projects are hidden. | `true` | ## Contribution diff --git a/package.nls.json b/package.nls.json index ba8bf485..2bfee6a2 100644 --- a/package.nls.json +++ b/package.nls.json @@ -48,7 +48,7 @@ "configuration.java.dependency.refreshDelay": "The delay time (ms) the auto refresh is invoked when changes are detected", "configuration.java.dependency.packagePresentation": "Package presentation mode: flat or hierarchical", "configuration.java.dependency.enableDependencyCheckup": "Show reminders when your Java runtimes or dependencies need an upgrade.", - "configuration.java.project.explorer.showNonJavaResources": "When enabled, the explorer shows non-Java resources.", + "configuration.java.project.explorer.showNonJavaResources": "When enabled, the explorer shows non-Java resources. When disabled, workspace folders without Java projects are hidden.", "configuration.java.project.exportJar.targetPath.customization": "The output path of the exported jar. Leave it empty if you want to manually pick the output location.", "configuration.java.project.exportJar.targetPath.workspaceFolder": "Export the jar file into the workspace folder. Its name is the same as the folder's.", "configuration.java.project.exportJar.targetPath.select": "Select output location manually when exporting the jar file.", diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index c7b0b8ab..29514fdf 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -44,7 +44,7 @@ "configuration.java.dependency.autoRefresh": "在 Java 项目管理器中自动同步修改", "configuration.java.dependency.refreshDelay": "控制 Java 项目管理器刷新的延迟时间 (毫秒)", "configuration.java.dependency.packagePresentation": "Java 包显示方式: 平行显示或者分层显示", - "configuration.java.project.explorer.showNonJavaResources": "启用时 Java 项目管理器将显示非 Java 资源。", + "configuration.java.project.explorer.showNonJavaResources": "启用时,Java 项目管理器将显示非 Java 资源;禁用时,将隐藏不包含 Java 项目的工作区文件夹。", "configuration.java.project.exportJar.targetPath.customization": "导出 Jar 文件的路径。您可以将此选项置为空串来手动选择 jar 文件的导出路径。", "configuration.java.project.exportJar.targetPath.workspaceFolder": "导出 Jar 文件到工作空间文件夹下。Jar 文件的名称和工作空间文件夹的名称相同。", "configuration.java.project.exportJar.targetPath.select": "在导出 Jar 文件时手动选择输出目录。", diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json index cfa7462d..496e486b 100644 --- a/package.nls.zh-tw.json +++ b/package.nls.zh-tw.json @@ -37,6 +37,7 @@ "configuration.java.dependency.autoRefresh": "在 Java 專案管理員中自動同步修改", "configuration.java.dependency.refreshDelay": "控制 Java 專案管理員重新整理的延遲時間 (毫秒)", "configuration.java.dependency.packagePresentation": "Java 套件顯示方式: 平行顯示或者分層顯示", + "configuration.java.project.explorer.showNonJavaResources": "啟用時,Java 專案管理員會顯示非 Java 資源;停用時,將隱藏不包含 Java 專案的工作區資料夾。", "configuration.java.project.exportJar.targetPath.customization": "匯出 Jar 檔案的路徑。如果您想要手動選擇輸出路徑,可以不填。", "configuration.java.project.exportJar.targetPath.workspaceFolder": "匯出 Jar 檔案到工作區資料夾下。Jar 檔案的名稱和工作區資料夾的名稱相同。", "configuration.java.project.exportJar.targetPath.select": "在匯出 Jar 檔案時手動選擇輸出位置。", diff --git a/src/views/dependencyDataProvider.ts b/src/views/dependencyDataProvider.ts index a8b192d6..22e50cfd 100644 --- a/src/views/dependencyDataProvider.ts +++ b/src/views/dependencyDataProvider.ts @@ -294,11 +294,20 @@ export class DependencyDataProvider implements TreeDataProvider { const folders = workspace.workspaceFolders; if (folders && folders.length) { if (folders.length > 1) { - folders.forEach((folder) => rootItems.push(new WorkspaceNode({ - name: folder.name, - uri: folder.uri.toString(), - kind: NodeKind.Workspace, - }, undefined))); + const javaProjectsByFolder = Settings.nonJavaResourcesFiltered() + ? await Promise.all(folders.map((folder) => Jdtls.getProjects(folder.uri.toString()))) + : undefined; + folders.forEach((folder, index) => { + // Java-only mode should not leave empty non-Java workspace roots in the tree. + if (javaProjectsByFolder && javaProjectsByFolder[index].length === 0) { + return; + } + rootItems.push(new WorkspaceNode({ + name: folder.name, + uri: folder.uri.toString(), + kind: NodeKind.Workspace, + }, undefined)); + }); this._rootItems = rootItems; } else { const result: INodeData[] = await Jdtls.getProjects(folders[0].uri.toString()); diff --git a/test/e2e-plans/java-dep-project-explorer.yaml b/test/e2e-plans/java-dep-project-explorer.yaml index 73854cf6..3223b2e3 100644 --- a/test/e2e-plans/java-dep-project-explorer.yaml +++ b/test/e2e-plans/java-dep-project-explorer.yaml @@ -5,6 +5,7 @@ # - linkWithFolderExplorer reveals active file in tree # - unlinkWithFolderExplorer stops auto-reveal # - revealInProjectExplorer reveals file from File Explorer context menu +# - hideNonJavaResources removes workspace roots without Java projects # # Usage: # npx autotest run test/e2e-plans/java-dep-project-explorer.yaml --vsix @@ -12,7 +13,7 @@ name: "Java Dependency — Project Explorer" description: | Tests the Java Projects explorer view: focus, link/unlink with editor, - reveal in project explorer. + reveal in project explorer, and filtering non-Java workspace roots. setup: extension: "redhat.java" @@ -188,6 +189,42 @@ steps: name: "non-java" timeout: 15 + # Hide Non-Java Resources now applies to the workspace-root level as well: + # roots without any Java project disappear, while Java workspace roots remain. + - id: "hide-non-java-workspace-root" + action: 'clickViewTitleAction "Java Projects" "Hide Non-Java Resources"' + + - id: "wait-hide-non-java-workspace-root" + action: "wait 5 seconds" + + - id: "verify-non-java-workspace-root-hidden" + action: "wait 1 seconds" + verifyTreeItem: + name: "non-java" + visible: false + inView: "Java Projects" + timeout: 30 + + - id: "verify-java-workspace-root-remains" + action: "wait 1 seconds" + verifyTreeItem: + name: "maven" + inView: "Java Projects" + timeout: 15 + + - id: "restore-non-java-workspace-root" + action: 'clickViewTitleAction "Java Projects" "Show Non-Java Resources"' + + - id: "wait-restore-non-java-workspace-root" + action: "wait 5 seconds" + + - id: "verify-non-java-workspace-root-restored" + action: "wait 1 seconds" + verifyTreeItem: + name: "non-java" + inView: "Java Projects" + timeout: 30 + # Add a Java folder after the mixed multi-root structure already exists and # refresh it into the expected WorkspaceNode -> ProjectNode hierarchy. - id: "invoke-add-java-root" diff --git a/test/multiple-suite/projectView.test.ts b/test/multiple-suite/projectView.test.ts index 2e10c3db..3d31d685 100644 --- a/test/multiple-suite/projectView.test.ts +++ b/test/multiple-suite/projectView.test.ts @@ -4,7 +4,7 @@ import * as assert from "assert"; import * as vscode from "vscode"; import { - Commands, contextManager, DependencyExplorer, ProjectNode, WorkspaceNode, + Commands, contextManager, DependencyExplorer, Jdtls, ProjectNode, WorkspaceNode, } from "../../extension.bundle"; import { setupTestEnv } from "../shared"; @@ -44,6 +44,43 @@ suite("Multiple Project View Tests", () => { assert.ok(updatedRoots?.every(root => root instanceof WorkspaceNode), "All roots should remain workspace nodes"); }); + test("Hides workspace folders without Java projects when non-Java resources are hidden", async function() { + const configuration = vscode.workspace.getConfiguration("java.project.explorer"); + const originalWorkspaceValue = configuration.inspect("showNonJavaResources")?.workspaceValue; + + await configuration.update("showNonJavaResources", false, vscode.ConfigurationTarget.Workspace); + try { + await vscode.commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH); + + const folders = vscode.workspace.workspaceFolders || []; + const expectedNames: string[] = []; + for (const folder of folders) { + if ((await Jdtls.getProjects(folder.uri.toString())).length > 0) { + expectedNames.push(folder.name); + } + } + + assert.ok(expectedNames.includes("maven"), "The Maven workspace folder should contain a Java project"); + assert.ok(!expectedNames.includes("non-java"), "The non-Java fixture should not contain a Java project"); + + const explorer = DependencyExplorer.getInstance(contextManager.context); + const roots = await explorer.dataProvider.getChildren(); + assert.deepStrictEqual( + roots?.map(root => root.getDisplayName()), + expectedNames, + "Only workspace folders containing Java projects should be shown", + ); + assert.ok(roots?.every(root => root instanceof WorkspaceNode), "All roots should remain workspace nodes"); + } finally { + await configuration.update( + "showNonJavaResources", + originalWorkspaceValue, + vscode.ConfigurationTarget.Workspace, + ); + await vscode.commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH); + } + }); + test("Does not add project roots while cached multi-root roots are stale", async function() { const explorer = DependencyExplorer.getInstance(contextManager.context); const roots = await explorer.dataProvider.getChildren(); From c20bb0b025c66bc9216b186435024702735c92d2 Mon Sep 17 00:00:00 2001 From: wenytang-ms Date: Wed, 2 Sep 2026 12:46:34 +0800 Subject: [PATCH 2/3] test: expand non-Java workspace root UI coverage --- test/e2e-plans/java-dep-project-explorer.yaml | 77 +++++++++++++++---- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/test/e2e-plans/java-dep-project-explorer.yaml b/test/e2e-plans/java-dep-project-explorer.yaml index 3223b2e3..c5cc7ef3 100644 --- a/test/e2e-plans/java-dep-project-explorer.yaml +++ b/test/e2e-plans/java-dep-project-explorer.yaml @@ -5,7 +5,8 @@ # - linkWithFolderExplorer reveals active file in tree # - unlinkWithFolderExplorer stops auto-reveal # - revealInProjectExplorer reveals file from File Explorer context menu -# - hideNonJavaResources removes workspace roots without Java projects +# - hideNonJavaResources removes non-Java workspace roots while preserving +# Java roots across refreshes and newly imported projects # # Usage: # npx autotest run test/e2e-plans/java-dep-project-explorer.yaml --vsix @@ -13,7 +14,8 @@ name: "Java Dependency — Project Explorer" description: | Tests the Java Projects explorer view: focus, link/unlink with editor, - reveal in project explorer, and filtering non-Java workspace roots. + reveal in project explorer, and filtering non-Java workspace roots without + hiding Java roots during refresh or project import. setup: extension: "redhat.java" @@ -154,7 +156,7 @@ steps: exact: true timeout: 15 - # ── Test 5: mixed multi-root project attribution (#1060) ── + # ── Test 5: mixed multi-root filtering and project attribution (#758, #1060) ── # First establish a mixed workspace and refresh it into WorkspaceNode roots. # The smoke-test driver renders folder pickers as an internal quick input: # entering an absolute folder path opens it, then the Add button confirms it. @@ -187,6 +189,10 @@ steps: action: "wait 1 seconds" verifyTreeItem: name: "non-java" + exact: true + count: 1 + level: 1 + inView: "Java Projects" timeout: 15 # Hide Non-Java Resources now applies to the workspace-root level as well: @@ -194,14 +200,13 @@ steps: - id: "hide-non-java-workspace-root" action: 'clickViewTitleAction "Java Projects" "Hide Non-Java Resources"' - - id: "wait-hide-non-java-workspace-root" - action: "wait 5 seconds" - - id: "verify-non-java-workspace-root-hidden" action: "wait 1 seconds" verifyTreeItem: name: "non-java" - visible: false + exact: true + count: 0 + level: 1 inView: "Java Projects" timeout: 30 @@ -209,24 +214,43 @@ steps: action: "wait 1 seconds" verifyTreeItem: name: "maven" + exact: true + count: 1 + level: 1 inView: "Java Projects" timeout: 15 - - id: "restore-non-java-workspace-root" - action: 'clickViewTitleAction "Java Projects" "Show Non-Java Resources"' + - id: "expand-java-workspace-root" + action: "expandTreeItem maven" - - id: "wait-restore-non-java-workspace-root" - action: "wait 5 seconds" + - id: "verify-nested-java-project-remains" + action: "wait 1 seconds" + verifyTreeItem: + name: "my-app" + exact: true + count: 1 + level: 2 + inView: "Java Projects" + timeout: 15 - - id: "verify-non-java-workspace-root-restored" + # Rebuilding the roots must preserve the Java-only view rather than + # reintroducing the filtered workspace folder. + - id: "refresh-hidden-workspace-roots" + action: "executeVSCodeCommand java.view.package.refresh" + + - id: "verify-non-java-root-stays-hidden-after-refresh" action: "wait 1 seconds" verifyTreeItem: name: "non-java" + exact: true + count: 0 + level: 1 inView: "Java Projects" timeout: 30 - # Add a Java folder after the mixed multi-root structure already exists and - # refresh it into the expected WorkspaceNode -> ProjectNode hierarchy. + # Add a Java folder while non-Java roots are hidden. A newly imported Java + # workspace root must still appear, while the existing non-Java root remains + # filtered. - id: "invoke-add-java-root" action: "executeVSCodeCommand workbench.action.addRootFolder" @@ -251,8 +275,19 @@ steps: exact: true count: 1 level: 1 + inView: "Java Projects" timeout: 15 + - id: "verify-non-java-root-stays-hidden-after-java-import" + action: "wait 1 seconds" + verifyTreeItem: + name: "non-java" + exact: true + count: 0 + level: 1 + inView: "Java Projects" + timeout: 30 + # Deterministically simulate the onDidProjectsImport path. Before #1060 this # command appended a second top-level ProjectNode named "simple" beside the # existing WorkspaceNode. The fixed provider ignores progressive insertion @@ -264,4 +299,18 @@ steps: exact: true count: 1 level: 1 + inView: "Java Projects" timeout: 15 + + - id: "restore-non-java-workspace-root" + action: 'clickViewTitleAction "Java Projects" "Show Non-Java Resources"' + + - id: "verify-non-java-workspace-root-restored" + action: "wait 1 seconds" + verifyTreeItem: + name: "non-java" + exact: true + count: 1 + level: 1 + inView: "Java Projects" + timeout: 30 From af4f5c3afeb1d7e905a588d79569a47775b04b11 Mon Sep 17 00:00:00 2001 From: wenytang-ms Date: Wed, 2 Sep 2026 14:26:40 +0800 Subject: [PATCH 3/3] test: use standard tree absence assertions --- test/e2e-plans/java-dep-project-explorer.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e-plans/java-dep-project-explorer.yaml b/test/e2e-plans/java-dep-project-explorer.yaml index c5cc7ef3..45ace756 100644 --- a/test/e2e-plans/java-dep-project-explorer.yaml +++ b/test/e2e-plans/java-dep-project-explorer.yaml @@ -205,7 +205,7 @@ steps: verifyTreeItem: name: "non-java" exact: true - count: 0 + visible: false level: 1 inView: "Java Projects" timeout: 30 @@ -243,7 +243,7 @@ steps: verifyTreeItem: name: "non-java" exact: true - count: 0 + visible: false level: 1 inView: "Java Projects" timeout: 30 @@ -283,7 +283,7 @@ steps: verifyTreeItem: name: "non-java" exact: true - count: 0 + visible: false level: 1 inView: "Java Projects" timeout: 30