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

knowledgepixels / nanodash / 17518110100

06 Sep 2025 06:34PM UTC coverage: 11.955% (-0.1%) from 12.094%
17518110100

push

github

tkuhn
Undo custom AjaxLazyLoadPanel to fix paging navigation

334 of 3876 branches covered (8.62%)

Branch coverage included in aggregate %.

958 of 6931 relevant lines covered (13.82%)

0.61 hits per line

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

0.0
src/main/java/com/knowledgepixels/nanodash/page/SearchPage.java
1
package com.knowledgepixels.nanodash.page;
2

3
import java.time.Duration;
4
import java.util.ArrayList;
5
import java.util.HashMap;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.Optional;
9

10
import org.apache.wicket.ajax.AjaxRequestTarget;
11
import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior;
12
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
13
import org.apache.wicket.markup.html.WebMarkupContainer;
14
import org.apache.wicket.markup.html.basic.Label;
15
import org.apache.wicket.markup.html.form.CheckBox;
16
import org.apache.wicket.markup.html.form.Form;
17
import org.apache.wicket.markup.html.form.RadioChoice;
18
import org.apache.wicket.markup.html.form.TextField;
19
import org.apache.wicket.model.Model;
20
import org.apache.wicket.request.mapper.parameter.PageParameters;
21
import org.nanopub.extra.services.ApiResponseEntry;
22
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24

25
import com.knowledgepixels.nanodash.NanodashPreferences;
26
import com.knowledgepixels.nanodash.NanodashSession;
27
import com.knowledgepixels.nanodash.NanopubElement;
28
import com.knowledgepixels.nanodash.QueryApiAccess;
29
import com.knowledgepixels.nanodash.User;
30
import com.knowledgepixels.nanodash.Utils;
31
import com.knowledgepixels.nanodash.component.NanopubResults;
32
import com.knowledgepixels.nanodash.component.TitleBar;
33

34
/**
35
 * SearchPage allows users to search for nanopublications by URI or free text.
36
 */
