fix(pdf): fix missing logos and product images in datasheets, update pipeline
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Successful in 2m20s
Build & Deploy / 🏗️ Build (push) Successful in 3m56s
Build & Deploy / 🚀 Deploy (push) Successful in 22s
Build & Deploy / 🧪 Post-Deploy Verification (push) Failing after 4m30s
Build & Deploy / 🔔 Notify (push) Successful in 2s

This commit is contained in:
2026-03-08 01:55:52 +01:00
parent 7583540de2
commit d575e5924a
58 changed files with 67 additions and 25 deletions
+21 -4
View File
@@ -197,6 +197,7 @@ interface ProductData {
applicationHtml?: string; applicationHtml?: string;
images?: string[]; images?: string[];
featuredImage?: string | null; featuredImage?: string | null;
logoDataUrl?: string | null;
categories?: Array<{ name: string }>; categories?: Array<{ name: string }>;
attributes?: Array<{ name: string; options: string[] }>; attributes?: Array<{ name: string; options: string[] }>;
} }
@@ -204,7 +205,7 @@ interface ProductData {
export interface PDFDatasheetProps { export interface PDFDatasheetProps {
product: ProductData; product: ProductData;
locale: 'en' | 'de'; locale: 'en' | 'de';
logoUrl?: string; logoDataUrl?: string | null;
technicalItems?: KeyValueItem[]; technicalItems?: KeyValueItem[];
voltageTables?: DatasheetVoltageTable[]; voltageTables?: DatasheetVoltageTable[];
legendItems?: KeyValueItem[]; legendItems?: KeyValueItem[];
@@ -485,8 +486,15 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
<Page size="A4" style={styles.page}> <Page size="A4" style={styles.page}>
<View style={styles.hero}> <View style={styles.hero}>
<View style={styles.header}> <View style={styles.header}>
<View> <View style={{ width: 80 }}>
<Text style={styles.logoText}>KLZ</Text> {product.logoDataUrl || (product as any).logoDataUrl ? (
<Image
src={product.logoDataUrl || (product as any).logoDataUrl}
style={{ width: '100%', objectFit: 'contain' }}
/>
) : (
<Text style={styles.logoText}>KLZ</Text>
)}
</View> </View>
<Text style={styles.docTitle}>{labels.productDatasheet}</Text> <Text style={styles.docTitle}>{labels.productDatasheet}</Text>
</View> </View>
@@ -586,7 +594,16 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
</View> </View>
<View style={styles.footer} fixed> <View style={styles.footer} fixed>
<Text style={styles.footerBrand}>KLZ CABLES</Text> <View style={{ width: 60 }}>
{product.logoDataUrl || (product as any).logoDataUrl ? (
<Image
src={product.logoDataUrl || (product as any).logoDataUrl}
style={{ width: '100%', objectFit: 'contain' }}
/>
) : (
<Text style={styles.footerBrand}>KLZ CABLES</Text>
)}
</View>
<Text style={styles.footerText}> <Text style={styles.footerText}>
{new Date().toLocaleDateString(locale === 'en' ? 'en-US' : 'de-DE', { {new Date().toLocaleDateString(locale === 'en' ? 'en-US' : 'de-DE', {
year: 'numeric', year: 'numeric',
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+30 -15
View File
@@ -15,6 +15,7 @@ SOURCE_ENV="${1:-}" # local | testing | staging | prod
TARGET_ENV="${2:-}" # testing | staging | prod TARGET_ENV="${2:-}" # testing | staging | prod
SSH_HOST="root@alpha.mintel.me" SSH_HOST="root@alpha.mintel.me"
LOCAL_MEDIA_DIR="./public/media" LOCAL_MEDIA_DIR="./public/media"
LOCAL_DATASHEETS_DIR="./public/datasheets"
DRY_RUN="" DRY_RUN=""
CHECKSUM="" CHECKSUM=""
@@ -38,6 +39,16 @@ get_media_path() {
esac esac
} }
get_datasheets_path() {
case "$1" in
local) echo "$LOCAL_DATASHEETS_DIR" ;;
testing) echo "/home/deploy/sites/testing.klz-cables.com/public/datasheets" ;;
staging) echo "/home/deploy/sites/staging.klz-cables.com/public/datasheets" ;;
prod|production) echo "/home/deploy/sites/klz-cables.com/public/datasheets" ;;
*) echo "❌ Unknown environment: $1"; exit 1 ;;
esac
}
get_app_container() { get_app_container() {
case "$1" in case "$1" in
testing) echo "klz-testing-klz-app-1" ;; testing) echo "klz-testing-klz-app-1" ;;
@@ -52,35 +63,39 @@ TGT_PATH=$(get_media_path "$TARGET_ENV")
TGT_CONTAINER=$(get_app_container "$TARGET_ENV") TGT_CONTAINER=$(get_app_container "$TARGET_ENV")
echo "🚀 Syncing assets: $SOURCE_ENV → $TARGET_ENV" echo "🚀 Syncing assets: $SOURCE_ENV → $TARGET_ENV"
echo "📂 Source: $SRC_PATH"
echo "📂 Target: $TGT_PATH"
# ── Execution ──────────────────────────────────────────────────────────────
if [[ ! -d "$SRC_PATH" ]] && [[ "$SOURCE_ENV" == "local" ]]; then
echo "❌ Source directory does not exist: $SRC_PATH"
exit 1
fi
# ── Media Sync ─────────────────────────────────────────────────────────────
echo "🖼️ Syncing Media..."
if [[ "$SOURCE_ENV" == "local" ]]; then if [[ "$SOURCE_ENV" == "local" ]]; then
# Local → Remote
echo "📡 Running rsync..."
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SRC_PATH/" "$SSH_HOST:$TGT_PATH/" rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SRC_PATH/" "$SSH_HOST:$TGT_PATH/"
elif [[ "$TARGET_ENV" == "local" ]]; then elif [[ "$TARGET_ENV" == "local" ]]; then
# Remote → Local
mkdir -p "$LOCAL_MEDIA_DIR" mkdir -p "$LOCAL_MEDIA_DIR"
echo "📡 Running rsync..."
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SSH_HOST:$SRC_PATH/" "$TGT_PATH/" rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SSH_HOST:$SRC_PATH/" "$TGT_PATH/"
else else
# Remote → Remote (e.g., testing → staging)
echo "📡 Running remote rsync..."
ssh "$SSH_HOST" "rsync -avzi $CHECKSUM --delete --progress $DRY_RUN $SRC_PATH/ $TGT_PATH/" ssh "$SSH_HOST" "rsync -avzi $CHECKSUM --delete --progress $DRY_RUN $SRC_PATH/ $TGT_PATH/"
fi fi
# ── Datasheets Sync ────────────────────────────────────────────────────────
echo "📄 Syncing Datasheets..."
SRC_DS_PATH=$(get_datasheets_path "$SOURCE_ENV")
TGT_DS_PATH=$(get_datasheets_path "$TARGET_ENV")
if [[ "$SOURCE_ENV" == "local" ]]; then
ssh "$SSH_HOST" "mkdir -p $TGT_DS_PATH"
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SRC_DS_PATH/" "$SSH_HOST:$TGT_DS_PATH/"
elif [[ "$TARGET_ENV" == "local" ]]; then
mkdir -p "$LOCAL_DATASHEETS_DIR"
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SSH_HOST:$SRC_DS_PATH/" "$TGT_DS_PATH/"
else
ssh "$SSH_HOST" "mkdir -p $TGT_DS_PATH && rsync -avzi $CHECKSUM --delete --progress $DRY_RUN $SRC_DS_PATH/ $TGT_DS_PATH/"
fi
# Fix ownership on remote target if it's not local # Fix ownership on remote target if it's not local
if [[ "$TARGET_ENV" != "local" && -z "$DRY_RUN" ]]; then if [[ "$TARGET_ENV" != "local" && -z "$DRY_RUN" ]]; then
echo "🔑 Fixing media file permissions on $TARGET_ENV..." echo "🔑 Fixing media file permissions on $TARGET_ENV..."
ssh "$SSH_HOST" "docker exec -u 0 $TGT_CONTAINER chown -R 1001:65533 /app/public/media/ 2>/dev/null || true" ssh "$SSH_HOST" "docker exec -u 0 $TGT_CONTAINER chown -R 1001:65533 /app/public/media/ 2>/dev/null || true"
echo "🔑 Fixing datasheet permissions..."
ssh "$SSH_HOST" "chown -R 1001:1001 $TGT_DS_PATH 2>/dev/null || true"
fi fi
echo "✅ Asset sync complete!" echo "✅ Asset sync complete!"
+12 -5
View File
@@ -268,7 +268,10 @@ async function processChunk(
} }
// Load assets as Data URLs for React-PDF // Load assets as Data URLs for React-PDF
const heroDataUrl = await loadImageAsPngDataUrl(model.product.heroSrc); const [heroDataUrl, logoDataUrl] = await Promise.all([
loadImageAsPngDataUrl(model.product.heroSrc),
loadImageAsPngDataUrl('/logo-black.svg'),
]);
const fileName = generateFileName(product, locale); const fileName = generateFileName(product, locale);
const voltageType = (product as any).voltageType || 'other'; const voltageType = (product as any).voltageType || 'other';
@@ -281,14 +284,18 @@ async function processChunk(
// Render using the unified component // Render using the unified component
const element = ( const element = (
<PDFDatasheet <PDFDatasheet
product={{ product={
...model.product, {
featuredImage: heroDataUrl, ...model.product,
}} featuredImage: heroDataUrl,
logoDataUrl,
} as any
}
locale={locale} locale={locale}
technicalItems={model.technicalItems} technicalItems={model.technicalItems}
voltageTables={model.voltageTables} voltageTables={model.voltageTables}
legendItems={model.legendItems} legendItems={model.legendItems}
logoDataUrl={logoDataUrl}
/> />
); );
+4 -1
View File
@@ -147,7 +147,10 @@ function compactCellForDenseTable(
function resolveMediaToLocalPath(urlOrPath: string | null | undefined): string | null { function resolveMediaToLocalPath(urlOrPath: string | null | undefined): string | null {
if (!urlOrPath) return null; if (!urlOrPath) return null;
if (urlOrPath.startsWith('/')) return urlOrPath; if (urlOrPath.startsWith('/')) {
// Handle Payload API URL prefix: /api/media/file/filename.ext -> /media/filename.ext
return urlOrPath.replace(/^\/api\/media\/file\//, '/media/');
}
if (/^media\//i.test(urlOrPath)) return `/${urlOrPath}`; if (/^media\//i.test(urlOrPath)) return `/${urlOrPath}`;
const mapped = ASSET_MAP[urlOrPath]; const mapped = ASSET_MAP[urlOrPath];
if (mapped) { if (mapped) {