Tucker McKnight <tmcknight@instructure.com> | Sun Aug 09 2026
Make language bar graphs work on commits page This is definitely not a great implementation, but I want to get something merged in here. A few things can use improvement: 1. Any diff larger than 100 lines will just take up the entire width -- there is no scaling taking place. (I've left a TODO about this. 2. It just shows the total size of lines added and lines removed, not a different color for added vs. removed like in the original mockup. 3. The code is very messy.
0 1 2 3 4
import m from 'mithril'
import {NavHelper} from './helpers/nav.ts'
import htmlPage from './common/htmlPage.ts'
export default async (
reposConfig: any,0 1 2 3 4 5
import m from 'mithril'
import {NavHelper} from './helpers/nav.ts'
import htmlPage from './common/htmlPage.ts'
import { colorAndPercentMap } from '../src/languageGraph.ts'
export default async (
reposConfig: any,18 19 20 21 22
currentRefType: data.patchPage.type,
})
const pageContent = [
m('div', {class: "row mt-3 mb-1"},
m('div', {class: "col"},18 19 20 21 22 23 24
currentRefType: data.patchPage.type,
})
const colors = await colorAndPercentMap(reposConfig, data.currentRef, data.currentRepo.files)
const pageContent = [
m('div', {class: "row mt-3 mb-1"},
m('div', {class: "col"},109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
])
]),
m('div', {class: "col-12 col-md-4 d-flex"}, [
m('div', { class: "d-flex flex-column" }, topLanguagePercentages.map((topLangPercent) => {
return m('div', {
class: 'font-monospace small',
style: 'height: 1rem;'
}, topLangPercent.extension)
}).concat(otherLanguageDiffs[0] > 0 || otherLanguageDiffs[1] > 0
? m('div', {
class: 'font-monospace small',
style: 'height: 1rem;'
}, `other ${otherLanguageDiffs[0]} ${otherLanguageDiffs[1]}`)
: null,
)),
m('div', {109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
])
]),
m('div', {class: "col-12 col-md-4 d-flex"}, [
m('div', { class: "d-flex flex-column col-md-3 me-1 mb-2" }, topLanguagePercentages.map((topLangPercent) => {
return m('div', {
class: 'font-monospace small d-flex justify-content-end align-items-center flex-grow-1',
style: 'max-height: 1rem; margin: 1px 0;'
}, topLangPercent.extension)
}).concat(otherLanguageDiffs[0] > 0 || otherLanguageDiffs[1] > 0
? m('div', {
class: 'font-monospace small d-flex justify-content-end align-items-center flex-grow-1',
style: 'max-height: 1rem; margin: 1px 0;'
}, 'other')
: null,
)),
m('div', {127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
const langDiffs = languageCounts.get(topLangPercent.extension)
// TODO: make the average commit size adjustable
const adjustedLength = Math.min(langDiffs[0] + langDiffs[1], 100)
return m('div', {
style: `height: 1rem; width: ${adjustedLength}%; background: black;`
})
}))
]),
]),
]),
m('div', {class: 'col-12 col-md-auto'}, [
m('div', {class: "input-group mb-2 flex-nowrap"}, [
m('span', {class: "font-monospace input-group-text border-info text-white text-bg-dark overflow-scroll"}, commit.hash.slice(0, 6)),
m('button', {'data-copy-text': commit.hash, class: "btn btn-sm btn-info shadow-none copy-button"}, 'Copy')
])
]),127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
const langDiffs = languageCounts.get(topLangPercent.extension)
// TODO: make the average commit size adjustable
const adjustedLength = Math.min(langDiffs[0] + langDiffs[1], 100)
const languageInfo = colors[topLangPercent.extension] || colors['other']
return m('div', {
class: 'language-col',
style: `height: 1rem; width: ${adjustedLength}%; background: ${languageInfo.color};`
})
}).concat(otherLanguageDiffs[0] > 0 || otherLanguageDiffs[1] > 0
? m('div', {
class: 'language-col',
style: `height: 1rem; width: ${Math.min(otherLanguageDiffs[0] + otherLanguageDiffs[1], 100)}%; background: #666;`
})
: null
))
]),
]),
]),
m('div', {class: 'col-12 col-md-auto'}, [
m('div', {class: "input-group mb-2 flex-nowrap"}, [
m('span', {class: "font-monospace input-group-text border-info overflow-scroll"}, commit.hash.slice(0, 6)),
m('button', {'data-copy-text': commit.hash, class: "btn btn-sm btn-info shadow-none copy-button"}, 'Copy')
])
]),123 124 125 126 127
border-bottom: 6px solid color.adjust($body-bg-dark, $lightness: -3%);
border-right: 6px solid color.adjust($body-bg-dark, $lightness: -5%);
}
}
.btn-bg, .btn-bg:hover {123 124 125 126 127 128 129 130 131 132
border-bottom: 6px solid color.adjust($body-bg-dark, $lightness: -3%);
border-right: 6px solid color.adjust($body-bg-dark, $lightness: -5%);
}
.commit {
border-color: #666;
}
}
.btn-bg, .btn-bg:hover {65 66 67 68 69 70 71
if (!obj.added && !obj.removed) {
beforeText = beforeText + escape(obj.value)
afterText = afterText + escape(obj.value)
added += obj.value.split('\n').length
removed += obj.value.split('\n').length
}
if (obj.added) {
afterText = afterText + "<mark>" + escape(obj.value) + "</mark>"65 66 67 68 69 70 71
if (!obj.added && !obj.removed) {
beforeText = beforeText + escape(obj.value)
afterText = afterText + escape(obj.value)
added += obj.value.split('\n').filter(l => l != '').length
removed += obj.value.split('\n').filter(l => l != '').length
}
if (obj.added) {
afterText = afterText + "<mark>" + escape(obj.value) + "</mark>"