feat(repository): improve treeview so its possible to go upper in the tree@@ -1,5 +1,5 @@
{
- "_generatedAtUnix": 1663723391190,
+ "_generatedAtUnix": 1663726257814,
"_hashAlgorithm": "sha1",
"_version": 2,
"islands": {
@@ -22,7 +22,7 @@
"pathSourceMap": "./public/.islands/RepositoryInitialSetup.bundle.js.map"
},
"RepositoryTreeView": {
- "hash": "a554d26afd55e725eeaedac229be2790d72bca85",
+ "hash": "f1affa1ed5c3dc2c543bf07bd799d582bb1292de",
"pathSource": "./app/islands/RepositoryTreeView.tsx",
"pathBundle": "./public/.islands/RepositoryTreeView.bundle.js",
"pathSourceMap": "./public/.islands/RepositoryTreeView.bundle.js.map"
@@ -53,6 +53,10 @@
"hash": "e21209cae1f4aaab6678ac937259c085084abbff",
"pathSource": "./app/views/repository/RepositoryBrowserView.tsx"
},
+ "RepositoryCommitsLogView": {
+ "hash": "2cae832cc936ac1d69fda4ad0ef1a470f1424933",
+ "pathSource": "./app/views/repository/RepositoryCommitsLogView.tsx"
+ },
"RepositoryCreateView": {
"hash": "f141b710674ecd55db0fa429ab73901e30001a39",
"pathSource": "./app/views/repository/RepositoryCreateView.tsx"
@@ -0,0 +1,40 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makeRepositoryService } from "../../services/repository";
+// app views
+import RepositoryCommitsLogView, {
+ RepositoryCommitsLogViewProps,
+} from "../../views/repository/RepositoryCommitsLogView";
+
+const getRepositoryCommitsLogView: ReqHandler = async (request, reply) => {
+ const { orgSlug, repoSlug } =
+ request.params as AppRoutesParams[AppRoute.REPOSITORY_BROWSER]["params"];
+
+ const orgService = makeOrganizationService({ request });
+ const repoService = makeRepositoryService({ request });
+
+ const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+ const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+ if (repo == null) {
+ return reply.status(404).callNotFound();
+ }
+
+ const history = await repoService.getRepositoryCommitLog(repo);
+
+ const reqHandler = reply.makeRequestHandler(request, reply);
+ return reqHandler<RepositoryCommitsLogViewProps>(
+ RepositoryCommitsLogView.name,
+ {
+ parentOrg,
+ repo,
+ history,
+ }
+ );
+};
+
+export default getRepositoryCommitsLogView;
@@ -1,4 +1,5 @@
import { default as getRepositoryBrowserView } from "./getRepositoryBrowserView";
+import { default as getRepositoryCommitsLogView } from "./getRepositoryCommitsLogView";
import { default as getRepositoryCreateView } from "./getRepositoryCreateView";
import { default as getRepositoryDetailsView } from "./getRepositoryDetailsView";
import { default as getRepositoryExploreView } from "./getRepositoryExploreView";
@@ -6,6 +7,7 @@ import { default as postRepositoryCreateAction } from "./postRepositoryCreateAct
export const RepositoryController = {
getRepositoryBrowserView,
+ getRepositoryCommitsLogView,
getRepositoryCreateView,
getRepositoryDetailsView,
getRepositoryExploreView,
@@ -37,6 +37,22 @@ const RepositoryTreeView: ReactIsland<RepositoryTreeViewProps> = ({
[orgSlug, repoSlug, currPath]
);
+ const currPathParts = currPath.split("/");
+
+ let prevPath: string | null = currPathParts
+ .slice(0, currPathParts.length - 2)
+ .join("/");
+ prevPath = prevPath.trim() === "" ? null : prevPath;
+ prevPath = prevPath == null ? "/" : prevPath;
+
+ const prevPathLink =
+ prevPath === "/"
+ ? `/${orgSlug}/${repoSlug}`
+ : `/${orgSlug}/${repoSlug}/main/tree/${
+ prevPath.endsWith("/") ? prevPath : `${prevPath}/`
+ }`;
+ const shouldShowPrevPath = currPath !== "/";
+
return (
<StyledRepositoryTreeViewContainer>
<div>
@@ -52,9 +68,15 @@ const RepositoryTreeView: ReactIsland<RepositoryTreeViewProps> = ({
</span>
{" ∙ "}
<span>{new Date(lastCommit.author.date).toUTCString()}</span>
+ <a href={`/${orgSlug}/${repoSlug}/commits`}>History</a>
</div>
<div>
<ul>
+ {shouldShowPrevPath && (
+ <li key={"go-previous"}>
+ <a href={prevPathLink}>..</a>
+ </li>
+ )}
{repoFiles.map((file) => {
const fileLink = buildRepoFileLink(file);
return (
@@ -24,6 +24,7 @@ export enum AppRoute {
AUTH_LOGOUT_ACTION = "auth.logout.action",
USER_DASHBOARD = "user.dashboard",
REPOSITORY_EXPLORE = "repository.explore",
+ REPOSITORY_COMMITS_LOG = "repository.commits_log",
REPOSITORY_CREATE = "repository.create",
REPOSITORY_CREATE_ACTION = "repository.create.action",
REPOSITORY_DETAILS = "repository.details",
@@ -53,6 +54,12 @@ export interface AppRoutesParams extends IRouteParams {
[AppRoute.AUTH_LOGOUT_ACTION]: undefined;
[AppRoute.USER_DASHBOARD]: undefined;
[AppRoute.REPOSITORY_EXPLORE]: undefined;
+ [AppRoute.REPOSITORY_COMMITS_LOG]: {
+ params: {
+ orgSlug: string;
+ repoSlug: string;
+ };
+ };
[AppRoute.REPOSITORY_CREATE]: undefined;
[AppRoute.REPOSITORY_CREATE_ACTION]: {
body: {
@@ -128,6 +135,21 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
[AppRoute.AUTH_LOGOUT_ACTION]: undefined,
[AppRoute.USER_DASHBOARD]: undefined,
[AppRoute.REPOSITORY_EXPLORE]: undefined,
+ [AppRoute.REPOSITORY_COMMITS_LOG]: {
+ params: {
+ type: "object",
+ required: ["orgSlug", "repoSlug"],
+ additionalProperties: false,
+ properties: {
+ orgSlug: {
+ type: "string",
+ },
+ repoSlug: {
+ type: "string",
+ },
+ },
+ },
+ },
[AppRoute.REPOSITORY_CREATE]: undefined,
[AppRoute.REPOSITORY_CREATE_ACTION]: {
body: {
@@ -308,6 +330,14 @@ const RootAppRouter: AppRouter = () => {
path={"/repo/explore"}
handler={RepositoryController.getRepositoryExploreView}
/>
+ <Router.Route
+ name={AppRoute.REPOSITORY_COMMITS_LOG}
+ method={"GET"}
+ path={"/:orgSlug/:repoSlug/commits"}
+ preHandler={loggedOrLoginRedirect}
+ schema={AppRoutesSchemas[AppRoute.REPOSITORY_COMMITS_LOG]}
+ handler={RepositoryController.getRepositoryCommitsLogView}
+ />
<Router.Route
name={AppRoute.REPOSITORY_CREATE}
method={"GET"}
@@ -16,7 +16,7 @@ const makeGetRepositoryCommitLog: ServiceMethodFactory<
[Repository, string | undefined, string | undefined, boolean | undefined],
Promise<RepositoryLog[]>
> = ({ request }) => {
- return async (repo, path = undefined, ref = "HEAD", onlyLast = false) => {
+ return async (repo, path = "", ref = "HEAD", onlyLast = false) => {
const parentOrg = await request.prisma.organization.findUnique({
where: {
id: repo.organizationId,
@@ -37,12 +37,11 @@ const makeGetRepositoryCommitLog: ServiceMethodFactory<
var format =
"{%n ^@^commit^@^: ^@^%H^@^,%n ^@^abbreviated_commit^@^: ^@^%h^@^,%n ^@^tree^@^: ^@^%T^@^,%n ^@^abbreviated_tree^@^: ^@^%t^@^,%n ^@^parent^@^: ^@^%P^@^,%n ^@^abbreviated_parent^@^: ^@^%p^@^,%n ^@^refs^@^: ^@^%D^@^,%n ^@^encoding^@^: ^@^%e^@^,%n ^@^subject^@^: ^@^%s^@^,%n ^@^sanitized_subject_line^@^: ^@^%f^@^,%n ^@^body^@^: ^@^%b^@^,%n ^@^commit_notes^@^: ^@^%N^@^,%n ^@^verification_flag^@^: ^@^%G?^@^,%n ^@^signer^@^: ^@^%GS^@^,%n ^@^signer_key^@^: ^@^%GK^@^,%n ^@^author^@^: {%n ^@^name^@^: ^@^%aN^@^,%n ^@^email^@^: ^@^%aE^@^,%n ^@^date^@^: ^@^%aD^@^%n },%n ^@^commiter^@^: {%n ^@^name^@^: ^@^%cN^@^,%n ^@^email^@^: ^@^%cE^@^,%n ^@^date^@^: ^@^%cD^@^%n }%n},";
- path;
const args = [
"log",
"--quiet",
`--pretty=format:${format}`,
- onlyLast ? "-1" : "",
+ onlyLast ? "-1" : null,
ref,
path != null && path.trim() !== "" ? "--" : null,
path != null && path.trim() !== "" ? "-p" : null,
@@ -52,8 +51,6 @@ const makeGetRepositoryCommitLog: ServiceMethodFactory<
cwd: repoPath,
});
- console.log(`$ git ${args.join(" ")}`);
-
const gitLogResult = await new Promise<RepositoryLog[]>(
(resolve, reject) => {
let buffer = [] as string[];
@@ -0,0 +1,66 @@
+// 1st-party
+import type { ReactView } from "@ethicdevs/react-monolith";
+// 3rd-party
+import React from "react";
+// generated via script[generate:prisma]
+import type { Organization, Repository } from "@prisma/client";
+// app
+import type { CommonProps, RepositoryLog } from "../../types";
+import { Layout, PageWrapper } from "../../components";
+
+export interface RepositoryCommitsLogViewProps extends CommonProps {
+ history: RepositoryLog[];
+ parentOrg: Organization;
+ repo: Repository;
+}
+
+const RepositoryCommitsLogView: ReactView<RepositoryCommitsLogViewProps> = ({
+ commonProps,
+ history,
+ parentOrg,
+ repo,
+}) => {
+ return (
+ <Layout {...commonProps}>
+ <PageWrapper>
+ <h1>
+ <a href={`/${parentOrg.slug}`}>
+ {parentOrg.displayName || parentOrg.slug}
+ </a>
+ {" / "}
+ <a href={`/${parentOrg.slug}/${repo.slug}`}>
+ {repo.displayName || repo.slug}
+ </a>
+ {" / Commits"}
+ </h1>
+ <div style={{ width: "100%" }}>
+ <ul>
+ {history.map((log) => (
+ <li key={log.tree}>
+ <a
+ href={`/${parentOrg.slug}/${repo.slug}/commits/${log.commit}`}
+ >
+ <strong>{log.author.name}</strong>
+ {" ∙ "}
+ <span>{log.subject}</span>
+ {" - "}
+ <span>
+ {log.abbreviated_commit}
+ {log.abbreviated_parent.trim() != ""
+ ? ` ∙ parent ${log.abbreviated_parent}`
+ : ""}
+ </span>
+ {" ∙ "}
+ <span>{new Date(log.author.date).toUTCString()}</span>
+ </a>
+ </li>
+ ))}
+ </ul>
+ </div>
+ </PageWrapper>
+ </Layout>
+ );
+};
+
+RepositoryCommitsLogView.displayName = "RepositoryCommitsLogView";
+export default RepositoryCommitsLogView;