PluginProbe
The Innovative Form Builder – IvyForms / 0.6.1.1
The Innovative Form Builder – IvyForms v0.6.1.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / constants / integrations.ts

integrations.ts in The Innovative Form Builder – IvyForms 0.6.1.1, at frontend/src/constants/integrations.ts

170 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useApiClient } from '@/composables/useApiClient'
2
3 /**
4 * Backend integration configuration interface
5 */
6 interface BackendIntegrationConfig {
7 slug: string
8 label: string
9 component: string
10 icon?: string
11 description?: string
12 category?: string
13 requiresAuth?: boolean
14 plan?: string
15 settingsSchema?: Record<string, unknown>
16 learnMoreUrl?: string
17 }
18
19 /**
20 * Backend-registered integrations cache
21 * Populated dynamically from the IntegrationRegistry via REST API
22 */
23 let integrationsCache: Integration[] | null = null
24 let integrationsFetchPromise: Promise<Integration[]> | null = null
25
26 /**
27 * Fetch integrations from backend registry
28 * Uses caching to avoid multiple API calls
29 */
30 async function fetchBackendIntegrations(): Promise<Integration[]> {
31 // Return cached value if available
32 if (integrationsCache) {
33 return integrationsCache
34 }
35
36 // Return existing promise if fetch is in progress
37 if (integrationsFetchPromise) {
38 return integrationsFetchPromise
39 }
40
41 // Start new fetch
42 integrationsFetchPromise = (async () => {
43 try {
44 const { request } = useApiClient()
45 const response = await request<{
46 success: boolean
47 data: Record<string, BackendIntegrationConfig>
48 }>('integrations')
49
50 // The API controller returns {success: true, data: {wpdatatables: {...}, mailchimp: {...}}}
51 // useApiClient wraps it in {message: 'OK', data: {success: true, data: {...}}}
52 // So we need to unwrap twice: response.data.data.data
53 const wrappedData = response.data?.data // {success: true, data: {...}}
54 const backendData = wrappedData?.data as Record<string, BackendIntegrationConfig> // {wpdatatables: {...}, mailchimp: {...}}
55
56 if (!backendData || typeof backendData !== 'object') {
57 throw new Error('Invalid response format')
58 }
59
60 // Transform backend format to frontend format
61 const transformed: Integration[] = Object.entries(backendData).map(([slug, config]) => ({
62 name: config.label, // Translation key from backend (e.g., 'wpdatatables_label')
63 value: slug, // Use slug as value
64 image: config.icon || slug,
65 description: config.description || '', // Translation key from backend (e.g., 'wpdatatables_description')
66 category: config.category || 'Other',
67 type: config.plan === 'lite' ? 'disabled' : 'soon', // Default type, will be updated by useIntegrations
68 searchCategory: config.plan || 'lite',
69 requiredPlan: config.plan !== 'lite' ? config.plan : undefined,
70 component: config.component,
71 learnMoreUrl: config.learnMoreUrl || '',
72 }))
73
74 integrationsCache = transformed
75 return transformed
76 } catch (error) {
77 console.error('Failed to load integrations from backend:', error)
78
79 // Fallback to hardcoded defaults
80 const fallback: Integration[] = [
81 {
82 name: 'wpdatatables',
83 value: 'wpdatatables',
84 image: 'wpdatatables',
85 description: 'wpdt_integration_description',
86 category: 'Data Management',
87 type: 'disabled',
88 searchCategory: 'lite',
89 },
90 ]
91
92 integrationsCache = fallback
93 return fallback
94 } finally {
95 integrationsFetchPromise = null
96 }
97 })()
98
99 return integrationsFetchPromise
100 }
101
102 /**
103 * Get integrations with filters applied
104 * This function applies filters at runtime, allowing Pro to modify integrations
105 *
106 * NOTE: This is now async and should be used with await or in a component setup
107 */
108 export async function getIntegrations(): Promise<Integration[]> {
109 let result = await fetchBackendIntegrations()
110
111 // Allow Pro to extend/filter integrations via dedicated hooks
112 if (typeof window !== 'undefined') {
113 const w = window as Window & {
114 IvyFormsPro?: {
115 integrationsHooks?: Array<(integrations: Integration[]) => Integration[]>
116 }
117 IvyForms?: {
118 hooks?: {
119 applyFilters?: (hookName: string, value: Integration[]) => Integration[]
120 }
121 }
122 }
123
124 // Check Pro-specific hooks first (direct hooks from Pro plugin)
125 const proHooks = w.IvyFormsPro?.integrationsHooks || []
126 for (const hook of proHooks) {
127 result = hook(result)
128 }
129
130 // Also support general filters if defined
131 if (w.IvyForms?.hooks?.applyFilters) {
132 result = w.IvyForms.hooks.applyFilters('ivyforms/integrations/list', result)
133 }
134 }
135
136 return result
137 }
138
139 /**
140 * Clear integrations cache
141 * Useful for forcing a refresh after new integrations are registered
142 */
143 export function clearIntegrationsCache(): void {
144 integrationsCache = null
145 integrationsFetchPromise = null
146 }
147
148 // Remove legacy export - integrations are now loaded dynamically
149
150 export type integrationType =
151 | 'active'
152 | 'disabled'
153 | 'upgrade'
154 | 'proActive'
155 | 'proDisabled'
156 | 'soon'
157
158 export interface Integration {
159 name: string
160 value: string
161 image?: string
162 description: string
163 category: string
164 type: integrationType
165 searchCategory: string
166 requiredPlan?: string // Optional: minimum plan required for Pro integrations
167 component?: string // Component name for settings UI
168 learnMoreUrl?: string // Optional: documentation/learn more URL
169 }
170