@varity-labs/sdk 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +31 -0
- package/README.md +253 -0
- package/dist/analytics/index.d.ts +7 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +6 -0
- package/dist/analytics/tracker.d.ts +128 -0
- package/dist/analytics/tracker.d.ts.map +1 -0
- package/dist/analytics/tracker.js +203 -0
- package/dist/blockchain/BlockchainService.d.ts +100 -0
- package/dist/blockchain/BlockchainService.d.ts.map +1 -0
- package/dist/blockchain/BlockchainService.js +188 -0
- package/dist/blockchain/NFTLicensingService.d.ts +69 -0
- package/dist/blockchain/NFTLicensingService.d.ts.map +1 -0
- package/dist/blockchain/NFTLicensingService.js +136 -0
- package/dist/blockchain/RevenueSplitService.d.ts +71 -0
- package/dist/blockchain/RevenueSplitService.d.ts.map +1 -0
- package/dist/blockchain/RevenueSplitService.js +111 -0
- package/dist/blockchain/index.d.ts +48 -0
- package/dist/blockchain/index.d.ts.map +1 -0
- package/dist/blockchain/index.js +46 -0
- package/dist/blockchain/types.d.ts +63 -0
- package/dist/blockchain/types.d.ts.map +1 -0
- package/dist/blockchain/types.js +6 -0
- package/dist/chains/arbitrum.d.ts +89 -0
- package/dist/chains/arbitrum.d.ts.map +1 -0
- package/dist/chains/arbitrum.js +134 -0
- package/dist/chains/base.d.ts +84 -0
- package/dist/chains/base.d.ts.map +1 -0
- package/dist/chains/base.js +131 -0
- package/dist/chains/index.d.ts +36 -0
- package/dist/chains/index.d.ts.map +1 -0
- package/dist/chains/index.js +32 -0
- package/dist/chains/registry.d.ts +113 -0
- package/dist/chains/registry.d.ts.map +1 -0
- package/dist/chains/registry.js +201 -0
- package/dist/chains/varityL3.d.ts +81 -0
- package/dist/chains/varityL3.d.ts.map +1 -0
- package/dist/chains/varityL3.js +125 -0
- package/dist/cli/commands/clone.d.ts +8 -0
- package/dist/cli/commands/clone.d.ts.map +1 -0
- package/dist/cli/commands/clone.js +391 -0
- package/dist/cli/commands/dev.d.ts +8 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +40 -0
- package/dist/cli/commands/generate.d.ts +8 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +303 -0
- package/dist/cli/commands/init.d.ts +8 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +317 -0
- package/dist/cli/commands/validate.d.ts +8 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +69 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +33 -0
- package/dist/cli/utils/logger.d.ts +17 -0
- package/dist/cli/utils/logger.d.ts.map +1 -0
- package/dist/cli/utils/logger.js +35 -0
- package/dist/cli/utils/prompts.d.ts +21 -0
- package/dist/cli/utils/prompts.d.ts.map +1 -0
- package/dist/cli/utils/prompts.js +103 -0
- package/dist/contracts/abis/iso/AccessControlRegistry.json +1468 -0
- package/dist/contracts/abis/iso/DataProofRegistry.json +797 -0
- package/dist/contracts/abis/iso/MerchantRegistry.json +1237 -0
- package/dist/contracts/abis/iso/RepPerformance.json +1351 -0
- package/dist/contracts/abis/iso/ResidualCalculator.json +1118 -0
- package/dist/contracts/abis/iso/TransactionVault.json +1588 -0
- package/dist/contracts/abis/iso/VarityWalletFactory.json +475 -0
- package/dist/contracts/addresses.d.ts +88 -0
- package/dist/contracts/addresses.d.ts.map +1 -0
- package/dist/contracts/addresses.js +94 -0
- package/dist/contracts/index.d.ts +7 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +6 -0
- package/dist/core/VaritySDK.d.ts +177 -0
- package/dist/core/VaritySDK.d.ts.map +1 -0
- package/dist/core/VaritySDK.js +325 -0
- package/dist/core/config.d.ts +120 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +187 -0
- package/dist/core/credentials-proxy.d.ts +157 -0
- package/dist/core/credentials-proxy.d.ts.map +1 -0
- package/dist/core/credentials-proxy.js +345 -0
- package/dist/core/credentials.d.ts +219 -0
- package/dist/core/credentials.d.ts.map +1 -0
- package/dist/core/credentials.js +345 -0
- package/dist/core/template-loader.d.ts +15 -0
- package/dist/core/template-loader.d.ts.map +1 -0
- package/dist/core/template-loader.js +380 -0
- package/dist/core/template.d.ts +321 -0
- package/dist/core/template.d.ts.map +1 -0
- package/dist/core/template.js +189 -0
- package/dist/core/types.d.ts +572 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +52 -0
- package/dist/dev/dev-server.d.ts +16 -0
- package/dist/dev/dev-server.d.ts.map +1 -0
- package/dist/dev/dev-server.js +119 -0
- package/dist/generators/contracts/generator.d.ts +21 -0
- package/dist/generators/contracts/generator.d.ts.map +1 -0
- package/dist/generators/contracts/generator.js +252 -0
- package/dist/generators/tests/generator.d.ts +20 -0
- package/dist/generators/tests/generator.d.ts.map +1 -0
- package/dist/generators/tests/generator.js +375 -0
- package/dist/generators/types/generator.d.ts +19 -0
- package/dist/generators/types/generator.d.ts.map +1 -0
- package/dist/generators/types/generator.js +165 -0
- package/dist/generators/ui/component-generator.d.ts +20 -0
- package/dist/generators/ui/component-generator.d.ts.map +1 -0
- package/dist/generators/ui/component-generator.js +749 -0
- package/dist/generators/ui/dashboard-generator.d.ts +20 -0
- package/dist/generators/ui/dashboard-generator.d.ts.map +1 -0
- package/dist/generators/ui/dashboard-generator.js +349 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/modules/analytics/AnalyticsModule.d.ts +349 -0
- package/dist/modules/analytics/AnalyticsModule.d.ts.map +1 -0
- package/dist/modules/analytics/AnalyticsModule.js +274 -0
- package/dist/modules/analytics/index.d.ts +3 -0
- package/dist/modules/analytics/index.d.ts.map +1 -0
- package/dist/modules/analytics/index.js +1 -0
- package/dist/modules/auth/AccessKeyModule.d.ts +189 -0
- package/dist/modules/auth/AccessKeyModule.d.ts.map +1 -0
- package/dist/modules/auth/AccessKeyModule.js +322 -0
- package/dist/modules/auth/AuthModule.d.ts +133 -0
- package/dist/modules/auth/AuthModule.d.ts.map +1 -0
- package/dist/modules/auth/AuthModule.js +214 -0
- package/dist/modules/auth/index.d.ts +8 -0
- package/dist/modules/auth/index.d.ts.map +1 -0
- package/dist/modules/auth/index.js +6 -0
- package/dist/modules/cache/CacheModule.d.ts +279 -0
- package/dist/modules/cache/CacheModule.d.ts.map +1 -0
- package/dist/modules/cache/CacheModule.js +493 -0
- package/dist/modules/cache/index.d.ts +3 -0
- package/dist/modules/cache/index.d.ts.map +1 -0
- package/dist/modules/cache/index.js +1 -0
- package/dist/modules/compute/ComputeModule.d.ts +226 -0
- package/dist/modules/compute/ComputeModule.d.ts.map +1 -0
- package/dist/modules/compute/ComputeModule.js +379 -0
- package/dist/modules/compute/index.d.ts +6 -0
- package/dist/modules/compute/index.d.ts.map +1 -0
- package/dist/modules/compute/index.js +4 -0
- package/dist/modules/contracts/ContractsModule.d.ts +164 -0
- package/dist/modules/contracts/ContractsModule.d.ts.map +1 -0
- package/dist/modules/contracts/ContractsModule.js +242 -0
- package/dist/modules/contracts/index.d.ts +6 -0
- package/dist/modules/contracts/index.d.ts.map +1 -0
- package/dist/modules/contracts/index.js +4 -0
- package/dist/modules/export/ExportModule.d.ts +346 -0
- package/dist/modules/export/ExportModule.d.ts.map +1 -0
- package/dist/modules/export/ExportModule.js +432 -0
- package/dist/modules/export/index.d.ts +3 -0
- package/dist/modules/export/index.d.ts.map +1 -0
- package/dist/modules/export/index.js +1 -0
- package/dist/modules/forecasting/ForecastingModule.d.ts +579 -0
- package/dist/modules/forecasting/ForecastingModule.d.ts.map +1 -0
- package/dist/modules/forecasting/ForecastingModule.js +310 -0
- package/dist/modules/forecasting/index.d.ts +3 -0
- package/dist/modules/forecasting/index.d.ts.map +1 -0
- package/dist/modules/forecasting/index.js +1 -0
- package/dist/modules/monitoring/MonitoringModule.d.ts +359 -0
- package/dist/modules/monitoring/MonitoringModule.d.ts.map +1 -0
- package/dist/modules/monitoring/MonitoringModule.js +483 -0
- package/dist/modules/monitoring/index.d.ts +3 -0
- package/dist/modules/monitoring/index.d.ts.map +1 -0
- package/dist/modules/monitoring/index.js +1 -0
- package/dist/modules/notifications/NotificationsModule.d.ts +336 -0
- package/dist/modules/notifications/NotificationsModule.d.ts.map +1 -0
- package/dist/modules/notifications/NotificationsModule.js +418 -0
- package/dist/modules/notifications/index.d.ts +3 -0
- package/dist/modules/notifications/index.d.ts.map +1 -0
- package/dist/modules/notifications/index.js +1 -0
- package/dist/modules/oracle/OracleModule.d.ts +110 -0
- package/dist/modules/oracle/OracleModule.d.ts.map +1 -0
- package/dist/modules/oracle/OracleModule.js +151 -0
- package/dist/modules/oracle/index.d.ts +6 -0
- package/dist/modules/oracle/index.d.ts.map +1 -0
- package/dist/modules/oracle/index.js +4 -0
- package/dist/modules/storage/S3Module.d.ts +377 -0
- package/dist/modules/storage/S3Module.d.ts.map +1 -0
- package/dist/modules/storage/S3Module.js +680 -0
- package/dist/modules/storage/StorageModule.d.ts +157 -0
- package/dist/modules/storage/StorageModule.d.ts.map +1 -0
- package/dist/modules/storage/StorageModule.js +302 -0
- package/dist/modules/storage/adapters/AdapterFactory.d.ts +100 -0
- package/dist/modules/storage/adapters/AdapterFactory.d.ts.map +1 -0
- package/dist/modules/storage/adapters/AdapterFactory.js +209 -0
- package/dist/modules/storage/adapters/FilecoinAdapter.d.ts +94 -0
- package/dist/modules/storage/adapters/FilecoinAdapter.d.ts.map +1 -0
- package/dist/modules/storage/adapters/FilecoinAdapter.js +263 -0
- package/dist/modules/storage/adapters/IStorageAdapter.d.ts +287 -0
- package/dist/modules/storage/adapters/IStorageAdapter.d.ts.map +1 -0
- package/dist/modules/storage/adapters/IStorageAdapter.js +81 -0
- package/dist/modules/storage/adapters/MultiTierAdapter.d.ts +187 -0
- package/dist/modules/storage/adapters/MultiTierAdapter.d.ts.map +1 -0
- package/dist/modules/storage/adapters/MultiTierAdapter.js +430 -0
- package/dist/modules/storage/adapters/index.d.ts +12 -0
- package/dist/modules/storage/adapters/index.d.ts.map +1 -0
- package/dist/modules/storage/adapters/index.js +12 -0
- package/dist/modules/storage/index.d.ts +16 -0
- package/dist/modules/storage/index.d.ts.map +1 -0
- package/dist/modules/storage/index.js +15 -0
- package/dist/modules/storage/tiering/AccessAnalyzer.d.ts +227 -0
- package/dist/modules/storage/tiering/AccessAnalyzer.d.ts.map +1 -0
- package/dist/modules/storage/tiering/AccessAnalyzer.js +367 -0
- package/dist/modules/storage/tiering/CostOptimizer.d.ts +248 -0
- package/dist/modules/storage/tiering/CostOptimizer.d.ts.map +1 -0
- package/dist/modules/storage/tiering/CostOptimizer.js +356 -0
- package/dist/modules/storage/tiering/MetadataStore.d.ts +287 -0
- package/dist/modules/storage/tiering/MetadataStore.d.ts.map +1 -0
- package/dist/modules/storage/tiering/MetadataStore.js +535 -0
- package/dist/modules/storage/tiering/TieringEngine.d.ts +237 -0
- package/dist/modules/storage/tiering/TieringEngine.d.ts.map +1 -0
- package/dist/modules/storage/tiering/TieringEngine.js +419 -0
- package/dist/modules/storage/tiering/example.d.ts +8 -0
- package/dist/modules/storage/tiering/example.d.ts.map +1 -0
- package/dist/modules/storage/tiering/example.js +250 -0
- package/dist/modules/storage/tiering/index.d.ts +17 -0
- package/dist/modules/storage/tiering/index.d.ts.map +1 -0
- package/dist/modules/storage/tiering/index.js +13 -0
- package/dist/modules/webhooks/WebhooksModule.d.ts +476 -0
- package/dist/modules/webhooks/WebhooksModule.d.ts.map +1 -0
- package/dist/modules/webhooks/WebhooksModule.js +359 -0
- package/dist/modules/webhooks/index.d.ts +3 -0
- package/dist/modules/webhooks/index.d.ts.map +1 -0
- package/dist/modules/webhooks/index.js +1 -0
- package/dist/modules/zk/ZKModule.d.ts +153 -0
- package/dist/modules/zk/ZKModule.d.ts.map +1 -0
- package/dist/modules/zk/ZKModule.js +262 -0
- package/dist/modules/zk/index.d.ts +7 -0
- package/dist/modules/zk/index.d.ts.map +1 -0
- package/dist/modules/zk/index.js +4 -0
- package/dist/thirdweb/BridgeClient.d.ts +228 -0
- package/dist/thirdweb/BridgeClient.d.ts.map +1 -0
- package/dist/thirdweb/BridgeClient.js +160 -0
- package/dist/thirdweb/EngineClient.d.ts +396 -0
- package/dist/thirdweb/EngineClient.d.ts.map +1 -0
- package/dist/thirdweb/EngineClient.js +386 -0
- package/dist/thirdweb/GatewayClient.d.ts +190 -0
- package/dist/thirdweb/GatewayClient.d.ts.map +1 -0
- package/dist/thirdweb/GatewayClient.js +257 -0
- package/dist/thirdweb/NebulaClient.d.ts +292 -0
- package/dist/thirdweb/NebulaClient.d.ts.map +1 -0
- package/dist/thirdweb/NebulaClient.js +180 -0
- package/dist/thirdweb/StorageClient.d.ts +445 -0
- package/dist/thirdweb/StorageClient.d.ts.map +1 -0
- package/dist/thirdweb/StorageClient.js +405 -0
- package/dist/thirdweb/ThirdwebWrapper.d.ts +236 -0
- package/dist/thirdweb/ThirdwebWrapper.d.ts.map +1 -0
- package/dist/thirdweb/ThirdwebWrapper.js +332 -0
- package/dist/thirdweb/index.d.ts +21 -0
- package/dist/thirdweb/index.d.ts.map +1 -0
- package/dist/thirdweb/index.js +28 -0
- package/dist/thirdweb/varity-chain.d.ts +48 -0
- package/dist/thirdweb/varity-chain.d.ts.map +1 -0
- package/dist/thirdweb/varity-chain.js +64 -0
- package/dist/thirdweb/x402Client.d.ts +319 -0
- package/dist/thirdweb/x402Client.d.ts.map +1 -0
- package/dist/thirdweb/x402Client.js +223 -0
- package/dist/tracking/gasTracker.d.ts +158 -0
- package/dist/tracking/gasTracker.d.ts.map +1 -0
- package/dist/tracking/gasTracker.js +227 -0
- package/dist/tracking/index.d.ts +10 -0
- package/dist/tracking/index.d.ts.map +1 -0
- package/dist/tracking/index.js +8 -0
- package/dist/tracking/types.d.ts +327 -0
- package/dist/tracking/types.d.ts.map +1 -0
- package/dist/tracking/types.js +8 -0
- package/dist/ui/components/ChartWidget.d.ts +36 -0
- package/dist/ui/components/ChartWidget.d.ts.map +1 -0
- package/dist/ui/components/ChartWidget.js +82 -0
- package/dist/ui/components/DashboardLayout.d.ts +41 -0
- package/dist/ui/components/DashboardLayout.d.ts.map +1 -0
- package/dist/ui/components/DashboardLayout.js +102 -0
- package/dist/ui/components/DataTable.d.ts +49 -0
- package/dist/ui/components/DataTable.d.ts.map +1 -0
- package/dist/ui/components/DataTable.js +96 -0
- package/dist/ui/components/EntityForm.d.ts +60 -0
- package/dist/ui/components/EntityForm.d.ts.map +1 -0
- package/dist/ui/components/EntityForm.js +182 -0
- package/dist/ui/components/KPICard.d.ts +29 -0
- package/dist/ui/components/KPICard.d.ts.map +1 -0
- package/dist/ui/components/KPICard.js +61 -0
- package/dist/ui/components/Modal.d.ts +34 -0
- package/dist/ui/components/Modal.d.ts.map +1 -0
- package/dist/ui/components/Modal.js +30 -0
- package/dist/ui/components/index.d.ts +18 -0
- package/dist/ui/components/index.d.ts.map +1 -0
- package/dist/ui/components/index.js +11 -0
- package/dist/validation/template-validator.d.ts +25 -0
- package/dist/validation/template-validator.d.ts.map +1 -0
- package/dist/validation/template-validator.js +305 -0
- package/package.json +102 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chart Widget Component
|
|
3
|
+
*
|
|
4
|
+
* Universal chart component supporting multiple chart types
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Card, CardContent, Typography, Box, Skeleton } from '@mui/material';
|
|
8
|
+
import { LineChart, Line, BarChart, Bar, AreaChart, Area, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
|
|
9
|
+
const DEFAULT_COLORS = [
|
|
10
|
+
'#1976d2', // blue
|
|
11
|
+
'#2e7d32', // green
|
|
12
|
+
'#ed6c02', // orange
|
|
13
|
+
'#d32f2f', // red
|
|
14
|
+
'#9c27b0', // purple
|
|
15
|
+
'#0288d1', // light blue
|
|
16
|
+
'#f57c00', // deep orange
|
|
17
|
+
'#c2185b' // pink
|
|
18
|
+
];
|
|
19
|
+
export const ChartWidget = ({ title, type, data, xKey = 'name', yKeys, labels = {}, loading = false, height = 300, colors = DEFAULT_COLORS, showLegend = true, showGrid = true }) => {
|
|
20
|
+
if (loading) {
|
|
21
|
+
return (React.createElement(Card, null,
|
|
22
|
+
React.createElement(CardContent, null,
|
|
23
|
+
React.createElement(Typography, { variant: "h6", gutterBottom: true }, title),
|
|
24
|
+
React.createElement(Skeleton, { variant: "rectangular", height: height }))));
|
|
25
|
+
}
|
|
26
|
+
if (!data || data.length === 0) {
|
|
27
|
+
return (React.createElement(Card, null,
|
|
28
|
+
React.createElement(CardContent, null,
|
|
29
|
+
React.createElement(Typography, { variant: "h6", gutterBottom: true }, title),
|
|
30
|
+
React.createElement(Box, { sx: {
|
|
31
|
+
height,
|
|
32
|
+
display: 'flex',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
color: 'text.secondary'
|
|
36
|
+
} },
|
|
37
|
+
React.createElement(Typography, null, "No data available")))));
|
|
38
|
+
}
|
|
39
|
+
const renderChart = () => {
|
|
40
|
+
switch (type) {
|
|
41
|
+
case 'line':
|
|
42
|
+
return (React.createElement(LineChart, { data: data },
|
|
43
|
+
showGrid && React.createElement(CartesianGrid, { strokeDasharray: "3 3" }),
|
|
44
|
+
React.createElement(XAxis, { dataKey: xKey }),
|
|
45
|
+
React.createElement(YAxis, null),
|
|
46
|
+
React.createElement(Tooltip, null),
|
|
47
|
+
showLegend && React.createElement(Legend, null),
|
|
48
|
+
yKeys.map((key, index) => (React.createElement(Line, { key: key, type: "monotone", dataKey: key, stroke: colors[index % colors.length], strokeWidth: 2, dot: { r: 4 }, activeDot: { r: 6 }, name: labels[key] || key })))));
|
|
49
|
+
case 'bar':
|
|
50
|
+
return (React.createElement(BarChart, { data: data },
|
|
51
|
+
showGrid && React.createElement(CartesianGrid, { strokeDasharray: "3 3" }),
|
|
52
|
+
React.createElement(XAxis, { dataKey: xKey }),
|
|
53
|
+
React.createElement(YAxis, null),
|
|
54
|
+
React.createElement(Tooltip, null),
|
|
55
|
+
showLegend && React.createElement(Legend, null),
|
|
56
|
+
yKeys.map((key, index) => (React.createElement(Bar, { key: key, dataKey: key, fill: colors[index % colors.length], name: labels[key] || key })))));
|
|
57
|
+
case 'area':
|
|
58
|
+
return (React.createElement(AreaChart, { data: data },
|
|
59
|
+
showGrid && React.createElement(CartesianGrid, { strokeDasharray: "3 3" }),
|
|
60
|
+
React.createElement(XAxis, { dataKey: xKey }),
|
|
61
|
+
React.createElement(YAxis, null),
|
|
62
|
+
React.createElement(Tooltip, null),
|
|
63
|
+
showLegend && React.createElement(Legend, null),
|
|
64
|
+
yKeys.map((key, index) => (React.createElement(Area, { key: key, type: "monotone", dataKey: key, stroke: colors[index % colors.length], fill: colors[index % colors.length], fillOpacity: 0.6, name: labels[key] || key })))));
|
|
65
|
+
case 'pie':
|
|
66
|
+
// For pie chart, use first yKey
|
|
67
|
+
const pieDataKey = yKeys[0];
|
|
68
|
+
return (React.createElement(PieChart, null,
|
|
69
|
+
React.createElement(Pie, { data: data, dataKey: pieDataKey, nameKey: xKey, cx: "50%", cy: "50%", outerRadius: 80, label: true }, data.map((_, index) => (React.createElement(Cell, { key: `cell-${index}`, fill: colors[index % colors.length] })))),
|
|
70
|
+
React.createElement(Tooltip, null),
|
|
71
|
+
showLegend && React.createElement(Legend, null)));
|
|
72
|
+
default:
|
|
73
|
+
return React.createElement("div", null,
|
|
74
|
+
"Unsupported chart type: ",
|
|
75
|
+
type);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
return (React.createElement(Card, null,
|
|
79
|
+
React.createElement(CardContent, null,
|
|
80
|
+
React.createElement(Typography, { variant: "h6", gutterBottom: true, sx: { mb: 2 } }, title),
|
|
81
|
+
React.createElement(ResponsiveContainer, { width: "100%", height: height }, renderChart()))));
|
|
82
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Layout Component
|
|
3
|
+
*
|
|
4
|
+
* Responsive dashboard layout with sidebar and header
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
export interface NavigationItem {
|
|
8
|
+
/** Item label */
|
|
9
|
+
label: string;
|
|
10
|
+
/** Item icon */
|
|
11
|
+
icon?: React.ReactNode;
|
|
12
|
+
/** Click handler */
|
|
13
|
+
onClick: () => void;
|
|
14
|
+
/** Active state */
|
|
15
|
+
active?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface DashboardLayoutProps {
|
|
18
|
+
/** Dashboard title */
|
|
19
|
+
title: string;
|
|
20
|
+
/** Navigation items */
|
|
21
|
+
navigation: NavigationItem[];
|
|
22
|
+
/** Children content */
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
/** User info */
|
|
25
|
+
user?: {
|
|
26
|
+
name: string;
|
|
27
|
+
address: string;
|
|
28
|
+
avatar?: string;
|
|
29
|
+
};
|
|
30
|
+
/** User menu items */
|
|
31
|
+
userMenuItems?: Array<{
|
|
32
|
+
label: string;
|
|
33
|
+
onClick: () => void;
|
|
34
|
+
}>;
|
|
35
|
+
/** Logo */
|
|
36
|
+
logo?: React.ReactNode;
|
|
37
|
+
/** Drawer width */
|
|
38
|
+
drawerWidth?: number;
|
|
39
|
+
}
|
|
40
|
+
export declare const DashboardLayout: React.FC<DashboardLayoutProps>;
|
|
41
|
+
//# sourceMappingURL=DashboardLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardLayout.d.ts","sourceRoot":"","sources":["../../../src/ui/components/DashboardLayout.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAA;AA2BvC,MAAM,WAAW,cAAc;IAC7B,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,gBAAgB;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,oBAAoB;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,mBAAmB;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,UAAU,EAAE,cAAc,EAAE,CAAA;IAC5B,uBAAuB;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,gBAAgB;IAChB,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,sBAAsB;IACtB,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,IAAI,CAAA;KACpB,CAAC,CAAA;IACF,WAAW;IACX,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgM1D,CAAA"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Layout Component
|
|
3
|
+
*
|
|
4
|
+
* Responsive dashboard layout with sidebar and header
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from 'react';
|
|
7
|
+
import { Box, Drawer, AppBar, Toolbar, Typography, IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Divider, useTheme, useMediaQuery, Avatar, Menu, MenuItem } from '@mui/material';
|
|
8
|
+
import { Menu as MenuIcon, ChevronLeft as ChevronLeftIcon, Dashboard as DashboardIcon, AccountCircle as AccountIcon } from '@mui/icons-material';
|
|
9
|
+
export const DashboardLayout = ({ title, navigation, children, user, userMenuItems = [], logo, drawerWidth = 240 }) => {
|
|
10
|
+
const theme = useTheme();
|
|
11
|
+
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
12
|
+
const [open, setOpen] = useState(!isMobile);
|
|
13
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
|
14
|
+
const handleDrawerToggle = () => {
|
|
15
|
+
setOpen(!open);
|
|
16
|
+
};
|
|
17
|
+
const handleUserMenuOpen = (event) => {
|
|
18
|
+
setAnchorEl(event.currentTarget);
|
|
19
|
+
};
|
|
20
|
+
const handleUserMenuClose = () => {
|
|
21
|
+
setAnchorEl(null);
|
|
22
|
+
};
|
|
23
|
+
const drawer = (React.createElement(Box, null,
|
|
24
|
+
React.createElement(Toolbar, { sx: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
justifyContent: 'space-between',
|
|
28
|
+
px: [1]
|
|
29
|
+
} },
|
|
30
|
+
logo || (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
31
|
+
React.createElement(DashboardIcon, { color: "primary" }),
|
|
32
|
+
React.createElement(Typography, { variant: "h6", noWrap: true, component: "div", color: "primary" }, title))),
|
|
33
|
+
isMobile && (React.createElement(IconButton, { onClick: handleDrawerToggle },
|
|
34
|
+
React.createElement(ChevronLeftIcon, null)))),
|
|
35
|
+
React.createElement(Divider, null),
|
|
36
|
+
React.createElement(List, null, navigation.map((item, index) => (React.createElement(ListItem, { key: index, disablePadding: true },
|
|
37
|
+
React.createElement(ListItemButton, { onClick: item.onClick, selected: item.active, sx: {
|
|
38
|
+
'&.Mui-selected': {
|
|
39
|
+
backgroundColor: 'primary.light',
|
|
40
|
+
'&:hover': {
|
|
41
|
+
backgroundColor: 'primary.light'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} },
|
|
45
|
+
item.icon && React.createElement(ListItemIcon, null, item.icon),
|
|
46
|
+
React.createElement(ListItemText, { primary: item.label }))))))));
|
|
47
|
+
return (React.createElement(Box, { sx: { display: 'flex', minHeight: '100vh' } },
|
|
48
|
+
React.createElement(AppBar, { position: "fixed", sx: {
|
|
49
|
+
width: { md: `calc(100% - ${open ? drawerWidth : 0}px)` },
|
|
50
|
+
ml: { md: `${open ? drawerWidth : 0}px` },
|
|
51
|
+
transition: theme.transitions.create(['margin', 'width'], {
|
|
52
|
+
easing: theme.transitions.easing.sharp,
|
|
53
|
+
duration: theme.transitions.duration.leavingScreen
|
|
54
|
+
})
|
|
55
|
+
} },
|
|
56
|
+
React.createElement(Toolbar, null,
|
|
57
|
+
React.createElement(IconButton, { color: "inherit", "aria-label": "open drawer", edge: "start", onClick: handleDrawerToggle, sx: { mr: 2 } },
|
|
58
|
+
React.createElement(MenuIcon, null)),
|
|
59
|
+
React.createElement(Typography, { variant: "h6", noWrap: true, component: "div", sx: { flexGrow: 1 } }, title),
|
|
60
|
+
user && (React.createElement(React.Fragment, null,
|
|
61
|
+
React.createElement(IconButton, { size: "large", "aria-label": "account of current user", "aria-controls": "menu-appbar", "aria-haspopup": "true", onClick: handleUserMenuOpen, color: "inherit" }, user.avatar ? (React.createElement(Avatar, { src: user.avatar, alt: user.name })) : (React.createElement(AccountIcon, null))),
|
|
62
|
+
React.createElement(Menu, { id: "menu-appbar", anchorEl: anchorEl, anchorOrigin: {
|
|
63
|
+
vertical: 'bottom',
|
|
64
|
+
horizontal: 'right'
|
|
65
|
+
}, keepMounted: true, transformOrigin: {
|
|
66
|
+
vertical: 'top',
|
|
67
|
+
horizontal: 'right'
|
|
68
|
+
}, open: Boolean(anchorEl), onClose: handleUserMenuClose },
|
|
69
|
+
React.createElement(MenuItem, { disabled: true },
|
|
70
|
+
React.createElement(Typography, { variant: "body2", color: "text.secondary" }, user.name)),
|
|
71
|
+
React.createElement(MenuItem, { disabled: true },
|
|
72
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary" },
|
|
73
|
+
user.address.slice(0, 6),
|
|
74
|
+
"...",
|
|
75
|
+
user.address.slice(-4))),
|
|
76
|
+
React.createElement(Divider, null),
|
|
77
|
+
userMenuItems.map((item, index) => (React.createElement(MenuItem, { key: index, onClick: () => {
|
|
78
|
+
item.onClick();
|
|
79
|
+
handleUserMenuClose();
|
|
80
|
+
} }, item.label)))))))),
|
|
81
|
+
React.createElement(Drawer, { variant: isMobile ? 'temporary' : 'persistent', open: open, onClose: isMobile ? handleDrawerToggle : undefined, sx: {
|
|
82
|
+
width: drawerWidth,
|
|
83
|
+
flexShrink: 0,
|
|
84
|
+
'& .MuiDrawer-paper': {
|
|
85
|
+
width: drawerWidth,
|
|
86
|
+
boxSizing: 'border-box'
|
|
87
|
+
}
|
|
88
|
+
} }, drawer),
|
|
89
|
+
React.createElement(Box, { component: "main", sx: {
|
|
90
|
+
flexGrow: 1,
|
|
91
|
+
p: 3,
|
|
92
|
+
width: { md: `calc(100% - ${open ? drawerWidth : 0}px)` },
|
|
93
|
+
ml: { md: open ? 0 : `-${drawerWidth}px` },
|
|
94
|
+
transition: theme.transitions.create(['margin', 'width'], {
|
|
95
|
+
easing: theme.transitions.easing.sharp,
|
|
96
|
+
duration: theme.transitions.duration.leavingScreen
|
|
97
|
+
})
|
|
98
|
+
} },
|
|
99
|
+
React.createElement(Toolbar, null),
|
|
100
|
+
" ",
|
|
101
|
+
children)));
|
|
102
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataTable Component
|
|
3
|
+
*
|
|
4
|
+
* Universal data table with sorting, pagination, and actions
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
export interface Column {
|
|
8
|
+
/** Column identifier */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Column label */
|
|
11
|
+
label: string;
|
|
12
|
+
/** Minimum width */
|
|
13
|
+
minWidth?: number;
|
|
14
|
+
/** Alignment */
|
|
15
|
+
align?: 'left' | 'right' | 'center';
|
|
16
|
+
/** Format function */
|
|
17
|
+
format?: (value: any) => React.ReactNode;
|
|
18
|
+
/** Sortable */
|
|
19
|
+
sortable?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface DataTableProps {
|
|
22
|
+
/** Table columns */
|
|
23
|
+
columns: Column[];
|
|
24
|
+
/** Table data */
|
|
25
|
+
data: any[];
|
|
26
|
+
/** Loading state */
|
|
27
|
+
loading?: boolean;
|
|
28
|
+
/** Enable pagination */
|
|
29
|
+
pagination?: boolean;
|
|
30
|
+
/** Rows per page options */
|
|
31
|
+
rowsPerPageOptions?: number[];
|
|
32
|
+
/** Row actions */
|
|
33
|
+
actions?: {
|
|
34
|
+
onView?: (row: any) => void;
|
|
35
|
+
onEdit?: (row: any) => void;
|
|
36
|
+
onDelete?: (row: any) => void;
|
|
37
|
+
custom?: Array<{
|
|
38
|
+
icon: React.ReactNode;
|
|
39
|
+
label: string;
|
|
40
|
+
onClick: (row: any) => void;
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
/** Empty state message */
|
|
44
|
+
emptyMessage?: string;
|
|
45
|
+
/** Click handler for row */
|
|
46
|
+
onRowClick?: (row: any) => void;
|
|
47
|
+
}
|
|
48
|
+
export declare const DataTable: React.FC<DataTableProps>;
|
|
49
|
+
//# sourceMappingURL=DataTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/ui/components/DataTable.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAA;AAwBvC,MAAM,WAAW,MAAM;IACrB,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;IACnC,sBAAsB;IACtB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,KAAK,CAAC,SAAS,CAAA;IACxC,eAAe;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,oBAAoB;IACpB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,iBAAiB;IACjB,IAAI,EAAE,GAAG,EAAE,CAAA;IACX,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,wBAAwB;IACxB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,4BAA4B;IAC5B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC7B,kBAAkB;IAClB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;QAC3B,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;QAC3B,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;QAC7B,MAAM,CAAC,EAAE,KAAK,CAAC;YACb,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;YACrB,KAAK,EAAE,MAAM,CAAA;YACb,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;SAC5B,CAAC,CAAA;KACH,CAAA;IACD,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;CAChC;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA0N9C,CAAA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataTable Component
|
|
3
|
+
*
|
|
4
|
+
* Universal data table with sorting, pagination, and actions
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from 'react';
|
|
7
|
+
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TablePagination, TableSortLabel, Paper, IconButton, Box, Typography, Skeleton } from '@mui/material';
|
|
8
|
+
import { Edit as EditIcon, Delete as DeleteIcon, Visibility as ViewIcon } from '@mui/icons-material';
|
|
9
|
+
export const DataTable = ({ columns, data, loading = false, pagination = true, rowsPerPageOptions = [10, 25, 50, 100], actions, emptyMessage = 'No data available', onRowClick }) => {
|
|
10
|
+
const [page, setPage] = useState(0);
|
|
11
|
+
const [rowsPerPage, setRowsPerPage] = useState(rowsPerPageOptions[0]);
|
|
12
|
+
const [orderBy, setOrderBy] = useState('');
|
|
13
|
+
const [order, setOrder] = useState('asc');
|
|
14
|
+
const handleChangePage = (_event, newPage) => {
|
|
15
|
+
setPage(newPage);
|
|
16
|
+
};
|
|
17
|
+
const handleChangeRowsPerPage = (event) => {
|
|
18
|
+
setRowsPerPage(parseInt(event.target.value, 10));
|
|
19
|
+
setPage(0);
|
|
20
|
+
};
|
|
21
|
+
const handleSort = (columnId) => {
|
|
22
|
+
const isAsc = orderBy === columnId && order === 'asc';
|
|
23
|
+
setOrder(isAsc ? 'desc' : 'asc');
|
|
24
|
+
setOrderBy(columnId);
|
|
25
|
+
};
|
|
26
|
+
const sortedData = React.useMemo(() => {
|
|
27
|
+
if (!orderBy)
|
|
28
|
+
return data;
|
|
29
|
+
return [...data].sort((a, b) => {
|
|
30
|
+
const aValue = a[orderBy];
|
|
31
|
+
const bValue = b[orderBy];
|
|
32
|
+
if (aValue === bValue)
|
|
33
|
+
return 0;
|
|
34
|
+
const comparison = aValue < bValue ? -1 : 1;
|
|
35
|
+
return order === 'asc' ? comparison : -comparison;
|
|
36
|
+
});
|
|
37
|
+
}, [data, order, orderBy]);
|
|
38
|
+
const paginatedData = pagination
|
|
39
|
+
? sortedData.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
|
40
|
+
: sortedData;
|
|
41
|
+
if (loading) {
|
|
42
|
+
return (React.createElement(TableContainer, { component: Paper },
|
|
43
|
+
React.createElement(Table, null,
|
|
44
|
+
React.createElement(TableHead, null,
|
|
45
|
+
React.createElement(TableRow, null,
|
|
46
|
+
columns.map((column) => (React.createElement(TableCell, { key: column.id, align: column.align || 'left' },
|
|
47
|
+
React.createElement(Skeleton, { variant: "text" })))),
|
|
48
|
+
actions && React.createElement(TableCell, null, "Actions"))),
|
|
49
|
+
React.createElement(TableBody, null, [...Array(5)].map((_, index) => (React.createElement(TableRow, { key: index },
|
|
50
|
+
columns.map((column) => (React.createElement(TableCell, { key: column.id },
|
|
51
|
+
React.createElement(Skeleton, { variant: "text" })))),
|
|
52
|
+
actions && (React.createElement(TableCell, null,
|
|
53
|
+
React.createElement(Skeleton, { variant: "circular", width: 32, height: 32 }))))))))));
|
|
54
|
+
}
|
|
55
|
+
if (data.length === 0) {
|
|
56
|
+
return (React.createElement(Paper, { sx: { p: 4, textAlign: 'center' } },
|
|
57
|
+
React.createElement(Typography, { variant: "body1", color: "text.secondary" }, emptyMessage)));
|
|
58
|
+
}
|
|
59
|
+
return (React.createElement(Paper, null,
|
|
60
|
+
React.createElement(TableContainer, null,
|
|
61
|
+
React.createElement(Table, { stickyHeader: true },
|
|
62
|
+
React.createElement(TableHead, null,
|
|
63
|
+
React.createElement(TableRow, null,
|
|
64
|
+
columns.map((column) => (React.createElement(TableCell, { key: column.id, align: column.align || 'left', style: { minWidth: column.minWidth } }, column.sortable !== false ? (React.createElement(TableSortLabel, { active: orderBy === column.id, direction: orderBy === column.id ? order : 'asc', onClick: () => handleSort(column.id) }, column.label)) : (column.label)))),
|
|
65
|
+
actions && (React.createElement(TableCell, { align: "right", style: { minWidth: 120 } }, "Actions")))),
|
|
66
|
+
React.createElement(TableBody, null, paginatedData.map((row, index) => (React.createElement(TableRow, { hover: true, key: index, onClick: () => onRowClick?.(row), sx: {
|
|
67
|
+
cursor: onRowClick ? 'pointer' : 'default',
|
|
68
|
+
'&:last-child td, &:last-child th': { border: 0 }
|
|
69
|
+
} },
|
|
70
|
+
columns.map((column) => {
|
|
71
|
+
const value = row[column.id];
|
|
72
|
+
return (React.createElement(TableCell, { key: column.id, align: column.align || 'left' }, column.format ? column.format(value) : value));
|
|
73
|
+
}),
|
|
74
|
+
actions && (React.createElement(TableCell, { align: "right" },
|
|
75
|
+
React.createElement(Box, { sx: { display: 'flex', gap: 0.5, justifyContent: 'flex-end' } },
|
|
76
|
+
actions.onView && (React.createElement(IconButton, { size: "small", onClick: (e) => {
|
|
77
|
+
e.stopPropagation();
|
|
78
|
+
actions.onView(row);
|
|
79
|
+
}, title: "View" },
|
|
80
|
+
React.createElement(ViewIcon, { fontSize: "small" }))),
|
|
81
|
+
actions.onEdit && (React.createElement(IconButton, { size: "small", onClick: (e) => {
|
|
82
|
+
e.stopPropagation();
|
|
83
|
+
actions.onEdit(row);
|
|
84
|
+
}, title: "Edit" },
|
|
85
|
+
React.createElement(EditIcon, { fontSize: "small" }))),
|
|
86
|
+
actions.onDelete && (React.createElement(IconButton, { size: "small", color: "error", onClick: (e) => {
|
|
87
|
+
e.stopPropagation();
|
|
88
|
+
actions.onDelete(row);
|
|
89
|
+
}, title: "Delete" },
|
|
90
|
+
React.createElement(DeleteIcon, { fontSize: "small" }))),
|
|
91
|
+
actions.custom?.map((action, idx) => (React.createElement(IconButton, { key: idx, size: "small", onClick: (e) => {
|
|
92
|
+
e.stopPropagation();
|
|
93
|
+
action.onClick(row);
|
|
94
|
+
}, title: action.label }, action.icon)))))))))))),
|
|
95
|
+
pagination && (React.createElement(TablePagination, { rowsPerPageOptions: rowsPerPageOptions, component: "div", count: data.length, rowsPerPage: rowsPerPage, page: page, onPageChange: handleChangePage, onRowsPerPageChange: handleChangeRowsPerPage }))));
|
|
96
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Form Component
|
|
3
|
+
*
|
|
4
|
+
* Dynamic form generator based on entity field configuration
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
export interface FormField {
|
|
8
|
+
/** Field name/id */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Field label */
|
|
11
|
+
label: string;
|
|
12
|
+
/** Field type - Universal support for all industries */
|
|
13
|
+
type: 'string' | 'number' | 'boolean' | 'enum' | 'array' | 'object' | 'currency' | 'decimal' | 'percentage' | 'date' | 'time' | 'datetime' | 'duration' | 'email' | 'phone' | 'url' | 'address' | 'ssn' | 'tax-id' | 'medical-code' | 'sku' | 'barcode' | 'rich-text' | 'markdown' | 'json' | 'file' | 'image' | 'document' | 'lookup' | 'multi-select' | 'coordinates' | 'color' | 'ip-address' | 'bytes' | 'bytes32';
|
|
14
|
+
/** Required field */
|
|
15
|
+
required?: boolean;
|
|
16
|
+
/** Help text */
|
|
17
|
+
helperText?: string;
|
|
18
|
+
/** Enum options (for enum/multi-select types) */
|
|
19
|
+
enumValues?: string[];
|
|
20
|
+
/** Validation rules */
|
|
21
|
+
validation?: {
|
|
22
|
+
min?: number;
|
|
23
|
+
max?: number;
|
|
24
|
+
minLength?: number;
|
|
25
|
+
maxLength?: number;
|
|
26
|
+
pattern?: string;
|
|
27
|
+
precision?: number;
|
|
28
|
+
fileTypes?: string[];
|
|
29
|
+
maxFileSize?: number;
|
|
30
|
+
custom?: (value: any) => string | null;
|
|
31
|
+
};
|
|
32
|
+
/** Default value */
|
|
33
|
+
defaultValue?: any;
|
|
34
|
+
/** Disabled state */
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
/** Placeholder text */
|
|
37
|
+
placeholder?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface EntityFormProps {
|
|
40
|
+
/** Form fields */
|
|
41
|
+
fields: FormField[];
|
|
42
|
+
/** Form title */
|
|
43
|
+
title?: string;
|
|
44
|
+
/** Submit button text */
|
|
45
|
+
submitText?: string;
|
|
46
|
+
/** Cancel button text */
|
|
47
|
+
cancelText?: string;
|
|
48
|
+
/** Submit handler */
|
|
49
|
+
onSubmit: (data: Record<string, any>) => Promise<void> | void;
|
|
50
|
+
/** Cancel handler */
|
|
51
|
+
onCancel?: () => void;
|
|
52
|
+
/** Initial data (for edit mode) */
|
|
53
|
+
initialData?: Record<string, any>;
|
|
54
|
+
/** Loading state */
|
|
55
|
+
loading?: boolean;
|
|
56
|
+
/** Grid columns (2 or 1) */
|
|
57
|
+
columns?: 1 | 2;
|
|
58
|
+
}
|
|
59
|
+
export declare const EntityForm: React.FC<EntityFormProps>;
|
|
60
|
+
//# sourceMappingURL=EntityForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntityForm.d.ts","sourceRoot":"","sources":["../../../src/ui/components/EntityForm.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAA;AAoBvC,MAAM,WAAW,SAAS;IACxB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,IAAI,EACA,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAC7D,UAAU,GAAG,SAAS,GAAG,YAAY,GACrC,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,GACzC,OAAO,GAAG,OAAO,GAAG,KAAK,GACzB,SAAS,GACT,KAAK,GAAG,QAAQ,GAAG,cAAc,GAAG,KAAK,GAAG,SAAS,GACrD,WAAW,GAAG,UAAU,GAAG,MAAM,GACjC,MAAM,GAAG,OAAO,GAAG,UAAU,GAC7B,QAAQ,GAAG,cAAc,GAAG,aAAa,GAAG,OAAO,GAAG,YAAY,GAClE,OAAO,GAAG,SAAS,CAAA;IACvB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gBAAgB;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,uBAAuB;IACvB,UAAU,CAAC,EAAE;QACX,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;QACpB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,CAAA;KACvC,CAAA;IACD,oBAAoB;IACpB,YAAY,CAAC,EAAE,GAAG,CAAA;IAClB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,kBAAkB;IAClB,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yBAAyB;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yBAAyB;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qBAAqB;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC7D,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACjC,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CAChB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAsXhD,CAAA"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Form Component
|
|
3
|
+
*
|
|
4
|
+
* Dynamic form generator based on entity field configuration
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from 'react';
|
|
7
|
+
import { TextField, Select, MenuItem, FormControl, InputLabel, FormHelperText, Checkbox, FormControlLabel, Button, Box, Grid, Typography, Alert } from '@mui/material';
|
|
8
|
+
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
|
9
|
+
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
10
|
+
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|
11
|
+
export const EntityForm = ({ fields, title, submitText = 'Submit', cancelText = 'Cancel', onSubmit, onCancel, initialData = {}, loading = false, columns = 2 }) => {
|
|
12
|
+
const [formData, setFormData] = useState(fields.reduce((acc, field) => ({
|
|
13
|
+
...acc,
|
|
14
|
+
[field.name]: initialData[field.name] ?? field.defaultValue ?? ''
|
|
15
|
+
}), {}));
|
|
16
|
+
const [errors, setErrors] = useState({});
|
|
17
|
+
const [submitError, setSubmitError] = useState('');
|
|
18
|
+
const validateField = (field, value) => {
|
|
19
|
+
if (field.required && !value) {
|
|
20
|
+
return `${field.label} is required`;
|
|
21
|
+
}
|
|
22
|
+
if (field.validation) {
|
|
23
|
+
const { min, max, pattern, custom } = field.validation;
|
|
24
|
+
if (field.type === 'number') {
|
|
25
|
+
const numValue = Number(value);
|
|
26
|
+
if (min !== undefined && numValue < min) {
|
|
27
|
+
return `${field.label} must be at least ${min}`;
|
|
28
|
+
}
|
|
29
|
+
if (max !== undefined && numValue > max) {
|
|
30
|
+
return `${field.label} must be at most ${max}`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (field.type === 'string' && pattern && value) {
|
|
34
|
+
const regex = new RegExp(pattern);
|
|
35
|
+
if (!regex.test(value)) {
|
|
36
|
+
return `${field.label} format is invalid`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (custom) {
|
|
40
|
+
const customError = custom(value);
|
|
41
|
+
if (customError)
|
|
42
|
+
return customError;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (field.type === 'address' && value) {
|
|
46
|
+
const addressRegex = /^0x[a-fA-F0-9]{40}$/;
|
|
47
|
+
if (!addressRegex.test(value)) {
|
|
48
|
+
return 'Invalid Ethereum address';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
};
|
|
53
|
+
const handleChange = (fieldName, value) => {
|
|
54
|
+
setFormData(prev => ({ ...prev, [fieldName]: value }));
|
|
55
|
+
// Clear error for this field
|
|
56
|
+
if (errors[fieldName]) {
|
|
57
|
+
setErrors(prev => {
|
|
58
|
+
const newErrors = { ...prev };
|
|
59
|
+
delete newErrors[fieldName];
|
|
60
|
+
return newErrors;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const handleSubmit = async (e) => {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
setSubmitError('');
|
|
67
|
+
// Validate all fields
|
|
68
|
+
const newErrors = {};
|
|
69
|
+
fields.forEach(field => {
|
|
70
|
+
const error = validateField(field, formData[field.name]);
|
|
71
|
+
if (error) {
|
|
72
|
+
newErrors[field.name] = error;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
if (Object.keys(newErrors).length > 0) {
|
|
76
|
+
setErrors(newErrors);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
await onSubmit(formData);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
setSubmitError(error instanceof Error ? error.message : 'An error occurred');
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const renderField = (field) => {
|
|
87
|
+
const value = formData[field.name] ?? '';
|
|
88
|
+
const error = errors[field.name];
|
|
89
|
+
// Get placeholder based on field type
|
|
90
|
+
const getPlaceholder = () => {
|
|
91
|
+
if (field.placeholder)
|
|
92
|
+
return field.placeholder;
|
|
93
|
+
switch (field.type) {
|
|
94
|
+
case 'address': return '0x...';
|
|
95
|
+
case 'email': return 'user@example.com';
|
|
96
|
+
case 'phone': return '+1 (555) 123-4567';
|
|
97
|
+
case 'url': return 'https://example.com';
|
|
98
|
+
case 'ssn': return '123-45-6789';
|
|
99
|
+
case 'tax-id': return '12-3456789';
|
|
100
|
+
case 'sku': return 'SKU-12345';
|
|
101
|
+
case 'ip-address': return '192.168.1.1';
|
|
102
|
+
case 'coordinates': return '40.7128, -74.0060';
|
|
103
|
+
default: return undefined;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
// Text-based inputs (string and string-like types)
|
|
107
|
+
if (['string', 'address', 'bytes', 'bytes32', 'email', 'phone', 'url',
|
|
108
|
+
'ssn', 'tax-id', 'medical-code', 'sku', 'barcode', 'ip-address',
|
|
109
|
+
'coordinates', 'markdown', 'json'].includes(field.type)) {
|
|
110
|
+
return (React.createElement(TextField, { fullWidth: true, name: field.name, label: field.label, value: value, onChange: (e) => handleChange(field.name, e.target.value), required: field.required, error: !!error, helperText: error || field.helperText, disabled: field.disabled || loading, placeholder: getPlaceholder(), type: field.type === 'email' ? 'email' : field.type === 'url' ? 'url' : 'text' }));
|
|
111
|
+
}
|
|
112
|
+
// Multi-line text inputs
|
|
113
|
+
if (['rich-text', 'time', 'duration'].includes(field.type)) {
|
|
114
|
+
return (React.createElement(TextField, { fullWidth: true, multiline: true, rows: field.type === 'rich-text' ? 6 : 3, name: field.name, label: field.label, value: value, onChange: (e) => handleChange(field.name, e.target.value), required: field.required, error: !!error, helperText: error || field.helperText, disabled: field.disabled || loading }));
|
|
115
|
+
}
|
|
116
|
+
// Number-based inputs
|
|
117
|
+
if (['number', 'currency', 'decimal', 'percentage'].includes(field.type)) {
|
|
118
|
+
return (React.createElement(TextField, { fullWidth: true, type: "number", name: field.name, label: field.label, value: value, onChange: (e) => handleChange(field.name, e.target.value), required: field.required, error: !!error, helperText: error || field.helperText, disabled: field.disabled || loading, inputProps: {
|
|
119
|
+
step: field.type === 'currency' ? '0.01' : field.type === 'decimal' ? '0.001' : '1',
|
|
120
|
+
min: field.validation?.min,
|
|
121
|
+
max: field.validation?.max
|
|
122
|
+
} }));
|
|
123
|
+
}
|
|
124
|
+
// Boolean checkbox
|
|
125
|
+
if (field.type === 'boolean') {
|
|
126
|
+
return (React.createElement(FormControlLabel, { control: React.createElement(Checkbox, { checked: !!value, onChange: (e) => handleChange(field.name, e.target.checked), disabled: field.disabled || loading }), label: field.label }));
|
|
127
|
+
}
|
|
128
|
+
// Enum/Select dropdown
|
|
129
|
+
if (field.type === 'enum') {
|
|
130
|
+
return (React.createElement(FormControl, { fullWidth: true, error: !!error, disabled: field.disabled || loading },
|
|
131
|
+
React.createElement(InputLabel, null, field.label),
|
|
132
|
+
React.createElement(Select, { value: value, label: field.label, onChange: (e) => handleChange(field.name, e.target.value), required: field.required }, field.enumValues?.map((option) => (React.createElement(MenuItem, { key: option, value: option }, option)))),
|
|
133
|
+
(error || field.helperText) && (React.createElement(FormHelperText, null, error || field.helperText))));
|
|
134
|
+
}
|
|
135
|
+
// Multi-select
|
|
136
|
+
if (field.type === 'multi-select') {
|
|
137
|
+
return (React.createElement(FormControl, { fullWidth: true, error: !!error, disabled: field.disabled || loading },
|
|
138
|
+
React.createElement(InputLabel, null, field.label),
|
|
139
|
+
React.createElement(Select, { multiple: true, value: Array.isArray(value) ? value : [], label: field.label, onChange: (e) => handleChange(field.name, e.target.value), required: field.required }, field.enumValues?.map((option) => (React.createElement(MenuItem, { key: option, value: option }, option)))),
|
|
140
|
+
(error || field.helperText) && (React.createElement(FormHelperText, null, error || field.helperText))));
|
|
141
|
+
}
|
|
142
|
+
// Date picker
|
|
143
|
+
if (['date', 'datetime'].includes(field.type)) {
|
|
144
|
+
return (React.createElement(LocalizationProvider, { dateAdapter: AdapterDateFns },
|
|
145
|
+
React.createElement(DatePicker, { label: field.label, value: value ? new Date(value) : null, onChange: (date) => handleChange(field.name, date?.getTime()), disabled: field.disabled || loading, slotProps: {
|
|
146
|
+
textField: {
|
|
147
|
+
fullWidth: true,
|
|
148
|
+
required: field.required,
|
|
149
|
+
error: !!error,
|
|
150
|
+
helperText: error || field.helperText
|
|
151
|
+
}
|
|
152
|
+
} })));
|
|
153
|
+
}
|
|
154
|
+
// Color picker
|
|
155
|
+
if (field.type === 'color') {
|
|
156
|
+
return (React.createElement(TextField, { fullWidth: true, type: "color", name: field.name, label: field.label, value: value, onChange: (e) => handleChange(field.name, e.target.value), required: field.required, error: !!error, helperText: error || field.helperText, disabled: field.disabled || loading }));
|
|
157
|
+
}
|
|
158
|
+
// File/Image/Document upload
|
|
159
|
+
if (['file', 'image', 'document'].includes(field.type)) {
|
|
160
|
+
return (React.createElement(Box, null,
|
|
161
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true },
|
|
162
|
+
field.label,
|
|
163
|
+
" ",
|
|
164
|
+
field.required && '*'),
|
|
165
|
+
React.createElement(TextField, { fullWidth: true, type: "file", name: field.name, onChange: (e) => {
|
|
166
|
+
const file = e.target.files?.[0];
|
|
167
|
+
handleChange(field.name, file);
|
|
168
|
+
}, required: field.required, error: !!error, helperText: error || field.helperText, disabled: field.disabled || loading, inputProps: {
|
|
169
|
+
accept: field.validation?.fileTypes?.join(',')
|
|
170
|
+
} })));
|
|
171
|
+
}
|
|
172
|
+
// Fallback for unsupported types (array, object, lookup)
|
|
173
|
+
return (React.createElement(TextField, { fullWidth: true, name: field.name, label: field.label, value: value, onChange: (e) => handleChange(field.name, e.target.value), required: field.required, error: !!error, helperText: error || `${field.type} field type - advanced configuration needed`, disabled: field.disabled || loading, placeholder: `Enter ${field.type} value...` }));
|
|
174
|
+
};
|
|
175
|
+
return (React.createElement(Box, { component: "form", onSubmit: handleSubmit },
|
|
176
|
+
title && (React.createElement(Typography, { variant: "h6", gutterBottom: true }, title)),
|
|
177
|
+
submitError && (React.createElement(Alert, { severity: "error", sx: { mb: 2 } }, submitError)),
|
|
178
|
+
React.createElement(Grid, { container: true, spacing: 2 }, fields.map((field) => (React.createElement(Grid, { item: true, xs: 12, md: columns === 2 ? 6 : 12, key: field.name }, renderField(field))))),
|
|
179
|
+
React.createElement(Box, { sx: { mt: 3, display: 'flex', gap: 2, justifyContent: 'flex-end' } },
|
|
180
|
+
onCancel && (React.createElement(Button, { variant: "outlined", onClick: onCancel, disabled: loading }, cancelText)),
|
|
181
|
+
React.createElement(Button, { type: "submit", variant: "contained", disabled: loading }, loading ? 'Submitting...' : submitText))));
|
|
182
|
+
};
|