diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 2e70fda..50b3649 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -52,7 +52,12 @@ const RawGitako: React.FC = function RawGitako(props) { * Catch unexpected PJAX, force trigger init on scope change. */ const pageScope = useStateIO(platform.resolvePageScope?.()) - useOnPJAXDone(() => pageScope.onChange(platform.resolvePageScope?.())) + useOnPJAXDone( + React.useCallback( + () => pageScope.onChange(platform.resolvePageScope?.(metaData?.defaultBranchName)), + [metaData?.defaultBranchName], + ), + ) React.useEffect(() => { props.init() }, [accessToken, pageScope.value]) diff --git a/src/driver/core/SideBar.ts b/src/driver/core/SideBar.ts index 43b5c6d..31d21f8 100644 --- a/src/driver/core/SideBar.ts +++ b/src/driver/core/SideBar.ts @@ -43,7 +43,7 @@ export const init: BoundMethodCreator = dispatch => async () => { dispatch.set({ state: 'disabled' }) return } - const { userName, repoName, branchName } = metaData + const { userName, repoName, branchName, defaultBranchName } = metaData DOMHelper.markGitakoReadyState(true) dispatch.set({ @@ -70,10 +70,11 @@ export const init: BoundMethodCreator = dispatch => async () => { getTreeData.catch(error => error) // catch it early to prevent the error being raised higher if (branchName) { - const safeMetaData = { + const safeMetaData: MetaData = { userName, repoName, branchName, + defaultBranchName, } dispatch.set({ metaData: safeMetaData }) getTreeData.catch(error => { @@ -89,10 +90,11 @@ export const init: BoundMethodCreator = dispatch => async () => { throw new Error(`Failed resolving default branch name`) } - const safeMetaData = { + const safeMetaData: MetaData = { userName, repoName, branchName: defaultBranchName, + defaultBranchName, } dispatch.set({ metaData: safeMetaData }) diff --git a/src/global.d.ts b/src/global.d.ts index a7771b6..081c987 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -2,6 +2,7 @@ type MetaData = { userName: string repoName: string branchName: string + defaultBranchName?: string type?: EnumString<'tree' | 'blob' | 'pull'> } diff --git a/src/platforms/GitHub/DOMHelper.ts b/src/platforms/GitHub/DOMHelper.ts index 146812a..0d62f0e 100644 --- a/src/platforms/GitHub/DOMHelper.ts +++ b/src/platforms/GitHub/DOMHelper.ts @@ -232,3 +232,23 @@ export function attachCopySnippet() { ) }) } + +export function getPath() { + const folderPathElementSelector = '.file-navigation .position-relative' // available when in path like '/tree/...' + const blobPathElementSelector = '#blob-path' // available when in path like '/blob/...' + const pathElement = + document.querySelector(blobPathElementSelector) || + document.querySelector(folderPathElementSelector)?.nextElementSibling + if (!pathElement || !pathElement.querySelector('.js-repo-root')) { + raiseError(new Error(`Path element not found`)) + return '' + } + const path = ((pathElement as HTMLDivElement).innerText || '') + .replace(/ \/ Jump to $/, '') + .trim() + .split('/') + .filter(Boolean) + .slice(1) // the first is the repo's name + .join('/') + return path +} diff --git a/src/platforms/GitHub/index.ts b/src/platforms/GitHub/index.ts index 49cf7c0..4b63d68 100644 --- a/src/platforms/GitHub/index.ts +++ b/src/platforms/GitHub/index.ts @@ -1,3 +1,4 @@ +import { raiseError } from 'analytics' import { GITHUB_OAUTH } from 'env' import { Base64 } from 'js-base64' import { platform } from 'platforms' @@ -82,6 +83,40 @@ export function isEnterprise() { return !window.location.host.endsWith('github.com') } +function getBranchName() { + const pathFromDOM = DOMHelper.getPath() + const pathAndBranchFromURL = URLHelper.parse().path.filter(Boolean).join('/') + if (pathAndBranchFromURL.endsWith(pathFromDOM)) { + return pathAndBranchFromURL + .slice(0, pathAndBranchFromURL.length - pathFromDOM.length) + .replace(/\/$/, '') + } + raiseError(new Error(`Parsed path not end with path from DOM`)) +} + +function resolvePageScope(defaultBranchName?: string) { + const parsed = URLHelper.parse() + switch (parsed.type) { + // case undefined: + // return `branch-${defaultBranchName}` + case 'blob': + case 'tree': { + // handle URLs like {user}/{repo}/tree/{sha|branch}, issue#131 + const branchName = getBranchName() + if (branchName && branchName !== defaultBranchName) return `branch-${branchName}` + break + } + case 'tags': + return 'tags' + case 'releases': + return 'releases' + case 'pull': + const pullId = URLHelper.isInPullPage() + if (pullId) return `pull-${pullId}` + } + return 'general' +} + const pathSHAMap = new Map() export const GitHub: Platform = { @@ -115,15 +150,11 @@ export const GitHub: Platform = { repoName, type, branchName, + defaultBranchName: type ? undefined : branchName, } return metaData }, - resolvePageScope() { - if (URLHelper.parse().type === 'releases') return 'releases' - const pullId = URLHelper.isInPullPage() - if (pullId) return `pull-${pullId}` - return 'general' - }, + resolvePageScope, async getDefaultBranchName({ userName, repoName }, accessToken) { const data = await API.getRepoMeta(userName, repoName, accessToken) return data.default_branch diff --git a/src/platforms/platform.d.ts b/src/platforms/platform.d.ts index 12cd2a6..6bf87ac 100644 --- a/src/platforms/platform.d.ts +++ b/src/platforms/platform.d.ts @@ -2,7 +2,7 @@ type Platform = { isEnterprise(): boolean // branch name might not be available when resolving from DOM and URL resolveMeta(): MakeOptional | null - resolvePageScope?(): string + resolvePageScope?(branchName?: string): string getDefaultBranchName( metaData: Pick, accessToken?: string,