This commit is contained in:
robin shine 2013-10-14 11:11:17 +08:00
commit 89c6f438a8
41 changed files with 2235 additions and 352 deletions

View File

@ -72,7 +72,7 @@ public class DefaultGeneralDao implements GeneralDao, Serializable {
return null;
}
return (Class<T>) entityClass;
return entityClass;
}
@Sessional
@ -99,7 +99,7 @@ public class DefaultGeneralDao implements GeneralDao, Serializable {
public <T extends AbstractEntity> int count(DetachedCriteria detachedCriteria) {
Criteria criteria = detachedCriteria.getExecutableCriteria(getSession());
criteria.setProjection(Projections.rowCount());
return (Integer) criteria.uniqueResult();
return ((Long) criteria.uniqueResult()).intValue();
}
public Object writeReplace() throws ObjectStreamException {

View File

@ -36,7 +36,13 @@
<version>1.0.29</version>
</dependency>
<!-- JERSEY CLIENT -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.17.1</version>
</dependency>
<!-- WICKET -->
<dependency>
<groupId>com.vaynberg.wicket.select2</groupId>
@ -66,7 +72,7 @@
<artifactId>imgscalr-lib</artifactId>
<version>4.2</version>
</dependency>
<dependency>
<groupId>com.pmease</groupId>
<artifactId>commons.jetty</artifactId>

View File

@ -12,9 +12,11 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.Application;
import org.apache.wicket.Page;
import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.Session;
import org.apache.wicket.bean.validation.BeanValidationConfiguration;
import org.apache.wicket.core.request.mapper.MountedMapper;
import org.apache.wicket.devutils.stateless.StatelessChecker;
import org.apache.wicket.markup.html.IPackageResourceGuard;
import org.apache.wicket.markup.html.SecurePackageResourceGuard;
import org.apache.wicket.request.IRequestMapper;
@ -39,6 +41,8 @@ import com.pmease.gitop.web.page.account.AccountHomePage;
import com.pmease.gitop.web.page.account.RegisterPage;
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;
import com.pmease.gitop.web.page.account.setting.permission.EditTeamPage;
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;
@ -102,15 +106,17 @@ public class GitopWebApp extends AbstractWicketConfig {
loadDefaultUserAvatarData();
new ShiroWicketPlugin().mountLoginPage("login", LoginPage.class)
.mountLogoutPage("logout", LogoutPage.class).install(this);
new ShiroWicketPlugin()
.mountLoginPage("login", LoginPage.class)
.mountLogoutPage("logout", LogoutPage.class)
.install(this);
mountPages();
configureResources();
// if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT) {
// getComponentPreOnBeforeRenderListeners().add(new StatelessChecker());
// }
if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT) {
getComponentPreOnBeforeRenderListeners().add(new StatelessChecker());
}
}
public byte[] getDefaultUserAvatar() {
@ -173,6 +179,8 @@ public class GitopWebApp extends AbstractWicketConfig {
mountPage("settings/password", AccountPasswordPage.class);
mountPage("settings/permission", AccountPermissionPage.class);
mountPage("settings/repos", AccountReposPage.class);
mountPage("teams/add", AddTeamPage.class);
mountPage("teams/edit/${teamId}", EditTeamPage.class);
mountPage("/test", TestPage.class);
mountPage("test2", TestPage2.class);

View File

@ -2,10 +2,13 @@ package com.pmease.gitop.web;
import javax.inject.Singleton;
import com.pmease.commons.jersey.JerseyConfigurator;
import com.pmease.commons.jersey.JerseyEnvironment;
import com.pmease.commons.jetty.ServletConfigurator;
import com.pmease.commons.loader.AbstractPluginModule;
import com.pmease.commons.wicket.AbstractWicketConfig;
import com.pmease.gitop.core.validation.UserNameReservation;
import com.pmease.gitop.web.resource.TestResource;
/**
* NOTE: Do not forget to rename moduleClass property defined in the pom if you've renamed this class.
@ -23,6 +26,15 @@ public class WebModule extends AbstractPluginModule {
contribute(ServletConfigurator.class, WebServletConfigurator.class);
contribute(UserNameReservation.class, WebUserNameReservation.class);
contribute(JerseyConfigurator.class, new JerseyConfigurator() {
@Override
public void configure(JerseyEnvironment environment) {
environment.addComponentFromPackage(TestResource.class);
}
});
}
}

View File

@ -38,11 +38,32 @@ ul.disc { list-style:disc outside; }
.piped:after { clear: both; }
ul.piped, ol.piped { margin: 0; padding: 0; }
.action-links { white-space: nowrap; }
.action-links > .link-item { display: inline-block; margin-left: 12px; }
.action-links > .link-item:first-child { margin-left: 0;}
/* LINKS */
.checkable-link { color: #333; cursor: pointer; }
.checkable-link:hover { text-decoration: none; }
.checkable-link > .icon-checkbox:before { content: "\f096"; width: 16px; }
.checkable-link.checked > .icon-checkbox:before { content: "\f046"; width: 16px; }
.checkable-link.disabled { color: #888; }
em.checkable-link { color: #888 !important; }
/** LIST GROUP */
.list-navs > .list-group-item { border-width: 1px 0; }
.list-navs > .list-group-item { border-width: 1px 0; positioin: relative; }
.list-navs > .list-group-item:first-child,
.list-navs > .list-group-item:last-child { border-radius: 0; }
.list-group.list-group-hoverable .list-group-item:hover { background: #ffe; }
.list-group-item .item-actions { position: absolute; right: 30px; top: 10px; }
.list-group-item .item-actions a { color: #999; }
.list-group-item .item-actions a:hover { color: #333; text-decoration: none; }
.list-view .list-group-item { border-left: none; border-right: none; position: relative; }
.list-view .list-group-item:first-child,
.list-view .list-group-item:last-child { border-radius: 0; }
/* ADDITIONAL ICONS */
@font-face {
@ -173,23 +194,32 @@ a > .icon-null, .icon-null { display: inline-block; width: 10px; }
background: #2ba6cb;
}
.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; }
/**
* TABLE
*/
.table { width: 100%; }
.norecords-tr .norecords-td { background: #F9F7ED; font-size: 1.5em; line-height: 3em; font-weight: bold; text-align: center; }
.table th a { color: #333; text-decoration: underline; }
.operations-td a { color: #999; }
.operations-td a:hover { color: #333; }
.table .operations-td { white-space: nowrap; }
.operations-td a, .operations-td a.iconlink { color: #999; }
.operations-td a:hover { color: #333; text-decoration: none; }
.search-nav-td { font-size: 11px; }
.search-nav-td form { position: relative; }
.search-nav-td input.form-control, .search-nav-td select.form-control { padding: 2px 4px; height: 24px; }
.search-nav-td .btn { padding: 2px 8px; height: 24px; }
.form-inline.navigation-form select.form-control { width: 60px; }
.form-inline.navigation-form input.form-control { width: 40px; }
.form-inline.navigation-form .btn-group { margin-left: 6px; }
.search-form button { position: absolute; right: 2px; top: 1px; border: none; height: 22px; background: transparent; color: #888; }
/**
* FORM COMPONENT
*/
/* FORM COMPONENT */
.select2-container .select2-choice { padding-top: 4px; padding-bottom: 4px; height: auto; }
.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-highlighted .user-choice-row p.text-muted { color: #ccc; }
.required { color: #a00; margin-left: 3px;}
@ -247,65 +277,13 @@ a > .icon-null, .icon-null { display: inline-block; width: 10px; }
transition: all 0.2s ease-in-out;
}
.avatar.img-thumbnail { padding: 1px; }
.avatar > img { display: block; margin: 0 auto; width: 100%; height: 100%; border-radius: 3px; }
.avatar-circle { border-radius: 50%; }
.avatar-circle > img { border-radius: 50%; }
.avatar-big { width: 32px; height: 32px; }
.avatar-xlarge { width: 128px; height: 128px; }
/**
* LAYOUT
*/
#globalheader, #main, #globalfooter {position: relative;}
#globalheader:before, #globalheader:after, #main:before, #main:after, #globalfooter:before, #globalfooter:after {
display: table;
content: " ";
}
#globalheader:after, #main:after, #globalfooter:after { clear: both; }
/**
* GLOBAL HEADER
*/
#globalheader .navbar { border-width: 0 0 1px 0; border-color: #ddd; border-radius: 0; margin: 0;
background: #f0f2f4; color: white;
}
#globalheader .navbar-brand { padding: 10px 10px 10px 20px; }
#globalheader .search-form { margin-top: 12px; margin-bottom: 0;}
.search-form input.text-field {
height: 30px;
width: 200px;
line-height: normal;
text-indent: 0;
position: relative;
padding: 3px 30px 3px 8px;
font-size: 12px;
-webkit-transition: width 200ms, background 200ms ease; transition: width 200ms, background 200ms ease;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAEJWlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XpShal6dgqJJQ6N4mpmxjb6baqT3uBNwb8AUDZAw9IPCGNX2J72fYA2qSpoIpqEtIeOvFDiEl7QVX4rp3YDoqYo15/Pec753zn3GubqO+zkmkaUYVope5YhUxSOX1mUenboig9Sf00RP0lzTYT+fwc4RJccQ9dEaIHPxFWottjPfwhak/YX+a2RhR5BN5G2dZWgM8RxQzNtByi+F3YJ886JnDfU8CPWxAIrApc9XBK4CUPn3Y5xcI0OEKrrNVKZeB14NGlkL0awp4GMJAnw+vc0jVFzCJvNSq6wV2HtzzEHWL+H1wxmujZvYaxDtjL8ydwHxG916yZQht/rJXS88DPwX7DdJLC/gLw783lhQTwAaLoYxXr+ILHj768Viu+DrwH9rLuZItt+1p9KXcSGLHRjeXGCZFHcG5o9jRmSc8A36nxrNhj6JGozFNp4FHg4Vpzpp1fmrVX54XdzbNWm84BI49kvVWazQMPAb9rNQqiFjRLG9zIiFrIL10znXxbg7RTN3KiFvplMrfdHpFT2nFqxRkvlh12rGI7li1W9OPZNn/dNNyzCG3sktUsCG3Iz26VrHQGGHnY37y+IOYGHNtbLqXEbMeBj9GpSIk4NWgJq0Z12iWFCpShJO4mWfBUSCcDFg4vh0WPPErLsPXm5V2OFxMwqm70johGld4cr8K9NqfBBpnKDuHvCJtjR9kkmyKFvcJeZcdYCtYpdsRXkA/pVKhK96DUy/M2NVFZ6DhFyYtDzRE/RrlgvalrN9/7C2qCLhuBH3n8jqG5EZ4A2ZhAp7ux8Jyur3+71/com+zyG7cHrq/TyYfNN3Y3thPbxLoV2w7iY7/EtvHbogR2wHAVrUCV7u6E7fPGunq4CqZDJay/gteA1o7Srh2t1C8OBR4xCf5O7kGOLowGVvVn9Q91U/1EvaT+1lUjyNg1JelD6UvpO+kr6WvpB1KkK9JV6XvpmvSF9I2fs/fee1n8vXf7FTbRrdiFTr3wrDkZclLeJz8rp+Sn5eflOZ+lyIPyhDwj74dnn79vRuDv6kWnM5hVZ6q9a4knQKcFKNHpLLgWpiomXKfzyBp+TtpK2TCbYNn/nNpJcZY7KuLpeCqeICV+ID4Vn4jPCtx58uL74ZvCmvbVe0+Oz+jqgIdYmIqfZ8w9deKsiuhV6Dagmzv8HL4dRNMN87ylV2uOclBVX1IS+JRxJVvXxkeVkmEorstWLG5za5WXx0l8B0Uc0f2C+32L7LkZ2JzXiI7+iXfWrcC22CT63CYafDGwjeCd+MRHRJcPa01r1ctHkciPRHbl0EH3/8hAEu+mO63Wfbyv+j4g2n2/1fpno9Xa/RT5t4muGP8CYGVxecXFpEEAAAEiSURBVCgVhZG9SsRAFIVnkhBwSZ7AYGUXlDSCrYVYaCFKirBZCfgOamvrGySdkGwKEQRXO7XQxiKFINjrvsB2QoT4jThhENELh7nnnHvm5kd2XSeKohh4nncghBiBAEzRT9u2Pcmy7B3elx2G4ZzjODcoQynlA5jQu5z7tm2vNU0zjqLoQyccbjmErDKwkyTJhTbKsty1LOvMdV3lH2vdohkxfGkOKzNN03P0a9o9xXWpQMDzvmjBPNGf4AumpgJTEJmi0S/TvxlcWKwtEdbrut42DfUO8E2g/L5knucD3/dvWb9CeML5jLsEtgCSfOQrbsRxPFMpyYD+D0fwIZgHr2D8zRfN0FcA49eqqipg+A6zD/0ZULf8CN3/GzBCV2ybfQLGkGWtzcDkHAAAAABJRU5ErkJggg==') white no-repeat 180px 8px;
}
.search-form input.text-field:focus { width: 300px; background: white; }
#globalheader .tooltip { white-space: nowrap; }
#globalheader .navbar-right { margin-right: 20px; }
#globalheader .user-links { margin: 0; }
.user-links > li { margin: 0; }
.user-links > li.separator { height: 50px; border-left: 1px solid #d5d5d5; border-right: 1px solid #fefefe; margin: 0 6px;}
.user-links a { padding: 16px 10px 5px; line-height: 20px; }
.user-links a > i { font-size: 16px; }
.user-links a:hover { color: #333; text-decoration: none; }
.user-links li .caret { border-top-color: #09f; }
.user-links li a:hover .caret { border-top-color: #333; }
.user-links > li.avatar-user { white-space: nowrap; }
.user-links > li.avatar-user .avatar { margin-right: 3px; }
/**
* GLOBAL FOOTER
*/
#globalfooter { padding: 20px; border-top: 1px solid #ddd; font-size: 11.9px; }
/**
* MAIN
*/
#main { background: white; }
/** FAUX ROW */
.faux { display: table; width: 100%; border-collapse: collapse; table-layout: fixed; border-spacing: 0; }
.faux-row { display: table-row; }
@ -314,24 +292,3 @@ a > .icon-null, .icon-null { display: inline-block; width: 10px; }
.sidebar-inner { position: relative; width: 240px; overflow-x: hidden; }
.faux .content { }
.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; }
.sidebar .list-navs > .list-group-item,
.sidebar .list-navs > .list-group-item.active {
padding: 0; margin: 0; border-top-width: 0; background: transparent;
}
.sidebar .list-navs > .list-group-item.active { border-color: #ccc; }
.sidebar .list-navs > .list-group-item:first-child { border-top-width: 1px; }
.sidebar .list-navs > .list-group-item a { padding: 10px 20px; display: block; color: #888; }
.sidebar .list-navs > .list-group-item a:hover { color: #333; text-decoration: none; background: #f2f2f2; }
.sidebar .list-navs > .list-group-item.active a,
.sidebar .list-navs > .list-group-item.active a:hover { color: #222; background: #e5e5e5; font-weight: bold; }
section .head { border-style: solid; border-width: 1px 0; border-color: #ddd; }
section:first-child .head { border-top: none; }
section .head h2, section .head h3 { margin: 0; font-size: 18px; line-height: 24px; color: #888; font-weight: 300; }
section .padder, section > .body { padding: 0px 20px 20px; margin-bottom: 18px; }

View File

@ -1,3 +1,100 @@
/**
* LAYOUT
*/
#globalheader, #main, #globalfooter {position: relative;}
#globalheader:before, #globalheader:after, #main:before, #main:after, #globalfooter:before, #globalfooter:after {
display: table;
content: " ";
}
#globalheader:after, #main:after, #globalfooter:after { clear: both; }
/**
* GLOBAL HEADER
*/
#globalheader .navbar { border-width: 0 0 1px 0; border-color: #ddd; border-radius: 0; margin: 0;
background: #f0f2f4; color: white;
}
#globalheader .navbar-brand { padding: 10px 10px 10px 20px; }
#globalheader .search-form { margin-top: 12px; margin-bottom: 0;}
.search-form input.text-field {
height: 30px;
width: 200px;
line-height: normal;
text-indent: 0;
position: relative;
padding: 3px 30px 3px 8px;
font-size: 12px;
-webkit-transition: width 200ms, background 200ms ease; transition: width 200ms, background 200ms ease;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAEJWlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XpShal6dgqJJQ6N4mpmxjb6baqT3uBNwb8AUDZAw9IPCGNX2J72fYA2qSpoIpqEtIeOvFDiEl7QVX4rp3YDoqYo15/Pec753zn3GubqO+zkmkaUYVope5YhUxSOX1mUenboig9Sf00RP0lzTYT+fwc4RJccQ9dEaIHPxFWottjPfwhak/YX+a2RhR5BN5G2dZWgM8RxQzNtByi+F3YJ886JnDfU8CPWxAIrApc9XBK4CUPn3Y5xcI0OEKrrNVKZeB14NGlkL0awp4GMJAnw+vc0jVFzCJvNSq6wV2HtzzEHWL+H1wxmujZvYaxDtjL8ydwHxG916yZQht/rJXS88DPwX7DdJLC/gLw783lhQTwAaLoYxXr+ILHj768Viu+DrwH9rLuZItt+1p9KXcSGLHRjeXGCZFHcG5o9jRmSc8A36nxrNhj6JGozFNp4FHg4Vpzpp1fmrVX54XdzbNWm84BI49kvVWazQMPAb9rNQqiFjRLG9zIiFrIL10znXxbg7RTN3KiFvplMrfdHpFT2nFqxRkvlh12rGI7li1W9OPZNn/dNNyzCG3sktUsCG3Iz26VrHQGGHnY37y+IOYGHNtbLqXEbMeBj9GpSIk4NWgJq0Z12iWFCpShJO4mWfBUSCcDFg4vh0WPPErLsPXm5V2OFxMwqm70johGld4cr8K9NqfBBpnKDuHvCJtjR9kkmyKFvcJeZcdYCtYpdsRXkA/pVKhK96DUy/M2NVFZ6DhFyYtDzRE/RrlgvalrN9/7C2qCLhuBH3n8jqG5EZ4A2ZhAp7ux8Jyur3+71/com+zyG7cHrq/TyYfNN3Y3thPbxLoV2w7iY7/EtvHbogR2wHAVrUCV7u6E7fPGunq4CqZDJay/gteA1o7Srh2t1C8OBR4xCf5O7kGOLowGVvVn9Q91U/1EvaT+1lUjyNg1JelD6UvpO+kr6WvpB1KkK9JV6XvpmvSF9I2fs/fee1n8vXf7FTbRrdiFTr3wrDkZclLeJz8rp+Sn5eflOZ+lyIPyhDwj74dnn79vRuDv6kWnM5hVZ6q9a4knQKcFKNHpLLgWpiomXKfzyBp+TtpK2TCbYNn/nNpJcZY7KuLpeCqeICV+ID4Vn4jPCtx58uL74ZvCmvbVe0+Oz+jqgIdYmIqfZ8w9deKsiuhV6Dagmzv8HL4dRNMN87ylV2uOclBVX1IS+JRxJVvXxkeVkmEorstWLG5za5WXx0l8B0Uc0f2C+32L7LkZ2JzXiI7+iXfWrcC22CT63CYafDGwjeCd+MRHRJcPa01r1ctHkciPRHbl0EH3/8hAEu+mO63Wfbyv+j4g2n2/1fpno9Xa/RT5t4muGP8CYGVxecXFpEEAAAEiSURBVCgVhZG9SsRAFIVnkhBwSZ7AYGUXlDSCrYVYaCFKirBZCfgOamvrGySdkGwKEQRXO7XQxiKFINjrvsB2QoT4jThhENELh7nnnHvm5kd2XSeKohh4nncghBiBAEzRT9u2Pcmy7B3elx2G4ZzjODcoQynlA5jQu5z7tm2vNU0zjqLoQyccbjmErDKwkyTJhTbKsty1LOvMdV3lH2vdohkxfGkOKzNN03P0a9o9xXWpQMDzvmjBPNGf4AumpgJTEJmi0S/TvxlcWKwtEdbrut42DfUO8E2g/L5knucD3/dvWb9CeML5jLsEtgCSfOQrbsRxPFMpyYD+D0fwIZgHr2D8zRfN0FcA49eqqipg+A6zD/0ZULf8CN3/GzBCV2ybfQLGkGWtzcDkHAAAAABJRU5ErkJggg==') white no-repeat 180px 8px;
}
.search-form input.text-field:focus { width: 300px; background: white; }
#globalheader .tooltip { white-space: nowrap; }
#globalheader .navbar-right { margin-right: 20px; }
#globalheader .user-links { margin: 0; }
.user-links > li { margin: 0; }
.user-links > li.separator { height: 50px; border-left: 1px solid #d5d5d5; border-right: 1px solid #fefefe; margin: 0 6px;}
.user-links a { padding: 16px 10px 5px; line-height: 20px; }
.user-links a > i { font-size: 16px; }
.user-links a:hover { color: #333; text-decoration: none; }
.user-links li .caret { border-top-color: #09f; }
.user-links li a:hover .caret { border-top-color: #333; }
.user-links > li.avatar-user { white-space: nowrap; }
.user-links > li.avatar-user .avatar { margin-right: 3px; }
/**
* GLOBAL FOOTER
*/
#globalfooter { padding: 20px; border-top: 1px solid #ddd; font-size: 11.9px; }
/**
* MAIN
*/
#main { background: white; }
.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; }
.sidebar .list-navs > .list-group-item,
.sidebar .list-navs > .list-group-item.active {
padding: 0; margin: 0; border-top-width: 0; background: transparent;
}
.sidebar .list-navs > .list-group-item.active { border-color: #ccc; }
.sidebar .list-navs > .list-group-item:first-child { border-top-width: 1px; }
.sidebar .list-navs > .list-group-item a { padding: 10px 20px; display: block; color: #888; }
.sidebar .list-navs > .list-group-item a:hover { color: #333; text-decoration: none; background: #f2f2f2; }
.sidebar .list-navs > .list-group-item.active a,
.sidebar .list-navs > .list-group-item.active a:hover { color: #222; background: #e5e5e5; font-weight: bold; }
section .head { border-style: solid; border-width: 1px 0; border-color: #ddd; }
section:first-child .head { border-top: none; }
section .head h2, section .head h3 { margin: 0; font-size: 18px; line-height: 24px; color: #888; font-weight: 300; }
section .padder, section > .body { padding: 0px 20px 20px; margin-bottom: 18px; }
/** TABLE */
th.wicket_orderUp, th.wicket_orderDown, th.wicket_orderNone { position: relative; }
.wicket_orderUp:before, .wicket_orderDown:before, .wicket_orderNone:before {
font-family: pmease-icons;
font-weight: normal;
font-style: normal;
-webkit-font-smoothing: antialiased;
*margin-right: .3em;
text-decoration: none;
display: inline-block;
speak: none;
position: absolute;
left: 5px;
top: 5px;
color: #666;
}
th.wicket_orderUp a, th.wicket_orderDown a { padding-left: 20px; }
.wicket_orderUp:before { content: "\f062"; }
.wicket_orderDown:before { content: "\f063"; }
/** SERVER INIT PAGE */
.server-init {
text-align: center;
width: 50%;
@ -20,28 +117,22 @@
#login-form .btn { width: 100%;}
#dropzone {
background: white;
width: 150px;
height: 50px;
line-height: 50px;
text-align: center;
font-weight: bold;
}
#dropzone.in {
width: 600px;
height: 200px;
line-height: 200px;
font-size: larger;
}
#dropzone.hover {
background: lawngreen;
}
#dropzone.fade {
-webkit-transition: all 0.3s ease-out;
-moz-transition: all 0.3s ease-out;
-ms-transition: all 0.3s ease-out;
-o-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
opacity: 1;
}
/* TEAM EDIT PAGE */
.member-list .members { width: 48%; }
.member-list .members.first { float: left; }
.member-list .members.last { float: right; }
.members a { color: #999; font-size: 16px; }
.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 .avatar { width: 32px; height: 32px; margin-right: 8px; }
.permission-link { color: #666; }
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; }
.btn-group-permissions > a { width: 80px; }

View File

@ -0,0 +1,5 @@
<html xmlns:wicket>
<wicket:panel>
<a wicket:id="link" class="iconlink"><i wicket:id="icon"></i> <span wicket:id="label"></span></a>
</wicket:panel>
</html>

View File

@ -0,0 +1,51 @@
package com.pmease.gitop.web.common.bootstrap;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
public abstract class AjaxIconLink extends Panel {
private static final long serialVersionUID = 1L;
private final IModel<IconType> iconModel;
private final IModel<String> labelModel;
public AjaxIconLink(String id, IModel<IconType> iconModel) {
this(id, iconModel, Model.of(""));
}
public AjaxIconLink(String id, IModel<IconType> iconModel,
IModel<String> labelModel) {
super(id);
this.iconModel = iconModel;
this.labelModel = labelModel;
}
@Override
protected void onInitialize() {
super.onInitialize();
AjaxLink<?> link = createLink("link");
add(link);
link.add(new Icon("icon", iconModel));
link.add(new Label("label", labelModel));
}
@Override
protected void onDetach() {
super.onDetach();
if (iconModel != null) {
iconModel.detach();
}
if (labelModel != null) {
labelModel.detach();
}
}
abstract protected AjaxLink<?> createLink(String id);
}

View File

@ -0,0 +1,29 @@
package com.pmease.gitop.web.common.bootstrap;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
public class Icon extends WebMarkupContainer {
private static final long serialVersionUID = 1L;
public Icon(String id, final IconType type) {
super(id);
add(type.newCssClassNameModifier());
}
@SuppressWarnings("serial")
public Icon(String id, final IModel<IconType> type) {
super(id);
add(AttributeAppender.append("class",
new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return type.getObject().cssClassName();
}
}));
}
}

View File

@ -0,0 +1,400 @@
package com.pmease.gitop.web.common.bootstrap;
import org.apache.wicket.behavior.AttributeAppender;
public enum IconType {
NULL("icon-null"),
ADJUST("icon-adjust"),
ANCHOR("icon-anchor"),
ARCHIVE("icon-archive"),
ASTERISK("icon-asterisk"),
BAN_CIRCLE("icon-ban-circle"),
BAR_CHART("icon-bar-chart"),
BARCODE("icon-barcode"),
BEAKER("icon-beaker"),
BEER("icon-beer"),
BELL("icon-bell"),
BELL_ALT("icon-bell-alt"),
BOLT("icon-bolt"),
BOOK("icon-book"),
BOOKMARK("icon-bookmark"),
BOOKMARK_EMPTY("icon-bookmark-empty"),
BRIEFCASE("icon-briefcase"),
BUG("icon-bug"),
BUILDING("icon-building"),
BULLHORN("icon-bullhorn"),
BULLSEYE("icon-bullseye"),
CALENDAR("icon-calendar"),
CALENDAR_EMPTY("icon-calendar-empty"),
CAMERA("icon-camera"),
CAMERA_RETRO("icon-camera-retro"),
CERTIFICATE("icon-certificate"),
CHECK("icon-check"),
CHECK_EMPTY("icon-check-empty"),
CHECK_MINUS("icon-check-minus"),
CHECK_SIGN("icon-check-sign"),
CIRCLE("icon-circle"),
CIRCLE_BLANK("icon-circle-blank"),
CLOUD("icon-cloud"),
CLOUD_DOWNLOAD("icon-cloud-download"),
CLOUD_UPLOAD("icon-cloud-upload"),
CODE("icon-code"),
CODE_FORK("icon-code-fork"),
COFFEE("icon-coffee"),
COG("icon-cog"),
COGS("icon-cogs"),
COLLAPSE("icon-collapse"),
COLLAPSE_ALT("icon-collapse-alt"),
COLLAPSE_TOP("icon-collapse-top"),
COMMENT("icon-comment"),
COMMENT_ALT("icon-comment-alt"),
COMMENTS("icon-comments"),
COMMENTS_ALT("icon-comments-alt"),
COMPASS("icon-compass"),
CREDIT_CARD("icon-credit-card"),
CROP("icon-crop"),
DASHBOARD("icon-dashboard"),
DESKTOP("icon-desktop"),
DOWNLOAD("icon-download"),
DOWNLOAD_ALT("icon-download-alt"),
EDIT("icon-edit"),
EDIT_SIGN("icon-edit-sign"),
ELLIPSIS_HORIZONTAL("icon-ellipsis-horizontal"),
ELLIPSIS_VERTICAL("icon-ellipsis-vertical"),
ENVELOPE("icon-envelope"),
ENVELOPE_ALT("icon-envelope-alt"),
ERASER("icon-eraser"),
EXCHANGE("icon-exchange"),
EXCLAMATION("icon-exclamation"),
EXCLAMATION_SIGN("icon-exclamation-sign"),
EXPAND("icon-expand"),
EXPAND_ALT("icon-expand-alt"),
EXTERNAL_LINK("icon-external-link"),
EXTERNAL_LINK_SIGN("icon-external-link-sign"),
EYE_CLOSE("icon-eye-close"),
EYE_OPEN("icon-eye-open"),
FACETIME_VIDEO("icon-facetime-video"),
FEMALE("icon-female"),
FIGHTER_JET("icon-fighter-jet"),
FILM("icon-film"),
FILTER("icon-filter"),
FIRE("icon-fire"),
FIRE_EXTINGUISHER("icon-fire-extinguisher"),
FLAG("icon-flag"),
FLAG_ALT("icon-flag-alt"),
FLAG_CHECKERED("icon-flag-checkered"),
FOLDER_CLOSE("icon-folder-close"),
FOLDER_CLOSE_ALT("icon-folder-close-alt"),
FOLDER_OPEN("icon-folder-open"),
FOLDER_OPEN_ALT("icon-folder-open-alt"),
FOOD("icon-food"),
FROWN("icon-frown"),
GAMEPAD("icon-gamepad"),
GEAR("icon-gear"),
GEARS("icon-gears"),
GIFT("icon-gift"),
GLASS("icon-glass"),
GLOBE("icon-globe"),
GROUP("icon-group"),
HDD("icon-hdd"),
HEADPHONES("icon-headphones"),
HEART("icon-heart"),
HEART_EMPTY("icon-heart-empty"),
HOME("icon-home"),
INBOX("icon-inbox"),
INFO("icon-info"),
INFO_SIGN("icon-info-sign"),
KEY("icon-key"),
KEYBOARD("icon-keyboard"),
LAPTOP("icon-laptop"),
LEAF("icon-leaf"),
LEGAL("icon-legal"),
LEMON("icon-lemon"),
LEVEL_DOWN("icon-level-down"),
LEVEL_UP("icon-level-up"),
LIGHTBULB("icon-lightbulb"),
LOCATION_ARROW("icon-location-arrow"),
LOCK("icon-lock"),
MAGIC("icon-magic"),
MAGNET("icon-magnet"),
MAIL_FORWARD("icon-mail-forward"),
MAIL_REPLY("icon-mail-reply"),
MAIL_REPLY_ALL("icon-mail-reply-all"),
MALE("icon-male"),
MAP_MARKER("icon-map-marker"),
MEH("icon-meh"),
MICROPHONE("icon-microphone"),
MICROPHONE_OFF("icon-microphone-off"),
MINUS("icon-minus"),
MINUS_SIGN("icon-minus-sign"),
MINUS_SIGN_ALT("icon-minus-sign-alt"),
MOBILE_PHONE("icon-mobile-phone"),
MONEY("icon-money"),
MOON("icon-moon"),
MOVE("icon-move"),
MUSIC("icon-music"),
OFF("icon-off"),
OK("icon-ok"),
OK_CIRCLE("icon-ok-circle"),
OK_SIGN("icon-ok-sign"),
PENCIL("icon-pencil"),
PHONE("icon-phone"),
PHONE_SIGN("icon-phone-sign"),
PICTURE("icon-picture"),
PLANE("icon-plane"),
PLUS("icon-plus"),
PLUS_SIGN("icon-plus-sign"),
PLUS_SIGN_ALT("icon-plus-sign-alt"),
POWER_OFF("icon-power-off"),
PRINT("icon-print"),
PUSHPIN("icon-pushpin"),
PUZZLE_PIECE("icon-puzzle-piece"),
QRCODE("icon-qrcode"),
QUESTION("icon-question"),
QUESTION_SIGN("icon-question-sign"),
QUOTE_LEFT("icon-quote-left"),
QUOTE_RIGHT("icon-quote-right"),
RANDOM("icon-random"),
REFRESH("icon-refresh"),
REMOVE("icon-remove"),
REMOVE_CIRCLE("icon-remove-circle"),
REMOVE_SIGN("icon-remove-sign"),
REORDER("icon-reorder"),
REPLY("icon-reply"),
REPLY_ALL("icon-reply-all"),
RESIZE_HORIZONTAL("icon-resize-horizontal"),
RESIZE_VERTICAL("icon-resize-vertical"),
RETWEET("icon-retweet"),
ROAD("icon-road"),
ROCKET("icon-rocket"),
RSS("icon-rss"),
RSS_SIGN("icon-rss-sign"),
SCREENSHOT("icon-screenshot"),
SEARCH("icon-search"),
SHARE("icon-share"),
SHARE_ALT("icon-share-alt"),
SHARE_SIGN("icon-share-sign"),
SHIELD("icon-shield"),
SHOPPING_CART("icon-shopping-cart"),
SIGN_BLANK("icon-sign-blank"),
SIGNAL("icon-signal"),
SIGNIN("icon-signin"),
SIGNOUT("icon-signout"),
SITEMAP("icon-sitemap"),
SMILE("icon-smile"),
SORT("icon-sort"),
SORT_BY_ALPHABET("icon-sort-by-alphabet"),
SORT_BY_ALPHABET_ALT("icon-sort-by-alphabet-alt"),
SORT_BY_ATTRIBUTES("icon-sort-by-attributes"),
SORT_BY_ATTRIBUTES_ALT("icon-sort-by-attributes-alt"),
SORT_BY_ORDER("icon-sort-by-order"),
SORT_BY_ORDER_ALT("icon-sort-by-order-alt"),
SORT_DOWN("icon-sort-down"),
SORT_UP("icon-sort-up"),
SPINNER("icon-spinner"),
STAR("icon-star"),
STAR_EMPTY("icon-star-empty"),
STAR_HALF("icon-star-half"),
STAR_HALF_EMPTY("icon-star-half-empty"),
STAR_HALF_FULL("icon-star-half-full"),
SUBSCRIPT("icon-subscript"),
SUITCASE("icon-suitcase"),
SUN("icon-sun"),
SUPERSCRIPT("icon-superscript"),
TABLET("icon-tablet"),
TAG("icon-tag"),
TAGS("icon-tags"),
TASKS("icon-tasks"),
TERMINAL("icon-terminal"),
THUMBS_DOWN("icon-thumbs-down"),
THUMBS_DOWN_ALT("icon-thumbs-down-alt"),
THUMBS_UP("icon-thumbs-up"),
THUMBS_UP_ALT("icon-thumbs-up-alt"),
TICKET("icon-ticket"),
TIME("icon-time"),
TINT("icon-tint"),
TRASH("icon-trash"),
TROPHY("icon-trophy"),
TRUCK("icon-truck"),
UMBRELLA("icon-umbrella"),
UNCHECKED("icon-unchecked"),
UNLOCK("icon-unlock"),
UNLOCK_ALT("icon-unlock-alt"),
UPLOAD("icon-upload"),
UPLOAD_ALT("icon-upload-alt"),
USER("icon-user"),
VOLUME_DOWN("icon-volume-down"),
VOLUME_OFF("icon-volume-off"),
VOLUME_UP("icon-volume-up"),
WARNING_SIGN("icon-warning-sign"),
WRENCH("icon-wrench"),
ZOOM_IN("icon-zoom-in"),
ZOOM_OUT("icon-zoom-out"),
BITCOIN("icon-bitcoin"),
BTC("icon-btc"),
CNY("icon-cny"),
DOLLAR("icon-dollar"),
EUR("icon-eur"),
EURO("icon-euro"),
GBP("icon-gbp"),
INR("icon-inr"),
JPY("icon-jpy"),
KRW("icon-krw"),
RENMINBI("icon-renminbi"),
RUPEE("icon-rupee"),
USD("icon-usd"),
WON("icon-won"),
YEN("icon-yen"),
ALIGN_CENTER("icon-align-center"),
ALIGN_JUSTIFY("icon-align-justify"),
ALIGN_LEFT("icon-align-left"),
ALIGN_RIGHT("icon-align-right"),
BOLD("icon-bold"),
COLUMNS("icon-columns"),
COPY("icon-copy"),
CUT("icon-cut"),
FILE("icon-file"),
FILE_ALT("icon-file-alt"),
FILE_TEXT("icon-file-text"),
FILE_TEXT_ALT("icon-file-text-alt"),
FONT("icon-font"),
INDENT_LEFT("icon-indent-left"),
INDENT_RIGHT("icon-indent-right"),
ITALIC("icon-italic"),
LINK("icon-link"),
LIST("icon-list"),
LIST_ALT("icon-list-alt"),
LIST_OL("icon-list-ol"),
LIST_UL("icon-list-ul"),
PAPER_CLIP("icon-paper-clip"),
PAPERCLIP("icon-paperclip"),
PASTE("icon-paste"),
REPEAT("icon-repeat"),
ROTATE_LEFT("icon-rotate-left"),
ROTATE_RIGHT("icon-rotate-right"),
SAVE("icon-save"),
STRIKETHROUGH("icon-strikethrough"),
TABLE("icon-table"),
TEXT_HEIGHT("icon-text-height"),
TEXT_WIDTH("icon-text-width"),
TH("icon-th"),
TH_LARGE("icon-th-large"),
TH_LIST("icon-th-list"),
UNDERLINE("icon-underline"),
UNDO("icon-undo"),
UNLINK("icon-unlink"),
ANGLE_DOWN("icon-angle-down"),
ANGLE_LEFT("icon-angle-left"),
ANGLE_RIGHT("icon-angle-right"),
ANGLE_UP("icon-angle-up"),
ARROW_DOWN("icon-arrow-down"),
ARROW_LEFT("icon-arrow-left"),
ARROW_RIGHT("icon-arrow-right"),
ARROW_UP("icon-arrow-up"),
CARET_DOWN("icon-caret-down"),
CARET_LEFT("icon-caret-left"),
CARET_RIGHT("icon-caret-right"),
CARET_UP("icon-caret-up"),
CHEVRON_DOWN("icon-chevron-down"),
CHEVRON_LEFT("icon-chevron-left"),
CHEVRON_RIGHT("icon-chevron-right"),
CHEVRON_SIGN_DOWN("icon-chevron-sign-down"),
CHEVRON_SIGN_LEFT("icon-chevron-sign-left"),
CHEVRON_SIGN_RIGHT("icon-chevron-sign-right"),
CHEVRON_SIGN_UP("icon-chevron-sign-up"),
CHEVRON_UP("icon-chevron-up"),
CIRCLE_ARROW_DOWN("icon-circle-arrow-down"),
CIRCLE_ARROW_LEFT("icon-circle-arrow-left"),
CIRCLE_ARROW_RIGHT("icon-circle-arrow-right"),
CIRCLE_ARROW_UP("icon-circle-arrow-up"),
DOUBLE_ANGLE_DOWN("icon-double-angle-down"),
DOUBLE_ANGLE_LEFT("icon-double-angle-left"),
DOUBLE_ANGLE_RIGHT("icon-double-angle-right"),
DOUBLE_ANGLE_UP("icon-double-angle-up"),
HAND_DOWN("icon-hand-down"),
HAND_LEFT("icon-hand-left"),
HAND_RIGHT("icon-hand-right"),
HAND_UP("icon-hand-up"),
LONG_ARROW_DOWN("icon-long-arrow-down"),
LONG_ARROW_LEFT("icon-long-arrow-left"),
LONG_ARROW_RIGHT("icon-long-arrow-right"),
LONG_ARROW_UP("icon-long-arrow-up"),
BACKWARD("icon-backward"),
EJECT("icon-eject"),
FAST_BACKWARD("icon-fast-backward"),
FAST_FORWARD("icon-fast-forward"),
FORWARD("icon-forward"),
FULLSCREEN("icon-fullscreen"),
PAUSE("icon-pause"),
PLAY("icon-play"),
PLAY_CIRCLE("icon-play-circle"),
PLAY_SIGN("icon-play-sign"),
RESIZE_FULL("icon-resize-full"),
RESIZE_SMALL("icon-resize-small"),
STEP_BACKWARD("icon-step-backward"),
STEP_FORWARD("icon-step-forward"),
STOP("icon-stop"),
YOUTUBE_PLAY("icon-youtube-play"),
ADN("icon-adn"),
ANDROID("icon-android"),
APPLE("icon-apple"),
BITBUCKET("icon-bitbucket"),
BITBUCKET_SIGN("icon-bitbucket-sign"),
CSS3("icon-css3"),
DRIBBBLE("icon-dribbble"),
DROPBOX("icon-dropbox"),
FACEBOOK("icon-facebook"),
FACEBOOK_SIGN("icon-facebook-sign"),
FLICKR("icon-flickr"),
FOURSQUARE("icon-foursquare"),
GITHUB("icon-github"),
GITHUB_ALT("icon-github-alt"),
GITHUB_SIGN("icon-github-sign"),
GITTIP("icon-gittip"),
GOOGLE_PLUS("icon-google-plus"),
GOOGLE_PLUS_SIGN("icon-google-plus-sign"),
HTML5("icon-html5"),
INSTAGRAM("icon-instagram"),
LINKEDIN("icon-linkedin"),
LINKEDIN_SIGN("icon-linkedin-sign"),
LINUX("icon-linux"),
MAXCDN("icon-maxcdn"),
PINTEREST("icon-pinterest"),
PINTEREST_SIGN("icon-pinterest-sign"),
RENREN("icon-renren"),
SKYPE("icon-skype"),
STACKEXCHANGE("icon-stackexchange"),
TRELLO("icon-trello"),
TUMBLR("icon-tumblr"),
TUMBLR_SIGN("icon-tumblr-sign"),
TWITTER("icon-twitter"),
TWITTER_SIGN("icon-twitter-sign"),
VK("icon-vk"),
WEIBO("icon-weibo"),
WINDOWS("icon-windows"),
XING("icon-xing"),
XING_SIGN("icon-xing-sign"),
YOUTUBE("icon-youtube"),
YOUTUBE_SIGN("icon-youtube-sign"),
AMBULANCE("icon-ambulance"),
H_SIGN("icon-h-sign"),
HOSPITAL("icon-hospital"),
MEDKIT("icon-medkit"),
STETHOSCOPE("icon-stethoscope"),
USER_MD("icon-user-md");
private final String cssClassName;
IconType(String cssClassName) {
this.cssClassName = cssClassName;
}
public String cssClassName() {
return cssClassName;
}
public AttributeAppender newCssClassNameModifier() {
return AttributeAppender.append("class", cssClassName());
}
}

View File

@ -28,15 +28,15 @@ public abstract class HibernateDataProvider<T extends AbstractEntity> extends So
public Iterator<? extends T> iterator(long first, long count) {
GeneralDao dao = getDao();
DetachedCriteria criteria = getCriteria();
SortParam<String> param = getSort();
if (param != null) {
DetachedCriteria crit = getCriteria();
Iterable<String> it = Splitter.on(",").trimResults().split(param.getProperty());
for (String each : it) {
if (param.isAscending())
crit.addOrder(Order.asc(each));
criteria.addOrder(Order.asc(each));
else
crit.addOrder(Order.desc(each));
criteria.addOrder(Order.desc(each));
}
}

View File

@ -28,205 +28,217 @@ import com.pmease.gitop.web.common.component.datagrid.event.SearchStringChanged;
public class SearchNavToolbar extends AbstractToolbar {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
public SearchNavToolbar(DataTable<?, ?> table) {
super(table);
public SearchNavToolbar(DataTable<?, ?> table) {
super(table);
setOutputMarkupId(true);
}
setOutputMarkupId(true);
}
@Override
protected void onInitialize() {
super.onInitialize();
@Override
protected void onInitialize() {
super.onInitialize();
WebMarkupContainer span = new WebMarkupContainer("td");
add(span);
span.add(AttributeModifier.replace("colspan", new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
WebMarkupContainer span = new WebMarkupContainer("td");
add(span);
span.add(AttributeModifier.replace("colspan",
new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
return String.valueOf(getTable().getColumns().size());
}
}));
@Override
public String getObject() {
return String.valueOf(getTable().getColumns().size());
}
}));
span.add(newSearchForm("search"));
span.add(newNavigationForm("nav"));
}
span.add(newSearchForm("search"));
span.add(newNavigationForm("nav"));
}
@Override
protected void onConfigure() {
super.onConfigure();
this.setVisibilityAllowed(getTable().getRowCount() > 0);
}
protected Component newSearchForm(String id) {
Fragment frag = new Fragment(id, "searchFrag", this);
frag.add(new SearchForm("searchForm"));
return frag;
}
@SuppressWarnings({"serial"})
private class SearchForm extends Form<Void> {
@Override
protected void onConfigure() {
super.onConfigure();
private String pattern;
public SearchForm(String id) {
super(id);
}
@Override
protected void onInitialize() {
super.onInitialize();
TextField<String> input = new TextField<String>("input", new PropertyModel<String>(this, "pattern"));
add(input);
IndicatingAjaxButton submit = new IndicatingAjaxButton("submit", this) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
send(getTable(), Broadcast.BREADTH, new SearchStringChanged(target, pattern));
}
};
add(submit);
setDefaultButton(submit);
}
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof SearchStringChanged) {
SearchStringChanged e = (SearchStringChanged) event.getPayload();
this.pattern = e.getPattern();
e.getTarget().add(this);
}
}
}
this.setVisibilityAllowed(getTable().getRowCount() > 0);
}
protected void onPageChanged(AjaxRequestTarget target) {
target.add(getTable());
target.add(this);
}
protected Component newNavigationForm(String id) {
Fragment frag = new Fragment(id, "navFrag", this);
frag.add(new NavigationForm("form"));
return frag;
}
protected Component newSearchForm(String id) {
Fragment frag = new Fragment(id, "searchFrag", this);
frag.add(new SearchForm("searchForm"));
return frag;
}
static final List<Integer> ROWS_PER_PAGE = ImmutableList.<Integer>of(10, 25, 50, 100, 250, 500);
@SuppressWarnings({"serial"})
private class NavigationForm extends Form<Void> {
private int rowsPerPage = 10;
private int currentPage = 1;
public NavigationForm(String id) {
super(id);
}
@Override
protected void onInitialize() {
super.onInitialize();
DropDownChoice<Integer> rowsSelector = new DropDownChoice<Integer>("rowsSelector",
new PropertyModel<Integer>(this, "rowsPerPage"), ROWS_PER_PAGE);
add(rowsSelector);
rowsSelector.add(new AjaxFormComponentUpdatingBehavior("onchange") {
@SuppressWarnings({ "serial" })
private class SearchForm extends Form<Void> {
@Override
protected void onUpdate(AjaxRequestTarget target) {
currentPage = 1;
getTable().setItemsPerPage(rowsPerPage);
send(getTable(), Broadcast.BREADTH, new PageChanged(target, currentPage - 1));
}
});
add(new AjaxLink<Void>("previousLink") {
private String pattern;
@Override
public void onClick(AjaxRequestTarget target) {
long current = getTable().getCurrentPage();
if (current == 0) {
return;
}
current--;
if (current < 0) {
current = 0;
}
send(getTable(), Broadcast.BREADTH, new PageChanged(target, (int) current));
}
});
add(new AjaxLink<Void>("nextLink") {
public SearchForm(String id) {
super(id);
}
@Override
public void onClick(AjaxRequestTarget target) {
long current = getTable().getCurrentPage();
long totals = getTable().getPageCount();
if (current == totals) {
return;
}
current++;
if (current >= totals) {
current = totals - 1;
}
send(getTable(), Broadcast.BREADTH, new PageChanged(target, (int) current));
}
});
add(new TextField<Integer>("pageInput", new PropertyModel<Integer>(this, "currentPage")));
AjaxButton btn = new AjaxButton("submit", this) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if (currentPage == getTable().getCurrentPage() + 1) {
return;
}
long totals = getTable().getPageCount();
currentPage = Math.min(currentPage, (int) totals);
currentPage = Math.max(currentPage, 0);
send(getTable(), Broadcast.BREADTH, new PageChanged(target, currentPage - 1));
}
@Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
target.add(form);
}
};
add(btn);
setDefaultButton(btn);
add(new Label("navlabel", new AbstractReadOnlyModel<String>() {
@Override
protected void onInitialize() {
super.onInitialize();
@Override
public String getObject() {
long totals = getTable().getRowCount();
long items = getTable().getItemsPerPage();
long start = (currentPage - 1) * items + 1;
long end = start + items - 1;
end = Math.min(end, totals);
return start + " - " + end + " of " + totals;
}
}));
}
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof PageChanged) {
PageChanged e = (PageChanged) event.getPayload();
currentPage = e.getPage() + 1;
rowsPerPage = (int) getTable().getItemsPerPage();
e.getTarget().add(this);
}
}
}
TextField<String> input = new TextField<String>("input",
new PropertyModel<String>(this, "pattern"));
add(input);
IndicatingAjaxButton submit = new IndicatingAjaxButton("submit",
this) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
send(getTable(), Broadcast.BREADTH,
new SearchStringChanged(target, pattern));
}
};
add(submit);
setDefaultButton(submit);
}
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof SearchStringChanged) {
SearchStringChanged e = (SearchStringChanged) event
.getPayload();
this.pattern = e.getPattern();
e.getTarget().add(this);
}
}
}
protected void onPageChanged(AjaxRequestTarget target) {
target.add(getTable());
target.add(this);
}
protected Component newNavigationForm(String id) {
Fragment frag = new Fragment(id, "navFrag", this);
frag.add(new NavigationForm("form"));
return frag;
}
static final List<Integer> ROWS_PER_PAGE = ImmutableList.<Integer> of(10,
25, 50, 100, 250, 500);
@SuppressWarnings({ "serial" })
private class NavigationForm extends Form<Void> {
private int rowsPerPage = 10;
private int currentPage = 1;
public NavigationForm(String id) {
super(id);
}
@Override
protected void onInitialize() {
super.onInitialize();
DropDownChoice<Integer> rowsSelector = new DropDownChoice<Integer>(
"rowsSelector", new PropertyModel<Integer>(this,
"rowsPerPage"), ROWS_PER_PAGE);
add(rowsSelector);
rowsSelector.add(new AjaxFormComponentUpdatingBehavior("onchange") {
@Override
protected void onUpdate(AjaxRequestTarget target) {
currentPage = 1;
getTable().setItemsPerPage(rowsPerPage);
send(getTable(), Broadcast.BREADTH, new PageChanged(target,
currentPage - 1));
}
});
add(new AjaxLink<Void>("previousLink") {
@Override
public void onClick(AjaxRequestTarget target) {
long current = getTable().getCurrentPage();
if (current == 0) {
return;
}
current--;
if (current < 0) {
current = 0;
}
send(getTable(), Broadcast.BREADTH, new PageChanged(target,
(int) current));
}
});
add(new AjaxLink<Void>("nextLink") {
@Override
public void onClick(AjaxRequestTarget target) {
long current = getTable().getCurrentPage();
long totals = getTable().getPageCount();
if (current == totals) {
return;
}
current++;
if (current >= totals) {
current = totals - 1;
}
send(getTable(), Broadcast.BREADTH, new PageChanged(target,
(int) current));
}
});
add(new TextField<Integer>("pageInput", new PropertyModel<Integer>(
this, "currentPage")));
AjaxButton btn = new AjaxButton("submit", this) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if (currentPage == getTable().getCurrentPage() + 1) {
return;
}
long totals = getTable().getPageCount();
currentPage = Math.min(currentPage, (int) totals);
currentPage = Math.max(currentPage, 0);
send(getTable(), Broadcast.BREADTH, new PageChanged(target,
currentPage - 1));
}
@Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
target.add(form);
}
};
add(btn);
setDefaultButton(btn);
add(new Label("navlabel", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
long totals = getTable().getRowCount();
long items = getTable().getItemsPerPage();
long start = (currentPage - 1) * items + 1;
long end = start + items - 1;
end = Math.min(end, totals);
return start + " - " + end + " of " + totals;
}
}));
}
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof PageChanged) {
PageChanged e = (PageChanged) event.getPayload();
currentPage = e.getPage() + 1;
rowsPerPage = (int) getTable().getItemsPerPage();
e.getTarget().add(this);
}
}
}
}

View File

@ -7,7 +7,7 @@ import com.pmease.gitop.web.common.util.Options;
public class Messenger {
static enum Type {
INFO, SUCCESS, ERROR
INFO, SUCCESS, WARNING, ERROR
}
private final String jsFunc;
@ -31,6 +31,10 @@ public class Messenger {
public static Messenger error(String message) {
return message(message, Type.ERROR);
}
public static Messenger warn(String message) {
return message(message, Type.WARNING);
}
private static Messenger message(String message, Type type) {
return post(new Options()

View File

@ -356,6 +356,9 @@ ul.messenger-theme-flat .messenger-message.alert-success .messenger-message-inne
ul.messenger-theme-flat .messenger-message.alert-info .messenger-message-inner:before {
background: #00B5AD;
}
ul.messenger-theme-flat .messenger-message.alert-warning .messenger-message-inner:before {
background: #ff9500;
}
/* line 103, ../../src/sass/messenger-theme-flat.sass */
ul.messenger-theme-flat .messenger-message.alert-error .messenger-message-inner:before {
background: #ff2a68;

View File

@ -4,9 +4,7 @@ import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.IModel;
@ -20,13 +18,11 @@ public class AjaxConfirmButton extends AjaxButton {
}
public AjaxConfirmButton(String id, Form<?> form, IModel<String> textModel,
IModel<VexIcon> iconModel, IModel<String> yesLabelModel,
final IModel<VexIcon> iconModel, IModel<String> yesLabelModel,
IModel<String> noLabelModel, IModel<String> confirmCssClassModel) {
super(id, form);
add(new VexLinkBehavior(textModel, iconModel, yesLabelModel,
noLabelModel, confirmCssClassModel));
add(AttributeAppender.append("class", "confirm-link"));
}
@Override
@ -54,8 +50,5 @@ public class AjaxConfirmButton extends AjaxButton {
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forReference(VexConfirmJavaScriptResourceReference.get()));
response.render(JavaScriptHeaderItem.forScript("vex.defaultOptions.className = 'vex-theme-wireframe'", "vex-theme-options"));
}
}

View File

@ -4,6 +4,7 @@ import org.apache.wicket.Component;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.model.IComponentAssignedModel;
import org.apache.wicket.model.IModel;
@ -44,6 +45,9 @@ public class VexLinkBehavior extends Behavior {
public void renderHead(Component component, IHeaderResponse response) {
super.renderHead(component, response);
response.render(JavaScriptHeaderItem.forReference(VexConfirmJavaScriptResourceReference.get()));
response.render(JavaScriptHeaderItem.forScript("vex.defaultOptions.className = 'vex-theme-wireframe'", "vex-theme-options"));
String markupId = component.getMarkupId(true);
response.render(OnDomReadyHeaderItem.forScript(String.format(
"$('#%s').on('click', function(e){e.preventDefault(); $(this).confirm(); });",

View File

@ -0,0 +1,41 @@
package com.pmease.gitop.web.component.choice;
import java.util.Collection;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import com.pmease.gitop.core.model.User;
import com.vaynberg.wicket.select2.Select2MultiChoice;
public class MultipleUserChoice extends Select2MultiChoice<User> {
private static final long serialVersionUID = 1L;
public MultipleUserChoice(String id, IModel<Collection<User>> model) {
super(id, model, new UserChoiceProvider());
}
@Override
protected void onInitialize() {
super.onInitialize();
// getSettings().setMinimumInputLength(1);
getSettings().setPlaceholder("Choose an user ...");
getSettings().setFormatResult("UserChoice.formatter.formatResult");
getSettings()
.setFormatSelection("UserChoice.formatter.formatSelection");
getSettings().setEscapeMarkup("UserChoice.formatter.escapeMarkup");
}
private ResourceReference userChoiceReference = new PackageResourceReference(
SingleUserChoice.class, "userchoice.js");
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forReference(userChoiceReference));
}
}

View File

@ -0,0 +1,39 @@
package com.pmease.gitop.web.component.choice;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import com.pmease.gitop.core.model.Team;
import com.vaynberg.wicket.select2.ChoiceProvider;
import com.vaynberg.wicket.select2.Select2Choice;
@SuppressWarnings("serial")
public class SingleTeamChoice extends Select2Choice<Team> {
public SingleTeamChoice(String id, IModel<Team> model,
ChoiceProvider<Team> teamsProvider) {
super(id, model, teamsProvider);
}
@Override
protected void onInitialize() {
super.onInitialize();
getSettings().setPlaceholder("Choose a team ...");
getSettings().setFormatResult("TeamChoice.formatter.formatResult");
getSettings()
.setFormatSelection("TeamChoice.formatter.formatSelection");
getSettings().setEscapeMarkup("TeamChoice.formatter.escapeMarkup");
}
private ResourceReference teamChoiceReference =
new JavaScriptResourceReference(SingleUserChoice.class, "teamchoice.js");
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forReference(teamChoiceReference));
}
}

View File

@ -0,0 +1,39 @@
package com.pmease.gitop.web.component.choice;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import com.pmease.gitop.core.model.User;
import com.vaynberg.wicket.select2.Select2Choice;
@SuppressWarnings("serial")
public class SingleUserChoice extends Select2Choice<User> {
public SingleUserChoice(String id, IModel<User> model) {
super(id, model, new UserChoiceProvider());
}
@Override
protected void onInitialize() {
super.onInitialize();
// getSettings().setMinimumInputLength(1);
getSettings().setPlaceholder("Choose an user ...");
getSettings().setFormatResult("UserChoice.formatter.formatResult");
getSettings()
.setFormatSelection("UserChoice.formatter.formatSelection");
getSettings().setEscapeMarkup("UserChoice.formatter.escapeMarkup");
}
private ResourceReference userChoiceReference =
new JavaScriptResourceReference(SingleUserChoice.class, "userchoice.js");
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forReference(userChoiceReference));
}
}

View File

@ -0,0 +1,75 @@
package com.pmease.gitop.web.component.choice;
import java.util.Collection;
import java.util.List;
import org.apache.wicket.model.IModel;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.common.collect.Lists;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.TeamManager;
import com.pmease.gitop.core.model.Team;
import com.vaynberg.wicket.select2.ChoiceProvider;
import com.vaynberg.wicket.select2.Response;
public class TeamChoiceProvider extends ChoiceProvider<Team> {
private static final long serialVersionUID = 1L;
IModel<DetachedCriteria> criteria;
public TeamChoiceProvider(IModel<DetachedCriteria> criteria) {
this.criteria = criteria;
}
@Override
public void query(String term, int page, Response<Team> response) {
DetachedCriteria crit = criteria == null ? null : criteria.getObject();
if (crit == null) {
crit = DetachedCriteria.forClass(Team.class);
}
crit.add(Restrictions.ilike("name", term, MatchMode.START));
crit.addOrder(Order.asc("name"));
int first = page * 10;
@SuppressWarnings("unchecked")
List<Team> teams = (List<Team>) Gitop.getInstance(GeneralDao.class).query(crit, first, 10);
response.addAll(teams);
}
@Override
public void toJson(Team choice, JSONWriter writer) throws JSONException {
writer.key("id").value(choice.getId())
.key("name").value(choice.getName())
.key("permission").value(choice.getAuthorizedOperation());
}
@Override
public Collection<Team> toChoices(Collection<String> ids) {
List<Team> teams = Lists.newArrayList();
TeamManager tm = Gitop.getInstance(TeamManager.class);
for (String each : ids) {
Long id = Long.valueOf(each);
teams.add(tm.get(id));
}
return teams;
}
@Override
public void detach() {
super.detach();
if (criteria != null) {
criteria.detach();
}
}
}

View File

@ -0,0 +1,81 @@
package com.pmease.gitop.web.component.choice;
import java.util.Collection;
import java.util.List;
import org.apache.wicket.request.cycle.RequestCycle;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
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.GitopWebApp;
import com.pmease.gitop.web.component.avatar.AvatarImageResourceReference;
import com.pmease.gitop.web.util.Gravatar;
import com.pmease.gitop.web.util.WicketUtils;
import com.vaynberg.wicket.select2.ChoiceProvider;
import com.vaynberg.wicket.select2.Response;
public class UserChoiceProvider extends ChoiceProvider<User> {
private static final long serialVersionUID = 1L;
@Override
public void query(String term, int page, Response<User> response) {
if (Strings.isNullOrEmpty(term)) {
return;
}
UserManager um = Gitop.getInstance(UserManager.class);
int first = page * 10;
List<User> users = um.query(new Criterion[] {
Restrictions.ilike("name", term, MatchMode.START),
Restrictions.ilike("displayName", term, MatchMode.START)
}, new Order[0], first, 10);
response.addAll(users);
}
@Override
public void toJson(User choice, JSONWriter writer) throws JSONException {
writer.key("id").value(choice.getId())
.key("name").value(choice.getName())
.key("displayName").value(choice.getDisplayName())
.key("email").value(choice.getEmail())
.key("avatar").value(getAvatarUrl(choice));
}
@Override
public Collection<User> toChoices(Collection<String> ids) {
List<User> users = Lists.newArrayList();
UserManager um = Gitop.getInstance(UserManager.class);
for (String each : ids) {
Long id = Long.valueOf(each);
users.add(um.get(id));
}
return users;
}
private String getAvatarUrl(User user) {
String path = user.getAvatarUrl();
if (GitopWebApp.get().isGravatarEnabled() && Strings.isNullOrEmpty(path)) {
return Gravatar.getURL(user.getEmail());
} else {
CharSequence url = RequestCycle.get().urlFor(
new AvatarImageResourceReference(),
WicketUtils.newPageParams(
"id",String.valueOf(user.getId()),
"type", "user"));
return url.toString() + "?antiCache=" + System.currentTimeMillis();
}
}
}

View File

@ -0,0 +1,14 @@
var TeamChoice = TeamChoice || {};
TeamChoice.formatter = {
formatSelection: function(team) {
return team.name;
},
formatResult: function(team) {
return team.name;
},
escapeMarkup: function(m) {
return m;
}
};

View File

@ -0,0 +1,17 @@
var UserChoice = UserChoice || {};
UserChoice.formatter = {
formatSelection: function(user) {
return "<img class='img-thumbnail avatar' src='" + user.avatar + "' /> " + user.name + " (" + user.displayName + ")";
},
formatResult: function(user) {
return "<div class='user-choice-row'><img class='img-thumbnail avatar avatar-big' src='" + user.avatar + "' />"
+ "<p>"+ user.name + " (" + user.displayName + ")" + "</p>"
+ "<p class='text-muted'>" + user.email + "</p>"
+ "</div>";
},
escapeMarkup: function(m) {
return m;
}
};

View File

@ -1,36 +1,37 @@
package com.pmease.gitop.web.model;
import org.apache.wicket.model.LoadableDetachableModel;
import com.google.common.base.Preconditions;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.commons.loader.AppLoader;
public class EntityModel<T extends AbstractEntity> extends LoadableDetachableModel<T> {
private static final long serialVersionUID = 1L;
protected T entity;
private final Class<T> entityClass;
protected GeneralDao getDao() {
return AppLoader.getInstance(GeneralDao.class);
}
@SuppressWarnings("unchecked")
public EntityModel(T entity) {
this.entity = entity;
this.entityClass = (Class<T>) entity.getClass();
}
@Override
protected T load() {
if (entity.isNew()) {
return entity;
} else {
return getDao().get(entityClass, entity.getId());
}
}
private static final long serialVersionUID = 1L;
protected T entity;
private final Class<T> entityClass;
protected GeneralDao getDao() {
return AppLoader.getInstance(GeneralDao.class);
}
@SuppressWarnings("unchecked")
public EntityModel(T entity) {
Preconditions.checkNotNull(entity, "entity");
this.entity = entity;
this.entityClass = (Class<T>) entity.getClass();
}
@Override
protected T load() {
if (entity.isNew()) {
return entity;
} else {
return getDao().get(entityClass, entity.getId());
}
}
}

View File

@ -0,0 +1,12 @@
package com.pmease.gitop.web.model;
import com.pmease.gitop.core.model.Team;
public class TeamModel extends EntityModel<Team> {
private static final long serialVersionUID = 1L;
public TeamModel(Team team) {
super(team);
}
}

View File

@ -183,7 +183,7 @@ public abstract class BasePage extends WebPage {
protected void onPageInitialize() {
if (!isPermitted()) {
throw new AccessDeniedException();
throw new AccessDeniedException("Access denied");
}
add(new Label("title", getPageTitle()));

View File

@ -1,9 +1,14 @@
package com.pmease.gitop.web.page;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.Link;
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.project.ProjectHomePage;
import com.pmease.gitop.web.util.WicketUtils;
public class PageSpec {
@ -11,11 +16,30 @@ public class PageSpec {
public static final String ID = "id";
public static final String TYPE = "type";
public static final String USER = "user";
public static final String PROJECT = "project";
public static final String REPO = "repo";
public static final String TAB = "tab";
public static PageParameters avatarOfUser(User user) {
return WicketUtils.newPageParams(TYPE, AvatarImageType.USER.name().toLowerCase(),
ID, String.valueOf(user.getId()));
return WicketUtils.newPageParams(TYPE, AvatarImageType.USER.name()
.toLowerCase(), ID, String.valueOf(user.getId()));
}
public static PageParameters forUser(User user) {
return WicketUtils.newPageParams(USER, user.getName());
}
public static PageParameters forProject(Project project) {
return WicketUtils.newPageParams(USER, project.getOwner().getName(),
PROJECT, project.getName());
}
public static Link<?> newUserHomeLink(String id, User user) {
return new BookmarkablePageLink<Void>(id, AccountHomePage.class, forUser(user));
}
public static Link<?> newProjectHomeLink(String id, Project project) {
return new BookmarkablePageLink<Void>(id, ProjectHomePage.class, forProject(project));
}
}

View File

@ -51,9 +51,7 @@ public class RegisterPage extends AbstractLayoutPage {
@Override
protected void onInitialize() {
super.onInitialize();
}
};
add(form);

View File

@ -6,15 +6,24 @@
</div>
<div class="body">
<h4>Anonymous Users</h4>
<p><a>Anonymous users can browse and pull any repositories under this account </a></p>
<p><a class="checkable-link" wicket:id="anonymouslink"><i class="icon-checkbox"></i> Anonymous users can browse and pull any repositories under this account </a></p>
<hr/>
<h4>Logged-in Users</h4>
<p class="text-muted">Logged-in users can access any repositories under this account with permission:</p>
<p>Logged-in users can access any repositories under this account with permission:</p>
<div class="btn-group btn-group-justified btn-radio-group" wicket:id="loggedInPermissions">
<wicket:container wicket:id="permissions">
<a wicket:id="permission" class="btn">
<span class="icon-ok"></span>
<span wicket:id="name"></span>
</a>
</wicket:container>
</div>
<hr/>
<h4>Teams</h4>
<p class="text-muted"></p>
<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>
<wicket:container wicket:id="teams"></wicket:container>
</div>
</section>
</wicket:extend>

View File

@ -1,5 +1,20 @@
package com.pmease.gitop.web.page.account.setting.permission;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.behavior.AttributeAppender;
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.model.AbstractReadOnlyModel;
import com.google.common.collect.ImmutableList;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
import com.pmease.gitop.web.model.UserModel;
import com.pmease.gitop.web.page.account.setting.AccountSettingPage;
@SuppressWarnings("serial")
@ -15,4 +30,81 @@ public class AccountPermissionPage extends AccountSettingPage {
return Category.PERMISSION;
}
@Override
protected void onPageInitialize() {
super.onPageInitialize();
AjaxLink<?> link = new AjaxLink<Void>("anonymouslink") {
@Override
public void onClick(AjaxRequestTarget target) {
User account = getAccount();
account.setPubliclyAccessible(!account.isPubliclyAccessible());
Gitop.getInstance(UserManager.class).save(account);
target.add(this);
}
};
add(link);
link.setOutputMarkupId(true);
link.add(AttributeAppender.append("class", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return getAccount().isPubliclyAccessible() ?
"checked" : "";
}
}));
WebMarkupContainer loggedInPermissions = new WebMarkupContainer("loggedInPermissions");
add(loggedInPermissions);
loggedInPermissions.setOutputMarkupId(true);
loggedInPermissions.add(new ListView<GeneralOperation>("permissions",
ImmutableList.<GeneralOperation>of(GeneralOperation.NO_ACCESS, GeneralOperation.READ, GeneralOperation.WRITE)) {
@Override
protected void populateItem(ListItem<GeneralOperation> item) {
AjaxLink<?> link = new PermissionLink("permission", item.getModelObject());
item.add(link);
link.add(new Label("name", item.getModelObject().toString()));
}
});
add(new TeamsPanel("teams", new UserModel(getAccount())));
}
class PermissionLink extends AjaxLink<Void> {
final GeneralOperation permssion;
PermissionLink(String id, final GeneralOperation permission) {
super(id);
this.permssion = permission;
add(AttributeAppender.append("class", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return getAccount().getDefaultAuthorizedOperation() == permission ?
"btn-default active" : "btn-default";
}
}));
}
@Override
public void onClick(AjaxRequestTarget target) {
User account = getAccount();
if (account.getDefaultAuthorizedOperation() == permssion) {
return;
}
account.setDefaultAuthorizedOperation(permssion);
Gitop.getInstance(UserManager.class).save(account);
target.add(AccountPermissionPage.this.get("loggedInPermissions"));
}
}
}

View File

@ -0,0 +1,15 @@
package com.pmease.gitop.web.page.account.setting.permission;
import com.pmease.gitop.core.model.Team;
@SuppressWarnings("serial")
public class AddTeamPage extends EditTeamPage {
public AddTeamPage() {
}
@Override
protected Team getTeam() {
return new Team();
}
}

View File

@ -0,0 +1,12 @@
<html xmlns:wicket>
<wicket:extend>
<section>
<div class="head">
<h2 wicket:id="head">Edit Team</h2>
</div>
<div class="body">
<div wicket:id="editor"></div>
</div>
</section>
</wicket:extend>
</html>

View File

@ -0,0 +1,59 @@
package com.pmease.gitop.web.page.account.setting.permission;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.TeamManager;
import com.pmease.gitop.core.model.Team;
import com.pmease.gitop.web.model.TeamModel;
import com.pmease.gitop.web.model.UserModel;
import com.pmease.gitop.web.page.account.setting.AccountSettingPage;
@SuppressWarnings("serial")
public class EditTeamPage extends AccountSettingPage {
protected final Long teamId;
public EditTeamPage() {
this.teamId = null;
}
public EditTeamPage(PageParameters params) {
this.teamId = params.get("teamId").toLongObject();
}
@Override
protected Category getSettingCategory() {
return Category.PERMISSION;
}
@Override
protected String getPageTitle() {
return "Edit Team";
}
@Override
protected void onPageInitialize() {
super.onPageInitialize();
add(new TeamEditor("editor", new UserModel(getAccount()), new TeamModel(getTeam())));
add(new Label("head", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return getTeam().isNew() ? "Create Team" : "Edit Team";
}
}));
}
protected Team getTeam() {
if (teamId == null) {
throw new IllegalStateException("Team id cannot be null when editing team");
} else {
return Gitop.getInstance(TeamManager.class).get(teamId);
}
}
}

View File

@ -0,0 +1,54 @@
<html xmlns:wicket>
<wicket:panel>
<form class="form-inline" wicket:id="infoForm">
<div wicket:id="feedback" class="form-feedback"></div>
<p>Team Name:</p>
<input class="form-control focusable" type="text" placeholder="Team Name" wicket:id="name" />
<div class="btn-group btn-radio-group btn-group-permissions" wicket:id="permissionContainer">
<wicket:container wicket:id="permissions">
<a wicket:id="permission" class="btn btn-default">
<span class="icon-ok"></span>
<span wicket:id="name"></span>
</a>
</wicket:container>
</div>
<button type="submit" class="btn btn-primary btn-colorful-text" wicket:id="submit"><span wicket:id="label"></span></button>
</form>
<wicket:container wicket:id="span">
<hr />
<h4>Members</h4>
<form class="form-inline" wicket:id="membersForm">
<div class="form-feedback" wicket:id="feedback"></div>
<input wicket:id="userchoice" class="user-choice" type="hidden" style="width: 300px"></input>
<button type="submit" class="btn btn-success btn-colorful-text" wicket:id="submit"><i class="icon-plus"></i> Add</button>
</form>
<hr/>
<div>
<h4 class="text-muted"><b wicket:id="total"></b> members total</h4>
<div class="member-list clearfix">
<div class="members first" wicket:id="oddlist">
</div>
<div class="members last" wicket:id="evenlist">
</div>
</div>
</div>
</wicket:container>
<wicket:fragment wicket:id="membersview">
<ul class="list-group list-view list-group-hoverable">
<li class="list-group-item" wicket:id="member">
<span class="avatar" wicket:id="avatar"></span>
<a class="name" wicket:id="link">
<span wicket:id="name"></span>
(<em wicket:id="fullname"></em>)
</a>
<div class="item-actions">
<a class="img-link" wicket:id="remove"><i class="icon-remove-sign"></i></a>
</div>
</li>
</ul>
</wicket:fragment>
</wicket:panel>
</html>

View File

@ -0,0 +1,344 @@
package com.pmease.gitop.web.page.account.setting.permission;
import java.util.Collections;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
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 org.hibernate.criterion.Restrictions;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.MembershipManager;
import com.pmease.gitop.core.manager.TeamManager;
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.core.permission.operation.GeneralOperation;
import com.pmease.gitop.web.common.component.messenger.Messenger;
import com.pmease.gitop.web.common.form.FeedbackPanel;
import com.pmease.gitop.web.component.avatar.AvatarImage;
import com.pmease.gitop.web.component.choice.SingleUserChoice;
import com.pmease.gitop.web.model.UserModel;
import com.pmease.gitop.web.page.PageSpec;
@SuppressWarnings("serial")
public class TeamEditor extends Panel {
private final IModel<User> userModel;
private WebMarkupContainer membersContainer;
public TeamEditor(String id, IModel<User> userModel, IModel<Team> model) {
super(id, model);
this.userModel = userModel;
this.setOutputMarkupId(true);
}
private User getAccount() {
return userModel.getObject();
}
private Team getTeam() {
return (Team) getDefaultModelObject();
}
@Override
protected void onInitialize() {
super.onInitialize();
this.name = getTeam().getName();
this.operation = getTeam().getAuthorizedOperation();
add(createInfoForm());
membersContainer = new WebMarkupContainer("span") {
@Override
protected void onConfigure() {
super.onConfigure();
this.setVisibilityAllowed(!getTeam().isNew());
}
};
add(membersContainer);
membersContainer.setOutputMarkupId(true);
membersContainer.add(createMembersForm());
final IModel<List<Membership>> relationModel = new LoadableDetachableModel<List<Membership>>() {
@Override
protected List<Membership> load() {
Team team = getTeam();
if (team.isNew()) {
return Collections.emptyList();
}
List<Membership> r = Gitop.getInstance(MembershipManager.class)
.query(Restrictions.eq("team", getTeam()));
Collections.sort(r, new java.util.Comparator<Membership>() {
@Override
public int compare(Membership o1, Membership o2) {
return o1.getUser().getName()
.compareTo(o2.getUser().getName());
}
});
return r;
}
};
membersContainer.add(createMemberList("oddlist", relationModel, true));
membersContainer.add(createMemberList("evenlist", relationModel, false));
membersContainer.add(new Label("total", new AbstractReadOnlyModel<Integer>() {
@Override
public Integer getObject() {
return relationModel.getObject().size();
}
}).setOutputMarkupId(true));
}
private GeneralOperation operation;
private String name;
private Form<?> createInfoForm() {
operation = getTeam().getAuthorizedOperation();
Form<?> infoForm = new Form<Void>("infoForm");
add(infoForm);
infoForm.add(new FeedbackPanel("feedback"));
infoForm.add(new TextField<String>("name", new PropertyModel<String>(
this, "name")).add(new IValidator<String>() {
@Override
public void validate(IValidatable<String> validatable) {
TeamManager tm = Gitop.getInstance(TeamManager.class);
Team team = tm.find(getAccount(), validatable.getValue());
Team current = getTeam();
if (team != null && !Objects.equal(team, current)) {
validatable.error(new ValidationError()
.setMessage("The team is already exist."));
}
}
}).setRequired(true));
WebMarkupContainer permissionContainer = new WebMarkupContainer(
"permissionContainer");
permissionContainer.setOutputMarkupId(true);
infoForm.add(permissionContainer);
permissionContainer.add(new ListView<GeneralOperation>("permissions",
ImmutableList.<GeneralOperation> of(
GeneralOperation.READ,
GeneralOperation.WRITE,
GeneralOperation.ADMIN)) {
@Override
protected void populateItem(ListItem<GeneralOperation> item) {
GeneralOperation permission = item.getModelObject();
AjaxLink<?> link = new PermissionLink("permission", permission);
link.add(new Label("name", permission.toString()));
item.add(link);
}
});
AjaxButton btn = new AjaxButton("submit", infoForm) {
@Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
target.add(form);
}
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
Team team = getTeam();
boolean isNew = team.isNew();
User owner = getAccount();
Preconditions.checkNotNull(owner, "owner");
team.setName(name);
team.setAuthorizedOperation(operation);
team.setOwner(owner);
Gitop.getInstance(TeamManager.class).save(team);
target.add(TeamEditor.this);
Messenger.success(
String.format("Team has been %s successfully.",
isNew ? "created" : "updated")).run(target);
}
};
btn.add(new Label("label", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return getTeam().isNew() ? "Create Team" : "Update Team";
}
}));
infoForm.add(btn);
return infoForm;
}
class PermissionLink extends AjaxLink<Void> {
final GeneralOperation permission;
PermissionLink(String id, final GeneralOperation permission) {
super(id);
this.permission = permission;
add(AttributeAppender.append("class",
new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return Objects.equal(operation, permission) ?
"active" : "";
}
}));
}
@Override
public void onClick(AjaxRequestTarget target) {
if (Objects.equal(operation, permission)) {
return;
}
operation = permission;
target.add(TeamEditor.this.get("infoForm").get("permissionContainer"));
}
}
User userToAdd;
private Form<?> createMembersForm() {
Form<?> form = new Form<Void>("membersForm");
form.add(new FeedbackPanel("feedback"));
form.add(new SingleUserChoice("userchoice", new PropertyModel<User>(
this, "userToAdd")));
form.add(new AjaxButton("submit", form) {
@Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
form.error("Please fix errors below.");
}
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if (userToAdd == null) {
form.error("Please select an user first");
target.add(form);
return;
}
Team team = getTeam();
MembershipManager mm = Gitop
.getInstance(MembershipManager.class);
Membership m = mm.find(Restrictions.eq("team", team),
Restrictions.eq("user", userToAdd));
if (m != null) {
form.warn("User has been added already");
target.add(form);
return;
}
m = new Membership();
m.setUser(userToAdd);
m.setTeam(team);
mm.save(m);
Messenger.success(String.format("User [%s] is added to team [%s]",
userToAdd.getName(), team.getName()))
.run(target);
userToAdd = null;
target.add(form);
onMembersChanged(target);
}
});
return form;
}
private void onMembersChanged(AjaxRequestTarget target) {
target.add(membersContainer.get("oddlist"));
target.add(membersContainer.get("evenlist"));
target.add(membersContainer.get("total"));
}
private Component createMemberList(String id,
IModel<List<Membership>> model, final boolean expected) {
Fragment frag = new Fragment(id, "membersview", this);
frag.setOutputMarkupId(true);
frag.add(new ListView<Membership>("member", model) {
@Override
protected void populateItem(ListItem<Membership> item) {
int index = item.getIndex();
boolean odd = index % 2 == 0;
if (odd != expected) {
item.setVisibilityAllowed(false);
return;
}
Membership membership = item.getModelObject();
User user = membership.getUser();
item.add(new AvatarImage("avatar", new UserModel(user)));
Link<?> link = PageSpec.newUserHomeLink("link", user);
link.add(new Label("name", user.getName()));
link.add(new Label("fullname", user.getDisplayName()));
item.add(link);
final Long id = membership.getId();
item.add(new AjaxLink<Void>("remove") {
@Override
public void onClick(AjaxRequestTarget target) {
MembershipManager mm = Gitop.getInstance(MembershipManager.class);
Membership membership = mm.get(id);
Gitop.getInstance(MembershipManager.class).delete(membership);
Messenger.warn(String.format("User [%s] is removed from team [%s]",
membership.getUser().getName(),
membership.getTeam().getName()))
.run(target);
onMembersChanged(target);
}
});
}
});
return frag;
}
@Override
public void onDetach() {
if (userModel != null) {
userModel.detach();
}
super.onDetach();
}
}

