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

knowledgepixels / nanodash / 28899187612

07 Jul 2026 09:14PM UTC coverage: 28.105% (-0.4%) from 28.465%
28899187612

Pull #543

github

web-flow
Merge 39c9ede0f into f1a7efda7
Pull Request #543: feat: query-form views (gen:QueryFormView) with view-results page

1813 of 7309 branches covered (24.81%)

Branch coverage included in aggregate %.

3717 of 12367 relevant lines covered (30.06%)

4.46 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.behavior.AttributeAppender;
11
import org.apache.wicket.markup.html.WebMarkupContainer;
12
import org.apache.wicket.markup.html.basic.Label;
13
import org.apache.wicket.markup.html.form.TextField;
14
import org.apache.wicket.model.Model;
15
import org.nanopub.extra.services.ApiResponse;
16
import org.nanopub.extra.services.QueryRef;
17
import org.slf4j.Logger;
18
import org.slf4j.LoggerFactory;
19

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

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

32
    // An empty title override (ViewDisplay.withTitle("")) hides the title row; kept as
33
    // a flag so the builder's later setTitleVisible(true) doesn't re-show an empty h4.
34
    private boolean emptyTitle = false;
×
35

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

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

50
        viewSelector = new WebMarkupContainer("viewSelector");
×
51
        viewSelector.setOutputMarkupId(true);
×
52

53
        // The tiled (grid) view mode is deactivated for now: this view always renders
54
        // as a list (see buildNanopubResults), so the list/grid toggle is omitted.
55
        viewSelector.add(new Label("np"));
×
56
        add(viewSelector);
×
57
        showViewDisplayMenu = false; // handled in populateComponent() inside viewSelector
×
58

59
        String titleLabel = grlcQuery.getLabel();
×
60
        if (viewDisplay.getTitle() != null) {
×
61
            titleLabel = viewDisplay.getTitle();
×
62
        }
63
        emptyTitle = (titleLabel == null || titleLabel.isEmpty());
×
64
        add(new Label("title", titleLabel));
×
65

66
        TextField<String> filterField = new TextField<>("filter", filterModel);
×
67
        filterField.setOutputMarkupId(true);
×
68
        filterField.add(new FilterUpdatingBehavior() {
×
69
            @Override
70
            protected void onUpdate(AjaxRequestTarget target) {
71
                if (filteredDataProvider != null && nanopubsContainer != null) {
×
72
                    filteredDataProvider.setFilterText(filterModel.getObject());
×
73
                    nanopubsContainer.addOrReplace(buildNanopubResults());
×
74
                    target.add(nanopubsContainer);
×
75
                }
76
            }
×
77
        });
78
        filterField.setVisible(!fitsOnFirstPage());
×
79
        viewSelector.add(filterField);
×
80

81
        setOutputMarkupId(true);
×
82
    }
×
83

84
    @Override
85
    protected void populateComponent() {
86
        logger.info("Populating the component with nanopub results.");
×
87
        filteredDataProvider = new FilteredQueryResultDataProvider(new QueryResultDataProvider(response.getData()), response);
×
88

89
        nanopubsContainer = new WebMarkupContainer("nanopubs-container");
×
90
        nanopubsContainer.setOutputMarkupId(true);
×
91
        nanopubsContainer.add(buildNanopubResults());
×
92
        Label noRecordsLabel = new Label("no-records", "(nothing found)") {
×
93
            @Override
94
            protected void onConfigure() {
95
                super.onConfigure();
×
96
                setVisible(filteredDataProvider.size() == 0);
×
97
            }
×
98
        };
99
        nanopubsContainer.add(noRecordsLabel);
×
100
        add(nanopubsContainer);
×
101

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

109
    private NanopubResults buildNanopubResults() {
110
        // Each card carries the view's entry actions (applied to its result row) as a
111
        // dropdown in its top-right corner, matching the per-row menus of the other
112
        // view types.
113
        NanopubResults nanopubResults = NanopubResults.fromApiResponse("nanopubs", filteredDataProvider.getFilteredData(), itemsPerPage,
×
114
                row -> ViewActionMappings.buildEntryActionLinks(viewDisplay.getView(), row, queryRef,
×
115
                        resourceWithProfile != null ? resourceWithProfile : pageResource,
×
116
                        contextId, partId, refRoot, postPublishTab));
117
        // Tiled (grid) mode deactivated for now — always render this view as a list,
118
        // regardless of the session's view-mode setting.
119
        nanopubResults.add(AttributeAppender.append("class", NanopubResults.ViewMode.LIST.getValue()));
×
120
        // Hide the (empty) results container when there is nothing to show, so the
121
        // "(nothing found)" note sits directly below the header instead of being pushed
122
        // down by the flex-container's padding.
123
        nanopubResults.setVisible(!filteredDataProvider.getFilteredData().isEmpty());
×
124
        return nanopubResults;
×
125
    }
126

127
    /**
128
     * Sets the visibility of the title.
129
     *
130
     * @param hasTitle true to show the title, false to hide it
131
     */
132
    public void setTitleVisible(boolean hasTitle) {
133
        boolean visible = hasTitle && !emptyTitle;
×
134
        this.get("title").setVisible(visible);
×
135
        if (!visible) {
×
136
            viewSelector.add(AttributeAppender.append("class", " no-title"));
×
137
        }
138
    }
×
139

140
}
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