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

knowledgepixels / nanodash / 19228463704

10 Nov 2025 10:26AM UTC coverage: 14.759% (-0.03%) from 14.79%
19228463704

push

github

tkuhn
fix(ActivityPanel): Use AjaxNavigationToolbar to avoid jumping to top

540 of 4596 branches covered (11.75%)

Branch coverage included in aggregate %.

1393 of 8501 relevant lines covered (16.39%)

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

3
import java.io.Serializable;
4
import java.time.Year;
5
import java.util.ArrayList;
6
import java.util.Calendar;
7
import java.util.HashMap;
8
import java.util.HashSet;
9
import java.util.Iterator;
10
import java.util.List;
11
import java.util.Map;
12
import java.util.Set;
13

14
import org.apache.wicket.behavior.AttributeAppender;
15
import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxNavigationToolbar;
16
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
17
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
18
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
19
import org.apache.wicket.extensions.markup.html.repeater.data.table.HeadersToolbar;
20
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
21
import org.apache.wicket.markup.html.basic.Label;
22
import org.apache.wicket.markup.html.panel.Panel;
23
import org.apache.wicket.markup.repeater.Item;
24
import org.apache.wicket.markup.repeater.data.IDataProvider;
25
import org.apache.wicket.model.IModel;
26
import org.apache.wicket.model.Model;
27
import org.nanopub.extra.services.ApiResponse;
28
import org.nanopub.extra.services.ApiResponseEntry;
29
import org.slf4j.Logger;
30
import org.slf4j.LoggerFactory;
31

32
import com.knowledgepixels.nanodash.Utils;
33

34
/**
35
 * A panel that displays activity data in a table format.
36
 * It shows the number of nanopublications per type and month.
37
 */
38
public class ActivityPanel extends Panel {
39

40
    private Map<String, Map<String, String>> typeMonthValueMap = new HashMap<>();
×
41
    private final Logger logger = LoggerFactory.getLogger(ActivityPanel.class);
×
42

43
    /**
44
     * Constructor for ActivityPanel.
45
     *
46
     * @param markupId the Wicket markup ID for this panel
47
     * @param response the ApiResponse containing activity data
48
     */
49
    public ActivityPanel(String markupId, ApiResponse response) {
50
        super(markupId);
×
51
        setOutputMarkupId(true);
×
52

53
        List<Entity> list = new ArrayList<>();
×
54
        Set<String> types = new HashSet<>();
×
55
        for (ApiResponseEntry e : response.getData()) {
×
56
            String type = e.get("type");
×
57
            if (!types.contains(type)) {
×
58
                list.add(new Entity(type));
×
59
                types.add(type);
×
60
            }
61
            if (!typeMonthValueMap.containsKey(type)) {
×
62
                typeMonthValueMap.put(type, new HashMap<>());
×
63
            }
64
            typeMonthValueMap.get(type).put(e.get("month"), e.get("npCount"));
×
65
        }
×
66

67
        final Calendar calendar = Calendar.getInstance();
×
68
        int year = Year.now().getValue() - 1;
×
69
        int month = calendar.get(Calendar.MONTH) + 1;
×
70

71
        List<IColumn<Entity, String>> columns = new ArrayList<>();
×
72
        columns.add(new Column("type"));
×
73

74
        int count = 0;
×
75
        while (count < 12) {
×
76
            month++;
×
77
            if (month == 13) {
×
78
                year++;
×
79
                month = 1;
×
80
            }
81
            columns.add(new Column(formatYearMonth(year, month)));
×
82
            count++;
×
83
        }
84

85
        DataTable<Entity, String> table = new DataTable<Entity, String>("table", columns, new EntityProvider(list), 10);
×
86
        table.addBottomToolbar(new AjaxNavigationToolbar(table));
×
87
        table.addTopToolbar(new HeadersToolbar<String>(table, null));
×
88
        table.setOutputMarkupId(true);
×
89
        add(table);
×
90
    }
×
91

92
    private static String formatYearMonth(int year, int month) {
93
        return year + "-" + (month > 9 ? "" + month : "0" + month);
×
94
    }
95

96
    private class Entity implements Serializable {
97

98
        public String type;
99

100
        public Entity(String type) {
×
101
            this.type = type;
×
102
        }
×
103

104
        public String getValue(String month) {
105
            if (!typeMonthValueMap.containsKey(type)) return "";
×
106
            if (!typeMonthValueMap.get(type).containsKey(month)) return "";
×
107
            return typeMonthValueMap.get(type).get(month);
×
108
        }
109

110
    }
111

112
    private class Column extends AbstractColumn<Entity, String> {
113

114
        private String title;
115

116
        public Column(String title) {
117
            this(new Model<String>(title));
×
118
        }
×
119

120
        public Column(Model<String> titleModel) {
×
121
            super(titleModel);
×
122
            this.title = titleModel.getObject();
×
123
            titleModel.setObject(titleModel.getObject().replaceFirst("^20", ""));
×
124
        }
×
125

126
        @Override
127
        public void populateItem(Item<ICellPopulator<Entity>> cellItem, String componentId, IModel<Entity> rowModel) {
128
            Entity e = rowModel.getObject();
×
129
            if (title.equals("type")) {
×
130
                cellItem.add(new NanodashLink(componentId, e.type));
×
131
            } else {
132
                String v = e.getValue(title);
×
133
                cellItem.add(new Label(componentId, v));
×
134
                if (!v.isBlank()) {
×
135
                    try {
136
                        int i = Integer.parseInt(v);
×
137
                        if (i >= 100) {
×
138
                            cellItem.add(new AttributeAppender("class", " high"));
×
139
                        } else if (i >= 10) {
×
140
                            cellItem.add(new AttributeAppender("class", " med"));
×
141
                        } else if (i >= 1) {
×
142
                            cellItem.add(new AttributeAppender("class", " low"));
×
143
                        }
144
                    } catch (NumberFormatException ex) {
×
145
                        logger.error("Error in parsing integer from value: {}", v, ex);
×
146
                    }
×
147
                }
148
            }
149
        }
×
150
    }
151

152
    private class EntityProvider implements IDataProvider<Entity> {
153

154
        private List<Entity> list;
155

156
        /**
157
         * Constructor for EntityProvider.
158
         *
159
         * @param list the list of Entity objects to provide
160
         */
161
        public EntityProvider(List<Entity> list) {
×
162
            this.list = list;
×
163
        }
×
164

165
        @Override
166
        public Iterator<? extends Entity> iterator(long first, long count) {
167
            return Utils.subList(list, first, first + count).iterator();
×
168
        }
169

170
        @Override
171
        public long size() {
172
            return list.size();
×
173
        }
174

175
        @Override
176
        public IModel<Entity> model(Entity object) {
177
            return new Model<Entity>(object);
×
178
        }
179

180
    }
181

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