mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
refactor: simplify init logics
This commit is contained in:
parent
2a9ab02fda
commit
f3f86a79ea
6 changed files with 120 additions and 96 deletions
|
|
@ -2,6 +2,7 @@ import { ConfigsContextShape } from 'containers/ConfigsContext'
|
|||
import { GetCreatedMethod, MethodCreator } from 'driver/connect'
|
||||
import { errors, platform, platformName } from 'platforms'
|
||||
import * as DOMHelper from 'utils/DOMHelper'
|
||||
import { createPromiseQueue } from 'utils/general'
|
||||
|
||||
export type Props = {
|
||||
configContext: ConfigsContextShape
|
||||
|
|
@ -26,7 +27,6 @@ export type ConnectorState = {
|
|||
initializingPromise: Promise<void> | null
|
||||
} & {
|
||||
init: GetCreatedMethod<typeof init>
|
||||
setMetaData: GetCreatedMethod<typeof setMetaData>
|
||||
setShouldShow: GetCreatedMethod<typeof setShouldShow>
|
||||
toggleShowSideBar: GetCreatedMethod<typeof toggleShowSideBar>
|
||||
toggleShowSettings: GetCreatedMethod<typeof toggleShowSettings>
|
||||
|
|
@ -34,18 +34,10 @@ export type ConnectorState = {
|
|||
|
||||
type BoundMethodCreator<Args extends any[] = []> = MethodCreator<Props, ConnectorState, Args>
|
||||
|
||||
export const init: BoundMethodCreator = dispatch => async () => {
|
||||
const {
|
||||
state: { initializingPromise },
|
||||
} = dispatch.get()
|
||||
if (initializingPromise) await initializingPromise
|
||||
const promiseQueue = createPromiseQueue()
|
||||
|
||||
let done: any = null // cannot use type `(() => void) | null` here
|
||||
dispatch.set({
|
||||
initializingPromise: new Promise(resolve => {
|
||||
done = () => resolve()
|
||||
}),
|
||||
})
|
||||
export const init: BoundMethodCreator = dispatch => async () => {
|
||||
const leave = await promiseQueue.enter()
|
||||
|
||||
try {
|
||||
const metaData = platform.resolveMeta()
|
||||
|
|
@ -53,90 +45,85 @@ export const init: BoundMethodCreator = dispatch => async () => {
|
|||
dispatch.set({ disabled: true })
|
||||
return
|
||||
}
|
||||
const { userName, repoName, branchName } = metaData
|
||||
|
||||
DOMHelper.markGitakoReadyState(true)
|
||||
dispatch.set({
|
||||
errorDueToAuth: false,
|
||||
showSettings: false,
|
||||
logoContainerElement: DOMHelper.insertLogoMountPoint(),
|
||||
})
|
||||
dispatch.call(setMetaData, metaData)
|
||||
|
||||
const {
|
||||
props: { configContext },
|
||||
} = dispatch.get()
|
||||
const { accessToken } = configContext.val
|
||||
|
||||
if (!metaData.userName || !metaData.repoName) return
|
||||
const guessDefaultBranch = 'master'
|
||||
const getTreeDataAggressively = platform.getTreeData(
|
||||
const guessDefaultBranch = 'master' // when to switch to 'main'?
|
||||
let getTreeData = platform.getTreeData(
|
||||
{
|
||||
branchName: metaData.branchName || guessDefaultBranch,
|
||||
userName: metaData.userName,
|
||||
repoName: metaData.repoName,
|
||||
branchName: branchName || guessDefaultBranch,
|
||||
userName,
|
||||
repoName,
|
||||
},
|
||||
'/',
|
||||
true,
|
||||
accessToken,
|
||||
)
|
||||
const caughtAggressiveError = getTreeDataAggressively?.catch(error => {
|
||||
// 1. the repo has no master branch
|
||||
// 2. detect branch name from DOM failed
|
||||
// 3. not very possible...
|
||||
// not handle this error immediately
|
||||
return error
|
||||
})
|
||||
let getTreeData = getTreeDataAggressively
|
||||
const metaDataFromAPI = await platform.getMetaData(
|
||||
{
|
||||
userName: metaData.userName,
|
||||
repoName: metaData.repoName,
|
||||
},
|
||||
accessToken,
|
||||
)
|
||||
const projectDefaultBranchName = metaDataFromAPI?.defaultBranchName
|
||||
const detectedBranchName = metaData.branchName
|
||||
if (
|
||||
!detectedBranchName &&
|
||||
projectDefaultBranchName &&
|
||||
projectDefaultBranchName !== metaData.branchName &&
|
||||
metaData.type !== 'pull'
|
||||
) {
|
||||
// Accessing repository's non-homepage(no branch name in URL, nor in DOM)
|
||||
// We predicted its default branch to be 'master' and sent aggressive request
|
||||
// Throw that request due to the repo do not use {defaultBranchName} as default branch
|
||||
metaData.branchName = projectDefaultBranchName
|
||||
getTreeData = platform.getTreeData(
|
||||
{
|
||||
branchName: metaData.branchName,
|
||||
userName: metaData.userName,
|
||||
repoName: metaData.repoName,
|
||||
},
|
||||
'/',
|
||||
true,
|
||||
accessToken,
|
||||
)
|
||||
getTreeData.catch(error => error) // catch it early to prevent the error being raised higher
|
||||
|
||||
const metaDataFromAPI = await platform.getMetaData({ userName, repoName }, accessToken)
|
||||
|
||||
if (branchName) {
|
||||
const safeMetaData = {
|
||||
...metaDataFromAPI,
|
||||
userName,
|
||||
repoName,
|
||||
branchName,
|
||||
}
|
||||
dispatch.set({ metaData: safeMetaData })
|
||||
getTreeData.catch(error => {
|
||||
dispatch.call(handleError, error)
|
||||
})
|
||||
} else {
|
||||
caughtAggressiveError.then(error => {
|
||||
// aggressive requested correct branch but ends in failure (e.g. project is empty)
|
||||
if (error instanceof Error) {
|
||||
dispatch.call(handleError, error)
|
||||
}
|
||||
})
|
||||
const { defaultBranchName } = metaDataFromAPI
|
||||
|
||||
if (!defaultBranchName) {
|
||||
throw new Error(`Failed resolving default branch name`)
|
||||
}
|
||||
|
||||
const safeMetaData = {
|
||||
...metaDataFromAPI,
|
||||
userName,
|
||||
repoName,
|
||||
branchName: defaultBranchName,
|
||||
}
|
||||
dispatch.set({ metaData: safeMetaData })
|
||||
|
||||
if (defaultBranchName !== guessDefaultBranch && metaData.type !== 'pull') {
|
||||
// Accessing repository's non-homepage(no branch name in URL, nor in DOM)
|
||||
// We predicted its default branch to be 'master' and sent aggressive request
|
||||
// Throw that request due to the repo do not use {defaultBranchName} as default branch
|
||||
getTreeData = platform.getTreeData(
|
||||
{
|
||||
branchName: defaultBranchName,
|
||||
userName,
|
||||
repoName,
|
||||
},
|
||||
'/',
|
||||
true,
|
||||
accessToken,
|
||||
)
|
||||
}
|
||||
}
|
||||
getTreeData
|
||||
.then(async ({ root: treeData, defer }) => {
|
||||
if (treeData) {
|
||||
dispatch.set({ treeData, defer })
|
||||
}
|
||||
})
|
||||
.catch(err => dispatch.call(handleError, err))
|
||||
Object.assign(metaData, metaDataFromAPI)
|
||||
dispatch.call(setMetaData, metaData)
|
||||
|
||||
const { root: treeData, defer } = await getTreeData
|
||||
dispatch.set({ treeData, defer })
|
||||
} catch (err) {
|
||||
dispatch.call(handleError, err)
|
||||
} finally {
|
||||
if (done) done()
|
||||
}
|
||||
|
||||
leave()
|
||||
}
|
||||
|
||||
export const handleError: BoundMethodCreator<[Error]> = dispatch => async err => {
|
||||
|
|
@ -197,6 +184,3 @@ export const toggleShowSettings: BoundMethodCreator = dispatch => () =>
|
|||
dispatch.set(({ showSettings }) => ({
|
||||
showSettings: !showSettings,
|
||||
}))
|
||||
|
||||
export const setMetaData: BoundMethodCreator<[ConnectorState['metaData']]> = dispatch => metaData =>
|
||||
dispatch.set({ metaData })
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { raiseError } from 'analytics'
|
||||
|
||||
export function parse(): Pick<MetaData, 'userName' | 'repoName' | 'type'> & { path: string[] } {
|
||||
export function parse(): Partial<Pick<MetaData, 'userName' | 'repoName' | 'type'>> & {
|
||||
path: string[]
|
||||
} {
|
||||
const { pathname } = window.location
|
||||
let [
|
||||
,
|
||||
|
|
|
|||
|
|
@ -101,10 +101,17 @@ export const GitHub: Platform = {
|
|||
branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA()
|
||||
}
|
||||
|
||||
const { userName, repoName, type } = URLHelper.parse()
|
||||
if (!userName || !repoName) {
|
||||
return null
|
||||
}
|
||||
|
||||
const metaData = {
|
||||
...URLHelper.parse(),
|
||||
userName,
|
||||
repoName,
|
||||
type,
|
||||
branchName,
|
||||
} as MetaData
|
||||
}
|
||||
return metaData
|
||||
},
|
||||
async getMetaData({ userName, repoName }, accessToken) {
|
||||
|
|
@ -202,14 +209,14 @@ export const GitHub: Platform = {
|
|||
})),
|
||||
)
|
||||
|
||||
const gitModules = root.contents?.find(item => item.name === '.gitmodules')
|
||||
if (gitModules) {
|
||||
if (userName && repoName && gitModules.sha) {
|
||||
const blobData = await API.getBlobData(userName, repoName, gitModules.sha, accessToken)
|
||||
const gitModules = root.contents?.find(
|
||||
item => item.type === 'blob' && item.name === '.gitmodules',
|
||||
)
|
||||
if (gitModules?.sha) {
|
||||
const blobData = await API.getBlobData(userName, repoName, gitModules.sha, accessToken)
|
||||
|
||||
if (blobData && blobData.encoding === 'base64' && blobData.content) {
|
||||
await resolveGitModules(root, Base64.decode(blobData.content))
|
||||
}
|
||||
if (blobData && blobData.encoding === 'base64' && blobData.content) {
|
||||
await resolveGitModules(root, Base64.decode(blobData.content))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,15 +82,23 @@ export const Gitea: Platform = {
|
|||
return null
|
||||
}
|
||||
|
||||
let detectedBranchName
|
||||
let branchName
|
||||
if (DOMHelper.isInCodePage()) {
|
||||
detectedBranchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA()
|
||||
branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA()
|
||||
}
|
||||
|
||||
const { userName, repoName, type } = URLHelper.parse()
|
||||
if (!userName || !repoName) {
|
||||
return null
|
||||
}
|
||||
|
||||
const metaData = {
|
||||
...URLHelper.parse(),
|
||||
branchName: detectedBranchName,
|
||||
} as MetaData
|
||||
userName,
|
||||
repoName,
|
||||
type,
|
||||
branchName,
|
||||
}
|
||||
|
||||
return metaData
|
||||
},
|
||||
async getMetaData(partialMetaData, accessToken) {
|
||||
|
|
|
|||
|
|
@ -78,17 +78,24 @@ export const Gitee: Platform = {
|
|||
return null
|
||||
}
|
||||
|
||||
let detectedBranchName
|
||||
let branchName
|
||||
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()
|
||||
branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA()
|
||||
}
|
||||
|
||||
const { userName, repoName, type } = URLHelper.parse()
|
||||
if (!userName || !repoName) {
|
||||
return null
|
||||
}
|
||||
|
||||
const metaData = {
|
||||
...URLHelper.parse(),
|
||||
branchName: detectedBranchName,
|
||||
} as MetaData
|
||||
userName,
|
||||
repoName,
|
||||
type,
|
||||
branchName,
|
||||
}
|
||||
return metaData
|
||||
},
|
||||
async getMetaData(partialMetaData, accessToken) {
|
||||
|
|
|
|||
|
|
@ -187,3 +187,19 @@ export function withEffect<Method extends (...args: any[]) => any>(
|
|||
export function run<T>(fn: () => T) {
|
||||
return fn()
|
||||
}
|
||||
|
||||
export function createPromiseQueue() {
|
||||
let promise: Promise<void>
|
||||
return {
|
||||
async enter() {
|
||||
let leave: () => void
|
||||
const current = new Promise<void>(resolve => (leave = () => resolve()))
|
||||
|
||||
const lastPromise = promise
|
||||
promise = current!
|
||||
if (lastPromise) await lastPromise
|
||||
|
||||
return leave!
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue