Skip to content

feat: Add TagsField for keywords#15126

Merged
calixtus merged 19 commits into
JabRef:mainfrom
statxc:fix/issue-15108
Mar 16, 2026
Merged

feat: Add TagsField for keywords#15126
calixtus merged 19 commits into
JabRef:mainfrom
statxc:fix/issue-15108

Conversation

@statxc

@statxc statxc commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

Related issues and pull requests

Closes: #15108

PR Description

This PR implements TagsField support for the Groups field by creating an abstract TagsEditor base class and refactoring both KeywordsEditor and GroupsEditor to inherit from it. The Groups field now provides the same modern tag-based interface as the Keywords field, including visual tags, drag-and-drop functionality, double-click editing, and context menus. This change ensures consistent user experience across both fields and eliminates the previous invalidation of user expectations when switching between Keywords and Groups fields, while also preventing code invalidation through proper inheritance hierarchy.

Steps to test

  1. Open JabRef and load any bibliography file (or create a new one)
  2. Open an entry editor by double-clicking on any entry
  3. Navigate to the General tab
  4. Test the Groups field:
    • Type "demo" and press Enter → should create a visual tag
    • Type "Paywalled" and press Enter → should create another tag
    • Click the X button on any tag → should remove the tag
    • Double-click on a tag → should remove it and put text in editor for editing
    • Right-click on a tag → should show Copy/Cut/Delete context menu
    • Try dragging tags to reorder them
  5. Compare with Keywords field → both should now have identical tag-based interfaces
  6. Test drag-and-drop from group tree (if groups panel is visible) → should add groups as tags
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

@github-actions

Copy link
Copy Markdown
Contributor

Hey @intelliking! 👋

Thank you for contributing to JabRef!

We have automated checks in place, based on which you will soon get feedback if any of them are failing. We also use Qodo for review assistance. It will update your pull request description with a review help and offer suggestions to improve the pull request.

After all automated checks pass, a maintainer will also review your contribution. Once that happens, you can go through their comments in the "Files changed" tab and act on them, or reply to the conversation if you have further inputs. You can read about the whole pull request process in our contribution guide.

Please ensure that your pull request is in line with our AI Usage Policy and make necessary disclosures.

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

Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Implement TagsField for Groups field with shared editor base class

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Implement TagsField support for Groups field with modern tag-based interface
• Create abstract TagsEditor base class for shared tag editor functionality
• Refactor KeywordsEditor to inherit from TagsEditor for code reuse
• Add GroupsEditor with drag-and-drop, context menus, and tag editing features
Diagram
flowchart LR
  A["GroupEditor<br/>Old Implementation"] -->|Replaced| B["GroupsEditor<br/>New TagsField-based"]
  C["KeywordsEditor<br/>Refactored"] -->|Inherits| D["TagsEditor<br/>Abstract Base Class"]
  B -->|Inherits| D
  D -->|Implements| E["FieldEditorFX<br/>Interface"]
  B -->|Features| F["Drag-Drop<br/>Context Menus<br/>Tag Editing"]
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/fieldeditors/TagsEditor.java ✨ Enhancement +46/-0

Abstract base class for tag editors

• New abstract base class extending HBox and implementing FieldEditorFX
• Provides common functionality for tag-based field editors
• Defines shared properties: field, suggestionProvider, fieldCheckers, undoManager
• Implements getNode() and getWeight() methods for consistent editor behavior

jabgui/src/main/java/org/jabref/gui/fieldeditors/TagsEditor.java


2. jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java ✨ Enhancement +254/-0

New Groups field editor with TagsField UI

• New editor class extending TagsEditor for Groups field with TagsField UI
• Implements drag-and-drop support from group tree with duplicate prevention
• Provides tag context menu with Copy, Cut, Delete actions
• Supports double-click editing, tag reordering, and clipboard paste operations
• Handles hierarchical group names with proper separator support

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java


3. jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditorViewModel.java ✨ Enhancement +100/-0

ViewModel for Groups field management

• New ViewModel for Groups field managing group list and serialization
• Provides bidirectional binding between UI tags and field text content
• Implements suggestion provider for group autocomplete functionality
• Handles group parsing and serialization with configurable separator

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditorViewModel.java


View more (5)
4. jabgui/src/main/resources/org/jabref/gui/fieldeditors/GroupsEditor.fxml ✨ Enhancement +8/-0

FXML layout for Groups editor UI

• New FXML layout file defining Groups editor UI structure
• Contains TagsField component with horizontal growth constraint
• Binds to GroupsEditor controller for event handling

