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

knowledgepixels / nanodash / 27145358627

08 Jun 2026 02:39PM UTC coverage: 20.682% (-0.3%) from 20.947%
27145358627

push

github

web-flow
Merge pull request #479 from knowledgepixels/feat/about-pages-478

Resource-page tabs, presets, and role-gated view actions (#478, #302)

1052 of 6429 branches covered (16.36%)

Branch coverage included in aggregate %.

2642 of 11432 relevant lines covered (23.11%)

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

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

19
import java.io.Serializable;
20

21
/**
22
 * Builder class for creating QueryResultTable components with various configurations.
23
 */
24
public class QueryResultTableBuilder implements Serializable {
25

26
    private String markupId;
27
    private boolean plain = false;
×
28
    private ViewDisplay viewDisplay;
29
    private String contextId = null;
×
30
    private QueryRef queryRef;
31
    private AbstractResourceWithProfile resourceWithProfile = null;
×
32
    private String id = null;
×
33

34
    private QueryResultTableBuilder(String markupId, QueryRef queryRef, ViewDisplay viewDisplay) {
×
35
        this.markupId = markupId;
×
36
        this.queryRef = queryRef;
×
37
        this.viewDisplay = viewDisplay;
×
38
    }
×
39

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

52
    /**
53
     * Sets the resource with profile for the QueryResultTable.
54
     *
55
     * @param resourceWithProfile the ResourceWithProfile object
56
     * @return the current QueryResultTableBuilder instance
57
     */
58
    public QueryResultTableBuilder resourceWithProfile(AbstractResourceWithProfile resourceWithProfile) {
59
        this.resourceWithProfile = resourceWithProfile;
×
60
        return this;
×
61
    }
62

63
    /**
64
     * Sets the ID for the QueryResultTable.
65
     *
66
     * @param id the ID string
67
     * @return the current QueryResultTableBuilder instance
68
     */
69
    public QueryResultTableBuilder id(String id) {
70
        this.id = id;
×
71
        return this;
×
72
    }
73

74
    /**
75
     * Sets whether the table should be plain.
76
     *
77
     * @param plain true for plain table, false otherwise
78
     * @return the current QueryResultTableBuilder instance
79
     */
80
    public QueryResultTableBuilder plain(boolean plain) {
81
        this.plain = plain;
×
82
        return this;
×
83
    }
84

85
    /**
86
     * Sets the context ID for the QueryResultTable.
87
     *
88
     * @param contextId the context ID string
89
     * @return the current QueryResultTableBuilder instance
90
     */
91
    public QueryResultTableBuilder contextId(String contextId) {
92
        this.contextId = contextId;
×
93
        return this;
×
94
    }
95

96
    /**
97
     * Builds the QueryResultTable component based on the configured parameters.
98
     *
99
     * @return the constructed Component
100
     */
101
    public Component build() {
102
        ApiResponse response = ApiCache.retrieveResponseAsync(queryRef);
×
103
        String colClass = " col-" + viewDisplay.getDisplayWidth();
×
104
        if (resourceWithProfile != null) {
×
105
            if (response != null) {
×
106
                QueryResultTable table = new QueryResultTable(markupId, queryRef, response, viewDisplay, false);
×
107
                table.setContextId(contextId);
×
108
                if (id != null && contextId != null && !id.equals(contextId)) {
×
109
                    table.setPartId(id);
×
110
                }
111
                table.setResourceWithProfile(resourceWithProfile);
×
112
                table.setPageResource(resourceWithProfile);
×
113
                addViewActions(table, viewDisplay, queryRef, id, contextId, resourceWithProfile);
×
114
                table.add(new AttributeAppender("class", colClass));
×
115
                return table;
×
116
            } else {
117
                ApiResultComponent comp = new ApiResultComponent(markupId, queryRef) {
×
118
                    @Override
119
                    public Component getApiResultComponent(String markupId, ApiResponse response) {
120
                        QueryResultTable table = new QueryResultTable(markupId, queryRef, response, viewDisplay, false);
×
121
                        table.setContextId(contextId);
×
122
                        if (id != null && contextId != null && !id.equals(contextId)) {
×
123
                            table.setPartId(id);
×
124
                        }
125
                        table.setResourceWithProfile(resourceWithProfile);
×
126
                        table.setPageResource(resourceWithProfile);
×
127
                        addViewActions(table, viewDisplay, queryRef, id, contextId, resourceWithProfile);
×
128
                        return table;
×
129
                    }
130
                };
131
                comp.add(new AttributeAppender("class", colClass));
×
132
                return comp;
×
133
            }
134
        } else {
135
            if (response != null) {
×
136
                QueryResultTable table = new QueryResultTable(markupId, queryRef, response, viewDisplay, plain);
×
137
                table.setContextId(contextId);
×
138
                addViewActions(table, viewDisplay, queryRef, id, contextId, resourceWithProfile);
×
139
                table.add(new AttributeAppender("class", colClass));
×
140
                return table;
×
141
            } else {
142
                ApiResultComponent comp = new ApiResultComponent(markupId, queryRef) {
×
143
                    @Override
144
                    public Component getApiResultComponent(String markupId, ApiResponse response) {
145
                        QueryResultTable table = new QueryResultTable(markupId, queryRef, response, viewDisplay, plain);
×
146
                        table.setContextId(contextId);
×
147
                        addViewActions(table, viewDisplay, queryRef, id, contextId, resourceWithProfile);
×
148
                        return table;
×
149
                    }
150
                };
151
                comp.add(new AttributeAppender("class", colClass));
×
152
                return comp;
×
153
            }
154
        }
155
    }
156

157
    /**
158
     * Adds a button to the table for each result action declared by the view, linking to the
159
     * action's template on the publish page. Resource-context parameters (the target field, the
160
     * context, the part, and the part field) are only set when the corresponding id/contextId is
161
     * available, so this also works on resource-less listings such as the general Spaces page.
162
     *
163
     * @param table       the table to add the action buttons to
164
     * @param viewDisplay the view display whose view declares the actions
165
     * @param queryRef    the query reference backing the table (used for refresh and query mapping)
166
     * @param id          the resource id, or null if there is no specific resource in context
167
     * @param contextId   the context id, or null if there is no context
168
     */
169
    private static void addViewActions(QueryResultTable table, ViewDisplay viewDisplay, QueryRef queryRef, String id, String contextId, AbstractResourceWithProfile resourceWithProfile) {
170
        View view = viewDisplay.getView();
×
171
        if (view == null) return;
×
172
        for (IRI actionIri : view.getViewResultActionList()) {
×
173
            // Per-action role gating (docs/role-specific-views.md): skip an action
174
            // whose gen:isVisibleTo the current viewer does not satisfy. Additive —
175
            // actions without gen:isVisibleTo are unaffected.
176
            if (!SpaceMemberRole.isViewerEntitled(view.getActionVisibleTo(actionIri), resourceWithProfile)) continue;
×
177
            Template t = view.getTemplateForAction(actionIri);
×
178
            if (t == null) continue;
×
179
            String targetField = view.getTemplateTargetFieldForAction(actionIri);
×
180
            if (targetField == null) targetField = "resource";
×
181
            String label = view.getLabelForAction(actionIri);
×
182
            if (label == null) label = "action...";
×
183
            if (!label.endsWith("...")) label += "...";
×
184
            PageParameters params = new PageParameters().set("template", t.getId())
×
185
                    .set("template-version", "latest");
×
186
            if (id != null) params.set("param_" + targetField, id);
×
187
            if (contextId != null) params.set("context", contextId);
×
188
            if (id != null && contextId != null && !id.equals(contextId)) {
×
189
                params.set("part", id);
×
190
            }
191
            String partField = view.getTemplatePartFieldForAction(actionIri);
×
192
            if (partField != null && contextId != null) {
×
193
                // TODO Find a better way to pass the MaintainedResource object to this method:
194
                MaintainedResource r = MaintainedResourceRepository.get().findById(contextId);
×
195
                if (r != null && r.getNamespace() != null) {
×
196
                    params.set("param_" + partField, r.getNamespace() + "<SET-SUFFIX>");
×
197
                }
198
            }
199
            String queryMapping = view.getTemplateQueryMapping(actionIri);
×
200
            if (queryMapping != null && queryMapping.contains(":")) {
×
201
                params.set("values-from-query", queryRef.getAsUrlString());
×
202
                params.set("values-from-query-mapping", queryMapping);
×
203
            }
204
            params.set("refresh-upon-publish", queryRef.getAsUrlString());
×
205
            table.addButton(label, PublishPage.class, params);
×
206
        }
×
207
    }
×
208

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