Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docusaurus.config.en.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,10 @@ const config = {
blogSidebarLink: "/docs/knowledgebase",
galaxyApiEndpoint:
process.env.NEXT_PUBLIC_GALAXY_API_ENDPOINT || "http://localhost:3000",
strapiUrl:
process.env.CLIENT_STRAPI_URL || "https://staging-cms.clickhouse.com",
strapiToken:
process.env.CLIENT_STRAPI_TOKEN || "",
},

};
Expand Down
4 changes: 4 additions & 0 deletions docusaurus.config.jp.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ const config = {
blogSidebarLink: "/docs/knowledgebase", // Used for KB article page
galaxyApiEndpoint:
process.env.NEXT_PUBLIC_GALAXY_API_ENDPOINT || "http://localhost:3000",
strapiUrl:
process.env.CLIENT_STRAPI_URL || "https://staging-cms.clickhouse.com",
strapiToken:
process.env.CLIENT_STRAPI_TOKEN || "",
},
};

Expand Down
4 changes: 4 additions & 0 deletions docusaurus.config.ko.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ const config = {
blogSidebarLink: "/docs/knowledgebase", // Used for KB article page
galaxyApiEndpoint:
process.env.NEXT_PUBLIC_GALAXY_API_ENDPOINT || "http://localhost:3000",
strapiUrl:
process.env.CLIENT_STRAPI_URL || "https://staging-cms.clickhouse.com",
strapiToken:
process.env.CLIENT_STRAPI_TOKEN || "",
secondaryNavItems: [
{
type: "dropdown",
Expand Down
4 changes: 4 additions & 0 deletions docusaurus.config.ru.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ const config = {
blogSidebarLink: "/docs/knowledgebase", // Used for KB article page
galaxyApiEndpoint:
process.env.NEXT_PUBLIC_GALAXY_API_ENDPOINT || "http://localhost:3000",
strapiUrl:
process.env.CLIENT_STRAPI_URL || "https://staging-cms.clickhouse.com",
strapiToken:
process.env.CLIENT_STRAPI_TOKEN || "",
},
};

Expand Down
4 changes: 4 additions & 0 deletions docusaurus.config.zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ const config = {
blogSidebarLink: "/docs/knowledgebase", // Used for KB article page
galaxyApiEndpoint:
process.env.NEXT_PUBLIC_GALAXY_API_ENDPOINT || "http://localhost:3000",
strapiUrl:
process.env.CLIENT_STRAPI_URL || "https://staging-cms.clickhouse.com",
strapiToken:
process.env.CLIENT_STRAPI_TOKEN || "",
secondaryNavItems: [
{
type: "dropdown",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@monaco-editor/react": "^4.7.0",
"@radix-ui/react-navigation-menu": "^1.2.13",
"@redocly/cli": "^1.34.0",
"@strapi/client": "^1.6.1",
"axios": "^1.13.5",
"clsx": "^2.1.0",
"docusaurus-plugin-sass": "^0.2.6",
Expand Down
154 changes: 56 additions & 98 deletions src/components/IntegrationGrid/IntegrationGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,27 @@ import useBaseUrl from "@docusaurus/useBaseUrl";
import { useColorMode } from "@docusaurus/theme-common";
import CUICard from "@site/src/components/CUICard";
import styles from "./styles.module.scss";
import { useStrapiClient } from "@site/src/lib/useStrapiClient";

type CMSIntegrationData = {
id: number;
attributes: {
name: string;
slug: string;
category: string;
supportLevel: string;
docsLink?: string;
logo?: {
data?: {
attributes: {
url: string;
};
};
};
logo_dark?: {
data?: {
attributes: {
url: string;
};
};
};
documentId: string;
name: string;
slug: string;
category: string;
supportLevel: string;
docsLink?: string;
logo?: {
id: number;
url: string;
};
logo_dark?: {
id: number;
url: string;
};
};


type IntegrationData = {
slug: string;
docsLink?: string;
Expand Down Expand Up @@ -157,134 +152,97 @@ function IntegrationCards({
);
}

// Helper function to transform CMS data to the expected format
function transformCMSData(cmsData: CMSIntegrationData[]): IntegrationData[] {
// Mapping from CMS category to display-friendly integration type
const categoryMapping: { [key: string]: string } = {
AI_ML: "AI/ML",
CLICKPIPES: "ClickPipes",
DATA_INGESTION: "Data ingestion",
DATA_INTEGRATION: "Data integration",
DATA_MANAGEMENT: "Data management",
DATA_VISUALIZATION: "Data visualization",
LANGUAGE_CLIENT: "Language client",
SECURITY_GOVERNANCE: "Security governance",
SQL_CLIENT: "SQL client",
};
const categoryMapping: { [key: string]: string } = {
AI_ML: "AI/ML",
CLICKPIPES: "ClickPipes",
DATA_INGESTION: "Data ingestion",
DATA_INTEGRATION: "Data integration",
DATA_MANAGEMENT: "Data management",
DATA_VISUALIZATION: "Data visualization",
LANGUAGE_CLIENT: "Language client",
SECURITY_GOVERNANCE: "Security governance",
SQL_CLIENT: "SQL client",
};

function transformCMSData(cmsData: CMSIntegrationData[], baseUrl: string): IntegrationData[] {
return cmsData.map((item) => {
// Map category to integration_type array
const integrationTypes = item.attributes.category
? [categoryMapping[item.attributes.category] || item.attributes.category]
const integrationTypes = item.category
? [categoryMapping[item.category] || item.category]
: [];

// Map supportLevel to integration_tier
const integrationTier = item.attributes.supportLevel?.toLowerCase() || "";
const integrationTier = item.supportLevel?.toLowerCase() || "";

return {
slug: item.attributes.slug.startsWith("/")
? item.attributes.slug
: `/${item.attributes.slug}`,
docsLink: item.attributes.docsLink,
integration_logo: item.attributes.logo?.data?.attributes.url
? `https://cms.clickhouse-dev.com:1337${item.attributes.logo.data.attributes.url}`
slug: item.slug.startsWith("/") ? item.slug : `/${item.slug}`,
docsLink: item.docsLink,
integration_logo: item.logo?.url
? `${baseUrl}${item.logo.url}`
: "",
integration_logo_dark: item.attributes.logo_dark?.data?.attributes.url
? `https://cms.clickhouse-dev.com:1337${item.attributes.logo_dark.data.attributes.url}`
integration_logo_dark: item.logo_dark?.url
? `${baseUrl}${item.logo_dark.url}`
: undefined,
integration_type: integrationTypes,
integration_title: item.attributes.name,
integration_title: item.name,
integration_tier: integrationTier,
};
});
}

// Configuration: Set to true to fetch from CMS, false to use only static fallback
const USE_CMS_ENDPOINT = false;

// Custom hook for fetching CMS data
const USE_CMS_ENDPOINT = true;

function useCMSIntegrations() {
const [integrations, setIntegrations] = useState<IntegrationData[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fallbackPath = useBaseUrl("/integrations-fallback.json");
const { client: strapiClient, strapiBaseUrl } = useStrapiClient();

useEffect(() => {
const fetchIntegrations = async () => {
// Step 1: Load fallback data first for immediate display
try {
const fallbackResponse = await fetch(fallbackPath, {
cache: "no-cache", // Always revalidate with server to get fresh data
cache: "no-cache",
});

if (fallbackResponse.ok) {
const fallbackData = await fallbackResponse.json();
const transformedData = transformCMSData(fallbackData.data || []);
const transformedData = transformCMSData(fallbackData.data || [], strapiBaseUrl);
setIntegrations(transformedData);
setError(null);
setLoading(false); // Show content immediately with fallback data
console.log("Loaded fallback integrations data");
setLoading(false);
} else {
console.warn("Fallback file not available, will try CMS only");
console.warn("Fallback file not available");
}
} catch (fallbackErr) {
console.error(
"Failed to load fallback integrations data:",
fallbackErr,
);
// Continue to try CMS even if fallback fails
}

// Step 2: Try to fetch fresh data from CMS with timeout (if enabled)
if (USE_CMS_ENDPOINT) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
console.log("CMS request timed out after 8 seconds");
}, 8000); // 8 second timeout

const response = await fetch(
"https://cms.clickhouse-dev.com:1337/api/integrations?populate[]=logo&populate[]=logo_dark",
{
signal: controller.signal,
// Add headers to help with CORS and caching
headers: {
Accept: "application/json",
"Strapi-Response-Format": "v4",
},
const { data } = await strapiClient.collection("integrations").find({
fields: ["name", "slug", "category", "supportLevel", "docsLink"],
populate: {
logo: { fields: ["url"] },
logo_dark: { fields: ["url"] },
},
);
pagination: { pageSize: 500 },
});

clearTimeout(timeoutId);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const transformedData = transformCMSData(data as unknown as CMSIntegrationData[], strapiBaseUrl);

const data = await response.json();
const transformedData = transformCMSData(data.data || []);

// Update with fresh CMS data
setIntegrations(transformedData);
setError(null);
console.log("Successfully updated with fresh CMS data");
} catch (cmsErr) {
// CMS fetch failed, but that's okay - we already have fallback data
if (cmsErr instanceof Error) {
if (cmsErr.name === "AbortError") {
console.log(
"CMS request was aborted due to timeout, using fallback data",
);
} else {
console.error(
"Error loading integrations from CMS:",
cmsErr.message,
);
}
console.error(
"Error loading integrations from CMS:",
cmsErr.message,
);
}

// Only set error if we don't have any integrations data at all
if (integrations.length === 0) {
setError(
"Unable to load integrations. Please try refreshing the page.",
Expand Down
17 changes: 17 additions & 0 deletions src/lib/useStrapiClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { strapi } from '@strapi/client';
import { useMemo } from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';

const STRAPI_DEFAULT_URL = 'https://staging-cms.clickhouse.com';

export function useStrapiClient(): { client: ReturnType<typeof strapi>; baseUrl: string } {
const { siteConfig } = useDocusaurusContext();
const baseUrl = (siteConfig.customFields?.strapiUrl as string) || STRAPI_DEFAULT_URL;
const auth = (siteConfig.customFields?.strapiToken as string) || undefined;
const client = useMemo(() => strapi({
baseURL: `${baseUrl}/api`,
...(auth && { auth }),
}), [baseUrl, auth]);

return { client, strapiBaseUrl: baseUrl };
}
Loading
Loading