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

knowledgepixels / nanodash / 17760079101

16 Sep 2025 08:42AM UTC coverage: 13.879% (+0.08%) from 13.799%
17760079101

push

github

ashleycaselli
refactor: replace hardcoded local URI prefix with LocalUri constant and checks with Utils methods

443 of 4012 branches covered (11.04%)

Branch coverage included in aggregate %.

1126 of 7293 relevant lines covered (15.44%)

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

3
import com.knowledgepixels.nanodash.LocalUri;
4
import com.knowledgepixels.nanodash.NanodashSession;
5
import com.knowledgepixels.nanodash.User;
6
import com.knowledgepixels.nanodash.Utils;
7
import com.knowledgepixels.nanodash.component.IriTextfieldItem.Validator;
8
import com.knowledgepixels.nanodash.page.ProfilePage;
9
import com.knowledgepixels.nanodash.template.Template;
10
import com.knowledgepixels.nanodash.template.TemplateContext;
11
import com.knowledgepixels.nanodash.template.UnificationException;
12
import org.apache.wicket.Component;
13
import org.apache.wicket.ajax.AjaxRequestTarget;
14
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
15
import org.apache.wicket.behavior.AttributeAppender;
16
import org.apache.wicket.markup.html.basic.Label;
17
import org.apache.wicket.markup.html.link.ExternalLink;
18
import org.apache.wicket.markup.html.panel.Panel;
19
import org.apache.wicket.model.IModel;
20
import org.apache.wicket.model.Model;
21
import org.apache.wicket.validation.Validatable;
22
import org.eclipse.rdf4j.model.IRI;
23
import org.eclipse.rdf4j.model.Value;
24
import org.eclipse.rdf4j.model.ValueFactory;
25
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
26
import org.nanopub.vocabulary.NTEMPLATE;
27
import org.slf4j.Logger;
28
import org.slf4j.LoggerFactory;
29
import org.wicketstuff.select2.ChoiceProvider;
30
import org.wicketstuff.select2.Response;
31
import org.wicketstuff.select2.Select2Choice;
32

33
import java.util.*;
34

35
/**
36
 * A component that allows users to select an agent (user) from a list or enter an ORCID or URL.
37
 */
