mirror of https://github.com/jenkinsci/jenkins.git
Integrated a newer timeline component.
git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@25557 71c3de6d-444a-0410-be80-ed276b4c234a
This commit is contained in:
parent
df0170ec87
commit
43791a1a35
|
|
@ -352,7 +352,7 @@ THE SOFTWARE.
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.kohsuke.stapler</groupId>
|
<groupId>org.kohsuke.stapler</groupId>
|
||||||
<artifactId>stapler-adjunct-timeline</artifactId>
|
<artifactId>stapler-adjunct-timeline</artifactId>
|
||||||
<version>1.0</version>
|
<version>1.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency><!-- this helps us see the source code of the control while we edit Hudson. -->
|
<dependency><!-- this helps us see the source code of the control while we edit Hudson. -->
|
||||||
<groupId>org.kohsuke.stapler</groupId>
|
<groupId>org.kohsuke.stapler</groupId>
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ import hudson.util.ShiftedCategoryAxis;
|
||||||
import hudson.util.StackedAreaRenderer2;
|
import hudson.util.StackedAreaRenderer2;
|
||||||
import hudson.util.TextFile;
|
import hudson.util.TextFile;
|
||||||
import hudson.util.Graph;
|
import hudson.util.Graph;
|
||||||
import hudson.util.TimeUnit2;
|
|
||||||
import hudson.widgets.HistoryWidget;
|
import hudson.widgets.HistoryWidget;
|
||||||
import hudson.widgets.Widget;
|
import hudson.widgets.Widget;
|
||||||
import hudson.widgets.HistoryWidget.Adapter;
|
import hudson.widgets.HistoryWidget.Adapter;
|
||||||
|
|
@ -68,15 +67,16 @@ import java.io.StringWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
|
|
@ -85,7 +85,6 @@ import javax.xml.transform.TransformerFactory;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
|
||||||
import net.sf.json.JSONArray;
|
|
||||||
import net.sf.json.JSONObject;
|
import net.sf.json.JSONObject;
|
||||||
import net.sf.json.JSONException;
|
import net.sf.json.JSONException;
|
||||||
|
|
||||||
|
|
@ -109,6 +108,8 @@ import org.kohsuke.stapler.WebMethod;
|
||||||
import org.kohsuke.stapler.export.Exported;
|
import org.kohsuke.stapler.export.Exported;
|
||||||
import org.kohsuke.args4j.Argument;
|
import org.kohsuke.args4j.Argument;
|
||||||
import org.kohsuke.args4j.CmdLineException;
|
import org.kohsuke.args4j.CmdLineException;
|
||||||
|
import org.koshuke.stapler.simile.timeline.Event;
|
||||||
|
import org.koshuke.stapler.simile.timeline.TimelineEventList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A job is an runnable entity under the monitoring of Hudson.
|
* A job is an runnable entity under the monitoring of Hudson.
|
||||||
|
|
@ -621,6 +622,38 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
|
||||||
return _getRuns().get(n);
|
return _getRuns().get(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a list of builds, in the descending order, that are within the specified time range [start,end).
|
||||||
|
*
|
||||||
|
* @return can be empty but never null.
|
||||||
|
*/
|
||||||
|
public List<RunT> getBuildsByTimestamp(long start, long end) {
|
||||||
|
final List<RunT> builds = getBuilds();
|
||||||
|
AbstractList<Long> TIMESTAMP_ADAPTER = new AbstractList<Long>() {
|
||||||
|
public Long get(int index) {
|
||||||
|
return builds.get(index).timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return builds.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Comparator<Long> DESCENDING_ORDER = new Comparator<Long>() {
|
||||||
|
public int compare(Long o1, Long o2) {
|
||||||
|
if (o1 > o2) return -1;
|
||||||
|
if (o1 < o2) return +1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int s = Collections.binarySearch(TIMESTAMP_ADAPTER, start, DESCENDING_ORDER);
|
||||||
|
if (s<0) s=-(s+1); // min is inclusive
|
||||||
|
int e = Collections.binarySearch(TIMESTAMP_ADAPTER, end, DESCENDING_ORDER);
|
||||||
|
if (e<0) e=-(e+1); else e++; // max is exclusive, so the exact match should be excluded
|
||||||
|
|
||||||
|
return builds.subList(e,s);
|
||||||
|
}
|
||||||
|
|
||||||
@CLIResolver
|
@CLIResolver
|
||||||
public RunT getBuildForCLI(@Argument(required=true,metaVar="BUILD#",usage="Build number") String id) throws CmdLineException {
|
public RunT getBuildForCLI(@Argument(required=true,metaVar="BUILD#",usage="Build number") String id) throws CmdLineException {
|
||||||
try {
|
try {
|
||||||
|
|
@ -1285,27 +1318,22 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
|
||||||
return Hudson.getInstance().getAuthorizationStrategy().getACL(this);
|
return Hudson.getInstance().getAuthorizationStrategy().getACL(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doTimelineData(@QueryParameter long min, @QueryParameter long max, StaplerResponse rsp) throws IOException {
|
public TimelineEventList doTimelineData(StaplerRequest req, @QueryParameter long min, @QueryParameter long max) throws IOException {
|
||||||
Date l = new Date(min);
|
TimelineEventList result = new TimelineEventList();
|
||||||
Date h = new Date(max);
|
for (RunT r : getBuildsByTimestamp(min,max)) {
|
||||||
List<Event> result = new ArrayList<Event>();
|
|
||||||
for (int i=0; i<10; i++) {
|
|
||||||
Event e = new Event();
|
Event e = new Event();
|
||||||
e.start = new Date(min+ TimeUnit2.HOURS.toMillis(i));
|
e.start = r.getTime();
|
||||||
e.title = "Event "+i;
|
e.end = new Date(r.timestamp+r.getDuration());
|
||||||
e.description = "Longish description of event "+i;
|
e.title = r.getFullDisplayName();
|
||||||
JSONObject.fromObject(e);
|
// what to put in the description?
|
||||||
|
// e.description = "Longish description of event "+r.getFullDisplayName();
|
||||||
|
// e.durationEvent = true;
|
||||||
|
e.link = req.getContextPath()+'/'+r.getUrl();
|
||||||
|
BallColor c = r.getIconColor();
|
||||||
|
e.color = String.format("#%06X",c.getBaseColor().darker().getRGB()&0xFFFFFF);
|
||||||
|
e.classname = "event-"+c.noAnime().toString()+" " + (c.isAnimated()?"animated":"");
|
||||||
result.add(e);
|
result.add(e);
|
||||||
}
|
}
|
||||||
JSONObject o = new JSONObject();
|
return result;
|
||||||
o.put("events", JSONArray.fromObject(result));
|
|
||||||
rsp.setContentType("application/javascript;charset=UTF-8");
|
|
||||||
o.write(rsp.getWriter());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Event {
|
|
||||||
public Date start;
|
|
||||||
public Date end;
|
|
||||||
public String title, description;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,28 +32,6 @@ THE SOFTWARE.
|
||||||
<div id="tl" style="height:500px; border:1px solid black;" />
|
<div id="tl" style="height:500px; border:1px solid black;" />
|
||||||
<div id="status" />
|
<div id="status" />
|
||||||
<script><![CDATA[
|
<script><![CDATA[
|
||||||
var timeline_data = { // save as a global variable
|
|
||||||
'dateTimeFormat': 'iso8601',
|
|
||||||
|
|
||||||
'events' : [
|
|
||||||
{'start': '1924',
|
|
||||||
'title': 'Barfusserkirche',
|
|
||||||
'description': 'by Lyonel Feininger, American/German Painter, 1871-1956',
|
|
||||||
'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
|
|
||||||
'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
{'start': '1900',
|
|
||||||
'end': '1913',
|
|
||||||
'title': 'Three Figures',
|
|
||||||
'description': 'by Kasimir Malevich, Ukrainian Painter, 1878-1935',
|
|
||||||
'image': 'http://images.allposters.com/images/BRGPOD/75857_b.jpg',
|
|
||||||
'link': 'http://www.allposters.com/-sp/Three-Figures-1913-28-Posters_i1349989_.htm'
|
|
||||||
}
|
|
||||||
]};
|
|
||||||
|
|
||||||
var tl;
|
|
||||||
window.addEventListener('load', function() {
|
window.addEventListener('load', function() {
|
||||||
var tl_el = document.getElementById("tl");
|
var tl_el = document.getElementById("tl");
|
||||||
var eventSource1 = new Timeline.DefaultEventSource();
|
var eventSource1 = new Timeline.DefaultEventSource();
|
||||||
|
|
@ -61,6 +39,7 @@ THE SOFTWARE.
|
||||||
var interval = 24*60*60*1000;
|
var interval = 24*60*60*1000;
|
||||||
eventSource1.ensureVisible = function(band) {
|
eventSource1.ensureVisible = function(band) {
|
||||||
// make sure all data are loaded for the portion visible in the band
|
// make sure all data are loaded for the portion visible in the band
|
||||||
|
// $('status').innerHTML = "min="+band.getMinDate()+" max="+band.getMaxDate();
|
||||||
var min = Math.floor(band.getMinDate().getTime()/interval);
|
var min = Math.floor(band.getMinDate().getTime()/interval);
|
||||||
var max = Math.ceil(band.getMaxDate().getTime()/interval);
|
var max = Math.ceil(band.getMaxDate().getTime()/interval);
|
||||||
for (var i=min; i<=max; i++) {
|
for (var i=min; i<=max; i++) {
|
||||||
|
|
@ -70,7 +49,11 @@ THE SOFTWARE.
|
||||||
method:"POST",
|
method:"POST",
|
||||||
parameters: {min: i*interval, max:(i+1)*interval},
|
parameters: {min: i*interval, max:(i+1)*interval},
|
||||||
onSuccess: function(t) {
|
onSuccess: function(t) {
|
||||||
eventSource1.loadJSON(eval(t.responseText));
|
try {
|
||||||
|
eventSource1.loadJSON(eval('('+t.responseText+')'),'.');
|
||||||
|
} catch (e) {
|
||||||
|
alert(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -82,10 +65,10 @@ THE SOFTWARE.
|
||||||
// theme1.autoWidth = true; // Set the Timeline's "width" automatically.
|
// theme1.autoWidth = true; // Set the Timeline's "width" automatically.
|
||||||
// Set autoWidth on the Timeline's first band's theme,
|
// Set autoWidth on the Timeline's first band's theme,
|
||||||
// will affect all bands.
|
// will affect all bands.
|
||||||
theme1.timeline_start = new Date(Date.UTC(1890, 0, 1));
|
theme1.timeline_start = new Date(${it.firstBuild.timeInMillis-24*60*60*1000});
|
||||||
theme1.timeline_stop = new Date(Date.UTC(2160, 0, 1));
|
theme1.timeline_stop = new Date(${it.lastBuild.timeInMillis+24*60*60*1000});
|
||||||
|
|
||||||
var d = Timeline.DateTime.parseGregorianDateTime("1900")
|
var d = theme1.timeline_stop;
|
||||||
var bandInfos = [
|
var bandInfos = [
|
||||||
// the bar that shows outline
|
// the bar that shows outline
|
||||||
Timeline.createBandInfo({
|
Timeline.createBandInfo({
|
||||||
|
|
@ -110,18 +93,15 @@ THE SOFTWARE.
|
||||||
bandInfos[0].syncWith = 1;
|
bandInfos[0].syncWith = 1;
|
||||||
|
|
||||||
// create the Timeline
|
// create the Timeline
|
||||||
tl = Timeline.create(tl_el, bandInfos, Timeline.HORIZONTAL);
|
var tl = Timeline.create(tl_el, bandInfos, Timeline.HORIZONTAL);
|
||||||
|
|
||||||
tl.getBand(1).addOnScrollListener(function(band) {
|
tl.getBand(0).addOnScrollListener(function(band) {
|
||||||
eventSource1.ensureVisible(band);
|
eventSource1.ensureVisible(band);
|
||||||
});
|
});
|
||||||
|
|
||||||
var url = '.'; // The base url for image, icon and background image
|
|
||||||
// references in the data
|
|
||||||
eventSource1.loadJSON(timeline_data, url);
|
|
||||||
tl.layout(); // display the Timeline
|
tl.layout(); // display the Timeline
|
||||||
},false);
|
|
||||||
|
|
||||||
|
// if resized, redo layout
|
||||||
var resizeTimerID = null;
|
var resizeTimerID = null;
|
||||||
window.addEventListener('resize',function() {
|
window.addEventListener('resize',function() {
|
||||||
if (resizeTimerID == null) {
|
if (resizeTimerID == null) {
|
||||||
|
|
@ -131,6 +111,7 @@ THE SOFTWARE.
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
},false);
|
},false);
|
||||||
|
},false);
|
||||||
]]></script>
|
]]></script>
|
||||||
</l:main-panel>
|
</l:main-panel>
|
||||||
</l:layout>
|
</l:layout>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue