feat(ui): colonne tags de versions à gauche du graph Git — #193
This commit is contained in:
@ -69,6 +69,8 @@ const LANE_W = 16;
|
||||
const ROW_H = 36;
|
||||
/** Radius of the commit dot. */
|
||||
const DOT_R = 4.5;
|
||||
/** Stable version tag column, kept outside the DAG lanes. */
|
||||
const TAGS_COL_W = 112;
|
||||
|
||||
/** Horizontal centre of a lane. */
|
||||
const laneX = (lane: number) => lane * LANE_W + LANE_W / 2;
|
||||
@ -283,6 +285,8 @@ export function GitGraphView({ projectId }: GitGraphViewProps) {
|
||||
)}
|
||||
{vm.rows.map((row) => {
|
||||
const isSelected = row.commit.hash === selectedHash;
|
||||
const tagRefs = row.commit.refs.filter(isTag);
|
||||
const branchRefs = row.commit.refs.filter((ref) => !isTag(ref));
|
||||
return (
|
||||
<div
|
||||
key={row.commit.hash}
|
||||
@ -297,21 +301,36 @@ export function GitGraphView({ projectId }: GitGraphViewProps) {
|
||||
)}
|
||||
style={{ height: ROW_H }}
|
||||
>
|
||||
{/* Version tags live in their own stable column, left of the DAG. */}
|
||||
<div
|
||||
data-testid={`git-tags-cell-${row.commit.hash.slice(0, 8)}`}
|
||||
className="flex shrink-0 items-center gap-1 overflow-hidden"
|
||||
style={{ width: TAGS_COL_W }}
|
||||
>
|
||||
{tagRefs.map((ref) => (
|
||||
<span
|
||||
key={ref}
|
||||
title={ref}
|
||||
className="min-w-0 max-w-full truncate rounded bg-warning/20 px-1 py-0.5 text-xs font-medium text-warning"
|
||||
>
|
||||
{ref}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* SVG lanes + node */}
|
||||
<GraphColumn row={row} laneCount={laneCount} />
|
||||
|
||||
{/* Ref badges */}
|
||||
{row.commit.refs.length > 0 && (
|
||||
<div className="flex shrink-0 flex-wrap gap-1">
|
||||
{row.commit.refs.map((ref) => (
|
||||
{/* Branch refs stay beside the graph in the existing refs zone. */}
|
||||
{branchRefs.length > 0 && (
|
||||
<div
|
||||
data-testid={`git-branch-refs-cell-${row.commit.hash.slice(0, 8)}`}
|
||||
className="flex shrink-0 flex-wrap gap-1"
|
||||
>
|
||||
{branchRefs.map((ref) => (
|
||||
<span
|
||||
key={ref}
|
||||
className={cn(
|
||||
"rounded px-1 py-0.5 text-xs font-medium",
|
||||
isTag(ref)
|
||||
? "bg-warning/20 text-warning"
|
||||
: "bg-primary/20 text-primary",
|
||||
)}
|
||||
className="rounded bg-primary/20 px-1 py-0.5 text-xs font-medium text-primary"
|
||||
>
|
||||
{ref}
|
||||
</span>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
* - Clicking close hides the detail panel.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, waitFor, fireEvent } from "@testing-library/react";
|
||||
|
||||
import { MockGitGateway } from "@/adapters/mock";
|
||||
@ -22,7 +22,7 @@ import { GitGraphView } from "./GitGraphView";
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function renderView(git: MockGitGateway = new MockGitGateway()) {
|
||||
function renderView(git: unknown = new MockGitGateway()) {
|
||||
const gateways = { git } as unknown as Gateways;
|
||||
return render(
|
||||
<DIProvider gateways={gateways}>
|
||||
@ -71,6 +71,10 @@ describe("GitGraphView", () => {
|
||||
expect(tagBadge).toBeTruthy();
|
||||
// Tag badge should have the warning colour class
|
||||
expect(tagBadge.className).toMatch(/warning/);
|
||||
const tagCell = screen.getByTestId("git-tags-cell-aaaaaaaa");
|
||||
expect(tagCell.textContent).toContain("tag: v1.0");
|
||||
expect(tagCell.style.width).toBe("112px");
|
||||
expect(tagBadge.className).toMatch(/truncate/);
|
||||
});
|
||||
|
||||
it("shows 'feature' branch badge", async () => {
|
||||
@ -82,6 +86,29 @@ describe("GitGraphView", () => {
|
||||
expect(featureBadge.className).toMatch(/primary/);
|
||||
});
|
||||
|
||||
it("keeps tags in the left tag column and branches in the refs zone", async () => {
|
||||
renderView({
|
||||
graph: vi.fn(async () => [
|
||||
{
|
||||
hash: "1111111111111111111111111111111111111111",
|
||||
summary: "Release build",
|
||||
parents: [],
|
||||
refs: ["main", "tag: v2026.08.14-long-release-name"],
|
||||
author: "Alice",
|
||||
timestamp: 1_717_200_000,
|
||||
},
|
||||
]),
|
||||
});
|
||||
await waitForCommits();
|
||||
|
||||
const tagCell = screen.getByTestId("git-tags-cell-11111111");
|
||||
const branchCell = screen.getByTestId("git-branch-refs-cell-11111111");
|
||||
expect(tagCell.textContent).toContain("tag: v2026.08.14-long-release-name");
|
||||
expect(tagCell.textContent).not.toContain("main");
|
||||
expect(branchCell.textContent).toContain("main");
|
||||
expect(branchCell.textContent).not.toContain("tag: v2026.08.14-long-release-name");
|
||||
});
|
||||
|
||||
it("clicking a commit row opens the detail panel", async () => {
|
||||
renderView();
|
||||
await waitForCommits();
|
||||
|
||||
Reference in New Issue
Block a user