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

knowledgepixels / nanodash / 27810295987

19 Jun 2026 06:48AM UTC coverage: 26.548% (-0.4%) from 26.963%
27810295987

Pull #484

github

web-flow
Merge 6786f73e7 into 0f6281554
Pull Request #484: Space-ref disambiguation: conflict notice, claimants overview, ref-pinned pages

1549 of 6853 branches covered (22.6%)

Branch coverage included in aggregate %.

3411 of 11830 relevant lines covered (28.83%)

4.25 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/QueryResultListBuilder.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.knowledgepixels.nanodash.*;
4
import com.knowledgepixels.nanodash.domain.AbstractResourceWithProfile;
5
import com.knowledgepixels.nanodash.domain.MaintainedResource;
6
import com.knowledgepixels.nanodash.domain.Space;
7
import com.knowledgepixels.nanodash.page.PublishPage;
8
import com.knowledgepixels.nanodash.repository.MaintainedResourceRepository;
9
import com.knowledgepixels.nanodash.template.Template;
10
import org.apache.wicket.Component;
11
import org.apache.wicket.behavior.AttributeAppender;
12
import org.apache.wicket.request.mapper.parameter.PageParameters;
13
import org.eclipse.rdf4j.model.IRI;
14
import org.nanopub.extra.services.ApiResponse;
15
import org.nanopub.extra.services.QueryRef;
16

17
import java.io.Serializable;
18

19
/**
20
 * Builder class for creating QueryResultList components.
21
 */
