From 79644fba82712dff8343d59fcf8159d40f9b523e Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 9 May 2021 23:16:39 +0800 Subject: [PATCH] refactor: deprecate driven sidebar --- src/components/RepoContext.tsx | 43 ++++++++++- src/components/SideBar.tsx | 114 +++++++++++++++------------- src/components/ToggleShowButton.tsx | 2 +- src/driver/core/SideBar.ts | 50 ------------ src/driver/core/index.ts | 3 - 5 files changed, 106 insertions(+), 106 deletions(-) delete mode 100644 src/driver/core/SideBar.ts 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