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

knowledgepixels / nanodash / 22760940566

06 Mar 2026 11:11AM UTC coverage: 15.877% (+0.009%) from 15.868%
22760940566

push

github

web-flow
Merge pull request #379 from knowledgepixels/222-profile-logo

Users can set a profile picture

705 of 5393 branches covered (13.07%)

Branch coverage included in aggregate %.

1741 of 10013 relevant lines covered (17.39%)

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

3
import com.knowledgepixels.nanodash.NanodashPageRef;
4
import com.knowledgepixels.nanodash.QueryApiAccess;
5
import com.knowledgepixels.nanodash.Utils;
6
import com.knowledgepixels.nanodash.component.*;
7
import com.knowledgepixels.nanodash.connector.ConnectorConfig;
8
import com.knowledgepixels.nanodash.connector.GenOverviewPage;
9
import com.knowledgepixels.nanodash.domain.AbstractResourceWithProfile;
10
import com.knowledgepixels.nanodash.domain.MaintainedResource;
11
import com.knowledgepixels.nanodash.domain.Space;
12
import com.knowledgepixels.nanodash.repository.MaintainedResourceRepository;
13
import com.knowledgepixels.nanodash.repository.SpaceRepository;
14
import com.knowledgepixels.nanodash.vocabulary.KPXL_TERMS;
15
import org.apache.wicket.Component;
16
import org.apache.wicket.RestartResponseException;
17
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
18
import org.apache.wicket.markup.html.basic.Label;
19
import org.apache.wicket.markup.html.link.AbstractLink;
20
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
21
import org.apache.wicket.model.Model;
22
import org.apache.wicket.request.mapper.parameter.PageParameters;
23
import org.nanopub.Nanopub;
24
import org.nanopub.extra.services.QueryRef;
25

26
import java.time.LocalDateTime;
27
import java.time.ZoneId;
28
import java.time.format.DateTimeFormatter;
29
import java.util.ArrayList;
30
import java.util.List;
31

32
/**
33
 * The SpacePage class represents a space page in the Nanodash application.
34
 */
