Skip to content

Feature visual timer 15122#15151

Merged
Siedlerchr merged 6 commits into
JabRef:mainfrom
LoayTarek5:feature-visual-timer-15122
Feb 19, 2026
Merged

Feature visual timer 15122#15151
Siedlerchr merged 6 commits into
JabRef:mainfrom
LoayTarek5:feature-visual-timer-15122

Conversation

@LoayTarek5

Copy link
Copy Markdown
Collaborator

Related issues and pull requests

Closes #15122

PR Description

cleanups now run as a visible background task, when the user clicks "Clean up", a progress
indicator appears in the status bar showing real time progress "3 of 50 entries
cleaned up.", so the user knows the process hasn't stalled. The cleanup can also be
cancelled mid-operation.

Steps to test

1- Select at least one entry (the more the better to see progress).
2- Go to "Quality" then "Clean up entries".
3- In the cleanup dialog, select any tab, ex: "Single field"
4- Add "Filed name" and "Formatter name" then click a "Clean up" button
image
image

Checklist

  • I own the copyright of the code submitted and I license it under the MIT license
  • I manually tested my changes in running JabRef (always required)
  • [/] I added JUnit tests for changes (if applicable)
  • I added screenshots in the PR description (if change is visible to the user)
  • I added a screenshot in the PR description showing a library with a single entry with me as author and as title the issue number
  • I described the change in CHANGELOG.md in a way that can be understood by the average user (if change is visible to the user)
  • [/] I checked the user documentation for up to dateness and submitted a pull request to our user documentation repository

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Add visual progress indicator for cleanup operations

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add progress indicator for cleanup operations showing real-time progress
• Implement cancellable background task for cleanup with entry count tracking
• Display progress message format "%0 of %1 entries cleaned up." in status bar
• Add localization entries for cleanup progress messages
Diagram
flowchart LR
  A["User clicks<br/>Clean up"] --> B["BackgroundTask<br/>created"]
  B --> C["cleanupWithProgress<br/>called"]
  C --> D["Progress shown<br/>in status bar"]
  D --> E["User can<br/>cancel"]
  E --> F["Cleanup<br/>completes"]
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java ✨ Enhancement +56/-8

Implement progress tracking for cleanup operations

• Refactored cleanup execution to use explicit BackgroundTask instead of BackgroundTask.wrap()
• Added new cleanupWithProgress() method that tracks and displays real-time progress
• Progress updates show current entry count and allow task cancellation via task.isCancelled()
• Task visibility and title set only when processing multiple entries

jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java


2. CHANGELOG.md 📝 Documentation +1/-0

Document cleanup progress indicator feature

• Added entry documenting new progress indicator feature for cleanup operation
• References issue #15122

CHANGELOG.md


3. jablib/src/main/resources/l10n/JabRef_en.properties Localization +3/-0

Add localization strings for cleanup progress

• Added localization key Cleaning\ up\ entries for task title
• Added localization key %0\ of\ %1\ entries\ cleaned\ up. for progress message format

jablib/src/main/resources/l10n/JabRef_en.properties


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

✅ 1. Cancellation loses undo history 🐞 Bug ✓ Correctness
Description
When the user cancels a running cleanup, cleanupWithProgress() returns immediately without calling
compoundEdit.end() or undoManager.addEdit(compoundEdit). Every entry already processed has been
permanently mutated in memory by doCleanup(), but those mutations are never registered with the
undo manager, so the user cannot undo the partial cleanup they cancelled.
Code

jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[R227-229]

+            if (task.isCancelled()) {
+                return;
+            }
Evidence
The early return on cancellation (line 228) bypasses the compoundEdit.end() and
undoManager.addEdit() calls at lines 243-247. The original cleanup() method always executes
these statements, ensuring all changes are undoable. doCleanup() mutates BibEntry objects
in-place and accumulates UndoableFieldChange records into compoundEdit; those records only
become reachable for undo after undoManager.addEdit(compoundEdit) is called.

jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[226-229]
jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[243-247]
jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[195-205]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When `task.isCancelled()` is detected inside `cleanupWithProgress()`, the method returns immediately without calling `compoundEdit.end()` or `undoManager.addEdit(compoundEdit)`. All entries processed before the cancellation check have already been mutated in memory, but those mutations are never added to the undo stack, making them irreversible.
## Issue Context
The original `cleanup()` method always calls `compoundEdit.end()` and `undoManager.addEdit()` after the loop. The new `cleanupWithProgress()` must do the same on the cancellation path.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[226-229]
- jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[243-247]
Replace the bare `return` with:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. onSuccess fires after cancellation 🐞 Bug ✓ Correctness
Description
Because cleanupWithProgress() returns normally (no exception thrown) on cancellation, call()
returns null and the task executor treats the task as successfully completed. The onSuccess
handler fires, invoking showResults(), which notifies the user 'X entry(s) needed a clean up'
and calls markBaseChanged() — even though the user explicitly cancelled the operation, giving
misleading feedback about a partial, non-undoable cleanup.
Code

jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[R133-144]

+            new BackgroundTask<Void>() {
+                @Override
+                public Void call() {
+                    cleanupWithProgress(cleanupPreset, entriesToProcess, this);
+                    return null;
+                }
+            }
+                    .onSuccess(result -> {
+                        if (showFeedback) {
+                            showResults();
+                        }
+                    })
Evidence
cleanupWithProgress() returns normally on cancellation (line 228), so call() at line 137 returns
null. The onSuccess lambda (lines 140-144) is then invoked unconditionally, calling
showResults() which notifies the user of a successful cleanup and marks the library as changed —
regardless of whether the task was cancelled.

jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[133-144]
jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[181-186]
jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[227-229]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`cleanupWithProgress()` returns normally on cancellation, causing the `onSuccess` callback to fire and `showResults()` to notify the user of a successful cleanup even though the operation was cancelled mid-way.
## Issue Context
The `call()` method in the anonymous `BackgroundTask` always returns `null`, regardless of whether `cleanupWithProgress()` exited due to cancellation or normal completion. The `onSuccess` lambda cannot distinguish the two cases.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[133-146]
- jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[212-252]
Change `cleanupWithProgress()` to return a `boolean` (`true` = completed, `false` = cancelled), then in `call()` return that boolean and check it in `onSuccess`:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Cleanup strings misplaced in properties 📘 Rule violation ✓ Correctness
Description
The new localization strings Cleaning up entries and %0 of %1 entries cleaned up. are inserted
at lines 2072–2073 (near the 'Website' section), while all existing cleanup-related strings (`Clean
up entry, Clean up entries, %0 entry(s) needed a clean up`, etc.) are grouped together near
lines 1199–1220. New strings must be placed with semantically related strings.
Code

jablib/src/main/resources/l10n/JabRef_en.properties[R2072-2074]

+Cleaning\ up\ entries=Cleaning up entries
+%0\ of\ %1\ entries\ cleaned\ up.=%0 of %1 entries cleaned up.
+
Evidence
Compliance rule 31 requires new localization strings to be grouped semantically with related ones.
The existing cleanup strings are clustered at lines 1199–1220 (e.g., Clean up entry(s), `Clean up
entries, %0 entry(s) needed a clean up`), while the two new strings are added far away at lines
2072–2073 with no semantic relation to the surrounding entries.

AGENTS.md
jablib/src/main/resources/l10n/JabRef_en.properties[2072-2074]
jablib/src/main/resources/l10n/JabRef_en.properties[1209-1219]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Two new localization strings were added at lines 2072–2074, far from the semantic group of existing cleanup strings located at lines 1199–1220. This breaks semantic grouping and makes translation maintenance harder.
## Issue Context
JabRef requires new localization strings to be grouped semantically with related strings to aid translation consistency and discoverability. All cleanup-related strings are currently grouped near lines 1199–1220.
## Fix Focus Areas
- jablib/src/main/resources/l10n/JabRef_en.properties[2072-2074] (remove the new strings from here)
- jablib/src/main/resources/l10n/JabRef_en.properties[1219-1221] (insert the two new strings here, after `%0\ entry(s)\ needed\ a\ clean\ up`)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Progress percentage lags behind message 🐞 Bug ⛯ Reliability
Description
After processing entry i (0-indexed), task.updateProgress(i, count) sets the progress fraction
to i/count (0% for the first entry), while the message simultaneously reads `"i+1 of count entries
cleaned up."` The progress bar always shows one entry fewer than the text claims throughout the
entire operation.
Code

jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[R235-238]

+            task.updateProgress(i, count);
+            task.updateMessage(Localization.lang("%0 of %1 entries cleaned up.",
+                    String.valueOf(i + 1),
+                    String.valueOf(count)));
Evidence
updateProgress(i, count) passes workDone=i to BackgroundProgress.getWorkDonePercentage() which
computes workDone/max. When i=0, progress=0% but the message says '1 of N entries cleaned up'.
The mismatch persists for every iteration. A separate task.updateProgress(count, count) call after
the loop is needed to correct the final value to 100%, confirming the loop itself never reaches
100%.

jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[235-238]
jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[241-241]
jablib/src/main/java/org/jabref/logic/util/BackgroundTask.java[280-290]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`task.updateProgress(i, count)` uses the 0-based loop index, so the progress bar shows `i/count` while the message already reports `i+1` entries done. The bar lags one entry behind the text on every iteration.
## Issue Context
The pattern used in `BibFieldsIndexer.addToIndex()` (a similar progress-reporting loop in the same codebase) has the same off-by-one issue, but the fix here is straightforward.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[235-241]
Change:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +133 to +144
new BackgroundTask<Void>() {
@Override
public Void call() {
cleanupWithProgress(cleanupPreset, entriesToProcess, this);
return null;
}
}
.onSuccess(result -> {
if (showFeedback) {
showResults();
}
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Onsuccess fires after cancellation 🐞 Bug ✓ Correctness

Because cleanupWithProgress() returns normally (no exception thrown) on cancellation, call()
returns null and the task executor treats the task as successfully completed. The onSuccess
handler fires, invoking showResults(), which notifies the user 'X entry(s) needed a clean up'
and calls markBaseChanged() — even though the user explicitly cancelled the operation, giving
misleading feedback about a partial, non-undoable cleanup.
Agent Prompt
## Issue description
`cleanupWithProgress()` returns normally on cancellation, causing the `onSuccess` callback to fire and `showResults()` to notify the user of a successful cleanup even though the operation was cancelled mid-way.

## Issue Context
The `call()` method in the anonymous `BackgroundTask` always returns `null`, regardless of whether `cleanupWithProgress()` exited due to cancellation or normal completion. The `onSuccess` lambda cannot distinguish the two cases.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[133-146]
- jabgui/src/main/java/org/jabref/gui/cleanup/CleanupDialogViewModel.java[212-252]

Change `cleanupWithProgress()` to return a `boolean` (`true` = completed, `false` = cancelled), then in `call()` return that boolean and check it in `onSuccess`:
```java
new BackgroundTask<Boolean>() {
    @Override
    public Boolean call() {
        return cleanupWithProgress(cleanupPreset, entriesToProcess, this);
    }
}
    .onSuccess(completed -> {
        if (showFeedback && completed) {
            showResults();
        }
    })
```

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@testlens-app

testlens-app Bot commented Feb 18, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 6c1c092
▶️ Tests: 11192 executed
⚪️ Checks: 67/67 completed


Learn more about TestLens at testlens.app.

@Siedlerchr Siedlerchr added the status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers label Feb 19, 2026
@Siedlerchr Siedlerchr enabled auto-merge February 19, 2026 20:16
@Siedlerchr Siedlerchr added this pull request to the merge queue Feb 19, 2026
@github-actions github-actions Bot added the status: to-be-merged PRs which are accepted and should go into the merge-queue. label Feb 19, 2026
Merged via the queue into JabRef:main with commit 9132827 Feb 19, 2026
67 checks passed
Website=Website

Cleaning\ up\ entries=Cleaning up entries
%0\ of\ %1\ entries\ cleaned\ up.=%0 of %1 entries cleaned up.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next time, please sort this in at related translation keys.

Siedlerchr added a commit to ustmd/jabref that referenced this pull request Feb 20, 2026
* upstream/main: (26 commits)
  Fix matrix
  Feature visual timer 15122 (JabRef#15151)
  Chore(deps): Bump com.googlecode.plist:dd-plist from 1.28 to 1.29 in /versions (JabRef#15166)
  Chore(deps): Bump jablib/src/main/resources/csl-styles from `a0eb8d7` to `e306b56` (JabRef#15162)
  Chore(deps): Bump io.zonky.test.postgres:embedded-postgres-binaries-bom (JabRef#15165)
  Chore(deps): Bump jablib/src/main/resources/csl-locales (JabRef#15163)
  Chore(deps): Bump jablib/src/main/abbrv.jabref.org (JabRef#15164)
  Change Dependabot schedule from weekly to daily
  macos-15-intel should run on main only (JabRef#15161)
  Chore(deps): Bump jablib/src/main/resources/csl-styles (JabRef#15152)
  Chore(deps): Bump org.jetbrains:annotations in /versions (JabRef#15154)
  Chore(deps): Bump jablib/src/main/abbrv.jabref.org (JabRef#15153)
  Chore(deps): Bump org.itsallcode.openfasttrace from 3.1.0 to 3.1.1 (JabRef#15141)
  Chore(deps): Bump org.junit:junit-bom from 6.0.2 to 6.0.3 in /versions (JabRef#15148)
  Chore(deps): Bump org.eclipse.lsp4j:org.eclipse.lsp4j from 0.24.0 to 1.0.0 in /versions (JabRef#15149)
  Chore(deps): Bump org.postgresql:postgresql in /versions (JabRef#15146)
  Chore(deps): Bump net.bytebuddy:byte-buddy in /versions (JabRef#15147)
  Refine code (JabRef#15132)
  Chore(deps): Bump com.dlsc.gemsfx:gemsfx in /versions (JabRef#15143)
  Update dependency de.undercouch:citeproc-java to v3.5.0 (JabRef#15145)
  ...
RakockiW pushed a commit to RakockiW/jabref that referenced this pull request Mar 1, 2026
* update to include new progress indicator for cleanup.

* refactor cleanup process to include progress tracking

* add new localization entries for cleanup process

* add break instead of return tp fix irreversible
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good third issue status: no-bot-comments status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers status: to-be-merged PRs which are accepted and should go into the merge-queue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cleanups should be a background task

3 participants