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

knowledgepixels / nanodash / 19960741136

05 Dec 2025 10:54AM UTC coverage: 15.197% (-0.2%) from 15.4%
19960741136

push

github

web-flow
Merge pull request #321 from knowledgepixels/320-fix-breadcrumb-path-resources

Add full breadcrumb path for resource parts

579 of 4972 branches covered (11.65%)

Branch coverage included in aggregate %.

1556 of 9077 relevant lines covered (17.14%)

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

3
import com.knowledgepixels.nanodash.*;
4
import com.knowledgepixels.nanodash.component.ButtonList;
5
import com.knowledgepixels.nanodash.component.TitleBar;
6
import com.knowledgepixels.nanodash.component.ViewList;
7
import com.knowledgepixels.nanodash.vocabulary.KPXL_TERMS;
8
import org.apache.wicket.Component;
9
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
10
import org.apache.wicket.markup.html.basic.Label;
11
import org.apache.wicket.markup.html.link.AbstractLink;
12
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
13
import org.apache.wicket.model.Model;
14
import org.apache.wicket.request.mapper.parameter.PageParameters;
15
import org.eclipse.rdf4j.model.IRI;
16
import org.eclipse.rdf4j.model.Statement;
17
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
18
import org.eclipse.rdf4j.model.vocabulary.RDF;
19
import org.eclipse.rdf4j.model.vocabulary.RDFS;
20
import org.eclipse.rdf4j.model.vocabulary.SKOS;
21
import org.nanopub.Nanopub;
22
import org.nanopub.extra.services.ApiResponse;
23
import org.nanopub.extra.services.QueryRef;
24

25
import java.util.ArrayList;
26
import java.util.HashSet;
27
import java.util.List;
28
import java.util.Set;
29

30
/**
31
 * This class represents a page for a maintained resource.
32
 */
