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

knowledgepixels / nanodash / 27622721129

16 Jun 2026 01:55PM UTC coverage: 26.963% (+6.3%) from 20.697%
27622721129

Pull #483

github

web-flow
Merge 73a4d0fe1 into 663f14f46
Pull Request #483: Space/resource About pages, ref-aware spaces, and magic query params

1542 of 6717 branches covered (22.96%)

Branch coverage included in aggregate %.

3407 of 11638 relevant lines covered (29.27%)

4.31 hits per line

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

43.59
src/main/java/com/knowledgepixels/nanodash/component/NanodashLink.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.knowledgepixels.nanodash.domain.IndividualAgent;
4
import com.knowledgepixels.nanodash.domain.MaintainedResource;
5
import com.knowledgepixels.nanodash.domain.Space;
6
import com.knowledgepixels.nanodash.domain.User;
7
import com.knowledgepixels.nanodash.Utils;
8
import com.knowledgepixels.nanodash.connector.ios.DsConfig;
9
import com.knowledgepixels.nanodash.connector.ios.DsNanopubPage;
10
import com.knowledgepixels.nanodash.connector.pensoft.BdjConfig;
11
import com.knowledgepixels.nanodash.connector.pensoft.BdjNanopubPage;
12
import com.knowledgepixels.nanodash.connector.pensoft.RioConfig;
13
import com.knowledgepixels.nanodash.connector.pensoft.RioNanopubPage;
14
import com.knowledgepixels.nanodash.page.ExplorePage;
15
import com.knowledgepixels.nanodash.page.MaintainedResourcePage;
16
import com.knowledgepixels.nanodash.page.ResourcePartPage;
17
import com.knowledgepixels.nanodash.page.SpacePage;
18
import com.knowledgepixels.nanodash.page.UserPage;
19
import com.knowledgepixels.nanodash.repository.MaintainedResourceRepository;
20
import com.knowledgepixels.nanodash.repository.SpaceRepository;
21
import com.knowledgepixels.nanodash.template.Template;
22
import com.knowledgepixels.nanodash.template.TemplateData;
23
import net.trustyuri.TrustyUriUtils;
24
import org.apache.commons.codec.Charsets;
25
import org.apache.wicket.Component;
26
import org.apache.wicket.behavior.AttributeAppender;
27
import org.apache.wicket.markup.html.basic.Label;
28
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
29
import org.apache.wicket.markup.html.link.ExternalLink;
30
import org.apache.wicket.markup.html.panel.Panel;
31
import org.apache.wicket.model.Model;
32
import org.apache.wicket.request.mapper.parameter.PageParameters;
33
import org.eclipse.rdf4j.model.IRI;
34
import org.eclipse.rdf4j.model.Statement;
35
import org.eclipse.rdf4j.model.ValueFactory;
36
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
37
import org.eclipse.rdf4j.model.vocabulary.RDFS;
38
import org.nanopub.Nanopub;
39
import org.nanopub.vocabulary.NP;
40
import org.nanopub.vocabulary.NTEMPLATE;
41

42
import java.net.URLEncoder;
43
import java.util.*;
44

45
/**
46
 * A Wicket component that creates a link to a nanopublication or an IRI.
47
 */
