diff --git a/scm-core/src/main/java/sonia/scm/ConcurrentModificationException.java b/scm-core/src/main/java/sonia/scm/ConcurrentModificationException.java index d566859b4c..990d05181b 100644 --- a/scm-core/src/main/java/sonia/scm/ConcurrentModificationException.java +++ b/scm-core/src/main/java/sonia/scm/ConcurrentModificationException.java @@ -17,7 +17,7 @@ public class ConcurrentModificationException extends ExceptionWithContext { this(Collections.singletonList(new ContextEntry(type, id))); } - private ConcurrentModificationException(List context) { + public ConcurrentModificationException(List context) { super(context, createMessage(context)); } @@ -32,3 +32,4 @@ public class ConcurrentModificationException extends ExceptionWithContext { .collect(joining(" in ", "", " has been modified concurrently")); } } + diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java index 5ec69cccdd..2048d13dea 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java @@ -213,8 +213,14 @@ public class GitBrowseCommand extends AbstractGitCommand if (lfsPointer.isPresent()) { BlobStore lfsBlobStore = lfsBlobStoreFactory.getLfsBlobStore(repository); - Blob blob = lfsBlobStore.get(lfsPointer.get().getOid().getName()); - file.setLength(blob.getSize()); + String oid = lfsPointer.get().getOid().getName(); + Blob blob = lfsBlobStore.get(oid); + if (blob == null) { + logger.error("lfs blob for lob id {} not found in lfs store of repository {}", oid, repository.getNamespaceAndName()); + file.setLength(-1); + } else { + file.setLength(blob.getSize()); + } } else { file.setLength(loader.getSize()); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java index 35ff4d6ac2..193ab5bbc8 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java @@ -145,7 +145,12 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand { private Loader loadFromLfsStore(TreeWalk treeWalk, RevWalk revWalk, LfsPointer lfsPointer) throws IOException { BlobStore lfsBlobStore = lfsBlobStoreFactory.getLfsBlobStore(repository); - Blob blob = lfsBlobStore.get(lfsPointer.getOid().getName()); + String oid = lfsPointer.getOid().getName(); + Blob blob = lfsBlobStore.get(oid); + if (blob == null) { + logger.error("lfs blob for lob id {} not found in lfs store of repository {}", oid, repository.getNamespaceAndName()); + throw notFound(entity("LFS", oid).in(repository)); + } GitUtil.release(revWalk); GitUtil.release(treeWalk); return new BlobLoader(blob); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBrowseCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBrowseCommand.java index 48772ad5e5..b3e8e89a5f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBrowseCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBrowseCommand.java @@ -77,7 +77,9 @@ public class HgBrowseCommand extends AbstractCommand implements BrowseCommand String revision = MoreObjects.firstNonNull(request.getRevision(), "tip"); Changeset c = LogCommand.on(getContext().open()).rev(revision).limit(1).single(); - cmd.rev(c.getNode()); + if (c != null) { + cmd.rev(c.getNode()); + } if (!Strings.isNullOrEmpty(request.getPath())) { @@ -100,6 +102,6 @@ public class HgBrowseCommand extends AbstractCommand implements BrowseCommand } FileObject file = cmd.execute(); - return new BrowserResult(c.getNode(), revision, file); + return new BrowserResult(c == null? "tip": c.getNode(), revision, file); } } diff --git a/scm-ui/ui-components/src/apiclient.ts b/scm-ui/ui-components/src/apiclient.ts index 560b7c5722..babb0b64d7 100644 --- a/scm-ui/ui-components/src/apiclient.ts +++ b/scm-ui/ui-components/src/apiclient.ts @@ -80,7 +80,7 @@ class ApiClient { return fetch(createUrl(url), applyFetchOptions({})).then(handleFailure); } - post(url: string, payload: any, contentType = "application/json") { + post(url: string, payload?: any, contentType = "application/json") { return this.httpRequestWithJSONBody("POST", url, contentType, payload); } @@ -115,11 +115,13 @@ class ApiClient { return fetch(createUrl(url), options).then(handleFailure); } - httpRequestWithJSONBody(method: string, url: string, contentType: string, payload: any): Promise { + httpRequestWithJSONBody(method: string, url: string, contentType: string, payload?: any): Promise { const options: RequestInit = { - method: method, - body: JSON.stringify(payload) + method: method }; + if (payload) { + options.body = JSON.stringify(payload); + } return this.httpRequestWithBinaryBody(options, url, contentType); } diff --git a/scm-ui/ui-components/src/buttons/Button.tsx b/scm-ui/ui-components/src/buttons/Button.tsx index 8c1004ac52..3507ba7a06 100644 --- a/scm-ui/ui-components/src/buttons/Button.tsx +++ b/scm-ui/ui-components/src/buttons/Button.tsx @@ -18,6 +18,7 @@ export type ButtonProps = { type Props = ButtonProps & RouteComponentProps & { + title?: string; type?: "button" | "submit" | "reset"; color?: string; }; @@ -38,7 +39,19 @@ class Button extends React.Component { }; render() { - const { label, loading, disabled, type, color, className, icon, fullWidth, reducedMobile, children } = this.props; + const { + label, + title, + loading, + disabled, + type, + color, + className, + icon, + fullWidth, + reducedMobile, + children + } = this.props; const loadingClass = loading ? "is-loading" : ""; const fullWidthClass = fullWidth ? "is-fullwidth" : ""; const reducedMobileClass = reducedMobile ? "is-reduced-mobile" : ""; @@ -46,6 +59,7 @@ class Button extends React.Component { return (