-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3344 from MasterHW/oso
Add OpenSourceObserver stats to explorer
- Loading branch information
Showing
8 changed files
with
302 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
import { useState } from "react"; | ||
import useSWR from "swr"; | ||
import { Hex } from "viem"; | ||
import { gql, GraphQLClient } from "graphql-request"; | ||
|
||
const osoApiKey = process.env.REACT_APP_OSO_API_KEY as string; | ||
const osoUrl = "https://opensource-observer.hasura.app/v1/graphql"; | ||
const graphQLClient = new GraphQLClient(osoUrl, { | ||
headers: { | ||
authorization: `Bearer ${osoApiKey}`, | ||
}, | ||
}); | ||
let hasFetched = false; | ||
|
||
interface IOSOId { | ||
artifacts_by_project: { | ||
project_id: Hex; | ||
}; | ||
} | ||
|
||
export interface IOSOStats { | ||
code_metrics_by_project: { | ||
contributors: number; | ||
first_commit_date: number; | ||
}; | ||
events_monthly_to_project: [ | ||
{ | ||
bucket_month: number; | ||
amount: number; | ||
}, | ||
{ | ||
bucket_month: number; | ||
amount: number; | ||
}, | ||
{ | ||
bucket_month: number; | ||
amount: number; | ||
}, | ||
{ | ||
bucket_month: number; | ||
amount: number; | ||
}, | ||
{ | ||
bucket_month: number; | ||
amount: number; | ||
}, | ||
{ | ||
bucket_month: number; | ||
amount: number; | ||
}, | ||
]; | ||
} | ||
|
||
export function useOSO(projectGithub?: string) { | ||
const emptyReturn: IOSOStats = { | ||
code_metrics_by_project: { | ||
contributors: 0, | ||
first_commit_date: 0, | ||
}, | ||
events_monthly_to_project: [ | ||
{ | ||
bucket_month: 0, | ||
amount: 0, | ||
}, | ||
{ | ||
bucket_month: 0, | ||
amount: 0, | ||
}, | ||
{ | ||
bucket_month: 0, | ||
amount: 0, | ||
}, | ||
{ | ||
bucket_month: 0, | ||
amount: 0, | ||
}, | ||
{ | ||
bucket_month: 0, | ||
amount: 0, | ||
}, | ||
{ | ||
bucket_month: 0, | ||
amount: 0, | ||
}, | ||
], | ||
}; | ||
const [stats, setStats] = useState<IOSOStats | null>(null); | ||
|
||
const getStatsFor = async (projectRegistryGithub: string) => { | ||
if (osoApiKey === "") | ||
throw new Error("OpenSourceObserver API key not set."); | ||
const queryId = gql`{ | ||
artifacts_by_project(where: {artifact_name: {_ilike: "%${projectRegistryGithub}/%"}} | ||
distinct_on: project_id | ||
) { | ||
project_id | ||
} | ||
}`; | ||
|
||
try { | ||
hasFetched = true; | ||
const idData: IOSOId = await graphQLClient.request<IOSOId>(queryId); | ||
|
||
if (!Array.isArray(idData.artifacts_by_project)) { | ||
setStats(emptyReturn); | ||
return; | ||
} | ||
|
||
const parsedId: IOSOId = { | ||
artifacts_by_project: idData.artifacts_by_project[0], | ||
}; | ||
|
||
const queryStats = gql`{ | ||
code_metrics_by_project(where: {project_id: {_eq: "${parsedId.artifacts_by_project.project_id}"}}) { | ||
contributors | ||
first_commit_date | ||
} | ||
events_monthly_to_project( | ||
where: {project_id: {_eq: "${parsedId.artifacts_by_project.project_id}"}, event_type: {_eq: "COMMIT_CODE"}} | ||
limit: 6 | ||
order_by: {bucket_month: desc} | ||
) { | ||
bucket_month | ||
amount | ||
} | ||
}`; | ||
|
||
const items: IOSOStats = | ||
await graphQLClient.request<IOSOStats>(queryStats); | ||
|
||
if (!Array.isArray(items.code_metrics_by_project)) { | ||
setStats(emptyReturn); | ||
return; | ||
} | ||
|
||
if (items.events_monthly_to_project.length === 6) { | ||
const parsedItems: IOSOStats = { | ||
code_metrics_by_project: items.code_metrics_by_project[0], | ||
events_monthly_to_project: items.events_monthly_to_project, | ||
}; | ||
setStats(parsedItems); | ||
} else { | ||
const parsedItems: IOSOStats = { | ||
code_metrics_by_project: items.code_metrics_by_project[0], | ||
events_monthly_to_project: emptyReturn.events_monthly_to_project, | ||
}; | ||
setStats(parsedItems); | ||
} | ||
} catch (e) { | ||
console.error(`No stats found for project: ${projectGithub}`); | ||
console.error(e); | ||
setStats(emptyReturn); | ||
} | ||
}; | ||
|
||
const { isLoading } = useSWR(osoUrl, { | ||
fetcher: async () => projectGithub && getStatsFor(projectGithub), | ||
revalidateOnMount: true, | ||
}); | ||
|
||
if (stats === null && !hasFetched) | ||
projectGithub && getStatsFor(projectGithub); | ||
return { | ||
/** | ||
* Fetch OSO for stats on a project | ||
* @param projectRegistryGithub projectGithub | ||
*/ | ||
getStatsFor, | ||
/** | ||
* Stats for a project (loaded from OSO) | ||
*/ | ||
stats, | ||
isStatsLoading: isLoading, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
packages/grant-explorer/src/features/round/OSO/ImpactStats.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import React from "react"; | ||
import { IOSOStats } from "../../api/oso"; | ||
import { Flex, Link, Text } from "@chakra-ui/react"; | ||
import { Stat } from "../ViewProjectDetails"; | ||
import { formatTimeAgo } from "../../common/utils/utils"; | ||
|
||
|
||
export const StatList = ({ stats }: { stats: IOSOStats | null }) => { | ||
if (stats === null) return; | ||
return ( | ||
stats.code_metrics_by_project.contributors > 0 ? ( | ||
<React.Fragment> | ||
<h4 className="text-3xl mt-5 ml-4" >Impact stats</h4> | ||
<Flex gap={2} flexDir={{base: 'column', md: 'row'}} py={6} px={3} > | ||
<div | ||
className={ | ||
"rounded-2xl bg-gray-50 flex-auto p-3 md:p-6 gap-4 flex flex-col" | ||
} | ||
> | ||
<div> <Stat | ||
isLoading={false} | ||
value={`${formatTimeAgo(stats.code_metrics_by_project.first_commit_date)}`} | ||
> | ||
Project age | ||
</Stat> | ||
</div> | ||
</div> | ||
<div | ||
className={ | ||
"rounded-2xl bg-gray-50 flex-auto p-3 md:p-6 gap-4 flex flex-col" | ||
} | ||
> | ||
<Stat | ||
isLoading={false} | ||
value={`${stats.code_metrics_by_project.contributors}`} | ||
> | ||
Unique code contributors | ||
</Stat> | ||
</div> | ||
<div | ||
className={ | ||
"rounded-2xl bg-gray-50 flex-auto p-3 md:p-6 gap-4 flex flex-col" | ||
} | ||
> | ||
<Stat | ||
isLoading={false} | ||
value={`${projectVelocity(stats)}`} | ||
> | ||
Velocity | ||
</Stat> | ||
</div> | ||
</Flex> | ||
<Text fontFamily="DM Mono" textAlign="center" mt={0} className={"text-xs"}> | ||
Data provided by {" "} | ||
<Link href={"https://www.opensource.observer/"} target="_blank"> | ||
<Text as="span" className="text-gitcoin-violet-500"> | ||
opensource.observer | ||
</Text> | ||
</Link> | ||
</Text> | ||
</React.Fragment> | ||
) : ( | ||
<div> | ||
</div> | ||
) | ||
); | ||
}; | ||
|
||
function projectVelocity(stats : IOSOStats) { | ||
const recentCommits = stats.events_monthly_to_project[0].amount + stats.events_monthly_to_project[1].amount + stats.events_monthly_to_project[2].amount; | ||
const olderCommits = stats.events_monthly_to_project[3].amount + stats.events_monthly_to_project[4].amount + stats.events_monthly_to_project[5].amount; | ||
|
||
if (recentCommits === 0 && olderCommits === 0) return 'unknown'; | ||
if (recentCommits >= (1.5 * olderCommits)) return 'increasing'; | ||
if (recentCommits <= 0.5 * olderCommits) return 'decreasing'; | ||
return 'steady'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.