View File

@ -0,0 +1,19 @@
<html xmlns:wicket>
<wicket:panel>
<p>
<a class="btn btn-info" wicket:id="addTeam"><i class="icon-plus"></i> Create a team</a>
</p>
<table class="table table-condensed table-hover" wicket:id="teams"></table>
<wicket:fragment wicket:id="ops">
<div class="action-links">
<span class="link-item"><a wicket:id="edit"><i class="icon-edit"></i> edit</a></span>
<span class="link-item"><a wicket:id="remove"><i class="icon-remove-sign"></i> remove</a></span>
</div>
</wicket:fragment>
<wicket:fragment wicket:id="namefrag">
<span wicket:id="name"></span> <span class="text-muted">(<b wicket:id="members"></b> members)</span>
</wicket:fragment>
</wicket:panel>
</html>

View File

@ -0,0 +1,214 @@
package com.pmease.gitop.web.page.account.setting.permission;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackHeadersToolbar;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.NoRecordsToolbar;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.TeamManager;
import com.pmease.gitop.core.model.Team;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
import com.pmease.gitop.web.common.bootstrap.AjaxIconLink;
import com.pmease.gitop.web.common.bootstrap.IconType;
import com.pmease.gitop.web.common.component.datagrid.DataGrid;
import com.pmease.gitop.web.common.component.datagrid.event.SearchStringChanged;
import com.pmease.gitop.web.common.component.datagrid.hibernate.HibernateDataProvider;
import com.pmease.gitop.web.common.component.datagrid.toolbar.SearchNavToolbar;
import com.pmease.gitop.web.common.component.vex.AjaxConfirmLink;
import com.pmease.gitop.web.util.WicketUtils;
@SuppressWarnings("serial")
public class TeamsPanel extends Panel {
public TeamsPanel(String id, IModel<User> user) {
super(id, user);
}
@Override
protected void onInitialize() {
super.onInitialize();
add(new BookmarkablePageLink<Void>("addTeam", AddTeamPage.class));
add(createTeamPermissionsTable("teams"));
}
private Component createTeamPermissionsTable(String id) {
List<IColumn<Team, String>> columns = Lists.newArrayList();
columns.add(new AbstractColumn<Team, String>(Model.of("Name"), "name") {
@Override
public void populateItem(Item<ICellPopulator<Team>> cellItem,
String componentId, IModel<Team> rowModel) {
Team team = rowModel.getObject();
Fragment frag = new Fragment(componentId, "namefrag",
TeamsPanel.this);
frag.add(new Label("name", team.getName()));
frag.add(new Label("members", team.getMemberships().size()));
cellItem.add(frag);
}
});
columns.add(new TeamPermissionColumn(Model.of("Read"), GeneralOperation.READ));
columns.add(new TeamPermissionColumn(Model.of("Write"), GeneralOperation.WRITE));
columns.add(new TeamPermissionColumn(Model.of("Admin"), GeneralOperation.ADMIN));
columns.add(new AbstractColumn<Team, String>(Model.of("")) {
@Override
public void populateItem(Item<ICellPopulator<Team>> cellItem,
String componentId, final IModel<Team> rowModel) {
Fragment frag = new Fragment(componentId, "ops", TeamsPanel.this);
frag.add(new BookmarkablePageLink<Void>("edit",
EditTeamPage.class, WicketUtils.newPageParams("teamId", rowModel.getObject().getId())));
Team team = rowModel.getObject();
frag.add(new AjaxConfirmLink<Void>("remove",
Model.of("Are you sure you want to remove team " + team.getName())) {
@Override
public void onClick(AjaxRequestTarget target) {
Team p = rowModel.getObject();
Gitop.getInstance(TeamManager.class).delete(p);
onTeamTableChanged(target);
}
});
cellItem.add(frag);
}
@Override
public String getCssClass() {
return "operations-td";
}
});
final List<Criterion> criterions = Lists.newArrayList();
HibernateDataProvider<Team> teamProvider = new HibernateDataProvider<Team>() {
@Override
protected DetachedCriteria getCriteria() {
DetachedCriteria criteria = DetachedCriteria.forClass(Team.class);
criteria.add(Restrictions.eq("owner", getUser()));
for (Criterion each : criterions) {
criteria.add(each);
}
return criteria;
}
};
DataGrid<Team> dataTable = new DataGrid<Team>(id, columns,
teamProvider, 10) {
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof SearchStringChanged) {
SearchStringChanged e = (SearchStringChanged) event.getPayload();
criterions.clear();
if (!Strings.isNullOrEmpty(e.getPattern())) {
criterions.add(Restrictions.ilike("name", e.getPattern(), MatchMode.ANYWHERE));
}
e.getTarget().add(this);
}
}
};
dataTable.setOutputMarkupId(true);
dataTable.addTopToolbar(new AjaxFallbackHeadersToolbar<String>(dataTable, teamProvider));
dataTable.addBottomToolbar(new NoRecordsToolbar(dataTable, Model.of("No Teams Found")));
dataTable.addBottomToolbar(new SearchNavToolbar(dataTable));
return dataTable;
}
private class TeamPermissionColumn extends AbstractColumn<Team, String> {
private GeneralOperation expected;
public TeamPermissionColumn(IModel<String> displayModel,
GeneralOperation expected) {
super(displayModel);
this.expected = expected;
}
@Override
public void populateItem(Item<ICellPopulator<Team>> cellItem,
String componentId, final IModel<Team> rowModel) {
IModel<IconType> iconModel = new AbstractReadOnlyModel<IconType>() {
@Override
public IconType getObject() {
return rowModel.getObject().getAuthorizedOperation().can(expected) ?
IconType.CHECK : IconType.CHECK_EMPTY;
}
};
cellItem.add(new AjaxIconLink(componentId, iconModel) {
@Override
protected AjaxLink<?> createLink(String id) {
AjaxLink<?> link = new AjaxLink<Void>(id) {
@Override
public void onClick(AjaxRequestTarget target) {
GeneralOperation old = rowModel.getObject().getAuthorizedOperation();
Team team = rowModel.getObject();
if (old == expected) {
int ordinal = expected.ordinal() - 1;
if (ordinal < 0) {
ordinal = 0;
}
team.setAuthorizedOperation(GeneralOperation.values()[ordinal]);
} else {
team.setAuthorizedOperation(expected);
}
Gitop.getInstance(TeamManager.class).save(team);
onTeamTableChanged(target);
}
};
link.add(AttributeAppender.append("class", "permission-link"));
return link;
}
});
}
}
private void onTeamTableChanged(AjaxRequestTarget target) {
target.add(get("teams"));
}
private User getUser() {
return (User) getDefaultModelObject();
}
}

