Refactor Redux integration demo layout

This commit is contained in:
2026-01-18 00:27:45 +00:00
parent 9cb7297f5b
commit a00cb7b71b
10 changed files with 542 additions and 279 deletions

View File

@@ -1,39 +1,29 @@
import { useEffect } from 'react'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
import { toast } from 'sonner'
import {
ArrowsClockwise,
Database,
CloudArrowUp,
CloudArrowDown,
CheckCircle,
XCircle,
Clock,
Trash,
FilePlus
} from '@phosphor-icons/react'
import { useReduxFiles } from '@/hooks/use-redux-files'
import { useReduxComponentTrees } from '@/hooks/use-redux-component-trees'
import { useReduxSync } from '@/hooks/use-redux-sync'
import { useAppSelector } from '@/store'
import { ComponentTreesCard } from '@/components/redux-integration/ComponentTreesCard'
import { DangerZoneCard } from '@/components/redux-integration/DangerZoneCard'
import { FilesCard } from '@/components/redux-integration/FilesCard'
import { ReduxIntegrationHeader } from '@/components/redux-integration/ReduxIntegrationHeader'
import { StatusCardsSection } from '@/components/redux-integration/StatusCardsSection'
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
export function ReduxIntegrationDemo() {
const { files, load: loadFiles, save: saveFile, remove: removeFile } = useReduxFiles()
const { trees, load: loadTrees } = useReduxComponentTrees()
const {
status,
lastSyncedAt,
flaskConnected,
const {
status,
lastSyncedAt,
flaskConnected,
flaskStats,
syncToFlask,
syncToFlask,
syncFromFlask,
checkConnection,
clearFlaskData
clearFlaskData,
} = useReduxSync()
const settings = useAppSelector((state) => state.settings.settings)
useEffect(() => {
@@ -51,284 +41,49 @@ export function ReduxIntegrationDemo() {
updatedAt: Date.now(),
}
saveFile(newFile)
toast.success('Test file created and saved to IndexedDB')
toast.success(reduxIntegrationCopy.toast.createTestFile)
}
const handleDeleteFile = (fileId: string) => {
removeFile(fileId)
toast.success('File deleted from IndexedDB')
toast.success(reduxIntegrationCopy.toast.deleteFile)
}
const handleSyncUp = () => {
syncToFlask()
toast.info('Syncing to Flask API...')
toast.info(reduxIntegrationCopy.toast.syncUp)
}
const handleSyncDown = () => {
syncFromFlask()
toast.info('Syncing from Flask API...')
toast.info(reduxIntegrationCopy.toast.syncDown)
}
const handleClearFlask = () => {
clearFlaskData()
toast.warning('Clearing Flask storage...')
}
const getSyncStatusBadge = () => {
switch (status) {
case 'idle':
return <Badge variant="outline">Idle</Badge>
case 'syncing':
return <Badge variant="secondary" className="animate-pulse">Syncing...</Badge>
case 'success':
return <Badge variant="default" className="bg-green-600"><CheckCircle className="w-3 h-3 mr-1" />Success</Badge>
case 'error':
return <Badge variant="destructive"><XCircle className="w-3 h-3 mr-1" />Error</Badge>
}
}
const getConnectionBadge = () => {
return flaskConnected ? (
<Badge variant="default" className="bg-green-600">
<CheckCircle className="w-3 h-3 mr-1" />Connected
</Badge>
) : (
<Badge variant="destructive">
<XCircle className="w-3 h-3 mr-1" />Disconnected
</Badge>
)
toast.warning(reduxIntegrationCopy.toast.clearFlask)
}
return (
<div className="h-full w-full overflow-auto p-6 space-y-6">
<div className="max-w-7xl mx-auto">
<div className="mb-6">
<h1 className="text-3xl font-bold mb-2">Redux Integration Demo</h1>
<p className="text-muted-foreground">
Comprehensive Redux Toolkit integration with IndexedDB and Flask API synchronization
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Database className="w-5 h-5" />
IndexedDB Status
</CardTitle>
<CardDescription>Local browser storage</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Files</span>
<Badge variant="outline">{files.length}</Badge>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Component Trees</span>
<Badge variant="outline">{trees.length}</Badge>
</div>
<Separator />
<Button
onClick={handleCreateTestFile}
variant="outline"
size="sm"
className="w-full"
>
<FilePlus className="w-4 h-4 mr-2" />
Create Test File
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CloudArrowUp className="w-5 h-5" />
Flask API Status
</CardTitle>
<CardDescription>Remote server connection</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Connection</span>
{getConnectionBadge()}
</div>
{flaskStats && (
<>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Total Keys</span>
<Badge variant="outline">{flaskStats.totalKeys}</Badge>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Storage Size</span>
<Badge variant="outline">
{(flaskStats.totalSizeBytes / 1024).toFixed(2)} KB
</Badge>
</div>
</>
)}
<Separator />
<Button
onClick={checkConnection}
variant="outline"
size="sm"
className="w-full"
>
<ArrowsClockwise className="w-4 h-4 mr-2" />
Check Connection
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<ArrowsClockwise className="w-5 h-5" />
Sync Status
</CardTitle>
<CardDescription>Data synchronization</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Status</span>
{getSyncStatusBadge()}
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Auto Sync</span>
<Badge variant={settings.autoSync ? "default" : "outline"}>
{settings.autoSync ? 'Enabled' : 'Disabled'}
</Badge>
</div>
{lastSyncedAt && (
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">Last Sync</span>
<Badge variant="outline" className="flex items-center gap-1">
<Clock className="w-3 h-3" />
{new Date(lastSyncedAt).toLocaleTimeString()}
</Badge>
</div>
)}
<Separator />
<div className="flex gap-2">
<Button
onClick={handleSyncUp}
variant="outline"
size="sm"
className="flex-1"
disabled={!flaskConnected || status === 'syncing'}
>
<CloudArrowUp className="w-4 h-4 mr-1" />
Push
</Button>
<Button
onClick={handleSyncDown}
variant="outline"
size="sm"
className="flex-1"
disabled={!flaskConnected || status === 'syncing'}
>
<CloudArrowDown className="w-4 h-4 mr-1" />
Pull
</Button>
</div>
</CardContent>
</Card>
</div>
<Card className="mt-6">
<CardHeader>
<CardTitle>Files in Redux Store</CardTitle>
<CardDescription>
Files managed by Redux and synced with IndexedDB/Flask
</CardDescription>
</CardHeader>
<CardContent>
{files.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
<Database className="w-12 h-12 mx-auto mb-3 opacity-50" />
<p>No files yet. Create a test file to get started.</p>
</div>
) : (
<div className="space-y-2">
{files.map((file) => (
<div
key={file.id}
className="flex items-center justify-between p-3 border border-border rounded-md hover:bg-muted/50 transition-colors"
>
<div className="flex-1">
<div className="font-medium">{file.name}</div>
<div className="text-xs text-muted-foreground">
{file.path} Updated {new Date(file.updatedAt).toLocaleString()}
</div>
</div>
<Button
variant="ghost"
size="sm"
onClick={() => handleDeleteFile(file.id)}
>
<Trash className="w-4 h-4 text-destructive" />
</Button>
</div>
))}
</div>
)}
</CardContent>
</Card>
<Card className="mt-6">
<CardHeader>
<CardTitle>Component Trees in Redux Store</CardTitle>
<CardDescription>
JSON component trees loaded from components.json
</CardDescription>
</CardHeader>
<CardContent>
{trees.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
<Database className="w-12 h-12 mx-auto mb-3 opacity-50" />
<p>No component trees loaded yet.</p>
</div>
) : (
<div className="space-y-2">
{trees.map((tree) => (
<div
key={tree.id}
className="flex items-center justify-between p-3 border border-border rounded-md hover:bg-muted/50 transition-colors"
>
<div className="flex-1">
<div className="font-medium">{tree.name}</div>
{tree.description && (
<div className="text-xs text-muted-foreground">{tree.description}</div>
)}
</div>
<Badge variant="outline">
{tree.root.type}
</Badge>
</div>
))}
</div>
)}
</CardContent>
</Card>
<Card className="mt-6 border-destructive/50">
<CardHeader>
<CardTitle className="text-destructive">Danger Zone</CardTitle>
<CardDescription>
Irreversible operations - use with caution
</CardDescription>
</CardHeader>
<CardContent>
<Button
variant="destructive"
onClick={handleClearFlask}
disabled={!flaskConnected}
>
<Trash className="w-4 h-4 mr-2" />
Clear Flask Storage
</Button>
</CardContent>
</Card>
<ReduxIntegrationHeader />
<StatusCardsSection
filesCount={files.length}
treesCount={trees.length}
flaskConnected={flaskConnected}
flaskStats={flaskStats}
status={status}
lastSyncedAt={lastSyncedAt}
autoSyncEnabled={settings.autoSync}
onCreateTestFile={handleCreateTestFile}
onCheckConnection={checkConnection}
onSyncUp={handleSyncUp}
onSyncDown={handleSyncDown}
/>
<FilesCard files={files} onDeleteFile={handleDeleteFile} />
<ComponentTreesCard trees={trees} />
<DangerZoneCard flaskConnected={flaskConnected} onClearFlask={handleClearFlask} />
</div>
</div>
)

View File

@@ -0,0 +1,45 @@
import { Badge } from '@/components/ui/badge'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Database } from '@phosphor-icons/react'
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
import { ComponentTree } from '@/store/slices/componentTreesSlice'
type ComponentTreesCardProps = {
trees: ComponentTree[]
}
export function ComponentTreesCard({ trees }: ComponentTreesCardProps) {
return (
<Card className="mt-6">
<CardHeader>
<CardTitle>{reduxIntegrationCopy.componentTrees.title}</CardTitle>
<CardDescription>{reduxIntegrationCopy.componentTrees.description}</CardDescription>
</CardHeader>
<CardContent>
{trees.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
<Database className="w-12 h-12 mx-auto mb-3 opacity-50" />
<p>{reduxIntegrationCopy.componentTrees.empty}</p>
</div>
) : (
<div className="space-y-2">
{trees.map((tree) => (
<div
key={tree.id}
className="flex items-center justify-between p-3 border border-border rounded-md hover:bg-muted/50 transition-colors"
>
<div className="flex-1">
<div className="font-medium">{tree.name}</div>
{tree.description && (
<div className="text-xs text-muted-foreground">{tree.description}</div>
)}
</div>
<Badge variant="outline">{tree.root.type}</Badge>
</div>
))}
</div>
)}
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,26 @@
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Trash } from '@phosphor-icons/react'
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
type DangerZoneCardProps = {
flaskConnected: boolean
onClearFlask: () => void
}
export function DangerZoneCard({ flaskConnected, onClearFlask }: DangerZoneCardProps) {
return (
<Card className="mt-6 border-destructive/50">
<CardHeader>
<CardTitle className="text-destructive">{reduxIntegrationCopy.danger.title}</CardTitle>
<CardDescription>{reduxIntegrationCopy.danger.description}</CardDescription>
</CardHeader>
<CardContent>
<Button variant="destructive" onClick={onClearFlask} disabled={!flaskConnected}>
<Trash className="w-4 h-4 mr-2" />
{reduxIntegrationCopy.danger.clearButton}
</Button>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,50 @@
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Database, Trash } from '@phosphor-icons/react'
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
import { FileItem } from '@/store/slices/filesSlice'
type FilesCardProps = {
files: FileItem[]
onDeleteFile: (fileId: string) => void
}
export function FilesCard({ files, onDeleteFile }: FilesCardProps) {
return (
<Card className="mt-6">
<CardHeader>
<CardTitle>{reduxIntegrationCopy.files.title}</CardTitle>
<CardDescription>{reduxIntegrationCopy.files.description}</CardDescription>
</CardHeader>
<CardContent>
{files.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
<Database className="w-12 h-12 mx-auto mb-3 opacity-50" />
<p>{reduxIntegrationCopy.files.empty}</p>
</div>
) : (
<div className="space-y-2">
{files.map((file) => (
<div
key={file.id}
className="flex items-center justify-between p-3 border border-border rounded-md hover:bg-muted/50 transition-colors"
>
<div className="flex-1">
<div className="font-medium">{file.name}</div>
<div className="text-xs text-muted-foreground">
{file.path} {reduxIntegrationCopy.files.updatedLabel}{' '}
{new Date(file.updatedAt).toLocaleString()}
</div>
</div>
<Button variant="ghost" size="sm" onClick={() => onDeleteFile(file.id)}>
<Trash className="w-4 h-4 text-destructive" />
</Button>
</div>
))}
</div>
)}
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,76 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
import { ArrowsClockwise, CheckCircle, CloudArrowUp, XCircle } from '@phosphor-icons/react'
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
type FlaskStats = {
totalKeys: number
totalSizeBytes: number
} | null
type FlaskStatusCardProps = {
flaskConnected: boolean
flaskStats: FlaskStats
onCheckConnection: () => void
}
export function FlaskStatusCard({ flaskConnected, flaskStats, onCheckConnection }: FlaskStatusCardProps) {
const connectionLabel = flaskConnected
? reduxIntegrationCopy.cards.flask.status.connected
: reduxIntegrationCopy.cards.flask.status.disconnected
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CloudArrowUp className="w-5 h-5" />
{reduxIntegrationCopy.cards.flask.title}
</CardTitle>
<CardDescription>{reduxIntegrationCopy.cards.flask.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.flask.labels.connection}
</span>
{flaskConnected ? (
<Badge variant="default" className="bg-green-600">
<CheckCircle className="w-3 h-3 mr-1" />
{connectionLabel}
</Badge>
) : (
<Badge variant="destructive">
<XCircle className="w-3 h-3 mr-1" />
{connectionLabel}
</Badge>
)}
</div>
{flaskStats && (
<>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.flask.labels.totalKeys}
</span>
<Badge variant="outline">{flaskStats.totalKeys}</Badge>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.flask.labels.storageSize}
</span>
<Badge variant="outline">
{(flaskStats.totalSizeBytes / 1024).toFixed(2)}{' '}
{reduxIntegrationCopy.cards.flask.labels.storageUnit}
</Badge>
</div>
</>
)}
<Separator />
<Button onClick={onCheckConnection} variant="outline" size="sm" className="w-full">
<ArrowsClockwise className="w-4 h-4 mr-2" />
{reduxIntegrationCopy.cards.flask.labels.checkConnection}
</Button>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,49 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
import { Database, FilePlus } from '@phosphor-icons/react'
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
type IndexedDbStatusCardProps = {
filesCount: number
treesCount: number
onCreateTestFile: () => void
}
export function IndexedDbStatusCard({
filesCount,
treesCount,
onCreateTestFile,
}: IndexedDbStatusCardProps) {
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Database className="w-5 h-5" />
{reduxIntegrationCopy.cards.indexedDb.title}
</CardTitle>
<CardDescription>{reduxIntegrationCopy.cards.indexedDb.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.indexedDb.labels.files}
</span>
<Badge variant="outline">{filesCount}</Badge>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.indexedDb.labels.componentTrees}
</span>
<Badge variant="outline">{treesCount}</Badge>
</div>
<Separator />
<Button onClick={onCreateTestFile} variant="outline" size="sm" className="w-full">
<FilePlus className="w-4 h-4 mr-2" />
{reduxIntegrationCopy.cards.indexedDb.labels.createTestFile}
</Button>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,10 @@
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
export function ReduxIntegrationHeader() {
return (
<div className="mb-6">
<h1 className="text-3xl font-bold mb-2">{reduxIntegrationCopy.page.title}</h1>
<p className="text-muted-foreground">{reduxIntegrationCopy.page.description}</p>
</div>
)
}

View File

@@ -0,0 +1,60 @@
import { IndexedDbStatusCard } from '@/components/redux-integration/IndexedDbStatusCard'
import { FlaskStatusCard } from '@/components/redux-integration/FlaskStatusCard'
import { SyncStatusCard } from '@/components/redux-integration/SyncStatusCard'
import { SyncStatus } from '@/store/slices/syncSlice'
type FlaskStats = {
totalKeys: number
totalSizeBytes: number
} | null
type StatusCardsSectionProps = {
filesCount: number
treesCount: number
flaskConnected: boolean
flaskStats: FlaskStats
status: SyncStatus
lastSyncedAt: number | null
autoSyncEnabled: boolean
onCreateTestFile: () => void
onCheckConnection: () => void
onSyncUp: () => void
onSyncDown: () => void
}
export function StatusCardsSection({
filesCount,
treesCount,
flaskConnected,
flaskStats,
status,
lastSyncedAt,
autoSyncEnabled,
onCreateTestFile,
onCheckConnection,
onSyncUp,
onSyncDown,
}: StatusCardsSectionProps) {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<IndexedDbStatusCard
filesCount={filesCount}
treesCount={treesCount}
onCreateTestFile={onCreateTestFile}
/>
<FlaskStatusCard
flaskConnected={flaskConnected}
flaskStats={flaskStats}
onCheckConnection={onCheckConnection}
/>
<SyncStatusCard
status={status}
lastSyncedAt={lastSyncedAt}
autoSyncEnabled={autoSyncEnabled}
flaskConnected={flaskConnected}
onSyncUp={onSyncUp}
onSyncDown={onSyncDown}
/>
</div>
)
}

