mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
Add user home page
This commit is contained in:
parent
081104ae0e
commit
26e934079d
@ -66,6 +66,12 @@
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.imgscalr</groupId>
|
||||
|
||||
@ -37,8 +37,8 @@ import com.pmease.gitop.core.manager.UserManager;
|
||||
import com.pmease.gitop.web.assets.AssetLocator;
|
||||
import com.pmease.gitop.web.component.avatar.AvatarImageResource;
|
||||
import com.pmease.gitop.web.component.avatar.AvatarImageResourceReference;
|
||||
import com.pmease.gitop.web.page.account.AccountHomePage;
|
||||
import com.pmease.gitop.web.page.account.RegisterPage;
|
||||
import com.pmease.gitop.web.page.account.home.AccountHomePage;
|
||||
import com.pmease.gitop.web.page.account.setting.password.AccountPasswordPage;
|
||||
import com.pmease.gitop.web.page.account.setting.permission.AccountPermissionPage;
|
||||
import com.pmease.gitop.web.page.account.setting.permission.AddTeamPage;
|
||||
@ -47,6 +47,7 @@ import com.pmease.gitop.web.page.account.setting.profile.AccountProfilePage;
|
||||
import com.pmease.gitop.web.page.account.setting.repos.AccountReposPage;
|
||||
import com.pmease.gitop.web.page.home.HomePage;
|
||||
import com.pmease.gitop.web.page.init.ServerInitPage;
|
||||
import com.pmease.gitop.web.page.project.CreateProjectPage;
|
||||
import com.pmease.gitop.web.page.project.ProjectHomePage;
|
||||
import com.pmease.gitop.web.page.test.TestPage;
|
||||
import com.pmease.gitop.web.page.test.TestPage2;
|
||||
@ -181,6 +182,9 @@ public class GitopWebApp extends AbstractWicketConfig {
|
||||
mountPage("settings/repos", AccountReposPage.class);
|
||||
mountPage("teams/add", AddTeamPage.class);
|
||||
mountPage("teams/edit/${teamId}", EditTeamPage.class);
|
||||
|
||||
// project related
|
||||
mountPage("new", CreateProjectPage.class);
|
||||
|
||||
mountPage("/test", TestPage.class);
|
||||
mountPage("test2", TestPage2.class);
|
||||
|
||||
@ -194,6 +194,47 @@ a > .icon-null, .icon-null { display: inline-block; width: 10px; }
|
||||
background: #2ba6cb;
|
||||
}
|
||||
|
||||
.btn-gray {
|
||||
color: #333333;
|
||||
background-color: #eaeaea;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
|
||||
.btn-gray:hover,
|
||||
.btn-gray:focus,
|
||||
.btn-gray:active,
|
||||
.btn-gray.active,
|
||||
.open .dropdown-toggle.btn-gray {
|
||||
color: #333333;
|
||||
background-color: #d5d5d5;
|
||||
border-color: #adadad;
|
||||
}
|
||||
|
||||
.btn-gray:active,
|
||||
.btn-gray.active,
|
||||
.open .dropdown-toggle.btn-gray {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.btn-gray.disabled,
|
||||
.btn-gray[disabled],
|
||||
fieldset[disabled] .btn-gray,
|
||||
.btn-gray.disabled:hover,
|
||||
.btn-gray[disabled]:hover,
|
||||
fieldset[disabled] .btn-gray:hover,
|
||||
.btn-gray.disabled:focus,
|
||||
.btn-gray[disabled]:focus,
|
||||
fieldset[disabled] .btn-gray:focus,
|
||||
.btn-gray.disabled:active,
|
||||
.btn-gray[disabled]:active,
|
||||
fieldset[disabled] .btn-gray:active,
|
||||
.btn-gray.disabled.active,
|
||||
.btn-gray[disabled].active,
|
||||
fieldset[disabled] .btn-gray.active {
|
||||
background-color: #eaeaea;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
|
||||
.btn-radio-group .btn .icon-ok { display: none; }
|
||||
.btn-radio-group .btn.active { background: #999; color: white; }
|
||||
.btn-radio-group .btn.active .icon-ok, .btn-radio-group .btn:hover .icon-ok { display: inline-block; }
|
||||
|
||||
@ -51,6 +51,8 @@
|
||||
*/
|
||||
#main { background: white; }
|
||||
|
||||
.padder { padding: 20px; }
|
||||
|
||||
.sidebar .head, .content .head { padding: 15px 20px; white-space: nowrap; overflow: hidden; border-bottom: 1px solid #ddd; margin-bottom: 20px; }
|
||||
.sidebar .head a { color: #666; font-weight:bold; line-height: 24px; }
|
||||
.sidebar .head a:hover { text-decoration: none; color: #09F; }
|
||||
@ -106,8 +108,8 @@ th.wicket_orderUp a, th.wicket_orderDown a { padding-left: 20px; }
|
||||
}
|
||||
|
||||
/* LOGIN PAGE */
|
||||
#register-form, #login-form { padding: 50px 0; width: 500px; margin: 0 auto; }
|
||||
#login-form h1, #register-form h1 { font-size: 32px; margin: 0 0 30px; font-weight: 300; }
|
||||
.small-section, #register-form, #login-form { padding: 50px 0; width: 500px; margin: 0 auto; }
|
||||
.small-section h1, #login-form h1, #register-form h1 { font-size: 32px; margin: 0 0 30px; font-weight: 300; }
|
||||
#login-form .input-group-addon { font-size: 18px; color: #666; }
|
||||
#login-form .user-group .input-group-addon { border-bottom-left-radius: 0; }
|
||||
#login-form .user-group input.form-control { border-bottom-right-radius: 0; }
|
||||
@ -125,7 +127,7 @@ th.wicket_orderUp a, th.wicket_orderDown a { padding-left: 20px; }
|
||||
.members .list-group-item:hover a { color: #333; }
|
||||
.members .item-actions {top: 12px;}
|
||||
.members .item-actions .img-link { color: #ddd; font-size: 20px; }
|
||||
.members .list-group-item:hover .img-link, .members .item-actions .img-link:hover { color: #990000; }
|
||||
.members .list-group-item:hover .remove-link, .members .item-actions .remove-link:hover { color: #990000; }
|
||||
.members .avatar { width: 32px; height: 32px; margin-right: 8px; }
|
||||
|
||||
.permission-link { color: #666; }
|
||||
@ -134,5 +136,63 @@ a.permission-link:hover { color: #333; text-decoration: none; }
|
||||
.user-choice-row .img-thumbnail { float: left; }
|
||||
.user-choice-row p { margin-left: 44px; margin-bottom: 0; }
|
||||
.user-choice-row p.text-muted { font-size: 0.85em; }
|
||||
.select2-container.user-choice .select2-choice { height: 34px; line-height: 34px;}
|
||||
|
||||
.btn-group-permissions > a { width: 80px; }
|
||||
|
||||
.link-item a.confirm-link:hover { color: #990000; }
|
||||
|
||||
/* ACCOUNT HOME */
|
||||
.vcard-column { padding: 20px; }
|
||||
.vcard-column .avatar { width: 200px; height: 200px; margin-bottom: 18px; }
|
||||
.vcard-column .avatar > img { border-radius: 8px; }
|
||||
.vcard-name { margin: 0 0 18px; }
|
||||
.vcard-name b, .vcard-name em { display: block; white-space: nowrap; overflow: hidden; }
|
||||
.vcard-name b { font-size: 26px; }
|
||||
.vcard-name em { font-size: 24px; color: #888; font-style: normal; font-weight: 300; }
|
||||
.vcard-stats { padding: 20px 0; border-top: 1px solid #ddd; overflow: hidden; }
|
||||
.vcard-stats a { display: inline-block; color: #999; font-size: 12px; line-height: 1.123; width: 66px; overflow: hidden; text-align: center; }
|
||||
.vcard-stats a > b { display: block; color: #333; font-size: 28px; }
|
||||
.vcard-stats a:hover { text-decoration: none; color: #09f; }
|
||||
.vcard-stats a:hover > b { color: #09f; }
|
||||
|
||||
.nav-piped > li { float: left; }
|
||||
|
||||
.page-nav { border-bottom: 1px solid #ddd; padding: 10px 20px 0; }
|
||||
.page-nav ul { margin: 0; padding: 0; list-style: none; }
|
||||
|
||||
.page-nav .nav-piped > li > a { color: #999; padding: 12px 15px;}
|
||||
.page-nav .nav-piped > li > a:hover { background: transparent; color: #09f; }
|
||||
.page-nav .nav-piped > li.active > a { color: #333; font-weight: bold; }
|
||||
.page-nav .nav-piped > li.active > a:after{
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
right: 50%;
|
||||
margin-right: -6px;
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 6px solid #333;
|
||||
border-right: 6px solid transparent;
|
||||
border-top: 0 dotted;
|
||||
border-left: 6px solid transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
ul.btn-list { list-style: none; margin: 0; }
|
||||
.btn-list > li { float: left; list-style: none; padding: 0; margin: 0 6px;}
|
||||
.page-nav .btn-list > li { padding: 7px 0; }
|
||||
.page-nav .btn-list .btn { font-weight: bold; }
|
||||
|
||||
.project-list .list-group-item { position: relative; padding-left: 44px; }
|
||||
.project-list .list-group-item i { position: absolute; left: 0; top: 10px; font-size: 32px; width: 32px; color: #bbb; }
|
||||
.project-list h4 { margin: 0 0 9px; }
|
||||
.project-list p { margin: 0 0 6px; font-size: 12px;}
|
||||
.project-list .last-updated { color: #999; }
|
||||
|
||||
ul.members-list { list-style: none; margin: 0; padding: 0; }
|
||||
.members-list > li.member { width: 220px; display: inline-block; list-style: none; padding-left: 60px; margin-right: 18px; margin-bottom: 18px; position: relative; font-size: 18px; white-space: nowrap; overflow: hidden;}
|
||||
.member > .avatar { width: 48px; height: 48px; position: absolute; left: 0; top: 0; }
|
||||
.member > .avatar > img { border-radius: 50%; }
|
||||
.member > h4 { margin-top: 0; }
|
||||
.member > em { font-style: normal; display: block; color: #999; }
|
||||
@ -0,0 +1,5 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:panel>
|
||||
<a wicket:id="link"><span wicket:id="text"></span></a>
|
||||
</wicket:panel>
|
||||
</html>
|
||||
@ -0,0 +1,25 @@
|
||||
package com.pmease.gitop.web.common.component.link;
|
||||
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.link.AbstractLink;
|
||||
import org.apache.wicket.markup.html.panel.Panel;
|
||||
import org.apache.wicket.model.IModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class LinkPanel extends Panel {
|
||||
|
||||
public LinkPanel(String id, IModel<String> label) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
AbstractLink link = createLink("link");
|
||||
add(link);
|
||||
link.add(new Label("text", getDefaultModel()));
|
||||
}
|
||||
|
||||
protected abstract AbstractLink createLink(String id);
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class AbstractDataType implements DataType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern) {
|
||||
return asString(from, pattern, Locale.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString(Object from) {
|
||||
return asString(from, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern) {
|
||||
return fromString(value, pattern, Locale.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value) {
|
||||
return fromString(value, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumericType() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.BigDecimalValidator;
|
||||
|
||||
public abstract class AbstractNumericType extends AbstractDataType {
|
||||
|
||||
@Override
|
||||
public boolean isNumericType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Number toNumber(Object from) {
|
||||
if (from == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (from instanceof Number) {
|
||||
return (Number) from;
|
||||
}
|
||||
|
||||
if (from instanceof String) {
|
||||
String s = (String) from;
|
||||
if ("NaN".equalsIgnoreCase(s)) {
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
return BigDecimalValidator.getInstance().validate(s, null, Locale.getDefault());
|
||||
}
|
||||
|
||||
if (from instanceof Boolean) {
|
||||
return ((Boolean) from) ? 1 : 0;
|
||||
}
|
||||
|
||||
throw new TypeCastException(this, from);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
public class BooleanType extends AbstractDataType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Boolean b = (Boolean) typeCast(from);
|
||||
if (Strings.isNullOrEmpty(pattern)) {
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
String[] tokens = Iterables.toArray(Splitter.on(":").limit(2).omitEmptyStrings().split(pattern), String.class);
|
||||
return b ? tokens[0] : tokens[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
if (Strings.isNullOrEmpty(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(pattern)) {
|
||||
if ("TRUE".equalsIgnoreCase(value)) {
|
||||
return Boolean.TRUE;
|
||||
} else {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
String[] tokens = Iterables.toArray(Splitter.on(":").limit(2).omitEmptyStrings().split(pattern), String.class);
|
||||
if (Objects.equal(value, tokens[0])) {
|
||||
return Boolean.TRUE;
|
||||
} else {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
if (from == null){
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
if (from instanceof Boolean) {
|
||||
return from;
|
||||
}
|
||||
|
||||
if (from instanceof Number) {
|
||||
return ((Number) from).intValue() > 0;
|
||||
}
|
||||
|
||||
if (from instanceof String) {
|
||||
if ("TRUE".equalsIgnoreCase((String) from)) {
|
||||
return Boolean.TRUE;
|
||||
} else {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeCastException(this, from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "BOOLEAN";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.ByteValidator;
|
||||
|
||||
public class ByteType extends AbstractNumericType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Byte b = (Byte) typeCast(from);
|
||||
return ByteValidator.getInstance().format(b, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return ByteValidator.getInstance().validate(value, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
Number number = toNumber(from);
|
||||
return number.byteValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Byte.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "BYTE";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public interface DataType {
|
||||
|
||||
String asString(Object from, String pattern, Locale locale);
|
||||
|
||||
String asString(Object from, String pattern);
|
||||
|
||||
String asString(Object from);
|
||||
|
||||
Object fromString(String value, String pattern, Locale locale);
|
||||
|
||||
Object fromString(String value, String pattern);
|
||||
|
||||
Object fromString(String value);
|
||||
|
||||
Class<?> getReturnClass();
|
||||
|
||||
boolean isNumericType();
|
||||
|
||||
Object typeCast(Object from);
|
||||
|
||||
String getTypeName();
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
public class DataTypes {
|
||||
|
||||
private static enum NULLE {
|
||||
}
|
||||
|
||||
public static final DataType BOOLEAN = new BooleanType();
|
||||
public static final DataType BYTE = new ByteType();
|
||||
public static final DataType SHORT = new ShortType();
|
||||
public static final DataType INTEGER = new IntegerType();
|
||||
public static final DataType LONG = new LongType();
|
||||
public static final DataType FLOAT = new FloatType();
|
||||
public static final DataType DOUBLE = new DoubleType();
|
||||
public static final DataType PERCENT = new PercentType();
|
||||
public static final DataType DATE = new DateType();
|
||||
public static final DataType ENUM = new EnumType(NULLE.class);
|
||||
public static final DataType STRING = new StringType();
|
||||
|
||||
static final DataType[] PRIMITIVES = new DataType[] {
|
||||
BOOLEAN, BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, PERCENT, ENUM, STRING
|
||||
};
|
||||
|
||||
public static DataType getType(Class<?> clazz) {
|
||||
for (DataType each : PRIMITIVES) {
|
||||
if (each.getReturnClass().isAssignableFrom(clazz)) {
|
||||
return each;
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unable to find the data type for class [" + clazz + "]");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.DateValidator;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.ReadableDateTime;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
public class DateType extends AbstractDataType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Date date = (Date) typeCast(from);
|
||||
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(pattern)) {
|
||||
return ISODateTimeFormat.dateTime().withZoneUTC().print(new DateTime(date));
|
||||
}
|
||||
|
||||
return DateValidator.getInstance().format(date, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
if (Strings.isNullOrEmpty(pattern)) {
|
||||
return ISODateTimeFormat.dateTime().withZoneUTC().parseDateTime(value).toDate();
|
||||
}
|
||||
|
||||
return DateValidator.getInstance().validate(value, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Date.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
if (from == null || (from instanceof Date)) {
|
||||
return from;
|
||||
}
|
||||
|
||||
if (from instanceof Long) {
|
||||
return new Date((Long) from);
|
||||
}
|
||||
|
||||
if (from instanceof Calendar) {
|
||||
return new Date(((Calendar) from).getTimeInMillis());
|
||||
}
|
||||
|
||||
if (from instanceof java.sql.Timestamp) {
|
||||
return new Date(((java.sql.Timestamp) from).getTime());
|
||||
}
|
||||
|
||||
if (from instanceof ReadableDateTime) {
|
||||
return ((ReadableDateTime) from).toDateTime().toDate();
|
||||
}
|
||||
|
||||
if (from instanceof String) {
|
||||
DateTime dt = ISODateTimeFormat.dateTime().parseDateTime((String) from);
|
||||
if (dt != null) {
|
||||
return dt.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeCastException(this, from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "DATE";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.DoubleValidator;
|
||||
|
||||
public class DoubleType extends AbstractNumericType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Double d = (Double) typeCast(from);
|
||||
return DoubleValidator.getInstance().format(d, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return DoubleValidator.getInstance().validate(value, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Double.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
return toNumber(from).doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "DOUBLE";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,158 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import org.joda.time.format.ISOPeriodFormat;
|
||||
import org.joda.time.format.PeriodFormatter;
|
||||
import org.joda.time.format.PeriodFormatterBuilder;
|
||||
|
||||
public class DurationFormatUtils {
|
||||
// public static final String ISO8601 = "yyyy-MM-dd'T'HH:mm:ssZ";
|
||||
|
||||
public static PeriodFormatter createPeriodFormatter(String pattern) {
|
||||
PeriodFormatterBuilder builder = new PeriodFormatterBuilder();
|
||||
parsePatternTo(builder, pattern);
|
||||
return builder.toFormatter();
|
||||
}
|
||||
|
||||
private static void parsePatternTo(PeriodFormatterBuilder builder, String pattern) {
|
||||
int length = pattern.length();
|
||||
int[] indexRef = new int[1];
|
||||
|
||||
builder.printZeroAlways();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
indexRef[0] = i;
|
||||
String token = parseToken(pattern, indexRef);
|
||||
i = indexRef[0];
|
||||
|
||||
int tokenLen = token.length();
|
||||
if (tokenLen == 0) {
|
||||
break;
|
||||
}
|
||||
char c = token.charAt(0);
|
||||
|
||||
switch (c) {
|
||||
case 'y': // year (number)
|
||||
builder.appendYears();
|
||||
break;
|
||||
case 'd': // days
|
||||
builder.minimumPrintedDigits(tokenLen);
|
||||
builder.appendDays();
|
||||
break;
|
||||
case 'H': // hours
|
||||
builder.minimumPrintedDigits(tokenLen);
|
||||
builder.appendHours();
|
||||
break;
|
||||
case 'm': // minutes
|
||||
builder.minimumPrintedDigits(tokenLen);
|
||||
builder.appendMinutes();
|
||||
break;
|
||||
case 's': // seconds
|
||||
builder.minimumPrintedDigits(tokenLen);
|
||||
builder.appendSeconds();
|
||||
break;
|
||||
case 'S': // milliseconds
|
||||
builder.minimumPrintedDigits(tokenLen);
|
||||
builder.appendMillis();
|
||||
break;
|
||||
case '\'': // literal text
|
||||
String sub = token.substring(1);
|
||||
builder.appendLiteral(new String(sub));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal pattern component: " + token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an individual token.
|
||||
*
|
||||
* @param pattern the pattern string
|
||||
* @param indexRef a single element array, where the input is the start location and the output is
|
||||
* the location after parsing the token
|
||||
* @return the parsed token
|
||||
*/
|
||||
private static String parseToken(String pattern, int[] indexRef) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
int i = indexRef[0];
|
||||
int length = pattern.length();
|
||||
|
||||
char c = pattern.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
|
||||
// Scan a run of the same character, which indicates a time
|
||||
// pattern.
|
||||
buf.append(c);
|
||||
|
||||
while (i + 1 < length) {
|
||||
char peek = pattern.charAt(i + 1);
|
||||
if (peek == c) {
|
||||
buf.append(c);
|
||||
i++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This will identify token as text.
|
||||
buf.append('\'');
|
||||
|
||||
boolean inLiteral = false;
|
||||
|
||||
for (; i < length; i++) {
|
||||
c = pattern.charAt(i);
|
||||
|
||||
if (c == '\'') {
|
||||
if (i + 1 < length && pattern.charAt(i + 1) == '\'') {
|
||||
// '' is treated as escaped '
|
||||
i++;
|
||||
buf.append(c);
|
||||
} else {
|
||||
inLiteral = !inLiteral;
|
||||
}
|
||||
} else if (!inLiteral && (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
|
||||
i--;
|
||||
break;
|
||||
} else {
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
indexRef[0] = i;
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static PeriodFormatter isoFormatter() {
|
||||
return ISOPeriodFormat.standard();
|
||||
}
|
||||
|
||||
static PeriodFormatter wordFormatter = new PeriodFormatterBuilder().appendYears()
|
||||
.appendSuffix(" year", " years").appendSeparator(" ").appendMonths()
|
||||
.appendSuffix(" month", " months").appendSeparator(" ").appendDays()
|
||||
.appendSuffix(" day", " days").appendSeparator(" ").appendHours()
|
||||
.appendSuffix(" hour", " hours").appendSeparator(" ").appendMinutes()
|
||||
.appendSuffix(" minute", " minutes").appendSeparator(" ").appendSeconds()
|
||||
.appendSuffix(" second", " seconds").appendSeparator(" ").appendMillis3Digit().toFormatter();
|
||||
|
||||
public static PeriodFormatter wordFormatter() {
|
||||
return wordFormatter;
|
||||
}
|
||||
|
||||
static PeriodFormatter shortWordFormatter = new PeriodFormatterBuilder().appendDays()
|
||||
.appendSuffix("d").appendSeparator(", ").appendHours().appendSuffix("h").appendSeparator(":")
|
||||
.appendMinutes().appendSuffix("m").appendSeparator(":").appendSeconds().appendSuffix("s")
|
||||
.appendSeparator(", ").appendMillis().toFormatter();
|
||||
|
||||
public static PeriodFormatter shortWordFormatter() {
|
||||
return shortWordFormatter;
|
||||
}
|
||||
|
||||
static PeriodFormatter timeFormatter = new PeriodFormatterBuilder().printZeroAlways()
|
||||
.appendHours().appendSuffix(":").appendMinutes().appendSuffix(":").appendSeconds()
|
||||
.toFormatter();
|
||||
|
||||
public static PeriodFormatter getTimeFormatter() {
|
||||
return timeFormatter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.BigDecimalValidator;
|
||||
import org.joda.time.DateTimeConstants;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.Period;
|
||||
import org.joda.time.PeriodType;
|
||||
import org.joda.time.chrono.ISOChronology;
|
||||
import org.joda.time.format.PeriodFormatter;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
public class DurationType extends LongType {
|
||||
|
||||
public static final String FMT_WORD = "WORD";
|
||||
public static final String FMT_ISO = "ISO";
|
||||
public static final String FMT_SHORT_WORD = "SHORT";
|
||||
|
||||
@Override
|
||||
public Object fromString(String str, String pattern, Locale locale) {
|
||||
if (Strings.isNullOrEmpty(str)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ("NaN".equalsIgnoreCase(str)) {
|
||||
return new Long(0);
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(pattern)) {
|
||||
try {
|
||||
return Long.valueOf(str);
|
||||
} catch (NumberFormatException e) {
|
||||
Number number = BigDecimalValidator.getInstance().validate(str, locale);
|
||||
if (number != null) {
|
||||
return number.longValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PeriodFormatter formatter = getFormatter(pattern, locale);
|
||||
|
||||
Period period = formatter.parsePeriod(str);
|
||||
return Long.valueOf(period.toStandardDuration().getMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString(Object value, String pattern, Locale locale) {
|
||||
Long mills = (Long) typeCast(value);
|
||||
if (mills == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(pattern)) {
|
||||
return mills.toString();
|
||||
}
|
||||
|
||||
if (mills == 0) {
|
||||
return "0 mil";
|
||||
} else if (mills < DateTimeConstants.MILLIS_PER_SECOND) {
|
||||
return mills + " mils";
|
||||
}
|
||||
|
||||
PeriodFormatter fmt = getFormatter(pattern, locale);
|
||||
Duration duration = new Duration(mills);
|
||||
return fmt.print(duration.toPeriod(PeriodType.yearMonthDayTime(),
|
||||
ISOChronology.getInstanceUTC()));
|
||||
}
|
||||
|
||||
protected PeriodFormatter getFormatter(String pattern, Locale locale) {
|
||||
PeriodFormatter fmt = null;
|
||||
if (FMT_WORD.equalsIgnoreCase(pattern)) {
|
||||
fmt = DurationFormatUtils.wordFormatter();
|
||||
} else if (FMT_ISO.equalsIgnoreCase(pattern)) {
|
||||
fmt = DurationFormatUtils.isoFormatter();
|
||||
} else if (FMT_SHORT_WORD.equalsIgnoreCase(pattern)) {
|
||||
fmt = DurationFormatUtils.shortWordFormatter();
|
||||
} else {
|
||||
fmt = DurationFormatUtils.createPeriodFormatter(pattern);
|
||||
}
|
||||
if (locale != null) {
|
||||
fmt = fmt.withLocale(locale);
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class EnumType extends AbstractDataType {
|
||||
|
||||
private final Class<? extends Enum> enumClass;
|
||||
|
||||
public EnumType(Class<? extends Enum> enumClass) {
|
||||
this.enumClass = enumClass;
|
||||
}
|
||||
|
||||
public static EnumType of(Class<? extends Enum> clazz) {
|
||||
return new EnumType(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Enum<?> e = (Enum<?>) typeCast(from);
|
||||
if (e == null) {
|
||||
return null;
|
||||
} else {
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return Enum.valueOf(enumClass, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Enum.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
if (from == null || from instanceof Enum) {
|
||||
return from;
|
||||
}
|
||||
|
||||
if (from instanceof String) {
|
||||
return fromString((String) from);
|
||||
}
|
||||
|
||||
if (from instanceof Integer) {
|
||||
int i = (Integer) from;
|
||||
return enumClass.getEnumConstants()[i];
|
||||
}
|
||||
|
||||
throw new TypeCastException(this, from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "ENUM";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.FloatValidator;
|
||||
|
||||
public class FloatType extends AbstractNumericType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Float f = (Float) typeCast(from);
|
||||
return FloatValidator.getInstance().format(f, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return FloatValidator.getInstance().validate(value, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Float.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
return toNumber(from).floatValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "FLOAT";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.IntegerValidator;
|
||||
|
||||
public class IntegerType extends AbstractNumericType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Integer i = (Integer) typeCast(from);
|
||||
return IntegerValidator.getInstance().format(i, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return IntegerValidator.getInstance().validate(value, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
return toNumber(from).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "INTEGER";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.LongValidator;
|
||||
|
||||
public class LongType extends AbstractNumericType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Long l = (Long) typeCast(from);
|
||||
return LongValidator.getInstance().format(l, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return LongValidator.getInstance().validate(value, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Long.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
return toNumber(from).longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "LONG";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.PercentValidator;
|
||||
|
||||
public class PercentType extends AbstractNumericType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Double d = (Double) typeCast(from);
|
||||
return PercentValidator.getInstance().format(d, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return PercentValidator.getInstance().validate(value, pattern, locale).doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Double.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
return toNumber(from).doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "PERCENT";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.validator.routines.ShortValidator;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
public class ShortType extends AbstractNumericType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
Short s = (Short) typeCast(from);
|
||||
return ShortValidator.getInstance().format(s, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
if (Strings.isNullOrEmpty(value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ShortValidator.getInstance().validate(value, pattern, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return Short.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
return toNumber(from).shortValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "SHORT";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class StringType extends AbstractDataType {
|
||||
|
||||
@Override
|
||||
public String asString(Object from, String pattern, Locale locale) {
|
||||
if (from == null || (from instanceof String)) {
|
||||
return (String) from;
|
||||
}
|
||||
|
||||
return from.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value, String pattern, Locale locale) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnClass() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object typeCast(Object from) {
|
||||
if (from == null || (from instanceof String)) {
|
||||
return from;
|
||||
}
|
||||
|
||||
return from.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "STRING";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.pmease.gitop.web.common.datatype;
|
||||
|
||||
public class TypeCastException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public TypeCastException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public TypeCastException(DataType dataType, Object value) {
|
||||
this("Cannot cast object [" + value + "] to data type [" + dataType + "]");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.pmease.gitop.web.component.link;
|
||||
|
||||
import org.apache.wicket.markup.html.link.AbstractLink;
|
||||
import org.apache.wicket.model.AbstractReadOnlyModel;
|
||||
import org.apache.wicket.model.IModel;
|
||||
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
import com.pmease.gitop.web.common.component.link.LinkPanel;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
|
||||
public class ProjectHomeLink extends LinkPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final IModel<Project> projectModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public ProjectHomeLink(String id, final IModel<Project> projectModel) {
|
||||
super(id, new AbstractReadOnlyModel<String>() {
|
||||
|
||||
@Override
|
||||
public String getObject() {
|
||||
Project project = projectModel.getObject();
|
||||
return project.getOwner().getName() + " / " + project.getName();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.projectModel = projectModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLink createLink(String id) {
|
||||
return PageSpec.newProjectHomeLink(id, projectModel.getObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
if (projectModel != null) {
|
||||
projectModel.detach();
|
||||
}
|
||||
|
||||
super.onDetach();
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,7 @@ import com.google.common.base.Preconditions;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.web.component.avatar.AvatarImage;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
import com.pmease.gitop.web.page.account.AccountHomePage;
|
||||
import com.pmease.gitop.web.page.account.home.AccountHomePage;
|
||||
import com.pmease.gitop.web.util.WicketUtils;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
</wicket:enclosure>
|
||||
|
||||
<wicket:enclosure child="logoutLink">
|
||||
<li><a href="#" data-toggle="tooltip" title="Create a new repository"><i class="icon-plus icon-fixed-width"></i></a></li>
|
||||
<li><a href="#" data-toggle="tooltip" title="Create a new repository" wicket:id="newlink"><i class="icon-plus icon-fixed-width"></i></a></li>
|
||||
<li><a wicket:id="profileLink" data-toggle="tooltip" title="Account settings"><i class="icon-cog"></i></a></li>
|
||||
<li><a href="#" data-toggle="tooltip" title="Sign out" wicket:id="logoutLink"><i class="icon-signout"></i></a></li>
|
||||
<li class="separator"></li>
|
||||
|
||||
@ -10,6 +10,7 @@ import com.pmease.gitop.web.component.link.UserAvatarLink;
|
||||
import com.pmease.gitop.web.model.UserModel;
|
||||
import com.pmease.gitop.web.page.account.RegisterPage;
|
||||
import com.pmease.gitop.web.page.account.setting.profile.AccountProfilePage;
|
||||
import com.pmease.gitop.web.page.project.CreateProjectPage;
|
||||
import com.pmease.gitop.web.shiro.LoginPage;
|
||||
import com.pmease.gitop.web.shiro.LogoutPage;
|
||||
|
||||
@ -28,6 +29,7 @@ public class GlobalHeaderPanel extends Panel {
|
||||
if (isSignedIn()) {
|
||||
add(new UserAvatarLink("userlink", new UserModel(currentUser().get())));
|
||||
add(new BookmarkablePageLink<Void>("profileLink", AccountProfilePage.class));
|
||||
add(new BookmarkablePageLink<Void>("newlink", CreateProjectPage.class));
|
||||
} else {
|
||||
add(new WebMarkupContainer("userlink").setVisibilityAllowed(false));
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.web.component.avatar.AvatarImage.AvatarImageType;
|
||||
import com.pmease.gitop.web.page.account.AccountHomePage;
|
||||
import com.pmease.gitop.web.page.account.home.AccountHomePage;
|
||||
import com.pmease.gitop.web.page.project.ProjectHomePage;
|
||||
import com.pmease.gitop.web.util.WicketUtils;
|
||||
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
package com.pmease.gitop.web.page.account;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.pmease.gitop.core.Gitop;
|
||||
import com.pmease.gitop.core.manager.UserManager;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.web.model.UserModel;
|
||||
import com.pmease.gitop.web.page.AbstractLayoutPage;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractAccountPage extends AbstractLayoutPage {
|
||||
|
||||
protected final IModel<User> accountModel;
|
||||
|
||||
public AbstractAccountPage(PageParameters params) {
|
||||
String name = params.get(PageSpec.USER).toString();
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(name));
|
||||
|
||||
User user = Gitop.getInstance(UserManager.class).find(name);
|
||||
if (user == null) {
|
||||
throw new EntityNotFoundException("User " + name + " not found");
|
||||
}
|
||||
|
||||
this.accountModel = new UserModel(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
if (accountModel != null) {
|
||||
accountModel.detach();
|
||||
}
|
||||
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
protected User getAccount() {
|
||||
return accountModel.getObject();
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:extend>
|
||||
<h1>Welcome, Account home</h1>
|
||||
<div wicket:id="accountName"></div>
|
||||
<a wicket:id="link">link</a>
|
||||
</wicket:extend>
|
||||
</html>
|
||||
@ -1,78 +0,0 @@
|
||||
package com.pmease.gitop.web.page.account;
|
||||
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.link.Link;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import com.pmease.commons.util.GeneralException;
|
||||
import com.pmease.gitop.core.Gitop;
|
||||
import com.pmease.gitop.core.manager.UserManager;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.web.page.AbstractLayoutPage;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class AccountHomePage extends AbstractLayoutPage {
|
||||
|
||||
private final IModel<User> accountModel;
|
||||
|
||||
public AccountHomePage(PageParameters params) {
|
||||
String accountName = params.get("user").toString();
|
||||
|
||||
User account = Gitop.getInstance(UserManager.class).find(accountName);
|
||||
if (account == null)
|
||||
throw new GeneralException("Account %s does not exist!", accountName);
|
||||
|
||||
final Long accountId = account.getId();
|
||||
|
||||
accountModel = new LoadableDetachableModel<User>() {
|
||||
|
||||
@Override
|
||||
protected User load() {
|
||||
return Gitop.getInstance(UserManager.class).load(accountId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPageInitialize() {
|
||||
super.onPageInitialize();
|
||||
|
||||
add(new Label("accountName", getAccount().getName()));
|
||||
|
||||
add(new Link<Void>("link") {
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPageTitle() {
|
||||
return "Gitop";
|
||||
}
|
||||
|
||||
public User getAccount() {
|
||||
return accountModel.getObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachModels() {
|
||||
if (accountModel != null)
|
||||
accountModel.detach();
|
||||
|
||||
super.detachModels();
|
||||
}
|
||||
|
||||
public static PageParameters paramsOf(User account) {
|
||||
PageParameters params = new PageParameters();
|
||||
params.set("user", account.getName());
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:extend>
|
||||
<div class="faux">
|
||||
<div class="faux-row">
|
||||
<div class="faux-cell sidebar">
|
||||
<div class="sidebar-inner">
|
||||
<div class="vcard-column">
|
||||
<div wicket:id="avatar" class="avatar"></div>
|
||||
<h1 class="vcard-name">
|
||||
<b wicket:id="fullname"></b>
|
||||
<em wicket:id="username"></em>
|
||||
</h1>
|
||||
<div class="vcard-stats">
|
||||
<a href="#"><b>12</b> repos</a>
|
||||
<a href="#"><b>188</b> members</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="faux-cell content">
|
||||
<div class="content-inner">
|
||||
<div class="page-nav clearfix">
|
||||
<ul class="nav nav-piped pull-left">
|
||||
<li wicket:id="category"><a wicket:id="link"><wicket:container wicket:id="name"></wicket:container></a></li>
|
||||
</ul>
|
||||
<ul class="btn-list pull-right">
|
||||
<li><a class="btn btn-sm btn-gray"><i class="icon-pencil"></i> Edit your profile</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="padder">
|
||||
<wicket:container wicket:id="content"></wicket:container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wicket:extend>
|
||||
</html>
|
||||
@ -0,0 +1,96 @@
|
||||
package com.pmease.gitop.web.page.account.home;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.wicket.Component;
|
||||
import org.apache.wicket.behavior.AttributeAppender;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.link.AbstractLink;
|
||||
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
||||
import org.apache.wicket.markup.html.list.ListItem;
|
||||
import org.apache.wicket.markup.html.list.ListView;
|
||||
import org.apache.wicket.model.PropertyModel;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.pmease.gitop.core.permission.ObjectPermission;
|
||||
import com.pmease.gitop.web.component.avatar.AvatarImage;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
import com.pmease.gitop.web.page.account.AbstractAccountPage;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class AccountHomePage extends AbstractAccountPage {
|
||||
|
||||
public static enum Category {
|
||||
PROJECTS("Projects"),
|
||||
MEMBERS("Members");
|
||||
|
||||
final String displayName;
|
||||
Category(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
private Category category = Category.PROJECTS;
|
||||
|
||||
public AccountHomePage(PageParameters params) {
|
||||
super(params);
|
||||
|
||||
String tab = params.get("tab").toString();
|
||||
if (!Strings.isNullOrEmpty(tab)) {
|
||||
category = Category.valueOf(tab.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPageInitialize() {
|
||||
super.onPageInitialize();
|
||||
add(new AvatarImage("avatar", accountModel));
|
||||
add(new Label("fullname", new PropertyModel<String>(accountModel, "displayName")));
|
||||
add(new Label("username", new PropertyModel<String>(accountModel, "name")));
|
||||
|
||||
add(new ListView<Category>("category", Lists.newArrayList(Category.values())) {
|
||||
|
||||
@Override
|
||||
protected void populateItem(ListItem<Category> item) {
|
||||
Category current = item.getModelObject();
|
||||
PageParameters params = PageSpec.forUser(accountModel.getObject());
|
||||
if (current != Category.PROJECTS) {
|
||||
params.add(PageSpec.TAB, current.name().toLowerCase());
|
||||
}
|
||||
|
||||
AbstractLink link = new BookmarkablePageLink<Void>("link",
|
||||
AccountHomePage.class, params);
|
||||
link.add(new Label("name", current.displayName));
|
||||
item.add(link);
|
||||
item.add(AttributeAppender.append("class", category == current ? "active" : ""));
|
||||
}
|
||||
});
|
||||
|
||||
add(createContent("content"));
|
||||
}
|
||||
|
||||
private Component createContent(String id) {
|
||||
switch (category) {
|
||||
case PROJECTS:
|
||||
return new ProjectListPanel(id, accountModel);
|
||||
|
||||
case MEMBERS:
|
||||
return new MemberListPanel(id, accountModel);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("tab " + category);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPermitted() {
|
||||
return SecurityUtils.getSubject().isPermitted(ObjectPermission.ofUserRead(getAccount()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPageTitle() {
|
||||
return getAccount().getName() + " (" + getAccount().getDisplayName() + ")";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:panel>
|
||||
<ul class="members-list">
|
||||
<li class="member" wicket:id="member">
|
||||
<span class="avatar" wicket:id="avatar"></span>
|
||||
<h4><a wicket:id="namelink"><wicket:container wicket:id="name"></wicket:container></a></h4>
|
||||
<em><wicket:container wicket:id="displayname"></wicket:container></em>
|
||||
</li>
|
||||
</ul>
|
||||
</wicket:panel>
|
||||
</html>
|
||||
@ -0,0 +1,79 @@
|
||||
package com.pmease.gitop.web.page.account.home;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.link.AbstractLink;
|
||||
import org.apache.wicket.markup.html.list.ListItem;
|
||||
import org.apache.wicket.markup.html.list.ListView;
|
||||
import org.apache.wicket.markup.html.panel.Panel;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
import org.apache.wicket.model.PropertyModel;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.pmease.gitop.core.model.Membership;
|
||||
import com.pmease.gitop.core.model.Team;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.web.component.avatar.AvatarImage;
|
||||
import com.pmease.gitop.web.model.UserModel;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class MemberListPanel extends Panel {
|
||||
|
||||
public MemberListPanel(String id, IModel<User> model) {
|
||||
super(id, model);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
IModel<List<User>> model = new LoadableDetachableModel<List<User>>() {
|
||||
|
||||
@Override
|
||||
protected List<User> load() {
|
||||
User account = getThisAccount();
|
||||
Collection<Team> teams = account.getTeams();
|
||||
Set<User> users = Sets.newHashSet();
|
||||
|
||||
for (Team each : teams) {
|
||||
for (Membership membership : each.getMemberships()) {
|
||||
users.add(membership.getUser());
|
||||
}
|
||||
}
|
||||
|
||||
List<User> result = Lists.newArrayList(users);
|
||||
Collections.sort(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ListView<User> membersView = new ListView<User>("member", model) {
|
||||
|
||||
@Override
|
||||
protected void populateItem(ListItem<User> item) {
|
||||
User user = item.getModelObject();
|
||||
IModel<User> model = new UserModel(user);
|
||||
item.add(new AvatarImage("avatar", model));
|
||||
AbstractLink link = PageSpec.newUserHomeLink("namelink", user);
|
||||
link.add(new Label("name", new PropertyModel<String>(model, "name")));
|
||||
item.add(link);
|
||||
item.add(new Label("displayname", new PropertyModel<String>(model, "displayName")));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
add(membersView);
|
||||
}
|
||||
|
||||
private User getThisAccount() {
|
||||
return (User) getDefaultModelObject();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:panel>
|
||||
<div class="clearfix">
|
||||
<div class="pull-left">
|
||||
<form class="form-inline form-search">
|
||||
<div class="form-group">
|
||||
<input type="search" class="form-control" placeholder="Find a project ..." />
|
||||
</div>
|
||||
<button class="btn btn-gray">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-info btn-colorful-text"><i class="icon-repo-plus"></i> New</a>
|
||||
</div>
|
||||
</div>
|
||||
<p></p>
|
||||
<ul class="list-group list-view project-list">
|
||||
<li class="list-group-item" wicket:id="project">
|
||||
<i class="icon-repo-book"></i>
|
||||
<h4><a wicket:id="projectlink"><span wicket:id="name"></span></a></h4>
|
||||
<wicket:enclosure>
|
||||
forked from <span wicket:id="forklink"></span>
|
||||
</wicket:enclosure>
|
||||
<p wicket:id="description"></p>
|
||||
<p class="last-updated">Last updated 6 hours ago</p>
|
||||
</li>
|
||||
</ul>
|
||||
</wicket:panel>
|
||||
</html>
|
||||
@ -0,0 +1,76 @@
|
||||
package com.pmease.gitop.web.page.account.home;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.list.ListItem;
|
||||
import org.apache.wicket.markup.html.list.ListView;
|
||||
import org.apache.wicket.markup.html.panel.Panel;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.core.permission.ObjectPermission;
|
||||
import com.pmease.gitop.web.component.link.ProjectHomeLink;
|
||||
import com.pmease.gitop.web.model.ProjectModel;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class ProjectListPanel extends Panel {
|
||||
|
||||
public ProjectListPanel(String id, IModel<User> model) {
|
||||
super(id, model);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
IModel<List<Project>> model = new LoadableDetachableModel<List<Project>>() {
|
||||
|
||||
@Override
|
||||
protected List<Project> load() {
|
||||
User account = getThisAccount();
|
||||
List<Project> projects = Lists.newArrayList();
|
||||
for (Project each : account.getRepositories()) {
|
||||
if (SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(each))) {
|
||||
projects.add(each);
|
||||
}
|
||||
}
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ListView<Project> projectsView = new ListView<Project>("project", model) {
|
||||
|
||||
@Override
|
||||
protected void populateItem(ListItem<Project> item) {
|
||||
Project project = item.getModelObject();
|
||||
// IModel<Project> model = new ProjectModel(project);
|
||||
item.add(PageSpec.newProjectHomeLink("projectlink", project)
|
||||
.add(new Label("name", project.getName())));
|
||||
|
||||
if (project.getForkedFrom() != null) {
|
||||
item.add(new ProjectHomeLink("forklink", new ProjectModel(project.getForkedFrom())));
|
||||
} else {
|
||||
item.add(new WebMarkupContainer("forklink").setVisibilityAllowed(false));
|
||||
}
|
||||
|
||||
item.add(new Label("description", project.getDescription()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
add(projectsView);
|
||||
}
|
||||
|
||||
private User getThisAccount() {
|
||||
return (User) getDefaultModelObject();
|
||||
}
|
||||
}
|
||||
@ -22,7 +22,7 @@
|
||||
<hr/>
|
||||
|
||||
<h4>Teams</h4>
|
||||
<p class="text-muted">Manage teams and grant the permissions so that all members in the team can have the permission to access any repositories under this account.</p>
|
||||
<p class="text-muted">Manage teams and grant the permissions so that all members in the team can have the permissions to access any repositories under this account.</p>
|
||||
<wicket:container wicket:id="teams"></wicket:container>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
(<em wicket:id="fullname"></em>)
|
||||
</a>
|
||||
<div class="item-actions">
|
||||
<a class="img-link" wicket:id="remove"><i class="icon-remove-sign"></i></a>
|
||||
<a class="img-link remove-link" wicket:id="remove"><i class="icon-remove-sign"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:extend>
|
||||
<section>
|
||||
<div class="head">
|
||||
<h2>Repositories</h2>
|
||||
</div>
|
||||
<div class="body">
|
||||
<ul class="list-group list-view list-group-hoverable repos-list">
|
||||
<li class="list-group-item" wicket:id="projects">
|
||||
<div wicket:id="info"></div>
|
||||
<ul class="piped item-actions">
|
||||
<li><a class="first" wicket:id="admin"><i class="icon-cog"></i> Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</wicket:extend>
|
||||
</html>
|
||||
@ -1,6 +1,19 @@
|
||||
package com.pmease.gitop.web.page.account.setting.repos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
||||
import org.apache.wicket.markup.html.list.ListItem;
|
||||
import org.apache.wicket.markup.html.list.ListView;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
import com.pmease.gitop.web.model.ProjectModel;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
import com.pmease.gitop.web.page.account.setting.AccountSettingPage;
|
||||
import com.pmease.gitop.web.page.project.ProjectAdminPage;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class AccountReposPage extends AccountSettingPage {
|
||||
@ -14,4 +27,32 @@ public class AccountReposPage extends AccountSettingPage {
|
||||
protected Category getSettingCategory() {
|
||||
return Category.REPOS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPageInitialize() {
|
||||
super.onPageInitialize();
|
||||
|
||||
IModel<List<Project>> model = new LoadableDetachableModel<List<Project>>() {
|
||||
|
||||
@Override
|
||||
protected List<Project> load() {
|
||||
return Lists.newArrayList(getAccount().getRepositories());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ListView<Project> view = new ListView<Project>("projects", model) {
|
||||
|
||||
@Override
|
||||
protected void populateItem(ListItem<Project> item) {
|
||||
Project project = item.getModelObject();
|
||||
item.add(new SimpleProjectInfo("info", new ProjectModel(project)));
|
||||
item.add(new BookmarkablePageLink<Void>("admin", ProjectAdminPage.class,
|
||||
PageSpec.forProject(project)));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
add(view);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:panel>
|
||||
<a>steve/repo</a>
|
||||
</wicket:panel>
|
||||
</html>
|
||||
@ -0,0 +1,58 @@
|
||||
package com.pmease.gitop.web.page.account.setting.repos;
|
||||
|
||||
import org.apache.wicket.markup.html.panel.Panel;
|
||||
import org.apache.wicket.model.IModel;
|
||||
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
|
||||
public class SimpleProjectInfo extends Panel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SimpleProjectInfo(String id, IModel<Project> model) {
|
||||
super(id, model);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
// add(new UserProjectLink("project", (IModel<Project>) getDefaultModel()));
|
||||
// add(new Label("age", new AbstractReadOnlyModel<String>() {
|
||||
//
|
||||
// @Override
|
||||
// public String getObject() {
|
||||
// return DateUtils.formatAge(getProject().getCreatedAt());
|
||||
// }
|
||||
//
|
||||
// }).add(AttributeModifier.replace("title",
|
||||
// new AbstractReadOnlyModel<String>() {
|
||||
//
|
||||
// @Override
|
||||
// public String getObject() {
|
||||
// return DataTypes.DATE
|
||||
// .asString(getProject().getCreatedAt(),
|
||||
// Constants.DATETIME_FULL_FORMAT);
|
||||
// }
|
||||
//
|
||||
// })));
|
||||
//
|
||||
// if (getProject().isForked()) {
|
||||
// add(new UserProjectLink("forkedFrom",
|
||||
// new LoadableDetachableModel<Project>() {
|
||||
//
|
||||
// @Override
|
||||
// protected Project load() {
|
||||
// return getProject().getParentFork().getForkedFrom();
|
||||
// }
|
||||
// }));
|
||||
// } else {
|
||||
// add(new WebMarkupContainer("forkedFrom")
|
||||
// .setVisibilityAllowed(false));
|
||||
// }
|
||||
}
|
||||
|
||||
protected Project getProject() {
|
||||
return (Project) getDefaultModelObject();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.pmease.gitop.web.page.project;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.pmease.gitop.core.Gitop;
|
||||
import com.pmease.gitop.core.manager.ProjectManager;
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.core.permission.ObjectPermission;
|
||||
import com.pmease.gitop.web.model.ProjectModel;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
import com.pmease.gitop.web.page.account.AbstractAccountPage;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractProjectPage extends AbstractAccountPage {
|
||||
|
||||
protected IModel<Project> projectModel;
|
||||
|
||||
public AbstractProjectPage(PageParameters params) {
|
||||
super(params);
|
||||
|
||||
String projectName = params.get(PageSpec.PROJECT).toString();
|
||||
Preconditions.checkNotNull(projectName);
|
||||
|
||||
User user = accountModel.getObject();
|
||||
Project project = Gitop.getInstance(ProjectManager.class).find(
|
||||
user, projectName);
|
||||
|
||||
if (project == null) {
|
||||
throw new EntityNotFoundException("Unable to find project "
|
||||
+ user.getName() + " / " + projectName);
|
||||
}
|
||||
|
||||
projectModel = new ProjectModel(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPermitted() {
|
||||
return SecurityUtils.getSubject().isPermitted(
|
||||
ObjectPermission.ofProjectRead(projectModel.getObject()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:extend>
|
||||
<div class="small-section">
|
||||
<h1>Create Project</h1>
|
||||
|
||||
<form wicket:id="form">
|
||||
<div wicket:id="feedback" class="form-feedback"></div>
|
||||
<div wicket:id="name"></div>
|
||||
<div wicket:id="description"></div>
|
||||
<hr/>
|
||||
<div wicket:id="public"></div>
|
||||
<hr />
|
||||
<button class="btn btn-info" wicket:id="submit">Create project</button>
|
||||
</form>
|
||||
</div>
|
||||
</wicket:extend>
|
||||
</html>
|
||||
@ -0,0 +1,88 @@
|
||||
package com.pmease.gitop.web.page.project;
|
||||
|
||||
import org.apache.shiro.authz.annotation.RequiresUser;
|
||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
|
||||
import org.apache.wicket.bean.validation.PropertyValidator;
|
||||
import org.apache.wicket.markup.html.form.Form;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.Model;
|
||||
import org.apache.wicket.model.PropertyModel;
|
||||
import org.apache.wicket.validation.IValidatable;
|
||||
import org.apache.wicket.validation.IValidator;
|
||||
import org.apache.wicket.validation.ValidationError;
|
||||
|
||||
import com.pmease.gitop.core.Gitop;
|
||||
import com.pmease.gitop.core.manager.ProjectManager;
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
import com.pmease.gitop.core.model.User;
|
||||
import com.pmease.gitop.web.common.form.FeedbackPanel;
|
||||
import com.pmease.gitop.web.common.form.flatcheckbox.FlatCheckBoxElement;
|
||||
import com.pmease.gitop.web.common.form.textfield.TextFieldElement;
|
||||
import com.pmease.gitop.web.model.ProjectModel;
|
||||
import com.pmease.gitop.web.page.AbstractLayoutPage;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@RequiresUser
|
||||
public class CreateProjectPage extends AbstractLayoutPage {
|
||||
|
||||
@Override
|
||||
protected String getPageTitle() {
|
||||
return "Create a new project";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPageInitialize() {
|
||||
super.onPageInitialize();
|
||||
|
||||
final IModel<Project> projectModel = new ProjectModel(new Project());
|
||||
Form<Project> form = new Form<Project>("form", projectModel);
|
||||
add(form);
|
||||
|
||||
form.add(new FeedbackPanel("feedback"));
|
||||
form.add(new TextFieldElement<String>("name", "Project Name",
|
||||
new PropertyModel<String>(projectModel, "name"))
|
||||
.add(new PropertyValidator<String>())
|
||||
.add(new IValidator<String>() {
|
||||
|
||||
@Override
|
||||
public void validate(IValidatable<String> validatable) {
|
||||
String name = validatable.getValue();
|
||||
User owner = User.getCurrent();
|
||||
|
||||
for (Project each : owner.getRepositories()) {
|
||||
if (each.getName().equalsIgnoreCase(name)) {
|
||||
validatable.error(new ValidationError().setMessage("This project already exists"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
form.add(new TextFieldElement<String>("description", "Description",
|
||||
new PropertyModel<String>(projectModel, "description"))
|
||||
.add(new PropertyValidator<String>())
|
||||
.setRequired(false));
|
||||
|
||||
form.add(new FlatCheckBoxElement("public", "Public Accessible",
|
||||
new PropertyModel<Boolean>(projectModel, "publiclyAccessible"),
|
||||
Model.of("Anyone can browse and pull this repository")));
|
||||
|
||||
form.add(new AjaxButton("submit", form) {
|
||||
@Override
|
||||
protected void onError(AjaxRequestTarget target, Form<?> form) {
|
||||
target.add(form);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
|
||||
Project project = projectModel.getObject();
|
||||
project.setOwner(User.getCurrent());
|
||||
Gitop.getInstance(ProjectManager.class).save(project);
|
||||
setResponsePage(ProjectHomePage.class, PageSpec.forProject(project));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
<html xmlns:wicket>
|
||||
<wicket:extend>
|
||||
<h1>Project Administration</h1>
|
||||
</wicket:extend>
|
||||
</html>
|
||||
@ -0,0 +1,13 @@
|
||||
package com.pmease.gitop.web.page.project;
|
||||
|
||||
import com.pmease.gitop.web.page.AbstractLayoutPage;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class ProjectAdminPage extends AbstractLayoutPage {
|
||||
|
||||
@Override
|
||||
protected String getPageTitle() {
|
||||
return "Administration - {Project}";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package com.pmease.gitop.web.page.project;
|
||||
|
||||
import org.apache.shiro.authz.annotation.RequiresAuthentication;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
@ -10,10 +10,11 @@ import com.pmease.commons.util.GeneralException;
|
||||
import com.pmease.gitop.core.Gitop;
|
||||
import com.pmease.gitop.core.manager.ProjectManager;
|
||||
import com.pmease.gitop.core.model.Project;
|
||||
import com.pmease.gitop.core.permission.ObjectPermission;
|
||||
import com.pmease.gitop.web.page.AbstractLayoutPage;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@RequiresAuthentication
|
||||
public class ProjectHomePage extends AbstractLayoutPage {
|
||||
|
||||
private final IModel<Project> projectModel;
|
||||
@ -24,8 +25,8 @@ public class ProjectHomePage extends AbstractLayoutPage {
|
||||
}
|
||||
|
||||
public ProjectHomePage(PageParameters params) {
|
||||
String userName = params.get("user").toString();
|
||||
String projectName = params.get("project").toString();
|
||||
String userName = params.get(PageSpec.USER).toString();
|
||||
String projectName = params.get(PageSpec.PROJECT).toString();
|
||||
|
||||
if (projectName.endsWith(".git"))
|
||||
projectName = projectName.substring(0, projectName.length() - ".git".length());
|
||||
@ -47,6 +48,11 @@ public class ProjectHomePage extends AbstractLayoutPage {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPermitted() {
|
||||
return SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(getProject()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPageInitialize() {
|
||||
super.onPageInitialize();
|
||||
@ -65,13 +71,4 @@ public class ProjectHomePage extends AbstractLayoutPage {
|
||||
projectModel.detach();
|
||||
super.detachModels();
|
||||
}
|
||||
|
||||
public static PageParameters paramsOf(Project project) {
|
||||
PageParameters params = new PageParameters();
|
||||
params.set("user", project.getOwner().getName());
|
||||
params.set("project", project.getName());
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import com.pmease.gitop.web.common.form.checkbox.CheckBoxElement;
|
||||
import com.pmease.gitop.web.common.form.flatcheckbox.FlatCheckBoxElement;
|
||||
import com.pmease.gitop.web.page.AbstractLayoutPage;
|
||||
import com.pmease.gitop.web.page.PageSpec;
|
||||
import com.pmease.gitop.web.page.account.AccountHomePage;
|
||||
import com.pmease.gitop.web.page.account.home.AccountHomePage;
|
||||
import com.pmease.gitop.web.util.WicketUtils;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
158
gitop.web/src/main/java/com/pmease/gitop/web/util/DateUtils.java
Normal file
158
gitop.web/src/main/java/com/pmease/gitop/web/util/DateUtils.java
Normal file
@ -0,0 +1,158 @@
|
||||
package com.pmease.gitop.web.util;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.time.DurationFormatUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeConstants;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.Hours;
|
||||
import org.joda.time.Period;
|
||||
import org.joda.time.PeriodType;
|
||||
import org.joda.time.chrono.ISOChronology;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.PeriodFormatter;
|
||||
import org.joda.time.format.PeriodFormatterBuilder;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.pmease.gitop.web.Constants;
|
||||
|
||||
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
|
||||
|
||||
public static final String AGE = "age";
|
||||
|
||||
static enum DurationUnit {
|
||||
year, month, week, day, hour, minute, second
|
||||
}
|
||||
|
||||
static String formatAge(DateTime dtBefore, DateTime dtNow) {
|
||||
return formatAge(dtBefore, dtNow, Constants.DATETIME_FORMAT);
|
||||
}
|
||||
|
||||
static String formatAge(DateTime dtBefore, DateTime dtNow,
|
||||
String fullDateFormat) {
|
||||
Preconditions.checkArgument(dtBefore != null && dtNow != null);
|
||||
|
||||
Period period = new Period(dtBefore, dtNow);
|
||||
|
||||
int years = period.getYears();
|
||||
int months = period.getMonths();
|
||||
int weeks = period.getWeeks();
|
||||
int days = Days.daysBetween(dtBefore.toDateMidnight(),
|
||||
dtNow.toDateMidnight()).getDays();
|
||||
|
||||
if (years > 0 || months > 0 || weeks > 0 || days > 6) {
|
||||
return DateUtils.formatDate(dtBefore.toDate(), fullDateFormat);
|
||||
}
|
||||
|
||||
if (days > 1) {
|
||||
return formatDurationPart(days, DurationUnit.day);
|
||||
}
|
||||
|
||||
// acutal hours
|
||||
int hours = Hours.hoursBetween(
|
||||
dtBefore.hourOfDay().roundHalfFloorCopy(),
|
||||
dtNow.hourOfDay().roundHalfFloorCopy()).getHours();
|
||||
|
||||
if ((hours >= DateTimeConstants.HOURS_PER_DAY)
|
||||
|| (days == 1 && hours > 12)) {
|
||||
return formatDurationPart(days, DurationUnit.day);
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
return formatDurationPart(hours, DurationUnit.hour);
|
||||
}
|
||||
|
||||
int minutes = period.getMinutes();
|
||||
if (minutes > 0) {
|
||||
return formatDurationPart(minutes, DurationUnit.minute);
|
||||
}
|
||||
return formatDurationPart(period.getSeconds(), DurationUnit.second);
|
||||
}
|
||||
|
||||
private static String formatDurationPart(int dur, DurationUnit unit) {
|
||||
if (unit == DurationUnit.second && dur < 5) { // < 30 seconds
|
||||
return "just now";
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("about ").append(dur).append(" ").append(unit);
|
||||
;
|
||||
if (dur > 1) {
|
||||
sb.append("s");
|
||||
}
|
||||
sb.append(" ago");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String formatAge(Date date) {
|
||||
return formatAge(new DateTime(date), DateTime.now());
|
||||
}
|
||||
|
||||
public static String formatDate(Date date) {
|
||||
return formatDate(date, Constants.DATE_FORMAT);
|
||||
}
|
||||
|
||||
public static String formatDateTime(Date date) {
|
||||
return formatDate(date, Constants.DATETIME_FORMAT);
|
||||
}
|
||||
|
||||
public static String formatDate(Date date, String pattern) {
|
||||
return DateTimeFormat.forPattern(pattern)
|
||||
.withZone(DateTimeZone.UTC)
|
||||
.print(new DateTime(date));
|
||||
}
|
||||
|
||||
public static String formatDuration(long durationMillis) {
|
||||
if (durationMillis < 1000) {
|
||||
return durationMillis + " ms";
|
||||
} else {
|
||||
return DurationFormatUtils.formatDurationWords(durationMillis,
|
||||
true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatDurationShortWords(long durationMills) {
|
||||
if (durationMills < DateTimeConstants.MILLIS_PER_SECOND) {
|
||||
return durationMills + " ms";
|
||||
} else {
|
||||
Duration duration = new Duration(durationMills);
|
||||
return shortWordFormatter.print(duration.toPeriod(
|
||||
PeriodType.yearMonthDayTime(),
|
||||
ISOChronology.getInstanceUTC()));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] argv) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.YEAR, 2012);
|
||||
cal.set(Calendar.MONTH, 9); // Oct.
|
||||
cal.set(Calendar.DAY_OF_MONTH, 21);
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.setTimeZone(DateTimeZone.forID("America/Sao_Paulo").toTimeZone());
|
||||
DateTime dt = new DateTime(cal);
|
||||
try {
|
||||
dt.withMillisOfDay(0);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Illegal instant due to time zone offset transition
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println(dt.toDateMidnight());
|
||||
}
|
||||
|
||||
static PeriodFormatter shortWordFormatter = new PeriodFormatterBuilder()
|
||||
.appendDays().appendSuffix("d").appendSeparator(", ").appendHours()
|
||||
.appendSuffix("h").appendSeparator(":").appendMinutes()
|
||||
.appendSuffix("m").appendSeparator(":").appendSeconds()
|
||||
.appendSuffix("s")
|
||||
// .appendSeparator(", ")
|
||||
// .appendMillis()
|
||||
.toFormatter();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user