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

knowledgepixels / nanodash / 28379052105

29 Jun 2026 02:22PM UTC coverage: 28.039% (-0.01%) from 28.052%
28379052105

push

github

web-flow
Merge pull request #519 from knowledgepixels/feat/term-namespace-part-fallback

feat: show namespace-declaring resource's part view for plain terms

1721 of 6995 branches covered (24.6%)

Branch coverage included in aggregate %.

3605 of 12000 relevant lines covered (30.04%)

4.45 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.ApiCache;
4
import com.knowledgepixels.nanodash.NanodashPageRef;
5
import com.knowledgepixels.nanodash.QueryApiAccess;
6
import com.knowledgepixels.nanodash.Utils;
7
import com.knowledgepixels.nanodash.component.*;
8
import com.knowledgepixels.nanodash.domain.AbstractResourceWithProfile;
9
import com.knowledgepixels.nanodash.domain.IndividualAgent;
10
import com.knowledgepixels.nanodash.domain.MaintainedResource;
11
import com.knowledgepixels.nanodash.domain.User;
12
import com.knowledgepixels.nanodash.repository.MaintainedResourceRepository;
13
import com.knowledgepixels.nanodash.repository.SpaceRepository;
14
import org.apache.wicket.Component;
15
import org.apache.wicket.RestartResponseException;
16
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
17
import org.apache.wicket.markup.html.WebMarkupContainer;
18
import org.apache.wicket.markup.html.basic.Label;
19
import org.apache.wicket.markup.html.panel.EmptyPanel;
20
import org.apache.wicket.model.Model;
21
import org.apache.wicket.request.mapper.parameter.PageParameters;
22
import org.eclipse.rdf4j.model.IRI;
23
import org.eclipse.rdf4j.model.Statement;
24
import org.eclipse.rdf4j.model.util.Values;
25
import org.eclipse.rdf4j.model.vocabulary.RDF;
26
import org.eclipse.rdf4j.model.vocabulary.RDFS;
27
import org.nanopub.Nanopub;
28
import org.nanopub.extra.services.ApiResponse;
29
import org.nanopub.extra.services.QueryRef;
30

31
import java.util.ArrayList;
32
import java.util.HashSet;
33
import java.util.List;
34
import java.util.Set;
35

36
/**
37
 * This class represents a page for a resource part in the context of a maintained resource, space, or user.
38
 */
