commit task-fix-template
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { IconCopy, IconEye } from '@tabler/icons-react';
|
||||
import { toast } from 'sonner';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger
|
||||
} from '@/components/ui/sheet';
|
||||
|
||||
type TemplateJsonSheetProps = {
|
||||
version: string;
|
||||
filePath?: string | null;
|
||||
schemaJson: unknown;
|
||||
triggerLabel?: string;
|
||||
};
|
||||
|
||||
function formatSchemaJson(schemaJson: unknown) {
|
||||
try {
|
||||
return JSON.stringify(schemaJson ?? {}, null, 2);
|
||||
} catch {
|
||||
return '{}';
|
||||
}
|
||||
}
|
||||
|
||||
function getSchemaPageCount(schemaJson: unknown) {
|
||||
if (
|
||||
schemaJson &&
|
||||
typeof schemaJson === 'object' &&
|
||||
'schemas' in schemaJson &&
|
||||
Array.isArray((schemaJson as { schemas?: unknown }).schemas)
|
||||
) {
|
||||
return (schemaJson as { schemas: unknown[] }).schemas.length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function TemplateJsonSheet({
|
||||
version,
|
||||
filePath,
|
||||
schemaJson,
|
||||
triggerLabel = 'View JSON'
|
||||
}: TemplateJsonSheetProps) {
|
||||
const formattedJson = React.useMemo(() => formatSchemaJson(schemaJson), [schemaJson]);
|
||||
const pageCount = React.useMemo(() => getSchemaPageCount(schemaJson), [schemaJson]);
|
||||
const hasSchemaJson = formattedJson !== '{}';
|
||||
|
||||
async function handleCopy() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(formattedJson);
|
||||
toast.success('Copied JSON');
|
||||
} catch {
|
||||
toast.error('Unable to copy JSON');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant='outline' size='sm'>
|
||||
<IconEye className='size-4' />
|
||||
{triggerLabel}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
|
||||
<SheetContent side='right' className='w-full max-w-[90vw] sm:max-w-5xl'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Template Schema JSON</SheetTitle>
|
||||
<SheetDescription>
|
||||
Version {version}
|
||||
{filePath ? ` | ${filePath}` : ''}
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
|
||||
<div className='flex items-center justify-between gap-3'>
|
||||
<div className='text-muted-foreground text-sm'>
|
||||
{pageCount > 0 ? `Pages: ${pageCount}` : 'Schema metadata unavailable'}
|
||||
</div>
|
||||
|
||||
<Button variant='outline' size='sm' onClick={handleCopy}>
|
||||
<IconCopy className='size-4' />
|
||||
Copy JSON
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{hasSchemaJson ? (
|
||||
<pre className='bg-muted max-h-[calc(100vh-180px)] overflow-auto rounded-lg border p-4 font-mono text-xs whitespace-pre'>
|
||||
<code>{formattedJson}</code>
|
||||
</pre>
|
||||
) : (
|
||||
<div className='text-muted-foreground rounded-lg border border-dashed p-6 text-sm'>
|
||||
No schema JSON available.
|
||||
</div>
|
||||
)}
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { TemplateJsonSheet } from './template-json-sheet';
|
||||
import {
|
||||
createDocumentTemplateMappingMutation,
|
||||
createDocumentTemplateMutation,
|
||||
@@ -182,6 +183,10 @@ function Field({
|
||||
);
|
||||
}
|
||||
|
||||
function getTableColumnCount(version: DocumentTemplateVersionDetail) {
|
||||
return version.mappings.reduce((total, mapping) => total + mapping.columns.length, 0);
|
||||
}
|
||||
|
||||
function TemplateDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
@@ -574,40 +579,61 @@ function TemplateDetailCard({ templateId }: { templateId: string }) {
|
||||
No versions created yet.
|
||||
</div>
|
||||
) : null}
|
||||
{template.versions.map((version) => (
|
||||
<TabsContent key={version.id} value={version.id} className='space-y-4'>
|
||||
<div className='rounded-lg border p-4'>
|
||||
<div className='flex flex-wrap items-center justify-between gap-3'>
|
||||
<div>
|
||||
<div className='font-medium'>Version {version.version}</div>
|
||||
<div className='text-muted-foreground text-sm'>
|
||||
{version.filePath || 'No file path set'}{version.previewImageUrl ? ` • ${version.previewImageUrl}` : ''}
|
||||
{template.versions.map((version) => (
|
||||
<TabsContent key={version.id} value={version.id} className='space-y-4'>
|
||||
<div className='rounded-lg border p-4'>
|
||||
<div className='flex flex-wrap items-start justify-between gap-3'>
|
||||
<div className='min-w-0 flex-1 space-y-3'>
|
||||
<div className='font-medium'>Version {version.version}</div>
|
||||
<div className='grid gap-3 sm:grid-cols-2 xl:grid-cols-4'>
|
||||
<div className='rounded-lg bg-muted/40 p-3'>
|
||||
<div className='text-muted-foreground text-xs'>File Path</div>
|
||||
<div className='mt-1 break-all text-sm font-medium'>
|
||||
{version.filePath || 'No file path set'}
|
||||
</div>
|
||||
</div>
|
||||
<div className='rounded-lg bg-muted/40 p-3'>
|
||||
<div className='text-muted-foreground text-xs'>Mappings</div>
|
||||
<div className='mt-1 text-sm font-medium'>{version.mappings.length}</div>
|
||||
</div>
|
||||
<div className='rounded-lg bg-muted/40 p-3'>
|
||||
<div className='text-muted-foreground text-xs'>Table Columns</div>
|
||||
<div className='mt-1 text-sm font-medium'>{getTableColumnCount(version)}</div>
|
||||
</div>
|
||||
<div className='rounded-lg bg-muted/40 p-3'>
|
||||
<div className='text-muted-foreground text-xs'>Preview Image</div>
|
||||
<div className='mt-1 break-all text-sm font-medium'>
|
||||
{version.previewImageUrl || '-'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-wrap items-center gap-2'>
|
||||
<Badge variant={version.isActive ? 'secondary' : 'outline'}>
|
||||
{version.isActive ? 'Active' : 'Inactive'}
|
||||
</Badge>
|
||||
<TemplateJsonSheet
|
||||
version={version.version}
|
||||
filePath={version.filePath}
|
||||
schemaJson={version.schemaJson}
|
||||
/>
|
||||
<Button variant='outline' onClick={() => setVersionDialogOpen(true)}>
|
||||
Edit Version
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
setMappingDialogState({
|
||||
open: true,
|
||||
version
|
||||
})
|
||||
}
|
||||
>
|
||||
<Icons.add className='mr-2 h-4 w-4' />
|
||||
Add Mapping
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-2'>
|
||||
<Badge variant={version.isActive ? 'secondary' : 'outline'}>
|
||||
{version.isActive ? 'Active' : 'Inactive'}
|
||||
</Badge>
|
||||
<Button variant='outline' onClick={() => setVersionDialogOpen(true)}>
|
||||
Edit Version
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
setMappingDialogState({
|
||||
open: true,
|
||||
version
|
||||
})
|
||||
}
|
||||
>
|
||||
<Icons.add className='mr-2 h-4 w-4' />
|
||||
Add Mapping
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<pre className='bg-muted mt-4 max-h-72 overflow-auto rounded-lg p-4 text-xs'>
|
||||
{JSON.stringify(version.schemaJson, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
<div className='space-y-3'>
|
||||
{version.mappings.map((mapping) => (
|
||||
<div key={mapping.id} className='rounded-lg border p-4'>
|
||||
|
||||
Reference in New Issue
Block a user