summaryrefslogtreecommitdiffstats
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/gitblit/models/DailyLogEntry.java59
-rw-r--r--src/main/java/com/gitblit/models/PushLogEntry.java17
-rw-r--r--src/main/java/com/gitblit/utils/PushLogUtils.java176
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.java5
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.properties15
-rw-r--r--src/main/java/com/gitblit/wicket/charting/GoogleChart.java6
-rw-r--r--src/main/java/com/gitblit/wicket/charting/GooglePieChart.java4
-rw-r--r--src/main/java/com/gitblit/wicket/ng/NgController.java79
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ActivityPage.html8
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ActivityPage.java10
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BasePage.html3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/DashboardPage.html99
-rw-r--r--src/main/java/com/gitblit/wicket/pages/DashboardPage.java418
-rw-r--r--src/main/java/com/gitblit/wicket/pages/HomePage.html16
-rw-r--r--src/main/java/com/gitblit/wicket/pages/HomePage.java182
-rw-r--r--src/main/java/com/gitblit/wicket/pages/OverviewPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/PushesPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RootPage.java4
-rw-r--r--src/main/java/com/gitblit/wicket/panels/ActivityPanel.html2
-rw-r--r--src/main/java/com/gitblit/wicket/panels/PushesPanel.html10
-rw-r--r--src/main/java/com/gitblit/wicket/panels/PushesPanel.java100
21 files changed, 939 insertions, 278 deletions
diff --git a/src/main/java/com/gitblit/models/DailyLogEntry.java b/src/main/java/com/gitblit/models/DailyLogEntry.java
new file mode 100644
index 00000000..db605268
--- /dev/null
+++ b/src/main/java/com/gitblit/models/DailyLogEntry.java
@@ -0,0 +1,59 @@
+/*
+ * 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.models;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import org.eclipse.jgit.lib.PersonIdent;
+
+/**
+ * Model class to simulate a push for presentation in the push log news feed
+ * for a repository that does not have a Gitblit push log. Commits are grouped
+ * by date and may be additionally split by ref.
+ *
+ * @author James Moger
+ */
+public class DailyLogEntry extends PushLogEntry implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public DailyLogEntry(String repository, Date date) {
+ super(repository, date, new UserModel("digest"));
+ }
+
+ public DailyLogEntry(String repository, Date date, UserModel user) {
+ super(repository, date, user);
+ }
+
+ @Override
+ public PersonIdent getCommitterIdent() {
+ if (getAuthorCount() == 1) {
+ return getCommits().get(0).getCommitterIdent();
+ }
+
+ return super.getCommitterIdent();
+ }
+
+ @Override
+ public PersonIdent getAuthorIdent() {
+ if (getAuthorCount() == 1) {
+ return getCommits().get(0).getAuthorIdent();
+ }
+
+ return super.getAuthorIdent();
+ }
+}
diff --git a/src/main/java/com/gitblit/models/PushLogEntry.java b/src/main/java/com/gitblit/models/PushLogEntry.java
index d8f0b091..8b006d96 100644
--- a/src/main/java/com/gitblit/models/PushLogEntry.java
+++ b/src/main/java/com/gitblit/models/PushLogEntry.java
@@ -54,6 +54,8 @@ public class PushLogEntry implements Serializable, Comparable<PushLogEntry> {
private final Map<String, ReceiveCommand.Type> refUpdates;
private final Map<String, String> refIdChanges;
+
+ private int authorCount;
/**
* Constructor for specified duration of push from start date.
@@ -72,6 +74,7 @@ public class PushLogEntry implements Serializable, Comparable<PushLogEntry> {
this.commits = new LinkedHashSet<RepositoryCommit>();
this.refUpdates = new HashMap<String, ReceiveCommand.Type>();
this.refIdChanges = new HashMap<String, String>();
+ this.authorCount = -1;
}
/**
@@ -152,6 +155,7 @@ public class PushLogEntry implements Serializable, Comparable<PushLogEntry> {
public RepositoryCommit addCommit(String branch, RevCommit commit) {
RepositoryCommit commitModel = new RepositoryCommit(repository, branch, commit);
if (commits.add(commitModel)) {
+ authorCount = -1;
return commitModel;
}
return null;
@@ -165,6 +169,7 @@ public class PushLogEntry implements Serializable, Comparable<PushLogEntry> {
*/
public void addCommits(List<RepositoryCommit> list) {
commits.addAll(list);
+ authorCount = -1;
}
/**
@@ -254,6 +259,18 @@ public class PushLogEntry implements Serializable, Comparable<PushLogEntry> {
return list;
}
+ public int getAuthorCount() {
+ if (authorCount == -1) {
+ Set<String> authors = new HashSet<String>();
+ for (RepositoryCommit commit : commits) {
+ String name = commit.getAuthorIdent().getName();
+ authors.add(name);
+ }
+ authorCount = authors.size();
+ }
+ return authorCount;
+ }
+
/**
* The total number of commits in the push.
*
diff --git a/src/main/java/com/gitblit/utils/PushLogUtils.java b/src/main/java/com/gitblit/utils/PushLogUtils.java
index 2f076fb5..e10a6864 100644
--- a/src/main/java/com/gitblit/utils/PushLogUtils.java
+++ b/src/main/java/com/gitblit/utils/PushLogUtils.java
@@ -16,8 +16,11 @@
package com.gitblit.utils;
import java.io.IOException;
+import java.text.DateFormat;
import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -50,6 +53,7 @@ import org.eclipse.jgit.treewalk.TreeWalk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.gitblit.models.DailyLogEntry;
import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.PushLogEntry;
import com.gitblit.models.RefModel;
@@ -109,6 +113,25 @@ public class PushLogUtils {
return null;
}
+ private static UserModel newUserModelFrom(PersonIdent ident) {
+ String name = ident.getName();
+ String username;
+ String displayname;
+ if (name.indexOf('/') > -1) {
+ int slash = name.indexOf('/');
+ displayname = name.substring(0, slash);
+ username = name.substring(slash + 1);
+ } else {
+ displayname = name;
+ username = ident.getEmailAddress();
+ }
+
+ UserModel user = new UserModel(username);
+ user.displayName = displayname;
+ user.emailAddress = ident.getEmailAddress();
+ return user;
+ }
+
/**
* Updates a push log.
*
@@ -135,9 +158,15 @@ public class PushLogUtils {
DirCache index = createIndex(repository, headId, commands);
ObjectId indexTreeId = index.writeTree(odi);
- PersonIdent ident =
- new PersonIdent(MessageFormat.format("{0}/{1}", user.getDisplayName(), user.username),
+ PersonIdent ident;
+ if (UserModel.ANONYMOUS.equals(user)) {
+ // anonymous push
+ ident = new PersonIdent("anonymous", "anonymous");
+ } else {
+ // construct real pushing account
+ ident = new PersonIdent(MessageFormat.format("{0}/{1}", user.getDisplayName(), user.username),
user.emailAddress == null ? user.username : user.emailAddress);
+ }
// Create a commit object
CommitBuilder commit = new CommitBuilder();
@@ -339,23 +368,9 @@ public class PushLogUtils {
continue;
}
- String name = push.getAuthorIdent().getName();
- String username;
- String displayname;
- if (name.indexOf('/') > -1) {
- int slash = name.indexOf('/');
- displayname = name.substring(0, slash);
- username = name.substring(slash + 1);
- } else {
- displayname = name;
- username = push.getAuthorIdent().getEmailAddress();
- }
-
- UserModel user = new UserModel(username);
- user.displayName = displayname;
- user.emailAddress = push.getAuthorIdent().getEmailAddress();
-
+ UserModel user = newUserModelFrom(push.getAuthorIdent());
Date date = push.getAuthorIdent().getWhen();
+
PushLogEntry log = new PushLogEntry(repositoryName, date, user);
list.add(log);
List<PathChangeModel> changedRefs = JGitUtils.getFilesInCommit(repository, push);
@@ -413,14 +428,22 @@ public class PushLogUtils {
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>>();
- for (PushLogEntry push : getPushLog(repositoryName, repository, offset, maxCount)) {
+ List<PushLogEntry> pushes = getPushLog(repositoryName, repository, offset, maxCount);
+ for (PushLogEntry push : pushes) {
for (String ref : push.getChangedRefs()) {
if (!refMap.containsKey(ref)) {
refMap.put(ref, new ArrayList<PushLogEntry>());
}
// construct new ref-specific push log entry
- PushLogEntry refPush = new PushLogEntry(push.repository, push.date, push.user);
+ PushLogEntry refPush;
+ if (push instanceof DailyLogEntry) {
+ // simulated push log from commits grouped by date
+ refPush = new DailyLogEntry(push.repository, push.date);
+ } else {
+ // real push log entry
+ refPush = new PushLogEntry(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);
@@ -451,15 +474,16 @@ public class PushLogUtils {
public static List<PushLogEntry> getPushLogByRef(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>>();
- for (PushLogEntry push : getPushLog(repositoryName, repository, minimumDate)) {
+ List<PushLogEntry> pushes = getPushLog(repositoryName, repository, minimumDate);
+ for (PushLogEntry push : pushes) {
for (String ref : push.getChangedRefs()) {
if (!refMap.containsKey(ref)) {
refMap.put(ref, new ArrayList<PushLogEntry>());
}
-
- // construct new ref-specific push log entry
- PushLogEntry refPush = new PushLogEntry(push.repository, push.date, push.user);
- refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref));
+
+ // construct new ref-specific push log entry
+ PushLogEntry refPush = new PushLogEntry(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);
}
@@ -476,4 +500,106 @@ public class PushLogUtils {
return refPushLog;
}
+
+ /**
+ * Returns a commit log grouped by day.
+ *
+ * @param repositoryName
+ * @param repository
+ * @param minimumDate
+ * @param offset
+ * @param maxCount
+ * if < 0, all pushes are returned.
+ * @return a list of grouped commit log entries
+ */
+ public static List<DailyLogEntry> getDailyLog(String repositoryName, Repository repository,
+ Date minimumDate, int offset, int maxCount) {
+
+ DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+// df.setTimeZone(timezone);
+
+ Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository);
+ Map<String, DailyLogEntry> tags = new HashMap<String, DailyLogEntry>();
+ Map<String, DailyLogEntry> dailydigests = new HashMap<String, DailyLogEntry>();
+ for (RefModel local : JGitUtils.getLocalBranches(repository, true, -1)) {
+ String branch = local.getName();
+ List<RevCommit> commits = JGitUtils.getRevLog(repository, branch, minimumDate);
+ for (RevCommit commit : commits) {
+ Date date = JGitUtils.getCommitDate(commit);
+ String dateStr = df.format(date);
+ if (!dailydigests.containsKey(dateStr)) {
+ dailydigests.put(dateStr, new DailyLogEntry(repositoryName, date));
+ }
+ PushLogEntry digest = dailydigests.get(dateStr);
+ digest.updateRef(branch, ReceiveCommand.Type.UPDATE, commit.getParents()[0].getId().getName(), commit.getName());
+ RepositoryCommit repoCommit = digest.addCommit(branch, commit);
+ if (repoCommit != null) {
+ repoCommit.setRefs(allRefs.get(commit.getId()));
+ if (!ArrayUtils.isEmpty(repoCommit.getRefs())) {
+ // treat tags as special events in the log
+ for (RefModel ref : repoCommit.getRefs()) {
+ if (ref.getName().startsWith(Constants.R_TAGS)) {
+ if (!tags.containsKey(dateStr)) {
+ UserModel tagUser = newUserModelFrom(commit.getAuthorIdent());
+ Date tagDate = commit.getAuthorIdent().getWhen();
+ tags.put(dateStr, new DailyLogEntry(repositoryName, tagDate, tagUser));
+ }
+ PushLogEntry tagEntry = tags.get(dateStr);
+ tagEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE);
+ tagEntry.addCommits(Arrays.asList(repoCommit));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ List<DailyLogEntry> list = new ArrayList<DailyLogEntry>(dailydigests.values());
+ list.addAll(tags.values());
+ Collections.sort(list);
+ return list;
+ }
+
+ /**
+ * Returns the list of commits separated by ref (e.g. each ref has it's own
+ * PushLogEntry object for each day).
+ *
+ * @param repositoryName
+ * @param repository
+ * @param minimumDate
+ * @return a list of push log entries separated by ref and date
+ */
+ public static List<DailyLogEntry> getDailyLogByRef(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<DailyLogEntry>> refMap = new HashMap<String, List<DailyLogEntry>>();
+ List<DailyLogEntry> pushes = getDailyLog(repositoryName, repository, minimumDate, 0, -1);
+ for (DailyLogEntry push : pushes) {
+ for (String ref : push.getChangedRefs()) {
+ if (!refMap.containsKey(ref)) {
+ refMap.put(ref, new ArrayList<DailyLogEntry>());
+ }
+
+ // construct new ref-specific push log entry
+ DailyLogEntry refPush = new DailyLogEntry(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<DailyLogEntry> refPushLog = new ArrayList<DailyLogEntry>();
+ for (List<DailyLogEntry> refPush : refMap.values()) {
+ for (DailyLogEntry entry : refPush) {
+ if (entry.getCommitCount() > 0) {
+ refPushLog.add(entry);
+ }
+ }
+ }
+
+ // sort ref push log
+ Collections.sort(refPushLog);
+
+ return refPushLog;
+ }
}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index bdb4d455..f4180faa 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -44,6 +44,7 @@ import com.gitblit.wicket.pages.ForksPage;
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;
@@ -68,7 +69,7 @@ import com.gitblit.wicket.pages.UsersPage;
public class GitBlitWebApp extends WebApplication {
- public final static Class<? extends BasePage> HOME_PAGE_CLASS = RepositoriesPage.class;
+ public final static Class<? extends BasePage> HOME_PAGE_CLASS = DashboardPage.class;
@Override
public void init() {
@@ -94,7 +95,7 @@ public class GitBlitWebApp extends WebApplication {
}
// setup the standard gitweb-ish urls
-// mount("/repositories", RepositoriesPage.class);
+ mount("/repositories", RepositoriesPage.class);
mount("/overview", OverviewPage.class, "r", "h");
mount("/summary", SummaryPage.class, "r");
mount("/pushes", PushesPage.class, "r", "h");
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
index 1b8583e6..036af264 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -452,7 +452,7 @@ gb.incrementalPushTagMessage = Auto-tagged [{0}] branch on push
gb.externalPermissions = {0} access permissions are externally maintained
gb.viewAccess = You do not have Gitblit read or write access
gb.overview = overview
-gb.home = home
+gb.dashboard = dashboard
gb.monthlyActivity = monthly activity
gb.myProfile = my profile
gb.compare = compare
@@ -460,17 +460,28 @@ gb.manual = manual
gb.from = from
gb.to = to
gb.at = at
+gb.of = of
+gb.in = in
gb.morePushes = all pushes...
gb.pushes = pushes
gb.pushedNCommitsTo = pushed {0} commits to
gb.pushedOneCommitTo = pushed 1 commit to
+gb.commitsTo = {0} commits to
+gb.oneCommitTo = 1 commit to
+gb.byNAuthors = by {0} authors
+gb.byOneAuthor = by {0}
gb.viewComparison = view comparison of these {0} commits \u00bb
gb.nMoreCommits = {0} more commits \u00bb
gb.oneMoreCommit = 1 more commit \u00bb
gb.pushedNewTag = pushed new tag
+gb.createdNewTag = created new tag
gb.deletedTag = deleted tag
gb.pushedNewBranch = pushed new branch
gb.deletedBranch = deleted branch
gb.rewind = REWIND
gb.star = star
-gb.unstar = unstar \ No newline at end of file
+gb.unstar = unstar
+gb.stargazers = stargazers
+gb.starredRepositories = starred repositories
+gb.failedToUpdateUser = Failed to update user account!
+gb.myRepositories = my repositories
diff --git a/src/main/java/com/gitblit/wicket/charting/GoogleChart.java b/src/main/java/com/gitblit/wicket/charting/GoogleChart.java
index b6309ffe..334b870d 100644
--- a/src/main/java/com/gitblit/wicket/charting/GoogleChart.java
+++ b/src/main/java/com/gitblit/wicket/charting/GoogleChart.java
@@ -38,6 +38,7 @@ public abstract class GoogleChart implements Serializable {
final List<ChartValue> values;
int width;
int height;
+ boolean showLegend;
public GoogleChart(String tagId, String title, String keyName, String valueName) {
this.tagId = tagId;
@@ -46,6 +47,7 @@ public abstract class GoogleChart implements Serializable {
this.keyName = keyName;
this.valueName = valueName;
values = new ArrayList<ChartValue>();
+ showLegend = true;
}
public void setWidth(int width) {
@@ -55,6 +57,10 @@ public abstract class GoogleChart implements Serializable {
public void setHeight(int height) {
this.height = height;
}
+
+ public void setShowLegend(boolean val) {
+ this.showLegend = val;
+ }
public void addValue(String name, int value) {
values.add(new ChartValue(name, value));
diff --git a/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java b/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java
index 119a8248..945e08b1 100644
--- a/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java
+++ b/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java
@@ -68,8 +68,8 @@ public class GooglePieChart extends GoogleChart {
cName, tagId));
line(sb,
MessageFormat
- .format("{0}.draw({1}, '{'width: {2,number,0}, height: {3,number,0}, chartArea:'{'left:20,top:20'}', title: ''{4}'', {5} '}');",
- cName, dName, width, height, title, colors.toString()));
+ .format("{0}.draw({1}, '{' title: ''{4}'', {5}, legend: '{' position:''{6}'' '}' '}');",
+ cName, dName, width, height, title, colors.toString(), showLegend ? "right" : "none"));
line(sb, "");
}
} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/ng/NgController.java b/src/main/java/com/gitblit/wicket/ng/NgController.java
new file mode 100644
index 00000000..fb88cf35
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/ng/NgController.java
@@ -0,0 +1,79 @@
+/*
+ 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.ng;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.wicket.markup.html.IHeaderContributor;
+import org.apache.wicket.markup.html.IHeaderResponse;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * Simple AngularJS data controller which injects scoped objects as static,
+ * embedded JSON within the generated page. This allows use of AngularJS
+ * client-side databinding (magic) with server-generated pages.
+ *
+ * @author James Moger
+ *
+ */
+public class NgController implements IHeaderContributor {
+
+ private static final long serialVersionUID = 1L;
+
+ final String name;
+
+ final Map<String, Object> variables;
+
+ public NgController(String name) {
+ this.name = name;
+ this.variables = new HashMap<String, Object>();
+ }
+
+ public void addVariable(String name, Object o) {
+ variables.put(name, o);
+ }
+
+ @Override
+ public void renderHead(IHeaderResponse response) {
+ // add Google AngularJS reference
+ response.renderJavascriptReference("bootstrap/js/angular.js");
+
+ Gson gson = new GsonBuilder().create();
+
+ StringBuilder sb = new StringBuilder();
+ line(sb, MessageFormat.format("<!-- AngularJS {0} data controller -->", name));
+ line(sb, MessageFormat.format("function {0}($scope) '{'", name));
+ for (Map.Entry<String, Object> entry : variables.entrySet()) {
+ String var = entry.getKey();
+ Object o = entry.getValue();
+ String json = gson.toJson(o);
+ line(sb, MessageFormat.format("\t$scope.{0} = {1};", var, json));
+ }
+ line(sb, "}");
+
+ response.renderJavascript(sb.toString(), null);
+ }
+
+ private void line(StringBuilder sb, String line) {
+ sb.append(line);
+ sb.append('\n');
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/ActivityPage.html b/src/main/java/com/gitblit/wicket/pages/ActivityPage.html
index 14ae459f..f43b26fd 100644
--- a/src/main/java/com/gitblit/wicket/pages/ActivityPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/ActivityPage.html
@@ -9,12 +9,12 @@
<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>
</div>
- <div class="hidden-phone" style="height: 155px;text-align: center;">
+ <div class="hidden-phone" style="text-align: center;">
<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 style="width:310px; height:150px" class="hidden-tablet" id="chartDaily"></div></td>
+ <td><div style="width:310px; height:175px" id="chartRepositories"></div></td>
+ <td><div style="width:310px; height:175px" id="chartAuthors"></div></td>
</tr>
</table>
</div>
diff --git a/src/main/java/com/gitblit/wicket/pages/ActivityPage.java b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java
index bceac8f4..8e841c79 100644
--- a/src/main/java/com/gitblit/wicket/pages/ActivityPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java
@@ -162,8 +162,6 @@ public class ActivityPage extends RootPage {
}
// build google charts
- int w = 310;
- int h = 150;
GoogleCharts charts = new GoogleCharts();
// sort in reverse-chronological order and then reverse that
@@ -178,8 +176,6 @@ public class ActivityPage extends RootPage {
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
@@ -188,8 +184,7 @@ public class ActivityPage extends RootPage {
for (Metric metric : repositoryMetrics.values()) {
chart.addValue(metric.name, metric.count);
}
- chart.setWidth(w);
- chart.setHeight(h);
+ chart.setShowLegend(false);
charts.addChart(chart);
// active authors pie chart
@@ -198,8 +193,7 @@ public class ActivityPage extends RootPage {
for (Metric metric : authorMetrics.values()) {
chart.addValue(metric.name, metric.count);
}
- chart.setWidth(w);
- chart.setHeight(h);
+ chart.setShowLegend(false);
charts.addChart(chart);
return charts;
diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.html b/src/main/java/com/gitblit/wicket/pages/BasePage.html
index a24f2362..0f96f343 100644
--- a/src/main/java/com/gitblit/wicket/pages/BasePage.html
+++ b/src/main/java/com/gitblit/wicket/pages/BasePage.html
@@ -2,7 +2,8 @@
<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">
+ lang="en"
+ ng-app>
<!-- Head -->
<wicket:head>
diff --git a/src/main/java/com/gitblit/wicket/pages/DashboardPage.html b/src/main/java/com/gitblit/wicket/pages/DashboardPage.html
new file mode 100644
index 00000000..d2516f0f
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/DashboardPage.html
@@ -0,0 +1,99 @@
+<!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="markdown" style="padding-bottom:5px;" wicket:id="repositoriesMessage">[repositories message]</div>
+
+ <div class="row">
+ <div class="span7">
+ <div class="hidden-phone hidden-tablet" style="text-align:center;">
+ <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>
+ </div>
+ <div wicket:id="pushes"></div>
+ </div>
+ <div class="span5">
+ <div wicket:id="active">[active]</div>
+ <div wicket:id="starred">[starred]</div>
+ <div wicket:id="owned">[owned]</div>
+ </div>
+
+ </div>
+</div>
+
+<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 class="pull-right">
+ <a class="btn btn-mini">more</a>
+ </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 starred | limitTo: 20 | filter:query" style="padding: 3px;border-top: 1px solid #ddd;">
+ <b><span class="repositorySwatch" style="background-color:{{item.c}};"><span ng-show="item.wc">!</span><span ng-show="!item.wc">&nbsp;</span></span></b>
+ <a href="summary/?r={{item.r}}">{{item.p}}<b>{{item.n}}</b></a>
+ <span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
+ <span ng-show="item.s" class="pull-right">
+ <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i class="iconic-star"></i></span>
+ </span>
+ </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="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">&nbsp;</span></span></b>
+ <a href="summary/?r={{item.r}}">{{item.p}}<b>{{item.n}}</b></a>
+ <span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
+ <span ng-show="item.s" class="pull-right">
+ <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i class="iconic-star"></i></span>
+ </span>
+ </div>
+ </div>
+</wicket:fragment>
+
+<wicket:fragment wicket:id="activeListFragment">
+ <div ng-controller="activeCtrl" 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.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">&nbsp;</span></span></b>
+ <a href="summary/?r={{item.r}}">{{item.p}}<b>{{item.n}}</b></a>
+ <span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
+ <span ng-show="item.s" class="pull-right">
+ <span style="padding: 0px 5px;color: #888;font-weight:bold;vertical-align:middle;">{{item.s | number}} <i class="iconic-star"></i></span>
+ </span>
+ </div>
+ </div>
+</wicket:fragment>
+
+</wicket:extend>
+</body>
+</html> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java
new file mode 100644
index 00000000..6a4c5658
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java
@@ -0,0 +1,418 @@
+/*
+ * 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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.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.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.WicketUtils;
+import com.gitblit.wicket.charting.GoogleChart;
+import com.gitblit.wicket.charting.GoogleCharts;
+import com.gitblit.wicket.charting.GooglePieChart;
+import com.gitblit.wicket.ng.NgController;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.PushesPanel;
+
+public class DashboardPage extends RootPage {
+
+ public DashboardPage() {
+ super();
+ setup(null);
+ }
+
+ public DashboardPage(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("repositoriesPanel"));
+ 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();
+
+ Comparator<RepositoryModel> lastUpdateSort = new Comparator<RepositoryModel>() {
+ @Override
+ public int compare(RepositoryModel o1, RepositoryModel o2) {
+ return o2.lastChange.compareTo(o1.lastChange);
+ }
+ };
+
+ Map<String, RepositoryModel> reposMap = new HashMap<String, RepositoryModel>();
+
+ // owned repositories
+ List<RepositoryModel> owned = new ArrayList<RepositoryModel>();
+ if (user != null && !UserModel.ANONYMOUS.equals(user)) {
+ for (RepositoryModel model : GitBlit.self().getRepositoryModels(user)) {
+ reposMap.put(model.name, model);
+ if (model.isUsersPersonalRepository(user.username) || model.isOwner(user.username)) {
+ owned.add(model);
+ }
+ }
+ }
+ Collections.sort(owned, lastUpdateSort);
+
+ // starred repositories
+ List<RepositoryModel> starred = new ArrayList<RepositoryModel>();
+ if (user != null && !UserModel.ANONYMOUS.equals(user)) {
+ for (String name : user.getPreferences().getStarredRepositories()) {
+ if (!reposMap.containsKey(name)) {
+ RepositoryModel repo = GitBlit.self().getRepositoryModel(name);
+ reposMap.put(name, repo);
+ }
+ starred.add(reposMap.get(name));
+ }
+ }
+ Collections.sort(starred, lastUpdateSort);
+
+ // parameters
+ int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params);
+ if (daysBack < 1) {
+ daysBack = 14;
+ }
+ Calendar c = Calendar.getInstance();
+ c.add(Calendar.DATE, -1*daysBack);
+ Date minimumDate = c.getTime();
+
+ // active repositories (displayed for anonymous users)
+ List<RepositoryModel> active = new ArrayList<RepositoryModel>();
+ if (user == null || UserModel.ANONYMOUS.equals(user)) {
+ List<RepositoryModel> list = GitBlit.self().getRepositoryModels(UserModel.ANONYMOUS);
+ for (RepositoryModel model : list) {
+ if (model.lastChange.after(minimumDate)) {
+ active.add(model);
+ reposMap.put(model.name, model);
+ }
+ }
+ Collections.sort(active, lastUpdateSort);
+ }
+
+ // show pushlog feed
+ List<PushLogEntry> pushes = new ArrayList<PushLogEntry>();
+ for (RepositoryModel model : reposMap.values()) {
+ Repository repository = GitBlit.self().getRepository(model.name);
+ List<DailyLogEntry> entries = PushLogUtils.getDailyLogByRef(model.name, repository, minimumDate);
+ pushes.addAll(entries);
+ repository.close();
+ }
+
+ if (pushes.size() == 0) {
+ if (reposMap.size() == 0) {
+ add(new LinkPanel("pushes", null, "find some repositories", RepositoriesPage.class));
+ } else {
+ add(new Label("pushes", "all is quiet"));
+ }
+ } else {
+ Collections.sort(pushes);
+ add(new PushesPanel("pushes", pushes));
+ }
+
+ // add the nifty charts
+ if (!ArrayUtils.isEmpty(pushes)) {
+ GoogleCharts charts = createCharts(pushes);
+ add(new HeaderContributor(charts));
+ }
+
+ // active repository list
+ if (ArrayUtils.isEmpty(active)) {
+ add(new Label("active").setVisible(false));
+ } else {
+ Fragment activeView = createNgList("active", "activeListFragment", "activeCtrl", active);
+ add(activeView);
+ }
+
+ // 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);
+ }
+ }
+
+ protected Fragment createNgList(String wicketId, String fragmentId, String ngController, List<RepositoryModel> repositories) {
+ String format = GitBlit.getString(Keys.web.datestampShortFormat, "MM/dd/yy");
+ final DateFormat df = new SimpleDateFormat(format);
+ df.setTimeZone(getTimeZone());
+
+ Fragment fragment = new Fragment(wicketId, fragmentId, this);
+
+ List<RepoListItem> list = new ArrayList<RepoListItem>();
+ for (RepositoryModel repo : repositories) {
+ String name = StringUtils.stripDotGit(repo.name);
+ String path = "";
+ if (name.indexOf('/') > -1) {
+ path = name.substring(0, name.lastIndexOf('/') + 1);
+ name = name.substring(name.lastIndexOf('/') + 1);
+ }
+
+ RepoListItem item = new RepoListItem();
+ item.n = name;
+ item.p = path;
+ item.r = repo.name;
+ item.s = GitBlit.self().getStarCount(repo);
+ item.t = getTimeUtils().timeAgo(repo.lastChange);
+ item.d = df.format(repo.lastChange);
+ item.c = StringUtils.getColor(StringUtils.stripDotGit(repo.name));
+ item.wc = repo.isBare ? 0 : 1;
+ list.add(item);
+ }
+
+ // inject an AngularJS controller with static data
+ NgController ctrl = new NgController(ngController);
+ ctrl.addVariable(wicketId, list);
+ add(new HeaderContributor(ctrl));
+
+ return fragment;
+ }
+
+ @Override
+ protected void addDropDownMenus(List<PageRegistration> pages) {
+ PageParameters params = getPageParameters();
+
+ DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ GitBlitWebApp.HOME_PAGE_CLASS);
+ // preserve time filter option on repository choices
+ menu.menuItems.addAll(getRepositoryFilterItems(params));
+
+ // preserve repository filter option on time choices
+ menu.menuItems.addAll(getTimeFilterItems(params));
+
+ if (menu.menuItems.size() > 0) {
+ // Reset Filter
+ menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ }
+
+ 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
+ * @return
+ */
+ private GoogleCharts createCharts(List<PushLogEntry> recentPushes) {
+ // activity metrics
+ Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();
+ Map<String, Metric> authorMetrics = new HashMap<String, Metric>();
+
+ // aggregate repository and author metrics
+ for (PushLogEntry push : recentPushes) {
+
+ // aggregate repository metrics
+ String repository = StringUtils.stripDotGit(push.repository);
+ if (!repositoryMetrics.containsKey(repository)) {
+ repositoryMetrics.put(repository, new Metric(repository));
+ }
+ repositoryMetrics.get(repository).count += 1;
+
+ for (RepositoryCommit commit : push.getCommits()) {
+ String author = commit.getAuthorIdent().getName();
+ if (!authorMetrics.containsKey(author)) {
+ authorMetrics.put(author, new Metric(author));
+ }
+ authorMetrics.get(author).count += 1;
+ }
+ }
+
+ // build google charts
+ GoogleCharts charts = new GoogleCharts();
+
+ // active repositories pie chart
+ GoogleChart 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.setShowLegend(false);
+ 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.setShowLegend(false);
+ charts.addChart(chart);
+
+ return charts;
+ }
+
+ class RepoListItem implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ String r; // repository
+ String n; // name
+ String p; // project/path
+ String t; // time ago
+ String d; // last updated
+ long s; // stars
+ String c; // html color
+ int wc; // working copy, 1 = true
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/HomePage.html b/src/main/java/com/gitblit/wicket/pages/HomePage.html
deleted file mode 100644
index 3730d786..00000000
--- a/src/main/java/com/gitblit/wicket/pages/HomePage.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!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="markdown" style="padding-bottom:5px;" wicket:id="repositoriesMessage">[repositories message]</div>
-
-<!-- <div wicket:id="repositoriesPanel">[repositories panel]</div> -->
-</div>
-</wicket:extend>
-</body>
-</html> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/HomePage.java b/src/main/java/com/gitblit/wicket/pages/HomePage.java
deleted file mode 100644
index 9dfd1ae4..00000000
--- a/src/main/java/com/gitblit/wicket/pages/HomePage.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2011 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.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.eclipse.jgit.lib.Constants;
-
-import com.gitblit.GitBlit;
-import com.gitblit.Keys;
-import com.gitblit.utils.MarkdownUtils;
-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;
-
-public class HomePage extends RootPage {
-
- public HomePage() {
- super();
- setup(null);
- }
-
- public HomePage(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("repositoriesPanel"));
- 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);
-
-// List<RepositoryModel> repositories = getRepositories(params);
-//
-// RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", showAdmin,
-// true, repositories, true, getAccessRestrictions());
-// // push the panel down if we are hiding the admin controls and the
-// // welcome message
-// if (!showAdmin && !repositoriesMessage.isVisible()) {
-// WicketUtils.setCssStyle(repositoriesPanel, "padding-top:5px;");
-// }
-// add(repositoriesPanel);
- }
-
- @Override
- protected void addDropDownMenus(List<PageRegistration> pages) {
- PageParameters params = getPageParameters();
-
- DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
- GitBlitWebApp.HOME_PAGE_CLASS);
- // preserve time filter option on repository choices
- menu.menuItems.addAll(getRepositoryFilterItems(params));
-
- // preserve repository filter option on time choices
- menu.menuItems.addAll(getTimeFilterItems(params));
-
- if (menu.menuItems.size() > 0) {
- // Reset Filter
- menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
- }
-
- 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);
- }
-}
diff --git a/src/main/java/com/gitblit/wicket/pages/OverviewPage.java b/src/main/java/com/gitblit/wicket/pages/OverviewPage.java
index aea07bfe..6fd38915 100644
--- a/src/main/java/com/gitblit/wicket/pages/OverviewPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/OverviewPage.java
@@ -110,7 +110,7 @@ public class OverviewPage extends RepositoryPage {
add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model));
int pushCount = GitBlit.getInteger(Keys.web.overviewPushCount, 5);
- PushesPanel pushes = new PushesPanel("pushesPanel", getRepositoryModel(), r, pushCount, 0);
+ PushesPanel pushes = new PushesPanel("pushesPanel", getRepositoryModel(), r, pushCount, 0, false);
add(pushes);
add(new TagsPanel("tagsPanel", repositoryName, r, numberRefs).hideIfEmpty());
add(new BranchesPanel("branchesPanel", getRepositoryModel(), r, numberRefs, false).hideIfEmpty());
diff --git a/src/main/java/com/gitblit/wicket/pages/PushesPage.java b/src/main/java/com/gitblit/wicket/pages/PushesPage.java
index a0e7c973..866964ac 100644
--- a/src/main/java/com/gitblit/wicket/pages/PushesPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/PushesPage.java
@@ -33,7 +33,7 @@ public class PushesPage extends RepositoryPage {
int nextPage = pageNumber + 1;
PushesPanel pushesPanel = new PushesPanel("pushesPanel", getRepositoryModel(), getRepository(), -1,
- pageNumber - 1);
+ pageNumber - 1, false);
boolean hasMore = pushesPanel.hasMore();
add(pushesPanel);
diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java
index 30251516..bbe20f5b 100644
--- a/src/main/java/com/gitblit/wicket/pages/RootPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java
@@ -118,8 +118,8 @@ public abstract class RootPage extends BasePage {
// navigation links
List<PageRegistration> pages = new ArrayList<PageRegistration>();
if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) {
-// pages.add(new PageRegistration("gb.home", HomePage.class,
-// getRootPageParameters()));
+ pages.add(new PageRegistration("gb.dashboard", DashboardPage.class,
+ getRootPageParameters()));
pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class,
getRootPageParameters()));
pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters()));
diff --git a/src/main/java/com/gitblit/wicket/panels/ActivityPanel.html b/src/main/java/com/gitblit/wicket/panels/ActivityPanel.html
index b818e94a..9dff0a7c 100644
--- a/src/main/java/com/gitblit/wicket/panels/ActivityPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/ActivityPanel.html
@@ -13,7 +13,7 @@
<tr wicket:id="commit">
<td class="hidden-phone date" style="width:60px; vertical-align: middle;text-align: right;padding-right:10px;" ><span wicket:id="time">[time of day]</span></td>
<td style="width:10em;text-align:left;vertical-align: middle;">
- <span wicket:id="repository" class="repositorySwatch">[repository link]</span>
+ <span wicket:id="repository" class="activitySwatch">[repository link]</span>
</td>
<td class="hidden-phone hidden-tablet" style="width:30px;vertical-align: middle;"><span wicket:id="avatar" style="vertical-align: middle;"></span></td>
<td style="vertical-align: middle;padding-left:15px;">
diff --git a/src/main/java/com/gitblit/wicket/panels/PushesPanel.html b/src/main/java/com/gitblit/wicket/panels/PushesPanel.html
index cad59323..9fb5aed0 100644
--- a/src/main/java/com/gitblit/wicket/panels/PushesPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/PushesPanel.html
@@ -6,21 +6,21 @@
<body>
<wicket:panel>
-<div wicket:id="push" style="border-bottom: 1px solid #ddd;margin-bottom: 15px;">
+<div wicket:id="push" class="push">
<table style="padding: 3px 0px;">
<tr>
- <td class="hidden-phone" style="vertical-align: top;padding-top:10px"><i style="font-size:3.25em;color:#bbb;" wicket:id="pushIcon"></i></td>
+ <td class="hidden-phone" style="vertical-align: top;padding-top:10px"><i wicket:id="pushIcon"></i></td>
<td style="padding-left: 7px;">
<div>
<span wicket:id="whenPushed"></span> <span wicket:id="refRewind" class="alert alert-error" style="padding: 1px 5px;font-size: 10px;font-weight: bold;margin-left: 10px;">[rewind]</span>
</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></div>
+ <div style="font-weight:bold;"><span wicket:id="whoPushed">[pusher]</span> <span wicket:id="whatPushed"></span><span wicket:id="refPushed"></span> <span wicket:id="repoPreposition"></span> <span wicket:id="repoPushed"></span> <span wicket:id="byAuthors"></span></div>
<div style="padding: 10px 0px 5px;">
<table>
<tr wicket:id="commit">
- <td style="vertical-align:top;"><span wicket:id="commitAuthor"></span></td>
+ <td class="hidden-phone hidden-tablet" style="vertical-align:top;padding-left:7px;"><span wicket:id="commitAuthor"></span></td>
<td style="vertical-align:top;"><span wicket:id="hashLink" style="padding-left: 5px;">[hash link]</span></td>
- <td style="vertical-align:top;"><img wicket:id="commitIcon" /></td>
+ <td style="vertical-align:top;padding-left:5px;"><img wicket:id="commitIcon" /></td>
<td style="vertical-align:top;">
<span wicket:id="commitShortMessage">[commit short message]</span>
</td>
diff --git a/src/main/java/com/gitblit/wicket/panels/PushesPanel.java b/src/main/java/com/gitblit/wicket/panels/PushesPanel.java
index 29161ba8..423c44b4 100644
--- a/src/main/java/com/gitblit/wicket/panels/PushesPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/PushesPanel.java
@@ -29,6 +29,7 @@ import org.eclipse.jgit.lib.Repository;
import com.gitblit.Constants;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
+import com.gitblit.models.DailyLogEntry;
import com.gitblit.models.PushLogEntry;
import com.gitblit.models.RepositoryCommit;
import com.gitblit.models.RepositoryModel;
@@ -51,7 +52,7 @@ public class PushesPanel extends BasePanel {
private boolean hasMore;
- public PushesPanel(String wicketId, final RepositoryModel model, Repository r, int limit, int pageOffset) {
+ public PushesPanel(String wicketId, final RepositoryModel model, Repository r, int limit, int pageOffset, boolean showRepo) {
super(wicketId);
boolean pageResults = limit <= 0;
int pushesPerPage = GitBlit.getInteger(Keys.web.pushesPerPage, 10);
@@ -71,7 +72,7 @@ public class PushesPanel extends BasePanel {
hasMore = pushes.size() >= pushesPerPage;
hasPushes = pushes.size() > 0;
- setup(pushes);
+ setup(pushes, showRepo);
// determine to show pager, more, or neither
if (limit <= 0) {
@@ -99,11 +100,11 @@ public class PushesPanel extends BasePanel {
public PushesPanel(String wicketId, List<PushLogEntry> pushes) {
super(wicketId);
hasPushes = pushes.size() > 0;
- setup(pushes);
+ setup(pushes, true);
add(new Label("morePushes").setVisible(false));
}
- protected void setup(List<PushLogEntry> pushes) {
+ protected void setup(List<PushLogEntry> pushes, final boolean showRepo) {
final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6);
ListDataProvider<PushLogEntry> dp = new ListDataProvider<PushLogEntry>(pushes);
@@ -121,36 +122,58 @@ public class PushesPanel extends BasePanel {
shortRefName = shortRefName.substring(org.eclipse.jgit.lib.Constants.R_TAGS.length());
isTag = true;
}
+ boolean isDigest = push instanceof DailyLogEntry;
pushItem.add(WicketUtils.createDateLabel("whenPushed", push.date, getTimeZone(), getTimeUtils()));
Label pushIcon = new Label("pushIcon");
+ if (showRepo) {
+ // if we are showing the repo, we are showing multiple
+ // repos. use the repository hash color to differentiate
+ // the icon.
+ String color = StringUtils.getColor(StringUtils.stripDotGit(push.repository));
+ WicketUtils.setCssStyle(pushIcon, "color: " + color);
+ }
if (isTag) {
WicketUtils.setCssClass(pushIcon, "iconic-tag");
- } else {
+ } else if (isDigest) {
WicketUtils.setCssClass(pushIcon, "iconic-loop");
- }
- pushItem.add(pushIcon);
- if (push.user.username.equals(push.user.emailAddress) && push.user.emailAddress.indexOf('@') > -1) {
- // username is an email address - 1.2.1 push log bug
- pushItem.add(new Label("whoPushed", push.user.getDisplayName()));
} else {
- // link to user acount page
- pushItem.add(new LinkPanel("whoPushed", null, push.user.getDisplayName(),
- UserPage.class, WicketUtils.newUsernameParameter(push.user.username)));
+ WicketUtils.setCssClass(pushIcon, "iconic-upload");
}
+ pushItem.add(pushIcon);
+
+ if (isDigest && !isTag) {
+ pushItem.add(new Label("whoPushed").setVisible(false));
+ } else {
+ if (push.user.username.equals(push.user.emailAddress) && push.user.emailAddress.indexOf('@') > -1) {
+ // username is an email address - 1.2.1 push log bug
+ pushItem.add(new Label("whoPushed", push.user.getDisplayName()));
+ } else {
+ // link to user account page
+ pushItem.add(new LinkPanel("whoPushed", null, push.user.getDisplayName(),
+ UserPage.class, WicketUtils.newUsernameParameter(push.user.username)));
+ }
+ }
- String preposition = "gb.at";
+ String preposition = "gb.of";
boolean isDelete = false;
boolean isRewind = false;
String what;
+ String by = null;
switch(push.getChangeType(fullRefName)) {
case CREATE:
if (isTag) {
- what = getString("gb.pushedNewTag");
+ if (isDigest) {
+ what = getString("gb.createdNewTag");
+ preposition = "gb.in";
+ } else {
+ what = getString("gb.pushedNewTag");
+ preposition = "gb.to";
+ }
} else {
what = getString("gb.pushedNewBranch");
+ preposition = "gb.to";
}
- preposition = "gb.to";
break;
case DELETE:
isDelete = true;
@@ -164,10 +187,21 @@ public class PushesPanel extends BasePanel {
case UPDATE_NONFASTFORWARD:
isRewind = true;
default:
- what = MessageFormat.format(push.getCommitCount() > 1 ? getString("gb.pushedNCommitsTo") : getString("gb.pushedOneCommitTo") , push.getCommitCount());
+ if (isDigest) {
+ what = MessageFormat.format(push.getCommitCount() > 1 ? getString("gb.commitsTo") : getString("gb.oneCommitTo"), push.getCommitCount());
+ } else {
+ what = MessageFormat.format(push.getCommitCount() > 1 ? getString("gb.pushedNCommitsTo") : getString("gb.pushedOneCommitTo") , push.getCommitCount());
+ }
+
+ if (push.getAuthorCount() == 1) {
+ by = MessageFormat.format(getString("gb.byOneAuthor"), push.getAuthorIdent().getName());
+ } else {
+ by = MessageFormat.format(getString("gb.byNAuthors"), push.getAuthorCount());
+ }
break;
}
pushItem.add(new Label("whatPushed", what));
+ pushItem.add(new Label("byAuthors", by).setVisible(!StringUtils.isEmpty(by)));
pushItem.add(new Label("refRewind", getString("gb.rewind")).setVisible(isRewind));
@@ -184,13 +218,20 @@ public class PushesPanel extends BasePanel {
TreePage.class, WicketUtils.newObjectParameter(push.repository, fullRefName)));
}
- // to/from/etc
- pushItem.add(new Label("repoPreposition", getString(preposition)));
-
- String repoName = StringUtils.stripDotGit(push.repository);
- pushItem.add(new LinkPanel("repoPushed", null, repoName,
- SummaryPage.class, WicketUtils.newRepositoryParameter(push.repository)));
+ if (showRepo) {
+ // to/from/etc
+ pushItem.add(new Label("repoPreposition", getString(preposition)));
+ String repoName = StringUtils.stripDotGit(push.repository);
+ pushItem.add(new LinkPanel("repoPushed", null, repoName,
+ SummaryPage.class, WicketUtils.newRepositoryParameter(push.repository)));
+ } else {
+ // do not display repository name if we are viewing the push
+ // log of a repository.
+ pushItem.add(new Label("repoPreposition").setVisible(false));
+ pushItem.add(new Label("repoPushed").setVisible(false));
+ }
+
int maxCommitCount = 5;
List<RepositoryCommit> commits = push.getCommits();
if (commits.size() > maxCommitCount) {
@@ -213,6 +254,8 @@ public class PushesPanel extends BasePanel {
pushItem.add(new LinkPanel("compareLink", null, compareLinkText, ComparePage.class, WicketUtils.newRangeParameter(push.repository, startRangeId, endRangeId)));
}
+ final boolean showSwatch = showRepo && 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;
@@ -254,15 +297,20 @@ public class PushesPanel extends BasePanel {
WicketUtils.setCssClass(commitHash, "shortsha1");
WicketUtils.setHtmlTooltip(commitHash, commit.getName());
commitItem.add(commitHash);
+
+ if (showSwatch) {
+ // set repository color
+ String color = StringUtils.getColor(StringUtils.stripDotGit(push.repository));
+ WicketUtils.setCssStyle(commitItem, MessageFormat.format("border-left: 2px solid {0};", color));
+ }
}
};
-
+
pushItem.add(commitsView);
}
};
+
add(pushView);
-
-
}
public boolean hasMore() {