diff --git a/CHANGELOG.md b/CHANGELOG.md index 82b854fd..db02263f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 +### Added +- Implement dynamic tab titles for files and folders in browse tab. [#560](https://github.com/sourcebot-dev/sourcebot/pull/560) + ### Fixed - Fixed "dubious ownership" errors when cloning / fetching repos. [#553](https://github.com/sourcebot-dev/sourcebot/pull/553) diff --git a/packages/web/src/app/[domain]/browse/[...path]/page.tsx b/packages/web/src/app/[domain]/browse/[...path]/page.tsx index 9c9b19e7..42b80730 100644 --- a/packages/web/src/app/[domain]/browse/[...path]/page.tsx +++ b/packages/web/src/app/[domain]/browse/[...path]/page.tsx @@ -4,7 +4,43 @@ import { CodePreviewPanel } from "./components/codePreviewPanel"; import { Loader2 } from "lucide-react"; import { TreePreviewPanel } from "./components/treePreviewPanel"; import { Metadata } from "next"; -import { parsePathForTitle} from "@/lib/utils"; + +/** + * Parses the URL path to generate a descriptive title. + * It handles three cases: + * 1. File view (`blob`): "filename.ts - owner/repo" + * 2. Directory view (`tree`): "directory/ - owner/repo" + * 3. Repository root: "owner/repo" + * + * @param path The array of path segments from Next.js params. + * @returns A formatted title string. + */ +export const parsePathForTitle = (path: string[]): string => { + const pathParam = path.join('/'); + + const { repoName, revisionName, path: filePath, pathType } = getBrowseParamsFromPathParam(pathParam); + + // Build the base repository and revision string. + const cleanRepoName = repoName.split('/').slice(1).join('/'); // Remove the version control system prefix + const repoAndRevision = `${cleanRepoName}${revisionName ? ` @ ${revisionName}` : ''}`; + + switch (pathType) { + case 'blob': { + // For blobs, get the filename from the end of the path. + const fileName = filePath.split('/').pop() || filePath; + return `${fileName} - ${repoAndRevision}`; + } + case 'tree': { + // If the path is empty, it's the repo root. + if (filePath === '' || filePath === '/') { + return repoAndRevision; + } + // Otherwise, show the directory path. + const directoryPath = filePath.endsWith('/') ? filePath : `${filePath}/`; + return `${directoryPath} - ${repoAndRevision}`; + } + } +} type Props = { params: Promise<{ @@ -21,8 +57,6 @@ export async function generateMetadata({ params: paramsPromise }: Props): Promis title = parsePathForTitle(params.path); } catch (error) { - // TODO: Maybe I need to look into a better way of handling this error. - // for now, it is just a log, fallback tab title and prevents the app from crashing. console.error("Failed to generate metadata title from path:", error); } diff --git a/packages/web/src/lib/utils.ts b/packages/web/src/lib/utils.ts index 261c9270..a7669e6c 100644 --- a/packages/web/src/lib/utils.ts +++ b/packages/web/src/lib/utils.ts @@ -487,44 +487,4 @@ export const isHttpError = (error: unknown, status: number): boolean => { && typeof error === 'object' && 'status' in error && error.status === status; -} - -/** - * Parses the URL path to generate a descriptive title. - * It handles three cases: - * 1. File view (`blob`): "filename.ts - owner/repo" - * 2. Directory view (`tree`): "directory/ - owner/repo" - * 3. Repository root: "owner/repo" - * - * @param path The array of path segments from Next.js params. - * @returns A formatted title string. - */ -export const parsePathForTitle = (path: string[]): string => { - const pathParam = path.join('/'); - - const { repoName, revisionName, path: filePath, pathType } = getBrowseParamsFromPathParam(pathParam); - - // Build the base repository and revision string. - const cleanRepoName = repoName.split('/').slice(1).join('/'); // Remove the version control system prefix - const repoAndRevision = `${cleanRepoName}${revisionName ? ` @ ${revisionName}` : ''}`; - - switch (pathType) { - case 'blob': { - // For blobs, get the filename from the end of the path. - const fileName = filePath.split('/').pop() || filePath; - return `${fileName} - ${repoAndRevision}`; - } - case 'tree': { - // If the path is empty, it's the repo root. - if (filePath === '' || filePath === '/') { - return repoAndRevision; - } - // Otherwise, show the directory path. - const directoryPath = filePath.endsWith('/') ? filePath : `${filePath}/`; - return `${directoryPath} - ${repoAndRevision}`; - } - default: - // Fallback to just the repository name. - return repoAndRevision; - } } \ No newline at end of file