38
public class AgentChoiceItem extends Panel implements ContextComponent {
39

40
    private static final long serialVersionUID = 1L;
41
    private TemplateContext context;
42
    private Select2Choice<String> textfield;
43
    private ExternalLink tooltipLink;
44
    private Label tooltipDescription;
45
    private IRI iri;
46
    private IModel<String> model;
47
    private static final Logger logger = LoggerFactory.getLogger(AgentChoiceItem.class);
×
48

49
    private String getChoiceLabel(String choiceId) {
50
        IRI iri = vf.createIRI(choiceId);
×
51
        String name = User.getName(iri);
×
52
        if (name != null) return name;
×
53
        return choiceId;
×
54
    }
55

56
    /**
57
     * Constructor for AgentChoiceItem.
58
     *
59
     * @param id       the component ID
60
     * @param parentId the parent component ID
61
     * @param iriP     the IRI of the agent choice item
62
     * @param optional whether the choice is optional
63
     * @param context  the template context
64
     */
65
    public AgentChoiceItem(String id, String parentId, final IRI iriP, boolean optional, final TemplateContext context) {
66
        super(id);
×
67
        this.context = context;
×
68
        this.iri = iriP;
×
69
        final Template template = context.getTemplate();
×
70
        model = context.getComponentModels().get(iri);
×
71
        if (model == null) {
×
72
            model = Model.of("");
×
73
            context.getComponentModels().put(iri, model);
×
74
        }
75
        String postfix = Utils.getUriPostfix(iri);
×
76
        if (context.hasParam(postfix)) {
×
77
            model.setObject(context.getParam(postfix));
×
78
        }
79
        final List<String> possibleValues = new ArrayList<>();
×
80
        for (Value v : template.getPossibleValues(iri)) {
×
81
            possibleValues.add(v.toString());
×
82
        }
×
83

84
        ChoiceProvider<String> choiceProvider = new ChoiceProvider<String>() {
×
85

86
            private static final long serialVersionUID = 1L;
87

88
            @Override
89
            public String getDisplayValue(String choiceId) {
90
                if (choiceId == null || choiceId.isEmpty()) return "";
×
91
                String label = getChoiceLabel(choiceId);
×
92
                if (label == null || label.isBlank()) {
×
93
                    return choiceId;
×
94
                }
95
                return label + " (" + choiceId + ")";
×
96
            }
97

98
            @Override
99
            public String getIdValue(String object) {
100
                return object;
×
101
            }
102

103
            // Getting strange errors with Tomcat if this method is not overridden:
104
            @Override
105
            public void detach() {
106
            }
×
107

108
            @Override
109
            public void query(String term, int page, Response<String> response) {
110
                if (term == null) {
×
111
                    if (possibleValues.isEmpty()) {
×
112
                        if (NanodashSession.get().getUserIri() != null) {
×
113
                            response.add(NanodashSession.get().getUserIri().stringValue());
×
114
                        }
115
                    } else {
116
                        response.addAll(possibleValues);
×
117
                    }
118
                    return;
×
119
                }
120
                if (term.startsWith("https://") || term.startsWith("http://")) {
×
121
                    response.add(term);
×
122
                } else if (term.matches(ProfilePage.ORCID_PATTERN)) {
×
123
                    response.add("https://orcid.org/" + term);
×
124
                }
125
                Map<String, Boolean> alreadyAddedMap = new HashMap<>();
×
126
                term = term.toLowerCase();
×
127
                for (String s : possibleValues) {
×
128
                    if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
129
                        response.add(s);
×
130
                        alreadyAddedMap.put(s, true);
×
131
                    }
132
                }
×
133

134
                // TODO: We'll need some indexing to perform this more efficiently at some point:
135
                for (IRI iri : User.getUsers(true)) {
×
136
                    // Collect approved users
137
                    if (response.size() > 9) break;
×
138
                    if (response.getResults().contains(iri.stringValue())) continue;
×
139
                    String name = User.getName(iri);
×
140
                    if (iri.stringValue().contains(term)) {
×
141
                        response.add(iri.stringValue());
×
142
                    } else if (name != null && name.toLowerCase().contains(term)) {
×
143
                        response.add(iri.stringValue());
×
144
                    }
145
                }
×
146
                for (IRI iri : User.getUsers(false)) {
×
147
                    // Collect non-approved users
148
                    if (response.size() > 9) break;
×
149
                    if (response.getResults().contains(iri.stringValue())) continue;
×
150
                    String name = User.getName(iri);
×
151
                    if (iri.stringValue().contains(term)) {
×
152
                        response.add(iri.stringValue());
×
153
                    } else if (name != null && name.toLowerCase().contains(term)) {
×
154
                        response.add(iri.stringValue());
×
155
                    }
156
                }
×
157
            }
×
158

159
            @Override
160
            public Collection<String> toChoices(Collection<String> ids) {
161
                return ids;
×
162
            }
163

164
        };
165
        textfield = new Select2Choice<String>("textfield", model, choiceProvider);
×
166
        textfield.getSettings().getAjax(true).setDelay(500);
×
167
        textfield.getSettings().setCloseOnSelect(true);
×
168
        String placeholder = template.getLabel(iri);
×
169
        if (placeholder == null) placeholder = "select user or paste ORCID/URL";
×
170
        textfield.getSettings().setPlaceholder(placeholder);
×
171
        Utils.setSelect2ChoiceMinimalEscapeMarkup(textfield);
×
172
        textfield.getSettings().setAllowClear(true);
×
173

174
        if (!optional) textfield.setRequired(true);
×
175
        textfield.add(new AttributeAppender("class", " wide"));
×
176
        textfield.add(new Validator(iri, template, "", context));
×
177
        context.getComponents().add(textfield);
×
178

179
        tooltipDescription = new Label("description", new IModel<String>() {
×
180

181
            private static final long serialVersionUID = 1L;
182

183
            @Override
184
            public String getObject() {
185
                String obj = AgentChoiceItem.this.getModel().getObject();
×
186
                if (obj == null || obj.isEmpty()) return "choose a value";
×
187
                String label = getChoiceLabel(AgentChoiceItem.this.getModel().getObject());
×
188
                if (label == null || !label.contains(" - ")) return "";
×
189
                return label.substring(label.indexOf(" - ") + 3);
×
190
            }
191

192
        });
193
        tooltipDescription.setOutputMarkupId(true);
×
194
        add(tooltipDescription);
×
195

196
        tooltipLink = Utils.getUriLink("uri", model);
×
197
        tooltipLink.setOutputMarkupId(true);
×
198
        add(tooltipLink);
×
199

200
        textfield.add(new OnChangeAjaxBehavior() {
×
201

202
            private static final long serialVersionUID = 1L;
203

204
            @Override
205
            protected void onUpdate(AjaxRequestTarget target) {
206
                for (Component c : context.getComponents()) {
×
207
                    if (c == textfield) continue;
×
208
                    if (c.getDefaultModel() == textfield.getModel()) {
×
209
                        c.modelChanged();
×
210
                        target.add(c);
×
211
                    }
212
                }
×
213
                target.add(tooltipLink);
×
214
                target.add(tooltipDescription);
×
215
            }
×
216

217
        });
218
        add(textfield);
×
219
    }