22
public class QueryResultListBuilder implements Serializable {
23

24
    private String markupId;
25
    private ViewDisplay viewDisplay;
26
    private String contextId = null;
×
27
    private QueryRef queryRef;
28
    private AbstractResourceWithProfile resourceWithProfile = null;
×
29
    private String id = null;
×
30
    private AbstractResourceWithProfile pageResource = null;
×
31
    private String postPublishTab = null;
×
32
    private String refRoot = null;
×
33

34
    private QueryResultListBuilder(String markupId, QueryRef queryRef, ViewDisplay viewDisplay) {
×
35
        this.markupId = markupId;
×
36
        // Bind session-derived "magic" query parameters here on the request thread
37
        // (ApiCache fetches on background threads where the session is absent).
38
        this.queryRef = com.knowledgepixels.nanodash.MagicQueryParams.augment(queryRef);
×
39
        this.viewDisplay = viewDisplay;
×
40
    }
×
41

42
    /**
43
     * Creates a new QueryResultListBuilder instance.
44
     *
45
     * @param markupId    the markup ID for the component
46
     * @param queryRef    the query reference
47
     * @param viewDisplay the view display
48
     * @return a new QueryResultListBuilder instance
49
     */
50
    public static QueryResultListBuilder create(String markupId, QueryRef queryRef, ViewDisplay viewDisplay) {
51
        return new QueryResultListBuilder(markupId, queryRef, viewDisplay);
×
52
    }
53

54
    public QueryResultListBuilder resourceWithProfile(AbstractResourceWithProfile resourceWithProfile) {
55
        this.resourceWithProfile = resourceWithProfile;
×
56
        return this;
×
57
    }
58

59
    /**
60
     * Sets the context ID for the QueryResultList.
61
     *
62
     * @param contextId the context ID
63
     * @return the current QueryResultListBuilder instance
64
     */
65
    public QueryResultListBuilder contextId(String contextId) {
66
        this.contextId = contextId;
×
67
        return this;
×
68
    }
69

70
    public QueryResultListBuilder id(String id) {
71
        this.id = id;
×
72
        return this;
×
73
    }
74

75
    public QueryResultListBuilder pageResource(AbstractResourceWithProfile pageResource) {
76
        this.pageResource = pageResource;
×
77
        return this;
×
78
    }
79

80
    /**
81
     * Sets the tab to return to after publishing one of this view's action
82
     * buttons (e.g. {@code "about"}). Null leaves the post-publish redirect on
83
     * its default tab.
84
     *
85
     * @param postPublishTab the tab name, or null for the default
86
     * @return the current QueryResultListBuilder instance
87
     */
88
    public QueryResultListBuilder postPublishTab(String postPublishTab) {
89
        this.postPublishTab = postPublishTab;
×
90
        return this;
×
91
    }
92

93
    /**
94
     * Pins this list to a specific ref (root definition), so action visibility is gated
95
     * against that claimant's authority rather than the resource's representative ref. Used
96
     * on {@code ?root=}-pinned pages. Null leaves it on the representative ref.
97
     *
98
     * @param refRoot the ref's root nanopub, or null
99
     * @return the current QueryResultListBuilder instance
100
     */
101
    public QueryResultListBuilder refRoot(String refRoot) {
102
        this.refRoot = refRoot;
×
103
        return this;
×
104
    }
105

106
    /**
107
     * Builds the QueryResultList component.
108
     *
109
     * @return the QueryResultList component
110
     */
111
    public Component build() {
112
        ApiResponse response = ApiCache.retrieveResponseAsync(queryRef);
×
113
        String colClass = " col-" + viewDisplay.getDisplayWidth();
×
114
        if (resourceWithProfile != null) {
×
115
            if (response != null) {
×
116
                QueryResultList resultList = new QueryResultList(markupId, queryRef, response, viewDisplay);
×
117
                resultList.setResourceWithProfile(resourceWithProfile);
×
118
                resultList.setPageResource(pageResource);
×
119
                resultList.setContextId(contextId);
×
120
                resultList.setPostPublishTab(postPublishTab);
×
121
                resultList.setRefRoot(refRoot);
×
122
                View view = viewDisplay.getView();
×
123
                if (view != null) {
×
124
                    for (IRI actionIri : view.getViewResultActionList()) {
×
125
                        if (!SpaceMemberRole.isViewerEntitled(view.getActionVisibleTo(actionIri), resourceWithProfile, refRoot)) continue;
×
126
                        Template t = view.getTemplateForAction(actionIri);
×
127
                        if (t == null) continue;
×
128
                        String targetField = view.getTemplateTargetFieldForAction(actionIri);
×
129
                        if (targetField == null) targetField = "resource";
×
130
                        String label = view.getLabelForAction(actionIri);
×
131
                        if (label == null) label = "action...";
×
132
                        if (!label.endsWith("...")) label += "...";
×
133
                        PageParameters params = new PageParameters().set("template", t.getId())
×
134
                                .set("param_" + targetField, id)
×
135
                                .set("context", contextId)
×
136
                                .set("template-version", "latest");
×
137
                        if (id != null && contextId != null && !id.equals(contextId)) {
×
138
                            params.set("part", id);
×
139
                        }
140
                        String partField = view.getTemplatePartFieldForAction(actionIri);
×
141
                        if (partField != null && contextId != null) {
×
142
                            // The part field pre-fills a namespaced child IRI (the user fills the suffix).
143
                            // TODO Find a better way to pass the MaintainedResource object to this method:
144
                            MaintainedResource r = MaintainedResourceRepository.get().findById(contextId);
×
145
                            String namespace = null;
×
146
                            if (r != null) {
×
147
                                namespace = r.getNamespace();
×
148
                            } else if (resourceWithProfile instanceof Space) {
×
149
                                // The Space-creation templates' `space` placeholder has a fixed
150
                                // `https://w3id.org/spaces/` prefix, so the pre-fill is relative to it.
151
                                // Nesting the new space's IRI under this space's path makes it a
152
                                // sub-space via the prefix match.
153
                                namespace = contextId.replaceFirst("https://w3id.org/spaces/", "") + "/";
×
154
                            }
155
                            if (namespace != null) {
×
156
                                params.set("param_" + partField, namespace + "<SET-SUFFIX>");
×
157
                            }
158
                        }
159
                        String queryMapping = view.getTemplateQueryMapping(actionIri);
×
160
                        if (queryMapping != null && queryMapping.contains(":")) {
×
161
                            params.set("values-from-query", queryRef.getAsUrlString());
×
162
                            params.set("values-from-query-mapping", queryMapping);
×
163
                        }
164
                        params.set("refresh-upon-publish", queryRef.getAsUrlString());
×
165
                        if (postPublishTab != null) params.set("postpub-tab", postPublishTab);
×
166
                        resultList.addButton(label, PublishPage.class, params);
×
167
                    }
×
168
                }
169
                resultList.add(new AttributeAppender("class", colClass));
×
170
                return resultList;
×
171
            } else {
172
                ApiResultComponent comp = new ApiResultComponent(markupId, queryRef) {
×
173
                    @Override
174
                    public Component getApiResultComponent(String markupId, ApiResponse response) {
175
                        QueryResultList resultList = new QueryResultList(markupId, queryRef, response, viewDisplay);
×
176
                        resultList.setResourceWithProfile(resourceWithProfile);
×
177
                        resultList.setPageResource(pageResource);
×
178
                        resultList.setContextId(contextId);
×
179
                        resultList.setPostPublishTab(postPublishTab);
×
180
                        resultList.setRefRoot(refRoot);
×
181
                        View view = viewDisplay.getView();
×
182
                        if (view != null) {
×
183
                            for (IRI actionIri : view.getViewResultActionList()) {
×
184
                                if (!SpaceMemberRole.isViewerEntitled(view.getActionVisibleTo(actionIri), resourceWithProfile, refRoot)) continue;
×
185
                                Template t = view.getTemplateForAction(actionIri);
×
186
                                if (t == null) continue;
×
187
                                String targetField = view.getTemplateTargetFieldForAction(actionIri);
×
188
                                if (targetField == null) targetField = "resource";
×
189
                                String label = view.getLabelForAction(actionIri);
×
190
                                if (label == null) label = "action...";
×
191
                                if (!label.endsWith("...")) label += "...";
×
192
                                PageParameters params = new PageParameters().set("template", t.getId())
×
193
                                        .set("param_" + targetField, id)
×
194
                                        .set("context", contextId)
×
195
                                        .set("template-version", "latest");
×
196
                                if (id != null && contextId != null && !id.equals(contextId)) {
×
197
                                    params.set("part", id);
×
198
                                }
199
                                String partField = view.getTemplatePartFieldForAction(actionIri);
×
200
                                if (partField != null && contextId != null) {
×
201
                                    // The part field pre-fills a namespaced child IRI (the user fills the suffix).
202
                                    // TODO Find a better way to pass the MaintainedResource object to this method:
203
                                    MaintainedResource r = MaintainedResourceRepository.get().findById(contextId);
×
204
                                    String namespace = null;
×
205
                                    if (r != null) {
×
206
                                        namespace = r.getNamespace();
×
207
                                    } else if (resourceWithProfile instanceof Space) {
×
208
                                        // The Space-creation templates' `space` placeholder has a fixed
209
                                        // `https://w3id.org/spaces/` prefix, so the pre-fill is relative to it.
210
                                        // Nesting the new space's IRI under this space's path makes it a
211
                                        // sub-space via the prefix match.
212
                                        namespace = contextId.replaceFirst("https://w3id.org/spaces/", "") + "/";
×
213
                                    }
214
                                    if (namespace != null) {
×
215
                                        params.set("param_" + partField, namespace + "<SET-SUFFIX>");
×
216
                                    }
217
                                }
218
                                String queryMapping = view.getTemplateQueryMapping(actionIri);
×
219
                                if (queryMapping != null && queryMapping.contains(":")) {
×
220
                                    params.set("values-from-query", queryRef.getAsUrlString());
×
221
                                    params.set("values-from-query-mapping", queryMapping);
×
222
                                }
223
                                params.set("refresh-upon-publish", queryRef.getAsUrlString());
×
224
                                if (postPublishTab != null) params.set("postpub-tab", postPublishTab);
×
225
                                resultList.addButton(label, PublishPage.class, params);
×
226
                            }
×
227
                        }
228
                        return resultList;
×
229
                    }
230
                };
231
                comp.add(new AttributeAppender("class", colClass));
×
232
                return comp;
×
233
            }
234
        } else {
235
            if (response != null) {
×
236
                QueryResultList resultList = new QueryResultList(markupId, queryRef, response, viewDisplay);
×
237
                resultList.setPageResource(pageResource);
×
238
                resultList.setContextId(contextId);
×
239
                resultList.add(new AttributeAppender("class", colClass));
×
240
                return resultList;
×
241
            } else {
242
                ApiResultComponent comp = new ApiResultComponent(markupId, queryRef) {
×
243
                    @Override
244
                    public Component getApiResultComponent(String markupId, ApiResponse response) {
245
                        QueryResultList resultList = new QueryResultList(markupId, queryRef, response, viewDisplay);
×
246
                        resultList.setPageResource(pageResource);
×
247
                        resultList.setContextId(contextId);
×
248
                        return resultList;
×
249
                    }
250
                };
251
                comp.add(new AttributeAppender("class", colClass));
×
252
                return comp;
×
253
            }
254
        }
255
    }
256

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