Jakvai/postgresql-pixie-dust
0
1document.addEventListener('DOMContentLoaded', function() {2 // DOM Elements3 const queryInput = document.getElementById('query-input');4 const generateBtn = document.getElementById('generate-btn');5 const clearBtn = document.getElementById('clear-btn');6 const formatBtn = document.getElementById('format-btn');7 const resultsSection = document.getElementById('results-section');8 const tableHeaders = document.getElementById('table-headers');9 const tableBody = document.getElementById('table-body');10 const exportCsv = document.getElementById('export-csv');11 const exportJson = document.getElementById('export-json');12 const fileUpload = document.getElementById('sql-upload');13 // Database configuration from environment14 const dbConfig = {15 host: '127.0.0.1', // Will be replaced with process.env.DB_HOST in Node.js16 port: 5432, // Will be replaced with process.env.DB_PORT17 database: 'queryviz', // Will be replaced with process.env.DB_DATABASE18 user: 'postgres', // Will be replaced with process.env.DB_USERNAME19 password: '', // Will be replaced with process.env.DB_PASSWORD20 max: 20, // Will be replaced with process.env.DB_POOL_MAX_CONNECTIONS21 idleTimeoutMillis: 30000 // Will be replaced with process.env.DB_POOL_IDLE_TIMEOUT22 };23 24 // Sample data for demo purposes25 const sampleData = {26headers: ['id', 'name', 'email', 'created_at', 'status'],27 rows: [28 [1, 'John Doe', 'john@example.com', '2023-01-15', 'active'],29 [2, 'Jane Smith', 'jane@example.com', '2023-02-20', 'active'],30 [3, 'Bob Johnson', 'bob@example.com', '2023-03-10', 'inactive'],31 [4, 'Alice Brown', 'alice@example.com', '2023-04-05', 'active'],32 [5, 'Charlie Wilson', 'charlie@example.com', '2023-05-12', 'pending']33 ]34 };35 36 // Event Listeners37 generateBtn.addEventListener('click', generateReport);38 clearBtn.addEventListener('click', clearInput);39 formatBtn.addEventListener('click', formatQuery);40 exportCsv.addEventListener('click', exportToCsv);41 exportJson.addEventListener('click', exportToJson);42 fileUpload.addEventListener('change', handleFileUpload);43 44 // Functions45 function generateReport() {46 const query = queryInput.value.trim();47 48 if (!query) {49 showToast('Please enter or upload a SQL query', 'error');50 return;51 }52 53 // Show loading state54 generateBtn.disabled = true;55 generateBtn.innerHTML = '<i data-feather="loader" class="w-4 h-4 mr-2 animate-spin"></i> Processing...';56 feather.replace();57 58 // Simulate API call with timeout59 setTimeout(() => {60 // In a real app, this would connect to PostgreSQL using the dbConfig61 // Example connection using pg (Node.js PostgreSQL client):62 // const { Pool } = require('pg');63 // const pool = new Pool(dbConfig);64 // const { rows } = await pool.query(query);65displayResults(sampleData);66 67 // Reset button68 generateBtn.disabled = false;69 generateBtn.innerHTML = '<i data-feather="zap" class="w-4 h-4 mr-2"></i> Generate Report';70 feather.replace();71 }, 1500);72 }73 74 function displayResults(data) {75 // Clear previous results76 tableHeaders.innerHTML = '';77 tableBody.innerHTML = '';78 79 // Add headers80 data.headers.forEach(header => {81 const th = document.createElement('th');82 th.className = 'px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider';83 th.textContent = header;84 tableHeaders.appendChild(th);85 });86 87 // Add rows88 data.rows.forEach(row => {89 const tr = document.createElement('tr');90 row.forEach(cell => {91 const td = document.createElement('td');92 td.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300';93 td.textContent = cell;94 tr.appendChild(td);95 });96 tableBody.appendChild(tr);97 });98 99 // Show results section100 resultsSection.classList.remove('hidden');101 102 // Render chart103 renderChart(data);104 105 // Scroll to results106 resultsSection.scrollIntoView({ behavior: 'smooth' });107 }108 109 function renderChart(data) {110 const ctx = document.getElementById('results-chart').getContext('2d');111 112 // Simple chart showing count by status (for demo)113 const statusCounts = {};114 const statusIndex = data.headers.indexOf('status');115 116 if (statusIndex !== -1) {117 data.rows.forEach(row => {118 const status = row[statusIndex];119 statusCounts[status] = (statusCounts[status] || 0) + 1;120 });121 }122 123 new Chart(ctx, {124 type: 'bar',125 data: {126 labels: Object.keys(statusCounts),127 datasets: [{128 label: 'Records by Status',129 data: Object.values(statusCounts),130 backgroundColor: [131 'rgba(59, 130, 246, 0.7)',132 'rgba(16, 185, 129, 0.7)',133 'rgba(245, 158, 11, 0.7)'134 ],135 borderColor: [136 'rgba(59, 130, 246, 1)',137 'rgba(16, 185, 129, 1)',138 'rgba(245, 158, 11, 1)'139 ],140 borderWidth: 1141 }]142 },143 options: {144 responsive: true,145 maintainAspectRatio: false,146 scales: {147 y: {148 beginAtZero: true,149 ticks: {150 color: '#6b7280'151 },152 grid: {153 color: 'rgba(209, 213, 219, 0.3)'154 }155 },156 x: {157 ticks: {158 color: '#6b7280'159 },160 grid: {161 color: 'rgba(209, 213, 219, 0.3)'162 }163 }164 },165 plugins: {166 legend: {167 labels: {168 color: '#6b7280'169 }170 }171 }172 }173 });174 }175 176 function clearInput() {177 queryInput.value = '';178 fileUpload.value = '';179 }180 181 function formatQuery() {182 // In a real app, you would use a proper SQL formatter library183 const query = queryInput.value.trim();184 if (query) {185 // Simple formatting for demo186 const formatted = query187 .replace(/SELECT/gi, '\nSELECT')188 .replace(/FROM/gi, '\nFROM')189 .replace(/WHERE/gi, '\nWHERE')190 .replace(/GROUP BY/gi, '\nGROUP BY')191 .replace(/ORDER BY/gi, '\nORDER BY')192 .replace(/LIMIT/gi, '\nLIMIT');193 194 queryInput.value = formatted.trim();195 showToast('Query formatted', 'success');196 }197 }198 199 function handleFileUpload(event) {200 const file = event.target.files[0];201 if (!file) return;202 203 const reader = new FileReader();204 reader.onload = function(e) {205 queryInput.value = e.target.result;206 showToast('File loaded successfully', 'success');207 };208 reader.readAsText(file);209 }210 211 function exportToCsv() {212 // In a real app, implement CSV export213 showToast('CSV export would be implemented here', 'info');214 }215 216 function exportToJson() {217 // In a real app, implement JSON export218 showToast('JSON export would be implemented here', 'info');219 }220 221 function showToast(message, type = 'info') {222 const toast = document.createElement('div');223 toast.className = `fixed bottom-4 right-4 px-4 py-2 rounded-md shadow-lg text-white ${224 type === 'error' ? 'bg-red-500' : 225 type === 'success' ? 'bg-green-500' : 226 'bg-blue-500'227 }`;228 toast.textContent = message;229 document.body.appendChild(toast);230 231 setTimeout(() => {232 toast.classList.add('opacity-0', 'transition-opacity', 'duration-300');233 setTimeout(() => toast.remove(), 300);234 }, 3000);235 }236});