Skip to content

Commit

Permalink
more testings
Browse files Browse the repository at this point in the history
  • Loading branch information
Fallen-Breath committed Jan 24, 2025
1 parent 61e5c75 commit 829b13d
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 70 deletions.
74 changes: 63 additions & 11 deletions src/app/[locale]/stats/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { LineChart } from "@/components/charts/line";
import { getEverything } from "@/catalogue/data";
import { LineChart, LineChartValues } from "@/components/charts/line";
import { Counts, NestedCounts, PieChart } from "@/components/charts/pie";
import { CommonContentLayout } from "@/components/layout/common-content-layout";
import { TimeFormatted } from "@/components/time-formatted";
Expand All @@ -23,6 +24,29 @@ async function mapCountryCode(counts: Counts): Promise<Counts> {
return newCounts
}

async function getLatestPluginDownloadCounts(): Promise<NestedCounts> {
const everything = await getEverything()
const counts: NestedCounts = { keyCounts: {}, subkeyCounts: {} }
for (let [pluginId, plugin] of Object.entries(everything.plugins)) {
counts.keyCounts[pluginId] = 0
counts.subkeyCounts[pluginId] = {}
for (let releaseInfo of (plugin.release?.releases || [])) {
let downloadCount = releaseInfo.asset.download_count
counts.keyCounts[pluginId] += downloadCount
counts.subkeyCounts[pluginId][releaseInfo.meta.version] = downloadCount
}
}

const topN = 20
const topNPlugins = Object.entries(counts.keyCounts).sort((a, b) => a[1] - b[1]).reverse().slice(0, topN).map(([pluginId, _]) => pluginId)
const topNCounts: NestedCounts = { keyCounts: {}, subkeyCounts: {} }
for (let pluginId of topNPlugins) {
topNCounts.keyCounts[pluginId] = counts.keyCounts[pluginId]
topNCounts.subkeyCounts[pluginId] = counts.subkeyCounts[pluginId]
}
return topNCounts
}

