feat(repository): add support for all kind of images to RepositoryBrowserView@@ -1,5 +1,5 @@
{
- "_generatedAtUnix": 1663770947993,
+ "_generatedAtUnix": 1663773368816,
"_hashAlgorithm": "sha1",
"_version": 2,
"islands": {
@@ -50,7 +50,7 @@
"pathSource": "./app/views/auth/RegisterView.tsx"
},
"RepositoryBrowserView": {
- "hash": "2d4e879f98bd3a8316e1e86bd97baee50e515b2e",
+ "hash": "932ee3dcdabd946d727876e494b58264c3043069",
"pathSource": "./app/views/repository/RepositoryBrowserView.tsx"
},
"RepositoryCommitsLogView": {
@@ -82,19 +82,24 @@ const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
});
}
- let fileContent = await repoService.getRepositoryFileContent(repo, path, ref);
+ let linguistInfos = await request.codeAnalysisService.getLinguistFileInfos(
+ path
+ );
+
+ let fileContent =
+ linguistInfos.type === "image"
+ ? await repoService.getRepositoryFileContentBase64(repo, path, ref)
+ : await repoService.getRepositoryFileContent(repo, path, ref);
if (fileContent == null) {
return reply.status(404).callNotFound();
}
- const linguistInfos = await request.codeAnalysisService.getLinguistFileInfos(
+ linguistInfos = await request.codeAnalysisService.getLinguistFileInfos(
path,
fileContent.content
);
- fileContent.mimeType = linguistInfos.mimeType;
-
return reqHandler<RepositoryBrowserViewProps>(RepositoryBrowserView.name, {
currentUser,
fileContent,
@@ -56,7 +56,7 @@ const makeGetRepositoryFileContent: ServiceMethodFactory<
reject(new Error(Buffer.from(data).toString("utf-8")));
});
gitCatFileProcess.stdout.on("close", () => {
- resolve(buffer.join(""));
+ resolve(Buffer.from(buffer.join("")).toString("utf-8"));
});
});
@@ -0,0 +1,86 @@
+// std
+import { existsSync } from "node:fs";
+import { spawn } from "node:child_process";
+// 1st-party
+import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
+// generated via script[generate:prisma]
+import type { Repository } from "@prisma/client";
+// app
+import { Env } from "../../env";
+// service
+import type { RepositoryFileContent } from "../../types";
+import type { RepositoryServiceDeps } from "./types";
+
+const makeGetRepositoryFileContentBase64: ServiceMethodFactory<
+ RepositoryServiceDeps,
+ [Repository, string, string | undefined],
+ Promise<null | RepositoryFileContent>
+> = ({ request }) => {
+ return async (repo, path, ref = "HEAD") => {
+ if (path.endsWith("/")) {
+ throw new Error("Could not retrieve file content for a folder.");
+ }
+
+ const parentOrg = await request.prisma.organization.findUnique({
+ where: {
+ id: repo.organizationId,
+ },
+ });
+
+ if (parentOrg == null) {
+ throw new Error(
+ `Could not find the parent organization for project "${repo.slug}".`
+ );
+ }
+
+ try {
+ const repoPath = `${Env.GIT_REPOSITORIES_ROOT}/${parentOrg.slug}/${repo.slug}.git`;
+ if (existsSync(repoPath) === false) {
+ throw new Error(
+ `Could not find a valid git repository at: ${repoPath}`
+ );
+ }
+
+ const gitCatFileProcess = spawn(
+ "git",
+ ["cat-file", "-p", `${ref}:${path}`],
+ {
+ cwd: repoPath,
+ }
+ );
+
+ // pipe gitCatFileProcess stdout into base64 stdin
+ const base64FileProcess = spawn("base64", [], {
+ cwd: repoPath,
+ stdio: [gitCatFileProcess.stdout, "pipe"],
+ });
+
+ const gitCatFileResult = await new Promise<string>((resolve, reject) => {
+ let buffer = [] as string[];
+ base64FileProcess.stdout?.on("data", (data) => buffer.push(data));
+ base64FileProcess.stderr?.on("data", (data) => {
+ reject(new Error(Buffer.from(data).toString("utf-8")));
+ });
+ base64FileProcess.stdout?.on("close", () => {
+ resolve(buffer.join(""));
+ });
+ });
+
+ const { mimeType } =
+ await request.codeAnalysisService.getLinguistFileInfos(
+ path,
+ gitCatFileResult
+ );
+
+ return {
+ content: `data:${mimeType};base64,${gitCatFileResult}`,
+ mimeType,
+ };
+ } catch (_) {
+ console.error("err:", _);
+ return null;
+ }
+ };
+};
+
+export default makeGetRepositoryFileContentBase64;
@@ -8,6 +8,7 @@ import { default as makeGetRepository } from "./getRepository";
import { default as makeGetRepositoryCommitLog } from "./getRepositoryCommitLog";
import { default as makeGetRepositoryExploreCollection } from "./getRepositoryExploreCollection";
import { default as makeGetRepositoryFileContent } from "./getRepositoryFileContent";
+import { default as makeGetRepositoryFileContentBase64 } from "./getRepositoryFileContentBase64";
import { default as makeGetRepositoryFiles } from "./getRepositoryFiles";
import { default as makeGetRepositoryHead } from "./getRepositoryHead";
import { default as makeGetRepositoryHTTPCloneUrl } from "./getRepositoryHTTPCloneUrl";
@@ -23,6 +24,7 @@ export const makeRepositoryService = makeService<
getRepositoryCommitLog: makeGetRepositoryCommitLog,
getRepositoryExploreCollection: makeGetRepositoryExploreCollection,
getRepositoryFileContent: makeGetRepositoryFileContent,
+ getRepositoryFileContentBase64: makeGetRepositoryFileContentBase64,
getRepositoryFiles: makeGetRepositoryFiles,
getRepositoryHead: makeGetRepositoryHead,
getRepositoryHTTPCloneUrl: makeGetRepositoryHTTPCloneUrl,
@@ -46,6 +46,11 @@ export interface RepositoryServiceAPI extends ServiceApiContract {
path: string,
ref?: string
): Promise<null | RepositoryFileContent>;
+ getRepositoryFileContentBase64(
+ repository: Repository,
+ path: string,
+ ref?: string
+ ): Promise<null | RepositoryFileContent>;
getRepositoryFiles(
repository: Repository,
path?: string,
@@ -14,6 +14,7 @@ import {
Layout,
PageWrapper,
getThemedCodeCss,
+ Card,
} from "../../components";
export interface RepositoryBrowserViewProps extends CommonProps {
@@ -62,12 +63,15 @@ const RepositoryBrowserView: ReactView<RepositoryBrowserViewProps> = ({
</div>
</Grid.Row>
{linguistInfos.type === "image" ? (
- <img
- src={`data:${fileContent.mimeType};base64,${Buffer.from(
- fileContent.content
- ).toString("base64")}`}
- style={{ width: "100%", height: "auto" }}
- />
+ <Card
+ style={{ width: "100%" }}
+ themeScheme={commonProps.themeScheme}
+ >
+ <img
+ src={fileContent.content}
+ style={{ width: "100%", height: "auto" }}
+ />
+ </Card>
) : (
<>
{getThemedCodeCss(commonProps.themeScheme)}