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

knowledgepixels / nanodash / 24382503285

14 Apr 2026 05:24AM UTC coverage: 15.886% (-0.2%) from 16.094%
24382503285

push

github

web-flow
Merge pull request #438 from knowledgepixels/feature/item-list-view-435

feat: implement ItemListView and fix async view rendering

789 of 6130 branches covered (12.87%)

Branch coverage included in aggregate %.

1978 of 11288 relevant lines covered (17.52%)

2.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
src/main/java/com/knowledgepixels/nanodash/ViewDisplay.java
1
package com.knowledgepixels.nanodash;
2

3
import com.knowledgepixels.nanodash.vocabulary.KPXL_TERMS;
4
import org.eclipse.rdf4j.model.IRI;
5
import org.eclipse.rdf4j.model.Literal;
6
import org.eclipse.rdf4j.model.Statement;
7
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
8
import org.eclipse.rdf4j.model.vocabulary.RDF;
9
import org.nanopub.Nanopub;
10
import org.nanopub.NanopubUtils;
11
import org.slf4j.Logger;
12
import org.slf4j.LoggerFactory;
13

14
import java.io.Serializable;
15
import java.util.HashSet;
16
import java.util.Set;
17

18
/**
19
 * A class representing the display of a resource view associated with a Space.
20
 */
