diff --git a/apps/openpage-api/app/community/total-forks/route.ts b/apps/openpage-api/app/community/total-forks/route.ts index 330ddc587..2c78d087c 100644 --- a/apps/openpage-api/app/community/total-forks/route.ts +++ b/apps/openpage-api/app/community/total-forks/route.ts @@ -12,6 +12,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/community/total-issues/route.ts b/apps/openpage-api/app/community/total-issues/route.ts index 386e766cb..eaa633cb2 100644 --- a/apps/openpage-api/app/community/total-issues/route.ts +++ b/apps/openpage-api/app/community/total-issues/route.ts @@ -12,6 +12,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/community/total-prs/route.ts b/apps/openpage-api/app/community/total-prs/route.ts index 4bffd1702..b0174e082 100644 --- a/apps/openpage-api/app/community/total-prs/route.ts +++ b/apps/openpage-api/app/community/total-prs/route.ts @@ -12,6 +12,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/community/total-stars/route.ts b/apps/openpage-api/app/community/total-stars/route.ts index 60e8b431e..ac76b6e12 100644 --- a/apps/openpage-api/app/community/total-stars/route.ts +++ b/apps/openpage-api/app/community/total-stars/route.ts @@ -12,6 +12,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/github/forks/route.ts b/apps/openpage-api/app/github/forks/route.ts index f512dd57d..331a0f644 100644 --- a/apps/openpage-api/app/github/forks/route.ts +++ b/apps/openpage-api/app/github/forks/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/github/issues/route.ts b/apps/openpage-api/app/github/issues/route.ts index eccc1bd32..5047e3135 100644 --- a/apps/openpage-api/app/github/issues/route.ts +++ b/apps/openpage-api/app/github/issues/route.ts @@ -12,6 +12,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/github/prs/route.ts b/apps/openpage-api/app/github/prs/route.ts index 7516e6986..83a31cd2f 100644 --- a/apps/openpage-api/app/github/prs/route.ts +++ b/apps/openpage-api/app/github/prs/route.ts @@ -12,6 +12,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/github/stars/route.ts b/apps/openpage-api/app/github/stars/route.ts index 79c03f0cd..860533282 100644 --- a/apps/openpage-api/app/github/stars/route.ts +++ b/apps/openpage-api/app/github/stars/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/growth/completed-documents/route.ts b/apps/openpage-api/app/growth/completed-documents/route.ts index 0887d39ec..85ad83d08 100644 --- a/apps/openpage-api/app/growth/completed-documents/route.ts +++ b/apps/openpage-api/app/growth/completed-documents/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/growth/new-users/route.ts b/apps/openpage-api/app/growth/new-users/route.ts index 460adf9da..359fa6556 100644 --- a/apps/openpage-api/app/growth/new-users/route.ts +++ b/apps/openpage-api/app/growth/new-users/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/growth/signer-conversion/route.ts b/apps/openpage-api/app/growth/signer-conversion/route.ts index 8be97ded5..3ed45c192 100644 --- a/apps/openpage-api/app/growth/signer-conversion/route.ts +++ b/apps/openpage-api/app/growth/signer-conversion/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/growth/total-completed-documents/route.ts b/apps/openpage-api/app/growth/total-completed-documents/route.ts index 29bd0c9ce..d23967563 100644 --- a/apps/openpage-api/app/growth/total-completed-documents/route.ts +++ b/apps/openpage-api/app/growth/total-completed-documents/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/growth/total-customers/route.ts b/apps/openpage-api/app/growth/total-customers/route.ts index c403ac311..ab1658859 100644 --- a/apps/openpage-api/app/growth/total-customers/route.ts +++ b/apps/openpage-api/app/growth/total-customers/route.ts @@ -16,6 +16,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/growth/total-signer-conversion/route.ts b/apps/openpage-api/app/growth/total-signer-conversion/route.ts index d620ee4e6..a10014161 100644 --- a/apps/openpage-api/app/growth/total-signer-conversion/route.ts +++ b/apps/openpage-api/app/growth/total-signer-conversion/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/app/growth/total-users/route.ts b/apps/openpage-api/app/growth/total-users/route.ts index bd34055ef..ba4e8ee37 100644 --- a/apps/openpage-api/app/growth/total-users/route.ts +++ b/apps/openpage-api/app/growth/total-users/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request) { status: 200, headers: { 'content-type': 'application/json', + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200', }, }), ); diff --git a/apps/openpage-api/lib/add-zero-month.ts b/apps/openpage-api/lib/add-zero-month.ts index eb5914599..91e0d89c7 100644 --- a/apps/openpage-api/lib/add-zero-month.ts +++ b/apps/openpage-api/lib/add-zero-month.ts @@ -1,15 +1,20 @@ import { DateTime } from 'luxon'; -export interface TransformedData { +export type TransformedData = { labels: string[]; datasets: Array<{ label: string; data: number[]; }>; -} +}; -export function addZeroMonth(transformedData: TransformedData): TransformedData { - const result = { +const FORMAT = 'MMM yyyy'; + +export const addZeroMonth = ( + transformedData: TransformedData, + isCumulative = false, +): TransformedData => { + const result: TransformedData = { labels: [...transformedData.labels], datasets: transformedData.datasets.map((dataset) => ({ label: dataset.label, @@ -21,34 +26,28 @@ export function addZeroMonth(transformedData: TransformedData): TransformedData return result; } - if (result.datasets.every((dataset) => dataset.data[0] === 0)) { - return result; - } - - try { - let firstMonth = DateTime.fromFormat(result.labels[0], 'MMM yyyy'); + if (!result.datasets.every((dataset) => dataset.data[0] === 0)) { + const firstMonth = DateTime.fromFormat(result.labels[0], FORMAT); if (!firstMonth.isValid) { - const formats = ['MMM yyyy', 'MMMM yyyy', 'MM/yyyy', 'yyyy-MM']; - - for (const format of formats) { - firstMonth = DateTime.fromFormat(result.labels[0], format); - if (firstMonth.isValid) break; - } - - if (!firstMonth.isValid) { - console.warn(`Could not parse date: "${result.labels[0]}"`); - return transformedData; - } + console.warn(`Could not parse date: "${result.labels[0]}"`); + return transformedData; } - const zeroMonth = firstMonth.minus({ months: 1 }).toFormat('MMM yyyy'); - result.labels.unshift(zeroMonth); + result.labels.unshift(firstMonth.minus({ months: 1 }).toFormat(FORMAT)); result.datasets.forEach((dataset) => { dataset.data.unshift(0); }); - - return result; - } catch (error) { - return transformedData; } -} + + const now = DateTime.now().startOf('month'); + const lastMonth = DateTime.fromFormat(result.labels[result.labels.length - 1], FORMAT); + + if (lastMonth.isValid && lastMonth.startOf('month') < now) { + result.labels.push(now.toFormat(FORMAT)); + result.datasets.forEach((dataset) => { + dataset.data.push(isCumulative ? dataset.data[dataset.data.length - 1] : 0); + }); + } + + return result; +}; diff --git a/apps/openpage-api/lib/growth/get-monthly-completed-document.ts b/apps/openpage-api/lib/growth/get-monthly-completed-document.ts index 808d7259d..b704c04eb 100644 --- a/apps/openpage-api/lib/growth/get-monthly-completed-document.ts +++ b/apps/openpage-api/lib/growth/get-monthly-completed-document.ts @@ -21,8 +21,7 @@ export const getCompletedDocumentsMonthly = async (type: 'count' | 'cumulative' .where(() => sql`"Envelope"."status" = ${DocumentStatus.COMPLETED}::"DocumentStatus"`) .where(() => sql`"Envelope"."type" = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`) .groupBy('month') - .orderBy('month', 'desc') - .limit(12); + .orderBy('month', 'desc'); const result = await qb.execute(); @@ -38,7 +37,7 @@ export const getCompletedDocumentsMonthly = async (type: 'count' | 'cumulative' ], }; - return addZeroMonth(transformedData); + return addZeroMonth(transformedData, type === 'cumulative'); }; export type GetCompletedDocumentsMonthlyResult = Awaited< diff --git a/apps/openpage-api/lib/growth/get-signer-conversion.ts b/apps/openpage-api/lib/growth/get-signer-conversion.ts index c70600179..8d25e3a14 100644 --- a/apps/openpage-api/lib/growth/get-signer-conversion.ts +++ b/apps/openpage-api/lib/growth/get-signer-conversion.ts @@ -36,7 +36,7 @@ export const getSignerConversionMonthly = async (type: 'count' | 'cumulative' = ], }; - return addZeroMonth(transformedData); + return addZeroMonth(transformedData, type === 'cumulative'); }; export type GetSignerConversionMonthlyResult = Awaited< diff --git a/apps/openpage-api/lib/growth/get-user-monthly-growth.ts b/apps/openpage-api/lib/growth/get-user-monthly-growth.ts index 9eba7311f..ae428813c 100644 --- a/apps/openpage-api/lib/growth/get-user-monthly-growth.ts +++ b/apps/openpage-api/lib/growth/get-user-monthly-growth.ts @@ -17,8 +17,7 @@ export const getUserMonthlyGrowth = async (type: 'count' | 'cumulative' = 'count .as('cume_count'), ]) .groupBy('month') - .orderBy('month', 'desc') - .limit(12); + .orderBy('month', 'desc'); const result = await qb.execute(); @@ -34,7 +33,7 @@ export const getUserMonthlyGrowth = async (type: 'count' | 'cumulative' = 'count ], }; - return addZeroMonth(transformedData); + return addZeroMonth(transformedData, type === 'cumulative'); }; export type GetUserMonthlyGrowthResult = Awaited>; diff --git a/apps/openpage-api/lib/transform-data.ts b/apps/openpage-api/lib/transform-data.ts index 079ed4f6e..801dd4281 100644 --- a/apps/openpage-api/lib/transform-data.ts +++ b/apps/openpage-api/lib/transform-data.ts @@ -1,6 +1,6 @@ import { DateTime } from 'luxon'; -import { addZeroMonth } from './add-zero-month'; +import { type TransformedData, addZeroMonth } from './add-zero-month'; type MetricKeys = { stars: number; @@ -14,14 +14,6 @@ type DataEntry = { [key: string]: MetricKeys; }; -type TransformData = { - labels: string[]; - datasets: { - label: string; - data: number[]; - }[]; -}; - type MetricKey = keyof MetricKeys; const FRIENDLY_METRIC_NAMES: { [key in MetricKey]: string } = { @@ -38,7 +30,7 @@ export function transformData({ }: { data: DataEntry; metric: MetricKey; -}): TransformData { +}): TransformedData { try { if (!data || Object.keys(data).length === 0) { return { @@ -103,7 +95,7 @@ export function transformData({ ], }; - return addZeroMonth(transformedData); + return addZeroMonth(transformedData, true); } catch (error) { return { labels: [], @@ -111,6 +103,3 @@ export function transformData({ }; } } - -// To be on the safer side -export const transformRepoStats = transformData;