Skip to content

Commit 4cb3a29

Browse files
authored
fix: Project Settings UI update the absolute path (#1623)
* fix: Project Settings UI update the absolute path * test: add test case * fix: update code to comments * test: adjust test case
1 parent 8de1414 commit 4cb3a29

5 files changed

Lines changed: 106 additions & 22 deletions

File tree

src/project-settings/assets/classpath/features/components/Libraries.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,21 @@ import { removeReferencedLibrary, addLibraries } from "../classpathConfiguration
1111
import { ClasspathRequest } from "../../../vscode/utils";
1212

1313
import { ClasspathEntry, ClasspathEntryKind } from "../../../../types";
14+
import { isProjectType } from "../../../../../utils/webview";
1415

1516
const Libraries = (): JSX.Element => {
1617

1718
const [hoveredRow, setHoveredRow] = useState<string | null>(null);
19+
const addLibraryBtnRef = useRef<HTMLElement>(null);
1820
const activeProjectIndex: number = useSelector((state: any) => state.commonConfig.ui.activeProjectIndex);
1921
const activeProjectIndexRef = useRef(activeProjectIndex);
2022
useEffect(() => {
2123
activeProjectIndexRef.current = activeProjectIndex;
2224
}, [activeProjectIndex]);
2325

2426
const libraries: ClasspathEntry[] = useSelector((state: any) => state.classpathConfig.data.libraries[activeProjectIndex]);
27+
const projectType: unknown = useSelector((state: any) => state.commonConfig.data.projectType[activeProjectIndex]);
28+
const canAddLibrary = isProjectType(projectType);
2529
const dispatch: Dispatch<any> = useDispatch();
2630

2731
const handleRemove = (index: number) => {
@@ -32,9 +36,22 @@ const Libraries = (): JSX.Element => {
3236
};
3337

3438
const handleAdd = () => {
35-
ClasspathRequest.onWillSelectLibraries();
39+
if (!canAddLibrary) {
40+
return;
41+
}
42+
ClasspathRequest.onWillSelectLibraries(projectType);
3643
};
3744

45+
useEffect(() => {
46+
const el = addLibraryBtnRef.current;
47+
if (!el) return;
48+
if (canAddLibrary) {
49+
el.removeAttribute("disabled");
50+
} else {
51+
el.setAttribute("disabled", "");
52+
}
53+
}, [canAddLibrary]);
54+
3855
const onDidAddLibraries = (event: OnDidAddLibrariesEvent) => {
3956
const {data} = event;
4057
if (data.command === "classpath.onDidAddLibraries") {
@@ -110,7 +127,7 @@ const Libraries = (): JSX.Element => {
110127
<div className="setting-section">
111128
<div>
112129
<div id="list-actions" className="flex-center setting-list-actions">
113-
<vscode-button class="ghost-button" onClick={() => handleAdd()}>
130+
<vscode-button ref={addLibraryBtnRef} class="ghost-button" onClick={() => handleAdd()}>
114131
<span className="codicon codicon-add mr-1"></span>
115132
Add Library...
116133
</vscode-button>

src/project-settings/assets/vscode/utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ export namespace ClasspathRequest {
8181
});
8282
}
8383

84-
export function onWillSelectLibraries() {
84+
export function onWillSelectLibraries(projectType: ProjectType) {
8585
vscode.postMessage({
86-
command: "classpath.onWillSelectLibraries"
86+
command: "classpath.onWillSelectLibraries",
87+
projectType,
8788
});
8889
}
8990

src/project-settings/handlers/ClasspathRequestHandler.ts

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ClasspathComponent, VmInstall, ClasspathEntry, ClasspathEntryKind } fro
88
import _ from "lodash";
99
import { instrumentOperation, sendError, sendInfo, setUserError } from "vscode-extension-telemetry-wrapper";
1010
import { getProjectType } from "../../utils/jdt";
11-
import { ProjectType } from "../../utils/webview";
11+
import { ProjectType, isProjectType } from "../../utils/webview";
1212

1313
export class ClasspathRequestHandler implements vscode.Disposable {
1414
private webview: vscode.Webview;
@@ -58,7 +58,7 @@ export class ClasspathRequestHandler implements vscode.Disposable {
5858
await this.addNewJdk(this.currentProjectRoot);
5959
break;
6060
case "classpath.onWillSelectLibraries":
61-
await this.selectLibraries(this.currentProjectRoot);
61+
await this.selectLibraries(this.currentProjectRoot, message.projectType);
6262
break;
6363
case "classpath.onClickGotoProjectConfiguration":
6464
this.gotoProjectConfigurationFile(message.rootUri, message.projectType);
@@ -197,7 +197,7 @@ export class ClasspathRequestHandler implements vscode.Disposable {
197197
path: `org.eclipse.jdt.launching.JRE_CONTAINER/${vmInstallPath}`,
198198
});
199199
}
200-
classpathEntries.push(...libraries);
200+
classpathEntries.push(...libraries.map(library => this.toClasspathEntryForUpdate(library, currentProjectRoot)));
201201
if (classpathEntries.length > 0) {
202202
await vscode.commands.executeCommand(
203203
"java.execute.workspaceCommand",
@@ -362,7 +362,7 @@ export class ClasspathRequestHandler implements vscode.Disposable {
362362
}
363363
});
364364

365-
private selectLibraries = instrumentOperation("projectSettings.classpath.selectLibraries", async (_operationId: string, currentProjectRoot: vscode.Uri) => {
365+
private selectLibraries = instrumentOperation("projectSettings.classpath.selectLibraries", async (_operationId: string, currentProjectRoot: vscode.Uri, projectType: unknown) => {
366366
const jarFiles: vscode.Uri[] | undefined = await vscode.window.showOpenDialog({
367367
defaultUri: vscode.workspace.workspaceFolders?.[0].uri,
368368
openLabel: "Select Jar File",
@@ -374,24 +374,42 @@ export class ClasspathRequestHandler implements vscode.Disposable {
374374
},
375375
});
376376
if (jarFiles) {
377-
const jarPaths: string[] = jarFiles.map(uri => {
378-
if (uri.fsPath.startsWith(currentProjectRoot.fsPath)) {
379-
return path.relative(currentProjectRoot.fsPath, uri.fsPath);
380-
}
381-
return uri.fsPath;
382-
});
383377
this.webview.postMessage({
384378
command: "classpath.onDidAddLibraries",
385-
jars: jarPaths.map(jarPath => {
379+
jars: jarFiles.map(uri => {
386380
return {
387381
kind: ClasspathEntryKind.Library,
388-
path: jarPath,
382+
path: this.toLibraryPathForProject(uri, currentProjectRoot, projectType),
389383
};
390384
}),
391385
});
392386
}
393387
});
394388

389+
private toLibraryPathForProject(uri: vscode.Uri, currentProjectRoot: vscode.Uri, projectType: unknown): string {
390+
if (isProjectType(projectType) && projectType !== ProjectType.UnmanagedFolder) {
391+
return uri.fsPath;
392+
}
393+
394+
const relativePath = path.relative(currentProjectRoot.fsPath, uri.fsPath);
395+
if (relativePath && relativePath !== ".." && !relativePath.startsWith(".." + path.sep) && !path.isAbsolute(relativePath)) {
396+
return relativePath;
397+
}
398+
399+
return uri.fsPath;
400+
}
401+
402+
private toClasspathEntryForUpdate(entry: ClasspathEntry, currentProjectRoot: vscode.Uri): ClasspathEntry {
403+
if (entry.kind === ClasspathEntryKind.Library && !path.isAbsolute(entry.path)) {
404+
return {
405+
...entry,
406+
path: path.join(currentProjectRoot.fsPath, entry.path),
407+
};
408+
}
409+
410+
return entry;
411+
}
412+
395413
private updateUnmanagedFolderLibraries = instrumentOperation("projectSettings.classpath.updateUnmanagedFolderLibraries", async (_operationId: string, jarFilePaths: string[]) => {
396414
const setting = this.getReferencedLibrariesSetting();
397415
setting.include = jarFilePaths;

src/utils/webview.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ export enum ProjectType {
5454
Others = "Others",
5555
}
5656

57+
export function isProjectType(projectType: unknown): projectType is ProjectType {
58+
return projectType === ProjectType.Default ||
59+
projectType === ProjectType.UnmanagedFolder ||
60+
projectType === ProjectType.Maven ||
61+
projectType === ProjectType.Gradle ||
62+
projectType === ProjectType.Others;
63+
}
64+
5765
export enum NatureId {
5866
Maven = "org.eclipse.m2e.core.maven2Nature",
5967
Gradle = "org.eclipse.buildship.core.gradleprojectnature",

test-plans/java-extension-pack.yaml

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
# Test Plan: Java Extension Pack — Classpath Configuration (from vscode-java-pack.wiki)
22
#
33
# Source: wiki Test-Plan.md "Java Extension Pack" scenario
4-
# Verify: Trigger Java: Configure Classpath command → configuration page appears
5-
#
6-
# Note: Classpath configuration uses a webview; the current framework has limited support
7-
# for webview internal interactions — only verifies the command can be triggered and the page appears.
4+
# Verify: Trigger Java: Configure Classpath command → configuration page appears;
5+
# add a project-local JAR to a non-unmanaged project and apply it.
86
#
97
# Prerequisites:
108
# - vscode-java repo is cloned locally
@@ -15,14 +13,15 @@
1513
name: "Java Extension Pack — Classpath Configuration"
1614
description: |
1715
Corresponds to the Java Extension Pack scenario in the wiki Test Plan:
18-
Trigger the Java: Configure Classpath command and verify the configuration page appears.
16+
Trigger the Java: Configure Classpath command, verify the configuration page
17+
appears, and cover the non-unmanaged-project Add Library flow.
1918
2019
setup:
2120
extension: "redhat.java"
2221
extensions:
2322
- "vscjava.vscode-java-pack"
2423
vscodeVersion: "stable"
25-
workspace: "../../vscode-java/test/resources/projects/maven/salut"
24+
workspace: "../../vscode-java/test/resources/projects/eclipse/simple-app"
2625
timeout: 90
2726

2827
steps:
@@ -35,6 +34,14 @@ steps:
3534
skipLlmVerify: true
3635
timeout: 120
3736

37+
- id: "create-project-local-jar"
38+
action: "insertLineInFile lib/autotest-lib.jar 1 autotest placeholder jar"
39+
verify: "A project-local JAR placeholder exists for the mocked Add Library file picker"
40+
verifyFile:
41+
path: "~/lib/autotest-lib.jar"
42+
exists: true
43+
skipLlmVerify: true
44+
3845
# ── Trigger Classpath configuration command ──────────────
3946
# wiki: "Trigger the command 'Java: Configure Classpath'"
4047
# The classpath webview lazy-loads. Use a lenient verify on the command
@@ -47,3 +54,36 @@ steps:
4754
- id: "verify-page"
4855
action: "wait 5 seconds"
4956
verify: "Project Settings webview displays the Classpath Configuration UI (sections such as JDK, libraries, sources)"
57+
verifyWebview:
58+
contains:
59+
- "Classpath"
60+
- "Libraries"
61+
62+
- id: "open-libraries-tab"
63+
action: "clickInWebview text=Libraries"
64+
verify: "The Libraries tab is selected and shows library management actions"
65+
verifyWebview:
66+
contains: "Add Library..."
67+
68+
- id: "add-project-local-library"
69+
action: "clickInWebview text=Add Library..."
70+
verify: "The file picker opens for selecting a JAR"
71+
72+
- id: "select-project-local-library"
73+
action: "fillQuickInput ${workspaceFolder}/lib/autotest-lib.jar"
74+
verify: "The project-local JAR is selected and added to the Libraries list"
75+
verifyWebview:
76+
contains: "autotest-lib.jar"
77+
78+
- id: "apply-library-change"
79+
action: "clickInWebview text=Apply Settings"
80+
verify: "Apply Settings is clicked; the persisted .classpath update is verified by the next deterministic file assertion"
81+
skipLlmVerify: true
82+
83+
- id: "verify-library-applied"
84+
action: "wait 5 seconds"
85+
verify: "The Eclipse .classpath contains the added library entry, proving the Project Settings UI sent a valid absolute library path to JDT LS instead of failing with a relative-path classpath error"
86+
verifyFile:
87+
path: "~/.classpath"
88+
contains: "autotest-lib.jar"
89+
skipLlmVerify: true

0 commit comments

Comments
 (0)