|
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) => { |
|
|
|
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) |
|
} |
|
)(); |