@friggframework/devtools 2.0.0-next.3 → 2.0.0-next.30
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/frigg-cli/.eslintrc.js +141 -0
- package/frigg-cli/__tests__/jest.config.js +102 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
- package/frigg-cli/__tests__/utils/command-tester.js +170 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +286 -0
- package/frigg-cli/build-command/index.js +54 -0
- package/frigg-cli/deploy-command/index.js +36 -0
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +332 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/generate-iam-command.js +115 -0
- package/frigg-cli/index.js +47 -1
- package/frigg-cli/index.test.js +1 -4
- package/frigg-cli/init-command/backend-first-handler.js +756 -0
- package/frigg-cli/init-command/index.js +93 -0
- package/frigg-cli/init-command/template-handler.js +143 -0
- package/frigg-cli/install-command/index.js +1 -4
- package/frigg-cli/package.json +51 -0
- package/frigg-cli/start-command/index.js +24 -4
- package/frigg-cli/test/init-command.test.js +180 -0
- package/frigg-cli/test/npm-registry.test.js +319 -0
- package/frigg-cli/ui-command/index.js +154 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +16 -17
- package/frigg-cli/utils/npm-registry.js +167 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +245 -0
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +596 -0
- package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
- package/infrastructure/GENERATE-IAM-DOCS.md +253 -0
- package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
- package/infrastructure/README-TESTING.md +332 -0
- package/infrastructure/README.md +421 -0
- package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
- package/infrastructure/__tests__/helpers/test-utils.js +277 -0
- package/infrastructure/aws-discovery.js +568 -0
- package/infrastructure/aws-discovery.test.js +373 -0
- package/infrastructure/build-time-discovery.js +206 -0
- package/infrastructure/build-time-discovery.test.js +375 -0
- package/infrastructure/create-frigg-infrastructure.js +3 -5
- package/infrastructure/frigg-deployment-iam-stack.yaml +379 -0
- package/infrastructure/iam-generator.js +687 -0
- package/infrastructure/iam-generator.test.js +169 -0
- package/infrastructure/iam-policy-basic.json +212 -0
- package/infrastructure/iam-policy-full.json +282 -0
- package/infrastructure/integration.test.js +383 -0
- package/infrastructure/run-discovery.js +110 -0
- package/infrastructure/serverless-template.js +923 -113
- package/infrastructure/serverless-template.test.js +541 -0
- package/management-ui/.eslintrc.js +22 -0
- package/management-ui/README.md +203 -0
- package/management-ui/components.json +21 -0
- package/management-ui/docs/phase2-integration-guide.md +320 -0
- package/management-ui/index.html +13 -0
- package/management-ui/package-lock.json +16517 -0
- package/management-ui/package.json +76 -0
- package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
- package/management-ui/postcss.config.js +6 -0
- package/management-ui/server/api/backend.js +256 -0
- package/management-ui/server/api/cli.js +315 -0
- package/management-ui/server/api/codegen.js +663 -0
- package/management-ui/server/api/connections.js +857 -0
- package/management-ui/server/api/discovery.js +185 -0
- package/management-ui/server/api/environment/index.js +1 -0
- package/management-ui/server/api/environment/router.js +378 -0
- package/management-ui/server/api/environment.js +328 -0
- package/management-ui/server/api/integrations.js +876 -0
- package/management-ui/server/api/logs.js +248 -0
- package/management-ui/server/api/monitoring.js +282 -0
- package/management-ui/server/api/open-ide.js +31 -0
- package/management-ui/server/api/project.js +1029 -0
- package/management-ui/server/api/users/sessions.js +371 -0
- package/management-ui/server/api/users/simulation.js +254 -0
- package/management-ui/server/api/users.js +362 -0
- package/management-ui/server/api-contract.md +275 -0
- package/management-ui/server/index.js +873 -0
- package/management-ui/server/middleware/errorHandler.js +93 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +346 -0
- package/management-ui/server/services/aws-monitor.js +413 -0
- package/management-ui/server/services/npm-registry.js +347 -0
- package/management-ui/server/services/template-engine.js +538 -0
- package/management-ui/server/utils/cliIntegration.js +220 -0
- package/management-ui/server/utils/environment/auditLogger.js +471 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
- package/management-ui/server/utils/environment/encryption.js +278 -0
- package/management-ui/server/utils/environment/envFileManager.js +286 -0
- package/management-ui/server/utils/import-commonjs.js +28 -0
- package/management-ui/server/utils/response.js +83 -0
- package/management-ui/server/websocket/handler.js +325 -0
- package/management-ui/src/App.jsx +109 -0
- package/management-ui/src/assets/FriggLogo.svg +1 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +70 -0
- package/management-ui/src/components/Card.jsx +97 -0
- package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
- package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
- package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
- package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
- package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
- package/management-ui/src/components/ErrorBoundary.jsx +73 -0
- package/management-ui/src/components/IntegrationCard.jsx +481 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +336 -0
- package/management-ui/src/components/Layout.jsx +716 -0
- package/management-ui/src/components/LoadingSpinner.jsx +113 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +350 -0
- package/management-ui/src/components/StatusBadge.jsx +208 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
- package/management-ui/src/components/UserSimulation.jsx +327 -0
- package/management-ui/src/components/Welcome.jsx +434 -0
- package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
- package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
- package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
- package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
- package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
- package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
- package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
- package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
- package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
- package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
- package/management-ui/src/components/codegen/index.js +10 -0
- package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
- package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
- package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
- package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
- package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
- package/management-ui/src/components/connections/index.js +5 -0
- package/management-ui/src/components/index.js +21 -0
- package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
- package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
- package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
- package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
- package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
- package/management-ui/src/components/monitoring/index.js +6 -0
- package/management-ui/src/components/monitoring/monitoring.css +218 -0
- package/management-ui/src/components/theme-provider.jsx +52 -0
- package/management-ui/src/components/theme-toggle.jsx +39 -0
- package/management-ui/src/components/ui/badge.tsx +36 -0
- package/management-ui/src/components/ui/button.test.jsx +56 -0
- package/management-ui/src/components/ui/button.tsx +57 -0
- package/management-ui/src/components/ui/card.tsx +76 -0
- package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
- package/management-ui/src/components/ui/select.tsx +157 -0
- package/management-ui/src/components/ui/skeleton.jsx +15 -0
- package/management-ui/src/hooks/useFrigg.jsx +601 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +193 -0
- package/management-ui/src/lib/utils.ts +6 -0
- package/management-ui/src/main.jsx +10 -0
- package/management-ui/src/pages/CodeGeneration.jsx +14 -0
- package/management-ui/src/pages/Connections.jsx +252 -0
- package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
- package/management-ui/src/pages/Dashboard.jsx +311 -0
- package/management-ui/src/pages/Environment.jsx +314 -0
- package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
- package/management-ui/src/pages/IntegrationTest.jsx +742 -0
- package/management-ui/src/pages/Integrations.jsx +253 -0
- package/management-ui/src/pages/Monitoring.jsx +17 -0
- package/management-ui/src/pages/Simulation.jsx +155 -0
- package/management-ui/src/pages/Users.jsx +492 -0
- package/management-ui/src/services/api.js +41 -0
- package/management-ui/src/services/apiModuleService.js +193 -0
- package/management-ui/src/services/websocket-handlers.js +120 -0
- package/management-ui/src/test/api/project.test.js +273 -0
- package/management-ui/src/test/components/Welcome.test.jsx +378 -0
- package/management-ui/src/test/mocks/server.js +178 -0
- package/management-ui/src/test/setup.js +61 -0
- package/management-ui/src/test/utils/test-utils.jsx +134 -0
- package/management-ui/src/utils/repository.js +98 -0
- package/management-ui/src/utils/repository.test.js +118 -0
- package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
- package/management-ui/tailwind.config.js +63 -0
- package/management-ui/tsconfig.json +37 -0
- package/management-ui/tsconfig.node.json +10 -0
- package/management-ui/vite.config.js +26 -0
- package/management-ui/vitest.config.js +38 -0
- package/package.json +16 -9
- package/infrastructure/app-handler-helpers.js +0 -57
- package/infrastructure/backend-utils.js +0 -90
- package/infrastructure/routers/auth.js +0 -26
- package/infrastructure/routers/integration-defined-routers.js +0 -37
- package/infrastructure/routers/middleware/loadUser.js +0 -15
- package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
- package/infrastructure/routers/user.js +0 -41
- package/infrastructure/routers/websocket.js +0 -55
- package/infrastructure/workers/integration-defined-workers.js +0 -24
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import { Card } from '../Card';
|
|
3
|
+
import { Button } from '../Button';
|
|
4
|
+
|
|
5
|
+
const PROJECT_TEMPLATES = {
|
|
6
|
+
'basic-backend': {
|
|
7
|
+
name: 'Basic Backend',
|
|
8
|
+
description: 'Simple Frigg backend with core functionality',
|
|
9
|
+
features: ['Express server', 'MongoDB integration', 'Basic authentication', 'Environment configuration']
|
|
10
|
+
},
|
|
11
|
+
'microservices': {
|
|
12
|
+
name: 'Microservices',
|
|
13
|
+
description: 'Multi-service architecture with API Gateway',
|
|
14
|
+
features: ['API Gateway', 'Service discovery', 'Load balancing', 'Circuit breakers']
|
|
15
|
+
},
|
|
16
|
+
'serverless': {
|
|
17
|
+
name: 'Serverless',
|
|
18
|
+
description: 'AWS Lambda-based serverless backend',
|
|
19
|
+
features: ['Lambda functions', 'API Gateway', 'DynamoDB', 'CloudWatch logging']
|
|
20
|
+
},
|
|
21
|
+
'full-stack': {
|
|
22
|
+
name: 'Full Stack',
|
|
23
|
+
description: 'Complete application with frontend and backend',
|
|
24
|
+
features: ['React frontend', 'Express backend', 'Database integration', 'Authentication']
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const INTEGRATION_OPTIONS = [
|
|
29
|
+
{ id: 'hubspot', name: 'HubSpot', category: 'CRM' },
|
|
30
|
+
{ id: 'salesforce', name: 'Salesforce', category: 'CRM' },
|
|
31
|
+
{ id: 'slack', name: 'Slack', category: 'Communication' },
|
|
32
|
+
{ id: 'mailchimp', name: 'Mailchimp', category: 'Marketing' },
|
|
33
|
+
{ id: 'stripe', name: 'Stripe', category: 'Payments' },
|
|
34
|
+
{ id: 'twilio', name: 'Twilio', category: 'Communication' },
|
|
35
|
+
{ id: 'google-analytics', name: 'Google Analytics', category: 'Analytics' },
|
|
36
|
+
{ id: 'microsoft-teams', name: 'Microsoft Teams', category: 'Communication' }
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const DATABASE_OPTIONS = [
|
|
40
|
+
{ value: 'mongodb', label: 'MongoDB', description: 'Document database' },
|
|
41
|
+
{ value: 'postgresql', label: 'PostgreSQL', description: 'Relational database' },
|
|
42
|
+
{ value: 'mysql', label: 'MySQL', description: 'Relational database' },
|
|
43
|
+
{ value: 'dynamodb', label: 'DynamoDB', description: 'AWS NoSQL database' },
|
|
44
|
+
{ value: 'redis', label: 'Redis', description: 'In-memory cache' }
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const ProjectScaffoldWizard = ({ onGenerate }) => {
|
|
48
|
+
const [projectData, setProjectData] = useState({
|
|
49
|
+
name: '',
|
|
50
|
+
description: '',
|
|
51
|
+
template: 'basic-backend',
|
|
52
|
+
database: 'mongodb',
|
|
53
|
+
integrations: [],
|
|
54
|
+
features: {
|
|
55
|
+
authentication: true,
|
|
56
|
+
logging: true,
|
|
57
|
+
monitoring: true,
|
|
58
|
+
testing: true,
|
|
59
|
+
docker: true,
|
|
60
|
+
ci: false
|
|
61
|
+
},
|
|
62
|
+
deployment: {
|
|
63
|
+
platform: 'aws',
|
|
64
|
+
environment: 'development'
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
69
|
+
|
|
70
|
+
const steps = [
|
|
71
|
+
{ title: 'Project Info', description: 'Basic project configuration' },
|
|
72
|
+
{ title: 'Template', description: 'Choose project template' },
|
|
73
|
+
{ title: 'Database', description: 'Select database options' },
|
|
74
|
+
{ title: 'Integrations', description: 'Choose integrations' },
|
|
75
|
+
{ title: 'Features', description: 'Enable additional features' },
|
|
76
|
+
{ title: 'Deployment', description: 'Deployment configuration' }
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const handleInputChange = useCallback((field, value) => {
|
|
80
|
+
setProjectData(prev => ({
|
|
81
|
+
...prev,
|
|
82
|
+
[field]: value
|
|
83
|
+
}));
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
const handleFeatureToggle = useCallback((feature) => {
|
|
87
|
+
setProjectData(prev => ({
|
|
88
|
+
...prev,
|
|
89
|
+
features: {
|
|
90
|
+
...prev.features,
|
|
91
|
+
[feature]: !prev.features[feature]
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
const handleIntegrationToggle = useCallback((integrationId) => {
|
|
97
|
+
setProjectData(prev => ({
|
|
98
|
+
...prev,
|
|
99
|
+
integrations: prev.integrations.includes(integrationId)
|
|
100
|
+
? prev.integrations.filter(id => id !== integrationId)
|
|
101
|
+
: [...prev.integrations, integrationId]
|
|
102
|
+
}));
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
const generateProjectFiles = useCallback(() => {
|
|
106
|
+
const template = PROJECT_TEMPLATES[projectData.template];
|
|
107
|
+
|
|
108
|
+
// Generate package.json
|
|
109
|
+
const packageJson = {
|
|
110
|
+
name: projectData.name,
|
|
111
|
+
version: '1.0.0',
|
|
112
|
+
description: projectData.description,
|
|
113
|
+
main: 'app.js',
|
|
114
|
+
scripts: {
|
|
115
|
+
start: 'node app.js',
|
|
116
|
+
dev: 'nodemon app.js',
|
|
117
|
+
test: projectData.features.testing ? 'jest' : undefined,
|
|
118
|
+
build: projectData.template === 'serverless' ? 'serverless package' : undefined,
|
|
119
|
+
deploy: projectData.template === 'serverless' ? 'serverless deploy' : undefined
|
|
120
|
+
},
|
|
121
|
+
dependencies: {
|
|
122
|
+
'@friggframework/core': '^1.0.0',
|
|
123
|
+
express: '^4.18.0',
|
|
124
|
+
...(projectData.database === 'mongodb' ? { mongoose: '^7.0.0' } : {}),
|
|
125
|
+
...(projectData.database === 'postgresql' ? { pg: '^8.8.0', 'pg-hstore': '^2.3.4' } : {}),
|
|
126
|
+
...(projectData.database === 'mysql' ? { mysql2: '^3.0.0' } : {}),
|
|
127
|
+
...(projectData.features.authentication ? { passport: '^0.6.0', 'passport-jwt': '^4.0.0' } : {}),
|
|
128
|
+
...(projectData.features.logging ? { winston: '^3.8.0' } : {}),
|
|
129
|
+
...(projectData.integrations.map(id => ({ [`@friggframework/api-module-${id}`]: '^1.0.0' })).reduce((acc, obj) => ({ ...acc, ...obj }), {}))
|
|
130
|
+
},
|
|
131
|
+
devDependencies: {
|
|
132
|
+
nodemon: '^2.0.0',
|
|
133
|
+
...(projectData.features.testing ? { jest: '^29.0.0', supertest: '^6.3.0' } : {})
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Generate app.js
|
|
138
|
+
const appJs = generateAppJs();
|
|
139
|
+
|
|
140
|
+
// Generate serverless.yml (if serverless template)
|
|
141
|
+
const serverlessYml = projectData.template === 'serverless' ? generateServerlessYml() : null;
|
|
142
|
+
|
|
143
|
+
// Generate docker files (if docker enabled)
|
|
144
|
+
const dockerfile = projectData.features.docker ? generateDockerfile() : null;
|
|
145
|
+
const dockerCompose = projectData.features.docker ? generateDockerCompose() : null;
|
|
146
|
+
|
|
147
|
+
// Generate README
|
|
148
|
+
const readme = generateReadme();
|
|
149
|
+
|
|
150
|
+
// Generate environment files
|
|
151
|
+
const envExample = generateEnvExample();
|
|
152
|
+
|
|
153
|
+
const files = [
|
|
154
|
+
{ name: 'package.json', content: JSON.stringify(packageJson, null, 2) },
|
|
155
|
+
{ name: 'app.js', content: appJs },
|
|
156
|
+
{ name: 'README.md', content: readme },
|
|
157
|
+
{ name: '.env.example', content: envExample },
|
|
158
|
+
...(serverlessYml ? [{ name: 'serverless.yml', content: serverlessYml }] : []),
|
|
159
|
+
...(dockerfile ? [{ name: 'Dockerfile', content: dockerfile }] : []),
|
|
160
|
+
...(dockerCompose ? [{ name: 'docker-compose.yml', content: dockerCompose }] : []),
|
|
161
|
+
...(projectData.features.ci ? [{ name: '.github/workflows/ci.yml', content: generateCIConfig() }] : [])
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
const metadata = {
|
|
165
|
+
name: projectData.name,
|
|
166
|
+
template: projectData.template,
|
|
167
|
+
type: 'project-scaffold',
|
|
168
|
+
files
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
onGenerate(projectData, { files }, metadata);
|
|
172
|
+
}, [projectData, onGenerate]);
|
|
173
|
+
|
|
174
|
+
const generateAppJs = () => {
|
|
175
|
+
return `const express = require('express');
|
|
176
|
+
const { FriggManager } = require('@friggframework/core');
|
|
177
|
+
${projectData.features.logging ? "const winston = require('winston');" : ''}
|
|
178
|
+
${projectData.database === 'mongodb' ? "const mongoose = require('mongoose');" : ''}
|
|
179
|
+
|
|
180
|
+
const app = express();
|
|
181
|
+
const port = process.env.PORT || 3000;
|
|
182
|
+
|
|
183
|
+
// Middleware
|
|
184
|
+
app.use(express.json());
|
|
185
|
+
app.use(express.urlencoded({ extended: true }));
|
|
186
|
+
|
|
187
|
+
${projectData.features.logging ? `
|
|
188
|
+
// Logging configuration
|
|
189
|
+
const logger = winston.createLogger({
|
|
190
|
+
level: 'info',
|
|
191
|
+
format: winston.format.combine(
|
|
192
|
+
winston.format.timestamp(),
|
|
193
|
+
winston.format.json()
|
|
194
|
+
),
|
|
195
|
+
transports: [
|
|
196
|
+
new winston.transports.Console(),
|
|
197
|
+
new winston.transports.File({ filename: 'app.log' })
|
|
198
|
+
]
|
|
199
|
+
});
|
|
200
|
+
` : ''}
|
|
201
|
+
|
|
202
|
+
${projectData.database === 'mongodb' ? `
|
|
203
|
+
// Database connection
|
|
204
|
+
mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/${projectData.name}', {
|
|
205
|
+
useNewUrlParser: true,
|
|
206
|
+
useUnifiedTopology: true
|
|
207
|
+
});
|
|
208
|
+
` : ''}
|
|
209
|
+
|
|
210
|
+
// Frigg Manager initialization
|
|
211
|
+
const friggManager = new FriggManager({
|
|
212
|
+
database: '${projectData.database}',
|
|
213
|
+
integrations: [
|
|
214
|
+
${projectData.integrations.map(id => ` require('@friggframework/api-module-${id}')`).join(',\n')}
|
|
215
|
+
]
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Routes
|
|
219
|
+
app.get('/', (req, res) => {
|
|
220
|
+
res.json({
|
|
221
|
+
message: 'Welcome to ${projectData.name}',
|
|
222
|
+
status: 'running',
|
|
223
|
+
integrations: [${projectData.integrations.map(id => `'${id}'`).join(', ')}]
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
app.get('/health', (req, res) => {
|
|
228
|
+
res.json({ status: 'healthy', timestamp: new Date().toISOString() });
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Start server
|
|
232
|
+
app.listen(port, () => {
|
|
233
|
+
${projectData.features.logging ? 'logger.info' : 'console.log'}(\`Server running on port \${port}\`);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
module.exports = app;`;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const generateServerlessYml = () => {
|
|
240
|
+
return `service: ${projectData.name}
|
|
241
|
+
|
|
242
|
+
frameworkVersion: '3'
|
|
243
|
+
|
|
244
|
+
provider:
|
|
245
|
+
name: aws
|
|
246
|
+
runtime: nodejs18.x
|
|
247
|
+
stage: \${opt:stage, 'dev'}
|
|
248
|
+
region: \${opt:region, 'us-east-1'}
|
|
249
|
+
environment:
|
|
250
|
+
NODE_ENV: \${self:provider.stage}
|
|
251
|
+
${projectData.integrations.map(id => `${id.toUpperCase()}_API_KEY: \${env:${id.toUpperCase()}_API_KEY}`).join('\n ')}
|
|
252
|
+
|
|
253
|
+
functions:
|
|
254
|
+
app:
|
|
255
|
+
handler: app.handler
|
|
256
|
+
events:
|
|
257
|
+
- http:
|
|
258
|
+
path: /{proxy+}
|
|
259
|
+
method: ANY
|
|
260
|
+
cors: true
|
|
261
|
+
- http:
|
|
262
|
+
path: /
|
|
263
|
+
method: ANY
|
|
264
|
+
cors: true
|
|
265
|
+
|
|
266
|
+
${projectData.database === 'dynamodb' ? `
|
|
267
|
+
resources:
|
|
268
|
+
Resources:
|
|
269
|
+
${projectData.name}Table:
|
|
270
|
+
Type: AWS::DynamoDB::Table
|
|
271
|
+
Properties:
|
|
272
|
+
TableName: \${self:provider.stage}-${projectData.name}
|
|
273
|
+
AttributeDefinitions:
|
|
274
|
+
- AttributeName: id
|
|
275
|
+
AttributeType: S
|
|
276
|
+
KeySchema:
|
|
277
|
+
- AttributeName: id
|
|
278
|
+
KeyType: HASH
|
|
279
|
+
BillingMode: PAY_PER_REQUEST
|
|
280
|
+
` : ''}
|
|
281
|
+
|
|
282
|
+
plugins:
|
|
283
|
+
- serverless-offline`;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const generateDockerfile = () => {
|
|
287
|
+
return `FROM node:18-alpine
|
|
288
|
+
|
|
289
|
+
WORKDIR /app
|
|
290
|
+
|
|
291
|
+
COPY package*.json ./
|
|
292
|
+
RUN npm ci --only=production
|
|
293
|
+
|
|
294
|
+
COPY . .
|
|
295
|
+
|
|
296
|
+
EXPOSE 3000
|
|
297
|
+
|
|
298
|
+
CMD ["npm", "start"]`;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const generateDockerCompose = () => {
|
|
302
|
+
return `version: '3.8'
|
|
303
|
+
|
|
304
|
+
services:
|
|
305
|
+
app:
|
|
306
|
+
build: .
|
|
307
|
+
ports:
|
|
308
|
+
- "3000:3000"
|
|
309
|
+
environment:
|
|
310
|
+
- NODE_ENV=development
|
|
311
|
+
${projectData.database === 'mongodb' ? '- MONGODB_URI=mongodb://mongo:27017/' + projectData.name : ''}
|
|
312
|
+
depends_on:
|
|
313
|
+
${projectData.database === 'mongodb' ? '- mongo' : ''}
|
|
314
|
+
volumes:
|
|
315
|
+
- .:/app
|
|
316
|
+
- /app/node_modules
|
|
317
|
+
|
|
318
|
+
${projectData.database === 'mongodb' ? ` mongo:
|
|
319
|
+
image: mongo:5
|
|
320
|
+
ports:
|
|
321
|
+
- "27017:27017"
|
|
322
|
+
volumes:
|
|
323
|
+
- mongo_data:/data/db
|
|
324
|
+
|
|
325
|
+
volumes:
|
|
326
|
+
mongo_data:` : ''}`;
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const generateReadme = () => {
|
|
330
|
+
const template = PROJECT_TEMPLATES[projectData.template];
|
|
331
|
+
|
|
332
|
+
return `# ${projectData.name}
|
|
333
|
+
|
|
334
|
+
${projectData.description}
|
|
335
|
+
|
|
336
|
+
## Project Template: ${template.name}
|
|
337
|
+
|
|
338
|
+
${template.description}
|
|
339
|
+
|
|
340
|
+
### Features
|
|
341
|
+
|
|
342
|
+
${template.features.map(feature => `- ${feature}`).join('\n')}
|
|
343
|
+
|
|
344
|
+
### Integrations
|
|
345
|
+
|
|
346
|
+
${projectData.integrations.length > 0
|
|
347
|
+
? projectData.integrations.map(id => {
|
|
348
|
+
const integration = INTEGRATION_OPTIONS.find(i => i.id === id);
|
|
349
|
+
return `- ${integration?.name} (${integration?.category})`;
|
|
350
|
+
}).join('\n')
|
|
351
|
+
: 'No integrations configured'
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
### Database
|
|
355
|
+
|
|
356
|
+
- ${DATABASE_OPTIONS.find(db => db.value === projectData.database)?.label}
|
|
357
|
+
|
|
358
|
+
### Additional Features
|
|
359
|
+
|
|
360
|
+
${Object.entries(projectData.features)
|
|
361
|
+
.filter(([, enabled]) => enabled)
|
|
362
|
+
.map(([feature]) => `- ${feature.charAt(0).toUpperCase() + feature.slice(1)}`)
|
|
363
|
+
.join('\n')}
|
|
364
|
+
|
|
365
|
+
## Getting Started
|
|
366
|
+
|
|
367
|
+
1. Install dependencies:
|
|
368
|
+
\`\`\`bash
|
|
369
|
+
npm install
|
|
370
|
+
\`\`\`
|
|
371
|
+
|
|
372
|
+
2. Copy environment variables:
|
|
373
|
+
\`\`\`bash
|
|
374
|
+
cp .env.example .env
|
|
375
|
+
\`\`\`
|
|
376
|
+
|
|
377
|
+
3. Update environment variables in \`.env\`
|
|
378
|
+
|
|
379
|
+
${projectData.features.docker ? `4. Start with Docker:
|
|
380
|
+
\`\`\`bash
|
|
381
|
+
docker-compose up
|
|
382
|
+
\`\`\`
|
|
383
|
+
|
|
384
|
+
Or start locally:` : '4. Start the application:'}
|
|
385
|
+
\`\`\`bash
|
|
386
|
+
npm run dev
|
|
387
|
+
\`\`\`
|
|
388
|
+
|
|
389
|
+
## API Endpoints
|
|
390
|
+
|
|
391
|
+
- \`GET /\` - Welcome message and status
|
|
392
|
+
- \`GET /health\` - Health check
|
|
393
|
+
|
|
394
|
+
## Deployment
|
|
395
|
+
|
|
396
|
+
${projectData.template === 'serverless'
|
|
397
|
+
? `This project uses Serverless Framework for deployment:
|
|
398
|
+
|
|
399
|
+
\`\`\`bash
|
|
400
|
+
npm run deploy
|
|
401
|
+
\`\`\``
|
|
402
|
+
: `Configure your deployment platform (${projectData.deployment.platform}) according to your needs.`
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
## License
|
|
406
|
+
|
|
407
|
+
MIT`;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const generateEnvExample = () => {
|
|
411
|
+
return `# Environment Configuration
|
|
412
|
+
NODE_ENV=development
|
|
413
|
+
PORT=3000
|
|
414
|
+
|
|
415
|
+
# Database
|
|
416
|
+
${projectData.database === 'mongodb' ? `MONGODB_URI=mongodb://localhost:27017/${projectData.name}` : ''}
|
|
417
|
+
${projectData.database === 'postgresql' ? `DATABASE_URL=postgresql://user:password@localhost:5432/${projectData.name}` : ''}
|
|
418
|
+
${projectData.database === 'mysql' ? `DATABASE_URL=mysql://user:password@localhost:3306/${projectData.name}` : ''}
|
|
419
|
+
|
|
420
|
+
# Integration API Keys
|
|
421
|
+
${projectData.integrations.map(id => `${id.toUpperCase()}_API_KEY=your_${id}_api_key_here`).join('\n')}
|
|
422
|
+
|
|
423
|
+
# Authentication (if enabled)
|
|
424
|
+
${projectData.features.authentication ? `JWT_SECRET=your_jwt_secret_here
|
|
425
|
+
JWT_EXPIRES_IN=24h` : ''}
|
|
426
|
+
|
|
427
|
+
# AWS Configuration (if using AWS services)
|
|
428
|
+
${projectData.deployment.platform === 'aws' ? `AWS_ACCESS_KEY_ID=your_access_key
|
|
429
|
+
AWS_SECRET_ACCESS_KEY=your_secret_key
|
|
430
|
+
AWS_REGION=us-east-1` : ''}`;
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const generateCIConfig = () => {
|
|
434
|
+
return `name: CI/CD Pipeline
|
|
435
|
+
|
|
436
|
+
on:
|
|
437
|
+
push:
|
|
438
|
+
branches: [ main, develop ]
|
|
439
|
+
pull_request:
|
|
440
|
+
branches: [ main ]
|
|
441
|
+
|
|
442
|
+
jobs:
|
|
443
|
+
test:
|
|
444
|
+
runs-on: ubuntu-latest
|
|
445
|
+
|
|
446
|
+
strategy:
|
|
447
|
+
matrix:
|
|
448
|
+
node-version: [16.x, 18.x]
|
|
449
|
+
|
|
450
|
+
steps:
|
|
451
|
+
- uses: actions/checkout@v3
|
|
452
|
+
|
|
453
|
+
- name: Use Node.js \${{ matrix.node-version }}
|
|
454
|
+
uses: actions/setup-node@v3
|
|
455
|
+
with:
|
|
456
|
+
node-version: \${{ matrix.node-version }}
|
|
457
|
+
cache: 'npm'
|
|
458
|
+
|
|
459
|
+
- run: npm ci
|
|
460
|
+
|
|
461
|
+
${projectData.features.testing ? '- run: npm test' : ''}
|
|
462
|
+
|
|
463
|
+
- run: npm run lint
|
|
464
|
+
|
|
465
|
+
deploy:
|
|
466
|
+
needs: test
|
|
467
|
+
runs-on: ubuntu-latest
|
|
468
|
+
if: github.ref == 'refs/heads/main'
|
|
469
|
+
|
|
470
|
+
steps:
|
|
471
|
+
- uses: actions/checkout@v3
|
|
472
|
+
|
|
473
|
+
- name: Use Node.js 18.x
|
|
474
|
+
uses: actions/setup-node@v3
|
|
475
|
+
with:
|
|
476
|
+
node-version: 18.x
|
|
477
|
+
cache: 'npm'
|
|
478
|
+
|
|
479
|
+
- run: npm ci
|
|
480
|
+
|
|
481
|
+
${projectData.template === 'serverless' ? '- run: npm run deploy' : '# Add your deployment steps here'}`;
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
const nextStep = () => {
|
|
485
|
+
if (currentStep < steps.length - 1) {
|
|
486
|
+
setCurrentStep(currentStep + 1);
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
const prevStep = () => {
|
|
491
|
+
if (currentStep > 0) {
|
|
492
|
+
setCurrentStep(currentStep - 1);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
const canProceed = () => {
|
|
497
|
+
switch (currentStep) {
|
|
498
|
+
case 0:
|
|
499
|
+
return projectData.name && projectData.description;
|
|
500
|
+
case 1:
|
|
501
|
+
return projectData.template;
|
|
502
|
+
case 2:
|
|
503
|
+
return projectData.database;
|
|
504
|
+
default:
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
const renderStep = () => {
|
|
510
|
+
switch (currentStep) {
|
|
511
|
+
case 0:
|
|
512
|
+
return (
|
|
513
|
+
<div className="space-y-4">
|
|
514
|
+
<h3 className="text-lg font-medium">Project Information</h3>
|
|
515
|
+
<div className="grid grid-cols-1 gap-4">
|
|
516
|
+
<div>
|
|
517
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
518
|
+
Project Name *
|
|
519
|
+
</label>
|
|
520
|
+
<input
|
|
521
|
+
type="text"
|
|
522
|
+
value={projectData.name}
|
|
523
|
+
onChange={(e) => handleInputChange('name', e.target.value)}
|
|
524
|
+
placeholder="my-frigg-project"
|
|
525
|
+
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
526
|
+
/>
|
|
527
|
+
</div>
|
|
528
|
+
<div>
|
|
529
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
530
|
+
Description *
|
|
531
|
+
</label>
|
|
532
|
+
<textarea
|
|
533
|
+
value={projectData.description}
|
|
534
|
+
onChange={(e) => handleInputChange('description', e.target.value)}
|
|
535
|
+
placeholder="Brief description of your project"
|
|
536
|
+
rows={3}
|
|
537
|
+
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
538
|
+
/>
|
|
539
|
+
</div>
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
case 1:
|
|
545
|
+
return (
|
|
546
|
+
<div className="space-y-4">
|
|
547
|
+
<h3 className="text-lg font-medium">Choose Project Template</h3>
|
|
548
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
549
|
+
{Object.entries(PROJECT_TEMPLATES).map(([key, template]) => (
|
|
550
|
+
<Card
|
|
551
|
+
key={key}
|
|
552
|
+
className={`cursor-pointer transition-all p-4 ${
|
|
553
|
+
projectData.template === key
|
|
554
|
+
? 'border-blue-500 bg-blue-50'
|
|
555
|
+
: 'hover:border-gray-300'
|
|
556
|
+
}`}
|
|
557
|
+
onClick={() => handleInputChange('template', key)}
|
|
558
|
+
>
|
|
559
|
+
<div className="flex items-start justify-between mb-2">
|
|
560
|
+
<h4 className="font-medium">{template.name}</h4>
|
|
561
|
+
<input
|
|
562
|
+
type="radio"
|
|
563
|
+
checked={projectData.template === key}
|
|
564
|
+
onChange={() => handleInputChange('template', key)}
|
|
565
|
+
className="mt-1"
|
|
566
|
+
/>
|
|
567
|
+
</div>
|
|
568
|
+
<p className="text-sm text-gray-600 mb-3">{template.description}</p>
|
|
569
|
+
<div className="space-y-1">
|
|
570
|
+
{template.features.map((feature, index) => (
|
|
571
|
+
<div key={index} className="text-xs text-gray-500 flex items-center">
|
|
572
|
+
<span className="w-1 h-1 bg-gray-400 rounded-full mr-2"></span>
|
|
573
|
+
{feature}
|
|
574
|
+
</div>
|
|
575
|
+
))}
|
|
576
|
+
</div>
|
|
577
|
+
</Card>
|
|
578
|
+
))}
|
|
579
|
+
</div>
|
|
580
|
+
</div>
|
|
581
|
+
);
|
|
582
|
+
|
|
583
|
+
case 2:
|
|
584
|
+
return (
|
|
585
|
+
<div className="space-y-4">
|
|
586
|
+
<h3 className="text-lg font-medium">Database Configuration</h3>
|
|
587
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
588
|
+
{DATABASE_OPTIONS.map((db) => (
|
|
589
|
+
<Card
|
|
590
|
+
key={db.value}
|
|
591
|
+
className={`cursor-pointer transition-all p-4 ${
|
|
592
|
+
projectData.database === db.value
|
|
593
|
+
? 'border-blue-500 bg-blue-50'
|
|
594
|
+
: 'hover:border-gray-300'
|
|
595
|
+
}`}
|
|
596
|
+
onClick={() => handleInputChange('database', db.value)}
|
|
597
|
+
>
|
|
598
|
+
<div className="flex items-start justify-between mb-2">
|
|
599
|
+
<h4 className="font-medium">{db.label}</h4>
|
|
600
|
+
<input
|
|
601
|
+
type="radio"
|
|
602
|
+
checked={projectData.database === db.value}
|
|
603
|
+
onChange={() => handleInputChange('database', db.value)}
|
|
604
|
+
className="mt-1"
|
|
605
|
+
/>
|
|
606
|
+
</div>
|
|
607
|
+
<p className="text-sm text-gray-600">{db.description}</p>
|
|
608
|
+
</Card>
|
|
609
|
+
))}
|
|
610
|
+
</div>
|
|
611
|
+
</div>
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
case 3:
|
|
615
|
+
return (
|
|
616
|
+
<div className="space-y-4">
|
|
617
|
+
<h3 className="text-lg font-medium">Select Integrations</h3>
|
|
618
|
+
<p className="text-sm text-gray-600">Choose the integrations you want to include in your project.</p>
|
|
619
|
+
|
|
620
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
621
|
+
{INTEGRATION_OPTIONS.map((integration) => (
|
|
622
|
+
<div
|
|
623
|
+
key={integration.id}
|
|
624
|
+
className={`border rounded p-3 cursor-pointer transition-all ${
|
|
625
|
+
projectData.integrations.includes(integration.id)
|
|
626
|
+
? 'border-blue-500 bg-blue-50'
|
|
627
|
+
: 'hover:border-gray-300'
|
|
628
|
+
}`}
|
|
629
|
+
onClick={() => handleIntegrationToggle(integration.id)}
|
|
630
|
+
>
|
|
631
|
+
<div className="flex items-center justify-between">
|
|
632
|
+
<div>
|
|
633
|
+
<h4 className="font-medium text-sm">{integration.name}</h4>
|
|
634
|
+
<p className="text-xs text-gray-500">{integration.category}</p>
|
|
635
|
+
</div>
|
|
636
|
+
<input
|
|
637
|
+
type="checkbox"
|
|
638
|
+
checked={projectData.integrations.includes(integration.id)}
|
|
639
|
+
onChange={() => handleIntegrationToggle(integration.id)}
|
|
640
|
+
/>
|
|
641
|
+
</div>
|
|
642
|
+
</div>
|
|
643
|
+
))}
|
|
644
|
+
</div>
|
|
645
|
+
</div>
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
case 4:
|
|
649
|
+
return (
|
|
650
|
+
<div className="space-y-4">
|
|
651
|
+
<h3 className="text-lg font-medium">Additional Features</h3>
|
|
652
|
+
<p className="text-sm text-gray-600">Enable additional features for your project.</p>
|
|
653
|
+
|
|
654
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
655
|
+
{Object.entries(projectData.features).map(([feature, enabled]) => (
|
|
656
|
+
<div key={feature} className="flex items-center justify-between p-3 border rounded">
|
|
657
|
+
<div>
|
|
658
|
+
<h4 className="font-medium capitalize">{feature.replace(/([A-Z])/g, ' $1')}</h4>
|
|
659
|
+
<p className="text-sm text-gray-500">
|
|
660
|
+
{feature === 'authentication' && 'JWT-based authentication system'}
|
|
661
|
+
{feature === 'logging' && 'Winston logging configuration'}
|
|
662
|
+
{feature === 'monitoring' && 'Health checks and metrics'}
|
|
663
|
+
{feature === 'testing' && 'Jest testing framework'}
|
|
664
|
+
{feature === 'docker' && 'Docker and docker-compose files'}
|
|
665
|
+
{feature === 'ci' && 'GitHub Actions CI/CD pipeline'}
|
|
666
|
+
</p>
|
|
667
|
+
</div>
|
|
668
|
+
<input
|
|
669
|
+
type="checkbox"
|
|
670
|
+
checked={enabled}
|
|
671
|
+
onChange={() => handleFeatureToggle(feature)}
|
|
672
|
+
/>
|
|
673
|
+
</div>
|
|
674
|
+
))}
|
|
675
|
+
</div>
|
|
676
|
+
</div>
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
case 5:
|
|
680
|
+
return (
|
|
681
|
+
<div className="space-y-4">
|
|
682
|
+
<h3 className="text-lg font-medium">Deployment Configuration</h3>
|
|
683
|
+
|
|
684
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
685
|
+
<div>
|
|
686
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
687
|
+
Platform
|
|
688
|
+
</label>
|
|
689
|
+
<select
|
|
690
|
+
value={projectData.deployment.platform}
|
|
691
|
+
onChange={(e) => handleInputChange('deployment', { ...projectData.deployment, platform: e.target.value })}
|
|
692
|
+
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
693
|
+
>
|
|
694
|
+
<option value="aws">AWS</option>
|
|
695
|
+
<option value="gcp">Google Cloud</option>
|
|
696
|
+
<option value="azure">Microsoft Azure</option>
|
|
697
|
+
<option value="heroku">Heroku</option>
|
|
698
|
+
<option value="vercel">Vercel</option>
|
|
699
|
+
<option value="netlify">Netlify</option>
|
|
700
|
+
</select>
|
|
701
|
+
</div>
|
|
702
|
+
<div>
|
|
703
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
704
|
+
Environment
|
|
705
|
+
</label>
|
|
706
|
+
<select
|
|
707
|
+
value={projectData.deployment.environment}
|
|
708
|
+
onChange={(e) => handleInputChange('deployment', { ...projectData.deployment, environment: e.target.value })}
|
|
709
|
+
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
710
|
+
>
|
|
711
|
+
<option value="development">Development</option>
|
|
712
|
+
<option value="staging">Staging</option>
|
|
713
|
+
<option value="production">Production</option>
|
|
714
|
+
</select>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
|
|
718
|
+
<div className="bg-blue-50 p-4 rounded-md">
|
|
719
|
+
<h4 className="font-medium text-blue-900 mb-2">Project Summary</h4>
|
|
720
|
+
<div className="text-sm text-blue-800 space-y-1">
|
|
721
|
+
<p><strong>Name:</strong> {projectData.name}</p>
|
|
722
|
+
<p><strong>Template:</strong> {PROJECT_TEMPLATES[projectData.template].name}</p>
|
|
723
|
+
<p><strong>Database:</strong> {DATABASE_OPTIONS.find(db => db.value === projectData.database)?.label}</p>
|
|
724
|
+
<p><strong>Integrations:</strong> {projectData.integrations.length > 0 ? projectData.integrations.join(', ') : 'None'}</p>
|
|
725
|
+
<p><strong>Features:</strong> {Object.entries(projectData.features).filter(([, enabled]) => enabled).map(([feature]) => feature).join(', ')}</p>
|
|
726
|
+
</div>
|
|
727
|
+
</div>
|
|
728
|
+
</div>
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
default:
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
return (
|
|
737
|
+
<div className="space-y-6">
|
|
738
|
+
<h2 className="text-2xl font-bold">Project Scaffold Wizard</h2>
|
|
739
|
+
|
|
740
|
+
{/* Progress indicator */}
|
|
741
|
+
<div className="flex items-center justify-between mb-8">
|
|
742
|
+
{steps.map((step, index) => (
|
|
743
|
+
<div key={index} className="flex items-center">
|
|
744
|
+
<div className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium ${
|
|
745
|
+
index <= currentStep
|
|
746
|
+
? 'bg-blue-600 text-white'
|
|
747
|
+
: 'bg-gray-200 text-gray-500'
|
|
748
|
+
}`}>
|
|
749
|
+
{index + 1}
|
|
750
|
+
</div>
|
|
751
|
+
<div className="ml-2 text-sm">
|
|
752
|
+
<div className={`font-medium ${index <= currentStep ? 'text-blue-600' : 'text-gray-500'}`}>
|
|
753
|
+
{step.title}
|
|
754
|
+
</div>
|
|
755
|
+
<div className="text-gray-400 text-xs">{step.description}</div>
|
|
756
|
+
</div>
|
|
757
|
+
{index < steps.length - 1 && (
|
|
758
|
+
<div className={`w-16 h-px mx-4 ${index < currentStep ? 'bg-blue-600' : 'bg-gray-200'}`} />
|
|
759
|
+
)}
|
|
760
|
+
</div>
|
|
761
|
+
))}
|
|
762
|
+
</div>
|
|
763
|
+
|
|
764
|
+
<Card className="p-6">
|
|
765
|
+
{renderStep()}
|
|
766
|
+
</Card>
|
|
767
|
+
|
|
768
|
+
<div className="flex justify-between">
|
|
769
|
+
<Button
|
|
770
|
+
variant="outline"
|
|
771
|
+
onClick={prevStep}
|
|
772
|
+
disabled={currentStep === 0}
|
|
773
|
+
>
|
|
774
|
+
Previous
|
|
775
|
+
</Button>
|
|
776
|
+
|
|
777
|
+
{currentStep === steps.length - 1 ? (
|
|
778
|
+
<Button
|
|
779
|
+
onClick={generateProjectFiles}
|
|
780
|
+
className="bg-green-600 hover:bg-green-700"
|
|
781
|
+
>
|
|
782
|
+
Generate Project
|
|
783
|
+
</Button>
|
|
784
|
+
) : (
|
|
785
|
+
<Button
|
|
786
|
+
onClick={nextStep}
|
|
787
|
+
disabled={!canProceed()}
|
|
788
|
+
>
|
|
789
|
+
Next
|
|
790
|
+
</Button>
|
|
791
|
+
)}
|
|
792
|
+
</div>
|
|
793
|
+
</div>
|
|
794
|
+
);
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
export default ProjectScaffoldWizard;
|