mirror of
https://github.com/borbann-platform/backend-api.git
synced 2025-12-18 20:24:05 +01:00
feat: add PipelineDataSource, PipelineExportData, PipelineDataSchema, and PipelineDataPreview components to enhance data pipeline details page
This commit is contained in:
parent
668847edc3
commit
7783d00f56
@ -2,13 +2,17 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { ArrowLeft, Download, Edit, Play, Trash, Copy, Check, Plus } from "lucide-react"
|
import { ArrowLeft, Download, Edit, Play, Trash, Copy, Check } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import PageHeader from "@/components/page-header"
|
import PageHeader from "@/components/page-header"
|
||||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
|
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { PipelineStatus } from "@/components/pipeline/status"
|
import { PipelineStatus } from "@/components/pipeline/status"
|
||||||
|
import { PipelineDataSource } from "@/components/pipeline/data-source"
|
||||||
|
import { PipelineExportData } from "@/components/pipeline/export-data"
|
||||||
|
import { PipelineDataSchema } from "@/components/pipeline/data-schema"
|
||||||
|
import { PipelineDataPreview } from "@/components/pipeline/data-preview"
|
||||||
|
|
||||||
export default function PipelineDetailsPage() {
|
export default function PipelineDetailsPage() {
|
||||||
return (
|
return (
|
||||||
@ -51,133 +55,8 @@ export default function PipelineDetailsPage() {
|
|||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-3 mt-6">
|
<div className="grid gap-6 md:grid-cols-3 mt-6">
|
||||||
<PipelineStatus />
|
<PipelineStatus />
|
||||||
|
<PipelineDataSource />
|
||||||
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
<PipelineExportData />
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="text-lg">Data Sources</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="p-3 border-2 rounded-md hover:border-highlight-border transition-all duration-200">
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<span className="font-medium">example-realty.com</span>
|
|
||||||
<Badge>Website</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-muted-foreground mt-1">Last updated: 2 hours ago</p>
|
|
||||||
<p className="text-sm mt-1">540 records</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-3 border-2 rounded-md hover:border-highlight-border transition-all duration-200">
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<span className="font-medium">property-listings.com</span>
|
|
||||||
<Badge>Website</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-muted-foreground mt-1">Last updated: 2 hours ago</p>
|
|
||||||
<p className="text-sm mt-1">420 records</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-3 border-2 rounded-md hover:border-highlight-border transition-all duration-200">
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<span className="font-medium">real-estate-api.com</span>
|
|
||||||
<Badge>API</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-muted-foreground mt-1">Last updated: 2 hours ago</p>
|
|
||||||
<p className="text-sm mt-1">280 records</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="text-lg">Export Options</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Accordion type="single" collapsible className="w-full" defaultValue="format-1">
|
|
||||||
<AccordionItem value="format-1" className="border-0">
|
|
||||||
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
|
||||||
<AccordionTrigger className="py-1 px-2">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Download className="mr-2 h-4 w-4 text-primary" />
|
|
||||||
<span>Export as JSON</span>
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent className="pt-2 pb-1 px-2">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<input type="checkbox" id="pretty-json" className="h-4 w-4" defaultChecked />
|
|
||||||
<label htmlFor="pretty-json" className="text-sm">
|
|
||||||
Pretty print
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<Button size="sm" className="w-full">
|
|
||||||
Download JSON
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</AccordionContent>
|
|
||||||
</div>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem value="format-2" className="border-0">
|
|
||||||
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
|
||||||
<AccordionTrigger className="py-1 px-2">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Download className="mr-2 h-4 w-4 text-primary" />
|
|
||||||
<span>Export as CSV</span>
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent className="pt-2 pb-1 px-2">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<input type="checkbox" id="include-headers" className="h-4 w-4" defaultChecked />
|
|
||||||
<label htmlFor="include-headers" className="text-sm">
|
|
||||||
Include headers
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<Button size="sm" className="w-full">
|
|
||||||
Download CSV
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</AccordionContent>
|
|
||||||
</div>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem value="format-3" className="border-0">
|
|
||||||
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
|
||||||
<AccordionTrigger className="py-1 px-2">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Download className="mr-2 h-4 w-4 text-primary" />
|
|
||||||
<span>Export as SQLite</span>
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent className="pt-2 pb-1 px-2">
|
|
||||||
<Button size="sm" className="w-full">
|
|
||||||
Download SQLite
|
|
||||||
</Button>
|
|
||||||
</AccordionContent>
|
|
||||||
</div>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem value="format-4" className="border-0">
|
|
||||||
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
|
||||||
<AccordionTrigger className="py-1 px-2">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Download className="mr-2 h-4 w-4 text-primary" />
|
|
||||||
<span>Export as YAML</span>
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent className="pt-2 pb-1 px-2">
|
|
||||||
<Button size="sm" className="w-full">
|
|
||||||
Download YAML
|
|
||||||
</Button>
|
|
||||||
</AccordionContent>
|
|
||||||
</div>
|
|
||||||
</AccordionItem>
|
|
||||||
</Accordion>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
@ -191,226 +70,11 @@ export default function PipelineDetailsPage() {
|
|||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="schema" className="mt-4">
|
<TabsContent value="schema" className="mt-4">
|
||||||
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
<PipelineDataSchema />
|
||||||
<CardHeader>
|
</TabsContent>
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<div>
|
|
||||||
<CardTitle>Data Schema & Field Management</CardTitle>
|
|
||||||
<CardDescription>Customize fields detected from your data sources</CardDescription>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h3 className="text-sm font-medium">Detected Fields</h3>
|
|
||||||
<Button variant="outline" size="sm">
|
|
||||||
Refresh Detection
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="border rounded-md p-4">
|
<TabsContent value="preview" className="mt-4">
|
||||||
<div className="space-y-3">
|
<PipelineDataPreview />
|
||||||
<div className="field-mapping-item flex items-center">
|
|
||||||
<input type="checkbox" id="field-title" className="h-4 w-4 mr-3" defaultChecked />
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Label htmlFor="field-title" className="font-medium">
|
|
||||||
Title
|
|
||||||
</Label>
|
|
||||||
<Badge className="ml-2 bg-green-500 text-white">Auto-detected</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground">Property title or name</p>
|
|
||||||
</div>
|
|
||||||
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
|
||||||
<option>String</option>
|
|
||||||
<option>Number</option>
|
|
||||||
<option>Boolean</option>
|
|
||||||
<option>Date</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="field-mapping-item flex items-center">
|
|
||||||
<input type="checkbox" id="field-price" className="h-4 w-4 mr-3" defaultChecked />
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Label htmlFor="field-price" className="font-medium">
|
|
||||||
Price
|
|
||||||
</Label>
|
|
||||||
<Badge className="ml-2 bg-green-500 text-white">Auto-detected</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground">Property price</p>
|
|
||||||
</div>
|
|
||||||
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
|
||||||
<option>Number</option>
|
|
||||||
<option>String</option>
|
|
||||||
<option>Boolean</option>
|
|
||||||
<option>Date</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="field-mapping-item flex items-center">
|
|
||||||
<input type="checkbox" id="field-location" className="h-4 w-4 mr-3" defaultChecked />
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Label htmlFor="field-location" className="font-medium">
|
|
||||||
Location
|
|
||||||
</Label>
|
|
||||||
<Badge className="ml-2 bg-green-500 text-white">Auto-detected</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground">Property location</p>
|
|
||||||
</div>
|
|
||||||
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
|
||||||
<option>String</option>
|
|
||||||
<option>Number</option>
|
|
||||||
<option>Boolean</option>
|
|
||||||
<option>Date</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="field-mapping-item flex items-center">
|
|
||||||
<input type="checkbox" id="field-bedrooms" className="h-4 w-4 mr-3" defaultChecked />
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Label htmlFor="field-bedrooms" className="font-medium">
|
|
||||||
Bedrooms
|
|
||||||
</Label>
|
|
||||||
<Badge className="ml-2 bg-green-500 text-white">Auto-detected</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground">Number of bedrooms</p>
|
|
||||||
</div>
|
|
||||||
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
|
||||||
<option>Number</option>
|
|
||||||
<option>String</option>
|
|
||||||
<option>Boolean</option>
|
|
||||||
<option>Date</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="field-mapping-item flex items-center">
|
|
||||||
<input type="checkbox" id="field-bathrooms" className="h-4 w-4 mr-3" defaultChecked />
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Label htmlFor="field-bathrooms" className="font-medium">
|
|
||||||
Bathrooms
|
|
||||||
</Label>
|
|
||||||
<Badge className="ml-2 bg-green-500 text-white">Auto-detected</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground">Number of bathrooms</p>
|
|
||||||
</div>
|
|
||||||
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
|
||||||
<option>Number</option>
|
|
||||||
<option>String</option>
|
|
||||||
<option>Boolean</option>
|
|
||||||
<option>Date</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="field-mapping-item flex items-center border-dashed">
|
|
||||||
<input type="checkbox" id="field-custom" className="h-4 w-4 mr-3" />
|
|
||||||
<div className="flex-1">
|
|
||||||
<Input placeholder="Add custom field" className="border-none text-sm p-0 h-6" />
|
|
||||||
</div>
|
|
||||||
<Button variant="ghost" size="sm" className="h-8 px-2">
|
|
||||||
<Plus className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-2 mt-4">
|
|
||||||
<Label htmlFor="derived-fields">Derived Fields</Label>
|
|
||||||
<Card className="border border-dashed">
|
|
||||||
<CardHeader className="py-3">
|
|
||||||
<CardTitle className="text-sm">Create calculated fields</CardTitle>
|
|
||||||
<CardDescription>Use formulas to generate new fields from existing data</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="py-0">
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div className="field-mapping-item">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<Label className="font-medium">Price Per Square Foot</Label>
|
|
||||||
<Badge variant="outline">Derived</Badge>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center mt-2">
|
|
||||||
<span className="text-xs text-muted-foreground mr-2">Formula:</span>
|
|
||||||
<code className="text-xs bg-muted/50 p-1 rounded">price / squareFeet</code>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button variant="outline" size="sm" className="w-full">
|
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
|
||||||
Add Derived Field
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-end">
|
|
||||||
<Button variant="outline" className="gap-2 mr-2">
|
|
||||||
Reset to Default
|
|
||||||
</Button>
|
|
||||||
<Button>Save Field Configuration</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent value="preview" className="mt-4">
|
|
||||||
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Data Preview</CardTitle>
|
|
||||||
<CardDescription>Sample of the collected data</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="border rounded-md overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead className="bg-muted">
|
|
||||||
<tr>
|
|
||||||
<th className="px-4 py-2 text-left text-sm font-medium">ID</th>
|
|
||||||
<th className="px-4 py-2 text-left text-sm font-medium">Title</th>
|
|
||||||
<th className="px-4 py-2 text-left text-sm font-medium">Price</th>
|
|
||||||
<th className="px-4 py-2 text-left text-sm font-medium">Bedrooms</th>
|
|
||||||
<th className="px-4 py-2 text-left text-sm font-medium">Bathrooms</th>
|
|
||||||
<th className="px-4 py-2 text-left text-sm font-medium">Location</th>
|
|
||||||
<th className="px-4 py-2 text-left text-sm font-medium">Sq. Ft.</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="divide-y">
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 text-sm">P001</td>
|
|
||||||
<td className="px-4 py-2 text-sm">Modern Apartment</td>
|
|
||||||
<td className="px-4 py-2 text-sm">$350,000</td>
|
|
||||||
<td className="px-4 py-2 text-sm">2</td>
|
|
||||||
<td className="px-4 py-2 text-sm">2</td>
|
|
||||||
<td className="px-4 py-2 text-sm">Downtown</td>
|
|
||||||
<td className="px-4 py-2 text-sm">1,200</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 text-sm">P002</td>
|
|
||||||
<td className="px-4 py-2 text-sm">Luxury Villa</td>
|
|
||||||
<td className="px-4 py-2 text-sm">$1,250,000</td>
|
|
||||||
<td className="px-4 py-2 text-sm">5</td>
|
|
||||||
<td className="px-4 py-2 text-sm">4</td>
|
|
||||||
<td className="px-4 py-2 text-sm">Suburbs</td>
|
|
||||||
<td className="px-4 py-2 text-sm">3,500</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 text-sm">P003</td>
|
|
||||||
<td className="px-4 py-2 text-sm">Cozy Studio</td>
|
|
||||||
<td className="px-4 py-2 text-sm">$180,000</td>
|
|
||||||
<td className="px-4 py-2 text-sm">1</td>
|
|
||||||
<td className="px-4 py-2 text-sm">1</td>
|
|
||||||
<td className="px-4 py-2 text-sm">City Center</td>
|
|
||||||
<td className="px-4 py-2 text-sm">650</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="output" className="mt-4">
|
<TabsContent value="output" className="mt-4">
|
||||||
|
|||||||
70
frontend/components/pipeline/data-preview.tsx
Normal file
70
frontend/components/pipeline/data-preview.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "../ui/card";
|
||||||
|
|
||||||
|
export function PipelineDataPreview() {
|
||||||
|
return (
|
||||||
|
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Data Preview</CardTitle>
|
||||||
|
<CardDescription>Sample of the collected data</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="border rounded-md overflow-x-auto">
|
||||||
|
<table className="w-full">
|
||||||
|
<thead className="bg-muted">
|
||||||
|
<tr>
|
||||||
|
<th className="px-4 py-2 text-left text-sm font-medium">ID</th>
|
||||||
|
<th className="px-4 py-2 text-left text-sm font-medium">
|
||||||
|
Title
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 text-left text-sm font-medium">
|
||||||
|
Price
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 text-left text-sm font-medium">
|
||||||
|
Bedrooms
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 text-left text-sm font-medium">
|
||||||
|
Bathrooms
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 text-left text-sm font-medium">
|
||||||
|
Location
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 text-left text-sm font-medium">
|
||||||
|
Sq. Ft.
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y">
|
||||||
|
<tr>
|
||||||
|
<td className="px-4 py-2 text-sm">P001</td>
|
||||||
|
<td className="px-4 py-2 text-sm">Modern Apartment</td>
|
||||||
|
<td className="px-4 py-2 text-sm">$350,000</td>
|
||||||
|
<td className="px-4 py-2 text-sm">2</td>
|
||||||
|
<td className="px-4 py-2 text-sm">2</td>
|
||||||
|
<td className="px-4 py-2 text-sm">Downtown</td>
|
||||||
|
<td className="px-4 py-2 text-sm">1,200</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td className="px-4 py-2 text-sm">P002</td>
|
||||||
|
<td className="px-4 py-2 text-sm">Luxury Villa</td>
|
||||||
|
<td className="px-4 py-2 text-sm">$1,250,000</td>
|
||||||
|
<td className="px-4 py-2 text-sm">5</td>
|
||||||
|
<td className="px-4 py-2 text-sm">4</td>
|
||||||
|
<td className="px-4 py-2 text-sm">Suburbs</td>
|
||||||
|
<td className="px-4 py-2 text-sm">3,500</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td className="px-4 py-2 text-sm">P003</td>
|
||||||
|
<td className="px-4 py-2 text-sm">Cozy Studio</td>
|
||||||
|
<td className="px-4 py-2 text-sm">$180,000</td>
|
||||||
|
<td className="px-4 py-2 text-sm">1</td>
|
||||||
|
<td className="px-4 py-2 text-sm">1</td>
|
||||||
|
<td className="px-4 py-2 text-sm">City Center</td>
|
||||||
|
<td className="px-4 py-2 text-sm">650</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
246
frontend/components/pipeline/data-schema.tsx
Normal file
246
frontend/components/pipeline/data-schema.tsx
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
import { Plus } from "lucide-react";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import { Label } from "../ui/label";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
} from "../ui/card";
|
||||||
|
import { Input } from "../ui/input";
|
||||||
|
import { Badge } from "../ui/badge";
|
||||||
|
|
||||||
|
export function PipelineDataSchema() {
|
||||||
|
return (
|
||||||
|
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Data Schema & Field Management</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Customize fields detected from your data sources
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h3 className="text-sm font-medium">Detected Fields</h3>
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
Refresh Detection
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border rounded-md p-4">
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="field-mapping-item flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="field-title"
|
||||||
|
className="h-4 w-4 mr-3"
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Label htmlFor="field-title" className="font-medium">
|
||||||
|
Title
|
||||||
|
</Label>
|
||||||
|
<Badge className="ml-2 bg-green-500 text-white">
|
||||||
|
Auto-detected
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Property title or name
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
||||||
|
<option>String</option>
|
||||||
|
<option>Number</option>
|
||||||
|
<option>Boolean</option>
|
||||||
|
<option>Date</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="field-mapping-item flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="field-price"
|
||||||
|
className="h-4 w-4 mr-3"
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Label htmlFor="field-price" className="font-medium">
|
||||||
|
Price
|
||||||
|
</Label>
|
||||||
|
<Badge className="ml-2 bg-green-500 text-white">
|
||||||
|
Auto-detected
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Property price
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
||||||
|
<option>Number</option>
|
||||||
|
<option>String</option>
|
||||||
|
<option>Boolean</option>
|
||||||
|
<option>Date</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="field-mapping-item flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="field-location"
|
||||||
|
className="h-4 w-4 mr-3"
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Label htmlFor="field-location" className="font-medium">
|
||||||
|
Location
|
||||||
|
</Label>
|
||||||
|
<Badge className="ml-2 bg-green-500 text-white">
|
||||||
|
Auto-detected
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Property location
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
||||||
|
<option>String</option>
|
||||||
|
<option>Number</option>
|
||||||
|
<option>Boolean</option>
|
||||||
|
<option>Date</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="field-mapping-item flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="field-bedrooms"
|
||||||
|
className="h-4 w-4 mr-3"
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Label htmlFor="field-bedrooms" className="font-medium">
|
||||||
|
Bedrooms
|
||||||
|
</Label>
|
||||||
|
<Badge className="ml-2 bg-green-500 text-white">
|
||||||
|
Auto-detected
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Number of bedrooms
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
||||||
|
<option>Number</option>
|
||||||
|
<option>String</option>
|
||||||
|
<option>Boolean</option>
|
||||||
|
<option>Date</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="field-mapping-item flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="field-bathrooms"
|
||||||
|
className="h-4 w-4 mr-3"
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Label htmlFor="field-bathrooms" className="font-medium">
|
||||||
|
Bathrooms
|
||||||
|
</Label>
|
||||||
|
<Badge className="ml-2 bg-green-500 text-white">
|
||||||
|
Auto-detected
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Number of bathrooms
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<select className="h-8 rounded-md border border-input bg-background px-2 py-1 text-xs">
|
||||||
|
<option>Number</option>
|
||||||
|
<option>String</option>
|
||||||
|
<option>Boolean</option>
|
||||||
|
<option>Date</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="field-mapping-item flex items-center border-dashed">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="field-custom"
|
||||||
|
className="h-4 w-4 mr-3"
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<Input
|
||||||
|
placeholder="Add custom field"
|
||||||
|
className="border-none text-sm p-0 h-6"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button variant="ghost" size="sm" className="h-8 px-2">
|
||||||
|
<Plus className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2 mt-4">
|
||||||
|
<Label htmlFor="derived-fields">Derived Fields</Label>
|
||||||
|
<Card className="border border-dashed">
|
||||||
|
<CardHeader className="py-3">
|
||||||
|
<CardTitle className="text-sm">
|
||||||
|
Create calculated fields
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Use formulas to generate new fields from existing data
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="py-0">
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="field-mapping-item">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label className="font-medium">
|
||||||
|
Price Per Square Foot
|
||||||
|
</Label>
|
||||||
|
<Badge variant="outline">Derived</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-2">
|
||||||
|
<span className="text-xs text-muted-foreground mr-2">
|
||||||
|
Formula:
|
||||||
|
</span>
|
||||||
|
<code className="text-xs bg-muted/50 p-1 rounded">
|
||||||
|
price / squareFeet
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button variant="outline" size="sm" className="w-full">
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
Add Derived Field
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<Button variant="outline" className="gap-2 mr-2">
|
||||||
|
Reset to Default
|
||||||
|
</Button>
|
||||||
|
<Button>Save Field Configuration</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
48
frontend/components/pipeline/data-source.tsx
Normal file
48
frontend/components/pipeline/data-source.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { Badge } from "../ui/badge";
|
||||||
|
import { Card, CardHeader, CardTitle, CardContent } from "../ui/card";
|
||||||
|
|
||||||
|
export function PipelineDataSource(){
|
||||||
|
return (
|
||||||
|
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-lg">Data Sources</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="p-3 border-2 rounded-md hover:border-highlight-border transition-all duration-200">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="font-medium">example-realty.com</span>
|
||||||
|
<Badge>Website</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground mt-1">
|
||||||
|
Last updated: 2 hours ago
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">540 records</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-3 border-2 rounded-md hover:border-highlight-border transition-all duration-200">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="font-medium">property-listings.com</span>
|
||||||
|
<Badge>Website</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground mt-1">
|
||||||
|
Last updated: 2 hours ago
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">420 records</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-3 border-2 rounded-md hover:border-highlight-border transition-all duration-200">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="font-medium">real-estate-api.com</span>
|
||||||
|
<Badge>API</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground mt-1">
|
||||||
|
Last updated: 2 hours ago
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">280 records</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
119
frontend/components/pipeline/export-data.tsx
Normal file
119
frontend/components/pipeline/export-data.tsx
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/ui/accordion";
|
||||||
|
import { Download } from "lucide-react";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import { Card, CardHeader, CardTitle, CardContent } from "../ui/card";
|
||||||
|
|
||||||
|
export function PipelineExportData() {
|
||||||
|
return (
|
||||||
|
<Card className="border-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-lg">Export Options</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<Accordion
|
||||||
|
type="single"
|
||||||
|
collapsible
|
||||||
|
className="w-full"
|
||||||
|
defaultValue="format-1"
|
||||||
|
>
|
||||||
|
<AccordionItem value="format-1" className="border-0">
|
||||||
|
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<AccordionTrigger className="py-1 px-2">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Download className="mr-2 h-4 w-4 text-primary" />
|
||||||
|
<span>Export as JSON</span>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="pt-2 pb-1 px-2">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="pretty-json"
|
||||||
|
className="h-4 w-4"
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
<label htmlFor="pretty-json" className="text-sm">
|
||||||
|
Pretty print
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<Button size="sm" className="w-full">
|
||||||
|
Download JSON
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</div>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem value="format-2" className="border-0">
|
||||||
|
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<AccordionTrigger className="py-1 px-2">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Download className="mr-2 h-4 w-4 text-primary" />
|
||||||
|
<span>Export as CSV</span>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="pt-2 pb-1 px-2">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="include-headers"
|
||||||
|
className="h-4 w-4"
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
<label htmlFor="include-headers" className="text-sm">
|
||||||
|
Include headers
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<Button size="sm" className="w-full">
|
||||||
|
Download CSV
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</div>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem value="format-3" className="border-0">
|
||||||
|
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<AccordionTrigger className="py-1 px-2">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Download className="mr-2 h-4 w-4 text-primary" />
|
||||||
|
<span>Export as SQLite</span>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="pt-2 pb-1 px-2">
|
||||||
|
<Button size="sm" className="w-full">
|
||||||
|
Download SQLite
|
||||||
|
</Button>
|
||||||
|
</AccordionContent>
|
||||||
|
</div>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem value="format-4" className="border-0">
|
||||||
|
<div className="border rounded-md p-2 hover:border-highlight-border transition-all duration-200">
|
||||||
|
<AccordionTrigger className="py-1 px-2">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Download className="mr-2 h-4 w-4 text-primary" />
|
||||||
|
<span>Export as YAML</span>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="pt-2 pb-1 px-2">
|
||||||
|
<Button size="sm" className="w-full">
|
||||||
|
Download YAML
|
||||||
|
</Button>
|
||||||
|
</AccordionContent>
|
||||||
|
</div>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user