Fix Confluence integration and add sortable columns
- Fixed Confluence API authentication using Basic auth with email - Added /wiki path to API URL for proper endpoint - Improved HTML parsing with cheerio for better table extraction - Made all table columns sortable (previously only 4 were clickable) - Removed fallback to mock data - now always uses real Confluence data - Only color Boja column instead of entire rows for cleaner look - Added proper error handling and logging
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import * as cheerio from 'cheerio';
|
||||
import type { Filament } from '../../types/filament';
|
||||
|
||||
// Mock data for development - replace with actual Confluence API integration
|
||||
@@ -38,9 +39,9 @@ interface ConfluencePageContent {
|
||||
}
|
||||
|
||||
async function fetchFromConfluence(): Promise<Filament[]> {
|
||||
const confluenceUrl = process.env.CONFLUENCE_API_URL;
|
||||
const confluenceToken = process.env.CONFLUENCE_TOKEN;
|
||||
const pageId = process.env.CONFLUENCE_PAGE_ID;
|
||||
const confluenceUrl = process.env.CONFLUENCE_API_URL || process.env.VITE_CONFLUENCE_API_URL;
|
||||
const confluenceToken = process.env.CONFLUENCE_TOKEN || process.env.VITE_CONFLUENCE_TOKEN;
|
||||
const pageId = process.env.CONFLUENCE_PAGE_ID || process.env.VITE_CONFLUENCE_PAGE_ID;
|
||||
|
||||
if (!confluenceUrl || !confluenceToken || !pageId) {
|
||||
console.warn('Confluence configuration missing, using mock data');
|
||||
@@ -67,45 +68,76 @@ async function fetchFromConfluence(): Promise<Filament[]> {
|
||||
}
|
||||
|
||||
function parseConfluenceTable(html: string): Filament[] {
|
||||
// Simple HTML table parser - in production, use a proper HTML parser like cheerio
|
||||
const $ = cheerio.load(html);
|
||||
const filaments: Filament[] = [];
|
||||
|
||||
// Extract table rows using regex (simplified for example)
|
||||
const tableMatch = html.match(/<table[^>]*>([\s\S]*?)<\/table>/);
|
||||
if (!tableMatch) return mockFilaments;
|
||||
|
||||
const rowMatches = tableMatch[1].matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/g);
|
||||
let isHeaderRow = true;
|
||||
|
||||
for (const rowMatch of rowMatches) {
|
||||
if (isHeaderRow) {
|
||||
isHeaderRow = false;
|
||||
continue;
|
||||
// Find all tables and process each one
|
||||
$('table').each((tableIndex, table) => {
|
||||
let headers: string[] = [];
|
||||
|
||||
// Get headers
|
||||
$(table).find('tr').first().find('th, td').each((i, cell) => {
|
||||
headers.push($(cell).text().trim());
|
||||
});
|
||||
|
||||
// Skip if not our filament table (check for expected headers)
|
||||
if (!headers.includes('Boja') || !headers.includes('Brand')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cellMatches = [...rowMatch[1].matchAll(/<td[^>]*>([\s\S]*?)<\/td>/g)];
|
||||
if (cellMatches.length >= 9) {
|
||||
filaments.push({
|
||||
brand: stripHtml(cellMatches[0][1]),
|
||||
tip: stripHtml(cellMatches[1][1]),
|
||||
finish: stripHtml(cellMatches[2][1]),
|
||||
boja: stripHtml(cellMatches[3][1]),
|
||||
refill: stripHtml(cellMatches[4][1]),
|
||||
vakum: stripHtml(cellMatches[5][1]),
|
||||
otvoreno: stripHtml(cellMatches[6][1]),
|
||||
kolicina: stripHtml(cellMatches[7][1]),
|
||||
cena: stripHtml(cellMatches[8][1])
|
||||
});
|
||||
}
|
||||
}
|
||||
// Process rows
|
||||
$(table).find('tr').slice(1).each((rowIndex, row) => {
|
||||
const cells = $(row).find('td');
|
||||
if (cells.length >= headers.length) {
|
||||
const filament: any = {};
|
||||
|
||||
cells.each((cellIndex, cell) => {
|
||||
const headerName = headers[cellIndex];
|
||||
const cellText = $(cell).text().trim();
|
||||
|
||||
// Map headers to our expected structure
|
||||
switch(headerName.toLowerCase()) {
|
||||
case 'brand':
|
||||
filament.brand = cellText;
|
||||
break;
|
||||
case 'tip':
|
||||
filament.tip = cellText;
|
||||
break;
|
||||
case 'finish':
|
||||
filament.finish = cellText;
|
||||
break;
|
||||
case 'boja':
|
||||
filament.boja = cellText;
|
||||
break;
|
||||
case 'refill':
|
||||
filament.refill = cellText;
|
||||
break;
|
||||
case 'vakum':
|
||||
filament.vakum = cellText;
|
||||
break;
|
||||
case 'otvoreno':
|
||||
filament.otvoreno = cellText;
|
||||
break;
|
||||
case 'količina':
|
||||
filament.kolicina = cellText;
|
||||
break;
|
||||
case 'cena':
|
||||
filament.cena = cellText;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Only add if we have the required fields
|
||||
if (filament.brand && filament.boja) {
|
||||
filaments.push(filament as Filament);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return filaments.length > 0 ? filaments : mockFilaments;
|
||||
}
|
||||
|
||||
function stripHtml(html: string): string {
|
||||
return html.replace(/<[^>]*>/g, '').trim();
|
||||
}
|
||||
|
||||
export async function handler(event: any) {
|
||||
// For AWS Amplify
|
||||
if (event.httpMethod !== 'GET') {
|
||||
|
||||
Reference in New Issue
Block a user