From ac4c9d7e1e5beed822276f3351b3c3f9e2f9b6f2 Mon Sep 17 00:00:00 2001 From: Raymond Cheng Date: Wed, 22 May 2024 12:39:32 -0700 Subject: [PATCH] fix: frontend queries to use new schema (#1338) fix: frontend queries to use new schema on the API v1 * Removes use of slug => source/namespace/name * Update GraphQL queries to follow new names * Update the page routing to use enums directly --- .github/workflows/ci-default.yml | 2 + .../[type] => [source]}/[...name]/page.tsx | 52 +++-- .../project/{[...slug] => [...name]}/page.tsx | 22 ++- .../dataprovider/event-data-provider.tsx | 24 ++- apps/frontend/lib/graphql/cached-queries.ts | 30 +-- apps/frontend/lib/graphql/queries.ts | 178 ++++++++++-------- apps/frontend/lib/paths.ts | 26 +-- 7 files changed, 177 insertions(+), 157 deletions(-) rename apps/frontend/app/artifact/{[namespace]/[type] => [source]}/[...name]/page.tsx (70%) rename apps/frontend/app/project/{[...slug] => [...name]}/page.tsx (88%) diff --git a/.github/workflows/ci-default.yml b/.github/workflows/ci-default.yml index bd4969025..52d8cb855 100644 --- a/.github/workflows/ci-default.yml +++ b/.github/workflows/ci-default.yml @@ -22,6 +22,8 @@ env: DOCS_ALGOLIA_API_KEY: "test" DOCS_ALGOLIA_INDEX: "test" DOCS_SEGMENT_WRITE_KEY: "test" + # Hasura variables + DBT_TARGET: "production" # Google variables GOOGLE_PROJECT_ID: "opensource-observer" GOOGLE_TEST_DUMMY_CREDENTIALS_JSON: ${{ vars.GOOGLE_TEST_DUMMY_CREDENTIALS_JSON }} diff --git a/apps/frontend/app/artifact/[namespace]/[type]/[...name]/page.tsx b/apps/frontend/app/artifact/[source]/[...name]/page.tsx similarity index 70% rename from apps/frontend/app/artifact/[namespace]/[type]/[...name]/page.tsx rename to apps/frontend/app/artifact/[source]/[...name]/page.tsx index 35228d91e..4e2d613da 100644 --- a/apps/frontend/app/artifact/[namespace]/[type]/[...name]/page.tsx +++ b/apps/frontend/app/artifact/[source]/[...name]/page.tsx @@ -1,33 +1,29 @@ import { notFound } from "next/navigation"; import { cache } from "react"; import { PlasmicComponent } from "@plasmicapp/loader-nextjs"; -import { PLASMIC } from "../../../../../plasmic-init"; -import { PlasmicClientRootProvider } from "../../../../../plasmic-init-client"; -import { cachedGetArtifactByName } from "../../../../../lib/graphql/cached-queries"; -import { logger } from "../../../../../lib/logger"; -import { - catchallPathToString, - pathToNamespaceEnum, - pathToTypeEnum, -} from "../../../../../lib/paths"; +import { PLASMIC } from "../../../../plasmic-init"; +import { PlasmicClientRootProvider } from "../../../../plasmic-init-client"; +import { cachedGetArtifactByName } from "../../../../lib/graphql/cached-queries"; +import { logger } from "../../../../lib/logger"; const PLASMIC_COMPONENT = "ArtifactPage"; //export const dynamic = STATIC_EXPORT ? "force-static" : "force-dynamic"; export const dynamic = "force-static"; export const dynamicParams = true; export const revalidate = false; // 3600 = 1 hour +/** // TODO: This cannot be empty due to this bug // https://github.com/vercel/next.js/issues/61213 -const STATIC_EXPORT_PARAMS = [ +const STATIC_EXPORT_PARAMS: ArtifactPagePath[] = [ { - namespace: "github", - type: "repo", + source: "github", name: ["opensource-observer", "oso"], }, ]; export async function generateStaticParams() { return STATIC_EXPORT_PARAMS; } + */ const cachedFetchComponent = cache(async (componentName: string) => { try { @@ -44,40 +40,42 @@ const cachedFetchComponent = cache(async (componentName: string) => { * on the first HTTP request, which should be faster than fetching it client-side */ +type ArtifactPagePath = { + source: string; + name: string[]; +}; + type ArtifactPageProps = { - params: { - namespace: string; - type: string; - name: string[]; - }; + params: ArtifactPagePath; }; export default async function ArtifactPage(props: ArtifactPageProps) { const { params } = props; - const namespace = pathToNamespaceEnum(params.namespace); - const type = pathToTypeEnum(params.type); - const name = catchallPathToString(params.name); + if ( - !params.namespace || - !params.type || + !params.source || !params.name || !Array.isArray(params.name) || - params.name.length < 1 || - !namespace || - !type + params.name.length < 1 ) { logger.warn("Invalid artifact page path", params); notFound(); } + const source = params.source.toUpperCase(); + const [namespace, name] = + params.name.length > 1 ? params.name : [undefined, params.name[0]]; + // Get artifact metadata from the database const { artifacts: artifactArray } = await cachedGetArtifactByName({ + artifact_source: source, artifact_namespace: namespace, - artifact_type: type, artifact_name: name, }); if (!Array.isArray(artifactArray) || artifactArray.length < 1) { - logger.warn(`Cannot find artifact (namespace=${namespace}, name=${name})`); + logger.warn( + `Cannot find artifact (source=${source}, namespace=${namespace}, name=${name})`, + ); notFound(); } const artifact = artifactArray[0]; diff --git a/apps/frontend/app/project/[...slug]/page.tsx b/apps/frontend/app/project/[...name]/page.tsx similarity index 88% rename from apps/frontend/app/project/[...slug]/page.tsx rename to apps/frontend/app/project/[...name]/page.tsx index a9a76cde5..50baffe18 100644 --- a/apps/frontend/app/project/[...slug]/page.tsx +++ b/apps/frontend/app/project/[...name]/page.tsx @@ -4,7 +4,7 @@ import { PlasmicComponent } from "@plasmicapp/loader-nextjs"; import { PLASMIC } from "../../../plasmic-init"; import { PlasmicClientRootProvider } from "../../../plasmic-init-client"; import { - cachedGetProjectsBySlugs, + cachedGetProjectByName, cachedGetCodeMetricsByProjectIds, cachedGetOnchainMetricsByProjectIds, cachedGetAllEventTypes, @@ -22,7 +22,7 @@ export const revalidate = false; // 3600 = 1 hour const STATIC_EXPORT_SLUGS: string[] = ["opensource-observer"]; export async function generateStaticParams() { return STATIC_EXPORT_SLUGS.map((s) => ({ - slug: [s], + name: [s], })); } @@ -41,26 +41,28 @@ const cachedFetchComponent = cache(async (componentName: string) => { * on the first HTTP request, which should be faster than fetching it client-side */ +type ProjectPagePath = { + name: string[]; +}; + type ProjectPageProps = { - params: { - slug: string[]; - }; + params: ProjectPagePath; }; export default async function ProjectPage(props: ProjectPageProps) { const { params } = props; - const slugs = [catchallPathToString(params.slug)]; - if (!params.slug || !Array.isArray(params.slug) || params.slug.length < 1) { + if (!params.name || !Array.isArray(params.name) || params.name.length < 1) { logger.warn("Invalid project page path", params); notFound(); } // Get project metadata from the database - const { projects: projectArray } = await cachedGetProjectsBySlugs({ - project_slugs: slugs, + const name = catchallPathToString(params.name); + const { projects: projectArray } = await cachedGetProjectByName({ + project_name: name, }); if (!Array.isArray(projectArray) || projectArray.length < 1) { - logger.warn(`Cannot find project (slugs=${slugs})`); + logger.warn(`Cannot find project (name=${name})`); notFound(); } const project = projectArray[0]; diff --git a/apps/frontend/components/dataprovider/event-data-provider.tsx b/apps/frontend/components/dataprovider/event-data-provider.tsx index f466715b6..27e23d382 100644 --- a/apps/frontend/components/dataprovider/event-data-provider.tsx +++ b/apps/frontend/components/dataprovider/event-data-provider.tsx @@ -13,7 +13,7 @@ import { GET_EVENTS_DAILY_TO_PROJECT, GET_EVENTS_WEEKLY_TO_PROJECT, GET_EVENTS_MONTHLY_TO_PROJECT, - GET_USERS_MONTHLY_TO_PROJECT, + //GET_USERS_MONTHLY_TO_PROJECT, GET_EVENTS_MONTHLY_TO_COLLECTION, GET_EVENTS_WEEKLY_TO_COLLECTION, GET_EVENTS_DAILY_TO_COLLECTION, @@ -380,12 +380,15 @@ function ArtifactEventDataProvider(props: EventDataProviderProps) { ), amount: ensure(x.amount, "Data missing 'number'"), })); - const entityData = artifactData?.artifacts.map((x) => ({ + const entityData = artifactData?.artifacts_v1.map((x) => ({ id: ensure(x.artifact_id, "artifact missing 'artifact_id'"), - name: ensure( - x.artifact_latest_name, - "artifact missing 'artifact_latest_name'", - ), + name: + ensure( + x.artifact_namespace, + "artifact missing 'artifact_namespace'", + ) + + "/" + + ensure(x.artifact_name, "artifact missing 'artifact_name'"), })); const formattedData = formatData(props, normalizedEventData, entityData, { gapFill: bucketWidth === "day", @@ -448,7 +451,7 @@ function ProjectEventDataProvider(props: EventDataProviderProps) { ), amount: ensure(x.amount, "Data missing 'number'"), })); - const entityData = projectData?.projects.map((x) => ({ + const entityData = projectData?.projects_v1.map((x) => ({ id: ensure(x.project_id, "project missing 'project_id'"), name: ensure(x.project_name, "project missing 'project_name'"), })); @@ -513,7 +516,7 @@ function CollectionEventDataProvider(props: EventDataProviderProps) { ), amount: ensure(x.amount, "Data missing 'number'"), })); - const entityData = collectionData?.collections.map((x) => ({ + const entityData = collectionData?.collections_v1.map((x) => ({ id: ensure(x.collection_id, "collection missing 'collection_id'"), name: ensure( x.collection_name, @@ -539,8 +542,9 @@ function CollectionEventDataProvider(props: EventDataProviderProps) { * @param props * @returns */ -function ProjectUserDataProvider(props: EventDataProviderProps) { +function ProjectUserDataProvider(_props: EventDataProviderProps) { useEnsureAuth(); + /** const { data: rawEventData, error: eventError, @@ -585,6 +589,8 @@ function ProjectUserDataProvider(props: EventDataProviderProps) { error={eventError ?? projectError} /> ); + */ + return

Unimplemented

; } export { diff --git a/apps/frontend/lib/graphql/cached-queries.ts b/apps/frontend/lib/graphql/cached-queries.ts index caec4dc6e..13dc8c92c 100644 --- a/apps/frontend/lib/graphql/cached-queries.ts +++ b/apps/frontend/lib/graphql/cached-queries.ts @@ -3,9 +3,10 @@ import { getApolloClient } from "../clients/apollo"; import { QueryOptions } from "@apollo/client"; import { GET_ARTIFACTS_BY_IDS, - GET_ARTIFACT_BY_NAME, + GET_ARTIFACT_BY_SOURCE_NAMESPACE_NAME, + GET_ARTIFACT_BY_SOURCE_NAME, GET_ARTIFACT_IDS_BY_PROJECT_IDS, - GET_PROJECTS_BY_SLUGS, + GET_PROJECT_BY_NAME, GET_COLLECTIONS_BY_IDS, GET_COLLECTION_IDS_BY_PROJECT_IDS, GET_CODE_METRICS_BY_PROJECT, @@ -33,10 +34,10 @@ const cachedGetAllEventTypes = cache(async () => }), ); -const cachedGetProjectsBySlugs = cache( - async (variables: { project_slugs: string[] }) => +const cachedGetProjectByName = cache( + async (variables: { project_name: string }) => queryWrapper({ - query: GET_PROJECTS_BY_SLUGS, + query: GET_PROJECT_BY_NAME, variables, }), ); @@ -51,14 +52,19 @@ const cachedGetArtifactsByIds = cache( const cachedGetArtifactByName = cache( async (variables: { - artifact_namespace: string; - artifact_type: string; + artifact_source: string; + artifact_namespace?: string; artifact_name: string; }) => - queryWrapper({ - query: GET_ARTIFACT_BY_NAME, - variables, - }), + variables.artifact_namespace + ? queryWrapper({ + query: GET_ARTIFACT_BY_SOURCE_NAMESPACE_NAME, + variables, + }) + : queryWrapper({ + query: GET_ARTIFACT_BY_SOURCE_NAME, + variables, + }), ); const cachedGetArtifactIdsByProjectIds = cache( @@ -105,7 +111,7 @@ export { cachedGetArtifactsByIds, cachedGetArtifactByName, cachedGetArtifactIdsByProjectIds, - cachedGetProjectsBySlugs, + cachedGetProjectByName, cachedGetCollectionsByIds, cachedGetCollectionIdsByProjectIds, cachedGetCodeMetricsByProjectIds, diff --git a/apps/frontend/lib/graphql/queries.ts b/apps/frontend/lib/graphql/queries.ts index f310ad39c..bc9e59e06 100644 --- a/apps/frontend/lib/graphql/queries.ts +++ b/apps/frontend/lib/graphql/queries.ts @@ -9,40 +9,47 @@ import { gql } from "../__generated__/gql"; const GET_ALL_ARTIFACTS = gql(` query Artifacts @cached (ttl: 300) { - artifacts { + artifacts_v1 { artifact_id + artifact_source artifact_namespace - artifact_type - artifact_source_id - artifact_latest_name - artifact_names + artifact_name + artifact_url } } `); const GET_ARTIFACTS_BY_IDS = gql(` query ArtifactByIds($artifact_ids: [String!]) @cached(ttl: 300) { - artifacts(where: { artifact_id: { _in: $artifact_ids }}) { + artifacts_v1(where: { artifact_id: { _in: $artifact_ids }}) { + artifact_id + artifact_source + artifact_namespace + artifact_name + artifact_url + } + } +`); + +const GET_ARTIFACT_BY_SOURCE_NAMESPACE_NAME = gql(` + query ArtifactBySourceNamespaceName($artifact_source: String!, $artifact_namespace: String!, $artifact_name: String!) @cached(ttl: 300) { + artifacts_v1(where: { artifact_source: { _eq: $artifact_source }, artifact_namespace: { _eq: $artifact_namespace }, artifact_name: { _eq: $artifact_name } }) { artifact_id + artifact_source artifact_namespace - artifact_type - artifact_source_id - artifact_latest_name - artifact_names + artifact_name artifact_url } } `); -const GET_ARTIFACT_BY_NAME = gql(` - query ArtifactByName($artifact_namespace: String!, $artifact_type: String!, $artifact_name: String!) @cached(ttl: 300) { - artifacts(where: { artifact_namespace: { _eq: $artifact_namespace }, artifact_type: { _eq: $artifact_type }, artifact_latest_name: { _eq: $artifact_name } }) { +const GET_ARTIFACT_BY_SOURCE_NAME = gql(` + query ArtifactBySourceName($artifact_source: String!, $artifact_name: String!) @cached(ttl: 300) { + artifacts_v1(where: { artifact_source: { _eq: $artifact_source }, artifact_name: { _eq: $artifact_name } }) { artifact_id + artifact_source artifact_namespace - artifact_type - artifact_source_id - artifact_latest_name - artifact_names + artifact_name artifact_url } } @@ -50,7 +57,7 @@ const GET_ARTIFACT_BY_NAME = gql(` const GET_ARTIFACT_IDS_BY_PROJECT_IDS = gql(` query ArtifactIdsByProjectIds($project_ids: [String!]) @cached(ttl: 300) { - artifacts_by_project(where: { project_id: { _in: $project_ids }}) { + artifacts_by_project_v1(where: { project_id: { _in: $project_ids }}) { artifact_id } } @@ -62,30 +69,38 @@ const GET_ARTIFACT_IDS_BY_PROJECT_IDS = gql(` const GET_ALL_PROJECTS = gql(` query Projects @cached(ttl: 300) { - projects { + projects_v1 { project_id - project_slug + project_source + project_namespace project_name + display_name } } `); const GET_PROJECTS_BY_IDS = gql(` query ProjectsByIds($project_ids: [String!]) @cached(ttl: 300) { - projects(where: { project_id: { _in: $project_ids }}) { + projects_v1(where: { project_id: { _in: $project_ids }}) { project_id - project_slug + project_source + project_namespace project_name + display_name + description } } `); -const GET_PROJECTS_BY_SLUGS = gql(` - query ProjectsBySlugs($project_slugs: [String!]) @cached(ttl: 300) { - projects(where: { project_slug: { _in: $project_slugs } }) { +const GET_PROJECT_BY_NAME = gql(` + query ProjectByName($project_name: String!) @cached(ttl: 300) { + projects_v1(where: { project_name: { _eq: $project_name } }) { project_id - project_slug + project_source + project_namespace project_name + display_name + description } } `); @@ -96,40 +111,45 @@ const GET_PROJECTS_BY_SLUGS = gql(` const GET_ALL_COLLECTIONS = gql(` query Collections @cached(ttl: 300) { - collections { + collections_v1 { collection_id - user_namespace - collection_slug + collection_source + collection_namespace collection_name + display_name } } `); const GET_COLLECTIONS_BY_IDS = gql(` query CollectionsByIds($collection_ids: [String!]) @cached(ttl: 300) { - collections(where: { collection_id: { _in: $collection_ids }}) { + collections_v1(where: { collection_id: { _in: $collection_ids }}) { collection_id - user_namespace - collection_slug + collection_source + collection_namespace collection_name + display_name + description } } `); -const GET_COLLECTIONS_BY_SLUGS = gql(` - query CollectionsBySlugs($collection_slugs: [String!]) @cached(ttl: 300) { - collections(where: { collection_slug: { _in: $collection_slugs }, user_namespace: { _eq: "oso" } }) { +const GET_COLLECTION_BY_NAME = gql(` + query CollectionByName($collection_name: String!) @cached(ttl: 300) { + collections_v1(where: { collection_name: { _eq: $collection_name } }) { collection_id - user_namespace - collection_slug + collection_source + collection_namespace collection_name + display_name + description } } `); const GET_COLLECTION_IDS_BY_PROJECT_IDS = gql(` query CollectionIdsByProjectIds($project_ids: [String!]) @cached(ttl: 300) { - projects_by_collection(where: { project_id: { _in: $project_ids }}) { + projects_by_collection_v1(where: { project_id: { _in: $project_ids }}) { collection_id } } @@ -143,26 +163,30 @@ const GET_CODE_METRICS_BY_PROJECT = gql(` query CodeMetricsByProject( $project_ids: [String!], ) { - code_metrics_by_project(where: { + code_metrics_by_project_v1(where: { project_id: { _in: $project_ids }, }) { project_id + project_source + project_namespace project_name - stars - repositories - pull_requests_opened_6_months - pull_requests_merged_6_months - new_contributors_6_months - last_commit_date - issues_opened_6_months - issues_closed_6_months - avg_active_devs_6_months - avg_fulltime_devs_6_months - commits_6_months - contributors - contributors_6_months + display_name + event_source + active_developer_count_6_months + closed_issue_count_6_months + commit_count_6_months + contributor_count + contributor_count_6_months first_commit_date - forks + fork_count + fulltime_developer_average_6_months + last_commit_date + merged_pull_request_count_6_months + new_contributor_count_6_months + opened_issue_count_6_months + opened_pull_request_count_6_months + repository_count + star_count } } `); @@ -171,26 +195,29 @@ const GET_ONCHAIN_METRICS_BY_PROJECT = gql(` query OnchainMetricsByProject( $project_ids: [String!], ) { - onchain_metrics_by_project(where: { + onchain_metrics_by_project_v1(where: { project_id: { _in: $project_ids }, }) { project_id + project_source + project_namespace project_name - active_users - first_txn_date - high_frequency_users - l2_gas_6_months - less_active_users - more_active_users - multi_project_users - network - new_user_count - num_contracts - total_l2_gas - total_txns - total_users - txns_6_months - users_6_months + display_name + event_source + active_contract_count_90_days + address_count + address_count_90_days + days_since_first_transaction + gas_fees_sum + gas_fees_sum_6_months + high_activity_address_count_90_days + low_activity_address_count_90_days + medium_activity_address_count_90_days + multi_project_address_count_90_days + new_address_count_90_days + returning_address_count_90_days + transaction_count + transaction_count_6_months } } `); @@ -201,7 +228,7 @@ const GET_ONCHAIN_METRICS_BY_PROJECT = gql(` const GET_ALL_EVENT_TYPES = gql(` query GetAllEventTypes @cached(ttl: 300) { - event_types { + event_types_v1 { event_type } } @@ -327,6 +354,7 @@ const GET_EVENTS_MONTHLY_TO_PROJECT = gql(` } `); +/** const GET_USERS_MONTHLY_TO_PROJECT = gql(` query UsersMonthlyToProject( $project_ids: [String!], @@ -346,6 +374,7 @@ const GET_USERS_MONTHLY_TO_PROJECT = gql(` } } `); +*/ const GET_EVENTS_DAILY_TO_ARTIFACT = gql(` query EventsDailyToArtifact( @@ -410,14 +439,15 @@ const GET_EVENTS_MONTHLY_TO_ARTIFACT = gql(` export { GET_ALL_ARTIFACTS, GET_ARTIFACTS_BY_IDS, - GET_ARTIFACT_BY_NAME, + GET_ARTIFACT_BY_SOURCE_NAMESPACE_NAME, + GET_ARTIFACT_BY_SOURCE_NAME, GET_ARTIFACT_IDS_BY_PROJECT_IDS, GET_ALL_PROJECTS, GET_PROJECTS_BY_IDS, - GET_PROJECTS_BY_SLUGS, + GET_PROJECT_BY_NAME, GET_ALL_COLLECTIONS, GET_COLLECTIONS_BY_IDS, - GET_COLLECTIONS_BY_SLUGS, + GET_COLLECTION_BY_NAME, GET_COLLECTION_IDS_BY_PROJECT_IDS, GET_CODE_METRICS_BY_PROJECT, GET_ONCHAIN_METRICS_BY_PROJECT, @@ -431,5 +461,5 @@ export { GET_EVENTS_DAILY_TO_COLLECTION, GET_EVENTS_WEEKLY_TO_COLLECTION, GET_EVENTS_MONTHLY_TO_COLLECTION, - GET_USERS_MONTHLY_TO_PROJECT, + //GET_USERS_MONTHLY_TO_PROJECT, }; diff --git a/apps/frontend/lib/paths.ts b/apps/frontend/lib/paths.ts index c9246e15c..c5622df36 100644 --- a/apps/frontend/lib/paths.ts +++ b/apps/frontend/lib/paths.ts @@ -8,30 +8,6 @@ const catchallPathToString = (parts: string[]) => { return parts.map((p) => decodeURIComponent(p)).join("/"); }; -/** - * Converts a path string to an enum - * @param namespacePath - * @returns - */ -const pathToNamespaceEnum = (namespacePath: string) => { - switch (namespacePath) { - case "github": - return "GITHUB"; - case "gitlab": - return "GITLAB"; - case "npm": - return "NPM_REGISTRY"; - case "ethereum": - return "ETHEREUM"; - case "optimism": - return "OPTIMISM"; - case "goerli": - return "GOERLI"; - default: - return null; - } -}; - /** * Converts a path string to an artifact type */ @@ -46,4 +22,4 @@ const pathToTypeEnum = (typePath: string) => { } }; -export { catchallPathToString, pathToNamespaceEnum, pathToTypeEnum }; +export { catchallPathToString, pathToTypeEnum };