Skip to content

Commit

Permalink
Merge pull request #67 from mansona/stats
Browse files Browse the repository at this point in the history
Add stats to the lttf dashboard
  • Loading branch information
mansona authored Dec 13, 2024
2 parents b2d2f7e + f896cfb commit b449e25
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 16 deletions.
123 changes: 123 additions & 0 deletions app/components/stats.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<details data-test-completed-rules>
<summary>Stats</summary>
<div class="stats-wrapper">
{{#if this.removedToday.size}}
<div class="stat-card">
🎉🌅 Rules removed today

<ul>
{{#each this.removedToday as |rule|}}
<li>
<LinkTo @route="rule" @model={{rule}}>{{rule}}</LinkTo>
</li>
{{/each}}
</ul>
</div>
{{/if}}

{{#if this.removedThisWeek.size}}
<div class="stat-card">
🎉🗓️ Rules removed this week

<ul>
{{#each this.removedThisWeek as |rule|}}
<li>
<LinkTo @route="rule" @model={{rule}}>{{rule}}</LinkTo>
</li>
{{/each}}
</ul>
</div>
{{/if}}

{{#if this.improvedToday}}
<div class="stat-card">
📉🌅 Biggest improvement since yesterday:
<div class="my-2">
<LinkTo
@route="rule"
@model={{this.improvedToday.rule}}
>{{this.improvedToday.rule}}</LinkTo></div>
which has removed
{{absolute this.improvedToday.value}}
files
</div>
{{/if}}

{{#if this.improvedThisWeek}}
<div class="stat-card">
📉🗓️ Biggest improvment this week:

<div class="my-2">
<LinkTo @route="rule" @model={{this.improvedThisWeek.rule}}>
{{this.improvedThisWeek.rule}}</LinkTo>
</div>
which has removed
{{absolute this.improvedThisWeek.value}}
files

</div>
{{/if}}
</div>

<div class="stats-wrapper">
{{#if this.newToday.size}}
<div class="stat-card">
🆕🌅 New rules added since yesterday:

<ul>
{{#each this.newToday as |rule|}}
<li><LinkTo @route="rule" @model={{rule}}>{{rule}}</LinkTo></li>
{{/each}}
</ul>
</div>
{{/if}}

{{#if this.newThisWeek.size}}
<div class="stat-card">
🆕🗓️ New rules added this week:

<ul>
{{#each this.newThisWeek as |rule|}}
<li><LinkTo @route="rule" @model={{rule}}>{{rule}}</LinkTo></li>
{{/each}}
</ul>
</div>
{{/if}}

{{#if this.mostAddedToday}}
<div class="stat-card">
📈🌅 Most new files since yesterday:

<div class="my-2">
<LinkTo
@route="rule"
@model={{this.mostAddedToday.rule}}
>{{this.mostAddedToday.rule}}</LinkTo>
</div>

which added
{{this.mostAddedToday.value}}
files

</div>
{{/if}}

{{#if this.mostAddedThisWeek}}
<div class="stat-card">
📈🗓️ Most new files this week:

<div class="my-2">
<LinkTo
@route="rule"
@model={{this.mostAddedThisWeek.rule}}
>{{this.mostAddedThisWeek.rule}}</LinkTo>
</div>

which added
{{this.mostAddedThisWeek.value}}
files

</div>
{{/if}}
</div>
</details>
114 changes: 114 additions & 0 deletions app/components/stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import Component from '@glimmer/component';

export default class Stats extends Component {
get improvedToday() {
let biggest;

for (let [rule, value] of Object.entries(this.args.data?.today?.changed)) {
if (value > 0) {
continue;
}
// removing trumps improvement
if (this.removedToday.has(rule)) {
continue;
}
// remember smaller numbers are bigger "improvmeents";
if (!biggest || value < biggest.value) {
biggest = { rule, value };
}
}
return biggest;
}

get improvedThisWeek() {
let biggest;

for (let [rule, value] of Object.entries(
this.args.data?.thisWeek?.changed,
)) {
if (
value > 0 ||
rule === this.improvedToday?.rule ||
value >= this.improvedToday?.value
) {
continue;
}

// removing trumps improvement
if (this.removedThisWeek.has(rule)) {
continue;
}

// remember smaller numbers are bigger "improvmeents";
if (!biggest || value < biggest.value) {
biggest = { rule, value };
}
}

return biggest;
}

get mostAddedToday() {
let biggest;

for (let [rule, value] of Object.entries(this.args.data?.today?.changed)) {
if (value < 0) {
continue;
}
// new trumps added
if (this.newToday.has(rule)) {
continue;
}

if (!biggest || value > biggest.value) {
biggest = { rule, value };
}
}
return biggest;
}

get mostAddedThisWeek() {
let biggest;

for (let [rule, value] of Object.entries(
this.args.data?.thisWeek?.changed,
)) {
if (
value < 0 ||
rule === this.mostAddedToday?.rule ||
value <= this.mostAddedToday?.value
) {
continue;
}

// new trumps added
if (this.newToday.has(rule) || this.newThisWeek.has(rule)) {
continue;
}

if (!biggest || value > biggest.value) {
biggest = { rule, value };
}
}

return biggest;
}

get newToday() {
return new Set(this.args.data?.today?.added);
}

get newThisWeek() {
return new Set(this.args.data.thisWeek.added).difference(this.newToday);
}

get removedToday() {
return new Set(this.args.data?.today?.removed);
}

get removedThisWeek() {
return new Set(this.args.data.thisWeek.removed).difference(
this.removedToday,
);
}
}
5 changes: 5 additions & 0 deletions app/helpers/absolute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { helper } from '@ember/component/helper';

export default helper(function absolute(positional /*, named*/) {
return Math.abs(positional);
});
80 changes: 74 additions & 6 deletions app/routes/application.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,98 @@
/* eslint-disable prettier/prettier */
import Route from '@ember/routing/route';
import fetch from 'fetch';
import { Temporal } from 'temporal-polyfill'

import env from 'lint-to-the-future/config/environment';

import timeSeries from 'lint-to-the-future/utils/time-series';

function lengthOrValuOrZero(data) {
if(!data) {
return 0;
}
return data.length ?? data;
}

function compareData(data, today, past) {
const timeSeriesData = timeSeries(data);

let changed = {}
let removed = [];
let added = [];

for(let rule in timeSeriesData) {
let diff = lengthOrValuOrZero(timeSeriesData[rule][today]) - lengthOrValuOrZero(timeSeriesData[rule][past]);

if (diff !== 0 ) {
changed[rule] = diff;
}

if (!timeSeriesData[rule][today] && timeSeriesData[rule][past]) {
removed.push(rule);
}

if (timeSeriesData[rule][today] && !timeSeriesData[rule][past]) {
added.push(rule);
}
}
return {
changed,
removed,
added,
}
}

export default class ApplicationRoute extends Route {
async model() {
let data = await (await fetch(`${env.rootURL}data.json`)).json();

let allDates = Object.keys(data).sort((a, b) => b.localeCompare(a))

let timeSeriesData = timeSeries(data);

let highestDate;
const globalHighestDate = allDates[0];
const stats = {}

const today = Temporal.PlainDate.from(globalHighestDate);

// there is at least another date in the data
if (allDates[1]) {
const yesterday = Temporal.PlainDate.from(allDates[1]);
if (yesterday.until(today).days === 1) {
// there was a yesterday
stats.today = compareData({
[globalHighestDate]: data[globalHighestDate],
[allDates[1]]: data[allDates[1]]
}, globalHighestDate, allDates[1])
}

let lastWeek = yesterday;

for (let i = 2; i < allDates.length; i++) {
const currentDate = Temporal.PlainDate.from(allDates[i]);
if (currentDate.until(today).days > 7) {
break;
}

for (const rule in timeSeriesData) {
for (const date in timeSeriesData[rule]) {
if(!highestDate || highestDate < date) {
highestDate = date;
if (currentDate.until(lastWeek).days > 0) {
lastWeek = Temporal.PlainDate.from(currentDate)
}
}

// if we have a date that is bigger than yesterday but not bigger than 7 days ago
if (lastWeek !== yesterday) {
stats.thisWeek = compareData({
[globalHighestDate]: data[globalHighestDate],
[lastWeek.toString()]: data[lastWeek.toString()]
}, globalHighestDate, lastWeek.toString())
}
}

return {
data: timeSeriesData,
highestDate,
highestDate: globalHighestDate,
stats,
}
}
}
Loading

0 comments on commit b449e25

Please sign in to comment.