jabgui/src/main/resources/org/jabref/gui/fieldeditors/GroupsEditor.fxml


5. jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java ✨ Enhancement +3/-11

Refactor KeywordsEditor to use TagsEditor base class

• Refactored to extend TagsEditor instead of HBox
• Removed duplicate getNode() and getWeight() method implementations
• Added super constructor call to initialize base class properties
• Maintains all existing tag editing functionality and features

jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java


6. jabgui/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java ✨ Enhancement +1/-1

Update Groups field editor factory method

• Updated Groups field editor instantiation to use new GroupsEditor class
• Simplified constructor call removing unnecessary parameters
• Changed from GroupEditor to GroupsEditor with TagsField implementation

jabgui/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java


7. jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupEditor.java ✨ Enhancement +0/-64

Remove deprecated GroupEditor class

• Removed old GroupEditor class implementation
• Replaced by new GroupsEditor with modern TagsField-based interface

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupEditor.java


8. jabgui/src/test/java/org/jabref/gui/fieldeditors/GroupsEditorViewModelTest.java 🧪 Tests +17/-0

Unit tests for GroupsEditorViewModel

• New test class for GroupsEditorViewModel functionality
• Tests string converter with hierarchical group names
• Verifies proper serialization of hierarchical group format

jabgui/src/test/java/org/jabref/gui/fieldeditors/GroupsEditorViewModelTest.java


Grey Divider

Qodo Logo

@github-actions github-actions Bot added the status: changes-required Pull requests that are not yet complete label Feb 16, 2026
@qodo-free-for-open-source-projects

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

Copy link
Copy Markdown
Contributor

Code Review by Qodo

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

Grey Divider


Action required

1. getSuggestions() uses Collectors.toList()📘 Rule violation ➹ Performance
Description
New code collects a stream via collect(Collectors.toList()) instead of using the modern
Stream.toList() API. This conflicts with the requirement to prefer modern Java (24+) APIs and may
trigger modernization quality gates.
Code

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditorViewModel.java[R82-87]

+        List<Keyword> suggestions = suggestionProvider.getPossibleSuggestions().stream()
+                                                      .map(String.class::cast)
+                                                      .filter(group -> group.toLowerCase().contains(request.toLowerCase()))
+                                                      .map(Keyword::new)
+                                                      .distinct()
+                                                      .collect(Collectors.toList());
Evidence
Compliance requires preferring modern Java APIs; the new implementation explicitly uses
Collectors.toList() in changed code where .toList() is available and clearer.

AGENTS.md
jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditorViewModel.java[82-87]

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

## Issue description
`GroupsEditorViewModel#getSuggestions` uses `collect(Collectors.toList())` even though `Stream.toList()` is the preferred modern API.
## Issue Context
The compliance checklist requires preferring modern Java (24+) APIs where applicable.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditorViewModel.java[82-87]

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


2. GROUP drop data unchecked📘 Rule violation ⛯ Reliability
Description
The drag-and-drop handler assumes the dragboard content is a List and non-empty, then calls
getFirst() without validating emptiness/type. Malformed or empty drag data can cause runtime
exceptions and crash the UI interaction.
Code

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[R139-147]

