mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: setup gitee
This commit is contained in:
parent
0f1f129c01
commit
07b520db07
10 changed files with 584 additions and 1 deletions
|
|
@ -22,6 +22,7 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
|
|||
}
|
||||
|
||||
.#{$name}-ready {
|
||||
// github
|
||||
.js-header-wrapper {
|
||||
background: $gray-dark;
|
||||
}
|
||||
|
|
@ -29,6 +30,29 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
|
|||
max-width: 1012px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
// gitee
|
||||
&.git-project {
|
||||
#git-header-nav {
|
||||
position: static;
|
||||
}
|
||||
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.with-gitako-spacing {
|
||||
// gitee
|
||||
&.git-project {
|
||||
// width: auto; // shrink width
|
||||
.ui.container {
|
||||
// width: auto;
|
||||
}
|
||||
.site-content {
|
||||
// min-width: auto;
|
||||
// max-width: 1020px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $github-content-width) {
|
||||
|
|
@ -517,6 +541,21 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gitee
|
||||
body.git-project {
|
||||
// reset styles
|
||||
input[type='text'],
|
||||
input[type='password'],
|
||||
.ui-autocomplete-input,
|
||||
textarea,
|
||||
.uneditable-input {
|
||||
padding: initial;
|
||||
// line-height: 18px;
|
||||
border: none;
|
||||
// border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
|
|
|
|||
|
|
@ -5,4 +5,9 @@ export const GITHUB_OAUTH = {
|
|||
clientSecret: process.env.GITHUB_OAUTH_CLIENT_SECRET,
|
||||
}
|
||||
|
||||
export const GITEE_OAUTH = {
|
||||
clientId: process.env.GITEE_OAUTH_CLIENT_ID,
|
||||
clientSecret: process.env.GITEE_OAUTH_CLIENT_SECRET,
|
||||
}
|
||||
|
||||
export const VERSION = process.env.VERSION
|
||||
|
|
|
|||
117
src/platforms/Gitee/API.ts
Normal file
117
src/platforms/Gitee/API.ts
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
import { raiseError } from 'analytics'
|
||||
import { GITEE_OAUTH } from 'env'
|
||||
import { errors } from 'platforms'
|
||||
|
||||
function apiRateLimitExceeded(content: any /* safe any */) {
|
||||
return content?.['documentation_url'] === 'https://developer.github.com/v3/#rate-limiting'
|
||||
}
|
||||
|
||||
function isEmptyProject(content: any /* safe any */) {
|
||||
return content?.['message'] === 'Git Repository is empty.'
|
||||
}
|
||||
|
||||
function isBlockedProject(content: any /* safe any */) {
|
||||
return content?.['message'] === 'Repository access blocked'
|
||||
}
|
||||
|
||||
async function request(
|
||||
url: string,
|
||||
{
|
||||
accessToken,
|
||||
}: {
|
||||
accessToken?: string
|
||||
} = {},
|
||||
) {
|
||||
const headers = {} as HeadersInit & {
|
||||
Authorization?: string
|
||||
}
|
||||
if (accessToken) {
|
||||
headers.Authorization = `token ${accessToken}`
|
||||
}
|
||||
const res = await fetch(url, { headers })
|
||||
const contentType = res.headers.get('Content-Type') || res.headers.get('content-type')
|
||||
if (!contentType) {
|
||||
throw new Error(`Response has no content type`)
|
||||
} else if (!contentType.includes('application/json')) {
|
||||
throw new Error(`Response content type is ${contentType}`)
|
||||
}
|
||||
// About res.ok:
|
||||
// True if res.status between 200~299
|
||||
// Ref: https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
|
||||
if (res.ok) {
|
||||
return res.json()
|
||||
} else {
|
||||
debugger
|
||||
if (res.status === 404 || res.status === 401) throw new Error(errors.NOT_FOUND)
|
||||
else if (res.status === 500) throw new Error(errors.SERVER_FAULT)
|
||||
else {
|
||||
const content = await res.json()
|
||||
if (apiRateLimitExceeded(content)) throw new Error(errors.API_RATE_LIMIT)
|
||||
if (isEmptyProject(content)) throw new Error(errors.EMPTY_PROJECT)
|
||||
if (isBlockedProject(content)) throw new Error(errors.BLOCKED_PROJECT)
|
||||
// Unknown type of error, report it!
|
||||
raiseError(new Error(res.statusText))
|
||||
throw new Error(content && content.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getRepoMeta(
|
||||
userName: string,
|
||||
repoName: string,
|
||||
accessToken?: string,
|
||||
): Promise<GiteeAPI.MetaData> {
|
||||
const url = `https://gitee.com/api/v5/repos/${encodeURIComponent(userName)}/${encodeURIComponent(
|
||||
repoName,
|
||||
)}`
|
||||
return await request(url, { accessToken })
|
||||
}
|
||||
|
||||
export async function getTreeData(
|
||||
userName: string,
|
||||
repoName: string,
|
||||
branchName: string,
|
||||
accessToken?: string,
|
||||
): Promise<GiteeAPI.TreeData> {
|
||||
const url = `https://gitee.com/api/v5/repos/${encodeURIComponent(userName)}/${encodeURIComponent(
|
||||
repoName,
|
||||
)}/git/trees/${encodeURIComponent(branchName)}?recursive=1`
|
||||
return await request(url, { accessToken })
|
||||
}
|
||||
|
||||
export async function getBlobData(
|
||||
userName: string,
|
||||
repoName: string,
|
||||
sha: string,
|
||||
accessToken?: string,
|
||||
): Promise<GiteeAPI.BlobData> {
|
||||
const url = `https://gitee.com/api/v5/repos/${encodeURIComponent(userName)}/${encodeURIComponent(
|
||||
repoName,
|
||||
)}/git/blobs/${encodeURIComponent(sha)}`
|
||||
return await request(url, { accessToken })
|
||||
}
|
||||
|
||||
export async function OAuth(code: string): Promise<GiteeAPI.OAuth> {
|
||||
if (!GITEE_OAUTH.clientId || !GITEE_OAUTH.clientSecret)
|
||||
throw new Error(`No Gitee OAuth credientials`)
|
||||
const params = new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
code: code,
|
||||
client_id: GITEE_OAUTH.clientId,
|
||||
client_secret: GITEE_OAUTH.clientSecret,
|
||||
})
|
||||
|
||||
const res = await fetch('https://gitee.com/oauth/token?' + params.toString(), {
|
||||
mode: 'cors',
|
||||
cache: 'no-cache',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
redirect: 'follow',
|
||||
referrerPolicy: 'no-referrer',
|
||||
method: 'post',
|
||||
})
|
||||
return res.json()
|
||||
}
|
||||
83
src/platforms/Gitee/DOMHelper.ts
Normal file
83
src/platforms/Gitee/DOMHelper.ts
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { raiseError } from 'analytics'
|
||||
import { Clippy, ClippyClassName } from 'components/Clippy'
|
||||
import * as React from 'react'
|
||||
import { $ } from 'utils/DOMHelper'
|
||||
import { renderReact } from 'utils/general'
|
||||
|
||||
export function isInRepoPage() {
|
||||
const repoHeaderSelector = '.git-project-header-details'
|
||||
return Boolean($(repoHeaderSelector))
|
||||
}
|
||||
|
||||
export function isInCodePage() {
|
||||
const branchListSelector = '#git-project-bread'
|
||||
return Boolean($(branchListSelector))
|
||||
}
|
||||
|
||||
export function getCurrentBranch() {
|
||||
const selectedBranchButtonSelector = '#git-project-branch'
|
||||
const branchButtonElement: HTMLElement = $(selectedBranchButtonSelector)
|
||||
if (branchButtonElement) {
|
||||
const branchNameSpanElement = branchButtonElement.querySelector('.text')
|
||||
if (branchNameSpanElement) {
|
||||
const partialBranchNameFromInnerText = branchNameSpanElement.textContent
|
||||
if (!partialBranchNameFromInnerText?.includes('…')) return partialBranchNameFromInnerText
|
||||
}
|
||||
}
|
||||
|
||||
raiseError(new Error('cannot get current branch'))
|
||||
}
|
||||
|
||||
const REPO_TYPE_PRIVATE = 'private'
|
||||
const REPO_TYPE_PUBLIC = 'public'
|
||||
export function getRepoPageType() {
|
||||
const headerSelector = `.git-project-title .icon-lock`
|
||||
return $(
|
||||
headerSelector,
|
||||
() => REPO_TYPE_PRIVATE,
|
||||
() => REPO_TYPE_PUBLIC,
|
||||
)
|
||||
}
|
||||
|
||||
export function attachCopySnippet() {
|
||||
const readmeSelector = '.file_content.markdown-body'
|
||||
return $(readmeSelector, () => {
|
||||
const readmeArticleSelector = '.file_content.markdown-body .highlight'
|
||||
return $(readmeArticleSelector, readmeElement => {
|
||||
const mouseOverCallback = async ({ target }: Event): Promise<void> => {
|
||||
if (target instanceof Element && target.nodeName === 'PRE') {
|
||||
if (
|
||||
target.previousSibling === null ||
|
||||
!(target.previousSibling instanceof Element) ||
|
||||
!target.previousSibling.classList.contains(ClippyClassName)
|
||||
) {
|
||||
/**
|
||||
* <article>
|
||||
* <pre></pre> <!-- case A -->
|
||||
* <div class="highlight">
|
||||
* <pre></pre> <!-- case B -->
|
||||
* </div>
|
||||
* </article>
|
||||
*/
|
||||
if (target.parentNode) {
|
||||
const clippyElement = await renderReact(
|
||||
React.createElement(Clippy, { codeSnippetElement: target }),
|
||||
)
|
||||
if (clippyElement instanceof HTMLElement) {
|
||||
target.parentNode.insertBefore(clippyElement, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
readmeElement.addEventListener('mouseover', mouseOverCallback)
|
||||
return () => {
|
||||
readmeElement.removeEventListener('mouseover', mouseOverCallback)
|
||||
const buttons = document.querySelectorAll(`.${ClippyClassName}`)
|
||||
buttons.forEach(button => {
|
||||
button.parentElement?.removeChild(button)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
40
src/platforms/Gitee/Request.d.ts
vendored
Normal file
40
src/platforms/Gitee/Request.d.ts
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
declare namespace GiteeAPI {
|
||||
type TreeItem = {
|
||||
path: string
|
||||
mode: string
|
||||
sha: string
|
||||
size: number
|
||||
url: string
|
||||
type: 'blob' | 'commit' | 'tree'
|
||||
}
|
||||
|
||||
type TreeData = {
|
||||
sha: string
|
||||
truncated: boolean
|
||||
tree: TreeItem[]
|
||||
url: string
|
||||
}
|
||||
|
||||
type MetaData = {
|
||||
default_branch: string
|
||||
html_url: string
|
||||
parent: {
|
||||
url: string
|
||||
}
|
||||
}
|
||||
|
||||
type BlobData = {
|
||||
encoding: 'base64' | string
|
||||
sha: string
|
||||
content?: string
|
||||
size: number
|
||||
url: string
|
||||
}
|
||||
|
||||
type OAuth = {
|
||||
access_token?: string
|
||||
scope?: string
|
||||
token_type?: string
|
||||
error_description?: string
|
||||
}
|
||||
}
|
||||
91
src/platforms/Gitee/URLHelper.ts
Normal file
91
src/platforms/Gitee/URLHelper.ts
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import { raiseError } from 'analytics'
|
||||
import { isInRepoPage } from './DOMHelper'
|
||||
|
||||
export function parse(): Partial<MetaData> & { path: string[] } {
|
||||
const { pathname } = window.location
|
||||
let [
|
||||
,
|
||||
// ignore content before the first '/'
|
||||
userName,
|
||||
repoName,
|
||||
type,
|
||||
...path // should be [...branchName.split('/'), ...filePath.split('/')]
|
||||
] = unescape(decodeURIComponent(pathname)).split('/')
|
||||
return {
|
||||
userName,
|
||||
repoName,
|
||||
branchName: undefined,
|
||||
type,
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
||||
export function parseSHA() {
|
||||
const { type, path } = parse()
|
||||
return type === 'blob' || type === 'tree' ? path[0] : undefined
|
||||
}
|
||||
|
||||
// route types related to determining if sidebar should show
|
||||
const TYPES = {
|
||||
TREE: 'tree',
|
||||
BLOB: 'blob',
|
||||
COMMIT: 'commit',
|
||||
// known but not related types: issues, pulls, wiki, insight,
|
||||
// TODO: record more types
|
||||
}
|
||||
|
||||
export function isInCodePage(metaData?: Partial<MetaData>) {
|
||||
const mergedRepo = { ...parse(), ...metaData }
|
||||
const { type, branchName } = mergedRepo
|
||||
return Boolean(
|
||||
isInRepoPage() &&
|
||||
(!type || type === TYPES.TREE || type === TYPES.BLOB) &&
|
||||
type !== TYPES.COMMIT &&
|
||||
(branchName || (!type && !branchName)),
|
||||
)
|
||||
}
|
||||
|
||||
function isCommitPath(path: string[]) {
|
||||
return isCompleteCommitSHA(path[0])
|
||||
}
|
||||
|
||||
function isCompleteCommitSHA(sha?: string) {
|
||||
return typeof sha === 'string' && /^[abcdef0-9]{40}$/i.test(sha)
|
||||
}
|
||||
|
||||
export function getCurrentPath(branchName = '') {
|
||||
const { path, type } = parse()
|
||||
if (type === 'blob' || type === 'tree') {
|
||||
if (isCommitPath(path)) {
|
||||
// path = commit-SHA/path/to/item
|
||||
path.shift()
|
||||
} else {
|
||||
// path = branch/name/path/to/item or HEAD/path/to/item
|
||||
// HEAD is not a valid branch name. Getting HEAD means being detached.
|
||||
if (path[0] === 'HEAD') path.shift()
|
||||
else {
|
||||
const splitBranchName = branchName.split('/')
|
||||
while (splitBranchName.length) {
|
||||
if (
|
||||
splitBranchName[0] === path[0] ||
|
||||
// Keep consuming as their heads are same
|
||||
(splitBranchName.length === 1 && splitBranchName[0].startsWith(path[0]))
|
||||
// This happens when visiting URLs like /blob/{commitSHA}/path/to/file
|
||||
// and {commitSHA} is shorter than we got from DOM
|
||||
) {
|
||||
splitBranchName.shift()
|
||||
path.shift()
|
||||
} else {
|
||||
raiseError(new Error(`branch name and path prefix not match`), {
|
||||
branchName,
|
||||
path: parse().path,
|
||||
})
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return path.map(decodeURIComponent)
|
||||
}
|
||||
return []
|
||||
}
|
||||
39
src/platforms/Gitee/components.tsx
Normal file
39
src/platforms/Gitee/components.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { GITEE_OAUTH } from 'env'
|
||||
import * as React from 'react'
|
||||
|
||||
export function GiteeAccessDeniedError({ hasToken }: { hasToken: boolean }) {
|
||||
return (
|
||||
<div className={'description'}>
|
||||
<h5>Access Denied</h5>
|
||||
{hasToken ? (
|
||||
<>
|
||||
<p>
|
||||
Current access token is either invalid or not granted with permissions to access this
|
||||
project.
|
||||
</p>
|
||||
<p>
|
||||
You can grant or request access{' '}
|
||||
<a
|
||||
href={`https://github.com/settings/connections/applications/${GITEE_OAUTH.clientId}`}
|
||||
>
|
||||
here
|
||||
</a>{' '}
|
||||
if you setup Gitako with OAuth.
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<p>
|
||||
Gitako needs access token to read this project due to{' '}
|
||||
<a href="https://developer.github.com/v3/#rate-limiting" target="_blank">
|
||||
GitHub rate limiting
|
||||
</a>{' '}
|
||||
and{' '}
|
||||
<a href="https://developer.github.com/v3/#authentication" target="_blank">
|
||||
auth needs
|
||||
</a>
|
||||
. Please setup access token in the settings panel below.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
167
src/platforms/Gitee/index.ts
Normal file
167
src/platforms/Gitee/index.ts
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
import { platform } from 'platforms'
|
||||
import * as React from 'react'
|
||||
import { useEvent } from 'react-use'
|
||||
import { resolveGitModules } from 'utils/gitSubmodule'
|
||||
import { sortFoldersToFront } from 'utils/treeParser'
|
||||
import * as API from './API'
|
||||
import * as DOMHelper from './DOMHelper'
|
||||
import * as URLHelper from './URLHelper'
|
||||
|
||||
function parseTreeData(treeData: GiteeAPI.TreeData, metaData: MetaData) {
|
||||
const { tree } = treeData
|
||||
|
||||
// nodes are created from items and put onto tree
|
||||
const pathToNode = new Map<string, TreeNode>()
|
||||
const pathToItem = new Map<string, GiteeAPI.TreeItem>()
|
||||
|
||||
const root: TreeNode = { name: '', path: '', contents: [], type: 'tree' }
|
||||
pathToNode.set('', root)
|
||||
|
||||
tree.forEach(item => pathToItem.set(item.path, item))
|
||||
tree.forEach(item => {
|
||||
// bottom-up search for the deepest node created
|
||||
let path = item.path
|
||||
const itemsToCreateTreeNode: GiteeAPI.TreeItem[] = []
|
||||
while (path !== '' && !pathToNode.has(path)) {
|
||||
const item = pathToItem.get(path)
|
||||
if (item) {
|
||||
itemsToCreateTreeNode.push(item)
|
||||
}
|
||||
// 'a/b' -> 'a'
|
||||
// 'a' -> ''
|
||||
path = path.substring(0, path.lastIndexOf('/'))
|
||||
}
|
||||
|
||||
// top-down create nodes
|
||||
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,
|
||||
}
|
||||
const parentNode = pathToNode.get(path)
|
||||
if (parentNode && parentNode.contents) {
|
||||
parentNode.contents.push(node)
|
||||
}
|
||||
pathToNode.set(node.path, node)
|
||||
path = node.path
|
||||
}
|
||||
})
|
||||
|
||||
sortFoldersToFront(root)
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
function getUrlForRedirect(
|
||||
userName: string,
|
||||
repoName: string,
|
||||
branchName: string,
|
||||
type = 'blob',
|
||||
path = '',
|
||||
) {
|
||||
return `https://gitee.com/${userName}/${repoName}/${type}/${branchName}/${path}`
|
||||
}
|
||||
|
||||
export const Gitee: Platform = {
|
||||
resolveMeta() {
|
||||
if (!DOMHelper.isInRepoPage()) {
|
||||
return null
|
||||
}
|
||||
|
||||
let detectedBranchName
|
||||
if (DOMHelper.isInCodePage()) {
|
||||
// not working well with non-branch blob
|
||||
// cannot handle '/' split branch name, should not use when possibly on branch page
|
||||
detectedBranchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA()
|
||||
}
|
||||
|
||||
const metaData = {
|
||||
...URLHelper.parse(),
|
||||
branchName: detectedBranchName || 'master',
|
||||
} as MetaData
|
||||
return metaData
|
||||
},
|
||||
async getMetaData(rawMetaData, accessToken) {
|
||||
const { userName, repoName, branchName } = rawMetaData
|
||||
const data = await API.getRepoMeta(userName, repoName, accessToken)
|
||||
const metaData: MetaData = {
|
||||
userName,
|
||||
repoName,
|
||||
branchName,
|
||||
userUrl: data?.parent?.url,
|
||||
repoUrl: data?.html_url,
|
||||
}
|
||||
|
||||
return metaData
|
||||
},
|
||||
async getTreeData(metaData, accessToken) {
|
||||
const { userName, repoName, branchName } = metaData
|
||||
const treeData = await API.getTreeData(userName, repoName, branchName)
|
||||
const root = parseTreeData(treeData, metaData)
|
||||
|
||||
const gitModules = root.contents?.find(item => item.name === '.gitmodules')
|
||||
if (gitModules) {
|
||||
if (metaData.userName && metaData.repoName && gitModules.sha) {
|
||||
const blobData = await API.getBlobData(
|
||||
metaData.repoName,
|
||||
metaData.userName,
|
||||
gitModules.sha,
|
||||
accessToken,
|
||||
)
|
||||
|
||||
if (blobData && blobData.encoding === 'base64' && blobData.content) {
|
||||
resolveGitModules(root, Base64.decode(blobData.content))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return root
|
||||
},
|
||||
shouldShow(metaData) {
|
||||
return URLHelper.isInCodePage(metaData)
|
||||
},
|
||||
getCurrentPath(branchName) {
|
||||
return URLHelper.getCurrentPath(branchName)
|
||||
},
|
||||
async setOAuth(code) {
|
||||
const res = await API.OAuth(code)
|
||||
const { access_token: accessToken, scope, error_description: errorDescription } = res
|
||||
if (errorDescription) {
|
||||
if (errorDescription === `The code passed is incorrect or expired.`) {
|
||||
alert(`Gitako: The OAuth token has expired, please try again.`)
|
||||
return null
|
||||
} else {
|
||||
throw new Error(errorDescription)
|
||||
}
|
||||
} else if (scope !== 'repo' || !accessToken) {
|
||||
throw new Error(`Cannot resolve token response: '${JSON.stringify(res)}'`)
|
||||
}
|
||||
return accessToken
|
||||
},
|
||||
}
|
||||
|
||||
export function useGiteeAttachCopySnippetButton(copySnippetButton: boolean) {
|
||||
const attachCopySnippetButton = React.useCallback(
|
||||
function attachCopySnippetButton() {
|
||||
if (platform !== Gitee) return
|
||||
if (copySnippetButton) return DOMHelper.attachCopySnippet() || undefined // for the sake of react effect
|
||||
},
|
||||
[copySnippetButton],
|
||||
)
|
||||
React.useEffect(attachCopySnippetButton, [copySnippetButton])
|
||||
useEvent('pjax:complete', attachCopySnippetButton, window)
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import * as storageHelper from 'utils/storageHelper'
|
||||
import { dummyPlatformForTypeSafety } from './dummyPlatformForTypeSafety'
|
||||
import { Gitee } from './Gitee'
|
||||
import { GitHub } from './GitHub'
|
||||
|
||||
const platformsMap: Record<
|
||||
|
|
@ -8,7 +9,7 @@ const platformsMap: Record<
|
|||
> = {
|
||||
GitHub: { platform: GitHub, hosts: ['github.com'] },
|
||||
GitLab: { platform: GitHub, hosts: ['gitlab.com'] },
|
||||
Gitee: { platform: GitHub, hosts: ['gitee.com'] },
|
||||
Gitee: { platform: Gitee, hosts: ['gitee.com'] },
|
||||
}
|
||||
|
||||
const CustomDomainsStorageKey = 'CUSTOM_DOMAINS'
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export function usePJAX() {
|
|||
'title',
|
||||
'[data-pjax="#js-repo-pjax-container"]',
|
||||
'.page-content',
|
||||
'#git-project-content',
|
||||
],
|
||||
scrollTo: false,
|
||||
analytics: false,
|
||||
|
|
|
|||
Loading…
Reference in a new issue