Make language bar graphs work on commits page

7357b85c0af87fecb7b1bbc5f4e64eb18cddaa1d

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.
js_templates/commits.ts:1
Before
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,
After
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,
js_templates/commits.ts:19
Before
18
19
20


21
22
    currentRefType: data.patchPage.type,
  })

⁣
⁣
  const pageContent = [
    m('div', {class: "row mt-3 mb-1"},
      m('div', {class: "col"},
After
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"},
js_templates/commits.ts:110
Before
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', {
After
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', {
js_templates/commits.ts:128
Before
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')
            ])
          ]),
After
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')
            ])
          ]),
scss/design-board.scss:124
Before
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 {
After
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 {
src/helpers.ts:66
Before
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>"
After
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>"