settingsv2: fix process for deeplinks with env vars (#2142)

This commit is contained in:
Lily Delalande
2025-04-11 10:17:08 -04:00
committed by GitHub
parent 58c67da2e5
commit cb9af4d96f
4 changed files with 52 additions and 7 deletions
+3
View File
@@ -86,6 +86,9 @@
"prettier": "^3.4.2", "prettier": "^3.4.2",
"tailwindcss": "^3.4.14", "tailwindcss": "^3.4.14",
"vite": "^5.4.17" "vite": "^5.4.17"
},
"engines": {
"node": "^23.0.0"
} }
}, },
"node_modules/@ai-sdk/openai": { "node_modules/@ai-sdk/openai": {
@@ -6,18 +6,21 @@ import ExtensionsSection from './extensions/ExtensionsSection';
import ModelsSection from './models/ModelsSection'; import ModelsSection from './models/ModelsSection';
import { ModeSection } from './mode/ModeSection'; import { ModeSection } from './mode/ModeSection';
import SessionSharingSection from './sessions/SessionSharingSection'; import SessionSharingSection from './sessions/SessionSharingSection';
import { ExtensionConfig } from '../../api';
export type SettingsViewOptions = { export type SettingsViewOptions = {
extensionId?: string; deepLinkConfig?: ExtensionConfig;
showEnvVars?: boolean; showEnvVars?: boolean;
}; };
export default function SettingsView({ export default function SettingsView({
onClose, onClose,
setView, setView,
viewOptions,
}: { }: {
onClose: () => void; onClose: () => void;
setView: (view: View) => void; setView: (view: View) => void;
viewOptions: SettingsViewOptions;
}) { }) {
return ( return (
<div className="h-screen w-full animate-[fadein_200ms_ease-in_forwards]"> <div className="h-screen w-full animate-[fadein_200ms_ease-in_forwards]">
@@ -36,7 +39,10 @@ export default function SettingsView({
{/* Models Section */} {/* Models Section */}
<ModelsSection setView={setView} /> <ModelsSection setView={setView} />
{/* Extensions Section */} {/* Extensions Section */}
<ExtensionsSection /> <ExtensionsSection
deepLinkConfig={viewOptions.deepLinkConfig}
showEnvVars={viewOptions.showEnvVars}
/>
{/* Goose Modes */} {/* Goose Modes */}
<ModeSection /> <ModeSection />
{/*Session sharing*/} {/*Session sharing*/}
@@ -1,4 +1,4 @@
import React, { useEffect, useState, useCallback } from 'react'; import { useEffect, useState, useCallback } from 'react';
import { Button } from '../../ui/button'; import { Button } from '../../ui/button';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { GPSIcon } from '../../ui/icons'; import { GPSIcon } from '../../ui/icons';
@@ -14,14 +14,25 @@ import {
} from './utils'; } from './utils';
import { activateExtension, deleteExtension, toggleExtension, updateExtension } from './index'; import { activateExtension, deleteExtension, toggleExtension, updateExtension } from './index';
import { ExtensionConfig } from '../../../api/types.gen';
export default function ExtensionsSection() { interface ExtensionSectionProps {
deepLinkConfig?: ExtensionConfig;
showEnvVars?: boolean;
}
export default function ExtensionsSection({ deepLinkConfig, showEnvVars }: ExtensionSectionProps) {
const { getExtensions, addExtension, removeExtension } = useConfig(); const { getExtensions, addExtension, removeExtension } = useConfig();
const [extensions, setExtensions] = useState<FixedExtensionEntry[]>([]); const [extensions, setExtensions] = useState<FixedExtensionEntry[]>([]);
const [selectedExtension, setSelectedExtension] = useState<FixedExtensionEntry | null>(null); const [selectedExtension, setSelectedExtension] = useState<FixedExtensionEntry | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const [isAddModalOpen, setIsAddModalOpen] = useState(false); const [isAddModalOpen, setIsAddModalOpen] = useState(false);
// We don't need errorFormData anymore since we're not reopening modals on failure const [deepLinkConfigStateVar, setDeepLinkConfigStateVar] = useState<
ExtensionConfig | undefined | null
>(deepLinkConfig);
const [showEnvVarsStateVar, setShowEnvVarsStateVar] = useState<boolean | undefined | null>(
showEnvVars
);
const fetchExtensions = useCallback(async () => { const fetchExtensions = useCallback(async () => {
const extensionsList = await getExtensions(true); // Force refresh const extensionsList = await getExtensions(true); // Force refresh
@@ -115,6 +126,9 @@ export default function ExtensionsSection() {
}; };
const handleModalClose = () => { const handleModalClose = () => {
setDeepLinkConfigStateVar(null);
setShowEnvVarsStateVar(null);
setIsModalOpen(false); setIsModalOpen(false);
setIsAddModalOpen(false); setIsAddModalOpen(false);
setSelectedExtension(null); setSelectedExtension(null);
@@ -178,6 +192,18 @@ export default function ExtensionsSection() {
modalType={'add'} modalType={'add'}
/> />
)} )}
{/* Modal for adding extension from deeplink*/}
{deepLinkConfigStateVar && showEnvVarsStateVar && (
<ExtensionModal
title="Add custom extension"
initialData={extensionToFormData({ ...deepLinkConfig, enabled: true })}
onClose={handleModalClose}
onSubmit={handleAddExtension}
submitLabel="Add Extension"
modalType={'add'}
/>
)}
</div> </div>
</section> </section>
); );
@@ -2,6 +2,7 @@ import type { ExtensionConfig } from '../../../api/types.gen';
import { toastService } from '../../../toasts'; import { toastService } from '../../../toasts';
import { activateExtension } from './extension-manager'; import { activateExtension } from './extension-manager';
import { DEFAULT_EXTENSION_TIMEOUT, nameToKey } from './utils'; import { DEFAULT_EXTENSION_TIMEOUT, nameToKey } from './utils';
import { settingsV2Enabled } from '../../../flags';
/** /**
* Build an extension config for stdio from the deeplink URL * Build an extension config for stdio from the deeplink URL
@@ -82,7 +83,12 @@ export async function addExtensionFromDeepLink(
extensionConfig: ExtensionConfig, extensionConfig: ExtensionConfig,
enabled: boolean enabled: boolean
) => Promise<void>, ) => Promise<void>,
setView: (view: string, options: { extensionId: string; showEnvVars: boolean }) => void setView: (
view: string,
options:
| { extensionId: string; showEnvVars: boolean }
| { deepLinkConfig: ExtensionConfig; showEnvVars: boolean }
) => void
) { ) {
const parsedUrl = new URL(url); const parsedUrl = new URL(url);
@@ -123,7 +129,11 @@ export async function addExtensionFromDeepLink(
// Check if extension requires env vars and go to settings if so // Check if extension requires env vars and go to settings if so
if (config.envs && Object.keys(config.envs).length > 0) { if (config.envs && Object.keys(config.envs).length > 0) {
console.log('Environment variables required, redirecting to settings'); console.log('Environment variables required, redirecting to settings');
setView('settings', { extensionId: nameToKey(name), showEnvVars: true }); if (settingsV2Enabled) {
setView('settings', { deepLinkConfig: config, showEnvVars: true });
} else {
setView('settings', { extensionId: nameToKey(name), showEnvVars: true });
}
return; return;
} }