let dark = document.location.search.includes('dark-theme=true'); if (dark) document.body.classList.add('dark-theme'); var COLORS = dark ? ['#FF0000', '#00FF00', '#0000FF', '#FF00FF', '#FFFF00', '#0000FF', '#F090F0', '#90F0F0', '#F0F090'] : ['#CC0000', '#00CC00', '#0000CC', '#CC00CC', '#CCCC00', '#0000CC', '#C060C0', '#60C0C0', '#C0C060'] const load = () => { const l0 = document.createElement('div') const l1 = document.createElement('div') const l2 = document.createElement('div') l0.classList.add('lds-ripple') l0.appendChild(l1) l0.appendChild(l2) return l0 } const getCheckedOptions = () => { const options = Array.from(document.querySelectorAll('.option-div')) .map(e => Array.from(e.children) .filter(e => e.nodeName == 'DIV')) .filter(e => e.length) .flat() .map(e => e.id) .filter(e => document.querySelector(`#${e}-checkbox`).checked) const optionsDict = {} for (let option of options) { const key = option.split('-option-')[0] const value = option.split('-option-')[1] if (key in optionsDict) optionsDict[key].push(value) else optionsDict[key] = [value] } return optionsDict; } const addOption = (category, optionName) => { /* Options for the issue div */ const issueDiv = document.getElementById(`${category}Div`); const div = document.createElement('div') let found = false; let optionNumber = 0; while (!found && ++optionNumber < 100) { let previousOption = document.getElementById(`${category}-option-${optionNumber}`); found = previousOption === null; } div.id = `${category}-option-${optionNumber}`; issueDiv.appendChild(div); const checkBox = document.createElement('input'); checkBox.type = 'checkbox' checkBox.id = `${category}-option-${optionNumber}-checkbox` const checkBoxLabel = document.createElement('label'); const labelSpan = document.createElement('span') labelSpan.textContent = optionName; checkBoxLabel.appendChild(checkBox) checkBoxLabel.appendChild(labelSpan) div.appendChild(checkBoxLabel) return optionNumber } let charts = []; const createButton = (title, libraries, methods) => { const button = document.createElement('button') button.textContent = title; button.onclick = async () => { document.getElementById('pip-graph').innerHTML = '' document.getElementById('star-graph').innerHTML = '' document.getElementById('issue-graph').innerHTML = '' const e = load() document.body.appendChild(e) const selectedInternalLibraries = libraries.internal.filter(e => document.querySelector(`#${e}Checkbox`).checked); const selectedExternalLibraries = libraries.external.filter(e => document.querySelector(`#${e}Checkbox`).checked); const selectedLibraries = selectedInternalLibraries.concat(selectedExternalLibraries); const relevantOptions = getCheckedOptions(); if (charts.length !== 0) { for (const chart of charts) { chart.destroy() } } for (const method of methods()) { charts.push(await method(selectedLibraries, relevantOptions)) } document.body.removeChild(e) }; return button; } const initialize = async () => { const inferResponse = await fetch(`initialize`); console.log(inferResponse); const inferJson = await inferResponse.json(); console.log(inferJson); const warnings = document.getElementById("warnings") const librarySelector = document.getElementById('library-selector'); const graphSelector = document.getElementById('graph-selector'); const selectorSubmit = document.getElementById('selector-submit'); const introSpan = document.createElement("h3") introSpan.textContent = "Select libraries to display" librarySelector.appendChild(introSpan); const graphSpan = document.createElement("h3") graphSpan.textContent = "Select graphs to display" graphSelector.appendChild(graphSpan); if (inferJson.warnings.length > 0) { for (const warning of inferJson.warnings) { const div = document.createElement('div'); div.classList.add('warning-div') const labelSpan = document.createElement('span'); labelSpan.textContent = `Warning: ${warning}`; div.appendChild(labelSpan); warnings.appendChild(div); } } for (const element of inferJson.internal) { const div = document.createElement('div'); const checkBox = document.createElement('input'); checkBox.type = 'checkbox' checkBox.id = `${element}Checkbox`; const checkBoxLabel = document.createElement('label'); const labelSpan = document.createElement('span') labelSpan.textContent = element.charAt(0).toUpperCase() + element.slice(1) checkBoxLabel.appendChild(checkBox) checkBoxLabel.appendChild(labelSpan) div.appendChild(checkBoxLabel) librarySelector.appendChild(div) } const externalLibs = document.createElement("h3") externalLibs.textContent = "External Libraries" librarySelector.appendChild(externalLibs); for (const element of inferJson.external) { const div = document.createElement('div'); const checkBox = document.createElement('input'); checkBox.type = 'checkbox' checkBox.id = `${element}Checkbox`; const checkBoxLabel = document.createElement('label'); const labelSpan = document.createElement('span') labelSpan.textContent = element.charAt(0).toUpperCase() + element.slice(1) checkBoxLabel.appendChild(checkBox) checkBoxLabel.appendChild(labelSpan) div.appendChild(checkBoxLabel) librarySelector.appendChild(div) } for (const element of ['pip', 'stars', 'issue']) { const div = document.createElement('div'); div.classList.add('option-div') div.id = `${element}Div`; const checkBox = document.createElement('input'); checkBox.type = 'checkbox' checkBox.id = `${element}CheckboxGraph`; const checkBoxLabel = document.createElement('label'); const labelSpan = document.createElement('span') labelSpan.textContent = element.charAt(0).toUpperCase() + element.slice(1) checkBoxLabel.appendChild(checkBox) checkBoxLabel.appendChild(labelSpan) div.appendChild(checkBoxLabel) graphSelector.appendChild(div) } addOption('pip', "Cumulated"); addOption('pip', "Week over week"); addOption('issue', "Exclude org members"); addOption('issue', "Week over week"); addOption('issue', "Cumulated"); addOption('stars', "Week over week"); addOption('stars', "Cumulated"); const fetchButton = createButton('Fetch', inferJson, () => { const graphNames = ['pip', 'stars', 'issue'].filter(e => document.querySelector(`#${e}CheckboxGraph`).checked); const graphs = [] if (graphNames.includes('pip')) graphs.push(retrievePipInstalls) if (graphNames.includes('stars')) graphs.push(retrieveStars) if (graphNames.includes('issue')) graphs.push(retrieveIssues) return graphs }) selectorSubmit.appendChild(fetchButton); }; const retrievePipInstalls = async (libraryNames, options) => { const relevantOptions = options['pip'] const inferResponse = await fetch(`retrievePipInstalls?input=${libraryNames}&options=${relevantOptions}`); const inferJson = await inferResponse.json(); const colors = [...COLORS]; const labels = Array.from(inferJson['day']).map(e => new Date(e)) const datasets = []; for (const element in inferJson) { if (element === 'day') continue const color = colors.pop() datasets.push({ label: element, data: inferJson[element], backgroundColor: color, borderColor: color, tension: 0.01, pointRadius: 1, borderWidth: 2, fill: false }) } const ctx = document.getElementById('pip-graph'); const myChart = new Chart(ctx, { type: 'line', data: {labels, datasets}, options: { scales: { y: { beginAtZero: true }, x: { type: 'time', } }, plugins: { title: { display: true, text: 'Pip installs' } } } }); return myChart; }; const retrieveStars = async (libraryNames, options) => { const relevantOptions = options['stars'] const inferResponse = await fetch(`retrieveStars?input=${libraryNames}&options=${relevantOptions}`); const inferJson = await inferResponse.json(); const colors = [...COLORS]; const labels = Array.from(inferJson['day']).map(e => new Date(e)) const datasets = []; for (const element in inferJson) { if (element === 'day') continue const color = colors.pop() datasets.push({ label: element, data: inferJson[element], backgroundColor: color, borderColor: color, tension: 0.01, pointRadius: 1, borderWidth: 2, fill: false }) } const ctx = document.getElementById('star-graph'); const myChart = new Chart(ctx, { title: "Stars", type: 'line', data: {labels, datasets}, options: { scales: { y: { beginAtZero: true }, x: { type: 'time', } }, plugins: { title: { display: true, text: 'Number of stargazers' } } } }); return myChart; }; const retrieveIssues = async (libraryNames, options) => { const relevantOptions = options['issue'] const inferResponse = await fetch(`retrieveIssues?input=${libraryNames}&options=${relevantOptions}`); const inferJson = await inferResponse.json(); const colors = [...COLORS]; const labels = Array.from(inferJson['day']).map(e => new Date(e)) const datasets = []; for (const element in inferJson) { if (element === 'day') continue const color = colors.pop() datasets.push({ label: element, data: inferJson[element], backgroundColor: color, borderColor: color, tension: 0.01, pointRadius: 1, borderWidth: 2, fill: false }) } const ctx = document.getElementById('issue-graph'); const myChart = new Chart(ctx, { title: "Issues", type: 'line', data: {labels, datasets}, options: { scales: { y: { beginAtZero: true }, x: { type: 'time', } }, plugins: { title: { display: true, text: 'Cumulated number of issues, PRs, and comments' } } } }); return myChart; }; ( async () => { const e = load() document.body.appendChild(e) await initialize() document.body.removeChild(e) } )();