mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-22 08:34:21 +01:00
feat: V1.0 (#734)
Co-authored-by: Michael Neale <michael.neale@gmail.com> Co-authored-by: Wendy Tang <wendytang@squareup.com> Co-authored-by: Jarrod Sibbison <72240382+jsibbison-square@users.noreply.github.com> Co-authored-by: Alex Hancock <alex.hancock@example.com> Co-authored-by: Alex Hancock <alexhancock@block.xyz> Co-authored-by: Lifei Zhou <lifei@squareup.com> Co-authored-by: Wes <141185334+wesrblock@users.noreply.github.com> Co-authored-by: Max Novich <maksymstepanenko1990@gmail.com> Co-authored-by: Zaki Ali <zaki@squareup.com> Co-authored-by: Salman Mohammed <smohammed@squareup.com> Co-authored-by: Kalvin C <kalvinnchau@users.noreply.github.com> Co-authored-by: Alec Thomas <alec@swapoff.org> Co-authored-by: lily-de <119957291+lily-de@users.noreply.github.com> Co-authored-by: kalvinnchau <kalvin@block.xyz> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rizel Scarlett <rizel@squareup.com> Co-authored-by: bwrage <bwrage@squareup.com> Co-authored-by: Kalvin Chau <kalvin@squareup.com> Co-authored-by: Alice Hau <110418948+ahau-square@users.noreply.github.com> Co-authored-by: Alistair Gray <ajgray@stripe.com> Co-authored-by: Nahiyan Khan <nahiyan.khan@gmail.com> Co-authored-by: Alex Hancock <alexhancock@squareup.com> Co-authored-by: Nahiyan Khan <nahiyan@squareup.com> Co-authored-by: marcelle <1852848+laanak08@users.noreply.github.com> Co-authored-by: Yingjie He <yingjiehe@block.xyz> Co-authored-by: Yingjie He <yingjiehe@squareup.com> Co-authored-by: Lily Delalande <ldelalande@block.xyz> Co-authored-by: Adewale Abati <acekyd01@gmail.com> Co-authored-by: Ebony Louis <ebony774@gmail.com> Co-authored-by: Angie Jones <jones.angie@gmail.com> Co-authored-by: Ebony Louis <55366651+EbonyLouis@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
import React from 'react';
|
||||
import { Card } from '../../ui/card';
|
||||
import { Button } from '../../ui/button';
|
||||
import { Input } from '../../ui/input';
|
||||
import { FullExtensionConfig } from '../../../extensions';
|
||||
import { getApiUrl, getSecretKey } from '../../../config';
|
||||
import { addExtension } from '../../../extensions';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
interface ConfigureExtensionModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: () => void;
|
||||
onRemove: () => void;
|
||||
extension: FullExtensionConfig | null;
|
||||
}
|
||||
|
||||
export function ConfigureExtensionModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
onSubmit,
|
||||
onRemove,
|
||||
extension,
|
||||
}: ConfigureExtensionModalProps) {
|
||||
const [envValues, setEnvValues] = React.useState<Record<string, string>>({});
|
||||
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
||||
|
||||
// Reset form when dialog closes or extension changes
|
||||
React.useEffect(() => {
|
||||
if (!isOpen || !extension) {
|
||||
setEnvValues({});
|
||||
}
|
||||
}, [isOpen, extension]);
|
||||
|
||||
const handleExtensionConfigSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!extension) return;
|
||||
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
// First store all environment variables
|
||||
if (extension.env_keys?.length > 0) {
|
||||
for (const envKey of extension.env_keys) {
|
||||
const value = envValues[envKey];
|
||||
if (!value) continue;
|
||||
|
||||
const storeResponse = await fetch(getApiUrl('/secrets/store'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Secret-Key': getSecretKey(),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key: envKey,
|
||||
value: value.trim(),
|
||||
}),
|
||||
});
|
||||
|
||||
if (!storeResponse.ok) {
|
||||
throw new Error(`Failed to store environment variable: ${envKey}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await addExtension(extension);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to add system configuration');
|
||||
}
|
||||
|
||||
toast.success(`Successfully configured the ${extension.name} extension`);
|
||||
onSubmit();
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error('Error configuring extension:', error);
|
||||
toast.error('Failed to configure extension');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!extension || !isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/20 backdrop-blur-sm">
|
||||
<Card className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[440px] bg-white dark:bg-gray-800 rounded-xl shadow-xl overflow-hidden p-[16px] pt-[24px] pb-0">
|
||||
<div className="px-8 pb-0 space-y-8">
|
||||
{/* Header */}
|
||||
<div className="flex">
|
||||
<h2 className="text-2xl font-regular dark:text-white text-gray-900">
|
||||
Configure {extension.name}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<form onSubmit={handleExtensionConfigSubmit}>
|
||||
<div className="mt-[24px]">
|
||||
{extension.env_keys?.length > 0 ? (
|
||||
<>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 mb-6">
|
||||
Please provide the required environment variables for this extension:
|
||||
</p>
|
||||
<div className="space-y-4">
|
||||
{extension.env_keys?.map((envVarName) => (
|
||||
<div key={envVarName}>
|
||||
<label
|
||||
htmlFor={envVarName}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
{envVarName}
|
||||
</label>
|
||||
<Input
|
||||
type="text"
|
||||
id={envVarName}
|
||||
name={envVarName}
|
||||
placeholder={envVarName}
|
||||
value={envValues[envVarName] || ''}
|
||||
onChange={(e) =>
|
||||
setEnvValues((prev) => ({
|
||||
...prev,
|
||||
[envVarName]: e.target.value,
|
||||
}))
|
||||
}
|
||||
className="w-full h-14 px-4 font-regular rounded-lg border shadow-none border-gray-300 bg-white text-lg placeholder:text-gray-400 font-regular text-gray-900 dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:placeholder:text-gray-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
This extension doesn't require any environment variables.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="mt-[8px] ml-[-24px] mr-[-24px] pt-[16px]">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="ghost"
|
||||
disabled={isSubmitting}
|
||||
className="w-full h-[60px] rounded-none border-t dark:border-gray-600 text-lg hover:bg-gray-50 hover:dark:text-black dark:text-white dark:border-gray-600 font-regular"
|
||||
>
|
||||
{isSubmitting ? 'Saving...' : 'Save Configuration'}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={onRemove}
|
||||
disabled={isSubmitting}
|
||||
className="w-full h-[60px] rounded-none border-t dark:border-gray-600 text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 dark:border-gray-600 text-lg font-regular"
|
||||
>
|
||||
Remove Extension
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={onClose}
|
||||
disabled={isSubmitting}
|
||||
className="w-full h-[60px] rounded-none border-t dark:border-gray-600 text-gray-400 hover:bg-gray-50 dark:border-gray-600 text-lg font-regular"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user