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

knowledgepixels / nanodash / 20332936699

18 Dec 2025 09:53AM UTC coverage: 15.293% (+0.9%) from 14.405%
20332936699

push

github

tkuhn
fix(Space): Leaking Space objects fixed

592 of 5002 branches covered (11.84%)

Branch coverage included in aggregate %.

1577 of 9181 relevant lines covered (17.18%)

2.23 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.*;
4
import com.knowledgepixels.nanodash.component.*;
5
import com.knowledgepixels.nanodash.connector.ConnectorConfig;
6
import com.knowledgepixels.nanodash.connector.GenOverviewPage;
7
import com.knowledgepixels.nanodash.vocabulary.KPXL_TERMS;
8
import org.apache.wicket.Component;
9
import org.apache.wicket.RestartResponseException;
10
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
11
import org.apache.wicket.markup.html.basic.Label;
12
import org.apache.wicket.markup.html.link.AbstractLink;
13
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
14
import org.apache.wicket.model.Model;
15
import org.apache.wicket.request.mapper.parameter.PageParameters;
16
import org.nanopub.Nanopub;
17
import org.nanopub.extra.services.FailedApiCallException;
18
import org.nanopub.extra.services.QueryRef;
19

20
import java.time.LocalDateTime;
21
import java.time.ZoneId;
22
import java.time.format.DateTimeFormatter;
23
import java.util.ArrayList;
24
import java.util.List;
25

26
/**
27
 * The ProjectPage class represents a space page in the Nanodash application.
28
 */
29
public class SpacePage extends NanodashPage {
30

31
    /**
32
     * The mount path for this page.
33
     */
34
    public static final String MOUNT_PATH = "/space";
35

36
    /**
37
     * {@inheritDoc}
38
     */
39
    @Override
40
    public String getMountPath() {
41
        return MOUNT_PATH;
×
42
    }
43

44
    /**
45
     * Space object with the data shown on this page.
46
     */
47
    private Space space;
48

49
    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
×
50

51
    /**
52
     * Constructor for the SpacePage.
53
     *
54
     * @param parameters the page parameters
55
     * @throws org.nanopub.extra.services.FailedApiCallException if the API call fails
56
     */
57
    public SpacePage(final PageParameters parameters) throws FailedApiCallException {
58
        super(parameters);
×
59

60
        String id = parameters.get("id").toString();
×
61
        space = Space.get(id);
×
62
        if (space == null && MaintainedResource.get(id) != null) {
×
63
            throw new RestartResponseException(MaintainedResourcePage.class, parameters);
×
64
        }
65
        Nanopub np = space.getNanopub();
×
66
        space.triggerDataUpdate();
×
67

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

80
        add(new Label("pagetitle", space.getLabel() + " (space) | nanodash"));
×
81
        add(new Label("spacename", space.getLabel()));
×
82
        add(new Label("spacetype", space.getTypeLabel()));
×
83
        add(new BookmarkablePageLink<Void>("id", ExplorePage.class, parameters.set("label", space.getLabel())).setBody(Model.of(space.getId())));
×
84
        add(new BookmarkablePageLink<Void>("np", ExplorePage.class, new PageParameters().set("id", np.getUri())));
×
85

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

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

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

111
        final List<AbstractLink> pinButtons = new ArrayList<>();
×
112

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

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

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

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

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

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

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

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

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

163
            });
164
        }
165

166
        final List<AbstractLink> viewButtons = new ArrayList<>();
×
167
        AbstractLink addViewButton = new BookmarkablePageLink<NanodashPage>("button", PublishPage.class, new PageParameters()
×
168
                .set("template", "https://w3id.org/np/RAPxKWDTDP4neVtRckQcTqKHqCC_GHWWPrs7DESb2BJjo")
×
169
                .set("template-version", "latest")
×
170
                .set("param_resource", space.getId())
×
171
                .set("param_appliesToResource", space.getId())
×
172
                .set("context", space.getId())
×
173
                .set("refresh-upon-publish", id)
×
174
        );
175
        addViewButton.setBody(Model.of("+ view"));
×
176
        viewButtons.add(addViewButton);
×
177

178
        if (space.isDataInitialized()) {
×
179
            add(new ViewList("views", space));
×
180
            add(new ButtonList("view-buttons", space, null, null, viewButtons));
×
181
        } else {
182
            add(new AjaxLazyLoadPanel<Component>("views") {
×
183

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

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

194
            });
195
            add(new AjaxLazyLoadPanel<Component>("view-buttons") {
×
196

197
                @Override
198
                public Component getLazyLoadComponent(String markupId) {
199
                    return new ButtonList(markupId, space, null, null, viewButtons);
×
200
                }
201

202
                @Override
203
                protected boolean isContentReady() {
204
                    return space.isDataInitialized();
×
205
                }
206

207
                public Component getLoadingComponent(String id) {
208
                    return new Label(id).setVisible(false);
×
209
                }
210

211
            });
212
        }
213