48
public class NanodashLink extends Panel {
49

50
    public NanodashLink(String id, String uri, Nanopub np, IRI templateClass, String label) {
51
        this(id, uri, np, templateClass, label, null);
24✔
52
    }
3✔
53

54
    /**
55
     * Creates a link to a nanopublication or an IRI.
56
     *
57
     * @param id            the Wicket component ID
58
     * @param uri           the URI of the nanopublication or IRI
59
     * @param np            the nanopublication, or null if the link is not to a nanopublication
60
     * @param templateClass the template class of the nanopublication, or null if the link is not to a nanopublication
61
     * @param label         the label to display for the link, or null to derive it from the nanopublication or IRI
62
     */
63
    public NanodashLink(String id, String uri, Nanopub np, IRI templateClass, String label, String contextId) {
64
        super(id);
9✔
65

66
        final List<Template> templates = new ArrayList<>();
12✔
67
        final Map<IRI, String> labels = new HashMap<>();
12✔
68
        if (np != null) {
6!
69
            for (Statement st : np.getPubinfo()) {
33✔
70
                if (st.getPredicate().equals(NTEMPLATE.HAS_LABEL_FROM_API) || st.getPredicate().equals(RDFS.LABEL)) {
30!
71
                    labels.put((IRI) st.getSubject(), st.getObject().stringValue());
×
72
                }
73
            }
3✔
74
        }
75

76
        final TemplateData td = TemplateData.get();
6✔
77

78
        if (NTEMPLATE.ASSERTION_TEMPLATE.equals(templateClass)) {
12!
79
            IRI templateId = td.getTemplateId(np);
×
80
            if (templateId != null) {
×
81
                templates.add(td.getTemplate(templateId.stringValue()));
×
82
            }
83
        } else if (NTEMPLATE.PROVENANCE_TEMPLATE.equals(templateClass)) {
12!
84
            IRI templateId = td.getProvenanceTemplateId(np);
×
85
            if (templateId != null) {
×
86
                templates.add(td.getTemplate(templateId.stringValue()));
×
87
            }
88
        } else if (NTEMPLATE.PUBINFO_TEMPLATE.equals(templateClass)) {
12!
89
            Set<IRI> templateIds = td.getPubinfoTemplateIds(np);
×
90
            for (IRI templateId : templateIds) {
×
91
                templates.add(td.getTemplate(templateId.stringValue()));
×
92
            }
×
93
        }
94

95
        final IRI iriObj = vf.createIRI(uri);
12✔
96
        if (np != null && uri.equals(np.getUri().stringValue())) {
24!
97
            ExternalLink link = new ExternalLink("link", ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, Charsets.UTF_8), "this");
×
98
            add(link);
×
99
            add(new Label("description", "this specific nanopublication"));
×
100
        } else if (np != null && uri.equals(np.getAssertionUri().stringValue())) {
24!
101
            ExternalLink link = new ExternalLink("link", ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, Charsets.UTF_8), "this assertion");
×
102
            link.add(new AttributeAppender("class", " nanopub-assertion "));
×
103
            add(link);
×
104
            add(new Label("description", "the assertion of this specific nanopublication"));
×
105
        } else if (uri.equals(NP.HAS_ASSERTION.stringValue())) {
15!
106
            ExternalLink link = new ExternalLink("link", ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, Charsets.UTF_8), "assertion");
×
107
            link.add(new AttributeAppender("class", " nanopub-assertion "));
×
108
            add(link);
×
109
            add(new Label("description", "links a nanopublication to its assertion"));
×
110
        } else if (uri.equals(NP.HAS_PROVENANCE.stringValue())) {
15!
111
            ExternalLink link = new ExternalLink("link", ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, Charsets.UTF_8), "provenance");
×
112
            link.add(new AttributeAppender("class", " nanopub-provenance "));
×
113
            add(link);
×
114
            add(new Label("description", "links a nanopublication to its provenance"));
×
115
        } else if (uri.equals(NP.HAS_PUBINFO.stringValue())) {
15!
116
            ExternalLink link = new ExternalLink("link", ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, Charsets.UTF_8), "pubinfo");
×
117
            link.add(new AttributeAppender("class", " nanopub-pubinfo "));
×
118
            add(link);
×
119
            add(new Label("description", "links a nanopublication to its pubinfo"));
