From f58462df32897f5e21851c29eae0a220a228b2a8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 16:34:11 +0000 Subject: [PATCH 1/3] Add GitHub workflow for PDF generation using Playwright Create a workflow that generates a DIN A4 PDF of the print version of index.html and stores it as an artifact. Uses Playwright with Chromium to load the page, wait for QR codes to render, and generate the PDF. --- .github/workflows/generate-pdf.yml | 37 +++++++++++++++++++++++++++ package.json | 12 +++++++++ scripts/generate-pdf.js | 41 ++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 .github/workflows/generate-pdf.yml create mode 100644 package.json create mode 100644 scripts/generate-pdf.js diff --git a/.github/workflows/generate-pdf.yml b/.github/workflows/generate-pdf.yml new file mode 100644 index 0000000..18646e6 --- /dev/null +++ b/.github/workflows/generate-pdf.yml @@ -0,0 +1,37 @@ +name: Generate PDF Labels + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + workflow_dispatch: + +jobs: + generate-pdf: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Install Playwright Chromium + run: npx playwright install chromium + + - name: Generate PDF + run: npm run generate-pdf + + - name: Upload PDF artifact + uses: actions/upload-artifact@v4 + with: + name: asn-labels-pdf + path: asn-labels.pdf + retention-days: 30 diff --git a/package.json b/package.json new file mode 100644 index 0000000..6531df0 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "asn-qr-code-label-generator", + "version": "1.0.0", + "description": "QR code label generator for Paperless-ngx Archive Serial Numbers", + "private": true, + "scripts": { + "generate-pdf": "node scripts/generate-pdf.js" + }, + "devDependencies": { + "playwright": "^1.49.0" + } +} diff --git a/scripts/generate-pdf.js b/scripts/generate-pdf.js new file mode 100644 index 0000000..56d4220 --- /dev/null +++ b/scripts/generate-pdf.js @@ -0,0 +1,41 @@ +const { chromium } = require('playwright'); +const path = require('path'); + +async function generatePDF() { + const browser = await chromium.launch(); + const context = await browser.newContext(); + const page = await context.newPage(); + + // Load the local HTML file + const htmlPath = path.join(__dirname, '..', 'index.html'); + await page.goto(`file://${htmlPath}`); + + // Wait for AlpineJS to initialize and generate labels + await page.waitForFunction(() => { + const labels = document.querySelectorAll('ol li'); + return labels.length === 189; // 7 columns x 27 rows + }); + + // Wait for all QR code images to load + await page.waitForFunction(() => { + const images = document.querySelectorAll('ol li img'); + return Array.from(images).every(img => img.complete && img.naturalHeight > 0); + }, { timeout: 60000 }); + + // Generate PDF with A4 format and print media + await page.pdf({ + path: 'asn-labels.pdf', + format: 'A4', + printBackground: true, + margin: { top: 0, right: 0, bottom: 0, left: 0 } + }); + + console.log('PDF generated successfully: asn-labels.pdf'); + + await browser.close(); +} + +generatePDF().catch(err => { + console.error('Error generating PDF:', err); + process.exit(1); +}); From 499c842b452e6c19b6c61be7b8e6908a7b45674a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 16:41:14 +0000 Subject: [PATCH 2/3] Add lockfile, dependabot, and improve PDF script reliability - Add package-lock.json for reproducible builds (npm ci) - Add dependabot.yml for npm and GitHub Actions updates - Add .gitignore for node_modules and generated PDF - Update workflow to use npm ci with caching - Improve PDF script with proper error handling and HTTP server --- .github/dependabot.yml | 16 +++++++ .github/workflows/generate-pdf.yml | 3 +- .gitignore | 2 + package-lock.json | 62 ++++++++++++++++++++++++ scripts/generate-pdf.js | 75 +++++++++++++++++++++--------- 5 files changed, 134 insertions(+), 24 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .gitignore create mode 100644 package-lock.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a1046b8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/generate-pdf.yml b/.github/workflows/generate-pdf.yml index 18646e6..55b3e1f 100644 --- a/.github/workflows/generate-pdf.yml +++ b/.github/workflows/generate-pdf.yml @@ -19,9 +19,10 @@ jobs: uses: actions/setup-node@v4 with: node-version: '20' + cache: 'npm' - name: Install dependencies - run: npm install + run: npm ci - name: Install Playwright Chromium run: npx playwright install chromium diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf4eba1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +asn-labels.pdf diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6d2624e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,62 @@ +{ + "name": "asn-qr-code-label-generator", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "asn-qr-code-label-generator", + "version": "1.0.0", + "devDependencies": { + "playwright": "^1.49.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/scripts/generate-pdf.js b/scripts/generate-pdf.js index 56d4220..96ff80d 100644 --- a/scripts/generate-pdf.js +++ b/scripts/generate-pdf.js @@ -1,38 +1,67 @@ const { chromium } = require('playwright'); +const http = require('http'); +const fs = require('fs'); const path = require('path'); async function generatePDF() { - const browser = await chromium.launch(); + // Start a simple HTTP server to serve the HTML file + const htmlPath = path.join(__dirname, '..', 'index.html'); + const htmlContent = fs.readFileSync(htmlPath, 'utf8'); + + const server = http.createServer((req, res) => { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(htmlContent); + }); + + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); + const port = server.address().port; + console.log(`Server started on port ${port}`); + + const browser = await chromium.launch({ + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-dev-shm-usage' + ] + }); const context = await browser.newContext(); const page = await context.newPage(); - // Load the local HTML file - const htmlPath = path.join(__dirname, '..', 'index.html'); - await page.goto(`file://${htmlPath}`); + try { + // Load the page from local server and wait for network to settle + await page.goto(`http://127.0.0.1:${port}`, { waitUntil: 'networkidle' }); - // Wait for AlpineJS to initialize and generate labels - await page.waitForFunction(() => { - const labels = document.querySelectorAll('ol li'); - return labels.length === 189; // 7 columns x 27 rows - }); + // Wait for AlpineJS to initialize and generate labels + console.log('Waiting for labels to be generated...'); + await page.waitForFunction(() => { + const labels = document.querySelectorAll('ol li'); + return labels.length === 189; // 7 columns x 27 rows + }, { timeout: 60000 }); - // Wait for all QR code images to load - await page.waitForFunction(() => { - const images = document.querySelectorAll('ol li img'); - return Array.from(images).every(img => img.complete && img.naturalHeight > 0); - }, { timeout: 60000 }); + console.log('Labels generated, waiting for QR code images to load...'); - // Generate PDF with A4 format and print media - await page.pdf({ - path: 'asn-labels.pdf', - format: 'A4', - printBackground: true, - margin: { top: 0, right: 0, bottom: 0, left: 0 } - }); + // Wait for all QR code images to load + await page.waitForFunction(() => { + const images = document.querySelectorAll('ol li img'); + if (images.length === 0) return false; + return Array.from(images).every(img => img.complete && img.naturalHeight > 0); + }, { timeout: 120000 }); - console.log('PDF generated successfully: asn-labels.pdf'); + console.log('All images loaded, generating PDF...'); - await browser.close(); + // Generate PDF with A4 format and print media + await page.pdf({ + path: 'asn-labels.pdf', + format: 'A4', + printBackground: true, + margin: { top: 0, right: 0, bottom: 0, left: 0 } + }); + + console.log('PDF generated successfully: asn-labels.pdf'); + } finally { + await browser.close(); + server.close(); + } } generatePDF().catch(err => { From 4c6885bff903b80611918f8eb3309047a8f6555f Mon Sep 17 00:00:00 2001 From: "Tobias L. Maier" Date: Sun, 23 Nov 2025 17:55:43 +0100 Subject: [PATCH 3/3] Update package.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6531df0..c38c791 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "generate-pdf": "node scripts/generate-pdf.js" }, "devDependencies": { - "playwright": "^1.49.0" + "playwright": "^1.56.0" } }