37
public class SearchPage extends NanodashPage {
38

39
    private static final long serialVersionUID = 1L;
40
    private static final Logger logger = LoggerFactory.getLogger(SearchPage.class);
×
41

42
    /**
43
     * The mount path for this page.
44
     */
45
    public static final String MOUNT_PATH = "/search";
46

47
    /**
48
     * {@inheritDoc}
49
     */
50
    @Override
51
    public String getMountPath() {
52
        return MOUNT_PATH;
×
53
    }
54

55
    private TextField<String> searchField;
56
    private CheckBox filterUser;
57
    private Model<String> progress;
58

59
    private Map<String, String> pubKeyMap;
60
    private RadioChoice<String> pubkeySelection;
61

62
    /**
63
     * Constructor for SearchPage.
64
     *
65
     * @param parameters Page parameters containing the search query, filter option, and public key.
66
     */
67
    public SearchPage(final PageParameters parameters) {
68
        super(parameters);
×
69

70
        add(new TitleBar("titlebar", this, "search"));
×
71

72
        final String searchText = parameters.get("query").toString();
×
73
        final Boolean filterCheck = Boolean.valueOf(parameters.get("filter").toString());
×
74
        final String pubkey = parameters.get("pubkey").toString();
×
75

76
        Form<?> form = new Form<Void>("form") {
×
77

78
            private static final long serialVersionUID = 1L;
79

80
            protected void onSubmit() {
81
                String searchText = searchField.getModelObject().trim();
×
82
                Boolean filterCheck = filterUser.getModelObject();
×
83
                String pubkey = pubkeySelection.getModelObject();
×
84
                PageParameters params = new PageParameters();
×
85
                params.add("query", searchText);
×
86
                params.add("filter", filterCheck);
×
87
                if (pubkey != null) params.add("pubkey", pubkey);
×
88
                setResponsePage(SearchPage.class, params);
×
89
            }
×
90
        };
91
        add(form);
×
92

93
        form.add(searchField = new TextField<String>("search", Model.of(searchText)));
×
94
        WebMarkupContainer ownFilter = new WebMarkupContainer("own-filter");
×
95
        ownFilter.add(filterUser = new CheckBox("filter", Model.of(filterCheck)));
×
96
        NanodashSession session = NanodashSession.get();
×
97
        ownFilter.setVisible(!NanodashPreferences.get().isReadOnlyMode() && session.getUserIri() != null);
×
98
        ArrayList<String> pubKeyList = new ArrayList<>();
×
99
        if (session.getUserIri() != null) {
×
100
            pubKeyMap = new HashMap<>();
×
101
            String lKeyShort = Utils.getShortPubkeyhashLabel(session.getPubkeyString(), session.getUserIri());
×
102
            pubKeyList.add(lKeyShort);
×
103
            pubKeyMap.put(lKeyShort, session.getPubkeyString());
×
104
            for (String pk : User.getPubkeyhashes(session.getUserIri(), null)) {
×
105
                String keyShort = Utils.getShortPubkeyhashLabel(pk, session.getUserIri());
×
106
                if (!pubKeyMap.containsKey(keyShort)) {
×
107
                    pubKeyList.add(keyShort);
×
108
                    pubKeyMap.put(keyShort, pk);
×
109
                }
110
            }
×
111
        }
112

113
        pubkeySelection = new RadioChoice<String>("pubkeygroup", Model.of(pubkey), pubKeyList);
×
114
        if (!pubKeyList.isEmpty() && pubkeySelection.getModelObject() == null) {
×
115
            pubkeySelection.setDefaultModelObject(pubKeyList.get(0));
×
116
        }
117
        ownFilter.add(pubkeySelection);
×
118

119
        form.add(ownFilter);
×
120

121
        // TODO: Progress bar doesn't update at the moment:
122
        progress = new Model<>();
×
123
        final Label progressLabel = new Label("progress", progress);
×
124
        progressLabel.setOutputMarkupId(true);
×
125
        progressLabel.add(new AjaxSelfUpdatingTimerBehavior(Duration.ofMillis(1000)));
×
126
        add(progressLabel);
×
127

128
        if (searchText == null || searchText.isEmpty()) {
×
129
            add(new Label("nanopubs", "Enter a search term above."));
×
130
        } else {
131
            add(new AjaxLazyLoadPanel<NanopubResults>("nanopubs") {
×
132

133
                private static final long serialVersionUID = 1L;
134

135
                @Override
136
                public NanopubResults getLazyLoadComponent(String markupId) {
137
                    Map<String, String> nanopubParams = new HashMap<>();
×
138
                    List<ApiResponseEntry> nanopubResults = new ArrayList<>();
×
139
                    String s = searchText;
×
140
                    if (s != null) {
×
141
                        s = s.trim();
×
142
                        if (s.matches("https?://[^\\s]+")) {
×
143
                            logger.info("URI QUERY: {}", s);
×
144
                            nanopubParams.put("ref", s);
×
145
                            if (Boolean.TRUE.equals(filterCheck)) {
×
146
                                String pubkey = pubKeyMap.get(pubkeySelection.getModelObject());
×
147
                                logger.info("Filter for PUBKEY: {}", pubkey);
×
148
                                nanopubParams.put("pubkey", pubkey);
×
149
                            }
150
                            try {
151
                                // nanopubResults = ApiAccess.getAll("find_nanopubs_with_uri", nanopubParams).getData();
152
                                nanopubResults = QueryApiAccess.get("find-uri-references", nanopubParams).getData();
×
153
                            } catch (Exception ex) {
×
154
                                logger.error("Error while running the query for URI", ex);
×
155
                            }
×
156
//                                                        nanopubResults = ApiAccess.getRecent("find_nanopubs_with_uri", nanopubParams, progress);
157
                        } else {
158
                            String freeTextQuery = getFreeTextQuery(s);
×
159
                            if (!freeTextQuery.isEmpty()) {
×
160
                                logger.info("FREE TEXT QUERY: {}", freeTextQuery);
×
161
                                nanopubParams.put("query", freeTextQuery);
×
162
                                if (filterCheck != null && Boolean.TRUE.equals(filterCheck)) {
×
163
                                    String pubkey = pubKeyMap.get(pubkeySelection.getModelObject());
×
164
                                    logger.info("Filter for PUBKEY: {}", pubkey);
×
165
                                    nanopubParams.put("pubkey", pubkey);
×
166
                                }
167
                                try {
168
                                    // nanopubResults = ApiAccess.getAll("find_nanopubs_with_text", nanopubParams).getData();
169
                                    nanopubResults = QueryApiAccess.get("fulltext-search-on-labels", nanopubParams).getData();
×
170
                                } catch (Exception ex) {
×
171
                                    logger.error("Error during search", ex);
×
172
                                }
×
173
//                                                                nanopubResults = ApiAccess.getRecent("find_nanopubs_with_text", nanopubParams, progress);
174
                            }
175
                        }
176
                    }
177
                    nanopubResults.sort(new ApiResponseEntry.DataComparator());
×
178
                    List<String> nanopubIds = new ArrayList<>();
×
179
                    while (!nanopubResults.isEmpty() && nanopubIds.size() < 100) {
×
180
                        String npUri = nanopubResults.remove(0).get("np");
×
181
                        if (!nanopubIds.contains(npUri)) nanopubIds.add(npUri);
×
182
                    }
×
183
                    progress.setObject("");
×
184
                    if (nanopubIds.isEmpty()) progress.setObject("nothing found");
×
185
                    List<NanopubElement> nanopubs = new ArrayList<>();
×
186
                    for (String id : nanopubIds) nanopubs.add(NanopubElement.get(id));
×
187
                    return NanopubResults.fromList(markupId, nanopubs);
×
188
                }
189

190
                @Override
191
                protected void onContentLoaded(NanopubResults content, Optional<AjaxRequestTarget> target) {
192
                    super.onContentLoaded(content, target);
×
193
                    if (target.isPresent()) {
×
194
                        target.get().appendJavaScript("updateElements();");
×
195
                    }
196
                }
×
197

198
            });
199

200
        }
201
    }
×
202

203
    private static String getFreeTextQuery(String searchText) {
204
        String freeTextQuery = "";
×
205
        String previous = "AND";
×
206
        String preprocessed = "";
×
207
        boolean inQuote = true;
×
208
        for (String s : searchText.replaceAll("\\(\\s+", "(").replaceAll("\\s+\\)", ")").replaceAll("@", "").split("\"")) {
×
209
            inQuote = !inQuote;
×
210
            if (inQuote) {
×
211
                s = "\\\"" + String.join("@", s.split("[^\\p{L}0-9\\-_]+")) + "\\\"";
×
212
            }
213
            preprocessed += s;
×
214
        }
215
        preprocessed = preprocessed.trim();
×
216
        for (String s : preprocessed.split("[^\\p{L}0-9\\-_\\(\\)@\\\"\\\\]+")) {
×
217
            if (s.matches("[0-9].*")) continue;
×
218
            if (!s.matches("AND|OR|\\(+|\\)+|\\(?NOT")) {
×
219
                if (s.toLowerCase().matches("and|or|not")) {
×
220
                    // ignore lower-case and/or/not
221
                    continue;
×
222
                }
223
                if (!previous.matches("AND|OR|\\(?NOT")) {
×
224
                    freeTextQuery += " AND";
×
225
                }
226
            }
227
            freeTextQuery += " " + s.toLowerCase();
×
228
            previous = s;
×
229
        }
230
        freeTextQuery = freeTextQuery.replaceAll("@", " ").trim();
×
231
        return freeTextQuery;
×
232
    }
233

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