374374 0% { transform : rotate (0deg ); }
375375 100% { transform : rotate (360deg ); }
376376 }
377-
377+
378378 .modal-overlay {
379379 display : none;
380380 position : fixed;
@@ -1046,7 +1046,16 @@ <h2 class="section-title">
10461046 </ div >
10471047
10481048 < script >
1049- const API_BASE = 'http://localhost:8000' ;
1049+ // Environment configuration
1050+ // In production, window.LEXECON_ENV will be undefined or 'production'
1051+ // To enable dev mode, set: <script>window.LEXECON_ENV = 'development'; </ script > before this file
1052+ const ENV = window.LEXECON_ENV || 'production';
1053+ const IS_DEV = ENV === 'development' || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
1054+
1055+ // API Base URL - environment aware
1056+ const API_BASE = window.LEXECON_API_BASE ||
1057+ (IS_DEV ? 'http://localhost:8000' : window.location.origin + '/api');
1058+
10501059 let currentTimeWindow = 'all';
10511060
10521061 async function fetchAPI(endpoint) {
@@ -1256,7 +1265,7 @@ <h2 class="section-title">
12561265 document.getElementById('auditModal').style.display = 'block';
12571266 currentStep = 1;
12581267 updateModalUI();
1259-
1268+
12601269 // Pre-fill current user if available
12611270 const today = new Date().toISOString().split('T')[0];
12621271 document.getElementById('dateTo').value = today;
@@ -1344,7 +1353,7 @@ <h2 class="section-title">
13441353 const requester = document.getElementById('requesterName').value.trim();
13451354 const email = document.getElementById('requesterEmail').value.trim();
13461355 const purpose = document.getElementById('requestPurpose').value;
1347-
1356+
13481357 if (!requester) {
13491358 alert('❌ Please enter your name');
13501359 return false;
@@ -1361,10 +1370,10 @@ <h2 class="section-title">
13611370}
13621371
13631372function validateStep2() {
1364- const hasFormat = document . getElementById ( 'formatJSON' ) . checked ||
1365- document . getElementById ( 'formatText' ) . checked ||
1373+ const hasFormat = document.getElementById('formatJSON').checked ||
1374+ document.getElementById('formatText').checked ||
13661375 document.getElementById('formatCSV').checked;
1367-
1376+
13681377 if (!hasFormat) {
13691378 alert('❌ Please select at least one export format');
13701379 return false;
@@ -1386,7 +1395,7 @@ <h2 class="section-title">
13861395function captureStep2Data() {
13871396 const dateFrom = document.getElementById('dateFrom').value;
13881397 const dateTo = document.getElementById('dateTo').value;
1389-
1398+
13901399 auditPacketData.config = {
13911400 date_range: {
13921401 from: dateFrom || null,
@@ -1409,35 +1418,35 @@ <h2 class="section-title">
14091418async function updatePreview() {
14101419 // Update metadata preview
14111420 document.getElementById('previewRequester').textContent = auditPacketData.metadata.requester_name;
1412- document . getElementById ( 'previewPurpose' ) . textContent =
1421+ document.getElementById('previewPurpose').textContent =
14131422 document.getElementById('requestPurpose').options[document.getElementById('requestPurpose').selectedIndex].text;
14141423 document.getElementById('previewCaseId').textContent = auditPacketData.metadata.case_id;
1415-
1424+
14161425 // Update date range
14171426 const from = auditPacketData.config.date_range.from || 'All time';
14181427 const to = auditPacketData.config.date_range.to;
1419- document . getElementById ( 'previewDateRange' ) . textContent =
1428+ document.getElementById('previewDateRange').textContent =
14201429 from === 'All time' ? 'All time' : `${from} to ${to}`;
1421-
1430+
14221431 // Update formats
14231432 const formats = [];
14241433 if (auditPacketData.config.formats.json) formats.push('JSON');
14251434 if (auditPacketData.config.formats.text) formats.push('Text');
14261435 if (auditPacketData.config.formats.csv) formats.push('CSV');
14271436 document.getElementById('previewFormats').textContent = formats.join(', ');
1428-
1437+
14291438 // Fetch actual counts from API (simplified - you'd call real endpoints)
14301439 try {
14311440 const timeWindow = calculateTimeWindow();
14321441 const [ledger, storage] = await Promise.all([
14331442 fetchAPI('/ledger/entries'),
14341443 fetchAPI('/compliance/eu-ai-act/article-14/storage/stats')
14351444 ]);
1436-
1445+
14371446 const decisions = ledger?.entries?.filter(e => e.event_type === 'decision').length || 0;
14381447 const interventions = storage?.total_interventions || 0;
14391448 const ledgerEntries = ledger?.entries?.length || 0;
1440-
1449+
14411450 document.getElementById('previewDecisions').textContent = auditPacketData.config.include.decisions ? decisions : 'Excluded';
14421451 document.getElementById('previewInterventions').textContent = auditPacketData.config.include.interventions ? interventions : 'Excluded';
14431452 document.getElementById('previewLedger').textContent = auditPacketData.config.include.ledger ? ledgerEntries : 'Excluded';
@@ -1449,13 +1458,13 @@ <h2 class="section-title">
14491458function calculateTimeWindow() {
14501459 const from = auditPacketData.config.date_range.from;
14511460 const to = auditPacketData.config.date_range.to;
1452-
1461+
14531462 if (!from) return 'all';
1454-
1463+
14551464 const fromDate = new Date(from);
14561465 const toDate = new Date(to);
14571466 const diffDays = Math.ceil((toDate - fromDate) / (1000 * 60 * 60 * 24));
1458-
1467+
14591468 if (diffDays < = 1) return '24h';
14601469 if (diffDays < = 7) return '7d';
14611470 if (diffDays < = 30) return '30d';
@@ -1466,7 +1475,7 @@ <h2 class="section-title">
14661475 const today = new Date();
14671476 const to = today.toISOString().split('T')[0];
14681477 document.getElementById('dateTo').value = to;
1469-
1478+
14701479 if (range === 'all') {
14711480 document.getElementById('dateFrom').value = '';
14721481 } else {
@@ -1556,45 +1565,45 @@ <h2 class="section-title">
15561565 document.getElementById('modalStep5').style.display = 'block';
15571566 document.getElementById('modalBackBtn').style.display = 'none';
15581567 document.getElementById('modalNextBtn').style.display = 'none';
1559-
1568+
15601569 const progressFill = document.getElementById('progressFill');
15611570 const statusText = document.getElementById('generationStatus');
1562-
1571+
15631572 try {
15641573 // Step 1: Validate request
15651574 progressFill.style.width = '20%';
15661575 statusText.textContent = 'Validating request...';
15671576 await sleep(300);
1568-
1577+
15691578 // Step 2: Collect data
15701579 progressFill.style.width = '40%';
15711580 statusText.textContent = 'Collecting compliance data...';
15721581 await sleep(300);
1573-
1582+
15741583 const timeWindow = calculateTimeWindow();
15751584 const formats = [];
15761585 if (auditPacketData.config.formats.json) formats.push('json');
15771586 if (auditPacketData.config.formats.text) formats.push('text');
15781587 if (auditPacketData.config.formats.csv) formats.push('csv');
1579-
1588+
15801589 // Step 3: Generate packets
15811590 progressFill.style.width = '60%';
15821591 statusText.textContent = 'Generating audit packets...';
1583-
1592+
15841593 const downloads = [];
15851594 for (const format of formats) {
15861595 const response = await fetch(`${API_BASE}/compliance/eu-ai-act/audit-packet?time_window=${timeWindow}&format=${format}`);
15871596 if (!response.ok) throw new Error(`Failed to generate ${format} format`);
1588-
1597+
15891598 const data = format === 'json' ? await response.json() : await response.text();
15901599 downloads.push({ format, data });
15911600 }
1592-
1601+
15931602 // Step 4: Add metadata
15941603 progressFill.style.width = '80%';
15951604 statusText.textContent = 'Adding request metadata...';
15961605 await sleep(200);
1597-
1606+
15981607 // Enhance JSON packet with metadata
15991608 if (auditPacketData.config.formats.json) {
16001609 const jsonDownload = downloads.find(d => d.format === 'json');
@@ -1603,21 +1612,21 @@ <h2 class="section-title">
16031612 jsonDownload.data.generation_config = auditPacketData.config;
16041613 }
16051614 }
1606-
1615+
16071616 // Step 5: Download files
16081617 progressFill.style.width = '100%';
16091618 statusText.textContent = 'Preparing downloads...';
16101619 await sleep(200);
1611-
1620+
16121621 const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);
1613-
1622+
16141623 for (const download of downloads) {
16151624 const extension = download.format === 'json' ? 'json' : download.format === 'text' ? 'txt' : 'csv';
16161625 const content = download.format === 'json' ? JSON.stringify(download.data, null, 2) : download.data;
1617- const blob = new Blob ( [ content ] , {
1618- type : download . format === 'json' ? 'application/json' : 'text/plain'
1626+ const blob = new Blob([content], {
1627+ type: download.format === 'json' ? 'application/json' : 'text/plain'
16191628 });
1620-
1629+
16211630 const url = window.URL.createObjectURL(blob);
16221631 const a = document.createElement('a');
16231632 a.href = url;
@@ -1626,13 +1635,13 @@ <h2 class="section-title">
16261635 a.click();
16271636 document.body.removeChild(a);
16281637 window.URL.revokeObjectURL(url);
1629-
1638+
16301639 await sleep(100); // Small delay between downloads
16311640 }
1632-
1641+
16331642 // Success!
16341643 closeAuditModal();
1635-
1644+
16361645 alert(`✅ Audit Packet Generated Successfully!
16371646
16381647Requester: ${auditPacketData.metadata.requester_name}
@@ -1641,13 +1650,13 @@ <h2 class="section-title">
16411650Files Downloaded: ${downloads.length}
16421651
16431652This generation has been logged in the audit trail.`);
1644-
1653+
16451654 } catch (error) {
16461655 console.error('Generation failed:', error);
16471656 progressFill.style.width = '0%';
16481657 statusText.textContent = 'Generation failed';
16491658 statusText.style.color = 'var(--danger)';
1650-
1659+
16511660 setTimeout(() => {
16521661 alert('❌ Failed to generate audit packet:\n\n' + error.message);
16531662 closeAuditModal();
@@ -1686,7 +1695,7 @@ <h2 class="section-title">
16861695 < h2 class ="modal-title "> Generate Compliance Audit Packet</ h2 >
16871696 < button class ="modal-close " onclick ="closeAuditModal() "> ×</ button >
16881697 </ div >
1689-
1698+
16901699 < div class ="modal-body ">
16911700 <!-- Step Indicator -->
16921701 < div class ="step-indicator ">
@@ -2016,7 +2025,7 @@ <h3 style="color: var(--text-primary); margin-bottom: 8px;">Generating Audit Pac
20162025 </ div >
20172026 </ div >
20182027 </ div >
2019-
2028+
20202029 < div class ="modal-footer ">
20212030 < button class ="action-btn btn-secondary " id ="modalBackBtn " onclick ="previousStep() " style ="display: none; ">
20222031 ← Back
0 commit comments