Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions apps/code/src/main/services/folders/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,82 @@ describe("FoldersService", () => {
]);
});

it("strips .git suffix from remote repo name in display name (defensive against legacy data)", async () => {
const repos = [
{
id: "folder-1",
path: "/home/user/my-billing-fork",
remoteUrl: "PostHog/billing.git",
lastAccessedAt: "2024-01-01T00:00:00.000Z",
createdAt: "2024-01-01T00:00:00.000Z",
updatedAt: "2024-01-01T00:00:00.000Z",
},
];
mockRepositoryRepo.findAll.mockReturnValue(repos);
mockExistsSync.mockReturnValue(true);

const result = await service.getFolders();

expect(result[0].name).toBe("my-billing-fork (billing)");
});

it("uses remote repo name in display name when it differs from local dir", async () => {
const repos = [
{
id: "folder-1",
path: "/home/user/ph-tour-demo",
remoteUrl: "PostHog/hogotchi",
lastAccessedAt: "2024-01-01T00:00:00.000Z",
createdAt: "2024-01-01T00:00:00.000Z",
updatedAt: "2024-01-01T00:00:00.000Z",
},
];
mockRepositoryRepo.findAll.mockReturnValue(repos);
mockExistsSync.mockReturnValue(true);

const result = await service.getFolders();

expect(result[0].name).toBe("ph-tour-demo (hogotchi)");
});

it("uses local dir name when it matches remote repo name", async () => {
const repos = [
{
id: "folder-1",
path: "/home/user/hogotchi",
remoteUrl: "PostHog/hogotchi",
lastAccessedAt: "2024-01-01T00:00:00.000Z",
createdAt: "2024-01-01T00:00:00.000Z",
updatedAt: "2024-01-01T00:00:00.000Z",
},
];
mockRepositoryRepo.findAll.mockReturnValue(repos);
mockExistsSync.mockReturnValue(true);

const result = await service.getFolders();

expect(result[0].name).toBe("hogotchi");
});

it("uses local dir name when it matches remote repo name case-insensitively", async () => {
const repos = [
{
id: "folder-1",
path: "/home/user/Hogotchi",
remoteUrl: "PostHog/hogotchi",
lastAccessedAt: "2024-01-01T00:00:00.000Z",
createdAt: "2024-01-01T00:00:00.000Z",
updatedAt: "2024-01-01T00:00:00.000Z",
},
];
mockRepositoryRepo.findAll.mockReturnValue(repos);
mockExistsSync.mockReturnValue(true);

const result = await service.getFolders();

expect(result[0].name).toBe("Hogotchi");
});

it("marks non-existent folders", async () => {
const repos = [
{
Expand Down
24 changes: 20 additions & 4 deletions apps/code/src/main/services/folders/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import path from "node:path";
import { getRemoteUrl, isGitRepository } from "@posthog/git/queries";
import { InitRepositorySaga } from "@posthog/git/sagas/init";

import { normalizeRepoKey } from "@shared/utils/repo";

function extractRepoKey(url: string): string | null {
const httpsMatch = url.match(/github\.com\/([^/]+\/[^/]+)/);
if (httpsMatch) return httpsMatch[1].replace(/\.git$/, "");
if (httpsMatch) return normalizeRepoKey(httpsMatch[1]);

const sshMatch = url.match(/github\.com:([^/]+\/[^/]+)/);
if (sshMatch) return sshMatch[1].replace(/\.git$/, "");
if (sshMatch) return normalizeRepoKey(sshMatch[1]);

return null;
}
Expand Down Expand Up @@ -80,14 +82,28 @@ export class FoldersService {
}
}

private getDisplayName(
repoPath: string,
remoteUrl: string | null | undefined,
): string {
const localName = path.basename(repoPath);
if (remoteUrl) {
const repoName = normalizeRepoKey(remoteUrl).split("/").pop();
if (repoName && repoName.toLowerCase() !== localName.toLowerCase()) {
return `${localName} (${repoName})`;
}
}
return localName;
}

async getFolders(): Promise<(RegisteredFolder & { exists: boolean })[]> {
const repos = this.repositoryRepo.findAll();
return repos
.filter((r) => r.path)
.map((r) => ({
id: r.id,
path: r.path,
name: path.basename(r.path),
name: this.getDisplayName(r.path, r.remoteUrl),
remoteUrl: r.remoteUrl ?? null,
lastAccessed: r.lastAccessedAt ?? r.createdAt,
createdAt: r.createdAt,
Expand Down Expand Up @@ -177,7 +193,7 @@ export class FoldersService {
return {
id: repo.id,
path: repo.path,
name: path.basename(repo.path),
name: this.getDisplayName(repo.path, repo.remoteUrl),
remoteUrl: repo.remoteUrl ?? null,
lastAccessed: repo.lastAccessedAt ?? repo.createdAt,
createdAt: repo.createdAt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "@phosphor-icons/react";
import { Box, Flex, Popover, Text } from "@radix-ui/themes";
import { useWorkspace } from "@renderer/features/workspace/hooks/useWorkspace";
import { normalizeRepoKey } from "@shared/utils/repo";
import { useNavigationStore } from "@stores/navigationStore";
import { useCallback, useEffect } from "react";
import type { TaskData, TaskGroup } from "../hooks/useSidebarData";
Expand Down Expand Up @@ -378,7 +379,9 @@ export function TaskListView({
const isExpanded = !collapsedSections.has(group.id);
const folder = folders.find(
(f) =>
f.remoteUrl?.toLowerCase() === group.id.toLowerCase() ||
(f.remoteUrl &&
normalizeRepoKey(f.remoteUrl).toLowerCase() ===
normalizeRepoKey(group.id).toLowerCase()) ||
f.path === group.id,
);
const groupFolderId =
Expand All @@ -387,7 +390,7 @@ export function TaskListView({
<DraggableFolder key={group.id} id={group.id} index={index}>
<SidebarSection
id={group.id}
label={group.name}
label={folder?.name ?? group.name}
icon={
isExpanded ? (
<FolderOpenIcon size={14} className="text-gray-10" />
Expand All @@ -406,7 +409,7 @@ export function TaskListView({
navigateToTaskInput();
}
}}
newTaskTooltip={`Start new task in ${group.name}`}
newTaskTooltip={`Start new task in ${folder?.name ?? group.name}`}
>
{group.tasks.map((task) => (
<TaskRow
Expand Down
3 changes: 3 additions & 0 deletions apps/code/src/shared/utils/repo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function normalizeRepoKey(key: string): string {
return key.trim().replace(/\.git$/, "");
}
Loading