Compare commits

..

9 Commits

Author SHA1 Message Date
3334937b67 2.3.35
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 9s
Build & Deploy / 🧪 QA (push) Successful in 1m13s
Build & Deploy / 🏗️ Build (push) Successful in 2m22s
Build & Deploy / 🚀 Deploy (push) Successful in 16s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m18s
Build & Deploy / 🔔 Notify (push) Successful in 2s
Nightly QA / 💨 Smoke & Health (push) Successful in 1m7s
2026-08-07 17:51:12 +02:00
246e6540d4 fix(products): remove malformed payload AST brace artifact from markdown 2026-08-07 17:51:11 +02:00
aa299b285d 2.3.34
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Successful in 1m12s
Build & Deploy / 🏗️ Build (push) Successful in 2m14s
Build & Deploy / 🚀 Deploy (push) Successful in 16s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m16s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-08-07 17:20:21 +02:00
2be0d1ea92 chore(products): migrate payload CMS lexical AST into permanent markdown
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 11s
Build & Deploy / 🧪 QA (push) Successful in 1m10s
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-08-07 17:18:02 +02:00
0554460153 fix(products): extract lexical AST and JSON-LD data correctly from productTabs block
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Failing after 52s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-08-07 17:12:55 +02:00
4ae45b1aa7 chore(release): 2.3.33 - NA Kabel Leiterklassen Fix
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 9s
Build & Deploy / 🧪 QA (push) Successful in 1m11s
Build & Deploy / 🏗️ Build (push) Successful in 2m15s
Build & Deploy / 🚀 Deploy (push) Successful in 16s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m1s
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-08-07 16:16:25 +02:00
76cbdaa37e fix: remove class 1 conductor shapes (RE, SE) from all NA cables
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 9s
Build & Deploy / 🏗️ Build (push) Has been cancelled
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
Build & Deploy / 🧪 QA (push) Has been cancelled
2026-08-07 14:49:27 +02:00
5b1a2eff7f fix(mdx): handle productTabs in MDXContent to resolve Unknown Block Type
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 9s
Build & Deploy / 🧪 QA (push) Successful in 1m13s
Build & Deploy / 🏗️ Build (push) Successful in 2m15s
Build & Deploy / 🚀 Deploy (push) Successful in 16s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m22s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-08-07 12:54:02 +02:00
60422da644 chore(glitchtip): ignore version drift errors like ChunkLoadError globally
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 9m9s
Build & Deploy / 🧪 QA (push) Successful in 1m19s
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-07-21 12:23:52 +02:00
34 changed files with 1118 additions and 564 deletions

1
.gitignore vendored
View File

@@ -28,3 +28,4 @@ backups/
# Local data / backups # Local data / backups
.data/ .data/
scratch/

View File

