Skip to content

Commit 7bb34eb

Browse files
committed
generate grid from the CMS
1 parent 19e0bd3 commit 7bb34eb

File tree

2 files changed

+137
-27
lines changed

2 files changed

+137
-27
lines changed

docs/integrations/index_new.mdx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@ import { IntegrationGrid } from '@site/src/components/IntegrationGrid';
1414

1515
Connect ClickHouse with your favorite tools and services to build powerful data pipelines and analytics workflows.
1616

17-
ClickHouse integrations are organized by type, and their level of support:
18-
19-
| Integration tier | Description |
20-
|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
21-
|**Core integrations:** | these are integrations built or maintained by ClickHouse. They are supported by ClickHouse and live in the ClickHouse GitHub organization. |
22-
|**Partner integrations:** | these are built or maintained, and supported by, third-party software vendors. |
23-
|**Community integrations:**| built or maintained and supported by community members. No direct support is available besides the public GitHub repositories and community Slack channels.|
24-
2517
<IntegrationGrid />
2618

2719
:::note Notice

src/components/IntegrationGrid/IntegrationGrid.tsx

Lines changed: 137 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,65 @@ import React, { useState, useMemo, useEffect } from 'react';
22
import Link from '@docusaurus/Link';
33
import useBaseUrl from '@docusaurus/useBaseUrl';
44
import CUICard from '@site/src/components/CUICard';
5-
// @ts-ignore
6-
import integrationsData from '@site/static/integrations.json';
7-
// @ts-ignore
8-
import integrationsCustomData from '@site/static/integrations_custom.json';
95
import styles from './styles.module.scss';
106

7+
type CMSIntegrationData = {
8+
id: number;
9+
attributes: {
10+
name: string;
11+
slug: string;
12+
category: string;
13+
supportLevel: string;
14+
docsLink?: string;
15+
logo?: {
16+
data?: {
17+
attributes: {
18+
url: string;
19+
};
20+
};
21+
};
22+
logo_dark?: {
23+
data?: {
24+
attributes: {
25+
url: string;
26+
};
27+
};
28+
};
29+
};
30+
};
31+
1132
type IntegrationData = {
1233
slug: string;
34+
docsLink?: string;
1335
integration_logo: string;
1436
integration_type: string[];
1537
integration_title?: string;
1638
integration_tier?: string;
1739
};
1840

