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

knowledgepixels / nanodash / 21595502811

02 Feb 2026 03:10PM UTC coverage: 14.286% (-0.3%) from 14.572%
21595502811

push

github

web-flow
Merge pull request #348 from knowledgepixels/336-implement-nanopub-lists-as-views

Implement Nanopubs list/grid as `ResourceView`

569 of 5258 branches covered (10.82%)

Branch coverage included in aggregate %.

1552 of 9589 relevant lines covered (16.19%)

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

3
import com.google.common.collect.ArrayListMultimap;
4
import com.google.common.collect.Multimap;
5
import com.knowledgepixels.nanodash.*;
6
import com.knowledgepixels.nanodash.component.*;
7
import org.apache.wicket.AttributeModifier;
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.panel.EmptyPanel;
13
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
14
import org.apache.wicket.model.Model;
15
import org.apache.wicket.request.flow.RedirectToUrlException;
16
import org.apache.wicket.request.mapper.parameter.PageParameters;
17
import org.eclipse.rdf4j.model.IRI;
18
import org.nanopub.extra.services.ApiResponse;
19
import org.slf4j.Logger;
20
import org.slf4j.LoggerFactory;
21

22
import java.util.ArrayList;
23
import java.util.List;
24

25
/**
26
 * Page that shows a user profile, including their nanopubs and stats.
27
 */