@@ -266,18 +266,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
notFound(); notFound();
} }
let technicalItems = []; let technicalItems: any[] = [];
try {
const tabMatch =
typeof product.content === 'string' &&
product.content.match(/<Block type="productTabs" data={({.*?})}\s*\/>/s);
if (tabMatch && tabMatch[1]) {
const data = JSON.parse(tabMatch[1]);
technicalItems = data.technicalItems || [];
}
} catch (e) {
// Ignore JSON parse errors for AST
}
const datasheetPath = getDatasheetPath(productSlug, locale); const datasheetPath = getDatasheetPath(productSlug, locale);
const isFallback = (product.frontmatter as any).isFallback; const isFallback = (product.frontmatter as any).isFallback;
@@ -296,8 +285,20 @@ export default async function ProductPage({ params }: ProductPageProps) {
if (typeof product.content === 'string') { if (typeof product.content === 'string') {
const tabBlockMatch = product.content.match(/<Block type="productTabs".*?\/>/s); const tabBlockMatch = product.content.match(/<Block type="productTabs".*?\/>/s);
if (tabBlockMatch) { if (tabBlockMatch) {
descriptionContent = product.content.replace(tabBlockMatch[0], '');
technicalContent = tabBlockMatch[0]; technicalContent = tabBlockMatch[0];
descriptionContent = product.content.replace(tabBlockMatch[0], '');
const dataMatch =
technicalContent.match(/data="({.*?})"/s) || technicalContent.match(/data={({.*?})}/s);
if (dataMatch && dataMatch[1]) {
try {
const rawJsonStr = dataMatch[1].replace(/&quot;/g, '"');
const data = JSON.parse(rawJsonStr);
technicalItems = data.technicalItems || [];
} catch (e) {
console.error('Failed to parse productTabs data for page:', e);
}
}
} }
} }

View File

@@ -24,6 +24,7 @@ import VideoSection from './home/VideoSection';
import CTA from './home/CTA'; import CTA from './home/CTA';
import { AgbHistoryBlock } from './AgbHistoryBlock'; import { AgbHistoryBlock } from './AgbHistoryBlock';
import { PDFDownloadBlock } from './PDFDownloadBlock'; import { PDFDownloadBlock } from './PDFDownloadBlock';
import ProductTechnicalData from './ProductTechnicalData';
function ContactSection(props: any) { function ContactSection(props: any) {
return ( return (
<div className="p-8 border-2 border-dashed border-primary my-8 text-center text-primary font-bold"> <div className="p-8 border-2 border-dashed border-primary my-8 text-center text-primary font-bold">
@@ -100,6 +101,8 @@ async function Block(props: any) {
return <AgbHistoryBlock {...data} />; return <AgbHistoryBlock {...data} />;
case 'pdfDownload': case 'pdfDownload':
return <PDFDownloadBlock {...data} />; return <PDFDownloadBlock {...data} />;
case 'productTabs':
return <ProductTechnicalData data={data} />;
default: default:
return ( return (

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -66,3 +66,81 @@ export function fixMdxDataProps(content: string): string {
return fixedContent; return fixedContent;
} }
export function lexicalToMarkdown(node: any, depth = 0): string {
if (!node) return '';
if (typeof node === 'string') return node;
if (node.type === 'text') {
let text = node.text || '';
if (node.format === 1) text = `**${text}**`; // Bold
if (node.format === 2) text = `*${text}*`; // Italic
return text;
}
if (node.type === 'heading') {
const level = parseInt((node.tag || 'h1').replace('h', '')) || 1;
const prefix = '#'.repeat(level);
const text = (node.children || []).map((c: any) => lexicalToMarkdown(c, depth)).join('');
return `${prefix} ${text}\n\n`;
}
if (node.type === 'paragraph') {
const text = (node.children || []).map((c: any) => lexicalToMarkdown(c, depth)).join('');
return text.trim() ? `${text}\n\n` : '\n';
}
if (node.type === 'list') {
const isOrdered = node.tag === 'ol';
const items = (node.children || [])
.map((c: any, index: number) => {
const prefix = isOrdered ? `${index + 1}.` : '-';
return `${prefix} ${lexicalToMarkdown(c, depth + 1).trim()}`;
})
.join('\n');
return `${items}\n\n`;
}
if (node.type === 'listitem') {
return (node.children || []).map((c: any) => lexicalToMarkdown(c, depth)).join('');
}
if (node.type === 'quote') {
const text = (node.children || []).map((c: any) => lexicalToMarkdown(c, depth)).join('');
return `> ${text}\n\n`;
}
if (node.type === 'link') {
const url = node.fields?.url || node.url || '';
const text = (node.children || []).map((c: any) => lexicalToMarkdown(c, depth)).join('');
return `[${text}](${url})`;
}
if (node.type === 'upload') {
const url = node.value?.url || '';
const alt = node.value?.alt || node.value?.filename || '';
return `![${alt}](${url})\n\n`;
}
if (node.type === 'block') {
const blockType = node.fields?.blockType;
if (blockType === 'contactSection') {
return `<ContactSection showMap={${!!node.fields?.showMap}} showForm={${!!node.fields?.showForm}} showHours={${!!node.fields?.showHours}} />\n\n`;
}
if (blockType === 'heroSection') {
return `<HeroSection badge="${node.fields?.badge || ''}" title="${node.fields?.title || ''}" subtitle="${node.fields?.subtitle || ''}" alignment="${node.fields?.alignment || 'left'}" />\n\n`;
}
if (blockType === 'features') {
return `<FeaturesSection layout="${node.fields?.layout || ''}" />\n\n`;
}
// Generic MDX block wrapper if unknown
return `<Block type="${blockType}" data={${JSON.stringify(node.fields)}} />\n\n`;
}
if (node.children && Array.isArray(node.children)) {
return node.children.map((c: any) => lexicalToMarkdown(c, depth)).join('');
}
return '';
}

View File

@@ -56,6 +56,11 @@ export class GlitchtipErrorReportingService implements ErrorReportingService {
tracesSampleRate: this.options.tracesSampleRate ?? 0.1, tracesSampleRate: this.options.tracesSampleRate ?? 0.1,
replaysOnErrorSampleRate: 1.0, replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 0.1, replaysSessionSampleRate: 0.1,
ignoreErrors: [
'ChunkLoadError',
'Failed to fetch dynamically imported module',
'Failed to find Server Action',
],
}); });
} }
return Sentry; return Sentry;

View File

@@ -116,7 +116,7 @@
"prepare": "husky", "prepare": "husky",
"preinstall": "npx only-allow pnpm" "preinstall": "npx only-allow pnpm"
}, },
"version": "2.3.31", "version": "2.3.35",
"pnpm": { "pnpm": {
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
"@parcel/watcher", "@parcel/watcher",

View File

@@ -0,0 +1,47 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { GlitchtipErrorReportingService } from '../lib/services/errors/glitchtip-error-reporting-service';
// Mock the LoggerService
const mockLogger = {
child: vi.fn().mockReturnThis(),
info: vi.fn(),
error: vi.fn(),
warn: vi.fn(),
debug: vi.fn(),
} as any;
const mockSentryInit = vi.fn();
vi.mock('@sentry/nextjs', () => ({
init: (...args: any[]) => mockSentryInit(...args),
captureException: vi.fn(),
captureMessage: vi.fn(),
}));
describe('GlitchtipErrorReportingService', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should ignore version drift errors (ChunkLoadError and Server Action) in Sentry config', async () => {
// Simulate window to force client-side init behavior instantly
const originalWindow = global.window;
global.window = {
requestIdleCallback: (cb: Function) => cb(),
} as any;
const service = new GlitchtipErrorReportingService({ enabled: true }, mockLogger);
// Give the dynamic import a moment to resolve
await new Promise((resolve) => setTimeout(resolve, 50));
expect(mockSentryInit).toHaveBeenCalledOnce();
const initCallArgs = mockSentryInit.mock.calls[0][0];
expect(initCallArgs.ignoreErrors).toBeDefined();
expect(initCallArgs.ignoreErrors).toContain('ChunkLoadError');
expect(initCallArgs.ignoreErrors).toContain('Failed to find Server Action');
global.window = originalWindow;
});
});

27
tests/lexical.test.ts Normal file
View File

@@ -0,0 +1,27 @@
import { describe, it, expect } from 'vitest';
import { lexicalToMarkdown } from '../lib/mdx-utils';
describe('lexicalToMarkdown', () => {
it('should convert lexical AST to markdown', () => {
const ast = {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{ type: 'text', text: 'Hello ' },
{ type: 'text', text: 'World', format: 1 }, // bold
],
},
{
type: 'heading',
tag: 'h2',
children: [{ type: 'text', text: 'Title' }],
},
],
};
const result = lexicalToMarkdown(ast);
expect(result).toBe('Hello **World**\n\n## Title\n\n');
});
});

View File

@@ -0,0 +1,14 @@
import { describe, it, expect } from 'vitest';
import * as fs from 'fs';
import * as path from 'path';
describe('MDXContent Mapping', () => {
it('should have productTabs in the switch statement to prevent Unknown Block Type errors', () => {
const filePath = path.join(process.cwd(), 'components/MDXContent.tsx');
const fileContent = fs.readFileSync(filePath, 'utf-8');
// Check if the switch case for productTabs exists
expect(fileContent).toContain("case 'productTabs':");
expect(fileContent).toContain('<ProductTechnicalData');
});
});