From 796571c3245a02ab5dbab3ade72f3d64087a646c Mon Sep 17 00:00:00 2001 From: 0xKurt Date: Fri, 8 Nov 2024 09:51:28 +0100 Subject: [PATCH] add whitelist --- packages/common/src/index.ts | 1 + packages/common/src/programWhitelist.ts | 20 +++++++ packages/data-layer/src/data-layer.ts | 13 +++- .../grant-explorer/src/features/api/rounds.ts | 14 ++++- .../features/discovery/ExploreRoundsPage.tsx | 15 ++++- .../src/features/discovery/LandingPage.tsx | 6 +- .../discovery/hooks/useFilterRounds.ts | 5 +- .../src/features/program/TabGroup.tsx | 60 ++++++++++++------- 8 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 packages/common/src/programWhitelist.ts diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 8f53630454..80b6b4df6c 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -488,3 +488,4 @@ export function isLitUnavailable(chainId: number) { } export * from "./chains"; +export * from "./programWhitelist"; \ No newline at end of file diff --git a/packages/common/src/programWhitelist.ts b/packages/common/src/programWhitelist.ts new file mode 100644 index 0000000000..d1b441aec6 --- /dev/null +++ b/packages/common/src/programWhitelist.ts @@ -0,0 +1,20 @@ +export async function getWhitelistedPrograms(): Promise { + try { + const response = await fetch( + "https://docs.google.com/spreadsheets/d/e/2PACX-1vQxC34V_N3ubt3ycs7LvMya_zYeBmAqTxPczt0yDbLSfpI-kMp6o5E08fC0BxQG4uMp7EPV5bxP-64a/pub?gid=0&single=true&output=csv" + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const csvText = await response.text(); + + const stringArray = csvText + .split(/\r?\n/) + .filter((line) => line.trim() !== ""); + + return stringArray; + } catch (error) { + return []; + } +} diff --git a/packages/data-layer/src/data-layer.ts b/packages/data-layer/src/data-layer.ts index 9755c4a0fd..88c244036b 100644 --- a/packages/data-layer/src/data-layer.ts +++ b/packages/data-layer/src/data-layer.ts @@ -942,18 +942,25 @@ export class DataLayer { first, orderBy, filter, + whitelistedPrograms, }: { chainIds: number[]; first: number; orderBy?: OrderByRounds; orderDirection?: "asc" | "desc"; filter?: RoundsQueryVariables["filter"]; + whitelistedPrograms?: string[]; }): Promise<{ rounds: RoundGetRound[] }> { return await request(this.gsIndexerEndpoint, getRoundsQuery, { orderBy: orderBy ?? "NATURAL", chainIds, first, - filter, + filter: whitelistedPrograms + ? { + ...filter, + projectId: { in: whitelistedPrograms }, + } + : filter, }); } @@ -1011,8 +1018,8 @@ export class DataLayer { async getAttestationCount({ attestationChainIds, }: { - attestationChainIds: number[] + attestationChainIds: number[]; }): Promise { - return this.attestationService.getAttestationCount({attestationChainIds}); + return this.attestationService.getAttestationCount({ attestationChainIds }); } } diff --git a/packages/grant-explorer/src/features/api/rounds.ts b/packages/grant-explorer/src/features/api/rounds.ts index e18014a473..413cc6f0b0 100644 --- a/packages/grant-explorer/src/features/api/rounds.ts +++ b/packages/grant-explorer/src/features/api/rounds.ts @@ -1,10 +1,12 @@ +import { getWhitelistedPrograms } from "common"; import useSWR, { SWRResponse } from "swr"; import { createISOTimestamp } from "../discovery/utils/createRoundsStatusFilter"; import { RoundGetRound, RoundsQueryVariables, useDataLayer } from "data-layer"; export const useRounds = ( variables: RoundsQueryVariables, - chainIds: number[] + chainIds: number[], + onlywWhitelistedPrograms = false ): SWRResponse => { const dataLayer = useDataLayer(); @@ -13,12 +15,17 @@ export const useRounds = ( // same, cache will be used instead of new requests) ["rounds", chainIds, variables], async () => { + const whitelistedPrograms = onlywWhitelistedPrograms + ? await getWhitelistedPrograms() + : undefined; + const [spamRounds, { rounds }] = await Promise.all([ fetchSpamRounds(), dataLayer.getRounds({ ...variables, first: 500, chainIds, + whitelistedPrograms, }), ]); @@ -64,8 +71,9 @@ const OVERRIDE_PRIVATE_ROUND_IDS = [ export const filterOutPrivateRounds = (rounds: RoundGetRound[]) => { return rounds.filter( (round) => - (round.roundMetadata && round.roundMetadata.roundType) && - round.roundMetadata.roundType !== "private" || + (round.roundMetadata && + round.roundMetadata.roundType && + round.roundMetadata.roundType !== "private") || OVERRIDE_PRIVATE_ROUND_IDS.includes(round.id.toLowerCase()) ); }; diff --git a/packages/grant-explorer/src/features/discovery/ExploreRoundsPage.tsx b/packages/grant-explorer/src/features/discovery/ExploreRoundsPage.tsx index 6da621e50d..a94bc07ad6 100644 --- a/packages/grant-explorer/src/features/discovery/ExploreRoundsPage.tsx +++ b/packages/grant-explorer/src/features/discovery/ExploreRoundsPage.tsx @@ -11,15 +11,24 @@ import { getExplorerPageTitle } from "./utils/getExplorerPageTitle"; import { RoundsGrid } from "./RoundsGrid"; import { getEnabledChains } from "../../app/chainConfig"; import { useMemo } from "react"; +import { getWhitelistedPrograms } from "common"; const ExploreRoundsPage = () => { const [params] = useSearchParams(); const filter = getRoundSelectionParamsFromUrlParams(params); - // Pass the filter from the search params and build the graphql query - const rounds = useFilterRounds(filter, getEnabledChains()); + const rounds = useFilterRounds(filter, getEnabledChains(), true); - const publicRounds = useMemo(() => rounds.data?.filter(round => (round.roundMetadata && round.roundMetadata.roundType) && round.roundMetadata.roundType?.toLowerCase() !== "private"), [rounds]); + const publicRounds = useMemo( + () => + rounds.data?.filter( + (round) => + round.roundMetadata && + round.roundMetadata.roundType && + round.roundMetadata.roundType?.toLowerCase() !== "private" + ), + [rounds] + ); rounds.data = publicRounds; const sectionTitle = getExplorerPageTitle(filter); diff --git a/packages/grant-explorer/src/features/discovery/LandingPage.tsx b/packages/grant-explorer/src/features/discovery/LandingPage.tsx index a280cc07aa..b484dc9f78 100644 --- a/packages/grant-explorer/src/features/discovery/LandingPage.tsx +++ b/packages/grant-explorer/src/features/discovery/LandingPage.tsx @@ -22,11 +22,13 @@ import { CollectionsGrid } from "../collections/CollectionsGrid"; const LandingPage = () => { const activeRounds = useFilterRounds( ACTIVE_ROUNDS_FILTER, - getEnabledChains() + getEnabledChains(), + true ); const roundsEndingSoon = useFilterRounds( ROUNDS_ENDING_SOON_FILTER, - getEnabledChains() + getEnabledChains(), + true ); const filteredActiveRounds = useMemo(() => { diff --git a/packages/grant-explorer/src/features/discovery/hooks/useFilterRounds.ts b/packages/grant-explorer/src/features/discovery/hooks/useFilterRounds.ts index 689b1ac0b8..ddafc8df10 100644 --- a/packages/grant-explorer/src/features/discovery/hooks/useFilterRounds.ts +++ b/packages/grant-explorer/src/features/discovery/hooks/useFilterRounds.ts @@ -74,7 +74,8 @@ export const ROUNDS_ENDING_SOON_FILTER: RoundSelectionParams & { export const useFilterRounds = ( where: RoundSelectionParams, - chains: TChain[] + chains: TChain[], + onlywWhitelistedPrograms?: boolean ): SWRResponse => { const chainIds = where.network === undefined || where.network.trim() === "" @@ -102,7 +103,7 @@ export const useFilterRounds = ( const orderBy = where.orderBy === undefined ? "CREATED_AT_BLOCK_DESC" : where.orderBy; const vars = { orderBy, filter }; - return useRounds(vars, chainIds); + return useRounds(vars, chainIds, onlywWhitelistedPrograms); }; const createRoundWhereFilter = ( diff --git a/packages/round-manager/src/features/program/TabGroup.tsx b/packages/round-manager/src/features/program/TabGroup.tsx index e113ea9643..e0eae76e96 100644 --- a/packages/round-manager/src/features/program/TabGroup.tsx +++ b/packages/round-manager/src/features/program/TabGroup.tsx @@ -312,31 +312,49 @@ export const TabGroup = () => { aria-current={tab.name === currentTab ? "page" : undefined} > {tab.name} - {["Quadratic funding", "Direct grants"].includes(tab.name) && + {["Quadratic funding", "Direct grants"].includes( + tab.name + ) && ( - {tab.name === "Quadratic funding" ? qfRounds.length : dgRounds.length} + {tab.name === "Quadratic funding" + ? qfRounds.length + : dgRounds.length} - } + )} ))}
{programToRender?.tags?.includes(getAlloVersion()) && ( - { - setIsModalOpen(true); - }} - className="flex flex-row justify-between items-center hover:shadow-md p-2 rounded-lg text-sm text-grey-500 font-mono ml-auto bg-yellow-100 cursor-pointer" - data-testid="create-round-small-link" - > - +
+ { + setIsModalOpen(true); + }} + className="flex flex-row justify-between items-center hover:shadow-md p-2 rounded-lg text-sm text-grey-500 font-mono ml-auto bg-yellow-100 cursor-pointer" + data-testid="create-round-small-link" + > + + { + window.open( + `https://docs.google.com/forms/d/e/1FAIpQLSeplytOjF6mbG51bLOccNMmxOUZlZIDQdyOOw3KiDu5VZkvmA/viewform?usp=pp_url&entry.658554959=${programToRender?.id}&entry.1289763714=${programToRender?.metadata?.name}`, + "_blank" + ); + }} + className="flex flex-row justify-between items-center hover:shadow-md p-2 rounded-lg text-sm text-grey-500 font-mono ml-auto bg-blue-100 cursor-pointer" + data-testid="create-round-small-link" + > + Request Explorer Listing + +
)}
@@ -355,8 +373,11 @@ export const TabGroup = () => {
{dgRoundItems}
)} - { currentTab === "Settings" && ( - + {currentTab === "Settings" && ( + )} @@ -364,8 +385,7 @@ export const TabGroup = () => { rounds.length === 0 && programToRender?.tags?.includes(getAlloVersion()) && currentTab !== "Settings" && - noRoundsGroup - } + noRoundsGroup}