21
public class ViewDisplay implements Serializable, Comparable<ViewDisplay> {
22

23
    private static final Logger logger = LoggerFactory.getLogger(ViewDisplay.class);
×
24

25
    private String id;
26
    private Nanopub nanopub;
27
    private View view;
28
    private IRI viewIri;
29
    private String title;
30
    private Integer pageSize;
31
    private Integer displayWidth;
32
    private String structuralPosition;
33
    private Set<IRI> types = new HashSet<>();
×
34
    private Set<String> appliesTo = new HashSet<>();
×
35
    private Set<IRI> appliesToClasses = new HashSet<>();
×
36
    private Set<IRI> appliesToNamespaces = new HashSet<>();
×
37
    private IRI resource;
38

39
    /**
40
     * Constructor for ViewDisplay with only a View. This is used for temporary view displays used in profiles as defaults.
41
     *
42
     * @param view the View associated with this ViewDisplay
43
     */
44
    public ViewDisplay(View view) {
×
45
        this.id = null;
×
46
        this.nanopub = view.getNanopub();
×
47
        this.view = view;
×
48
    }
×
49

50
    /**
51
     * Get a View by its ID.
52
     *
53
     * @param id the ID of the View
54
     * @return the View object
55
     */
56
    public static ViewDisplay get(String id) throws IllegalArgumentException {
57
        // Try to resolve to the latest version (same pattern as View.get()):
58
        try {
59
            String npId = id.replaceFirst("^(.*[^A-Za-z0-9-_]RA[A-Za-z0-9-_]{43})[^A-Za-z0-9-_].*$", "$1");
×
60
            String latestNpId = QueryApiAccess.getLatestVersionId(npId);
×
61
            if (!latestNpId.equals(npId)) {
×
62
                Nanopub np = Utils.getAsNanopub(latestNpId);
×
63
                if (np != null) {
×
64
                    Set<String> embeddedIris = NanopubUtils.getEmbeddedIriIds(np);
×
65
                    if (embeddedIris.size() == 1) {
×
66
                        return new ViewDisplay(embeddedIris.iterator().next(), np);
×
67
                    }
68
                }
69
            }
70
        } catch (Exception ex) {
×
71
            logger.error("Error resolving latest version for view display: {}", id, ex);
×
72
        }
×
73
        // Fall back to loading the nanopub as given:
74
        try {
75
            Nanopub np = Utils.getAsNanopub(id.replaceFirst("^(.*[^A-Za-z0-9-_])?(RA[A-Za-z0-9-_]{43})[^A-Za-z0-9-_].*$", "$2"));
×
76
            return new ViewDisplay(id, np);
×
77
        } catch (Exception ex) {
×
78
            logger.error("Couldn't load nanopub for resource: {}", id, ex);
×
79
            throw new IllegalArgumentException("invalid view value " + id);
×
80
        }
81
    }
82

83
    /**
84
     * Constructor for ViewDisplay.
85
     *
86
     * @param id      the ID of the ViewDisplay
87
     * @param nanopub the Nanopub containing the data for this ViewDisplay
88
     */
89
    private ViewDisplay(String id, Nanopub nanopub) {
×
90
        this.id = id;
×
91
        this.nanopub = nanopub;
×
92

93
        boolean viewDisplayTypeFound = false;
×
94
        for (Statement st : nanopub.getAssertion()) {
×
95
            if (st.getSubject().stringValue().equals(id)) {
×
96
                if (st.getPredicate().equals(RDF.TYPE)) {
×
97
                    if (st.getObject().equals(KPXL_TERMS.VIEW_DISPLAY) || st.getObject().equals(KPXL_TERMS.DEACTIVATED_VIEW_DISPLAY)) {
×
98
                        viewDisplayTypeFound = true;
×
99
                    }
100
                    if (st.getObject() instanceof IRI objIri && !st.getObject().equals(KPXL_TERMS.VIEW_DISPLAY)) {
×
101
                        types.add(objIri);
×
102
                    }
103
                } else if (st.getPredicate().equals(DCTERMS.TITLE)) {
×
104
                    title = st.getObject().stringValue();
×
105
                } else if (st.getPredicate().equals(KPXL_TERMS.IS_DISPLAY_OF_VIEW) && st.getObject() instanceof IRI objIri) {
×
106
                    if (view != null) {
×
107
                        throw new IllegalArgumentException("View already set: " + objIri);
×
108
                    }
109
                    viewIri = objIri;
×
110
                    view = View.get(objIri.stringValue());
×
111
                } else if (st.getPredicate().equals(KPXL_TERMS.IS_DISPLAY_FOR) && st.getObject() instanceof IRI objIri) {
×
112
                    if (resource != null) {
×
113
                        throw new IllegalArgumentException("Resource already set: " + objIri);
×
114
                    }
115
                    resource = objIri;
×
116
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_PAGE_SIZE) && st.getObject() instanceof Literal objL) {
×
117
                    try {
118
                        pageSize = Integer.parseInt(objL.stringValue());
×
119
                    } catch (NumberFormatException ex) {
×
120
                        logger.error("Invalid page size value: {}", objL.stringValue(), ex);
×
121
                    }
×
122
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_DISPLAY_WIDTH) && st.getObject() instanceof IRI objIri) {
×
123
                    displayWidth = View.columnWidths.get(objIri);
×
124
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_STRUCTURAL_POSITION) && st.getObject() instanceof Literal objL) {
×
125
                    structuralPosition = objL.stringValue();
×
126
                } else if (st.getPredicate().equals(KPXL_TERMS.APPLIES_TO_NAMESPACE) && st.getObject() instanceof IRI objIri) {
×
127
                    appliesToNamespaces.add(objIri);
×
128
                } else if (st.getPredicate().equals(KPXL_TERMS.APPLIES_TO_INSTANCES_OF) && st.getObject() instanceof IRI objIri) {
×
129
                    appliesToClasses.add(objIri);
×
130
                } else if (st.getPredicate().equals(KPXL_TERMS.APPLIES_TO) && st.getObject() instanceof IRI objIri) {
×
131
                    appliesTo.add(objIri.stringValue());
×
132
                }
133
            }
134
        }
×
135
        if (!viewDisplayTypeFound) throw new IllegalArgumentException("Not a proper view display nanopub: " + id);
×
136
        if (view == null) throw new IllegalArgumentException("View not found: " + id);
×
137
    }
×
138

139
    public String getId() {
140
        return id;
×
141
    }
142