33
public class ResourcePartPage extends NanodashPage {
34

35
    /**
36
     * The mount path for this page.
37
     */
38
    public static final String MOUNT_PATH = "/part";
39

40
    /**
41
     * {@inheritDoc}
42
     */
43
    @Override
44
    public String getMountPath() {
45
        return MOUNT_PATH;
×
46
    }
47

48
    /**
49
     * Profiled resource (Space or MaintainedResource) object with the data shown on this page.
50
     */
51
    private ProfiledResource profiledResource;
52

53
    public ResourcePartPage(final PageParameters parameters) {
54
        super(parameters);
×
55

56
        final String id = parameters.get("id").toString();
×
57
        final String contextId = parameters.get("context").toString();
×
58
        final String nanopubId;
59
        String label = id.replaceFirst("^.*[#/]([^#/]+)$", "$1");
×
60
        String description = null;
×
61
        Set<IRI> classes = new HashSet<>();
×
62

63
        profiledResource = MaintainedResource.get(contextId);
×
64
        if (profiledResource == null) {
×
65
            if (Space.get(contextId) == null) {
×
66
                throw new IllegalArgumentException("Not a resource or space: " + contextId);
×
67
            }
68
            profiledResource = Space.get(contextId);
×
69
        }
70

71
        QueryRef getDefQuery = new QueryRef("get-term-definitions", "term", id);
×
72
        for (IRI userIri : profiledResource.getSpace().getUsers()) {
×
73
            for (String pubkey : User.getUserData().getPubkeyhashes(userIri, true)) {
×
74
                getDefQuery.getParams().put("pubkey", pubkey);
×
75
            }
×
76
        }
×
77

78
        ApiResponse getDefResp = ApiCache.retrieveResponse(getDefQuery);
×
79
        if (getDefResp == null) {
×
80
            getDefResp = QueryApiAccess.forcedGet(getDefQuery);
×
81
        }
82
        if (getDefResp != null && !getDefResp.getData().isEmpty()) {
×
83
            nanopubId = getDefResp.getData().iterator().next().get("np");
×
84

85
            Nanopub nanopub = Utils.getAsNanopub(nanopubId);
×
86
            for (Statement st : nanopub.getAssertion()) {
×
87
                if (!st.getSubject().stringValue().equals(id)) {
×
88
                    continue;
×
89
                }
90
                if (st.getPredicate().equals(RDFS.LABEL)) {
×
91
                    label = st.getObject().stringValue();
×
92
                }
93
                if (st.getPredicate().equals(SKOS.DEFINITION) || st.getPredicate().equals(DCTERMS.DESCRIPTION) || st.getPredicate().equals(RDFS.COMMENT)) {
×
94
                    description = st.getObject().stringValue();
×
95
                }
96
                if (st.getPredicate().equals(RDF.TYPE) && st.getObject() instanceof IRI objIri) {
×
97
                    classes.add(objIri);
×
98
                }
99
            }
×
100
        } else {
×
101
            nanopubId = null;
×
102
        }
103
//        if (getDefResp == null || getDefResp.getData().isEmpty()) {
104
//            throw new RestartResponseException(ExplorePage.class, parameters);
105
//        }
106

107
        if (description != null) {
×
108
            add(new Label("description", description));
×
109
        } else {
110
            add(new Label("description").setVisible(false));
×
111
        }
112

113
        List<ProfiledResource> superSpaces = profiledResource.getSpace().getAllSuperSpacesUntilRoot();
×
114
        if (profiledResource instanceof MaintainedResource) {
×
115
            superSpaces.add(profiledResource.getSpace());
×
116
        }
117
        superSpaces.add(profiledResource);
×
118
        List<NanodashPageRef> breadCrumb = new ArrayList<>(superSpaces.stream().map(ss -> new NanodashPageRef(SpacePage.class, new PageParameters().add("id", ss.getId()), ss.getLabel())).toList());
×
119
        breadCrumb.add(new NanodashPageRef(ResourcePartPage.class, new PageParameters().add("id", id).add("context", contextId).add("label", label), label));
×
120
        NanodashPageRef[] breadCrumbArray = breadCrumb.toArray(new NanodashPageRef[0]);
×
121
        add(new TitleBar("titlebar", this, null,
×
122
                breadCrumbArray
123
        ));
124

125
        add(new Label("pagetitle", label + " (resource part) | nanodash"));
×
126
        add(new Label("name", label));
×
127
        add(new BookmarkablePageLink<Void>("id", ExplorePage.class, parameters.set("label", label)).setBody(Model.of(id)));
×
128
        add(new BookmarkablePageLink<Void>("np", ExplorePage.class, new PageParameters().set("id", nanopubId == null ? id : nanopubId)));
×
129

130
        // TODO Improve this code, e.g. make Space a subclass of MaintainedResource or otherwise refactor:
131
        // we now use the ProfileResource abstraction, but the code still has to be imprved
132
        if (profiledResource != null) {
×
133
            final List<AbstractLink> viewButtons = new ArrayList<>();
×
134
            AbstractLink addViewButton = new BookmarkablePageLink<NanodashPage>("button", PublishPage.class, new PageParameters()
×
135
                    .set("template", "https://w3id.org/np/RAxERE0cQ9jLQZ5VjeA-1v3XnE9ugxLpFG8vpkAd5FqHE")
×
136
                    .set("param_displayType", KPXL_TERMS.PART_LEVEL_VIEW_DISPLAY)
×
137
                    .set("param_resource", profiledResource.getId())
×
138
                    .set("context", profiledResource.getId())
×
139
            );
140
            addViewButton.setBody(Model.of("+ view"));
×
141
            viewButtons.add(addViewButton);
×
142

143
            final String nanopubRef = nanopubId == null ? "x:" : nanopubId;
×
144
            if (profiledResource.isDataInitialized()) {
×
145
                add(new ViewList("views", profiledResource, id, nanopubRef, classes));
×
146
                add(new ButtonList("view-buttons", profiledResource.getSpace(), null, null, viewButtons));
×
147
            } else {
148
                add(new AjaxLazyLoadPanel<Component>("views") {
×
149

150
                    @Override
151
                    public Component getLazyLoadComponent(String markupId) {
152
                        return new ViewList(markupId, profiledResource, id, nanopubRef, classes);
×
153
                    }
154

155
                    @Override
156
                    protected boolean isContentReady() {
157
                        return profiledResource.isDataInitialized();
×
158
                    }
159

160
                });
161
                add(new AjaxLazyLoadPanel<Component>("view-buttons") {
×
162

163
                    @Override
164
                    public Component getLazyLoadComponent(String markupId) {
165
                        return new ButtonList(markupId, profiledResource.getSpace(), null, null, viewButtons);
×
166
                    }
167

168
                    @Override
169
                    protected boolean isContentReady() {
170
                        return profiledResource.isDataInitialized();
×
171
                    }
172

173
                    public Component getLoadingComponent(String id) {
174
                        return new Label(id).setVisible(false);
×
175
                    }
176

177
                });
178
            }
179
        } else {
×
180
            // TODO Ugly code duplication (see above):
181

182
            final List<AbstractLink> viewButtons = new ArrayList<>();
×
183
            AbstractLink addViewButton = new BookmarkablePageLink<NanodashPage>("button", PublishPage.class, new PageParameters()
×
184
                    .set("template", "https://w3id.org/np/RAxERE0cQ9jLQZ5VjeA-1v3XnE9ugxLpFG8vpkAd5FqHE")
×
185
                    .set("param_displayType", KPXL_TERMS.PART_LEVEL_VIEW_DISPLAY)
×
186
                    .set("param_resource", profiledResource.getSpace().getId())
×
187
                    .set("context", profiledResource.getSpace().getId())
×
188
            );
189
            addViewButton.setBody(Model.of("+ view"));
×
190
            viewButtons.add(addViewButton);
×
191

192
            if (profiledResource.getSpace().isDataInitialized()) {
×
193
                add(new ViewList("views", profiledResource.getSpace(), id, nanopubId, classes));
×
194
                add(new ButtonList("view-buttons", profiledResource.getSpace(), null, null, viewButtons));
×
195
            } else {
196
                add(new AjaxLazyLoadPanel<Component>("views") {
×
197

198
                    @Override
199
                    public Component getLazyLoadComponent(String markupId) {
200
                        return new ViewList(markupId, profiledResource.getSpace(), id, nanopubId, classes);
×
201
                    }
202

203
                    @Override
204
                    protected boolean isContentReady() {
205
                        return profiledResource.getSpace().isDataInitialized();
×
206
                    }
207

208
                });
209
                add(new AjaxLazyLoadPanel<Component>("view-buttons") {
×
210

211
                    @Override
212
                    public Component getLazyLoadComponent(String markupId) {
213
                        return new ButtonList(markupId, profiledResource.getSpace(), null, null, viewButtons);
×
214
                    }
215

216
                    @Override
217
                    protected boolean isContentReady() {
218
                        return profiledResource.getSpace().isDataInitialized();
×
219
                    }
220

221
                    public Component getLoadingComponent(String id) {
222
                        return new Label(id).setVisible(false);
×
223
                    }
224

225
                });
226
            }
227
        }
228
    }
×
229

230
    /**
231
     * Checks if auto-refresh is enabled for this page.
232
     *
233
     * @return true if auto-refresh is enabled, false otherwise
234
     */
235
    protected boolean hasAutoRefreshEnabled() {
236
        return true;
×
237
    }
238

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