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;
|
(window as any).electron = mockElectron;
|
||||||
|
|
||||||
|
vi.mock('./ConfigContext', () => ({
|
||||||
|
useConfig: () => ({
|
||||||
|
extensionsList: [],
|
||||||
|
getExtensions: vi.fn().mockResolvedValue([]),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('ExtensionInstallModal', () => {
|
describe('ExtensionInstallModal', () => {
|
||||||
const mockAddExtension = vi.fn();
|
const mockAddExtension = vi.fn();
|
||||||
const mockSetView = 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 { IpcRendererEvent } from 'electron';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -13,6 +13,8 @@ import { extractExtensionName } from './settings/extensions/utils';
|
|||||||
import { addExtensionFromDeepLink } from './settings/extensions/deeplink';
|
import { addExtensionFromDeepLink } from './settings/extensions/deeplink';
|
||||||
import type { ExtensionConfig } from '../api/types.gen';
|
import type { ExtensionConfig } from '../api/types.gen';
|
||||||
import { View, ViewOptions } from '../utils/navigationUtils';
|
import { View, ViewOptions } from '../utils/navigationUtils';
|
||||||
|
import { useConfig } from './ConfigContext';
|
||||||
|
import { toastService } from '../toasts';
|
||||||
|
|
||||||
type ModalType = 'blocked' | 'untrusted' | 'trusted';
|
type ModalType = 'blocked' | 'untrusted' | 'trusted';
|
||||||
|
|
||||||
@@ -66,6 +68,14 @@ function extractRemoteUrl(link: string): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ExtensionInstallModal({ addExtension, setView }: ExtensionInstallModalProps) {
|
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>({
|
const [modalState, setModalState] = useState<ExtensionModalState>({
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
modalType: 'trusted',
|
modalType: 'trusted',
|
||||||
@@ -149,12 +159,30 @@ export function ExtensionInstallModal({ addExtension, setView }: ExtensionInstal
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleExtensionRequest = useCallback(async (link: string): Promise<void> => {
|
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 {
|
try {
|
||||||
console.log(`Processing extension request: ${link}`);
|
console.log(`Processing extension request: ${link}`);
|
||||||
|
|
||||||
const command = extractCommand(link);
|
const command = extractCommand(link);
|
||||||
const remoteUrl = extractRemoteUrl(link);
|
const remoteUrl = extractRemoteUrl(link);
|
||||||
const extName = extractExtensionName(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 = {
|
const extensionInfo: ExtensionInfo = {
|
||||||
name: extName,
|
name: extName,
|
||||||
@@ -182,6 +210,8 @@ export function ExtensionInstallModal({ addExtension, setView }: ExtensionInstal
|
|||||||
...prev,
|
...prev,
|
||||||
error: error instanceof Error ? error.message : 'Unknown error',
|
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]">
|
<DialogContent className="sm:max-w-[500px]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className={getTitleClassName()}>{config.title}</DialogTitle>
|
<DialogTitle className={getTitleClassName()}>{config.title}</DialogTitle>
|
||||||
<DialogDescription className="whitespace-pre-wrap text-left">
|
<DialogDescription className="text-left whitespace-pre-wrap">
|
||||||
{config.message}
|
{config.message}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|||||||
Reference in New Issue
Block a user