ui: add description field to modal (#1846)

This commit is contained in:
Lily Delalande
2025-03-25 13:28:09 -04:00
committed by GitHub
parent 96b905a501
commit 615788ae62
4 changed files with 56 additions and 30 deletions

View File

@@ -5,6 +5,7 @@ import React, { useState } from 'react';
interface ExtensionInfoFieldsProps {
name: string;
type: 'stdio' | 'sse' | 'builtin';
description: string;
onChange: (key: string, value: any) => void;
submitAttempted: boolean;
}
@@ -12,6 +13,7 @@ interface ExtensionInfoFieldsProps {
export default function ExtensionInfoFields({
name,
type,
description,
onChange,
submitAttempted,
}: ExtensionInfoFieldsProps) {
@@ -20,37 +22,54 @@ export default function ExtensionInfoFields({
};
return (
<div className="flex justify-between gap-4 mb-6">
<div className="flex-1">
<label className="text-sm font-medium mb-2 block text-textStandard">Extension Name</label>
<div className="relative">
<Input
value={name}
onChange={(e) => onChange('name', e.target.value)}
placeholder="Enter extension name..."
className={`${!submitAttempted || isNameValid() ? 'border-borderSubtle' : 'border-red-500'} text-textStandard focus:border-borderStandard`}
<div className="flex flex-col gap-4 mb-6">
{/* Top row with Name and Type side by side */}
<div className="flex justify-between gap-4">
<div className="flex-1">
<label className="text-sm font-medium mb-2 block text-textStandard">Extension Name</label>
<div className="relative">
<Input
value={name}
onChange={(e) => onChange('name', e.target.value)}
placeholder="Enter extension name..."
className={`${!submitAttempted || isNameValid() ? 'border-borderSubtle' : 'border-red-500'} text-textStandard focus:border-borderStandard`}
/>
{submitAttempted && !isNameValid() && (
<div className="absolute text-xs text-red-500 mt-1">Name is required</div>
)}
</div>
</div>
{/* Type Dropdown */}
<div className="w-[200px]">
<label className="text-sm font-medium mb-2 block text-textStandard">Type</label>
<Select
value={{ value: type, label: type.toUpperCase() }}
onChange={(option: { value: string; label: string } | null) => {
if (option) {
onChange('type', option.value);
}
}}
options={[
{ value: 'stdio', label: 'Standard IO (STDIO)' },
{ value: 'sse', label: 'Security Service Edge (SSE)' },
]}
isSearchable={false}
/>
{submitAttempted && !isNameValid() && (
<div className="absolute text-xs text-red-500 mt-1">Name is required</div>
)}
</div>
</div>
{/* Type Dropdown */}
<div className="w-[200px]">
<label className="text-sm font-medium mb-2 block text-textStandard">Type</label>
<Select
value={{ value: type, label: type.toUpperCase() }}
onChange={(option: { value: string; label: string } | null) => {
if (option) {
onChange('type', option.value);
}
}}
options={[
{ value: 'stdio', label: 'Standard IO (STDIO)' },
{ value: 'sse', label: 'Security Service Edge (SSE)' },
]}
isSearchable={false}
/>
{/* Bottom row with Description spanning full width */}
<div className="w-full">
<label className="text-sm font-medium mb-2 block text-textStandard">Description</label>
<div className="relative">
<Input
value={description}
onChange={(e) => onChange('description', e.target.value)}
placeholder="Optional description..."
className={`text-textStandard focus:border-borderStandard`}
/>
</div>
</div>
</div>
);

View File

@@ -177,6 +177,7 @@ export default function ExtensionModal({
<ExtensionInfoFields
name={formData.name}
type={formData.type}
description={formData.description}
onChange={(key, value) => setFormData({ ...formData, [key]: value })}
submitAttempted={submitAttempted}
/>

View File

@@ -59,10 +59,10 @@ export function getSubtitle(config: ExtensionConfig): string {
}
if (config.type === 'stdio') {
const full_command = combineCmdAndArgs(config.cmd, config.args);
return `STDIO extension${full_command ? `\n${full_command}` : ''}`;
return `STDIO extension${config.description ? `: ${config.description}` : ''}${full_command ? `\n${full_command}` : ''}`;
}
if (config.type === 'sse') {
return `SSE extension${config.uri ? ` (${config.uri})` : ''}`;
return `SSE extension${config.description ? `: ${config.description}` : ''}${config.uri ? ` (${config.uri})` : ''}`;
}
return `Unknown type of extension`;
}

View File

@@ -3,6 +3,7 @@ import { ExtensionConfig } from '../../../api/types.gen';
export interface ExtensionFormData {
name: string;
description: string;
type: 'stdio' | 'sse' | 'builtin';
cmd?: string;
endpoint?: string;
@@ -13,6 +14,7 @@ export interface ExtensionFormData {
export function getDefaultFormData(): ExtensionFormData {
return {
name: '',
description: '',
type: 'stdio',
cmd: '',
endpoint: '',
@@ -35,6 +37,8 @@ export function extensionToFormData(extension: FixedExtensionEntry): ExtensionFo
return {
name: extension.name,
description:
extension.type === 'stdio' || extension.type === 'sse' ? extension.description : undefined,
type: extension.type,
cmd: extension.type === 'stdio' ? combineCmdAndArgs(extension.cmd, extension.args) : undefined,
endpoint: extension.type === 'sse' ? extension.uri : undefined,
@@ -61,6 +65,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
return {
type: 'stdio',
name: formData.name,
description: formData.description,
cmd: cmd,
args: args,
...(Object.keys(envs).length > 0 ? { envs } : {}),
@@ -69,6 +74,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
return {
type: 'sse',
name: formData.name,
description: formData.description,
uri: formData.endpoint, // Assuming endpoint maps to uri for SSE type
...(Object.keys(envs).length > 0 ? { envs } : {}),
};