28
public class UserPage extends NanodashPage {
29

30
    private static final Logger logger = LoggerFactory.getLogger(UserPage.class);
×
31

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

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

45
    private IRI userIri;
46
    private String pubkeyHashes = "";
×
47

48
    /**
49
     * Constructor for UserPage.
50
     *
51
     * @param parameters Page parameters, must include "id" with the user IRI.
52
     */
53
    public UserPage(final PageParameters parameters) {
54
        super(parameters);
×
55
        setOutputMarkupId(true);
×
56

57
        if (parameters.get("id") == null) throw new RedirectToUrlException(ProfilePage.MOUNT_PATH);
×
58
        final String userIriString = parameters.get("id").toString();
×
59
        userIri = Utils.vf.createIRI(userIriString);
×
60
        //NanodashSession session = NanodashSession.get();
61

62
        for (String pk : User.getPubkeyhashes(userIri, null)) {
×
63
            pubkeyHashes += " " + pk;
×
64
        }
×
65
        if (!pubkeyHashes.isEmpty()) pubkeyHashes = pubkeyHashes.substring(1);
×
66

67
        String pageType = "users";
×
68
        add(new TitleBar("titlebar", this, pageType));
×
69

70
        add(new JustPublishedMessagePanel("justPublishedMessage", parameters));
×
71

72
        final String displayName = User.getShortDisplayName(userIri);
×
73
        add(new Label("pagetitle", displayName + " (user) | nanodash"));
×
74
        EmptyPanel userIcon = new EmptyPanel("userIcon");
×
75
        userIcon.add(AttributeModifier.replace("class", User.isSoftware(userIri) ? "bot-icon" : "user-icon"));
×
76
        add(userIcon);
×
77
        add(new Label("username", displayName));
×
78

79
        add(new BookmarkablePageLink<Void>("fullid", ExplorePage.class, parameters.set("label", displayName)).setBody(Model.of(userIriString)));
×
80

81
        add(new BookmarkablePageLink<Void>("showprofile", ProfilePage.class).setVisible(userIri.equals(NanodashSession.get().getUserIri())));
×
82

83
//                final Map<String,String> statsParams = new HashMap<>();
84
//                final String statsQueryName;
85
//                if (pubkeyHashes.isEmpty()) {
86
//                        statsQueryName = "get-user-stats-from-userid";
87
//                        statsParams.put("userid", userIriString);
88
//                } else {
89
//                        statsQueryName = "get-user-stats-from-pubkeys";
90
//                        statsParams.put("userid", userIriString);
91
//                        statsParams.put("pubkeyhashes", pubkeyHashes);
92
//                } 
93
//                Map<String,String> statsMap = ApiCache.retrieveMap(statsQueryName, statsParams);
94
//                if (statsMap != null) {
95
//                        add(new StatsPanel("stats", userIriString, pubkeyHashes, statsMap));
96
//                } else {
97
//                        add(new AjaxLazyLoadPanel<Component>("stats") {
98
//        
99
//                                @Override
100
//                                public Component getLazyLoadComponent(String markupId) {
101
//                                        Map<String,String> m = null;
102
//                                        while (true) {
103
//                                                try {
104
//                                                        Thread.sleep(500);
105
//                                                } catch (InterruptedException ex) {
106
//                                                        logger.error();
107
//                                                }
108
//                                                if (!ApiCache.isRunning(statsQueryName, statsParams)) {
109
//                                                        m = ApiCache.retrieveMap(statsQueryName, statsParams);
110
//                                                        if (m != null) break;
111
//                                                }
112
//                                        }
113
//                                        return new StatsPanel(markupId, userIriString, pubkeyHashes, m);
114
//                                }
115
//
116
//                                @Override
117
//                                protected void onContentLoaded(Component content, Optional<AjaxRequestTarget> target) {
118
//                                        super.onContentLoaded(content, target);
119
//                                        if (target.get() != null) target.get().appendJavaScript("updateElements();");
120
//                                }
121
//        
122
//                        });
123
//                }
124

125
        final Multimap<String, String> params = ArrayListMultimap.create();
×
126
        final String queryName;
127
        if (pubkeyHashes.isEmpty()) {
×
128
            queryName = "get-latest-nanopubs-from-userid";
×
129
            params.put("userid", userIri.stringValue());
×
130
        } else {
131
            queryName = "get-latest-nanopubs-from-pubkeys";
×
132
            params.put("pubkeyhashes", pubkeyHashes);
×
133
            params.put("userid", userIri.stringValue());
×
134
        }
135
        /*final QueryRef queryRef = new QueryRef(queryName, params);
136
        ApiResponse response = ApiCache.retrieveResponseAsync(queryRef);
137
        if (response != null) {
138
            add(makeNanopubResultComponent("latestnanopubs", response));
139
        } else {
140
            add(new AjaxLazyLoadPanel<Component>("latestnanopubs") {
141

142
                @Override
143
                public Component getLazyLoadComponent(String markupId) {
144
                    ApiResponse r = null;
145
                    while (true) {
146
                        try {
147
                            Thread.sleep(500);
148
                        } catch (InterruptedException ex) {
149
                            logger.error("Thread interrupted while waiting for API response", ex);
150
                        }
151
                        if (!ApiCache.isRunning(queryRef)) {
152
                            r = ApiCache.retrieveResponseAsync(queryRef);
153
                            if (r != null) break;
154
                        }
155
                    }
156
                    return makeNanopubResultComponent(markupId, r);
157
                }
158

159
//                                @Override
160
//                                protected void onContentLoaded(Component content, Optional<AjaxRequestTarget> target) {
161
//                                        super.onContentLoaded(content, target);
162
//                                        if (target.get() != null) target.get().appendJavaScript("updateElements();");
163
//                                }
164

165
            });
166
        }*/
167

168
        Space.triggerAllDataUpdates();
×
169
        add(new ItemListPanel<Space>(
×
170
                "spaces",
171
                "Spaces",
172
                Space::areAllSpacesInitialized,
173
                () -> {
174
                    List<Space> spaces = new ArrayList<>();
×
175
                    for (Space space : Space.getSpaceList()) {
×
176
                        if (space.isMember(userIri)) spaces.add(space);
×
177
                    }
×
178
                    return spaces;
×
179
                },
180
                (s) -> new ItemListElement("item", SpacePage.class, new PageParameters().set("id", s.getId()), s.getLabel(), "(" + s.getTypeLabel() + ")", null)
×
181
        ));
182

183
//        if (pubkeyHashes.isEmpty()) {
184
//            add(new Label("activity", "<span class=\"negative\">Activity cannot be shown for this user due to missing user introduction.</span>").setEscapeModelStrings(false));
185
//        } else {
186
//            final QueryRef activityQueryRef = new QueryRef("get-monthly-type-overview-by-pubkeys");
187
//            for (String pk : pubkeyHashes.split(" ")) {
188
//                activityQueryRef.getParams().put("pubkey", pk);
189
//            }
190
//            ApiResponse activityQueryResponse = ApiCache.retrieveResponse(activityQueryRef);
191
//            if (activityQueryResponse != null) {
192
//                if (activityQueryResponse.getData().isEmpty()) {
193
//                    add(new Label("activity", "<em>No recent activity to show for this user.</em>").setEscapeModelStrings(false));
194
//                } else {
195
//                    add(new ActivityPanel("activity", activityQueryResponse));
196
//                }
197
//            } else {
198
//                add(new ApiResultComponent("activity", activityQueryRef) {
199
//
200
//                    @Override
201
//                    public Component getApiResultComponent(String markupId, ApiResponse response) {
202
//                        if (response.getData().isEmpty()) {
203
//                            return new Label(markupId, "<em>No recent activity to show for this user.</em>").setEscapeModelStrings(false);
204
//                        } else {
205
//                            return new ActivityPanel(markupId, response);
206
//                        }
207
//                    }
208
//                });
209
//
210
//            }
211
//        }
212

213
        final List<AbstractLink> viewButtons = new ArrayList<>();
×
214
        AbstractLink addViewButton = new BookmarkablePageLink<NanodashPage>("button", PublishPage.class, new PageParameters()
×
215
                .set("template", "https://w3id.org/np/RAPxKWDTDP4neVtRckQcTqKHqCC_GHWWPrs7DESb2BJjo")
×
216
                .set("template-version", "latest")
×
217
                .set("param_resource", userIriString)
×
218
                .set("param_appliesToResource", userIriString)
×
219
                .set("context", userIriString)
×
220
                .set("refresh-upon-publish", userIriString)
×
221
        );
222
        addViewButton.setBody(Model.of("+ view"));
×
223
        viewButtons.add(addViewButton);
×
224

225
        IndividualAgent individualAgent = IndividualAgent.get(userIriString);
×
226
        if (individualAgent.isDataInitialized()) {
×
227
            add(new ViewList("views", individualAgent));
×
228
            add(new ButtonList("view-buttons", individualAgent, null, null, viewButtons));
×
229
        } else {
230
            add(new AjaxLazyLoadPanel<Component>("views") {
×
231

232
                @Override
233
                public Component getLazyLoadComponent(String markupId) {
234
                    return new ViewList(markupId, individualAgent);
×
235
                }
236

237
                @Override
238
                protected boolean isContentReady() {
239
                    return individualAgent.isDataInitialized();
×
240
                }
241

242
            });
243
            add(new AjaxLazyLoadPanel<Component>("view-buttons") {
×
244

245
                @Override
246
                public Component getLazyLoadComponent(String markupId) {
247
                    return new ButtonList(markupId, individualAgent, null, null, viewButtons);
×
248
                }
249

250
                @Override
251
                protected boolean isContentReady() {
252
                    return individualAgent.isDataInitialized();
×
253
                }
254

255
                public Component getLoadingComponent(String id) {
256
                    return new Label(id).setVisible(false);
×
257
                }
258

259
            });
260
        }
261
    }
×
262

263
    private static Component makeNanopubResultComponent(String markupId, ApiResponse response) {
264
        if (response.getData().isEmpty()) {
×
265
            return new Label(markupId, "(none)");
×
266
        } else {
267
            return NanopubResults.fromApiResponse(markupId, response, 5);
×
268
        }
269
    }
270

271
    /**
272
     * <p>hasAutoRefreshEnabled.</p>
273
     *
274
     * @return a boolean
275
     */
276
    protected boolean hasAutoRefreshEnabled() {
277
        return true;
×
278
    }
279

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