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

knowledgepixels / nanodash / 28788771886

06 Jul 2026 11:38AM UTC coverage: 28.51% (+0.008%) from 28.502%
28788771886

Pull #535

github

web-flow
Merge d9131b781 into 571599d46
Pull Request #535: feat: persistent navigation context with back-link and post-publish forwarding

1811 of 7177 branches covered (25.23%)

Branch coverage included in aggregate %.

3710 of 12188 relevant lines covered (30.44%)

4.52 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/QueryPage.java
1
package com.knowledgepixels.nanodash.page;
2

3
import com.github.jsonldjava.shaded.com.google.common.base.Charsets;
4
import com.google.common.collect.ArrayListMultimap;
5
import com.google.common.collect.Multimap;
6
import com.knowledgepixels.nanodash.ApiCache;
7
import com.knowledgepixels.nanodash.GrlcQuery;
8
import com.knowledgepixels.nanodash.Utils;
9
import com.knowledgepixels.nanodash.ViewDisplay;
10
import com.knowledgepixels.nanodash.component.QueryParamField;
11
import com.knowledgepixels.nanodash.component.QueryResultRdf;
12
import com.knowledgepixels.nanodash.component.QueryResultTableBuilder;
13
import com.knowledgepixels.nanodash.component.RdfResultComponent;
14
import com.knowledgepixels.nanodash.component.TitleBar;
15
import org.apache.wicket.Component;
16
import org.eclipse.rdf4j.model.Model;
17
import org.apache.wicket.RestartResponseException;
18
import org.apache.wicket.feedback.FeedbackMessage;
19
import org.apache.wicket.markup.html.WebMarkupContainer;
20
import org.apache.wicket.markup.html.basic.Label;
21
import org.apache.wicket.markup.html.form.Form;
22
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
23
import org.apache.wicket.ajax.AjaxRequestTarget;
24
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
25
import org.apache.wicket.markup.html.link.ExternalLink;
26
import org.apache.wicket.markup.html.list.ListItem;
27
import org.apache.wicket.markup.html.list.ListView;
28
import org.apache.wicket.request.IRequestParameters;
29
import org.apache.wicket.markup.html.panel.FeedbackPanel;
30
import org.apache.wicket.request.mapper.parameter.INamedParameters.NamedPair;
31
import org.apache.wicket.request.mapper.parameter.PageParameters;
32
import org.apache.wicket.util.string.StringValue;
33
import org.nanopub.extra.services.QueryRef;
34

35
import java.net.URLEncoder;
36
import java.util.List;
37

38
/**
39
 * Page for displaying a query and its parameters, allowing users to run the query with specified parameters.
40
 */
