mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
Generated by Spark: Now just use said json data as seed data and load it all from database
This commit is contained in:
199
SEED_DATA_GUIDE.md
Normal file
199
SEED_DATA_GUIDE.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# Seed Data System
|
||||
|
||||
## Overview
|
||||
|
||||
The application now includes a comprehensive seed data system that loads initial data from JSON configuration into the database (KV store) on first launch.
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Automatic Data Loading
|
||||
- Seed data is automatically loaded on application startup
|
||||
- Only loads if data doesn't already exist (safe to re-run)
|
||||
- All data is stored in the KV database for persistence
|
||||
|
||||
### 2. Seed Data Management UI
|
||||
Navigate to **Settings → Data** tab to access the Seed Data Manager with three options:
|
||||
|
||||
- **Load Seed Data**: Populates database with initial data (only if not already loaded)
|
||||
- **Reset to Defaults**: Overwrites all data with fresh seed data
|
||||
- **Clear All Data**: Removes all data from the database (destructive action)
|
||||
|
||||
### 3. Dashboard Integration
|
||||
The Project Dashboard displays available seed data including:
|
||||
- Number of pre-configured files
|
||||
- Number of sample models
|
||||
- Number of example components
|
||||
- And more...
|
||||
|
||||
## Seed Data Contents
|
||||
|
||||
The system includes the following pre-configured data:
|
||||
|
||||
### Files (`project-files`)
|
||||
- Sample Next.js pages (page.tsx, layout.tsx)
|
||||
- Material UI integration examples
|
||||
- TypeScript configuration
|
||||
|
||||
### Models (`project-models`)
|
||||
- User model with authentication fields
|
||||
- Post model with relationships
|
||||
- Complete Prisma schema examples
|
||||
|
||||
### Components (`project-components`)
|
||||
- Button components with variants
|
||||
- Card components with styling
|
||||
- Reusable UI elements
|
||||
|
||||
### Workflows (`project-workflows`)
|
||||
- User registration flow
|
||||
- Complete workflow with triggers and actions
|
||||
- Visual workflow nodes and connections
|
||||
|
||||
### Lambdas (`project-lambdas`)
|
||||
- User data processing function
|
||||
- HTTP trigger configuration
|
||||
- Environment variable examples
|
||||
|
||||
### Tests (`project-playwright-tests`, `project-storybook-stories`, `project-unit-tests`)
|
||||
- E2E test examples
|
||||
- Component story examples
|
||||
- Unit test templates
|
||||
|
||||
### Component Trees (`project-component-trees`)
|
||||
- Application layout tree
|
||||
- Nested component structures
|
||||
- Material UI component hierarchies
|
||||
|
||||
## Configuration
|
||||
|
||||
### Adding New Seed Data
|
||||
|
||||
Edit `/src/config/seed-data.json` to add or modify seed data:
|
||||
|
||||
```json
|
||||
{
|
||||
"project-files": [...],
|
||||
"project-models": [...],
|
||||
"your-custom-key": [...]
|
||||
}
|
||||
```
|
||||
|
||||
### Seed Data Schema
|
||||
|
||||
Each data type follows the TypeScript interfaces defined in `/src/types/project.ts`:
|
||||
|
||||
- `ProjectFile`
|
||||
- `PrismaModel`
|
||||
- `ComponentNode`
|
||||
- `Workflow`
|
||||
- `Lambda`
|
||||
- `PlaywrightTest`
|
||||
- `StorybookStory`
|
||||
- `UnitTest`
|
||||
- `ComponentTree`
|
||||
|
||||
## API Reference
|
||||
|
||||
### Hook: `useSeedData()`
|
||||
|
||||
```typescript
|
||||
import { useSeedData } from '@/hooks/data/use-seed-data'
|
||||
|
||||
const { isLoaded, isLoading, loadSeedData, resetSeedData, clearAllData } = useSeedData()
|
||||
```
|
||||
|
||||
**Returns:**
|
||||
- `isLoaded`: Boolean indicating if seed data has been loaded
|
||||
- `isLoading`: Boolean indicating if an operation is in progress
|
||||
- `loadSeedData()`: Function to load seed data (if not already loaded)
|
||||
- `resetSeedData()`: Function to reset all data to seed defaults
|
||||
- `clearAllData()`: Function to clear all data from database
|
||||
|
||||
### Direct KV API
|
||||
|
||||
You can also interact with seed data directly:
|
||||
|
||||
```typescript
|
||||
// Get specific seed data
|
||||
const files = await window.spark.kv.get('project-files')
|
||||
|
||||
// Update seed data
|
||||
await window.spark.kv.set('project-files', updatedFiles)
|
||||
|
||||
// Delete seed data
|
||||
await window.spark.kv.delete('project-files')
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### `<SeedDataManager />`
|
||||
Management UI for seed data operations (used in Settings → Data tab)
|
||||
|
||||
### `<SeedDataStatus />`
|
||||
Display component showing available seed data (used on Dashboard)
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use the useKV hook** for reactive state management
|
||||
2. **Use functional updates** when modifying arrays/objects to prevent data loss
|
||||
3. **Test seed data** thoroughly before deploying
|
||||
4. **Document custom seed data** for team members
|
||||
5. **Keep seed data minimal** - only include essential examples
|
||||
|
||||
## Example: Custom Seed Data
|
||||
|
||||
```typescript
|
||||
// 1. Add to seed-data.json
|
||||
{
|
||||
"my-custom-data": [
|
||||
{ "id": "1", "name": "Example 1" },
|
||||
{ "id": "2", "name": "Example 2" }
|
||||
]
|
||||
}
|
||||
|
||||
// 2. Use in component
|
||||
import { useKV } from '@github/spark/hooks'
|
||||
|
||||
function MyComponent() {
|
||||
const [data, setData] = useKV('my-custom-data', [])
|
||||
|
||||
// Always use functional updates
|
||||
const addItem = (newItem) => {
|
||||
setData(current => [...current, newItem])
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{data.map(item => (
|
||||
<div key={item.id}>{item.name}</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Data Not Loading
|
||||
- Check browser console for errors
|
||||
- Verify seed-data.json is valid JSON
|
||||
- Ensure data keys match KV store keys
|
||||
|
||||
### Data Persisting After Clear
|
||||
- Hard refresh the browser (Ctrl+Shift+R)
|
||||
- Check for cached service workers (PWA)
|
||||
- Verify clearAllData completed successfully
|
||||
|
||||
### Type Errors
|
||||
- Ensure seed data matches TypeScript interfaces
|
||||
- Update types in `/src/types/project.ts` if needed
|
||||
- Run type checking: `npm run type-check`
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Planned improvements:
|
||||
- Import/export seed data as JSON files
|
||||
- Version control for seed data
|
||||
- Seed data migration system
|
||||
- Seed data validation UI
|
||||
- Partial seed data loading
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, lazy, Suspense, useMemo } from 'react'
|
||||
import { useState, lazy, Suspense, useMemo, useEffect } from 'react'
|
||||
import { Tabs, TabsContent } from '@/components/ui/tabs'
|
||||
import { AppHeader, PageHeader } from '@/components/organisms'
|
||||
import { LoadingFallback } from '@/components/molecules'
|
||||
@@ -6,6 +6,7 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/componen
|
||||
import { useProjectState } from '@/hooks/use-project-state'
|
||||
import { useFileOperations } from '@/hooks/use-file-operations'
|
||||
import { useKeyboardShortcuts } from '@/hooks/use-keyboard-shortcuts'
|
||||
import { useSeedData } from '@/hooks/data/use-seed-data'
|
||||
import { getPageConfig, getEnabledPages, getPageShortcuts, resolveProps } from '@/config/page-loader'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
@@ -74,6 +75,7 @@ function App() {
|
||||
|
||||
const fileOps = useFileOperations(files, setFiles)
|
||||
const { activeFileId, setActiveFileId, handleFileChange, handleFileAdd, handleFileClose } = fileOps
|
||||
const { loadSeedData } = useSeedData()
|
||||
|
||||
const [activeTab, setActiveTab] = useState('dashboard')
|
||||
const [searchOpen, setSearchOpen] = useState(false)
|
||||
@@ -81,6 +83,10 @@ function App() {
|
||||
const [lastSaved] = useState<number | null>(Date.now())
|
||||
const [errorCount] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
loadSeedData()
|
||||
}, [])
|
||||
|
||||
const pageConfig = useMemo(() => getPageConfig(), [])
|
||||
const enabledPages = useMemo(() => getEnabledPages(featureToggles), [featureToggles])
|
||||
const shortcuts = useMemo(() => getPageShortcuts(featureToggles), [featureToggles])
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
Warning
|
||||
} from '@phosphor-icons/react'
|
||||
import { ProjectFile, PrismaModel, ComponentNode, ThemeConfig, PlaywrightTest, StorybookStory, UnitTest, FlaskConfig } from '@/types/project'
|
||||
import { SeedDataStatus } from '@/components/atoms'
|
||||
|
||||
interface ProjectDashboardProps {
|
||||
files: ProjectFile[]
|
||||
@@ -131,6 +132,8 @@ export function ProjectDashboard({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SeedDataStatus />
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Project Details</CardTitle>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, D
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Plus, Trash, Package, Cube, Code } from '@phosphor-icons/react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { SeedDataManager } from '@/components/molecules'
|
||||
|
||||
interface ProjectSettingsDesignerProps {
|
||||
nextjsConfig: NextJsConfig
|
||||
@@ -134,6 +135,7 @@ export function ProjectSettingsDesigner({
|
||||
<TabsTrigger value="nextjs">Next.js Config</TabsTrigger>
|
||||
<TabsTrigger value="packages">NPM Packages</TabsTrigger>
|
||||
<TabsTrigger value="scripts">Scripts</TabsTrigger>
|
||||
<TabsTrigger value="data">Data</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
@@ -504,6 +506,12 @@ export function ProjectSettingsDesigner({
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="data" className="mt-0">
|
||||
<div className="max-w-2xl">
|
||||
<SeedDataManager />
|
||||
</div>
|
||||
</TabsContent>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</Tabs>
|
||||
|
||||
60
src/components/atoms/SeedDataStatus.tsx
Normal file
60
src/components/atoms/SeedDataStatus.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Database, Check, X } from '@phosphor-icons/react'
|
||||
import seedDataConfig from '@/config/seed-data.json'
|
||||
|
||||
export function SeedDataStatus() {
|
||||
const dataKeys = Object.keys(seedDataConfig)
|
||||
|
||||
const getDataCount = (key: string): number => {
|
||||
const data = seedDataConfig[key as keyof typeof seedDataConfig]
|
||||
return Array.isArray(data) ? data.length : 0
|
||||
}
|
||||
|
||||
const getLabelForKey = (key: string): string => {
|
||||
const labels: Record<string, string> = {
|
||||
'project-files': 'Files',
|
||||
'project-models': 'Models',
|
||||
'project-components': 'Components',
|
||||
'project-workflows': 'Workflows',
|
||||
'project-lambdas': 'Lambdas',
|
||||
'project-playwright-tests': 'Playwright Tests',
|
||||
'project-storybook-stories': 'Storybook Stories',
|
||||
'project-unit-tests': 'Unit Tests',
|
||||
'project-component-trees': 'Component Trees',
|
||||
}
|
||||
return labels[key] || key
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-lg">
|
||||
<Database size={20} weight="duotone" />
|
||||
Seed Data Available
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Pre-configured data ready to load from database
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||
{dataKeys.map((key) => {
|
||||
const count = getDataCount(key)
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="flex items-center justify-between p-3 rounded-lg border border-border bg-muted/50"
|
||||
>
|
||||
<span className="text-sm font-medium">{getLabelForKey(key)}</span>
|
||||
<Badge variant="secondary" className="ml-2">
|
||||
{count}
|
||||
</Badge>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -8,3 +8,4 @@ export { EmptyStateIcon } from './EmptyStateIcon'
|
||||
export { TreeIcon } from './TreeIcon'
|
||||
export { FileIcon } from './FileIcon'
|
||||
export { ActionIcon } from './ActionIcon'
|
||||
export { SeedDataStatus } from './SeedDataStatus'
|
||||
|
||||
97
src/components/molecules/SeedDataManager.tsx
Normal file
97
src/components/molecules/SeedDataManager.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { useSeedData } from '@/hooks/data/use-seed-data'
|
||||
import { Database, ArrowClockwise, Trash, CheckCircle, CircleNotch } from '@phosphor-icons/react'
|
||||
|
||||
export function SeedDataManager() {
|
||||
const { isLoaded, isLoading, loadSeedData, resetSeedData, clearAllData } = useSeedData()
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Database size={24} weight="duotone" />
|
||||
Seed Data Management
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Load, reset, or clear application seed data from the database
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
{isLoaded && (
|
||||
<Alert>
|
||||
<CheckCircle className="h-4 w-4" weight="fill" />
|
||||
<AlertDescription>
|
||||
Seed data is loaded and available
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<Button
|
||||
onClick={loadSeedData}
|
||||
disabled={isLoading || isLoaded}
|
||||
variant="default"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<CircleNotch className="animate-spin" size={16} />
|
||||
Loading...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Database size={16} weight="fill" />
|
||||
Load Seed Data
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={resetSeedData}
|
||||
disabled={isLoading}
|
||||
variant="outline"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<CircleNotch className="animate-spin" size={16} />
|
||||
Resetting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ArrowClockwise size={16} weight="bold" />
|
||||
Reset to Defaults
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={clearAllData}
|
||||
disabled={isLoading}
|
||||
variant="destructive"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<CircleNotch className="animate-spin" size={16} />
|
||||
Clearing...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash size={16} weight="fill" />
|
||||
Clear All Data
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
<p><strong>Load Seed Data:</strong> Populates database with initial data if not already loaded</p>
|
||||
<p><strong>Reset to Defaults:</strong> Overwrites all data with fresh seed data</p>
|
||||
<p><strong>Clear All Data:</strong> Removes all data from the database (destructive action)</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -13,6 +13,7 @@ export { NavigationGroupHeader } from './NavigationGroupHeader'
|
||||
export { NavigationItem } from './NavigationItem'
|
||||
export { PageHeaderContent } from './PageHeaderContent'
|
||||
export { SaveIndicator } from './SaveIndicator'
|
||||
export { SeedDataManager } from './SeedDataManager'
|
||||
export { StatCard } from './StatCard'
|
||||
export { ToolbarButton } from './ToolbarButton'
|
||||
export { TreeCard } from './TreeCard'
|
||||
|
||||
351
src/config/seed-data.json
Normal file
351
src/config/seed-data.json
Normal file
@@ -0,0 +1,351 @@
|
||||
{
|
||||
"project-files": [
|
||||
{
|
||||
"id": "file-1",
|
||||
"name": "page.tsx",
|
||||
"path": "/src/app/page.tsx",
|
||||
"content": "'use client'\n\nimport { ThemeProvider } from '@mui/material/styles'\nimport CssBaseline from '@mui/material/CssBaseline'\nimport { theme } from '@/theme'\nimport { Box, Typography, Button } from '@mui/material'\n\nexport default function Home() {\n return (\n <ThemeProvider theme={theme}>\n <CssBaseline />\n <Box sx={{ p: 4 }}>\n <Typography variant=\"h3\" gutterBottom>\n Welcome to Your App\n </Typography>\n <Button variant=\"contained\" color=\"primary\">\n Get Started\n </Button>\n </Box>\n </ThemeProvider>\n )\n}",
|
||||
"language": "typescript"
|
||||
},
|
||||
{
|
||||
"id": "file-2",
|
||||
"name": "layout.tsx",
|
||||
"path": "/src/app/layout.tsx",
|
||||
"content": "export const metadata = {\n title: 'My Next.js App',\n description: 'Generated with CodeForge',\n}\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n )\n}",
|
||||
"language": "typescript"
|
||||
}
|
||||
],
|
||||
"project-models": [
|
||||
{
|
||||
"id": "model-1",
|
||||
"name": "User",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-1",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-2",
|
||||
"name": "email",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-3",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-4",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-2",
|
||||
"name": "Post",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-5",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-6",
|
||||
"name": "title",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-7",
|
||||
"name": "content",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-8",
|
||||
"name": "published",
|
||||
"type": "Boolean",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "false"
|
||||
},
|
||||
{
|
||||
"id": "field-9",
|
||||
"name": "authorId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "User"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-components": [
|
||||
{
|
||||
"id": "comp-1",
|
||||
"type": "Button",
|
||||
"name": "PrimaryButton",
|
||||
"props": {
|
||||
"variant": "contained",
|
||||
"color": "primary"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "comp-2",
|
||||
"type": "Card",
|
||||
"name": "UserCard",
|
||||
"props": {
|
||||
"elevation": 2
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "comp-3",
|
||||
"type": "CardContent",
|
||||
"name": "CardContent",
|
||||
"props": {},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-workflows": [
|
||||
{
|
||||
"id": "workflow-1",
|
||||
"name": "User Registration Flow",
|
||||
"description": "Complete user registration and onboarding workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-1",
|
||||
"type": "trigger",
|
||||
"name": "Form Submit",
|
||||
"position": { "x": 100, "y": 100 },
|
||||
"data": {
|
||||
"label": "Registration Form Submitted"
|
||||
},
|
||||
"config": {
|
||||
"triggerType": "event"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-2",
|
||||
"type": "action",
|
||||
"name": "Validate Input",
|
||||
"position": { "x": 300, "y": 100 },
|
||||
"data": {
|
||||
"label": "Validate User Data"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-3",
|
||||
"type": "database",
|
||||
"name": "Create User",
|
||||
"position": { "x": 500, "y": 100 },
|
||||
"data": {
|
||||
"label": "Insert User Record"
|
||||
},
|
||||
"config": {
|
||||
"databaseQuery": "INSERT INTO users"
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "conn-1",
|
||||
"source": "node-1",
|
||||
"target": "node-2"
|
||||
},
|
||||
{
|
||||
"id": "conn-2",
|
||||
"source": "node-2",
|
||||
"target": "node-3"
|
||||
}
|
||||
],
|
||||
"isActive": true,
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-lambdas": [
|
||||
{
|
||||
"id": "lambda-1",
|
||||
"name": "processUserData",
|
||||
"description": "Process and transform user data",
|
||||
"code": "export async function handler(event) {\n const { userId, data } = event;\n // Process user data\n return {\n statusCode: 200,\n body: JSON.stringify({ success: true })\n };\n}",
|
||||
"language": "typescript",
|
||||
"runtime": "nodejs20.x",
|
||||
"handler": "index.handler",
|
||||
"timeout": 30,
|
||||
"memory": 256,
|
||||
"environment": {
|
||||
"NODE_ENV": "production"
|
||||
},
|
||||
"triggers": [
|
||||
{
|
||||
"id": "trigger-1",
|
||||
"type": "http",
|
||||
"config": {
|
||||
"method": "POST",
|
||||
"path": "/api/process-user"
|
||||
}
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-playwright-tests": [
|
||||
{
|
||||
"id": "test-1",
|
||||
"name": "User Login Flow",
|
||||
"description": "Test user authentication flow",
|
||||
"pageUrl": "/login",
|
||||
"steps": [
|
||||
{
|
||||
"id": "step-1",
|
||||
"action": "navigate",
|
||||
"value": "/login"
|
||||
},
|
||||
{
|
||||
"id": "step-2",
|
||||
"action": "fill",
|
||||
"selector": "#email",
|
||||
"value": "test@example.com"
|
||||
},
|
||||
{
|
||||
"id": "step-3",
|
||||
"action": "fill",
|
||||
"selector": "#password",
|
||||
"value": "password123"
|
||||
},
|
||||
{
|
||||
"id": "step-4",
|
||||
"action": "click",
|
||||
"selector": "button[type='submit']"
|
||||
},
|
||||
{
|
||||
"id": "step-5",
|
||||
"action": "expect",
|
||||
"selector": ".dashboard",
|
||||
"assertion": "toBeVisible"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-storybook-stories": [
|
||||
{
|
||||
"id": "story-1",
|
||||
"componentName": "Button",
|
||||
"storyName": "Primary",
|
||||
"args": {
|
||||
"variant": "primary",
|
||||
"children": "Click me",
|
||||
"disabled": false
|
||||
},
|
||||
"description": "Primary button variant",
|
||||
"category": "Components"
|
||||
},
|
||||
{
|
||||
"id": "story-2",
|
||||
"componentName": "Card",
|
||||
"storyName": "Default",
|
||||
"args": {
|
||||
"title": "Card Title",
|
||||
"description": "Card description",
|
||||
"elevation": 2
|
||||
},
|
||||
"description": "Default card component",
|
||||
"category": "Layout"
|
||||
}
|
||||
],
|
||||
"project-unit-tests": [
|
||||
{
|
||||
"id": "test-1",
|
||||
"name": "Button Component Tests",
|
||||
"description": "Unit tests for Button component",
|
||||
"testType": "component",
|
||||
"targetFile": "/src/components/Button.tsx",
|
||||
"testCases": [
|
||||
{
|
||||
"id": "case-1",
|
||||
"description": "renders with correct text",
|
||||
"assertions": [
|
||||
"expect(screen.getByText('Click me')).toBeInTheDocument()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "case-2",
|
||||
"description": "calls onClick handler when clicked",
|
||||
"assertions": [
|
||||
"expect(handleClick).toHaveBeenCalledTimes(1)"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-component-trees": [
|
||||
{
|
||||
"id": "tree-1",
|
||||
"name": "Main App Layout",
|
||||
"description": "Primary application layout tree",
|
||||
"rootNodes": [
|
||||
{
|
||||
"id": "root-1",
|
||||
"type": "Container",
|
||||
"name": "AppContainer",
|
||||
"props": {
|
||||
"maxWidth": "xl"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "header-1",
|
||||
"type": "AppBar",
|
||||
"name": "Header",
|
||||
"props": {
|
||||
"position": "sticky"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "main-1",
|
||||
"type": "Box",
|
||||
"name": "MainContent",
|
||||
"props": {
|
||||
"sx": { "py": 4 }
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
]
|
||||
}
|
||||
65
src/hooks/data/use-seed-data.ts
Normal file
65
src/hooks/data/use-seed-data.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import seedDataConfig from '@/config/seed-data.json'
|
||||
|
||||
export function useSeedData() {
|
||||
const [isLoaded, setIsLoaded] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const loadSeedData = async () => {
|
||||
if (isLoading || isLoaded) return
|
||||
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const keys = await window.spark.kv.keys()
|
||||
|
||||
for (const [key, value] of Object.entries(seedDataConfig)) {
|
||||
if (!keys.includes(key)) {
|
||||
await window.spark.kv.set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
setIsLoaded(true)
|
||||
} catch (error) {
|
||||
console.error('Failed to load seed data:', error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const resetSeedData = async () => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
for (const [key, value] of Object.entries(seedDataConfig)) {
|
||||
await window.spark.kv.set(key, value)
|
||||
}
|
||||
setIsLoaded(true)
|
||||
} catch (error) {
|
||||
console.error('Failed to reset seed data:', error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const clearAllData = async () => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const keys = await window.spark.kv.keys()
|
||||
for (const key of keys) {
|
||||
await window.spark.kv.delete(key)
|
||||
}
|
||||
setIsLoaded(false)
|
||||
} catch (error) {
|
||||
console.error('Failed to clear data:', error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isLoaded,
|
||||
isLoading,
|
||||
loadSeedData,
|
||||
resetSeedData,
|
||||
clearAllData,
|
||||
}
|
||||
}
|
||||
@@ -12,3 +12,4 @@ export * from './config/use-feature-flags'
|
||||
|
||||
export * from './ai/use-ai-generation'
|
||||
|
||||
export * from './data/use-seed-data'
|
||||
|
||||
Reference in New Issue
Block a user