ui: add description field to modal (#1846)
This commit is contained in:
@@ -5,6 +5,7 @@ import React, { useState } from 'react';
|
|||||||
interface ExtensionInfoFieldsProps {
|
interface ExtensionInfoFieldsProps {
|
||||||
name: string;
|
name: string;
|
||||||
type: 'stdio' | 'sse' | 'builtin';
|
type: 'stdio' | 'sse' | 'builtin';
|
||||||
|
description: string;
|
||||||
onChange: (key: string, value: any) => void;
|
onChange: (key: string, value: any) => void;
|
||||||
submitAttempted: boolean;
|
submitAttempted: boolean;
|
||||||
}
|
}
|
||||||
@@ -12,6 +13,7 @@ interface ExtensionInfoFieldsProps {
|
|||||||
export default function ExtensionInfoFields({
|
export default function ExtensionInfoFields({
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
|
description,
|
||||||
onChange,
|
onChange,
|
||||||
submitAttempted,
|
submitAttempted,
|
||||||
}: ExtensionInfoFieldsProps) {
|
}: ExtensionInfoFieldsProps) {
|
||||||
@@ -20,37 +22,54 @@ export default function ExtensionInfoFields({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between gap-4 mb-6">
|
<div className="flex flex-col gap-4 mb-6">
|
||||||
<div className="flex-1">
|
{/* Top row with Name and Type side by side */}
|
||||||
<label className="text-sm font-medium mb-2 block text-textStandard">Extension Name</label>
|
<div className="flex justify-between gap-4">
|
||||||
<div className="relative">
|
<div className="flex-1">
|
||||||
<Input
|
<label className="text-sm font-medium mb-2 block text-textStandard">Extension Name</label>
|
||||||
value={name}
|
<div className="relative">
|
||||||
onChange={(e) => onChange('name', e.target.value)}
|
<Input
|
||||||
placeholder="Enter extension name..."
|
value={name}
|
||||||
className={`${!submitAttempted || isNameValid() ? 'border-borderSubtle' : 'border-red-500'} text-textStandard focus:border-borderStandard`}
|
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>
|
||||||
</div>
|
</div>
|
||||||
{/* Type Dropdown */}
|
|
||||||
<div className="w-[200px]">
|
{/* Bottom row with Description spanning full width */}
|
||||||
<label className="text-sm font-medium mb-2 block text-textStandard">Type</label>
|
<div className="w-full">
|
||||||
<Select
|
<label className="text-sm font-medium mb-2 block text-textStandard">Description</label>
|
||||||
value={{ value: type, label: type.toUpperCase() }}
|
<div className="relative">
|
||||||
onChange={(option: { value: string; label: string } | null) => {
|
<Input
|
||||||
if (option) {
|
value={description}
|
||||||
onChange('type', option.value);
|
onChange={(e) => onChange('description', e.target.value)}
|
||||||
}
|
placeholder="Optional description..."
|
||||||
}}
|
className={`text-textStandard focus:border-borderStandard`}
|
||||||
options={[
|
/>
|
||||||
{ value: 'stdio', label: 'Standard IO (STDIO)' },
|
</div>
|
||||||
{ value: 'sse', label: 'Security Service Edge (SSE)' },
|
|
||||||
]}
|
|
||||||
isSearchable={false}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ export default function ExtensionModal({
|
|||||||
<ExtensionInfoFields
|
<ExtensionInfoFields
|
||||||
name={formData.name}
|
name={formData.name}
|
||||||
type={formData.type}
|
type={formData.type}
|
||||||
|
description={formData.description}
|
||||||
onChange={(key, value) => setFormData({ ...formData, [key]: value })}
|
onChange={(key, value) => setFormData({ ...formData, [key]: value })}
|
||||||
submitAttempted={submitAttempted}
|
submitAttempted={submitAttempted}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ export function getSubtitle(config: ExtensionConfig): string {
|
|||||||
}
|
}
|
||||||
if (config.type === 'stdio') {
|
if (config.type === 'stdio') {
|
||||||
const full_command = combineCmdAndArgs(config.cmd, config.args);
|
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') {
|
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`;
|
return `Unknown type of extension`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ExtensionConfig } from '../../../api/types.gen';
|
|||||||
|
|
||||||
export interface ExtensionFormData {
|
export interface ExtensionFormData {
|
||||||
name: string;
|
name: string;
|
||||||
|
description: string;
|
||||||
type: 'stdio' | 'sse' | 'builtin';
|
type: 'stdio' | 'sse' | 'builtin';
|
||||||
cmd?: string;
|
cmd?: string;
|
||||||
endpoint?: string;
|
endpoint?: string;
|
||||||
@@ -13,6 +14,7 @@ export interface ExtensionFormData {
|
|||||||
export function getDefaultFormData(): ExtensionFormData {
|
export function getDefaultFormData(): ExtensionFormData {
|
||||||
return {
|
return {
|
||||||
name: '',
|
name: '',
|
||||||
|
description: '',
|
||||||
type: 'stdio',
|
type: 'stdio',
|
||||||
cmd: '',
|
cmd: '',
|
||||||
endpoint: '',
|
endpoint: '',
|
||||||
@@ -35,6 +37,8 @@ export function extensionToFormData(extension: FixedExtensionEntry): ExtensionFo
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: extension.name,
|
name: extension.name,
|
||||||
|
description:
|
||||||
|
extension.type === 'stdio' || extension.type === 'sse' ? extension.description : undefined,
|
||||||
type: extension.type,
|
type: extension.type,
|
||||||
cmd: extension.type === 'stdio' ? combineCmdAndArgs(extension.cmd, extension.args) : undefined,
|
cmd: extension.type === 'stdio' ? combineCmdAndArgs(extension.cmd, extension.args) : undefined,
|
||||||
endpoint: extension.type === 'sse' ? extension.uri : undefined,
|
endpoint: extension.type === 'sse' ? extension.uri : undefined,
|
||||||
@@ -61,6 +65,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
|
|||||||
return {
|
return {
|
||||||
type: 'stdio',
|
type: 'stdio',
|
||||||
name: formData.name,
|
name: formData.name,
|
||||||
|
description: formData.description,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
args: args,
|
args: args,
|
||||||
...(Object.keys(envs).length > 0 ? { envs } : {}),
|
...(Object.keys(envs).length > 0 ? { envs } : {}),
|
||||||
@@ -69,6 +74,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
|
|||||||
return {
|
return {
|
||||||
type: 'sse',
|
type: 'sse',
|
||||||
name: formData.name,
|
name: formData.name,
|
||||||
|
description: formData.description,
|
||||||
uri: formData.endpoint, // Assuming endpoint maps to uri for SSE type
|
uri: formData.endpoint, // Assuming endpoint maps to uri for SSE type
|
||||||
...(Object.keys(envs).length > 0 ? { envs } : {}),
|
...(Object.keys(envs).length > 0 ? { envs } : {}),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user