41
public class QueryPage extends NanodashPage {
42

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

48
    /**
49
     * Prefix of the generic ("portable") nanopub-query service URLs that w3id-redirect to
50
     * whatever concrete query instance is current. These appear both as a query's endpoint and
51
     * inside SPARQL bodies (e.g. {@code SERVICE} clauses); for the YasGUI link they are rewritten
52
     * to a concrete instance so the browser-based editor can run them.
53
     */
54
    private static final String GENERIC_QUERY_SERVICE_PREFIX = "https://w3id.org/np/l/nanopub-query-1.1/";
55

56
    private final Form<Void> form;
57
    private final List<QueryParamField> paramFields;
58
    private final FeedbackPanel feedbackPanel;
59

60
    /**
61
     * {@inheritDoc}
62
     */
63
    @Override
64
    public String getMountPath() {
65
        return MOUNT_PATH;
×
66
    }
67

68
    @Override
69
    public boolean hasFullWidthContent() {
70
        return true;
×
71
    }
72

73
    /**
74
     * Constructor for the QueryPage.
75
     *
76
     * @param parameters The page parameters, which should include the query ID and any query parameters.
77
     */
78
    public QueryPage(final PageParameters parameters) {
79
        super(parameters);
×
80
        add(new TitleBar("titlebar", this, null));
×
81
        add(new Label("pagetitle", "Query Info | nanodash"));
×
82

83
        String id = parameters.get("id").toString();
×
84
        final String queryId = parameters.get("runquery").toString();
×
85
        if (id == null) id = queryId;
×
86

87
        final Multimap<String, String> queryParams = ArrayListMultimap.create();
×
88
        for (NamedPair param : parameters.getAllNamed()) {
×
89
            if (!param.getKey().startsWith("queryparam_")) continue;
×
90
            queryParams.put(param.getKey().replaceFirst("queryparam_", ""), param.getValue());
×
91
        }
×
92

93
        GrlcQuery q = GrlcQuery.get(id);
×
94
        if (!q.getQueryId().equals(id)) {
×
95
            throw new RestartResponseException(getClass(), parameters.set("id", q.getQueryId()));
×
96
        }
97

98
        add(new Label("querylabel", q.getLabel()));
×
99
        add(new BookmarkablePageLink<Void>("np", ExplorePage.class, new PageParameters().set("id", q.getNanopub().getUri().stringValue())));
×
100
        // TODO Replace hard-coded domain with dynamic solution:
101
        add(new ExternalLink("openapi-this", "https://query.knowledgepixels.com/openapi/?url=spec/" + id));
×
102
        add(new ExternalLink("openapi-latest", "https://query.knowledgepixels.com/openapi/?url=spec/" + id + "%3Fapi-version=latest"));
×
103
        add(new Label("querydesc", q.getDescription()));
×
104

105
        form = new Form<Void>("form") {
×
106

107
            @Override
108
            protected void onConfigure() {
109
                super.onConfigure();
×
110
                form.getFeedbackMessages().clear();
×
111
            }
×
112

113
            @Override
114
            protected void onSubmit() {
115
                try {
116
                    PageParameters params = new PageParameters();
×
117
                    params.set("runquery", q.getQueryId());
×
118
                    for (QueryParamField f : paramFields) {
×
119
                        for (String v : f.getValues()) {
×
120
                            params.add("queryparam_" + f.getParamName(), v);
×
121
                        }
122
                    }
×
123
                    setResponsePage(QueryPage.class, params);
×
124
                } catch (Exception ex) {
×
125
                    String message = ex.getClass().getName();
×
126
                    if (ex.getMessage() != null) message = ex.getMessage();
×
127
                    feedbackPanel.error(message);
×
128
                }
×
129
            }
×
130

131
            @Override
132
            protected void onValidate() {
133
                super.onValidate();
×
134
                for (QueryParamField f : paramFields) {
×
135
                    f.getFormComponent().processInput();
×
136
                    for (FeedbackMessage fm : f.getFormComponent().getFeedbackMessages()) {
×
137
                        form.getFeedbackMessages().add(fm);
×
138
                    }
×
139
                }
×
140
            }
×
141

142
        };
143
        form.setOutputMarkupId(true);
×
144

145
        WebMarkupContainer paramContainer = new WebMarkupContainer("params");
×
146

147
        paramFields = q.createParamFields("paramfield");
×
148
        for (QueryParamField f : paramFields) {
×
149
            for (StringValue parameter : parameters.getValues("queryparam_" + f.getParamName())) {
×
150
                f.putValue(parameter.toString().replaceFirst("\\s*$", ""));
×
151
            }
×
152
        }
×
153
        paramContainer.add(new ListView<QueryParamField>("paramfields", paramFields) {
×
154

155
            protected void populateItem(ListItem<QueryParamField> item) {
156
                item.add(item.getModelObject());
×
157
            }
×
158

159
        });
160
        paramContainer.setVisible(!paramFields.isEmpty());
×
161
        form.add(paramContainer);
×
162

163
        form.add(new AjaxButton("yasgui", form) {
×
164

165
            @Override
166
            protected void onSubmit(AjaxRequestTarget target) {
167
                IRequestParameters params = getRequest().getPostParameters();
×
168
                for (QueryParamField f : paramFields) {
×
169
                    StringValue input = params.getParameterValue(f.getFormComponent().getInputName());
×
170
                    f.clearValue();
×
171
                    if (!input.isNull() && !input.isEmpty()) {
×
172
                        f.putValue(input.toString());
×
173
                    }
174
                }
×
175
                String sparql = q.expandQuery(paramFields);
×
176
                boolean allSet = GrlcQuery.allMandatoryFieldsSet(paramFields);
×
177
                if (!allSet) {
×
178
                    sparql = "'auto_execution_blocker: Fill in placeholders below, then remove this line to run the query'\n\n" + sparql;
×
179
                }
180
                // Point the generic query-service URLs (e.g. SERVICE clauses) at a concrete
181
                // instance so they resolve in the browser-based YasGUI editor.
182
                String queryUrl = Utils.getMainQueryUrl();
×
183
                sparql = sparql.replace(GENERIC_QUERY_SERVICE_PREFIX, queryUrl);
×
184
                String editLink = q.getEndpoint().stringValue().replaceFirst("^.*/repo/", queryUrl + "tools/")
×
185
                    + "/yasgui.html#query=" + URLEncoder.encode(sparql, Charsets.UTF_8);
×
186
                target.appendJavaScript("window.location.href='" + editLink.replace("\\", "\\\\").replace("'", "\\'") + "';");
×
187
            }
×
188

189
        }.setDefaultFormProcessing(false));
×
190

191
        add(form);
×
192

193
        feedbackPanel = new FeedbackPanel("feedback");
×
194
        feedbackPanel.setOutputMarkupId(true);
×
195
        add(feedbackPanel);
×
196

197
        if (queryId == null) {
×
198
            add(new Label("resulttable").setVisible(false));
×
199
        } else if (q.isConstructQuery()) {
×
200
            QueryRef constructQueryRef = new QueryRef(queryId, queryParams);
×
201
            Model rdfModel = ApiCache.retrieveRdfModelAsync(constructQueryRef);
×
202
            if (rdfModel != null) {
×
203
                add(new QueryResultRdf("resulttable", rdfModel));
×
204
            } else {
205
                add(new RdfResultComponent("resulttable", constructQueryRef) {
×
206
                    @Override
207
                    public Component getRdfResultComponent(String markupId, Model model) {
208
                        return new QueryResultRdf(markupId, model);
×
209
                    }
210
                });
211
            }
212
        } else {
×
213
            add(QueryResultTableBuilder.create("resulttable", new QueryRef(queryId, queryParams), new ViewDisplay(20)).plain(true).build());
×
214
        }
215
    }
×
216

217
    /**
218
     * <p>hasAutoRefreshEnabled.</p>
219
     *
220
     * @return a boolean
221
     */
222
    protected boolean hasAutoRefreshEnabled() {
223
        return true;
×
224
    }
225

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