Reflogs, Digests, and Dashboards
Renamed pushlog to reflog to better match it's current and future purpose.
Split PushesPanel into ReflogPanel and DigestsPanel.
Overhauled project pages and gave them a coherent purpose from the dashboard.
5 files renamed
2 files deleted
4 files added
19 files modified
1 files copied
| | |
| | | # SINCE 0.5.0
|
| | | web.itemsPerPage = 50
|
| | |
|
| | | # The number of pushes to display on the overview page
|
| | | # The number of reflog changes to display on the overview page
|
| | | # Value must exceed 0 else default of 5 is used
|
| | | #
|
| | | # SINCE 1.3.0
|
| | | web.overviewPushCount = 5
|
| | | web.overviewReflogCount = 5
|
| | |
|
| | | # The number of pushes to show on a push page before show the first, prev, next
|
| | | # pagination links. A default of 10 is used for any invalid value.
|
| | | # The number of reflog changes to show on a reflog page before show the first,
|
| | | # prev, next pagination links. A default of 10 is used for any invalid value.
|
| | | #
|
| | | # SINCE 1.3.0
|
| | | web.pushesPerPage = 10
|
| | | web.reflogChangesPerPage = 10
|
| | |
|
| | | # Registered file extensions to ignore during Lucene indexing
|
| | | #
|
| | |
| | | import com.gitblit.utils.ArrayUtils;
|
| | | import com.gitblit.utils.ClientLogger;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.PushLogUtils;
|
| | | import com.gitblit.utils.RefLogUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | /**
|
| | |
| | |
|
| | | // update push log
|
| | | try {
|
| | | PushLogUtils.updatePushLog(user, rp.getRepository(), commands);
|
| | | RefLogUtils.updateRefLog(user, rp.getRepository(), commands);
|
| | | logger.debug(MessageFormat.format("{0} push log updated", repository.name));
|
| | | } catch (Exception e) {
|
| | | logger.error(MessageFormat.format("Failed to update {0} pushlog", repository.name), e);
|
| | |
| | | * |
| | | * @author James Moger |
| | | */ |
| | | public class DailyLogEntry extends PushLogEntry implements Serializable { |
| | | public class DailyLogEntry extends RefLogEntry implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
File was renamed from src/main/java/com/gitblit/models/PushLogEntry.java |
| | |
| | | *
|
| | | * @author James Moger
|
| | | */
|
| | | public class PushLogEntry implements Serializable, Comparable<PushLogEntry> {
|
| | | public class RefLogEntry implements Serializable, Comparable<RefLogEntry> {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | | * @param user
|
| | | * the user who pushed
|
| | | */
|
| | | public PushLogEntry(String repository, Date date, UserModel user) {
|
| | | public RefLogEntry(String repository, Date date, UserModel user) {
|
| | | this.repository = repository;
|
| | | this.date = date;
|
| | | this.user = user;
|
| | |
| | | }
|
| | |
|
| | | @Override
|
| | | public int compareTo(PushLogEntry o) {
|
| | | public int compareTo(RefLogEntry o) {
|
| | | // reverse chronological order
|
| | | return o.date.compareTo(date);
|
| | | }
|
File was renamed from src/main/java/com/gitblit/utils/PushLogUtils.java |
| | |
| | | import org.eclipse.jgit.lib.ObjectId; |
| | | import org.eclipse.jgit.lib.ObjectInserter; |
| | | import org.eclipse.jgit.lib.PersonIdent; |
| | | import org.eclipse.jgit.lib.RefRename; |
| | | import org.eclipse.jgit.lib.RefUpdate; |
| | | import org.eclipse.jgit.lib.RefUpdate.Result; |
| | | import org.eclipse.jgit.lib.Repository; |
| | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.models.DailyLogEntry; |
| | | import com.gitblit.models.PathModel.PathChangeModel; |
| | | import com.gitblit.models.PushLogEntry; |
| | | import com.gitblit.models.RefLogEntry; |
| | | import com.gitblit.models.RefModel; |
| | | import com.gitblit.models.RepositoryCommit; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | /** |
| | | * Utility class for maintaining a pushlog within a git repository on an |
| | | * Utility class for maintaining a reflog within a git repository on an |
| | | * orphan branch. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class PushLogUtils { |
| | | public class RefLogUtils { |
| | | |
| | | public static final String GB_PUSHES = "refs/gitblit/pushes"; |
| | | private static final String GB_REFLOG = "refs/gitblit/reflog"; |
| | | |
| | | static final Logger LOGGER = LoggerFactory.getLogger(PushLogUtils.class); |
| | | private static final Logger LOGGER = LoggerFactory.getLogger(RefLogUtils.class); |
| | | |
| | | /** |
| | | * Log an error message and exception. |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns a RefModel for the gb-pushes branch in the repository. If the |
| | | * Returns a RefModel for the reflog branch in the repository. If the |
| | | * branch can not be found, null is returned. |
| | | * |
| | | * @param repository |
| | | * @return a refmodel for the gb-pushes branch or null |
| | | * @return a refmodel for the reflog branch or null |
| | | */ |
| | | public static RefModel getPushLogBranch(Repository repository) { |
| | | public static RefModel getRefLogBranch(Repository repository) { |
| | | List<RefModel> refs = JGitUtils.getRefs(repository, com.gitblit.Constants.R_GITBLIT); |
| | | RefModel pushLog = null; |
| | | final String GB_PUSHES = "refs/gitblit/pushes"; |
| | | for (RefModel ref : refs) { |
| | | if (ref.reference.getName().equals(GB_PUSHES)) { |
| | | if (ref.reference.getName().equals(GB_REFLOG)) { |
| | | return ref; |
| | | } else if (ref.reference.getName().equals(GB_PUSHES)) { |
| | | pushLog = ref; |
| | | } |
| | | } |
| | | if (pushLog != null) { |
| | | // rename refs/gitblit/pushes to refs/gitblit/reflog |
| | | RefRename cmd; |
| | | try { |
| | | cmd = repository.renameRef(GB_PUSHES, GB_REFLOG); |
| | | cmd.setRefLogIdent(new PersonIdent("Gitblit", "gitblit@localhost")); |
| | | cmd.setRefLogMessage("renamed " + GB_PUSHES + " => " + GB_REFLOG); |
| | | Result res = cmd.rename(); |
| | | switch (res) { |
| | | case RENAMED: |
| | | return getRefLogBranch(repository); |
| | | default: |
| | | LOGGER.error("failed to rename " + GB_PUSHES + " => " + GB_REFLOG + " (" + res.name() + ")"); |
| | | } |
| | | } catch (IOException e) { |
| | | LOGGER.error("failed to rename pushlog", e); |
| | | } |
| | | } |
| | | return null; |
| | |
| | | } |
| | | |
| | | /** |
| | | * Updates a push log. |
| | | * Updates the reflog with the received commands. |
| | | * |
| | | * @param user |
| | | * @param repository |
| | | * @param commands |
| | | * @return true, if the update was successful |
| | | */ |
| | | public static boolean updatePushLog(UserModel user, Repository repository, |
| | | public static boolean updateRefLog(UserModel user, Repository repository, |
| | | Collection<ReceiveCommand> commands) { |
| | | RefModel pushlogBranch = getPushLogBranch(repository); |
| | | if (pushlogBranch == null) { |
| | | JGitUtils.createOrphanBranch(repository, GB_PUSHES, null); |
| | | RefModel reflogBranch = getRefLogBranch(repository); |
| | | if (reflogBranch == null) { |
| | | JGitUtils.createOrphanBranch(repository, GB_REFLOG, null); |
| | | } |
| | | |
| | | boolean success = false; |
| | | String message = "push"; |
| | | |
| | | try { |
| | | ObjectId headId = repository.resolve(GB_PUSHES + "^{commit}"); |
| | | ObjectId headId = repository.resolve(GB_REFLOG + "^{commit}"); |
| | | ObjectInserter odi = repository.newObjectInserter(); |
| | | try { |
| | | // Create the in-memory index of the push log entry |
| | |
| | | RevWalk revWalk = new RevWalk(repository); |
| | | try { |
| | | RevCommit revCommit = revWalk.parseCommit(commitId); |
| | | RefUpdate ru = repository.updateRef(GB_PUSHES); |
| | | RefUpdate ru = repository.updateRef(GB_REFLOG); |
| | | ru.setNewObjectId(commitId); |
| | | ru.setExpectedOldObjectId(headId); |
| | | ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); |
| | |
| | | ru.getRef(), rc); |
| | | default: |
| | | throw new JGitInternalException(MessageFormat.format( |
| | | JGitText.get().updatingRefFailed, GB_PUSHES, commitId.toString(), |
| | | JGitText.get().updatingRefFailed, GB_REFLOG, commitId.toString(), |
| | | rc)); |
| | | } |
| | | } finally { |
| | |
| | | odi.release(); |
| | | } |
| | | } catch (Throwable t) { |
| | | error(t, repository, "Failed to commit pushlog entry to {0}"); |
| | | error(t, repository, "Failed to commit reflog entry to {0}"); |
| | | } |
| | | return success; |
| | | } |
| | |
| | | return inCoreIndex; |
| | | } |
| | | |
| | | public static List<PushLogEntry> getPushLog(String repositoryName, Repository repository) { |
| | | return getPushLog(repositoryName, repository, null, 0, -1); |
| | | public static List<RefLogEntry> getRefLog(String repositoryName, Repository repository) { |
| | | return getRefLog(repositoryName, repository, null, 0, -1); |
| | | } |
| | | |
| | | public static List<PushLogEntry> getPushLog(String repositoryName, Repository repository, int maxCount) { |
| | | return getPushLog(repositoryName, repository, null, 0, maxCount); |
| | | public static List<RefLogEntry> getRefLog(String repositoryName, Repository repository, int maxCount) { |
| | | return getRefLog(repositoryName, repository, null, 0, maxCount); |
| | | } |
| | | |
| | | public static List<PushLogEntry> getPushLog(String repositoryName, Repository repository, int offset, int maxCount) { |
| | | return getPushLog(repositoryName, repository, null, offset, maxCount); |
| | | public static List<RefLogEntry> getRefLog(String repositoryName, Repository repository, int offset, int maxCount) { |
| | | return getRefLog(repositoryName, repository, null, offset, maxCount); |
| | | } |
| | | |
| | | public static List<PushLogEntry> getPushLog(String repositoryName, Repository repository, Date minimumDate) { |
| | | return getPushLog(repositoryName, repository, minimumDate, 0, -1); |
| | | public static List<RefLogEntry> getRefLog(String repositoryName, Repository repository, Date minimumDate) { |
| | | return getRefLog(repositoryName, repository, minimumDate, 0, -1); |
| | | } |
| | | |
| | | /** |
| | | * Returns the list of push log entries as they were recorded by Gitblit. |
| | | * Each PushLogEntry may represent multiple ref updates. |
| | | * Returns the list of reflog entries as they were recorded by Gitblit. |
| | | * Each RefLogEntry may represent multiple ref updates. |
| | | * |
| | | * @param repositoryName |
| | | * @param repository |
| | |
| | | * if < 0, all pushes are returned. |
| | | * @return a list of push log entries |
| | | */ |
| | | public static List<PushLogEntry> getPushLog(String repositoryName, Repository repository, |
| | | public static List<RefLogEntry> getRefLog(String repositoryName, Repository repository, |
| | | Date minimumDate, int offset, int maxCount) { |
| | | List<PushLogEntry> list = new ArrayList<PushLogEntry>(); |
| | | RefModel ref = getPushLogBranch(repository); |
| | | List<RefLogEntry> list = new ArrayList<RefLogEntry>(); |
| | | RefModel ref = getRefLogBranch(repository); |
| | | if (ref == null) { |
| | | return list; |
| | | } |
| | |
| | | Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository); |
| | | List<RevCommit> pushes; |
| | | if (minimumDate == null) { |
| | | pushes = JGitUtils.getRevLog(repository, GB_PUSHES, offset, maxCount); |
| | | pushes = JGitUtils.getRevLog(repository, GB_REFLOG, offset, maxCount); |
| | | } else { |
| | | pushes = JGitUtils.getRevLog(repository, GB_PUSHES, minimumDate); |
| | | pushes = JGitUtils.getRevLog(repository, GB_REFLOG, minimumDate); |
| | | } |
| | | for (RevCommit push : pushes) { |
| | | if (push.getAuthorIdent().getName().equalsIgnoreCase("gitblit")) { |
| | |
| | | UserModel user = newUserModelFrom(push.getAuthorIdent()); |
| | | Date date = push.getAuthorIdent().getWhen(); |
| | | |
| | | PushLogEntry log = new PushLogEntry(repositoryName, date, user); |
| | | RefLogEntry log = new RefLogEntry(repositoryName, date, user); |
| | | list.add(log); |
| | | List<PathChangeModel> changedRefs = JGitUtils.getFilesInCommit(repository, push); |
| | | for (PathChangeModel change : changedRefs) { |
| | |
| | | * @param maxCount |
| | | * @return a list of push log entries separated by ref |
| | | */ |
| | | public static List<PushLogEntry> getPushLogByRef(String repositoryName, Repository repository, int maxCount) { |
| | | return getPushLogByRef(repositoryName, repository, 0, maxCount); |
| | | public static List<RefLogEntry> getLogByRef(String repositoryName, Repository repository, int maxCount) { |
| | | return getLogByRef(repositoryName, repository, 0, maxCount); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param maxCount |
| | | * @return a list of push log entries separated by ref |
| | | */ |
| | | public static List<PushLogEntry> getPushLogByRef(String repositoryName, Repository repository, int offset, |
| | | public static List<RefLogEntry> getLogByRef(String repositoryName, Repository repository, int offset, |
| | | int maxCount) { |
| | | // break the push log into ref push logs and then merge them back into a list |
| | | Map<String, List<PushLogEntry>> refMap = new HashMap<String, List<PushLogEntry>>(); |
| | | List<PushLogEntry> pushes = getPushLog(repositoryName, repository, offset, maxCount); |
| | | for (PushLogEntry push : pushes) { |
| | | for (String ref : push.getChangedRefs()) { |
| | | Map<String, List<RefLogEntry>> refMap = new HashMap<String, List<RefLogEntry>>(); |
| | | List<RefLogEntry> refLog = getRefLog(repositoryName, repository, offset, maxCount); |
| | | for (RefLogEntry entry : refLog) { |
| | | for (String ref : entry.getChangedRefs()) { |
| | | if (!refMap.containsKey(ref)) { |
| | | refMap.put(ref, new ArrayList<PushLogEntry>()); |
| | | refMap.put(ref, new ArrayList<RefLogEntry>()); |
| | | } |
| | | |
| | | // construct new ref-specific push log entry |
| | | PushLogEntry refPush; |
| | | if (push instanceof DailyLogEntry) { |
| | | // construct new ref-specific ref change entry |
| | | RefLogEntry refChange; |
| | | if (entry instanceof DailyLogEntry) { |
| | | // simulated push log from commits grouped by date |
| | | refPush = new DailyLogEntry(push.repository, push.date); |
| | | refChange = new DailyLogEntry(entry.repository, entry.date); |
| | | } else { |
| | | // real push log entry |
| | | refPush = new PushLogEntry(push.repository, push.date, push.user); |
| | | refChange = new RefLogEntry(entry.repository, entry.date, entry.user); |
| | | } |
| | | refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref)); |
| | | refPush.addCommits(push.getCommits(ref)); |
| | | refMap.get(ref).add(refPush); |
| | | refChange.updateRef(ref, entry.getChangeType(ref), entry.getOldId(ref), entry.getNewId(ref)); |
| | | refChange.addCommits(entry.getCommits(ref)); |
| | | refMap.get(ref).add(refChange); |
| | | } |
| | | } |
| | | |
| | | // merge individual ref pushes into master list |
| | | List<PushLogEntry> refPushLog = new ArrayList<PushLogEntry>(); |
| | | for (List<PushLogEntry> refPush : refMap.values()) { |
| | | refPushLog.addAll(refPush); |
| | | // merge individual ref changes into master list |
| | | List<RefLogEntry> mergedRefLog = new ArrayList<RefLogEntry>(); |
| | | for (List<RefLogEntry> refPush : refMap.values()) { |
| | | mergedRefLog.addAll(refPush); |
| | | } |
| | | |
| | | // sort ref push log |
| | | Collections.sort(refPushLog); |
| | | // sort ref log |
| | | Collections.sort(mergedRefLog); |
| | | |
| | | return refPushLog; |
| | | return mergedRefLog; |
| | | } |
| | | |
| | | /** |
| | | * Returns the list of pushes separated by ref (e.g. each ref has it's own |
| | | * PushLogEntry object). |
| | | * Returns the list of ref changes separated by ref (e.g. each ref has it's own |
| | | * RefLogEntry object). |
| | | * |
| | | * @param repositoryName |
| | | * @param repository |
| | | * @param minimumDate |
| | | * @return a list of push log entries separated by ref |
| | | * @return a list of ref log entries separated by ref |
| | | */ |
| | | public static List<PushLogEntry> getPushLogByRef(String repositoryName, Repository repository, Date minimumDate) { |
| | | public static List<RefLogEntry> getLogByRef(String repositoryName, Repository repository, Date minimumDate) { |
| | | // break the push log into ref push logs and then merge them back into a list |
| | | Map<String, List<PushLogEntry>> refMap = new HashMap<String, List<PushLogEntry>>(); |
| | | List<PushLogEntry> pushes = getPushLog(repositoryName, repository, minimumDate); |
| | | for (PushLogEntry push : pushes) { |
| | | Map<String, List<RefLogEntry>> refMap = new HashMap<String, List<RefLogEntry>>(); |
| | | List<RefLogEntry> pushes = getRefLog(repositoryName, repository, minimumDate); |
| | | for (RefLogEntry push : pushes) { |
| | | for (String ref : push.getChangedRefs()) { |
| | | if (!refMap.containsKey(ref)) { |
| | | refMap.put(ref, new ArrayList<PushLogEntry>()); |
| | | refMap.put(ref, new ArrayList<RefLogEntry>()); |
| | | } |
| | | |
| | | // construct new ref-specific push log entry |
| | | PushLogEntry refPush = new PushLogEntry(push.repository, push.date, push.user); |
| | | RefLogEntry refPush = new RefLogEntry(push.repository, push.date, push.user); |
| | | refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref)); |
| | | refPush.addCommits(push.getCommits(ref)); |
| | | refMap.get(ref).add(refPush); |
| | |
| | | } |
| | | |
| | | // merge individual ref pushes into master list |
| | | List<PushLogEntry> refPushLog = new ArrayList<PushLogEntry>(); |
| | | for (List<PushLogEntry> refPush : refMap.values()) { |
| | | List<RefLogEntry> refPushLog = new ArrayList<RefLogEntry>(); |
| | | for (List<RefLogEntry> refPush : refMap.values()) { |
| | | refPushLog.addAll(refPush); |
| | | } |
| | | |
| | |
| | | Date tagDate = commit.getAuthorIdent().getWhen(); |
| | | tags.put(dateStr, new DailyLogEntry(repositoryName, tagDate, tagUser)); |
| | | } |
| | | PushLogEntry tagEntry = tags.get(dateStr); |
| | | RefLogEntry tagEntry = tags.get(dateStr); |
| | | tagEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); |
| | | tagEntry.addCommit(ref.getName(), commit); |
| | | } else if (ref.getName().startsWith(Constants.R_PULL)) { |
| | |
| | | Date commitDate = commit.getAuthorIdent().getWhen(); |
| | | pulls.put(dateStr, new DailyLogEntry(repositoryName, commitDate, commitUser)); |
| | | } |
| | | PushLogEntry pullEntry = pulls.get(dateStr); |
| | | RefLogEntry pullEntry = pulls.get(dateStr); |
| | | pullEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); |
| | | pullEntry.addCommit(ref.getName(), commit); |
| | | } |
| | |
| | | import com.gitblit.wicket.pages.GitSearchPage;
|
| | | import com.gitblit.wicket.pages.GravatarProfilePage;
|
| | | import com.gitblit.wicket.pages.HistoryPage;
|
| | | import com.gitblit.wicket.pages.DashboardPage;
|
| | | import com.gitblit.wicket.pages.LogPage;
|
| | | import com.gitblit.wicket.pages.LogoutPage;
|
| | | import com.gitblit.wicket.pages.LuceneSearchPage;
|
| | | import com.gitblit.wicket.pages.MarkdownPage;
|
| | | import com.gitblit.wicket.pages.MetricsPage;
|
| | | import com.gitblit.wicket.pages.MyDashboardPage;
|
| | | import com.gitblit.wicket.pages.OverviewPage;
|
| | | import com.gitblit.wicket.pages.PatchPage;
|
| | | import com.gitblit.wicket.pages.ProjectPage;
|
| | | import com.gitblit.wicket.pages.ProjectsPage;
|
| | | import com.gitblit.wicket.pages.PushesPage;
|
| | | import com.gitblit.wicket.pages.RawPage;
|
| | | import com.gitblit.wicket.pages.ReflogPage;
|
| | | import com.gitblit.wicket.pages.RepositoriesPage;
|
| | | import com.gitblit.wicket.pages.ReviewProposalPage;
|
| | | import com.gitblit.wicket.pages.SummaryPage;
|
| | |
| | |
|
| | | public class GitBlitWebApp extends WebApplication {
|
| | |
|
| | | public final static Class<? extends BasePage> HOME_PAGE_CLASS = DashboardPage.class;
|
| | | public final static Class<? extends BasePage> HOME_PAGE_CLASS = MyDashboardPage.class;
|
| | |
|
| | | @Override
|
| | | public void init() {
|
| | |
| | | mount("/repositories", RepositoriesPage.class);
|
| | | mount("/overview", OverviewPage.class, "r", "h");
|
| | | mount("/summary", SummaryPage.class, "r");
|
| | | mount("/pushes", PushesPage.class, "r", "h");
|
| | | mount("/reflog", ReflogPage.class, "r", "h");
|
| | | mount("/commits", LogPage.class, "r", "h");
|
| | | mount("/log", LogPage.class, "r", "h");
|
| | | mount("/tags", TagsPage.class, "r");
|
| | |
| | | gb.at = at |
| | | gb.of = of |
| | | gb.in = in |
| | | gb.morePushes = all pushes... |
| | | gb.pushes = pushes |
| | | gb.moreChanges = all changes... |
| | | gb.pushedNCommitsTo = pushed {0} commits to |
| | | gb.pushedOneCommitTo = pushed 1 commit to |
| | | gb.commitsTo = {0} commits to |
| | |
| | | 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.noActivity = there has been no activity in the last {0} days |
| | | gb.findSomeRepositories = find some repositories |
| | | gb.metricAuthorExclusions = author metric exclusions |
| | | gb.myDashboard = my dashboard |
| | | gb.failedToFindAccount = failed to find user account ''{0}'' |
| | | gb.reflog = reflog |
| | | gb.active = active |
| | | gb.starred = starred |
| | | gb.owned = owned |
| | |
| | | */
|
| | | package com.gitblit.wicket.pages;
|
| | |
|
| | | import java.io.File;
|
| | | import java.io.FileInputStream;
|
| | | import java.io.InputStream;
|
| | | import java.io.InputStreamReader;
|
| | | import java.io.Serializable;
|
| | | import java.text.DateFormat;
|
| | | import java.text.MessageFormat;
|
| | | import java.text.SimpleDateFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Calendar;
|
| | | import java.util.Collection;
|
| | | import java.util.Collections;
|
| | | 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 java.util.TreeSet;
|
| | |
|
| | | import org.apache.wicket.Component;
|
| | | import org.apache.wicket.PageParameters;
|
| | | import org.apache.wicket.behavior.HeaderContributor;
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | import org.apache.wicket.markup.html.panel.Fragment;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | |
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.models.DailyLogEntry;
|
| | | import com.gitblit.models.Metric;
|
| | | import com.gitblit.models.PushLogEntry;
|
| | | import com.gitblit.models.RefLogEntry;
|
| | | import com.gitblit.models.RepositoryCommit;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.ArrayUtils;
|
| | | import com.gitblit.utils.MarkdownUtils;
|
| | | import com.gitblit.utils.PushLogUtils;
|
| | | import com.gitblit.utils.RefLogUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.wicket.GitBlitWebApp;
|
| | | import com.gitblit.wicket.GitBlitWebSession;
|
| | | import com.gitblit.wicket.PageRegistration;
|
| | | import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
|
| | | import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
|
| | |
| | | import com.gitblit.wicket.charting.GoogleCharts;
|
| | | import com.gitblit.wicket.charting.GooglePieChart;
|
| | | import com.gitblit.wicket.ng.NgController;
|
| | | import com.gitblit.wicket.panels.DigestsPanel;
|
| | | import com.gitblit.wicket.panels.LinkPanel;
|
| | | import com.gitblit.wicket.panels.PushesPanel;
|
| | |
|
| | | public class DashboardPage extends RootPage {
|
| | | public abstract class DashboardPage extends RootPage {
|
| | |
|
| | | public DashboardPage() {
|
| | | super();
|
| | | setup(null);
|
| | | }
|
| | |
|
| | | public DashboardPage(PageParameters params) {
|
| | | super(params);
|
| | | setup(params);
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | return true;
|
| | | }
|
| | |
|
| | | private void setup(PageParameters params) {
|
| | | setupPage("", "");
|
| | | // check to see if we should display a login message
|
| | | boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
|
| | | if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) {
|
| | | String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit");
|
| | | String message = readMarkdown(messageSource, "login.mkd");
|
| | | Component repositoriesMessage = new Label("repositoriesMessage", message);
|
| | | add(repositoriesMessage.setEscapeModelStrings(false));
|
| | | add(new Label("digests"));
|
| | | add(new Label("active").setVisible(false));
|
| | | add(new Label("starred").setVisible(false));
|
| | | add(new Label("owned").setVisible(false));
|
| | | add(new Label("feedheader").setVisible(false));
|
| | | return;
|
| | | }
|
| | |
|
| | | // Load the markdown welcome message
|
| | | String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit");
|
| | | String message = readMarkdown(messageSource, "welcome.mkd");
|
| | | Component repositoriesMessage = new Label("repositoriesMessage", message)
|
| | | .setEscapeModelStrings(false).setVisible(message.length() > 0);
|
| | | add(repositoriesMessage);
|
| | |
|
| | | UserModel user = GitBlitWebSession.get().getUser();
|
| | | if (user == null) {
|
| | | user = UserModel.ANONYMOUS;
|
| | | }
|
| | |
|
| | | Comparator<RepositoryModel> lastUpdateSort = new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | return o2.lastChange.compareTo(o1.lastChange);
|
| | | }
|
| | | };
|
| | | |
| | | // parameters
|
| | | int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params);
|
| | | if (daysBack < 1) {
|
| | | daysBack = 7;
|
| | | }
|
| | | protected void addActivity(UserModel user, Collection<RepositoryModel> repositories, int daysBack) {
|
| | | Calendar c = Calendar.getInstance();
|
| | | c.add(Calendar.DATE, -1*daysBack);
|
| | | Date minimumDate = c.getTime();
|
| | | TimeZone timezone = getTimeZone();
|
| | |
|
| | | // build repo lists |
| | | List<RepositoryModel> starred = new ArrayList<RepositoryModel>();
|
| | | List<RepositoryModel> owned = new ArrayList<RepositoryModel>();
|
| | | List<RepositoryModel> active = new ArrayList<RepositoryModel>();
|
| | |
|
| | | for (RepositoryModel model : getRepositoryModels()) {
|
| | | if (model.isUsersPersonalRepository(user.username) || model.isOwner(user.username)) {
|
| | | owned.add(model);
|
| | | }
|
| | | |
| | | if (user.getPreferences().isStarredRepository(model.name)) {
|
| | | starred.add(model);
|
| | | }
|
| | | |
| | | if (model.isShowActivity() && model.lastChange.after(minimumDate)) {
|
| | | active.add(model);
|
| | | }
|
| | | }
|
| | | |
| | | 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 : feedSources) {
|
| | | List<DailyLogEntry> digests = new ArrayList<DailyLogEntry>();
|
| | | for (RepositoryModel model : repositories) {
|
| | | Repository repository = GitBlit.self().getRepository(model.name);
|
| | | List<DailyLogEntry> entries = PushLogUtils.getDailyLogByRef(model.name, repository, minimumDate, timezone);
|
| | | pushes.addAll(entries);
|
| | | List<DailyLogEntry> entries = RefLogUtils.getDailyLogByRef(model.name, repository, minimumDate, timezone);
|
| | | digests.addAll(entries);
|
| | | repository.close();
|
| | | }
|
| | |
|
| | | if (pushes.size() == 0) {
|
| | | Fragment activityFragment = new Fragment("activity", "activityFragment", this);
|
| | | add(activityFragment);
|
| | | if (digests.size() == 0) {
|
| | | // quiet or no starred repositories
|
| | | if (feedSources.size() == 0) {
|
| | | if (repositories.size() == 0) {
|
| | | if (UserModel.ANONYMOUS.equals(user)) {
|
| | | add(new Label("digests", getString("gb.noActivity"))); |
| | | activityFragment.add(new Label("digests", MessageFormat.format(getString("gb.noActivity"), daysBack))); |
| | | } else {
|
| | | add(new LinkPanel("digests", null, getString("gb.findSomeRepositories"), RepositoriesPage.class));
|
| | | activityFragment.add(new LinkPanel("digests", null, getString("gb.findSomeRepositories"), RepositoriesPage.class));
|
| | | }
|
| | | } else {
|
| | | add(new Label("digests", getString("gb.noActivity")));
|
| | | activityFragment.add(new Label("digests", MessageFormat.format(getString("gb.noActivity"), daysBack)));
|
| | | }
|
| | | } else {
|
| | | // show daily commit digest feed
|
| | | Collections.sort(pushes);
|
| | | add(new PushesPanel("digests", pushes));
|
| | | Collections.sort(digests);
|
| | | DigestsPanel digestsPanel = new DigestsPanel("digests", digests);
|
| | | WicketUtils.setCssStyle(digestsPanel, "margin-top:-20px");
|
| | | activityFragment.add(digestsPanel);
|
| | | }
|
| | |
|
| | | // add the nifty charts
|
| | | if (!ArrayUtils.isEmpty(pushes)) {
|
| | | if (!ArrayUtils.isEmpty(digests)) {
|
| | | // aggregate author exclusions
|
| | | Set<String> authorExclusions = new TreeSet<String>();
|
| | | for (String author : GitBlit.getStrings(Keys.web.metricAuthorExclusions)) {
|
| | | authorExclusions.add(author.toLowerCase());
|
| | | }
|
| | | for (RepositoryModel model : feedSources) {
|
| | | for (RepositoryModel model : repositories) {
|
| | | if (!ArrayUtils.isEmpty(model.metricAuthorExclusions)) {
|
| | | for (String author : model.metricAuthorExclusions) {
|
| | | authorExclusions.add(author.toLowerCase());
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | addCharts(pushes, authorExclusions, daysBack);
|
| | | addCharts(activityFragment, digests, authorExclusions, daysBack);
|
| | | } else {
|
| | | add(new Label("feedheader").setVisible(false));
|
| | | }
|
| | | |
| | | // active repository list
|
| | | if (starred.isEmpty()) {
|
| | | Fragment activeView = createNgList("active", "activeListFragment", "activeCtrl", active);
|
| | | add(activeView);
|
| | | } else {
|
| | | add(new Label("active").setVisible(false));
|
| | | }
|
| | | |
| | | // starred repository list
|
| | | if (ArrayUtils.isEmpty(starred)) {
|
| | | add(new Label("starred").setVisible(false));
|
| | | } else {
|
| | | Fragment starredView = createNgList("starred", "starredListFragment", "starredCtrl", starred);
|
| | | add(starredView);
|
| | | }
|
| | | |
| | | // owned repository list
|
| | | if (ArrayUtils.isEmpty(owned)) {
|
| | | add(new Label("owned").setVisible(false));
|
| | | } else {
|
| | | Fragment ownedView = createNgList("owned", "ownedListFragment", "ownedCtrl", owned);
|
| | | if (user.canCreate) {
|
| | | // create button
|
| | | ownedView.add(new LinkPanel("create", "btn btn-mini", getString("gb.newRepository"), EditRepositoryPage.class));
|
| | | } else {
|
| | | // no button
|
| | | ownedView.add(new Label("create").setVisible(false));
|
| | | }
|
| | | add(ownedView);
|
| | | activityFragment.add(new Label("charts").setVisible(false));
|
| | | activityFragment.add(new Label("feedheader").setVisible(false));
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | item.n = name;
|
| | | item.p = path;
|
| | | item.r = repo.name;
|
| | | item.i = repo.description;
|
| | | item.s = GitBlit.self().getStarCount(repo);
|
| | | item.t = getTimeUtils().timeAgo(repo.lastChange);
|
| | | item.d = df.format(repo.lastChange);
|
| | |
| | | pages.add(menu);
|
| | | }
|
| | |
|
| | | private String readMarkdown(String messageSource, String resource) {
|
| | | String message = "";
|
| | | if (messageSource.equalsIgnoreCase("gitblit")) {
|
| | | // Read default message
|
| | | message = readDefaultMarkdown(resource);
|
| | | } else {
|
| | | // Read user-supplied message
|
| | | if (!StringUtils.isEmpty(messageSource)) {
|
| | | File file = GitBlit.getFileOrFolder(messageSource);
|
| | | if (file.exists()) {
|
| | | try {
|
| | | FileInputStream fis = new FileInputStream(file);
|
| | | InputStreamReader reader = new InputStreamReader(fis,
|
| | | Constants.CHARACTER_ENCODING);
|
| | | message = MarkdownUtils.transformMarkdown(reader);
|
| | | reader.close();
|
| | | } catch (Throwable t) {
|
| | | message = getString("gb.failedToRead") + " " + file;
|
| | | warn(message, t);
|
| | | }
|
| | | } else {
|
| | | message = messageSource + " " + getString("gb.isNotValidFile");
|
| | | }
|
| | | }
|
| | | }
|
| | | return message;
|
| | | }
|
| | |
|
| | | private String readDefaultMarkdown(String file) {
|
| | | String base = file.substring(0, file.lastIndexOf('.'));
|
| | | String ext = file.substring(file.lastIndexOf('.'));
|
| | | String lc = getLanguageCode();
|
| | | String cc = getCountryCode();
|
| | |
|
| | | // try to read file_en-us.ext, file_en.ext, file.ext
|
| | | List<String> files = new ArrayList<String>();
|
| | | if (!StringUtils.isEmpty(lc)) {
|
| | | if (!StringUtils.isEmpty(cc)) {
|
| | | files.add(base + "_" + lc + "-" + cc + ext);
|
| | | files.add(base + "_" + lc + "_" + cc + ext);
|
| | | }
|
| | | files.add(base + "_" + lc + ext);
|
| | | }
|
| | | files.add(file);
|
| | |
|
| | | for (String name : files) {
|
| | | String message;
|
| | | InputStreamReader reader = null;
|
| | | try {
|
| | | InputStream is = getClass().getResourceAsStream("/" + name);
|
| | | if (is == null) {
|
| | | continue;
|
| | | }
|
| | | reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING);
|
| | | message = MarkdownUtils.transformMarkdown(reader);
|
| | | reader.close();
|
| | | return message;
|
| | | } catch (Throwable t) {
|
| | | message = MessageFormat.format(getString("gb.failedToReadMessage"), file);
|
| | | error(message, t, false);
|
| | | return message;
|
| | | } finally {
|
| | | if (reader != null) {
|
| | | try {
|
| | | reader.close();
|
| | | } catch (Exception e) {
|
| | | }
|
| | | }
|
| | | } |
| | | }
|
| | | return MessageFormat.format(getString("gb.failedToReadMessage"), file);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Creates the daily activity line chart, the active repositories pie chart,
|
| | | * and the active authors pie chart
|
| | | *
|
| | | * @param recentPushes
|
| | | * @param recentChanges
|
| | | * @param authorExclusions
|
| | | * @param daysBack
|
| | | */
|
| | | private void addCharts(List<PushLogEntry> recentPushes, Set<String> authorExclusions, int daysBack) {
|
| | | protected void addCharts(Fragment frag, List<DailyLogEntry> recentChanges, Set<String> authorExclusions, int daysBack) {
|
| | | // activity metrics
|
| | | Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();
|
| | | Map<String, Metric> authorMetrics = new HashMap<String, Metric>();
|
| | |
|
| | | // aggregate repository and author metrics
|
| | | int totalCommits = 0;
|
| | | for (PushLogEntry push : recentPushes) {
|
| | | for (RefLogEntry change : recentChanges) {
|
| | |
|
| | | // aggregate repository metrics
|
| | | String repository = StringUtils.stripDotGit(push.repository);
|
| | | String repository = StringUtils.stripDotGit(change.repository);
|
| | | if (!repositoryMetrics.containsKey(repository)) {
|
| | | repositoryMetrics.put(repository, new Metric(repository));
|
| | | }
|
| | | repositoryMetrics.get(repository).count += 1;
|
| | |
|
| | | for (RepositoryCommit commit : push.getCommits()) {
|
| | | for (RepositoryCommit commit : change.getCommits()) {
|
| | | totalCommits++;
|
| | | String author = StringUtils.removeNewlines(commit.getAuthorIdent().getName());
|
| | | String authorName = author.toLowerCase();
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | add(new Label("feedheader", MessageFormat.format(getString("gb.recentActivityStats"),
|
| | | frag.add(new Label("feedheader", MessageFormat.format(getString("gb.recentActivityStats"),
|
| | | daysBack, totalCommits, authorMetrics.size())));
|
| | |
|
| | | // build google charts
|
| | |
| | | charts.addChart(chart);
|
| | |
|
| | | add(new HeaderContributor(charts));
|
| | | frag.add(new Fragment("charts", "chartsFragment", this));
|
| | | }
|
| | |
|
| | | class RepoListItem implements Serializable {
|
| | | protected class RepoListItem implements Serializable {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | | String p; // project/path
|
| | | String t; // time ago
|
| | | String d; // last updated
|
| | | String i; // information/description
|
| | | long s; // stars
|
| | | String c; // html color
|
| | | int wc; // working copy, 1 = true
|
New file |
| | |
| | | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
| | | <html xmlns="http://www.w3.org/1999/xhtml" |
| | | xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd" |
| | | xml:lang="en" |
| | | lang="en"> |
| | |
|
| | | <body>
|
| | | <wicket:extend>
|
| | | <div class="container">
|
| | |
|
| | | <div class="row" style="padding-top:5px;">
|
| | | <div class="span7">
|
| | | <div class="hidden-phone markdown" style="padding-bottom: 30px;" wicket:id="repositoriesMessage">[repositories message]</div>
|
| | | <div wicket:id="activity"></div>
|
| | | </div>
|
| | | <div class="span5">
|
| | | <div wicket:id="repositoryTabs"></div>
|
| | | </div> |
| | | </div>
|
| | | </div>
|
| | |
|
| | | <wicket:fragment wicket:id="anonymousTabsFragment">
|
| | | <ul class="nav nav-pills">
|
| | | <li class="active"><a href="#recent" data-toggle="tab"><wicket:message key="gb.active">[active]</wicket:message></a></li>
|
| | | <li><a href="#projects" data-toggle="tab"><wicket:message key="gb.projects">[projects]</wicket:message></a></li>
|
| | | </ul>
|
| | | <div class="tab-content">
|
| | | <div class="tab-pane active" id="recent">
|
| | | <div wicket:id="active">[recently active]</div>
|
| | | </div>
|
| | | <div class="tab-pane" id="projects">
|
| | | <div wicket:id="projectList">[all projects]</div>
|
| | | </div>
|
| | | </div>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="authenticatedTabsFragment">
|
| | | <ul class="nav nav-pills">
|
| | | <li class="active"><a href="#starred" data-toggle="tab"><wicket:message key="gb.starred">[starred]</wicket:message></a></li>
|
| | | <li><a href="#owned" data-toggle="tab"><wicket:message key="gb.owned">[owned]</wicket:message></a></li>
|
| | | <li><a href="#recent" data-toggle="tab"><wicket:message key="gb.active">[active]</wicket:message></a></li>
|
| | | <li><a href="#projects" data-toggle="tab"><wicket:message key="gb.projects">[projects]</wicket:message></a></li>
|
| | | </ul>
|
| | | <div class="tab-content">
|
| | | <div class="tab-pane active" id="starred">
|
| | | <div wicket:id="starred">[starred repositories]</div>
|
| | | </div>
|
| | | <div class="tab-pane" id="owned">
|
| | | <div wicket:id="owned">[my repositories]</div>
|
| | | </div>
|
| | | <div class="tab-pane" id="recent">
|
| | | <div wicket:id="active">[recently active]</div>
|
| | | </div>
|
| | | <div class="tab-pane" id="projects">
|
| | | <div wicket:id="projectList">[all projects]</div>
|
| | | </div>
|
| | | </div>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="activityFragment">
|
| | | <div class="dashboardTitle"><wicket:message key="gb.recentActivity"></wicket:message> <small><span wicket:id="feedheader"></span></small></div>
|
| | | <div class="hidden-phone hidden-tablet" style="text-align:center;">
|
| | | <div wicket:id="charts"></div>
|
| | | </div>
|
| | | <div wicket:id="digests"></div>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="chartsFragment">
|
| | | <table>
|
| | | <tr>
|
| | | <td><div id="chartRepositories" style="display:inline-block;width: 175px; height:175px"></div></td>
|
| | | <td><div id="chartAuthors" style="display:inline-block;width: 175px; height: 175px;"></div></td>
|
| | | </tr>
|
| | | </table>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="starredListFragment">
|
| | | <div ng-controller="starredCtrl" style="border: 1px solid #ddd;border-radius: 4px;margin-bottom: 20px;">
|
| | | <div class="header" style="padding: 5px;border: none;"><i class="icon-star"></i> <wicket:message key="gb.starredRepositories"></wicket:message> ({{starred.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>
|
| | | </div>
|
| | | </div>
|
| | | |
| | | <div ng-repeat="item in starred | 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}}" title="{{item.i}}">{{item.p}}<b>{{item.n}}</b></a>
|
| | | <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 style="vertical-align:baseline;" class="iconic-star"></i></span>
|
| | | </span>
|
| | | </div>
|
| | | |
| | | </div>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="ownedListFragment">
|
| | | <div ng-controller="ownedCtrl" style="border: 1px solid #ddd;border-radius: 4px;">
|
| | | <div class="header" style="padding: 5px;border: none;"><i class="icon-user"></i> <wicket:message key="gb.myRepositories"></wicket:message> ({{owned.length}})
|
| | | <div class="hidden-phone pull-right">
|
| | | <span wicket:id="create"></span>
|
| | | </div>
|
| | | <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>
|
| | | </div>
|
| | | </div>
|
| | | |
| | | <div ng-repeat="item in owned | 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}}" title="{{item.i}}">{{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 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;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>
|
| | | </div>
|
| | | </div>
|
| | | |
| | | <div ng-repeat="item in active | 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}}" title="{{item.i}}">{{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 style="vertical-align:baseline;" class="iconic-star"></i></span>
|
| | | </span>
|
| | | </div> |
| | | </div>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="projectListFragment">
|
| | | <div ng-controller="projectListCtrl" style="border: 1px solid #ddd;border-radius: 4px;margin-bottom: 20px;">
|
| | | <div class="header" style="padding: 5px;border: none;"><i class="icon-folder-close"></i> <wicket:message key="gb.projects"></wicket:message> ({{projectList.length}})
|
| | | <div style="padding: 5px 0px 0px;">
|
| | | <input type="text" ng-model="query.n" class="input-large" wicket:message="placeholder:gb.filter" style="border-radius: 14px; padding: 3px 14px;margin: 0px;"></input>
|
| | | </div>
|
| | | </div>
|
| | | |
| | | <div ng-repeat="item in projectList | filter:query" style="padding: 3px;border-top: 1px solid #ddd;">
|
| | | <a href="project/{{item.p}}" title="{{item.i}}"><b>{{item.n}}</b></a>
|
| | | <span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
|
| | | <span class="pull-right">
|
| | | <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;" wicket:message="title:gb.repositories">{{item.c | number}}</span>
|
| | | </span>
|
| | | </div>
|
| | | </div>
|
| | | </wicket:fragment>
|
| | |
|
| | | </wicket:extend>
|
| | | </body>
|
| | | </html> |
New file |
| | |
| | | /*
|
| | | * Copyright 2013 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | package com.gitblit.wicket.pages;
|
| | |
|
| | | import java.io.File;
|
| | | import java.io.FileInputStream;
|
| | | import java.io.InputStream;
|
| | | import java.io.InputStreamReader;
|
| | | import java.io.Serializable;
|
| | | import java.text.DateFormat;
|
| | | import java.text.MessageFormat;
|
| | | import java.text.SimpleDateFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Calendar;
|
| | | import java.util.Collections;
|
| | | import java.util.Comparator;
|
| | | import java.util.Date;
|
| | | import java.util.HashSet;
|
| | | import java.util.List;
|
| | | import java.util.Set;
|
| | |
|
| | | import org.apache.wicket.Component;
|
| | | import org.apache.wicket.PageParameters;
|
| | | import org.apache.wicket.behavior.HeaderContributor;
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | import org.apache.wicket.markup.html.panel.Fragment;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | |
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.models.ProjectModel;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.ArrayUtils;
|
| | | import com.gitblit.utils.MarkdownUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.wicket.GitBlitWebSession;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.ng.NgController;
|
| | | import com.gitblit.wicket.panels.LinkPanel;
|
| | |
|
| | | public class MyDashboardPage extends DashboardPage {
|
| | |
|
| | | public MyDashboardPage() {
|
| | | super();
|
| | | setup(null);
|
| | | }
|
| | |
|
| | | public MyDashboardPage(PageParameters params) {
|
| | | super(params);
|
| | | setup(params);
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected boolean reusePageParameters() {
|
| | | return true;
|
| | | }
|
| | |
|
| | | private void setup(PageParameters params) {
|
| | | setupPage("", "");
|
| | | // check to see if we should display a login message
|
| | | boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
|
| | | if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) {
|
| | | String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit");
|
| | | String message = readMarkdown(messageSource, "login.mkd");
|
| | | Component repositoriesMessage = new Label("repositoriesMessage", message);
|
| | | add(repositoriesMessage.setEscapeModelStrings(false));
|
| | | add(new Label("activity").setVisible(false));
|
| | | add(new Label("repositoryTabs").setVisible(false));
|
| | | return;
|
| | | }
|
| | |
|
| | | // Load the markdown welcome message
|
| | | String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit");
|
| | | String message = readMarkdown(messageSource, "welcome.mkd");
|
| | | Component repositoriesMessage = new Label("repositoriesMessage", message)
|
| | | .setEscapeModelStrings(false).setVisible(message.length() > 0);
|
| | | add(repositoriesMessage);
|
| | |
|
| | | UserModel user = GitBlitWebSession.get().getUser();
|
| | | if (user == null) {
|
| | | user = UserModel.ANONYMOUS;
|
| | | }
|
| | |
|
| | | // parameters
|
| | | int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params);
|
| | | if (daysBack < 1) {
|
| | | daysBack = 7;
|
| | | }
|
| | | Calendar c = Calendar.getInstance();
|
| | | c.add(Calendar.DATE, -1*daysBack);
|
| | | Date minimumDate = c.getTime();
|
| | | |
| | | // build repo lists |
| | | List<RepositoryModel> starred = new ArrayList<RepositoryModel>();
|
| | | List<RepositoryModel> owned = new ArrayList<RepositoryModel>();
|
| | | List<RepositoryModel> active = new ArrayList<RepositoryModel>();
|
| | |
|
| | | for (RepositoryModel model : getRepositoryModels()) {
|
| | | if (model.isUsersPersonalRepository(user.username) || model.isOwner(user.username)) {
|
| | | owned.add(model);
|
| | | }
|
| | | |
| | | if (user.getPreferences().isStarredRepository(model.name)) {
|
| | | starred.add(model);
|
| | | }
|
| | | |
| | | if (model.isShowActivity() && model.lastChange.after(minimumDate)) {
|
| | | active.add(model);
|
| | | }
|
| | | }
|
| | | |
| | | Comparator<RepositoryModel> lastUpdateSort = new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | return o2.lastChange.compareTo(o1.lastChange);
|
| | | }
|
| | | };
|
| | | |
| | | Collections.sort(owned, lastUpdateSort);
|
| | | Collections.sort(starred, lastUpdateSort);
|
| | | Collections.sort(active, lastUpdateSort);
|
| | | |
| | | Set<RepositoryModel> feed = new HashSet<RepositoryModel>();
|
| | | feed.addAll(starred);
|
| | | feed.addAll(owned);
|
| | | if (feed.isEmpty()) {
|
| | | feed.addAll(active);
|
| | | }
|
| | | |
| | | addActivity(user, feed, daysBack);
|
| | | |
| | | Fragment repositoryTabs;
|
| | | if (UserModel.ANONYMOUS.equals(user)) {
|
| | | repositoryTabs = new Fragment("repositoryTabs", "anonymousTabsFragment", this);
|
| | | } else {
|
| | | repositoryTabs = new Fragment("repositoryTabs", "authenticatedTabsFragment", this);
|
| | | }
|
| | | |
| | | add(repositoryTabs);
|
| | | |
| | | Fragment projectList = createProjectList();
|
| | | repositoryTabs.add(projectList);
|
| | | |
| | | // active repository list
|
| | | if (active.isEmpty()) {
|
| | | repositoryTabs.add(new Label("active").setVisible(false));
|
| | | } else {
|
| | | Fragment activeView = createNgList("active", "activeListFragment", "activeCtrl", active);
|
| | | repositoryTabs.add(activeView);
|
| | | }
|
| | | |
| | | // starred repository list
|
| | | if (ArrayUtils.isEmpty(starred)) {
|
| | | repositoryTabs.add(new Label("starred").setVisible(false));
|
| | | } else {
|
| | | Fragment starredView = createNgList("starred", "starredListFragment", "starredCtrl", starred);
|
| | | repositoryTabs.add(starredView);
|
| | | }
|
| | | |
| | | // owned repository list
|
| | | if (ArrayUtils.isEmpty(owned)) {
|
| | | repositoryTabs.add(new Label("owned").setVisible(false));
|
| | | } else {
|
| | | Fragment ownedView = createNgList("owned", "ownedListFragment", "ownedCtrl", owned);
|
| | | if (user.canCreate) {
|
| | | // create button
|
| | | ownedView.add(new LinkPanel("create", "btn btn-mini", getString("gb.newRepository"), EditRepositoryPage.class));
|
| | | } else {
|
| | | // no button
|
| | | ownedView.add(new Label("create").setVisible(false));
|
| | | }
|
| | | repositoryTabs.add(ownedView);
|
| | | }
|
| | | }
|
| | | |
| | | private String readMarkdown(String messageSource, String resource) {
|
| | | String message = "";
|
| | | if (messageSource.equalsIgnoreCase("gitblit")) {
|
| | | // Read default message
|
| | | message = readDefaultMarkdown(resource);
|
| | | } else {
|
| | | // Read user-supplied message
|
| | | if (!StringUtils.isEmpty(messageSource)) {
|
| | | File file = GitBlit.getFileOrFolder(messageSource);
|
| | | if (file.exists()) {
|
| | | try {
|
| | | FileInputStream fis = new FileInputStream(file);
|
| | | InputStreamReader reader = new InputStreamReader(fis,
|
| | | Constants.CHARACTER_ENCODING);
|
| | | message = MarkdownUtils.transformMarkdown(reader);
|
| | | reader.close();
|
| | | } catch (Throwable t) {
|
| | | message = getString("gb.failedToRead") + " " + file;
|
| | | warn(message, t);
|
| | | }
|
| | | } else {
|
| | | message = messageSource + " " + getString("gb.isNotValidFile");
|
| | | }
|
| | | }
|
| | | }
|
| | | return message;
|
| | | }
|
| | |
|
| | | private String readDefaultMarkdown(String file) {
|
| | | String base = file.substring(0, file.lastIndexOf('.'));
|
| | | String ext = file.substring(file.lastIndexOf('.'));
|
| | | String lc = getLanguageCode();
|
| | | String cc = getCountryCode();
|
| | |
|
| | | // try to read file_en-us.ext, file_en.ext, file.ext
|
| | | List<String> files = new ArrayList<String>();
|
| | | if (!StringUtils.isEmpty(lc)) {
|
| | | if (!StringUtils.isEmpty(cc)) {
|
| | | files.add(base + "_" + lc + "-" + cc + ext);
|
| | | files.add(base + "_" + lc + "_" + cc + ext);
|
| | | }
|
| | | files.add(base + "_" + lc + ext);
|
| | | }
|
| | | files.add(file);
|
| | |
|
| | | for (String name : files) {
|
| | | String message;
|
| | | InputStreamReader reader = null;
|
| | | try {
|
| | | InputStream is = getClass().getResourceAsStream("/" + name);
|
| | | if (is == null) {
|
| | | continue;
|
| | | }
|
| | | reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING);
|
| | | message = MarkdownUtils.transformMarkdown(reader);
|
| | | reader.close();
|
| | | return message;
|
| | | } catch (Throwable t) {
|
| | | message = MessageFormat.format(getString("gb.failedToReadMessage"), file);
|
| | | error(message, t, false);
|
| | | return message;
|
| | | } finally {
|
| | | if (reader != null) {
|
| | | try {
|
| | | reader.close();
|
| | | } catch (Exception e) {
|
| | | }
|
| | | }
|
| | | } |
| | | }
|
| | | return MessageFormat.format(getString("gb.failedToReadMessage"), file);
|
| | | }
|
| | | |
| | | protected Fragment createProjectList() {
|
| | | String format = GitBlit.getString(Keys.web.datestampShortFormat, "MM/dd/yy");
|
| | | final DateFormat df = new SimpleDateFormat(format);
|
| | | df.setTimeZone(getTimeZone());
|
| | | List<ProjectModel> projects = GitBlit.self().getProjectModels(getRepositoryModels(), false);
|
| | | Collections.sort(projects, new Comparator<ProjectModel>() {
|
| | | @Override
|
| | | public int compare(ProjectModel o1, ProjectModel o2) {
|
| | | return o2.lastChange.compareTo(o1.lastChange);
|
| | | }
|
| | | });
|
| | |
|
| | | List<ProjectListItem> list = new ArrayList<ProjectListItem>();
|
| | | for (ProjectModel proj : projects) {
|
| | | if (proj.isUserProject() || proj.repositories.isEmpty()) {
|
| | | // exclude user projects from list
|
| | | continue;
|
| | | }
|
| | | ProjectListItem item = new ProjectListItem();
|
| | | item.p = proj.name;
|
| | | item.n = StringUtils.isEmpty(proj.title) ? proj.name : proj.title;
|
| | | item.i = proj.description;
|
| | | item.t = getTimeUtils().timeAgo(proj.lastChange);
|
| | | item.d = df.format(proj.lastChange);
|
| | | item.c = proj.repositories.size();
|
| | | list.add(item);
|
| | | }
|
| | | |
| | | // inject an AngularJS controller with static data
|
| | | NgController ctrl = new NgController("projectListCtrl");
|
| | | ctrl.addVariable("projectList", list);
|
| | | add(new HeaderContributor(ctrl));
|
| | | |
| | | Fragment fragment = new Fragment("projectList", "projectListFragment", this);
|
| | | return fragment;
|
| | | }
|
| | | |
| | | protected class ProjectListItem implements Serializable {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | | |
| | | String p; // path
|
| | | String n; // name
|
| | | String t; // time ago
|
| | | String d; // last updated
|
| | | String i; // information/description
|
| | | long c; // repository count
|
| | | }
|
| | | }
|
| | |
| | | <div class="span6">
|
| | | <div class="hidden-tablet" style="padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid #ddd;" wicket:id="repositoryUrlPanel">[repository url panel]</div>
|
| | |
|
| | | <div wicket:id="pushesPanel">[pushes panel]</div> |
| | | <div wicket:id="reflogPanel">[reflog panel]</div> |
| | | </div>
|
| | | </div>
|
| | |
|
| | |
| | | import com.gitblit.wicket.charting.GoogleLineChart;
|
| | | import com.gitblit.wicket.panels.BranchesPanel;
|
| | | import com.gitblit.wicket.panels.LinkPanel;
|
| | | import com.gitblit.wicket.panels.PushesPanel;
|
| | | import com.gitblit.wicket.panels.ReflogPanel;
|
| | | import com.gitblit.wicket.panels.RepositoryUrlPanel;
|
| | | import com.gitblit.wicket.panels.TagsPanel;
|
| | |
|
| | |
| | |
|
| | | add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model));
|
| | |
|
| | | int pushCount = GitBlit.getInteger(Keys.web.overviewPushCount, 5);
|
| | | PushesPanel pushes = new PushesPanel("pushesPanel", getRepositoryModel(), r, pushCount, 0, false);
|
| | | add(pushes);
|
| | | int reflogCount = GitBlit.getInteger(Keys.web.overviewReflogCount, 5);
|
| | | ReflogPanel reflog = new ReflogPanel("reflogPanel", getRepositoryModel(), r, reflogCount, 0);
|
| | | add(reflog);
|
| | | add(new TagsPanel("tagsPanel", repositoryName, r, numberRefs).hideIfEmpty());
|
| | | add(new BranchesPanel("branchesPanel", getRepositoryModel(), r, numberRefs, false).hideIfEmpty());
|
| | |
|
| | |
| | |
|
| | | <body>
|
| | | <wicket:extend>
|
| | |
|
| | | <div class="container">
|
| | | <div class="row">
|
| | | <div class="row" style="padding-top:5px;">
|
| | | <div class="span12">
|
| | | <h2><span wicket:id="projectTitle"></span> <small><span wicket:id="projectDescription"></span></small>
|
| | | <a class="hidden-phone hidden-tablet brand" style="text-decoration: none;" wicket:id="syndication" wicket:message="title:gb.feed">
|
| | | <img style="border:0px;vertical-align:middle;" src="feed_16x16.png"></img>
|
| | | <div class="dashboardTitle">
|
| | | <span wicket:id="projectTitle"></span>
|
| | | <small><span wicket:id="projectDescription"></span></small>
|
| | | |
| | | <a
|
| | | class="hidden-phone hidden-tablet brand"
|
| | | style="text-decoration: none;" wicket:id="syndication"
|
| | | wicket:message="title:gb.feed"> <img
|
| | | style="border: 0px; vertical-align: middle;" src="feed_16x16.png"></img>
|
| | | </a>
|
| | | </h2>
|
| | | <div class="markdown" wicket:id="projectMessage">[project message]</div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <div class="tabbable">
|
| | | <!-- tab titles -->
|
| | | <ul class="nav nav-tabs">
|
| | | <li class="active"><a href="#repositories" data-toggle="tab"><wicket:message key="gb.repositories"></wicket:message></a></li>
|
| | | <li ><a href="#activity" data-toggle="tab"><wicket:message key="gb.activity"></wicket:message></a></li>
|
| | | </ul>
|
| | | |
| | | <!-- tab content -->
|
| | | <div class="tab-content">
|
| | |
|
| | | <!-- repositories tab -->
|
| | | <div class="tab-pane active" id="repositories">
|
| | | <!-- markdown -->
|
| | | <div class="row">
|
| | | <div class="span12">
|
| | | <div class="span7"> |
| | | <div class="markdown" style="padding-bottom: 30px;" wicket:id="projectMessage">[project message]</div>
|
| | | <div wicket:id="activity">[activity panel]</div>
|
| | | </div>
|
| | | <div class="span5">
|
| | | <div class="markdown" wicket:id="repositoriesMessage">[repositories message]</div>
|
| | | </div>
|
| | | </div>
|
| | | <div class="row">
|
| | | <div class="span6" wicket:id="repositoryList">
|
| | | <span wicket:id="repository"></span>
|
| | | <div wicket:id="repositoryList">[repository list]</div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <!-- activity tab -->
|
| | | <div class="tab-pane" id="activity">
|
| | | <div class="pageTitle">
|
| | | <h2><wicket:message key="gb.recentActivity"></wicket:message><small> <span class="hidden-phone">/ <span wicket:id="subheader">[days back]</span></span></small></h2>
|
| | | <wicket:fragment wicket:id="activityFragment">
|
| | | <div class="dashboardTitle"><wicket:message key="gb.recentActivity"></wicket:message> <small><span wicket:id="feedheader"></span></small></div>
|
| | | <div class="hidden-phone hidden-tablet" style="text-align:center;">
|
| | | <div wicket:id="charts"></div>
|
| | | </div>
|
| | | <div wicket:id="digests"></div>
|
| | | </wicket:fragment>
|
| | |
|
| | | <div class="hidden-phone" style="height: 155px;text-align: center;">
|
| | | <wicket:fragment wicket:id="chartsFragment">
|
| | | <table>
|
| | | <tr>
|
| | | <td><span class="hidden-tablet" id="chartDaily"></span></td>
|
| | | <td><span id="chartRepositories"></span></td>
|
| | | <td><span id="chartAuthors"></span></td>
|
| | | <td><div id="chartRepositories" style="display:inline-block;width: 175px; height:175px"></div></td>
|
| | | <td><div id="chartAuthors" style="display:inline-block;width: 175px; height: 175px;"></div></td>
|
| | | </tr>
|
| | | </table>
|
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="repositoryListFragment">
|
| | | <div ng-controller="repositoryListCtrl" style="border: 1px solid #ddd;border-radius: 4px;margin-bottom: 20px;">
|
| | | <div class="header" style="padding: 5px;border: none;"><img style="vertical-align: middle;" src="git-black-16x16.png"/> <wicket:message key="gb.repositories"></wicket:message> ({{repositoryList.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>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <div wicket:id="activityPanel">[activity panel]</div>
|
| | | </div>
|
| | | |
| | | <div ng-repeat="item in repositoryList | 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}}" title="{{item.i}}">{{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 style="vertical-align:baseline;" class="iconic-star"></i></span>
|
| | | </span>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | </wicket:fragment> |
| | | </wicket:extend>
|
| | | </body>
|
| | | </html> |
| | |
| | | */
|
| | | package com.gitblit.wicket.pages;
|
| | |
|
| | | import java.text.MessageFormat;
|
| | | import java.text.SimpleDateFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Collections;
|
| | | import java.util.Comparator;
|
| | | import java.util.HashMap;
|
| | | import java.util.HashSet;
|
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | | import java.util.Set;
|
| | |
|
| | | import org.apache.wicket.Component;
|
| | | import org.apache.wicket.PageParameters;
|
| | | import org.apache.wicket.behavior.HeaderContributor;
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | import org.apache.wicket.markup.html.link.ExternalLink;
|
| | | 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.apache.wicket.markup.html.panel.Fragment;
|
| | |
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.SyndicationServlet;
|
| | | import com.gitblit.models.Activity;
|
| | | import com.gitblit.models.Metric;
|
| | | import com.gitblit.models.ProjectModel;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.utils.ActivityUtils;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.MarkdownUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.wicket.GitBlitWebApp;
|
| | |
| | | import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
|
| | | import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.charting.GoogleChart;
|
| | | import com.gitblit.wicket.charting.GoogleCharts;
|
| | | import com.gitblit.wicket.charting.GoogleLineChart;
|
| | | import com.gitblit.wicket.charting.GooglePieChart;
|
| | | import com.gitblit.wicket.panels.ActivityPanel;
|
| | | import com.gitblit.wicket.panels.ProjectRepositoryPanel;
|
| | |
|
| | | public class ProjectPage extends RootPage {
|
| | | public class ProjectPage extends DashboardPage {
|
| | |
|
| | | List<ProjectModel> projectModels = new ArrayList<ProjectModel>();
|
| | |
|
| | |
| | | setup(params);
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected boolean reusePageParameters() {
|
| | | return true;
|
| | | protected Class<? extends BasePage> getRootNavPageClass() {
|
| | | return RepositoriesPage.class;
|
| | | }
|
| | |
|
| | | private void setup(PageParameters params) {
|
| | |
| | | .setEscapeModelStrings(false).setVisible(rmessage.length() > 0);
|
| | | add(repositoriesMessage);
|
| | |
|
| | | List<RepositoryModel> repositories = getRepositories(params);
|
| | | UserModel user = GitBlitWebSession.get().getUser();
|
| | | if (user == null) {
|
| | | user = UserModel.ANONYMOUS;
|
| | | }
|
| | | int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params);
|
| | | if (daysBack < 1) {
|
| | | daysBack = 7;
|
| | | }
|
| | | // reset the daysback parameter so that we have a complete project
|
| | | // repository list. the recent activity will be built up by the
|
| | | // reflog utils.
|
| | | params.put("db", 0);
|
| | |
|
| | | List<RepositoryModel> repositories = getRepositories(params);
|
| | | Collections.sort(repositories, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | |
| | | }
|
| | | });
|
| | |
|
| | | final ListDataProvider<RepositoryModel> dp = new ListDataProvider<RepositoryModel>(repositories);
|
| | | DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("repositoryList", dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public void populateItem(final Item<RepositoryModel> item) {
|
| | | final RepositoryModel entry = item.getModelObject();
|
| | | addActivity(user, repositories, daysBack);
|
| | |
|
| | | ProjectRepositoryPanel row = new ProjectRepositoryPanel("repository", |
| | | getLocalizer(), this, showAdmin, entry, getAccessRestrictions());
|
| | | item.add(row);
|
| | | }
|
| | | };
|
| | | add(dataView);
|
| | |
|
| | | // project activity
|
| | | // parameters
|
| | | int daysBack = WicketUtils.getDaysBack(params);
|
| | | if (daysBack < 1) {
|
| | | daysBack = 14;
|
| | | }
|
| | | String objectId = WicketUtils.getObject(params);
|
| | |
|
| | | List<Activity> recentActivity = ActivityUtils.getRecentActivity(repositories, |
| | | daysBack, objectId, getTimeZone());
|
| | | if (recentActivity.size() == 0) {
|
| | | // no activity, skip graphs and activity panel
|
| | | add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityNone"),
|
| | | daysBack)));
|
| | | add(new Label("activityPanel"));
|
| | | if (repositories.isEmpty()) {
|
| | | add(new Label("repositoryList").setVisible(false));
|
| | | } else {
|
| | | // calculate total commits and total authors
|
| | | int totalCommits = 0;
|
| | | Set<String> uniqueAuthors = new HashSet<String>();
|
| | | for (Activity activity : recentActivity) {
|
| | | totalCommits += activity.getCommitCount();
|
| | | uniqueAuthors.addAll(activity.getAuthorMetrics().keySet());
|
| | | Fragment activeView = createNgList("repositoryList", "repositoryListFragment", "repositoryListCtrl", repositories);
|
| | | add(activeView);
|
| | | }
|
| | | int totalAuthors = uniqueAuthors.size();
|
| | |
|
| | | // add the subheader with stat numbers
|
| | | add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityStats"),
|
| | | daysBack, totalCommits, totalAuthors)));
|
| | |
|
| | | // create the activity charts
|
| | | GoogleCharts charts = createCharts(recentActivity);
|
| | | add(new HeaderContributor(charts));
|
| | |
|
| | | // add activity panel
|
| | | add(new ActivityPanel("activityPanel", recentActivity));
|
| | | }
|
| | | }
|
| | | |
| | | /**
|
| | | * Creates the daily activity line chart, the active repositories pie chart,
|
| | | * and the active authors pie chart
|
| | | * |
| | | * @param recentActivity
|
| | | * @return
|
| | | */
|
| | | private GoogleCharts createCharts(List<Activity> recentActivity) {
|
| | | // activity metrics
|
| | | Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();
|
| | | Map<String, Metric> authorMetrics = new HashMap<String, Metric>();
|
| | |
|
| | | // aggregate repository and author metrics
|
| | | for (Activity activity : recentActivity) {
|
| | |
|
| | | // aggregate author metrics
|
| | | for (Map.Entry<String, Metric> entry : activity.getAuthorMetrics().entrySet()) {
|
| | | String author = entry.getKey();
|
| | | if (!authorMetrics.containsKey(author)) {
|
| | | authorMetrics.put(author, new Metric(author));
|
| | | }
|
| | | authorMetrics.get(author).count += entry.getValue().count;
|
| | | }
|
| | |
|
| | | // aggregate repository metrics
|
| | | for (Map.Entry<String, Metric> entry : activity.getRepositoryMetrics().entrySet()) {
|
| | | String repository = StringUtils.stripDotGit(entry.getKey());
|
| | | if (!repositoryMetrics.containsKey(repository)) {
|
| | | repositoryMetrics.put(repository, new Metric(repository));
|
| | | }
|
| | | repositoryMetrics.get(repository).count += entry.getValue().count;
|
| | | }
|
| | | }
|
| | |
|
| | | // build google charts
|
| | | int w = 310;
|
| | | int h = 150;
|
| | | GoogleCharts charts = new GoogleCharts();
|
| | |
|
| | | // sort in reverse-chronological order and then reverse that
|
| | | Collections.sort(recentActivity);
|
| | | Collections.reverse(recentActivity);
|
| | |
|
| | | // daily line chart
|
| | | GoogleChart chart = new GoogleLineChart("chartDaily", getString("gb.dailyActivity"), "day",
|
| | | getString("gb.commits"));
|
| | | SimpleDateFormat df = new SimpleDateFormat("MMM dd");
|
| | | df.setTimeZone(getTimeZone());
|
| | | for (Activity metric : recentActivity) {
|
| | | chart.addValue(df.format(metric.startDate), metric.getCommitCount());
|
| | | }
|
| | | chart.setWidth(w);
|
| | | chart.setHeight(h);
|
| | | charts.addChart(chart);
|
| | |
|
| | | // active repositories pie chart
|
| | | chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"),
|
| | | getString("gb.repository"), getString("gb.commits"));
|
| | | for (Metric metric : repositoryMetrics.values()) {
|
| | | chart.addValue(metric.name, metric.count);
|
| | | }
|
| | | chart.setWidth(w);
|
| | | chart.setHeight(h);
|
| | | charts.addChart(chart);
|
| | |
|
| | | // active authors pie chart
|
| | | chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"),
|
| | | getString("gb.author"), getString("gb.commits"));
|
| | | for (Metric metric : authorMetrics.values()) {
|
| | | chart.addValue(metric.name, metric.count);
|
| | | }
|
| | | chart.setWidth(w);
|
| | | chart.setHeight(h);
|
| | | charts.addChart(chart);
|
| | |
|
| | | return charts;
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void addDropDownMenus(List<PageRegistration> pages) {
|
| | | PageParameters params = getPageParameters();
|
| | |
|
| | | DropDownMenuRegistration projects = new DropDownMenuRegistration("gb.projects",
|
| | | ProjectPage.class);
|
| | | projects.menuItems.addAll(getProjectsMenu());
|
| | | pages.add(0, projects);
|
| | |
|
| | | DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
|
| | | ProjectPage.class);
|
| | |
| | |
|
| | | if (menu.menuItems.size() > 0) {
|
| | | // Reset Filter
|
| | | menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
|
| | | menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), "p", WicketUtils.getProjectName(params)));
|
| | | }
|
| | |
|
| | | pages.add(menu);
|
| | | |
| | | DropDownMenuRegistration projects = new DropDownMenuRegistration("gb.projects",
|
| | | ProjectPage.class);
|
| | | projects.menuItems.addAll(getProjectsMenu());
|
| | | pages.add(projects);
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | <body>
|
| | | <wicket:extend>
|
| | | <div class="container">
|
| | | <div class="markdown" style="padding-bottom:5px;" wicket:id="projectsMessage">[projects message]</div>
|
| | |
|
| | | <table class="repositories">
|
| | | <thead>
|
| | |
| | | */
|
| | | package com.gitblit.wicket.pages;
|
| | |
|
| | | import java.io.File;
|
| | | import java.io.FileInputStream;
|
| | | import java.io.InputStream;
|
| | | import java.io.InputStreamReader;
|
| | | import java.text.MessageFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | |
|
| | | import org.apache.wicket.Component;
|
| | | import org.apache.wicket.PageParameters;
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | 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.apache.wicket.resource.ContextRelativeResource;
|
| | | import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | |
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.models.ProjectModel;
|
| | | import com.gitblit.utils.MarkdownUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.wicket.GitBlitWebSession;
|
| | | import com.gitblit.wicket.PageRegistration;
|
| | | import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
|
| | |
| | | }
|
| | |
|
| | | @Override
|
| | | protected Class<? extends BasePage> getRootNavPageClass() {
|
| | | return RepositoriesPage.class;
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected List<ProjectModel> getProjectModels() {
|
| | | return GitBlit.self().getProjectModels(getRepositoryModels(), false);
|
| | | }
|
| | |
| | | // check to see if we should display a login message
|
| | | boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
|
| | | if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) {
|
| | | String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit");
|
| | | String message = readMarkdown(messageSource, "login.mkd");
|
| | | Component repositoriesMessage = new Label("projectsMessage", message);
|
| | | add(repositoriesMessage.setEscapeModelStrings(false));
|
| | | add(new Label("projectsPanel"));
|
| | | return;
|
| | | }
|
| | |
|
| | | // Load the markdown welcome message
|
| | | String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit");
|
| | | String message = readMarkdown(messageSource, "welcome.mkd");
|
| | | Component projectsMessage = new Label("projectsMessage", message).setEscapeModelStrings(
|
| | | false).setVisible(message.length() > 0);
|
| | | add(projectsMessage);
|
| | |
|
| | | List<ProjectModel> projects = getProjects(params);
|
| | |
|
| | |
| | | }
|
| | | };
|
| | | add(dataView);
|
| | |
|
| | | // push the panel down if we are hiding the admin controls and the
|
| | | // welcome message
|
| | | if (!showAdmin && !projectsMessage.isVisible()) {
|
| | | WicketUtils.setCssStyle(dataView, "padding-top:5px;");
|
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void addDropDownMenus(List<PageRegistration> pages) {
|
| | | PageParameters params = getPageParameters();
|
| | | |
| | | pages.add(0, new PageRegistration("gb.projects", ProjectsPage.class, params));
|
| | |
|
| | | DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
|
| | | ProjectsPage.class);
|
| | |
| | | }
|
| | |
|
| | | pages.add(menu);
|
| | | }
|
| | |
|
| | | private String readMarkdown(String messageSource, String resource) {
|
| | | String message = "";
|
| | | if (messageSource.equalsIgnoreCase("gitblit")) {
|
| | | // Read default message
|
| | | message = readDefaultMarkdown(resource);
|
| | | } else {
|
| | | // Read user-supplied message
|
| | | if (!StringUtils.isEmpty(messageSource)) {
|
| | | File file = new File(messageSource);
|
| | | if (file.exists()) {
|
| | | try {
|
| | | FileInputStream fis = new FileInputStream(file);
|
| | | InputStreamReader reader = new InputStreamReader(fis,
|
| | | Constants.CHARACTER_ENCODING);
|
| | | message = MarkdownUtils.transformMarkdown(reader);
|
| | | reader.close();
|
| | | } catch (Throwable t) {
|
| | | message = getString("gb.failedToRead") + " " + file;
|
| | | warn(message, t);
|
| | | }
|
| | | } else {
|
| | | message = messageSource + " " + getString("gb.isNotValidFile");
|
| | | }
|
| | | }
|
| | | }
|
| | | return message;
|
| | | }
|
| | |
|
| | | private String readDefaultMarkdown(String file) {
|
| | | String base = file.substring(0, file.lastIndexOf('.'));
|
| | | String ext = file.substring(file.lastIndexOf('.'));
|
| | | String lc = getLanguageCode();
|
| | | String cc = getCountryCode();
|
| | |
|
| | | // try to read file_en-us.ext, file_en.ext, file.ext
|
| | | List<String> files = new ArrayList<String>();
|
| | | if (!StringUtils.isEmpty(lc)) {
|
| | | if (!StringUtils.isEmpty(cc)) {
|
| | | files.add(base + "_" + lc + "-" + cc + ext);
|
| | | files.add(base + "_" + lc + "_" + cc + ext);
|
| | | }
|
| | | files.add(base + "_" + lc + ext);
|
| | | }
|
| | | files.add(file);
|
| | | |
| | | for (String name : files) {
|
| | | String message;
|
| | | InputStreamReader reader = null;
|
| | | try {
|
| | | ContextRelativeResource res = WicketUtils.getResource(name);
|
| | | InputStream is = res.getResourceStream().getInputStream();
|
| | | reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING);
|
| | | message = MarkdownUtils.transformMarkdown(reader);
|
| | | reader.close();
|
| | | return message;
|
| | | } catch (ResourceStreamNotFoundException t) {
|
| | | continue;
|
| | | } catch (Throwable t) {
|
| | | message = MessageFormat.format(getString("gb.failedToReadMessage"), file);
|
| | | error(message, t, false);
|
| | | return message;
|
| | | } finally {
|
| | | if (reader != null) {
|
| | | try {
|
| | | reader.close();
|
| | | } catch (Exception e) {
|
| | | }
|
| | | }
|
| | | } |
| | | }
|
| | | return MessageFormat.format(getString("gb.failedToReadMessage"), file);
|
| | | }
|
| | | }
|
File was renamed from src/main/java/com/gitblit/wicket/pages/PushesPage.html |
| | |
| | | <a wicket:id="firstPage"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPage">« <wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPage"><wicket:message key="gb.pageNext"></wicket:message> »</a>
|
| | | </div>
|
| | |
|
| | | <!-- push log -->
|
| | | <div style="margin-top:5px;" wicket:id="pushesPanel">[push log panel]</div>
|
| | | <!-- ref log -->
|
| | | <div style="margin-top:5px;" wicket:id="reflogPanel">[reflog panel]</div>
|
| | |
|
| | | <!-- pager links -->
|
| | | <div style="padding-bottom:5px;">
|
File was renamed from src/main/java/com/gitblit/wicket/pages/PushesPage.java |
| | |
| | | import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
| | |
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.panels.PushesPanel;
|
| | | import com.gitblit.wicket.panels.ReflogPanel;
|
| | |
|
| | | public class PushesPage extends RepositoryPage {
|
| | | public class ReflogPage extends RepositoryPage {
|
| | |
|
| | | public PushesPage(PageParameters params) {
|
| | | public ReflogPage(PageParameters params) {
|
| | | super(params);
|
| | |
|
| | | addSyndicationDiscoveryLink();
|
| | |
| | | int prevPage = Math.max(0, pageNumber - 1);
|
| | | int nextPage = pageNumber + 1;
|
| | |
|
| | | PushesPanel pushesPanel = new PushesPanel("pushesPanel", getRepositoryModel(), getRepository(), -1,
|
| | | pageNumber - 1, false);
|
| | | boolean hasMore = pushesPanel.hasMore();
|
| | | add(pushesPanel);
|
| | | ReflogPanel reflogPanel = new ReflogPanel("reflogPanel", getRepositoryModel(), getRepository(), -1,
|
| | | pageNumber - 1);
|
| | | boolean hasMore = reflogPanel.hasMore();
|
| | | add(reflogPanel);
|
| | |
|
| | | add(new BookmarkablePageLink<Void>("firstPage", PushesPage.class,
|
| | | add(new BookmarkablePageLink<Void>("firstPage", ReflogPage.class,
|
| | | WicketUtils.newObjectParameter(repositoryName, objectId))
|
| | | .setEnabled(pageNumber > 1));
|
| | | add(new BookmarkablePageLink<Void>("prevPage", PushesPage.class,
|
| | | add(new BookmarkablePageLink<Void>("prevPage", ReflogPage.class,
|
| | | WicketUtils.newLogPageParameter(repositoryName, objectId, prevPage))
|
| | | .setEnabled(pageNumber > 1));
|
| | | add(new BookmarkablePageLink<Void>("nextPage", PushesPage.class,
|
| | | add(new BookmarkablePageLink<Void>("nextPage", ReflogPage.class,
|
| | | WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage))
|
| | | .setEnabled(hasMore));
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected String getPageName() {
|
| | | return getString("gb.pushes");
|
| | | return getString("gb.reflog");
|
| | | }
|
| | | }
|
| | |
| | | import com.gitblit.utils.ArrayUtils;
|
| | | import com.gitblit.utils.DeepCopier;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.PushLogUtils;
|
| | | import com.gitblit.utils.RefLogUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.TicgitUtils;
|
| | | import com.gitblit.wicket.GitBlitWebSession;
|
| | |
| | | RepositoryModel model = getRepositoryModel();
|
| | |
|
| | | // standard links
|
| | | if (PushLogUtils.getPushLogBranch(r) == null) {
|
| | | if (RefLogUtils.getRefLogBranch(r) == null) {
|
| | | pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
|
| | | } else {
|
| | | pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
|
| | | // pages.put("overview", new PageRegistration("gb.overview", OverviewPage.class, params));
|
| | | pages.put("pushes", new PageRegistration("gb.pushes", PushesPage.class, params));
|
| | | pages.put("reflog", new PageRegistration("gb.reflog", ReflogPage.class, params));
|
| | | }
|
| | | pages.put("commits", new PageRegistration("gb.commits", LogPage.class, params));
|
| | | pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
|
| | |
| | | // navigation links
|
| | | List<PageRegistration> pages = new ArrayList<PageRegistration>();
|
| | | if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) {
|
| | | pages.add(new PageRegistration(GitBlitWebSession.get().isLoggedIn() ? "gb.myDashboard" : "gb.dashboard", DashboardPage.class,
|
| | | pages.add(new PageRegistration(GitBlitWebSession.get().isLoggedIn() ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class,
|
| | | getRootPageParameters()));
|
| | | pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class,
|
| | | getRootPageParameters()));
|
File was renamed from src/main/java/com/gitblit/wicket/panels/PushesPanel.html |
| | |
| | |
|
| | | <body>
|
| | | <wicket:panel>
|
| | | <div wicket:id="push" class="push">
|
| | | <div wicket:id="change" class="reflog">
|
| | | <table style="padding: 3px 0px;">
|
| | | <tr>
|
| | | <td class="icon hidden-phone"><i wicket:id="pushIcon"></i></td>
|
| | | <td class="icon hidden-phone"><i wicket:id="changeIcon"></i></td>
|
| | | <td style="padding-left: 7px;vertical-align:middle;">
|
| | | <div>
|
| | | <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>
|
| | | <span class="when" wicket:id="whenChanged"></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="font-weight:bold;"><span wicket:id="whoChanged">[who changed]</span> <span wicket:id="whatChanged"></span><span wicket:id="refChanged"></span> <span wicket:id="repoPreposition"></span> <span wicket:id="repoChanged"></span> <span wicket:id="byAuthors"></span></div>
|
| | | </td>
|
| | | </tr>
|
| | | <tr>
|
| | |
| | | </tr>
|
| | | </table>
|
| | | </div>
|
| | | <div wicket:id="morePushes">[more...]</div>
|
| | | </wicket:panel>
|
| | | </body>
|
| | | </html> |
New file |
| | |
| | | /*
|
| | | * Copyright 2013 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | 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 org.apache.wicket.markup.repeater.data.DataView;
|
| | | import org.apache.wicket.markup.repeater.data.ListDataProvider;
|
| | |
|
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.models.DailyLogEntry;
|
| | | import com.gitblit.models.RepositoryCommit;
|
| | | 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;
|
| | | import com.gitblit.wicket.pages.SummaryPage;
|
| | | import com.gitblit.wicket.pages.TagPage;
|
| | | import com.gitblit.wicket.pages.TreePage;
|
| | | import com.gitblit.wicket.pages.UserPage;
|
| | |
|
| | | public class DigestsPanel extends BasePanel {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | private final boolean hasChanges;
|
| | | |
| | | private boolean hasMore;
|
| | |
|
| | | public DigestsPanel(String wicketId, List<DailyLogEntry> digests) {
|
| | | super(wicketId);
|
| | | hasChanges = digests.size() > 0;
|
| | |
|
| | | 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<DailyLogEntry> dp = new ListDataProvider<DailyLogEntry>(digests);
|
| | | DataView<DailyLogEntry> pushView = new DataView<DailyLogEntry>("change", dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public void populateItem(final Item<DailyLogEntry> logItem) {
|
| | | final DailyLogEntry change = logItem.getModelObject();
|
| | | String fullRefName = change.getChangedRefs().get(0);
|
| | | String shortRefName = fullRefName;
|
| | | boolean isTag = 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;
|
| | | }
|
| | | |
| | | String fuzzydate;
|
| | | TimeUtils tu = getTimeUtils();
|
| | | Date pushDate = change.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);
|
| | | }
|
| | | logItem.add(new Label("whenChanged", fuzzydate + ", " + df.format(pushDate)));
|
| | |
|
| | | Label changeIcon = new Label("changeIcon");
|
| | | // use the repository hash color to differentiate the icon.
|
| | | String color = StringUtils.getColor(StringUtils.stripDotGit(change.repository));
|
| | | WicketUtils.setCssStyle(changeIcon, "color: " + color);
|
| | |
|
| | | if (isTag) {
|
| | | WicketUtils.setCssClass(changeIcon, "iconic-tag");
|
| | | } else {
|
| | | WicketUtils.setCssClass(changeIcon, "iconic-loop");
|
| | | }
|
| | | logItem.add(changeIcon);
|
| | |
|
| | | if (!isTag) {
|
| | | logItem.add(new Label("whoChanged").setVisible(false));
|
| | | } else {
|
| | | if (change.user.username.equals(change.user.emailAddress) && change.user.emailAddress.indexOf('@') > -1) {
|
| | | // username is an email address can not link - 1.2.1 push log bug
|
| | | logItem.add(new Label("whoChanged", change.user.getDisplayName()));
|
| | | } else {
|
| | | // link to user account page
|
| | | logItem.add(new LinkPanel("whoChanged", null, change.user.getDisplayName(),
|
| | | UserPage.class, WicketUtils.newUsernameParameter(change.user.username)));
|
| | | }
|
| | | }
|
| | | |
| | | String preposition = "gb.of";
|
| | | boolean isDelete = false;
|
| | | String what;
|
| | | String by = null;
|
| | | switch(change.getChangeType(fullRefName)) {
|
| | | case CREATE:
|
| | | if (isTag) {
|
| | | // new tag
|
| | | what = getString("gb.createdNewTag");
|
| | | preposition = "gb.in";
|
| | | } else {
|
| | | // new branch
|
| | | what = getString("gb.createdNewBranch");
|
| | | preposition = "gb.in";
|
| | | }
|
| | | break;
|
| | | case DELETE:
|
| | | isDelete = true;
|
| | | if (isTag) {
|
| | | what = getString("gb.deletedTag");
|
| | | } else {
|
| | | what = getString("gb.deletedBranch");
|
| | | }
|
| | | preposition = "gb.from";
|
| | | break;
|
| | | default:
|
| | | what = MessageFormat.format(change.getCommitCount() > 1 ? getString("gb.commitsTo") : getString("gb.oneCommitTo"), change.getCommitCount());
|
| | | |
| | | if (change.getAuthorCount() == 1) {
|
| | | by = MessageFormat.format(getString("gb.byOneAuthor"), change.getAuthorIdent().getName());
|
| | | } else {
|
| | | by = MessageFormat.format(getString("gb.byNAuthors"), change.getAuthorCount()); |
| | | }
|
| | | break;
|
| | | }
|
| | | logItem.add(new Label("whatChanged", what));
|
| | | logItem.add(new Label("byAuthors", by).setVisible(!StringUtils.isEmpty(by)));
|
| | | |
| | | if (isDelete) {
|
| | | // can't link to deleted ref
|
| | | logItem.add(new Label("refChanged", shortRefName));
|
| | | } else if (isTag) {
|
| | | // link to tag
|
| | | logItem.add(new LinkPanel("refChanged", null, shortRefName,
|
| | | TagPage.class, WicketUtils.newObjectParameter(change.repository, fullRefName)));
|
| | | } else {
|
| | | // link to tree
|
| | | logItem.add(new LinkPanel("refChanged", null, shortRefName,
|
| | | TreePage.class, WicketUtils.newObjectParameter(change.repository, fullRefName)));
|
| | | }
|
| | | |
| | | // to/from/etc
|
| | | logItem.add(new Label("repoPreposition", getString(preposition)));
|
| | | String repoName = StringUtils.stripDotGit(change.repository);
|
| | | logItem.add(new LinkPanel("repoChanged", null, repoName,
|
| | | SummaryPage.class, WicketUtils.newRepositoryParameter(change.repository)));
|
| | | |
| | | int maxCommitCount = 5;
|
| | | List<RepositoryCommit> commits = change.getCommits();
|
| | | if (commits.size() > maxCommitCount) {
|
| | | commits = new ArrayList<RepositoryCommit>(commits.subList(0, maxCommitCount)); |
| | | }
|
| | | |
| | | // compare link
|
| | | String compareLinkText = null;
|
| | | if ((change.getCommitCount() <= maxCommitCount) && (change.getCommitCount() > 1)) {
|
| | | compareLinkText = MessageFormat.format(getString("gb.viewComparison"), commits.size());
|
| | | } else if (change.getCommitCount() > maxCommitCount) {
|
| | | int diff = change.getCommitCount() - maxCommitCount;
|
| | | compareLinkText = MessageFormat.format(diff > 1 ? getString("gb.nMoreCommits") : getString("gb.oneMoreCommit"), diff);
|
| | | }
|
| | | if (StringUtils.isEmpty(compareLinkText)) {
|
| | | logItem.add(new Label("compareLink").setVisible(false));
|
| | | } else {
|
| | | String endRangeId = change.getNewId(fullRefName);
|
| | | String startRangeId = change.getOldId(fullRefName);
|
| | | logItem.add(new LinkPanel("compareLink", null, compareLinkText, ComparePage.class, WicketUtils.newRangeParameter(change.repository, startRangeId, endRangeId)));
|
| | | }
|
| | | |
| | | final boolean showSwatch = GitBlit.getBoolean(Keys.web.repositoryListSwatches, true);
|
| | | |
| | | ListDataProvider<RepositoryCommit> cdp = new ListDataProvider<RepositoryCommit>(commits);
|
| | | DataView<RepositoryCommit> commitsView = new DataView<RepositoryCommit>("commit", cdp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public void populateItem(final Item<RepositoryCommit> commitItem) {
|
| | | final RepositoryCommit commit = commitItem.getModelObject();
|
| | |
|
| | | // author gravatar
|
| | | commitItem.add(new GravatarImage("commitAuthor", commit.getAuthorIdent().getName(),
|
| | | commit.getAuthorIdent().getEmailAddress(), null, 16, false, false));
|
| | | |
| | | // merge icon
|
| | | if (commit.getParentCount() > 1) {
|
| | | commitItem.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png"));
|
| | | } else {
|
| | | commitItem.add(WicketUtils.newBlankImage("commitIcon"));
|
| | | }
|
| | |
|
| | | // short message
|
| | | String shortMessage = commit.getShortMessage();
|
| | | String trimmedMessage = shortMessage;
|
| | | if (commit.getRefs() != null && commit.getRefs().size() > 0) {
|
| | | trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
|
| | | } else {
|
| | | trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
|
| | | }
|
| | | LinkPanel shortlog = new LinkPanel("commitShortMessage", "list",
|
| | | trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter(
|
| | | change.repository, commit.getName()));
|
| | | if (!shortMessage.equals(trimmedMessage)) {
|
| | | WicketUtils.setHtmlTooltip(shortlog, shortMessage);
|
| | | }
|
| | | commitItem.add(shortlog);
|
| | |
|
| | | // commit hash link
|
| | | LinkPanel commitHash = new LinkPanel("hashLink", null, commit.getName().substring(0, hashLen),
|
| | | CommitPage.class, WicketUtils.newObjectParameter(
|
| | | change.repository, commit.getName()));
|
| | | WicketUtils.setCssClass(commitHash, "shortsha1");
|
| | | WicketUtils.setHtmlTooltip(commitHash, commit.getName());
|
| | | commitItem.add(commitHash);
|
| | | |
| | | if (showSwatch) {
|
| | | // set repository color
|
| | | String color = StringUtils.getColor(StringUtils.stripDotGit(change.repository));
|
| | | WicketUtils.setCssStyle(commitItem, MessageFormat.format("border-left: 2px solid {0};", color));
|
| | | }
|
| | | }
|
| | | };
|
| | |
|
| | | logItem.add(commitsView);
|
| | | }
|
| | | };
|
| | | |
| | | add(pushView);
|
| | | }
|
| | |
|
| | | public boolean hasMore() {
|
| | | return hasMore;
|
| | | }
|
| | | |
| | | public boolean hideIfEmpty() {
|
| | | setVisible(hasChanges);
|
| | | return hasChanges;
|
| | | }
|
| | | }
|
| | |
| | | <wicket:message key="gb.lastChange">[last change]</wicket:message> <span wicket:id="repositoryLastChange">[last change]</span>,
|
| | | <span style="font-size:0.8em;" wicket:id="repositorySize">[repository size]</span>
|
| | | </div>
|
| | | |
| | | <div class="hidden-phone hidden-tablet" style="padding-top: 5px;" wicket:id="repositoryPrimaryUrl">[repository primary url]</div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
| | | }
|
| | |
|
| | | add(new ExternalLink("syndication", SyndicationServlet.asLink("", entry.name, null, 0)));
|
| | |
|
| | | add(new RepositoryUrlPanel("repositoryPrimaryUrl", true, user, entry));
|
| | | }
|
| | | }
|
copy from src/main/java/com/gitblit/wicket/panels/PushesPanel.html
copy to src/main/java/com/gitblit/wicket/panels/ReflogPanel.html
File was copied from src/main/java/com/gitblit/wicket/panels/PushesPanel.html |
| | |
| | |
|
| | | <body>
|
| | | <wicket:panel>
|
| | | <div wicket:id="push" class="push">
|
| | | <div wicket:id="change" class="reflog">
|
| | | <table style="padding: 3px 0px;">
|
| | | <tr>
|
| | | <td class="icon hidden-phone"><i wicket:id="pushIcon"></i></td>
|
| | | <td class="icon hidden-phone"><i wicket:id="changeIcon"></i></td>
|
| | | <td style="padding-left: 7px;vertical-align:middle;">
|
| | | <div>
|
| | | <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>
|
| | | <span class="when" wicket:id="whenChanged"></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="font-weight:bold;"><span wicket:id="whoChanged">[change author]</span> <span wicket:id="whatChanged"></span><span wicket:id="refChanged"></span> <span wicket:id="byAuthors"></span></div>
|
| | | </td>
|
| | | </tr>
|
| | | <tr>
|
| | |
| | | </tr>
|
| | | </table>
|
| | | </div>
|
| | | <div wicket:id="morePushes">[more...]</div>
|
| | | <div wicket:id="moreChanges">[more...]</div>
|
| | | </wicket:panel>
|
| | | </body>
|
| | | </html> |
New file |
| | |
| | | /*
|
| | | * Copyright 2013 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | 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 org.apache.wicket.markup.repeater.data.DataView;
|
| | | import org.apache.wicket.markup.repeater.data.ListDataProvider;
|
| | | import org.apache.wicket.model.StringResourceModel;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | |
|
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.models.RefLogEntry;
|
| | | import com.gitblit.models.RepositoryCommit;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.utils.RefLogUtils;
|
| | | 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;
|
| | | import com.gitblit.wicket.pages.ReflogPage;
|
| | | import com.gitblit.wicket.pages.TagPage;
|
| | | import com.gitblit.wicket.pages.TreePage;
|
| | | import com.gitblit.wicket.pages.UserPage;
|
| | |
|
| | | public class ReflogPanel extends BasePanel {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | private final boolean hasChanges;
|
| | | |
| | | private boolean hasMore;
|
| | |
|
| | | public ReflogPanel(String wicketId, final RepositoryModel model, Repository r, int limit, int pageOffset) {
|
| | | super(wicketId);
|
| | | boolean pageResults = limit <= 0;
|
| | | int changesPerPage = GitBlit.getInteger(Keys.web.reflogChangesPerPage, 10);
|
| | | if (changesPerPage <= 1) {
|
| | | changesPerPage = 10;
|
| | | }
|
| | |
|
| | | List<RefLogEntry> changes;
|
| | | if (pageResults) {
|
| | | changes = RefLogUtils.getLogByRef(model.name, r, pageOffset * changesPerPage, changesPerPage);
|
| | | } else {
|
| | | changes = RefLogUtils.getLogByRef(model.name, r, limit);
|
| | | }
|
| | |
|
| | | // inaccurate way to determine if there are more commits.
|
| | | // works unless commits.size() represents the exact end.
|
| | | hasMore = changes.size() >= changesPerPage;
|
| | | hasChanges = changes.size() > 0;
|
| | | |
| | | setup(changes);
|
| | | |
| | | // determine to show pager, more, or neither
|
| | | if (limit <= 0) {
|
| | | // no display limit
|
| | | add(new Label("moreChanges").setVisible(false));
|
| | | } else {
|
| | | if (pageResults) {
|
| | | // paging
|
| | | add(new Label("moreChanges").setVisible(false));
|
| | | } else {
|
| | | // more
|
| | | if (changes.size() == limit) {
|
| | | // show more
|
| | | add(new LinkPanel("moreChanges", "link", new StringResourceModel("gb.moreChanges",
|
| | | this, null), ReflogPage.class,
|
| | | WicketUtils.newRepositoryParameter(model.name)));
|
| | | } else {
|
| | | // no more
|
| | | add(new Label("moreChanges").setVisible(false));
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | | |
| | | public ReflogPanel(String wicketId, List<RefLogEntry> changes) {
|
| | | super(wicketId);
|
| | | hasChanges = changes.size() > 0;
|
| | | setup(changes);
|
| | | add(new Label("moreChanges").setVisible(false));
|
| | | }
|
| | | |
| | | protected void setup(List<RefLogEntry> changes) {
|
| | | 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<RefLogEntry> dp = new ListDataProvider<RefLogEntry>(changes);
|
| | | DataView<RefLogEntry> changeView = new DataView<RefLogEntry>("change", dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public void populateItem(final Item<RefLogEntry> changeItem) {
|
| | | final RefLogEntry change = changeItem.getModelObject();
|
| | | String fullRefName = change.getChangedRefs().get(0);
|
| | | String shortRefName = fullRefName;
|
| | | boolean isTag = 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;
|
| | | }
|
| | | |
| | | String fuzzydate;
|
| | | TimeUtils tu = getTimeUtils();
|
| | | Date changeDate = change.date;
|
| | | if (TimeUtils.isToday(changeDate, timezone)) {
|
| | | fuzzydate = tu.today();
|
| | | } else if (TimeUtils.isYesterday(changeDate, timezone)) {
|
| | | fuzzydate = tu.yesterday();
|
| | | } else {
|
| | | // calculate a fuzzy time ago date
|
| | | cal.setTime(changeDate);
|
| | | cal.set(Calendar.HOUR_OF_DAY, 0);
|
| | | cal.set(Calendar.MINUTE, 0);
|
| | | cal.set(Calendar.SECOND, 0);
|
| | | cal.set(Calendar.MILLISECOND, 0);
|
| | | changeDate = cal.getTime();
|
| | | fuzzydate = getTimeUtils().timeAgo(changeDate);
|
| | | }
|
| | | changeItem.add(new Label("whenChanged", fuzzydate + ", " + df.format(changeDate)));
|
| | |
|
| | | Label changeIcon = new Label("changeIcon");
|
| | | if (isTag) {
|
| | | WicketUtils.setCssClass(changeIcon, "iconic-tag");
|
| | | } else {
|
| | | WicketUtils.setCssClass(changeIcon, "iconic-upload");
|
| | | }
|
| | | changeItem.add(changeIcon);
|
| | |
|
| | | if (change.user.username.equals(change.user.emailAddress) && change.user.emailAddress.indexOf('@') > -1) {
|
| | | // username is an email address - 1.2.1 push log bug
|
| | | changeItem.add(new Label("whoChanged", change.user.getDisplayName()));
|
| | | } else {
|
| | | // link to user account page
|
| | | changeItem.add(new LinkPanel("whoChanged", null, change.user.getDisplayName(),
|
| | | UserPage.class, WicketUtils.newUsernameParameter(change.user.username)));
|
| | | }
|
| | | |
| | | boolean isDelete = false;
|
| | | boolean isRewind = false;
|
| | | String what;
|
| | | String by = null;
|
| | | switch(change.getChangeType(fullRefName)) {
|
| | | case CREATE:
|
| | | if (isTag) {
|
| | | // new tag
|
| | | what = getString("gb.pushedNewTag");
|
| | | } else {
|
| | | // new branch
|
| | | what = getString("gb.pushedNewBranch");
|
| | | }
|
| | | break;
|
| | | case DELETE:
|
| | | isDelete = true;
|
| | | if (isTag) {
|
| | | what = getString("gb.deletedTag");
|
| | | } else {
|
| | | what = getString("gb.deletedBranch");
|
| | | }
|
| | | break;
|
| | | case UPDATE_NONFASTFORWARD:
|
| | | isRewind = true;
|
| | | default:
|
| | | what = MessageFormat.format(change.getCommitCount() > 1 ? getString("gb.pushedNCommitsTo") : getString("gb.pushedOneCommitTo") , change.getCommitCount());
|
| | | |
| | | if (change.getAuthorCount() == 1) {
|
| | | by = MessageFormat.format(getString("gb.byOneAuthor"), change.getAuthorIdent().getName());
|
| | | } else {
|
| | | by = MessageFormat.format(getString("gb.byNAuthors"), change.getAuthorCount()); |
| | | }
|
| | | break;
|
| | | }
|
| | | changeItem.add(new Label("whatChanged", what));
|
| | | changeItem.add(new Label("byAuthors", by).setVisible(!StringUtils.isEmpty(by)));
|
| | | |
| | | changeItem.add(new Label("refRewind", getString("gb.rewind")).setVisible(isRewind));
|
| | | |
| | | if (isDelete) {
|
| | | // can't link to deleted ref
|
| | | changeItem.add(new Label("refChanged", shortRefName));
|
| | | } else if (isTag) {
|
| | | // link to tag
|
| | | changeItem.add(new LinkPanel("refChanged", null, shortRefName,
|
| | | TagPage.class, WicketUtils.newObjectParameter(change.repository, fullRefName)));
|
| | | } else {
|
| | | // link to tree
|
| | | changeItem.add(new LinkPanel("refChanged", null, shortRefName,
|
| | | TreePage.class, WicketUtils.newObjectParameter(change.repository, fullRefName)));
|
| | | }
|
| | | |
| | | int maxCommitCount = 5;
|
| | | List<RepositoryCommit> commits = change.getCommits();
|
| | | if (commits.size() > maxCommitCount) {
|
| | | commits = new ArrayList<RepositoryCommit>(commits.subList(0, maxCommitCount)); |
| | | }
|
| | | |
| | | // compare link
|
| | | String compareLinkText = null;
|
| | | if ((change.getCommitCount() <= maxCommitCount) && (change.getCommitCount() > 1)) {
|
| | | compareLinkText = MessageFormat.format(getString("gb.viewComparison"), commits.size());
|
| | | } else if (change.getCommitCount() > maxCommitCount) {
|
| | | int diff = change.getCommitCount() - maxCommitCount;
|
| | | compareLinkText = MessageFormat.format(diff > 1 ? getString("gb.nMoreCommits") : getString("gb.oneMoreCommit"), diff);
|
| | | }
|
| | | if (StringUtils.isEmpty(compareLinkText)) {
|
| | | changeItem.add(new Label("compareLink").setVisible(false));
|
| | | } else {
|
| | | String endRangeId = change.getNewId(fullRefName);
|
| | | String startRangeId = change.getOldId(fullRefName);
|
| | | changeItem.add(new LinkPanel("compareLink", null, compareLinkText, ComparePage.class, WicketUtils.newRangeParameter(change.repository, startRangeId, endRangeId)));
|
| | | }
|
| | | |
| | | ListDataProvider<RepositoryCommit> cdp = new ListDataProvider<RepositoryCommit>(commits);
|
| | | DataView<RepositoryCommit> commitsView = new DataView<RepositoryCommit>("commit", cdp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public void populateItem(final Item<RepositoryCommit> commitItem) {
|
| | | final RepositoryCommit commit = commitItem.getModelObject();
|
| | |
|
| | | // author gravatar
|
| | | commitItem.add(new GravatarImage("commitAuthor", commit.getAuthorIdent().getName(),
|
| | | commit.getAuthorIdent().getEmailAddress(), null, 16, false, false));
|
| | | |
| | | // merge icon
|
| | | if (commit.getParentCount() > 1) {
|
| | | commitItem.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png"));
|
| | | } else {
|
| | | commitItem.add(WicketUtils.newBlankImage("commitIcon"));
|
| | | }
|
| | |
|
| | | // short message
|
| | | String shortMessage = commit.getShortMessage();
|
| | | String trimmedMessage = shortMessage;
|
| | | if (commit.getRefs() != null && commit.getRefs().size() > 0) {
|
| | | trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
|
| | | } else {
|
| | | trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
|
| | | }
|
| | | LinkPanel shortlog = new LinkPanel("commitShortMessage", "list",
|
| | | trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter(
|
| | | change.repository, commit.getName()));
|
| | | if (!shortMessage.equals(trimmedMessage)) {
|
| | | WicketUtils.setHtmlTooltip(shortlog, shortMessage);
|
| | | }
|
| | | commitItem.add(shortlog);
|
| | |
|
| | | // commit hash link
|
| | | LinkPanel commitHash = new LinkPanel("hashLink", null, commit.getName().substring(0, hashLen),
|
| | | CommitPage.class, WicketUtils.newObjectParameter(
|
| | | change.repository, commit.getName()));
|
| | | WicketUtils.setCssClass(commitHash, "shortsha1");
|
| | | WicketUtils.setHtmlTooltip(commitHash, commit.getName());
|
| | | commitItem.add(commitHash);
|
| | | }
|
| | | };
|
| | |
|
| | | changeItem.add(commitsView);
|
| | | }
|
| | | };
|
| | | |
| | | add(changeView);
|
| | | }
|
| | |
|
| | | public boolean hasMore() {
|
| | | return hasMore;
|
| | | }
|
| | | |
| | | public boolean hideIfEmpty() {
|
| | | setVisible(hasChanges);
|
| | | return hasChanges;
|
| | | }
|
| | | }
|
| | |
| | | background-color: #002060;
|
| | | }
|
| | |
|
| | | div.push {
|
| | | div.reflog {
|
| | | border-bottom: 1px solid #ddd;
|
| | | margin-bottom: 5px;
|
| | | padding-bottom: 5px;
|
| | | }
|
| | |
|
| | | div.push .icon {
|
| | | div.reflog .icon {
|
| | | font-size: 42px;
|
| | | line-height: 42px;
|
| | | }
|
| | |
|
| | | div.push i {
|
| | | div.reflog .when {
|
| | | color: #aaa;
|
| | | }
|
| | |
|
| | | div.reflog i {
|
| | | font-size: 42px;
|
| | | color: #bbb;
|
| | | vertical-align: middle;
|
| | | }
|
| | |
|
| | | div.dashboardTitle {
|
| | | font-size: 1.75em;
|
| | | padding-bottom: 5px;
|
| | | margin-bottom: 10px;
|
| | | border-bottom: 1px solid #ccc;
|
| | | }
|
| | |
|
| | | div.dashboardTitle small {
|
| | | color: #888;
|
| | | font-size: 0.7em;
|
| | | }
|
| | |
|
| | | .repositorynavbar {
|
| | | background-color: #fbfbfb;
|
| | | border-bottom: 1px solid #ccc;
|
| | |
| | | import com.gitblit.Constants.AuthorizationControl;
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.models.PushLogEntry;
|
| | | import com.gitblit.models.RefLogEntry;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.ArrayUtils;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.PushLogUtils;
|
| | | import com.gitblit.utils.RefLogUtils;
|
| | |
|
| | | public class GitServletTest {
|
| | |
|
| | |
| | | String name = "refchecks/ticgit.git";
|
| | | File refChecks = new File(GitBlitSuite.REPOSITORIES, name);
|
| | | Repository repository = new FileRepositoryBuilder().setGitDir(refChecks).build();
|
| | | List<PushLogEntry> pushes = PushLogUtils.getPushLog(name, repository);
|
| | | List<RefLogEntry> pushes = RefLogUtils.getRefLog(name, repository);
|
| | | GitBlitSuite.close(repository);
|
| | | assertTrue("Repository has an empty push log!", pushes.size() > 0);
|
| | | }
|
| | |
| | | import org.eclipse.jgit.util.FS;
|
| | | import org.junit.Test;
|
| | |
|
| | | import com.gitblit.models.PushLogEntry;
|
| | | import com.gitblit.utils.PushLogUtils;
|
| | | import com.gitblit.models.RefLogEntry;
|
| | | import com.gitblit.utils.RefLogUtils;
|
| | |
|
| | | public class PushLogTest {
|
| | |
|
| | |
| | | String name = "~james/helloworld.git";
|
| | | File gitDir = FileKey.resolve(new File(GitBlitSuite.REPOSITORIES, name), FS.DETECTED);
|
| | | Repository repository = new FileRepositoryBuilder().setGitDir(gitDir).build();
|
| | | List<PushLogEntry> pushes = PushLogUtils.getPushLog(name, repository);
|
| | | List<RefLogEntry> pushes = RefLogUtils.getRefLog(name, repository);
|
| | | GitBlitSuite.close(repository);
|
| | | }
|
| | | } |