×
120
        } else {
×
121
            if (label == null || label.isBlank()) {
6!
122
                label = Utils.getShortNameFromURI(uri);
9✔
123
                if (iriObj.equals(User.getSignatureOwnerIri(np))) {
15!
124
                    // TODO We might want to introduce a "(you)" flag here at some point
125
                    label = User.getShortDisplayName(iriObj);
×
126
                } else if (User.getName(iriObj) != null) {
9!
127
                    label = User.getShortDisplayName(iriObj);
×
128
                } else if (SpaceRepository.get().findById(uri) != null) {
12!
129
                    label = SpaceRepository.get().findById(uri).getLabel();
×
130
                } else if (SpaceRepository.get().findByAltId(uri) != null) {
12!
131
                    label = SpaceRepository.get().findByAltId(uri).getLabel();
×
132
                } else if (MaintainedResourceRepository.get().findById(uri) != null) {
12!
133
                    label = MaintainedResourceRepository.get().findById(uri).getLabel();
×
134
                } else {
135
                    for (Template template : templates) {
18!
136
                        // TODO For pubinfo templates, we don't consider which triple came from which template (which is non-trivial):
137
                        String l = template.getLabel(iriObj);
×
138
                        if (l != null) {
×
139
                            label = l;
×
140
                            break;
×
141
                        }
142
                        l = labels.get(iriObj);
×
143
                        if (l != null) {
×
144
                            label = l;
×
145
                            break;
×
146
                        }
147
                    }
×
148
                }
149
            }
150
            String shortLabel = label.replaceFirst(" - [\\s\\S]*$", "");
15✔
151
            add(createLink("link", uri, shortLabel, contextId));
39✔
152
            String description = "";
6✔
153
            if (np != null && uri.startsWith(np.getUri().stringValue())) {
24!
154
                description = "This is a local identifier that was minted when the nanopublication was created.";
×
155
            }
156
            if (label.contains(" - ")) description = label.replaceFirst("^.* - ", "");
12!
157
            add(new Label("description", description));
39✔
158
        }
159
        add(Utils.getUriLink("uri", uri));
33✔
160
    }
3✔
161

162
    /**
163
     * <p>createLink.</p>
164
     *
165
     * @param markupId a {@link java.lang.String} object
166
     * @param uri      a {@link java.lang.String} object
167
     * @param label    a {@link java.lang.String} object
168
     * @return a {@link org.apache.wicket.Component} object
169
     */
170
    public static Component createLink(String markupId, String uri, String label, String contextId) {
171
        boolean isNp = TrustyUriUtils.isPotentialTrustyUri(uri);
9✔
172
        PageParameters params = new PageParameters().set("id", uri);
21✔
173
        if (contextId != null) params.set("context", contextId);
6!
174
        // TODO Improve this
175
        if (isNp && uri.startsWith(DsConfig.get().getTargetNamespace())) {
6!
176
            return new BookmarkablePageLink<Void>(markupId, DsNanopubPage.class, params.set("mode", "final")).setBody(Model.of(label));
×
177
        } else if (isNp && uri.startsWith(BdjConfig.get().getTargetNamespace())) {
6!
178
            return new BookmarkablePageLink<Void>(markupId, BdjNanopubPage.class, params.set("mode", "final")).setBody(Model.of(label));
×
179
        } else if (isNp && uri.startsWith(RioConfig.get().getTargetNamespace())) {
6!
180
            return new BookmarkablePageLink<Void>(markupId, RioNanopubPage.class, params.set("mode", "final")).setBody(Model.of(label));
×
181
        } else if (IndividualAgent.isUser(uri)) {
9!
182
            label = User.getShortDisplayName(vf.createIRI(uri));
×
183
            return new BookmarkablePageLink<Void>(markupId, UserPage.class, params).setBody(Model.of(label));
×
184
        } else if (SpaceRepository.get().findById(uri) != null) {
12!
185
            label = SpaceRepository.get().findById(uri).getLabel();
×
186
            return new BookmarkablePageLink<Void>(markupId, SpacePage.class, params).setBody(Model.of(label));
×
187
        } else if (SpaceRepository.get().findByAltId(uri) != null) {
12!
188
            Space space = SpaceRepository.get().findByAltId(uri);
×
189
            label = space.getLabel();
×
190
            params.set("id", space.getId());
×
191
            return new BookmarkablePageLink<Void>(markupId, SpacePage.class, params).setBody(Model.of(label));
×
192
        } else if (MaintainedResourceRepository.get().findById(uri) != null) {
12!
193
            label = MaintainedResourceRepository.get().findById(uri).getLabel();
×
194
            return new BookmarkablePageLink<Void>(markupId, MaintainedResourcePage.class, params).setBody(Model.of(label));
×
195
        } else {
196
            boolean isCaret = "^".equals(label);
12✔
197
            if (!isCaret) params.set("label", label);
21!
198
            BookmarkablePageLink<Void> link;
199
            if (isPartOfResource(uri, contextId)) {
12!
200
                link = new BookmarkablePageLink<Void>(markupId, ResourcePartPage.class, params);
×
201
            } else {
202
                link = new BookmarkablePageLink<Void>(markupId, ExplorePage.class, params.set("forward-to-part", "true"));
30✔
203
            }
204
            link.setBody(Model.of(label));
15✔
205
            // The "^" source-nanopub caret is styled like the admin lists (subtle, with
206
            // hover-darken), reusing SourceNanopub's `a.source` styling.
207
            if (isCaret) link.add(new AttributeAppender("class", "source"));
6!
208
            return link;
6✔
209
        }
210
    }
