Files
stats/apps/start/src/components/project-mapper.tsx
Carl-Gerhard Lindesvärd 212254d31a feat: new importer (#214)
2025-11-05 09:49:36 +01:00

117 lines
3.5 KiB
TypeScript

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import type { IServiceProject } from '@openpanel/db';
import { PlusIcon, XIcon } from 'lucide-react';
import type {
Control,
FieldArrayWithId,
UseFieldArrayAppend,
UseFieldArrayRemove,
UseFormRegister,
UseFormSetValue,
UseFormWatch,
} from 'react-hook-form';
interface ProjectMapperProps {
fields: FieldArrayWithId<any, 'projectMapper', 'id'>[];
append: UseFieldArrayAppend<any, 'projectMapper'>;
remove: UseFieldArrayRemove;
projects: IServiceProject[];
register: UseFormRegister<any>;
watch: UseFormWatch<any>;
setValue: UseFormSetValue<any>;
}
export function ProjectMapper({
fields,
append,
remove,
projects,
register,
watch,
setValue,
}: ProjectMapperProps) {
return (
<div className="space-y-2">
<div className="flex items-center justify-between">
<Label className="mb-0">Project Mapper (Optional)</Label>
<Button
type="button"
variant="outline"
size="sm"
onClick={() => append({ from: '', to: '' })}
>
<PlusIcon className="mr-1 h-4 w-4" />
Add Mapping
</Button>
</div>
{fields.length === 0 && (
<p className="text-sm text-muted-foreground leading-normal">
Map source project IDs to your OpenPanel projects. If you skip mapping
all data will be imported to your current project.
</p>
)}
{fields.length > 0 && (
<div className="space-y-2">
{fields.map((field, index) => (
<div key={field.id} className="gap-2 rounded-md border p-3 row">
<div className="grid grid-cols-2 gap-2">
<div className="flex-1">
<Label className="text-xs text-muted-foreground">
From (Source Project ID)
</Label>
<Input
placeholder="e.g., abc123"
{...register(`projectMapper.${index}.from`)}
className="mt-1"
/>
</div>
<div className="flex-1">
<Label className="text-xs text-muted-foreground">
To (OpenPanel Project)
</Label>
<Select
value={watch(`projectMapper.${index}.to`)}
onValueChange={(value) =>
setValue(`projectMapper.${index}.to`, value)
}
>
<SelectTrigger className="mt-1 w-full" size="sm">
<SelectValue placeholder="Select project" />
</SelectTrigger>
<SelectContent>
{projects.slice(0, 10).map((project) => (
<SelectItem key={project.id} value={project.id}>
{project.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<Button
type="button"
variant="ghost"
size="icon"
onClick={() => remove(index)}
className="mt-5"
>
<XIcon className="h-4 w-4" />
</Button>
</div>
))}
</div>
)}
</div>
);
}