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 { GetCreatedMethod, MethodCreator } from 'driver/connect'
|
||||||
import { errors, platform, platformName } from 'platforms'
|
import { errors, platform, platformName } from 'platforms'
|
||||||
import * as DOMHelper from 'utils/DOMHelper'
|
import * as DOMHelper from 'utils/DOMHelper'
|
||||||
|
import { createPromiseQueue } from 'utils/general'
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
configContext: ConfigsContextShape
|
configContext: ConfigsContextShape
|
||||||
|
|
@ -26,7 +27,6 @@ export type ConnectorState = {
|
||||||
initializingPromise: Promise<void> | null
|
initializingPromise: Promise<void> | null
|
||||||
} & {
|
} & {
|
||||||
init: GetCreatedMethod<typeof init>
|
init: GetCreatedMethod<typeof init>
|
||||||
setMetaData: GetCreatedMethod<typeof setMetaData>
|
|
||||||
setShouldShow: GetCreatedMethod<typeof setShouldShow>
|
setShouldShow: GetCreatedMethod<typeof setShouldShow>
|
||||||
toggleShowSideBar: GetCreatedMethod<typeof toggleShowSideBar>
|
toggleShowSideBar: GetCreatedMethod<typeof toggleShowSideBar>
|
||||||
toggleShowSettings: GetCreatedMethod<typeof toggleShowSettings>
|
toggleShowSettings: GetCreatedMethod<typeof toggleShowSettings>
|
||||||
|
|
@ -34,18 +34,10 @@ export type ConnectorState = {
|
||||||
|
|
||||||
type BoundMethodCreator<Args extends any[] = []> = MethodCreator<Props, ConnectorState, Args>
|
type BoundMethodCreator<Args extends any[] = []> = MethodCreator<Props, ConnectorState, Args>
|
||||||
|
|
||||||
export const init: BoundMethodCreator = dispatch => async () => {
|
const promiseQueue = createPromiseQueue()
|
||||||
const {
|
|
||||||
state: { initializingPromise },
|
|
||||||
} = dispatch.get()
|
|
||||||
if (initializingPromise) await initializingPromise
|
|
||||||
|
|
||||||
let done: any = null // cannot use type `(() => void) | null` here
|
export const init: BoundMethodCreator = dispatch => async () => {
|
||||||
dispatch.set({
|
const leave = await promiseQueue.enter()
|
||||||
initializingPromise: new Promise(resolve => {
|
|
||||||
done = () => resolve()
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const metaData = platform.resolveMeta()
|
const metaData = platform.resolveMeta()
|
||||||
|
|
@ -53,90 +45,85 @@ export const init: BoundMethodCreator = dispatch => async () => {
|
||||||
dispatch.set({ disabled: true })
|
dispatch.set({ disabled: true })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const { userName, repoName, branchName } = metaData
|
||||||
|
|
||||||
DOMHelper.markGitakoReadyState(true)
|
DOMHelper.markGitakoReadyState(true)
|
||||||
dispatch.set({
|
dispatch.set({
|
||||||
errorDueToAuth: false,
|
errorDueToAuth: false,
|
||||||
showSettings: false,
|
showSettings: false,
|
||||||
logoContainerElement: DOMHelper.insertLogoMountPoint(),
|
logoContainerElement: DOMHelper.insertLogoMountPoint(),
|
||||||
})
|
})
|
||||||
dispatch.call(setMetaData, metaData)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
props: { configContext },
|
props: { configContext },
|
||||||
} = dispatch.get()
|
} = dispatch.get()
|
||||||
const { accessToken } = configContext.val
|
const { accessToken } = configContext.val
|
||||||
|
|
||||||
if (!metaData.userName || !metaData.repoName) return
|
const guessDefaultBranch = 'master' // when to switch to 'main'?
|
||||||
const guessDefaultBranch = 'master'
|
let getTreeData = platform.getTreeData(
|
||||||
const getTreeDataAggressively = platform.getTreeData(
|
|
||||||
{
|
{
|
||||||
branchName: metaData.branchName || guessDefaultBranch,
|
branchName: branchName || guessDefaultBranch,
|
||||||
userName: metaData.userName,
|
userName,
|
||||||
repoName: metaData.repoName,
|
repoName,
|
||||||
},
|
},
|
||||||
'/',
|
'/',
|
||||||
true,
|
true,
|
||||||
accessToken,
|
accessToken,
|
||||||
)
|
)
|
||||||
const caughtAggressiveError = getTreeDataAggressively?.catch(error => {
|
getTreeData.catch(error => error) // catch it early to prevent the error being raised higher
|
||||||
// 1. the repo has no master branch
|
|
||||||
// 2. detect branch name from DOM failed
|
const metaDataFromAPI = await platform.getMetaData({ userName, repoName }, accessToken)
|
||||||
// 3. not very possible...
|
|
||||||
// not handle this error immediately
|
if (branchName) {
|
||||||
return error
|
const safeMetaData = {
|
||||||
})
|
...metaDataFromAPI,
|
||||||
let getTreeData = getTreeDataAggressively
|
userName,
|
||||||
const metaDataFromAPI = await platform.getMetaData(
|
repoName,
|
||||||
{
|
branchName,
|
||||||
userName: metaData.userName,
|
}
|
||||||
repoName: metaData.repoName,
|
dispatch.set({ metaData: safeMetaData })
|
||||||
},
|
getTreeData.catch(error => {
|
||||||
accessToken,
|
dispatch.call(handleError, error)
|
||||||
)
|
})
|
||||||
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,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
caughtAggressiveError.then(error => {
|
const { defaultBranchName } = metaDataFromAPI
|
||||||
// aggressive requested correct branch but ends in failure (e.g. project is empty)
|
|
||||||
if (error instanceof Error) {
|
if (!defaultBranchName) {
|
||||||
dispatch.call(handleError, error)
|
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 }) => {
|
const { root: treeData, defer } = await getTreeData
|
||||||
if (treeData) {
|
dispatch.set({ treeData, defer })
|
||||||
dispatch.set({ treeData, defer })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => dispatch.call(handleError, err))
|
|
||||||
Object.assign(metaData, metaDataFromAPI)
|
|
||||||
dispatch.call(setMetaData, metaData)
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
dispatch.call(handleError, err)
|
dispatch.call(handleError, err)
|
||||||
} finally {
|
|
||||||
if (done) done()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leave()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleError: BoundMethodCreator<[Error]> = dispatch => async err => {
|
export const handleError: BoundMethodCreator<[Error]> = dispatch => async err => {
|
||||||
|
|
@ -197,6 +184,3 @@ export const toggleShowSettings: BoundMethodCreator = dispatch => () =>
|
||||||
dispatch.set(({ showSettings }) => ({
|
dispatch.set(({ showSettings }) => ({
|
||||||
showSettings: !showSettings,
|
showSettings: !showSettings,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const setMetaData: BoundMethodCreator<[ConnectorState['metaData']]> = dispatch => metaData =>
|
|
||||||
dispatch.set({ metaData })
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { raiseError } from 'analytics'
|
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
|
const { pathname } = window.location
|
||||||
let [
|
let [
|
||||||
,
|
,
|
||||||
|
|
|
||||||
|
|
@ -101,10 +101,17 @@ export const GitHub: Platform = {
|
||||||
branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA()
|
branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { userName, repoName, type } = URLHelper.parse()
|
||||||
|
if (!userName || !repoName) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const metaData = {
|
const metaData = {
|
||||||
...URLHelper.parse(),
|
userName,
|
||||||
|
repoName,
|
||||||
|
type,
|
||||||
branchName,
|
branchName,
|
||||||
} as MetaData
|
}
|
||||||
return metaData
|
return metaData
|
||||||
},
|
},
|
||||||
async getMetaData({ userName, repoName }, accessToken) {
|
async getMetaData({ userName, repoName }, accessToken) {
|
||||||
|
|
@ -202,14 +209,14 @@ export const GitHub: Platform = {
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
const gitModules = root.contents?.find(item => item.name === '.gitmodules')
|
const gitModules = root.contents?.find(
|
||||||
if (gitModules) {
|
item => item.type === 'blob' && item.name === '.gitmodules',
|
||||||
if (userName && repoName && gitModules.sha) {
|
)
|
||||||
const blobData = await API.getBlobData(userName, repoName, gitModules.sha, accessToken)
|
if (gitModules?.sha) {
|
||||||
|
const blobData = await API.getBlobData(userName, repoName, gitModules.sha, accessToken)
|
||||||
|
|
||||||
if (blobData && blobData.encoding === 'base64' && blobData.content) {
|
if (blobData && blobData.encoding === 'base64' && blobData.content) {
|
||||||
await resolveGitModules(root, Base64.decode(blobData.content))
|
await resolveGitModules(root, Base64.decode(blobData.content))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,15 +82,23 @@ export const Gitea: Platform = {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let detectedBranchName
|
let branchName
|
||||||
if (DOMHelper.isInCodePage()) {
|
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 = {
|
const metaData = {
|
||||||
...URLHelper.parse(),
|
userName,
|
||||||
branchName: detectedBranchName,
|
repoName,
|
||||||
} as MetaData
|
type,
|
||||||
|
branchName,
|
||||||
|
}
|
||||||
|
|
||||||
return metaData
|
return metaData
|
||||||
},
|
},
|
||||||
async getMetaData(partialMetaData, accessToken) {
|
async getMetaData(partialMetaData, accessToken) {
|
||||||
|
|
|
||||||
|
|
@ -78,17 +78,24 @@ export const Gitee: Platform = {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let detectedBranchName
|
let branchName
|
||||||
if (DOMHelper.isInCodePage()) {
|
if (DOMHelper.isInCodePage()) {
|
||||||
// not working well with non-branch blob
|
// not working well with non-branch blob
|
||||||
// cannot handle '/' split branch name, should not use when possibly on branch page
|
// 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 = {
|
const metaData = {
|
||||||
...URLHelper.parse(),
|
userName,
|
||||||
branchName: detectedBranchName,
|
repoName,
|
||||||
} as MetaData
|
type,
|
||||||
|
branchName,
|
||||||
|
}
|
||||||
return metaData
|
return metaData
|
||||||
},
|
},
|
||||||
async getMetaData(partialMetaData, accessToken) {
|
async getMetaData(partialMetaData, accessToken) {
|
||||||
|
|
|
||||||
|
|
@ -187,3 +187,19 @@ export function withEffect<Method extends (...args: any[]) => any>(
|
||||||
export function run<T>(fn: () => T) {
|
export function run<T>(fn: () => T) {
|
||||||
return fn()
|
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