@friggframework/devtools 2.0.0-next.3 → 2.0.0-next.31
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 +17 -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,319 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
// Mock dependencies
|
|
4
|
+
jest.mock('axios');
|
|
5
|
+
jest.mock('node-cache');
|
|
6
|
+
|
|
7
|
+
describe('NPMRegistryService', () => {
|
|
8
|
+
let npmRegistry;
|
|
9
|
+
let mockCache;
|
|
10
|
+
let NodeCache;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks();
|
|
14
|
+
|
|
15
|
+
// Mock cache methods
|
|
16
|
+
mockCache = {
|
|
17
|
+
get: jest.fn(),
|
|
18
|
+
set: jest.fn(),
|
|
19
|
+
del: jest.fn()
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Re-require NodeCache and set up mock
|
|
23
|
+
NodeCache = require('node-cache');
|
|
24
|
+
NodeCache.mockImplementation(() => mockCache);
|
|
25
|
+
|
|
26
|
+
// Create new instance for each test
|
|
27
|
+
jest.isolateModules(() => {
|
|
28
|
+
npmRegistry = require('../utils/npm-registry');
|
|
29
|
+
// Access the cache directly to ensure our mock is used
|
|
30
|
+
npmRegistry.cache = mockCache;
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('searchApiModules', () => {
|
|
35
|
+
const mockApiResponse = {
|
|
36
|
+
data: {
|
|
37
|
+
objects: [
|
|
38
|
+
{
|
|
39
|
+
package: {
|
|
40
|
+
name: '@friggframework/api-module-slack',
|
|
41
|
+
version: '2.0.0',
|
|
42
|
+
description: 'Slack integration for Frigg',
|
|
43
|
+
keywords: ['frigg', 'slack', 'integration'],
|
|
44
|
+
author: { name: 'Frigg Team' },
|
|
45
|
+
date: '2024-01-01'
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
package: {
|
|
50
|
+
name: '@friggframework/api-module-hubspot',
|
|
51
|
+
version: '2.1.0',
|
|
52
|
+
description: 'HubSpot CRM integration',
|
|
53
|
+
keywords: ['frigg', 'hubspot', 'crm'],
|
|
54
|
+
author: { name: 'Frigg Team' },
|
|
55
|
+
date: '2024-01-02'
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
package: {
|
|
60
|
+
name: '@friggframework/not-api-module',
|
|
61
|
+
version: '1.0.0',
|
|
62
|
+
description: 'Should be filtered out'
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
it('should fetch and format API modules from npm registry', async () => {
|
|
70
|
+
mockCache.get.mockReturnValue(null);
|
|
71
|
+
axios.get.mockResolvedValue(mockApiResponse);
|
|
72
|
+
|
|
73
|
+
const result = await npmRegistry.searchApiModules();
|
|
74
|
+
|
|
75
|
+
expect(axios.get).toHaveBeenCalledWith(
|
|
76
|
+
'https://registry.npmjs.org/-/v1/search',
|
|
77
|
+
expect.objectContaining({
|
|
78
|
+
params: expect.objectContaining({
|
|
79
|
+
text: '@friggframework/api-module-',
|
|
80
|
+
size: 250
|
|
81
|
+
}),
|
|
82
|
+
timeout: 10000
|
|
83
|
+
})
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
expect(result).toHaveLength(2);
|
|
87
|
+
expect(result[0]).toMatchObject({
|
|
88
|
+
name: '@friggframework/api-module-slack',
|
|
89
|
+
version: '2.0.0',
|
|
90
|
+
integrationName: 'Slack',
|
|
91
|
+
category: 'Communication'
|
|
92
|
+
});
|
|
93
|
+
expect(result[1]).toMatchObject({
|
|
94
|
+
name: '@friggframework/api-module-hubspot',
|
|
95
|
+
integrationName: 'Hubspot',
|
|
96
|
+
category: 'CRM'
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should use cached results when available', async () => {
|
|
101
|
+
const cachedData = [{ name: 'cached-module' }];
|
|
102
|
+
mockCache.get.mockReturnValue(cachedData);
|
|
103
|
+
|
|
104
|
+
const result = await npmRegistry.searchApiModules();
|
|
105
|
+
|
|
106
|
+
expect(axios.get).not.toHaveBeenCalled();
|
|
107
|
+
expect(result).toEqual(cachedData);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should force refresh when requested', async () => {
|
|
111
|
+
const cachedData = [{ name: 'cached-module' }];
|
|
112
|
+
mockCache.get.mockReturnValue(cachedData);
|
|
113
|
+
axios.get.mockResolvedValue(mockApiResponse);
|
|
114
|
+
|
|
115
|
+
const result = await npmRegistry.searchApiModules({ forceRefresh: true });
|
|
116
|
+
|
|
117
|
+
expect(axios.get).toHaveBeenCalled();
|
|
118
|
+
expect(result).toHaveLength(2);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should filter out prerelease versions by default', async () => {
|
|
122
|
+
const responseWithPrerelease = {
|
|
123
|
+
data: {
|
|
124
|
+
objects: [
|
|
125
|
+
{
|
|
126
|
+
package: {
|
|
127
|
+
name: '@friggframework/api-module-test',
|
|
128
|
+
version: '2.0.0-beta.1',
|
|
129
|
+
description: 'Prerelease version'
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
package: {
|
|
134
|
+
name: '@friggframework/api-module-stable',
|
|
135
|
+
version: '1.0.0',
|
|
136
|
+
description: 'Stable version'
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
mockCache.get.mockReturnValue(null);
|
|
144
|
+
axios.get.mockResolvedValue(responseWithPrerelease);
|
|
145
|
+
|
|
146
|
+
const result = await npmRegistry.searchApiModules();
|
|
147
|
+
|
|
148
|
+
expect(result).toHaveLength(1);
|
|
149
|
+
expect(result[0].name).toBe('@friggframework/api-module-stable');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should include prerelease versions when requested', async () => {
|
|
153
|
+
const responseWithPrerelease = {
|
|
154
|
+
data: {
|
|
155
|
+
objects: [
|
|
156
|
+
{
|
|
157
|
+
package: {
|
|
158
|
+
name: '@friggframework/api-module-test',
|
|
159
|
+
version: '2.0.0-beta.1'
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
mockCache.get.mockReturnValue(null);
|
|
167
|
+
axios.get.mockResolvedValue(responseWithPrerelease);
|
|
168
|
+
|
|
169
|
+
const result = await npmRegistry.searchApiModules({ includePrerelease: true });
|
|
170
|
+
|
|
171
|
+
expect(result).toHaveLength(1);
|
|
172
|
+
expect(result[0].version).toBe('2.0.0-beta.1');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should handle network errors gracefully', async () => {
|
|
176
|
+
mockCache.get.mockReturnValue(null);
|
|
177
|
+
axios.get.mockRejectedValue(new Error('Network error'));
|
|
178
|
+
|
|
179
|
+
const result = await npmRegistry.searchApiModules();
|
|
180
|
+
|
|
181
|
+
expect(result).toEqual([]);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should cache results after successful fetch', async () => {
|
|
185
|
+
mockCache.get.mockReturnValue(null);
|
|
186
|
+
axios.get.mockResolvedValue(mockApiResponse);
|
|
187
|
+
|
|
188
|
+
await npmRegistry.searchApiModules();
|
|
189
|
+
|
|
190
|
+
expect(mockCache.set).toHaveBeenCalledWith(
|
|
191
|
+
expect.any(String),
|
|
192
|
+
expect.arrayContaining([
|
|
193
|
+
expect.objectContaining({ name: '@friggframework/api-module-slack' })
|
|
194
|
+
])
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('categorizeModule', () => {
|
|
200
|
+
it('should categorize modules based on keywords and name', async () => {
|
|
201
|
+
const testCases = [
|
|
202
|
+
{ name: '@friggframework/api-module-salesforce', keywords: ['crm'], expected: 'CRM' },
|
|
203
|
+
{ name: '@friggframework/api-module-slack', keywords: ['chat'], expected: 'Communication' },
|
|
204
|
+
{ name: '@friggframework/api-module-stripe', keywords: ['payment'], expected: 'E-commerce' },
|
|
205
|
+
{ name: '@friggframework/api-module-google-analytics', keywords: [], expected: 'Analytics' },
|
|
206
|
+
{ name: '@friggframework/api-module-mailchimp', keywords: ['email', 'marketing'], expected: 'Marketing' },
|
|
207
|
+
{ name: '@friggframework/api-module-facebook', keywords: [], expected: 'Social Media' },
|
|
208
|
+
{ name: '@friggframework/api-module-jira', keywords: ['project'], expected: 'Project Management' },
|
|
209
|
+
{ name: '@friggframework/api-module-dropbox', keywords: ['storage'], expected: 'Storage' },
|
|
210
|
+
{ name: '@friggframework/api-module-airtable', keywords: [], expected: 'Productivity' },
|
|
211
|
+
{ name: '@friggframework/api-module-github', keywords: ['git'], expected: 'Development' },
|
|
212
|
+
{ name: '@friggframework/api-module-zendesk', keywords: ['support'], expected: 'Support' },
|
|
213
|
+
{ name: '@friggframework/api-module-quickbooks', keywords: ['accounting'], expected: 'Finance' },
|
|
214
|
+
{ name: '@friggframework/api-module-unknown', keywords: [], expected: 'Other' }
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
mockCache.get.mockReturnValue(null);
|
|
218
|
+
axios.get.mockResolvedValue({
|
|
219
|
+
data: {
|
|
220
|
+
objects: testCases.map(tc => ({
|
|
221
|
+
package: {
|
|
222
|
+
name: tc.name,
|
|
223
|
+
version: '1.0.0',
|
|
224
|
+
keywords: tc.keywords
|
|
225
|
+
}
|
|
226
|
+
}))
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const results = await npmRegistry.searchApiModules();
|
|
231
|
+
|
|
232
|
+
testCases.forEach((testCase, index) => {
|
|
233
|
+
expect(results[index].category).toBe(testCase.expected);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe('getModulesByType', () => {
|
|
239
|
+
it('should group modules by category', async () => {
|
|
240
|
+
mockCache.get.mockReturnValue(null);
|
|
241
|
+
axios.get.mockResolvedValue({
|
|
242
|
+
data: {
|
|
243
|
+
objects: [
|
|
244
|
+
{
|
|
245
|
+
package: {
|
|
246
|
+
name: '@friggframework/api-module-slack',
|
|
247
|
+
version: '1.0.0',
|
|
248
|
+
keywords: ['chat', 'communication']
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
package: {
|
|
253
|
+
name: '@friggframework/api-module-discord',
|
|
254
|
+
version: '1.0.0',
|
|
255
|
+
keywords: ['chat', 'communication']
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
package: {
|
|
260
|
+
name: '@friggframework/api-module-salesforce',
|
|
261
|
+
version: '1.0.0',
|
|
262
|
+
keywords: ['crm']
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const grouped = await npmRegistry.getModulesByType();
|
|
270
|
+
|
|
271
|
+
expect(grouped).toMatchObject({
|
|
272
|
+
'Communication': expect.arrayContaining([
|
|
273
|
+
expect.objectContaining({ name: '@friggframework/api-module-slack' }),
|
|
274
|
+
expect.objectContaining({ name: '@friggframework/api-module-discord' })
|
|
275
|
+
]),
|
|
276
|
+
'CRM': expect.arrayContaining([
|
|
277
|
+
expect.objectContaining({ name: '@friggframework/api-module-salesforce' })
|
|
278
|
+
])
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
expect(grouped['Communication']).toHaveLength(2);
|
|
282
|
+
expect(grouped['CRM']).toHaveLength(1);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should handle empty results', async () => {
|
|
286
|
+
mockCache.get.mockReturnValue(null);
|
|
287
|
+
axios.get.mockResolvedValue({ data: { objects: [] } });
|
|
288
|
+
|
|
289
|
+
const grouped = await npmRegistry.getModulesByType();
|
|
290
|
+
|
|
291
|
+
expect(grouped).toEqual({});
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
describe('extractIntegrationName', () => {
|
|
296
|
+
it('should extract and format integration names correctly', async () => {
|
|
297
|
+
const testCases = [
|
|
298
|
+
{ input: '@friggframework/api-module-slack', expected: 'Slack' },
|
|
299
|
+
{ input: '@friggframework/api-module-google-sheets', expected: 'Google Sheets' },
|
|
300
|
+
{ input: '@friggframework/api-module-hubspot-crm', expected: 'Hubspot Crm' }
|
|
301
|
+
];
|
|
302
|
+
|
|
303
|
+
mockCache.get.mockReturnValue(null);
|
|
304
|
+
axios.get.mockResolvedValue({
|
|
305
|
+
data: {
|
|
306
|
+
objects: testCases.map(tc => ({
|
|
307
|
+
package: { name: tc.input, version: '1.0.0' }
|
|
308
|
+
}))
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const results = await npmRegistry.searchApiModules();
|
|
313
|
+
|
|
314
|
+
testCases.forEach((testCase, index) => {
|
|
315
|
+
expect(results[index].integrationName).toBe(testCase.expected);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const open = require('open');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const ProcessManager = require('../utils/process-manager');
|
|
5
|
+
const {
|
|
6
|
+
getCurrentRepositoryInfo,
|
|
7
|
+
discoverFriggRepositories,
|
|
8
|
+
promptRepositorySelection,
|
|
9
|
+
formatRepositoryInfo
|
|
10
|
+
} = require('../utils/repo-detection');
|
|
11
|
+
|
|
12
|
+
async function uiCommand(options) {
|
|
13
|
+
const { port = 3001, open: shouldOpen = true, repo: specifiedRepo, dev = false } = options;
|
|
14
|
+
|
|
15
|
+
let targetRepo = null;
|
|
16
|
+
let workingDirectory = process.cwd();
|
|
17
|
+
|
|
18
|
+
// If a specific repo path is provided, use it
|
|
19
|
+
if (specifiedRepo) {
|
|
20
|
+
const repoPath = path.resolve(specifiedRepo);
|
|
21
|
+
console.log(chalk.blue(`Using specified repository: ${repoPath}`));
|
|
22
|
+
workingDirectory = repoPath;
|
|
23
|
+
targetRepo = { path: repoPath, name: path.basename(repoPath) };
|
|
24
|
+
} else {
|
|
25
|
+
// Check if we're already in a Frigg repository
|
|
26
|
+
console.log(chalk.blue('Detecting Frigg repository...'));
|
|
27
|
+
const currentRepo = await getCurrentRepositoryInfo();
|
|
28
|
+
|
|
29
|
+
if (currentRepo) {
|
|
30
|
+
console.log(chalk.green(`✓ Found Frigg repository: ${formatRepositoryInfo(currentRepo)}`));
|
|
31
|
+
if (currentRepo.currentSubPath) {
|
|
32
|
+
console.log(chalk.gray(` Currently in subdirectory: ${currentRepo.currentSubPath}`));
|
|
33
|
+
}
|
|
34
|
+
targetRepo = currentRepo;
|
|
35
|
+
workingDirectory = currentRepo.path;
|
|
36
|
+
} else {
|
|
37
|
+
// Discover Frigg repositories
|
|
38
|
+
console.log(chalk.yellow('Current directory is not a Frigg repository.'));
|
|
39
|
+
console.log(chalk.blue('Searching for Frigg repositories...'));
|
|
40
|
+
|
|
41
|
+
const discoveredRepos = await discoverFriggRepositories();
|
|
42
|
+
|
|
43
|
+
if (discoveredRepos.length === 0) {
|
|
44
|
+
console.log(chalk.red('No Frigg repositories found. Please create one first.'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// For UI command, we'll let the UI handle repository selection
|
|
49
|
+
// Set a placeholder and pass the discovered repos via environment
|
|
50
|
+
targetRepo = {
|
|
51
|
+
name: 'Multiple Repositories Available',
|
|
52
|
+
path: process.cwd(),
|
|
53
|
+
isMultiRepo: true,
|
|
54
|
+
availableRepos: discoveredRepos
|
|
55
|
+
};
|
|
56
|
+
workingDirectory = process.cwd();
|
|
57
|
+
|
|
58
|
+
console.log(chalk.blue(`Found ${discoveredRepos.length} Frigg repositories. You'll be able to select one in the UI.`));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log(chalk.blue('🚀 Starting Frigg Management UI...'));
|
|
63
|
+
|
|
64
|
+
const processManager = new ProcessManager();
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const managementUiPath = path.join(__dirname, '../../management-ui');
|
|
68
|
+
|
|
69
|
+
// Check if we're in development mode
|
|
70
|
+
// For CLI usage, we prefer development mode unless explicitly set to production
|
|
71
|
+
const fs = require('fs');
|
|
72
|
+
const isDevelopment = dev || process.env.NODE_ENV !== 'production';
|
|
73
|
+
|
|
74
|
+
if (isDevelopment) {
|
|
75
|
+
const env = {
|
|
76
|
+
...process.env,
|
|
77
|
+
VITE_API_URL: `http://localhost:${port}`,
|
|
78
|
+
PORT: port,
|
|
79
|
+
PROJECT_ROOT: workingDirectory,
|
|
80
|
+
REPOSITORY_INFO: JSON.stringify(targetRepo),
|
|
81
|
+
AVAILABLE_REPOSITORIES: targetRepo.isMultiRepo ? JSON.stringify(targetRepo.availableRepos) : null
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Start backend server
|
|
85
|
+
processManager.spawnProcess(
|
|
86
|
+
'backend',
|
|
87
|
+
'npm',
|
|
88
|
+
['run', 'server'],
|
|
89
|
+
{ cwd: managementUiPath, env }
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// Start frontend dev server
|
|
93
|
+
processManager.spawnProcess(
|
|
94
|
+
'frontend',
|
|
95
|
+
'npm',
|
|
96
|
+
['run', 'dev'],
|
|
97
|
+
{ cwd: managementUiPath, env }
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Wait for servers to start
|
|
101
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
102
|
+
|
|
103
|
+
// Display clean status
|
|
104
|
+
processManager.printStatus(
|
|
105
|
+
'http://localhost:5173',
|
|
106
|
+
`http://localhost:${port}`,
|
|
107
|
+
targetRepo.name
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Open browser if requested
|
|
111
|
+
if (shouldOpen) {
|
|
112
|
+
setTimeout(() => {
|
|
113
|
+
open('http://localhost:5173');
|
|
114
|
+
}, 1000);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
} else {
|
|
118
|
+
// Production mode - just start the backend server
|
|
119
|
+
const { FriggManagementServer } = await import('../../management-ui/server/index.js');
|
|
120
|
+
|
|
121
|
+
const server = new FriggManagementServer({
|
|
122
|
+
port,
|
|
123
|
+
projectRoot: workingDirectory,
|
|
124
|
+
repositoryInfo: targetRepo,
|
|
125
|
+
availableRepositories: targetRepo.isMultiRepo ? targetRepo.availableRepos : null
|
|
126
|
+
});
|
|
127
|
+
await server.start();
|
|
128
|
+
|
|
129
|
+
processManager.printStatus(
|
|
130
|
+
`http://localhost:${port}`,
|
|
131
|
+
`http://localhost:${port}/api`,
|
|
132
|
+
targetRepo.name
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (shouldOpen) {
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
open(`http://localhost:${port}`);
|
|
138
|
+
}, 1000);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Keep the process running
|
|
143
|
+
process.stdin.resume();
|
|
144
|
+
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error(chalk.red('Failed to start Management UI:'), error.message);
|
|
147
|
+
if (error.code === 'EADDRINUSE') {
|
|
148
|
+
console.log(chalk.yellow(`Port ${port} is already in use. Try using a different port with --port <number>`));
|
|
149
|
+
}
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = { uiCommand };
|