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

knowledgepixels / nanodash / 27630621274

16 Jun 2026 03:58PM UTC coverage: 26.774% (-0.2%) from 26.963%
27630621274

Pull #484

github

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

1545 of 6783 branches covered (22.78%)

Branch coverage included in aggregate %.

3414 of 11739 relevant lines covered (29.08%)

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

3
import com.google.common.collect.ArrayListMultimap;
4
import com.google.common.collect.Multimap;
5
import com.knowledgepixels.nanodash.QueryApiAccess;
6
import com.knowledgepixels.nanodash.View;
7
import com.knowledgepixels.nanodash.ViewDisplay;
8
import com.knowledgepixels.nanodash.domain.Space;
9
import org.apache.wicket.markup.html.panel.Panel;
10
import org.nanopub.extra.services.QueryRef;
11

12
/**
13
 * The "About" tab body for a space: its structure (assigned presets, roles, and
14
 * configured view displays; issue #302), its users (members and observers), and
15
 * its sub-units (sub-spaces and maintained resources). Rendered as views
16
 * (query result tables) rather than the live view content.
17
 */
18
public class AboutSpacePanel extends Panel {
19

20
    /**
21
     * The "ℹ️ Info" view: key-value facts about the space (type, alternative IDs,
22
     * dates, latest and root definition). Also shown on the Content tab; surfaced
23
     * here at the top of the About tab. Its query needs both the space IRI
24
     * ({@code space}) and the space's nanopub ({@code spaceNp}) so it can scope to
25
     * a single space-ref.
26
     */
27
    public static final String SPACE_INFO_VIEW = "https://w3id.org/np/RAIh3Cq4K99abRiL2xZphMYTjByvZYATK-d--dI3DD05g/space-info-view-kind";
28

29
    /**
30
     * View that lists all assigned view displays of a resource (built on the
31
     * get-view-displays query Nanodash uses internally). Shown on About tabs
32
     * instead of rendering the assigned views themselves.
33
     */
34
    public static final String VIEW_DISPLAYS_VIEW = "https://w3id.org/np/RA2Wxm80NAzOrXCjIZK9oVJ2vzbycuQtT3wLSGTX5vDVw/view-displays-view";
35

36
    /**
37
     * View listing the presets assigned to a resource (issue #302).
38
     */
39
    public static final String PRESET_ASSIGNMENTS_VIEW = "https://w3id.org/np/RA1kCQYXscKPY_qDvQ-WAKhoVomrTQLSt91JSD4Y03CKI/preset-assignments-view";
40

41
    /**
42
     * View listing a space's assigned roles as a table (role, schema:name, and a
43
     * count of how many of the space's users hold each role), built on the
44
     * list-space-roles query. The built-in Admin role is always the first row.
45
     */
46
    public static final String SPACE_ROLES_VIEW = "https://w3id.org/np/RActRjB7sOPegsSWdlJPNXvEfqEuomlO9HvjmBuXMqfQw/space-roles-view";
47

48
    /**
49
     * View listing a space's members (admins, maintainers, members) with their
50
     * highest role tier, built on the list-space-members query. Observer-tier
51
     * members are excluded.
52
     */
53
    public static final String MEMBERS_VIEW = "https://w3id.org/np/RAFmrcEqniX7mqrZQ8c4OCqjU-3wwKjLhE2glXAZKFNT0/space-members-view";
54

55
    /**
56
     * View listing a space's non-approved role claims (agents holding an
57
     * admin/maintainer/member-tier role instantiation that is not in the
58
     * validated state — a self-assigned or otherwise ungranted claim awaiting
59
     * approval), built on the list-space-non-approved query. Carries a per-row
60
     * "approve" action (visible to members and above) that re-asserts the same
61
     * role triple, signed by the approver.
62
     */
63
    public static final String NON_APPROVED_VIEW = "https://w3id.org/np/RAk5nU4XXK1-CzrE2mcSLcRmJXnANVWgkQ2dNUQzDVR64/pending-members-view";
64

65
    /**
66
     * View listing a space's observers (members whose highest tier is observer,
67
     * i.e. holding no admin/maintainer/member role), built on the
68
     * list-space-observers query.
69
     */
70
    public static final String OBSERVERS_VIEW = "https://w3id.org/np/RA7uYe4WmsJCk3NaMTE8p0YofcMcRfjLyM8PGLaADkH18/space-observers-view";
71

72
    /**
73
     * View listing a space's direct sub-spaces with their types, built on the
74
     * list-sub-spaces query.
75
     */
76
    public static final String SUB_SPACES_VIEW = "https://w3id.org/np/RAoO4uYnSJXCHr0F5uVC5sYpkD4HOh-lsHQj4k3epqeH0/sub-spaces-view";
77

78
    /**
79
     * View listing the resources maintained by a space, built on the
80
     * list-maintained-resources query.
81
     */
82
    public static final String MAINTAINED_RESOURCES_VIEW = "https://w3id.org/np/RA4mk84QDZ4njO5N1sryJ5_wbyG7bAisL4BIAsNoISt-Y/maintained-resources-view";
83

84
    /**
85
     * @param id    the Wicket markup id
86
     * @param space the space whose About listings to render
87
     */
88
    public AboutSpacePanel(String id, Space space) {
89
        this(id, space, null);
×
90
    }
×
91

92
    /**
93
     * @param id            the Wicket markup id
94
     * @param space         the space whose About listings to render
95
     * @param effectiveRoot the root nanopub of the specific ref to scope the ref-aware views
96
     *                      (Info, Observers) to, or null to use the representative ref. See
97
     *                      docs/space-ref-identity.md.
98
     */
99
    public AboutSpacePanel(String id, Space space, String effectiveRoot) {
100
        super(id);
×
101

102
        // "Structure" section: key-value info, presets, assigned roles, view displays.
103

104
        // The info view leads the section (to the left of the presets). Its query is
105
        // scoped to a single space-ref, so it needs both the space IRI and the ref's
106
        // nanopub — bind them as separate params. When viewing a specific claimant the
107
        // effectiveRoot pins it to that ref's root definition.
108
        View infoView = View.get(SPACE_INFO_VIEW);
×
109
        Multimap<String, String> infoParams = ArrayListMultimap.create();
×
110
        infoParams.put("space", space.getId());
×
111
        infoParams.put("spaceNp", effectiveRoot != null ? effectiveRoot : space.getNanopubId());
×
112
        add(QueryResultTableBuilder.create("info", new QueryRef(infoView.getQuery().getQueryId(), infoParams), new ViewDisplay(infoView)).resourceWithProfile(space).id(space.getId()).contextId(space.getId()).build());
×
113

114
        View presetsView = View.get(PRESET_ASSIGNMENTS_VIEW);
×
115
        add(QueryResultTableBuilder.create("presets", new QueryRef(presetsView.getQuery().getQueryId(), "resource", space.getId()), new ViewDisplay(presetsView)).resourceWithProfile(space).id(space.getId()).contextId(space.getId()).build());
×
116

117
        View rolesView = View.get(SPACE_ROLES_VIEW);
×
118
        // Pass the space as resource/context so the roles view's per-entry action
119
        // button (publish a role assignment) renders with param_space prefilled,
120
        // mirroring the "+" button on the content tab's role list. postPublishTab
121
        // keeps the user on the About tab after publishing a role/assignment, so
122
        // they see the updated roles list (the presets/view-display views
123
        // intentionally fall through to the Content tab, where their effect shows).
124
        add(QueryResultTableBuilder.create("roles", new QueryRef(rolesView.getQuery().getQueryId(), "space", space.getId()), new ViewDisplay(rolesView)).resourceWithProfile(space).id(space.getId()).contextId(space.getId()).postPublishTab("about").build());
×
125

126
        View vdView = View.get(VIEW_DISPLAYS_VIEW);
×
127
        add(QueryResultTableBuilder.create("viewdisplays", new QueryRef(vdView.getQuery().getQueryId(), "resource", space.getId()), new ViewDisplay(vdView)).resourceWithProfile(space).id(space.getId()).contextId(space.getId()).build());
×
128

129
        // "Users" section: admins/maintainers/members, then observers.
130

131
        View membersView = View.get(MEMBERS_VIEW);
×
132
        add(QueryResultTableBuilder.create("members", new QueryRef(membersView.getQuery().getQueryId(), "space", space.getId()), new ViewDisplay(membersView)).build());
×
133

134
        // Non-approved (pending) higher-tier role claims, between members and observers.
135
        // Ref-scoped (root_np), like the observers table below; there is no IRI-keyed
136
        // fallback query, so when the ref root is unknown (pre-v3 data) the table is driven
137
        // by the param-less query, which yields no rows. The space is passed as
138
        // resource/context so the per-row "approve" action pre-fills param_space; the agent
139
        // and role template come from the row via the view's query mappings. postPublishTab
140
        // returns the approver to the About tab, where the approved member now shows.
141
        View nonApprovedView = View.get(NON_APPROVED_VIEW);
×
142
        String nonApprovedRefRoot = space.getRefRootId();
×
143
        QueryRef nonApprovedQuery = (nonApprovedRefRoot != null && !nonApprovedRefRoot.isEmpty())
×
144
                ? new QueryRef(QueryApiAccess.LIST_SPACE_NON_APPROVED_REF, "root_np", nonApprovedRefRoot)
×
145
                : new QueryRef(QueryApiAccess.LIST_SPACE_NON_APPROVED_REF);
×
146
        add(QueryResultTableBuilder.create("pendingmembers", nonApprovedQuery, new ViewDisplay(nonApprovedView)).resourceWithProfile(space).id(space.getId()).contextId(space.getId()).postPublishTab("about").build());
×
147

148
        View observersView = View.get(OBSERVERS_VIEW);
×
149
        // Drive the Observers table from the ref-scoped query that also includes un-introduced
150
        // self-declared observers (flagged via the headerless ⚠️ column), instead of the view's
151
        // own validated-only query. The view nanopub is left untouched. Falls back to the view's
152
        // IRI-keyed query when the ref root is unknown (pre-v3 data). See docs/space-ref-identity.md.
153
        String observersRefRoot = effectiveRoot != null ? effectiveRoot : space.getRefRootId();
×
154
        QueryRef observersQuery = (observersRefRoot != null && !observersRefRoot.isEmpty())
×
155
                ? new QueryRef(QueryApiAccess.LIST_SPACE_OBSERVERS_REF, "root_np", observersRefRoot)
×
156
                : new QueryRef(observersView.getQuery().getQueryId(), "space", space.getId());
×
157
        add(QueryResultTableBuilder.create("observers", observersQuery, new ViewDisplay(observersView)).build());
×
158

159
        // "Sub-units" section: sub-spaces and maintained resources, side by side
160
        // (both views declare 6/12 width). resourceWithProfile/id/contextId let the
161
        // views' "add" actions pre-fill the new sub-space's IRI under this space's
162
        // namespace and this space as the maintainer, respectively; postPublishTab
163
        // returns the user here, where the new entry shows up.
164

165
        View subSpacesView = View.get(SUB_SPACES_VIEW);
×
166
        add(QueryResultListBuilder.create("subspaces", new QueryRef(subSpacesView.getQuery().getQueryId(), "space", space.getId()), new ViewDisplay(subSpacesView)).resourceWithProfile(space).id(space.getId()).contextId(space.getId()).postPublishTab("about").build());
×
167

168
        View maintainedResourcesView = View.get(MAINTAINED_RESOURCES_VIEW);
×
169
        add(QueryResultListBuilder.create("maintainedresources", new QueryRef(maintainedResourcesView.getQuery().getQueryId(), "space", space.getId()), new ViewDisplay(maintainedResourcesView)).resourceWithProfile(space).id(space.getId()).contextId(space.getId()).postPublishTab("about").build());
×
170
    }
×
171

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