mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-01 19:15:52 +01:00
Svn external contains sub directory
In case of using Svn external with sub directory the ui showed an empty page Committed-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com>
This commit is contained in:
@@ -59,19 +59,19 @@ const ExtensionTd = styled.td`
|
||||
}
|
||||
`;
|
||||
|
||||
const FileName: FC<{ file: File; baseUrl: string }> = ({ file, baseUrl }) => {
|
||||
const FileName: FC<{ file: File; baseUrl: string; repositoryType: string }> = ({ file, baseUrl, repositoryType }) => {
|
||||
const ref = useKeyboardIteratorTarget();
|
||||
return (
|
||||
<FileLink ref={ref} baseUrl={baseUrl} file={file} tabIndex={0}>
|
||||
<FileLink ref={ref} baseUrl={baseUrl} file={file} tabIndex={0} repositoryType={repositoryType}>
|
||||
{file.name}
|
||||
</FileLink>
|
||||
);
|
||||
};
|
||||
|
||||
class FileTreeLeaf extends React.Component<Props> {
|
||||
createFileIcon = (file: File) => {
|
||||
createFileIcon = (file: File, repositoryType: string) => {
|
||||
return (
|
||||
<FileLink baseUrl={this.props.baseUrl} file={file} tabIndex={-1}>
|
||||
<FileLink baseUrl={this.props.baseUrl} file={file} tabIndex={-1} repositoryType={repositoryType}>
|
||||
<FileIcon file={file} />
|
||||
</FileLink>
|
||||
);
|
||||
@@ -112,9 +112,9 @@ class FileTreeLeaf extends React.Component<Props> {
|
||||
return (
|
||||
<>
|
||||
<tr>
|
||||
<td>{this.createFileIcon(file)}</td>
|
||||
<td>{this.createFileIcon(file, repository.type)}</td>
|
||||
<MinWidthTd className="is-word-break">
|
||||
<FileName file={file} baseUrl={baseUrl} />
|
||||
<FileName file={file} baseUrl={baseUrl} repositoryType={repository.type} />
|
||||
</MinWidthTd>
|
||||
<NoWrapTd className="is-hidden-mobile">
|
||||
{file.directory ? "" : this.contentIfPresent(file, "length", renderFileSize)}
|
||||
|
||||
@@ -28,13 +28,31 @@ import { File } from "@scm-manager/ui-types";
|
||||
|
||||
describe("create relative link tests", () => {
|
||||
it("should create relative link", () => {
|
||||
expect(createRelativeLink("http://localhost:8081/scm/repo/scmadmin/scm-manager")).toBe(
|
||||
"/scm/repo/scmadmin/scm-manager"
|
||||
expect(createRelativeLink("http://localhost:8081/scm/repo/scmadmin/scm-manager", "/scm")).toBe(
|
||||
"/repo/scmadmin/scm-manager/code/sources/"
|
||||
);
|
||||
expect(createRelativeLink("ssh://_anonymous@repo.scm-manager.org:1234/repo/public/anonymous-access")).toBe(
|
||||
"/repo/public/anonymous-access"
|
||||
expect(createRelativeLink("ssh://_anonymous@repo.scm-manager.org:1234/repo/public/anonymous-access", "")).toBe(
|
||||
"/repo/public/anonymous-access/code/sources/"
|
||||
);
|
||||
expect(createRelativeLink("ssh://server.local/project.git", "")).toBe("/project.git/code/sources/");
|
||||
expect(createRelativeLink("https://localhost:8081/scm/repo/scmadmin/scm-manager", "/scm", "2", "svn")).toBe(
|
||||
"/repo/scmadmin/scm-manager/code/sources/2/"
|
||||
);
|
||||
expect(createRelativeLink("https://localhost:8081/longContext/repo/scmadmin/scm-manager", "/longContext")).toBe(
|
||||
"/repo/scmadmin/scm-manager/code/sources/"
|
||||
);
|
||||
});
|
||||
|
||||
it("with sub directory", () => {
|
||||
expect(createRelativeLink("http://localhost:8081/scm/repo/scmadmin/test02/subfolder", "/scm")).toBe(
|
||||
"/repo/scmadmin/test02/code/sources/"
|
||||
);
|
||||
expect(createRelativeLink("https://localhost:8081/scm/repo/scmadmin/test02/subfolder", "/scm", "2")).toBe(
|
||||
"/repo/scmadmin/test02/code/sources/2/subfolder/"
|
||||
);
|
||||
expect(createRelativeLink("http://localhost:8081/scm/repo/scmadmin/test02/dir1/dir2/dir3", "/scm", null, "svn")).toBe(
|
||||
"/repo/scmadmin/test02/code/sources/-1/dir1/dir2/dir3/"
|
||||
);
|
||||
expect(createRelativeLink("ssh://server.local/project.git")).toBe("/project.git");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,8 +66,8 @@ describe("create folder link tests", () => {
|
||||
revision: "1a",
|
||||
_links: {},
|
||||
_embedded: {
|
||||
children: []
|
||||
}
|
||||
children: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -25,16 +25,17 @@ import React, { ReactNode } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { File } from "@scm-manager/ui-types";
|
||||
import { Tooltip } from "@scm-manager/ui-components";
|
||||
import { Tooltip, urls } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string;
|
||||
file: File;
|
||||
children: ReactNode;
|
||||
tabIndex?: number;
|
||||
repositoryType: string;
|
||||
};
|
||||
|
||||
const isLocalRepository = (repositoryUrl: string) => {
|
||||
const getHostname = (repositoryUrl: string) => {
|
||||
let host = repositoryUrl.split("/")[2];
|
||||
if (host.includes("@")) {
|
||||
// remove prefix
|
||||
@@ -44,7 +45,11 @@ const isLocalRepository = (repositoryUrl: string) => {
|
||||
host = host.split(":")[0];
|
||||
// remove query
|
||||
host = host.split("?")[0];
|
||||
return host === window.location.hostname;
|
||||
return host;
|
||||
};
|
||||
|
||||
const isLocalRepository = (repositoryUrl: string) => {
|
||||
return getHostname(repositoryUrl) === window.location.hostname;
|
||||
};
|
||||
|
||||
export const encodePart = (part: string) => {
|
||||
@@ -54,9 +59,30 @@ export const encodePart = (part: string) => {
|
||||
return encodeURIComponent(part);
|
||||
};
|
||||
|
||||
export const createRelativeLink = (repositoryUrl: string) => {
|
||||
export const createRelativeLink = (
|
||||
repositoryUrl: string,
|
||||
contextPath: string,
|
||||
revision?: string,
|
||||
repositoryType?: string
|
||||
) => {
|
||||
const paths = repositoryUrl.split("/");
|
||||
return "/" + paths.slice(3).join("/");
|
||||
const CONTEXT_PART_IN_URL = 3;
|
||||
const FOLDER_PART_IN_URL = 7;
|
||||
|
||||
const folder = paths.splice(FOLDER_PART_IN_URL).join("/");
|
||||
let url = "/" + paths.slice(CONTEXT_PART_IN_URL, FOLDER_PART_IN_URL).join("/");
|
||||
url = url.replace(contextPath, "");
|
||||
url += "/code/sources/";
|
||||
if (revision) {
|
||||
url += revision + "/";
|
||||
if (folder !== "") {
|
||||
url += folder + "/";
|
||||
}
|
||||
} else if (repositoryType === "svn" && folder !== "") {
|
||||
// type of outgoing repo is svn
|
||||
url += `-1/${folder}/`;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
export const createFolderLink = (base: string, file: File) => {
|
||||
@@ -74,49 +100,46 @@ export const createFolderLink = (base: string, file: File) => {
|
||||
return link;
|
||||
};
|
||||
|
||||
const FileLink = React.forwardRef<HTMLAnchorElement, Props>(({ baseUrl, file, children, tabIndex }, ref) => {
|
||||
const [t] = useTranslation("repos");
|
||||
if (file?.subRepository?.repositoryUrl) {
|
||||
// file link represents a subRepository
|
||||
let link = file.subRepository.repositoryUrl;
|
||||
if (file.subRepository.browserUrl) {
|
||||
// replace upstream url with public browser url
|
||||
link = file.subRepository.browserUrl;
|
||||
}
|
||||
if (link.startsWith("http://") || link.startsWith("https://")) {
|
||||
if (file.subRepository.revision && isLocalRepository(link)) {
|
||||
link += "/code/sources/" + file.subRepository.revision;
|
||||
const FileLink = React.forwardRef<HTMLAnchorElement, Props>(
|
||||
({ baseUrl, file, children, tabIndex, repositoryType }, ref) => {
|
||||
const [t] = useTranslation("repos");
|
||||
if (file?.subRepository?.repositoryUrl) {
|
||||
// file link represents a subRepository
|
||||
let link = file.subRepository.repositoryUrl;
|
||||
if (file.subRepository.browserUrl) {
|
||||
// replace upstream url with public browser url
|
||||
link = file.subRepository.browserUrl;
|
||||
}
|
||||
return (
|
||||
<a href={link} tabIndex={tabIndex}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
} else if (link.startsWith("ssh://") && isLocalRepository(link)) {
|
||||
link = createRelativeLink(link);
|
||||
if (file.subRepository.revision) {
|
||||
link += "/code/sources/" + file.subRepository.revision;
|
||||
|
||||
if (isLocalRepository(link)) {
|
||||
link = createRelativeLink(link, urls.withContextPath(""), file.subRepository.revision, repositoryType);
|
||||
return (
|
||||
<Link to={link} tabIndex={tabIndex}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
} else if (link.startsWith("http://") || link.startsWith("https://")) {
|
||||
return (
|
||||
<a href={link} tabIndex={tabIndex}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
// subRepository url cannot be linked
|
||||
return (
|
||||
<Tooltip location="top" message={t("sources.fileTree.subRepository") + ": \n" + link}>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Link to={link} tabIndex={tabIndex}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
// subRepository url cannot be linked
|
||||
return (
|
||||
<Tooltip location="top" message={t("sources.fileTree.subRepository") + ": \n" + link}>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
// normal file or folder
|
||||
return (
|
||||
<Link ref={ref} to={createFolderLink(baseUrl, file)} tabIndex={tabIndex}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
// normal file or folder
|
||||
return (
|
||||
<Link ref={ref} to={createFolderLink(baseUrl, file)} tabIndex={tabIndex}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
export default FileLink;
|
||||
|
||||
Reference in New Issue
Block a user