Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Add user story field, and ability to read data from a bug
Browse files Browse the repository at this point in the history
  • Loading branch information
jgraham committed Mar 4, 2024
1 parent 246dc8a commit 801a676
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 24 deletions.
51 changes: 35 additions & 16 deletions docs/scorebug/index.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<!doctype html>
<title>Score webcompat knowledge base bugs</title>
<script src="https://jgraham.github.io/tranco-subdomains/tranco.js"></script>
<script src="scorebug.js"></script>

<style>
:root {
font-family: sans;
}

ul {
list-style: none;
padding: 0;
Expand All @@ -22,41 +25,49 @@
margin-left: 1em;
}

th {
text-align: left;
}

dt {
font-weight: bold;
}

</style>

<h1>WebCompat Bug Scorer</h1>

<div class="input">
<ul>
<li><label>Bug id <input id="bug-id"></label>
<li><label>Bug id <input id="bug-id"></label> <button onclick="updateFromBug()">Update</button>

<li><label>URL <input id="url"></label>

<li>Platform
<ul>
<ul id="platform">
<li><input type=checkbox checked id="platform-windows" value="0.7"><label for=platform-windows>Windows</label>
<li><input type=checkbox checked id="platform-mac" value="0.2"><label for=platform-mac>macOS</label>
<li><input type=checkbox checked id="platform-linux" value="0.1"><label for=platform-linux>Linux</label>
<li><input type=checkbox checked id="platform-mobile" value="1"><label for="platform-mobile">Mobile</label>
<li><input type=checkbox checked id="platform-android" value="1"><label for=platform-android>Android</label>
</ul>

<li>Impact
<select id="impact">
<option value=100>Site broken
<option value=100>Unsupported / Blocked
<option value=60>Workflow broken
<option value=30>Feature broken
<option value=30>Content missing
<option value=20>Significant visual
<option value=1>Minor visual
<option value=20>Unsupported warning
<option id=impact-site-broken value=100>Site broken
<option id=impact-blocked value=100>Unsupported / Blocked
<option id=impact-workflow-broken value=60>Workflow broken
<option id=impact-feature-broken value=30>Feature broken
<option id=impact-content-missing value=30>Content missing
<option id=impact-significant-visual value=20>Significant visual
<option id=impact-minor-visual value=1>Minor visual
<option id=impact-unsupported-warning value=20>Unsupported warning
</select>

<li>Affects users
<select id="affects">
<option value=1>All
<option value=0.3>Some
<option value=0.1>Few
<option id=affects-all value=1>All
<option id=affects-some value=0.3>Some
<option id=affects-few value=0.1>Few
</select>

</ul>
Expand All @@ -70,7 +81,15 @@ <h1>WebCompat Bug Scorer</h1>
<tr><th>Severity Score: <td><output id="severity-score"></output>
<tr><th>Priority Score: <td><output id="priority-score"></output>
<tr><th>Overall Score: <td><output id="score"></output>
</table>
<hr>
<table>
<tr><th>Suggested Priority: <td><output id="priority"></output>
<tr><th>Suggested Severity: <td><output id="severity"></output>
</ul>
</table>
<dl>
<dt>User story: <dd><pre><output id="user-story"></output></pre><button onclick=copyElemText("user-story")>Copy</button>
</dl>
</div>

<script src="scorebug.js"></script>
135 changes: 127 additions & 8 deletions docs/scorebug/scorebug.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
const ALL_PLATFORMS = getCategoryValues("platform", "input");

const ALL_IMPACT = getCategoryValues("impact", "option");

const ALL_AFFECTS = getCategoryValues("affects", "option");

function getCategoryValues(prefix, elemType) {
console.log(`#${prefix} ${elemType}`, document.querySelectorAll(`#${prefix} ${elemType}`));
return Array.from(document.querySelectorAll(`#${prefix} ${elemType}`)).map(elem => {
const [gotPrefix, ...rest] = elem.id.split("-");
if (gotPrefix != prefix) {
console.warn("Unexpected element", elem);
return null;
}
return rest.join("-");
}).filter(x => x);
}

