mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-18 03:01:05 +01:00
merge
This commit is contained in:
5
Jenkinsfile
vendored
5
Jenkinsfile
vendored
@@ -50,6 +50,11 @@ node('docker') {
|
||||
def dockerImageTag = "2.0.0-dev-${commitHash.substring(0,7)}-${BUILD_NUMBER}"
|
||||
|
||||
if (isMainBranch()) {
|
||||
|
||||
stage('Lifecycle') {
|
||||
nexusPolicyEvaluation iqApplication: selectedApplication('scm'), iqScanPatterns: [[scanPattern: 'scm-server/target/scm-server-app.zip']], iqStage: 'build'
|
||||
}
|
||||
|
||||
stage('Archive') {
|
||||
archiveArtifacts 'scm-webapp/target/scm-webapp.war'
|
||||
archiveArtifacts 'scm-server/target/scm-server-app.*'
|
||||
|
||||
21
pom.xml
21
pom.xml
@@ -351,21 +351,6 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- utils -->
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.9.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- http -->
|
||||
|
||||
<dependency>
|
||||
@@ -825,11 +810,11 @@
|
||||
<logback.version>1.2.3</logback.version>
|
||||
<servlet.version>3.0.1</servlet.version>
|
||||
|
||||
<jaxrs.version>2.0.1</jaxrs.version>
|
||||
<resteasy.version>3.1.3.Final</resteasy.version>
|
||||
<jaxrs.version>2.1.1</jaxrs.version>
|
||||
<resteasy.version>3.6.2.Final</resteasy.version>
|
||||
<jersey-client.version>1.19.4</jersey-client.version>
|
||||
<enunciate.version>2.11.1</enunciate.version>
|
||||
<jackson.version>2.8.6</jackson.version>
|
||||
<jackson.version>2.9.8</jackson.version>
|
||||
<guice.version>4.0</guice.version>
|
||||
<jaxb.version>2.3.0</jaxb.version>
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>javax.ws.rs-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -235,7 +236,6 @@
|
||||
<links>
|
||||
<link>http://download.oracle.com/javase/6/docs/api/</link>
|
||||
<link>http://download.oracle.com/docs/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/</link>
|
||||
<link>http://jersey.java.net/nonav/apidocs/${jersey.version}/jersey/</link>
|
||||
<link>https://google.github.io/guice/api-docs/${guice.version}/javadoc</link>
|
||||
<link>http://www.slf4j.org/api/</link>
|
||||
<link>http://shiro.apache.org/static/${shiro.version}/apidocs/</link>
|
||||
|
||||
@@ -36,7 +36,6 @@ package sonia.scm;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The base class of all handlers.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import org.mapstruct.Context;
|
||||
import org.mapstruct.Mapping;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
public interface ChangesetToChangesetDtoMapper {
|
||||
|
||||
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
||||
ChangesetDto map(Changeset changeset, @Context Repository repository);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,24 +1,59 @@
|
||||
package sonia.scm.filter;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import sonia.scm.util.WebUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.container.ContainerResponseContext;
|
||||
import javax.ws.rs.container.ContainerResponseFilter;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.ext.WriterInterceptor;
|
||||
import javax.ws.rs.ext.WriterInterceptorContext;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Locale;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
@Provider
|
||||
@Slf4j
|
||||
public class GZipResponseFilter implements ContainerResponseFilter {
|
||||
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
|
||||
if (WebUtil.isGzipSupported(requestContext::getHeaderString)) {
|
||||
log.trace("compress output with gzip");
|
||||
GZIPOutputStream wrappedResponse = new GZIPOutputStream(responseContext.getEntityStream());
|
||||
responseContext.getHeaders().add("Content-Encoding", "gzip");
|
||||
responseContext.setEntityStream(wrappedResponse);
|
||||
@javax.ws.rs.ext.Provider
|
||||
public class GZipResponseFilter implements WriterInterceptor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GZipResponseFilter.class);
|
||||
|
||||
private final Provider<HttpServletRequest> requestProvider;
|
||||
|
||||
@Inject
|
||||
public GZipResponseFilter(Provider<HttpServletRequest> requestProvider) {
|
||||
this.requestProvider = requestProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
|
||||
if (isGZipSupported()) {
|
||||
LOG.trace("compress output with gzip");
|
||||
encodeWithGZip(context);
|
||||
} else {
|
||||
context.proceed();
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeWithGZip(WriterInterceptorContext context) throws IOException {
|
||||
context.getHeaders().remove(HttpHeaders.CONTENT_LENGTH);
|
||||
context.getHeaders().add(HttpHeaders.CONTENT_ENCODING, "gzip");
|
||||
|
||||
OutputStream outputStream = context.getOutputStream();
|
||||
GZIPOutputStream compressedOutputStream = new GZIPOutputStream(outputStream);
|
||||
context.setOutputStream(compressedOutputStream);
|
||||
try {
|
||||
context.proceed();
|
||||
} finally {
|
||||
compressedOutputStream.finish();
|
||||
context.setOutputStream(outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGZipSupported() {
|
||||
Object encoding = requestProvider.get().getHeader(HttpHeaders.ACCEPT_ENCODING);
|
||||
return encoding != null && encoding.toString().toLowerCase(Locale.ENGLISH).contains("gzip");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ package sonia.scm.net.ahc;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ package sonia.scm.plugin;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Module;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ConfigurationException;
|
||||
import sonia.scm.io.CommandResult;
|
||||
import sonia.scm.io.ExtendedCommand;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
|
||||
import java.io.File;
|
||||
@@ -67,11 +68,14 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
|
||||
LoggerFactory.getLogger(AbstractSimpleRepositoryHandler.class);
|
||||
|
||||
private final RepositoryLocationResolver repositoryLocationResolver;
|
||||
private final PluginLoader pluginLoader;
|
||||
|
||||
public AbstractSimpleRepositoryHandler(ConfigurationStoreFactory storeFactory,
|
||||
RepositoryLocationResolver repositoryLocationResolver) {
|
||||
RepositoryLocationResolver repositoryLocationResolver,
|
||||
PluginLoader pluginLoader) {
|
||||
super(storeFactory);
|
||||
this.repositoryLocationResolver = repositoryLocationResolver;
|
||||
this.pluginLoader = pluginLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,7 +159,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
|
||||
String content = defaultContent;
|
||||
|
||||
try {
|
||||
URL url = Resources.getResource(resource);
|
||||
URL url = pluginLoader.getUberClassLoader().getResource(resource);
|
||||
|
||||
if (url != null) {
|
||||
content = Resources.toString(url, Charsets.UTF_8);
|
||||
|
||||
@@ -37,7 +37,6 @@ package sonia.scm.repository;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Objects;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import sonia.scm.security.PermissionObject;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
@@ -47,9 +46,10 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.unmodifiableCollection;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
@@ -68,7 +68,7 @@ public class RepositoryPermission implements PermissionObject, Serializable
|
||||
private boolean groupPermission = false;
|
||||
private String name;
|
||||
@XmlElement(name = "verb")
|
||||
private Collection<String> verbs;
|
||||
private Set<String> verbs;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link RepositoryPermission}.
|
||||
@@ -79,7 +79,7 @@ public class RepositoryPermission implements PermissionObject, Serializable
|
||||
public RepositoryPermission(String name, Collection<String> verbs, boolean groupPermission)
|
||||
{
|
||||
this.name = name;
|
||||
this.verbs = unmodifiableCollection(new LinkedHashSet<>(verbs));
|
||||
this.verbs = unmodifiableSet(new LinkedHashSet<>(verbs));
|
||||
this.groupPermission = groupPermission;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,8 @@ public class RepositoryPermission implements PermissionObject, Serializable
|
||||
final RepositoryPermission other = (RepositoryPermission) obj;
|
||||
|
||||
return Objects.equal(name, other.name)
|
||||
&& CollectionUtils.isEqualCollection(verbs, other.verbs)
|
||||
&& verbs.containsAll(other.verbs)
|
||||
&& verbs.size() == other.verbs.size()
|
||||
&& Objects.equal(groupPermission, other.groupPermission);
|
||||
}
|
||||
|
||||
@@ -209,6 +210,6 @@ public class RepositoryPermission implements PermissionObject, Serializable
|
||||
*/
|
||||
public void setVerbs(Collection<String> verbs)
|
||||
{
|
||||
this.verbs = verbs;
|
||||
this.verbs = unmodifiableSet(new LinkedHashSet<>(verbs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.google.common.base.Objects;
|
||||
import com.google.common.base.Strings;
|
||||
import sonia.scm.Validateable;
|
||||
import sonia.scm.repository.Person;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.google.common.base.Objects;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ package sonia.scm.security;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
88
scm-core/src/main/java/sonia/scm/util/Comparables.java
Normal file
88
scm-core/src/main/java/sonia/scm/util/Comparables.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package sonia.scm.util;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
public final class Comparables {
|
||||
|
||||
private static final CacheLoader<Class, BeanInfo> beanInfoCacheLoader = new CacheLoader<Class, BeanInfo>() {
|
||||
@Override
|
||||
public BeanInfo load(Class type) throws IntrospectionException {
|
||||
return Introspector.getBeanInfo(type);
|
||||
}
|
||||
};
|
||||
|
||||
private static final LoadingCache<Class, BeanInfo> beanInfoCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(50) // limit the cache to avoid consuming to much memory on miss usage
|
||||
.build(beanInfoCacheLoader);
|
||||
|
||||
private Comparables() {
|
||||
}
|
||||
|
||||
public static <T> Comparator<T> comparator(Class<T> type, String sortBy) {
|
||||
BeanInfo info = createBeanInfo(type);
|
||||
PropertyDescriptor propertyDescriptor = findPropertyDescriptor(sortBy, info);
|
||||
|
||||
Method readMethod = propertyDescriptor.getReadMethod();
|
||||
checkIfPropertyIsComparable(readMethod, sortBy);
|
||||
|
||||
return new MethodComparator<>(readMethod);
|
||||
}
|
||||
|
||||
private static void checkIfPropertyIsComparable(Method readMethod, String sortBy) {
|
||||
checkArgument(isReturnTypeComparable(readMethod), "property %s is not comparable", sortBy);
|
||||
}
|
||||
|
||||
private static boolean isReturnTypeComparable(Method readMethod) {
|
||||
return Comparable.class.isAssignableFrom(readMethod.getReturnType());
|
||||
}
|
||||
|
||||
private static PropertyDescriptor findPropertyDescriptor(String sortBy, BeanInfo info) {
|
||||
PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
|
||||
|
||||
Optional<PropertyDescriptor> sortByPropertyDescriptor = Arrays.stream(propertyDescriptors)
|
||||
.filter(p -> p.getName().equals(sortBy))
|
||||
.findFirst();
|
||||
|
||||
return sortByPropertyDescriptor.orElseThrow(() -> new IllegalArgumentException("could not find property " + sortBy));
|
||||
}
|
||||
|
||||
private static <T> BeanInfo createBeanInfo(Class<T> type) {
|
||||
return beanInfoCache.getUnchecked(type);
|
||||
}
|
||||
|
||||
private static class MethodComparator<T> implements Comparator<T> {
|
||||
|
||||
private final Method readMethod;
|
||||
|
||||
private MethodComparator(Method readMethod) {
|
||||
this.readMethod = readMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public int compare(T left, T right) {
|
||||
try {
|
||||
Comparable leftResult = (Comparable) readMethod.invoke(left);
|
||||
Comparable rightResult = (Comparable) readMethod.invoke(right);
|
||||
return leftResult.compareTo(rightResult);
|
||||
} catch (IllegalAccessException | InvocationTargetException ex) {
|
||||
throw new IllegalArgumentException("failed to invoke read method", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package sonia.scm.filter;
|
||||
|
||||
import com.google.inject.util.Providers;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.ext.WriterInterceptorContext;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class GZipResponseFilterTest {
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Mock
|
||||
private WriterInterceptorContext context;
|
||||
|
||||
@Mock
|
||||
private MultivaluedMap<String,Object> headers;
|
||||
|
||||
private GZipResponseFilter filter;
|
||||
|
||||
@BeforeEach
|
||||
void setupObjectUnderTest() {
|
||||
filter = new GZipResponseFilter(Providers.of(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSkipGZipCompression() throws IOException {
|
||||
when(request.getHeader(HttpHeaders.ACCEPT_ENCODING)).thenReturn("deflate, br");
|
||||
|
||||
filter.aroundWriteTo(context);
|
||||
|
||||
verifySkipped();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSkipGZipCompressionWithoutAcceptEncodingHeader() throws IOException {
|
||||
filter.aroundWriteTo(context);
|
||||
|
||||
verifySkipped();
|
||||
}
|
||||
|
||||
private void verifySkipped() throws IOException {
|
||||
verify(context, never()).getOutputStream();
|
||||
verify(context).proceed();
|
||||
}
|
||||
|
||||
|
||||
@Nested
|
||||
class AcceptGZipEncoding {
|
||||
|
||||
@BeforeEach
|
||||
void setUpContext() {
|
||||
when(request.getHeader(HttpHeaders.ACCEPT_ENCODING)).thenReturn("gzip, deflate, br");
|
||||
when(context.getHeaders()).thenReturn(headers);
|
||||
when(context.getOutputStream()).thenReturn(new ByteArrayOutputStream());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldEncode() throws IOException {
|
||||
filter.aroundWriteTo(context);
|
||||
|
||||
verify(headers).remove(HttpHeaders.CONTENT_LENGTH);
|
||||
verify(headers).add(HttpHeaders.CONTENT_ENCODING, "gzip");
|
||||
|
||||
verify(context).setOutputStream(any(GZIPOutputStream.class));
|
||||
verify(context, times(2)).setOutputStream(any(OutputStream.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import com.google.common.io.ByteSource;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
@@ -46,4 +46,13 @@ class RepositoryPermissionTest {
|
||||
|
||||
assertThat(permission1).isNotEqualTo(permission2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeEqualWithRedundantVerbs() {
|
||||
RepositoryPermission permission1 = new RepositoryPermission("name1", asList("one", "two"), false);
|
||||
RepositoryPermission permission2 = new RepositoryPermission("name1", asList("one", "two"), false);
|
||||
permission2.setVerbs(asList("one", "two", "two"));
|
||||
|
||||
assertThat(permission1).isEqualTo(permission2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package sonia.scm.security;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.apache.shiro.authc.DisabledAccountException;
|
||||
import org.apache.shiro.authc.UnknownAccountException;
|
||||
|
||||
57
scm-core/src/test/java/sonia/scm/util/ComparablesTest.java
Normal file
57
scm-core/src/test/java/sonia/scm/util/ComparablesTest.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package sonia.scm.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class ComparablesTest {
|
||||
|
||||
@Test
|
||||
void shouldCompare() {
|
||||
One a = new One("a");
|
||||
One b = new One("b");
|
||||
|
||||
Comparator<One> comparable = Comparables.comparator(One.class, "value");
|
||||
assertThat(comparable.compare(a, b)).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAnExceptionForNonExistingField() {
|
||||
assertThrows(IllegalArgumentException.class, () -> Comparables.comparator(One.class, "awesome"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAnExceptionForNonComparableField() {
|
||||
assertThrows(IllegalArgumentException.class, () -> Comparables.comparator(One.class, "nonComparable"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAnExceptionIfTheFieldHasNoGetter() {
|
||||
assertThrows(IllegalArgumentException.class, () -> Comparables.comparator(One.class, "incredible"));
|
||||
}
|
||||
|
||||
private static class One {
|
||||
|
||||
private String value;
|
||||
private String incredible;
|
||||
private NonComparable nonComparable;
|
||||
|
||||
One(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public NonComparable getNonComparable() {
|
||||
return nonComparable;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NonComparable {}
|
||||
|
||||
}
|
||||
@@ -37,9 +37,6 @@ package sonia.scm.store;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.repository.RepositoryLocationResolver;
|
||||
import sonia.scm.security.KeyGenerator;
|
||||
|
||||
@@ -38,7 +38,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.GenericDAO;
|
||||
import sonia.scm.ModelObject;
|
||||
import sonia.scm.group.xml.XmlGroupDAO;
|
||||
import sonia.scm.store.ConfigurationStore;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package sonia.scm.xml;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ package sonia.scm.it;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
@@ -5,10 +5,8 @@ import io.restassured.response.Response;
|
||||
import org.junit.Assert;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -18,8 +18,6 @@ import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
|
||||
/**
|
||||
* RESTful Web Service Resource to manage the configuration of the git plugin.
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.repository.spi.GitRepositoryServiceProvider;
|
||||
import sonia.scm.schedule.Scheduler;
|
||||
import sonia.scm.schedule.Task;
|
||||
@@ -103,9 +104,10 @@ public class GitRepositoryHandler
|
||||
public GitRepositoryHandler(ConfigurationStoreFactory storeFactory,
|
||||
Scheduler scheduler,
|
||||
RepositoryLocationResolver repositoryLocationResolver,
|
||||
GitWorkdirFactory workdirFactory)
|
||||
GitWorkdirFactory workdirFactory,
|
||||
PluginLoader pluginLoader)
|
||||
{
|
||||
super(storeFactory, repositoryLocationResolver);
|
||||
super(storeFactory, repositoryLocationResolver, pluginLoader);
|
||||
this.scheduler = scheduler;
|
||||
this.workdirFactory = workdirFactory;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ package sonia.scm.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.inject.Inject;
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React from "react";
|
||||
|
||||
import {apiClient, BranchSelector, ErrorPage, Loading, SubmitButton} from "@scm-manager/ui-components";
|
||||
import {apiClient, BranchSelector, ErrorPage, Loading, Subtitle, SubmitButton} from "@scm-manager/ui-components";
|
||||
import type {Branch, Repository} from "@scm-manager/ui-types";
|
||||
import {translate} from "react-i18next";
|
||||
|
||||
@@ -113,6 +113,7 @@ class RepositoryConfig extends React.Component<Props, State> {
|
||||
if (!(loadingBranches || loadingDefaultBranch)) {
|
||||
return (
|
||||
<>
|
||||
<Subtitle subtitle={t("scm-git-plugin.repo-config.title")}/>
|
||||
{this.renderBranchChangedNotification()}
|
||||
<form onSubmit={this.submit}>
|
||||
<BranchSelector
|
||||
@@ -127,6 +128,7 @@ class RepositoryConfig extends React.Component<Props, State> {
|
||||
disabled={!this.state.selectedBranchName}
|
||||
/>
|
||||
</form>
|
||||
<hr />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -27,14 +27,9 @@ binder.bind(
|
||||
);
|
||||
binder.bind("repos.repository-avatar", GitAvatar, gitPredicate);
|
||||
|
||||
cfgBinder.bindRepository(
|
||||
"/configuration",
|
||||
"scm-git-plugin.repo-config.link",
|
||||
"configuration",
|
||||
RepositoryConfig
|
||||
);
|
||||
// global config
|
||||
binder.bind("repo-config.route", RepositoryConfig, gitPredicate);
|
||||
|
||||
// global config
|
||||
cfgBinder.bindGlobal(
|
||||
"/git",
|
||||
"scm-git-plugin.config.link",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
},
|
||||
"repo-config": {
|
||||
"link": "Konfiguration",
|
||||
"title": "Git Einstellungen",
|
||||
"default-branch": "Standard Branch",
|
||||
"submit": "Speichern",
|
||||
"error": {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
},
|
||||
"repo-config": {
|
||||
"link": "Configuration",
|
||||
"title": "Git Settings",
|
||||
"default-branch": "Default branch",
|
||||
"submit": "Submit",
|
||||
"error": {
|
||||
|
||||
@@ -3,7 +3,7 @@ package sonia.scm.api.v2.resources;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.GitConfig;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.mockito.Captor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.GitConfig;
|
||||
import sonia.scm.repository.GitRepositoryConfig;
|
||||
import sonia.scm.repository.GitRepositoryHandler;
|
||||
@@ -29,6 +29,7 @@ import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import sonia.scm.web.GitVndMediaType;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
@@ -100,7 +101,7 @@ public class GitConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readWrite")
|
||||
public void shouldGetGitConfig() throws URISyntaxException {
|
||||
public void shouldGetGitConfig() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpResponse response = get();
|
||||
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
@@ -115,7 +116,7 @@ public class GitConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readWrite")
|
||||
public void shouldGetGitConfigEvenWhenItsEmpty() throws URISyntaxException {
|
||||
public void shouldGetGitConfigEvenWhenItsEmpty() throws URISyntaxException, UnsupportedEncodingException {
|
||||
when(repositoryHandler.getConfig()).thenReturn(null);
|
||||
|
||||
MockHttpResponse response = get();
|
||||
@@ -126,7 +127,7 @@ public class GitConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readOnly")
|
||||
public void shouldGetGitConfigWithoutUpdateLink() throws URISyntaxException {
|
||||
public void shouldGetGitConfigWithoutUpdateLink() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpResponse response = get();
|
||||
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
@@ -159,7 +160,7 @@ public class GitConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "writeOnly")
|
||||
public void shouldReadDefaultRepositoryConfig() throws URISyntaxException {
|
||||
public void shouldReadDefaultRepositoryConfig() throws URISyntaxException, UnsupportedEncodingException {
|
||||
when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X"));
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X");
|
||||
@@ -176,7 +177,7 @@ public class GitConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readOnly")
|
||||
public void shouldNotHaveUpdateLinkForReadOnlyUser() throws URISyntaxException {
|
||||
public void shouldNotHaveUpdateLinkForReadOnlyUser() throws URISyntaxException, UnsupportedEncodingException {
|
||||
when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X"));
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X");
|
||||
@@ -193,7 +194,7 @@ public class GitConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "writeOnly")
|
||||
public void shouldReadStoredRepositoryConfig() throws URISyntaxException {
|
||||
public void shouldReadStoredRepositoryConfig() throws URISyntaxException, UnsupportedEncodingException {
|
||||
when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X"));
|
||||
GitRepositoryConfig gitRepositoryConfig = new GitRepositoryConfig();
|
||||
gitRepositoryConfig.setDefaultBranch("test");
|
||||
|
||||
@@ -11,10 +11,9 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.GitConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@@ -14,9 +14,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.web.JsonEnricherContext;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -94,7 +94,7 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
|
||||
RepositoryLocationResolver locationResolver,
|
||||
File directory) {
|
||||
GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory,
|
||||
scheduler, locationResolver, gitWorkdirFactory);
|
||||
scheduler, locationResolver, gitWorkdirFactory, null);
|
||||
repositoryHandler.init(contextProvider);
|
||||
|
||||
GitConfig config = new GitConfig();
|
||||
@@ -108,7 +108,7 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
|
||||
@Test
|
||||
public void getDirectory() {
|
||||
GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory,
|
||||
scheduler, locationResolver, gitWorkdirFactory);
|
||||
scheduler, locationResolver, gitWorkdirFactory, null);
|
||||
GitConfig config = new GitConfig();
|
||||
config.setDisabled(false);
|
||||
config.setGcExpression("gc exp");
|
||||
|
||||
@@ -35,10 +35,8 @@ package sonia.scm.repository.spi;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider;
|
||||
import sonia.scm.repository.GitRepositoryConfig;
|
||||
import sonia.scm.store.InMemoryConfigurationStore;
|
||||
import sonia.scm.store.InMemoryConfigurationStoreFactory;
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,11 +35,9 @@ package sonia.scm.repository.spi;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import org.junit.Test;
|
||||
import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider;
|
||||
import sonia.scm.repository.BlameLine;
|
||||
import sonia.scm.repository.BlameResult;
|
||||
import sonia.scm.repository.GitRepositoryConfig;
|
||||
import sonia.scm.store.InMemoryConfigurationStoreFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@@ -32,11 +32,9 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import org.junit.Test;
|
||||
import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider;
|
||||
import sonia.scm.repository.BrowserResult;
|
||||
import sonia.scm.repository.FileObject;
|
||||
import sonia.scm.repository.GitRepositoryConfig;
|
||||
import sonia.scm.store.InMemoryConfigurationStoreFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -36,10 +36,8 @@ package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import org.junit.Test;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.ChangesetPagingResult;
|
||||
import sonia.scm.repository.ClearRepositoryCacheEvent;
|
||||
import sonia.scm.repository.GitRepositoryConfig;
|
||||
import sonia.scm.repository.Modifications;
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.GitConfig;
|
||||
import sonia.scm.repository.GitRepositoryHandler;
|
||||
|
||||
|
||||
@@ -35,14 +35,12 @@ package sonia.scm.installer;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.repository.HgConfig;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import sonia.scm.net.ahc.AdvancedHttpClient;
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.io.INIConfiguration;
|
||||
import sonia.scm.io.INIConfigurationReader;
|
||||
import sonia.scm.io.INIConfigurationWriter;
|
||||
import sonia.scm.io.INISection;
|
||||
import sonia.scm.util.ValidationUtil;
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import sonia.scm.io.INIConfigurationReader;
|
||||
import sonia.scm.io.INIConfigurationWriter;
|
||||
import sonia.scm.io.INISection;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.repository.spi.HgRepositoryServiceProvider;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import sonia.scm.util.IOUtil;
|
||||
@@ -111,9 +112,10 @@ public class HgRepositoryHandler
|
||||
@Inject
|
||||
public HgRepositoryHandler(ConfigurationStoreFactory storeFactory,
|
||||
Provider<HgContext> hgContextProvider,
|
||||
RepositoryLocationResolver repositoryLocationResolver)
|
||||
RepositoryLocationResolver repositoryLocationResolver,
|
||||
PluginLoader pluginLoader)
|
||||
{
|
||||
super(storeFactory, repositoryLocationResolver);
|
||||
super(storeFactory, repositoryLocationResolver, pluginLoader);
|
||||
this.hgContextProvider = hgContextProvider;
|
||||
|
||||
try
|
||||
|
||||
@@ -41,7 +41,6 @@ import com.aragost.javahg.internals.AbstractCommand;
|
||||
import com.aragost.javahg.internals.HgInputStream;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import sonia.scm.repository.FileObject;
|
||||
import sonia.scm.repository.SubRepository;
|
||||
@@ -52,7 +51,6 @@ import java.io.IOException;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mercurial command to list files of a repository.
|
||||
|
||||
@@ -44,7 +44,6 @@ import sonia.scm.web.filter.PermissionFilter;
|
||||
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.HgConfig;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.web.HgVndMediaType;
|
||||
|
||||
@@ -3,11 +3,9 @@ package sonia.scm.api.v2.resources;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.HgConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.installer.HgPackage;
|
||||
import sonia.scm.installer.HgPackageReader;
|
||||
import sonia.scm.net.ahc.AdvancedHttpClient;
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.installer.HgPackage;
|
||||
import sonia.scm.installer.HgPackages;
|
||||
|
||||
|
||||
@@ -16,15 +16,15 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.HgConfig;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.web.HgVndMediaType;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
@@ -99,7 +99,7 @@ public class HgConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readWrite")
|
||||
public void shouldGetHgConfigEvenWhenItsEmpty() throws URISyntaxException {
|
||||
public void shouldGetHgConfigEvenWhenItsEmpty() throws URISyntaxException, UnsupportedEncodingException {
|
||||
when(repositoryHandler.getConfig()).thenReturn(null);
|
||||
|
||||
MockHttpResponse response = get();
|
||||
@@ -110,7 +110,7 @@ public class HgConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readOnly")
|
||||
public void shouldGetHgConfigWithoutUpdateLink() throws URISyntaxException {
|
||||
public void shouldGetHgConfigWithoutUpdateLink() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpResponse response = get();
|
||||
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
|
||||
@@ -3,8 +3,6 @@ package sonia.scm.api.v2.resources;
|
||||
import sonia.scm.installer.HgPackage;
|
||||
import sonia.scm.repository.HgConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.HgConfig;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@@ -77,7 +77,7 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
|
||||
|
||||
@Override
|
||||
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory, RepositoryLocationResolver locationResolver, File directory) {
|
||||
HgRepositoryHandler handler = new HgRepositoryHandler(factory, new HgContextProvider(), locationResolver);
|
||||
HgRepositoryHandler handler = new HgRepositoryHandler(factory, new HgContextProvider(), locationResolver, null);
|
||||
|
||||
handler.init(contextProvider);
|
||||
HgTestUtil.checkForSkip(handler);
|
||||
@@ -87,7 +87,7 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
|
||||
|
||||
@Test
|
||||
public void getDirectory() {
|
||||
HgRepositoryHandler repositoryHandler = new HgRepositoryHandler(factory, provider, locationResolver);
|
||||
HgRepositoryHandler repositoryHandler = new HgRepositoryHandler(factory, provider, locationResolver, null);
|
||||
|
||||
HgConfig hgConfig = new HgConfig();
|
||||
hgConfig.setHgBinary("hg");
|
||||
|
||||
@@ -105,7 +105,7 @@ public final class HgTestUtil
|
||||
|
||||
RepositoryLocationResolver repositoryLocationResolver = new RepositoryLocationResolver(context, repoDao, new InitialRepositoryLocationResolver());
|
||||
HgRepositoryHandler handler =
|
||||
new HgRepositoryHandler(new InMemoryConfigurationStoreFactory(), new HgContextProvider(), repositoryLocationResolver);
|
||||
new HgRepositoryHandler(new InMemoryConfigurationStoreFactory(), new HgContextProvider(), repositoryLocationResolver, null);
|
||||
Path repoDir = directory.toPath();
|
||||
when(repoDao.getPath(any())).thenReturn(repoDir);
|
||||
handler.init(context);
|
||||
|
||||
@@ -8,7 +8,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -48,8 +48,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static sonia.scm.web.WireProtocolRequestMockFactory.CMDS_HEADS_KNOWN_NODES;
|
||||
import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.BOOKMARKS;
|
||||
import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.PHASES;
|
||||
|
||||
@@ -37,7 +37,7 @@ import com.google.common.collect.Lists;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -53,9 +53,9 @@ import sonia.scm.io.INIConfigurationWriter;
|
||||
import sonia.scm.io.INISection;
|
||||
import sonia.scm.logging.SVNKitLogger;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.repository.spi.HookEventFacade;
|
||||
import sonia.scm.repository.spi.SvnRepositoryServiceProvider;
|
||||
import sonia.scm.store.ConfigurationStore;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
@@ -97,9 +97,10 @@ public class SvnRepositoryHandler
|
||||
@Inject
|
||||
public SvnRepositoryHandler(ConfigurationStoreFactory storeFactory,
|
||||
HookEventFacade eventFacade,
|
||||
RepositoryLocationResolver repositoryLocationResolver)
|
||||
RepositoryLocationResolver repositoryLocationResolver,
|
||||
PluginLoader pluginLoader)
|
||||
{
|
||||
super(storeFactory, repositoryLocationResolver);
|
||||
super(storeFactory, repositoryLocationResolver, pluginLoader);
|
||||
|
||||
// register logger
|
||||
SVNDebugLog.setDefaultLog(new SVNKitLogger());
|
||||
|
||||
@@ -36,7 +36,6 @@ package sonia.scm.repository.spi;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tmatesoft.svn.core.SVNDirEntry;
|
||||
@@ -53,7 +52,6 @@ import sonia.scm.repository.SvnUtil;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package sonia.scm.api.v2.resources;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.Compatibility;
|
||||
import sonia.scm.repository.SvnConfig;
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.SvnConfig;
|
||||
import sonia.scm.repository.SvnRepositoryHandler;
|
||||
import sonia.scm.web.SvnVndMediaType;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
@@ -98,7 +98,7 @@ public class SvnConfigResourceTest {
|
||||
|
||||
@Test
|
||||
@SubjectAware(username = "readOnly")
|
||||
public void shouldGetSvnConfigWithoutUpdateLink() throws URISyntaxException {
|
||||
public void shouldGetSvnConfigWithoutUpdateLink() throws URISyntaxException, UnsupportedEncodingException {
|
||||
MockHttpResponse response = get();
|
||||
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
|
||||
@@ -11,11 +11,10 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.Compatibility;
|
||||
import sonia.scm.repository.SvnConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@@ -32,14 +32,10 @@
|
||||
package sonia.scm.repository;
|
||||
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
import sonia.scm.repository.spi.HookEventFacade;
|
||||
import sonia.scm.store.ConfigurationStore;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
|
||||
import java.io.File;
|
||||
@@ -47,7 +43,7 @@ import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
@@ -93,7 +89,7 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
|
||||
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory,
|
||||
RepositoryLocationResolver locationResolver,
|
||||
File directory) {
|
||||
SvnRepositoryHandler handler = new SvnRepositoryHandler(factory, null, locationResolver);
|
||||
SvnRepositoryHandler handler = new SvnRepositoryHandler(factory, null, locationResolver, null);
|
||||
|
||||
handler.init(contextProvider);
|
||||
|
||||
@@ -109,7 +105,7 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
|
||||
public void getDirectory() {
|
||||
when(factory.withType(any())).thenCallRealMethod();
|
||||
SvnRepositoryHandler repositoryHandler = new SvnRepositoryHandler(factory,
|
||||
facade, locationResolver);
|
||||
facade, locationResolver, null);
|
||||
|
||||
SvnConfig svnConfig = new SvnConfig();
|
||||
repositoryHandler.setConfig(svnConfig);
|
||||
|
||||
@@ -39,8 +39,6 @@ import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.ChangesetPagingResult;
|
||||
import sonia.scm.repository.Modifications;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@@ -59,7 +59,7 @@ public class DummyRepositoryHandler
|
||||
private final Set<String> existingRepoNames = new HashSet<>();
|
||||
|
||||
public DummyRepositoryHandler(ConfigurationStoreFactory storeFactory, RepositoryLocationResolver repositoryLocationResolver) {
|
||||
super(storeFactory, repositoryLocationResolver);
|
||||
super(storeFactory, repositoryLocationResolver, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,10 +13,11 @@ const styles = {
|
||||
minWidthOfLabel: {
|
||||
minWidth: "4.5rem"
|
||||
},
|
||||
wrapper: {
|
||||
padding: "1rem 1.5rem 0.25rem 1.5rem",
|
||||
border: "1px solid #eee",
|
||||
borderRadius: "5px 5px 0 0"
|
||||
labelSizing: {
|
||||
fontSize: "1rem !important"
|
||||
},
|
||||
noBottomMargin: {
|
||||
marginBottom: "0 !important"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,9 +53,9 @@ class BranchSelector extends React.Component<Props, State> {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"has-background-light field",
|
||||
"field",
|
||||
"is-horizontal",
|
||||
classes.wrapper
|
||||
classes.noBottomMargin
|
||||
)}
|
||||
>
|
||||
<div
|
||||
@@ -65,10 +66,14 @@ class BranchSelector extends React.Component<Props, State> {
|
||||
classes.minWidthOfLabel
|
||||
)}
|
||||
>
|
||||
<label className="label">{label}</label>
|
||||
<label className={classNames("label", classes.labelSizing)}>
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<div className="field is-narrow">
|
||||
<div
|
||||
className={classNames("field is-narrow", classes.noBottomMargin)}
|
||||
>
|
||||
<div className="control">
|
||||
<DropDown
|
||||
className="is-fullwidth"
|
||||
|
||||
@@ -3,14 +3,17 @@ import React from "react";
|
||||
|
||||
type Props = {
|
||||
displayName: string,
|
||||
url: string
|
||||
url: string,
|
||||
disabled: boolean,
|
||||
onClick?: () => void
|
||||
};
|
||||
|
||||
class DownloadButton extends React.Component<Props> {
|
||||
render() {
|
||||
const { displayName, url } = this.props;
|
||||
const { displayName, url, disabled, onClick } = this.props;
|
||||
const onClickOrDefault = !!onClick ? onClick : () => {};
|
||||
return (
|
||||
<a className="button is-large is-link" href={url}>
|
||||
<a className="button is-large is-link" href={url} disabled={disabled} onClick={onClickOrDefault}>
|
||||
<span className="icon is-medium">
|
||||
<i className="fas fa-arrow-circle-down" />
|
||||
</span>
|
||||
|
||||
@@ -72,6 +72,33 @@ class ConfigurationBinder {
|
||||
binder.bind("repository.route", RepoRoute, repoPredicate);
|
||||
}
|
||||
|
||||
bindRepositorySetting(to: string, labelI18nKey: string, linkName: string, RepositoryComponent: any) {
|
||||
|
||||
// create predicate based on the link name of the current repository route
|
||||
// if the linkname is not available, the navigation link and the route are not bound to the extension points
|
||||
const repoPredicate = (props: Object) => {
|
||||
return props.repository && props.repository._links && props.repository._links[linkName];
|
||||
};
|
||||
|
||||
// create NavigationLink with translated label
|
||||
const RepoNavLink = translate(this.i18nNamespace)(({t, url}) => {
|
||||
return this.navLink(url + "/settings" + to, labelI18nKey, t);
|
||||
});
|
||||
|
||||
// bind navigation link to extension point
|
||||
binder.bind("repository.subnavigation", RepoNavLink, repoPredicate);
|
||||
|
||||
|
||||
// route for global configuration, passes the current repository to component
|
||||
const RepoRoute = ({url, repository, ...additionalProps}) => {
|
||||
const link = repository._links[linkName].href;
|
||||
return this.route(url + "/settings" + to, <RepositoryComponent repository={repository} link={link} {...additionalProps}/>);
|
||||
};
|
||||
|
||||
// bind config route to extension point
|
||||
binder.bind("repository.route", RepoRoute, repoPredicate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new ConfigurationBinder();
|
||||
|
||||
@@ -10,7 +10,8 @@ type Props = {
|
||||
buttonLabel: string,
|
||||
fieldLabel: string,
|
||||
errorMessage: string,
|
||||
helpText?: string
|
||||
helpText?: string,
|
||||
validateEntry?: string => boolean
|
||||
};
|
||||
|
||||
type State = {
|
||||
@@ -25,6 +26,15 @@ class AddEntryToTableField extends React.Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
isValid = () => {
|
||||
const {validateEntry} = this.props;
|
||||
if (!this.state.entryToAdd || this.state.entryToAdd === "" || !validateEntry) {
|
||||
return true;
|
||||
} else {
|
||||
return validateEntry(this.state.entryToAdd);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
disabled,
|
||||
@@ -39,7 +49,7 @@ class AddEntryToTableField extends React.Component<Props, State> {
|
||||
label={fieldLabel}
|
||||
errorMessage={errorMessage}
|
||||
onChange={this.handleAddEntryChange}
|
||||
validationError={false}
|
||||
validationError={!this.isValid()}
|
||||
value={this.state.entryToAdd}
|
||||
onReturnPressed={this.appendEntry}
|
||||
disabled={disabled}
|
||||
@@ -48,7 +58,7 @@ class AddEntryToTableField extends React.Component<Props, State> {
|
||||
<AddButton
|
||||
label={buttonLabel}
|
||||
action={this.addButtonClicked}
|
||||
disabled={disabled || this.state.entryToAdd ===""}
|
||||
disabled={disabled || this.state.entryToAdd ==="" || !this.isValid()}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -28,7 +28,7 @@ class NavLink extends React.Component<Props> {
|
||||
|
||||
let showIcon = null;
|
||||
if (icon) {
|
||||
showIcon = (<><i className={icon}></i>{" "}</>);
|
||||
showIcon = (<><i className={icon} />{" "}</>);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -50,8 +50,19 @@ class PrimaryNavigation extends React.Component<Props> {
|
||||
|
||||
createNavigationItems = () => {
|
||||
const navigationItems = [];
|
||||
const { t, links } = this.props;
|
||||
|
||||
const props = {
|
||||
links,
|
||||
label: t("primary-navigation.first-menu")
|
||||
};
|
||||
|
||||
const append = this.createNavigationAppender(navigationItems);
|
||||
if (binder.hasExtension("primary-navigation.first-menu", props)) {
|
||||
navigationItems.push(
|
||||
<ExtensionPoint name="primary-navigation.first-menu" props={props} />
|
||||
);
|
||||
}
|
||||
append("/repos", "/(repo|repos)", "primary-navigation.repositories", "repositories");
|
||||
append("/users", "/(user|users)", "primary-navigation.users", "users");
|
||||
append("/groups", "/(group|groups)", "primary-navigation.groups", "groups");
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//@flow
|
||||
import * as React from "react";
|
||||
import { Link, Route } from "react-router-dom";
|
||||
|
||||
type Props = {
|
||||
to: string,
|
||||
icon?: string,
|
||||
label: string,
|
||||
activeOnlyWhenExact?: boolean,
|
||||
activeWhenMatch?: (route: any) => boolean,
|
||||
children?: React.Node
|
||||
};
|
||||
|
||||
class SubNavigation extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
activeOnlyWhenExact: false
|
||||
};
|
||||
|
||||
isActive(route: any) {
|
||||
const { activeWhenMatch } = this.props;
|
||||
return route.match || (activeWhenMatch && activeWhenMatch(route));
|
||||
}
|
||||
|
||||
renderLink = (route: any) => {
|
||||
const { to, icon, label } = this.props;
|
||||
|
||||
let defaultIcon = "fas fa-cog";
|
||||
if (icon) {
|
||||
defaultIcon = icon;
|
||||
}
|
||||
|
||||
let children = null;
|
||||
if (this.isActive(route)) {
|
||||
children = <ul className="sub-menu">{this.props.children}</ul>;
|
||||
}
|
||||
|
||||
return (
|
||||
<li>
|
||||
<Link className={this.isActive(route) ? "is-active" : ""} to={to}>
|
||||
<i className={defaultIcon} /> {label}
|
||||
</Link>
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { to, activeOnlyWhenExact } = this.props;
|
||||
|
||||
// removes last part of url
|
||||
let parents = to.split("/");
|
||||
parents.splice(-1, 1);
|
||||
let parent = parents.join("/");
|
||||
|
||||
return (
|
||||
<Route
|
||||
path={parent}
|
||||
exact={activeOnlyWhenExact}
|
||||
children={this.renderLink}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SubNavigation;
|
||||
@@ -3,6 +3,7 @@
|
||||
export { default as NavAction } from "./NavAction.js";
|
||||
export { default as NavLink } from "./NavLink.js";
|
||||
export { default as Navigation } from "./Navigation.js";
|
||||
export { default as SubNavigation } from "./SubNavigation.js";
|
||||
export { default as PrimaryNavigation } from "./PrimaryNavigation.js";
|
||||
export { default as PrimaryNavigationLink } from "./PrimaryNavigationLink.js";
|
||||
export { default as Section } from "./Section.js";
|
||||
|
||||
@@ -28,7 +28,7 @@ class ChangesetAuthor extends React.Component<Props> {
|
||||
renderWithMail(name: string, mail: string) {
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<a href={"mailto: " + mail} title={t("changesets.author.mailto") + " " + mail}>
|
||||
<a href={"mailto: " + mail} title={t("changeset.author.mailto") + " " + mail}>
|
||||
{name}
|
||||
</a>
|
||||
);
|
||||
@@ -38,7 +38,7 @@ class ChangesetAuthor extends React.Component<Props> {
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<>
|
||||
{t("changesets.author.prefix")} {child}
|
||||
{t("changeset.author.prefix")} {child}
|
||||
<ExtensionPoint
|
||||
name="changesets.author.suffix"
|
||||
props={{ changeset: this.props.changeset }}
|
||||
|
||||
@@ -29,7 +29,7 @@ class ChangesetButtonGroup extends React.Component<Props> {
|
||||
<i className="fas fa-code-branch"></i>
|
||||
</span>
|
||||
<span className="is-hidden-mobile is-hidden-tablet-only">
|
||||
{t("changesets.buttons.details")}
|
||||
{t("changeset.buttons.details")}
|
||||
</span>
|
||||
</Button>
|
||||
<Button link={sourcesLink}>
|
||||
@@ -37,7 +37,7 @@ class ChangesetButtonGroup extends React.Component<Props> {
|
||||
<i className="fas fa-code"></i>
|
||||
</span>
|
||||
<span className="is-hidden-mobile is-hidden-tablet-only">
|
||||
{t("changesets.buttons.sources")}
|
||||
{t("changeset.buttons.sources")}
|
||||
</span>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
@@ -25,7 +25,7 @@ class ChangesetDiff extends React.Component<Props> {
|
||||
render() {
|
||||
const { changeset, t } = this.props;
|
||||
if (!this.isDiffSupported(changeset)) {
|
||||
return <Notification type="danger">{t("changesets.diff.not-supported")}</Notification>;
|
||||
return <Notification type="danger">{t("changeset.diffNotSupported")}</Notification>;
|
||||
} else {
|
||||
const url = this.createUrl(changeset);
|
||||
return <LoadingDiff url={url} />;
|
||||
|
||||
@@ -21,7 +21,7 @@ class ChangesetList extends React.Component<Props> {
|
||||
/>
|
||||
);
|
||||
});
|
||||
return <div className="box">{content}</div>;
|
||||
return <>{content}</>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class ChangesetRow extends React.Component<Props> {
|
||||
|
||||
<h4 className="has-text-weight-bold is-ellipsis-overflow">
|
||||
<ExtensionPoint
|
||||
name="changesets.changeset.description"
|
||||
name="changeset.description"
|
||||
props={{ changeset, value: description.title }}
|
||||
renderAll={false}
|
||||
>
|
||||
@@ -89,14 +89,14 @@ class ChangesetRow extends React.Component<Props> {
|
||||
<div className={classNames(classes.metadata, "media-right")}>
|
||||
<p className="is-hidden-mobile is-hidden-tablet-only">
|
||||
<Interpolate
|
||||
i18nKey="changesets.changeset.summary"
|
||||
i18nKey="changeset.summary"
|
||||
id={changesetId}
|
||||
time={dateFromNow}
|
||||
/>
|
||||
</p>
|
||||
<p className="is-hidden-desktop">
|
||||
<Interpolate
|
||||
i18nKey="changesets.changeset.short-summary"
|
||||
i18nKey="changeset.shortSummary"
|
||||
id={changesetId}
|
||||
time={dateFromNow}
|
||||
/>
|
||||
|
||||
@@ -18,7 +18,7 @@ class ChangesetTagsCollapsed extends React.Component<Props> {
|
||||
const message = tags.map((tag) => tag.name).join(", ");
|
||||
return (
|
||||
<Tooltip location="top" message={message}>
|
||||
<ChangesetTagBase icon={"fa-tags"} label={ tags.length + " " + t("changesets.tags") } />
|
||||
<ChangesetTagBase icon={"fa-tags"} label={ tags.length + " " + t("changeset.tags") } />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,8 +43,10 @@
|
||||
"previous": "Zurück"
|
||||
},
|
||||
"profile": {
|
||||
"navigation-label": "Navigation",
|
||||
"actions-label": "Aktionen",
|
||||
"navigationLabel": "Profil Navigation",
|
||||
"informationNavLink": "Information",
|
||||
"changePasswordNavLink": "Passwort ändern",
|
||||
"settingsNavLink": "Einstellungen",
|
||||
"username": "Benutzername",
|
||||
"displayName": "Anzeigename",
|
||||
"mail": "E-Mail",
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{
|
||||
"config": {
|
||||
"navigation-title": "Navigation"
|
||||
},
|
||||
"global-config": {
|
||||
"navigationLabel": "Einstellungs Navigation",
|
||||
"globalConfigurationNavLink": "Globale Einstellungen",
|
||||
"title": "Einstellungen",
|
||||
"navigation-label": "Globale Einstellungen",
|
||||
"error-title": "Fehler",
|
||||
"error-subtitle": "Unbekannter Einstellungen Fehler"
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Einstellungen Fehler"
|
||||
},
|
||||
"config-form": {
|
||||
"submit": "Speichern",
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
"title": "Gruppen",
|
||||
"subtitle": "Verwaltung der Gruppen"
|
||||
},
|
||||
"single-group": {
|
||||
"error-title": "Fehler",
|
||||
"error-subtitle": "Unbekannter Gruppen Fehler",
|
||||
"navigation-label": "Navigation",
|
||||
"actions-label": "Aktionen",
|
||||
"information-label": "Informationen",
|
||||
"back-label": "Zurück"
|
||||
"singleGroup": {
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Gruppen Fehler",
|
||||
"menu": {
|
||||
"navigationLabel": "Gruppen Navigation",
|
||||
"informationNavLink": "Informationen",
|
||||
"settingsNavLink": "Einstellungen",
|
||||
"generalNavLink": "Generell",
|
||||
"setPermissionsNavLink": "Berechtigungen"
|
||||
}
|
||||
},
|
||||
"add-group": {
|
||||
"title": "Gruppe erstellen",
|
||||
@@ -43,28 +46,26 @@
|
||||
"placeholder": "Benutzername eingeben",
|
||||
"loading": "Suche...",
|
||||
"no-options": "Kein Vorschlag für Benutzername verfügbar"
|
||||
},
|
||||
|
||||
"group-form": {
|
||||
},
|
||||
"groupForm": {
|
||||
"subtitle": "Gruppe bearbeiten",
|
||||
"submit": "Speichern",
|
||||
"name-error": "Name ist ungültig",
|
||||
"description-error": "Beschreibung ist ungültig",
|
||||
"nameError": "Name ist ungültig",
|
||||
"descriptionError": "Beschreibung ist ungültig",
|
||||
"help": {
|
||||
"nameHelpText": "Eindeutiger Name der Gruppe",
|
||||
"descriptionHelpText": "Eine kurze Beschreibung der Gruppe",
|
||||
"memberHelpText": "Benutzername des Mitglieds der Gruppe"
|
||||
}
|
||||
},
|
||||
"delete-group-button": {
|
||||
"label": "Löschen",
|
||||
"confirm-alert": {
|
||||
"deleteGroup": {
|
||||
"subtitle": "Gruppe löschen",
|
||||
"button": "Löschen",
|
||||
"confirmAlert": {
|
||||
"title": "Gruppe löschen",
|
||||
"message": "Soll die Gruppe wirklich gelöscht werden?",
|
||||
"submit": "Ja",
|
||||
"cancel": "Nein"
|
||||
}
|
||||
},
|
||||
"set-permissions-button": {
|
||||
"label": "Berechtigungen ändern"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
{
|
||||
"form": {
|
||||
"submit-button": {
|
||||
"label": "Berechtigungen speichern"
|
||||
},
|
||||
"set-permissions-successful": "Berechtigungen erfolgreich gespeichert"
|
||||
"setPermissions": {
|
||||
"button": "Berechtigungen speichern",
|
||||
"setPermissionsSuccessful": "Berechtigungen erfolgreich gespeichert"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,41 +11,58 @@
|
||||
"name-invalid": "Der Name des Repository ist ungültig",
|
||||
"contact-invalid": "Der Kontakt muss eine gültige E-Mail Adresse sein"
|
||||
},
|
||||
"help": {
|
||||
"nameHelpText": "Der Name des Repository. Dieser wird Teil der URL des Repository sein.",
|
||||
"typeHelpText": "Der Typ des Repository (Mercurial, Git oder Subversion).",
|
||||
"contactHelpText": "E-Mail Adresse der Person, die für das Repository verantwortlich ist.",
|
||||
"descriptionHelpText": "Eine kurze Beschreibung des Repository."
|
||||
},
|
||||
"repositoryRoot": {
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Repository Fehler",
|
||||
"menu": {
|
||||
"navigationLabel": "Repository Navigation",
|
||||
"informationNavLink": "Informationen",
|
||||
"historyNavLink": "Commits",
|
||||
"sourcesNavLink": "Sources",
|
||||
"settingsNavLink": "Einstellungen",
|
||||
"generalNavLink": "Generell",
|
||||
"permissionsNavLink": "Berechtigungen"
|
||||
}
|
||||
},
|
||||
"overview": {
|
||||
"title": "Repositories",
|
||||
"subtitle": "Übersicht aller verfügbaren Repositories",
|
||||
"create-button": "Repository erstellen"
|
||||
},
|
||||
"repository-root": {
|
||||
"error-title": "Fehler",
|
||||
"error-subtitle": "Unbekannter Repository Fehler",
|
||||
"actions-label": "Aktionen",
|
||||
"back-label": "Zurück",
|
||||
"navigation-label": "Navigation",
|
||||
"history": "Commits",
|
||||
"information": "Informationen",
|
||||
"permissions": "Berechtigungen",
|
||||
"sources": "Sources"
|
||||
"createButton": "Repository erstellen"
|
||||
},
|
||||
"create": {
|
||||
"title": "Repository erstellen",
|
||||
"subtitle": "Erstellen eines neuen Repository"
|
||||
},
|
||||
"repository-form": {
|
||||
"submit": "Speichern"
|
||||
"changesets": {
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Changesets konnten nicht abgerufen werden",
|
||||
"branchSelectorLabel": "Branches"
|
||||
},
|
||||
"edit-nav-link": {
|
||||
"label": "Bearbeiten"
|
||||
},
|
||||
"delete-nav-action": {
|
||||
"label": "Löschen",
|
||||
"confirm-alert": {
|
||||
"title": "Repository löschen",
|
||||
"message": "Soll das Repository wirklich gelöscht werden?",
|
||||
"submit": "Ja",
|
||||
"cancel": "Nein"
|
||||
"changeset": {
|
||||
"description": "Beschreibung",
|
||||
"summary": "Changeset {{id}} wurde committet {{time}}",
|
||||
"shortSummary": "Committet {{id}} {{time}}",
|
||||
"tags": "Tags",
|
||||
"diffNotSupported": "Diff des Changesets wird von diesem Repositorytyp nicht unterstützt",
|
||||
"author": {
|
||||
"prefix": "Verfasst von",
|
||||
"mailto": "Mail senden an"
|
||||
},
|
||||
"buttons": {
|
||||
"details": "Details",
|
||||
"sources": "Sources"
|
||||
}
|
||||
},
|
||||
"repositoryForm": {
|
||||
"subtitle": "Repository bearbeiten",
|
||||
"submit": "Speichern"
|
||||
},
|
||||
"sources": {
|
||||
"file-tree": {
|
||||
"name": "Name",
|
||||
@@ -65,36 +82,8 @@
|
||||
"size": "Größe"
|
||||
}
|
||||
},
|
||||
"changesets": {
|
||||
"diff": {
|
||||
"not-supported": "Diff des Changesets wird von diesem Repositorytyp nicht unterstützt"
|
||||
},
|
||||
"error-title": "Fehler",
|
||||
"error-subtitle": "Changesets konnten nicht abgerufen werden",
|
||||
"changeset": {
|
||||
"id": "ID",
|
||||
"description": "Beschreibung",
|
||||
"contact": "Kontakt",
|
||||
"date": "Datum",
|
||||
"summary": "Changeset {{id}} wurde committet {{time}}",
|
||||
"short-summary": "Committet {{id}} {{time}}"
|
||||
},
|
||||
"tags": "Tags",
|
||||
"author": {
|
||||
"name": "Autor",
|
||||
"mail": "Mail",
|
||||
"prefix": "Verfasst von",
|
||||
"mailto": "Mail senden an"
|
||||
},
|
||||
"buttons": {
|
||||
"details": "Details",
|
||||
"sources": "Sources"
|
||||
}
|
||||
},
|
||||
"branch-selector": {
|
||||
"label": "Branches"
|
||||
},
|
||||
"permission": {
|
||||
"title": "Berechtigungen bearbeiten",
|
||||
"user": "Benutzer",
|
||||
"group": "Gruppe",
|
||||
"error-title": "Fehler",
|
||||
@@ -106,7 +95,7 @@
|
||||
"user-permission": "Benutzerberechtigung",
|
||||
"edit-permission": {
|
||||
"delete-button": "Löschen",
|
||||
"save-button": "Änderungen Speichern"
|
||||
"save-button": "Änderungen speichern"
|
||||
},
|
||||
"advanced-button": {
|
||||
"label": "Erweitert"
|
||||
@@ -146,10 +135,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"nameHelpText": "Der Name des Repository. Dieser wird Teil der URL des Repository sein.",
|
||||
"typeHelpText": "Der Typ des Repository (Mercurial, Git oder Subversion).",
|
||||
"contactHelpText": "E-Mail Adresse der Person, die für das Repository verantwortlich ist.",
|
||||
"descriptionHelpText": "Eine kurze Beschreibung des Repository."
|
||||
"deleteRepo": {
|
||||
"subtitle": "Repository löschen",
|
||||
"button": "Löschen",
|
||||
"confirmAlert": {
|
||||
"title": "Repository löschen",
|
||||
"message": "Soll das Repository wirklich gelöscht werden?",
|
||||
"submit": "Ja",
|
||||
"cancel": "Nein"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,59 +10,55 @@
|
||||
"creationDate": "Erstellt",
|
||||
"lastModified": "Zuletzt bearbeitet"
|
||||
},
|
||||
"users": {
|
||||
"title": "Benutzer",
|
||||
"subtitle": "Verwaltung der Benutzer"
|
||||
},
|
||||
"create-user-button": {
|
||||
"label": "Benutzer erstellen"
|
||||
},
|
||||
"delete-user-button": {
|
||||
"label": "Löschen",
|
||||
"confirm-alert": {
|
||||
"title": "Benutzer löschen",
|
||||
"message": "Soll der Benutzer wirklich gelöscht werden?",
|
||||
"submit": "Ja",
|
||||
"cancel": "Nein"
|
||||
}
|
||||
},
|
||||
"edit-user-button": {
|
||||
"label": "Bearbeiten"
|
||||
},
|
||||
"set-password-button": {
|
||||
"label": "Passwort ändern"
|
||||
},
|
||||
"set-permissions-button": {
|
||||
"label": "Berechtigungen ändern"
|
||||
},
|
||||
"user-form": {
|
||||
"submit": "Speichern"
|
||||
},
|
||||
"add-user": {
|
||||
"title": "Benutzer erstellen",
|
||||
"subtitle": "Erstellen eines neuen Benutzers"
|
||||
},
|
||||
"single-user": {
|
||||
"error-title": "Fehler",
|
||||
"error-subtitle": "Unbekannter Benutzer Fehler",
|
||||
"navigation-label": "Navigation",
|
||||
"actions-label": "Aktionen",
|
||||
"information-label": "Informationen",
|
||||
"back-label": "Zurück"
|
||||
},
|
||||
"validation": {
|
||||
"mail-invalid": "Diese E-Mail ist ungültig",
|
||||
"name-invalid": "Dieser Name ist ungültig",
|
||||
"displayname-invalid": "Dieser Anzeigename ist ungültig"
|
||||
},
|
||||
"password": {
|
||||
"set-password-successful": "Das Passwort wurde erfolgreich gespeichert."
|
||||
},
|
||||
"help": {
|
||||
"usernameHelpText": "Einzigartiger Name des Benutzers",
|
||||
"displayNameHelpText": "Anzeigename des Benutzers",
|
||||
"mailHelpText": "E-Mail Adresse des Benutzers",
|
||||
"adminHelpText": "Ein Administrator kann Repositories, Gruppen und Benutzer erstellen, bearbeiten und löschen.",
|
||||
"activeHelpText": "Aktivierung oder Deaktivierung eines Benutzers"
|
||||
},
|
||||
"users": {
|
||||
"title": "Benutzer",
|
||||
"subtitle": "Verwaltung der Benutzer",
|
||||
"createButton": "Benutzer erstellen"
|
||||
},
|
||||
"singleUser": {
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Benutzer Fehler",
|
||||
"menu": {
|
||||
"navigationLabel": "Benutzer Navigation",
|
||||
"informationNavLink": "Informationen",
|
||||
"settingsNavLink": "Einstellungen",
|
||||
"generalNavLink": "Generell",
|
||||
"setPasswordNavLink": "Passwort",
|
||||
"setPermissionsNavLink": "Berechtigungen"
|
||||
}
|
||||
},
|
||||
"addUser": {
|
||||
"title": "Benutzer erstellen",
|
||||
"subtitle": "Erstellen eines neuen Benutzers"
|
||||
},
|
||||
"deleteUser": {
|
||||
"subtitle": "Benutzer löschen",
|
||||
"button": "Löschen",
|
||||
"confirmAlert": {
|
||||
"title": "Benutzer löschen",
|
||||
"message": "Soll der Benutzer wirklich gelöscht werden?",
|
||||
"submit": "Ja",
|
||||
"cancel": "Nein"
|
||||
}
|
||||
},
|
||||
"singleUserPassword": {
|
||||
"button": "Passwort setzen",
|
||||
"setPasswordSuccessful": "Das Passwort wurde erfolgreich gespeichert."
|
||||
},
|
||||
"userForm": {
|
||||
"subtitle": "Benutzer bearbeiten",
|
||||
"button": "Speichern"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,10 @@
|
||||
"previous": "Previous"
|
||||
},
|
||||
"profile": {
|
||||
"navigation-label": "Navigation",
|
||||
"actions-label": "Actions",
|
||||
"navigationLabel": "Profile Navigation",
|
||||
"informationNavLink": "Information",
|
||||
"changePasswordNavLink": "Change password",
|
||||
"settingsNavLink": "Settings",
|
||||
"username": "Username",
|
||||
"displayName": "Display Name",
|
||||
"mail": "E-Mail",
|
||||
@@ -67,6 +69,6 @@
|
||||
"passwordInvalid": "Password has to be between 6 and 32 characters",
|
||||
"passwordConfirmFailed": "Passwords have to be identical",
|
||||
"submit": "Submit",
|
||||
"changedSuccessfully": "Password successfully changed"
|
||||
"changedSuccessfully": "Password changed successfully"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{
|
||||
"config": {
|
||||
"navigation-title": "Navigation"
|
||||
},
|
||||
"global-config": {
|
||||
"navigationLabel": "Configuration Navigation",
|
||||
"globalConfigurationNavLink": "Global Configuration",
|
||||
"title": "Configuration",
|
||||
"navigation-label": "Global Configuration",
|
||||
"error-title": "Error",
|
||||
"error-subtitle": "Unknown Config Error"
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown Config Error"
|
||||
},
|
||||
"config-form": {
|
||||
"submit": "Submit",
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
"title": "Groups",
|
||||
"subtitle": "Create, read, update and delete groups"
|
||||
},
|
||||
"single-group": {
|
||||
"error-title": "Error",
|
||||
"error-subtitle": "Unknown group error",
|
||||
"navigation-label": "Navigation",
|
||||
"actions-label": "Actions",
|
||||
"information-label": "Information",
|
||||
"back-label": "Back"
|
||||
"singleGroup": {
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown group error",
|
||||
"menu": {
|
||||
"navigationLabel": "Group Navigation",
|
||||
"informationNavLink": "Information",
|
||||
"settingsNavLink": "Settings",
|
||||
"generalNavLink": "General",
|
||||
"setPermissionsNavLink": "Permissions"
|
||||
}
|
||||
},
|
||||
"add-group": {
|
||||
"title": "Create Group",
|
||||
@@ -43,28 +46,26 @@
|
||||
"placeholder": "Enter Member",
|
||||
"loading": "Loading...",
|
||||
"no-options": "No suggestion available"
|
||||
},
|
||||
|
||||
"group-form": {
|
||||
},
|
||||
"groupForm": {
|
||||
"subtitle": "Edit Group",
|
||||
"submit": "Submit",
|
||||
"name-error": "Group name is invalid",
|
||||
"description-error": "Description is invalid",
|
||||
"nameError": "Group name is invalid",
|
||||
"descriptionError": "Description is invalid",
|
||||
"help": {
|
||||
"nameHelpText": "Unique name of the group",
|
||||
"descriptionHelpText": "A short description of the group",
|
||||
"memberHelpText": "Usernames of the group members"
|
||||
}
|
||||
},
|
||||
"delete-group-button": {
|
||||
"label": "Delete",
|
||||
"confirm-alert": {
|
||||
"deleteGroup": {
|
||||
"subtitle": "Delete Group",
|
||||
"button": "Delete",
|
||||
"confirmAlert": {
|
||||
"title": "Delete Group",
|
||||
"message": "Do you really want to delete the group?",
|
||||
"submit": "Yes",
|
||||
"cancel": "No"
|
||||
}
|
||||
},
|
||||
"set-permissions-button": {
|
||||
"label": "Set Permissions"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
{
|
||||
"form": {
|
||||
"submit-button": {
|
||||
"label": "Set Permissions"
|
||||
},
|
||||
"set-permissions-successful": "Permissions set successfully"
|
||||
"setPermissions": {
|
||||
"button": "Set permissions",
|
||||
"setPermissionsSuccessful": "Permissions set successfully"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,41 +11,58 @@
|
||||
"name-invalid": "The repository name is invalid",
|
||||
"contact-invalid": "Contact must be a valid mail address"
|
||||
},
|
||||
"help": {
|
||||
"nameHelpText": "The name of the repository. This name will be part of the repository url.",
|
||||
"typeHelpText": "The type of the repository (e.g. Mercurial, Git or Subversion).",
|
||||
"contactHelpText": "Email address of the person who is responsible for this repository.",
|
||||
"descriptionHelpText": "A short description of the repository."
|
||||
},
|
||||
"repositoryRoot": {
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown repository error",
|
||||
"menu": {
|
||||
"navigationLabel": "Repository Navigation",
|
||||
"informationNavLink": "Information",
|
||||
"historyNavLink": "Commits",
|
||||
"sourcesNavLink": "Sources",
|
||||
"settingsNavLink": "Settings",
|
||||
"generalNavLink": "General",
|
||||
"permissionsNavLink": "Permissions"
|
||||
}
|
||||
},
|
||||
"overview": {
|
||||
"title": "Repositories",
|
||||
"subtitle": "Overview of available repositories",
|
||||
"create-button": "Create Repository"
|
||||
},
|
||||
"repository-root": {
|
||||
"error-title": "Error",
|
||||
"error-subtitle": "Unknown repository error",
|
||||
"actions-label": "Actions",
|
||||
"back-label": "Back",
|
||||
"navigation-label": "Navigation",
|
||||
"history": "Commits",
|
||||
"information": "Information",
|
||||
"permissions": "Permissions",
|
||||
"sources": "Sources"
|
||||
"createButton": "Create Repository"
|
||||
},
|
||||
"create": {
|
||||
"title": "Create Repository",
|
||||
"subtitle": "Create a new repository"
|
||||
},
|
||||
"repository-form": {
|
||||
"submit": "Save"
|
||||
"changesets": {
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Could not fetch changesets",
|
||||
"branchSelectorLabel": "Branches"
|
||||
},
|
||||
"edit-nav-link": {
|
||||
"label": "Edit"
|
||||
},
|
||||
"delete-nav-action": {
|
||||
"label": "Delete",
|
||||
"confirm-alert": {
|
||||
"title": "Delete Repository",
|
||||
"message": "Do you really want to delete the repository?",
|
||||
"submit": "Yes",
|
||||
"cancel": "No"
|
||||
"changeset": {
|
||||
"description": "Description",
|
||||
"summary": "Changeset {{id}} was committed {{time}}",
|
||||
"shortSummary": "Committed {{id}} {{time}}",
|
||||
"tags": "Tags",
|
||||
"diffNotSupported": "Diff of changesets is not supported by the type of repository",
|
||||
"author": {
|
||||
"prefix": "Authored by",
|
||||
"mailto": "Send mail to"
|
||||
},
|
||||
"buttons": {
|
||||
"details": "Details",
|
||||
"sources": "Sources"
|
||||
}
|
||||
},
|
||||
"repositoryForm": {
|
||||
"subtitle": "Edit Repository",
|
||||
"submit": "Save"
|
||||
},
|
||||
"sources": {
|
||||
"file-tree": {
|
||||
"name": "Name",
|
||||
@@ -65,36 +82,8 @@
|
||||
"size": "Size"
|
||||
}
|
||||
},
|
||||
"changesets": {
|
||||
"diff": {
|
||||
"not-supported": "Diff of changesets is not supported by the type of repository"
|
||||
},
|
||||
"error-title": "Error",
|
||||
"error-subtitle": "Could not fetch changesets",
|
||||
"changeset": {
|
||||
"id": "ID",
|
||||
"description": "Description",
|
||||
"contact": "Contact",
|
||||
"date": "Date",
|
||||
"summary": "Changeset {{id}} was committed {{time}}",
|
||||
"short-summary": "Committed {{id}} {{time}}"
|
||||
},
|
||||
"tags": "Tags",
|
||||
"author": {
|
||||
"name": "Author",
|
||||
"mail": "Mail",
|
||||
"prefix": "Authored by",
|
||||
"mailto": "Send mail to"
|
||||
},
|
||||
"buttons": {
|
||||
"details": "Details",
|
||||
"sources": "Sources"
|
||||
}
|
||||
},
|
||||
"branch-selector": {
|
||||
"label": "Branches"
|
||||
},
|
||||
"permission": {
|
||||
"title": "Edit Permissions",
|
||||
"user": "User",
|
||||
"group": "Group",
|
||||
"error-title": "Error",
|
||||
@@ -114,7 +103,7 @@
|
||||
"delete-permission-button": {
|
||||
"label": "Delete",
|
||||
"confirm-alert": {
|
||||
"title": "Delete Permission",
|
||||
"title": "Delete permission",
|
||||
"message": "Do you really want to delete the permission?",
|
||||
"submit": "Yes",
|
||||
"cancel": "No"
|
||||
@@ -146,10 +135,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"nameHelpText": "The name of the repository. This name will be part of the repository url.",
|
||||
"typeHelpText": "The type of the repository (e.g. Mercurial, Git or Subversion).",
|
||||
"contactHelpText": "Email address of the person who is responsible for this repository.",
|
||||
"descriptionHelpText": "A short description of the repository."
|
||||
"deleteRepo": {
|
||||
"subtitle": "Delete Repository",
|
||||
"button": "Delete",
|
||||
"confirmAlert": {
|
||||
"title": "Delete repository",
|
||||
"message": "Do you really want to delete the repository?",
|
||||
"submit": "Yes",
|
||||
"cancel": "No"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,59 +10,55 @@
|
||||
"creationDate": "Creation Date",
|
||||
"lastModified": "Last Modified"
|
||||
},
|
||||
"users": {
|
||||
"title": "Users",
|
||||
"subtitle": "Create, read, update and delete users"
|
||||
},
|
||||
"create-user-button": {
|
||||
"label": "Create User"
|
||||
},
|
||||
"delete-user-button": {
|
||||
"label": "Delete",
|
||||
"confirm-alert": {
|
||||
"title": "Delete User",
|
||||
"message": "Do you really want to delete the user?",
|
||||
"submit": "Yes",
|
||||
"cancel": "No"
|
||||
}
|
||||
},
|
||||
"edit-user-button": {
|
||||
"label": "Edit"
|
||||
},
|
||||
"set-password-button": {
|
||||
"label": "Set Password"
|
||||
},
|
||||
"set-permissions-button": {
|
||||
"label": "Set Permissions"
|
||||
},
|
||||
"user-form": {
|
||||
"submit": "Submit"
|
||||
},
|
||||
"add-user": {
|
||||
"title": "Create User",
|
||||
"subtitle": "Create a new user"
|
||||
},
|
||||
"single-user": {
|
||||
"error-title": "Error",
|
||||
"error-subtitle": "Unknown user error",
|
||||
"navigation-label": "Navigation",
|
||||
"actions-label": "Actions",
|
||||
"information-label": "Information",
|
||||
"back-label": "Back"
|
||||
},
|
||||
"validation": {
|
||||
"mail-invalid": "This email is invalid",
|
||||
"name-invalid": "This name is invalid",
|
||||
"displayname-invalid": "This displayname is invalid"
|
||||
},
|
||||
"password": {
|
||||
"set-password-successful": "Password successfully set"
|
||||
},
|
||||
"help": {
|
||||
"usernameHelpText": "Unique name of the user.",
|
||||
"displayNameHelpText": "Display name of the user.",
|
||||
"mailHelpText": "Email address of the user.",
|
||||
"adminHelpText": "An administrator is able to create, modify and delete repositories, groups and users.",
|
||||
"activeHelpText": "Activate or deactivate the user."
|
||||
},
|
||||
"users": {
|
||||
"title": "Users",
|
||||
"subtitle": "Create, read, update and delete users",
|
||||
"createButton": "Create User"
|
||||
},
|
||||
"singleUser": {
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown user error",
|
||||
"menu": {
|
||||
"navigationLabel": "User Navigation",
|
||||
"informationNavLink": "Information",
|
||||
"settingsNavLink": "Settings",
|
||||
"generalNavLink": "General",
|
||||
"setPasswordNavLink": "Password",
|
||||
"setPermissionsNavLink": "Permissions"
|
||||
}
|
||||
},
|
||||
"addUser": {
|
||||
"title": "Create User",
|
||||
"subtitle": "Create a new user"
|
||||
},
|
||||
"deleteUser": {
|
||||
"subtitle": "Delete User",
|
||||
"button": "Delete",
|
||||
"confirmAlert": {
|
||||
"title": "Delete user",
|
||||
"message": "Do you really want to delete the user?",
|
||||
"submit": "Yes",
|
||||
"cancel": "No"
|
||||
}
|
||||
},
|
||||
"singleUserPassword": {
|
||||
"button": "Set password",
|
||||
"setPasswordSuccessful": "Password successfully set"
|
||||
},
|
||||
"userForm": {
|
||||
"subtitle": "Edit User",
|
||||
"button": "Submit"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,86 +1,87 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Route } from "react-router";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
|
||||
import type { Links } from "@scm-manager/ui-types";
|
||||
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
||||
import GlobalConfig from "./GlobalConfig";
|
||||
import type { History } from "history";
|
||||
import {connect} from "react-redux";
|
||||
import {compose} from "redux";
|
||||
import { getLinks } from "../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
links: Links,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
match: any,
|
||||
history: History
|
||||
};
|
||||
|
||||
class Config extends React.Component<Props> {
|
||||
stripEndingSlash = (url: string) => {
|
||||
if (url.endsWith("/")) {
|
||||
return url.substring(0, url.length - 2);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
matchedUrl = () => {
|
||||
return this.stripEndingSlash(this.props.match.url);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { links, t } = this.props;
|
||||
|
||||
const url = this.matchedUrl();
|
||||
const extensionProps = {
|
||||
links,
|
||||
url
|
||||
};
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<Route path={url} exact component={GlobalConfig} />
|
||||
<ExtensionPoint name="config.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-one-quarter">
|
||||
<Navigation>
|
||||
<Section label={t("config.navigation-title")}>
|
||||
<NavLink
|
||||
to={`${url}`}
|
||||
label={t("global-config.navigation-label")}
|
||||
/>
|
||||
<ExtensionPoint name="config.navigation"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</Section>
|
||||
</Navigation>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => {
|
||||
const links = getLinks(state);
|
||||
return {
|
||||
links
|
||||
};
|
||||
};
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps),
|
||||
translate("config")
|
||||
)(Config);
|
||||
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Route } from "react-router";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
|
||||
import type { Links } from "@scm-manager/ui-types";
|
||||
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
||||
import GlobalConfig from "./GlobalConfig";
|
||||
import type { History } from "history";
|
||||
import { connect } from "react-redux";
|
||||
import { compose } from "redux";
|
||||
import { getLinks } from "../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
links: Links,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
match: any,
|
||||
history: History
|
||||
};
|
||||
|
||||
class Config extends React.Component<Props> {
|
||||
stripEndingSlash = (url: string) => {
|
||||
if (url.endsWith("/")) {
|
||||
return url.substring(0, url.length - 2);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
matchedUrl = () => {
|
||||
return this.stripEndingSlash(this.props.match.url);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { links, t } = this.props;
|
||||
|
||||
const url = this.matchedUrl();
|
||||
const extensionProps = {
|
||||
links,
|
||||
url
|
||||
};
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<Route path={url} exact component={GlobalConfig} />
|
||||
<ExtensionPoint
|
||||
name="config.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-one-quarter">
|
||||
<Navigation>
|
||||
<Section label={t("config.navigationLabel")}>
|
||||
<NavLink
|
||||
to={`${url}`}
|
||||
label={t("config.globalConfigurationNavLink")}
|
||||
/>
|
||||
<ExtensionPoint
|
||||
name="config.navigation"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</Section>
|
||||
</Navigation>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => {
|
||||
const links = getLinks(state);
|
||||
return {
|
||||
links
|
||||
};
|
||||
};
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps),
|
||||
translate("config")
|
||||
)(Config);
|
||||
|
||||
@@ -78,8 +78,8 @@ class GlobalConfig extends React.Component<Props, State> {
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorPage
|
||||
title={t("global-config.error-title")}
|
||||
subtitle={t("global-config.error-subtitle")}
|
||||
title={t("config.errorTitle")}
|
||||
subtitle={t("config.errorSubtitle")}
|
||||
error={error}
|
||||
configUpdatePermission={configUpdatePermission}
|
||||
/>
|
||||
@@ -91,7 +91,7 @@ class GlobalConfig extends React.Component<Props, State> {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Title title={t("global-config.title")} />
|
||||
<Title title={t("config.title")} />
|
||||
{this.renderConfigChangedNotification()}
|
||||
<ConfigForm
|
||||
submitForm={config => this.modifyConfig(config)}
|
||||
|
||||
@@ -143,7 +143,6 @@ class Login extends React.Component<Props, State> {
|
||||
/>
|
||||
<SubmitButton
|
||||
label={t("login.submit")}
|
||||
disabled={this.isInValid()}
|
||||
fullWidth={true}
|
||||
loading={loading}
|
||||
/>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user