87 lines
3.6 KiB
Vue
87 lines
3.6 KiB
Vue
<script setup>
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/Components/ui/dialog";
|
|
import { Button } from "@/Components/ui/button";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/Components/ui/select";
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/Components/ui/table";
|
|
import { Badge } from "@/Components/ui/badge";
|
|
import { Label } from "@/Components/ui/label";
|
|
const props = defineProps({
|
|
show: Boolean,
|
|
limit: Number,
|
|
rows: Array,
|
|
columns: Array,
|
|
loading: Boolean,
|
|
truncated: Boolean,
|
|
hasHeader: Boolean,
|
|
})
|
|
const emits = defineEmits(['close','change-limit','refresh'])
|
|
function onLimit(e){ emits('change-limit', Number(e.target.value)); emits('refresh') }
|
|
</script>
|
|
<template>
|
|
<Dialog :open="show" @update:open="(val) => !val && $emit('close')">
|
|
<DialogContent class="max-w-6xl max-h-[90vh] overflow-hidden flex flex-col">
|
|
<DialogHeader>
|
|
<DialogTitle>CSV Preview ({{ rows.length }} / {{ limit }})</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
<div class="flex items-center gap-3 pb-3 border-b">
|
|
<div class="flex items-center gap-2">
|
|
<Label for="limit-select" class="text-sm text-gray-600">Limit:</Label>
|
|
<Select :model-value="String(limit)" @update:model-value="(val) => { emits('change-limit', Number(val)); emits('refresh'); }">
|
|
<SelectTrigger id="limit-select" class="w-24 h-8">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="50">50</SelectItem>
|
|
<SelectItem value="100">100</SelectItem>
|
|
<SelectItem value="200">200</SelectItem>
|
|
<SelectItem value="300">300</SelectItem>
|
|
<SelectItem value="500">500</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<Button @click="$emit('refresh')" variant="outline" size="sm" :disabled="loading">
|
|
{{ loading ? 'Loading…' : 'Refresh' }}
|
|
</Button>
|
|
<Badge v-if="truncated" variant="outline" class="bg-amber-50 text-amber-700 border-amber-200">
|
|
Truncated at limit
|
|
</Badge>
|
|
</div>
|
|
|
|
<div class="flex-1 overflow-auto border rounded-lg">
|
|
<Table>
|
|
<TableHeader class="sticky top-0 bg-white z-10">
|
|
<TableRow>
|
|
<TableHead class="w-16">#</TableHead>
|
|
<TableHead v-for="col in columns" :key="col">{{ col }}</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
<TableRow v-if="loading">
|
|
<TableCell :colspan="columns.length + 1" class="text-center text-gray-500">
|
|
Loading…
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow v-for="(r, idx) in rows" :key="idx">
|
|
<TableCell class="text-gray-500 font-medium">{{ idx + 1 }}</TableCell>
|
|
<TableCell v-for="col in columns" :key="col" class="whitespace-pre-wrap">
|
|
{{ r[col] }}
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow v-if="!loading && !rows.length">
|
|
<TableCell :colspan="columns.length + 1" class="text-center text-gray-500">
|
|
No rows
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
|
|
<div class="text-xs text-gray-500 pt-3 border-t">
|
|
Showing up to {{ limit }} rows from source file.
|
|
Header detection: <span class="font-medium">{{ hasHeader ? 'header present' : 'no header' }}</span>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</template>
|