143
    public boolean hasType(IRI type) {
144
        return types.contains(type);
×
145
    }
146

147
    /**
148
     * Creates a plain minimal view display without attached view object.
149
     *
150
     * @param pageSize the page size of the view display
151
     */
152
    public ViewDisplay(Integer pageSize) {
×
153
        this.pageSize = pageSize;
×
154
    }
×
155

156
    /**
157
     * Gets the View associated with this ViewDisplay.
158
     *
159
     * @return the View
160
     */
161
    public View getView() {
162
        return view;
×
163
    }
164

165
    public IRI getViewIri() {
166
        return viewIri;
×
167
    }
168

169
    public IRI getViewKindIri() {
170
        IRI kind = view.getViewKindIri();
×
171
        if (kind != null) return kind;
×
172
        return viewIri;
×
173
    }
174

175
    public boolean appliesTo(String resourceId, Set<IRI> classes) {
176
        if (appliesTo.contains(resourceId)) return true;
×
177
        if (appliesToNamespaces.isEmpty() && appliesToClasses.isEmpty()) {
×
178
            if (!appliesTo.isEmpty()) return false;
×
179
            return view.appliesTo(resourceId, classes);
×
180
        } else {
181
            for (IRI namespace : appliesToNamespaces) {
×
182
                if (resourceId.startsWith(namespace.stringValue())) return true;
×
183
            }
×
184
            if (classes != null) {
×
185
                for (IRI c : classes) {
×
186
                    if (appliesToClasses.contains(c)) return true;
×
187
                }
×
188
            }
189
        }
190
        return false;
×
191
    }
192

193
    public boolean appliesToClasses() {
194
        if (appliesToClasses.isEmpty()) {
×
195
            return view.appliesToClasses();
×
196
        } else {
197
            return true;
×
198
        }
199
    }
200

201
    public boolean appliesToClass(IRI targetClass) {
202
        if (appliesToClasses.isEmpty()) {
×
203
            return view.appliesToClasses();
×
204
        } else {
205
            return appliesToClasses.contains(targetClass);
×
206
        }
207
    }
208

209
    /**
210
     * Gets the nanopub ID associated with this ViewDisplay
211
     *
212
     * @return the nanopub ID
213
     */
214
    public IRI getNanopubId() {
215
        if (nanopub == null) {
×
216
            return null;
×
217
        }
218
        return nanopub.getUri();
×
219
    }
220

221
    /**
222
     * Gets the nanopub associated with this ViewDisplay
223
     *
224
     * @return the nanopub, or null if not available
225
     */
226
    public Nanopub getNanopub() {
227
        return nanopub;
×
228
    }
229

230
    public Integer getPageSize() {
231
        if (pageSize != null) return pageSize;
×
232
        if (view == null) return 10;
×
233
        if (view.getPageSize() != null) return view.getPageSize();
×
234
        return 10;
×
235
    }
236

237
    public Integer getDisplayWidth() {
238
        if (displayWidth != null) return displayWidth;
×
239
        if (view == null) return 12;
×
240
        if (view.getDisplayWidth() != null) return view.getDisplayWidth();
×
241
        return 12;
×
242
    }
243

244
    public ViewDisplay withDisplayWidth(int width) {
245
        this.displayWidth = width;
×
246
        return this;
×
247
    }
248

249
    public String getStructuralPosition() {
250
        if (structuralPosition != null) return structuralPosition;
×
251
        if (view == null) return "5.5.default";
×
252
        if (view.getStructuralPosition() != null) return view.getStructuralPosition();
×
253
        return "5.5.default";
×
254
    }
255

256
    public String getTitle() {
257
        if (title != null) return title;
×
258
        if (view != null) return view.getTitle();
×
259
        return null;
×
260
    }
261

262
    @Override
263
    public int compareTo(ViewDisplay other) {
264
        return this.getStructuralPosition().compareTo(other.getStructuralPosition());
×
265
    }
266

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