From 08d15e5dc7aa93f0172775e658c02bffaa62a66a Mon Sep 17 00:00:00 2001 From: NamH Date: Mon, 13 May 2024 16:47:27 +0700 Subject: [PATCH] fix: deeplink when app not open on linux (#2893) Co-authored-by: James --- electron/managers/window.ts | 2 +- web/containers/LoadingModal/index.tsx | 6 +- web/containers/Providers/DeepLinkListener.tsx | 99 ++++++++++++------- 3 files changed, 67 insertions(+), 40 deletions(-) diff --git a/electron/managers/window.ts b/electron/managers/window.ts index 6052f332a..ab76bb94b 100644 --- a/electron/managers/window.ts +++ b/electron/managers/window.ts @@ -29,7 +29,7 @@ class WindowManager { }, }) - if (process.platform === 'win32') { + if (process.platform === 'win32' || process.platform === 'linux') { /// This is work around for windows deeplink. /// second-instance event is not fired when app is not open, so the app /// does not received the deeplink. diff --git a/web/containers/LoadingModal/index.tsx b/web/containers/LoadingModal/index.tsx index cfaf05c7e..0159134f4 100644 --- a/web/containers/LoadingModal/index.tsx +++ b/web/containers/LoadingModal/index.tsx @@ -6,12 +6,10 @@ export type LoadingInfo = { message: string } -export const loadingModalVisibilityAtom = atom( - undefined -) +export const loadingModalInfoAtom = atom(undefined) const ResettingModal: React.FC = () => { - const loadingInfo = useAtomValue(loadingModalVisibilityAtom) + const loadingInfo = useAtomValue(loadingModalInfoAtom) return ( diff --git a/web/containers/Providers/DeepLinkListener.tsx b/web/containers/Providers/DeepLinkListener.tsx index ca275e52c..d5941204f 100644 --- a/web/containers/Providers/DeepLinkListener.tsx +++ b/web/containers/Providers/DeepLinkListener.tsx @@ -6,7 +6,7 @@ import { useDebouncedCallback } from 'use-debounce' import { useGetHFRepoData } from '@/hooks/useGetHFRepoData' -import { loadingModalVisibilityAtom as loadingModalInfoAtom } from '../LoadingModal' +import { loadingModalInfoAtom } from '../LoadingModal' import { toaster } from '../Toast' import { @@ -27,46 +27,75 @@ const DeepLinkListener: React.FC = ({ children }) => { importHuggingFaceModelStageAtom ) - const debounced = useDebouncedCallback(async (searchText) => { - if (searchText.indexOf('/') === -1) { - toaster({ - title: 'Failed to get Hugging Face models', - description: 'Invalid Hugging Face model URL', - type: 'error', - }) - return - } - - try { - setLoadingInfo({ - title: 'Getting Hugging Face models', - message: 'Please wait..', - }) - const data = await getHfRepoData(searchText) - setImportingHuggingFaceRepoData(data) - setImportHuggingFaceModelStage('REPO_DETAIL') - setLoadingInfo(undefined) - } catch (err) { - setLoadingInfo(undefined) - let errMessage = 'Unexpected Error' - if (err instanceof Error) { - errMessage = err.message + const handleDeepLinkAction = useDebouncedCallback( + async (deepLinkAction: DeepLinkAction) => { + if ( + deepLinkAction.action !== 'models' || + deepLinkAction.provider !== 'huggingface' + ) { + console.error( + `Invalid deeplink action (${deepLinkAction.action}) or provider (${deepLinkAction.provider})` + ) + return } - toaster({ - title: 'Failed to get Hugging Face models', - description: errMessage, - type: 'error', - }) - console.error(err) - } - }, 300) + + try { + setLoadingInfo({ + title: 'Getting Hugging Face models', + message: 'Please wait..', + }) + const data = await getHfRepoData(deepLinkAction.resource) + setImportingHuggingFaceRepoData(data) + setImportHuggingFaceModelStage('REPO_DETAIL') + setLoadingInfo(undefined) + } catch (err) { + setLoadingInfo(undefined) + toaster({ + title: 'Failed to get Hugging Face models', + description: err instanceof Error ? err.message : 'Unexpected Error', + type: 'error', + }) + console.error(err) + } + }, + 300 + ) + window.electronAPI?.onDeepLink((_event: string, input: string) => { window.core?.api?.ackDeepLink() - const url = input.replaceAll('jan://', '') - debounced(url) + + const action = deeplinkParser(input) + if (!action) return + handleDeepLinkAction(action) }) return {children} } +type DeepLinkAction = { + action: string + provider: string + resource: string +} + +const deeplinkParser = ( + deepLink: string | undefined +): DeepLinkAction | undefined => { + if (!deepLink) return undefined + + try { + const url = new URL(deepLink) + const params = url.pathname.split('/').filter((str) => str.length > 0) + + if (params.length < 3) return undefined + const action = params[0] + const provider = params[1] + const resource = params.slice(2).join('/') + return { action, provider, resource } + } catch (err) { + console.error(err) + return undefined + } +} + export default DeepLinkListener