View File

@@ -0,0 +1,116 @@
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Separator } from '@/components/ui/separator'
import { ArrowsClockwise, CheckCircle, Clock, CloudArrowDown, CloudArrowUp, XCircle } from '@phosphor-icons/react'
import reduxIntegrationCopy from '@/data/redux-integration-demo.json'
import { SyncStatus } from '@/store/slices/syncSlice'
type SyncStatusCardProps = {
status: SyncStatus
lastSyncedAt: number | null
autoSyncEnabled: boolean
flaskConnected: boolean
onSyncUp: () => void
onSyncDown: () => void
}
export function SyncStatusCard({
status,
lastSyncedAt,
autoSyncEnabled,
flaskConnected,
onSyncUp,
onSyncDown,
}: SyncStatusCardProps) {
const getSyncStatusBadge = () => {
switch (status) {
case 'idle':
return <Badge variant="outline">{reduxIntegrationCopy.cards.sync.status.idle}</Badge>
case 'syncing':
return (
<Badge variant="secondary" className="animate-pulse">
{reduxIntegrationCopy.cards.sync.status.syncing}
</Badge>
)
case 'success':
return (
<Badge variant="default" className="bg-green-600">
<CheckCircle className="w-3 h-3 mr-1" />
{reduxIntegrationCopy.cards.sync.status.success}
</Badge>
)
case 'error':
return (
<Badge variant="destructive">
<XCircle className="w-3 h-3 mr-1" />
{reduxIntegrationCopy.cards.sync.status.error}
</Badge>
)
}
}
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<ArrowsClockwise className="w-5 h-5" />
{reduxIntegrationCopy.cards.sync.title}
</CardTitle>
<CardDescription>{reduxIntegrationCopy.cards.sync.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.sync.labels.status}
</span>
{getSyncStatusBadge()}
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.sync.labels.autoSync}
</span>
<Badge variant={autoSyncEnabled ? 'default' : 'outline'}>
{autoSyncEnabled
? reduxIntegrationCopy.cards.sync.autoSync.enabled
: reduxIntegrationCopy.cards.sync.autoSync.disabled}
</Badge>
</div>
{lastSyncedAt && (
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground">
{reduxIntegrationCopy.cards.sync.labels.lastSync}
</span>
<Badge variant="outline" className="flex items-center gap-1">
<Clock className="w-3 h-3" />
{new Date(lastSyncedAt).toLocaleTimeString()}
</Badge>
</div>
)}
<Separator />
<div className="flex gap-2">
<Button
onClick={onSyncUp}
variant="outline"
size="sm"
className="flex-1"
disabled={!flaskConnected || status === 'syncing'}
>
<CloudArrowUp className="w-4 h-4 mr-1" />
{reduxIntegrationCopy.cards.sync.labels.push}
</Button>
<Button
onClick={onSyncDown}
variant="outline"
size="sm"
className="flex-1"
disabled={!flaskConnected || status === 'syncing'}
>
<CloudArrowDown className="w-4 h-4 mr-1" />
{reduxIntegrationCopy.cards.sync.labels.pull}
</Button>
</div>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,76 @@
{
"page": {
"title": "Redux Integration Demo",
"description": "Comprehensive Redux Toolkit integration with IndexedDB and Flask API synchronization"
},
"cards": {
"indexedDb": {
"title": "IndexedDB Status",
"description": "Local browser storage",
"labels": {
"files": "Files",
"componentTrees": "Component Trees",
"createTestFile": "Create Test File"
}
},
"flask": {
"title": "Flask API Status",
"description": "Remote server connection",
"labels": {
"connection": "Connection",
"totalKeys": "Total Keys",
"storageSize": "Storage Size",
"storageUnit": "KB",
"checkConnection": "Check Connection"
},
"status": {
"connected": "Connected",
"disconnected": "Disconnected"
}
},
"sync": {
"title": "Sync Status",
"description": "Data synchronization",
"labels": {
"status": "Status",
"autoSync": "Auto Sync",
"lastSync": "Last Sync",
"push": "Push",
"pull": "Pull"
},
"status": {
"idle": "Idle",
"syncing": "Syncing...",
"success": "Success",
"error": "Error"
},
"autoSync": {
"enabled": "Enabled",
"disabled": "Disabled"
}
}
},
"files": {
"title": "Files in Redux Store",
"description": "Files managed by Redux and synced with IndexedDB/Flask",
"empty": "No files yet. Create a test file to get started.",
"updatedLabel": "Updated"
},
"componentTrees": {
"title": "Component Trees in Redux Store",
"description": "JSON component trees loaded from components.json",
"empty": "No component trees loaded yet."
},
"danger": {
"title": "Danger Zone",
"description": "Irreversible operations - use with caution",
"clearButton": "Clear Flask Storage"
},
"toast": {
"createTestFile": "Test file created and saved to IndexedDB",
"deleteFile": "File deleted from IndexedDB",
"syncUp": "Syncing to Flask API...",
"syncDown": "Syncing from Flask API...",
"clearFlask": "Clearing Flask storage..."
}
}