agentscope / examples /web_ui /frontend /src /components /dialog /CreateCredentialDialog.tsx
ghostdrive1's picture
Upload folder using huggingface_hub
0b9dc2e verified
Raw
History Blame Contribute Delete
4.49 kB
import { CircleAlert, Loader2, PlusCircle } from 'lucide-react';
import { useState, useEffect } from 'react';
import { credentialApi } from '@/api';
import type { CredentialSchema } from '@/api';
import { SchemaForm, type SchemaFormValue } from '@/components/form/SchemaForm';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from '@/components/ui/dialog';
import { Field, FieldGroup, FieldLabel } from '@/components/ui/field.tsx';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { useCredentials } from '@/hooks/useCredentials';
import { useTranslation } from '@/i18n/useI18n.ts';
interface Props {
open: boolean;
onOpenChange: (open: boolean) => void;
onCreated?: () => void;
defaultType?: string;
}
export function CreateCredentialDialog({ open, onOpenChange, onCreated, defaultType }: Props) {
const { create } = useCredentials();
const { t } = useTranslation();
const [schemas, setSchemas] = useState<CredentialSchema[]>([]);
const [loadingSchemas, setLoadingSchemas] = useState(false);
const [selectedType, setSelectedType] = useState('');
const [values, setValues] = useState<Record<string, SchemaFormValue>>({});
const [submitting, setSubmitting] = useState(false);
useEffect(() => {
if (!open) return;
setLoadingSchemas(true);
credentialApi
.schemas()
.then((res) => {
setSchemas(res.schemas);
if (res.schemas.length > 0) {
const first = (res.schemas[0].properties.type?.const as string) ?? '';
setSelectedType(defaultType ?? first);
}
})
.finally(() => setLoadingSchemas(false));
}, [open, defaultType]);
const selectedSchema = schemas.find(
(s) => (s.properties.type?.const as string) === selectedType,
);
const handleTypeChange = (type: string) => {
setSelectedType(type);
setValues({});
};
const handleSubmit = async () => {
if (!selectedSchema) return;
setSubmitting(true);
try {
const data: Record<string, unknown> = { type: selectedType };
for (const [key, prop] of Object.entries(selectedSchema.properties)) {
if (key === 'id' || key === 'type' || prop.const !== undefined) continue;
const val = values[key];
if (val !== undefined && val !== '') data[key] = val;
}
await create({ data });
onOpenChange(false);
onCreated?.();
} finally {
setSubmitting(false);
}
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="!w-[500px] !max-w-[500px]">
<DialogHeader>
<DialogTitle>{t('dialog-credential-create.title')}</DialogTitle>
<DialogDescription>
{t('dialog-credential-create.description')}
</DialogDescription>
</DialogHeader>
<FieldGroup>
<Field>
<FieldLabel>{t('dialog-credential-create.selectType')}</FieldLabel>
<Select
value={selectedType}
onValueChange={handleTypeChange}
disabled={loadingSchemas}
>
<SelectTrigger>
<SelectValue
placeholder={
loadingSchemas
? t('common.loading')
: t('dialog-credential-create.selectTypePlaceholder')
}
/>
</SelectTrigger>
<SelectContent>
{schemas.map((s) => (
<SelectItem
key={s.properties.type?.const as string}
value={s.properties.type?.const as string}
>
{s.title}
</SelectItem>
))}
</SelectContent>
</Select>
</Field>
{selectedSchema && (
<SchemaForm
schema={selectedSchema}
values={values}
onChange={(key, val) => setValues((prev) => ({ ...prev, [key]: val }))}
/>
)}
</FieldGroup>
<DialogFooter>
<Button
variant="ghost"
onClick={() => onOpenChange(false)}
disabled={submitting}
>
<CircleAlert className="size-3.5" />
{t('common.cancel')}
</Button>
<Button onClick={handleSubmit} disabled={submitting || !selectedSchema}>
{submitting ? (
<Loader2 className="size-3.5 animate-spin" />
) : (
<PlusCircle className="size-3.5" />
)}
{submitting ? t('common.creating') : t('common.create')}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}