fix[desktop]: deeplink ui repeat on refresh (#6469)
Signed-off-by: Yelsin Sepulveda <yelsinsepulveda@gmail.com> Co-authored-by: Zane Staggs <zane@squareup.com>
This commit is contained in:
@@ -19,6 +19,13 @@ const mockElectron = {
|
||||
|
||||
(window as any).electron = mockElectron;
|
||||
|
||||
vi.mock('./ConfigContext', () => ({
|
||||
useConfig: () => ({
|
||||
extensionsList: [],
|
||||
getExtensions: vi.fn().mockResolvedValue([]),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('ExtensionInstallModal', () => {
|
||||
const mockAddExtension = vi.fn();
|
||||
const mockSetView = vi.fn();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { useState, useCallback, useEffect, useRef } from 'react';
|
||||
import { IpcRendererEvent } from 'electron';
|
||||
import {
|
||||
Dialog,
|
||||
@@ -13,6 +13,8 @@ import { extractExtensionName } from './settings/extensions/utils';
|
||||
import { addExtensionFromDeepLink } from './settings/extensions/deeplink';
|
||||
import type { ExtensionConfig } from '../api/types.gen';
|
||||
import { View, ViewOptions } from '../utils/navigationUtils';
|
||||
import { useConfig } from './ConfigContext';
|
||||
import { toastService } from '../toasts';
|
||||
|
||||
type ModalType = 'blocked' | 'untrusted' | 'trusted';
|
||||
|
||||
@@ -66,6 +68,14 @@ function extractRemoteUrl(link: string): string | null {
|
||||
}
|
||||
|
||||
export function ExtensionInstallModal({ addExtension, setView }: ExtensionInstallModalProps) {
|
||||
const { getExtensions } = useConfig();
|
||||
const getExtensionsRef = useRef(getExtensions);
|
||||
const processingLinkRef = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
getExtensionsRef.current = getExtensions;
|
||||
}, [getExtensions]);
|
||||
|
||||
const [modalState, setModalState] = useState<ExtensionModalState>({
|
||||
isOpen: false,
|
||||
modalType: 'trusted',
|
||||
@@ -149,12 +159,30 @@ export function ExtensionInstallModal({ addExtension, setView }: ExtensionInstal
|
||||
};
|
||||
|
||||
const handleExtensionRequest = useCallback(async (link: string): Promise<void> => {
|
||||
if (processingLinkRef.current === link) {
|
||||
console.log(`Skipping duplicate extension request (already processing): ${link}`);
|
||||
return;
|
||||
}
|
||||
processingLinkRef.current = link;
|
||||
|
||||
try {
|
||||
console.log(`Processing extension request: ${link}`);
|
||||
|
||||
const command = extractCommand(link);
|
||||
const remoteUrl = extractRemoteUrl(link);
|
||||
const extName = extractExtensionName(link);
|
||||
const extensionsList = await getExtensionsRef.current(true);
|
||||
|
||||
if (extensionsList?.find((ext) => ext.name === extName)) {
|
||||
console.log(`Extension Already Installed: ${extName}`);
|
||||
|
||||
toastService.success({
|
||||
title: `Extension '${extName}' Already Installed`,
|
||||
msg: `'${extName}' extension has already been installed successfully. Start a new chat session to use it.`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log('Extension not found, continuing to show modal');
|
||||
|
||||
const extensionInfo: ExtensionInfo = {
|
||||
name: extName,
|
||||
@@ -182,6 +210,8 @@ export function ExtensionInstallModal({ addExtension, setView }: ExtensionInstal
|
||||
...prev,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
}));
|
||||
} finally {
|
||||
processingLinkRef.current = null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -285,7 +315,7 @@ export function ExtensionInstallModal({ addExtension, setView }: ExtensionInstal
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className={getTitleClassName()}>{config.title}</DialogTitle>
|
||||
<DialogDescription className="whitespace-pre-wrap text-left">
|
||||
<DialogDescription className="text-left whitespace-pre-wrap">
|
||||
{config.message}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
Reference in New Issue
Block a user