diff --git a/website/src/components/MetricChartLine/MetricChartLine.tsx b/website/src/components/MetricChartLine/MetricChartLine.tsx new file mode 100644 index 0000000..2f9ba8a --- /dev/null +++ b/website/src/components/MetricChartLine/MetricChartLine.tsx @@ -0,0 +1,101 @@ +import React from "react"; +import { Stats } from "../Repo/Repo"; +import { LineChart } from "@mui/x-charts"; + +const getLineXChart = (data: string[]) => { + return data.map(d => new Date(d)) +} + +const yearFormatter = (date: Date) => `${date.getMonth()+1}-${date.getDate()}-${date.getFullYear()}`; + + + +export const MetricChartLine = (props: {data: {[key: string]: Stats}}) => { + const [forks, setForks] = React.useState(false); + const [issues, setIssues] = React.useState(false); + const [stars, setStars] = React.useState(true); + const [size, setSize] = React.useState(false); + const [all, setAll] = React.useState(false); + + const setEverything = () => { + setAll(!all) + setForks(!all) + setIssues(!all) + setStars(!all) + setSize(!all) + } + + const getSeriesLine = (data: {[key: string]: Stats}) => { + Object.values(data).map(v => v.forks) + const series = [] + forks && series.push( + { + label: 'Forks', + data: Object.values(data).map(v => v.forks), + showMark: false, + } + ) + stars && series.push( + { + label: 'Stars', + data: Object.values(data).map(v => v.stars), + showMark: false, + } + ) + issues && series.push( + { + label: 'Issues', + data: Object.values(data).map(v => v.issues), + showMark: false, + } + ) + size && series.push( + { + label: 'Size', + data: Object.values(data).map(v => v.size/1024), + showMark: false, + } + ) + return { + series: series + }; + } + + return ( + <> +
+
+ setStars(!stars)}/> + +
+
+ setForks(!forks)}/> + +
+
+ setIssues(!issues)}/> + +
+
+ setSize(!size)}/> + +
+
+ setEverything()}/> + +
+
+
+ ({ + ...series + }))} + width={800} + height={300} + /> +
+ + ) + +} \ No newline at end of file diff --git a/website/src/components/Repo/Repo.tsx b/website/src/components/Repo/Repo.tsx index 4616ef3..a0c519e 100644 --- a/website/src/components/Repo/Repo.tsx +++ b/website/src/components/Repo/Repo.tsx @@ -19,18 +19,41 @@ export interface Repository { language: {[key: string]: number} } -const getLastDate = (stats: string[]) => { +const getLastDate = (stats: string[]): [Date, Date] => { let arrayDates = stats.map((da) => new Date(da) ); - return arrayDates.reduce((a,b) => a > b ? a : b) + const latest = arrayDates.reduce((a,b) => a > b ? a : b) + let nearest = Infinity + let winner = -1 + let latestMonth = new Date(latest.getTime()); + if (latestMonth.getMonth() === 0) { + // It's January + latestMonth.setFullYear(latestMonth.getFullYear() - 1 ) + latestMonth.setMonth(11) + }else { + latestMonth.setMonth(latestMonth.getMonth() - 1) + } + const latestTime = latestMonth.getTime() + arrayDates.forEach((date, index) => { + let distance = Math.abs(date.getTime() - latestTime) + if (distance < nearest) { + nearest = distance + winner = index + } + }) + const closest = arrayDates[winner] + return [latest,closest] } + const formatDate = (d: Date) => { return `${d.getFullYear()}-${('0' + (d.getMonth()+1)).slice(-2)}-${('0' + d.getDate()).slice(-2)}` } export const Repo = (props: {repo: Repository}) => { - const date = getLastDate(Object.keys(props.repo.metrics)); - const met = props.repo.metrics[formatDate(date)] + const [latest, closest] = getLastDate(Object.keys(props.repo.metrics)); + const met = props.repo.metrics[formatDate(latest)]; + const formatClosest = formatDate(closest); + const metLastMonth = props.repo.metrics[formatClosest]; return ( @@ -70,17 +93,17 @@ export const Repo = (props: {repo: Repository}) => { Stats - - - - + + + +
- Last update: {date.toLocaleDateString()} + Last update: {latest.toLocaleDateString()}
diff --git a/website/src/components/Stat/Stat.tsx b/website/src/components/Stat/Stat.tsx index 4a7f1bd..f9e695c 100644 --- a/website/src/components/Stat/Stat.tsx +++ b/website/src/components/Stat/Stat.tsx @@ -1,6 +1,5 @@ import React from "react"; -import { Card, Col, Row } from "react-bootstrap"; - +import { Badge, Card, Col, OverlayTrigger, Row, Tooltip } from "react-bootstrap"; export const convertBytes = (bytes: number, options: { useBinaryUnits?: boolean; decimals?: number } = {}): string => { const { useBinaryUnits = false, decimals = 2} = options; @@ -18,7 +17,11 @@ export const convertBytes = (bytes: number, options: { useBinaryUnits?: boolean; return `${(bytes / Math.pow(base, i)).toFixed(decimals)} ${units[i]}`; } -export const Stat = (props: {name: string, value: number}) => { +const iconDown = "fas fa-arrow-down" +const iconUp = "fas fa-arrow-up" +const equals = "fas fa-equals" + +export const Stat = (props: {name: string, value: number, previous: number, previousDate: string}) => { var icon = switch(props.name) { @@ -39,19 +42,51 @@ export const Stat = (props: {name: string, value: number}) => { break; } + const getContentBadge = () => { + const value = props.value - props.previous; + let icon = iconUp + icon = value < 0 ? iconDown : value === 0 ? equals : iconUp + if (props.name === "issues") { + icon += value > 0 ? " text-danger" : value < 0 ? " text-success" : " text" + } else { + icon += value > 0 ? " text-success" : value < 0 ? " text-danger" : " text" + } + + return ( + <> + {props.name === "size" ? convertBytes(value*1024): value} + + ) + } + return ( - +
{icon}
- +

{props.name}

- {props.name === "size" ? convertBytes(props.value*1024): props.value} + + + Metric from {props.previousDate} + + } + > + + + {getContentBadge()} + + + {props.name === "size" ? convertBytes(props.value*1024): props.value} +
diff --git a/website/src/views/Metrics.tsx b/website/src/views/Metrics.tsx index 634b901..57e23f4 100644 --- a/website/src/views/Metrics.tsx +++ b/website/src/views/Metrics.tsx @@ -1,10 +1,11 @@ import React from "react"; import { Accordion, Badge, Card, Col, Container, Row, Stack } from "react-bootstrap"; import { convertBytes } from "../components/Stat/Stat"; -import { Repo, Repository, Stats } from "../components/Repo/Repo"; +import { Repo, Repository } from "../components/Repo/Repo"; import metrics from "../data/metrics.json"; -import { LineChart, PieChart } from "@mui/x-charts"; +import { PieChart } from "@mui/x-charts"; import { Box, Slider } from "@mui/material"; +import { MetricChartLine } from "../components/MetricChartLine/MetricChartLine"; export interface MetricsT { repositories: {[key: string] : Repository}; @@ -14,40 +15,7 @@ const getPieDataChart = (data: {[key:string]: number}) => { return Object.keys(data).map((key, index) => { return {"id": 0, "value": data[key], "label": key}}) } -const getLineXChart = (data: string[]) => { - return data.map(d => new Date(d)) -} - -const getSeriesLine = (data: {[key: string]: Stats}) => { - Object.values(data).map(v => v.forks) - - return { - series: [ - { - label: 'Forks', - data: Object.values(data).map(v => v.forks), - showMark: false, - }, - { - label: 'Stars', - data: Object.values(data).map(v => v.stars), - showMark: false, - }, - { - label: 'Issues', - data: Object.values(data).map(v => v.issues), - showMark: false, - }, - { - label: 'Size', - data: Object.values(data).map(v => v.size/1024), - showMark: false, - }, - ] - }; -} -const yearFormatter = (date: Date) => `${date.getMonth()+1}-${date.getDate()}-${date.getFullYear()}`; const Metrics = () => { const [pieLangSlice, setPieLangSlice] = React.useState(5); @@ -78,19 +46,9 @@ const Metrics = () => { Community grow -

Forks / Starts / Issues / Size (KB)

-
- ({ - ...series - }))} - width={800} - height={300} - /> -
+