211

212
    /**
213
     * Returns the best page URL for a given URI, routing to user/space/resource pages when applicable,
214
     * falling back to the Explore page otherwise.
215
     */
216
    public static String getPageUrl(String uri) {
217
        if (IndividualAgent.isUser(uri)) {
9!
218
            return UserPage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, java.nio.charset.StandardCharsets.UTF_8);
×
219
        } else if (SpaceRepository.get().findById(uri) != null) {
12!
220
            return SpacePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, java.nio.charset.StandardCharsets.UTF_8);
×
221
        } else if (SpaceRepository.get().findByAltId(uri) != null) {
12!
222
            String spaceId = SpaceRepository.get().findByAltId(uri).getId();
×
223
            return SpacePage.MOUNT_PATH + "?id=" + URLEncoder.encode(spaceId, java.nio.charset.StandardCharsets.UTF_8);
×
224
        } else if (MaintainedResourceRepository.get().findById(uri) != null) {
12!
225
            return MaintainedResourcePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, java.nio.charset.StandardCharsets.UTF_8);
×
226
        } else {
227
            return ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(uri, java.nio.charset.StandardCharsets.UTF_8);
15✔
228
        }
229
    }
230

231
    private static boolean isPartOfResource(String uri, String contextId) {
232
        if (contextId == null) return false;
12!
233
        String uriNamespace = MaintainedResource.getNamespace(uri);
×
234
        MaintainedResource resource = MaintainedResourceRepository.get().findByNamespace(uriNamespace);
×
235
        if (resource == null) return false;
×
236
        return resource.getId().equals(contextId);
×
237
    }
238

239
    /**
240
     * Creates a link to a nanopublication or an IRI.
241
     *
242
     * @param id            the Wicket component ID
243
     * @param uri           the URI of the nanopublication or IRI
244
     * @param np            the nanopublication, or null if the link is not to a nanopublication
245
     * @param templateClass the template class of the nanopublication, or null if the link is not to a nanopublication
246
     */
247
    public NanodashLink(String id, String uri, Nanopub np, IRI templateClass) {
248
        this(id, uri, np, templateClass, null);
21✔
249
    }
3✔
250

251
    /**
252
     * Creates a link to a nanopublication or an IRI.
253
     *
254
     * @param id  the Wicket component ID
255
     * @param uri the URI of the nanopublication or IRI
256
     * @param np  the nanopublication, or null if the link is not to a nanopublication
257
     */
258
    public NanodashLink(String id, String uri, Nanopub np) {
259
        this(id, uri, np, null);
×
260
    }
×
261

262
    /**
263
     * Creates a link to a nanopublication or an IRI.
264
     *
265
     * @param id  the Wicket component ID
266
     * @param uri the URI of the nanopublication or IRI
267
     */
268
    public NanodashLink(String id, String uri) {
269
        this(id, uri, null, null);
×
270
    }
×
271

272
    private static ValueFactory vf = SimpleValueFactory.getInstance();
9✔
273

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