• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanodash / 26622127697

29 May 2026 06:33AM UTC coverage: 20.725% (-0.007%) from 20.732%
26622127697

push

github

tkuhn
feat: apply view filters live as the user types

Filter text fields used AjaxFormComponentUpdatingBehavior("change"),
which only fires on blur/Enter, so the filter required pressing Enter.

Add a reusable FilterUpdatingBehavior that listens on the "input" event
(fires per keystroke) with a 300ms debounce so rapid typing coalesces
into a single request. Swap it into all filter fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

1003 of 6148 branches covered (16.31%)

Branch coverage included in aggregate %.

2584 of 11160 relevant lines covered (23.15%)

3.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
src/main/java/com/knowledgepixels/nanodash/component/QueryResultNanopubSet.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.knowledgepixels.nanodash.FilteredQueryResultDataProvider;
4
import com.knowledgepixels.nanodash.NanodashSession;
5
import com.knowledgepixels.nanodash.QueryResult;
6
import com.knowledgepixels.nanodash.QueryResultDataProvider;
7
import com.knowledgepixels.nanodash.ViewDisplay;
8
import com.knowledgepixels.nanodash.component.menu.ViewDisplayMenu;
9
import org.apache.wicket.ajax.AjaxRequestTarget;
10
import org.apache.wicket.ajax.markup.html.AjaxLink;
11
import org.apache.wicket.behavior.AttributeAppender;
12
import org.apache.wicket.markup.html.WebMarkupContainer;
13
import org.apache.wicket.markup.html.basic.Label;
14
import org.apache.wicket.markup.html.form.TextField;
15
import org.apache.wicket.model.Model;
16
import org.nanopub.extra.services.ApiResponse;
17
import org.nanopub.extra.services.QueryRef;
18
import org.slf4j.Logger;
19
import org.slf4j.LoggerFactory;
20

21
/**
22
 * Component for displaying query results in a list format.
23
 */
24
public class QueryResultNanopubSet extends QueryResult {
25

26
    private static final Logger logger = LoggerFactory.getLogger(QueryResultNanopubSet.class);
×
27
    private final WebMarkupContainer viewSelector;
28
    private final long itemsPerPage;
29
    private FilteredQueryResultDataProvider filteredDataProvider;
30
    private Model<String> filterModel = Model.of("");
×
31
    private WebMarkupContainer nanopubsContainer;
32

33
    /**
34
     * Constructor for QueryResultList.
35
     *
36
     * @param markupId    the markup ID
37
     * @param queryRef    the query reference
38
     * @param response    the API response
39
     * @param viewDisplay the view display
40
     */
41
    QueryResultNanopubSet(String markupId, QueryRef queryRef, ApiResponse response, ViewDisplay viewDisplay, long itemsPerPage) {
42
        super(markupId, queryRef, response, viewDisplay);
×
43
        this.itemsPerPage = itemsPerPage;
×
44

45
        logger.info("Rendering {} with '{}' mode.", this.getClass().getName(), NanodashSession.get().getNanopubResultsViewMode().getValue());
×
46

47
        viewSelector = new WebMarkupContainer("viewSelector");
×
48
        viewSelector.setOutputMarkupId(true);
×
49

50
        viewSelector.add(new AjaxLink<>("listEnabler") {
×
51
            @Override
52
            public void onClick(AjaxRequestTarget target) {
53
                NanodashSession.get().setNanopubResultsViewMode(NanopubResults.ViewMode.LIST);
×
54
                logger.info("ListEnabler -- Switched to '{}' mode", NanodashSession.get().getNanopubResultsViewMode().getValue());
×
55
            }
×
56
        });
57

58
        viewSelector.add(new AjaxLink<>("gridEnabler") {
×
59
            @Override
60
            public void onClick(AjaxRequestTarget target) {
61
                NanodashSession.get().setNanopubResultsViewMode(NanopubResults.ViewMode.GRID);
×
62
                logger.info("GridEnabler -- Switched to '{}' mode", NanodashSession.get().getNanopubResultsViewMode().getValue());
×
63
            }
×
64
        });
65

66
        viewSelector.add(new Label("np"));
×
67
        add(viewSelector);
×
68
        showViewDisplayMenu = false; // handled in populateComponent() inside viewSelector
×
69

70
        String titleLabel = grlcQuery.getLabel();
×
71
        if (viewDisplay.getTitle() != null) {
×
72
            titleLabel = viewDisplay.getTitle();
×
73
        }
74
        add(new Label("title", titleLabel));
×
75

76
        TextField<String> filterField = new TextField<>("filter", filterModel);
×
77
        filterField.setOutputMarkupId(true);
×
78
        filterField.add(new FilterUpdatingBehavior() {
×
79
            @Override
80
            protected void onUpdate(AjaxRequestTarget target) {
81
                if (filteredDataProvider != null && nanopubsContainer != null) {
×
82
                    filteredDataProvider.setFilterText(filterModel.getObject());
×
83
                    nanopubsContainer.addOrReplace(buildNanopubResults());
×
84
                    target.add(nanopubsContainer);
×
85
                }
86
            }
×
87
        });
88
        viewSelector.add(filterField);
×
89

90
        setOutputMarkupId(true);
×
91
    }
×
92

93
    @Override
94
    protected void populateComponent() {
95
        logger.info("Populating the component with nanopub results.");
×
96
        filteredDataProvider = new FilteredQueryResultDataProvider(new QueryResultDataProvider(response.getData()), response);
×
97

98
        nanopubsContainer = new WebMarkupContainer("nanopubs-container");
×
99
        nanopubsContainer.setOutputMarkupId(true);
×
100
        nanopubsContainer.add(buildNanopubResults());
×
101
        add(nanopubsContainer);
×
102

103
        if (viewDisplay.getNanopubId() != null) {
×
104
            viewSelector.addOrReplace(new ViewDisplayMenu("np", viewDisplay, queryRef, pageResource));
×
105
        } else {
106
            viewSelector.addOrReplace(new Label("np").setVisible(false));
×
107
        }
108
    }
×
109

110
    private NanopubResults buildNanopubResults() {
111
        NanopubResults nanopubResults = NanopubResults.fromApiResponse("nanopubs", filteredDataProvider.getFilteredData(), itemsPerPage);
×
112
        nanopubResults.add(AttributeAppender.append("class", NanodashSession.get().getNanopubResultsViewMode().getValue()));
×
113
        return nanopubResults;
×
114
    }
115

116
    /**
117
     * Sets the visibility of the title.
118
     *
119
     * @param hasTitle true to show the title, false to hide it
120
     */
121
    public void setTitleVisible(boolean hasTitle) {
122
        this.get("title").setVisible(hasTitle);
×
123
        if (!hasTitle) {
×
124
            viewSelector.add(AttributeAppender.append("class", " no-title"));
×
125
        }
126
    }
×
127

128
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc