diff --git a/ui/desktop/src/components/settings_v2/extensions/modal/ExtensionTimeoutField.tsx b/ui/desktop/src/components/settings_v2/extensions/modal/ExtensionTimeoutField.tsx
new file mode 100644
index 00000000..4f33fe66
--- /dev/null
+++ b/ui/desktop/src/components/settings_v2/extensions/modal/ExtensionTimeoutField.tsx
@@ -0,0 +1,54 @@
+import { Input } from '../../../ui/input';
+import Select from 'react-select';
+import React, { useState } from 'react';
+
+interface ExtensionTimeoutFieldProps {
+ timeout: number;
+ onChange: (key: string, value: any) => void;
+ submitAttempted: boolean;
+}
+
+export default function ExtensionTimeoutField({
+ timeout,
+ onChange,
+ submitAttempted,
+}: ExtensionTimeoutFieldProps) {
+ const isTimeoutValid = () => {
+ // Check if timeout is not undefined, null, or empty string
+ if (timeout === undefined || timeout === null) {
+ return false;
+ }
+
+ // Convert to number if it's a string
+ const timeoutValue = typeof timeout === 'string' ? Number(timeout) : timeout;
+
+ // Check if it's a valid number (not NaN) and is a positive number
+ return !isNaN(timeoutValue) && timeoutValue > 0;
+ };
+
+ return (
+
+ {/* Row with Timeout and timeout input side by side */}
+
+
+
+
+
+ {/* Type Dropdown */}
+
+
+
onChange('timeout', e.target.value)}
+ defaultValue={300}
+ className={`${!submitAttempted || isTimeoutValid() ? 'border-borderSubtle' : 'border-red-500'} text-textStandard focus:border-borderStandard`}
+ />
+ {submitAttempted && !isTimeoutValid() && (
+
Timeout
+ )}
+
+
+
+
+ );
+}
diff --git a/ui/desktop/src/components/settings_v2/extensions/utils.ts b/ui/desktop/src/components/settings_v2/extensions/utils.ts
index abc3006a..dc7989b7 100644
--- a/ui/desktop/src/components/settings_v2/extensions/utils.ts
+++ b/ui/desktop/src/components/settings_v2/extensions/utils.ts
@@ -1,5 +1,7 @@
// Default extension timeout in seconds
// TODO: keep in sync with rust better
+import * as module from 'node:module';
+
export const DEFAULT_EXTENSION_TIMEOUT = 300;
/**
@@ -24,6 +26,7 @@ export interface ExtensionFormData {
cmd?: string;
endpoint?: string;
enabled: boolean;
+ timeout?: number;
envVars: { key: string; value: string }[];
}
@@ -35,6 +38,7 @@ export function getDefaultFormData(): ExtensionFormData {
cmd: '',
endpoint: '',
enabled: true,
+ timeout: 300,
envVars: [],
};
}
@@ -59,6 +63,7 @@ export function extensionToFormData(extension: FixedExtensionEntry): ExtensionFo
cmd: extension.type === 'stdio' ? combineCmdAndArgs(extension.cmd, extension.args) : undefined,
endpoint: extension.type === 'sse' ? extension.uri : undefined,
enabled: extension.enabled,
+ timeout: extension.timeout,
envVars,
};
}
@@ -84,6 +89,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
description: formData.description,
cmd: cmd,
args: args,
+ timeout: formData.timeout,
...(Object.keys(envs).length > 0 ? { envs } : {}),
};
} else if (formData.type === 'sse') {
@@ -91,6 +97,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
type: 'sse',
name: formData.name,
description: formData.description,
+ timeout: formData.timeout,
uri: formData.endpoint, // Assuming endpoint maps to uri for SSE type
...(Object.keys(envs).length > 0 ? { envs } : {}),
};
@@ -99,6 +106,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
return {
type: formData.type,
name: formData.name,
+ timeout: formData.timeout,
};
}
}