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
|
@@ -1,196 +1,196 @@
|
|
|
1
|
-
import { ColumnType } from '@insforge/shared-schemas';
|
|
2
|
-
import { type ClassValue, clsx } from 'clsx';
|
|
3
|
-
import { twMerge } from 'tailwind-merge';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
import { format, parse, isValid, parseISO } from 'date-fns';
|
|
6
|
-
import {
|
|
7
|
-
uuidSchema,
|
|
8
|
-
integerSchema,
|
|
9
|
-
floatSchema,
|
|
10
|
-
booleanSchema,
|
|
11
|
-
dateSchema,
|
|
12
|
-
dateTimeSchema,
|
|
13
|
-
jsonSchema,
|
|
14
|
-
stringSchema,
|
|
15
|
-
} from './schemaValidations';
|
|
16
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
17
|
-
import type { ConvertedValue, DisplayValue, ValueConversionResult } from '@/components/datagrid';
|
|
18
|
-
|
|
19
|
-
export function cn(...inputs: ClassValue[]) {
|
|
20
|
-
return twMerge(clsx(inputs));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Convert and validate a string value based on the specified ColumnType
|
|
25
|
-
*/
|
|
26
|
-
export function convertValueForColumn(
|
|
27
|
-
type: ColumnType | string,
|
|
28
|
-
value: string | null | undefined
|
|
29
|
-
): ValueConversionResult {
|
|
30
|
-
try {
|
|
31
|
-
let convertedValue;
|
|
32
|
-
|
|
33
|
-
switch (type) {
|
|
34
|
-
case ColumnType.UUID:
|
|
35
|
-
convertedValue = uuidSchema.parse(value);
|
|
36
|
-
break;
|
|
37
|
-
case ColumnType.INTEGER:
|
|
38
|
-
convertedValue = integerSchema.parse(value);
|
|
39
|
-
break;
|
|
40
|
-
case ColumnType.FLOAT:
|
|
41
|
-
convertedValue = floatSchema.parse(value);
|
|
42
|
-
break;
|
|
43
|
-
case ColumnType.BOOLEAN:
|
|
44
|
-
convertedValue = booleanSchema.parse(value);
|
|
45
|
-
break;
|
|
46
|
-
case ColumnType.DATE:
|
|
47
|
-
convertedValue = dateSchema.parse(value);
|
|
48
|
-
break;
|
|
49
|
-
case ColumnType.DATETIME:
|
|
50
|
-
convertedValue = dateTimeSchema.parse(value);
|
|
51
|
-
break;
|
|
52
|
-
case ColumnType.JSON:
|
|
53
|
-
convertedValue = jsonSchema.parse(value);
|
|
54
|
-
break;
|
|
55
|
-
case ColumnType.STRING:
|
|
56
|
-
convertedValue = stringSchema.parse(value);
|
|
57
|
-
break;
|
|
58
|
-
default:
|
|
59
|
-
return {
|
|
60
|
-
success: false,
|
|
61
|
-
error: `Unsupported column type: ${type}`,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
success: true,
|
|
67
|
-
value: convertedValue,
|
|
68
|
-
};
|
|
69
|
-
} catch (error) {
|
|
70
|
-
if (error instanceof z.ZodError) {
|
|
71
|
-
return {
|
|
72
|
-
success: false,
|
|
73
|
-
error: error.errors[0]?.message || 'Validation failed',
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
return {
|
|
77
|
-
success: false,
|
|
78
|
-
error: error instanceof Error ? error.message : 'Unknown conversion error',
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Generate a UUID v4 using the uuid library
|
|
85
|
-
* Works in all browsers and contexts (secure and non-secure)
|
|
86
|
-
* Uses crypto.getRandomValues when available, falls back to Math.random
|
|
87
|
-
*/
|
|
88
|
-
export function generateUUID(): string {
|
|
89
|
-
return uuidv4();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Centralized value formatter that handles all data types consistently
|
|
94
|
-
* Converts database values to formatted display strings for UI components
|
|
95
|
-
*/
|
|
96
|
-
export function formatValueForDisplay(value: ConvertedValue, type?: ColumnType): DisplayValue {
|
|
97
|
-
// Handle null/undefined values
|
|
98
|
-
if (isEmptyValue(value)) {
|
|
99
|
-
return 'null';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Handle different column types
|
|
103
|
-
switch (type) {
|
|
104
|
-
case ColumnType.BOOLEAN:
|
|
105
|
-
return value ? 'True' : 'False';
|
|
106
|
-
|
|
107
|
-
case ColumnType.DATE: {
|
|
108
|
-
const date = parse(String(value), 'yyyy-MM-dd', new Date());
|
|
109
|
-
if (!isValid(date)) {
|
|
110
|
-
return String(value);
|
|
111
|
-
}
|
|
112
|
-
const displayValue = format(date, 'MMM dd, yyyy');
|
|
113
|
-
return displayValue;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
case ColumnType.DATETIME: {
|
|
117
|
-
const date = parseISO(String(value));
|
|
118
|
-
if (!isValid(date)) {
|
|
119
|
-
return String(value);
|
|
120
|
-
}
|
|
121
|
-
const displayValue = format(date, 'MMM dd, yyyy, hh:mm a');
|
|
122
|
-
return displayValue;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
case ColumnType.JSON: {
|
|
126
|
-
try {
|
|
127
|
-
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
128
|
-
const formatted =
|
|
129
|
-
parsed && typeof parsed === 'object' ? JSON.stringify(parsed) : String(parsed);
|
|
130
|
-
|
|
131
|
-
return formatted;
|
|
132
|
-
} catch {
|
|
133
|
-
return 'Invalid JSON';
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
case ColumnType.INTEGER:
|
|
138
|
-
case ColumnType.FLOAT: {
|
|
139
|
-
return String(value);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
case ColumnType.UUID:
|
|
143
|
-
case ColumnType.STRING:
|
|
144
|
-
default: {
|
|
145
|
-
// Convert to string and optionally truncate
|
|
146
|
-
return String(value);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Check if a value is considered empty for database purposes
|
|
153
|
-
*/
|
|
154
|
-
export function isEmptyValue(value: unknown): boolean {
|
|
155
|
-
return value === null || value === undefined || value === '';
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export const isInsForgeCloudProject = () => {
|
|
159
|
-
return window.location.hostname.endsWith('.insforge.app');
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
export const getBackendUrl = () => {
|
|
163
|
-
const isHttp = window.location.protocol === 'http:';
|
|
164
|
-
return isHttp ? 'http://localhost:7130' : window.location.origin;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
export const isIframe = () => {
|
|
168
|
-
return window.self !== window.top;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Formats a timestamp string to a human-readable format with time
|
|
173
|
-
* Used consistently across the application for displaying timestamps
|
|
174
|
-
* @param timestamp - ISO timestamp string
|
|
175
|
-
* @returns Formatted date string (e.g., "Jan 15, 2025, 03:30 PM")
|
|
176
|
-
*/
|
|
177
|
-
export function formatTime(timestamp: string): string {
|
|
178
|
-
const date = parseISO(timestamp);
|
|
179
|
-
if (!isValid(date)) {
|
|
180
|
-
return timestamp; // Return original if invalid
|
|
181
|
-
}
|
|
182
|
-
return format(date, 'MMM dd, yyyy, hh:mm a');
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Formats a timestamp string to a date-only format
|
|
187
|
-
* @param timestamp - ISO timestamp string
|
|
188
|
-
* @returns Formatted date string (e.g., "Jan 15, 2025")
|
|
189
|
-
*/
|
|
190
|
-
export function formatDate(timestamp: string): string {
|
|
191
|
-
const date = parseISO(timestamp);
|
|
192
|
-
if (!isValid(date)) {
|
|
193
|
-
return timestamp; // Return original if invalid
|
|
194
|
-
}
|
|
195
|
-
return format(date, 'MMM dd, yyyy');
|
|
196
|
-
}
|
|
1
|
+
import { ColumnType } from '@insforge/shared-schemas';
|
|
2
|
+
import { type ClassValue, clsx } from 'clsx';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { format, parse, isValid, parseISO } from 'date-fns';
|
|
6
|
+
import {
|
|
7
|
+
uuidSchema,
|
|
8
|
+
integerSchema,
|
|
9
|
+
floatSchema,
|
|
10
|
+
booleanSchema,
|
|
11
|
+
dateSchema,
|
|
12
|
+
dateTimeSchema,
|
|
13
|
+
jsonSchema,
|
|
14
|
+
stringSchema,
|
|
15
|
+
} from './schemaValidations';
|
|
16
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
17
|
+
import type { ConvertedValue, DisplayValue, ValueConversionResult } from '@/components/datagrid';
|
|
18
|
+
|
|
19
|
+
export function cn(...inputs: ClassValue[]) {
|
|
20
|
+
return twMerge(clsx(inputs));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Convert and validate a string value based on the specified ColumnType
|
|
25
|
+
*/
|
|
26
|
+
export function convertValueForColumn(
|
|
27
|
+
type: ColumnType | string,
|
|
28
|
+
value: string | null | undefined
|
|
29
|
+
): ValueConversionResult {
|
|
30
|
+
try {
|
|
31
|
+
let convertedValue;
|
|
32
|
+
|
|
33
|
+
switch (type) {
|
|
34
|
+
case ColumnType.UUID:
|
|
35
|
+
convertedValue = uuidSchema.parse(value);
|
|
36
|
+
break;
|
|
37
|
+
case ColumnType.INTEGER:
|
|
38
|
+
convertedValue = integerSchema.parse(value);
|
|
39
|
+
break;
|
|
40
|
+
case ColumnType.FLOAT:
|
|
41
|
+
convertedValue = floatSchema.parse(value);
|
|
42
|
+
break;
|
|
43
|
+
case ColumnType.BOOLEAN:
|
|
44
|
+
convertedValue = booleanSchema.parse(value);
|
|
45
|
+
break;
|
|
46
|
+
case ColumnType.DATE:
|
|
47
|
+
convertedValue = dateSchema.parse(value);
|
|
48
|
+
break;
|
|
49
|
+
case ColumnType.DATETIME:
|
|
50
|
+
convertedValue = dateTimeSchema.parse(value);
|
|
51
|
+
break;
|
|
52
|
+
case ColumnType.JSON:
|
|
53
|
+
convertedValue = jsonSchema.parse(value);
|
|
54
|
+
break;
|
|
55
|
+
case ColumnType.STRING:
|
|
56
|
+
convertedValue = stringSchema.parse(value);
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: `Unsupported column type: ${type}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
success: true,
|
|
67
|
+
value: convertedValue,
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (error instanceof z.ZodError) {
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
error: error.errors[0]?.message || 'Validation failed',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
error: error instanceof Error ? error.message : 'Unknown conversion error',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Generate a UUID v4 using the uuid library
|
|
85
|
+
* Works in all browsers and contexts (secure and non-secure)
|
|
86
|
+
* Uses crypto.getRandomValues when available, falls back to Math.random
|
|
87
|
+
*/
|
|
88
|
+
export function generateUUID(): string {
|
|
89
|
+
return uuidv4();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Centralized value formatter that handles all data types consistently
|
|
94
|
+
* Converts database values to formatted display strings for UI components
|
|
95
|
+
*/
|
|
96
|
+
export function formatValueForDisplay(value: ConvertedValue, type?: ColumnType): DisplayValue {
|
|
97
|
+
// Handle null/undefined values
|
|
98
|
+
if (isEmptyValue(value)) {
|
|
99
|
+
return 'null';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Handle different column types
|
|
103
|
+
switch (type) {
|
|
104
|
+
case ColumnType.BOOLEAN:
|
|
105
|
+
return value ? 'True' : 'False';
|
|
106
|
+
|
|
107
|
+
case ColumnType.DATE: {
|
|
108
|
+
const date = parse(String(value), 'yyyy-MM-dd', new Date());
|
|
109
|
+
if (!isValid(date)) {
|
|
110
|
+
return String(value);
|
|
111
|
+
}
|
|
112
|
+
const displayValue = format(date, 'MMM dd, yyyy');
|
|
113
|
+
return displayValue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
case ColumnType.DATETIME: {
|
|
117
|
+
const date = parseISO(String(value));
|
|
118
|
+
if (!isValid(date)) {
|
|
119
|
+
return String(value);
|
|
120
|
+
}
|
|
121
|
+
const displayValue = format(date, 'MMM dd, yyyy, hh:mm a');
|
|
122
|
+
return displayValue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
case ColumnType.JSON: {
|
|
126
|
+
try {
|
|
127
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
128
|
+
const formatted =
|
|
129
|
+
parsed && typeof parsed === 'object' ? JSON.stringify(parsed) : String(parsed);
|
|
130
|
+
|
|
131
|
+
return formatted;
|
|
132
|
+
} catch {
|
|
133
|
+
return 'Invalid JSON';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
case ColumnType.INTEGER:
|
|
138
|
+
case ColumnType.FLOAT: {
|
|
139
|
+
return String(value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case ColumnType.UUID:
|
|
143
|
+
case ColumnType.STRING:
|
|
144
|
+
default: {
|
|
145
|
+
// Convert to string and optionally truncate
|
|
146
|
+
return String(value);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Check if a value is considered empty for database purposes
|
|
153
|
+
*/
|
|
154
|
+
export function isEmptyValue(value: unknown): boolean {
|
|
155
|
+
return value === null || value === undefined || value === '';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export const isInsForgeCloudProject = () => {
|
|
159
|
+
return window.location.hostname.endsWith('.insforge.app');
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export const getBackendUrl = () => {
|
|
163
|
+
const isHttp = window.location.protocol === 'http:';
|
|
164
|
+
return isHttp ? 'http://localhost:7130' : window.location.origin;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export const isIframe = () => {
|
|
168
|
+
return window.self !== window.top;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Formats a timestamp string to a human-readable format with time
|
|
173
|
+
* Used consistently across the application for displaying timestamps
|
|
174
|
+
* @param timestamp - ISO timestamp string
|
|
175
|
+
* @returns Formatted date string (e.g., "Jan 15, 2025, 03:30 PM")
|
|
176
|
+
*/
|
|
177
|
+
export function formatTime(timestamp: string): string {
|
|
178
|
+
const date = parseISO(timestamp);
|
|
179
|
+
if (!isValid(date)) {
|
|
180
|
+
return timestamp; // Return original if invalid
|
|
181
|
+
}
|
|
182
|
+
return format(date, 'MMM dd, yyyy, hh:mm a');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Formats a timestamp string to a date-only format
|
|
187
|
+
* @param timestamp - ISO timestamp string
|
|
188
|
+
* @returns Formatted date string (e.g., "Jan 15, 2025")
|
|
189
|
+
*/
|
|
190
|
+
export function formatDate(timestamp: string): string {
|
|
191
|
+
const date = parseISO(timestamp);
|
|
192
|
+
if (!isValid(date)) {
|
|
193
|
+
return timestamp; // Return original if invalid
|
|
194
|
+
}
|
|
195
|
+
return format(date, 'MMM dd, yyyy');
|
|
196
|
+
}
|