39
public class ResourcePartPage extends NanodashPage {
40

41
    /**
42
     * The mount path for this page.
43
     */
44
    public static final String MOUNT_PATH = "/part";
45

46
    /**
47
     * {@inheritDoc}
48
     */
49
    @Override
50
    public String getMountPath() {
51
        return MOUNT_PATH;
×
52
    }
53

54
    /**
55
     * Resource with profile (Space or MaintainedResource) object with the data shown on this page.
56
     */
57
    private AbstractResourceWithProfile resourceWithProfile;
58

59
    /**
60
     * If the {@code id} in the given parameters falls under a namespace declared by a
61
     * maintained resource, forward to this page with that resource set as the
62
     * {@code context}. Does nothing if no maintained resource declares the namespace.
63
     *
64
     * @param parameters page parameters containing the {@code id} to resolve
65
     * @throws RestartResponseException if a containing maintained resource is found
66
     */
67
    public static void forwardToContainingResource(PageParameters parameters) {
68
        String id = parameters.get("id").toString();
×
69
        MaintainedResource containingResource = MaintainedResourceRepository.get().findByNamespace(MaintainedResource.getNamespace(id));
×
70
        if (containingResource != null) {
×
71
            PageParameters partParameters = new PageParameters(parameters);
×
72
            partParameters.set("context", containingResource.getId());
×
73
            throw new RestartResponseException(ResourcePartPage.class, partParameters);
×
74
        }
75
    }
×
76

77
    public ResourcePartPage(final PageParameters parameters) {
78
        super(parameters);
×
79

80
        final String id = parameters.get("id").toString();
×
81
        final String contextId = parameters.get("context").toString();
×
82
        final String nanopubId;
83
        String label = parameters.get("label").isEmpty() ? id.replaceFirst("^.*[#/]([^#/]+)$", "$1") : parameters.get("label").toString();
×
84
        Set<IRI> classes = new HashSet<>();
×
85

86
        resourceWithProfile = MaintainedResourceRepository.get().findById(contextId);
×
87
        if (resourceWithProfile == null) {
×
88
            if (SpaceRepository.get().findById(contextId) != null) {
×
89
                resourceWithProfile = SpaceRepository.get().findById(contextId);
×
90
            } else if (IndividualAgent.isUser(contextId)) {
×
91
                resourceWithProfile = IndividualAgent.get(contextId);
×
92
            } else {
93
                throw new IllegalArgumentException("Not a resource, space, or user: " + contextId);
×
94
            }
95
        }
96

97
        QueryRef getDefQuery = new QueryRef(QueryApiAccess.GET_TERM_DEFINITIONS, "term", id);
×
98
        if (resourceWithProfile.getSpace() != null) {
×
99
            for (IRI userIri : resourceWithProfile.getSpace().getUsers()) {
×
100
                for (String pubkey : User.getUserData().getPubkeyHashes(userIri, true)) {
×
101
                    getDefQuery.getParams().put("pubkey", pubkey);
×
102
                }
×
103
            }
×
104
        } else {
105
            for (String pubkey : User.getUserData().getPubkeyHashes(Utils.vf.createIRI(contextId), true)) {
×
106
                getDefQuery.getParams().put("pubkey", pubkey);
×
107
            }
×
108
        }
109

110
        ApiResponse getDefResp = ApiCache.retrieveResponseSync(getDefQuery, false);
×
111
        if (getDefResp != null && !getDefResp.getData().isEmpty()) {
×
112
            nanopubId = getDefResp.getData().iterator().next().get("np");
×
113

114
            Nanopub nanopub = Utils.getAsNanopub(nanopubId);
×
115
            for (Statement st : nanopub.getAssertion()) {
×
116
                if (!st.getSubject().stringValue().equals(id)) {
×
117
                    continue;
×
118
                }
119
                if (st.getPredicate().equals(RDFS.LABEL)) {
×
120
                    label = st.getObject().stringValue();
×
121
                }
122
                if (st.getPredicate().equals(RDF.TYPE) && st.getObject() instanceof IRI objIri) {
×
123
                    classes.add(objIri);
×
124
                }
125
            }
×
126
        } else {
×
127
            nanopubId = null;
×
128
        }
129
//        if (getDefResp == null || getDefResp.getData().isEmpty()) {
130
//            throw new RestartResponseException(ExplorePage.class, parameters);
131
//        }
132

133
        List<NanodashPageRef> breadCrumb;
134
        if (resourceWithProfile.getSpace() != null) {
×
135
            List<AbstractResourceWithProfile> superSpaces = resourceWithProfile.getSpace().getAllSuperSpacesUntilRoot();
×
136
            if (resourceWithProfile instanceof MaintainedResource) {
×
137
                superSpaces.add(resourceWithProfile.getSpace());
×
138
            }
139
            superSpaces.add(resourceWithProfile);
×
140
            breadCrumb = new ArrayList<>(superSpaces.stream().map(ss -> new NanodashPageRef(SpacePage.class, new PageParameters().add("id", ss.getId()), ss.getLabel())).toList());
×
141
        } else {
×
142
            breadCrumb = new ArrayList<>();
×
143
            breadCrumb.add(new NanodashPageRef(UserPage.class, new PageParameters().add("id", contextId), resourceWithProfile.getLabel()));
×
144
        }
145
        breadCrumb.add(new NanodashPageRef(ResourcePartPage.class, new PageParameters().add("id", id).add("context", contextId).add("label", label), label));
×
146
        NanodashPageRef[] breadCrumbArray = breadCrumb.toArray(new NanodashPageRef[0]);
×
147
        ResourceTabs.Tab activeTab = ResourceTabs.activeFromParam(parameters);
×
148
        add(new TitleBar("titlebar", this, null,
×
149
                breadCrumbArray
150
        ).setTabs(new ResourceTabs("tabs", "part", id, contextId, activeTab)));
×
151

152
        add(new Label("pagetitle", label + " (resource part) | nanodash"));
×
153
        add(new Label("name", label));
×
154
        add(new Label("titlesuffix", ResourceTabs.titleSuffix(activeTab)));
×
155
        add(new ExternalLinkWithActionsPanel("id", Model.of(id), Model.of(label), nanopubId == null ? Values.iri(id) : Values.iri(nanopubId)));
×
156

157
        final String nanopubRef = nanopubId == null ? "x:" : nanopubId;
×
158
        WebMarkupContainer contentContainer = new WebMarkupContainer("contentContainer");
×
159
        add(contentContainer);
×
160
        if (activeTab == ResourceTabs.Tab.ABOUT) {
×
161
            contentContainer.setVisible(false);
×
162
            // The panel constructor resolves view nanopubs over the network when they
163
            // aren't freshly cached, which would block the initial page render; the
164
            // view-id list must mirror the panel's View.get calls.
165
            add(LazyContentPanel.of("otherTab", markupId -> new AboutPartPanel(markupId, resourceWithProfile, id, classes),
×
166
                    AboutPartPanel.PART_INFO_VIEW, AboutResourcePanel.MAINTAINED_RESOURCE_PRESET_ASSIGNMENTS_VIEW, AboutPartPanel.PART_VIEW_DISPLAYS_VIEW));
167
        } else if (activeTab == ResourceTabs.Tab.EXPLORE) {
×
168
            contentContainer.setVisible(false);
×
169
            // The panel constructor resolves a view nanopub over the network when
170
            // it isn't freshly cached, which would block the initial page render.
171
            add(LazyContentPanel.of("otherTab", markupId -> new ExplorePanel(markupId, id),
×
172
                    ReferencesPage.REFERENCES_VIEW));
173
        } else if (activeTab == ResourceTabs.Tab.RAW) {
×
174
            contentContainer.setVisible(false);
×
175
            add(new DownloadRdfLinks("otherTab", "part", id, resourceWithProfile.getId()));
×
176
        } else {
177
            add(new EmptyPanel("otherTab").setVisible(false));
×
178
            if (resourceWithProfile.isDataInitialized()) {
×
179
                contentContainer.add(new ViewList("views", resourceWithProfile, id, nanopubRef, classes));
×
180
            } else {
181
                contentContainer.add(new AjaxLazyLoadPanel<Component>("views") {
×
182

183
                    @Override
184
                    public Component getLazyLoadComponent(String markupId) {
185
                        return new ViewList(markupId, resourceWithProfile, id, nanopubRef, classes);
×
186
                    }
187

188
                    @Override
189
                    protected boolean isContentReady() {
190
                        return resourceWithProfile.isDataInitialized();
×
191
                    }
192

193
                    @Override
194
                    public Component getLoadingComponent(String id) {
195
                        return new Label(id, "<div class=\"row-section\"><div class=\"col-12\">" + ResultComponent.getWaitIconHtml() + "</div></div>").setEscapeModelStrings(false);
×
196
                    }
197

198
                });
199
            }
200
        }
201
    }
×
202

203
    /**
204
     * Checks if auto-refresh is enabled for this page.
205
     *
206
     * @return true if auto-refresh is enabled, false otherwise
207
     */
208
    protected boolean hasAutoRefreshEnabled() {
209
        return true;
×
210
    }
211

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