35
public class SpacePage extends NanodashPage {
36

37
    /**
38
     * The mount path for this page.
39
     */
40
    public static final String MOUNT_PATH = "/space";
41

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

50
    /**
51
     * Space object with the data shown on this page.
52
     */
53
    private final Space space;
54
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
×
55

56
    /**
57
     * Constructor for the SpacePage.
58
     *
59
     * @param parameters the page parameters
60
     */
61
    public SpacePage(final PageParameters parameters) {
62
        super(parameters);
×
63

64
        space = resolveSpace(parameters);
×
65
        space.triggerDataUpdate();
×
66

67
        Nanopub np = space.getNanopub();
×
68

69
        List<AbstractResourceWithProfile> superSpaces = space.getAllSuperSpacesUntilRoot();
×
70
        if (superSpaces.isEmpty()) {
×
71
            add(new TitleBar("titlebar", this, null,
×
72
                    new NanodashPageRef(SpacePage.class, new PageParameters().add("id", space.getId()), space.getLabel())
×
73
            ));
74
        } else {
75
            superSpaces.add(space);
×
76
            add(new TitleBar("titlebar", this, null,
×
77
                    superSpaces.stream().map(ss -> new NanodashPageRef(SpacePage.class, new PageParameters().add("id", ss.getId()), ss.getLabel())).toArray(NanodashPageRef[]::new)
×
78
            ));
79
        }
80

81
        add(new JustPublishedMessagePanel("justPublishedMessage", parameters));
×
82

83
        add(new Label("pagetitle", space.getLabel() + " (space) | nanodash"));
×
84
        add(new Label("spacename", space.getLabel()));
×
85
        add(new Label("spacetype", space.getTypeLabel()));
×
86
        add(new ExternalLinkWithActionsPanel("id", Model.of(space.getId()), Model.of(space.getLabel()), np.getUri()));
×
87

88
        add(new ItemListPanel<String>(
×
89
                "altids",
90
                "Alternative IDs:",
91
                space.getAltIDs(),
×
92
                i -> new ItemListElement("item", ExplorePage.class, new PageParameters().set("id", i), i)
×
93
        ));
94

95
        if (space.getStartDate() != null) {
×
96
            String dateString;
97
            LocalDateTime dt = LocalDateTime.ofInstant(space.getStartDate().toInstant(), ZoneId.systemDefault());
×
98
            dateString = DATE_FORMATTER.format(dt);
×
99
            if (space.getEndDate() != null) {
×
100
                dt = LocalDateTime.ofInstant(space.getEndDate().toInstant(), ZoneId.systemDefault());
×
101
                String endDate = DATE_FORMATTER.format(dt);
×
102
                if (!dateString.equals(endDate)) {
×
103
                    dateString += " - " + endDate;
×
104
                }
105
            }
106
            add(new Label("date", dateString));
×
107
        } else {
×
108
            add(new Label("date").setVisible(false));
×
109
        }
110

111
        add(new Label("description", "<span>" + Utils.sanitizeHtml(space.getDescription()) + "</span>").setEscapeModelStrings(false));
×
112

113
        final List<AbstractLink> pinButtons = new ArrayList<>();
×
114

115
        AbstractLink addPinnedTemplateButton = new BookmarkablePageLink<NanodashPage>("button", PublishPage.class, new PageParameters()
×
116
                .set("template", "https://w3id.org/np/RA2YwreWrGW9HkzWls8jgwaIINKUB5ZTli1aFKQt13dUk")
×
117
                .set("template-version", "latest")
×
118
                .set("param_space", space.getId())
×
119
                .set("context", space.getId())
×
120
        );
121
        addPinnedTemplateButton.setBody(Model.of("+ template"));
×
122
        pinButtons.add(addPinnedTemplateButton);
×
123

124
        AbstractLink addPinnedQueryButton = new BookmarkablePageLink<NanodashPage>("button", PublishPage.class, new PageParameters()
×
125
                .set("template", "https://w3id.org/np/RAuLESdeRUlk1GcTwvzVXShiBMI0ntJs2DL2Bm5DzW_ZQ")
×
126
                .set("template-version", "latest")
×
127
                .set("param_space", space.getId())
×
128
        );
129
        addPinnedQueryButton.setBody(Model.of("+ query"));
×
130
        pinButtons.add(addPinnedQueryButton);
×
131

132
        if (space.isDataInitialized()) {
×
133
            add(new PinGroupList("pin-groups", space));
×
134
            add(new ButtonList("pin-buttons", space, null, null, pinButtons));
×
135
        } else {
136
            add(new AjaxLazyLoadPanel<Component>("pin-groups") {
×
137

138
                @Override
139
                public Component getLazyLoadComponent(String markupId) {
140
                    return new PinGroupList(markupId, space);
×
141
                }
142

143
                @Override
144
                protected boolean isContentReady() {
145
                    return space.isDataInitialized();
×
146
                }
147

148
            });
149
            add(new AjaxLazyLoadPanel<Component>("pin-buttons") {
×
150

151
                @Override
152
                public Component getLazyLoadComponent(String markupId) {
153
                    return new ButtonList(markupId, space, null, null, pinButtons);
×
154
                }
155

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

161
                public Component getLoadingComponent(String id) {
162
                    return new Label(id).setVisible(false);
×
163
                }
164

165
            });
166
        }
167

168
        final List<AbstractLink> viewButtons = new ArrayList<>();
×
169
        viewButtons.add(new AddViewDisplayButton("button",
×
170
                "https://w3id.org/np/RAwPPxDxkXwgWwYhmvzi6SUs8djPZS4IgWJdp2G0blqoQ",
171
                "latest",
172
                space.getId(),
×
173
                space.getId(),
×
174
                new PageParameters()
175
                        .set("param_appliesToResource", space.getId())
×
176
                        .set("refresh-upon-publish", space.getId())
×
177
        ));
178

179

180
        if (space.isDataInitialized()) {
×
181
            add(new ViewList("views", space, null, null, null, space, viewButtons));
×
182
        } else {
183
            add(new AjaxLazyLoadPanel<Component>("views") {
×
184

185
                @Override
186
                public Component getLazyLoadComponent(String markupId) {
187
                    return new ViewList(markupId, space, null, null, null, space, viewButtons);
×
188
                }
189

190
                @Override
191
                protected boolean isContentReady() {
192
                    return space.isDataInitialized();
×
193
                }
194

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

200
            });
201
        }
202

203
        add(new ItemListPanel<>(
×
204
                        "roles",
205
                        "Roles:",
206
                        space::isDataInitialized,
×
207
                        space::getRoles,
×
208
                        r -> new ItemListElement("item", ExplorePage.class, new PageParameters().set("id", r.getRole().getId()), r.getRole().getName(), null, Utils.getAsNanopub(r.getNanopubUri()))
×
209
                )
210
                        .makeInline()
×
211
                        .setProfiledResource(space)
×
212
                        .addAdminButton("+", PublishPage.class, new PageParameters()
×
213
                                .set("template", "https://w3id.org/np/RARBzGkEqiQzeiHk0EXFcv9Ol1d-17iOh9MoFJzgfVQDc")
×
214
                                .set("param_space", space.getId())
×
215
                                .set("refresh-upon-publish", space.getId())
×
216
                                .set("template-version", "latest")
×
217
                        )
218
        );
219

220
        if (space.isDataInitialized()) {
×
221
            add(new SpaceUserList("user-lists", space));
×
222
        } else {
223
            add(new AjaxLazyLoadPanel<Component>("user-lists") {
×
224

225
                @Override
226
                public Component getLazyLoadComponent(String markupId) {
227
                    return new SpaceUserList(markupId, space);
×
228
                }
229

230
                @Override
231
                protected boolean isContentReady() {
232
                    return space.isDataInitialized();
×
233
                }
234

235
            });
236
        }
237

238
        addSubspacePanel("Alliance", true);
×
239
        addSubspacePanel("Consortium", false);
×
240
        addSubspacePanel("Organization", true);
×
241
        addSubspacePanel("Taskforce", false);
×
242
        addSubspacePanel("Division", true);
×
243
        addSubspacePanel("Taskunit", false);
×
244
        addSubspacePanel("Group", true);
×
245
        addSubspacePanel("Project", false);
×
246
        addSubspacePanel("Program", true);
×
247
        addSubspacePanel("Initiative", false);
×
248
        addSubspacePanel("Outlet", true);
×
249
        addSubspacePanel("Campaign", false);
×
250
        addSubspacePanel("Community", true);
×
251
        addSubspacePanel("Event", false);
×
252

253
        add(new ItemListPanel<MaintainedResource>(
×
254
                "resources",
255
                "Resources",
256
                new QueryRef(QueryApiAccess.GET_MAINTAINED_RESOURCES),
257
                (apiResponse) -> {
258
                    MaintainedResourceRepository.get().ensureLoaded();
×
259
                    return MaintainedResourceRepository.get().findResourcesBySpace(space);
×
260
                },
261
                (resource) -> new ItemListElement("item", MaintainedResourcePage.class, new PageParameters().set("id", resource.getId()), resource.getLabel())
×
262
        )
263
                .setProfiledResource(space)
×
264
                .setReadyFunction(space::isDataInitialized)
×
265
                .addMemberButton("+", PublishPage.class, new PageParameters()
×
266
                        .set("template", "https://w3id.org/np/RA25VaVFxSOgKEuZ70gFINn-N3QV4Pf62-IMK_SWkg-c8")
×
267
                        .set("param_space", space.getId())
×
268
                        .set("context", space.getId())
×
269
                        .set("refresh-upon-publish", "maintainedResources")
×
270
                        .set("template-version", "latest")
×
271
                ));
272

273
        String shortId = space.getId().replace("https://w3id.org/spaces/", "");
×
274
        ConnectorConfig cc = ConnectorConfig.get(shortId);
×
275
        if (cc != null) {
×
276
            add(new BookmarkablePageLink<Void>("content-button", GenOverviewPage.class, new PageParameters().set("journal", shortId)).setBody(Model.of("Nanopublication Submissions")));
×
277
        } else {
278
            add(new Label("content-button").setVisible(false));
×
279
        }
280
    }
×
281

282
    private void addSubspacePanel(String type, boolean openEnded) {
283
        String typePl = type + "s";
×
284
        typePl = typePl.replaceFirst("ys$", "ies");
×
285

286
        add(new ItemListPanel<>(
×
287
                        typePl.toLowerCase(),
×
288
                        typePl,
289
                        SpaceRepository.get().findSubspaces(space, KPXL_TERMS.NAMESPACE + type),
×
290
                        (space) -> new ItemListElement("item", SpacePage.class, new PageParameters().set("id", space), space.getLabel())
×
291
                )
292
                        .setProfiledResource(space)
×
293
                        .setReadyFunction(space::isDataInitialized)
×
294
                        .addMemberButton("+", PublishPage.class, new PageParameters()
×
295
                                .set("template", openEnded ? "https://w3id.org/np/RA7dQfmndqKmooQ4PlHyQsAql9i2tg_8GLHf_dqtxsGEQ" : "https://w3id.org/np/RAaE7NP9RNIx03AHZxanFMdtUuaTfe50ns5tHhpEVloQ4")
×
296
                                .set("param_type", KPXL_TERMS.NAMESPACE + type)
×
297
                                .set("param_space", space.getId().replaceFirst("https://w3id.org/spaces/", "") + "/<SET-SUFFIX>")
×
298
                                .set("refresh-upon-publish", "spaces")
×
299
                                .set("template-version", "latest"))
×
300
        );
301
    }
×
302

303
    /**
304
     * Checks if auto-refresh is enabled for this page.
305
     *
306
     * @return true if auto-refresh is enabled, false otherwise
307
     */
308
    protected boolean hasAutoRefreshEnabled() {
309
        return true;
×
310
    }
311

312
    /**
313
     * Resolves the {@link Space} from the repository, or redirects as needed.
314
     *
315
     * @param parameters page parameters containing the space {@code id}
316
     * @return the resolved {@link Space}; never {@code null}
317
     * @throws RestartResponseException if the id belongs to a {@link MaintainedResource}
318
     * @throws IllegalArgumentException if the id cannot be resolved to any known resource
319
     */
320
    private Space resolveSpace(PageParameters parameters) {
321
        String id = parameters.get("id").toString();
×
322
        Space resolved = SpaceRepository.get().findById(id);
×
323
        if (resolved == null) {
×
324
            if (MaintainedResourceRepository.get().findById(id) != null) {
×
325
                throw new RestartResponseException(MaintainedResourcePage.class, parameters);
×
326
            }
327
            throw new IllegalArgumentException("No space or resource found for id: " + id);
×
328
        }
329

330
        return resolved;
×
331
    }
332

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