214
        add(new ItemListPanel<>(
×
215
                        "roles",
216
                        "Roles:",
217
                        () -> space.isDataInitialized(),
×
218
                        () -> space.getRoles(),
×
219
                        r -> new ItemListElement("item", ExplorePage.class, new PageParameters().set("id", r.getRole().getId()), r.getRole().getName(), null, Utils.getAsNanopub(r.getNanopubUri()))
×
220
                )
221
                        .makeInline()
×
222
                        .setProfiledResource(space)
×
223
                        .addAdminButton("+", PublishPage.class, new PageParameters()
×
224
                                .set("template", "https://w3id.org/np/RARBzGkEqiQzeiHk0EXFcv9Ol1d-17iOh9MoFJzgfVQDc")
×
225
                                .set("param_space", space.getId())
×
226
                                .set("refresh-upon-publish", space.getId())
×
227
                                .set("template-version", "latest")
×
228
                        )
229
        );
230

231
        if (space.isDataInitialized()) {
×
232
            add(new SpaceUserList("user-lists", space));
×
233
        } else {
234
            add(new AjaxLazyLoadPanel<Component>("user-lists") {
×
235

236
                @Override
237
                public Component getLazyLoadComponent(String markupId) {
238
                    return new SpaceUserList(markupId, space);
×
239
                }
240

241
                @Override
242
                protected boolean isContentReady() {
243
                    return space.isDataInitialized();
×
244
                }
245

246
            });
247
        }
248

249
        addSubspacePanel("Alliance", true);
×
250
        addSubspacePanel("Consortium", false);
×
251
        addSubspacePanel("Organization", true);
×
252
        addSubspacePanel("Taskforce", false);
×
253
        addSubspacePanel("Division", true);
×
254
        addSubspacePanel("Taskunit", false);
×
255
        addSubspacePanel("Group", true);
×
256
        addSubspacePanel("Project", false);
×
257
        addSubspacePanel("Program", true);
×
258
        addSubspacePanel("Initiative", false);
×
259
        addSubspacePanel("Outlet", true);
×
260
        addSubspacePanel("Campaign", false);
×
261
        addSubspacePanel("Community", true);
×
262
        addSubspacePanel("Event", false);
×
263

264
        add(new ItemListPanel<MaintainedResource>(
×
265
                "resources",
266
                "Resources",
267
                new QueryRef("get-maintained-resources"),
268
                (apiResponse) -> {
269
                    MaintainedResource.ensureLoaded();
×
270
                    return MaintainedResource.getResourcesBySpace(space);
×
271
                },
272
                (resource) -> {
273
                    return new ItemListElement("item", MaintainedResourcePage.class, new PageParameters().set("id", resource.getId()), resource.getLabel());
×
274
                }
275
        )
276
                .setProfiledResource(space)
×
277
                .setReadyFunction(space::isDataInitialized)
×
278
                .addMemberButton("+", PublishPage.class, new PageParameters()
×
279
                        .set("template", "https://w3id.org/np/RA25VaVFxSOgKEuZ70gFINn-N3QV4Pf62-IMK_SWkg-c8")
×
280
                        .set("param_space", space.getId())
×
281
                        .set("context", space.getId())
×
282
                        .set("refresh-upon-publish", "maintainedResources")
×
283
                        .set("template-version", "latest")
×
284
                ));
285

286
        String shortId = space.getId().replace("https://w3id.org/spaces/", "");
×
287
        ConnectorConfig cc = ConnectorConfig.get(shortId);
×
288
        if (cc != null) {
×
289
            add(new BookmarkablePageLink<Void>("content-button", GenOverviewPage.class, new PageParameters().set("journal", shortId)).setBody(Model.of("Nanopublication Submissions")));
×
290
        } else {
291
            add(new Label("content-button").setVisible(false));
×
292
        }
293
    }
×
294

295
    private void addSubspacePanel(String type, boolean openEnded) {
296
        String typePl = type + "s";
×
297
        typePl = typePl.replaceFirst("ys$", "ies");
×
298

299
        add(new ItemListPanel<>(
×
300
                        typePl.toLowerCase(),
×
301
                        typePl,
302
                        space.getSubspaces(KPXL_TERMS.NAMESPACE + type),
×
303
                        (space) -> new ItemListElement("item", SpacePage.class, new PageParameters().set("id", space), space.getLabel())
×
304
                )
305
                        .setProfiledResource(space)
×
306
                        .setReadyFunction(space::isDataInitialized)
×
307
                        .addMemberButton("+", PublishPage.class, new PageParameters()
×
308
                                .set("template", openEnded ? "https://w3id.org/np/RA7dQfmndqKmooQ4PlHyQsAql9i2tg_8GLHf_dqtxsGEQ" : "https://w3id.org/np/RAaE7NP9RNIx03AHZxanFMdtUuaTfe50ns5tHhpEVloQ4")
×
309
                                .set("param_type", KPXL_TERMS.NAMESPACE + type)
×
310
                                .set("param_space", space.getId().replaceFirst("https://w3id.org/spaces/", "") + "/<SET-SUFFIX>")
×
311
                                .set("refresh-upon-publish", "spaces")
×
312
                                .set("template-version", "latest"))
×
313
        );
314
    }
×
315

316
    /**
317
     * Checks if auto-refresh is enabled for this page.
318
     *
319
     * @return true if auto-refresh is enabled, false otherwise
320
     */
321
    protected boolean hasAutoRefreshEnabled() {
322
        return true;
×
323
    }
324

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