styles: settings v2 (#2103)
This commit is contained in:
@@ -113,11 +113,11 @@ export default function ExtensionsSection() {
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="extensions">
|
||||
<div className="flex justify-between items-center mb-6 px-8">
|
||||
<h1 className="text-3xl font-medium text-textStandard">Extensions</h1>
|
||||
<section id="extensions" className="px-8">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<h2 className="text-xl font-medium text-textStandard">Extensions</h2>
|
||||
</div>
|
||||
<div className="px-8">
|
||||
<div className="border-b border-borderSubtle pb-8">
|
||||
<p className="text-sm text-textStandard mb-6">
|
||||
These extensions use the Model Context Protocol (MCP). They can expand Goose's
|
||||
capabilities using three main components: Prompts, Resources, and Tools.
|
||||
@@ -131,46 +131,46 @@ export default function ExtensionsSection() {
|
||||
|
||||
<div className="flex gap-4 pt-4 w-full">
|
||||
<Button
|
||||
className="flex items-center gap-2 flex-1 justify-center text-white dark:text-textSubtle bg-black dark:bg-white hover:bg-subtle"
|
||||
className="flex items-center gap-2 justify-center text-white dark:text-textSubtle bg-bgAppInverse hover:bg-bgStandardInverse [&>svg]:!size-4"
|
||||
onClick={() => setIsAddModalOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Add custom extension
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-2 flex-1 justify-center text-textSubtle bg-white dark:bg-black hover:bg-subtle dark:border dark:border-gray-500 dark:hover:border-gray-400"
|
||||
className="flex items-center gap-2 justify-center text-textStandard bg-bgApp border border-borderSubtle hover:border-borderProminent hover:bg-bgApp [&>svg]:!size-4"
|
||||
onClick={() => window.open('https://block.github.io/goose/v1/extensions/', '_blank')}
|
||||
>
|
||||
<GPSIcon size={18} />
|
||||
Visit Extensions
|
||||
<GPSIcon size={12} />
|
||||
Browse extensions
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Modal for updating an existing extension */}
|
||||
{isModalOpen && selectedExtension && (
|
||||
<ExtensionModal
|
||||
title="Update Extension"
|
||||
initialData={extensionToFormData(selectedExtension)}
|
||||
onClose={handleModalClose}
|
||||
onSubmit={handleUpdateExtension}
|
||||
onDelete={handleDeleteExtension}
|
||||
submitLabel="Save Changes"
|
||||
modalType={'edit'}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Modal for adding a new extension */}
|
||||
{isAddModalOpen && (
|
||||
<ExtensionModal
|
||||
title="Add custom extension"
|
||||
initialData={getDefaultFormData()}
|
||||
onClose={handleModalClose}
|
||||
onSubmit={handleAddExtension}
|
||||
submitLabel="Add Extension"
|
||||
modalType={'add'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Modal for updating an existing extension */}
|
||||
{isModalOpen && selectedExtension && (
|
||||
<ExtensionModal
|
||||
title="Update Extension"
|
||||
initialData={extensionToFormData(selectedExtension)}
|
||||
onClose={handleModalClose}
|
||||
onSubmit={handleUpdateExtension}
|
||||
onDelete={handleDeleteExtension}
|
||||
submitLabel="Save Changes"
|
||||
modalType={'edit'}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Modal for adding a new extension */}
|
||||
{isAddModalOpen && (
|
||||
<ExtensionModal
|
||||
title="Add New Extension"
|
||||
initialData={getDefaultFormData()}
|
||||
onClose={handleModalClose}
|
||||
onSubmit={handleAddExtension}
|
||||
submitLabel="Add Extension"
|
||||
modalType={'add'}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function EnvVarsSection({
|
||||
<label className="text-sm font-medium text-textStandard mb-2 block">
|
||||
Environment Variables
|
||||
</label>
|
||||
<p className="text-xs text-textSubtle mb-2">
|
||||
<p className="text-xs text-textSubtle mb-4">
|
||||
Add key-value pairs for environment variables. Click the "+" button to add after filling
|
||||
both fields.
|
||||
</p>
|
||||
@@ -89,7 +89,7 @@ export default function EnvVarsSection({
|
||||
onChange={(e) => onChange(index, 'key', e.target.value)}
|
||||
placeholder="Variable name"
|
||||
className={cn(
|
||||
'w-full border-borderSubtle text-textStandard',
|
||||
'w-full text-textStandard border-borderSubtle hover:border-borderStandard',
|
||||
isFieldInvalid(index, 'key') && 'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
@@ -100,7 +100,7 @@ export default function EnvVarsSection({
|
||||
onChange={(e) => onChange(index, 'value', e.target.value)}
|
||||
placeholder="Value"
|
||||
className={cn(
|
||||
'w-full border-borderSubtle text-textStandard',
|
||||
'w-full text-textStandard border-borderSubtle hover:border-borderStandard',
|
||||
isFieldInvalid(index, 'value') && 'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
@@ -124,7 +124,7 @@ export default function EnvVarsSection({
|
||||
}}
|
||||
placeholder="Variable name"
|
||||
className={cn(
|
||||
'w-full border-borderStandard text-textStandard',
|
||||
'w-full text-textStandard border-borderSubtle hover:border-borderStandard',
|
||||
invalidFields.key && 'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
@@ -136,16 +136,16 @@ export default function EnvVarsSection({
|
||||
}}
|
||||
placeholder="Value"
|
||||
className={cn(
|
||||
'w-full border-borderStandard text-textStandard',
|
||||
'w-full text-textStandard border-borderSubtle hover:border-borderStandard',
|
||||
invalidFields.value && 'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
onClick={handleAdd}
|
||||
variant="ghost"
|
||||
className="flex items-center justify-start gap-1 px-2 pr-4 text-s font-medium rounded-full dark:bg-slate-400 dark:text-gray-300 bg-gray-300 dark:bg-slate text-slate-400 dark:hover:bg-slate-300 hover:bg-gray-500 hover:text-white dark:hover:text-gray-900 transition-colors min-w-[60px] h-9"
|
||||
className="flex items-center justify-start gap-1 px-2 pr-4 text-sm rounded-full text-textStandard bg-bgApp border border-borderSubtle hover:border-borderStandard transition-colors min-w-[60px] h-9 [&>svg]:!size-4"
|
||||
>
|
||||
<Plus className="h-3 w-3" /> Add
|
||||
<Plus /> Add
|
||||
</Button>
|
||||
</div>
|
||||
{validationError && <div className="mt-2 text-red-500 text-sm">{validationError}</div>}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Input } from '../../../ui/input';
|
||||
import Select from 'react-select';
|
||||
import { Select } from '../../../ui/Select';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
interface ExtensionInfoFieldsProps {
|
||||
|
||||
@@ -131,7 +131,7 @@ export default function ExtensionModal({
|
||||
<>
|
||||
<div className="w-full px-6 py-4 bg-red-900/20 border-t border-red-500/30">
|
||||
<p className="text-red-400 text-sm mb-2">
|
||||
Are you sure you want to delete "{formData.name}"? This action cannot be undone.
|
||||
Are you sure you want to remove "{formData.name}"? This action cannot be undone.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
@@ -143,7 +143,7 @@ export default function ExtensionModal({
|
||||
}}
|
||||
className="w-full h-[60px] rounded-none border-b border-borderSubtle bg-transparent hover:bg-red-900/20 text-red-500 font-medium text-md"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" /> Confirm Delete
|
||||
<Trash2 className="h-4 w-4 mr-2" /> Confirm removal
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setShowDeleteConfirmation(false)}
|
||||
@@ -159,9 +159,9 @@ export default function ExtensionModal({
|
||||
{modalType === 'edit' && onDelete && (
|
||||
<Button
|
||||
onClick={() => setShowDeleteConfirmation(true)}
|
||||
className="w-full h-[60px] rounded-none border-b border-borderSubtle bg-transparent hover:bg-bgSubtle text-red-500 font-medium text-md"
|
||||
className="w-full h-[60px] rounded-none border-b border-borderSubtle bg-transparent hover:bg-bgSubtle text-red-500 font-medium text-md [&>svg]:!size-4"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" /> Delete Extension
|
||||
<Trash2 className="h-4 w-4 mr-2" /> Remove extension
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
|
||||
@@ -29,25 +29,20 @@ export default function ExtensionTimeoutField({
|
||||
return (
|
||||
<div className="flex flex-col gap-4 mb-6">
|
||||
{/* Row with Timeout and timeout input side by side */}
|
||||
<div className="flex justify-between gap-4">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex-1">
|
||||
<label className="text-sm font-medium mb-2 block text-textStandard">Timeout</label>
|
||||
</div>
|
||||
|
||||
{/* Type Dropdown */}
|
||||
<div className="w-[200px]">
|
||||
<div className="relative">
|
||||
<Input
|
||||
value={timeout}
|
||||
onChange={(e) => onChange('timeout', e.target.value)}
|
||||
defaultValue={300}
|
||||
className={`${!submitAttempted || isTimeoutValid() ? 'border-borderSubtle' : 'border-red-500'} text-textStandard focus:border-borderStandard`}
|
||||
/>
|
||||
{submitAttempted && !isTimeoutValid() && (
|
||||
<div className="absolute text-xs text-red-500 mt-1">Timeout </div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
value={timeout}
|
||||
onChange={(e) => onChange('timeout', e.target.value)}
|
||||
defaultValue={300}
|
||||
className={`${!submitAttempted || isTimeoutValid() ? 'border-borderSubtle' : 'border-red-500'} text-textStandard focus:border-borderStandard`}
|
||||
/>
|
||||
{submitAttempted && !isTimeoutValid() && (
|
||||
<div className="absolute text-xs text-red-500 mt-1">Timeout </div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -57,27 +57,34 @@ export default function ExtensionItem({ extension, onToggle, onConfigure }: Exte
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-borderSubtle p-4 mb-2">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h3 className="font-medium text-textStandard">{getFriendlyTitle(extension)}</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Only show config button for non-builtin extensions */}
|
||||
{extension.type !== 'builtin' && (
|
||||
<button
|
||||
className="text-textSubtle hover:text-textStandard"
|
||||
onClick={() => onConfigure(extension)}
|
||||
>
|
||||
<Gear className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
<Switch
|
||||
checked={(isToggling && visuallyEnabled) || extension.enabled}
|
||||
onCheckedChange={() => handleToggle(extension)}
|
||||
variant="mono"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-between rounded-lg transition-colors border border-borderSubtle p-4 pt-3 hover:border-borderProminent hover:cursor-pointer"
|
||||
onClick={() => handleToggle(extension)}
|
||||
>
|
||||
<div className="flex flex-col w-max-[90%]">
|
||||
<h3 className="text-textStandard">{getFriendlyTitle(extension)}</h3>
|
||||
<p className="text-xs text-textSubtle">{renderFormattedSubtitle()}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex items-center justify-end gap-2 w-max-[10%]"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Only show config button for non-builtin extensions */}
|
||||
{extension.type !== 'builtin' && (
|
||||
<button
|
||||
className="text-textSubtle hover:text-textStandard"
|
||||
onClick={() => onConfigure(extension)}
|
||||
>
|
||||
<Gear className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
<Switch
|
||||
checked={(isToggling && visuallyEnabled) || extension.enabled}
|
||||
onCheckedChange={() => handleToggle(extension)}
|
||||
variant="mono"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-sm text-textSubtle">{renderFormattedSubtitle()}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ interface ExtensionListProps {
|
||||
|
||||
export default function ExtensionList({ extensions, onToggle, onConfigure }: ExtensionListProps) {
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="grid grid-cols-2 gap-2 mb-2">
|
||||
{extensions.map((extension) => (
|
||||
<ExtensionItem
|
||||
key={extension.name}
|
||||
|
||||
Reference in New Issue
Block a user