1941
function IntegrationCard({ integration }: { integration: IntegrationData }) {
42+
// Convert ClickHouse docs URLs to relative links
43+
const getNavigationLink = (docsLink: string | undefined, slug: string): string => {
44+
if (!docsLink) {
45+
return slug;
46+
}
47+
48+
// Check if it's a ClickHouse docs URL
49+
const clickhouseDocsMatch = docsLink.match(/https:\/\/clickhouse\.com\/docs\/(.+)/);
50+
if (clickhouseDocsMatch) {
51+
// Convert to relative link by removing the domain and keeping everything after /docs
52+
return `/${clickhouseDocsMatch[1]}`;
53+
}
54+
55+
// For external URLs, return as-is
56+
return docsLink;
57+
};
58+
59+
const linkTo = getNavigationLink(integration.docsLink, integration.slug);
60+
2061
return (
2162
<Link
22-
to={integration.slug}
63+
to={linkTo}
2364
style={{ textDecoration: 'none', color: 'inherit' }}
2465
>
2566
<CUICard style={{ position: 'relative' }}>
@@ -38,7 +79,7 @@ function IntegrationCard({ integration }: { integration: IntegrationData }) {
3879
<CUICard.Body>
3980
<CUICard.Header>
4081
<img
41-
src={useBaseUrl(integration.integration_logo)}
82+
src={integration.integration_logo}
4283
alt={`${integration.integration_title || integration.slug} logo`}
4384
/>
4485
</CUICard.Header>
@@ -65,20 +106,77 @@ function IntegrationCards({ integrations }: { integrations: IntegrationData[] })
65106
);
66107
}
67108

68-
export function IntegrationGrid() {
69-
// Combine integrations from both JSON files and normalize logo paths
70-
const integrations: IntegrationData[] = useMemo(() => {
71-
// Process custom integrations to fix logo paths
72-
const processedCustomData = integrationsCustomData.map(integration => ({
73-
...integration,
74-
integration_logo: integration.integration_logo.startsWith('/static/')
75-
? integration.integration_logo.replace('/static/', '/')
76-
: integration.integration_logo
77-
}));
78-
79-
return [...integrationsData, ...processedCustomData];
109+
// Helper function to transform CMS data to the expected format
110+
function transformCMSData(cmsData: CMSIntegrationData[]): IntegrationData[] {
111+
// Mapping from CMS category to display-friendly integration type
112+
const categoryMapping: { [key: string]: string } = {
113+
'AI_ML': 'AI/ML',
114+
'CLICKPIPES': 'ClickPipes',
115+
'DATA_INGESTION': 'Data ingestion',
116+
'DATA_INTEGRATION': 'Data integration',
117+
'DATA_MANAGEMENT': 'Data management',
118+
'DATA_VISUALIZATION': 'Data visualization',
119+
'LANGUAGE_CLIENT': 'Language client',
120+
'SECURITY_GOVERNANCE': 'Security governance',
121+
'SQL_CLIENT': 'SQL client'
122+
};
123+
124+
return cmsData.map(item => {
125+
// Map category to integration_type array
126+
const integrationTypes = item.attributes.category ? [categoryMapping[item.attributes.category] || item.attributes.category] : [];
127+
128+
// Map supportLevel to integration_tier
129+
const integrationTier = item.attributes.supportLevel?.toLowerCase() || '';
130+
131+
return {
132+
slug: item.attributes.slug.startsWith('/') ? item.attributes.slug : `/${item.attributes.slug}`,
133+
docsLink: item.attributes.docsLink,
134+
integration_logo: item.attributes.logo?.data?.attributes.url ? `https://cms.clickhouse-dev.com:1337${item.attributes.logo.data.attributes.url}` : '',
135+
integration_type: integrationTypes,
136+
integration_title: item.attributes.name,
137+
integration_tier: integrationTier
138+
};
139+
});
140+
}
141+
142+
// Custom hook for fetching CMS data
143+
function useCMSIntegrations() {
144+
const [integrations, setIntegrations] = useState<IntegrationData[]>([]);
145+
const [loading, setLoading] = useState(true);
146+
const [error, setError] = useState<string | null>(null);
147+
148+
useEffect(() => {
149+
const fetchIntegrations = async () => {
150+
try {
151+
setLoading(true);
152+
const response = await fetch('https://cms.clickhouse-dev.com:1337/api/integrations?populate[]=logo&populate[]=logo_dark');
153+
154+
if (!response.ok) {
155+
throw new Error(`HTTP error! status: ${response.status}`);
156+
}
157+
158+
const data = await response.json();
159+
const transformedData = transformCMSData(data.data || []);
160+
setIntegrations(transformedData);
161+
setError(null);
162+
} catch (err) {
163+
console.error('Failed to fetch integrations from CMS:', err);
164+
setError(err instanceof Error ? err.message : 'Failed to fetch integrations');
165+
setIntegrations([]);
166+
} finally {
167+
setLoading(false);
168+
}
169+
};
170+
171+
fetchIntegrations();
80172
}, []);
81173

174+
return { integrations, loading, error };
175+
}
176+
177+
export function IntegrationGrid() {
178+
const { integrations, loading, error } = useCMSIntegrations();
179+
82180
// Initialize state from localStorage or default values
83181
const [searchTerm, setSearchTerm] = useState(() => {
84182
if (typeof window !== 'undefined') {
@@ -230,10 +328,30 @@ export function IntegrationGrid() {
230328
return grouped;
231329
}, [filteredIntegrations]);
232330

331+
// Handle loading state
332+
if (loading) {
333+
return (
334+
<div style={{ textAlign: 'center', padding: '2rem' }}>
335+
<p>Loading integrations...</p>
336+
</div>
337+
);
338+
}
339+
340+
// Handle error state
341+
if (error) {
342+
return (
343+
<div style={{ textAlign: 'center', padding: '2rem', color: 'var(--ifm-color-danger)' }}>
344+
<p>Failed to load integrations: {error}</p>
345+
<p>Please try refreshing the page.</p>
346+
</div>
347+
);
348+
}
349+
350+
// Handle empty state
233351
if (integrations.length === 0) {
234352
return (
235353
<div style={{ textAlign: 'center', padding: '2rem' }}>
236-
<p>No integrations found with complete metadata.</p>
354+
<p>No integrations found.</p>
237355
</div>
238356
);
239357
}

0 commit comments

Comments
 (0)