Skip to content

Commit 8f85f5a

Browse files
committed
Search now have history
1 parent fef343c commit 8f85f5a

File tree

7 files changed

+152
-10
lines changed

7 files changed

+152
-10
lines changed

Diff for: src/main/java/hudson/plugins/nested_view/NestedViewsSearch.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import hudson.model.TopLevelItem;
66
import hudson.model.View;
77
import hudson.plugins.nested_view.search.HelpItem;
8+
import hudson.plugins.nested_view.search.HistoryItem;
89
import hudson.plugins.nested_view.search.NamableWithClass;
910
import hudson.plugins.nested_view.search.NestedViewsSearchResult;
1011
import hudson.plugins.nested_view.search.Query;
@@ -34,7 +35,7 @@ public class NestedViewsSearch extends Search {
3435

3536
private static final long refreshTimeout = 10l * 60l * 1000l;
3637
private static final int refreshAmount = 20;
37-
private final static Logger LOGGER = Logger.getLogger(Search.class.getName());
38+
public final static Logger LOGGER = Logger.getLogger(Search.class.getName());
3839
private static transient volatile List<NamableWithClass> allCache = new ArrayList(0);
3940
private static transient volatile int allTTL = 0;
4041
private static transient volatile Date lastRefresh = new Date(0);
@@ -96,13 +97,25 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException,
9697
}
9798
}
9899
}
100+
putToHistory(query, hits.size(), new Date());
99101
}
100102
Collections.sort(hits);
101103
//todo, add paging &start=&count= .. defaulting to 0 and somwhere on 1000. Probably add next/prev links to jelly. Include `showing x/form` in jelly
102104
RequestDispatcher v = req.getView(this, "search-results.jelly");
103105
v.forward(req, rsp);
104106
}
105107