×
220

221
    /**
222
     * Returns the IRI of the agent choice item.
223
     *
224
     * @return the IRI of the agent choice item
225
     */
226
    public IModel<String> getModel() {
227
        return model;
×
228
    }
229

230
    /**
231
     * {@inheritDoc}
232
     */
233
    @Override
234
    public void removeFromContext() {
235
        context.getComponents().remove(textfield);
×
236
    }
×
237

238
    /**
239
     * {@inheritDoc}
240
     */
241
    @Override
242
    public boolean isUnifiableWith(Value v) {
243
        if (v == null) return true;
×
244
        if (v instanceof IRI) {
×
245
            String vs = v.stringValue();
×
246
            if (Utils.isLocalURI(vs)) vs = vs.replaceFirst("^" + LocalUri.PREFIX, "");
×
247
            Validatable<String> validatable = new Validatable<>(vs);
×
248
            if (context.getTemplate().isLocalResource(iri) && !Utils.isUriPostfix(vs)) {
×
249
                vs = Utils.getUriPostfix(vs);
×
250
            }
251
            new Validator(iri, context.getTemplate(), "", context).validate(validatable);
×
252
            if (!validatable.isValid()) {
×
253
                return false;
×
254
            }
255
            if (textfield.getModelObject().isEmpty()) {
×
256
                return true;
×
257
            }
258
            return vs.equals(textfield.getModelObject());
×
259
        }
260
        return false;
×
261
    }
262

263
    /**
264
     * {@inheritDoc}
265
     */
266
    @Override
267
    public void unifyWith(Value v) throws UnificationException {
268
        if (v == null) return;
×
269
        if (!isUnifiableWith(v)) throw new UnificationException(v.stringValue());
×
270
        String vs = v.stringValue();
×
271
        if (Utils.isLocalURI(vs)) {
×
272
            vs = vs.replaceFirst("^" + LocalUri.PREFIX, "");
×
273
        }
274
        textfield.setModelObject(vs);
×
275
    }
×
276

277
    /**
278
     * {@inheritDoc}
279
     */
280
    @Override
281
    public void fillFinished() {
282
    }
×
283

284
    /**
285
     * {@inheritDoc}
286
     */
287
    @Override
288
    public void finalizeValues() {
289
        Value defaultValue = context.getTemplate().getDefault(iri);
×
290
        if (NTEMPLATE.CREATOR_PLACEHOLDER.equals(defaultValue)) {
×
291
            defaultValue = NanodashSession.get().getUserIri();
×
292
        }
293
        if (isUnifiableWith(defaultValue)) {
×
294
            try {
295
                unifyWith(defaultValue);
×
296
            } catch (UnificationException ex) {
×
297
                logger.error("Could not unify default value: {}", defaultValue, ex);
×
298
            }
×
299
        }
300
    }
×
301

302
    private static ValueFactory vf = SimpleValueFactory.getInstance();
×
303

304
    /**
305
     * <p>toString.</p>
306
     *
307
     * @return a {@link java.lang.String} object
308
     */
309
    public String toString() {
310
        return "[Agent choiced item: " + iri + "]";
×
311
    }
312

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