This tool displays data and profiling information after the workflow is run.
`;
}
};
const renderDataConfigTable = () => {
const listBody = document.getElementById('alt-data-list-body');
listBody.innerHTML = '';
sampleData.forEach(rec => {
listBody.innerHTML += `
| ${rec.CustomerID} | ${rec.State} | $${rec.Sales?.toFixed(2) || '0.00'} |
|
`;
});
};
const runWorkflow = () => {
resultsData = sampleData.filter(d => d.State === workflowConfig.filterState);
document.getElementById('alt-results-message').style.display = 'none';
renderResults();
alt_changeTab(null, 'Results');
};
const renderResults = () => {
const table = document.getElementById('alt-results-table');
table.innerHTML = '';
if (resultsData.length === 0) {
table.innerHTML = '
| Workflow ran successfully, but the filter produced 0 records. |
';
document.getElementById('alt-profile-panel').innerHTML = 'No data to profile.';
return;
};
const headers = Object.keys(resultsData[0]);
const headerRow = document.createElement('tr');
headers.forEach(header => {
const th = document.createElement('th');
th.textContent = header;
th.onclick = () => renderProfile(header);
headerRow.appendChild(th);
});
table.appendChild(headerRow);
resultsData.forEach(row => {
const tr = document.createElement('tr');
headers.forEach(header => {
const td = document.createElement('td');
td.textContent = row[header] === null ? '[Null]' : row[header];
tr.appendChild(td);
});
table.appendChild(tr);
});
renderProfile(headers[0]);
};
const renderProfile = (columnName) => {
const panel = document.getElementById('alt-profile-panel');
if (resultsData.length === 0) {
panel.innerHTML = 'No data to profile.';
return;
}
const values = resultsData.map(d => d[columnName]).filter(v => v !== null && v !== undefined);
const nulls = resultsData.length - values.length;
const dataType = typeof values[0];
let profileHTML = `
${columnName}
`;
profileHTML += `
Data Type: ${dataType}
Nulls: ${nulls} (${((nulls/resultsData.length)*100).toFixed(1)}%)
`;
if (dataType === 'number') {
const sum = values.reduce((s, v) => s + v, 0);
profileHTML += `
Min: ${Math.min(...values)}
Max: ${Math.max(...values)}
Average: ${(sum / values.length).toFixed(2)}
`;
}
profileHTML += '
';
panel.innerHTML = profileHTML;
const ctx = document.getElementById('alt-profile-chart')?.getContext('2d');
if (!ctx) return;
if (profileChart) profileChart.destroy();
const valueCounts = values.reduce((acc, v) => { acc[v] = (acc[v] || 0) + 1; return acc; }, {});
profileChart = new Chart(ctx, {
type: 'bar',
data: {
labels: Object.keys(valueCounts),
datasets: [{ data: Object.values(valueCounts), backgroundColor: '#007bff' }]
},
options: { responsive: true, plugins: { legend: { display: false }, title: { display: true, text: 'Value Distribution' } } }
});
};
// --- EVENT LISTENERS ---
document.getElementById('tool-input').onclick = () => renderConfigPanel('Input Data');
document.getElementById('tool-filter').onclick = () => renderConfigPanel('Filter');
document.getElementById('tool-browse').onclick = () => renderConfigPanel('Browse');
document.getElementById('alt-run-button').onclick = runWorkflow;
document.getElementById('alt-data-form').addEventListener('submit', (e) => {
e.preventDefault();
const newRecord = {
CustomerID: parseInt(document.getElementById('alt-form-id').value),
State: document.getElementById('alt-form-state').value,
Sales: parseFloat(document.getElementById('alt-form-sales').value),
JoinDate: document.getElementById('alt-form-date').value
};
if(sampleData.some(d => d.CustomerID === newRecord.CustomerID)) {
alert('Error: CustomerID must be unique.');
return;
}
sampleData.push(newRecord);
e.target.reset();
renderAll();
});
window.alt_deleteRecord = (id) => {
sampleData = sampleData.filter(d => d.CustomerID !== id);
renderAll();
};
// --- PDF & TAB NAVIGATION ---
window.alt_generatePDF = async () => {
const { jsPDF } = window.jspdf;
const content = document.getElementById('alt-results-content-for-pdf');
try {
const canvas = await html2canvas(content, { scale: 2 });
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'landscape', unit: 'px', format: [canvas.width, canvas.height] });
pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height);
pdf.save('alteryx-browse-results.pdf');
} catch(error) { console.error("PDF Error:", error); }
};
const tabs = document.querySelectorAll('.alt-tab-button');
const tabContents = document.querySelectorAll('.alt-tab-content');
const nextBtn = document.getElementById('alt-next-btn');
const prevBtn = document.getElementById('alt-prev-btn');
window.alt_changeTab = (event, tabName) => {
tabContents.forEach(c => c.classList.remove('active'));
tabs.forEach(t => t.classList.remove('active'));
document.getElementById(tabName).classList.add('active');
const clickedTab = event ? event.currentTarget : document.querySelector(`.alt-tab-button[onclick*="'${tabName}'"]`);
if(clickedTab) clickedTab.classList.add('active');
updateNavButtons();
};
const updateNavButtons = () => {
const idx = Array.from(tabs).findIndex(t => t.classList.contains('active'));
prevBtn.disabled = idx === 0;
nextBtn.disabled = idx === tabs.length - 1;
};
nextBtn.addEventListener('click', () => {
const idx = Array.from(tabs).findIndex(t => t.classList.contains('active'));
if (tabs[idx + 1]) tabs[idx + 1].click();
});
prevBtn.addEventListener('click', () => {
const idx = Array.from(tabs).findIndex(t => t.classList.contains('active'));
if (tabs[idx - 1]) tabs[idx - 1].click();
});
// --- INITIALIZATION --- //
renderAll();
});