未验证 提交 9537ee51 编写于 作者: O Oleg Nenashev 提交者: GitHub

Show plugin release date in plugin manager (#4535)

* Show plugin release date in plugin manager

* Add at-since
Co-Authored-By: NOleg Nenashev <o.v.nenashev@gmail.com>

* Make sorting work property

- Sort independently of sortable.js date parsing magic
- Hide categories when sorting by release date

* Show friendlier labels for the age of plugin releases
Co-authored-by: NOleg Nenashev <o.v.nenashev@gmail.com>
上级 3ebb9e35
......@@ -27,6 +27,8 @@ package hudson;
import hudson.model.Slave;
import hudson.security.*;
import java.text.SimpleDateFormat;
import java.util.function.Predicate;
import jenkins.util.SystemProperties;
import hudson.cli.CLICommand;
......@@ -219,10 +221,36 @@ public class Functions {
return Util.XS_DATETIME_FORMATTER.format(cal.getTime());
}
@Restricted(NoExternalUse.class)
public static String iso8601DateTime(Date date) {
return Util.XS_DATETIME_FORMATTER.format(date);
}
/**
* Returns a localized string for the specified date, not including time.
* @param date
* @return
*/
@Restricted(NoExternalUse.class)
public static String localDate(Date date) {
return SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT).format(date);
}
public static String rfc822Date(Calendar cal) {
return Util.RFC822_DATETIME_FORMATTER.format(cal.getTime());
}
/**
* Returns a human-readable string describing the time difference between now and the specified date.
*
* @param date
* @return
*/
@Restricted(NoExternalUse.class)
public static String getTimeSpanString(Date date) {
return Util.getTimeSpanString(Math.abs(date.getTime() - new Date().getTime()));
}
/**
* During Jenkins start-up, before {@link InitMilestone#PLUGINS_STARTED} the extensions lists will be empty
* and they are not guaranteed to be fully populated until after {@link InitMilestone#EXTENSIONS_AUGMENTED},
......
......@@ -43,8 +43,10 @@ import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
......@@ -1019,6 +1021,13 @@ public class UpdateSite {
*/
private Set<Plugin> incompatibleParentPlugins;
/**
* Date when this plugin was released.
* @since TODO
*/
@Exported
public final Date releaseTimestamp;
@DataBoundConstructor
public Plugin(String sourceId, JSONObject o) {
super(sourceId, o, UpdateSite.this.url);
......@@ -1028,6 +1037,16 @@ public class UpdateSite {
this.compatibleSinceVersion = Util.intern(get(o,"compatibleSinceVersion"));
this.minimumJavaVersion = Util.intern(get(o, "minimumJavaVersion"));
this.requiredCore = Util.intern(get(o,"requiredCore"));
final String releaseTimestamp = get(o, "releaseTimestamp");
Date date = null;
if (releaseTimestamp != null) {
try {
date = Date.from(Instant.parse(releaseTimestamp));
} catch (Exception ex) {
LOGGER.log(Level.FINE, "Failed to parse releaseTimestamp for " + title + " from " + sourceId, ex);
}
}
this.releaseTimestamp = date;
this.categories = o.has("labels") ? internInPlace((String[])o.getJSONArray("labels").toArray(EMPTY_STRING_ARRAY)) : null;
JSONArray ja = o.getJSONArray("dependencies");
int depCount = (int)(ja.stream().filter(IS_DEP_PREDICATE.and(IS_NOT_OPTIONAL)).count());
......
......@@ -4,6 +4,10 @@
width: 15em;
}
time {
white-space: nowrap;
}
#filter-container {
margin: 1em;
text-align: right;
......
......@@ -30,7 +30,7 @@ THE SOFTWARE.
page: page name to be passed to local:tabBar
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout title="${%Update Center}" permission="${app.ADMINISTER}">
<st:include page="sidepanel.jelly"/>
<l:main-panel>
......@@ -52,6 +52,7 @@ THE SOFTWARE.
width="32">${%Install}</th>
<th initialSortDir="${isUpdates?'down':null}">${%Name}</th>
<th>${%Version}</th>
<th>${%Released}</th>
<j:if test="${isUpdates}"><th>${%Installed}</th></j:if>
</tr>
<j:choose>
......@@ -132,6 +133,13 @@ THE SOFTWARE.
</j:if>
</td>
<td class="pane"><st:out value="${p.version}" /></td>
<td class="pane" data="${p.releaseTimestamp.time}">
<j:if test="${p.releaseTimestamp != null}">
<time datetime="${h.iso8601DateTime(p.releaseTimestamp)}" tooltip="${h.localDate(p.releaseTimestamp)}">
${%ago(h.getTimeSpanString(p.releaseTimestamp))}
</time>
</j:if>
</td>
<j:if test="${isUpdates}">
<td class="pane">
<j:choose><j:when test="${p.installed.active}">
......
......@@ -45,4 +45,4 @@ depJavaWarning=\
and in turn loading this plugin will fail.
securityWarning=\
Warning: This plugin version may not be safe to use. Please review the following security notices:
ago={0} ago
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册