Refinements to push log display and daily digests
* Properly support timezone-based date groupings
* Polish css for the major browsers on Win & Linux
* Use Gitblit constants for refs instead of JGit constants
| | |
| | |
|
| | | public static final String ISO8601 = "yyyy-MM-dd'T'HH:mm:ssZ";
|
| | |
|
| | | public static final String R_GITBLIT = "refs/gitblit/";
|
| | | |
| | | public static final String baseFolder = "baseFolder";
|
| | |
|
| | | public static final String baseFolder$ = "${" + baseFolder + "}";
|
| | |
|
| | | public static final String contextFolder$ = "${contextFolder}";
|
| | | |
| | | public static final String HEAD = "HEAD";
|
| | |
|
| | | public static final String R_GITBLIT = "refs/gitblit/";
|
| | | |
| | | public static final String R_HEADS = "refs/heads/";
|
| | | |
| | | public static final String R_NOTES = "refs/notes/";
|
| | | |
| | | public static final String R_CHANGES = "refs/changes/";
|
| | | |
| | | public static final String R_PULL= "refs/pull/";
|
| | |
|
| | | public static final String R_TAGS = "refs/tags/";
|
| | | |
| | | public static final String R_REMOTES = "refs/remotes/";
|
| | |
|
| | | public static String getVersion() {
|
| | | String v = Constants.class.getPackage().getImplementationVersion();
|
| | |
| | | }
|
| | | translation = bundle;
|
| | |
|
| | | timeUtils = new TimeUtils(translation);
|
| | | timeUtils = new TimeUtils(translation, null);
|
| | | }
|
| | |
|
| | | public static String get(String key) {
|
| | |
| | | import java.util.Date; |
| | | |
| | | import org.eclipse.jgit.lib.PersonIdent; |
| | | import org.eclipse.jgit.transport.ReceiveCommand; |
| | | |
| | | /** |
| | | * Model class to simulate a push for presentation in the push log news feed |
| | |
| | | |
| | | return super.getAuthorIdent(); |
| | | } |
| | | |
| | | /** |
| | | * Tracks the change type for the specified ref. |
| | | * |
| | | * @param ref |
| | | * @param type |
| | | * @param oldId |
| | | * @param newId |
| | | */ |
| | | public void updateRef(String ref, ReceiveCommand.Type type, String oldId, String newId) { |
| | | // daily digests are filled from most recent to oldest |
| | | String preservedNewId = getNewId(ref); |
| | | if (preservedNewId == null) { |
| | | // no preserved new id, this is newest commit |
| | | // for this ref |
| | | preservedNewId = newId; |
| | | } |
| | | refUpdates.put(ref, type); |
| | | refIdChanges.put(ref, oldId + "-" + preservedNewId); |
| | | } |
| | | |
| | | } |
| | |
| | |
|
| | | private final Set<RepositoryCommit> commits;
|
| | |
|
| | | private final Map<String, ReceiveCommand.Type> refUpdates;
|
| | | protected final Map<String, ReceiveCommand.Type> refUpdates;
|
| | |
|
| | | private final Map<String, String> refIdChanges;
|
| | | protected final Map<String, String> refIdChanges;
|
| | |
|
| | | private int authorCount;
|
| | |
|
| | |
| | | return !accessRestriction.atLeast(AccessRestrictionType.VIEW);
|
| | | }
|
| | |
|
| | | public boolean isShowActivity() {
|
| | | return maxActivityCommits > -1;
|
| | | }
|
| | | |
| | | public boolean isSparkleshared() {
|
| | | return !StringUtils.isEmpty(sparkleshareId);
|
| | | }
|
| | |
| | |
|
| | | Map<String, Activity> activity = new HashMap<String, Activity>();
|
| | | for (RepositoryModel model : models) {
|
| | | if (model.maxActivityCommits == -1) {
|
| | | if (!model.isShowActivity()) {
|
| | | // skip this repository
|
| | | continue;
|
| | | }
|
| | |
| | | import java.text.MessageFormat; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.Date; |
| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.TimeZone; |
| | | import java.util.TreeSet; |
| | | |
| | | import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; |
| | |
| | | import org.eclipse.jgit.dircache.DirCacheEntry; |
| | | import org.eclipse.jgit.internal.JGitText; |
| | | import org.eclipse.jgit.lib.CommitBuilder; |
| | | import org.eclipse.jgit.lib.Constants; |
| | | import org.eclipse.jgit.lib.FileMode; |
| | | import org.eclipse.jgit.lib.ObjectId; |
| | | import org.eclipse.jgit.lib.ObjectInserter; |
| | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.models.DailyLogEntry; |
| | | import com.gitblit.models.PathModel.PathChangeModel; |
| | | import com.gitblit.models.PushLogEntry; |
| | |
| | | CommitBuilder commit = new CommitBuilder(); |
| | | commit.setAuthor(ident); |
| | | commit.setCommitter(ident); |
| | | commit.setEncoding(Constants.CHARACTER_ENCODING); |
| | | commit.setEncoding(Constants.ENCODING); |
| | | commit.setMessage(message); |
| | | commit.setParentId(headId); |
| | | commit.setTreeId(indexTreeId); |
| | |
| | | dcEntry.setFileMode(FileMode.REGULAR_FILE); |
| | | |
| | | // insert object |
| | | dcEntry.setObjectId(inserter.insert(Constants.OBJ_BLOB, content.getBytes("UTF-8"))); |
| | | dcEntry.setObjectId(inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, content.getBytes("UTF-8"))); |
| | | |
| | | // add to temporary in-core index |
| | | dcBuilder.add(dcEntry); |
| | |
| | | * @param offset |
| | | * @param maxCount |
| | | * if < 0, all pushes are returned. |
| | | * @param the timezone to use when aggregating commits by date |
| | | * @return a list of grouped commit log entries |
| | | */ |
| | | public static List<DailyLogEntry> getDailyLog(String repositoryName, Repository repository, |
| | | Date minimumDate, int offset, int maxCount) { |
| | | |
| | | Date minimumDate, int offset, int maxCount, |
| | | TimeZone timezone) { |
| | | DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); |
| | | // df.setTimeZone(timezone); |
| | | df.setTimeZone(timezone); |
| | | |
| | | Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository); |
| | | Map<String, DailyLogEntry> tags = new HashMap<String, DailyLogEntry>(); |
| | | Map<String, DailyLogEntry> pulls = new HashMap<String, DailyLogEntry>(); |
| | | Map<String, DailyLogEntry> dailydigests = new HashMap<String, DailyLogEntry>(); |
| | | String linearParent = null; |
| | | for (RefModel local : JGitUtils.getLocalBranches(repository, true, -1)) { |
| | | String branch = local.getName(); |
| | | List<RevCommit> commits = JGitUtils.getRevLog(repository, branch, minimumDate); |
| | | for (RevCommit commit : commits) { |
| | | if (linearParent != null) { |
| | | if (!commit.getName().equals(linearParent)) { |
| | | // only follow linear branch commits |
| | | continue; |
| | | } |
| | | } |
| | | Date date = JGitUtils.getCommitDate(commit); |
| | | String dateStr = df.format(date); |
| | | if (!dailydigests.containsKey(dateStr)) { |
| | | dailydigests.put(dateStr, new DailyLogEntry(repositoryName, date)); |
| | | } |
| | | PushLogEntry digest = dailydigests.get(dateStr); |
| | | DailyLogEntry digest = dailydigests.get(dateStr); |
| | | if (commit.getParentCount() == 0) { |
| | | linearParent = null; |
| | | digest.updateRef(branch, ReceiveCommand.Type.CREATE); |
| | | } else { |
| | | digest.updateRef(branch, ReceiveCommand.Type.UPDATE, commit.getParents()[0].getId().getName(), commit.getName()); |
| | | linearParent = commit.getParents()[0].getId().getName(); |
| | | digest.updateRef(branch, ReceiveCommand.Type.UPDATE, linearParent, commit.getName()); |
| | | } |
| | | |
| | | RepositoryCommit repoCommit = digest.addCommit(branch, commit); |
| | | if (repoCommit != null) { |
| | | repoCommit.setRefs(allRefs.get(commit.getId())); |
| | | if (!ArrayUtils.isEmpty(repoCommit.getRefs())) { |
| | | // treat tags as special events in the log |
| | | for (RefModel ref : repoCommit.getRefs()) { |
| | | List<RefModel> matchedRefs = allRefs.get(commit.getId()); |
| | | repoCommit.setRefs(matchedRefs); |
| | | |
| | | if (!ArrayUtils.isEmpty(matchedRefs)) { |
| | | for (RefModel ref : matchedRefs) { |
| | | if (ref.getName().startsWith(Constants.R_TAGS)) { |
| | | // treat tags as special events in the log |
| | | if (!tags.containsKey(dateStr)) { |
| | | UserModel tagUser = newUserModelFrom(commit.getAuthorIdent()); |
| | | Date tagDate = commit.getAuthorIdent().getWhen(); |
| | | tags.put(dateStr, new DailyLogEntry(repositoryName, tagDate, tagUser)); |
| | | tags.put(dateStr, new DailyLogEntry(repositoryName, tagDate, tagUser)); |
| | | } |
| | | PushLogEntry tagEntry = tags.get(dateStr); |
| | | tagEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); |
| | | tagEntry.addCommits(Arrays.asList(repoCommit)); |
| | | tagEntry.addCommit(ref.getName(), commit); |
| | | } else if (ref.getName().startsWith(Constants.R_PULL)) { |
| | | // treat pull requests as special events in the log |
| | | if (!pulls.containsKey(dateStr)) { |
| | | UserModel commitUser = newUserModelFrom(commit.getAuthorIdent()); |
| | | Date commitDate = commit.getAuthorIdent().getWhen(); |
| | | pulls.put(dateStr, new DailyLogEntry(repositoryName, commitDate, commitUser)); |
| | | } |
| | | PushLogEntry pullEntry = pulls.get(dateStr); |
| | | pullEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); |
| | | pullEntry.addCommit(ref.getName(), commit); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | List<DailyLogEntry> list = new ArrayList<DailyLogEntry>(dailydigests.values()); |
| | | list.addAll(tags.values()); |
| | | //list.addAll(pulls.values()); |
| | | Collections.sort(list); |
| | | return list; |
| | | } |
| | |
| | | * @param repositoryName |
| | | * @param repository |
| | | * @param minimumDate |
| | | * @param the timezone to use when aggregating commits by date |
| | | * @return a list of push log entries separated by ref and date |
| | | */ |
| | | public static List<DailyLogEntry> getDailyLogByRef(String repositoryName, Repository repository, Date minimumDate) { |
| | | public static List<DailyLogEntry> getDailyLogByRef(String repositoryName, Repository repository, |
| | | Date minimumDate, TimeZone timezone) { |
| | | // break the push log into ref push logs and then merge them back into a list |
| | | Map<String, List<DailyLogEntry>> refMap = new HashMap<String, List<DailyLogEntry>>(); |
| | | List<DailyLogEntry> pushes = getDailyLog(repositoryName, repository, minimumDate, 0, -1); |
| | | List<DailyLogEntry> pushes = getDailyLog(repositoryName, repository, minimumDate, 0, -1, timezone); |
| | | for (DailyLogEntry push : pushes) { |
| | | for (String ref : push.getChangedRefs()) { |
| | | if (!refMap.containsKey(ref)) { |
| | |
| | | import java.util.Calendar;
|
| | | import java.util.Date;
|
| | | import java.util.ResourceBundle;
|
| | | import java.util.TimeZone;
|
| | |
|
| | | /**
|
| | | * Utility class of time functions.
|
| | |
| | |
|
| | | private final ResourceBundle translation;
|
| | |
|
| | | private final TimeZone timezone;
|
| | | |
| | | public TimeUtils() {
|
| | | this(null);
|
| | | this(null, null);
|
| | | }
|
| | |
|
| | | public TimeUtils(ResourceBundle translation) {
|
| | | public TimeUtils(ResourceBundle translation, TimeZone timezone) {
|
| | | this.translation = translation;
|
| | | this.timezone = timezone;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @param date
|
| | | * @return true if date is today
|
| | | */
|
| | | public static boolean isToday(Date date) {
|
| | | return (System.currentTimeMillis() - date.getTime()) < ONEDAY;
|
| | | public static boolean isToday(Date date, TimeZone timezone) {
|
| | | Date now = new Date();
|
| | | SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
|
| | | if (timezone != null) {
|
| | | df.setTimeZone(timezone);
|
| | | }
|
| | | return df.format(now).equals(df.format(date));
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @param date
|
| | | * @return true if date is yesterday
|
| | | */
|
| | | public static boolean isYesterday(Date date) {
|
| | | public static boolean isYesterday(Date date, TimeZone timezone) {
|
| | | Calendar cal = Calendar.getInstance();
|
| | | cal.setTime(new Date());
|
| | | cal.add(Calendar.DATE, -1);
|
| | | SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
|
| | | if (timezone != null) {
|
| | | df.setTimeZone(timezone);
|
| | | }
|
| | | return df.format(cal.getTime()).equals(df.format(date));
|
| | | }
|
| | |
|
| | |
| | | * @return the string representation of the duration OR the css class
|
| | | */
|
| | | private String timeAgo(Date date, boolean css) {
|
| | | if (isToday(date) || isYesterday(date)) {
|
| | | if (isToday(date, timezone) || isYesterday(date, timezone)) {
|
| | | int mins = minutesAgo(date, true);
|
| | | if (mins >= 120) {
|
| | | if (css) {
|
| | |
| | | gb.pushedNewBranch = pushed new branch |
| | | gb.createdNewBranch = created new branch |
| | | gb.deletedBranch = deleted branch |
| | | gb.createdNewPullRequest = created pull request |
| | | gb.mergedPullRequest = merged pull request |
| | | gb.rewind = REWIND |
| | | gb.star = star |
| | | gb.unstar = unstar |
| | |
| | | gb.starredRepositories = starred repositories |
| | | gb.failedToUpdateUser = Failed to update user account! |
| | | gb.myRepositories = my repositories |
| | | gb.noActivity = there has been no recent commit activity |
| | | gb.findSomeRepositories = find some repositories |
| | |
| | | dateString = df.format(date);
|
| | | }
|
| | | String title = null;
|
| | | if (TimeUtils.isToday(date)) {
|
| | | if (TimeUtils.isToday(date, timeZone)) {
|
| | | title = timeUtils.today();
|
| | | } else if (TimeUtils.isYesterday(date)) {
|
| | | } else if (TimeUtils.isYesterday(date, timeZone)) {
|
| | | title = timeUtils.yesterday();
|
| | | } else if (date.getTime() <= System.currentTimeMillis()) {
|
| | | // past
|
| | |
| | | } catch (Throwable t) {
|
| | | bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp");
|
| | | }
|
| | | timeUtils = new TimeUtils(bundle);
|
| | | timeUtils = new TimeUtils(bundle, getTimeZone());
|
| | | }
|
| | | return timeUtils;
|
| | | }
|
| | |
| | |
|
| | | protected void setupPage(String repositoryName, String pageName) {
|
| | | String siteName = GitBlit.getString(Keys.web.siteName, Constants.NAME);
|
| | | if (StringUtils.isEmpty(siteName)) {
|
| | | siteName = Constants.NAME;
|
| | | }
|
| | | if (repositoryName != null && repositoryName.trim().length() > 0) {
|
| | | add(new Label("title", repositoryName + " - " + siteName));
|
| | | } else {
|
| | |
| | | </tr>
|
| | | </table>
|
| | | </div>
|
| | | <div wicket:id="pushes"></div>
|
| | | <div wicket:id="digests"></div>
|
| | | </div>
|
| | | <div class="span5">
|
| | | <div wicket:id="active">[active]</div>
|
| | |
| | | <div ng-repeat="item in starred | limitTo: 20 | filter:query" style="padding: 3px;border-top: 1px solid #ddd;">
|
| | | <b><span class="repositorySwatch" style="background-color:{{item.c}};"><span ng-show="item.wc">!</span><span ng-show="!item.wc"> </span></span></b>
|
| | | <a href="summary/?r={{item.r}}">{{item.p}}<b>{{item.n}}</b></a>
|
| | | <span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
|
| | | <span class="link hidden-tablet hidden-phone" style="color: #aaa;" title="{{item.d}}">{{item.t}}</span>
|
| | | <span ng-show="item.s" class="pull-right">
|
| | | <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i class="iconic-star"></i></span>
|
| | | <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i style="vertical-align:baseline;" class="iconic-star"></i></span>
|
| | | </span>
|
| | | </div>
|
| | |
|
| | |
| | | <a href="summary/?r={{item.r}}">{{item.p}}<b>{{item.n}}</b></a>
|
| | | <span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
|
| | | <span ng-show="item.s" class="pull-right">
|
| | | <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i class="iconic-star"></i></span>
|
| | | <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i style="vertical-align:baseline;" class="iconic-star"></i></span>
|
| | | </span>
|
| | | </div>
|
| | | </div>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="activeListFragment">
|
| | | <div ng-controller="activeCtrl" style="border: 1px solid #ddd;border-radius: 4px;">
|
| | | <div ng-controller="activeCtrl" style="border: 1px solid #ddd;border-radius: 4px;margin-bottom: 20px;">
|
| | | <div class="header" style="padding: 5px;border: none;"><i class="icon-user"></i> <wicket:message key="gb.activeRepositories"></wicket:message> ({{active.length}})
|
| | | <div style="padding: 5px 0px 0px;">
|
| | | <input type="text" ng-model="query.r" class="input-large" wicket:message="placeholder:gb.filter" style="border-radius: 14px; padding: 3px 14px;margin: 0px;"></input>
|
| | |
| | | <a href="summary/?r={{item.r}}">{{item.p}}<b>{{item.n}}</b></a>
|
| | | <span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
|
| | | <span ng-show="item.s" class="pull-right">
|
| | | <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i class="iconic-star"></i></span>
|
| | | <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i style="vertical-align:baseline;" class="iconic-star"></i></span>
|
| | | </span>
|
| | | </div>
|
| | | </div>
|
| | |
| | | import java.util.Comparator;
|
| | | import java.util.Date;
|
| | | import java.util.HashMap;
|
| | | import java.util.HashSet;
|
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | | import java.util.Set;
|
| | | import java.util.TimeZone;
|
| | |
|
| | | import org.apache.wicket.Component;
|
| | | import org.apache.wicket.PageParameters;
|
| | |
| | | add(repositoriesMessage);
|
| | |
|
| | | UserModel user = GitBlitWebSession.get().getUser();
|
| | | if (user == null) {
|
| | | user = UserModel.ANONYMOUS;
|
| | | }
|
| | |
|
| | | Comparator<RepositoryModel> lastUpdateSort = new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | |
| | | }
|
| | | };
|
| | |
|
| | | Map<String, RepositoryModel> reposMap = new HashMap<String, RepositoryModel>();
|
| | |
|
| | | // owned repositories |
| | | List<RepositoryModel> owned = new ArrayList<RepositoryModel>();
|
| | | if (user != null && !UserModel.ANONYMOUS.equals(user)) {
|
| | | for (RepositoryModel model : GitBlit.self().getRepositoryModels(user)) {
|
| | | reposMap.put(model.name, model);
|
| | | if (model.isUsersPersonalRepository(user.username) || model.isOwner(user.username)) {
|
| | | owned.add(model);
|
| | | }
|
| | | }
|
| | | }
|
| | | Collections.sort(owned, lastUpdateSort);
|
| | |
|
| | | // starred repositories
|
| | | List<RepositoryModel> starred = new ArrayList<RepositoryModel>();
|
| | | if (user != null && !UserModel.ANONYMOUS.equals(user)) {
|
| | | for (String name : user.getPreferences().getStarredRepositories()) {
|
| | | if (!reposMap.containsKey(name)) {
|
| | | RepositoryModel repo = GitBlit.self().getRepositoryModel(name);
|
| | | reposMap.put(name, repo);
|
| | | }
|
| | | starred.add(reposMap.get(name));
|
| | | }
|
| | | }
|
| | | Collections.sort(starred, lastUpdateSort);
|
| | | |
| | | // parameters
|
| | | int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params);
|
| | | if (daysBack < 1) {
|
| | |
| | | Calendar c = Calendar.getInstance();
|
| | | c.add(Calendar.DATE, -1*daysBack);
|
| | | Date minimumDate = c.getTime();
|
| | | TimeZone timezone = getTimeZone();
|
| | |
|
| | | // active repositories (displayed for anonymous users)
|
| | | // build repo lists |
| | | List<RepositoryModel> starred = new ArrayList<RepositoryModel>();
|
| | | List<RepositoryModel> owned = new ArrayList<RepositoryModel>();
|
| | | List<RepositoryModel> active = new ArrayList<RepositoryModel>();
|
| | | if (user == null || UserModel.ANONYMOUS.equals(user)) {
|
| | | List<RepositoryModel> list = GitBlit.self().getRepositoryModels(UserModel.ANONYMOUS);
|
| | | for (RepositoryModel model : list) {
|
| | | if (model.lastChange.after(minimumDate)) {
|
| | | active.add(model);
|
| | | reposMap.put(model.name, model);
|
| | | }
|
| | |
|
| | | for (RepositoryModel model : GitBlit.self().getRepositoryModels(user)) {
|
| | | if (model.isUsersPersonalRepository(user.username) || model.isOwner(user.username)) {
|
| | | owned.add(model);
|
| | | }
|
| | | Collections.sort(active, lastUpdateSort);
|
| | | |
| | | if (user.getPreferences().isStarredRepository(model.name)) {
|
| | | starred.add(model);
|
| | | }
|
| | | |
| | | if (model.isShowActivity() && model.lastChange.after(minimumDate)) {
|
| | | active.add(model);
|
| | | }
|
| | | }
|
| | |
|
| | | // show pushlog feed
|
| | | Collections.sort(owned, lastUpdateSort);
|
| | | Collections.sort(starred, lastUpdateSort);
|
| | | Collections.sort(active, lastUpdateSort);
|
| | | |
| | | Set<RepositoryModel> feedSources = new HashSet<RepositoryModel>();
|
| | | feedSources.addAll(starred);
|
| | | if (feedSources.isEmpty()) {
|
| | | feedSources.addAll(active);
|
| | | }
|
| | | |
| | | // create daily commit digest feed
|
| | | List<PushLogEntry> pushes = new ArrayList<PushLogEntry>();
|
| | | for (RepositoryModel model : reposMap.values()) {
|
| | | for (RepositoryModel model : feedSources) {
|
| | | Repository repository = GitBlit.self().getRepository(model.name);
|
| | | List<DailyLogEntry> entries = PushLogUtils.getDailyLogByRef(model.name, repository, minimumDate);
|
| | | List<DailyLogEntry> entries = PushLogUtils.getDailyLogByRef(model.name, repository, minimumDate, timezone);
|
| | | pushes.addAll(entries);
|
| | | repository.close();
|
| | | }
|
| | |
|
| | | if (pushes.size() == 0) {
|
| | | if (reposMap.size() == 0) {
|
| | | add(new LinkPanel("pushes", null, "find some repositories", RepositoriesPage.class));
|
| | | // quiet or no starred repositories
|
| | | if (feedSources.size() == 0) {
|
| | | if (UserModel.ANONYMOUS.equals(user)) {
|
| | | add(new Label("digests", getString("gb.noActivity"))); |
| | | } else {
|
| | | add(new LinkPanel("digests", null, getString("gb.findSomeRepositories"), RepositoriesPage.class));
|
| | | }
|
| | | } else {
|
| | | add(new Label("pushes", "all is quiet"));
|
| | | add(new Label("digests", getString("gb.noActivity")));
|
| | | }
|
| | | } else {
|
| | | // show daily commit digest feed
|
| | | Collections.sort(pushes);
|
| | | add(new PushesPanel("pushes", pushes));
|
| | | add(new PushesPanel("digests", pushes));
|
| | | }
|
| | |
|
| | | // add the nifty charts
|
| | |
| | | }
|
| | |
|
| | | // active repository list
|
| | | if (ArrayUtils.isEmpty(active)) {
|
| | | add(new Label("active").setVisible(false));
|
| | | } else {
|
| | | if (starred.isEmpty()) {
|
| | | Fragment activeView = createNgList("active", "activeListFragment", "activeCtrl", active);
|
| | | add(activeView);
|
| | | } else {
|
| | | add(new Label("active").setVisible(false));
|
| | | }
|
| | |
|
| | | // starred repository list
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | // (un)star link allows a user to star someone else's repository
|
| | | if (user.isAuthenticated && !model.isOwner(user.username) && !model.isUsersPersonalRepository(user.username)) {
|
| | | // (un)star link allows a user to star a repository
|
| | | if (user.isAuthenticated) {
|
| | | PageParameters starParams = DeepCopier.copy(getPageParameters());
|
| | | starParams.put(PARAM_STAR, !user.getPreferences().isStarredRepository(model.name));
|
| | | String toggleStarUrl = getRequestCycle().urlFor(getClass(), starParams).toString();
|
| | |
| | | add(new Label("unstarLink").setVisible(false));
|
| | | }
|
| | | } else {
|
| | | // anonymous user or the repository owner is browsing the repository
|
| | | // anonymous user
|
| | | add(new Label("starLink").setVisible(false));
|
| | | add(new Label("unstarLink").setVisible(false));
|
| | | }
|
| | |
| | | } catch (Throwable t) {
|
| | | bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp");
|
| | | }
|
| | | timeUtils = new TimeUtils(bundle);
|
| | | timeUtils = new TimeUtils(bundle, getTimeZone());
|
| | | }
|
| | | return timeUtils;
|
| | | }
|
| | |
| | | <wicket:panel>
|
| | |
|
| | | <!-- header -->
|
| | | <div class="header"><i class="icon-random" style="vertical-align: middle;"></i> <b><span wicket:id="branches">[branches header]</span></b></div> |
| | | <div class="header"><i class="icon-random"></i> <b><span wicket:id="branches">[branches header]</span></b></div> |
| | |
|
| | | <table class="pretty">
|
| | | <tbody>
|
| | |
| | | <wicket:panel>
|
| | |
|
| | | <!-- header -->
|
| | | <div class="header"><i class="icon-refresh" style="vertical-align: middle;"></i> <b><span wicket:id="header">[log header]</span></b></div>
|
| | | <div class="header"><i class="icon-refresh"></i> <b><span wicket:id="header">[log header]</span></b></div>
|
| | | <table class="pretty">
|
| | | <tbody>
|
| | | <tr wicket:id="commit">
|
| | |
| | | <div wicket:id="push" class="push">
|
| | | <table style="padding: 3px 0px;">
|
| | | <tr>
|
| | | <td class="hidden-phone" style="vertical-align: top;padding-top:10px"><i wicket:id="pushIcon"></i></td>
|
| | | <td style="padding-left: 7px;">
|
| | | <td class="icon hidden-phone"><i wicket:id="pushIcon"></i></td>
|
| | | <td style="padding-left: 7px;vertical-align:middle;">
|
| | | <div>
|
| | | <span wicket:id="whenPushed"></span> <span wicket:id="refRewind" class="alert alert-error" style="padding: 1px 5px;font-size: 10px;font-weight: bold;margin-left: 10px;">[rewind]</span>
|
| | | <span style="color:#aaa;" wicket:id="whenPushed"></span> <span wicket:id="refRewind" class="alert alert-error" style="padding: 1px 5px;font-size: 10px;font-weight: bold;margin-left: 10px;">[rewind]</span>
|
| | | </div>
|
| | | <div style="font-weight:bold;"><span wicket:id="whoPushed">[pusher]</span> <span wicket:id="whatPushed"></span><span wicket:id="refPushed"></span> <span wicket:id="repoPreposition"></span> <span wicket:id="repoPushed"></span> <span wicket:id="byAuthors"></span></div>
|
| | | <div style="padding: 10px 0px 5px;">
|
| | | </td>
|
| | | </tr>
|
| | | <tr>
|
| | | <td></td>
|
| | | <td style="padding-left: 7px;">
|
| | | <div>
|
| | | <table>
|
| | | <tr wicket:id="commit">
|
| | | <td class="hidden-phone hidden-tablet" style="vertical-align:top;padding-left:7px;"><span wicket:id="commitAuthor"></span></td>
|
| | |
| | | */
|
| | | package com.gitblit.wicket.panels;
|
| | |
|
| | | import java.text.DateFormat;
|
| | | import java.text.MessageFormat;
|
| | | import java.text.SimpleDateFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Calendar;
|
| | | import java.util.Date;
|
| | | import java.util.List;
|
| | | import java.util.TimeZone;
|
| | |
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | import org.apache.wicket.markup.repeater.Item;
|
| | |
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.utils.PushLogUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.TimeUtils;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.pages.CommitPage;
|
| | | import com.gitblit.wicket.pages.ComparePage;
|
| | |
| | | protected void setup(List<PushLogEntry> pushes, final boolean showRepo) {
|
| | | final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6);
|
| | |
|
| | | String dateFormat = GitBlit.getString(Keys.web.datestampLongFormat, "EEEE, MMMM d, yyyy");
|
| | | final TimeZone timezone = getTimeZone();
|
| | | final DateFormat df = new SimpleDateFormat(dateFormat);
|
| | | df.setTimeZone(timezone);
|
| | | final Calendar cal = Calendar.getInstance(timezone);
|
| | | |
| | | ListDataProvider<PushLogEntry> dp = new ListDataProvider<PushLogEntry>(pushes);
|
| | | DataView<PushLogEntry> pushView = new DataView<PushLogEntry>("push", dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | String fullRefName = push.getChangedRefs().get(0);
|
| | | String shortRefName = fullRefName;
|
| | | boolean isTag = false;
|
| | | if (shortRefName.startsWith(org.eclipse.jgit.lib.Constants.R_HEADS)) {
|
| | | shortRefName = shortRefName.substring(org.eclipse.jgit.lib.Constants.R_HEADS.length());
|
| | | } else if (shortRefName.startsWith(org.eclipse.jgit.lib.Constants.R_TAGS)) {
|
| | | shortRefName = shortRefName.substring(org.eclipse.jgit.lib.Constants.R_TAGS.length());
|
| | | boolean isPull = false;
|
| | | if (shortRefName.startsWith(Constants.R_HEADS)) {
|
| | | shortRefName = shortRefName.substring(Constants.R_HEADS.length());
|
| | | } else if (shortRefName.startsWith(Constants.R_TAGS)) {
|
| | | shortRefName = shortRefName.substring(Constants.R_TAGS.length());
|
| | | isTag = true;
|
| | | } else if (shortRefName.startsWith(Constants.R_PULL)) {
|
| | | shortRefName = "#" + shortRefName.substring(Constants.R_PULL.length());
|
| | | if (shortRefName.endsWith("/head")) {
|
| | | // strip pull request head from name |
| | | shortRefName = shortRefName.substring(0, shortRefName.length() - "/head".length());
|
| | | } |
| | | isPull = true;
|
| | | }
|
| | | boolean isDigest = push instanceof DailyLogEntry;
|
| | |
|
| | | pushItem.add(WicketUtils.createDateLabel("whenPushed", push.date, getTimeZone(), getTimeUtils()));
|
| | | String fuzzydate;
|
| | | TimeUtils tu = getTimeUtils();
|
| | | Date pushDate = push.date;
|
| | | if (TimeUtils.isToday(pushDate, timezone)) {
|
| | | fuzzydate = tu.today();
|
| | | } else if (TimeUtils.isYesterday(pushDate, timezone)) {
|
| | | fuzzydate = tu.yesterday();
|
| | | } else {
|
| | | // calculate a fuzzy time ago date
|
| | | cal.setTime(pushDate);
|
| | | cal.set(Calendar.HOUR_OF_DAY, 0);
|
| | | cal.set(Calendar.MINUTE, 0);
|
| | | cal.set(Calendar.SECOND, 0);
|
| | | cal.set(Calendar.MILLISECOND, 0);
|
| | | pushDate = cal.getTime();
|
| | | fuzzydate = getTimeUtils().timeAgo(pushDate);
|
| | | }
|
| | | pushItem.add(new Label("whenPushed", fuzzydate + ", " + df.format(pushDate)));
|
| | |
|
| | | Label pushIcon = new Label("pushIcon");
|
| | | if (showRepo) {
|
| | | // if we are showing the repo, we are showing multiple
|
| | |
| | | }
|
| | | if (isTag) {
|
| | | WicketUtils.setCssClass(pushIcon, "iconic-tag");
|
| | | } else if (isPull) {
|
| | | WicketUtils.setCssClass(pushIcon, "iconic-share");
|
| | | } else if (isDigest) {
|
| | | WicketUtils.setCssClass(pushIcon, "iconic-loop");
|
| | | } else {
|
| | |
| | | switch(push.getChangeType(fullRefName)) {
|
| | | case CREATE:
|
| | | if (isTag) {
|
| | | // new tag
|
| | | if (isDigest) {
|
| | | what = getString("gb.createdNewTag");
|
| | | preposition = "gb.in";
|
| | |
| | | what = getString("gb.pushedNewTag");
|
| | | preposition = "gb.to";
|
| | | }
|
| | | } else if (isPull) {
|
| | | // merged pull request
|
| | | what = getString("gb.mergedPullRequest");
|
| | | preposition = "gb.in";
|
| | | } else {
|
| | | // new branch
|
| | | if (isDigest) {
|
| | | what = getString("gb.createdNewBranch");
|
| | | preposition = "gb.in";
|
| | |
| | | case DELETE:
|
| | | isDelete = true;
|
| | | if (isTag) {
|
| | | what = getString("gb.deletedTag");
|
| | | } if (isPull) {
|
| | | what = getString("gb.deletedTag");
|
| | | } else {
|
| | | what = getString("gb.deletedBranch");
|
| | |
| | | // link to tag
|
| | | pushItem.add(new LinkPanel("refPushed", null, shortRefName,
|
| | | TagPage.class, WicketUtils.newObjectParameter(push.repository, fullRefName)));
|
| | | } else if (isPull) {
|
| | | // link to pull request
|
| | | pushItem.add(new LinkPanel("refPushed", null, shortRefName,
|
| | | TagPage.class, WicketUtils.newObjectParameter(push.repository, fullRefName)));
|
| | | } else {
|
| | | // link to tree
|
| | | pushItem.add(new LinkPanel("refPushed", null, shortRefName,
|
| | |
| | | import org.apache.wicket.markup.repeater.Item;
|
| | | import org.apache.wicket.markup.repeater.data.DataView;
|
| | | import org.apache.wicket.markup.repeater.data.ListDataProvider;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | | import org.eclipse.jgit.lib.ObjectId;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | |
|
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.models.RefModel;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.pages.CommitPage;
|
| | |
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | private static final String R_CHANGES = "refs/changes/";
|
| | | |
| | | private static final String R_PULL= "refs/pull/";
|
| | |
|
| | | public RefsPanel(String id, final String repositoryName, RevCommit c,
|
| | | Map<ObjectId, List<RefModel>> refs) {
|
| | | this(id, repositoryName, refs.get(c.getId()));
|
| | |
| | | // local head
|
| | | linkClass = LogPage.class;
|
| | | cssClass = "headRef";
|
| | | } else if (name.startsWith(R_CHANGES)) {
|
| | | } else if (name.startsWith(Constants.R_CHANGES)) {
|
| | | // Gerrit change ref
|
| | | name = name.substring(R_CHANGES.length());
|
| | | name = name.substring(Constants.R_CHANGES.length());
|
| | | cssClass = "otherRef";
|
| | | } else if (name.startsWith(R_PULL)) {
|
| | | } else if (name.startsWith(Constants.R_PULL)) {
|
| | | // Pull Request ref
|
| | | name = "pull #" + name.substring(R_PULL.length());
|
| | | name = "pull #" + name.substring(Constants.R_PULL.length());
|
| | | if (name.endsWith("/head")) {
|
| | | // strip pull request head from name
|
| | | name = name.substring(0, name.length() - "/head".length());
|
| | | }
|
| | | } |
| | | cssClass = "pullRef";
|
| | | } else if (name.startsWith(Constants.R_REMOTES)) {
|
| | | // remote branch
|
| | |
| | | <wicket:panel>
|
| | |
|
| | | <!-- tags -->
|
| | | <div class="header"><i class="icon-tags" style="vertical-align: middle;"></i> <b><span wicket:id="header">[tags header]</span></b></div> |
| | | <div class="header"><i class="icon-tags"></i> <b><span wicket:id="header">[tags header]</span></b></div> |
| | | <table class="pretty">
|
| | | <tbody>
|
| | | <tr wicket:id="tag">
|
| | |
| | | [class*="iconic-"] { |
| | | font-style: inherit; |
| | | font-weight: normal; |
| | | vertical-align: bottom; |
| | | vertical-align: middle; |
| | | } |
| | | [class*="iconic-"]:before { |
| | | display: inline-block; |
| | | width: 1em; |
| | | font-family: IconicFill; |
| | | font-size: 0.9em; |
| | | text-align: center; |
| | | vertical-align: middle; |
| | | content: ""; |
| | | } |
| | | .iconic-stroke:before { |
| | |
| | | outline: none;
|
| | | }
|
| | |
|
| | | [class^="icon-"], [class*=" icon-"] a i {
|
| | | a.btn i {
|
| | | /* override for a links that look like bootstrap buttons */
|
| | | vertical-align: text-bottom;
|
| | | }
|
| | |
|
| | | [class^="icon-"], [class*=" icon-"] i {
|
| | | /* override for a links that look like bootstrap buttons */
|
| | | vertical-align: text-bottom;
|
| | | }
|
| | |
| | |
|
| | | div.push {
|
| | | border-bottom: 1px solid #ddd;
|
| | | margin-bottom: 15px;
|
| | | margin-bottom: 5px;
|
| | | padding-bottom: 5px;
|
| | | }
|
| | |
|
| | | div.push .icon {
|
| | | font-size: 42px;
|
| | | line-height: 42px;
|
| | | }
|
| | |
|
| | | div.push i {
|
| | | font-size:3.25em;
|
| | | color:#bbb;
|
| | | font-size: 42px;
|
| | | color: #bbb;
|
| | | vertical-align: middle;
|
| | | }
|
| | |
|
| | | .repositorynavbar {
|
| | |
| | |
|
| | | @Test
|
| | | public void testToday() throws Exception {
|
| | | assertTrue(TimeUtils.isToday(new Date()));
|
| | | assertTrue(TimeUtils.isToday(new Date(), null));
|
| | | }
|
| | |
|
| | | @Test
|
| | | public void testYesterday() throws Exception {
|
| | | assertTrue(TimeUtils.isYesterday(offset(TimeUtils.ONEDAY)));
|
| | | assertTrue(TimeUtils.isYesterday(offset(TimeUtils.ONEDAY), null));
|
| | | }
|
| | |
|
| | | @Test
|