diff --git a/src/components/RepoContext.tsx b/src/components/RepoContext.tsx
index 2c97118..7d46c7e 100644
--- a/src/components/RepoContext.tsx
+++ b/src/components/RepoContext.tsx
@@ -1,6 +1,7 @@
import { useConfigs } from 'containers/ConfigsContext'
import { platform } from 'platforms'
import * as React from 'react'
+import { parseURLSearch, run } from 'utils/general'
import { useEffectOnSerializableUpdates } from 'utils/hooks/useEffectOnSerializableUpdates'
import { useLoadedContext } from 'utils/hooks/useLoadedContext'
import { useOnPJAXDone } from 'utils/hooks/usePJAX'
@@ -14,8 +15,13 @@ export function RepoContextWrapper({ children }: React.PropsWithChildren<{}>) {
const partialMetaData = usePartialMetaData()
const defaultBranch = useDefaultBranch(partialMetaData)
const metaData = useMetaData(partialMetaData, defaultBranch)
+ const fetchingAccessToken = useSetAccessToken()
- return {metaData && children}
+ return (
+
+ {metaData && !fetchingAccessToken && children}
+
+ )
}
function resolvePartialMetaData() {
@@ -97,3 +103,38 @@ function useMetaData(
}, [partialMetaData, branchName, defaultBranchName])
return $metaData.value
}
+
+function useSetAccessToken() {
+ const $running = useStateIO(() => Boolean(getCodeSearchParam()))
+ const configContext = useConfigs()
+ const { accessToken } = configContext.value
+ React.useEffect(() => {
+ run(async function () {
+ const code = getCodeSearchParam()
+ if (code && !accessToken) {
+ const accessToken = await getAccessTokenWithCode(code)
+ if (accessToken) configContext.onChange({ accessToken })
+ }
+ $running.onChange(false)
+ })
+ }, [])
+
+ return $running.value
+}
+
+function getCodeSearchParam() {
+ return parseURLSearch().get('code')
+}
+
+async function getAccessTokenWithCode(code: string) {
+ const accessToken = await platform.setOAuth(code)
+ if (!accessToken) alert(`Gitako: The OAuth token may have expired, please try again.`)
+ const search = parseURLSearch()
+ search.delete('code')
+ window.history.replaceState(
+ {},
+ 'removed search param',
+ window.location.pathname.replace(window.location.search, search.toString()),
+ )
+ return accessToken
+}
diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx
index 3104d60..536195d 100644
--- a/src/components/SideBar.tsx
+++ b/src/components/SideBar.tsx
@@ -5,30 +5,32 @@ import { Portal } from 'components/Portal'
import { Resizable } from 'components/Resizable'
import { SettingsBar } from 'components/settings/SettingsBar'
import { ToggleShowButton } from 'components/ToggleShowButton'
-import { useConfigs } from 'containers/ConfigsContext'
-import { connect } from 'driver/connect'
-import { SideBarCore } from 'driver/core'
-import { ConnectorState, Props } from 'driver/core/SideBar'
+import { ConfigsContextShape, useConfigs } from 'containers/ConfigsContext'
import { platform } from 'platforms'
import { useGitHubAttachCopyFileButton, useGitHubAttachCopySnippetButton } from 'platforms/GitHub'
import * as React from 'react'
import { cx } from 'utils/cx'
import * as DOMHelper from 'utils/DOMHelper'
-import { parseURLSearch, run } from 'utils/general'
+import { run } from 'utils/general'
import { useCatchNetworkError } from 'utils/hooks/useCatchNetworkError'
import { useLoadedContext } from 'utils/hooks/useLoadedContext'
import { loadWithPJAX, useOnPJAXDone, usePJAX } from 'utils/hooks/usePJAX'
import { useProgressBar } from 'utils/hooks/useProgressBar'
import { useStateIO } from 'utils/hooks/useStateIO'
import * as keyHelper from 'utils/keyHelper'
+import { SideBarErrorContext } from './ErrorContext'
import { Icon } from './Icon'
import { IIFC } from './IIFC'
import { LoadingIndicator } from './LoadingIndicator'
-import { SideBarStateContext } from './SideBarState'
+import { SideBarState, SideBarStateContext, SideBarStateContextShape } from './SideBarState'
import { Theme } from './Theme'
-const RawSideBar: React.FC = function RawGitako(props) {
- const { metaData, error, shouldShow, toggleShowSideBar } = props
+export function SideBar(props: {
+ metaData: MetaData | null
+ configContext: ConfigsContextShape
+ stateContext: SideBarStateContextShape
+}) {
+ const { metaData } = props
const state = useLoadedContext(SideBarStateContext).value
const configContext = useConfigs()
@@ -55,30 +57,31 @@ const RawSideBar: React.FC = function RawGitako(props) {
}
}, [hasMetaData])
- React.useEffect(() => {
- run(async function () {
- if (!accessToken) {
- const accessToken = await trySetUpAccessTokenWithCode()
- if (accessToken) configContext.onChange({ accessToken })
- }
- })
+ const $shouldShow = useStateIO(false)
+ const shouldShow = $shouldShow.value
+ const setShouldShow = React.useCallback((shouldShow: boolean) => {
+ $shouldShow.onChange(shouldShow)
+ DOMHelper.setBodyIndent(shouldShow)
}, [])
+ React.useEffect(() => {
+ if (shouldShow) {
+ DOMHelper.focusFileExplorer() // TODO: verify if it works
+ }
+ }, [shouldShow])
+ const toggleShowSideBar = React.useCallback(() => {
+ $shouldShow.onChange(shouldShow => {
+ DOMHelper.setBodyIndent(!shouldShow)
+ return !shouldShow
+ })
- React.useEffect(
- function attachKeyDown() {
- if (state === 'disabled' || !configContext.value.shortcut) return
-
- function onKeyDown(e: KeyboardEvent) {
- const keys = keyHelper.parseEvent(e)
- if (keys === configContext.value.shortcut) {
- toggleShowSideBar()
- }
- }
- window.addEventListener('keydown', onKeyDown)
- return () => window.removeEventListener('keydown', onKeyDown)
- },
- [toggleShowSideBar, state === 'disabled', configContext.value.shortcut],
- )
+ const {
+ value: { intelligentToggle },
+ } = configContext
+ if (intelligentToggle !== null) {
+ configContext.onChange({ intelligentToggle: !shouldShow })
+ }
+ }, [])
+ useToggleSideBarWithKeyboard(state, configContext, toggleShowSideBar)
const intelligentToggle = configContext.value.intelligentToggle
// Hide sidebar when error due to auth but token is set #128
@@ -86,19 +89,26 @@ const RawSideBar: React.FC = function RawGitako(props) {
intelligentToggle === null && Boolean(state === 'error-due-to-auth' && accessToken)
React.useEffect(() => {
if (hideSidebarOnInvalidToken) {
- props.setShouldShow(false)
+ setShouldShow(false)
} else {
const shouldShow = intelligentToggle === null ? platform.shouldShow() : intelligentToggle
- props.setShouldShow(shouldShow)
+ setShouldShow(shouldShow)
}
}, [intelligentToggle, hideSidebarOnInvalidToken, metaData])
+ const error = useLoadedContext(SideBarErrorContext).value
+ React.useEffect(() => {
+ if (error) {
+ $shouldShow.onChange(false)
+ }
+ }, [error])
+
const updateSideBarVisibility = React.useCallback(
function updateSideBarVisibility() {
if (hideSidebarOnInvalidToken) {
- props.setShouldShow(false)
+ setShouldShow(false)
} else if (intelligentToggle === null) {
- props.setShouldShow(platform.shouldShow())
+ setShouldShow(platform.shouldShow())
}
},
[metaData?.branchName, intelligentToggle, hideSidebarOnInvalidToken],
@@ -169,22 +179,24 @@ const RawSideBar: React.FC = function RawGitako(props) {
)
}
-RawSideBar.defaultProps = {
- shouldShow: false,
-}
+function useToggleSideBarWithKeyboard(
+ state: SideBarState,
+ configContext: ConfigsContextShape,
+ toggleShowSideBar: () => void,
+) {
+ React.useEffect(
+ function attachKeyDown() {
+ if (state === 'disabled' || !configContext.value.shortcut) return
-export const SideBar = connect(SideBarCore)(RawSideBar)
-
-async function trySetUpAccessTokenWithCode() {
- const search = parseURLSearch()
- if ('code' in search) {
- const accessToken = await platform.setOAuth(search.code)
- if (!accessToken) alert(`Gitako: The OAuth token has expired, please try again.`)
- window.history.replaceState(
- {},
- 'removed search param',
- window.location.pathname.replace(window.location.search, ''),
- )
- return accessToken
- }
+ function onKeyDown(e: KeyboardEvent) {
+ const keys = keyHelper.parseEvent(e)
+ if (keys === configContext.value.shortcut) {
+ toggleShowSideBar()
+ }
+ }
+ window.addEventListener('keydown', onKeyDown)
+ return () => window.removeEventListener('keydown', onKeyDown)
+ },
+ [toggleShowSideBar, state === 'disabled', configContext.value.shortcut],
+ )
}
diff --git a/src/components/ToggleShowButton.tsx b/src/components/ToggleShowButton.tsx
index 4a07863..85bb34f 100644
--- a/src/components/ToggleShowButton.tsx
+++ b/src/components/ToggleShowButton.tsx
@@ -5,7 +5,7 @@ import { useDebounce, useWindowSize } from 'react-use'
import { Icon } from './Icon'
type Props = {
- error?: string
+ error?: string | null
} & Pick, 'onClick'>
export function ToggleShowButton({ error, onClick }: Props) {
diff --git a/src/driver/core/SideBar.ts b/src/driver/core/SideBar.ts
deleted file mode 100644
index 287c4a6..0000000
--- a/src/driver/core/SideBar.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { SideBarStateContextShape } from 'components/SideBarState'
-import { ConfigsContextShape } from 'containers/ConfigsContext'
-import { GetCreatedMethod, MethodCreator } from 'driver/connect'
-import * as DOMHelper from 'utils/DOMHelper'
-
-export type Props = {
- // meta data for the repository
- metaData: MetaData | null
- configContext: ConfigsContextShape
- stateContext: SideBarStateContextShape
-}
-
-export type ConnectorState = {
- // error message
- error?: string
- // whether Gitako side bar should be shown
- shouldShow: boolean
-} & {
- setShouldShow: GetCreatedMethod
- toggleShowSideBar: GetCreatedMethod
-}
-
-type BoundMethodCreator = MethodCreator
-
-export const toggleShowSideBar: BoundMethodCreator = dispatch => () => {
- const {
- state: { shouldShow },
- props: { configContext },
- } = dispatch.get()
- dispatch.call(setShouldShow, !shouldShow)
-
- const {
- value: { intelligentToggle },
- } = configContext
- if (intelligentToggle !== null) {
- configContext.onChange({ intelligentToggle: !shouldShow })
- }
-}
-
-export const setShouldShow: BoundMethodCreator<
- [ConnectorState['shouldShow']]
-> = dispatch => shouldShow => {
- dispatch.set({ shouldShow }, shouldShow ? DOMHelper.focusFileExplorer : undefined)
- DOMHelper.setBodyIndent(shouldShow)
-}
-
-export const setError: BoundMethodCreator<[ConnectorState['error']]> = dispatch => error => {
- dispatch.set({ error })
- dispatch.call(setShouldShow, false)
-}
diff --git a/src/driver/core/index.ts b/src/driver/core/index.ts
index 4eb403b..dd80f10 100644
--- a/src/driver/core/index.ts
+++ b/src/driver/core/index.ts
@@ -4,8 +4,5 @@ import {
ConnectorState as FileExplorerConnectorState,
Props as FileExplorerProps,
} from './FileExplorer'
-import * as SideBar from './SideBar'
-import { ConnectorState as SideBarConnectorState, Props as SideBarProps } from './SideBar'
export const FileExplorerCore: Sources = FileExplorer
-export const SideBarCore: Sources = SideBar