insforge 1.3.0 → 1.4.8
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/CHANGELOG.md +2 -0
- package/auth/package.json +5 -3
- package/auth/src/lib/broadcastService.ts +115 -117
- package/auth/src/lib/insforge.ts +8 -0
- package/auth/src/main.tsx +2 -4
- package/auth/src/pages/SignInPage.tsx +60 -60
- package/auth/src/pages/SignUpPage.tsx +60 -60
- package/auth/src/pages/VerifyEmailPage.tsx +18 -0
- package/auth/tsconfig.json +2 -1
- package/backend/package.json +10 -6
- package/backend/src/api/middlewares/rate-limiters.ts +127 -127
- package/backend/src/api/routes/ai/index.routes.ts +475 -468
- package/backend/src/api/routes/auth/index.routes.ts +85 -32
- package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
- package/backend/src/api/routes/database/index.routes.ts +2 -0
- package/backend/src/api/routes/database/records.routes.ts +39 -175
- package/backend/src/api/routes/database/rpc.routes.ts +69 -0
- package/backend/src/api/routes/deployments/index.routes.ts +192 -0
- package/backend/src/api/routes/docs/index.routes.ts +3 -2
- package/backend/src/api/routes/email/index.routes.ts +35 -35
- package/backend/src/api/routes/functions/index.routes.ts +3 -3
- package/backend/src/api/routes/metadata/index.routes.ts +26 -0
- package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
- package/backend/src/infra/database/database.manager.ts +0 -10
- package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
- package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
- package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
- package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
- package/backend/src/infra/security/token.manager.ts +1 -4
- package/backend/src/providers/ai/openrouter.provider.ts +12 -3
- package/backend/src/providers/database/base.provider.ts +39 -0
- package/backend/src/providers/database/cloud.provider.ts +159 -0
- package/backend/src/providers/deployments/vercel.provider.ts +516 -0
- package/backend/src/server.ts +19 -7
- package/backend/src/services/ai/ai-config.service.ts +6 -6
- package/backend/src/services/ai/ai-model.service.ts +60 -60
- package/backend/src/services/ai/ai-usage.service.ts +7 -7
- package/backend/src/services/ai/chat-completion.service.ts +415 -220
- package/backend/src/services/ai/helpers.ts +64 -64
- package/backend/src/services/ai/index.ts +13 -13
- package/backend/src/services/auth/auth-config.service.ts +4 -4
- package/backend/src/services/auth/auth-otp.service.ts +6 -6
- package/backend/src/services/auth/auth.service.ts +134 -74
- package/backend/src/services/auth/index.ts +4 -4
- package/backend/src/services/auth/oauth-config.service.ts +12 -12
- package/backend/src/services/database/database-advance.service.ts +19 -55
- package/backend/src/services/database/database-table.service.ts +38 -85
- package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
- package/backend/src/services/deployments/deployment.service.ts +693 -0
- package/backend/src/services/functions/function.service.ts +61 -41
- package/backend/src/services/logs/audit.service.ts +10 -10
- package/backend/src/services/secrets/secret.service.ts +101 -27
- package/backend/src/services/storage/storage.service.ts +30 -30
- package/backend/src/services/usage/usage.service.ts +6 -6
- package/backend/src/types/ai.ts +8 -0
- package/backend/src/types/auth.ts +5 -1
- package/backend/src/types/database.ts +2 -0
- package/backend/src/types/deployments.ts +33 -0
- package/backend/src/types/storage.ts +1 -1
- package/backend/src/types/webhooks.ts +45 -0
- package/backend/src/utils/cookies.ts +34 -35
- package/backend/src/utils/environment.ts +0 -14
- package/backend/src/utils/s3-config-loader.ts +64 -64
- package/backend/src/utils/seed.ts +334 -301
- package/backend/src/utils/sql-parser.ts +126 -0
- package/backend/src/utils/utils.ts +114 -114
- package/backend/src/utils/validations.ts +10 -10
- package/backend/tests/local/test-rpc.sh +141 -0
- package/backend/tests/local/test-secrets.sh +1 -1
- package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
- package/backend/tests/manual/test-rawsql-modes.sh +24 -24
- package/backend/tests/unit/database-advance.test.ts +326 -0
- package/backend/tests/unit/helpers.test.ts +2 -2
- package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
- package/docker-compose.prod.yml +1 -1
- package/docker-compose.yml +1 -1
- package/docs/agent-docs/deployment.md +79 -0
- package/docs/changelog.mdx +165 -72
- package/docs/core-concepts/ai/architecture.mdx +1 -23
- package/docs/core-concepts/ai/sdk.mdx +26 -1
- package/docs/core-concepts/authentication/architecture.mdx +6 -8
- package/docs/core-concepts/authentication/sdk.mdx +387 -91
- package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
- package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
- package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
- package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
- package/docs/core-concepts/database/architecture.mdx +58 -21
- package/docs/core-concepts/database/pgvector.mdx +138 -0
- package/docs/core-concepts/database/sdk.mdx +17 -17
- package/docs/core-concepts/deployments/architecture.mdx +152 -0
- package/docs/core-concepts/email/architecture.mdx +4 -2
- package/docs/core-concepts/functions/architecture.mdx +1 -1
- package/docs/core-concepts/functions/sdk.mdx +0 -1
- package/docs/core-concepts/realtime/architecture.mdx +1 -1
- package/docs/core-concepts/storage/architecture.mdx +1 -1
- package/docs/core-concepts/storage/sdk.mdx +25 -25
- package/docs/docs.json +14 -6
- package/docs/favicon.png +0 -0
- package/docs/favicon.svg +3 -18
- package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
- package/docs/images/changelog/dec-2025/moreModels.png +0 -0
- package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
- package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
- package/docs/images/changelog/dec-2025/realtime2.png +0 -0
- package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
- package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
- package/docs/images/mcp-setup/claude-code-connect.png +0 -0
- package/docs/images/mcp-setup/cline-1.png +0 -0
- package/docs/images/mcp-setup/cline-2.png +0 -0
- package/docs/images/mcp-setup/cline-3.png +0 -0
- package/docs/images/mcp-setup/connect-project.png +0 -0
- package/docs/images/mcp-setup/copilot-1.png +0 -0
- package/docs/images/mcp-setup/copilot-2.png +0 -0
- package/docs/images/mcp-setup/copilot-3.png +0 -0
- package/docs/images/mcp-setup/mcp-json-1.png +0 -0
- package/docs/images/mcp-setup/mcp-json-2.png +0 -0
- package/docs/images/mcp-setup/qoder-1.png +0 -0
- package/docs/images/mcp-setup/qoder-2.png +0 -0
- package/docs/images/mcp-setup/roocode-1.png +0 -0
- package/docs/images/mcp-setup/roocode-2.png +0 -0
- package/docs/images/mcp-setup/trae-1.png +0 -0
- package/docs/images/mcp-setup/trae-2.png +0 -0
- package/docs/images/mcp-setup/trae-3.png +0 -0
- package/docs/images/mcp-setup/trae-4.png +0 -0
- package/docs/images/mcp-setup/trae-5.png +0 -0
- package/docs/images/mcp-setup/windsurf-1.png +0 -0
- package/docs/images/mcp-setup/windsurf-2.png +0 -0
- package/docs/insforge-instructions-sdk.md +7 -3
- package/docs/introduction.mdx +9 -8
- package/docs/mcp-setup.mdx +332 -0
- package/docs/oauth-server.mdx +563 -0
- package/docs/partnership.mdx +79 -10
- package/docs/quickstart.mdx +1 -1
- package/docs/vscode-extension.mdx +74 -0
- package/eslint.config.js +1 -0
- package/examples/response-examples.md +1 -1
- package/frontend/package.json +1 -1
- package/frontend/src/App.tsx +8 -3
- package/frontend/src/assets/logos/antigravity.svg +1 -0
- package/frontend/src/assets/logos/copilot.svg +10 -0
- package/frontend/src/assets/logos/deepseek.svg +139 -0
- package/frontend/src/assets/logos/kiro.svg +9 -0
- package/frontend/src/assets/logos/qoder.svg +4 -0
- package/frontend/src/assets/logos/qwen.svg +15 -0
- package/frontend/src/components/CodeBlock.tsx +2 -2
- package/frontend/src/components/ConnectCTA.tsx +3 -2
- package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
- package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
- package/frontend/src/components/datagrid/index.ts +1 -1
- package/frontend/src/components/index.ts +0 -1
- package/frontend/src/components/layout/AppHeader.tsx +4 -27
- package/frontend/src/components/layout/AppSidebar.tsx +85 -100
- package/frontend/src/components/layout/Layout.tsx +34 -32
- package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
- package/frontend/src/components/radix/Select.tsx +151 -151
- package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
- package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
- package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
- package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
- package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
- package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
- package/frontend/src/features/ai/components/index.ts +6 -6
- package/frontend/src/features/ai/helpers.ts +147 -141
- package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
- package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
- package/frontend/src/features/auth/components/index.ts +5 -5
- package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
- package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
- package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
- package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
- package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
- package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
- package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
- package/frontend/src/features/database/constants.ts +16 -28
- package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
- package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
- package/frontend/src/features/database/hooks/useTables.ts +5 -7
- package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
- package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
- package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
- package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
- package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
- package/frontend/src/features/database/services/advance.service.ts +1 -15
- package/frontend/src/features/database/services/record.service.ts +4 -20
- package/frontend/src/features/database/services/table.service.ts +1 -4
- package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
- package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
- package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
- package/frontend/src/features/database/templates/notion-clone.ts +8 -8
- package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
- package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
- package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
- package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
- package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
- package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
- package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
- package/frontend/src/features/functions/components/index.ts +5 -5
- package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
- package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
- package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
- package/frontend/src/features/functions/services/function.service.ts +8 -25
- package/frontend/src/features/functions/services/secret.service.ts +23 -41
- package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
- package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
- package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
- package/frontend/src/features/logs/components/index.ts +1 -0
- package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
- package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
- package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
- package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
- package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
- package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
- package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
- package/frontend/src/features/onboard/components/index.ts +9 -4
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
- package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
- package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
- package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
- package/frontend/src/features/onboard/index.ts +17 -13
- package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
- package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
- package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
- package/frontend/src/index.css +249 -249
- package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
- package/frontend/src/lib/hooks/useMetadata.ts +45 -1
- package/frontend/src/lib/hooks/useModal.tsx +2 -0
- package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
- package/frontend/src/lib/services/metadata.service.ts +20 -3
- package/frontend/src/lib/utils/menuItems.ts +223 -207
- package/frontend/src/lib/utils/utils.ts +196 -196
- package/functions/server.ts +315 -315
- package/functions/worker-template.js +1 -1
- package/openapi/ai.yaml +115 -5
- package/openapi/auth.yaml +97 -17
- package/openapi/logs.yaml +0 -2
- package/openapi/metadata.yaml +0 -2
- package/openapi/records.yaml +21 -21
- package/openapi/tables.yaml +1 -2
- package/package.json +1 -1
- package/shared-schemas/package.json +1 -1
- package/shared-schemas/src/ai-api.schema.ts +251 -143
- package/shared-schemas/src/ai.schema.ts +63 -63
- package/shared-schemas/src/auth-api.schema.ts +34 -6
- package/shared-schemas/src/auth.schema.ts +17 -10
- package/shared-schemas/src/cloud-events.schema.ts +26 -0
- package/shared-schemas/src/deployments-api.schema.ts +55 -0
- package/shared-schemas/src/deployments.schema.ts +30 -0
- package/shared-schemas/src/docs.schema.ts +8 -2
- package/shared-schemas/src/email-api.schema.ts +30 -30
- package/shared-schemas/src/functions-api.schema.ts +13 -4
- package/shared-schemas/src/functions.schema.ts +1 -1
- package/shared-schemas/src/index.ts +22 -18
- package/shared-schemas/src/metadata.schema.ts +30 -4
- package/shared-schemas/src/secrets-api.schema.ts +44 -0
- package/shared-schemas/src/secrets.schema.ts +15 -0
- package/zeabur/README.md +13 -0
- package/zeabur/template.yml +20 -51
- package/backend/src/types/profile.ts +0 -55
- package/frontend/src/components/ProjectInfoModal.tsx +0 -128
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
|
|
2
|
+
import { CopyButton, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components';
|
|
3
|
+
import { ShowPasswordButton } from './ShowPasswordButton';
|
|
4
|
+
import { useDatabaseConnectionString, useDatabasePassword } from '@/lib/hooks/useMetadata';
|
|
5
|
+
import { cn } from '@/lib/utils/utils';
|
|
6
|
+
|
|
7
|
+
interface ParameterRowProps {
|
|
8
|
+
label: string;
|
|
9
|
+
value: string | number | undefined;
|
|
10
|
+
copyValue?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const RESET_TIMEOUT_MS = 2000;
|
|
14
|
+
|
|
15
|
+
function ParameterRow({ label, value, copyValue }: ParameterRowProps) {
|
|
16
|
+
const [copied, setCopied] = useState(false);
|
|
17
|
+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
18
|
+
|
|
19
|
+
const textToCopy = copyValue ?? String(value ?? '');
|
|
20
|
+
const displayValue = value ?? '-';
|
|
21
|
+
const hasCopyableValue = value !== undefined && value !== null && value !== '';
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
return () => {
|
|
25
|
+
if (timeoutRef.current) {
|
|
26
|
+
clearTimeout(timeoutRef.current);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
const handleCopy = useCallback(() => {
|
|
32
|
+
if (!hasCopyableValue) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (timeoutRef.current) {
|
|
37
|
+
clearTimeout(timeoutRef.current);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
navigator.clipboard
|
|
41
|
+
.writeText(textToCopy)
|
|
42
|
+
.then(() => {
|
|
43
|
+
setCopied(true);
|
|
44
|
+
timeoutRef.current = setTimeout(() => {
|
|
45
|
+
setCopied(false);
|
|
46
|
+
timeoutRef.current = null;
|
|
47
|
+
}, RESET_TIMEOUT_MS);
|
|
48
|
+
})
|
|
49
|
+
.catch((error) => {
|
|
50
|
+
console.error('Failed to copy to clipboard:', error);
|
|
51
|
+
});
|
|
52
|
+
}, [hasCopyableValue, textToCopy]);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className="group flex items-center gap-2">
|
|
56
|
+
<span className="text-gray-400 dark:text-neutral-500 text-sm">{label}:</span>
|
|
57
|
+
<TooltipProvider>
|
|
58
|
+
<Tooltip open={copied}>
|
|
59
|
+
<TooltipTrigger asChild>
|
|
60
|
+
<button
|
|
61
|
+
type="button"
|
|
62
|
+
className={cn(
|
|
63
|
+
'text-gray-700 dark:text-neutral-300 text-sm',
|
|
64
|
+
hasCopyableValue &&
|
|
65
|
+
'cursor-pointer hover:text-gray-900 dark:hover:text-neutral-100 transition-colors'
|
|
66
|
+
)}
|
|
67
|
+
disabled={!hasCopyableValue}
|
|
68
|
+
aria-label={`Copy ${label}`}
|
|
69
|
+
onClick={handleCopy}
|
|
70
|
+
>
|
|
71
|
+
{displayValue}
|
|
72
|
+
</button>
|
|
73
|
+
</TooltipTrigger>
|
|
74
|
+
<TooltipContent side="top" sideOffset={4}>
|
|
75
|
+
<p className="font-medium text-xs leading-5">Copied</p>
|
|
76
|
+
</TooltipContent>
|
|
77
|
+
</Tooltip>
|
|
78
|
+
</TooltipProvider>
|
|
79
|
+
{hasCopyableValue && (
|
|
80
|
+
<CopyButton
|
|
81
|
+
text={textToCopy}
|
|
82
|
+
showText={false}
|
|
83
|
+
className="h-6 w-6 p-1 min-w-0 shrink-0 text-black dark:text-white bg-white dark:bg-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-600 border-none opacity-0 group-hover:opacity-100 transition-opacity"
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface ConnectionStringSectionProps {
|
|
91
|
+
className?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function ConnectionStringSection({ className }: ConnectionStringSectionProps) {
|
|
95
|
+
const [showConnectionPassword, setShowConnectionPassword] = useState(false);
|
|
96
|
+
const [showParamsPassword, setShowParamsPassword] = useState(false);
|
|
97
|
+
|
|
98
|
+
const { connectionData, isLoading: isConnectionLoading } = useDatabaseConnectionString();
|
|
99
|
+
const { passwordData } = useDatabasePassword();
|
|
100
|
+
|
|
101
|
+
const dbParams = connectionData?.parameters;
|
|
102
|
+
const dbPassword = passwordData?.databasePassword || '';
|
|
103
|
+
const maskedPassword = dbParams?.password || '********';
|
|
104
|
+
|
|
105
|
+
const connectionStringDisplay = useMemo(() => {
|
|
106
|
+
if (!connectionData?.connectionURL) {
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
if (showConnectionPassword && dbPassword) {
|
|
110
|
+
return connectionData.connectionURL.replace('********', dbPassword);
|
|
111
|
+
}
|
|
112
|
+
return connectionData.connectionURL;
|
|
113
|
+
}, [connectionData?.connectionURL, showConnectionPassword, dbPassword]);
|
|
114
|
+
|
|
115
|
+
const connectionStringClipboard = useMemo(() => {
|
|
116
|
+
if (!connectionData?.connectionURL || !dbPassword) {
|
|
117
|
+
return connectionData?.connectionURL || '';
|
|
118
|
+
}
|
|
119
|
+
return connectionData.connectionURL.replace('********', dbPassword);
|
|
120
|
+
}, [connectionData?.connectionURL, dbPassword]);
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div className={cn('flex flex-col gap-6', isConnectionLoading && 'animate-pulse', className)}>
|
|
124
|
+
<p className="text-gray-500 dark:text-neutral-400 text-base leading-7">
|
|
125
|
+
Ideal for applications with persistent and long-lived connections, such as those running on
|
|
126
|
+
virtual machines or long-standing containers.
|
|
127
|
+
</p>
|
|
128
|
+
|
|
129
|
+
{/* Connection String */}
|
|
130
|
+
<div className="bg-gray-100 dark:bg-neutral-900 rounded p-3">
|
|
131
|
+
<div className="flex items-center justify-between mb-2">
|
|
132
|
+
<div className="bg-gray-200 dark:bg-neutral-700 rounded px-2 h-5 flex items-center justify-center">
|
|
133
|
+
<span className="text-gray-700 dark:text-neutral-50 text-xs">connection string</span>
|
|
134
|
+
</div>
|
|
135
|
+
<div className="flex items-center gap-2">
|
|
136
|
+
<ShowPasswordButton
|
|
137
|
+
show={showConnectionPassword}
|
|
138
|
+
onToggle={() => setShowConnectionPassword(!showConnectionPassword)}
|
|
139
|
+
/>
|
|
140
|
+
<CopyButton
|
|
141
|
+
text={connectionStringClipboard}
|
|
142
|
+
showText={false}
|
|
143
|
+
className="h-6 w-6 p-1 min-w-0 shrink-0 text-black dark:text-white bg-white dark:bg-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-600 border-none"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
<p className="text-gray-700 dark:text-neutral-300 text-sm leading-6 break-words">
|
|
148
|
+
{connectionStringDisplay || 'Loading...'}
|
|
149
|
+
</p>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div className="h-px bg-gray-200 dark:bg-neutral-700" />
|
|
153
|
+
|
|
154
|
+
{/* Parameters */}
|
|
155
|
+
<div className="bg-gray-100 dark:bg-neutral-900 rounded p-3">
|
|
156
|
+
<div className="flex items-center justify-between mb-4">
|
|
157
|
+
<div className="bg-gray-200 dark:bg-neutral-700 rounded px-2 h-5 flex items-center justify-center">
|
|
158
|
+
<span className="text-gray-700 dark:text-neutral-50 text-xs">parameters</span>
|
|
159
|
+
</div>
|
|
160
|
+
<ShowPasswordButton
|
|
161
|
+
show={showParamsPassword}
|
|
162
|
+
onToggle={() => setShowParamsPassword(!showParamsPassword)}
|
|
163
|
+
/>
|
|
164
|
+
</div>
|
|
165
|
+
<div className="flex flex-col gap-3">
|
|
166
|
+
<ParameterRow label="HOST" value={dbParams?.host} />
|
|
167
|
+
<ParameterRow label="DATABASE" value={dbParams?.database} />
|
|
168
|
+
<ParameterRow label="USER" value={dbParams?.user} />
|
|
169
|
+
<ParameterRow label="PORT" value={dbParams?.port} />
|
|
170
|
+
<ParameterRow
|
|
171
|
+
label="PASSWORD"
|
|
172
|
+
value={showParamsPassword ? dbPassword || maskedPassword : maskedPassword}
|
|
173
|
+
copyValue={dbPassword || maskedPassword}
|
|
174
|
+
/>
|
|
175
|
+
<ParameterRow label="SSL" value={dbParams?.sslmode} />
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { useState, useMemo } from 'react';
|
|
2
|
+
import { ChevronDown } from 'lucide-react';
|
|
3
|
+
import {
|
|
4
|
+
CodeBlock,
|
|
5
|
+
CopyButton,
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
DropdownMenuContent,
|
|
8
|
+
DropdownMenuItem,
|
|
9
|
+
DropdownMenuTrigger,
|
|
10
|
+
} from '@/components';
|
|
11
|
+
import { CursorDeeplinkGenerator } from './mcp/CursorDeeplinkGenerator';
|
|
12
|
+
import { QoderDeeplinkGenerator } from './mcp/QoderDeeplinkGenerator';
|
|
13
|
+
import { MCP_AGENTS, GenerateInstallCommand, createMCPConfig, type MCPAgent } from './mcp/helpers';
|
|
14
|
+
import { cn } from '@/lib/utils/utils';
|
|
15
|
+
|
|
16
|
+
interface McpConnectionSectionProps {
|
|
17
|
+
apiKey: string;
|
|
18
|
+
appUrl: string;
|
|
19
|
+
isLoading?: boolean;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function McpConnectionSection({
|
|
24
|
+
apiKey,
|
|
25
|
+
appUrl,
|
|
26
|
+
isLoading = false,
|
|
27
|
+
className,
|
|
28
|
+
}: McpConnectionSectionProps) {
|
|
29
|
+
const [selectedAgent, setSelectedAgent] = useState<MCPAgent>(MCP_AGENTS[0]);
|
|
30
|
+
|
|
31
|
+
const installCommand = useMemo(() => {
|
|
32
|
+
return GenerateInstallCommand(selectedAgent, apiKey);
|
|
33
|
+
}, [selectedAgent, apiKey]);
|
|
34
|
+
|
|
35
|
+
const mcpJsonConfig = useMemo(() => {
|
|
36
|
+
const config = createMCPConfig(apiKey, 'macos-linux', appUrl);
|
|
37
|
+
return JSON.stringify(config, null, 2);
|
|
38
|
+
}, [apiKey, appUrl]);
|
|
39
|
+
|
|
40
|
+
const testPrompt =
|
|
41
|
+
"I'm using InsForge as my backend platform, call InsForge MCP's fetch-docs tool to learn about InsForge instructions.";
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className={cn('flex flex-col gap-6', className)}>
|
|
45
|
+
<p className="text-gray-500 dark:text-neutral-400 text-base leading-7">
|
|
46
|
+
Install the MCP server so your coding agent can access and build the backend.
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
{/* Agent Selector Dropdown */}
|
|
50
|
+
<DropdownMenu>
|
|
51
|
+
<DropdownMenuTrigger asChild>
|
|
52
|
+
<button className="w-40 bg-gray-100 dark:bg-[rgba(0,0,0,0.12)] border border-gray-300 dark:border-[rgba(255,255,255,0.24)] rounded flex items-center justify-between px-2 py-1 cursor-pointer">
|
|
53
|
+
<div className="flex items-center gap-2">
|
|
54
|
+
{selectedAgent.logo && (
|
|
55
|
+
<div className="w-6 h-6 flex items-center justify-center">{selectedAgent.logo}</div>
|
|
56
|
+
)}
|
|
57
|
+
<span className="text-gray-900 dark:text-white text-sm font-medium">
|
|
58
|
+
{selectedAgent.displayName}
|
|
59
|
+
</span>
|
|
60
|
+
</div>
|
|
61
|
+
<ChevronDown className="w-5 h-5 text-gray-400 dark:text-neutral-400" />
|
|
62
|
+
</button>
|
|
63
|
+
</DropdownMenuTrigger>
|
|
64
|
+
<DropdownMenuContent
|
|
65
|
+
align="start"
|
|
66
|
+
className="w-40 bg-white dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded shadow-lg p-0"
|
|
67
|
+
>
|
|
68
|
+
{MCP_AGENTS.map((agent) => (
|
|
69
|
+
<DropdownMenuItem
|
|
70
|
+
key={agent.id}
|
|
71
|
+
onSelect={() => setSelectedAgent(agent)}
|
|
72
|
+
className="flex items-center gap-2 px-2 py-2 text-gray-900 dark:text-white text-sm hover:bg-gray-100 dark:hover:bg-neutral-700 cursor-pointer"
|
|
73
|
+
>
|
|
74
|
+
{agent.logo && (
|
|
75
|
+
<div className="w-6 h-6 flex items-center justify-center">{agent.logo}</div>
|
|
76
|
+
)}
|
|
77
|
+
<span className="font-medium">{agent.displayName}</span>
|
|
78
|
+
</DropdownMenuItem>
|
|
79
|
+
))}
|
|
80
|
+
</DropdownMenuContent>
|
|
81
|
+
</DropdownMenu>
|
|
82
|
+
|
|
83
|
+
{/* Step 1 - Conditional based on agent */}
|
|
84
|
+
{selectedAgent.id === 'cursor' ? (
|
|
85
|
+
<div className="flex flex-col gap-3">
|
|
86
|
+
<p className="text-gray-900 dark:text-white text-sm">
|
|
87
|
+
<span className="font-semibold leading-5">1.</span>
|
|
88
|
+
<span className="leading-6"> Install in one click</span>
|
|
89
|
+
</p>
|
|
90
|
+
<div className="w-fit">
|
|
91
|
+
<CursorDeeplinkGenerator apiKey={apiKey} os="macos-linux" />
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
) : selectedAgent.id === 'qoder' ? (
|
|
95
|
+
<div className="flex flex-col gap-3">
|
|
96
|
+
<p className="text-gray-900 dark:text-white text-sm">
|
|
97
|
+
<span className="font-semibold leading-5">1.</span>
|
|
98
|
+
<span className="leading-6"> Install in one click</span>
|
|
99
|
+
</p>
|
|
100
|
+
<div className="w-fit">
|
|
101
|
+
<QoderDeeplinkGenerator apiKey={apiKey} os="macos-linux" />
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
) : selectedAgent.id === 'mcp' ? (
|
|
105
|
+
<div className="flex flex-col gap-3">
|
|
106
|
+
<p className="text-gray-900 dark:text-white text-sm">
|
|
107
|
+
<span className="font-semibold leading-5">1.</span>
|
|
108
|
+
<span className="leading-6">
|
|
109
|
+
{' '}
|
|
110
|
+
Copy the configuration below and add it to your AI assistant.
|
|
111
|
+
</span>
|
|
112
|
+
</p>
|
|
113
|
+
<div className="bg-gray-100 dark:bg-neutral-900 rounded overflow-hidden flex flex-col h-[320px] w-full">
|
|
114
|
+
{/* Header - fixed at top */}
|
|
115
|
+
<div className="bg-gray-100 dark:bg-neutral-900 flex items-center justify-between p-3">
|
|
116
|
+
<div className="bg-gray-200 dark:bg-neutral-700 rounded px-2">
|
|
117
|
+
<span className="text-gray-700 dark:text-neutral-50 text-xs">
|
|
118
|
+
MCP Configuration
|
|
119
|
+
</span>
|
|
120
|
+
</div>
|
|
121
|
+
<CopyButton
|
|
122
|
+
text={mcpJsonConfig}
|
|
123
|
+
showText={false}
|
|
124
|
+
className="h-6 w-6 p-1 bg-white dark:bg-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-600 border-none rounded-md shadow-sm min-w-0 text-black dark:text-white"
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
{/* Scrollable content */}
|
|
128
|
+
<div className="flex-1 overflow-auto p-3">
|
|
129
|
+
<pre className="text-gray-700 dark:text-neutral-300 text-sm leading-6 m-0 whitespace-pre-wrap break-all">
|
|
130
|
+
<code>{mcpJsonConfig}</code>
|
|
131
|
+
</pre>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
) : (
|
|
136
|
+
<div className="flex flex-col gap-3">
|
|
137
|
+
<p className="text-gray-900 dark:text-white text-sm">
|
|
138
|
+
<span className="font-semibold leading-5">1.</span>
|
|
139
|
+
<span className="leading-6"> Install in one click</span>
|
|
140
|
+
</p>
|
|
141
|
+
<CodeBlock
|
|
142
|
+
code={installCommand}
|
|
143
|
+
label="Terminal Command"
|
|
144
|
+
className={cn(isLoading && 'animate-pulse')}
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
)}
|
|
148
|
+
|
|
149
|
+
{/* Step 2 */}
|
|
150
|
+
<div className="flex flex-col gap-3">
|
|
151
|
+
<p className="text-gray-900 dark:text-white text-sm">
|
|
152
|
+
<span className="font-semibold leading-5">2.</span>
|
|
153
|
+
<span className="leading-6"> Check for connection using this prompt</span>
|
|
154
|
+
</p>
|
|
155
|
+
<CodeBlock code={testPrompt} label="prompt" className="bg-gray-100 dark:bg-neutral-900" />
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useEffect, useCallback } from 'react';
|
|
2
|
+
import { useModal } from '@/lib/hooks/useModal';
|
|
3
|
+
import { parseCloudEvent } from '@/lib/utils/cloudMessaging';
|
|
4
|
+
import { isIframe } from '@/lib/utils/utils';
|
|
5
|
+
import { useMcpUsage } from '@/features/logs/hooks/useMcpUsage';
|
|
6
|
+
import { getOnboardingSkipped, setOnboardingSkipped } from './OnboardingModal';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* OnboardingController manages onboarding modal state:
|
|
10
|
+
* - Handles Cloud parent messages in iframe mode
|
|
11
|
+
* - Auto-opens onboarding for new users (non-iframe mode)
|
|
12
|
+
* - Auto-closes onboarding when MCP connection is established (all modes)
|
|
13
|
+
*/
|
|
14
|
+
export function OnboardingController() {
|
|
15
|
+
const { setOnboardingModalOpen } = useModal();
|
|
16
|
+
const { hasCompletedOnboarding, isLoading: isMcpLoading } = useMcpUsage();
|
|
17
|
+
|
|
18
|
+
// Handle messages from Cloud parent window (iframe mode only)
|
|
19
|
+
const handleMessage = useCallback(
|
|
20
|
+
(event: MessageEvent) => {
|
|
21
|
+
if (!isIframe()) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const result = parseCloudEvent(event.data);
|
|
26
|
+
if (!result.ok) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const cloudEvent = result.data;
|
|
31
|
+
|
|
32
|
+
switch (cloudEvent.type) {
|
|
33
|
+
case 'SHOW_ONBOARDING_OVERLAY':
|
|
34
|
+
setOnboardingModalOpen(true);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
[setOnboardingModalOpen]
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
window.addEventListener('message', handleMessage);
|
|
43
|
+
return () => {
|
|
44
|
+
window.removeEventListener('message', handleMessage);
|
|
45
|
+
};
|
|
46
|
+
}, [handleMessage]);
|
|
47
|
+
|
|
48
|
+
// Auto-open onboarding modal for new users (non-iframe mode only)
|
|
49
|
+
// In iframe mode, Cloud controls when to show the modal via messages
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (isIframe()) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!isMcpLoading && !hasCompletedOnboarding && !getOnboardingSkipped()) {
|
|
55
|
+
setOnboardingModalOpen(true);
|
|
56
|
+
}
|
|
57
|
+
}, [isMcpLoading, hasCompletedOnboarding, setOnboardingModalOpen]);
|
|
58
|
+
|
|
59
|
+
// Auto-close onboarding modal when MCP connection is established (all modes)
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!isMcpLoading && hasCompletedOnboarding) {
|
|
62
|
+
setOnboardingModalOpen(false);
|
|
63
|
+
setOnboardingSkipped(false);
|
|
64
|
+
}
|
|
65
|
+
}, [hasCompletedOnboarding, isMcpLoading, setOnboardingModalOpen]);
|
|
66
|
+
|
|
67
|
+
return null;
|
|
68
|
+
}
|