View File

@ -28,7 +28,7 @@
<input type="file" wicket:id="fileInput" />
</p>
<p class="text-muted">
Supported image types are png, gif, jpg and jpeg. The image size should be less than 128K bytes.
Supported image types are png, gif, jpg and jpeg. The image size should be less than 2M bytes.
</p>
<hr/>
<div class="btn-group btn-group-justified">

View File

@ -13,6 +13,7 @@ import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.util.lang.Bytes;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
@ -106,8 +107,13 @@ public class AccountProfilePage extends AccountSettingPage {
protected void onInitialize() {
super.onInitialize();
// limit avatar size to 2M bytes
setMaxSize(Bytes.megabytes(2));
setMultiPart(true);
final FileUploadField uploadField = new FileUploadField("fileInput");
uploadField.setRequired(false);
add(uploadField);
add(new FeedbackPanel("feedback"));

View File

@ -5,6 +5,7 @@ import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
@ -60,7 +61,14 @@ public class HomePage extends AbstractLayoutPage {
form.add(new AjaxConfirmButton("submit", form,
Model.of("Are you sure you want to submit the form?"),
Model.of(VexIcon.ERROR),
new AbstractReadOnlyModel<VexIcon>() {
@Override
public VexIcon getObject() {
return vexIcon;
}
},
Model.of("Yes"),
Model.of("No"),
null) {

View File

@ -0,0 +1,135 @@
package com.pmease.gitop.web.resource;
import java.io.IOException;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.apache.shiro.authc.credential.PasswordService;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.User;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
@Path("/github")
public class GitHubUserResource {
@Inject ObjectMapper objectMapper;
@Inject UserManager userManager;
@Inject PasswordService passwordService;
@GET
public Response get() {
try {
updateDatabase("github");
} catch (Exception e) {
throw Throwables.propagate(e);
}
return Response.ok("Everything is ok").build();
}
private void updateDatabase(String org) throws JsonParseException,
JsonMappingException, UniformInterfaceException,
ClientHandlerException, IOException {
Client client = Client.create();
client.addFilter(new HTTPBasicAuthFilter("zhenyuluo", "hongmei9"));
WebResource r = client.resource("https://api.github.com/orgs/" + org
+ "/public_members");
String content = r.get(String.class);
objectMapper.configure(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<HubUser> users = objectMapper.readValue(content,
new TypeReference<List<HubUser>>() {
});
users = users.subList(102, users.size());
for (HubUser each : users) {
try {
r = client.resource("https://api.github.com/users/"
+ each.login);
HubUser u = objectMapper.readValue(r.get(String.class),
HubUser.class);
User user = new User();
user.setName(u.login);
user.setDisplayName(u.name);
if (Strings.isNullOrEmpty(u.email)) {
user.setEmail(u.login + "@github.com");
} else {
user.setEmail(u.email);
}
user.setPasswordHash(passwordService.encryptPassword("12345"));
userManager.save(user);
System.out.println(user.getId() + " " + user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static class HubUsers {
@JsonProperty
List<HubUser> users = Lists.newArrayList();
public List<HubUser> getUsers() {
return users;
}
public void setUsers(List<HubUser> users) {
this.users = users;
}
}
public static class HubUser {
@JsonProperty
private String login;
@JsonProperty
private String name;
@JsonProperty
private String email;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
}