Skip to content
Open
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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
"scripts": {
"postinstall": "npm run bootstrap",
"bootstrap": "lerna bootstrap",
"build": "node run.js",
"build": "node run.js && node scripts/fix-empty-pages.js",
"test": "lerna run test",
"generate": "SKIP_TESTS=true node run.js",
"update-skip-dropdowns": "SKIP_DROPDOWNS=true node run.js"
"update-skip-dropdowns": "SKIP_DROPDOWNS=true node run.js",
"fix-empty-pages": "node scripts/fix-empty-pages.js"
},
"nyc": {
"include": [
Expand Down
92 changes: 92 additions & 0 deletions scripts/fix-empty-pages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Script to scan `build/*.html` and replace empty pages with the `fallback.njk` rendering.
* Usage: node scripts/fix-empty-pages.js
*/

const fs = require('fs-extra');
const path = require('path');
const nunjucks = require('nunjucks');
const jsdom = require('jsdom');

nunjucks.configure(path.resolve(__dirname, '../views'), { autoescape: false });

const buildDir = path.resolve(__dirname, '../build');
const templateIndexPath = path.join(buildDir, 'template-library.json');
const serverRoot = process.env.SERVER_ROOT ? process.env.SERVER_ROOT : 'https://templates.accordproject.org';
const studioRoot = 'https://studio.accordproject.org';
const githubRoot = `https://github.dev/accordproject/cicero-template-library/blob/master`;

async function run() {
if (!(await fs.pathExists(buildDir))) {
throw new Error(`Build directory "${buildDir}" does not exist. Please run the build (e.g., "npm run build") before running this script.`);
}
const files = (await fs.readdir(buildDir)).filter(f => f.endsWith('.html'));

let templateIndex = {};
try {
if(await fs.pathExists(templateIndexPath)) {
templateIndex = await fs.readJson(templateIndexPath);
}
} catch(e) {
console.warn('Could not read template index:', e);
}

for(const f of files) {
if(f === 'index.html') continue;
const filePath = path.join(buildDir, f);
let content;
try {
content = await fs.readFile(filePath, 'utf8');
} catch(e) {
console.error(`Failed reading ${filePath}:`, e);
continue;
}

// Cheap pre-check: if the <body> clearly contains non-whitespace content,
// skip the expensive JSDOM parsing for this file.
const bodyMatch = content.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
if (bodyMatch && bodyMatch[1] && bodyMatch[1].trim()) {
// Body is clearly non-empty; no need to process further.
continue;
}

// Fallback to JSDOM for files that might be empty or are uncertain.
const dom = new jsdom.JSDOM(content);
const bodyContent = dom.window.document && dom.window.document.body ? dom.window.document.body.innerHTML.trim() : '';
if(!bodyContent) {
const identifier = path.basename(f, '.html');
console.log(`Empty page detected: ${f} (identifier: ${identifier}). Replacing with fallback.`);

const meta = templateIndex[identifier] || {};
const displayName = meta.displayName || identifier;
const description = meta.description || '';
const archiveURL = `./archives/${identifier}.cta`;
const studioURL = `${studioRoot}/?template=${encodeURIComponent('ap://' + identifier + '#hash')}`;
const githubURL = `${githubRoot}/src/${encodeURIComponent(identifier.split('@')[0])}/README.md`;

const fallbackHtml = nunjucks.render('fallback.njk', {
serverRoot: serverRoot,
filePath: f,
identifier: identifier,
displayName: displayName,
description: description,
studioURL: studioURL,
githubURL: githubURL,
archiveURL: archiveURL,
umlCardURL: `${serverRoot}/assets/images/A-MARK-ACCORDPROJECT-ONELINE-white.svg`
});

try {
await fs.writeFile(filePath, fallbackHtml);
console.log(`Replaced ${f} with fallback page.`);
} catch(e) {
console.error(`Failed writing ${filePath}:`, e);
}
}
}
}

run().catch(e => {
console.error('Script failed:', e);
process.exit(1);
});
75 changes: 75 additions & 0 deletions views/fallback.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{% extends "page.njk" %}

{% block unfurl %}
<!-- Open Graph / Twitter cards for sharing -->
<meta property="og:url" content="{{serverRoot}}/{{filePath}}" />
<meta property="og:title" content="{{displayName}}" />
<meta property="og:description" content="{{description}}" />
<meta property="og:image" content="{{umlCardURL}}" />

<meta name="twitter:title" content="{{displayName}}" />
<meta name="twitter:description" content="{{description}}" />
<meta name="twitter:image" content="{{umlCardURL}}" />
<meta name="twitter:url" content="{{serverRoot}}/{{filePath}}" />
{% endblock %}

{% block body %}
<section class="section inner-content">
<div class="container">
<h1 class="title is-1">{{displayName}}</h1>

<div class="tags">
<span class="tag is-light">{{identifier}}</span>
<span class="tag is-light">Fallback</span>
</div>

<p class="subtitle">
{% if description %}{{description}}{% else %}<em>No description available.</em>{% endif %}
</p>

<div class="buttons">
<a href="{{archiveURL}}" class="button is-rounded is-primary">Download Archive</a>
<a href="{{studioURL}}" class="button is-rounded is-primary">Open in Template Studio</a>
<a href="{{githubURL}}" class="button is-rounded is-primary">Open in VSCode Web</a>
</div>

<hr/>

<div class="content box">
<p>
This page could not be generated automatically. The repository likely lacks assets for this template.
</p>
<p>
We replaced the empty output with this fallback so users can still see the template metadata and links to the archive and source.
</p>
</div>

<div class="columns">
<div class="column is-half">
<h4 class="title is-4">Template Identifier</h4>
<pre><code>{{identifier}}</code></pre>
</div>
<div class="column is-half">
<h4 class="title is-4">Links</h4>
<ul>
<li><a href="{{archiveURL}}">Archive (.cta)</a></li>
<li><a href="{{studioURL}}">Open in Template Studio</a></li>
<li><a href="{{githubURL}}">Open README in VSCode Web</a></li>
</ul>
</div>
</div>

<div class="content has-text-centered">
<img src="{{umlCardURL}}" alt="UML diagram placeholder" style="max-width:240px; opacity:0.9;"/>
</div>

<h2 class="title is-2">Technical Integration</h2>
<div class="content">
<p>
This is a fallback page — for the template source and code, check the README on GitHub: <a href="{{githubURL}}">{{githubURL}}</a>
</p>
</div>
</div>

</section>
{% endblock %}