108+
@SuppressFBWarnings(value = {"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, justification = "history is shared")
109+
private void putToHistory(String query, int size, Date date) {
110+
HistoryItem his = new HistoryItem(query.trim().replaceAll("\\s+", " "), size, date);
111+
HistoryItem.add(his);
112+
}
113+
114+
@SuppressFBWarnings(value = {"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, justification = "history is shared")
115+
public List getHistory() {
116+
return HistoryItem.get();
117+
}
118+
106119
@Override
107120
public SearchResult getSuggestions(final StaplerRequest req, @QueryParameter final String query) {
108121
SearchResult suggestedItems = super.getSuggestions(req, query);

Diff for: src/main/java/hudson/plugins/nested_view/search/BuildDetails.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,13 @@ public LinkableCandidate toLinkable(String projectName) {
4848
}
4949
post = post + "/" + result + "/" + timeStampString + " ago";
5050
;
51-
return new LinkableCandidate(pre, link, post, Jenkins.get().getRootUrl().replaceAll("[\\/]+$", "") + "/job/" + projectName + "/" + id);
51+
return new LinkableCandidate(pre, link, post, getJenkinsUrl() + "/job/" + projectName + "/" + id);
5252
} else {
5353
return new LinkableCandidate(prefix + "n/a");
5454
}
5555
}
56+
57+
public static String getJenkinsUrl() {
58+
return Jenkins.get().getRootUrl().replaceAll("[\\/]+$", "");
59+
}
5660
}

Diff for: src/main/java/hudson/plugins/nested_view/search/ExtendedSearch.java

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package hudson.plugins.nested_view.search;
22

3-
import hudson.plugins.nested_view.ProjectWrapper;
4-
53
// for some reasons, if class implements some interfaces, only methods from interface are available form jelly!
64
// thus this artificial interface...
75
public interface ExtendedSearch {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package hudson.plugins.nested_view.search;
2+
3+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
4+
import hudson.plugins.nested_view.NestedViewsSearch;
5+
import jenkins.model.Jenkins;
6+
7+
import java.io.File;
8+
import java.io.IOException;
9+
import java.nio.file.Files;
10+
import java.text.SimpleDateFormat;
11+
import java.util.ArrayList;
12+
import java.util.Collections;
13+
import java.util.Date;
14+
import java.util.List;
15+
import java.util.logging.Level;
16+
import java.util.stream.Collectors;
17+
18+
public class HistoryItem {
19+
20+
private static final int MAX_HISTORY = 500;
21+
private static final File historyCache = new File(Jenkins.get().root, ".nested-view-serch.cache");
22+
private static final List<HistoryItem> history = HistoryItem.load();
23+
24+
private final String query;
25+
private final int size;
26+
private final Date date;
27+
28+
@SuppressFBWarnings(value = {"EI_EXPOSE_REP2"}, justification = "date is not cared")
29+
public HistoryItem(String query, int size, Date date) {
30+
this.query = query;
31+
this.size = size;
32+
this.date = date;
33+
}
34+
35+
public static void save() {
36+
try {
37+
saveImp();
38+
} catch (Exception ex) {
39+
NestedViewsSearch.LOGGER.log(Level.SEVERE, "saving nested view search history failed", ex);
40+
}
41+
}
42+
43+
public static void saveImp() throws IOException {
44+
Files.write(historyCache.toPath(), history.stream().map(a -> a.toSave()).collect(Collectors.toList()));
45+
}
46+
47+
public static List<HistoryItem> load() {
48+
List<String> l = new ArrayList<>(0);
49+
if (historyCache.exists()) try {
50+
l = Files.readAllLines(historyCache.toPath());
51+
} catch (Exception ex) {
52+
NestedViewsSearch.LOGGER.log(Level.SEVERE, "loading nested view search history failed", ex);
53+
}
54+
ArrayList<HistoryItem> r = new ArrayList(MAX_HISTORY);
55+
for (String s : l) {
56+
try {
57+
r.add(new HistoryItem(s));
58+
} catch (Exception ex) {
59+
NestedViewsSearch.LOGGER.log(Level.SEVERE, "reading nested view search history " + s + " failed", ex);
60+
}
61+
}
62+
return Collections.synchronizedList(r);
63+
}
64+
65+
public static List<HistoryItem> get() {
66+
return Collections.unmodifiableList(history);
67+
}
68+
69+
public static void add(HistoryItem his) {
70+
history.removeAll(Collections.singleton(his));
71+
history.add(0, his);
72+
while (history.size() > MAX_HISTORY) {
73+
history.remove(history.size() - 1);
74+
}
75+
save();
76+
}
77+
78+
@Override
79+
public boolean equals(Object o) {
80+
if (this == o) return true;
81+
if (o == null || getClass() != o.getClass()) return false;
82+
HistoryItem that = (HistoryItem) o;
83+
return query.equals(that.query);
84+
}
85+
86+
@Override
87+
public int hashCode() {
88+
return query.hashCode();
89+
}
90+
91+
public String getQuery() {
92+
return query;
93+
}
94+
95+
public String getUrl() {
96+
return BuildDetails.getJenkinsUrl() + "/search/?q=" + getQuery();
97+
}
98+
99+
public int getSize() {
100+
return size;
101+
}
102+
103+
public String getDate() {
104+
return new SimpleDateFormat("HH:mm:ss dd/MM").format(date);
105+
}
106+
107+
public String toSave() {
108+
return size + " " + date.getTime() + " " + query;
109+
}
110+
111+
public HistoryItem(String saved) {
112+
String[] sd = saved.split(" ");
113+
size = Integer.parseInt(sd[0]);
114+
date = new Date(Long.parseLong(sd[1]));
115+
query = saved.replace(size + " " + date.getTime() + " ", "");
116+
117+
}
118+
119+
}

Diff for: src/main/java/hudson/plugins/nested_view/search/NestedViewsSearchResult.java

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
44
import hudson.model.AbstractProject;
5-
import hudson.plugins.nested_view.ProjectWrapper;
65
import hudson.search.SearchIndex;
76
import hudson.search.SearchItem;
87

Diff for: src/main/java/hudson/plugins/nested_view/ProjectWrapper.java renamed to src/main/java/hudson/plugins/nested_view/search/ProjectWrapper.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package hudson.plugins.nested_view;
1+
package hudson.plugins.nested_view.search;
22

33
import java.util.ArrayList;
44
import java.util.Arrays;
@@ -15,10 +15,6 @@
1515
import hudson.model.AbstractProject;
1616
import hudson.model.Result;
1717
import hudson.model.Run;
18-
import hudson.plugins.nested_view.search.BuildDetails;
19-
import hudson.plugins.nested_view.search.LinkableCandidate;
20-
import hudson.plugins.nested_view.search.NamableWithClass;
21-
import hudson.plugins.nested_view.search.Query;
2218

2319
public class ProjectWrapper {
2420

Diff for: src/main/resources/hudson/plugins/nested_view/NestedViewsSearch/search-results.jelly

+13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@
66
<l:layout title="${%Search for} '${q}'">
77
<l:side-panel>
88
<h2><l:icon class="icon-help icon-sm" /> Search help</h2>
9+
<a onclick="document.getElementById('button_expand_2_1').style.display = 'none'; document.getElementById('button_collapse_2_1').style.display = 'inline'; document.getElementById('details_2_1').style.display = 'block'; return false;"
10+
style="font-size: smaller; display: inline" href="#" id="button_expand_2_1">Search History (expand)</a>
11+
<a onclick="document.getElementById('button_collapse_2_1').style.display = 'none';document.getElementById('details_2_1').style.display = 'none';document.getElementById('button_expand_2_1').style.display = 'inline'; return false;"
12+
style="font-size: smaller; display: none" href="#" id="button_collapse_2_1">Search History (collapse)</a>
13+
<div style="display: none" id="details_2_1">
14+
<ol>
15+
<j:forEach var="hist" items="${it.getHistory()}">
16+
<li>
17+
<a href="${hist.getUrl()}" >${hist.getQuery()}</a><st:nbsp/><small>found ${hist.getSize()} at ${hist.getDate()}</small>
18+
</li>
19+
</j:forEach>
20+
</ol>
21+
</div>
922
<h3>${%Supported keywords with an example}</h3>
1023
<ol>
1124
<j:forEach var="help" items="${it.getSearchHelp()}">

0 commit comments

Comments
 (0)