+            if (event.getDragboard().hasContent(DragAndDropDataFormats.GROUP)) {
+                List<String> draggedGroups = (List<String>) event.getDragboard().getContent(DragAndDropDataFormats.GROUP);
+                if (bibEntry.isPresent() && draggedGroups.getFirst() != null) {
+                    Keyword newGroup = new Keyword(draggedGroups.getFirst());
+                    if (!groupTagsField.getTags().contains(newGroup)) {
+                        groupTagsField.addTags(newGroup);
+                    }
+                    success = true;
+                }
Evidence
Robust error handling and input validation require guarding external inputs before processing; here
the code performs an unchecked cast and uses getFirst() without ensuring the list is non-empty or
well-typed.

Rule 3: Generic: Robust Error Handling and Edge Case Management
jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[139-147]
Best Practice: Learned patterns

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

## Issue description
The group drag-and-drop handler performs an unchecked cast to `List&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;String&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;` and calls `getFirst()` without verifying the list is non-empty. This can throw at runtime on malformed or empty dragboard content.
## Issue Context
Drag-and-drop content is an external input channel (from the UI system). It should be validated for type and empty/null values before use to avoid crashes.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[139-147]

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


3. Group DnD wrong value🐞 Bug ✓ Correctness
Description
GroupsEditor drops the group-tree dragboard payload (a group *path* like "parent > child", or empty
for the root) directly into the GROUPS field, but ExplicitGroup membership is matched by group name;
this means dropping a hierarchical group will not actually assign the entry to that group (and
dragging the root can add an empty tag).
Code

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[R137-147]

+        this.setOnDragDropped(event -> {
+            boolean success = false;
+            if (event.getDragboard().hasContent(DragAndDropDataFormats.GROUP)) {
+                List<String> draggedGroups = (List<String>) event.getDragboard().getContent(DragAndDropDataFormats.GROUP);
+                if (bibEntry.isPresent() && draggedGroups.getFirst() != null) {
+                    Keyword newGroup = new Keyword(draggedGroups.getFirst());
+                    if (!groupTagsField.getTags().contains(newGroup)) {
+                        groupTagsField.addTags(newGroup);
+                    }
+                    success = true;
+                }
Evidence
The group tree DnD payload is a list of group *paths* (not names). GroupTreeNode.getPath
concatenates ancestor names with " > " and explicitly skips the root (so the root path becomes "").
GroupsEditor takes the first path and stores it as a Keyword in the GROUPS tags. However,
ExplicitGroup stores/matches membership via WordKeywordGroup over StandardField.GROUPS with
searchExpression=name, and the matching logic checks exact keyword containment—so a stored value
like "parent > child" (or empty) will not match a group whose name is just "child".

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[129-147]
jabgui/src/main/java/org/jabref/gui/groups/GroupTreeView.java[356-374]
jablib/src/main/java/org/jabref/model/groups/GroupTreeNode.java[30-31]
jablib/src/main/java/org/jabref/model/groups/GroupTreeNode.java[243-251]
jablib/src/main/java/org/jabref/model/groups/ExplicitGroup.java[10-22]
jablib/src/main/java/org/jabref/model/groups/WordKeywordGroup.java[179-191]

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

## Issue description
Dragging a group from the group tree into `GroupsEditor` currently stores the group *path* (e.g., `parent &amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; child`, or `&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;` for the root) as a GROUPS tag. Explicit group membership is matched by group **name**, so this can silently fail to assign the entry to the dragged group and can even add an empty tag when the root is dragged.
### Issue Context
The dragboard payload for `DragAndDropDataFormats.GROUP` is a `List&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;String&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;` of `GroupTreeNode.getPath()` values.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[137-151]
### Implementation notes
- Iterate over `draggedGroups` and for each `path`:
- skip `null` / blank strings
- compute `groupName` as the last segment after the path delimiter (`&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; &amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;`), e.g. `path.substring(path.lastIndexOf(&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; &amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;) + 3)`
- add `new Keyword(groupName)` if not already present
- Consider accepting `TransferMode.COPY` for this operation (optional).
- Add a small unit test for the path-&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;name extraction logic if you factor it into a helper (optional but recommended).

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


View more (2)
4. Unused StandardField import🐞 Bug ⛯ Reliability
Description
GroupsEditor imports StandardField but never uses it; Checkstyle enforces UnusedImports, so CI will
fail.
Code

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[R39-41]

+import org.jabref.model.entry.field.Field;
+import org.jabref.model.entry.field.StandardField;
+
Evidence
The repository Checkstyle config enables the UnusedImports rule. In GroupsEditor, StandardField is
imported but not referenced anywhere in the class, so Checkstyle will report an error.

jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[36-41]
config/checkstyle/checkstyle.xml[87-95]

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

## Issue description
`GroupsEditor.java` imports `StandardField` but does not use it. Checkstyle’s `UnusedImports` rule will fail CI.
### Issue Context
JabRef enforces `UnusedImports` via Checkstyle.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java[36-41]
- config/checkstyle/checkstyle.xml[87-95]
### Suggested change
- Delete the unused import line for `org.jabref.model.entry.field.StandardField`.

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


5. Unused imports KeywordsEditor🐞 Bug ⛯ Reliability
Description
After refactoring KeywordsEditor to extend TagsEditor, KeywordsEditor still imports Parent and HBox
even though those responsibilities moved into TagsEditor; Checkstyle UnusedImports will fail CI.
Code

jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java[54]

+public class KeywordsEditor extends TagsEditor {
Evidence
KeywordsEditor now extends TagsEditor, which already extends HBox and implements getNode() returning
Parent. KeywordsEditor still imports Parent/HBox but does not use them directly; with Checkstyle’s
UnusedImports rule enabled, this will be reported.

jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java[12-23]
jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java[54-55]
jabgui/src/main/java/org/jabref/gui/fieldeditors/TagsEditor.java[5-42]
config/checkstyle/checkstyle.xml[87-95]

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

## Issue description
After changing `KeywordsEditor` to extend `TagsEditor`, `KeywordsEditor` still imports `javafx.scene.Parent` and `javafx.scene.layout.HBox`, which are no longer used directly. Checkstyle enforces `UnusedImports`, so CI will fail.
### Issue Context
`TagsEditor` now provides `getNode()` / `getWeight()` and extends `HBox`.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java[9-23]
- jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java[54-54]
- config/checkstyle/checkstyle.xml[87-95]
### Suggested change
- Remove unused imports from `KeywordsEditor.java` (specifically `javafx.scene.Parent` and `javafx.scene.layout.HBox` if they are indeed no longer referenced).

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



Remediation recommended

6. TagsEditor comment not ///📘 Rule violation ✓ Correctness
Description
A new multi-line documentation comment was added using /** ... */ instead of the required Markdown
Javadoc /// style. This reduces consistency with the project’s commenting standard.
Code

jabgui/src/main/java/org/jabref/gui/fieldeditors/TagsEditor.java[R13-16]

+/**
+ * Abstract base class for tag-based field editors.
+ * Provides common functionality for editors that display field values as tags.
+ */
Evidence
The checklist requires Markdown Javadoc (///) for multi-line documentation comments where
applicable; the new class-level documentation uses a traditional block Javadoc instead.

AGENTS.md
jabgui/src/main/java/org/jabref/gui/fieldeditors/TagsEditor.java[13-16]

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

## Issue description
The new `TagsEditor` documentation uses a `/** ... */` multi-line comment, but the commenting standard requires Markdown Javadoc using `///` for multi-line documentation.
## Issue Context
Aligning comment style reduces review friction and keeps documentation consistent across the codebase.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/fieldeditors/TagsEditor.java[13-16]

ⓘ 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 +82 to +87
List<Keyword> suggestions = suggestionProvider.getPossibleSuggestions().stream()
.map(String.class::cast)
.filter(group -> group.toLowerCase().contains(request.toLowerCase()))
.map(Keyword::new)
.distinct()
.collect(Collectors.toList());

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

1. getsuggestions() uses collectors.tolist() 📘 Rule violation ➹ Performance

New code collects a stream via collect(Collectors.toList()) instead of using the modern
Stream.toList() API. This conflicts with the requirement to prefer modern Java (24+) APIs and may
trigger modernization quality gates.
Agent Prompt
## Issue description
`GroupsEditorViewModel#getSuggestions` uses `collect(Collectors.toList())` even though `Stream.toList()` is the preferred modern API.

## Issue Context
The compliance checklist requires preferring modern Java (24+) APIs where applicable.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditorViewModel.java[82-87]

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

Comment thread jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java Outdated
Comment thread jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java Outdated
Comment thread jabgui/src/main/java/org/jabref/gui/fieldeditors/GroupsEditor.java
@testlens-app

This comment has been minimized.

Comment on lines +1 to +8
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.HBox?>
<?import com.dlsc.gemsfx.TagsField?>
<fx:root xmlns:fx="http://javafx.com/fxml/1" type="HBox" xmlns="http://javafx.com/javafx/8.0.112"
fx:controller="org.jabref.gui.fieldeditors.GroupsEditor" >
<TagsField fx:id="groupTagsField" HBox.hgrow="ALWAYS"/>
</fx:root>

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.

Parsing this is a bit silly, isnt it?

@github-actions github-actions Bot added status: no-bot-comments and removed status: changes-required Pull requests that are not yet complete labels Feb 18, 2026
@statxc statxc requested a review from calixtus February 18, 2026 14:53
@statxc

statxc commented Feb 19, 2026

Copy link
Copy Markdown
Contributor Author

@calixtus @koppor Could you please review this PR and share any feedback? thanks.

@koppor koppor added the status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers label Feb 19, 2026
Comment on lines +103 to +108
if (groupTagsField.getTags().size() < 2) {
isSortedTagsField = false;
} else if ((Comparators.isInOrder(groupTagsField.getTags(), Comparator.comparing(Keyword::get))) || isSortedTagsField) {
isSortedTagsField = true;
groupTagsField.getTags().sort(Comparator.comparing(Keyword::get));
}

@calixtus calixtus Feb 19, 2026

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.

This definitly needs a comment. This feels totally weird.
Please use your own words, do not use an AI.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is for sorting tags. When the tags added it is automatically sorted but if manually sort them(drag-and-drop) it respect the user's behavior

});

groupTagsField.getEditor().setOnKeyPressed(event -> {
KeyBindingRepository keyBindingRepository = Injector.instantiateModelOrService(KeyBindingRepository.class);

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.

Why dont you inject it with the other Injections above?

Comment on lines +135 to +148
if (event.getDragboard().hasContent(DragAndDropDataFormats.GROUP)) {
Object content = event.getDragboard().getContent(DragAndDropDataFormats.GROUP);
if (bibEntry.isPresent() && content instanceof List<?> rawList && !rawList.isEmpty()) {
for (Object item : rawList) {
if (item instanceof String path && !path.isBlank()) {
String groupName = path.contains(" > ") ? path.substring(path.lastIndexOf(" > ") + 3) : path;
Keyword newGroup = new Keyword(groupName);
if (!groupTagsField.getTags().contains(newGroup)) {
groupTagsField.addTags(newGroup);
}
success = true;
}
}
}

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.

This produces mental overload.
Fail fast principle.
Divide in separate methods.
Clean code!

if (bibEntry.isPresent() && content instanceof List<?> rawList && !rawList.isEmpty()) {
for (Object item : rawList) {
if (item instanceof String path && !path.isBlank()) {
String groupName = path.contains(" > ") ? path.substring(path.lastIndexOf(" > ") + 3) : path;

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.

Are you trying to parse Hierarichal Groups or something?
What does the chevron stand for? Use constants instead of magical strings


tagLabel.setOnDragDetected(event -> {
Dragboard db = tagLabel.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();

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.

ClipBoardManager.setContent ?

@statxc statxc Feb 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This sets content on the Dragboard for drag-and-drop, not the system clipboard. If we used ClipBoardManager.setContent() here, it would put the text into the user's clipboard instead of attaching it to the drag operation — the drop handler wouldn't be able to read it back from event.getDragboard(). Same approach as KeywordsEditor and GroupTreeView.

draggedGroup = Optional.of(group);
event.consume();
});
tagLabel.setOnDragEntered(_ -> tagLabel.setStyle("-fx-background-color: lightgrey;"));

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.

Dont manually add styles. Put them in base.css and use standard colors.

event.consume();
});
tagLabel.setOnDragEntered(_ -> tagLabel.setStyle("-fx-background-color: lightgrey;"));
tagLabel.setOnDragExited(_ -> tagLabel.setStyle(""));

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.

Do not overwrite styles

public void execute() {
switch (command) {
case COPY -> {
clipBoardManager.setContent(group.get());

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.

So you DO know about ClipBoardManager.setContent

Comment on lines +9 to +17
class GroupsEditorViewModelTest {
@Test
void stringConverterWithHierarchicalGroups() {
String hierarchicalString = "parent > node > child";
Keyword group = Keyword.ofHierarchical(hierarchicalString);

assertEquals(hierarchicalString, GroupsEditorViewModel.getStringConverter().toString(group));
}
}

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.

This is odd.

@statxc

statxc commented Mar 10, 2026

Copy link
Copy Markdown
Contributor Author

@koppor what else should I update? Please let me know 🙏

* upstream/main: (59 commits)
  Fix 15000 identifier (JabRef#15286)
  Chore(deps): Bump dev.langchain4j:langchain4j-bom in /versions (JabRef#15305)
  Supress JavaFX VirtualFlow Info log noise for large libraries (10k+). (JabRef#15298)
  Chore(deps): Bump commons-logging:commons-logging in /versions (JabRef#15304)
  Fix merge dialog closing immediately when only one PDF importer returns metadata (JabRef#15127) (JabRef#15287)
  Fixed nullable eventhandlers (JabRef#15288)
  New Crowdin updates (JabRef#15285)
  Fix the ESC key for GlobalSearchResultDialog (JabRef#15259)
  Remove jbang plugin banner (JabRef#15282)
  Chore(deps): Bump org.apache.httpcomponents.core5:httpcore5 in /versions (JabRef#15281)
  Udpate to latest gradle master (JabRef#15279)
  Migrate to GemsFX Notifications (JabRef#14762)
  Chore(deps): Bump JetBrains/junie-github-action from 0 to 1 (JabRef#15272)
  Chore(deps): Bump docker/setup-qemu-action from 3 to 4 (JabRef#15269)
  Feature/citation count dropdown (JabRef#15216)
  Update dependency org.apache.maven.plugins:maven-resources-plugin to v3.5.0 (JabRef#15275)
  Chore(deps): Bump jablib/src/main/resources/csl-styles (JabRef#15273)
  Fix more security
  Fix pr_body leakage
  Chore: add dependency-management.md (JabRef#15278)
  ...
@testlens-app

This comment has been minimized.

* upstream/main:
  fix jbang (JabRef#15311)
  New Crowdin updates (JabRef#15310)
  Fix exception in ExtractReferences from pdf (JabRef#15308)
  feat: add --entry-type-pattern option to citationkeys generate command (JabRef#15072)
  Fix reflection excpetion, add missing (JabRef#15307)
@testlens-app

This comment has been minimized.

@calixtus

calixtus commented Mar 10, 2026

Copy link
Copy Markdown
Member

Please don't push us. We all have day jobs and a real life. As GSoC proposal period is coming closer we have to deal with more and more AI generated slop. As we noticed that your contribution was at least also co-generated by Claude AI we respectfully ask you to be patient. We prioritze non-AI contributions over AI-supported ones, because the main focus of JabRef is to support student contributors learning about about software engineering and open source. JabRef is a classroom, not a factory.

Comment thread jabgui/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java Outdated
Siedlerchr
Siedlerchr previously approved these changes Mar 16, 2026
@Siedlerchr Siedlerchr added this pull request to the merge queue Mar 16, 2026
@Siedlerchr Siedlerchr removed this pull request from the merge queue due to a manual request Mar 16, 2026
@testlens-app

testlens-app Bot commented Mar 16, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 0f748d6
▶️ Tests: 10180 executed
⚪️ Checks: 51/51 completed


Learn more about TestLens at testlens.app.

@calixtus

Copy link
Copy Markdown
Member

Dev-Call decision: Merge now and postpone fixes, as current state is already improving things.

@calixtus calixtus enabled auto-merge March 16, 2026 20:06
@koppor koppor removed status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers status: no-bot-comments labels Mar 16, 2026
@calixtus calixtus added this pull request to the merge queue Mar 16, 2026
@github-actions github-actions Bot added the status: to-be-merged PRs which are accepted and should go into the merge-queue. label Mar 16, 2026
Merged via the queue into JabRef:main with commit 3ac4f6b Mar 16, 2026
51 checks passed
@statxc statxc deleted the fix/issue-15108 branch March 16, 2026 20:47
AnvitaPrasad pushed a commit to AnvitaPrasad/jabref that referenced this pull request Mar 18, 2026
* feat: Add TagsField for keywords

* fix for all feedback

* Fix comment style in TagsEditor.java to use /// for multi-line comments

* Reformat indentation in GroupsEditorViewModel.java to match code style

* Convert GroupsEditor and KeywordsEditor from FXML to programmatic

* address review feedback

* Address feedbacks

* remove GroupsEditorWiewModelTest

* Resolve merge conflicts in KeywordsEditor and integrate escape handling

Resolve merge conflicts from main merge into fix/issue-15108 branch.
KeywordsEditor now properly extends TagsEditor and overrides the
separator key handler to preserve the escaped keyword support added
in main (JabRef#14929).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Injection by constructor

* function references

---------

Co-authored-by: intelliking <intelliking@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Siedlerchr <siedlerkiller@gmail.com>
Co-authored-by: Carl Christian Snethlage <calixtus@users.noreply.github.com>
FynnianB pushed a commit to FynnianB/jabref that referenced this pull request Mar 19, 2026
* feat: Add TagsField for keywords

* fix for all feedback

* Fix comment style in TagsEditor.java to use /// for multi-line comments

* Reformat indentation in GroupsEditorViewModel.java to match code style

* Convert GroupsEditor and KeywordsEditor from FXML to programmatic

* address review feedback

* Address feedbacks

* remove GroupsEditorWiewModelTest

* Resolve merge conflicts in KeywordsEditor and integrate escape handling

Resolve merge conflicts from main merge into fix/issue-15108 branch.
KeywordsEditor now properly extends TagsEditor and overrides the
separator key handler to preserve the escaped keyword support added
in main (JabRef#14929).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Injection by constructor

* function references

---------

Co-authored-by: intelliking <intelliking@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Siedlerchr <siedlerkiller@gmail.com>
Co-authored-by: Carl Christian Snethlage <calixtus@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

first contrib 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.

Add TagsField for keywords

4 participants