function getSeverity(data, siteRank) {
const impactScore = parseInt(data.impact);
const impactScore = parseInt(data.impact.value);

const affectsModifier = parseFloat(data.affects);
const affectsModifier = parseFloat(data.affects.value);

const platformModifier = Array.from(Object.values(data.platforms)).reduce((prev, current) => parseFloat(current) + prev, 0);
const platformModifier = Array.from(Object.values(data.platforms)).reduce((prev, current) => parseFloat(current.value) + prev, 0);

const severityScore = Math.round(impactScore * affectsModifier * platformModifier);
let severity = "S4";
Expand Down Expand Up @@ -61,21 +78,39 @@ function getPriority(severity, siteRank) {
return {priority, priorityScore};
}

function getSelectedId(selectElem) {
const optionId = selectElem.selectedOptions[0].id;
const [prefix, ...value] = optionId.split("-");
return value.join("-");
}

function readData() {
const platforms = {};
["windows", "mac", "linux", "mobile"].forEach(platform => {
ALL_PLATFORMS.forEach(platform => {
const element = document.getElementById(`platform-${platform}`);
platforms[platform] = element.checked ? element.value : "0";
platforms[platform] = {name: platform,
value: element.checked ? element.value : "0",
included: element.checked};
});
return {
bugId: document.getElementById("bug-id").value,
url: document.getElementById("url").value,
platforms,
impact: document.getElementById("impact").value,
affects: document.getElementById("affects").value,
impact: {name: getSelectedId(document.getElementById("impact")),
value: document.getElementById("impact").value},
affects: {name: getSelectedId(document.getElementById("affects")),
value: document.getElementById("affects").value},
};
}

function getUserStory(data) {
console.log(data, Array.from(Object.values(data.platforms)).filter(x => x.included));
return `platform:${Array.from(Object.values(data.platforms)).filter(x => x.included).map(x => x.name).join(",")}
impact:${data.impact.name}
affects:${data.affects.name}
`;
}

function resetOutput() {
document.getElementById("output").hidden = true;
}
Expand All @@ -88,20 +123,104 @@ function setOutput(outputData) {
document.getElementById("severity").value = outputData.severity;
document.getElementById("priority").value = outputData.priority;
document.getElementById("score").value = outputData.score;
document.getElementById("user-story").value = outputData.userStory;
document.getElementById("output").hidden = false;
}

function copyElemText(elemId) {
const elem = document.getElementById(elemId);
navigator.clipboard.writeText(elem.textContent);
}

async function score() {
resetOutput();
const data = readData();
const rank = await rankUrl(data.url);
const severity = getSeverity(data, rank.rank);
const priority = getPriority(severity, rank.rank);
const userStory = getUserStory(data);
const outputData = {
...rank,
...severity,
...priority
...priority,
userStory
};
outputData.score = outputData.severityScore * outputData.priorityScore;
setOutput(outputData);
}

function parseUserStory(userStory) {
const lines = userStory.split(/\r?\n|\r|\n/g);
const rv = {};
for (const line of lines) {
const [prefix, ...rest] = line.split(":");
const data = rest.join(":").trim();
if (prefix === "platform") {
const foundPlatforms = [];
const [...dataPlatforms] = data.split(",");
for (let platform of dataPlatforms) {
platform = platform.trim();
if (ALL_PLATFORMS.includes(platform)) {
foundPlatforms.push(platform);
}
}
if (foundPlatforms.length) {
rv.platforms = foundPlatforms;
}
} else if (prefix === "impact") {
if (ALL_IMPACT.includes(data)) {
rv.impact = data;
}
} else if (prefix === "affects") {
if (ALL_AFFECTS.includes(data)) {
rv.affects = data;
}
}
}
return rv;
}

function setFieldsFromBug(data) {
document.getElementById("url").value = data.url;
let platforms;
if (data.platforms) {
ALL_PLATFORMS.forEach(platform => {
const element = document.getElementById(`platform-${platform}`);
element.checked = data.platforms.includes(platform);
});
}
if (data.impact) {
document.getElementById(`impact-${data.impact}`).selected = true;
}
if (data.affects) {
document.getElementById(`affects-${data.affects}`).selected = true;
}
}

async function updateFromBug() {
let bugNumber = parseInt(document.getElementById("bug-id").value);

const resp = await fetch(`https://bugzilla.mozilla.org/rest/bug/${bugNumber}`);
const bugsData = await resp.json();
const bugData = bugsData.bugs[0];

if (bugData.product != "Web Compatibility") {
console.log(`Bug {bugNumber} is not a Web Compatibility product bug`);
return;
}

const data = {url: bugData.url};
if (bugData.cf_user_story) {
Object.assign(data, parseUserStory(bugData.cf_user_story));
}
data.url = bugData.url;
if (!data.platforms) {
let platforms;
if (bugData.component == "Desktop") {
platforms = ["windows", "mac", "linux"];
} else if (bugData.component == "Mobile") {
platforms = ["android"];
}
}
setFieldsFromBug(data);
}

0 comments on commit 801a676

Please sign in to comment.