IEP-1701 Improve UI/UX of esp-idf manager view#1400
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughReplaced singleton-based creation of ESPIDFMainTablePage with direct construction; ESPIDFMainTablePage was refactored into a constructor + createPage lifecycle, converting the UI to a multi-column TableViewer with an IdfRow model, async data loading, persistent sort state, and updated editor call sites and messages. Changes
Sequence Diagram(s)sequenceDiagram
participant Editor as ESPIDFManagerEditor
participant Page as ESPIDFMainTablePage
participant EIM as EimJson (data/watch)
participant Job as SetupToolsInIdeJob
participant Listener as SetupToolsJobListener
Editor->>Page: new ESPIDFMainTablePage(eimJson)
Editor->>Page: createPage(parent)
Page->>Page: build TableViewer, columns, actions
Page->>EIM: request rows (async CompletableFuture)
EIM-->>Page: return eim data / installed list (async)
Page->>Page: map to IdfRow, update TableViewer (UI thread)
Page->>Job: schedule setup job for selected row
Job->>Listener: register listener
Job-->>Listener: progress/completion events
Listener->>Page: trigger refreshEditorUI()
Page->>Editor: update editor state / buttons / focus
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java (4)
224-250:Display.getDefault()called repeatedly inside label provider methods.
getForeground()callsDisplay.getDefault().getSystemColor(...)up to two times per cell render. While not a correctness bug, it's more idiomatic and slightly more efficient to obtain the display from the viewer's control once.Sketch
`@Override` public Color getForeground(Object element) { var row = (IdfRow) element; + var display = Display.getCurrent(); if (row.original().equals(currentInstallingNode)) - return Display.getDefault().getSystemColor(SWT.COLOR_DARK_YELLOW); - return row.isActive() ? Display.getDefault().getSystemColor(SWT.COLOR_DARK_GREEN) - : Display.getDefault().getSystemColor(SWT.COLOR_GRAY); + return display.getSystemColor(SWT.COLOR_DARK_YELLOW); + return row.isActive() ? display.getSystemColor(SWT.COLOR_DARK_GREEN) + : display.getSystemColor(SWT.COLOR_GRAY); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` around lines 224 - 250, The label provider is repeatedly calling Display.getDefault() in getForeground; instead capture the Display once from the viewer (e.g. final Display display = viewer.getControl().getDisplay()) before calling createCol and use display.getSystemColor(...) inside the anonymous ColumnLabelProvider methods; update the references in getForeground (and anywhere else in this provider) to use that cached display and avoid repeated Display.getDefault() calls, keeping the rest of the logic (IdfRow, currentInstallingNode, isActive) unchanged.
341-356: Dead code:else if (first instanceof IdfInstalled)branch is unreachable.The table input is always
List<IdfRow>(set at line 406), soselection.getFirstElement()will always be anIdfRow, never a rawIdfInstalled. This branch adds confusion with no benefit.Proposed fix
private IdfInstalled getSelectedIdf() { var selection = (IStructuredSelection) tableViewer.getSelection(); if (selection.isEmpty()) return null; Object first = selection.getFirstElement(); if (first instanceof IdfRow firstRow) { return firstRow.original(); } - else if (first instanceof IdfInstalled rawInstalled) - { - return rawInstalled; - } return null; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` around lines 341 - 356, The getSelectedIdf method contains an unreachable else-if branch checking "first instanceof IdfInstalled"; since the table input is always List<IdfRow>, remove the unreachable branch and simplify the method to only handle IdfRow cases: cast/unwrap the first selection to IdfRow (using IdfRow firstRow) and return firstRow.original(), keeping the existing empty-selection/null handling and preserving use of tableViewer and IStructuredSelection.
85-101: UnusedLocalResourceManager— created but never stored or used.Line 87 creates a
LocalResourceManagerwhose reference is immediately discarded. If no managed resources (images, colors, fonts) are allocated through it, the allocation is pointless. If managed resources are planned, store the reference in a field so it can be used.Proposed fix: remove unused allocation
public Composite createPage(Composite parent) { - new LocalResourceManager(JFaceResources.getResources(), parent); - container = new Composite(parent, SWT.NONE);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` around lines 85 - 101, The LocalResourceManager instance created in createPage (new LocalResourceManager(JFaceResources.getResources(), parent)) is never stored or used; either remove that unused allocation or assign it to a field (e.g., a private LocalResourceManager resourceManager) and use it for any managed resources and dispose it in the page's lifecycle (e.g., on dispose) to avoid leaks; update createPage to set resourceManager = new LocalResourceManager(...) and ensure disposeResourceManager is called when the page/container is disposed.
374-391: UncheckedRuntimeExceptionwrapping loses the original exception's context in logs.Line 390 wraps the caught exception in a
RuntimeException, and theexceptionallyhandler at line 410 logs onlyex.getCause().toString(). The stack trace is lost. Consider logging withLogger.log(Logger.ERROR, ...)or similar that preserves the stack, or at minimum logex.getCause()with its stack trace.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` around lines 374 - 391, The supplyAsync block in ESPIDFMainTablePage catches exceptions and throws new RuntimeException(e), which loses stacktrace clarity and pairs poorly with the existing exceptionally handler that logs ex.getCause().toString(); replace the throw with a CompletionException(e) (or simply let the exception propagate) so CompletableFuture preserves the original cause, and update the exceptionally handler that currently logs ex.getCause().toString() to log the full throwable (e.g., Logger.log(Logger.ERROR, "Failed to load IDF rows", ex.getCause()) or logger.error("...", ex.getCause())) so the stacktrace is preserved; look for CompletableFuture.supplyAsync(...) and the matching exceptionally(...) block to apply these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 130-198: Replace all hardcoded user-visible strings in
createMainContent and associated UI code with entries from the Messages resource
bundle: change group.setText("Installed IDF Versions") to
group.setText(Messages.EspIdfManagerInstalledVersions), change the
createActionButton label/tooltips ("Activate", "Set this version as the active
ESP-IDF", "Update Environment", the long tooltip) to Messages keys (e.g.,
Messages.EspIdfManagerActivate, Messages.EspIdfManagerActivateTooltip,
Messages.EspIdfManagerUpdateEnvironment,
Messages.EspIdfManagerUpdateEnvironmentTooltip), and replace the
column/header/status strings ("Status", "Setting up...", "\u2713 Active") used
in createColumns or wherever status text is emitted with
Messages.EspIdfManagerStatus, Messages.EspIdfManagerSettingUp,
Messages.EspIdfManagerActive (or similar keys). Add the corresponding keys to
the Messages properties and Java Messages accessor class following the existing
pattern used for Messages.EspIdfManagerVersionCol so that all UI text is
externalized for i18n.
---
Duplicate comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 469-483: The comparator in compare(Viewer, Object, Object) casts
to IdfRow and calls compareToIgnoreCase on r1.version()/name()/path(), which can
NPE if those fields are null; modify the switch in compare to perform null-safe
comparisons (e.g., normalize to empty string or use explicit null checks and
decide null ordering) for cases 1, 2, 3 so compareToIgnoreCase is never invoked
on null, and keep the existing Boolean.compare for case 0 and the direction flip
using (direction == SWT.UP) ? -rc : rc unchanged; locate this logic in the
compare method of ESPIDFMainTablePage.java where propertyIndex is switched and
update those branches to handle nulls consistently.
- Around line 7-8: The code currently imports and uses AWT's java.awt.Desktop
(and java.net.URI) in ESPIDFMainTablePage; replace any
Desktop.getDesktop().browse(...) or Desktop.open(...) calls with the SWT-native
Program.launch(...) API: import org.eclipse.swt.program.Program, convert the URI
to a String (uri.toString() or the original URL string) and call
Program.launch(urlString); remove the java.awt.Desktop import and the direct
java.net.URI use if not needed (or keep URI only to build the string), and
adjust exception handling accordingly since Program.launch returns boolean
rather than throwing IOExceptions.
- Around line 374-412: The code calls configParser.getEimJson(true) on the
background thread but then re-calls configParser.getEimJson(false) on the UI
thread (in ESPIDFMainTablePage’s CompletableFuture.thenAcceptAsync block),
risking inconsistent state and UI blocking; fix by computing and capturing the
parsed EIM JSON on the background thread (the CompletableFuture.supplyAsync that
creates rows) and pass or store that result so the UI thread reuses it instead
of calling getEimJson(false). Concretely, modify the supplyAsync work (the
lambda that calls configParser.getEimJson(true) and builds IdfRow list) to also
return or set the EIM JSON (e.g., return a small holder object or set
this.eimJson inside the background thread safely) and remove the call to
configParser.getEimJson(false) from the thenAcceptAsync block so
updateLaunchButtonState(), tableViewer.setInput(...), and updateButtonState()
use the already-parsed EIM JSON and the computed rows.
- Around line 59-61: IdfRow's components (version, name, path) can be null
causing NPEs in label providers and the comparator; add a compact constructor to
the record IdfRow that normalizes null Strings to "" (empty string) for the
version, name and path fields so callers (where IdfRow is constructed from
ToolsUtility.getIdfVersion(...), idf.getName(), idf.getPath()) never get null
values; update the compact constructor inside IdfRow to coerce null -> "" for
each String parameter and leave original and isActive unchanged so existing
label provider code and the comparator continue to work without NPEs.
---
Nitpick comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 224-250: The label provider is repeatedly calling
Display.getDefault() in getForeground; instead capture the Display once from the
viewer (e.g. final Display display = viewer.getControl().getDisplay()) before
calling createCol and use display.getSystemColor(...) inside the anonymous
ColumnLabelProvider methods; update the references in getForeground (and
anywhere else in this provider) to use that cached display and avoid repeated
Display.getDefault() calls, keeping the rest of the logic (IdfRow,
currentInstallingNode, isActive) unchanged.
- Around line 341-356: The getSelectedIdf method contains an unreachable else-if
branch checking "first instanceof IdfInstalled"; since the table input is always
List<IdfRow>, remove the unreachable branch and simplify the method to only
handle IdfRow cases: cast/unwrap the first selection to IdfRow (using IdfRow
firstRow) and return firstRow.original(), keeping the existing
empty-selection/null handling and preserving use of tableViewer and
IStructuredSelection.
- Around line 85-101: The LocalResourceManager instance created in createPage
(new LocalResourceManager(JFaceResources.getResources(), parent)) is never
stored or used; either remove that unused allocation or assign it to a field
(e.g., a private LocalResourceManager resourceManager) and use it for any
managed resources and dispose it in the page's lifecycle (e.g., on dispose) to
avoid leaks; update createPage to set resourceManager = new
LocalResourceManager(...) and ensure disposeResourceManager is called when the
page/container is disposed.
- Around line 374-391: The supplyAsync block in ESPIDFMainTablePage catches
exceptions and throws new RuntimeException(e), which loses stacktrace clarity
and pairs poorly with the existing exceptionally handler that logs
ex.getCause().toString(); replace the throw with a CompletionException(e) (or
simply let the exception propagate) so CompletableFuture preserves the original
cause, and update the exceptionally handler that currently logs
ex.getCause().toString() to log the full throwable (e.g.,
Logger.log(Logger.ERROR, "Failed to load IDF rows", ex.getCause()) or
logger.error("...", ex.getCause())) so the stacktrace is preserved; look for
CompletableFuture.supplyAsync(...) and the matching exceptionally(...) block to
apply these changes.
...s/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java (3)
465-469:prefslocal variable shadows theprefsfield — use the existing field directly.Line 469 creates a local
var prefs = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID)which is identical to theprivate final IEclipsePreferences prefsdeclared at Line 69. The field can be used directly.♻️ Proposed fix
public void setupInitialEspIdf() { if (tableViewer.getInput() instanceof List<?> list && !list.isEmpty()) { - var prefs = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID); - if (!prefs.getBoolean(EimConstants.INSTALL_TOOLS_FLAG, false)) + if (!this.prefs.getBoolean(EimConstants.INSTALL_TOOLS_FLAG, false))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` around lines 465 - 469, The local variable prefs declared inside setupInitialEspIdf shadows the class field prefs; remove the local declaration and use the existing private final IEclipsePreferences prefs field instead (replace the local "var prefs = InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID)" usage with the field prefs) so the method uses the class-level prefs consistently.
99-99:LocalResourceManagercreated but reference immediately discarded — dead code.
LocalResourceManageris designed to manage resources tied to a widget's lifetime; the typical pattern is to store the reference and use it to createColor/Font/Imageobjects. Here the result is thrown away, andgetImagereturnsnulleverywhere, so no resources are ever allocated through it. Either store it as a field and use it to produce images/colors, or remove the line entirely.♻️ Proposed fix
- new LocalResourceManager(JFaceResources.getResources(), parent); + // Remove if no SWT resources are managed, or assign and use: + // resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` at line 99, The LocalResourceManager instance created in ESPIDFMainTablePage is discarded immediately (new LocalResourceManager(...);) so resources are never allocated and getImage returns null; either store that LocalResourceManager in a field (e.g., add a private LocalResourceManager resourceManager) and use it to create and manage Images/Colors/Fonts used by getImage and other UI methods, or remove the creation entirely and ensure any existing getImage calls are updated to use the correct resource provider; update dispose/cleanup logic to dispose the stored resourceManager when the page is disposed.
131-131:Logger.log(e.toString())loses the stack trace — preferLogger.log(e).All three sites pass
e.toString()which invokes theLogger.log(String)overload, logging only the message atINFOseverity. TheLogger.log(Exception)overload records the full stack trace atERRORseverity, which is the correct choice for caught exceptions.♻️ Proposed fix (apply to all three sites)
- Logger.log(ex.toString()); // Line 131 + Logger.log(ex); - Logger.log(e.toString()); // Line 328 + Logger.log(e); - Logger.log(e.toString()); // Line 443 + Logger.log(e);For the
exceptionallyhandler (Line 450):- Logger.log(ex.getCause() != null ? ex.getCause().toString() : ex.toString()); + Throwable cause = ex.getCause() != null ? ex.getCause() : ex; + Logger.log(cause instanceof Exception ec ? ec : new RuntimeException(cause));Also applies to: 328-328, 443-444
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` at line 131, Replace the three calls that pass the exception as a string to Logger (the occurrences of Logger.log(ex.toString()) in ESPIDFMainTablePage) with the overload that accepts the Throwable object (Logger.log(ex)) so the full stack trace is recorded at ERROR severity; update each exceptionally/catch handler where Logger.log(e.toString()) is used to call Logger.log(e) instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 409-413: The bug is that refreshEditorUI() is being invoked on
throwaway ESPIDFMainTablePage instances whose container is null, so file-watcher
notifications are dropped; instead, change callers (EimJsonUiChangeHandler and
wherever a new ESPIDFMainTablePage is created and passed into
SetupToolsJobListener) to resolve and use the actual displayed page/editor
instance (e.g., obtain the live ESPIDFManagerEditor via the editor input or
IWorkbenchPage.findEditor() and call getActivePage()/the existing
ESPIDFMainTablePage) rather than constructing a new page or passing an
uninitialized instance; update EimJsonUiChangeHandler and SetupToolsJobListener
to accept/retrieve the real page reference and only call refreshEditorUI() on
that initialized instance (or expose a getter on ESPIDFManagerEditor to retrieve
the initialized ESPIDFMainTablePage) so container is non-null when
refreshEditorUI() runs.
---
Duplicate comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 138-222: The UI contains hardcoded user-visible strings in
createMainContent (e.g., Group title "Installed IDF Versions", button
labels/tooltips "Activate Selected", "Set this version as the active ESP-IDF",
"Refresh Environment" and its tooltip, plus status texts "Setting up..." and
"\u2713 Active") that bypass the NLS Messages pattern; replace each literal with
the appropriate Messages.<KEY> constant (or add new keys to the Messages
resource bundle and Messages class) and use those message fields where the
literals appear (references: createMainContent method, eimLaunchBtn/button
creation, table double-click handling/status text setters), then update the
Messages properties files and regenerate or update the Messages class so the UI
strings are localized.
- Around line 414-452: The code currently calls configParser.getEimJson(true) in
the background task and then calls configParser.getEimJson(false) again on the
UI thread, risking inconsistent snapshots and UI-thread I/O; fix this by
capturing the EIM JSON object returned by getEimJson(true) inside the
supplyAsync task (e.g. keep the newJson variable) and pass that parsed snapshot
to the UI continuation instead of re-calling configParser.getEimJson(false); set
this.eimJson = capturedNewJson (or its immutable/readonly representation) on the
UI thread, avoid any additional parsing or I/O there, and keep using the
already-built rows list for tableViewer.setInput and subsequent logic
(references: configParser.getEimJson, supplyAsync lambda, thenAcceptAsync
lambda, this.eimJson, tableViewer).
- Around line 520-534: The comparator in compare(Viewer, Object, Object) on
IdfRow uses version(), name(), and path() which may be null and can throw NPEs
during compareToIgnoreCase; make the comparisons null-safe by normalizing nulls
before comparing (e.g., treat null as "" or use explicit null checks) or use a
null-safe comparator equivalent (Comparator.nullsFirst/Last semantics) for the
cases where propertyIndex == 1, 2, 3; update the switch branch logic in
compare(...) so r1.version()/name()/path() and r2.* are checked/normalized
before calling compareToIgnoreCase and preserve the existing direction handling
with (direction == SWT.UP) ? -rc : rc.
- Around line 7-8: The java.awt.Desktop import and its usage (Desktop and
java.net.URI) must be removed and replaced with an Eclipse/SWT-friendly API;
locate the code that calls Desktop.browse(new URI(...)) (the Desktop symbol) and
change it to use org.eclipse.swt.program.Program.launch(url) with a String URL
(or use
PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(URL)
if you want the workbench external browser), then remove the unused
java.awt.Desktop and java.net.URI imports; ensure any exception handling is
adapted for URL/Program.launch usage and update imports accordingly.
---
Nitpick comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 465-469: The local variable prefs declared inside
setupInitialEspIdf shadows the class field prefs; remove the local declaration
and use the existing private final IEclipsePreferences prefs field instead
(replace the local "var prefs =
InstanceScope.INSTANCE.getNode(UIPlugin.PLUGIN_ID)" usage with the field prefs)
so the method uses the class-level prefs consistently.
- Line 99: The LocalResourceManager instance created in ESPIDFMainTablePage is
discarded immediately (new LocalResourceManager(...);) so resources are never
allocated and getImage returns null; either store that LocalResourceManager in a
field (e.g., add a private LocalResourceManager resourceManager) and use it to
create and manage Images/Colors/Fonts used by getImage and other UI methods, or
remove the creation entirely and ensure any existing getImage calls are updated
to use the correct resource provider; update dispose/cleanup logic to dispose
the stored resourceManager when the page is disposed.
- Line 131: Replace the three calls that pass the exception as a string to
Logger (the occurrences of Logger.log(ex.toString()) in ESPIDFMainTablePage)
with the overload that accepts the Throwable object (Logger.log(ex)) so the full
stack trace is recorded at ERROR severity; update each exceptionally/catch
handler where Logger.log(e.toString()) is used to call Logger.log(e) instead.
...s/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java (2)
99-99: Remove the unusedLocalResourceManagerallocation.The
LocalResourceManageris constructed but never assigned to a field or local variable. No resources (images, colours) are ever allocated through it, so it only attaches a no-op dispose listener toparent. Either store it in a field if you plan to create managed resources, or remove the line.♻️ Proposed fix
- new LocalResourceManager(JFaceResources.getResources(), parent); -🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` at line 99, The code creates a LocalResourceManager via new LocalResourceManager(JFaceResources.getResources(), parent) inside ESPIDFMainTablePage but never stores or uses it; remove that unused allocation line or assign it to a field (e.g., a private LocalResourceManager resourceManager) and use it for managed resources, ensuring you dispose it in the class' dispose() method; if you choose removal, simply delete the new LocalResourceManager(...) statement to avoid the no-op listener.
391-394: DeadIdfInstalledbranch ingetSelectedIdf()is unreachable.
tableViewer.setInput(rows)always provides aList<IdfRow>;ArrayContentProvidersurfaces those asIdfRowelements. Theelse if (first instanceof IdfInstalled rawInstalled)branch will never execute.♻️ Proposed fix
- else if (first instanceof IdfInstalled rawInstalled) - { - return rawInstalled; - }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` around lines 391 - 394, The else-if branch checking "first instanceof IdfInstalled rawInstalled" in getSelectedIdf() is unreachable because tableViewer (with ArrayContentProvider) always exposes IdfRow elements; remove that branch and simplify getSelectedIdf() to only handle IdfRow instances (extract the IdfInstalled from the IdfRow or return null if none). Update getSelectedIdf() to return the IdfInstalled via the existing IdfRow path (or adjust the IdfRow handling to expose the installed object) and delete the dead IdfInstalled branch so the method reflects the actual tableViewer input types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 465-477: Add a null-check for the UI viewer and use the viewer's
displayed-first-element instead of the backing list: in setupInitialEspIdf(),
return early if tableViewer is null (same guard pattern used in
refreshEditorUI/createMainContent) to avoid NPE, then check
prefs.getBoolean(EimConstants.INSTALL_TOOLS_FLAG, false) and that tableViewer
has elements, obtain the first displayed element with
tableViewer.getElementAt(0), cast it to IdfRow (as in the current instanceof
check) and call performToolsSetup(selectedRaw.original()) — this preserves the
sorted display order provided by IdViewerComparator and prevents calling
getInput() on a null viewer.
- Around line 446-447: The selection isn't restored because IdfRow's
auto-generated equals() compares the embedded IdfInstalled by reference and
refreshEditorUI rebuilds new IdfInstalled instances, so
setSelection(currentSelection) fails; fix by either (A) implementing equals()
and hashCode() on IdfInstalled to use its unique id field (e.g., override
equals/hashCode to compare getId()), or (B) after tableViewer.setInput(rows)
compute and apply a new selection by finding rows whose IdfInstalled.getId()
matches the previously selected IdfInstalled ids (use IdfRow/IdfInstalled/getId
and tableViewer.setSelection with the matched new IdfRow instances) so selection
is restored reliably.
---
Duplicate comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 138-185: Replace the hardcoded UI strings in createMainContent
with i18n keys: change group.setText("Installed IDF Versions") to use
Messages.<newKeyInstalledVersions>, change btnActivate creation to use
Messages.<newKeyActivateLabel> and its tooltip to
Messages.<newKeyActivateTooltip>, and change btnReinstall creation to use
Messages.<newKeyRefreshLabel> and its tooltip to
Messages.<newKeyRefreshTooltip>; add the corresponding keys and translations to
the Messages properties and update the Messages class accessor if needed, then
rebuild to ensure the calls (group.setText(...), createActionButton(...) for
btnActivate and btnReinstall) reference the new Messages constants instead of
literal strings.
- Around line 7-8: Remove the AWT import and any usage of java.awt.Desktop in
ESPIDFMainTablePage; replace calls that open external URLs with an SWT-safe
mechanism such as org.eclipse.swt.program.Program.launch(String url) or the
Eclipse browser API
(PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new
URL(url))). Update imports to remove java.awt.Desktop and java.net.URI (if only
used with Desktop) and import org.eclipse.swt.program.Program or
org.eclipse.ui.PlatformUI/BrowserSupport, and ensure URL-opening logic in
methods of ESPIDFMainTablePage uses the chosen SWT-safe call to avoid AWT/SWT
conflicts on macOS.
- Around line 518-532: The compare method in the ESPI DFMainTablePage comparator
can NPE because IdfRow.version(), name(), and path() may be null; update the
comparator (inside the overridden compare in ESPI DFMainTablePage) to perform
null-safe string comparisons for cases 1–3 (e.g., normalize null to "" or use
nullsFirst/nullsLast semantics) before calling compareToIgnoreCase, and ensure
the direction handling with SWT.UP remains the same; reference the
compare(Viewer, Object, Object) method and the IdfRow.version()/name()/path()
accessors when making the change.
- Around line 409-413: The refreshEditorUI() call on throwaway
ESPIDFMainTablePage instances (constructed in EimJsonUiChangeHandler) is a no-op
because container is null when createPage() was never run; instead of new
ESPIDFMainTablePage(eimJson) create/using the real live page instance: locate
the active/registered ESPIDFMainTablePage (via the editor/page manager or the
existing editor that hosts ESPIDFMainTablePage), then call refreshEditorUI() on
that resolved instance (or invoke createPage()/init lifecycle first if you must
construct one) so container is non-null; update EimJsonUiChangeHandler to
resolve the page rather than instantiating a throwaway.
- Around line 414-452: The code double-parses EIM JSON: getEimJson(true) is
called inside the CompletableFuture.supplyAsync and then getEimJson(false) is
called again on the UI thread in thenAcceptAsync, risking inconsistent data and
UI-thread I/O; fix it by returning the parsed EimJson from the supplier along
with the List<IdfRow> (e.g. create a small result record/class like ParsedRows {
EimJson eimJson; List<IdfRow> rows; } or a Pair) so the supplier builds both
rows and the EimJson using configParser.getEimJson(true) and thenAcceptAsync
receives that single result and assigns this.eimJson = result.eimJson (no second
getEimJson call), updates the UI with result.rows, and removes any I/O on the UI
thread.
---
Nitpick comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Line 99: The code creates a LocalResourceManager via new
LocalResourceManager(JFaceResources.getResources(), parent) inside
ESPIDFMainTablePage but never stores or uses it; remove that unused allocation
line or assign it to a field (e.g., a private LocalResourceManager
resourceManager) and use it for managed resources, ensuring you dispose it in
the class' dispose() method; if you choose removal, simply delete the new
LocalResourceManager(...) statement to avoid the no-op listener.
- Around line 391-394: The else-if branch checking "first instanceof
IdfInstalled rawInstalled" in getSelectedIdf() is unreachable because
tableViewer (with ArrayContentProvider) always exposes IdfRow elements; remove
that branch and simplify getSelectedIdf() to only handle IdfRow instances
(extract the IdfInstalled from the IdfRow or return null if none). Update
getSelectedIdf() to return the IdfInstalled via the existing IdfRow path (or
adjust the IdfRow handling to expose the installed object) and delete the dead
IdfInstalled branch so the method reflects the actual tableViewer input types.
| tableViewer.setInput(rows); | ||
| tableViewer.setSelection(currentSelection); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find bundles -name "IdfInstalled.java" -type fRepository: espressif/idf-eclipse-plugin
Length of output: 156
🏁 Script executed:
#!/bin/bash
# First, find the IdfInstalled.java file
IDF_INSTALLED_FILE=$(find bundles -name "IdfInstalled.java" -type f)
if [ -n "$IDF_INSTALLED_FILE" ]; then
echo "=== IdfInstalled.java content ==="
cat -n "$IDF_INSTALLED_FILE"
echo ""
echo "=== Checking for equals/hashCode methods ==="
rg -n "equals|hashCode" "$IDF_INSTALLED_FILE"
fiRepository: espressif/idf-eclipse-plugin
Length of output: 1803
🏁 Script executed:
# Find IdfRow to verify it's a record
find bundles -name "IdfRow.java" -type fRepository: espressif/idf-eclipse-plugin
Length of output: 54
🏁 Script executed:
#!/bin/bash
# Check IdfRow definition
IDF_ROW_FILE=$(find bundles -name "IdfRow.java" -type f)
if [ -n "$IDF_ROW_FILE" ]; then
echo "=== IdfRow.java content ==="
cat -n "$IDF_ROW_FILE"
fiRepository: espressif/idf-eclipse-plugin
Length of output: 54
🏁 Script executed:
#!/bin/bash
# Search for IdfRow definition across the entire codebase
rg -n "class IdfRow|record IdfRow" --type javaRepository: espressif/idf-eclipse-plugin
Length of output: 279
🏁 Script executed:
#!/bin/bash
# Also check the file in question for IdfRow and the context around lines 446-447
FILE="bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java"
echo "=== File size check ==="
wc -l "$FILE"
echo ""
echo "=== Context around lines 440-455 ==="
sed -n '440,455p' "$FILE" | cat -nRepository: espressif/idf-eclipse-plugin
Length of output: 755
🏁 Script executed:
#!/bin/bash
# Search for IdfRow definition in the same directory or file
rg -n "IdfRow" bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ --type java -B 2 -A 10 | head -100Repository: espressif/idf-eclipse-plugin
Length of output: 12730
🏁 Script executed:
#!/bin/bash
# Search for currentSelection assignment and usage
rg -n "currentSelection\s*=" bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java -B 3 -A 1Repository: espressif/idf-eclipse-plugin
Length of output: 257
🏁 Script executed:
#!/bin/bash
# Look for the refreshEditorUI method to understand the refresh flow
rg -n "refreshEditorUI|private.*rows" bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java -A 5 | head -80Repository: espressif/idf-eclipse-plugin
Length of output: 310
🏁 Script executed:
#!/bin/bash
# Get more context around the refresh method to see how rows are constructed
FILE="bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java"
sed -n '420,460p' "$FILE" | cat -nRepository: espressif/idf-eclipse-plugin
Length of output: 1588
setSelection(currentSelection) silently fails after every refresh — selection is never restored.
IdfRow is a Java record whose auto-generated equals() includes all component fields, including the original (IdfInstalled) field. IdfInstalled is a plain POJO with no equals()/hashCode() override, so it uses reference equality—two objects are equal only if they refer to the same memory location.
When refreshEditorUI() rebuilds the table, it creates new IdfRow instances with fresh IdfInstalled objects parsed from JSON. The currentSelection captured before the refresh contains old IdfRow wrappers pointing to old IdfInstalled references. After setInput(rows) is called with the new rows, the subsequent setSelection(currentSelection) attempt fails because the old IdfInstalled references in the selection don't match the new object instances in the updated list, so the selection is never restored.
Fix options:
- Override
equals()/hashCode()onIdfInstalledusing itsidfield. - Re-select by matching on
IdfInstalled.getId()manually aftersetInput.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`
around lines 446 - 447, The selection isn't restored because IdfRow's
auto-generated equals() compares the embedded IdfInstalled by reference and
refreshEditorUI rebuilds new IdfInstalled instances, so
setSelection(currentSelection) fails; fix by either (A) implementing equals()
and hashCode() on IdfInstalled to use its unique id field (e.g., override
equals/hashCode to compare getId()), or (B) after tableViewer.setInput(rows)
compute and apply a new selection by finding rows whose IdfInstalled.getId()
matches the previously selected IdfInstalled ids (use IdfRow/IdfInstalled/getId
and tableViewer.setSelection with the matched new IdfRow instances) so selection
is restored reliably.
There was a problem hiding this comment.
@sigmaaa I think this makes sense
After setInput(rows), the table content is new IdfRow instances (with new IdfInstalled references). IdfRow’s generated equals() includes original; IdfInstalled does not override equals()/hashCode(), so comparison is by reference. The old selection no longer matches any element in the new list, so setSelection(currentSelection) has no effect. Fix by either: (A) implementing equals()/hashCode() on IdfInstalled using a stable id (e.g. getId()), or (B) before setInput, storing the selected id(s) (e.g. IdfInstalled.getId()), then after setInput finding the new IdfRow(s) with matching id(s) and calling setSelection with those.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
...s/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties (1)
14-15:⚠️ Potential issue | 🟡 MinorRemove unused message properties
MsgYesandMsgNo.These properties defined at lines 14–15 are not referenced anywhere in the codebase and should be deleted from both
messages.propertiesand their corresponding field declarations inMessages.java.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties` around lines 14 - 15, Remove the unused message keys MsgYes and MsgNo from bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties and delete the corresponding static fields (and any generated references) from Messages.java; search for the identifiers MsgYes and MsgNo to confirm they are not used, then remove the two lines "MsgYes=Yes" and "MsgNo=No" from messages.properties and the matching field declarations in the Messages class (and regenerate or update any resource bundle accessor code if your build generates Messages.java).
🧹 Nitpick comments (2)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties (1)
8-8: Rename stale keyIDFGuideLinkLabel_Textto better reflect its current purpose.The PR removes the guide link and adds an info button, but the property key still carries
GuideLinkLabelin its name, creating semantic mismatch. The key is now used exclusively for an information label inESPIDFMainTablePage.java(line 120). Consider renaming it toIDFInfoLabelTextor similar to improve code clarity.✏️ Suggested rename
-IDFGuideLinkLabel_Text=Select the ESP-IDF version you want to use. Double-click a row or select it and click 'Activate Selected' to switch versions. +IDFInfoLabelText=Select the ESP-IDF version you want to use. Double-click a row or select it and click 'Activate Selected' to switch versions.Update the reference in
ESPIDFMainTablePage.java:120fromMessages.IDFGuideLinkLabel_TexttoMessages.IDFInfoLabelText.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties` at line 8, Rename the stale property key IDFGuideLinkLabel_Text to a name that matches its new purpose (e.g., IDFInfoLabelText) in the properties file and update all references accordingly; specifically change the resource lookup in ESPIDFMainTablePage.java from Messages.IDFGuideLinkLabel_Text to Messages.IDFInfoLabelText and keep the existing string value unchanged so the label text remains the same.bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java (1)
94-97:LocalResourceManageris created but never used — remove or wire it up.
new LocalResourceManager(JFaceResources.getResources(), parent)is discarded immediately. Since no resources (images, colors, fonts) are allocated through it, it adds a dispose listener overhead with no benefit. Either remove it or assign it to a field so it can actually manage resources.🧹 Proposed cleanup
- new LocalResourceManager(JFaceResources.getResources(), parent); - container = new Composite(parent, SWT.NONE);If resource management is needed in the future, store it:
+ var resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent); container = new Composite(parent, SWT.NONE);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java` around lines 94 - 97, In ESPIDFMainTablePage.createPage, the LocalResourceManager instance is constructed and discarded; either remove the unused new LocalResourceManager(...) call or store it in a field (e.g., localResourceManager) so it can be used to allocate UI resources and disposed properly; if you choose to store it, add a private LocalResourceManager field to the class, assign it in createPage, and dispose it in the page's dispose/cleanup method to avoid leaking the dispose listener.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties`:
- Around line 14-15: Remove the unused message keys MsgYes and MsgNo from
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties
and delete the corresponding static fields (and any generated references) from
Messages.java; search for the identifiers MsgYes and MsgNo to confirm they are
not used, then remove the two lines "MsgYes=Yes" and "MsgNo=No" from
messages.properties and the matching field declarations in the Messages class
(and regenerate or update any resource bundle accessor code if your build
generates Messages.java).
---
Duplicate comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 421-433: The selection is lost because IdfRow's equals() delegates
to IdfInstalled which uses reference equality; after tableViewer.setInput(rows)
the old IdfInstalled instances no longer match, so
setSelection(currentSelection) silently fails—fix by either implementing
equals() and hashCode() on IdfInstalled (based on its id field) so identity
matches across refreshes, or change the refresh flow in ESPIDFMainTablePage to
capture the selected IdfInstalled id(s) before setInput and after setInput
re-select rows by matching IdfInstalled.getId() (use IdfRow/IdfInstalled
identity via getId and call tableViewer.setSelection with the matched new IdfRow
objects).
- Around line 504-518: The compare() implementation in the anonymous Comparator
can throw NullPointerException when IdfRow fields are null (e.g., r1.version(),
r2.name(), r1.path()); update the comparisons in compare() to be null-safe by
coercing values to non-null strings (for example using
Objects.toString(r.version(), "") or similar) before calling
compareToIgnoreCase, or ensure IdfRow constructors normalize nulls to "" so
version(), name(), and path() never return null; modify the branches for
propertyIndex cases 1, 2, and 3 in the compare() method (which uses
IdfRow.version(), IdfRow.name(), IdfRow.path()) to use these null-safe values
and keep the existing direction handling.
- Around line 451-462: setupInitialEspIdf() can NPE because tableViewer may be
null and it uses the unsorted backing list; guard early by returning if
container==null or tableViewer==null, then check there is at least one visible
element (e.g., tableViewer.getItemCount() > 0) and use the visual first element
via tableViewer.getElementAt(0) instead of list.get(0); if that element is an
IdfRow, call performToolsSetup(selectedRaw.original()) as before.
- Line 127: Replace all hardcoded UI strings in ESPIDFMainTablePage with entries
in the Messages resource bundle and use those keys instead of literal strings:
externalize "Installed IDF Versions" (used in group.setText), the button
labels/tooltips for "Activate Selected" and "Refresh Environment" (and its long
tooltip), the column header "Status", the progress label "Setting up..." and the
status text "\u2713 Active" into new Messages keys (e.g.,
Messages.EspIdfManagerInstalledGroup, Messages.EspIdfManagerActivateBtn,
Messages.EspIdfManagerRefreshBtn, Messages.EspIdfManagerRefreshTooltip,
Messages.EspIdfManagerStatusCol, Messages.EspIdfManagerSettingUp,
Messages.EspIdfManagerActiveTick) and replace the hardcoded literals in
ESPIDFMainTablePage with calls to those Messages fields; add corresponding
entries to the Messages properties and update any generated Messages.java if
required so the UI uses the i18n pattern consistently.
- Around line 400-438: The code currently calls configParser.getEimJson(true) on
the background thread to build rows and then calls
configParser.getEimJson(false) again on the UI thread, risking race conditions
and blocking; instead capture the parsed EIM JSON once on the background thread
(keep the local variable newJson returned from the CompletableFuture), convert
it to rows there, and pass that same newJson into the UI continuation so the UI
thread sets this.eimJson = newJson (or an appropriate copy) and avoids calling
configParser.getEimJson again; update the CompletableFuture.supplyAsync to
return a small holder (e.g., a pair/record or map) containing both the parsed
newJson and the rows, then in thenAcceptAsync use that holder to set
this.eimJson, update tableViewer input/selection, and update button state,
removing the configParser.getEimJson(false) call and its exception handling on
the UI thread.
- Around line 395-399: refreshEditorUI() is a no-op when container is null
because EimJsonUiChangeHandler and SetupToolsJobListener create throwaway
ESPIDFMainTablePage instances instead of targeting the live page; fix this by
changing those callers to locate the real, active ESPIDFMainTablePage (do NOT
construct a new instance) via the workbench page/editor lookup APIs and invoke
refreshEditorUI on that instance, or alternatively make refreshEditorUI tolerant
by, when container==null, resolving the live page from the current
IWorkbenchWindow/IWorkbenchPage (or active editor) and delegating the refresh
(so symbols to change are EimJsonUiChangeHandler, SetupToolsJobListener,
refreshEditorUI, createPage, and container).
---
Nitpick comments:
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java`:
- Around line 94-97: In ESPIDFMainTablePage.createPage, the LocalResourceManager
instance is constructed and discarded; either remove the unused new
LocalResourceManager(...) call or store it in a field (e.g.,
localResourceManager) so it can be used to allocate UI resources and disposed
properly; if you choose to store it, add a private LocalResourceManager field to
the class, assign it in createPage, and dispose it in the page's dispose/cleanup
method to avoid leaking the dispose listener.
In
`@bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties`:
- Line 8: Rename the stale property key IDFGuideLinkLabel_Text to a name that
matches its new purpose (e.g., IDFInfoLabelText) in the properties file and
update all references accordingly; specifically change the resource lookup in
ESPIDFMainTablePage.java from Messages.IDFGuideLinkLabel_Text to
Messages.IDFInfoLabelText and keep the existing string value unchanged so the
label text remains the same.
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/messages.properties
Outdated
Show resolved
Hide resolved
...s/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java
Outdated
Show resolved
Hide resolved
Hi @kolipakakondal, as far as I know, this issue only happens in the dev environment when we make changes to the editor code. I think that since you changed the branch, you were able to see it once. |
| tableViewer.setInput(rows); | ||
| tableViewer.setSelection(currentSelection); |
There was a problem hiding this comment.
@sigmaaa I think this makes sense
After setInput(rows), the table content is new IdfRow instances (with new IdfInstalled references). IdfRow’s generated equals() includes original; IdfInstalled does not override equals()/hashCode(), so comparison is by reference. The old selection no longer matches any element in the new list, so setSelection(currentSelection) has no effect. Fix by either: (A) implementing equals()/hashCode() on IdfInstalled using a stable id (e.g. getId()), or (B) before setInput, storing the selected id(s) (e.g. IdfInstalled.getId()), then after setInput finding the new IdfRow(s) with matching id(s) and calling setSelection with those.
...s/com.espressif.idf.ui/src/com/espressif/idf/ui/tools/manager/pages/ESPIDFMainTablePage.java
Outdated
Show resolved
Hide resolved
|
Hi @alirana01, good catch, thanks for noticing it. Fixed in the last commit. PTAL |
|
@sigmaaa hi ! Tested under: Everything we discussed earlier is implemented in this PR and works properly ✅ |
…se UI guidelines" This reverts commit 987e64f.
209275d to
24b131f
Compare


Description
Updated the UI to resolve dark theme color issues and rendering glitches. The interface is now more closely aligned with Eclipse UI guidelines. Additionally, sorting functionality has been improved.

Fixes # (IEP-1701)
Type of change
Please delete options that are not relevant.
How has this been tested?
Open the ESP-IDF Manager: The default sorting should be by ESP-IDF version.
Verify State Persistence: Change the sort order, then close and reopen the manager; the sorting preference should be saved.
Test Buttons: Verify the activation and refresh buttons. Note that "Refresh" should reactivate the currently selected target.
Test Configuration:
Dependent components impacted by this PR:
Checklist
Summary by CodeRabbit
New Features
UI/UX Improvements