export default async function Page() {
const locale = await getLocale()
const messages = await getMessages()
Expand All @@ -44,15 +68,33 @@ export default async function Page() {
}
const rsp = (await fetchRsp.json()) as GetDataResponse

const mcdrInstancesTimstamps = rsp.data['mcdr_instance'][0].timestamps
const mcdrInstancesValues: {[label: string]: number[]} = {}
mcdrInstancesValues[t('line.total')] = rsp.data['mcdr_instance'][0].values
rsp.data['mcdr_version'].forEach(dataList => {
if (dataList.subkey) {
const points = new Map(dataList.timestamps.map((ts, index) => [ts, dataList.values[index]]))
mcdrInstancesValues[dataList.subkey] = mcdrInstancesTimstamps.map(ts => (points.get(ts) || 0))
const mainTimestamps = rsp.data['mcdr_instance'][0].timestamps

function extraLineChartSubkeyValues(key: string, keyType: 'key' | 'subkey', withTotal: boolean): LineChartValues {
const values: LineChartValues = {}
const sumValues = mainTimestamps.map(() => 0)
if (withTotal) {
values[t('line.total')] = sumValues
}
})
rsp.data[key].forEach(dataList => {
const valueKey = keyType === 'key' ? dataList.key : dataList.subkey
if (valueKey) {
values[valueKey] ??= mainTimestamps.map(() => 0)
const points = new Map(dataList.timestamps.map((ts, index) => [ts, dataList.values[index]]))
mainTimestamps.forEach((ts, index) => {
const y = points.get(ts) || 0
values[valueKey][index] += y
sumValues[index] += y
})
}
})
if (!withTotal) {
Object.keys(values).forEach(valueKey => {
values[valueKey] = values[valueKey].map((value, index) => value / sumValues[index])
})
}
return values
}

function extractCount(kind: string): NestedCounts {
let counts: NestedCounts = {
Expand Down Expand Up @@ -90,8 +132,13 @@ export default async function Page() {
)
}

const mcdrInstancesValues = extraLineChartSubkeyValues('mcdr_version', 'subkey', true)
const pythonVersionValues = extraLineChartSubkeyValues('python_version', 'key', false)
const systemVersionValues = extraLineChartSubkeyValues('system_version', 'key', false)

const countryCounts = extractCount('country')
countryCounts.keyCounts = await mapCountryCode(countryCounts.keyCounts)
const pluginDownloadCounts = await getLatestPluginDownloadCounts()

return (
<CommonContentLayout>
Expand All @@ -102,14 +149,19 @@ export default async function Page() {
<p>Hour count: {(rsp.end - rsp.start) / 3600 + 1}</p>
</div>
<div className="flex flex-col gap-10">
<LineChart title={t('kind.mcdr_instance')} timestamps={mcdrInstancesTimstamps} values={mcdrInstancesValues}/>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-10 flex-wrap lg:mx-20">
<LineChart title={t('kind.mcdr_instance')} timestamps={mainTimestamps} values={mcdrInstancesValues}/>
{/*<div className="grid grid-cols-1 lg:grid-cols-2 gap-5">*/}
{/* <LineChart title={t('kind.python_version')} timestamps={mainTimestamps} values={pythonVersionValues} showLegend={false}/>*/}
{/* <LineChart title={t('kind.system_version')} timestamps={mainTimestamps} values={systemVersionValues} showLegend={false}/>*/}
{/*</div>*/}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-5 flex-wrap lg:mx-20">
<PieChart title={t('kind.mcdr_version')} counts={extractCount('mcdr_version')}/>
<PieChart title={t('kind.python_version')} counts={extractCount('python_version')}/>
<PieChart title={t('kind.system_version')} counts={extractCount('system_version')}/>
<PieChart title={t('kind.system_arch')} counts={extractCount('system_arch')}/>
<PieChart title={t('kind.deployment_method')} counts={extractCount('deployment_method')}/>
<PieChart title={t('kind.country')} counts={countryCounts}/>
{/*<PieChart title={"plugin download"} counts={pluginDownloadCounts}/>*/}
</div>
</div>
</NextIntlClientProvider>
Expand Down
125 changes: 66 additions & 59 deletions src/components/charts/line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ Chart.register(PointElement)

Chart.register(LineController)

export interface LineChartValues {
[label: string]: number[]
}

interface LineChartProps {
className?: string
title: string

timestamps: number[]
values: {[label: string]: number[]}
values: LineChartValues

showLegend?: boolean
}

export function LineChart(props: LineChartProps) {
Expand All @@ -45,67 +51,68 @@ export function LineChart(props: LineChartProps) {
}

return (
<ReactChart
className={clsx(props.className)}
type="line"
plugins={[]}
options={{
responsive: true,
interaction: {
intersect: false,
axis: 'x',
mode: 'nearest',
},
scales: {
x: {
type: 'time',
time: {
unit: 'day',
displayFormats: {
'day': 'L',
<div className={clsx(props.className, 'max-h-[100vh] max-w-[100vw]')}>
<ReactChart
type="line"
plugins={[]}
options={{
responsive: true,
interaction: {
intersect: false,
axis: 'x',
mode: 'nearest',
},
scales: {
x: {
type: 'time',
time: {
unit: 'day',
displayFormats: {
'day': 'L',
},
tooltipFormat: 'LLLL',
},
tooltipFormat: 'LLLL',
ticks: {
autoSkip: true,
maxTicksLimit: 10,
}
},
ticks: {
autoSkip: true,
maxTicksLimit: 10,
}
}
},
plugins: {
tooltip: {
enabled: true,
},
title: {
display: true,
text: props.title,
font: {
size: 16,
plugins: {
tooltip: {
enabled: true,
},
},
legend: {
display: true,
position: 'right',
},
decimation: {
enabled: true,
},
}
}}
data={{
labels: props.timestamps.map(item => item * 1000),
datasets: Object.entries(values).map(([label, counts], idx) => {
return {
label: label,
data: counts,
tension: 0.5,
cubicInterpolationMode: 'monotone',
pointStyle: false,
backgroundColor: chroma(colorPalette[idx]).darken(0.3).hex(),
borderColor: chroma(colorPalette[idx]).brighten(0.1).hex(),
} as ChartDataset
}),
}}
/>
title: {
display: true,
text: props.title,
font: {
size: 16,
},
},
legend: {
display: props.showLegend ?? true,
position: 'right',
},
decimation: {
enabled: true,
},
}
}}
data={{
labels: props.timestamps.map(item => item * 1000),
datasets: Object.entries(values).map(([label, counts], idx) => {
return {
label: label,
data: counts,
tension: 0.5,
cubicInterpolationMode: 'monotone',
pointStyle: false,
backgroundColor: chroma(colorPalette[idx]).darken(0.3).hex(),
borderColor: chroma(colorPalette[idx]).brighten(0.1).hex(),
} as ChartDataset
}),
}}
/>
</div>
)
}

0 comments on commit 829b13d

Please sign in to comment.