Skip to content

Commit a29ed01

Browse files
authored
Satisfy minimum requirements for full typescript project (#37)
* Feature: satisfy minimum for full typescript * Feature: change report structure from array to object * Chore: jsdoc * Refactor: PR review suggestions * Refactor: type out simple reports * Refactor: rename variables * Refactor: more types for now some logic errors * Chore: docs * Fix: type -> interface * Chore: comments * Type refactor * Improve report to discord message * Make it optional * Improve discord message creation * renames * Record to index
1 parent f593337 commit a29ed01

22 files changed

+309
-199
lines changed

src/analytics/charts.js src/analytics/charts.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
import * as ImageCharts from "image-charts";
1+
import ImageCharts from "image-charts";
2+
3+
export interface ChartData {
4+
series: { [column: string]: number[] };
5+
periodEnds: string[];
6+
}
27

38
// Expects data to be:
49
// data = { series: { name: [number] }, periodEnds: [string] }
510
// Returns a string, URL leading to image-charts.com that contains query with exact
611
// instructions how to display this chart via image.
7-
export function buildChartImageUrl(data, title, type = "line") {
8-
const chart = ImageCharts()
12+
export function buildChartImageUrl(
13+
data: ChartData,
14+
title: string,
15+
type = "line",
16+
) {
17+
const chart = new ImageCharts()
918
.cht(type === "line" ? "ls" : "bvs") // Type: lines or vertical bars? Could also be other things.
1019
.chtt(title) // Title.
1120
.chd(

src/analytics/cli.ts

+32-23
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,70 @@
11
import logger from "../utils/logger";
22
import { getAnalyticsErrorMessage } from "./errors";
33
import * as reports from "./reports";
4+
import {
5+
AllTimePeriodReport,
6+
ChartReport,
7+
TextReport,
8+
} from "./reports/reports";
49

510
async function cliReport() {
611
const events = await reports.fetchEventsForReportGenerator();
712

8-
printTitle("TOTAL REPORT");
9-
showReportInCLI(await reports.generateTotalReport(events));
13+
printReportTitle("TOTAL REPORT");
14+
printReportInCLI(await reports.generateTotalReport(events));
1015

11-
printTitle("DAILY REPORT");
12-
showReportInCLI(await reports.generateDailyReport(events));
16+
printReportTitle("DAILY REPORT");
17+
printReportInCLI(await reports.generateDailyReport(events));
1318

14-
printTitle("WEEKLY REPORT");
15-
showReportInCLI(await reports.generateWeeklyReport(events));
19+
printReportTitle("WEEKLY REPORT");
20+
printReportInCLI(await reports.generateWeeklyReport(events));
1621

17-
printTitle("MONTHLY REPORT");
18-
showReportInCLI(await reports.generateMonthlyReport(events));
22+
printReportTitle("MONTHLY REPORT");
23+
printReportInCLI(await reports.generateMonthlyReport(events));
1924

20-
printTitle("ALL TIME MONTHLY REPORT (CSVs)");
21-
await allTimeMonthlyActiveUsersAndProjectsCsvCliReport(events);
25+
printReportTitle("ALL TIME MONTHLY REPORT (CSVs)");
26+
printAllTimeMonthlyReportCsvInCLI(
27+
await reports.generateAllTimeMonthlyReport(events),
28+
);
2229
}
2330

2431
// Outputs CSV of total metrics since the start of tracking them,
2532
// while skipping cohort analytis because that would be too complex.
2633
// Useful for manually producing charts that show total progress of Wasp.
27-
async function allTimeMonthlyActiveUsersAndProjectsCsvCliReport(events) {
28-
const report = await reports.generateAllTimeMonthlyReport(events);
34+
function printAllTimeMonthlyReportCsvInCLI(
35+
allTimePeriodReort: AllTimePeriodReport,
36+
) {
37+
const { userActivityReport, projectsReport } = allTimePeriodReort;
2938

3039
console.log("\n[CSV] Num active users");
31-
const activeUsersReport = report[0];
32-
for (const row of activeUsersReport.csv) {
40+
for (const row of userActivityReport.csv) {
3341
console.log(row.join(","));
3442
}
3543

3644
console.log("\n[CSV] Num projects");
37-
console.log(",created diff,created cumm,built diff,built cumm");
38-
const projectsReport = report[1];
45+
console.log("created diff,created cumm,built diff,built cumm");
3946
for (const row of projectsReport.csv) {
4047
console.log(row.join(","));
4148
}
4249
}
4350

44-
function showReportInCLI(report) {
45-
for (const metric of report) {
51+
function printReportInCLI(
52+
compositeReport: Record<string, Partial<TextReport & ChartReport>>,
53+
) {
54+
for (const simpleReport of Object.values(compositeReport)) {
4655
console.log();
47-
if (metric.text) {
48-
for (const textLine of metric.text) {
56+
if (simpleReport.text) {
57+
for (const textLine of simpleReport.text) {
4958
console.log(textLine);
5059
}
5160
}
52-
if (metric.chart) {
53-
console.log("- Chart: ", metric.chart.toURL());
61+
if (simpleReport.chart) {
62+
console.log("- Chart: ", simpleReport.chart.toURL());
5463
}
5564
}
5665
}
5766

58-
function printTitle(text) {
67+
function printReportTitle(text) {
5968
console.log(`\x1b[33m \n\n${text} \x1b[0m`);
6069
}
6170

src/analytics/eventContext.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { type PosthogEvent } from "./events";
22

33
/**
4-
* @param event
54
* @returns Context values, all lowercase strings.
65
*/
76
export function getEventContextValues(event: PosthogEvent): string[] {

src/analytics/executionEnvs.js src/analytics/executionEnvs.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as _ from "lodash";
1+
import _ from "lodash";
22

33
import { getEventContextValues } from "./eventContext";
44

@@ -41,7 +41,7 @@ export function groupEventsByExecutionEnv(events) {
4141

4242
function getExecutionEnvFromEventContext(event) {
4343
const contextValues = getEventContextValues(event);
44-
for (let [key, actor] of Object.entries(executionEnvs)) {
44+
for (const [key, actor] of Object.entries(executionEnvs)) {
4545
if (contextValues.includes(actor.contextKey)) {
4646
return key;
4747
}

src/analytics/moment.js src/analytics/moment.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as moment from "moment";
1+
import moment from "moment";
22

33
// Here we set moment to use ISO-8601, Europe locale.
44
moment.updateLocale("en", {

src/analytics/reports/events.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import * as _ from "lodash";
1+
import retry from "async-retry";
2+
import _ from "lodash";
23

3-
import moment from "../moment";
4-
import { type PosthogEvent, fetchAllCliEvents } from "../events";
54
import { addEventContextValue } from "../eventContext";
5+
import { type PosthogEvent, fetchAllCliEvents } from "../events";
66
import { executionEnvs } from "../executionEnvs";
7-
import * as retry from "async-retry";
7+
import moment from "../moment";
88

99
// These filters, when applyed to a list of events, remove
1010
// events that we don't want to go into analysis
@@ -120,7 +120,7 @@ export async function fetchEventsForReportGenerator() {
120120
retries: 10,
121121
minTimeout: 5 * 1000,
122122
maxTimeout: 60 * 1000,
123-
onRetry: (e) => {
123+
onRetry: (e: Error) => {
124124
console.error(
125125
"Error happened while fetching events for report generator, trying again:",
126126
e.message ?? e,

src/analytics/reports/index.ts

+16-18
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,36 @@
11
import moment from "../moment";
2+
import {
3+
generateAllTimePeriodReport,
4+
generatePeriodReport,
5+
} from "./periodReport";
6+
import { AllTimePeriodReport, PeriodReport } from "./reports";
27
export { fetchEventsForReportGenerator } from "./events";
38
export { generateTotalReport } from "./totalReport";
4-
import { generatePeriodReport } from "./periodReport";
59

6-
export async function generateDailyReport(
10+
export function generateDailyReport(
711
prefetchedEvents = undefined,
812
numPeriods = undefined,
9-
) {
10-
return generatePeriodReport(numPeriods ?? 14, "day", prefetchedEvents, false);
13+
): Promise<PeriodReport> {
14+
return generatePeriodReport(numPeriods ?? 14, "day", prefetchedEvents);
1115
}
1216

13-
export async function generateWeeklyReport(
17+
export function generateWeeklyReport(
1418
prefetchedEvents = undefined,
1519
numPeriods = undefined,
16-
) {
20+
): Promise<PeriodReport> {
1721
return generatePeriodReport(numPeriods ?? 12, "week", prefetchedEvents);
1822
}
1923

20-
export async function generateMonthlyReport(
24+
export function generateMonthlyReport(
2125
prefetchedEvents = undefined,
2226
numPeriods = undefined,
23-
genCohortRetentionReport = true,
24-
) {
25-
return generatePeriodReport(
26-
numPeriods ?? 12,
27-
"month",
28-
prefetchedEvents,
29-
genCohortRetentionReport,
30-
);
27+
): Promise<PeriodReport> {
28+
return generatePeriodReport(numPeriods ?? 12, "month", prefetchedEvents);
3129
}
3230

33-
export async function generateAllTimeMonthlyReport(
31+
export function generateAllTimeMonthlyReport(
3432
prefetchedEvents = undefined,
35-
) {
33+
): Promise<AllTimePeriodReport> {
3634
const numMonths = moment().diff(moment("2021-01-01"), "months") + 1;
37-
return generateMonthlyReport(prefetchedEvents, numMonths, false);
35+
return generateAllTimePeriodReport(numMonths, "month", prefetchedEvents);
3836
}

src/analytics/reports/periodReport/cohortRetentionReport.js src/analytics/reports/periodReport/cohortRetentionReport.ts

+21-23
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
import * as _ from "lodash";
2-
import { newSimpleTable } from "../../table";
1+
import _ from "lodash";
2+
33
import { groupEventsByExecutionEnv } from "../../executionEnvs";
4+
import { newSimpleTable } from "../../table";
45
import { fetchEventsForReportGenerator } from "../events";
5-
6-
import { groupEventsByUser, getIntersection } from "../utils";
7-
6+
import { CohortRetentionReport } from "../reports";
7+
import { getIntersection, groupEventsByUser } from "../utils";
88
import {
99
calcLastNPeriods,
10-
groupEventsByPeriods,
1110
getActiveUserIds,
11+
groupEventsByPeriods,
1212
isEventInPeriod,
1313
} from "./common";
1414

1515
export async function generateCohortRetentionReport(
1616
numPeriods,
1717
periodName,
1818
prefetchedEvents = undefined,
19-
) {
19+
): Promise<CohortRetentionReport> {
2020
const periodNameShort = periodName[0];
2121

2222
// All events, sorted by time (starting with oldest), with events caused by Wasp team members
@@ -88,21 +88,19 @@ export async function generateCohortRetentionReport(
8888
const fmt = (m) => m.format("DD-MM-YY");
8989
const firstPeriod = periods[0];
9090
const lastPeriod = _.last(periods);
91-
const report = [
92-
{
93-
text: [
94-
"==== Cohort Retention ====",
95-
"```",
96-
table.toString(),
97-
"```",
98-
`Period of ${periodNameShort} #0: ${fmt(firstPeriod[0])} - ${fmt(
99-
firstPeriod[1],
100-
)}`,
101-
`Period of ${periodNameShort} #${periods.length - 1}: ${fmt(
102-
lastPeriod[0],
103-
)} - ${fmt(lastPeriod[1])}`,
104-
],
105-
},
106-
];
91+
const report = {
92+
text: [
93+
"==== Cohort Retention ====",
94+
"```",
95+
table.toString(),
96+
"```",
97+
`Period of ${periodNameShort} #0: ${fmt(firstPeriod[0])} - ${fmt(
98+
firstPeriod[1],
99+
)}`,
100+
`Period of ${periodNameShort} #${periods.length - 1}: ${fmt(
101+
lastPeriod[0],
102+
)} - ${fmt(lastPeriod[1])}`,
103+
],
104+
};
107105
return report;
108106
}

src/analytics/reports/periodReport/common.js src/analytics/reports/periodReport/common.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as _ from "lodash";
1+
import _ from "lodash";
22

33
import moment from "../../moment";
44

@@ -49,7 +49,7 @@ export function calcLastNPeriods(numPeriods, periodName) {
4949
// If there are N periods, it will return a list with N sublists, where each sublist
5050
// contains events for a corresponding period.
5151
export function groupEventsByPeriods(events, periods) {
52-
let eventsByPeriods = [];
52+
const eventsByPeriods = [];
5353
let currentPeriodIdx = 0;
5454
let currentPeriodEvents = [];
5555
for (const event of events) {

src/analytics/reports/periodReport/index.js

-30
This file was deleted.

0 commit comments

Comments
 (0)