fix redirect to extensions page after deeplink install and show toast with success message (#4863)
Co-authored-by: Amed Rodriguez <amed@squareup.com>
This commit is contained in:
@@ -24,6 +24,7 @@ interface ExtensionSectionProps {
|
||||
disableConfiguration?: boolean;
|
||||
customToggle?: (extension: FixedExtensionEntry) => Promise<boolean | void>;
|
||||
selectedExtensions?: string[]; // Add controlled state
|
||||
onModalClose?: (extensionName: string) => void;
|
||||
}
|
||||
|
||||
export default function ExtensionsSection({
|
||||
@@ -34,6 +35,7 @@ export default function ExtensionsSection({
|
||||
disableConfiguration,
|
||||
customToggle,
|
||||
selectedExtensions = [],
|
||||
onModalClose,
|
||||
}: ExtensionSectionProps) {
|
||||
const { getExtensions, addExtension, removeExtension, extensionsList } = useConfig();
|
||||
const [selectedExtension, setSelectedExtension] = useState<FixedExtensionEntry | null>(null);
|
||||
@@ -127,11 +129,15 @@ export default function ExtensionsSection({
|
||||
extensionConfig: extensionConfig,
|
||||
sessionId: sessionId,
|
||||
});
|
||||
// Immediately refresh the extensions list after successful activation
|
||||
await fetchExtensions();
|
||||
} catch (error) {
|
||||
console.error('Failed to activate extension:', error);
|
||||
} finally {
|
||||
await fetchExtensions();
|
||||
if (onModalClose) {
|
||||
setTimeout(() => {
|
||||
onModalClose(formData.name);
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -88,7 +88,8 @@ function getStreamableHttpConfig(
|
||||
name: string,
|
||||
description: string,
|
||||
timeout: number,
|
||||
headers?: { [key: string]: string }
|
||||
headers?: { [key: string]: string },
|
||||
envs?: { [key: string]: string }
|
||||
) {
|
||||
const config: ExtensionConfig = {
|
||||
name,
|
||||
@@ -97,6 +98,7 @@ function getStreamableHttpConfig(
|
||||
description,
|
||||
timeout: timeout,
|
||||
headers: headers,
|
||||
envs: envs,
|
||||
};
|
||||
|
||||
return config;
|
||||
@@ -114,14 +116,9 @@ export async function addExtensionFromDeepLink(
|
||||
) => Promise<void>,
|
||||
setView: (
|
||||
view: string,
|
||||
options:
|
||||
| { extensionId: string; showEnvVars: boolean }
|
||||
| { deepLinkConfig: ExtensionConfig; showEnvVars: boolean }
|
||||
options: { showEnvVars: boolean; deepLinkConfig?: ExtensionConfig }
|
||||
) => void
|
||||
) {
|
||||
console.log('=== addExtensionFromDeepLink Debug ===');
|
||||
console.log('URL:', url);
|
||||
|
||||
const parsedUrl = new URL(url);
|
||||
|
||||
if (parsedUrl.protocol !== 'goose:') {
|
||||
@@ -168,9 +165,21 @@ export async function addExtensionFromDeepLink(
|
||||
)
|
||||
: undefined;
|
||||
|
||||
// Parse env vars for remote extensions (same logic as stdio)
|
||||
const envList = parsedUrl.searchParams.getAll('env');
|
||||
const envs =
|
||||
envList.length > 0
|
||||
? Object.fromEntries(
|
||||
envList.map((env) => {
|
||||
const [key] = env.split('=');
|
||||
return [key, ''];
|
||||
})
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const config = remoteUrl
|
||||
? transportType === 'streamable_http'
|
||||
? getStreamableHttpConfig(remoteUrl, name, description || '', timeout, headers)
|
||||
? getStreamableHttpConfig(remoteUrl, name, description || '', timeout, headers, envs)
|
||||
: getSseConfig(remoteUrl, name, description || '', timeout)
|
||||
: getStdioConfig(cmd!, parsedUrl, name, description || '', timeout);
|
||||
|
||||
@@ -180,21 +189,25 @@ export async function addExtensionFromDeepLink(
|
||||
config.type === 'streamable_http' && config.headers && Object.keys(config.headers).length > 0;
|
||||
|
||||
if (hasEnvVars || hasHeaders) {
|
||||
console.log('Environment variables or headers required, redirecting to settings');
|
||||
console.log('Calling setView with:', { deepLinkConfig: config, showEnvVars: true });
|
||||
setView('settings', { deepLinkConfig: config, showEnvVars: true });
|
||||
console.log(
|
||||
'Environment variables or headers required, redirecting to extensions with env variables modal showing'
|
||||
);
|
||||
setView('extensions', { deepLinkConfig: config, showEnvVars: true });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('No env vars required, activating extension directly');
|
||||
// Note: deeplink activation doesn't have access to sessionId
|
||||
// The extension will be added to config but not activated in the current session
|
||||
// It will be activated when the next session starts
|
||||
console.warn('Extension will be added to config but requires a session to activate');
|
||||
await addExtensionFn(config.name, config, true);
|
||||
} catch (error) {
|
||||
console.error('Failed to activate extension from deeplink:', error);
|
||||
throw error;
|
||||
}
|
||||
console.log('No env vars required, activating extension directly');
|
||||
// Note: deeplink activation doesn't have access to sessionId
|
||||
// The extension will be added to config but not activated in the current session
|
||||
// It will be activated when the next session starts
|
||||
await addExtensionFn(config.name, config, true);
|
||||
|
||||
// Show success toast and navigate to extensions page
|
||||
toastService.success({
|
||||
title: 'Extension Installed',
|
||||
msg: `${config.name} extension has been installed successfully. Start a new chat session to use it.`,
|
||||
});
|
||||
|
||||
// Navigate to extensions page to show the newly installed extension
|
||||
setView('extensions', { deepLinkConfig: config, showEnvVars: false });
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import kebabCase from 'lodash/kebabCase';
|
||||
import { Switch } from '../../../ui/switch';
|
||||
import { Gear } from '../../../icons/Gear';
|
||||
import { Gear } from '../../../icons';
|
||||
import { FixedExtensionEntry } from '../../../ConfigContext';
|
||||
import { getSubtitle, getFriendlyTitle } from './ExtensionList';
|
||||
import { Card, CardHeader, CardTitle, CardContent, CardAction } from '../../../ui/card';
|
||||
@@ -73,6 +74,7 @@ export default function ExtensionItem({
|
||||
|
||||
return (
|
||||
<Card
|
||||
id={`extension-${kebabCase(extension.name)}`}
|
||||
className="transition-all duration-200 hover:shadow-default hover:cursor-pointer min-h-[120px] overflow-hidden"
|
||||
onClick={() => handleToggle(extension)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user