mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: support pull request trees
This commit is contained in:
parent
328a04f9bb
commit
24693cedce
5 changed files with 127 additions and 34 deletions
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
|
|
@ -5,7 +5,7 @@ type MetaData = {
|
|||
defaultBranchName?: string
|
||||
repoUrl?: string
|
||||
userUrl?: string
|
||||
type?: 'tree' | 'blob' | string
|
||||
type?: 'tree' | 'blob' | 'pull' | string
|
||||
}
|
||||
|
||||
type TreeNode = {
|
||||
|
|
|
|||
|
|
@ -80,6 +80,16 @@ export async function getTreeData(
|
|||
return await request(url, { accessToken })
|
||||
}
|
||||
|
||||
export async function getPullTreeData(
|
||||
userName: string,
|
||||
repoName: string,
|
||||
pullId: string,
|
||||
accessToken?: string,
|
||||
): Promise<GitHubAPI.PullTreeData> {
|
||||
const url = `https://${API_ENDPOINT}/repos/${userName}/${repoName}/pulls/${pullId}/files`
|
||||
return await request(url, { accessToken })
|
||||
}
|
||||
|
||||
export async function getBlobData(
|
||||
userName: string,
|
||||
repoName: string,
|
||||
|
|
|
|||
15
src/platforms/GitHub/Request.d.ts
vendored
15
src/platforms/GitHub/Request.d.ts
vendored
|
|
@ -15,6 +15,21 @@ declare namespace GitHubAPI {
|
|||
url: string
|
||||
}
|
||||
|
||||
type PullTreeItem = {
|
||||
additions: number
|
||||
blob_url: string
|
||||
changes: number
|
||||
contents_url: string
|
||||
deletions: number
|
||||
filename: string
|
||||
patch: string
|
||||
raw_url: string
|
||||
sha: string
|
||||
status: 'modified' | 'added' | 'removed'
|
||||
}
|
||||
|
||||
type PullTreeData = PullTreeItem[]
|
||||
|
||||
type MetaData = {
|
||||
name: string
|
||||
default_branch: string
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ export function isInRepoPage() {
|
|||
return Boolean(document.querySelector(repoHeaderSelector))
|
||||
}
|
||||
|
||||
export function isInPullPage() {
|
||||
return parse().type === 'pull'
|
||||
}
|
||||
|
||||
function isCommitPath(path: string[]) {
|
||||
return isCompleteCommitSHA(path[0])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,22 +9,19 @@ import * as API from './API'
|
|||
import * as DOMHelper from './DOMHelper'
|
||||
import * as URLHelper from './URLHelper'
|
||||
|
||||
function parseTreeData(treeData: GitHubAPI.TreeData, metaData: MetaData) {
|
||||
const { tree } = treeData
|
||||
|
||||
function processTree(tree: TreeNode[]): TreeNode {
|
||||
// nodes are created from items and put onto tree
|
||||
const pathToNode = new Map<string, TreeNode>()
|
||||
const pathToItem = new Map<string, GitHubAPI.TreeItem>()
|
||||
|
||||
const root: TreeNode = { name: '', path: '', contents: [], type: 'tree' }
|
||||
pathToNode.set('', root)
|
||||
|
||||
const pathToItem = new Map<string, TreeNode>()
|
||||
tree.forEach(item => pathToItem.set(item.path, item))
|
||||
|
||||
const pathToCreated = new Map<string, TreeNode>()
|
||||
const root: TreeNode = { name: '', path: '', contents: [], type: 'tree' }
|
||||
pathToCreated.set('', root)
|
||||
tree.forEach(item => {
|
||||
// bottom-up search for the deepest node created
|
||||
let path = item.path
|
||||
const itemsToCreateTreeNode: GitHubAPI.TreeItem[] = []
|
||||
while (path !== '' && !pathToNode.has(path)) {
|
||||
const itemsToCreateTreeNode: TreeNode[] = []
|
||||
while (path !== '' && !pathToCreated.has(path)) {
|
||||
const item = pathToItem.get(path)
|
||||
if (item) {
|
||||
itemsToCreateTreeNode.push(item)
|
||||
|
|
@ -38,28 +35,13 @@ function parseTreeData(treeData: GitHubAPI.TreeData, metaData: MetaData) {
|
|||
while (itemsToCreateTreeNode.length) {
|
||||
const item = itemsToCreateTreeNode.pop()
|
||||
if (!item) continue
|
||||
const node: TreeNode = {
|
||||
path: item.path || '',
|
||||
type: item.type || 'blob',
|
||||
name: item.path?.replace(/^.*\//, '') || '',
|
||||
url:
|
||||
item.url && item.type && item.path
|
||||
? getUrlForRedirect(
|
||||
metaData.userName,
|
||||
metaData.repoName,
|
||||
metaData.branchName,
|
||||
item.type,
|
||||
item.path,
|
||||
)
|
||||
: undefined,
|
||||
contents: item.type === 'tree' ? [] : undefined,
|
||||
sha: item.sha,
|
||||
}
|
||||
const parentNode = pathToNode.get(path)
|
||||
if (parentNode && parentNode.contents) {
|
||||
const node: TreeNode = item
|
||||
const parentNode = pathToCreated.get(path)
|
||||
if (parentNode) {
|
||||
if (!parentNode.contents) parentNode.contents = []
|
||||
parentNode.contents.push(node)
|
||||
}
|
||||
pathToNode.set(node.path, node)
|
||||
pathToCreated.set(node.path, node)
|
||||
path = node.path
|
||||
}
|
||||
})
|
||||
|
|
@ -114,8 +96,63 @@ export const GitHub: Platform = {
|
|||
},
|
||||
async getTreeData(metaData, accessToken) {
|
||||
const { userName, repoName, branchName } = metaData
|
||||
|
||||
if (URLHelper.isInPullPage()) {
|
||||
const treeData = await API.getPullTreeData(
|
||||
userName,
|
||||
repoName,
|
||||
URLHelper.parse().path[0],
|
||||
accessToken,
|
||||
)
|
||||
|
||||
const nodes: TreeNode[] = treeData.map(item => {
|
||||
const id = document.querySelector(`*[data-path^="${item.filename}"]`)?.parentElement?.id
|
||||
return {
|
||||
path: item.filename || '',
|
||||
type: 'blob',
|
||||
name: item.filename?.replace(/^.*\//, '') || '',
|
||||
url: `#${id}`,
|
||||
contents: undefined,
|
||||
sha: item.sha,
|
||||
}
|
||||
})
|
||||
|
||||
const missingFolders = findMissingFolders(nodes)
|
||||
nodes.push(
|
||||
...missingFolders.map(
|
||||
folder =>
|
||||
({
|
||||
name: folder.replace(/^.*\//, ''),
|
||||
path: folder,
|
||||
type: 'tree',
|
||||
} as TreeNode),
|
||||
),
|
||||
)
|
||||
|
||||
const tree = processTree(nodes)
|
||||
return tree
|
||||
}
|
||||
|
||||
const treeData = await API.getTreeData(userName, repoName, branchName, accessToken)
|
||||
const root = parseTreeData(treeData, metaData)
|
||||
const root = processTree(
|
||||
treeData.tree.map(item => ({
|
||||
path: item.path || '',
|
||||
type: item.type || 'blob',
|
||||
name: item.path?.replace(/^.*\//, '') || '',
|
||||
url:
|
||||
item.url && item.type && item.path
|
||||
? getUrlForRedirect(
|
||||
metaData.userName,
|
||||
metaData.repoName,
|
||||
metaData.branchName,
|
||||
item.type,
|
||||
item.path,
|
||||
)
|
||||
: undefined,
|
||||
contents: item.type === 'tree' ? [] : undefined,
|
||||
sha: item.sha,
|
||||
})),
|
||||
)
|
||||
|
||||
const gitModules = root.contents?.find(item => item.name === '.gitmodules')
|
||||
if (gitModules) {
|
||||
|
|
@ -136,7 +173,7 @@ export const GitHub: Platform = {
|
|||
return root
|
||||
},
|
||||
shouldShow() {
|
||||
return DOMHelper.isInCodePage()
|
||||
return DOMHelper.isInCodePage() || URLHelper.isInPullPage()
|
||||
},
|
||||
getCurrentPath(branchName) {
|
||||
return URLHelper.getCurrentPath(branchName)
|
||||
|
|
@ -154,6 +191,33 @@ export const GitHub: Platform = {
|
|||
},
|
||||
}
|
||||
|
||||
function findMissingFolders(nodes: TreeNode[]) {
|
||||
const folders = new Set<string>()
|
||||
const foundFolders = new Set<string>()
|
||||
for (const node of nodes) {
|
||||
let path = node.path
|
||||
if (node.type === 'tree') foundFolders.add(path)
|
||||
else {
|
||||
while (true) {
|
||||
// 'a/b' -> 'a'
|
||||
// 'a' -> ''
|
||||
path = path.substring(0, path.lastIndexOf('/'))
|
||||
if (path === '') break
|
||||
folders.add(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const missingFolders: string[] = []
|
||||
for (const folder of folders) {
|
||||
if (!foundFolders.has(folder)) {
|
||||
missingFolders.push(folder)
|
||||
}
|
||||
}
|
||||
|
||||
return missingFolders
|
||||
}
|
||||
|
||||
export function useGitHubAttachCopySnippetButton(copySnippetButton: boolean) {
|
||||
const attachCopySnippetButton = React.useCallback(
|
||||
function attachCopySnippetButton() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue