Phase 2 of task management consolidation: - Added _data/tasks.js - fetches tasks from Gitea API at build time - Added tasks-index.njk - mobile-friendly task list page - Added node-fetch dependency for API calls - Added .gitignore for node_modules and _site Features: - Shows only open/blocked tasks (filters out complete) - Priority filtering (P1/P2/P3/P4) - Color-coded priority badges (Fire/Gold/Frost/Arcane) - Links to Gitea for full task details - Mobile-optimized touch targets Access at: firefrostgaming.com/tasks-index.html Chronicler #69
129 lines
4.4 KiB
JavaScript
129 lines
4.4 KiB
JavaScript
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
|
|
module.exports = async function() {
|
|
const GITEA_API = 'https://git.firefrostgaming.com/api/v1';
|
|
const REPO_OWNER = 'firefrost-gaming';
|
|
const REPO_NAME = 'firefrost-operations-manual';
|
|
const TOKEN = process.env.GITEA_TOKEN || 'e0e330cba1749b01ab505093a160e4423ebbbe36';
|
|
|
|
const tasks = [];
|
|
|
|
try {
|
|
// Get list of task directories
|
|
const response = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
},
|
|
timeout: 30000
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
console.error('Failed to fetch task list:', response.status);
|
|
return [];
|
|
}
|
|
|
|
const dirs = await response.json();
|
|
const taskDirs = dirs.filter(d => d.type === 'dir' && d.name !== '_archive');
|
|
|
|
// Fetch each task's README
|
|
for (const dir of taskDirs) {
|
|
try {
|
|
// Try README.md first
|
|
let readmePath = `docs/tasks/${dir.name}/README.md`;
|
|
let readmeResponse = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
|
|
if (!readmeResponse.ok) {
|
|
// Try to find any .md file
|
|
const filesResponse = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks/${encodeURIComponent(dir.name)}?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
|
|
if (filesResponse.ok) {
|
|
const files = await filesResponse.json();
|
|
const mdFile = files.find(f => f.name.endsWith('.md'));
|
|
if (mdFile) {
|
|
readmePath = `docs/tasks/${dir.name}/${mdFile.name}`;
|
|
readmeResponse = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (readmeResponse && readmeResponse.ok) {
|
|
const fileData = await readmeResponse.json();
|
|
const content = Buffer.from(fileData.content, 'base64').toString('utf-8');
|
|
|
|
// Parse YAML frontmatter
|
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
if (frontmatterMatch) {
|
|
const frontmatter = {};
|
|
frontmatterMatch[1].split('\n').forEach(line => {
|
|
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
if (match) {
|
|
frontmatter[match[1]] = match[2].trim();
|
|
}
|
|
});
|
|
|
|
// Extract title from first H1
|
|
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
const title = titleMatch ? titleMatch[1] : dir.name;
|
|
|
|
tasks.push({
|
|
slug: dir.name,
|
|
title: title,
|
|
status: frontmatter.status || 'open',
|
|
priority: frontmatter.priority || 'P3',
|
|
owner: frontmatter.owner || 'Michael',
|
|
created: frontmatter.created || '2026-01-01',
|
|
giteaUrl: `https://git.firefrostgaming.com/${REPO_OWNER}/${REPO_NAME}/src/branch/master/docs/tasks/${encodeURIComponent(dir.name)}`
|
|
});
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error(`Error processing ${dir.name}:`, err.message);
|
|
}
|
|
}
|
|
|
|
// Sort by priority (P1 first) then by title
|
|
tasks.sort((a, b) => {
|
|
if (a.priority !== b.priority) {
|
|
return a.priority.localeCompare(b.priority);
|
|
}
|
|
return a.title.localeCompare(b.title);
|
|
});
|
|
|
|
console.log(`[11ty] Loaded ${tasks.length} tasks from Gitea`);
|
|
return tasks;
|
|
|
|
} catch (err) {
|
|
console.error('[11ty] Error fetching tasks:', err.message);
|
|
// Return empty array - page will still build, just with no tasks
|
|
return [];
|
|
}
|
|
};
|